程序备份——将四边形截取出来(包围的最小矩形)

102 篇文章 30 订阅
52 篇文章 2 订阅

这里写图片描述
这里写图片描述

这里写图片描述

/*
工程在69那个例程文件目录

检测四边形轮廓以及角点
*/









#include <opencv.hpp>  
#include <iostream>  
#include<time.h>
#include<math.h>
#include <iostream>  
#include <set>
using namespace cv;
using namespace std;

RNG rng(12345);
char strangerName[2000];//截取的四边形矩形图片名字
float getDistance(CvPoint pointO, CvPoint pointA);
float getAngle(CvPoint pointM, CvPoint pointL, CvPoint pointR);

float getDist_P2L(CvPoint pointP, CvPoint pointA, CvPoint pointB);
int list_connor(int i1, int i2, int i3);
int main()
{
    Mat srcImage = Mat::zeros(600, 800, CV_8UC3);
    Mat srcImage0 = imread("10.jpg", 0);
    resize(srcImage0, srcImage, srcImage.size());
    srcImage = srcImage > 200;//二值化

    imshow("原图", srcImage);
    //getStructuringElement函数会返回指定形状和尺寸的结构元素
    Mat element = getStructuringElement(MORPH_RECT, Size(3, 3));
    //morphologyEx(srcImage, srcImage, MORPH_CLOSE, element);//闭运算滤波
    vector<vector<Point>> contours, RectContours;//轮廓,为点向量,
    findContours(srcImage, contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);//找轮廓
    vector<vector<Point>> hull(contours.size());//用于存放凸包
    Mat drawing(srcImage.size(), CV_8UC3, cv::Scalar(0));
    int i = 0;
    vector<float> length(contours.size());//用于保存每个轮廓的长度
    vector<float> Area_contours(contours.size()), Area_hull(contours.size()), Rectangularity(contours.size()), circularity(contours.size());
    for (i = 0; i < contours.size(); i++)
    {//把所有的轮廓画出来
        Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
        length[i] = arcLength(contours[i], true);//轮廓的长度
        if (length[i] >200 && length[i] <2000)
        {//通过长度匹配滤除小轮廓
            convexHull(Mat(contours[i]), hull[i], false);//把凸包找出来,寻找凸包函数
            Area_contours[i] = contourArea(contours[i]);   //轮廓面积
            Area_hull[i] = contourArea(hull[i]);           //凸包面积
            Rectangularity[i] = Area_contours[i] / Area_hull[i]; //矩形度
            circularity[i] = (4 * 3.1415*Area_contours[i]) / (length[i] * length[i]);//圆形度
            //drawContours(drawing, contours, i, color, 1);//得到方框

            if (Rectangularity[i]>0.8&&circularity[i]<0.9)
            {//通过矩形度和圆形度滤除数字
                //drawContours(drawing, contours, i, Scalar(255, 255, 255), 1);
                RectContours.push_back(hull[i]);//把提取出来的方框导入到新的轮廓组
                drawContours(drawing, hull, i, color, 1);//得到四边形


            }
        }
    }
    /**********************     自己添加的     **************************************************************************************************************/
    /**********************     自己添加的     **************************************************************************************************************/

    // 多边形逼近轮廓 + 获取矩形和圆形边界框
    vector<vector<Point> > contours_poly(RectContours.size());
    vector<Rect> boundRect(RectContours.size()); //最小矩形
    vector<Point2f>center(RectContours.size()); //圆心
    vector<float>radius(RectContours.size()); //半径

    //一个循环,遍历所有部分,进行本程序最核心的操作
    for (unsigned int i = 0; i < RectContours.size(); i++)
    {
        approxPolyDP(RectContours[i], contours_poly[i], 3, true);//用指定精度逼近多边形曲线 
        boundRect[i] = boundingRect(Mat(contours_poly[i]));//计算点集的最外面(up-right)矩形边界
        minEnclosingCircle(contours_poly[i], center[i], radius[i]);//对给定的 2D点集,寻找最小面积的包围圆形 
    }

    // 绘制多边形轮廓 + 包围的矩形框 + 圆形框
    Mat drawing1 = Mat::zeros(srcImage.size(), CV_8UC3);

    Mat image_cut[100];      //从img中按照rect进行切割,此时修改image_cut时image中对应部分也会修改,因此需要copy  
    Mat image_copy[100];   //clone函数创建新的图片 
    int geshu = 0;
    for (int unsigned i = 0; i < RectContours.size(); i++)
    {

        Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));//随机设置颜色
        //drawContours(drawing1, contours_poly, i, color, 1, 8, vector<Vec4i>(), 0, Point());//绘制轮廓
        Point text_lb;//中点


        //circle(drawing, center[i], (int)radius[i], color, 2, 8, 0);//绘制圆
        //if (radius[i]<39 && radius[i]>20 && center[i].y>300 && center[i].x>200 && center[i].x<400)
        //if (radius[i]<39 && radius[i]>20 && center[i].y>300 && center[i].x>350 && center[i].x<400)
        //中间下面的点
        //  if (radius[i]<39 && radius[i]>20 && center[i].y > 200 && center[i].x > 100 && center[i].x < 650)
        //{
        geshu++;
        rectangle(drawing1, boundRect[i].tl(), boundRect[i].br(), color, 2, 8, 0);//绘制矩形
        text_lb = Point((boundRect[i].tl().x + boundRect[i].br().x)*0.5, (boundRect[i].tl().y + boundRect[i].br().y)*0.5);
        //putTextZH(drawing, "中点", center[i], Scalar(0, 0, 255), 10, "Arial");
        int width = abs(boundRect[i].tl().x - boundRect[i].br().x);
        int height = abs(boundRect[i].tl().y - boundRect[i].br().y);



        Rect rect(boundRect[i].tl().x, boundRect[i].tl().y, width, height);   //创建一个Rect框,属于cv中的类,四个参数代表x,y,width,height  

        image_cut[i] = Mat(srcImage, rect);      //从img中按照rect进行切割,此时修改image_cut时image中对应部分也会修改,因此需要copy  
        image_copy[i] = image_cut[i].clone();   //clone函数创建新的图片  
        sprintf_s(strangerName, "数字%d", geshu);
        namedWindow(strangerName, 0);//参数为零,则可以自由拖动strangerName
        imshow(strangerName, image_copy[i]);


        /********************************************************************************************************************/

        //}

    }

    namedWindow("找到四边形外接矩形", 1);
    imshow("找到四边形外接矩形", drawing1);

    /***************************************************************************************/
    /***************************************************************************************/
    /***************************************************************************************/

    float distance = 0, distanceMax = 0;
    Point connorPoint1, connorPoint2, connorPoint3, connorPoint4, point_add;
    vector<Point> connor4_add(3);  //先找到的三个角点
    int conP_i1, conP_i2, conP_i3, conP_i_add;
    int j = 0, flag = 0;

     Point  finally_contours[80][4];//轮廓,为点向量,新的轮廓
    for (j = 0; j < RectContours.size(); j++)  //四边形轮廓个数
    {
        distance = 0;
        distanceMax = 0;
        for (i = 0; i < RectContours[j].size(); i++) //每个轮廓点的个数11到19点不等
        {//找第一个角点
            distance = getDistance(RectContours[j][i], RectContours[j][0]);
            if (distance>distanceMax)
            {
                distanceMax = distance;
                connorPoint1 = RectContours[j][i]; //第一个角点
                conP_i1 = i;
            }
        }
        distance = 0;
        distanceMax = 0;
        for (i = 0; i < RectContours[j].size(); i++)
        {//找第二个角点
            distance = getDistance(RectContours[j][i], connorPoint1);
            if (distance>distanceMax)
            {
                distanceMax = distance;
                connorPoint2 = RectContours[j][i]; //第二个角点
                conP_i2 = i;
            }
        }
        distance = 0;
        distanceMax = 0;
        for (i = 0; i < RectContours[j].size(); i++)
        {//找第三个角点
            distance = getDistance(RectContours[j][i], connorPoint1) + getDistance(RectContours[j][i], connorPoint2);
            if (distance>distanceMax)
            {
                distanceMax = distance;
                connorPoint3 = RectContours[j][i]; //第三个角点
                conP_i3 = i;
            }
        }
        flag = list_connor(conP_i1, conP_i2, conP_i3);//对三个角点由大到小排序
        switch (flag)
        {//对三个角点排序
        case 0:break;
        case 123:break;
        case 132:point_add = connorPoint2; connorPoint2 = connorPoint3; connorPoint3 = point_add; break;//2,3交换
        case 213:point_add = connorPoint1; connorPoint1 = connorPoint2; connorPoint2 = point_add; break;//1,2交换
        case 231:point_add = connorPoint1; connorPoint1 = connorPoint2; connorPoint2 = point_add;
            point_add = connorPoint2; connorPoint2 = connorPoint3; connorPoint3 = point_add; break;//1,2交换+2,3交换
        case 321:point_add = connorPoint3; connorPoint3 = connorPoint1; connorPoint1 = point_add; break;//1,3交换
        case 312:point_add = connorPoint3; connorPoint3 = connorPoint1; connorPoint1 = point_add;
            point_add = connorPoint2; connorPoint2 = connorPoint3; connorPoint3 = point_add; break;//1,3交换+2,3交换
        }
        switch (flag)
        {//对三个角点排序
        case 0:break;
        case 123:break;
        case 132:conP_i_add = conP_i2; conP_i2 = conP_i3; conP_i3 = conP_i_add; break;//2,3交换
        case 213:conP_i_add = conP_i1; conP_i1 = conP_i2; conP_i2 = conP_i_add; break;//1,2交换
        case 231:conP_i_add = conP_i1; conP_i1 = conP_i2; conP_i2 = conP_i_add;
            conP_i_add = conP_i2; conP_i2 = conP_i3; conP_i3 = conP_i_add; break;//1,2交换+2,3交换
        case 321:conP_i_add = conP_i3; conP_i3 = conP_i1; conP_i1 = conP_i_add; break;//1,3交换
        case 312:conP_i_add = conP_i3; conP_i3 = conP_i1; conP_i1 = conP_i_add;
            conP_i_add = conP_i2; conP_i2 = conP_i3; conP_i3 = conP_i_add; break;//1,3交换+2,3交换
        }
        distance = 0;
        distanceMax = 0;
        for (i = conP_i3; i < conP_i2; i++)
        {//相隔两角点之间找到怀疑是4角点的点
            distance = getDistance(RectContours[j][i], connorPoint3) + getDistance(RectContours[j][i], connorPoint2);
            if (distance>distanceMax)
            {
                distanceMax = distance;
                connor4_add[0] = RectContours[j][i];
            }
        }
        distance = 0;
        distanceMax = 0;
        for (i = conP_i2; i < conP_i1; i++)
        {//相隔两角点之间找到怀疑是4角点的点
            distance = getDistance(RectContours[j][i], connorPoint1) + getDistance(RectContours[j][i], connorPoint2);
            if (distance>distanceMax)
            {
                distanceMax = distance;
                connor4_add[1] = RectContours[j][i];
            }
        }
        distance = 0;
        distanceMax = 0;
        for (i = conP_i1; i < RectContours[j].size() + conP_i3; i++)
        {//相隔两角点之间找到怀疑是4角点的点
            if (i< RectContours[j].size())
            {
                distance = getDistance(RectContours[j][i], connorPoint1) + getDistance(RectContours[j][i], connorPoint3);
                if (distance>distanceMax)
                {
                    distanceMax = distance;
                    connor4_add[2] = RectContours[j][i];
                }
            }
            else
            {
                distance = getDistance(RectContours[j][i - RectContours[j].size()], connorPoint1) + getDistance(RectContours[j][i - RectContours[j].size()], connorPoint3);
                if (distance>distanceMax)
                {
                    distanceMax = distance;
                    connor4_add[2] = RectContours[j][i - RectContours[j].size()];
                }
            }
        }
        if (getDist_P2L(connor4_add[0], connorPoint3, connorPoint2)>10)
        {
            connorPoint4 = connor4_add[0];
        }
        else if (getDist_P2L(connor4_add[1], connorPoint2, connorPoint1)>10)
        {
            connorPoint4 = connor4_add[1];
        }
        else if (getDist_P2L(connor4_add[2], connorPoint1, connorPoint3)>10)
        {
            connorPoint4 = connor4_add[2];
        }

        circle(drawing, connorPoint1, 3, Scalar(255, 255, 255), FILLED, LINE_AA);
        circle(drawing, connorPoint2, 3, Scalar(255, 255, 255), FILLED, LINE_AA);
        circle(drawing, connorPoint3, 3, Scalar(255, 255, 255), FILLED, LINE_AA);
        circle(drawing, connorPoint4, 3, Scalar(255, 255, 255), FILLED, LINE_AA);

        finally_contours[j][0] = connorPoint1;
        finally_contours[j][1] = connorPoint2;
        finally_contours[j][2] = connorPoint3;
        finally_contours[j][3] = connorPoint4;

        cout << "\n轮廓 " << j+1 << "  的四个角点坐标分别为:\n" << finally_contours[j][0] << finally_contours[j][1] << finally_contours[j][2] << finally_contours[j][3] << endl;

    }


    imshow("轮廓", drawing);
    /********透视变换过程*************************************************************************/
    检测是否是四边形,很多图片检测不到
    //  if (approx.size() != 4)
    //  {
    //      std::cout << "The object is not quadrilateral(四边形)!" << std::endl;
    //      return -1;
    //  }
    //  //get mass center  寻找四边形中点
    //  for (unsigned int i = 0; i < corners.size(); i++)
    //  {
    //      center += corners[i];
    //  }
    //  center *= (1. / corners.size());
    //
    //  //确定四个点的中心线
    //  sortCorners(corners, center);
    //
    //  cv::Mat dst = src.clone();
    //
    //  //Draw Lines  画直线
    //  for (unsigned int i = 0; i<lines.size(); i++)
    //  {
    //      cv::Vec4i v = lines[i];
    //      cv::line(dst, cv::Point(v[0], v[1]), cv::Point(v[2], v[3]), CV_RGB(0, 255, 0));    //目标版块画绿线   
    //  }
    //
    //  //draw corner points  画角点
    //  cv::circle(dst, corners[0], 3, CV_RGB(255, 0, 0), 2);
    //  cv::circle(dst, corners[1], 3, CV_RGB(0, 255, 0), 2);
    //  cv::circle(dst, corners[2], 3, CV_RGB(0, 0, 255), 2);
    //  cv::circle(dst, corners[3], 3, CV_RGB(255, 255, 255), 2);
    //
    //  //draw mass center  画出四边形中点
    //  cv::circle(dst, center, 3, CV_RGB(255, 255, 0), 2);
    //
    //  cv::Mat quad = cv::Mat::zeros(300, 220, CV_8UC3);//设定校正过的图片从320*240变为300*220  
    //
    //  //corners of the destination image  
    //  std::vector<cv::Point2f> quad_pts;
    //  quad_pts.push_back(cv::Point2f(0, 0));
    //  quad_pts.push_back(cv::Point2f(quad.cols, 0));//(220,0)  
    //  quad_pts.push_back(cv::Point2f(quad.cols, quad.rows));//(220,300)  
    //  quad_pts.push_back(cv::Point2f(0, quad.rows));
    //
    //  // Get transformation matrix  
    //  cv::Mat transmtx = cv::getPerspectiveTransform(corners, quad_pts);   //求源坐标系(已畸变的)与目标坐标系的转换矩阵  
    //
    //  // Apply perspective transformation透视转换  
    //  cv::warpPerspective(src, quad, transmtx, quad.size());

    //  cv::namedWindow("image", 0);
    //  cv::imshow("image", dst);
    //
    //  cv::namedWindow("quadrilateral", 0);
    //  cv::imshow("quadrilateral", quad);


    waitKey(0);
    return 0;
}

