1 #include <highgui.h>
2 #include <cv.h>
3 #include "opencv_libs.h"
4
5 /*
6 *《学习OpenCV》第四章第三题b
7 * 完成时间:1:36 3/31 星期日 2013
8 */
9
10 /* 矩形框 */
11 CvRect rect;
12
13 bool draw = false; // 标记是否在画
14
15 IplImage* img;
16 IplImage * temp;
17 IplImage * original;
18
19 bool draw_hist = false;
20
21 IplImage* getHistImage(IplImage* image, CvHistogram* image_hist,
22 CvSize image_size, CvScalar value)
23 {
24 // 计算直方图
25 cvCalcHist( &image, image_hist, 0, NULL );
26 // 新建一幅3通道的图像
27 IplImage* dst = cvCreateImage(image_size, IPL_DEPTH_8U, 3 );
28
29 cvSet( dst, cvScalarAll(255) );
30
31 float max_value = 0;
32 cvGetMinMaxHistValue( image_hist, NULL, &max_value, NULL, NULL );
33 double bin_width = (double)dst->width/256;
34 double bin_unith = (double)dst->height/max_value; // 高度比例
35
36 for(int i = 0; i < 256; i++)
37 {
38 // 获得矩形左上角和右下角坐标
39 CvPoint p0 = cvPoint( i + bin_width, dst->height );
40 CvPoint p1 = cvPoint( (i+1) * bin_width,
41 dst->height - cvGetReal1D(image_hist->bins, i) * bin_unith );
42 // 画实心矩形
43 cvRectangle( dst, p0, p1, value, -1, 8, 0 );
44 }
45
46 return dst;
47 }
48
49 void draw_rect(IplImage* img, CvRect rect)
50 {
51 cvRectangle( img,
52 cvPoint( rect.x, rect.y ),
53 cvPoint( rect.x + rect.width, rect.y + rect.height),
54 cvScalar( 0x00, 0x00, 0xff) );
55 printf("draw\n");
56
57 // 在这里处理直方图
58 // 设置感兴趣区域
59 cvSetImageROI( img, rect);
60 IplImage* src_rect = cvCreateImage (
61 cvSize( rect.width, rect.height ),
62 img->depth, img->nChannels );
63 cvCopy(img, src_rect );
64 cvResetImageROI( img );
65
66 IplImage* r_img = cvCreateImage( cvGetSize( src_rect),
67 src_rect->depth, 1 );
68 IplImage* g_img = cvCreateImage( cvGetSize( src_rect),
69 src_rect->depth, 1 );
70 IplImage* b_img = cvCreateImage( cvGetSize( src_rect),
71 src_rect->depth, 1 );
72 IplImage* gray_img = cvCreateImage( cvGetSize( src_rect),
73 src_rect->depth, 1 );
74
75 // 分离RGB分量
76 cvSplit( src_rect, r_img, g_img, b_img, NULL);
77 cvShowImage( "red", r_img);
78 cvShowImage( "green", g_img);
79 cvShowImage( "blue", b_img);
80
81 // 灰度转换
82 cvCvtColor( src_rect, gray_img, CV_BGR2GRAY);
83 int size = 256;
84 float range[] = {0, 255};
85 float* ranges[] = {range};
86 // 创建直方图
87 CvHistogram * r_hist = cvCreateHist( 1, &size, CV_HIST_ARRAY, ranges, 1);
88 CvHistogram * g_hist = cvCreateHist( 1, &size, CV_HIST_ARRAY, ranges, 1);
89 CvHistogram * b_hist = cvCreateHist( 1, &size, CV_HIST_ARRAY, ranges, 1);
90 CvHistogram * gray_hist = cvCreateHist( 1, &size, CV_HIST_ARRAY, ranges, 1);
91
92 // 直方图尺寸
93 CvSize image_size = cvSize( 400, 300);
94
95 IplImage* r_dst = getHistImage(r_img, r_hist, image_size, cvScalar(0x00, 0x00, 0xff));
96 IplImage* g_dst = getHistImage(g_img, g_hist, image_size, cvScalar(0x00, 0xff, 0x00));
97 IplImage* b_dst = getHistImage(b_img, b_hist, image_size, cvScalar(0xff, 0x00, 0x00));
98 IplImage* gray_dst = getHistImage( gray_img, gray_hist, image_size, cvScalar(0) );
99
100 // 把四个直方图在一幅图片上显示出来
101 IplImage* dst = cvCreateImage( cvSize( image_size.width * 2, image_size.height * 2), 8, 3 );
102 cvSetZero( dst );
103 // 拷贝红色分量直方图
104 CvRect r_rect = cvRect( 0, 0, image_size.width, image_size.height);
105 cvSetImageROI(dst, r_rect);
106 cvCopy( r_dst, dst);
107 // 拷贝绿色分量直方图
108 CvRect g_rect = cvRect(image_size.width, 0, image_size.width, image_size.height );
109 cvSetImageROI( dst, g_rect);
110 cvCopy( g_dst, dst);
111 // 蓝色分量
112 CvRect b_rect = cvRect(0, image_size.height, image_size.width, image_size.height );
113 cvSetImageROI(dst, b_rect);
114 cvCopy( b_dst, dst );
115 // 灰度分量
116 CvRect gray_rect = cvRect( image_size.width, image_size.height,
117 image_size.width, image_size.height );
118 cvSetImageROI( dst, gray_rect);
119 cvCopy( gray_dst, dst);
120
121 cvResetImageROI( dst );
122
123 cvShowImage( "src", src_rect);
124 cvShowImage( "dst", dst );
125
126 cvWaitKey(0);
127
128 cvDestroyAllWindows();
129 cvReleaseImage( &r_img );
130 cvReleaseImage(&g_img);
131 cvReleaseImage(&b_img);
132 cvReleaseImage(&gray_img);
133 cvReleaseImage(&r_dst);
134 cvReleaseImage(&g_dst);
135 cvReleaseImage(&b_dst);
136 cvReleaseImage(&gray_dst);
137 cvReleaseImage(&src_rect);
138 cvReleaseImage(&dst);
139 }
140
141 // 鼠标回调函数
142 void my_mouse_callback( int event, int x, int y, int flags, void* param)
143 {
144 IplImage* image = (IplImage*) param;
145
146 switch( event )
147 {
148 case CV_EVENT_MOUSEMOVE:
149 {
150 if(draw)
151 {
152 rect.width = x - rect.x;
153 rect.height = y - rect.y;
154 }
155
156 draw_hist = false;
157 }
158 break;
159 case CV_EVENT_LBUTTONDOWN:
160 {
161 draw = true;
162 rect = cvRect( x, y, 0, 0 );
163 draw_hist = false;
164 }
165 break;
166 case CV_EVENT_LBUTTONUP:
167 {
168 draw = false;
169 draw_hist = true;
170 if(rect.width < 0)
171 {
172 rect.x += rect.width;
173 rect.width *= -1;
174 }
175 if(rect.height < 0)
176 {
177 rect.y += rect.height;
178 rect.height *= -1;
179 }
180 // draw
181 draw_rect(image, rect);
182 }
183 break;
184 // 在右键按下时清除
185 case CV_EVENT_RBUTTONDOWN:
186 cvCopyImage(original, img);
187 printf("clear.\n");
188 break;
189 }
190 }
191
192 int main()
193 {
194 img = cvLoadImage( "lena.bmp", 1 );
195
196 rect = cvRect( -1, -1, 0, 0);
197
198 // 副本
199 temp = cvCloneImage( img );
200 original = cvCloneImage(img);
201
202 cvNamedWindow("draw rect");
203 cvSetMouseCallback("draw rect", my_mouse_callback, (void*)img);
204
205 while(1)
206 {
207 cvCopyImage(img, temp);
208
209 if(draw_hist)
210 {
211 draw_rect( temp , rect );
212 }
213
214 cvShowImage( "draw rect", temp);
215
216 if(cvWaitKey(15) == 27)
217 break;
218 }
219 cvReleaseImage(&img);
220 cvReleaseImage(&temp);
221 cvDestroyAllWindows();
222
223 return 0;
224 }
运行结果:
不足:在源图像上用鼠标选择矩形区域的时候,无法实时地在图像上反映出来。