直线检测之极坐标表示

直线检测算法LSD有比较好的效果,相比Hough变换检测直线更高效,然而有个缺点是同一条直线上的线段会断开,此时想到将检测到的直线转化为极坐标表示,然后根据极坐标的相似程度对线段合并。这里图像上的直线与极坐标下角度的范围有着怎样的对应关系? 图像的坐标系Y轴向下,所以并不能直观地得到答案。

为此,写个小程序,来获得极坐标系下直线表示的角度与直线斜率的关系。取图像中心点为原点,以图像宽度的1/4为半径, θ 为角度( θ(0,2π) ),确定一条直线,并绘制出该直线,不同区域的直线以不同颜色区分。

// 说明: 建立极坐标系以图像中心为原点建立平面坐标系,极轴水平向右,第一象限为右上1/4圆,
// 第二象限为左上1/4圆, 依次类推。
//  极坐标系转换到平面坐标系,再到图像坐标系,注意转换关系
// 
    int _tmain(int argc, _TCHAR* argv[])
{

    int w = 600;
    int h = 600;
    Mat lines = Mat::zeros(Size(w,h), CV_8UC3);

    float theta = CV_PI/180; //角度间隔 为1°
    int _color = 0;

    float r = w/4;

    // 绘制360条直线,角度从1°到359°
    int j = 0;
    for (int i = 0 ; i< 360; i += 2)
    {

        float _sin = sin((double)theta*i);
        float _cos = cos((double)theta*i);

        if(fabs(_sin) < 1e-5 || fabs(_cos) < 1e-5 ) //特殊直线不处理了,即水平直线与垂直直线
            continue;

        _color = i/90; 

        float x0 = r*_cos + w/2;
        float y0 = h/2 - r*_sin;

        //u = 0, w;
        float y1 = h/2 - (r + w/2*_cos) /_sin; 
        float y2 = h/2 - (r - w/2*_cos) /_sin;

        float x1 = w/2 + (r - h/2*_sin)/_cos;
        float x2 = w/2 + (r + h/2*_sin)/_cos;

        Point2f pt1,pt2;
        pt1 = Point2f(0,y1);
        pt2 = Point2f(w,y2);

        if(x0 > w/2 && y0 < h/2 ){ 第一象限 直线与上边缘或者左边缘相交

            if(x1 > 0 && x1 < w)
                pt1 = Point2f(x1,0);
            else if(y1 > 0 && y1 < h)
                pt1 = Point2f(0,y1);
            else
                pt1 = Point2f(0,0);

            pt2 = Point2f(x0,y0);
        }

        if(x0 < w/2 && y0 < h/2 ) // 第二象限  直线与左边缘或者下边缘相交
        {
            if(y1 > 0 && y1 < h)
                pt1 = Point2f(0,y1);
            else if(x2 > 0 && x2 < w)
                pt1 = Point2f(x2,h);
            else
                pt1 = Point2f(0,0);

            pt2 = Point2f(x0,y0);
        }

        if(x0 < w/2 && y0 > h/2 ) // 第三象限 直线与下边缘或者右边缘相交
        {
            if(x2 > 0 && x2 < w)
                pt1 = Point2f(x2,h);
            else if(y2 > 0 && y2 < h)
                pt1 = Point2f(w,y2);
            else
                pt1 = Point2f(0,0);

            pt2 = Point2f(x0,y0);
        }

        if(x0 > w/2 && y0 > h/2 ) // 第四象限 直线与右边缘或者上边缘相交
        {
            if(y2 > 0 && y2 < h)
                pt1 = Point2f(w,y2);
            else if(x1 > 0 && x1 < w)
                pt1 = Point2f(x1,0);
            else
                pt1 = Point2f(0,0);

            pt2 = Point2f(x0,y0);
        }

        switch(_color)
        {
        case 0:
            line(lines,pt1,pt2,Scalar(255,0,0),1);
            break;
        case 1:
            line(lines,pt1,pt2,Scalar(0,255,0),1);
            break;
        case 2: 
            line(lines,pt1,pt2,Scalar(0,0,255),1);
            break;
        case 3:
            line(lines,pt1,pt2,Scalar(255,0,255),1);
            break;
        default:
            line(lines,pt1,pt2,Scalar(255,255,255),1);
        }
        char id[24];
        sprintf(id,"image/line_%03d.jpg",j++);
        imwrite(id,lines);
    }

    imwrite("line.jpg",lines);
    imshow("Polar Line",lines);
    waitKey();

    return 0;
}

