目录(?)[+]
主要涉及两个函数:
CvHistogram cvCalcHist
- #include<stdio.h>
- #include<cv.h>
- #include<highgui.h>
- int main()
- {
- int hist_size[]={16,16,16};
- float range[]={0,255};
- float *ranges[]={range};
- int i,j,bin_w;
- float max_value,min_value;
- int min_idx, max_idx;
- char *name[3]={"b","g","r"};
- double mean=0,variance=0;
- IplImage* img=cvLoadImage("b.jpg",1);
- IplImage *pImage=NULL;
- IplImage *pImg[3];
- pImg[0]=cvCreateImage(cvGetSize(img),8,1);
- pImg[1]=cvCreateImage(cvGetSize(img),8,1);
- pImg[2]=cvCreateImage(cvGetSize(img),8,1);
- cvSplit(img,pImg[0],pImg[1],pImg[2],NULL);
- pImage=cvCloneImage(img);
- CvRect rect= cvRect(0,0,500,600);
- cvSetImageROI(pImage,rect);
- //创建一个图像用来存放直方图
- IplImage *histImage[3];
- CvHistogram *hist[3];
- for(j=0;j<3;j++){
- histImage[j]=cvCreateImage(cvSize(320,200),8,3);
- //cvZero(histImage[j]);
- hist[j]=cvCreateHist(1,&hist_size[j],CV_HIST_ARRAY,ranges,1);
- //计算直方图并作用到hist变量中
- cvCalcHist(&pImg[j], hist[j], 0, NULL);
- //得到直方图的最值及标号
- cvGetMinMaxHistValue(hist[j],&min_value,&max_value,&min_idx,&max_idx);
- //缩放其最大值和最小值让其融入图像
- cvScale(hist[j]->bins,hist[j]->bins,((double)histImage[j]->height)/max_value,0);
- //设置所有的直方图的数值为255
- cvSet(histImage[j],cvScalarAll(255),0);
- //建一个比例因子 沿宽度释放
- bin_w=cvRound((double)histImage[j]->width/hist_size[j]);
- mean=0;
- for(i=0;i<hist_size[j];i++)
- {
- CvScalar scalar=cvScalarAll(0);
- scalar.val[j]=(i*255/hist_size[j]);
- cvRectangle(histImage[j],cvPoint(i*bin_w,histImage[j]->height),
- cvPoint((i+1)*bin_w,histImage[j]->height-cvRound(cvGetReal1D(hist[j]->bins,i))),scalar,-1,8,0);
- float *bins=cvGetHistValue_1D(hist[j],i);
- //增加均值
- mean+=bins[0];
- //std::cout<<bins[0]<<" "<<bins[1]<<std::endl;
- //printf("%d %d\n",bins[0],bins[1]);
- }
- cvNamedWindow(name[j],0);
- cvShowImage(name[j],histImage[j]);
- mean/=hist_size[j];
- //根据均值计算变化量
- for(i=0;i<hist_size[j];i++)
- {
- float* bins=cvGetHistValue_1D(hist[j],i);
- variance+=pow((bins[0]-mean),2);
- }
- variance/=hist_size[j];
- printf("histgram Mean:%f\n",mean);
- }
- //创建窗口
- cvNamedWindow("Original",0);
- cvShowImage("Original",pImage);
- cvWaitKey(0);
- cvReleaseImage(&img);
- for(j=0;j<3;j++){
- cvDestroyWindow(name[j]);
- cvReleaseImage(&pImg[j]);
- cvReleaseImage(&histImage[j]);
- cvReleaseHist(&hist[j]);
- }
- cvDestroyWindow("Original");
- return 0;
- }
- typedef struct CvHistogram
- {
- int type;
- CvArr* bins;
- float thresh[CV_MAX_DIM][2]; /* for uniform histograms */
- float** thresh2; /* for non-uniform histograms */
- CvMatND mat; /* embedded matrix header for array histograms */
- }
- CvHistogram;
bins :用于存放直方图每个灰度级数目的数组指针,数组在cvCreateHist的时候创建,其维数由cvCreateHist确定(一般以一维比较常见)
CreateHist
- CvHistogram* cvCreateHist( int dims, int* sizes, int type,float** ranges=NULL, int uniform=1 );
CV_HIST_ARRAY
意味着直方图数据表示为多维密集数组
CvMatND; CV_HIST_TREE
意味着直方图数据表示为多维稀疏数组
CvSparseMat.
uniform
的值。这个范围的用处是确定何时计算直方图或决定反向映射(
backprojected),每个方块对应于输入图像的哪个
/哪组值。
ranges[i]
(
0<=i<cDims
,译者注:
cDims
为直方图的维数,对于灰度图为
1,彩色图为
3)是包含两个元素的范围数组,包括直方图第
i
维的上界和下界。在第
i
维上的整个区域
[lower,upper]被分割成
dims[i]
个相等的块(译者注:
dims[i]
表示直方图第
i维的块数),这些块用来确定输入象素的第
i
个值(译者注:对于彩色图像,
i
确定
R,G,或者
B)的对应的块;如果为
0,则
ranges[i]
是包含
dims[i]+1
个元素的范围数组,包括
lower
0
,upper
0
,lower
1
,upper
1
==lower
2
,..., upper
dims[i]-1
,其中
lower
j
和
upper
j
分别是直方图第
i
维上第
j
个方块的上下界(针对输入象素的第
i
个值)。任何情况下,输入值如果超出了一个直方块所指定的范围外,都不会被
cvCalcHist 计数,而且会被函数
cvCalcBackProject 置零。
函数 cvCreateHist 创建一个指定尺寸的直方图,并且返回创建的直方图的指针。如果数组的 ranges
是0,则直方块的范围必须由函数cvSetHistBinRanges 稍后指定。虽然 cvCalcHist 和 cvCalcBackProject 可以处理8-比特图像而无需设置任何直方块的范围,但它们都被假设等分0..255之间的空间。
计算图像image(s)的直方图
void cvCalcHist( IplImage** image, CvHistogram* hist, int accumulate=0, const CvArr* mask=NULL );
计算图像image(s)的直方图
void cvCalcHist( IplImage** image, CvHistogram* hist, int accumulate=0, const CvArr* mask=NULL );
函数 cvCalcHist 计算单通道或多通道图像的直方图。用来增加直方块的数组元素可从相应输入图像的同样位置提取。
发现最大和最小直方块
void cvGetMinMaxHistValue( const CvHistogram* hist, float* min_value, float* max_value, int* min_idx=NULL, int* max_idx=NULL );
函数 cvGetMinMaxHistValue 发现最大和最小直方块以及它们的位置。任何输出变量都是可选的。在具有同样值几个极值中,返回具有最小下标索引(以字母排列顺序定)的那一个。
http://blog.csdn.net/lansatiankongxxc/article/details/8272633这个程序根据输入的图像计算出一个色相饱和度直方图,然后利用网格的方式将直方图以网格形式显示。
- #include<cv.h>
- #include<highgui.h>
- #include<stdio.h>
- #pragma comment(lib, "cv.lib")
- #pragma comment(lib, "cxcore.lib")
- #pragma comment(lib, "highgui.lib")
- int main()
- {
- IplImage* src = NULL;
- src = cvLoadImage ("test.png", 1);
- IplImage* hsv = cvCreateImage (cvGetSize(src), 8, 3);
- cvCvtColor (src, hsv, CV_BGR2HSV);
- IplImage* h_plane = cvCreateImage (cvGetSize(src), 8, 1);
- IplImage* s_plane = cvCreateImage (cvGetSize(src), 8, 1);
- IplImage* v_plane = cvCreateImage (cvGetSize(src), 8, 1);
- IplImage* planes[] = {h_plane, s_plane};
- cvCvtPixToPlane (hsv, h_plane, s_plane, v_plane, 0);
- /*创建和计算直方图*/
- int h_bins = 30;
- int s_bins = 32;
- CvHistogram* hist = NULL;
- int hist_size[] = {h_bins, s_bins};
- float h_ranges[] = {0, 180};
- float s_ranges[] = {0, 255};
- float* ranges[] = {h_ranges, s_ranges};
- hist = cvCreateHist (2, hist_size, CV_HIST_ARRAY, ranges, 1);
- cvCalcHist (planes, hist, 0, 0); //计算直方图
- cvNormalizeHist (hist, 1.0); //归一化
- /*测试匹配度并输出*/
- /*double like = cvCompareHist (hist, hist, CV_COMP_INTERSECT);
- printf("%lf\n", like);*/
- /*创建一个图像来可视化我们的直方图*/
- int scale = 10;
- IplImage* hist_img = cvCreateImage (cvSize(h_bins * scale, s_bins * scale), 8, 3);
- cvZero (hist_img);
- /*用小的灰度方格填充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);
- cvRectangle (hist_img, cvPoint(h*scale, s*scale), cvPoint((h+1)*scale-1, (s+1)*scale-1),
- CV_RGB(intensity, intensity, intensity),CV_FILLED);
- }
- }
- cvNamedWindow ("src", 1);
- cvShowImage ("src", src);
- cvNamedWindow ("H-S histogram", 1);
- cvShowImage ("H-S histogram", hist_img);
- cvWaitKey (0);
- cvReleaseImage (&src);
- cvReleaseImage (&hsv);
- cvReleaseImage (&hist_img);
- cvReleaseHist (&hist);
- return 0;
- }
在实验中,需要用到OpenCV直方图,并读取其中的bins里的信息,于是做了一些测试,确定了OpenCV直方图的创建方法与bins(直方图的格子们)信息读取方法。
1.如何使用自己的数据建立直方图结构。 使用的函数为cvMakeHistHeaderForArray()
hist 为函数所初始化的直方图头 data 用来存储直方块的数组
- CvHistogram* cvMakeHistHeaderForArray(
- int dims,
- int* sizes,
- CvHistogram* hist,
- float* data,
- float** ranges=NULL,
- int uniform=1 );
举个例子来理解上面函数中的各个参数,下面我将使用自己创建的数据来创建一个一维的直方图,看过《学习OpenCV》的人对于大部分参数应该都理解了,这里就着重介绍和函数cvMakeHistHeaderForArray关系密切的参数。
函数需要一个指向结构CvHistogram 的指针hist,这个指针在使用之前必须经过初始化,即必须是分配过空间的。这个函数还有dims,sizes,ranges,uniform这几个参数,说明这个函数还可以以这些参数产生新的直方图。经过测试,这个函数返回的直方图hist1和以形参形式传入的hist的值是一样的。 其实我很奇怪,不知道这个函数这样做的原因是什么,既然函数运行会改变形参对应的直方图hist的值,那为什么还要来个返回值呢?
- int dims=1;
- int sizes[]={8};
- float data[8]={30,32,60,89,98,87,87,87};
- float range1[]={0,8};
- float *ranges[]={range1};
- CvHistogram *hist=cvCreateHist(dims,sizes,CV_HIST_ARRAY,ranges,1);
- CvHistogram *hist1=cvMakeHistHeaderForArray(dims,sizes,hist,data,ranges,1);
2.如何改变直方图bins中的数据。 我想这个很多看过《学习OpenCV》的高手应该都知道了,我是第二遍回来看的时候才感觉到的,所以还是说下吧。 第一个方法是使用函数cvGetHistValue_1D(CvHistogram* hist,int idx0)这个函数接受一个直方图结构和一个索引值,并返回一个指向对应bins的一个指针ptr。那么就可以使用这个指针访问这个bins的值了。比如给这个bins重新赋值为56,语句为“*ptr=56.f”。 第二个方法是使用指针定位直方图中数据结构部分的数据。”hist->mat.data.fl[0]”这里我假设我访问的是一维直方图的第一个元素。同样的,用“hist->mat.data.fl[0]=56”就可以进行赋值操作了。