Предложете алгоритъм за съпоставяне на цветови шаблон спрямо голям известен набор

Имам изискване, което изисква съпоставяне на примерен набор от цветови стойности срещу известен набор от стойности, за да намеря или точно съвпадение, или съвпадения, които са на приемливо разстояние. Не съм напълно сигурен кой алгоритъм би бил най-подходящ за това и търся предложения.

Мислех да използвам SQL заявка, тъй като смятам, че това би било лесен подход, но в идеалния случай това ще бъде направено в паметта на сървъра на приложения или дори на GPU за максимална скорост.

Пример:

Да кажем, че ни е даден набор от три RGB цветови стойности, две сини и една оранжева:

Примерен комплект:

Цвят 1: 81 177 206 (син)

Цвят 2: 36, 70, 224 (син)

Цвят 3: 255, 132, 0 (оранжев)

Този набор от 3 цветови стойности трябва да бъде съпоставен с много по-голям набор от цветови стойности, за да се види дали този набор съществува в него, или със същите точни RGB стойности за всеки от 3-те цвята - или - ако съществува някакъв модел, където 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 съществуваше с тези стойности в известния набор, щяхме да получим положително попадение, защото това са точните RGB стойности като цвят 1 в нашия примерен набор. Освен това трябва да приемем различна степен на разлики в RGB стойностите, така че следното също ще върне положителни резултати, тъй като всяка RGB стойност е в рамките на 3 цифри от стойностите на цвят 1 от примерния набор:

