我还有改变的可能性 一想起这一点 我就心潮澎湃
使用霍夫直线变换做直线检测,前提条件:边缘检测已经完成
# 标准霍夫线变换
cv2.HoughLines(image, rho, theta, threshold, lines=None, srn=None, stn=None, min_theta=None, max_theta=None)
# 统计概率霍夫线变换
cv2.HoughLinesP(image, rho, theta, threshold, lines=None, minLineLength=None, maxLineGap=None)
import cv2
import numpy as np
# 标准霍夫线变换
def line_detection_demo(image):
# 灰度图像
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 提取边缘
edges = cv2.Canny(gray, 50, 150, apertureSize=3)
lines = cv2.HoughLines(edges, 1, np.pi/180, 160)
for line in lines:
rho, theta = line[0] # line[0]存储的是点到直线的极径和极角,其中极角是弧度表示的
a = np.cos(theta) # 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(image, (x1, y1), (x2, y2), (0, 0, 255), 2)
cv2.imshow("image_lines", image)
# 统计概率霍夫线变换
def line_detect_possible_demo(image):
gray = cv2.cvtColor(image, cv2.COLOR_BGRA2GRAY)
edges = cv2.Canny(gray, 50, 150, apertureSize=3)
lines = cv2.HoughLinesP(edges, 1, np.pi / 180, 100, minLineLength=50, maxLineGap=10)
for line in lines:
x1, y1, x2, y2 = line[0]
cv2.line(image, (x1, y1), (x2, y2), (0, 0, 255), 2)
cv2.imshow("line_detect_possible", image)
if __name__ == "__main__":
src = cv2.imread(r"./test/041.png")
cv2.imshow("image", src)
line_detection_demo(src)
line_detect_possible_demo(src)
cv2.waitKey(0)
cv2.destroyAllWindows()
运行效果如下:
cv2.HoughCircles(image, method, dp, minDist, circles=None, param1=None, param2=None, minRadius=None, maxRadius=None)
import cv2 as cv
import numpy as np
# 霍夫圆检测
def detect_circles_demo(image):
# 霍夫圆检测对噪声敏感 边缘保留滤波EPF 消除噪声
dst = cv.pyrMeanShiftFiltering(image, 10, 105) # 均值偏移滤波
cimage = cv.cvtColor(dst, cv.COLOR_RGB2GRAY)
# 输入图像 方法 走步长 最小距离 边缘提取的低值
circles = cv.HoughCircles(cimage, cv.HOUGH_GRADIENT, 1, 20, param1=50, param2=30, minRadius=0, maxRadius=0)
circles = np.uint16(np.around(circles)) # 把circles包含的圆心和半径的值变成整数
for i in circles[0, :]:
cv.circle(image, (i[0], i[1]), i[2], (0, 0, 255), 2) # 画圆
cv.circle(image, (i[0], i[1]), 2, (255, 0, 0), 2) # 画圆心
cv.imshow("circles", image)
if __name__ == "__main__":
src = cv.imread(r"./test/035.png")
cv.imshow('input_image', src)
detect_circles_demo(src)
cv.waitKey(0)
cv.destroyAllWindows()
运行效果如下:
"""
cv2.findContours(image, mode, method, contours, hierarchy, offset)
参数:
1 要寻找图像的轮廓 只能传入二值图像,不是灰度图像
2 轮廓的检索模式,有四种:
cv2.RETR_EXTERNAL 表示只检测外轮廓
cv2.RETR_LIST 检测的轮廓不建立等级关系
cv2.RETR_CCOMP 建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层
cv2.RETR_TREE 建立一个等级树结构的轮廓
3 轮廓的近似办法
cv2.CHAIN_APPROX_NONE存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1
cv2.CHAIN_APPROX_SIMPLE压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息
返回值:
contours:一个列表,每一项都是一个轮廓,不会存储轮廓所有的点,只存储能描述轮廓的点
hierarchy:一个ndarray, 元素数量和轮廓数量一样,
每个轮廓contours[i]对应4个hierarchy元素hierarchy[i][0] ~hierarchy[i][3],
分别表示后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号,如果没有对应项,则该值为负数
"""
"""
# 函数cv2.drawContours(image, contours, contourIdx, color, thickness, lineType, hierarchy, maxLevel, offset)
# 第一个参数是一张图片,可以是原图或者其他。
# 第二个参数是轮廓,也可以说是cv2.findContours()找出来的点集,一个列表。
# 第三个参数是对轮廓(第二个参数)的索引,当需要绘制独立轮廓时很有用,若要全部绘制可设为-1。
# 接下来的参数是轮廓的颜色和线宽
"""
import cv2
def contours_demo(image):
dst = cv2.GaussianBlur(image, (3, 3), 0)
gray = cv2.cvtColor(dst, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
# 得到修改后的图像,轮廓点集 各层轮廓的索引
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for i, contour in enumerate(contours):
# 绘制轮廓 第几个 颜色 线宽
cv2.drawContours(image, contours, i, (0, 0, 255), -1)
print(i)
cv2.imshow("detect contours", image)
if __name__ == "__main__":
img = cv2.imread(r"./test/042.png")
cv2.namedWindow("input image", cv2.WINDOW_AUTOSIZE)
cv2.imshow("input image", img)
contours_demo(img)
cv2.waitKey(0)
cv2.destroyAllWindows()
运行效果如下:
绘制轮廓时,线宽设置为-1,实现填充,效果如下:
通过Canny算法获取二值图像,再进行轮廓发现
import cv2
def edge_demo(image):
# 高斯模糊 降低噪声
blurred = cv2.GaussianBlur(image, (3, 3), 0)
# 转为灰度图像
gray = cv2.cvtColor(blurred, cv2.COLOR_BGR2GRAY)
# 计算x y 方向梯度
grad_x = cv2.Sobel(gray, cv2.CV_16SC1, 1, 0)
grad_y = cv2.Sobel(gray, cv2.CV_16SC1, 0, 1)
edge_output = cv2.Canny(grad_x, grad_y, 50, 100)
return edge_output
def contours_demo(image):
binary = edge_demo(image)
# 得到修改后的图像,轮廓点集 各层轮廓的索引
contours, hierarchy = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for i, contour in enumerate(contours):
# 绘制轮廓 第几个 颜色 线宽
cv2.drawContours(image, contours, i, (0, 0, 255), 2)
print(i)
cv2.imshow("detect contours", image)
if __name__ == "__main__":
img = cv2.imread(r"./test/036.png")
cv2.namedWindow("input image", cv2.WINDOW_AUTOSIZE)
cv2.imshow("input image", img)
contours_demo(img)
cv2.waitKey(0)
cv2.destroyAllWindows()
运行效果如下:
作者:叶庭云 微信公众号:修炼Python CSDN:https://yetingyun.blog.csdn.net/ 本文仅用于交流学习,未经作者允许,禁止转载,更勿做其他用途,违者必究。 觉得文章对你有帮助、让你有所收获的话,期待你的点赞呀,不足之处,也可以在评论区多多指正。