2015-03-25 5 views
2

Мне интересно, как построить 2d гистограмму матрицы HSV в opencv C++. Мой текущий код, пытающийся отобразить его, терпит неудачу. Я посмотрел вокруг, как построить гистограммы, и все, что я нашел, это те, которые замышляют их как независимые 1d гистограммы.opencv рисунок 2d гистограмма

Вот мой выходной ток с числом оттенков бункеров составляет 30 и бункеров насыщения является 32:

Вот еще один выход с количеством оттенков бункеров, являющихся 7 и saturaation бункеров, являющихся 5:

Я хотел бы, чтобы выглядеть как результат здесь

http://docs.opencv.org/doc/tutorials/imgproc/histograms/histogram_calculation/histogram_calculation.html

Я также заметил, что всякий раз, когда я делаю cout < < Hist.size это дает мне 50x50. Должен ли я понять, что просто означает, что первое измерение массива составляет 250?

Кроме того, как сортировать гистограмму с высокой до низкой (или наоборот) частоты? Это еще одна проблема, которую я пытаюсь решить.

Моя текущая функция заключается в следующем.

void Perform_Hist(Mat& MeanShift, Mat& Pyramid_Result, Mat& BackProj){ 

    Mat HSV, Hist; 

    int histSize[] = {hbins, sbins}; 
    int channels[] = {0, 1}; 

    float hranges[] = {0, 180}; 
    float sranges[] = {0, 256}; 

    const float* ranges[] = {hranges, sranges}; 

    cvtColor(MeanShift, HSV, CV_BGR2HSV); 

    Mat PyrGray = Pyramid_Result.clone(); 

    calcHist(&HSV, 1, channels, Mat(), Hist, 2, histSize, ranges, true, false); 
    normalize(Hist, Hist, 0, 255, NORM_MINMAX, -1, Mat()); 
    invert(Hist, Hist, 1); 
    calcBackProject(&PyrGray, 1, channels, Hist, BackProj, ranges, 1, true); 

    double maxVal = 0; minMaxLoc(Hist, 0, &maxVal, 0, 0); 

    int scale = 10; 
    Mat histImage = Mat::zeros(sbins*scale, hbins*10, CV_8UC3); 

    for(int i = 1; i < hbins * sbins; i++){ 
    line(histImage, 
    Point(hbins*sbins*(i-1), sbins - cvRound(Hist.at<float>(i-1))), 
    Point(hbins*sbins*(i-1), sbins - cvRound(Hist.at<float>(i))), 
    Scalar(255,0,0), 2, 8, 0); 
    } 
    imshow (HISTOGRAM, histImage); 
} 
+0

, что это двумерная гистограмма? Гистограмма - это вероятность (или количество пикселей) каждого цвета (или любого другого параметра) на изображении (или любой набор данных с любой размерностью), поэтому график 2d-графика x ось - это цвет (значение, код, индекс ...) и y ось - вероятность. Таким образом, вы подразумеваете под 2D-гистограммой это или вы хотите сделать гистограмму для каждого сегмента изображения (например, сетки)? и график гистограмм каким-то образом, как 3D-график? .... кстати. выход гистограммы обычно 1D-массив, а не изображение ... – Spektre

+0

Также вы не можете сортировать цвета по частоте, потому что цвет не является световой частотой (свет какой-то частоты имеет цвет, но назад он не работает), поэтому вы можете сортировать по оттенку вместо. если вы нормализуете интенсивность цвета (значение = 1), тогда вы можете построить 3D-график базы гистограммы. xy - это цветной круг HSV, а Z - вероятность этого цвета ... без нормализации вам понадобится 4D-график ... для таких plot type – Spektre

+0

Это действительно 2d гистограмма, я должен был сделать это ясно. Виноват! Кроме того, как бы я сортировать по оттенку? Могу ли я также сортировать по насыщенности, чтобы следить за каждым оттенком или нет? – Zypps987

ответ

8

Вы имели в виду что-то вроде этого?

HSV histogram as 3D graph

  • это HSV гистограмма показала, как 3D графика
  • V игнорируется, чтобы получить в 3D (в противном случае было бы 4D график ...)

если да то это как сделать это (я не использую OpenCV, поэтому отрегулируйте его по вашим потребностям):

  1. конвертировать исходное изображение в HSV
  2. вычислить гистограмму значения игнорирования V
    • всех цвета с тем же H, S не считается одним цветом, независимо от того, что V является
    • вы можете игнорировать любые другие, но параметр V выглядит как лучший выбор
  3. построить график

    • первый эллипс рисования с более темным цветом (базовый диск HSV)
    • затем для каждой точки возьмите соответствующее значение гистограммы и нарисуйте вертикальную линию с ярким цветом.Размер линии пропорциональна значению гистограммы

Вот код C++ Я сделал это с:

picture pic0,pic1,pic2,zed; 

int his[65536]; 
DWORD w; 

int h,s,v,x,y,z,i,n; 
double r,a; 
color c; 

// compute histogram (ignore v) 
pic2=pic0;      // copy input image pic0 to pic2 
pic2.rgb2hsv();     // convert to HSV 
for (x=0;x<65536;x++) his[x]=0; // clear histogram 
for (y=0;y<pic2.ys;y++)   // compute it 
for (x=0;x<pic2.xs;x++) 
    { 
    c=pic2.p[y][x]; 
    h=c.db[picture::_h]; 
    s=c.db[picture::_s]; 
    w=h+(s<<8);     // form 16 bit number from 24bit HSV color 
    his[w]++;     // update color usage count ... 
    } 
