当前位置:文档之家› 机器视觉课程设计报告

机器视觉课程设计报告

机器视觉课程设计对圆盘形零件圆心与直径和矩形零件长与宽尺寸测量学生学院机电学院专业班级学号学生姓名指导教师2015年1 月20 日目录1 问题描述 (3)1.1 基本目标 (3)1.2 基本要求 (3)2 程序及其算法 (3)2.1 检测与计算圆半径的程序 (3)2.2 检测与计算矩形长和宽的程序 (7)2.2.1 打开摄像头程序 (7)2.2.2 保存拍摄的照片程序 (8)2.2.3 读取拍摄到的图片(读取文名字CurrentImage.jpg的图片) (8)2.2.4 检测边上的点和计算长和高的函数 (9)2.2.5 老师写的显示图片的函数 (12)3 运行结果 (14)4 小结 (14)1 问题描述1.1 基本目标显示一张图片(包含一个矩形或一个圆),测量矩形的长宽或圆的直径。

完成得及格分,扩展有加分!要求图片1.2 基本要求“机器视觉”考试结果要求独立在计算机上完成,建议使用Visual C++和OpenCV实现一个具有视觉捕捉、图像显示、尺寸测量等功能的对话框程序,其中必须完成对圆盘形零件圆心与直径和矩形零件长与宽尺寸测量内容。

在教师提供的基本框架程序基础上,修改、补充界面和功能。

2 程序及其算法2.1 检测与计算圆半径的程序思路:从图片中间横扫取点得M_Point[0],M_Point[1](x坐标相加除2的圆心的x 坐标)中间纵向取点得M_Point[2],M_Point[3](y坐标相加除2的圆心的y坐标)圆上四个点到圆心的距离(半径)取平均值,输出为半径。

