我正在尝试检测乒乓球板上的线,但在板(侧面)和板上也检测到一些“噪音”。
还有摆脱桌面上的品牌/措辞的问题。
基本上是想检测绿色表格上的白线。
我一直在看一些例子,但对 OpenCV 不熟悉并没有帮助:-)
import cv2
import numpy as np
img = cv2.imread("table.jpg")
imgS = cv2.resize(img, (960, 1024))
#
# # Convert to grayscale first beforeget edges of the image
kernel_size = 5
gray = cv2.cvtColor(imgS, cv2.COLOR_BGR2GRAY)
blur_gray = cv2.GaussianBlur(gray,(kernel_size, kernel_size), 0)
# get edges of the image
edges = cv2.Canny(blur_gray, 75, 150)
lines = cv2.HoughLinesP(edges, 1, np.pi/180, 50, maxLineGap=100)
# print(lines)
# draw "lines"
for line in lines:
x1, y1, x2, y2 = line[0]
# print(line[0])
# Draw the line on original image (img) and set color to blue and thickness 2
cv2.line(imgS, (x1, y1), (x2, y2), (0, 255,0), 2)
cv2.imshow("Edges", edges)
cv2.imshow("img", imgS)
cv2.waitKey(0)
cv2.destroyAllWindows()
最佳答案
这里有一个方法
- 将图像转换为灰度和高斯模糊
- Canny 边缘检测
- 创建蒙版以保持白线轮廓
- 使用垂直内核执行形态转换以隔离垂直线
- 使用水平内核执行形态变换以隔离水平线
- 使用
cv2.HoughLinesP()
检测线条 - 遍历蒙版并找到轮廓
- 在原始图像上绘制轮廓
Canny边缘检测
接下来我们使用一个特殊的垂直内核使用 cv2.getStructuringElement()
过滤掉水平线,只提取垂直线
vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,3))
remove_horizontal = cv2.morphologyEx(canny, cv2.MORPH_OPEN, vertical_kernel)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
dilate_vertical = cv2.morphologyEx(remove_horizontal, cv2.MORPH_CLOSE, kernel, iterations=5)
我们对水平内核做同样的事情,只提取水平线
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,1))
remove_vertical = cv2.morphologyEx(canny, cv2.MORPH_OPEN, horizontal_kernel)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9,9))
dilate_horizontal = cv2.morphologyEx(remove_vertical, cv2.MORPH_CLOSE, kernel, iterations=3)
我们将两者结合起来得到最终的掩码
最后我们在蒙版上找到轮廓并将其绘制在原始图像上。这是结果
import cv2
import numpy as np
image = cv2.imread('1.jpg')
image = cv2.resize(image, (960, 1024))
mask = np.zeros(image.shape, np.uint8)
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (3,3), 0)
canny = cv2.Canny(blur, 150, 255, 1)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
# Find Vertical Lines
# ------
vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,3))
remove_horizontal = cv2.morphologyEx(canny, cv2.MORPH_OPEN, vertical_kernel)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
dilate_vertical = cv2.morphologyEx(remove_horizontal, cv2.MORPH_CLOSE, kernel, iterations=5)
minLineLength = 10
maxLineGap = 150
lines = cv2.HoughLinesP(dilate_vertical,1,np.pi/180,100,minLineLength,maxLineGap)
for line in lines:
for x1,y1,x2,y2 in line:
cv2.line(mask,(x1,y1),(x2,y2),(255,255,255),3)
cv2.imwrite('vertical_mask.png', mask)
# ------
# Find Horizontal Lines
# ------
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,1))
remove_vertical = cv2.morphologyEx(canny, cv2.MORPH_OPEN, horizontal_kernel)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9,9))
dilate_horizontal = cv2.morphologyEx(remove_vertical, cv2.MORPH_CLOSE, kernel, iterations=3)
minLineLength = 10
maxLineGap = 300
horizontal_mask = np.zeros(image.shape, np.uint8)
lines = cv2.HoughLinesP(dilate_horizontal,1,np.pi/180,100,minLineLength,maxLineGap)
for line in lines:
for x1,y1,x2,y2 in line:
cv2.line(mask,(x1,y1),(x2,y2),(255,255,255),3)
cv2.line(horizontal_mask,(x1,y1),(x2,y2),(255,255,255),3)
cv2.imwrite('horizontal_mask.png', horizontal_mask)
# ------
mask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
cnts = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
cv2.drawContours(image, [c], -1, (36,255,12), 2)
cv2.imwrite('remove_vertical.png', remove_vertical)
cv2.imwrite('remove_horizontal.png', remove_horizontal)
cv2.imwrite('dilate_horizontal.png', dilate_horizontal)
cv2.imwrite('mask.png', mask)
cv2.imwrite('image.png', image)
cv2.waitKey()
笔记:其他可能的策略和想法
- 使用颜色阈值和
cv2.inRange()
来隔离白线。 - 要过滤掉网络,您可以使用上述方法的修改版本,但不使用
cv2.HoughLinesP()
,而是使用 Numpy 切片仅提取上半部分/下半部分并仅搜索对于使用图像顶部1/4
和底部1/4
的行。也许是这样的
top_half = remove_vertical[0:int(image.shape[0] * .25), 0:image.shape[1]]
bottom_half = remove_vertical[int(image.shape[0] * .75):image.shape[0], 0:image.shape[1]]
只隔离中线的策略
- 将图像转换为灰度和高斯模糊
- Canny 边缘检测
- 使用垂直内核执行形态转换
- 扩张以增强轮廓
- 使用轮廓区域查找轮廓并进行过滤
Canny边缘检测
接下来我们使用一个特殊的垂直内核使用 cv2.getStructuringElement()
过滤掉水平线,只提取垂直线
vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,9))
remove_horizontal = cv2.morphologyEx(canny, cv2.MORPH_OPEN, vertical_kernel)
最后,我们扩张以增强轮廓并使用最小阈值区域进行过滤。这是结果
import cv2
image = cv2.imread('1.jpg')
image = cv2.resize(image, (960, 1024))
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (7,7), 0)
canny = cv2.Canny(blur, 120, 255, 1)
vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,9))
remove_horizontal = cv2.morphologyEx(canny, cv2.MORPH_OPEN, vertical_kernel)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))
dilate = cv2.morphologyEx(remove_horizontal, cv2.MORPH_CLOSE, kernel)
cnts = cv2.findContours(dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
area = cv2.contourArea(c)
if area > 50:
cv2.drawContours(image, [c], -1, (36,255,12), 3)
cv2.imwrite('result.png', image)
cv2.imwrite('canny.png', canny)
cv2.imwrite('remove_horizontal.png', remove_horizontal)
cv2.waitKey()
关于python - 检测和隔离绿色网球 table 板上的线条,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57149788/