python+opencv实现霍夫变换检测直线

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实现霍夫变换检测直线_第1张图片
根据实际安装的 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)

python+opencv实现霍夫变换检测直线_第2张图片

要得到图片的线段,在灰度图上继续做后续操作。对图像线段进行检测的算法,是通过算子进行边缘检测,常用算子有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)
HoughLinesP(image, rho, theta, threshold, lines=None, minLineLength=None, maxLineGap=None) 
  • image: 必须是二值图像,推荐使用canny边缘检测的结果图像;
  • rho: 线段以像素为单位的距离精度,double类型的,推荐用1.0
  • theta: 线段以弧度为单位的角度精度,推荐用numpy.pi/180
  • threshod: 累加平面的阈值参数,int类型,超过设定阈值才被检测出线段,值越大,基本上意味着检出的线段越长,检出的线段个数越少。根据情况推荐先用100试试
  • lines:这个参数的意义未知,发现不同的lines对结果没影响,但是不要忽略了它的存在
  • minLineLength:线段以像素为单位的最小长度,根据应用场景设置
  • maxLineGap:同一方向上两条线段判定为一条线段的最大允许间隔(断裂),超过了设定值,则把两条线段当成一条线段,值越大,允许线段上的断裂越大,越有可能检出潜在的直线段

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

由于图片画质因素,很多看似是直线的也未检测出是直线,还有许多散碎的直线并没有连接成长线。有待后续研究解决。
python+opencv实现霍夫变换检测直线_第3张图片

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, 110)
result = cut_img.copy()
# lines1 = lines[:, 0, :]  # 提取为为二维
# for rho, theta in lines1[:]:
#     a = np.cos(theta)
#     b = np.sin(theta)
#     x0 = a * rho
#     y0 = b * rho
#     x1 = int(x0 + 1000 * (-b))
#     y1 = int(y0 + 1000 * a)
#     x2 = int(x0 - 1000 * (-b))
#     y2 = int(y0 - 1000 * a)
#     cv2.line(result, (x1, y1), (x2, y2), (255, 0, 0), 1)

minLineLength = 70  # height/32
maxLineGap = 2  # height/40
lines = cv2.HoughLinesP(edges, 1, np.pi / 180, 50, minLineLength=minLineLength, maxLineGap=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)

python+opencv实现霍夫变换检测直线_第4张图片

import cv2
import numpy as np
img = cv2.imread("origin.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, 110)
result = cut_img.copy()
# lines1 = lines[:, 0, :]  # 提取为为二维
# for rho, theta in lines1[:]:
#     a = np.cos(theta)
#     b = np.sin(theta)
#     x0 = a * rho
#     y0 = b * rho
#     x1 = int(x0 + 1000 * (-b))
#     y1 = int(y0 + 1000 * a)
#     x2 = int(x0 - 1000 * (-b))
#     y2 = int(y0 - 1000 * a)
#     cv2.line(result, (x1, y1), (x2, y2), (255, 0, 0), 1)

minLineLength = 5  # height/32
maxLineGap = 0  # height/40
lines = cv2.HoughLinesP(edges, 1, np.pi / 180, 80, minLineLength=minLineLength, maxLineGap=maxLineGap)
line1 = lines[:, 0, :]  # 提取为二维

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

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

区别是
line1 = lines[:, 0, :] # 提取为二维

你可能感兴趣的:(opencv,opencv,python)