Nata 0 Жалоба Опубликовано June 3, 2009 Подскажите пожалуйста, как построить простую гистограмму серого изображения пробовала вот так: IplImage* planes[] = { gray}; // gray - ранее загруженное изображение int hist_size[] = {255}; float s_rang[] = { 0, 255 }; float* ranges[] = {rang}; CvHistogram* hist; hist = cvCreateHist( 1, hist_size, CV_HIST_ARRAY,ranges, 1 ); cvCalcHist( planes, hist, NULL, 0 ); программа ошибок не выдает, но значения гистограммы все кроме одного равны "0", а одно - 255; У меня проблемы с английским, может я не правельно понимаю параметры функций cvCreateHist и cvCalcHist. Объявните что не так Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано June 3, 2009 Подскажите пожалуйста, как построить простую гистограмму серого изображения пробовала вот так: IplImage* planes[] = { gray}; // gray - ранее загруженное изображение int hist_size[] = {255}; float s_rang[] = { 0, 255 }; float* ranges[] = {rang}; CvHistogram* hist; hist = cvCreateHist( 1, hist_size, CV_HIST_ARRAY,ranges, 1 ); cvCalcHist( planes, hist, NULL, 0 ); программа ошибок не выдает, но значения гистограммы все кроме одного равны "0", а одно - 255; У меня проблемы с английским, может я не правельно понимаю параметры функций cvCreateHist и cvCalcHist. Объявните что не так Вот проект с примером построения гистограммы. Архив с проектом: HistogramExample.rar Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
RinOS 16 Жалоба Опубликовано August 21, 2009 Всем привет! В общем написал код для сравнения гистограмм изображений: IplImage* hist2image(IplImage *src, int h_bins = 100, int s_bins = 100, int scale = 5) { IplImage *hsv = cvCreateImage(cvSize(src->width, src->height), 8, 3); IplImage *h = cvCreateImage(cvSize(src->width, src->height), 8, 1); IplImage *s = cvCreateImage(cvSize(src->width, src->height), 8, 1); IplImage *v = cvCreateImage(cvSize(src->width, src->height), 8, 1); IplImage* planes[] = {h, s}; int hist_size[] = {h_bins, s_bins}; float h_ranges[] = {0, 180}; float s_ranges[] = {0, 255}; float* ranges[] = {h_ranges, s_ranges}; cvCvtColor(src, hsv, CV_BGR2HSV); cvCvtPixToPlane(hsv, h, s, v, NULL); CvHistogram* hist; hist = cvCreateHist(2, hist_size, CV_HIST_ARRAY, ranges, 1); cvNormalizeHist(hist, 1.0); cvCalcHist(planes, hist, 0, 0); IplImage* hist_img = cvCreateImage(cvSize(h_bins*scale, s_bins*scale),8,3); cvZero( hist_img ); float max_value = 0; cvGetMinMaxHistValue(hist, 0, &max_value, 0, 0); for(int h = 0; h < h_bins; h++) { for(int s = 0; s < s_bins; s++ ) { float bin_val = cvQueryHistValue_2D( hist, h, s ); int intensity = cvRound( bin_val * 255 / (max_value+1) ); cvRectangle( hist_img, cvPoint(h*scale, s*scale), cvPoint((h+1)*scale - 1, (s+1)*scale - 1), CV_RGB(intensity,intensity,intensity), CV_FILLED); } } return hist_img; } CvHistogram* image2hist(IplImage *src) { IplImage *r1 = cvCreateImage(cvSize(src->width, src->height), 8, 1); IplImage *g1 = cvCreateImage(cvSize(src->width, src->height), 8, 1); IplImage *b1 = cvCreateImage(cvSize(src->width, src->height), 8, 1); IplImage* planes[] = {r1, g1, b1}; int hist_size[] = {200, 200}; float r_ranges[] = {0, 255}; float g_ranges[] = {0, 255}; float b_ranges[] = {0, 255}; float* ranges[] = {r_ranges, g_ranges, b_ranges}; CvHistogram* hist; hist = cvCreateHist(2, hist_size, CV_HIST_ARRAY, ranges, 1); cvCalcHist(planes, hist, 0, 0); return hist; } ... cvNamedWindow("MyWnd", CV_WINDOW_AUTOSIZE); cvNamedWindow("MyWnd2", CV_WINDOW_AUTOSIZE); cvNamedWindow("histMyWnd", CV_WINDOW_AUTOSIZE); cvNamedWindow("histMyWnd2", CV_WINDOW_AUTOSIZE); IplImage *src1 = cvLoadImage("1.bmp"); IplImage *src2 = cvLoadImage("2.bmp"); CvHistogram* hist1 = image2hist(src1); CvHistogram* hist2 = image2hist(src2); cvNormalizeHist(hist1, 1.0); cvNormalizeHist(hist2, 1.0); IplImage *imagehist1 = hist2image(src1); IplImage *imagehist2 = hist2image(src2); double dl = cvCompareHist(hist1, hist2, CV_COMP_CORREL); cvShowImage("MyWnd", src1); cvShowImage("MyWnd2", src2); cvShowImage("histMyWnd", imagehist1); cvShowImage("histMyWnd2", imagehist2); cvWaitKey(0); ... Не знаю, правильно ли работает этот код... Прошу прокомментировать. И еще в книжке читал про cvCompareHist, там последний параметр, это методы сравнения: CV_COMP_CORREL, CV_COMP_CHISQR, CV_COMP_INTERSECT, CV_COMP_BHATTACHARYYA Я конечно с помощью переводчика попробывал перевести... но ни чего из этого не понял(( Может у кого есть на русском? Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Vicul 0 Жалоба Опубликовано August 21, 2009 Ну ты и понакрутил! IplImage* hist2image() она по идее должна делать две вещи: 1. создавать HSV гистограмму 2. создавать ее имидж. CvHistogram* image2hist(IplImage *src) создает RGB гистограмму. Причем сразу вопрос - почему ты отбрасываешь B канал ? int hist_size[] = {200, 200}; // ??? int hist_size[] = {200, 200, 200} .... hist = cvCreateHist(2, hist_size, CV_HIST_ARRAY, ranges, 1); // ???? hist = cvCreateHist(3, hist_size, CV_HIST_ARRAY, ranges, 1); теперь ты создаешь RGB гистограммы CvHistogram* hist1 = image2hist(src1); CvHistogram* hist2 = image2hist(src2); и вызывашь hist2image(), которая создает HSV гистограмму (а зачем, если дальше ты работаешь с RGB гистограммами?) и показываешь их как НSV. Так может проще перейти на HSV и не морочиться с RGB? Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
RinOS 16 Жалоба Опубликовано August 24, 2009 Так может проще перейти на HSV и не морочиться с RGB? Так вроде я и работаю с HSV, входящее изображение RGB сразу и преобразовываю... cvCvtColor(src, hsv, CV_BGR2HSV); Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Vicul 0 Жалоба Опубликовано August 24, 2009 Так вроде я и работаю с HSV, входящее изображение RGB сразу и преобразовываю... cvCvtColor(src, hsv, CV_BGR2HSV); А что делает по твоему image2hist(IplImage *src)? Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано April 3, 2012 http://paulbourke.net/texture_colour/equalisation/ пытаюсь сделать как тут алгоритм допустим я получил измененную гистограмму, непонятно как применять полученную в итоге гистограмму ко всему изображению. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Nuzhny 243 Жалоба Опубликовано April 3, 2012 Через look-up table. Приём такой есть. Есть и в примерах в OpenCV. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано April 3, 2012 в каких конкретно примерах? посмотрел cvEqualizeHist CV_IMPL void cvEqualizeHist( const CvArr* srcarr, CvArr* dstarr ) { CvMat sstub, *src = cvGetMat(srcarr, &sstub); CvMat dstub, *dst = cvGetMat(dstarr, &dstub); CV_Assert( CV_ARE_SIZES_EQ(src, dst) && CV_ARE_TYPES_EQ(src, dst) && CV_MAT_TYPE(src->type) == CV_8UC1 ); CvSize size = cvGetMatSize(src); if( CV_IS_MAT_CONT(src->type & dst->type) ) { size.width *= size.height; size.height = 1; } int x, y; const int hist_sz = 256; int hist[hist_sz]; memset(hist, 0, sizeof(hist)); for( y = 0; y < size.height; y++ ) { const uchar* sptr = src->data.ptr + src->step*y; for( x = 0; x < size.width; x++ ) hist[sptr[x]]++; } float scale = 255.f/(size.width*size.height); int sum = 0; uchar lut[hist_sz+1]; for( int i = 0; i < hist_sz; i++ ) { sum += hist; int val = cvRound(sum*scale); lut = CV_CAST_8U(val); } lut[0] = 0; for( y = 0; y < size.height; y++ ) { const uchar* sptr = src->data.ptr + src->step*y; uchar* dptr = dst->data.ptr + dst->step*y; for( x = 0; x < size.width; x++ ) dptr[x] = lut[sptr[x]]; } } ну в hist мы подсчитали обычную гистограмму потом завели LUT, почему то на одну ячейку больше чем hist и положили туда коммулятивную сумму, причем пронормировали на коэффициент scale = 255.f/(size.width*size.height) и в конце мы пытаемся получить результирующее изображение из LUT подставляя туда цвет сорца. вообщем в итоге имеем hist size= 256 arg= цвет val= частота LUT size= 256+1 arg= цвет val= цвет вообщем зачем LUT size= 256+1 и lut[0] = 0; я не понял. вот мой код смысл таков загружаем 2 изображения и пытаемся выравнять второе относительно первого по гистограмме. int find_nearest(double val, vector<double> cumm_hist) { double delta=INT_MAX; for(int s=0;s<cumm_hist.size();++s) { double dval= abs(cumm_hist[s]-val); if(delta>dval) { delta= dval; } else { return s; } } return -1; } void hist_matching(IplImage* img1,IplImage* img2) { //кол-во ячеек int numBins = 256; float range[] = {0, 255}; float *ranges[] = { range }; //создаем CvHistogram *hist1 = cvCreateHist(1, &numBins, CV_HIST_ARRAY, ranges, 1); cvClearHist(hist1); CvHistogram *hist2 = cvCreateHist(1, &numBins, CV_HIST_ARRAY, ranges, 1); cvClearHist(hist2); //подсчитываем cvCalcHist(&img1, hist1, 0, 0); cvCalcHist(&img2, hist2, 0, 0); //по гистограмме накопленные гистограммы vector<double> cumm_hist1(256); vector<double> cumm_hist2(256); int sum1=0; int sum2=0; for(int s=0;s<numBins;++s) { float bin_val1 = cvQueryHistValue_1D(hist1,s); float bin_val2 = cvQueryHistValue_1D(hist2,s); sum1+= bin_val1; sum2+= bin_val2; cumm_hist1[s]= sum1; cumm_hist2[s]= sum2; } //нормируем на диапазон 0-1 for(int s=0;s<numBins;++s) { cumm_hist1[s]/= sum1; cumm_hist2[s]/= sum2; } vector<int> LUT(256); for(int s=0;s<numBins;++s) { double val=cumm_hist1[s]; int pos= find_nearest(val,cumm_hist2); LUT[s]= pos; //тут похоже ошибка //LUT[pos]= s; //похоже это правильный вариант, но как достать недостающие элементы } for(int y=0;y<img2->height;++y) { uchar* ptr = (uchar*)(img2->imageData+y*img2->widthStep); for(int x=0;x<img2->width;++x) { ptr[x]=LUT[ptr[x]]; } } cvSaveImage("test_hist_eq.png",img2); } если LUT= pos; то вроде бы работает неправильно если LUT[pos]= s; то есть недостающие элементы, т.к. для одного s может быть несколько pos Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Nuzhny 243 Жалоба Опубликовано April 3, 2012 Можешь выложить два изображения, по которым надо выравнивать? Чтобы сразу был виден результат. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано April 3, 2012 изменять надо второе, чтобы получить похожее на первое. и еще интересно, что если у нас не 2 изображения а много? можно конечно взять одно за эталон и от него отталкиваться, но мне кажется не самое лучшее решение. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Nuzhny 243 Жалоба Опубликовано April 4, 2012 Самая первая мысль - как-нибудь сгладить итог. Например: int LUT[HIST_SIZE] = {0}; for (int s = 0; s < numBins; ++s) { double val = cumm_hist1[s]; int pos = find_nearest(val, cumm_hist2, numBins); //LUT[s] = pos; //тут похоже ошибка LUT[pos] = s; //похоже это правильный вариант, но как достать недостающие элементы } if (!LUT[numBins - 1]) LUT[numBins - 1] = LUT[numBins - 2]; for (int s = 1; s < numBins - 2; ++s) { if (!LUT[s]) { if (LUT[s + 1]) LUT[s] = (LUT[s - 1] + LUT[s + 1]) / 2; else LUT[s] = (LUT[s - 1] + LUT[s + 2]) / 2; } } for (int y = 0; y < img2->height; ++y) { uchar* ptr = (uchar*)(img2->imageData + y * img2->widthStep); for (int x = 0; x < img2->width; ++x) { ptr[x] = (uchar)LUT[ptr[x]]; } } Примитивно, но работает. Можно придумать что-нибудь по умней. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Nuzhny 243 Жалоба Опубликовано April 4, 2012 А, понял. Надо находить нулевые интервалы и просто линейно аппроксимировать их, строя прямую по крайним не нулевым значениям. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Nuzhny 243 Жалоба Опубликовано April 4, 2012 Середину моего кода заменить на это: // Интерполяция LUT if (!LUT[numBins - 1]) LUT[numBins - 1] = LUT[numBins - 2]; int start_pos = 0; bool is_null = false; for (int s = 1; s < numBins - 1; ++s) { if (!is_null) { if (!LUT[s]) { start_pos = s - 1; is_null = true; } } else { if (LUT[s]) { double k = double(LUT[s] - LUT[start_pos]) / double(s - start_pos); double b = LUT[start_pos] - k * start_pos; for (int x = start_pos + 1; x < s; ++x) { LUT[x] = (int)(k * x + b ); } is_null = false; } } } P.S. Модератору: в строке LUT[x] = (int)(k * x + B ); маленькая b почему-то автоматически заменяется на большую. Смайлики? Smorodov: Да, смайлики, лечится пробелами межу буквой и скобками. Глубже копать лень. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Nuzhny 243 Жалоба Опубликовано April 4, 2012 Тоже самое в целочисленной арифметике: // Интерполяция LUT if (!LUT[numBins - 1]) LUT[numBins - 1] = LUT[numBins - 2]; int start_pos = 0; bool is_null = false; for (int s = 1; s < numBins - 1; ++s) { if (!is_null) { if (!LUT[s]) { start_pos = s - 1; is_null = true; } } else { if (LUT[s]) { int v1 = LUT[s] - LUT[start_pos]; int v2 = s - start_pos; int v3 = LUT[start_pos] - (v1 * start_pos) / v2; for (int x = start_pos + 1; x < s; ++x) { LUT[x] = (v1 * x) / v2 + v3; } is_null = false; } } } 1 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано April 4, 2012 ну да про интерполяцию я тоже подумал и вроде работает, но небольшие участки с "дырками" все равно остаются. вообщем как то не плавно получается, причем у них вроде дырок нету. хотя там пишут про дырки в гистограмме из-за дискретности As can be seen in the examples above, the matching introduces gaps in the histograms. This is to be expected since the histograms are being distorted. This is especially so for discrete datasets such as images, it can often be reduced for continuous data by creating finer histogram bins. у меня такое ощущение, что дырки на изображении надо как то обрабатывать дополнительно, наверно надо делать интерполяцию по самим пикселям на изображении по этим областям. причем странно, если изображения поменять местами, то выдает черный экран. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Nuzhny 243 Жалоба Опубликовано April 4, 2012 Чёрный экран у меня не получился. Дискретность - да, заметна. Я думаю, что ты прав: для достижения идеального эффекта надо обрабатывать уже итоговое изображения после применения преобразования гистограммы. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах