намалете изображението до N цвята в OpenCV Python

Мога да намеря само примери в C/C++ и те никога не изглежда да се съпоставят добре с OpenCV API. Зареждам видео кадри (както от файлове, така и от уеб камера) и искам да ги намаля до 16 цвята, но съпоставени към 24-битово RGB цветово пространство (това изисква моят изход - гигантски LED дисплей).

Прочетох данните така:

ret, frame = self._vid.read() 
image = cv2.cvtColor(frame, cv2.COLOR_RGB2BGRA)

Намерих примера на python по-долу, но не мога да разбера как да го съпоставя с типа изходни данни, от които се нуждая:

import numpy as np
import cv2

img = cv2.imread('home.jpg')
Z = img.reshape((-1,3))

# convert to np.float32
Z = np.float32(Z)

# define criteria, number of clusters(K) and apply kmeans()
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
K = 8
ret,label,center=cv2.kmeans(Z,K,None,criteria,10,cv2.KMEANS_RANDOM_CENTERS)

# Now convert back into uint8, and make original image
center = np.uint8(center)
res = center[label.flatten()]
res2 = res.reshape((img.shape))

cv2.imshow('res2',res2)
cv2.waitKey(0)
cv2.destroyAllWindows()

Това очевидно работи за програмата за преглед на изображения OpenCV, но се опитва да направи същите грешки в моя изходен код, тъй като имам нужда от RGB или RGBA формат. Моят резултат работи така:

for y in range(self.height):
    for x in range(self.width):
        self._led.set(x,y,tuple(image[y,x][0:3]))

Всеки цвят е представен като (r,g,b) кортеж.

Някакви мисли как да накарам това да работи?


person Adam Haile    schedule 20.09.2015    source източник
comment
res2 в примерния код на OpenCV по-горе е BGR цветно квантувано изображение и това работи добре. Значи проблемът ви е с вашия _led дисплей?   -  person Miki    schedule 20.09.2015
comment
Хм... направих грешка в кода, копирах отново този примерен код и сега работи... нещо като. Но е НАИСТИНА бавно. около 1,5 секунди на кадър   -  person Adam Haile    schedule 20.09.2015
comment
Е, първият проблем е решен! Вероятно е бавен, защото правите kmeans (много много бавен алгоритъм) на всеки кадър. Искате ли квантуваният цвят да се променя с времето? Или задавате фиксиран набор от цветове и ги използвате завинаги? Също така имайте предвид, че използването на алгоритъма medianCut може да бъде по-бързо от kmeans.   -  person Miki    schedule 20.09.2015


Отговори (2)


Мисля, че следното може да бъде по-бързо от kmeans, особено с k = 16.

  1. Преобразувайте цветното изображение в сиво
  2. Контрастно разтегнете това сиво изображение, така че получените нива на сивото на изображението да са между 0 и 255 (използвайте нормализиране с NORM_MINMAX)
  3. Изчислете хистограмата на това разтегнато сиво изображение, като използвате 16 като брой контейнери (calcHist)
  4. Сега можете да промените тези 16 стойности на хистограмата. Например можете да сортирате и присвоявате рангове (да речем от 0 до 15) или да присвоявате 16 равномерно разпределени стойности между 0 и 255 (мисля, че те могат да ви дадат последователен изход за видеоклип)
  5. Обратно проектирайте тази хистограма върху разтегнатото сиво изображение (calcBackProject)
  6. Приложете цветна карта към това обратно прожектирано изображение (може да искате да мащабирате обратно прожектираното изображение, преди да приложите цветна карта с помощта на applyColorMap)

Съвет за kmeans: Ако използвате kmeans за видео, можете да използвате центровете на клъстерите от предишния кадър като начални позиции в kmeans за текущия рамка. По този начин ще отнеме по-малко време за сближаване, така че kmeans в следващите кадри най-вероятно ще работят по-бързо.

person dhanushka    schedule 21.09.2015
comment
Простете за невежеството ми, но нямам представа как да направя нещо от това... Аз съм напълно начинаещ в OpenCV. - person Adam Haile; 21.09.2015
comment
@AdamHaile О. Актуализирах отговора си със съвет за kmeans. Тъй като вече сте използвали kmeans, можете да опитате предложената модификация. - person dhanushka; 22.09.2015

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

person Mikael Rousson    schedule 22.09.2015
comment
Как бихте избрали най-близкия центроид? Ако повторя центроидите и изчисля всяко разстояние от центроида до пиксела и след това избера най-малкото разстояние, отнема твърде много време. - person Adi; 20.07.2016
comment
@Adi погледнете алгоритмите за търсене на най-близки съседи за това. - person Mikael Rousson; 21.07.2016