opencv之轮廓特征属性及应用

本文介绍如何使用OpenCV中的minAreaRect函数来计算轮廓的最小外接矩形,并通过实例展示了如何利用该矩形进行图像的旋转矫正。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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());//利用放射变换进行旋转
//另一种方法,透视变换


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值