分割图像外接矩形画内部画多条直线

void SegMeasure::measure2(cv::Mat &mask, cv::Mat &img)
{
    // 1、原图画一个分割的绿色边界,轮廓排序
    mask.convertTo(mask, CV_8U);
    std::vector<std::vector<cv::Point>> contours;
    findsortContours(mask, contours, cv::CHAIN_APPROX_NONE);
    if (contours.size() < 1)
        return;
    cv::drawContours(img, contours, 0, cv::Scalar(0, 255, 0), 1); //从大到小排序轮廓

    
    // 2、计算面积最大的轮廓外接矩形,返回的排序从大到小,不用排序了
    std::vector<cv::Point> max_contour = contours[0]; //
    // 计算最小外接矩形
    cv::RotatedRect rect = cv::minAreaRect(max_contour);
    cv::Point2f vertices[4];//vertices[0] = (100, 50);四个点,画图时候
    rect.points(vertices);
    // 在原图中画出矩形框和边界线
    cv::Scalar color = cv::Scalar(0, 0, 255);
    for (int i = 0; i < 4; i++) { //四个点,依次连接画直线,最小矩形
        cv::line(img, vertices[i], vertices[(i + 1) % 4], color, 2);//连接最后的点时候3, (3+1)/4=0,和第一个相连
    }

    // 计算每条边的中点,默认顺时针或者逆时针,两个对点,哪个长哪个就是长轴的两个点
    cv::Point2f midpoints[4];
    midpoints[0] = (vertices[0] + vertices[1]) / 2;
    midpoints[1] = (vertices[1] + vertices[2]) / 2;
    midpoints[2] = (vertices[2] + vertices[3]) / 2;
    midpoints[3] = (vertices[3] + vertices[0]) / 2;
    
    // 确定中点坐标,边上的4个中点 是左右范围边界
    float long_d = cv::norm(midpoints[0]- midpoints[2]);
    float short_d = cv::norm(midpoints[1]- midpoints[3]);
    cv::Point2f mid_short[2];  // 移动直线的左右边界坐标,通过中心点在两个中位线上的移动进行实现
    cv::Point2f mid_long[2];  // 移动直线的左右边界坐标,通过中心点在两个中位线上的移动进行实现
    mid_short[0] = midpoints[1];  //you x y
    mid_short[1] = midpoints[3];
    mid_long[0] = midpoints[0];  //you x y
    mid_long[1] = midpoints[2];
    if (long_d<short_d) {
        mid_short[0] = midpoints[0];
        mid_short[1] = midpoints[2];
        mid_long[0] = midpoints[1];
        mid_long[1] = midpoints[3];        
    }
    // cv::line(img, mid_short[0], mid_short[1], cv::Scalar(255,255 , 0), 3);//是4个中点没错了
    cv::line(img, mid_long[0], mid_long[1], cv::Scalar(255,255 , 0), 3);
    
    // 3、计算最小矩形长宽方向的线段,矩形的中心点和长宽方向,来计算长宽方向的线段,斜率和截距,从而计算出线段的方程
    // 计算长边和短边的线段长度
    cv::Point2f center = rect.center;  // 矩形中心
    float angle = rect.angle;  // 矩形的旋转角度
    cv::Size2f rect_size = rect.size;  // 矩形的尺寸

    // 将矩形旋转角度限制在-45到45度范围内
    if (angle < -45.0)
    {
        angle += 90.0;
        std::swap(rect_size.width, rect_size.height);
    }
    
    // 3.1、最小矩形长的计算
    float k_long = tan(angle * CV_PI / 180.0);  // 长边的斜率,为tan(theta)
    float b_long = center.y - k_long * center.x;  // 长边的截距,为y-kx
    cv::Point2f left_long_point(rect.center.x - rect_size.width / 2, k_long * (rect.center.x - rect_size.width / 2) + b_long);
    cv::Point2f right_long_point(rect.center.x + rect_size.width / 2, k_long * (rect.center.x + rect_size.width / 2) + b_long);
    float long_edge_length = cv::norm(right_long_point - left_long_point); // 计算长边线段长度
    // cv::line(img, left_long_point, right_long_point, cv::Scalar(255,0 , 0), 2);


    // 3.2、最小矩形宽的计算, 短轴的计算
    float k = tan(angle * CV_PI / 180.0 + CV_PI / 2.0); //斜率
    float b = center.y - k * center.x;  //截距

    cv::Point2f top(center.x - rect_size.height / 2.0 / fabs(k), center.y - rect_size.height / 2.0);
    cv::Point2f bottom(center.x + rect_size.height / 2.0 / fabs(k), center.y + rect_size.height / 2.0);
    float short_edge_length = cv::norm(right_long_point - left_long_point); // 计算长边线段长度
    // cv::line(img, top, bottom, cv::Scalar(0, 0, 255), 2);// 限制在矩形框内的短轴方向直线,画的是中心点的坐标

    // 关键是 找中心点,沿着短斜率平移,先得到矩形框内的多条直线进行遍历
    // 短轴中心点左右移动,这个中心点在,长轴直线上,直接代新的x值就行了,最右边的短轴,中心点(x1+x2)/2
    // 下面是画纵轴方向矩形框内多条直线
    int l_left = int(mid_long[0].x);
    int r_right = int(mid_long[1].x);
    if (l_left>r_right){
        int t = l_left;
        l_left = r_right;
        r_right = t;
    }

    // 大一点的线段等间隔画直线,小一点的的线段
    float tt = r_right-l_left;
    int interval = int(tt * 0.05); // 矩形框左右中心点,水平方向x 长度,从左到右,间隔10移动,这里间隔多少按照长度比例来0.05%, 这种处理小的采样多,大的采样少
    if (tt<=60 && tt>3){
        interval = 2;
    }
    else if(tt<=3){
        int interval = 1;
    }
  

    std::cout<<l_left<<std::endl <<r_right<<std::endl;
    int ii = l_left;
    while( ii < r_right){
        float new_center_x = ii;
        float new_center_y = k_long *new_center_x +b_long;// x 带入长轴直线,得到 y  ,得到两个点的坐标
        // 将中心点,带入短轴的方向
        cv::Point2f top(new_center_x - rect_size.height / 2.0 / fabs(k), new_center_y - rect_size.height / 2.0);
        cv::Point2f bottom(new_center_x + rect_size.height / 2.0 / fabs(k), new_center_y + rect_size.height / 2.0);  
        // cv::line(img, top, bottom, cv::Scalar(255,255 , 0), 2);   //每条矩形内部的线画出来
        ii = ii + interval;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值