opencv之轮廓特征属性及应用

时间:2022-12-23 21:38:56

1)最小外接矩形
轮廓最小外接矩形–minAreaRect()
RotatedRect minAreaRect(InputArray points);
**points :输入的二维点集,可以填Mat 类型或std::vector
**返回值:RotatedRect类矩形对象,外接旋转矩形主要成员有center,size,angle,points


在opencv中,坐标的原点在左上角,与x轴平行的方向为角度0,逆时针旋转角度是负,顺时针旋转角度是正,而RotatedRect类是以矩形的哪一条边与x轴的夹角作为角度的呢?angle是水平轴(x轴)逆时针旋转,与碰到的第一个边的夹角,而opencv默认把这个边的边长作为width,angle的取值范围必然是负的

vector<RotatedRect>box(contours.size());
Point2f rect[4];
for(int i=0;i<contours.size();i++)
{
box[i]=minAreaRect(Mat(contours[i]));
}

应用一 :粗略计算长宽(像素)

应用二 :旋转矫正

//轮廓最小外接矩形的矩阵 计算长宽
//精度高的话 要用单目测距 双目测距

void main()
{
Mat srcImg=imread("cup.jpg");
imshow("src",srcImg);
Mat dstImg=srcImg.clone();
medianBlur(srcImg,srcImg,5);
GaussianBlur(srcImg,srcImg,Size(3,3),0,0);
cvtColor(srcImg,srcImg,CV_BGR2GRAY);
threshold(srcImg,srcImg,100,255,CV_THRESH_BINARY_INV);
imshow("threshold",srcImg);
vector<vector<Point>>contours;
vector<Vec4i>hierarcy;
findContours(srcImg,contours,hierarcy,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_NONE);
count<<"num="<<contours.size()<<endl;
vector<Rect>boundRect(contours.size());//定义外接矩形集合
vector<RotatedRect>box(contours.sie());//定义最小外接矩形集合
Point2f rect[4];
for(int i=0;i<contours.size();i++)
{
box[i]=minAreaRect(Mat(contours[i]));//计算每个轮廓最小外接矩形
boundRect[i]=boundingRect(Mat(contours[i]));
cout<<box[i].size<<endl;
cout<<box[i].center<<endl;
cout<<box[i].size.width<<endl;
cout<<box[i].size.height<<endl;
circle(dstImg,Point(box[i].center.x,box[i].center.y),5,Scalar(0,255,0),-1,8);
char width[20],height[20];
sprintf(width,"width=%0.2f",box[i].size.width);
sprintf(height,"height=%0.2f",box[i].size.height);
box[i].points(rect);//把最小外接矩形四个端点赋值给rect数组
rectangle(dstImg,Point(boundRect[i].x,boundRect[i].y),Point(bounfRect[i].x+boundRectt[i].width,boundRect[i].y+bounfRect[i].height));
for(int j=0;j<4;j++)
{
line(dstImg,rect[j],rect[(j+1)%4],Scalar(0,0,255),2,8);//绘制最小外接矩形每条边
}
putText(dstImg.width,Point(235,260),CV_FONT_HERSHEY_COMPLEX_SMALL,0.85,Scalar(0,255,0),2,8);
putText(dstImg.height,Point(235,285),CV_FONT_HERSHEY_COMPLEX_SMALL,085,Scalar(0,255,0),2,8);
}
imshow("dst",dstImg);
waitKey(0);
}

//倾斜物体矫正提取

Mat srcImg=imread("qrcode.jpg");
imshow("src",srcImg);
Mat dstImg=srcImg.clone();
GaussianBlur(srcImg,srcImg,Size(3,3),0,0);
cvtColor(srcImg,srcImg,Size(3,3),0,0);
Canny(srcImg,srcImg,100,200);
//threshold(srcImg,srcImg,100,255,CV_THRESH_BINARY_INV);//二值化
//adaptiveThreshold(srcImg,srcImg,255,AADAPTIVE_THRESH_GAUSSIAN_C,CV_YHRESH_BINARY_INV,15,3);
imshow("threshoold",srcImg);
Mat element=getStructuringElent(MOPRH_RECT,Size(11,11),Point(-1,-1));
dilate(srcImg,srcImg,element);
imshow("dilate",srcImg);
erode(srcImg,srcImg,element);
imshow("erode",srcImg); //做完膨胀做的腐蚀 用一样的核
vector<Rect>boundRect(contours.size());
vector<RotatedRect>box(contours.size());
Point2f rect[4];
for(int i=0;i<contours.size();i++)
{
box[i]=minAreaRect(Mat(contours[i]));
boundRect[i]=boundingRect(Mat(contours[i]));
if(box[i].size,width<100||box[i].size.height<100)
continue;//设置范围
circle(dstImg,Point(box[i].center.x,box[i],center.y),5,Scalar(0,255,0),-1,8);
count<<"num="<<box[i].angle<<endl;
angle[i]=box[i].angle;
char width[20],height[20];
sprintf(width,"width=%0.2f",box[i].size.width);
sprintf(height,"height=%0.2f",box[i].size.height);
box[i].points(rect);
rectangle(dstImg,Point(boundRect[i].x,boundRect[i].y),Point(boundRect[i].x+boundRect[i].width,boundRect[i].y+boundRect[i].height));
}



















//经验值
if(0<abs(angle)&&abs(angle)<=45)//逆时针
angle=angle;
else if(45<abs(angle)&&abs(angle)<90)//顺时针
angle=90-abs(angle);
Point2f center=box[i].center;//定义旋转中心坐标
double angle0=angle;
double scale=1;
Mat roateM;
roateM=getRotationMateix2D(center,angle0,scale);//获得旋转矩阵
warpAffine((dstImg,dstImg,roateM,dstImg.size());//利用放射变换进行旋转
//另一种方法,透视变换