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 "); 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. "); 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 }
运行结果:
不足:在源图像上用鼠标选择矩形区域的时候,无法实时地在图像上反映出来。