以下代码源于欧几里德距离算法的工作。颜色表只是测试算法的工具。它可能是重新发明轮子,但它本身是有用的。任何3个RGB整数(0-255)都可以与最近的X11颜色名称相关联。非常感谢svick的见解。
在当前代码中,在创建实例后,通过AddColor方法初始化ColorTable。但是,loadrgb / colorinfo组合可用于从Web下载X11颜色表。
我在从X11 rgb.txt文件的在线版本初始化颜色表时遇到了最后一个问题。我需要将文本解析为{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
答案 0 :(得分:2)
目前,构造colorinfo
的代码生成一个包含数组的序列,该数组只包含一个元素,它是一个元组(包含四个字符串)。这意味着整体结果的类型 - 在您当前的版本中 - seq<(string * string * string * string) []>
:
(...)
|> Seq.map (fun (rgb, name) ->
[|name, rgb.[0], rgb.[1], rgb.[2] |]
这可能不是预期的 - 如果你想创建一个包含四个字符串的数组,你需要使用分号而不是逗号[| name; rgb.[0]; ... |]
,如果你想创建四元素元组,那么你可以省略1}}和[|
围绕元组。
无法自动将数组或元组转换为命名记录类型(假设您有|]
和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
,它将Values = Array.map float rgb
中的所有字符串转换为浮点数,并且适用于数组的任何长度。)
答案 1 :(得分: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