for (n=0,x=0;x<65536;x++) if (n<his[x]) n=his[x]; // max probability 

// draw the colored HSV base plane and histogram 
zed =pic1; zed .clear(999); // zed buffer for 3D 
      pic1.clear(0); // image of histogram 
for (h=0;h<255;h++) 
for (s=0;s<255;s++) 
    { 
    c.db[picture::_h]=h; 
    c.db[picture::_s]=s; 
    c.db[picture::_v]=100;  // HSV base darker 
    c.db[picture::_a]=0; 
    x=pic1.xs>>1;    // HSV base disc position centers on the bottom 
    y=pic1.ys-100; 
    a=2.0*M_PI*double(h)/256.0; // disc -> x,y 
    r=double(s)/256.0; 
    x+=120.0*r*cos(a);   // elipse for 3D ilusion 
    y+= 50.0*r*sin(a); 
    z=-y; 
    if (zed.p[y][x].dd>=z){ pic1.p[y][x]=c; zed.p[y][x].dd=z; } x++; 
    if (zed.p[y][x].dd>=z){ pic1.p[y][x]=c; zed.p[y][x].dd=z; } y++; 
    if (zed.p[y][x].dd>=z){ pic1.p[y][x]=c; zed.p[y][x].dd=z; } x--; 
    if (zed.p[y][x].dd>=z){ pic1.p[y][x]=c; zed.p[y][x].dd=z; } y--; 

    w=h+(s<<8);     // get histogram index for this color 
    i=((pic1.ys-150)*his[w])/n; 
    c.db[picture::_v]=255;  // histogram brighter 
    for (;(i>0)&&(y>0);i--,y--) 
     { 
     if (zed.p[y][x].dd>=z){ pic1.p[y][x]=c; zed.p[y][x].dd=z; } x++; 
     if (zed.p[y][x].dd>=z){ pic1.p[y][x]=c; zed.p[y][x].dd=z; } y++; 
     if (zed.p[y][x].dd>=z){ pic1.p[y][x]=c; zed.p[y][x].dd=z; } x--; 
     if (zed.p[y][x].dd>=z){ pic1.p[y][x]=c; zed.p[y][x].dd=z; } y--; 
     } 
    } 
pic1.hsv2rgb();     // convert to RGB to see correct colors 
  • входное изображение pic0 (роза), выходное изображение pic1 (график гистограммы)
  • pic2 - pic0, преобразованный в HSV для вычисления гистограммы
  • zed является буфером Zed для 3D-дисплея, избегая Z сортировки ...

Я использую свой собственный класс изображения для изображений, поэтому некоторые члены:

  • xs,ys размера изображения в пикселях
  • p[y][x].dd пиксель в точке (х, у) позиции в качестве 32-битового целого типа
  • clear(color) - очищает все изображение
  • resize(xs,ys) - изменение размера изображения в новой резолюции
  • rgb2hsv() и hsv2rgb() ... думаю, что это делает :)

[edit1] ваш 2D гистограмма

Похоже, у вас есть цвет, закодированный в 2D массив. Одна ось - H, а вторая - S. Поэтому вам нужно вычислить значение H,S из адреса массива. Если она линейна, то для HSV[i][j]:

  • H=h0+(h1-h0)*i/maxi
  • S=s0+(s1-s0)*j/maxj
  • или i,j обратного
  • h0,h1,s0,s1 являются цвет диапазонов
  • maxi,maxj является размером массива

Как вы можете см. также отменить V, как и я, теперь у вас есть H,S для каждой ячейки в двумерной матрице гистограммы. Где вероятность - значение ячейки. Теперь, если вы хотите нарисовать изображение, вам нужно знать, как его выводить (как 2D-график, 3D, отображение, ...).Для несортированным 2D графике нарисовать график где:

  • x=i+maj*i
  • y=HSV[i][j]
  • color=(H,S,V=200);

Если вы хотите отсортировать его, то просто вычислить ось х по-разному или рамочную массив 2D в порядке сортировки и x просто приращение

[изменить2] обновление кода и некоторых изображений

Я отремонтировал код C++ выше (неправильный знак значения Z, изменил состояние Z-буфера и добавил больше точек для более приятного вывода). Ваши 2D цвета массива могут быть как это:

HS colors

Где одна ось/индекс H, другой S и Value фиксирована (я выбираю 200). Если ваши оси меняются местами, просто зеркально отразите их на y=x. Я думаю ...

Сортировка по цвету - это действительно просто заказ, в котором вы выбираете все цвета из массива. например:

v=200; x=0; 
for (h=0;h<256;h++) 
for (s=0;s<256;s++,x++) 
{ 
y=HSV[h][s]; 
// here draw line (x,0)->(x,y) by color hsv2rgb(h,s,v); 
} 

Это инкрементный способ. Вы можете вычислить x от H,S вместо достижения иной сортировки или своп fors (x++ должен быть во внутреннем цикле)

Если вы хотите RGB гистограмма участок вместо см:

+2

То есть ** так здорово **. +1. – rayryeng

+0

@rayryeng thx, но если добавить немного лучшего масштабирования, например, отбросить самый встречный цвет фона, это будет еще лучше. также точки должны быть больше 1 пикселя для покрытия отверстий и могут быть логарифмическими y будет еще лучше ... – Spektre

+0

Когда вы говорите «если вы хотите отсортировать его, а затем просто вычислите ось x по-другому», это cv :: sort (Hist, Hist, CV_SORT_DESCENDING); что ты имел в виду? – Zypps987

Смежные вопросы