float getDist_P2L(CvPoint pointP, CvPoint pointA, CvPoint pointB)
{//点到直线的距离:P到AB的距离
    //求直线方程
    int A = 0, B = 0, C = 0;
    A = pointA.y - pointB.y;
    B = pointB.x - pointA.x;
    C = pointA.x*pointB.y - pointA.y*pointB.x;
    //代入点到直线距离公式
    float distance = 0;
    distance = ((float)abs(A*pointP.x + B*pointP.y + C)) / ((float)sqrtf(A*A + B*B));
    return distance;
}


//对角点进行排序,因为之前检测出的轮廓是带序号的
int list_connor(int i1, int i2, int i3)
{//排序
    int flag = 0;
    Point point_add;
    if (i1 >= i2&&i2 >= i3)
        flag = 123;
    else if (i1 >= i3&& i3 >= i2)
        flag = 132;
    else if (i2 >= i1&&i1 >= i3)
        flag = 213;
    else if (i2 >= i3&&i3 >= i1)
        flag = 231;
    else if (i3 >= i2&&i2 >= i1)
        flag = 321;
    else if (i3 >= i1&&i1 >= i2)
        flag = 312;
    return flag;
}



float getDistance(CvPoint pointO, CvPoint pointA)
{//求两点之间距离
    float distance;
    distance = powf((pointO.x - pointA.x), 2) + powf((pointO.y - pointA.y), 2);
    distance = sqrtf(distance);

    return distance;
}

float getAngle(CvPoint pointM, CvPoint pointL, CvPoint pointR)
{//求三点之间的夹角
    CvPoint L, R;
    float dist_L, dist_R, Theta;
    L.x = pointL.x - pointM.x;
    L.y = pointL.y - pointM.y;
    R.x = pointR.x - pointM.x;
    R.y = pointR.y - pointM.y;
    dist_L = getDistance(pointL, pointM);
    dist_R = getDistance(pointR, pointM);
    Theta = acos((L.x*R.x + L.y*R.y) / (dist_L*dist_R));
    return Theta;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

翟羽嚄

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值