显示图片程序如下:double c_DialogTeclarn::f_MakeCircle(double e_dThreshold){if(NULL==m_pIplImageSource){return 0;}//定义变量存图像的宽,高,行像素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;CvPoint M_Point[4]={};//存放检索出的四个点循环检索//01纵扫for(int Cycle_Y=1;Cycle_Y<q_iHeight;Cycle_Y++){if(e_dThreshold>q_pchDataImage[q_iWidth/2+q_iWidthStep*(Cycle_Y-1)]){M_Point[0].x=q_iWidth/2;M_Point[0].y=Cycle_Y;}}for(int Cycle_Y=q_iHeight;Cycle_Y>1;Cycle_Y--){if(e_dThreshold>q_pchDataImage[q_iWidth/2+q_iWidthStep*(Cycle_Y-1)]){M_Point[1].x=q_iWidth/2;M_Point[1].y=Cycle_Y;}}for(int Cycle_X=1;Cycle_X<q_iWidth;Cycle_X++){if(e_dThreshold>q_pchDataImage[Cycle_X+q_iWidthStep*(q_iHeight/2-1)]) {M_Point[2].x=Cycle_X;M_Point[2].y=q_iHeight/2;}}for(int Cycle_X=q_iWidth;Cycle_X>1;Cycle_X--){if(e_dThreshold>q_pchDataImage[Cycle_X+q_iWidthStep*(q_iHeight/2-1)]){M_Point[3].x=Cycle_X;M_Point[3].y=q_iHeight/2;}}for (int i=0;i<4;i++)//画边界圆{cvCircle(m_pIplImageSource,M_Point[i],8,cvScalarAll(127),2);}int Ridius=0,clear=0;int circle_y=abs(M_Point[1].y+M_Point[0].y)/2;int circle_x=abs(M_Point[3].x+M_Point[2].x)/2;float c=0,j=0;for (int i=0;i<4;i++){j=(M_Point[i].x-circle_x)*(M_Point[i].x-circle_x)+(M_Point[i].y-circle_y)*(M_Point[i].y-c ircle_y);c=c+sqrt(j);}Ridius=c/4;//在窗口中显示长和高char ch1[10],ch2[10];itoa(Ridius,ch1,10);itoa(clear,ch2,10);SetDlgItemText(IDC_LONG,ch1);SetDlgItemText(IDC_SHORT,ch2);CWnd *e_pCWndPicture=this->GetDlgItem(ID_PICTURE_DISPLAY);f_ControlShowImage(m_pIplImageDisplay,e_pCWndPicture,m_pIplImageSource);cvSaveImage(_T(".//Result_Image.jpg"),m_pIplImageSource);return 0;}2.2 检测与计算矩形长和宽的程序思路:这个程序主要包括:打开摄像头---保存图片(拍照)---加载刚刚保存的图片---找出点并计算长和高四个按钮,每一个按钮包含下面的一段代码,拍摄的图片保存为CurrentImage.jpg,这里事先保存了一张同名的图片,所以可以直接点击Load Image 读取。

2.2.1 打开摄像头程序void c_DialogTeclarn::OnBnClickedButton OpenCamera(){CvCapture *q_pCvCapture=cvCreateCameraCapture(0);if(NULL==q_pCvCapture){return;}IplImage *q_pIplImageCapture=cvQueryFrame(q_pCvCapture);if(NULL==q_pIplImageCapture){return;}if(NULL!=m_pIplImageSource){cvReleaseImage(&m_pIplImageSource);m_pIplImageSource=NULL;}m_pIplImageSource=cvCloneImage(q_pIplImageCapture);cvReleaseCapture(&q_pCvCapture);CWnd *e_pCWndPicture=this->GetDlgItem(ID_PICTURE_DISPLAY);f_ControlShowImage(m_pIplImageDisplay,e_pCWndPicture,m_pIplImageSource);}注:绿色的为检测是否成功打开摄像头,蓝色的是读取摄像头拍摄的图片到内存,后面的语句是让图片在mfc窗口显示出来。

2.2.2 保存拍摄的照片程序void c_DialogTeclarn::OnBnClickedButton SaveImage(){// TODO: 在此添加控件通知处理程序代码cvSaveImage(_T(".//CurrentImage.jpg"),m_pIplImageSource);}2.2.3 读取拍摄到的图片(读取文名字CurrentImage.jpg的图片)void c_DialogTeclarn::OnBnClickedButton LoadImage(){// TODO: 在此添加控件通知处理程序代码if(NULL!=m_pIplImageSource){cvReleaseImage(&m_pIplImageSource);m_pIplImageSource=NULL;}m_pIplImageSource=cvLoadImage(_T(".//CurrentImage.jpg"),0);CWnd *e_pCWndPicture=this->GetDlgItem(ID_PICTURE_DISPLAY);f_ControlShowImage(m_pIplImageDisplay,e_pCWndPicture,m_pIplImageSource);}2.2.4 检测边上的点和计算长和高的函数思路是:第一步找到边上的点,设定一个变量e_dThreshold值为127,通过循环让它与每一个像素的像素值进行比较。

如果检测到一个点的像素值比127小,则这个点可能就是需要的点(黑色=0,白色=255)如果每个像素都要比较运算太多,所以上边两个点的检测是沿着图片长的的2/5分处和3/5分处向下检测,下边的点是沿着1/2处向上检测。

第二步是用找到6个点的坐标算出三角形的面积,然后除以底边边长得到高。

求三角形的面积用的是行列式的值等于三角形面积的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*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(int q_iCycleHeight=0;q_iCycleHeight<q_iHeight;q_iCycleHeight++){if(e_dThreshold>q_pchDataImage[q_iCycleHeight*q_iWidthStep+q_iXLeftTop]) {q_CvPointLeftTop.x=q_iXLeftTop;q_CvPointLeftTop.y=q_iCycleHeight;break;}}for(int q_iCycleHeight=0;q_iCycleHeight<q_iHeight;q_iCycleHeight++){if(e_dThreshold>q_pchDataImage[q_iCycleHeight*q_iWidthStep+q_iXRightTop]) {q_CvPointRightTop.x=q_iXRightTop;q_CvPointRightTop.y=q_iCycleHeight;break;}}for(int q_iCycleHeight=q_iHeight-1;q_iCycleHeight>=0;q_iCycleHeight--){if(e_dThreshold>q_pchDataImage[q_iCycleHeight*q_iWidthStep+q_iXBottom]){q_CvPointBottom.x=q_iXBottom;q_CvPointBottom.y=q_iCycleHeight;break;}}//求左右两边上的点,3个循环for(int q_iCycleWidth=0;q_iCycleWidth<q_iHeight;q_iCycleWidth++){if(e_dThreshold>q_pchDataImage[q_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_iCycleWidth<q_iHeight;q_iCycleWidth++){if(e_dThreshold>q_pchDataImage[q_iCycleWidth+q_iWidthStep*(q_iYLeftBottom-1)]) {q_CvLeft_Bottom.x=q_iCycleWidth;q_CvLeft_Bottom.y=q_iYLeftBottom;break;}}for(int q_iCycleWidth=q_iHeight-1;q_iCycleWidth>=0;q_iCycleWidth--){if(e_dThreshold>q_pchDataImage[q_iCycleWidth+q_iWidthStep*(q_iYRightMid-1)]){q_CvPointRight_Mid.x=q_iCycleWidth;q_CvPointRight_Mid.y=q_iYRightMid;break;}}//在检测到的点上画圆,只是为了更好看到找点的情况cv Circle(m_pIplImageSource,q_CvPointLeftTop,5,cvScalarAll(127),2);cvCircle(m_pIplImageSource,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,cvScalarAll(127),2);//显示画圆后的图片CWnd *e_pCWndPicture=this->GetDlgItem(ID_PICTURE_DISPLAY);f_Control ShowImage(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_CvPointLeftTop.y-q_CvPointRightTop.y;double c=a*a+b*b;//定义行列式doublearr[9]={q_CvPointLeftTop.x,q_CvPointLeftTop.y,1,q_CvPointRightTop.x,q_CvPointRightTop.y,1,q_CvPo intBottom.x,q_CvPointBottom.y,1};cvInitMatHeader(&Ma,3,3,CV_64FC1,arr);Area=abs(cvDet(&Ma));HIGH=Area/sqrt(c);int A=q_CvPointLeft_Top.x-q_CvLeft_Bottom.x;int B=q_CvPointLeft_Top.y-q_CvLeft_Bottom.y;double C=A*A+B*B;//定义行列式DoubleARR[9]={q_CvPointLeft_Top.x,q_CvPointLeft_Top.y,1,q_CvLeft_Bottom.x,q_CvLeft_Bottom.y,1,q_CvPointRig ht_Mid.x,q_CvPointRight_Mid.y,1};cvInitMatHeader(&Ma,3,3,CV_64FC1,ARR);Area=abs(cvDet(&Ma));WIDE=Area/sqrt(C);//在窗口中显示长和高char ch1[10],ch2[10];itoa(HIGH,ch1,10);itoa(WIDE,ch2,10);SetDlgItemText(IDC_LONG,ch1);SetDlgItemText(IDC_SHORT,ch2);cvSaveImage(_T(".//Result_Image.jpg"),m_pIplImageSource);return 0;}//调用上面的函数进行检测点和计算长和高的值,点击第四个按钮会调用这段程序,当里面的函数调用时,它会调用上面那段函数void c_DialogTeclarn::OnBnClickedButton Rectangle(){// TODO: 在此添加控件通知处理程序代码f_MakeRectangleWidth();}2.2.5 老师写的显示图片的函数void c_DialogTeclarn::f_ControlShowImage(IplImage *&e_pIplImageShow,CWnd *e_pCWndControl, IplImage *e_pIplImageSource){if((NULL==e_pCWndControl)||(NULL==e_pIplImageSource)){return;}CRect q_CRectControl;e_pCWndControl->GetClientRect(&q_CRectControl);if(NULL!=e_pIplImageShow){cvReleaseImage(&e_pIplImageShow);e_pIplImageShow=NULL;}e_pIplImageShow=cvCreateImage(cvSize(q_CRectControl.Width(),q_CRectControl.Height()),IPL_DEPTH_8U,e_pIplImageSource->nChannels);cvResize(e_pIplImageSource,e_pIplImageShow);HDC q_HDCControl=e_pCWndControl->GetDC()->GetSafeHdc();unsigned int q_piBuffer[sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*256];BITMAPINFO *e_pBITMAPINFODisplay=(BITMAPINFO *)q_piBuffer;BITMAPINFOHEADER *e_pBITMAPINFOHEADERDisplay=&(e_pBITMAPINFODisplay->bmiHeader); memset(e_pBITMAPINFOHEADERDisplay,0,sizeof(*e_pBITMAPINFOHEADERDisplay));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_pBITMAPINFOHEADERDisplay->biCompression=BI_RGB;RGBQUAD* palette=e_pBITMAPINFODisplay->bmiColors;if(8==e_pBITMAPINFOHEADERDisplay->biBitCount){for(int q_iCycle=0;q_iCycle<256;q_iCycle++){palette[q_iCycle].rgbBlue=(BYTE)q_iCycle;palette[q_iCycle].rgbGreen=(BYTE)q_iCycle;palette[q_iCycle].rgbRed=(BYTE)q_iCycle;palette[q_iCycle].rgbReserved=(BYTE)0;}}StretchDIBits(q_HDCControl,q_CRectControl.left,q_CRectControl.top,e_pIplImageShow->width,e_pIplImageShow->height,q_CRectControl.left,q_CRectControl.top,e_pIplImageShow->width,e_pIplImageShow->height,e_pIplImageShow->imageData,e_pBITMAPINFODisplay,DIB_RGB_COLORS,SRCCOPY);}。

相关主题