Ransac找直线 opencv C++

//img_bin:输入二值图,背景0,前景非0。

//line:直线方程标准式参数Ax+By+C=0,line[0]x+line[1]y+line[2]=0。注意:x,y指图像横纵坐标,分别对应width,height。

//成功返回真失败返回假

//抗干扰能力较好,低信噪比条件下也能有不错的效果。

bool RansacLine(cv::Mat& img_bin, float* line)
{
    if (img_bin.empty() || img_bin.channels() != 1)
        return false;
    std::vector<cv::Point> points;
    for (int i = 0;i < img_bin.rows;i++)
    {
        uchar* pb = img_bin.ptr<uchar>(i);
        for (int j = 0;j < img_bin.cols;j++)
        {
            if (pb[j] > 0)//前景,根据情况修改条件,收集所有目标点
                points.push_back(cv::Point(j, i));
        }
    }
    if (points.size() == 0)
        return false;
    int distance_thres = 2;//满足集内条件,即以当前点到直线距离不大于distance_thres认定为该点在直线上。
    int loop_count = 0;
    int iner_count = 0;
    int max_iner_count = 0;
    float distance = 0;
    float sqrt_ = 0;
    int rand_k1 = 0, rand_k2 = 0;
    cv::Point point1, point2;
    float A = 0, B = 0, C = 0;
    float max_dis = 0, min_dis = 100000, average_dis = 0;
    while (loop_count++ < 10000)//最大循环次数,根据情况可设定为所有点数的10倍
    {
        srand((unsigned int)time(0));    //以当前系统时间来初始化srand种子
        rand_k1 = rand() % points.size();
        point1 = points[rand_k1];
        rand_k2 = rand() % points.size();
        while (rand_k1 == rand_k2)
            rand_k2 = rand() % points.size();
        point2 = points[rand_k2];
        A = point2.y - point1.y;
        B = point1.x - point2.x;
        C = point1.x * (point1.y - point2.y) + point1.y * (point2.x - point1.x);
        sqrt_ = sqrtf(A * A + B * B);
        iner_count = 0;
        float max_dis_ = 0, min_dis_ = 100000, sum_dis = 0;
        for (int i = 0;i < points.size();i++)
        {
            distance = abs(points[i].x * A + points[i].y * B + C) * 1.0 / sqrt_;
            if (distance < distance_thres)
                iner_count++;
            if (max_dis_ < distance)
                max_dis_ = distance;
            if (min_dis_ > distance)
                min_dis_ = distance;
            sum_dis += distance;
        }
        if (iner_count >= max_iner_count)
        {
            max_iner_count = iner_count;
            line[0] = A;
            line[1] = B;
            line[2] = C;
            max_dis = max_dis_;
            min_dis = min_dis_;
            average_dis = sum_dis / points.size();
        }
    }
    std::cout << u8"Ransac line 最大误差:" << max_dis << u8" 最小误差:" << min_dis << u8" 平均误差:" << average_dis << std::endl;
    return true;
}



//使用示例:

//float line[3];///直线方程:line[0]*x+line[1]*y+line[2]=0

if (RansacLine(img_bin, line))
{
    cv::Point point1, point2;
    if (line[0] == 0 && line[1] != 0)
    {
        point1 = cv::Point(0, -1 * line[2] / line[1]);
        point2 = cv::Point(img_bin.cols - 1, -1 * line[2] / line[1]);
    }
    else if (line[0] != 0 && line[1] == 0)
    {
        point1 = cv::Point(-1 * line[2] / line[0], 0);
        point2 = cv::Point(-1 * line[2] / line[0], img_bin.rows - 1);
    }
    else
    {
        point1 = cv::Point(0, -1 * line[2] / line[1]);
        point2 = cv::Point(img_bin.cols, -1 * (img_bin.cols * line[0] + line[2]) / line[1]);

    }
        std::cout << "line: " << line << std::endl;
        cv::line(img_bin, point1, point2, cv::Scalar(0, 255, 0));
        cv::namedWindow("Ransac line", 0);
        imshow("Ransac line", img_bin);
        cv::waitKey(0);
    }
    else
    {
        std::cout << u8"寻找直线失败,请确认图像,并调整提取前景的阈值" << std::endl;
    }
}

效果:

Ransac寻找3维平面 opencv C++

 

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值