程序功能,将一张彩色图片转为灰度图后,分析其各灰度值(0-255)的像素个数以直方图的方式显示出来.

这次是用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.


最后用画矩形的方式显示也可以

                                                                         

     划线显示 划矩形显示

 

 

 


 

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