我要求调用将颜色值的样本集与已知的值集匹配,以找到完全匹配或匹配在可接受的距离内。我不完全确定哪种算法最适合这个,我正在寻找建议。
我考虑使用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通道中所需的方差。会有太多的组合允许构造哈希表来保存它们。
提前致谢,感谢您阅读这篇文章!
答案 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