程序功能,将一张彩色图片转为灰度图后,分析其各灰度值(0-255)的像素个数以直方图的方式显示出来.
几个关键函数介绍:
计算直方图,统计各灰度的像素个数,其输出为多维矩阵
const Mat* images:
为输入图像的指针。
int nimages:
要计算直方图的图像的个数。此函数可以为多图像求直方图,我们通常情况下都只作用于单一图像,所以通常nimages=1。
const int* channels:
图像的通道,它是一个数组,如果是灰度图像则channels[1]={0};如果是彩色图像则channels[3]={0,1,2};如果是只是求彩色图像第2个通道的直方图,则channels[1]={1};
IuputArray mask:
是一个遮罩图像用于确定哪些点参与计算,实际应用中是个很好的参数,默认情况我们都设置为一个空图像,即:Mat()。
OutArray hist:
计算得到的直方图
int dims:
得到的直方图的维数,灰度图像为1维,彩色图像为3维。
const int* histSize:
直方图横坐标的区间数。如果是10,则它会横坐标分为10份,然后统计每个区间的像素点总和。
const float** ranges:
这是一个二维数组,用来指出每个区间的范围。后面两个参数都有默认值,uniform参数表明直方图是否等距,最后一个参数与多图像下直方图的显示与存储有关。
src – Source single-channel array.
单通道数组
minVal – Pointer to the returned minimum value. NULL is used if not required.
指向最小值的指针
maxVal – Pointer to the returned maximum value. NULL is used if not required.
指向最大值的指针
minLoc – Pointer to the returned minimum location (in 2D case). NULL is used if not required.
最小值的二维坐标
maxLoc – Pointer to the returned maximum location (in 2D case). NULL is used if not required.
最大值得二维坐标
mask – Optional mask used to select a sub-array.
掩码
第二个参数pt1:直线起点
第二个参数pt2:直线终点
第三个参数color:直线的颜色 e.g:Scalor(0,0,255)
第四个参数thickness=1:线条粗细
第五个参数line_type=8,
8 (or 0) - 8-connected line(8邻接)连接 线。
4 - 4-connected line(4邻接)连接线。
CV_AA - antialiased 线条。
第六个参数:坐标点的小数点位数。
该运算符把expression_r_r转换为type-id类型,但没有运行时类型检查来保证转换的安全性。它主要有如下几种用法:
用于类层次结构中基类和子类之间指针或引用的转换。进行上行转换(把子类的指针或引用转换成基类表示)是安全的;进行下行转换(把基类指针或引用转换成子类表示)时,由于没有动态类型检查,所以是不安全的。
用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。
把空指针转换成目标类型的空指针。
把任何类型的表达式转换成void类型。
注意:static_cast不能转换掉expression_r_r的const、volitale、或者__unaligned属性。
注意:static_cast不能转换掉expression_r_r的const、volitale、或者__unaligned属性。
更详细的:http://blog.sina.com.cn/s/blog_4a84e45b0100f57m.html
由此可见,最大值210867,最小值0
总像素个数1000000,因为原图是1000*1000 的
这次是用c++写的,很多函数都很陌生,花了我很长时间。
#include"stdafx.h" #include<iostream> #include<highgui.hpp> #include<cv.hpp> #include<imgproc.hpp> using namespace std; using namespace cv; Mat getHistImage(const MatND& hist) { double maxValue = 0; double minValue = 0; int a = 0; for (int i = 0; i < hist.rows; i++) { for (int j = 0; j < hist.cols; j++) { float b = hist.at<float>(i, j); a += 1; cout << b << endl; } } minMaxLoc(hist, &minValue, &maxValue, 0, 0);//找到全局最小、最大的像素值数目 cout << "max: " << maxValue << "min: " << minValue << endl; int histSize = hist.rows; Mat histImage(histSize, histSize, CV_8UC3, Scalar(255,255,255)); int hpt = static_cast<int>(0.9*histSize); int total = 0; Scalar color(172, 172, 150);//BGR for (int h = 0; h < histSize; h++) { float binVal = hist.at<float>(h);//读取对应灰度级的像素个数,一共1000000个 cout << h<<": "<<binVal << endl; total += binVal; int intensity = static_cast<int>(binVal*hpt /maxValue);//按比例运算,当前数目*230/最大数目,与除以总数只是比例不同 line(histImage, Point(h, histSize), Point(h, histSize - intensity),color); //rectangle(histImage, Point(h, histSize), Point(h + 1, histSize - intensity), color); } cout << total << endl;//total = 1000000 return histImage; } int main(int argc, _TCHAR* argv[]) { Mat src = imread("D:/2.jpg",-1); //IplImage* image = cvLoadImage("D:/timg.jpg"); int a = src.channels();//a = 3通道 imshow("b", src); if (!src.data) { cout << "no picture!\n"; exit(1); } cvtColor(src, src, CV_BGR2GRAY, 0); a = src.channels();//a = 1通道 imshow("d", src); int image_count = 1;//要计算直方图的图像的个数 int channels[1] = { 0};//图像的通道' Mat out;//计算所得直方图 int dims = 1;//得到直方图的维数 int histsize[1] = { 256 };//直方图横坐标的子区间数 float hrange[2] = { 0, 255 };//区间的总范围 const float *ranges[1] = { hrange };//指针数组 calcHist(&src, image_count,channels, Mat(), out, dims, histsize, ranges); Mat last = getHistImage(out); imshow("ddd", last); waitKey(); return 0; }
几个关键函数介绍:
void calcHist(const Mat* images, int nimages, const int* channels, InputArray mask, OutputArray hist, int dims, const int* histSize, const float** ranges, booluniform=true, bool accumulate=false )
计算直方图,统计各灰度的像素个数,其输出为多维矩阵
const Mat* images:
为输入图像的指针。
int nimages:
要计算直方图的图像的个数。此函数可以为多图像求直方图,我们通常情况下都只作用于单一图像,所以通常nimages=1。
const int* channels:
图像的通道,它是一个数组,如果是灰度图像则channels[1]={0};如果是彩色图像则channels[3]={0,1,2};如果是只是求彩色图像第2个通道的直方图,则channels[1]={1};
IuputArray mask:
是一个遮罩图像用于确定哪些点参与计算,实际应用中是个很好的参数,默认情况我们都设置为一个空图像,即:Mat()。
OutArray hist:
计算得到的直方图
int dims:
得到的直方图的维数,灰度图像为1维,彩色图像为3维。
const int* histSize:
直方图横坐标的区间数。如果是10,则它会横坐标分为10份,然后统计每个区间的像素点总和。
const float** ranges:
这是一个二维数组,用来指出每个区间的范围。后面两个参数都有默认值,uniform参数表明直方图是否等距,最后一个参数与多图像下直方图的显示与存储有关。
void minMaxLoc(InputArray src, double* minVal, double* maxVal=0, Point* minLoc=0, Point* maxLoc=0, InputArray mask=noArray())找出矩阵中最大和最小的值以及他们的坐标
src – Source single-channel array.
单通道数组
minVal – Pointer to the returned minimum value. NULL is used if not required.
指向最小值的指针
maxVal – Pointer to the returned maximum value. NULL is used if not required.
指向最大值的指针
minLoc – Pointer to the returned minimum location (in 2D case). NULL is used if not required.
最小值的二维坐标
maxLoc – Pointer to the returned maximum location (in 2D case). NULL is used if not required.
最大值得二维坐标
mask – Optional mask used to select a sub-array.
掩码
Mat(int rows, int cols, int type, const Scalar& s)Mat的构造函数,行,列,类型,每一元素值
void cvLine( CvArr* img,CvPoint pt1, CvPoint pt2, CvScalar color,int thickness=1, int line_type=8, int shift=0 );第一个参数img:要划的线所在的图像;
第二个参数pt1:直线起点
第二个参数pt2:直线终点
第三个参数color:直线的颜色 e.g:Scalor(0,0,255)
第四个参数thickness=1:线条粗细
第五个参数line_type=8,
8 (or 0) - 8-connected line(8邻接)连接 线。
4 - 4-connected line(4邻接)连接线。
CV_AA - antialiased 线条。
第六个参数:坐标点的小数点位数。
static_cast用法:static_cast < type-id > ( expression_r_r )
该运算符把expression_r_r转换为type-id类型,但没有运行时类型检查来保证转换的安全性。它主要有如下几种用法:
用于类层次结构中基类和子类之间指针或引用的转换。进行上行转换(把子类的指针或引用转换成基类表示)是安全的;进行下行转换(把基类指针或引用转换成子类表示)时,由于没有动态类型检查,所以是不安全的。
用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。
把空指针转换成目标类型的空指针。
把任何类型的表达式转换成void类型。
注意:static_cast不能转换掉expression_r_r的const、volitale、或者__unaligned属性。
注意:static_cast不能转换掉expression_r_r的const、volitale、或者__unaligned属性。
更详细的:http://blog.sina.com.cn/s/blog_4a84e45b0100f57m.html
值得注意的是:
c++中Mat类的rows和cols与c中image的height和width一样
dim表示维度,一般都是2为,channels为维度,c++中是通过Mat::channels()函数来查看。
注意,彩色图dim也是二,channels是三
为了测试计算直方图函数的效果,我把计算后的矩阵里的每一个元素的出来
for (int i = 0; i < hist.rows; i++) { for (int j = 0; j < hist.cols; j++) { float b = hist.at<float>(i, j);//这里at函数里的必须是float类型,如果是int的话,就相当于(int&)float,输出的数没有意义,数值很大 a += 1; cout << b << endl; } } 结果如下: 0: 0 1: 0 2: 0 3: 0 4: 0 5: 0 6: 0 7: 0 8: 0 9: 0 10: 0 11: 0 12: 0 13: 0 14: 0 15: 0 16: 0 17: 0 18: 0 19: 0 20: 0 21: 0 22: 0 23: 0 24: 0 25: 0 26: 0 27: 0 28: 0 29: 0 30: 0 31: 0 32: 0 33: 0 34: 1 35: 1 36: 0 37: 0 38: 2 39: 3 40: 3 41: 8 42: 13 43: 19 44: 18 45: 28 46: 38 47: 52 48: 58 49: 76 50: 81 51: 105 52: 132 53: 175 54: 201 55: 269 56: 257 57: 344 58: 413 59: 528 60: 598 61: 898 62: 1042 63: 1330 64: 1580 65: 2431 66: 135547 67: 2503 68: 1612 69: 1233 70: 1012 71: 688 72: 562 73: 398 74: 287 75: 240 76: 173 77: 141 78: 120 79: 76 80: 77 81: 100 82: 58 83: 59 84: 61 85: 61 86: 72 87: 96 88: 111 89: 121 90: 131 91: 163 92: 217 93: 305 94: 425 95: 574 96: 741 97: 1084 98: 1520 99: 2191 100: 2985 101: 4345 102: 6866 103: 11409 104: 25454 105: 171666 106: 10226 107: 4380 108: 2887 109: 1814 110: 1257 111: 860 112: 649 113: 437 114: 430 115: 348 116: 345 117: 341 118: 309 119: 296 120: 310 121: 273 122: 336 123: 282 124: 277 125: 285 126: 289 127: 252 128: 347 129: 285 130: 283 131: 287 132: 259 133: 280 134: 265 135: 243 136: 288 137: 294 138: 258 139: 292 140: 294 141: 285 142: 279 143: 254 144: 276 145: 274 146: 261 147: 281 148: 318 149: 268 150: 347 151: 291 152: 351 153: 382 154: 450 155: 545 156: 647 157: 825 158: 1146 159: 1506 160: 2344 161: 3881 162: 6737 163: 122569 164: 6361 165: 4283 166: 6113 167: 12657 168: 144433 169: 3991 170: 1631 171: 932 172: 566 173: 406 174: 235 175: 174 176: 191 177: 176 178: 161 179: 136 180: 130 181: 136 182: 164 183: 135 184: 137 185: 123 186: 119 187: 130 188: 160 189: 145 190: 129 191: 142 192: 149 193: 138 194: 134 195: 129 196: 159 197: 164 198: 156 199: 169 200: 195 201: 225 202: 216 203: 208 204: 245 205: 300 206: 307 207: 433 208: 485 209: 663 210: 816 211: 1117 212: 1579 213: 2227 214: 3199 215: 4209 216: 6493 217: 210867 218: 5713 219: 3937 220: 2781 221: 1980 222: 1400 223: 979 224: 702 225: 514 226: 351 227: 217 228: 260 229: 168 230: 129 231: 107 232: 80 233: 75 234: 62 235: 55 236: 37 237: 28 238: 27 239: 13 240: 13 241: 13 242: 8 243: 6 244: 1 245: 1 246: 1 247: 0 248: 1 249: 0 250: 0 251: 0 252: 0 253: 0 254: 0 255: 0 total:1000000
由此可见,最大值210867,最小值0
总像素个数1000000,因为原图是1000*1000 的
若像素值4567980,则化为16进制为45b3ac,每两位化成十进制为:69 176 172 对应RGB
直方图中各个灰度值的高度是 该灰度的像素个数/图中最多像素个数*230 计算而得,它的比例是对于最多数来算的,其实这与对于总数来算是一样的,总数永远都是
1000000。 用于显示直方图的高度为 256,因此要给他一个最高限制0.9 * 256 = 230.
最后用画矩形的方式显示也可以
划线显示 划矩形显示