通过CCD视觉检测图像角度与几何坐标
通过CCD视觉检测图像角度与几何坐标
通过CCD视觉检测图像角度与几何坐标
通过CCD视觉检测图像角度与几何坐标
现在国家大力提倡工业4.0,机器人与视觉在工业上的应用正在加大,加速普及。
掌握了PLC,触摸屏编程的 会员们千万别知足止步不前;
这里介绍与分享一视觉的应用:通过CCD视觉检测图像角度与几何坐标
步骤:
1.先在一张图片上确定一个要检测的区域作为大模板;
2.再在大模板上确定一个小模板区域,作为参考区域;
3.开始对物体拍照得到图片。在图片先检测出全部大模板,再在全部大模板中检测小模板。
通过计算得出这些小模板与原始参考小模板的相对角度,以及大模板的中点。
进而得到物体的坐标及旋转角度, 机器人就可通过这参数进行位置纠正,正确抓取物体;
下面是程序核心代码
- BOOL CAngleDetect::Init(CString sPicName,HWND hWnd,BOOL bManuelConfirm)
- {
- if(!IsWindow(hWnd))
- return false;
- Clear();
- //<>
- HObject ho_Image, ho_Region, ho_RegionBorder;
- HObject ho_RegionDilation, ho_ImageReduced, ho_Edges, ho_ModelRegion;
- HObject ho_ModelImage, ho_ModelCenter, ho_ModelContour;
- HObject ho_ModelContourAffined, ho_AsymEdgesRegion, ho_AsymEdgesRegionPolar;
- HObject ho_PolarTransModelImage, ho_RegionTrans, ho_PolarModelImage;
- HObject ho_RefinedContours, ho_PolarTransImage;
- HObject ho_SearchImageReduced, ho_ContoursAffinTrans, ho_XYTransContour;
-
- HTuple hv_MinScoreMain,hv_Tolerance,hv_Interactive=bManuelConfirm,hv_Name = sPicName;
- HTuple hv_MinScorePolar, hv_ContrastMain, hv_ContrastPolar;
- HTuple hv_Greediness, hv_ContrastMin, hv_RowFitted, hv_ColumnFitted;
- HTuple hv_RadiusFitted, hv_SPhi, hv_EPhi, hv_POder;
- HTuple hv_AreaModelRegion, hv_RowModelRegion, hv_ColumnModelRegion;
- HTuple hv_RR, hv_CC, hv_AA, hv_SS, hv_Hom2DIdentity, hv_Hom2DTranslate;
- HTuple hv_Clip, hv_ImageWidth, hv_ImageHeight;
- HTuple hv_Aspect, hv_AsymModelReady;
- HTuple hv_AreaAsym, hv_RowAsym, hv_ColumnAsymn, hv_AngleRef;
- HTuple hv_PolarWidth, hv_PolarHeight, hv_Row1, hv_Column1;
- HTuple hv_Row2, hv_Column2, hv_RegionWidth, hv_AngleOverlap;
- HTuple hv_AngleRefPolar, hv_ScoreRefPolar;
- HTuple hv_ImageNum, hv_Index, hv_sIndex, hv_Row, hv_Column;
- HTuple hv_Angle, hv_Score, hv_NumMatches, hv_FinalAngle;
- HTuple hv_RowsPolar, hv_ColumnsPolar, hv_AnglesPolar, hv_RefinementFailed;
- HTuple hv_J, hv_RowPolar, hv_ColumnPolar, hv_AnglePolar;
- HTuple hv_ScorePolar, hv_HomMat2D, hv_Title;
-
- hv_MinScoreMain = 0.7;//主模板外形匹配的最小值
- hv_ContrastMain = 30; //主模板外形匹配的对比度
- hv_Greediness = 0.5;//主模板外形匹配的
- hv_ContrastPolar = 20; //小模板外形匹配的对比度
- hv_MinScorePolar = 0.4;//小模板查找最小得分
- hv_Tolerance = 2.5;
- hv_ContrastMin = 10;
- //<>
- ReadImage(&ho_Image, hv_Name);
- Threshold(ho_Image, &ho_Region, 120, 255);
- Boundary(ho_Region, &ho_RegionBorder, "inner");
- DilationCircle(ho_RegionBorder, &ho_RegionDilation, 3.5);
- ReduceDomain(ho_Image, ho_RegionDilation, &ho_ImageReduced);
- EdgesSubPix(ho_ImageReduced, &ho_Edges, "canny", 1, 20, 40);
- FitCircleContourXld(ho_Edges, "geohuber", -1, 0, 0, 3, 2, &hv_RowFitted, &hv_ColumnFitted,
- &hv_RadiusFitted, &hv_SPhi, &hv_EPhi, &hv_POder);
- GenCircle(&ho_ModelRegion, hv_RowFitted, hv_ColumnFitted, hv_RadiusFitted+10);
- ReduceDomain(ho_Image, ho_ModelRegion, &ho_ModelImage);
- CreateShapeModel(ho_ModelImage, "auto", 0, HTuple(360).TupleRad(), "auto", "auto",
- "use_polarity", hv_ContrastMain, hv_ContrastMin, &m_hv_ModelID);
- //校正主模板中点
- AreaCenter(ho_ModelRegion, &hv_AreaModelRegion, &hv_RowModelRegion, &hv_ColumnModelRegion);
- SetShapeModelOrigin(m_hv_ModelID, hv_RowFitted-hv_RowModelRegion, hv_ColumnFitted-hv_ColumnModelRegion);
- FindShapeModel(ho_Image, m_hv_ModelID, -0.39, 0.78, 0.5, 1, 0.5, "least_squares",
- 0, 0.9, &hv_RR, &hv_CC, &hv_AA, &hv_SS);
- //放大显示主模板
- GenCrossContourXld(&ho_ModelCenter, hv_RowFitted, hv_ColumnFitted, 12, 0.0);
- GetShapeModelContours(&ho_ModelContour, m_hv_ModelID, 1);
- HomMat2dIdentity(&hv_Hom2DIdentity);
- HomMat2dTranslate(hv_Hom2DIdentity, hv_RowFitted, hv_ColumnFitted, &hv_Hom2DTranslate);
- AffineTransContourXld(ho_ModelContour, &ho_ModelContourAffined, hv_Hom2DTranslate);
- hv_Clip = hv_RadiusFitted+60;
- OpenWindowFitImage(ho_Image, 0, 0, -1, 500, &m_hv_WindowHandle,hWnd);
- GetImageSize(ho_Image, &hv_ImageWidth, &hv_ImageHeight);
- hv_Aspect = (hv_ImageWidth.TupleReal())/hv_ImageHeight;
- if (HDevWindowStack::IsOpen())
- SetPart(HDevWindowStack::GetActive(),hv_RowFitted-hv_Clip, hv_ColumnFitted-(hv_Clip*hv_Aspect),
- hv_RowFitted+hv_Clip, hv_ColumnFitted+(hv_Clip*hv_Aspect));
- DisplayModel(ho_Image, ho_ModelRegion, ho_ModelCenter, ho_ModelContourAffined);
- //以交互或自定义形式,选择非对称区域生成一非对称模板
- hv_AsymModelReady = 0;
- while (0 != (hv_AsymModelReady.TupleNot()))
- {
- if (HDevWindowStack::IsOpen())
- SetColor(HDevWindowStack::GetActive(),"blue");
- if (0 != hv_Interactive)
- {
- DrawDetectingRegion(&ho_AsymEdgesRegion, m_hv_WindowHandle);
- ConfirmDrawedRegion(m_hv_WindowHandle, hv_RowFitted, hv_ColumnFitted, hv_Clip, &hv_AsymModelReady);
- }
- else
- {
- GenRectangle1(&ho_AsymEdgesRegion, 315, 694, 343, 711);
- hv_AsymModelReady = 1;
- }
- DisplayModel(ho_Image, ho_ModelRegion, ho_ModelCenter, ho_ModelContourAffined );
- DisplayMarkedEdge(ho_Image, ho_AsymEdgesRegion, hv_ContrastPolar, 315, 694, m_hv_WindowHandle);
- }
- DistancePr(ho_AsymEdgesRegion, hv_RowFitted, hv_ColumnFitted, &m_hv_RadiusInner, &m_hv_RadiusOuter);
- AreaCenter(ho_AsymEdgesRegion, &hv_AreaAsym, &hv_RowAsym, &hv_ColumnAsymn);
- AngleLx(hv_RowFitted, hv_ColumnFitted, hv_RowAsym, hv_ColumnAsymn, &hv_AngleRef);
- hv_PolarWidth = (m_hv_RadiusOuter*(HTuple(360).TupleRad())).TupleRound();
- hv_PolarHeight = (m_hv_RadiusOuter-m_hv_RadiusInner).TupleRound();
- PolarTransRegion(ho_AsymEdgesRegion, &ho_AsymEdgesRegionPolar, hv_RowFitted, hv_ColumnFitted,
- hv_AngleRef+(HTuple(180).TupleRad()), hv_AngleRef+(HTuple(540).TupleRad()),
- m_hv_RadiusInner, m_hv_RadiusOuter, hv_PolarWidth, hv_PolarHeight, "bilinear");
- SmallestRectangle1(ho_AsymEdgesRegionPolar, &hv_Row1, &hv_Column1, &hv_Row2, &hv_Column2);
- hv_RegionWidth = (hv_Column2-hv_Column1)+1;
- hv_AngleOverlap = (hv_RegionWidth*(HTuple(360).TupleRad()))/hv_PolarWidth;
- m_hv_PolarStartAngle = hv_AngleRef-(hv_AngleOverlap/2);
- m_hv_PolarEndAngle = (hv_AngleRef+(HTuple(360).TupleRad()))+(hv_AngleOverlap/2);
- m_hv_PolarAngleRangeExtended = m_hv_PolarEndAngle-m_hv_PolarStartAngle;
- m_hv_PolarWidthExtended = (m_hv_RadiusOuter*m_hv_PolarAngleRangeExtended).TupleRound();
- PolarTransImageExt(ho_Image, &ho_PolarTransModelImage, hv_RowFitted, hv_ColumnFitted,
- m_hv_PolarStartAngle, m_hv_PolarEndAngle, m_hv_RadiusInner, m_hv_RadiusOuter, m_hv_PolarWidthExtended,
- hv_PolarHeight, "bilinear");
- PolarTransRegion(ho_AsymEdgesRegion, &ho_AsymEdgesRegionPolar, hv_RowFitted, hv_ColumnFitted,
- m_hv_PolarStartAngle, m_hv_PolarStartAngle+hv_AngleOverlap, m_hv_RadiusInner, m_hv_RadiusOuter,
- hv_RegionWidth, hv_PolarHeight, "bilinear");
- ShapeTrans(ho_AsymEdgesRegionPolar, &ho_RegionTrans, "convex");
- ReduceDomain(ho_PolarTransModelImage, ho_RegionTrans, &ho_PolarModelImage);
- CreateShapeModel(ho_PolarModelImage, 1, 0, 0, "auto", "auto", "use_polarity", hv_ContrastPolar,
- hv_ContrastMin, &m_hv_ModelIDPolar);
- GetShapeModelContours(&m_ho_PolarModelContours, m_hv_ModelIDPolar, 1);
- FindShapeModel(ho_PolarModelImage, m_hv_ModelIDPolar, 0, 0, hv_MinScorePolar, 1,
- 0.0, "least_squares", 0, hv_Greediness, &m_hv_RowRefPolar, &m_hv_ColumnRefPolar, &hv_AngleRefPolar, &hv_ScoreRefPolar);
- if (HDevWindowStack::IsOpen())
- SetPart(HDevWindowStack::GetActive(),0, 0, hv_ImageHeight-1, hv_ImageWidth-1);
- if (HDevWindowStack::IsOpen())
- SetLineWidth(HDevWindowStack::GetActive(),1);
- return true;
- }
复制代码- BOOL CAngleDetect::DetectAngle(CString sPicName,BOOL bShowResult)
- {
- if(0 == m_hv_ModelID.Length())
- return false;
- HObject ho_Image;
- HTuple hv_MinScoreMain,hv_Greediness,hv_ImageWidth,hv_ImageHeight,hv_NumMatches,hv_Name = sPicName;
- HTuple hv_Row, hv_Column, hv_Angle, hv_Score,hv_Tolerance,hv_MinScorePolar;
- HTuple hv_RowPolar,hv_ColumnPolar,hv_AnglePolar,hv_ScorePolar,hv_HomMat2D;
- hv_MinScoreMain = 0.7;
- hv_Greediness = 0.5;
- hv_Tolerance = 2.5;
- hv_MinScorePolar = 0.4;//小模板查找最小得分
- ReadImage(&ho_Image, hv_Name);
- GetImageSize(ho_Image, &hv_ImageWidth, &hv_ImageHeight);
- FindShapeModel(ho_Image, m_hv_ModelID, 0, HTuple(360).TupleRad(), hv_MinScoreMain,
- 0, 0.0, "least_squares", 0, hv_Greediness, &hv_Row, &hv_Column, &hv_Angle, &hv_Score);
- hv_NumMatches = hv_Row.TupleLength();
- if (hv_NumMatches<=0)
- {
- DisplayMessage(m_hv_WindowHandle, "未找到", "window", 12, 12, "black", "true");
- return false;
- }
- //<>
- ClearData();//清空数据
- HTuple hv_PolarHeight = (m_hv_RadiusOuter-m_hv_RadiusInner).TupleRound();
- HObject ho_PolarTransImage,ho_SearchImageReduced,ho_RefinedContours,ho_ContoursAffinTrans,ho_XYTransContour;
- GenEmptyObj(&ho_RefinedContours);
- HTuple hv_FinalAngles = HTuple();
- HTuple hv_RefinementFailed = HTuple();
- HTuple end_val96 = hv_NumMatches-1;
- HTuple step_val96 = 1;
- HTuple hv_J;
- for (hv_J=0; hv_J.Continue(end_val96, step_val96); hv_J += step_val96)
- {
- PolarTransImageExt(ho_Image, &ho_PolarTransImage, HTuple(hv_Row[hv_J]), HTuple(hv_Column[hv_J]),
- m_hv_PolarStartAngle, m_hv_PolarEndAngle, m_hv_RadiusInner, m_hv_RadiusOuter, m_hv_PolarWidthExtended, hv_PolarHeight, "bilinear");
- Rectangle1Domain(ho_PolarTransImage, &ho_SearchImageReduced, m_hv_RowRefPolar-hv_Tolerance, 0, m_hv_RowRefPolar+hv_Tolerance, m_hv_PolarWidthExtended-1);
- FindShapeModel(ho_SearchImageReduced, m_hv_ModelIDPolar, 0, 0, hv_MinScorePolar,
- 1, 0.0, "least_squares", 0, hv_Greediness, &hv_RowPolar, &hv_ColumnPolar, &hv_AnglePolar, &hv_ScorePolar);
- if (0 != ((hv_ColumnPolar.TupleLength())>0))
- {
- hv_FinalAngles[hv_J] = ((hv_ColumnPolar-m_hv_ColumnRefPolar)/(m_hv_PolarWidthExtended-1))*m_hv_PolarAngleRangeExtended;
- DATA *pData = new DATA();
- pData->Angle = HTuple(hv_FinalAngles[hv_J]).TupleDeg().D();//hv_FinalAngles[hv_J].D();
- pData->XPos = HTuple(hv_Column[hv_J]).D();
- pData->YPos = HTuple(hv_Row[hv_J]).D();
- m_DataList.AddTail(pData);
- if(bShowResult)
- {
- VectorAngleToRigid(0, 0, 0, hv_RowPolar, hv_ColumnPolar, hv_AnglePolar, &hv_HomMat2D);
- AffineTransContourXld(m_ho_PolarModelContours, &ho_ContoursAffinTrans, hv_HomMat2D);
- PolarTransContourXldInv(ho_ContoursAffinTrans, &ho_XYTransContour, HTuple(hv_Row[hv_J]),
- HTuple(hv_Column[hv_J]), m_hv_PolarStartAngle, m_hv_PolarEndAngle, m_hv_RadiusInner,
- m_hv_RadiusOuter, m_hv_PolarWidthExtended, hv_PolarHeight, hv_ImageWidth, hv_ImageHeight);
- ConcatObj(ho_RefinedContours, ho_XYTransContour, &ho_RefinedContours);
- }
- }
- else
- {
- hv_FinalAngles[hv_J] = HTuple(hv_Angle[hv_J]);
- hv_RefinementFailed = hv_RefinementFailed.TupleConcat(hv_J+1);
- }
- }
- if(bShowResult)
- {
- HTuple hv_Title = "找到模型个数: "+hv_NumMatches;
- DisplayResult(ho_Image, ho_RefinedContours, hv_Row, hv_Column, hv_Angle, hv_FinalAngles, hv_RefinementFailed, m_hv_ModelID, hv_Title, m_hv_WindowHandle);
- }
- return true;
- }
复制代码- void CAngleDetect::ClearData()
- {
- POSITION pos = m_DataList.GetHeadPosition();
- while(pos)
- {
- DATA *pData = (DATA *)m_DataList.GetNext(pos);
- delete pData;
- }
- m_DataList.RemoveAll();
- }
- CPtrList*CAngleDetect::GetDataList()
- {
- return &m_DataList;
- }
- BOOL CAngleDetect::Clear()
- {
- if (0 != m_hv_WindowHandle.Length())
- {
- CloseWindow(m_hv_WindowHandle);
- m_hv_WindowHandle = HTuple();
- }
- if(0!=m_hv_ModelID.Length())
- {
- ClearShapeModel(m_hv_ModelID);
- m_hv_ModelID = HTuple();
- }
- if(0!=m_hv_ModelIDPolar.Length())
- {
- ClearShapeModel(m_hv_ModelIDPolar );
- m_hv_ModelIDPolar = HTuple();
- }
- ClearData();
- return true;
- }
复制代码- void CAngleDetectView::OnButton1()
- {
- CButton*pBtn = (CButton*)GetDlgItem(IDC_CHECK1);
- m_AngleDect.Init("pic/1.png",GetDlgItem(IDC_SHOW)->m_hWnd,pBtn->GetCheck());
- }
- void CAngleDetectView::OnButton2()
- {
- LARGE_INTEGER large_interger;
- QueryPerformanceFrequency(&large_interger);
- LONGLONG ff = large_interger.QuadPart;
- QueryPerformanceCounter(&large_interger);
- LONGLONG c1 = large_interger.QuadPart;
- //<>
- static Index = 1;
- CString sText;
- sText.Format("pic/%d.png",Index);
- CButton* pBtn = (CButton*)GetDlgItem(IDC_CHECK2);
- if( m_AngleDect.DetectAngle(sText,!pBtn->GetCheck()) )//正常检测后
- {
- QueryPerformanceCounter(&large_interger);
- LONGLONG c2 = large_interger.QuadPart;
- CComboBox*pBox1 = (CComboBox*)GetDlgItem(IDC_COMBO1);
- CComboBox*pBox2 = (CComboBox*)GetDlgItem(IDC_COMBO2);
- CComboBox*pBox3 = (CComboBox*)GetDlgItem(IDC_COMBO3);
- CComboBox*pBox4 = (CComboBox*)GetDlgItem(IDC_COMBO4);
- pBox1->ResetContent();
- pBox2->ResetContent();
- pBox3->ResetContent();
- pBox4->ResetContent();
- double dbTime = (double)(c2-c1)/ff;
- sText.Format("%f",dbTime*1000);
- pBox4->InsertString(0,sText);
- pBox4->SetCurSel(0);//用时
-
- DATA *pData;
- POSITION pos = m_AngleDect.GetDataList()->GetHeadPosition();
- while(pos)
- {
- pData = (DATA *)m_AngleDect.GetDataList()->GetNext(pos);
- sText.Format("%f",pData->XPos);
- pBox1->InsertString(0,sText);
- pBox1->SetCurSel(0);
- sText.Format("%f",pData->YPos);
- pBox2->InsertString(0,sText);
- pBox2->SetCurSel(0);
- sText.Format("%f",pData->Angle);
- pBox3->InsertString(0,sText);
- pBox3->SetCurSel(0);
- }
- }
- Index++;
- if(Index>16)
- Index=1;
- }
复制代码
完整代码及可执行程序,会员可下载学习及使用
百度云附件:上位机通过CCD视觉检测图像角度与几何坐标.rar
如果您认可,可联系功能定制! 如果您着急,充值会员可直接联系发您资料!
|