首先用形态学去膨胀整图,使二维码成为一个黑块,定位出这个正方形即获得二维码大致位置。
二维码的三个角都有2个嵌套关系的矩形,以下根据轮廓嵌套关系去定位这3个点:
Mat imgSrc=imread("qrcode.jpg");
if(imgSrc.empty())
{
cout<<"Load image error!!!"<<endl;
return -1;
}
Mat imgGray,imgBin;
cvtColor(imgSrc,imgGray,COLOR_BGR2GRAY);
threshold(imgGray,imgBin,0,255,THRESH_BINARY_INV | THRESH_OTSU);
vector<vector<Point>> contours,contours2;
vector<Vec4i> hierarchy;
findContours(imgBin.clone(),contours,hierarchy,CV_RETR_TREE,CV_CHAIN_APPROX_NONE);
size_t nSize=contours.size();
int c=0,ic=0,area=0;
int parentIdx=-1;
for(size_t i=0;i<nSize;i++)
{
if (hierarchy[i][2] != -1) //有子轮廓
{
if(ic==0) //TREE结构时,第一个父轮廓是最外层轮廓
parentIdx = i;
ic++;
}
else if(hierarchy[i][2] == -1)//无子轮廓
{
ic = 0;
parentIdx = -1;
}
//找到定位点信息
if ( ic >= 2) //有两层嵌套轮廓时
{
contours2.push_back(contours[parentIdx]); //添加父轮廓(最外层)
ic = 0;
parentIdx = -1;
}
}
nSize=contours2.size();
if(nSize!=3) //是否找到的是3个轮廓
{
cout<<"no codebar!!!"<<endl;
return -1;
}
vector<Point2f> vecPts(3); //3个圆心坐标
for(size_t i=0;i<nSize;i++)
{
//画轮廓,填充
drawContours(imgSrc,contours2,i,Scalar(0,255,0),-1);
//最小外接圆求圆心
float radius;
minEnclosingCircle(contours2[i],vecPts[i],radius);
//circle(imgSrc,center,1,Scalar(0,0,255),2);
}
//圆心之间画线相连
for(size_t i=0;i<nSize;i++)
{
int curId=i,nextId=(i+1)%3;
line(imgSrc,vecPts[curId],vecPts[nextId],Scalar(0,0,255));
}
这里还可以根据轮廓长宽比(是否接近正方形)来删选轮廓,
还可以根据 "这三个点成直角三角形" 这一特性来提升准确性。