结果如图:
这里写图片描述

以图像中心为极点,极轴为水平向右,则可得到该极坐标下角度 θ 与图像上直线斜率的对应关系。

针对图像上一条直线,以图像中心为原点,做一个与直线相切的圆,

  1. 切点(x,y)在圆的右上部分x> w/2,y< h/2,该直线在极坐标下的角度范围 (0,π/2) ;
  2. 切点(x,y)在圆的左上部分x< w/2,y< h/2,该直线在极坐标下的角度范围 (π/2,π) ;
  3. 切点(x,y)在圆的左下部分x< w/2,y> h/2,该直线在极坐标下的角度范围 (π,3π/2)
  4. 切点(x,y)在圆的右下部分x> w/2,y> h/2,该直线在极坐标下的角度范围 (3π/2,2π) .
  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
import cv2 as cv import numpy as np #直线检测 #使用霍夫直线变换做直线检测,前提条件:边缘检测已经完成 #标准霍夫线变换 def line_detection(image): gray = cv.cvtColor(image, cv.COLOR_RGB2GRAY) edges = cv.Canny(gray, 50, 150) #apertureSize参数默认其实就是3 cv.imshow("edges", edges) #cv.HoughLines参数设置:参数1,灰度图像;参数二,以像素为单位的距离精度(一般都是1,进度高,但是速度会慢一点) #参数三,以弧度为单位的角度精度(一般是1rad);参数四,阈值,大于阈值threshold的线段才可以被检测通过并返回到结果中 #该函数返回值为rho与theta lines = cv.HoughLines(edges, 1, np.pi/180, 200) for line in lines: rho, theta = line[0] #line[0]存储的是点到直线的极径和极角,其中极角是弧度表示的。 a = np.cos(theta) #theta是弧度 b = np.sin(theta) x0 = a * rho #代表x = r * cos(theta) y0 = b * rho #代表y = r * sin(theta) x1 = int(x0 + 1000 * (-b)) #计算直线起点横坐标 y1 = int(y0 + 1000 * a) #计算起始起点纵坐标 x2 = int(x0 - 1000 * (-b)) #计算直线终点横坐标 y2 = int(y0 - 1000 * a) #计算直线终点纵坐标 注:这里的数值1000给出了画出的线段长度范围大小,数值越小,画出的线段越短,数值越大,画出的线段越长 cv.line(image, (x1, y1), (x2, y2), (0, 0, 255), 2) #点的坐标必须是元组,不能是列表。 cv.imshow("image-lines", image) #统计概率霍夫线变换 def line_detect_possible_demo(image): gray = cv.cvtColor(image, cv.COLOR_RGB2GRAY) edges = cv.Canny(gray, 50, 150, apertureSize=3) # apertureSize参数默认其实就是3 lines = cv.HoughLinesP(edges, 1, np.pi / 180, 60, minLineLength=60, maxLineGap=5) for line in lines: x1, y1, x2, y2 = line[0] cv.line(image, (x1, y1), (x2, y2), (0, 0, 255), 2) cv.imshow("line_detect_possible_demo",image) src = cv.imread("E:/opencv/picture/track.jpg") print(src.shape) cv.namedWindow('input_image', cv.WINDOW_AUTOSIZE) cv.imshow('input_image', src) line_detection(src) src = cv.imread("E:/opencv/picture/track.jpg") #调用上一个函数后,会把传入的src数组改变,所以调用下一个函数时,要重新读取图片 line_detect_possible_demo(src) cv.waitKey(0) cv.destroyAllWindows() 霍夫检测直线原理: 关于hough变换,核心以及难点就是关于就是有原始空间到参数空间的变换上。以直线检测为例,假设有一条直线L,原点到该直线的垂直距离为p,垂线与x轴夹角为θθ,那么这条直线是唯一的,且直线的方程为 ρ=xcosθ+ysinθρ=xcosθ+ysinθ, 如下图所
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值