0

以下のコードは、ユークリッド距離アルゴリズムの作業に由来します。カラー テーブルは、アルゴリズムをテストするための手段に過ぎませんでした。車輪の再発明かもしれませんが、それ自体は役に立ちます。任意の 3 つの RGB 整数 (0 ~ 255) を、最も近い X11 カラー名に関連付けることができます。svickの洞察に感謝します。

現在のコードでは、インスタンスの作成後に AddColor メソッドによって ColorTable が初期化されます。ただし、loadrgb/colorinfo の組み合わせを使用して、Web から X11 カラー テーブルを取得できます。

X11 rgb.txt ファイルのオンライン バージョンからカラー テーブルを初期化する際に、最後の問題が 1 つあります。テキストを {Name: Values:} リストに解析する必要があります。現在、結果は文字列のタプルになっています。「colorinfo」に「ColorTable」をロードさせる作業を行っています。

// currently the color table is create via the AddColor method, however
// the initial values should be created with the loadrgb and colorinfo members
type MyFSColorTable() = 

// pull the X11 rgb.txt color table off the web in text format
  static let loadrgb =
    let url = "http://people.csail.mit.edu/jaffer/Color/rgb.txt"
    let req = WebRequest.Create(url)
    let resp = req.GetResponse()
    let stream = resp.GetResponseStream()
    let reader = new StreamReader(stream)
    let txt = reader.ReadToEnd()
    txt

// parse the text of the rgb.txt color table into a Name: Values: list
  static let colorinfo =
      loadrgb.Split([|'\n'|])
      |> Seq.skip 1
      |> Seq.map (fun line -> line.Split([|'\t'|]))        
      |> Seq.filter (fun values -> values |> Seq.length = 3)
      |> Seq.map (fun values -> string values.[0], string values.[2])
      |> Seq.map (fun (rgb, name) -> rgb.Split([|' '|]), name)
      |> Seq.map (fun (rgb, name) -> [|name, rgb.[0], rgb.[1], rgb.[2]|])

  // Mutable Color Table will be defined on-the-fly
  let mutable ColorTable = []
  // Euclidean distance between 2 vectors - float is overkill here
  static let Dist (V1: float[]) V2 =
    Array.zip V1 V2
      |> Array.map (fun (v1, v2) -> pown (v1 - v2) 2)
      |> Array.sum

//    Add new colors to the head of the ColorTable
  member x.AddColor name rgb = ColorTable <- {Name = name; Values = rgb}::ColorTable

//    Find nearest color by calculating euclidean distance of all colors, 
//    then calling List.minBy for the smallest 
  member x.FindNearestColor (rgb : float[]) =
    let nearestColor =
      ColorTable |> List.minBy (fun color -> Dist rgb color.Values)
    nearestColor.Name
4

2 に答える 2

2

現時点では、構築するコードcolorinfoは、タプル (4 つの文字列を含む) である要素が 1 つだけの配列を含むシーケンスを生成します。これは、全体的な結果のタイプが - 現在のバージョンでは - であることを意味しますseq<(string * string * string * string) []>:

  (...)
  |> Seq.map (fun (rgb, name) -> 
       [|name, rgb.[0], rgb.[1], rgb.[2] |]

これはおそらく意図したものではありません。4 つの文字列を含む配列を作成する場合は、カンマの代わりにセミコロンを使用する必要があり[| name; rgb.[0]; ... |]ます。4 要素のタプルを作成する場合は、タプルの前後の[|andを省略できます。|]

配列またはタプルを名前付きレコード タイプに自動的に変換する方法はありません ( and を含むレコードがあると仮定しますName:string) Values:float[]。そのため、最適なオプションは、パイプラインの最後のステップでこの変換を行うことです。上記を次のものに置き換えることができます。

  |> Seq.map (fun (rgb, name) -> 
        { Name = name
          Values = [| float rgb.[0]; float rgb.[1]; float rgb.[2] |] })
  |> List.ofSeq

List.ofSeqまた、リストを取得できるように、スニペットの最後に追加しました。これは、現在使用しているのと同じタイプですColorTable

(または、すべての文字列を float にValues = Array.map float rgb変換し、配列の任意の長さに対して機能すると言うことができます。)rgb

于 2013-02-06T17:41:13.717 に答える
0

次のようにして、コードを短縮し、{Name: string; Values: float[]} list必要に応じて返すことができます。

static let colorinfo =
  loadrgb.Split('\n')
    |> Seq.skip 1
    |> Seq.choose (fun line ->
      match line.Split('\t') with
      | [|rgb; _; name|] ->
        let values = rgb.Split(' ') |> Array.map float
        Some({Name=name; Values=values})
      | _ -> None)
    |> Seq.toList
于 2013-02-06T18:21:56.333 に答える