工控编程吧
标题:
上位机通过CCD视觉检测图像角度与几何坐标
[打印本页]
作者:
qq263946146
时间:
2017-5-28 15:51
标题:
上位机通过CCD视觉检测图像角度与几何坐标
(, 下载次数: 16)
上传
点击文件名下载附件
(, 下载次数: 5)
上传
点击文件名下载附件
(, 下载次数: 4)
上传
点击文件名下载附件
(, 下载次数: 10)
上传
点击文件名下载附件
现在国家大力提倡工业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
[weixinlianxi]1[/weixinlianxi]
欢迎光临 工控编程吧 (https://www.gkbc8.com/)
Powered by Discuz! X3.4