python - 检测和隔离绿色网球 table 板上的线条

标签 python image opencv image-processing computer-vision

我正在尝试检测乒乓球板上的线,但在板(侧面)和板上也检测到一些“噪音”。

还有摆脱桌面上的品牌/措辞的问题。

基本上是想检测绿色表格上的白线。

我一直在看一些例子,但对 OpenCV 不熟悉并没有帮助:-)

Table Tennis Board Edges enter image description here

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/

相关文章:

python - 我正在尝试制作一个基于 "top down"图 block 的游戏。我不知道如何最初制作瓦片 map 来放置图像

python - 为什么我应该制作数据框的*浅*副本?

image - Flutter - 仅在第一次加载时无法加载 Assets

python - 如何跨 SQL Server 和 Postgres 比较两个表列哈希的哈希值?

java - 检测给定文件是否为图像并且是否为 java 中特定类型的有效图像

CSS Selector 无序列表图片名称

c++ - 如何在黑色区域opencv(C++)中找到矩形

c++ - DescrpitorExtractor::create ("SIFT") 返回 0?

opencv - 如何使用 ffmpeg 和 opencv 编辑帧的内容?

python - 按位置循环二维数组