Перейти к содержимому
Compvision.ru
Nata

гистограмма изображения

Recommended Posts

Подскажите пожалуйста, как построить простую гистограмму серого изображения

пробовала

вот так:

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. Объявните что не так :(

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Подскажите пожалуйста, как построить простую гистограмму серого изображения

пробовала

вот так:

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.jpg

Архив с проектом: HistogramExample.rar

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Всем привет! В общем написал код для сравнения гистограмм изображений:

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

Я конечно с помощью переводчика попробывал перевести... но ни чего из этого не понял((

Может у кого есть на русском?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Ну ты и понакрутил!

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?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Так может проще перейти на HSV и не морочиться с RGB?

Так вроде я и работаю с HSV, входящее изображение RGB сразу и преобразовываю...

cvCvtColor(src, hsv, CV_BGR2HSV);

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Так вроде я и работаю с HSV, входящее изображение RGB сразу и преобразовываю...

cvCvtColor(src, hsv, CV_BGR2HSV);

А что делает по твоему image2hist(IplImage *src)?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

http://paulbourke.net/texture_colour/equalisation/

пытаюсь сделать как тут алгоритм

допустим я получил измененную гистограмму, непонятно как применять полученную в итоге гистограмму ко всему изображению.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Через look-up table. Приём такой есть. Есть и в примерах в OpenCV.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

в каких конкретно примерах?

посмотрел 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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Можешь выложить два изображения, по которым надо выравнивать? Чтобы сразу был виден результат.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

post-701-0-47662400-1333450597_thumb.jpg

post-701-0-26759900-1333450613_thumb.jpg

изменять надо второе, чтобы получить похожее на первое.

и еще интересно, что если у нас не 2 изображения а много?

можно конечно взять одно за эталон и от него отталкиваться, но мне кажется не самое лучшее решение.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Самая первая мысль - как-нибудь сгладить итог. Например:

	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]];

		}

	}

Примитивно, но работает. Можно придумать что-нибудь по умней.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

А, понял. Надо находить нулевые интервалы и просто линейно аппроксимировать их, строя прямую по крайним не нулевым значениям.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Середину моего кода заменить на это:

	// Интерполяция 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: Да, смайлики, лечится пробелами межу буквой и скобками. Глубже копать лень.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Тоже самое в целочисленной арифметике:

	// Интерполяция 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;

			}

		}

	}

  • Like 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

ну да про интерполяцию я тоже подумал и вроде работает, но небольшие участки с "дырками" все равно остаются.

вообщем как то не плавно получается, причем у них вроде дырок нету.

хотя там пишут про дырки в гистограмме из-за дискретности

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.

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

post-701-0-76253100-1333529630_thumb.png

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Чёрный экран у меня не получился. Дискретность - да, заметна.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте учётную запись или войдите для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать учётную запись

Зарегистрируйтесь для создания учётной записи. Это просто!

Зарегистрировать учётную запись

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас


  • Сейчас на странице   0 пользователей

    Нет пользователей, просматривающих эту страницу

×