建议一种针对大型已知集的颜色模式匹配的算法

时间:2015-04-19 13:04:09

标签: c# algorithm opencv hashtable knn

我要求调用将颜色值的样本集与已知的值集匹配,以找到完全匹配或匹配在可接受的距离内。我不完全确定哪种算法最适合这个,我正在寻找建议。

我考虑使用SQL查询,因为我认为这将是一种简单的方法,但是,理想情况下,这将在应用程序服务器上内存或甚至在GPU上以最大速度完成。

示例

假设我们给出了一组三个RGB颜色值,两个蓝色和一个橙色:

样本集:

颜色1:81,177,206(蓝色)

颜色2:36,70,224(蓝色)

颜色3:255,132,0(橙色)

这组3个颜色值必须与更大的颜色值集匹配,以查看该集合是否存在于其中,或者使用3种颜色中每种颜色的相同精确RGB值 - 或 - 如果存在任何模式颜色的RGB值以可接受的程度变化。假设任何RGB分量的值都可以高达或高于3位数。

假设我们要搜索的大量已知颜色值如下所示:

已知集:

            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是:81,177,206)

样本F: 80 ,177,206(红色通道距离1位数)

样本F:81, 175 204 (绿色和蓝色通道2位数)

样本F: 82,179,208 (3位数以外的所有三个频道)

但是,如果距离太远,则无法找到匹配项。任何RGB分量必须在3位数内才能触发正结果。因此,如果样本F看起来如下,我们得到正面结果,因为距离太远:

否定点击:

样本F: 85 ,177,206(红色通道距离4位数)

样本F:81, 170 ,206(绿色通道距离7位数)

样本F:81,177, 200 (蓝色通道距离6位数)

到目前为止,我们刚刚从样本集中考虑了颜色1。但是,该要求要求考虑整个样品组。因此,如果没有找到颜色1的正匹配,那么我们假设根本没有匹配,并且不考虑样本集中的颜色2和3。

然而,如果我们找到Color 1的正面结果,让我们说80,177,206只是红色通道80对81的1位数,那么我们继续处理Color 2,如果我们找到一个肯定的匹配,然后我们处理颜色3,依此类推。

您对最适合此问题的算法有何建议?我需要的东西可以让Known Set在没有太多性能影响的情况下进行扩展。大规模的已知集合中可能会有1M +样本。

我考虑过使用哈希表,每个颜色一个来构造已知集。所以我可以测试Color 1上的匹配,如果找到,测试颜色2的哈希表,并在找不到更多匹配时停止。如果我通过所有3种颜色/哈希表得到肯定的命中,那么我会有一个整体正面匹配,否则我不会。然而,该方法不允许每种颜色的每个RGB通道中所需的方差。会有太多的组合允许构造哈希表来保存它们。

提前致谢,感谢您阅读这篇文章!

3 个答案:

答案 0 :(得分:2)

保留一个已排序的列表。使用稳定排序对其进行三次排序,首先按B,然后按G,然后按R.按照RGB顺序对其进行排序。根据您的输入,使用二进制搜索找到第一个和最后一个可接受的R的索引。然后在该范围内搜索可接受的G,然后再搜索B的缩小范围。整件事应该是O(lgN)。

- 除非我遗漏了某些东西,否则这个解决方案会推广到匹配一组3种颜色,或10种颜色或k种颜色。在您的颜色集列表中生成索引数组。准备,如上所述稳定地对索引进行3 * k次排序。要搜索,请按相反的顺序进行3 * k二进制搜索。

(这假定颜色固定在列中。如果不是,你仍然可以使用这种方法,但你的索引列表会变成N * k大小:它需要一个A1,A2,A3的条目。结束添加一个检查,表明您已从每列中匹配一个。)

答案 1 :(得分:1)

最后,在尝试使用SQL和GPU编程(Cudafy)之后,最快,最简单,最可调试的解决方案是使用Parallel.For()简单地遍历数据。这种方法在18ms内处理了1.5M样本(总共90M字节)。

答案 2 :(得分:0)

根据您在问题中的描述和评论中的对话,为什么不使用简单的存储过程和用户​​定义的类型?通过适当的索引,应该没有性能问题。假设您要比较的颜色集包含多组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