C# 提出一种针对大型已知集合的颜色模式匹配算法
我有一个要求,要求将一组颜色值样本与一组已知值进行匹配,以找到精确匹配或在可接受距离内的匹配。我不完全确定什么算法最适合这个,我正在寻找建议 我考虑过使用SQL查询,因为我认为这将是一种简单的方法,但是,理想情况下,这将在应用服务器上的内存中完成,甚至在GPU上完成,以获得最大的速度 示例: 假设我们得到一组三个RGB颜色值,两个蓝色和一个橙色: 样本集:C# 提出一种针对大型已知集合的颜色模式匹配算法,c#,algorithm,opencv,hashtable,knn,C#,Algorithm,Opencv,Hashtable,Knn,我有一个要求,要求将一组颜色值样本与一组已知值进行匹配,以找到精确匹配或在可接受距离内的匹配。我不完全确定什么算法最适合这个,我正在寻找建议 我考虑过使用SQL查询,因为我认为这将是一种简单的方法,但是,理想情况下,这将在应用服务器上的内存中完成,甚至在GPU上完成,以获得最大的速度 示例: 假设我们得到一组三个RGB颜色值,两个蓝色和一个橙色: 样本集: Color 1 Color 2 Color 3 Sample A: [25, 25,
Color 1 Color 2 Color 3
Sample A: [25, 25, 25], [10, 10, 10], [100, 100, 100]
Sample B: [125, 125, 125], [10, 10, 10], [200, 200, 200]
Sample C: [13, 87, 255], [10, 10, 10], [100, 100, 100]
Sample D: [67, 111, 0], [10, 10, 10], [200, 200, 200]
Sample E: [255, 255, 255], [10, 10, 10], [100, 100, 100]
颜色1:81177206(蓝色)
颜色2:36、70、224(蓝色)
颜色3:255、132、0(橙色)
这组3个颜色值必须与一组更大的颜色值匹配,以查看是否存在这组颜色值,或者3种颜色中的每种颜色都具有相同的精确RGB值,或者如果存在任何图案,其中颜色的RGB值的变化程度可以接受。让我们假设任何RGB组件的值可以高出或低出3位
假设我们要搜索的一大组已知颜色值如下所示:
CREATE TABLE KnownColorSets (
KC_1_R tinyint NOT NULL,
KC_1_G tinyint NOT NULL,
KC_1_B tinyint NOT NULL,
KC_2_R tinyint NOT NULL,
KC_2_G tinyint NOT NULL,
KC_2_B tinyint NOT NULL,
KC_3_R tinyint NOT NULL,
KC_3_G tinyint NOT NULL,
KC_3_B tinyint NOT NULL
)
CREATE TYPE CompareColorSet As TABLE
(
CC_1_R tinyint NOT NULL,
CC_1_G tinyint NOT NULL,
CC_1_B tinyint NOT NULL,
CC_2_R tinyint NOT NULL,
CC_2_G tinyint NOT NULL,
CC_2_B tinyint NOT NULL,
CC_3_R tinyint NOT NULL,
CC_3_G tinyint NOT NULL,
CC_3_B tinyint NOT NULL
)
CREATE PROCEDURE stpCompareColorSets
(
@Exists bit output,
@CompareColorSet dbo.CompareColorSet readonly
)
AS
DECLARE @MaxDiviation tinyint = 3 -- This may be taken from a General params table or added as a parameter to the stored procedure
SET @Exists = 0
IF EXISTS (
SELECT 1
FROM KnownColorSets KC INNER JOIN
@CompareColorSet CC ON(
KC_1_R BETWEEN CC_1_R - @MaxDiviation AND CC_1_R - @MaxDiviation
AND KC_1_G BETWEEN CC_1_G - @MaxDiviation AND CC_1_G - @MaxDiviation
AND KC_1_B BETWEEN CC_1_B - @MaxDiviation AND CC_1_B - @MaxDiviation
AND KC_2_R BETWEEN CC_2_R - @MaxDiviation AND CC_2_R - @MaxDiviation
AND KC_2_G BETWEEN CC_2_G - @MaxDiviation AND CC_2_G - @MaxDiviation
AND KC_2_B BETWEEN CC_2_B - @MaxDiviation AND CC_2_B - @MaxDiviation
AND KC_3_R BETWEEN CC_3_R - @MaxDiviation AND CC_3_R - @MaxDiviation
AND KC_3_G BETWEEN CC_3_G - @MaxDiviation AND CC_3_G - @MaxDiviation
AND KC_3_B BETWEEN CC_3_B - @MaxDiviation AND CC_3_B - @MaxDiviation
)
)
SET @Exists = 1
已知集合:
Color 1 Color 2 Color 3
Sample A: [25, 25, 25], [10, 10, 10], [100, 100, 100]
Sample B: [125, 125, 125], [10, 10, 10], [200, 200, 200]
Sample C: [13, 87, 255], [10, 10, 10], [100, 100, 100]
Sample D: [67, 111, 0], [10, 10, 10], [200, 200, 200]
Sample E: [255, 255, 255], [10, 10, 10], [100, 100, 100]
在这种情况下,当我们对其运行样本集时,我们会发现零匹配,因为没有任何已知颜色的颜色1与样本集的值接近。但是,让我们向已知集添加另一种颜色,该颜色将返回正匹配:
Sample F: [81,177,206], [36, 70, 224], [255, 132, 0]
如果样本F与已知集合中的这些值一起存在,我们将得到一个正的命中,因为它与样本集合中颜色1的RGB值完全相同。此外,我们需要接受RGB值中不同程度的差异,因此以下内容也将返回正点击,因为每个RGB值都在样本集中颜色1值的3位以内:
正面点击数:(记住颜色1是:81177206)
样本F:80,177206(红色通道距离1位)
样本F:81、175、204(绿色和蓝色通道相隔2位)
样本F:82179208(3位以内的所有三个通道)
但是,如果距离太远,则无法找到匹配项。任何RGB分量必须在3位以内才能触发阳性结果。因此,如果样本F如下所示,我们将而不是得到一个正结果,因为距离太远:
负面点击:
Color 1 Color 2 Color 3
Sample A: [25, 25, 25], [10, 10, 10], [100, 100, 100]
Sample B: [125, 125, 125], [10, 10, 10], [200, 200, 200]
Sample C: [13, 87, 255], [10, 10, 10], [100, 100, 100]
Sample D: [67, 111, 0], [10, 10, 10], [200, 200, 200]
Sample E: [255, 255, 255], [10, 10, 10], [100, 100, 100]
样本F:85,177206(红色通道距离为4位)
样本F:81,170,206(绿色通道距离7位)
样本F:81177,200(蓝色通道距离6位)
到目前为止,我们只考虑了样本集中的颜色1。但是,该要求需要考虑整个样本集。因此,如果没有颜色匹配的1可以找到正匹配,那么我们就假设没有匹配,并且不考虑样本集的颜色2和3。p>
但是,如果我们发现颜色1的结果为正,比如说80177206,它在红色通道80和81中只差1位,那么我们继续处理颜色2,如果我们发现颜色2的结果为正,那么我们处理颜色3,依此类推
你对最适合这个问题的算法有什么建议?我需要的东西,将允许已知的设置规模非常大,没有太多的性能打击。在已知的样本集中,按比例可能会有100多万个样本
我考虑使用哈希表,每种颜色一个哈希表来构造已知的集合。所以我可以测试颜色1上的匹配,如果找到,测试颜色2的哈希表,当我没有找到更多的匹配时停止。如果我通过了所有3种颜色/哈希表的正面点击,那么我会有一个整体的正面匹配,否则我不会。但是,这种方法不考虑每种颜色的每个RGB通道中所需的变化。将有太多的组合,不允许构建哈希表来容纳所有的组合
提前感谢您,感谢您阅读本文 保留一个已排序的列表。使用稳定排序对其进行三次排序,先按B排序,然后按G排序,再按R排序。这样就可以按RGB顺序对其进行排序。根据您的输入,通过二进制搜索找到第一个和最后一个可接受的R的索引。然后在该范围内搜索可接受的G,然后在缩小的范围内再次搜索B。整个事情应该是O(lgN) -- 除非我遗漏了一些东西,否则这个解决方案可以推广到匹配一组3种颜色,或10种颜色或k种颜色。在颜色集列表中生成索引数组。要准备,请按上述方法对索引进行3*k次的稳定排序。要查找,请按相反顺序执行3*k二进制搜索
(这假设颜色固定在列中。如果没有,您仍然可以使用此方法,但索引列表变为N*k大小:它需要A1、A2、A3的条目。最后添加一个检查,确保您已匹配每列中的一个。)根据您在问题中的描述和评论中的对话,为什么不使用简单的存储过程和用户定义的类型?有了适当的索引,就不会有性能问题。假设要比较的颜色集包含多组3种颜色,我可能会这样做:
CREATE TABLE KnownColorSets (
KC_1_R tinyint NOT NULL,
KC_1_G tinyint NOT NULL,
KC_1_B tinyint NOT NULL,
KC_2_R tinyint NOT NULL,
KC_2_G tinyint NOT NULL,
KC_2_B tinyint NOT NULL,
KC_3_R tinyint NOT NULL,
KC_3_G tinyint NOT NULL,
KC_3_B tinyint NOT NULL
)
CREATE TYPE CompareColorSet As TABLE
(
CC_1_R tinyint NOT NULL,
CC_1_G tinyint NOT NULL,
CC_1_B tinyint NOT NULL,
CC_2_R tinyint NOT NULL,
CC_2_G tinyint NOT NULL,
CC_2_B tinyint NOT NULL,
CC_3_R tinyint NOT NULL,
CC_3_G tinyint NOT NULL,
CC_3_B tinyint NOT NULL
)
CREATE PROCEDURE stpCompareColorSets
(
@Exists bit output,
@CompareColorSet dbo.CompareColorSet readonly
)
AS
DECLARE @MaxDiviation tinyint = 3 -- This may be taken from a General params table or added as a parameter to the stored procedure
SET @Exists = 0
IF EXISTS (
SELECT 1
FROM KnownColorSets KC INNER JOIN
@CompareColorSet CC ON(
KC_1_R BETWEEN CC_1_R - @MaxDiviation AND CC_1_R - @MaxDiviation
AND KC_1_G BETWEEN CC_1_G - @MaxDiviation AND CC_1_G - @MaxDiviation
AND KC_1_B BETWEEN CC_1_B - @MaxDiviation AND CC_1_B - @MaxDiviation
AND KC_2_R BETWEEN CC_2_R - @MaxDiviation AND CC_2_R - @MaxDiviation
AND KC_2_G BETWEEN CC_2_G - @MaxDiviation AND CC_2_G - @MaxDiviation
AND KC_2_B BETWEEN CC_2_B - @MaxDiviation AND CC_2_B - @MaxDiviation
AND KC_3_R BETWEEN CC_3_R - @MaxDiviation AND CC_3_R - @MaxDiviation
AND KC_3_G BETWEEN CC_3_G - @MaxDiviation AND CC_3_G - @MaxDiviation
AND KC_3_B BETWEEN CC_3_B - @MaxDiviation AND CC_3_B - @MaxDiviation
)
)
SET @Exists = 1
最后,在试验了SQL和GPU编程(Cudafy)之后,最快、最简单、最可调试的解决方案是使用Parallel.For()简单地迭代数据。这种方法在18ms内处理了150万个样本(总字节数为90M) 3是允许的累积偏差,还是R、G、B值的累积偏差?是集合中每个颜色内的每个RGB值的累积偏差。这并不是一个文化上的偏差,尽管把它作为一个例子也许不是一个坏主意