困扰我4天的问题:三通道的camshift调试不过
#第一篇日志啊~#
最近要弄一个跟踪视频中车辆的算法。虽说是弄算法,但是opencv里面封装好了camshift,基本上拿出来用就行了。
网络上流传的比较广的camshiftdemo,大多使用hsv通道的h通道来进行跟踪。但是路上的车辆黑白颜色居多,路面大致也是深色的,只用h通道跟踪的效果不理想。因此希望通过统计hsv三个通道的值来进行跟踪,这样的话无论遇上黑色车白色车还是彩色车性能都应该能够得到改善。
想象是这个样子的。可是代码打出来之后,calchist过的histogram所有值都是0。多方调试四天未果,无奈只好把程序放上这个满地牛人之地,祈求牛人们多多指教。
因为才刚入门opencv,程序中那些可能的可疑的地方都被我改动过了,可能会有各种小问题,不过目前希望各位帮忙看看CalDrawhist这个函数里面为何histogram的数据出不来。
1 #include <iostream> 2 #include <string> 3 #include <io.h> 4 #include <opencv2/opencv.hpp> 5 #include<math.h> 6 #include<cv.h> 7 8 using namespace std; 9 using namespace cv; 10 11 12 13 //整体标志 14 int object=0;//0:未进行初始化,1:已进行特征提取,-1:从新选定区域后未进行特征提取 15 16 //第一部分常量 17 //数据类 18 CvCapture *capture; 19 IplImage *frame, //原图像 20 *frame_hsv, //hsv颜色空间预想 21 *frame_h, //h通道图像 22 *frame_s, //s通道图像 23 *frame_v, 24 *planes[]={frame_h,frame_s,frame_v}; 25 26 //直方图类 27 /** H 分量划分为16个等级,S分量划分为4个等级,v通道分为4个登记 */ 28 int h_bins = 8, s_bins = 4, v_bins=4; 29 int hist_size[] = {h_bins, s_bins, v_bins}; 30 31 //hsv范围 32 float h_ranges[] = { 0, 180 }; 33 float s_ranges[] = { 0, 255 }; 34 float v_ranges[] = { 0, 255 }; 35 float* ranges[] = { h_ranges, s_ranges, v_ranges }; 36 float histmax,histmin,scale; 37 38 //直方图 39 CvHistogram *histogram=cvCreateHist(3,hist_size,CV_HIST_ARRAY,ranges,1); 40 41 42 43 //第二部分常量 44 IplImage *backproject,*mask;//mask为掩膜,但是调试不成功程序中没使用 45 CvBox2D box; 46 Rect track_window; 47 CvConnectedComp track_comp; 48 49 //鼠标部分常量 50 Rect select; 51 bool select_flag=false; 52 Point origin; 53 54 void onMouse(int event,int x,int y,int,void*) 55 { 56 //Point origin;//不能在这个地方进行定义,因为这是基于消息响应的函数,执行完后origin就释放了,所以达不到效果。 57 if(!frame)return ; 58 if( frame->origin ) 59 y = frame->height - y; 60 //如果图像原点坐标在左下,则将其改为左上 61 if(select_flag) 62 { 63 select.x=MIN(origin.x,x);//不一定要等鼠标弹起才计算矩形框,而应该在鼠标按下开始到弹起这段时间实时计算所选矩形框 64 select.y=MIN(origin.y,y);//这两行保证了鼠标可以任意方向选择,因为select永远是最小的一个 65 select.width=abs(x-origin.x);//算矩形宽度和高度 66 select.height=abs(y-origin.y); 67 select&=Rect(0,0,frame->width,frame->height);//保证所选矩形框在视频显示区域之内 68 } 69 if(event==CV_EVENT_LBUTTONDOWN) 70 { 71 select_flag=1;//鼠标按下的标志赋真值 72 origin=Point(x,y);//保存下来单击是捕捉到的点 73 select&=Rect(x,y,0,0);//这里一定要初始化,宽和高为(0,0)是因为在opencv中Rect矩形框类内的点是包含左上角那个点的,但是不含右下角那个点 74 } 75 else if(event==CV_EVENT_LBUTTONUP) 76 { 77 select_flag=0; 78 object=1; 79 } 80 } 81 82 void CalDrawHist(void) 83 { 84 85 frame=cvQueryFrame(capture); 86 87 88 /** 输入图像转换到HSV颜色空间 */ 89 cvCvtColor( frame, frame_hsv, CV_BGR2HSV ); 90 cvCvtPixToPlane( frame_hsv, frame_h, frame_s, frame_v, 0 ); 91 92 /** 根据H,S,V三个平面数据统计直方图 */ 93 94 cvCalcHist( planes, histogram, 0, 0 ); 95 cvNormalizeHist(histogram,1); 96 97 /** 获取直方图统计的最大值,用于动态显示直方图 */ 98 99 cvGetMinMaxHistValue( histogram, &histmin, &histmax, 0, 0 ); 100 101 cout<<histmax; 102 103 /** 设置直方图显示图像 */ 104 int height = 180; 105 int width = (h_bins*s_bins*v_bins*6); 106 IplImage* frame_hist = cvCreateImage( cvSize(width,height), 8, 3 ); 107 cvZero( frame_hist ); 108 109 /** 用来进行HSV到RGB颜色转换的临时单位图像 */ 110 IplImage * hsv_color = cvCreateImage(cvSize(1,1),8,3); 111 IplImage * rgb_color = cvCreateImage(cvSize(1,1),8,3); 112 int bin_w = width / (h_bins * s_bins*v_bins); 113 for(int h = 0; h < h_bins; h++) 114 { 115 for(int s = 0; s < s_bins; s++) 116 { 117 118 for(int v = 0; v < v_bins; v++) 119 { 120 int i = h*s_bins*v_bins + s*v_bins + v; 121 /** 获得直方图中的统计次数,计算显示在图像中的高度 */ 122 float bin_val = cvQueryHistValue_3D( histogram, h, s, v ); 123 int intensity = cvRound(bin_val*height/histmax); 124 125 /** 获得当前直方图代表的颜色,转换成RGB用于绘制 */ 126 cvSet2D(hsv_color,0,0,cvScalar(h*180.f / h_bins,s*255.f/s_bins,v*255.f/v_bins,0));//获得一幅临时HSV图像 127 cvCvtColor(hsv_color,rgb_color,CV_HSV2BGR);//转换为RGB 128 CvScalar color = cvGet2D(rgb_color,0,0);//再从RGB中提取出色彩通道用于绘制 129 130 cvRectangle( frame_hist, cvPoint(i*bin_w,height), 131 cvPoint((i+1)*bin_w,height - intensity), 132 color, -1, 8, 0 ); 133 } 134 } 135 } 136 137 cvNamedWindow( "Source", 1 ); 138 cvShowImage( "Source", frame ); 139 140 141 142 } 143 144 void main(int argc, char** argv) 145 { 146 147 //载入文件 148 char name[40]; 149 cout<<"输入文件"; 150 cin>>name; 151 152 //建立窗口 153 cvNamedWindow("camera",CV_WINDOW_AUTOSIZE);//显示视频原图像的窗口 154 //载入第一帧 155 capture=cvCreateFileCapture(name); 156 frame=cvQueryFrame(capture); 157 //捕捉鼠标 158 setMouseCallback("camera",onMouse,0); 159 160 //进入视频循环 161 for(;;) 162 { 163 frame=cvQueryFrame(capture); 164 if(!frame)break; 165 166 if(object==0)//初运行程序,进行初始化 167 { 168 frame_hsv=cvCreateImage(cvGetSize(frame),8,3); 169 frame_h =cvCreateImage(cvGetSize(frame),8,1); 170 frame_s =cvCreateImage(cvGetSize(frame),8,1); 171 frame_v =cvCreateImage(cvGetSize(frame),8,1); 172 backproject=cvCreateImage(cvGetSize(frame),8,1); 173 mask=cvCreateImage(cvGetSize(frame),8,1); 174 175 //初始化完毕,标志置1 176 object=-2; 177 } 178 179 180 181 //如果没有进行特征提取,进行特征提取 182 if(object==1) 183 { 184 185 histogram = cvCreateHist( 3,hist_size, CV_HIST_ARRAY, ranges, 1 ); 186 187 188 CalDrawHist(); 189 190 191 //特征提取完毕,置标志位1 192 object=-1; 193 } 194 195 //如果已经特征处理,则进行camshift 196 if(object==-1) 197 { 198 //计算直方图反向投影 199 cvCalcBackProject(planes,backproject,histogram); 200 cvAnd(backproject,mask,backproject,0); 201 202 //camshift 203 cvCamShift(backproject, track_window,cvTermCriteria( CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 10, 1 ),&track_comp, &box ); 204 205 //设置下一帧track_window 206 track_comp.rect.height=abs(track_comp.rect.height); 207 track_comp.rect.width=abs(track_comp.rect.width); 208 track_window=track_comp.rect; 209 210 cvEllipseBox(frame,box, CV_RGB(255,0,0), 3, CV_AA, 0 ); 211 212 } 213 214 215 cvShowImage("camera1",backproject); 216 cvShowImage("camera",frame); 217 218 //如果鼠标按下,则绘出鼠标画出的矩 219 if(select_flag) 220 { 221 frame=cvQueryFrame(capture); 222 if(!frame)break; 223 cvRectangleR(frame,select,Scalar(225,0,0),2,8,0); 224 cvShowImage("camera",frame); 225 } 226 227 //退出功能 228 if(cvWaitKey(50)==27)break; 229 if(!frame)break; 230 } 231 232 //程序结束,各种release 233 cvDestroyAllWindows(); 234 235 cvReleaseCapture(&capture); 236 cvReleaseImage(&frame_hsv); 237 cvReleaseImage(&frame_h); 238 cvReleaseImage(&frame_s); 239 240 241 242 }