【练习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 }

 

结果图片:

 

posted on 2014-07-31 00:42  毋忆典藏  阅读(952)  评论(0编辑  收藏  举报