• OpenCV 霍夫线


    官方有两个算子,HoughLines和HoughLinesP

    HoughLines得到两个变量:θ、ρ

    在旋转矫正时,使用的是angle。具体见下图。

    θ 弧度制,[0,π)
    angle 角度制,[-90°,90°),正值则逆时针旋转
    下图中的angle是负值(需顺时针选择),angle=θ*180/π - 90

     

    #include <iostream>
    #include<opencv.hpp>
    using namespace cv;
    
    #include <numeric>   //for accumulate
    
    int main()
    {
        cv::Mat src = cv::imread("C:/line.bmp");
        //灰度化
        cv::Mat gray;
        cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY);
        //二值化,得到1和255的图
        Mat binary;
        threshold(gray, binary, 0, 255, cv::THRESH_BINARY_INV | cv::THRESH_OTSU);
        imshow("binary", binary);
        //霍夫线
        std::vector<cv::Vec2f> lines;
        cv::HoughLines(binary, lines, 1.0, CV_PI / 180, 100, 0, 0);
        int numLines = lines.size();
        std::vector<float> thetas;
        for (int l = 0; l < numLines; l++)
        {
            float rho = lines[l][0];                    //ρ
            float theta = lines[l][1];                    //θ
            cv::Point pt1, pt2;
            double a = cos(theta), b = sin(theta);
            double x0 = a * rho, y0 = b * rho;
            pt1.x = cvRound(x0 + 1000 * (-b));
            pt1.y = cvRound(y0 + 1000 * (a));
            pt2.x = cvRound(x0 - 1000 * (-b));
            pt2.y = cvRound(y0 - 1000 * (a));
            line(binary, pt1, pt2, cv::Scalar(255), 1);    //在二值图上画线
    
            thetas.push_back(theta);
        }
        cv::imshow("Hough直线", binary);
        //角度均值
        float sum = std::accumulate(std::begin(thetas), std::end(thetas), 0.0);
        float meanTheta = sum / thetas.size();
        float meanAngle = (meanTheta / CV_PI) * 180 - 90;
      
        //矫正       
        Point2f center;                                        //旋转中心为图像中心 
        center.x = float(src.cols / 2.0);
        center.y = float(src.rows / 2.0);
        Mat M = getRotationMatrix2D(center, meanAngle, 1);    //计算二维旋转的仿射变换矩阵    
        Mat img_rotate;
        int length = 0;
        length = sqrt(src.cols * src.cols + src.rows * src.rows);
        M.at<double>(0,2) += (length - src.size().width) / 2.0;    //平移,仿射变换矩阵2*3,第3列代表平移
        M.at<double>(1,2) += (length - src.size().height) / 2.0;
        warpAffine(src, img_rotate, M, Size(length, length), 1, 0, Scalar(255, 255, 255));//仿射变换,背景色填充为白色 
        //展示
        imshow("img_rotate", img_rotate);
        waitKey();
    }

    【探讨点】

    θ∈[0,π),在π时会突变为0,存在临界情况。这就导致在求多条线角度平均值的时候会产生错误情况。

    如下图三条线,θ均值应该为0,但是计算为π/3

    目前还没有找到合理的方法求角度均值,暂时解决如下:

    适用情况:线条角度偏差不大时,那么在临界左右,极差会很大,靠近π的要减去π后再求均值

        //直接计算均值,会在180°附近出现问题。以下计算方式有个假设:直线方向差异不大
        //极差超过一定值的,靠近180°的要-180°
        float max = *std::max_element(thetas.begin(), thetas.end());
        float min = *std::min_element(thetas.begin(), thetas.end());
        if ((max - min) > CV_PI / 2)
        {
            for (auto& i : thetas)            //引用,效率更高。i被改变则对应的元素被改变
            {
                if (CV_PI - i < 0.02)    //接近180°时
                {
                    i -= CV_PI;
                }
            }
        }
  • 相关阅读:
    Xcode7中你一定要知道的炸裂调试神技【转载】
    让Category支持添加属性与成员变量【转载】
    KVC与KVO
    时间与日期处理【转载】
    iOS 字符属性NSAttributedString描述【转载】
    搜索引擎-倒排索引基础知识
    sql server命令行
    复习索引
    【藏】使用Entity Framework时要注意的一些性能问题
    windows 8.1 安装 .Net Framework 3.5
  • 原文地址:https://www.cnblogs.com/xixixing/p/15918045.html
Copyright © 2020-2023  润新知