利用OpenCV-python进行直线检测

 最近需要利用摄像头对细小的偏移做矫正,由于之前的界面工具是用 PyQT 所写,在当前的工具中加入摄像头矫正程序,也打算用 python 直接完成。

OpenCV 简介:

Python 处理图像有 OpenCV 库。OpenCV 可以运行在 Linux,windows,macOS 上,由 C 函数和 C++ 类构成,用于实现计算机图像、视频的编辑,应用于图像识别、运动跟踪、机器视觉等领域。

OpenCV 安装:

OpenCV 无法用 pip 或easy_install 安装,需要手动下载 .whl 文件安装。

实际应用中安装的OpenCV 库版本为 2.4.13。之所以用 2.4.13 版本的OpenCV,不采用 3.4 版本,是因为项目中用到的直线检测算法——霍夫变换,在OpenCV 3.4 中只能检测到一条结果,这条结果是所有线段中最长的一条。

从以下网址获取 OpenCV 的安装包(网页加载的速度比较慢,需要静候)

https://www.lfd.uci.edu/~gohlke/pythonlibs/

打开链接,待加载完毕后,搜索 OpenCV,可以找到如下页面


根据实际安装的 python 环境,下载对应的 OpenCV 安装包。

输入命令,完成 OpenCV 的安装。

pip install opencv_python‑2.4.13.5‑cp27‑cp27m‑win_amd64.whl

OpenCV 使用:


我对图像的处理是对灰度图像进行处理,不考虑 RGB 值,为了减轻实际的计算量。OpenCV 提供的 RGB 转灰度值的接口是

gray = cv2.cvtColor(cut_img, cv2.COLOR_BGR2GRAY)

得到的灰度图像与原图的比较,如下图所示


要得到图片的线段,在灰度图上继续做后续操作。对图像线段进行检测的算法,是通过算子进行边缘检测,常用算子有Prewitt 算子、sobel 算子、Laplace 算子以及 Canny 算子。这里就不对这些算子的检测结果进行详述了,因为我也不是很明白几种算子实际效果的区别。本例中使用的是 canny 算子。

OpenCV 中调用 canny 算子的方式如下:

edge = cv2.Canny(image, threshold1,threshold2[, edges[, apertureSize[, L2gradient ]]])

必要参数:

第一个参数是需要处理的原图像,该图像必须为单通道的灰度图;

第二个参数是阈值1;

第三个参数是阈值2。

其中较大的阈值2用于检测图像中明显的边缘,但一般情况下检测的效果不会那么完美,边缘检测出来是断断续续的。所以这时候用较小的第一个阈值用于将这些间断的边缘连接起来。

可选参数中apertureSize就是Sobel算子的大小。而L2gradient参数是一个布尔值,如果为真,则使用更精确的L2范数进行计算(即两个方向的倒数的平方和再开放),否则使用L1范数(直接将两个方向导数的绝对值相加)。

随后进行霍夫变换,得到线段的坐标。

霍夫变换是经典的检测直线的算法。其最初用来检测图像中的直线,同时也可以将其扩展,以用来检测图像中简单的结构。

cv2.HoughLines函数输出的是[float,float]形式的ndarray,其中每个值表示检测到的线(ρ , θ)中浮点点值的参数。在本例中,函数将通过步长为1的半径和步长为π/180的角来搜索所有可能的直线。然而用这种方法检测出来的是贯穿整张图像的直线,需要检测线段时,则要采用概率霍夫变换。

lines = cv2.HoughLinesP(edges, 1,np.pi/180, 80, minLineLength, maxLineGap)

它有两个参数:

minLineLength-线的最短长度,比这个线短的都会被忽略。

maxLineGap-两条线之间的最大间隔,如果小于此值,这两条线就会被看成一条线。

这个函数的返回值就是直线的起点和终点。

最后将找到的线段均显示在图片上,即完成直线检测。

由于图片画质因素,很多看似是直线的也未检测出是直线,还有许多散碎的直线并没有连接成长线。有待后续研究解决。


附上完整代码:

import cv2
import numpy as np

#img = cv2.imread("C:/AE_PUFF/python_vision/2018_04_27/kk-3.jpg")
img = cv2.imread("test.jpg")
cv2.imshow('origin_img', img)
height = img.shape[0]  # 高度
width  = img.shape[1]  # 宽度
cut_img = img

gray = cv2.cvtColor(cut_img, cv2.COLOR_BGR2GRAY)
cv2.imshow('gray_img', gray)
cv2.waitKey(0)
edges = cv2.Canny(gray, 50, 150, apertureSize=3)

lines = cv2.HoughLines(edges, 1, np.pi/180, 118)
result = cut_img.copy()
minLineLength = 30 # height/32
maxLineGap = 10 # height/40
lines = cv2.HoughLinesP(edges, 1, np.pi/180, 80, minLineLength, maxLineGap)

for x1, y1, x2, y2 in lines[0]:
    cv2.line(result, (x1, y1), (x2, y2), (0,255,0), 2)

cv2.imshow('result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()


猜你喜欢

转载自blog.csdn.net/panfengzjz/article/details/80146601