1、机器视觉课程设计学 院 机电工程学院 专 业 机械设计制造及其自动化 (微电子制造专业方向) 年级班别 XXXXXXXXXXXXXXXX 学 号 XXXXXXXXXXXXX 学生姓名 XXXXXXXXX 指导教师 XXXXXXXXX 2015 年 1 月 18 日21 问题描述1.1 基本目标显示一张图片(包含一个矩形或一个圆) ,测量矩形的长宽或圆的直径。完成得及格分,扩展有加分!1.2 基本要求“机器视觉”考试结果要求独立在计算机上完成,建议使用 Visual C+和 OpenCV实现一个具有视觉捕捉、图像显示、尺寸测量等功能的对话框程序,其中必须完成对圆盘形零件圆心与直径和矩形零件长与宽
2、尺寸测量内容。在教师提供的基本框架程序基础上,修改、补充界面和功能。2 程序及其算法2.1 检测与计算圆半径的程序思路:从图片中间横扫取点得 M_Point0,M_Point1(x 坐标相加除 2 的圆心的x 坐标)中间纵向取点得 M_Point2,M_Point3(y 坐标相加除 2 的圆心的 y 坐标)圆上四个点到圆心的距离(半径)取平均值,输出为半径。要求图片3程序如下:double c_DialogTeclarn:f_MakeCircle(double e_dThreshold)if(NULL=m_pIplImageSource)return 0;/定义变量存图像的宽,高,行像素int
3、 q_iWidth=m_pIplImageSource-width;int q_iHeight=m_pIplImageSource-height;int q_iWidthStep=m_pIplImageSource-widthStep;uchar *q_pchDataImage=(uchar *)m_pIplImageSource-imageData;CvPoint M_Point4=;/存放检索出的四个点 循环检索/01 纵扫for(int Cycle_Y=1;Cycle_Yq_pchDataImageq_iWidth/2+q_iWidthStep*(Cycle_Y-1)M_Point0.x
4、=q_iWidth/2;M_Point0.y=Cycle_Y;显示图片4for(int Cycle_Y=q_iHeight;Cycle_Y1;Cycle_Y-)if(e_dThresholdq_pchDataImageq_iWidth/2+q_iWidthStep*(Cycle_Y-1)M_Point1.x=q_iWidth/2;M_Point1.y=Cycle_Y;for(int Cycle_X=1;Cycle_Xq_pchDataImageCycle_X+q_iWidthStep*(q_iHeight/2-1)M_Point2.x=Cycle_X;M_Point2.y=q_iHeight/
5、2;for(int Cycle_X=q_iWidth;Cycle_X1;Cycle_X-)if(e_dThresholdq_pchDataImageCycle_X+q_iWidthStep*(q_iHeight/2-1)M_Point3.x=Cycle_X;M_Point3.y=q_iHeight/2;for (int i=0;iGetDlgItem(ID_PICTURE_DISPLAY);f_ControlShowImage(m_pIplImageDisplay,e_pCWndPicture,m_pIplImageSource);cvSaveImage(_T(“./Result_Image.
6、jpg“),m_pIplImageSource);return 0;2.2 检测与计算矩形长和宽的程序思路:这个程序主要包括:打开摄像头-保存图片(拍照)-加载刚刚保存的图片-找出点并计算长和高 四个按钮,每一个按钮包含下面的一段代码,拍摄的图片保存为 CurrentImage.jpg,这里事先保存了一张同名的图片,所以可以直接点击Load Image 读取。2.2.1 打开摄像头程序void c_DialogTeclarn:OnBnClickedButtonOpenCamera()CvCapture *q_pCvCapture=cvCreateCameraCapture(0);if(NULL
7、=q_pCvCapture)return;6IplImage *q_pIplImageCapture=cvQueryFrame(q_pCvCapture);if(NULL=q_pIplImageCapture)return;if(NULL!=m_pIplImageSource)cvReleaseImage(m_pIplImageSource=NULL;m_pIplImageSource=cvCloneImage(q_pIplImageCapture);cvReleaseCapture(CWnd *e_pCWndPicture=this-GetDlgItem(ID_PICTURE_DISPLAY
8、);f_ControlShowImage(m_pIplImageDisplay,e_pCWndPicture,m_pIplImageSource);注:绿色的为检测是否成功打开摄像头,蓝色的是读取摄像头拍摄的图片到内存,后面的语句是让图片在 mfc 窗口显示出来。2.2.2 保存拍摄的照片程序void c_DialogTeclarn:OnBnClickedButtonSaveImage()/ TODO: 在此添加控件通知处理程序代码cvSaveImage(_T(“./CurrentImage.jpg“),m_pIplImageSource);2.2.3 读取拍摄到的图片(读取文名字 Curre
9、ntImage.jpg 的图片)void c_DialogTeclarn:OnBnClickedButtonLoadImage()/ TODO: 在此添加控件通知处理程序代码if(NULL!=m_pIplImageSource)cvReleaseImage(m_pIplImageSource=NULL;m_pIplImageSource=cvLoadImage(_T(“./CurrentImage.jpg“),0);CWnd *e_pCWndPicture=this-GetDlgItem(ID_PICTURE_DISPLAY);f_ControlShowImage(m_pIplImageDis
10、play,e_pCWndPicture,m_pIplImageSource);2.2.4 检测边上的点和计算长和高的函数思路是:第一步找到边上的点,设定一个变量 e_dThreshold 值为 127,通过循环7让它与每一个像素的像素值进行比较。如果检测到一个点的像素值比 127 小,则这个点可能就是需要的点(黑色=0,白色=255)如果每个像素都要比较运算太多,所以上边两个点的检测是沿着图片长的的 2/5 分处和 3/5 分处向下检测,下边的点是沿着 1/2 处向上检测。第二步是用找到 6 个点的坐标算出三角形的面积,然后除以底边边长得到高。求三角形的面积用的是行列式 的值等于三角形面积的
11、2 倍程序如下:double c_DialogTeclarn:f_MakeRectangleWidth(double e_dThreshold)/ TODO: 在此添加控件通知处理程序代码/定义一些点和变量int q_iWidth=m_pIplImageSource-width;int q_iHeight=m_pIplImageSource-height;int q_iWidthStep=m_pIplImageSource-widthStep;uchar *q_pchDataImage=(uchar *)m_pIplImageSource-imageData;int q_iXLeftTop=2
12、*q_iWidth/5;int q_iXRightTop=3*q_iWidth/5;int q_iXBottom=q_iWidth/2;int q_iYLeftTop=2*q_iHeight/5;int q_iYLeftBottom=3*q_iHeight/5;int q_iYRightMid=q_iHeight/2;CvPoint q_CvPointLeftTop,q_CvPointRightTop,q_CvPointBottom;CvPoint q_CvPointLeft_Top,q_CvPointRight_Mid,q_CvLeft_Bottom;/求上下两边上的点,3 个循环for(i
13、nt q_iCycleHeight=0;q_iCycleHeightq_pchDataImageq_iCycleHeight*q_iWidthStep+q_iXLeftTop)q_CvPointLeftTop.x=q_iXLeftTop;q_CvPointLeftTop.y=q_iCycleHeight;break;for(int q_iCycleHeight=0;q_iCycleHeightq_pchDataImageq_iCycleHeight*q_iWidthStep+q_iXRightTop)8q_CvPointRightTop.x=q_iXRightTop;q_CvPointRigh
14、tTop.y=q_iCycleHeight;break;for(int q_iCycleHeight=q_iHeight-1;q_iCycleHeight=0;q_iCycleHeight-)if(e_dThresholdq_pchDataImageq_iCycleHeight*q_iWidthStep+q_iXBottom)q_CvPointBottom.x=q_iXBottom;q_CvPointBottom.y=q_iCycleHeight;break;/求左右两边上的点,3 个循环for(int q_iCycleWidth=0;q_iCycleWidthq_pchDataImageq_
15、iCycleWidth+q_iWidthStep*(q_iYLeftTop-1)q_CvPointLeft_Top.x=q_iCycleWidth;q_CvPointLeft_Top.y=q_iYLeftTop;break;for(int q_iCycleWidth=0;q_iCycleWidthq_pchDataImageq_iCycleWidth+q_iWidthStep*(q_iYLeftBottom-1)q_CvLeft_Bottom.x=q_iCycleWidth;q_CvLeft_Bottom.y=q_iYLeftBottom;break;for(int q_iCycleWidth
16、=q_iHeight-1;q_iCycleWidth=0;q_iCycleWidth-)if(e_dThresholdq_pchDataImageq_iCycleWidth+q_iWidthStep*(q_iYRightMid-1)q_CvPointRight_Mid.x=q_iCycleWidth;q_CvPointRight_Mid.y=q_iYRightMid;break;/在检测到的点上画圆,只是为了更好看到找点的情况9cvCircle(m_pIplImageSource,q_CvPointLeftTop,5,cvScalarAll(127),2);cvCircle(m_pIplIma
17、geSource,q_CvPointRightTop,5,cvScalarAll(127),2);cvCircle(m_pIplImageSource,q_CvPointBottom,5,cvScalarAll(127),2);cvCircle(m_pIplImageSource,q_CvPointLeft_Top,5,cvScalarAll(127),2);cvCircle(m_pIplImageSource,q_CvLeft_Bottom,5,cvScalarAll(127),2);cvCircle(m_pIplImageSource,q_CvPointRight_Mid,5,cvScal
18、arAll(127),2);/显示画圆后的图片CWnd *e_pCWndPicture=this-GetDlgItem(ID_PICTURE_DISPLAY);f_ControlShowImage(m_pIplImageDisplay,e_pCWndPicture,m_pIplImageSource);/计算长和高的像素值,三角形 3 点的坐标构成行列式,行列式的值=2*面积,行列式的值/底边=高CvMat Ma;int HIGH,WIDE;float Area;int a=q_CvPointLeftTop.x-q_CvPointRightTop.x;int b=q_CvPointLeftTo
19、p.y-q_CvPointRightTop.y;double c=a*a+b*b;/定义行列式double arr9=q_CvPointLeftTop.x,q_CvPointLeftTop.y,1,q_CvPointRightTop.x,q_CvPointRightTop.y,1,q_CvPointBottom.x,q_CvPointBottom.y,1;cvInitMatHeader(Area=abs(cvDet(HIGH=Area/sqrt(c);int A=q_CvPointLeft_Top.x-q_CvLeft_Bottom.x;int B=q_CvPointLeft_Top.y-q_
20、CvLeft_Bottom.y;double C=A*A+B*B;/定义行列式Double ARR9=q_CvPointLeft_Top.x,q_CvPointLeft_Top.y,1,q_CvLeft_Bottom.x,q_CvLeft_Bottom.y,1,q_CvPointRight_Mid.x,q_CvPointRight_Mid.y,1;cvInitMatHeader(Area=abs(cvDet(WIDE=Area/sqrt(C);/在窗口中显示长和高char ch110,ch210;itoa(HIGH,ch1,10);itoa(WIDE,ch2,10);SetDlgItemTex
21、t(IDC_LONG,ch1);SetDlgItemText(IDC_SHORT,ch2);cvSaveImage(_T(“./Result_Image.jpg“),m_pIplImageSource);10return 0;/调用上面的函数进行检测点和计算长和高的值,点击第四个按钮会调用这段程序,当里面的函数调用时,它会调用上面那段函数void c_DialogTeclarn:OnBnClickedButtonRectangle()/ TODO: 在此添加控件通知处理程序代码f_MakeRectangleWidth();2.2.5 老师写的显示图片的函数void c_DialogTeclar
22、n:f_ControlShowImage(IplImage *CRect q_CRectControl;e_pCWndControl-GetClientRect(if(NULL!=e_pIplImageShow)cvReleaseImage(e_pIplImageShow=NULL;e_pIplImageShow=cvCreateImage(cvSize(q_CRectControl.Width(),q_CRectControl.Height(),IPL_DEPTH_8U,e_pIplImageSource-nChannels);cvResize(e_pIplImageSource,e_pIp
23、lImageShow);HDC q_HDCControl=e_pCWndControl-GetDC()-GetSafeHdc();unsigned int q_piBuffersizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*256;BITMAPINFO *e_pBITMAPINFODisplay=(BITMAPINFO *)q_piBuffer;BITMAPINFOHEADER *e_pBITMAPINFOHEADERDisplay=memset(e_pBITMAPINFOHEADERDisplay,0,sizeof(*e_pBITMAPINFOHEADERD
24、isplay);e_pBITMAPINFOHEADERDisplay-biSize=sizeof(BITMAPINFOHEADER);e_pBITMAPINFOHEADERDisplay-biWidth=e_pIplImageShow-width;e_pBITMAPINFOHEADERDisplay-biHeight=-e_pIplImageShow-height;e_pBITMAPINFOHEADERDisplay-biPlanes=1;e_pBITMAPINFOHEADERDisplay-biBitCount=8*e_pIplImageShow-nChannels;e_pBITMAPINF
25、OHEADERDisplay-biCompression=BI_RGB;RGBQUAD* palette=e_pBITMAPINFODisplay-bmiColors;11if(8=e_pBITMAPINFOHEADERDisplay-biBitCount)for(int q_iCycle=0;q_iCyclewidth,e_pIplImageShow-height,q_CRectControl.left,q_CRectControl.top,e_pIplImageShow-width,e_pIplImageShow-height,e_pIplImageShow-imageData,e_pBITMAPINFODisplay,DIB_RGB_COLORS,SRCCOPY);3 运行结果运行结果图形如下:124 小结呵呵拍摄图片-矩形 检测图片-矩形