#include"stdafx.h" #include<cv.h> #include<highgui.h> #include<stdlib.h> int main(int argc, _TCHAR* argv[]) { IplImage* image = cvLoadImage("D:/3.jpg"); IplImage* gray_image = cvCreateImage(cvGetSize(image), image->depth, 1); cvCvtColor(image, gray_image, CV_BGR2GRAY); cvShowImage("ddd", gray_image); int dims = 1;//灰度图像为一维 int size[] = { 256 }; float range[] = { 0, 255 }; float* ranges[] = { range }; CvHistogram* gray = cvCreateHist(dims, size, CV_HIST_ARRAY, ranges, 1); cvCalcHist(&gray_image, gray, 0,NULL); IplImage* show = cvCreateImage(cvSize(256, 256), 8, 3); cvZero(show); float max_value = 0; cvGetMinMaxHistValue(gray, 0, &max_value, 0, 0); float max = 256*0.9; CvScalar color = cvScalar(10, 50, 256); for (int i = 0; i < 256; i++) { float* value = cvGetHistValue_1D(gray, i); CvPoint p0 = cvPoint(i, 256); float out = 256 - (*value)*max / max_value; //printf("%d : %f\n",i, out); CvPoint p1 = cvPoint(i + 1, out); cvRectangle(show, p0, p1, color, 1, 8, 0); } cvShowImage("last", show); char c = cvWaitKey(); if (c == 27) { cvReleaseImage(&image); cvReleaseImage(&gray_image); cvReleaseImage(&show); return 0; } }
原图转灰度图:
测试每一灰度的高度:
0 : 255.887054 1 : 253.741180 2 : 251.708237 3 : 250.240005 4 : 247.190582 5 : 245.270584 6 : 242.898819 7 : 241.656464 8 : 239.284698 9 : 237.138824 10 : 237.703522 11 : 234.315292 12 : 228.329407 13 : 219.294113 14 : 209.355301 15 : 214.550598 16 : 210.484711 17 : 204.950592 18 : 199.529419 19 : 189.025879 20 : 171.519989 21 : 168.470581 22 : 161.468231 23 : 160.338821 24 : 161.920013 25 : 171.181183 26 : 178.409424 27 : 170.616486 28 : 175.924713 29 : 179.425873 30 : 179.877655 31 : 180.555298 32 : 183.717651 33 : 190.042358 34 : 193.656464 35 : 197.157654 36 : 193.995300 37 : 197.722351 38 : 194.221176 39 : 199.755295 40 : 194.447052 41 : 198.287064 42 : 200.320007 43 : 204.272949 44 : 202.578827 45 : 198.738831 46 : 200.432938 47 : 205.967056 48 : 201.788239 49 : 204.047058 50 : 204.385880 51 : 211.388245 52 : 211.162354 53 : 209.468231 54 : 212.404709 55 : 208.564697 56 : 205.854126 57 : 203.708237 58 : 206.870590 59 : 214.324707 60 : 205.854126 61 : 206.644714 62 : 204.498825 63 : 203.595306 64 : 205.854126 65 : 205.176468 66 : 209.242355 67 : 204.047058 68 : 200.771759 69 : 202.240005 70 : 201.788239 71 : 205.289413 72 : 203.030594 73 : 204.837646 74 : 203.934113 75 : 204.611755 76 : 208.451767 77 : 210.597656 78 : 207.548233 79 : 207.209412 80 : 208.112946 81 : 210.597656 82 : 207.887054 83 : 212.743530 84 : 209.355301 85 : 205.741180 86 : 200.997650 87 : 203.821182 88 : 205.063538 89 : 202.352936 90 : 196.254120 91 : 200.771759 92 : 194.334122 93 : 193.882355 94 : 194.108246 95 : 197.383530 96 : 191.510590 97 : 195.689423 98 : 189.251770 99 : 186.992950 100 : 190.042358 101 : 192.639999 102 : 184.056473 103 : 186.654114 104 : 185.185883 105 : 182.136475 106 : 177.392944 107 : 176.489410 108 : 173.778824 109 : 170.051773 110 : 162.936462 111 : 167.792938 112 : 156.047058 113 : 160.451767 114 : 156.611755 115 : 152.320007 116 : 152.545883 117 : 155.595306 118 : 158.531769 119 : 162.145889 120 : 156.272949 121 : 154.014130 122 : 146.672943 123 : 156.047058 124 : 150.964706 125 : 162.823532 126 : 164.743530 127 : 170.503540 128 : 169.600006 129 : 170.616486 130 : 159.209412 131 : 148.028229 132 : 129.279999 133 : 144.188232 134 : 156.160004 135 : 176.150589 136 : 183.604706 137 : 191.849411 138 : 193.543533 139 : 193.769409 140 : 198.399994 141 : 198.964706 142 : 198.174118 143 : 203.482361 144 : 199.868240 145 : 200.207062 146 : 204.950592 147 : 203.256470 148 : 204.950592 149 : 204.611755 150 : 200.545883 151 : 204.950592 152 : 203.708237 153 : 201.110596 154 : 204.837646 155 : 203.143524 156 : 205.063538 157 : 204.724701 158 : 205.063538 159 : 202.917648 160 : 204.272949 161 : 202.578827 162 : 201.110596 163 : 200.884705 164 : 199.981171 165 : 198.512939 166 : 207.435303 167 : 200.884705 168 : 199.190582 169 : 199.642365 170 : 197.383530 171 : 193.430588 172 : 196.141174 173 : 192.978821 174 : 185.637634 175 : 186.428238 176 : 183.378815 177 : 175.924713 178 : 173.778824 179 : 173.440002 180 : 165.421173 181 : 164.743530 182 : 164.856476 183 : 160.225891 184 : 166.211761 185 : 161.355301 186 : 154.691772 187 : 155.143524 188 : 148.367065 189 : 146.447052 190 : 149.044708 191 : 150.738831 192 : 144.865875 193 : 143.058823 194 : 150.851776 195 : 146.447052 196 : 146.898834 197 : 140.122360 198 : 139.896484 199 : 120.696472 200 : 116.404709 201 : 92.574127 202 : 95.058823 203 : 90.202362 204 : 81.167068 205 : 78.343536 206 : 73.938828 207 : 82.861176 208 : 78.569427 209 : 97.430588 210 : 101.496475 211 : 109.854126 212 : 96.639999 213 : 89.524704 214 : 86.249420 215 : 64.677643 216 : 51.011765 217 : 75.858826 218 : 60.724716 219 : 36.894119 220 : 25.600006 221 : 31.811768 222 : 72.244720 223 : 85.120010 224 : 98.672943 225 : 101.496475 226 : 136.734131 227 : 149.835297 228 : 149.044708 229 : 159.435303 230 : 168.018829 231 : 174.569427 232 : 181.797638 233 : 194.672943 234 : 204.160004 235 : 210.936478 236 : 221.327057 237 : 226.183533 238 : 231.378830 239 : 231.604706 240 : 236.461182 241 : 236.687057 242 : 239.397644 243 : 241.317642 244 : 243.576477 245 : 245.044708 246 : 246.738831 247 : 247.755295 248 : 250.352936 249 : 250.240005 250 : 249.901184 251 : 250.691772 252 : 254.305878 253 : 253.063522 254 : 254.644699 255 : 256.000000
对应结果:
函数解析:
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. */ }借个图帮助理解,其中也包含二维的使用:http://blog.csdn.net/lu597203933/article/details/14104505这里有该图的解释
第一个成员type:
用来指定第二个成员bins的具体类型。bins的类型是CvArr*,看其定义可以知道,CvArr* 仅仅是被用于作函数的参数,用于指示函数接收的数组类型可以不止一个,如 IplImage*, CvMat* 甚至 CvSeq*,所以需要type来具体指定bins的类型。
第二个成员bins :
用于存放直方图每个灰度级数目的数组指针,数组在cvCreateHist 的时候创建,其维数由cvCreateHist 确定(一般以一维比较常见)。
bin的含义:计算颜色直方图需要将颜色空间划分为若干小的颜色区间,即直方图的bin,通过计算颜色在每个小区间内德像素得到颜色直方图,bin越多,直方图对颜色的分辨率越强,但增加了计算机的负担。即(学习opencv图7-2中所分成的9个竖条区域,每个竖条区域称为一个bin)
第三个成员thresh:
一个二维数组,CV_MAX_DIM对应直方图的维数。且第二维固定为2。
这个数组比较难理解,首先要理解什么是一维直方图和二维直方图。一维直方图就是单通道图像的直方图,或者彩色图像中某个单独通道的直方图。二维直方图就是2个通道的直方图,比如彩色图像的红-蓝直方图。既然是直方图,必定有上下界,所以thresh的第二维是2,比如[0 255],就是统计[0-255]区间灰度分布的直方图。而二维红-蓝直方图的thresh为[0 255;100 200],就是分别统计红色图像灰度级在[0 255]以及蓝色图像在灰度级[100 200]的分布情况。
第四个成员是thresh2:
一个二维数组指针,用于非均匀直方图的情形。如果是均匀直方图,会自动根据bin的个数均分上下界,每个bin的大小一样。若是非均匀直方图,就要用到thresh2这个参数指定每个区间的上下界,要是多维的直方图,那么就要为每一维的所有bin都设定上下界。
最后一个成员mat:
用来存储数据。
CvHistogram* cvCreateHist( int dims, int* sizes, int type, float** ranges CV_DEFAULT(NULL), int uniform CV_DEFAULT(1) );创建直方图:
dims:表示直方图的维度
sizes:每一维上直方柱(bin)的数据--创建多大的矩阵,如一维则size[0] =256 二维则size[0]=256,size[1] = 256;
type:创建一个什么样的矩阵,直方图存储数据的方式:
CV_HIST_ARRAY意味着直方图数据表示为多维密集数组CvMatND;
CV_HIST_TREE 意味着直方图数据表示为多维稀疏数组CvSparseMat.---- 大于0才开设相应的空间存储它<高维的必选它>
Ranges:直方图在每一维度上的范围。
如果是一维则代码为:
Floatrange[] = {0,255};
Float*ranges[]={range};
如果是二维则代码为:
Float b_range[] = {0,255};
Float g_range[] ={0,255};
Float*ranges[] = {b_range, g_range};
uniform
该值为0时,表示bin的范围是程序员自由设定的。当该值为非零时,表示bin的划分,是均等划分。
cvQueryHistValue_1D 获取对应灰度值上的像素个数,也就是获取对应index上的值,就是cvGetReal1D函数
#define cvQueryHistValue_1D( hist, idx0 ) ((float)cvGetReal1D( (hist)->bins, (idx0)))
他也可以替换为
#define cvGetHistValue_1D( hist, idx0 ) ((float*)cvPtr1D( (hist)->bins, (idx0), 0))
只不过该函数返回的是指针
形象点的讲解:http://blog.csdn.net/dxmgood/article/details/7237437
void cvCalcHist( IplImage** image, CvHistogram* hist, int accumulate CV_DEFAULT(0), const CvArr* mask CV_DEFAULT(NULL) )
计算直方图:
image:需要计算的图像
hist:存放计算结果的直方图,需要提前通过cvCreateHist创建
accumlate:若为0 ,则在计算此图像的直方图前,将hist先清零,若非0,则在原来的基础上累加
mask:掩码,mask的必须为8位无符号整型 ,单通道图像IplImage 或者CvMat结构 ,将mask看成二值图,非零的地方即为使用(统计)的地方 ,
为0时对应的地方不参与运算操作
直接计算二维的:http://blog.csdn.net/xiaowei_cqu/article/details/7600666
最后怎么确定需要画出来的高度可以参考我用c++写的博客:http://blog.csdn.net/qq_24282081/article/details/73135799
最后总结一下过程:
目的:计算0——255这256个灰度值上的像素个数,最后以直方图的形式显示在256*256的图片上: