【练习4.3】在图片上画矩形并高亮显示矩形区域、统计矩形区域中像素情况并绘制直方图
《学习OpenCV》中文版第4章第3题
题目要求 |
程序代码 |
结果图片 |
①允许用户在图片上选择一个矩形区域,当鼠标放开,高亮显示矩形区域
②在另一个独立窗口中,使用绘图函数绘制一个图表,分别用蓝、绿和红色表示选中区域中各种颜色的像素在指定数值范围内的数量。
1 #include "stdafx.h" 2 #include <cv.h> 3 #include <highgui.h> 4 using namespace std; 5 using namespace cv; 6 7 //函数声明-->--->-->--->-->--->-->--->// 8 9 void MouseCallBack(int event, int x, int y, int flags, void *param); 10 void HighLight(IplImage * img, CvRect *rect); 11 void DrawHistogram(IplImage * colorImage, CvRect *rect, IplImage * imgHistogram); 12 int RangeCalculate(int value); 13 14 //<--<--<--<--<--<--<--<--<--函数声明// 15 16 CvRect box; 17 bool drawingBox = false; 18 19 void DrawBox(IplImage *img, CvRect rect) 20 { 21 cvRectangle(img, cvPoint(rect.x, rect.y), cvPoint(rect.x + rect.width, rect.y + rect.height), cvScalar(255, 0, 0)); 22 } 23 24 int _tmain(int argc, _TCHAR* argv[]) 25 { 26 box = cvRect(-1, -1, 0, 0); 27 28 const char * fileName = "D:\\Work\\Work_Programming\\Source\\Image\\introduction.jpg"; 29 IplImage * img = cvLoadImage(fileName, CV_LOAD_IMAGE_UNCHANGED); 30 IplImage *drawHistogram = cvCreateImage(cvSize(240, img->width*img->height), IPL_DEPTH_8U, 3); 31 32 cvNamedWindow("ExerciseWindow", CV_WINDOW_AUTOSIZE); 33 cvNamedWindow("区域直方图", 0); 34 35 assert(img && drawHistogram); 36 37 cvSetZero(drawHistogram); 38 drawHistogram->origin = IPL_ORIGIN_BL; //将图片原点设置为左下角 39 40 IplImage * temp=cvCloneImage(img); 41 IplImage * tempHist = cvCloneImage(drawHistogram); 42 cvSetMouseCallback("ExerciseWindow", MouseCallBack, temp); 43 44 while (true) 45 { 46 if (drawingBox) 47 { 48 cvCopyImage(img, temp); 49 DrawBox(temp, box); 50 51 cvCopyImage(drawHistogram, tempHist); 52 DrawHistogram(img, &box, tempHist); 53 } 54 55 cvShowImage("ExerciseWindow", temp); 56 cvShowImage("区域直方图", tempHist); 57 58 if (waitKey(15) == 27) 59 { 60 break; 61 } 62 } 63 64 cvWaitKey(0); 65 66 cvReleaseImage(&img); 67 cvReleaseImage(&drawHistogram); 68 cvReleaseImage(&temp); 69 cvReleaseImage(&tempHist); 70 cvDestroyWindow("区域直方图"); 71 cvDestroyWindow("ExerciseWindow"); 72 73 return 0; 74 } 75 76 //鼠标事件回调函数 77 void MouseCallBack(int event, int x, int y, int flags, void *param) 78 { 79 IplImage * img = (IplImage *)param; 80 81 switch (event) 82 { 83 case CV_EVENT_LBUTTONDOWN: 84 { 85 drawingBox = true; 86 box = cvRect(x, y, 0, 0); 87 } 88 break; 89 case CV_EVENT_MOUSEMOVE: 90 { 91 if (drawingBox) 92 { 93 box.width = x - box.x; 94 box.height = y - box.y; 95 } 96 } 97 break; 98 case CV_EVENT_LBUTTONUP: 99 { 100 drawingBox = false; 101 if (box.width < 0) 102 { 103 box.x += box.width; 104 box.width *= -1; 105 } 106 if (box.height < 0) 107 { 108 box.y += box.height; 109 box.height *= -1; 110 } 111 HighLight(img, &box); 112 } 113 break; 114 default: 115 break; 116 } 117 } 118 119 //高亮显示矩形区域 120 void HighLight(IplImage * img, CvRect *rect) 121 { 122 int startX = rect->x; 123 int startY = rect->y; 124 int boxWidth = rect->width; 125 int boxHeight = rect->height; 126 127 for (int h = startY; h < (startY+boxHeight); ++h) 128 { 129 uchar *ptr = (uchar *)(img->imageData + h*img->widthStep); 130 for (int w = startX; w < (startX+boxWidth); ++w) 131 { 132 ptr[3 * w + 2] = 255; 133 } 134 } 135 } 136 137 //统计矩形区域内像素情况并绘制直方图 138 void DrawHistogram(IplImage * colorImage,CvRect *rect,IplImage * imgHistogram) 139 { 140 int arrCountB[8]; //存储B通道值在0-31、32-63....223-255这八段各段像素的个数 141 int arrCountG[8]; 142 int arrCountR[8]; 143 144 for (int i = 0; i < 8; ++i) 145 { 146 arrCountB[i] = 0; 147 arrCountG[i] = 0; 148 arrCountR[i] = 0; 149 } 150 151 int startX = rect->x; 152 int startY = rect->y; 153 int boxWidth = rect->width; 154 int boxHeight = rect->height; 155 156 for (int h = startY; h < (startY + boxHeight); ++h) 157 { 158 uchar *ptr = (uchar *)(colorImage->imageData + h*colorImage->widthStep); 159 for (int w = startX; w < (startX + boxWidth); ++w) 160 { 161 int rangeB = RangeCalculate(ptr[3 * w + 0]); //判断B通道的当前值在哪个范围内,就将对应的arrCountB数组元素加一 162 arrCountB[rangeB]++; 163 164 int rangeG = RangeCalculate(ptr[3 * w + 1]); 165 arrCountG[rangeG]++; 166 167 int rangeR = RangeCalculate(ptr[3 * w + 2]); 168 arrCountR[rangeR]++; 169 } 170 } 171 172 int histWidth = 10; 173 174 //分别绘制八个区间B、G、R柱 175 for (int i = 0; i < 8; ++i) 176 { 177 cvRectangleR(imgHistogram, cvRect(3 * histWidth*i, 0, histWidth, arrCountB[i]), cvScalar(255, 0, 0), CV_FILLED); 178 cvRectangleR(imgHistogram, cvRect(3 * histWidth*i + histWidth, 0, histWidth, arrCountG[i]), cvScalar(0, 255, 0), CV_FILLED); 179 cvRectangleR(imgHistogram, cvRect(3 * histWidth*i + 2*histWidth, 0, histWidth, arrCountR[i]), cvScalar(0, 0, 255), CV_FILLED); 180 } 181 } 182 183 //判断值所在的区域段 184 int RangeCalculate(int value) 185 { 186 if (value >= 0 && value <= 31) 187 { 188 return 0; 189 } 190 191 if (value >= 32 && value <= 63) 192 { 193 return 1; 194 } 195 196 if (value >= 64 && value <= 95) 197 { 198 return 2; 199 } 200 201 if (value >= 96 && value <= 127) 202 { 203 return 3; 204 } 205 206 if (value >= 128 && value <= 159) 207 { 208 return 4; 209 } 210 211 if (value >= 160 && value <= 191) 212 { 213 return 5; 214 } 215 216 if (value >= 192 && value <= 223) 217 { 218 return 6; 219 } 220 221 if (value >= 224 && value <= 255) 222 { 223 return 7; 224 } 225 }
‖==========钟于原创 乐于分享 宁静致远 毋忆典藏==========‖