Положителни попадения: (не забравяйте, че цвят 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,170206 (зеленият канал е на 7 цифри разстояние)

Пример F: 81,177,200 (синият канал е на 6 цифри разстояние)

Досега сме взели предвид Цвят 1 от Примерния комплект. Изискването обаче изисква да се вземе предвид целият набор от проби. Така че, ако не могат да бъдат намерени положителни съвпадения за Цвят 1, тогава приемаме, че изобщо няма съвпадение и не вземаме предвид Цветове 2 и 3 от Примерния набор.

Въпреки това, ако намерим положителен резултат за Цвят 1, да кажем 80,177,206, което е само 1 цифра по-малко в червения канал 80 срещу 81, тогава правим да продължим да обработваме Цвят 2 и ако намерим положителен мач за това, след което обработваме Цвят 3 и т.н.

Какви са вашите предложения за най-подходящ алгоритъм за този проблем? Имам нужда от нещо, което ще позволи на известния набор да се разраства в много големи размери без прекалено голям удар в производителността. Вероятно ще има 1M+ проби в известния набор в мащаб.

Мислех да използвам хеш-таблици, по една на цвят, за да конструирам известния набор. Така че мога да тествам за съвпадение на цвят 1 и ако го намеря, да тествам хеш-таблицата за цвят 2 и да спра, когато не намеря повече попадения. Ако премина през всичките 3 цвята/хеш-таблици с положителни попадения, тогава ще имам общо положително съвпадение, иначе не бих. Този подход обаче не позволява необходимата вариация във всеки от RGB каналите за всеки цвят. Ще има твърде много комбинации, за да се даде възможност за конструиране на хеш-таблици, които да поберат всичко.

Благодаря предварително и благодаря, че прочетохте дотук!


person znelson    schedule 19.04.2015    source източник
comment
3 позволено ли е кумулативното отклонение или е за всяка от стойностите R, G, B?   -  person Anshul Goyal    schedule 19.04.2015
comment
Това е за всяка от RGB стойностите в рамките на всеки от цветовете в комплекта. Това не е кумулативно отклонение, въпреки че може би не е лоша идея да имате такова като допълнителна защита.   -  person znelson    schedule 19.04.2015
comment
Използвате OpenCV с C#? Използвайки EmguCV предполагам?   -  person Failed Scientist    schedule 19.04.2015
comment
Какво означава, че имате няколко набора от известния набор от цветове, които отговарят на критериите? Колко често се променя известният набор в сравнение с честотата на изпълнение на този алгоритъм? Размерът на допустимото отклонение фиксиран ли е или може да се променя с времето?   -  person Zohar Peled    schedule 19.04.2015
comment
@TalhaIrfan В идеалния случай, да. Опитвах се да използвам демонстрацията на SurfFeature като отправна точка. Но този пример сравнява изображение A с изображение B, докато аз трябва да сравня характеристиките на изображение A с цял известен набор в базата данни. Не успях да модифицирам пробата SurfFeature, за да направя това. Ако можете да ме насочите в правилната посока ще съм ви безкрайно благодарен.   -  person znelson    schedule 19.04.2015
comment
@ZoharPeled Докато една проба в известния набор съвпада (или е в рамките на отклонението на един или повече от RGB каналите за цвета, който се тества), това е цялостен успех. Известният набор само ще расте с времето. Отклонението може да се промени малко нагоре или надолу, за да се разреши фалшивите положителни/отрицателни резултати. Отклонението обаче не се променя по отношение на изпълнението на алгоритъма. С други думи, ако отклонението е 3, то винаги е 3 за всеки тест за цвят/проба, докато не реша да го променя един ден.   -  person znelson    schedule 19.04.2015
comment
Вашите цветни набори винаги ли ще съдържат 3 цвята или могат да бъдат произволен брой цветове? (например, ако го съхраните в база данни, ще имате ли таблица с 9 tinyint колони? (всеки цвят има 3 tinyint колони)   -  person Zohar Peled    schedule 19.04.2015
comment
@ZoharPeled да, винаги ще има същия брой цветове в рамките на набор. По отношение на SQL си прав.   -  person znelson    schedule 19.04.2015
comment
Е, скъпи, предполагам, че не си използвал много EmguCV. Просто прегледайте уебсайта му и ще получите цялата информация. Има и примерни проекти :)   -  person Failed Scientist    schedule 19.04.2015
comment
@TalhaIrfan Прегледах сайта и имам всички мостри. Моля, насочете ме към такъв, който използва GpuMat за референтни изображения, захранвани от база данни. Проблемът е как да го настроите, така че да не сравнява изображение A с изображение B, а по-скоро изображение A с n-изображения, като всички използват GPU.   -  person znelson    schedule 19.04.2015
comment
Пренесох логиката към Cudafy и я пуснах на моя GPU. Оказва се, че е с 50% по-бавен на GPU в сравнение с PLINQ на CPU. Преминете към stackoverflow .com/questions/29739044/, ако се интересувате да разберете как е възможно това!   -  person znelson    schedule 20.04.2015


Отговори (3)


Съхранявайте един сортиран списък. Сортирайте го три пъти със стабилно сортиране, първо по B, след това по G, след това по R. Това го оставя сортиран в RGB ред. Като се има предвид въведеното от вас, намерете индексите за първия и последния приемлив R с двоично търсене. След това потърсете този диапазон за приемливи G, след това потърсете отново намаления диапазон за B. Цялото нещо трябва да бъде O(lgN).

-- Освен ако не пропускам нещо, това решение обобщава съвпадението на набор от 3 цвята, или 10 цвята, или k цвята. Генерирайте масив от индекси във вашия списък с цветови набори. За да подготвите, стабилно сортирайте индексите 3*k пъти, както по-горе. За да търсите, направете 3*k двоични търсения в обратен ред.

(Това предполага, че цветовете са фиксирани в колони. Ако не са, пак можете да използвате този метод, но списъкът ви с индекси преминава към размер N*k: има нужда от запис за A1, A2, A3. И в края добавете проверете дали сте съпоставили по един от всяка колона.)

person AShelly    schedule 19.04.2015
comment
Благодаря - това обаче решава само един цвят в набора от проби. В примерите по-горе това ще работи, да речем, за Цвят 1, но ще трябва да го повторя за Цветове 2 и 3. Какво се случва, когато трябва да тествам 10 цвята в набор от проби? - person znelson; 19.04.2015
comment
Значи имате голям списък от N набора, където всеки набор има размер k, и искате да намерите само набор, където всички k стойности са достатъчно близки? - person AShelly; 19.04.2015
comment
Имам голям списък от N набора, където всеки набор е съставен от брой подмножества с фиксиран размер („цветовете“ в примера по-горе). В рамките на всяко от тези подмножества има три int стойности (r, g, b). Трябва да намеря кои набори от големия списък имат подмножества, чиито rgb стойности са в рамките на n-цифрени цифри от набора от примери, но на база цвят за цвят. - person znelson; 19.04.2015

В крайна сметка, след експериментиране със SQL и GPU програмиране (Cudafy), най-бързото, най-лесното и най-отстранимото решение беше просто да се обхождат данните с помощта на Parallel.For(). Този подход даде 1,5 милиона обработени проби (общо 90 милиона байта) за 18 ms.

person znelson    schedule 21.04.2015

Въз основа на вашето описание във въпроса и разговора в коментарите, защо не използвате проста съхранена процедура и дефиниран от потребителя тип? при правилно индексиране не би трябвало да има проблеми с производителността. Ако приемем, че наборите от цветове, които искате да сравните, съдържат множество набори от 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
person Zohar Peled    schedule 19.04.2015
comment
Благодаря - точно това опитвам в момента. Чувството ми е, че тъй като общият брой редове в таблицата ще бъде в ниските милиони и че SQL сървърът е доста ефективен с планове за заявки, имам много по-голям шанс за успех с този маршрут в сравнение с използването на структури от данни в C#, които аз не съм запознат с. - person znelson; 19.04.2015
comment
Силата на sql е работата с големи набори от данни и порядък от няколко милиона едва ли е закуска за добре индексирана таблица на sql сървър. Другото предимство е, че не е необходимо сами да пишете алгоритъма за търсене. - person Zohar Peled; 19.04.2015
comment
Оказва се, че SQL е най-бавният метод, последван от GPU (изненадващо), а най-бързият метод е PLINQ на CPU. - person znelson; 20.04.2015
comment
@znelson: Ако имате предвид наскоро изтрития ви въпрос, ядрото ви изглеждаше като обвързано с паметта и GPU вероятно е бавен, защото трябва да копирате данните в GPU. Ако данните се намират на GPU, а не на CPU, версията, базирана на GPU, би била по-ефективна. (също имахте огромни разгънати цикли и вероятно губехте инструкции за извличане на честотна лента на паметта) - person ; 20.04.2015
comment
@znelson Имахте ли някакви индекси на вашата таблица и тип? - person Zohar Peled; 20.04.2015
comment
@ZoharPeled Опитах тестове със и без индекси. Те определено подобриха производителността, но времето все още е 250-300ms срещу PLINQ, което е около 180ms-200ms. - person znelson; 20.04.2015
comment
@znelson Предполагам, че PLINQ е по-добро решение тогава :-) - person Zohar Peled; 20.04.2015