【问题标题】:Detect the green lines in this image and calculate their lengths检测此图像中的绿线并计算它们的长度
【发布时间】:2016-07-25 14:06:50
【问题描述】:

示例图片

当更多物体从背景中介入时,图像可能会更加嘈杂。现在我正在使用各种技术,使用 RGB 颜色空间来检测线条,但是当由于背景中的障碍物而导致颜色发生变化时,它会失败。我正在使用opencv和python。 我读过 HSV 更适合颜色检测​​和使用,但还没有成功。 我无法找到此问题的通用解决方案。在这个方向上的任何提示或线索都会有很大帮助。

【问题讨论】:

  • 我目前正在为您的问题编写代码。你能提供另一张图片吗?这些图像非常嘈杂。即使应用了去噪过滤器,仍然会有很多噪音。
  • 实际上图像可能更嘈杂。如果您愿意,我可以为您提供更多图片。顺便说一句,我注意到一件有趣的事情,当我将饱和度值增加到某个值以上(这个值在不同的图像中不同)时,线条会被删除,但仍然存在噪点。可能这是需要努力的事情!!!
  • 看,我今天将为您发布一个工作流程。如果可以为您提供代码,我会的。但是如果我没有写完代码,我会在稍后发布。
  • 您想同时检测细对角线,还是只想检测 4 条较粗的线?线的方向总是水平的还是可以是任何配置?当您说要检测线条时,您要检测它们的什么?长度?宽度?角度?位置?总数?
  • 我想检测 4 条较粗的线。方向通常是水平的,尽管有时它们可​​能有点倾斜。我想计算线的宽度和它们的垂直距离。

标签: python opencv image-processing rgb hsv


【解决方案1】:

仍在进行中

首先,RGB 图像由 3 个灰度图像组成。由于您需要绿色,您将只处理一个通道。绿色的那个。为此,您可以拆分图像,您可以使用b,g,r = cv2.split('Your Image')。如果您显示绿色通道,您将获得类似的输出:

之后,您应该使用所需的方式对图像进行阈值处理。在这种情况下,我更喜欢Otsu's thresholding。阈值化后的输出为:

很明显,经过阈值处理的图像非常嘈杂。所以执行erosion 会稍微降低噪音。降噪后的图像将类似于以下内容:

我尝试使用closing 代替dilation,但closing 保留了一些不需要的噪音。所以我分别执行erosion,然后是dilationdilation 之后的输出是:

注意: 你可以在形态学上做自己的事情。您可以使用opening 而不是我所做的。结果是主观的 一个人对另一个人。

现在您可以尝试以下两种方法之一:

1.斑点检测。 2。霍夫线变换。

待办事项

试试这两种方法,然后选择最好的。

【讨论】:

  • 谢谢奥萨马。我已经尝试过这些技术,但收效甚微。如果只考虑绿色部分,算法可以从背景中检测出绿色的东西。顺便说一句,您是否考虑过我在之前的评论中关于饱和度的观点。
  • @Abhyudai 对不起,我不明白你的意见。我不太明白。我在 rgb 颜色空间中对图像进行了操作,没​​关系。您也可以将其转换为 hsv,这将是一件好事。但对我来说,它在 rgb 中有效,所以为什么要更改色彩空间。我有一个问题,我的回答是否有帮助。到目前为止你有没有尝试过。完成后我会完成答案。
  • 如果您只使用绿色空间,您不认为背景中的对象(黄色(R + G))可能会妨碍您的工作流程吗?您的回答没有帮助,因为我在发布此问题之前已经使用了这些技术。该解决方案可能适用于某些图像,但我无法找到通用图像。如果您愿意,我可以为您提供更多样品。
  • @Abhyudai 好的,请为我提供另一个样本。试着在你的问题中说清楚,并说明你已经做了什么。我的工作仍在进行中,因为我想按照您所说的编写通用代码,但目前很难实现。
  • 我用过形态变换、otsu threshing、houghLines Transform、边缘检测、简单颜色掩蔽、斑点检测
【解决方案2】:

您应该使用您知道您正在尝试通过使用线霍夫变换来检测线的事实。 http://docs.opencv.org/2.4/doc/tutorials/imgproc/imgtrans/hough_lines/hough_lines.html

  • 当障碍物也看起来像一条线时,请使用您大致知道绿线方向的事实。
  • 如果您不知道线的方向,请使用具有相同方向的多条绿色线且只有一条线是障碍物的事实

这是我的意思的代码:

import cv2
import numpy as np

# Params
minLineCount = 300 # min number of point alogn line with the a specif orientation
minArea = 100

# Read img
img = cv2.imread('i.png')
greenChannel = img[:,:,1]

# Do noise reduction
iFilter = cv2.bilateralFilter(greenChannel,5,5,5)

# Threshold data
#ret,iThresh = cv2.threshold(iFilter,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
iThresh = (greenChannel > 4).astype(np.uint8)*255

# Remove small areas
se1 = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
iThreshRemove = cv2.morphologyEx(iThresh, cv2.MORPH_OPEN, se1)

# Find edges
iEdge = cv2.Canny(iThreshRemove,50,100)

# Hough line transform
lines = cv2.HoughLines(iEdge, 1, 3.14/180,75)

# Find the theta with the most lines
thetaCounter = dict()
for line in lines:
    theta = line[0, 1]
    if theta in thetaCounter:
        thetaCounter[theta] += 1
    else:
        thetaCounter[theta] = 1

maxThetaCount = 0
maxTheta = 0
for theta in thetaCounter:
    if thetaCounter[theta] > maxThetaCount:
        maxThetaCount = thetaCounter[theta]
        maxTheta = theta

# Find the rhos that corresponds to max theta
rhoValues = []
for line in lines:
    rho = line[0, 0]
    theta = line[0, 1]
    if theta == maxTheta:
        rhoValues.append(rho)

# Go over all the lines with the specific orientation and count the number of pixels on that line
# if the number is bigger than minLineCount draw the pixels in finaImage
lineImage = np.zeros_like(iThresh, np.uint8)
for rho in range(min(rhoValues), max(rhoValues), 1):
    a = np.cos(maxTheta)
    b = np.sin(maxTheta)
    x0 = round(a*rho)
    y0 = round(b*rho)
    lineCount = 0
    pixelList = []
    for jump in range(-1000, 1000, 1):
        x1 = int(x0 + jump * (-b))
        y1 = int(y0 + jump * (a))
        if x1 < 0 or y1 < 0 or x1 >= lineImage.shape[1] or y1 >= lineImage.shape[0]:
            continue
        if iThreshRemove[y1, x1] == int(255):
            pixelList.append((y1, x1))
            lineCount += 1

    if lineCount > minLineCount:
        for y,x in pixelList:
            lineImage[y, x] = int(255)

# Remove small areas

## Opencv 2.4
im2, contours, hierarchy = cv2.findContours(lineImage,cv2.RETR_CCOMP,cv2.CHAIN_APPROX_NONE )

finalImage = np.zeros_like(lineImage)
finalShapes = []
for contour in contours:
    if contour.size > minArea:
        finalShapes.append(contour)

cv2.fillPoly(finalImage, finalShapes, 255)
## Opencv 3.0
# output = cv2.connectedComponentsWithStats(lineImage, 8, cv2.CV_32S)
#
# finalImage = np.zeros_like(output[1])
# finalImage = output[1]
# stat = output[2]
# for label in range(output[0]):
#     if label == 0:
#         continue
#     cc = stat[label,:]
#     if cc[cv2.CC_STAT_AREA] < minArea:
#         finalImage[finalImage == label] = 0
#     else:
#         finalImage[finalImage == label] = 255

# Show image
#cv2.imwrite('finalImage2.jpg',finalImage)
cv2.imshow('a', finalImage.astype(np.uint8))
cv2.waitKey(0)

以及图像的结果:

【讨论】:

  • 您在识别线之前使用 OTSU 脱粒。如果线条的强度小于 OTSU 阈值,则会移除线条。此工作流程适用于这张图片,但不适用于大多数其他样本。
  • 我用 iThresh = (greenChannel > 10).astype(np.uint8)*255 之类的基本阈值替换了 OTSU 阈值,它仍然有效。请再发一张硬图,让我看看哪里有问题
  • 刚刚看到您添加了另一个示例,我将相应地修复我的代码
  • 我将代码更改为使用简单的阈值,最后进行了一些清理。
  • 我使用的是 opencv 2.4.9。您的代码可能使用 3.0。它不会对代码产生其他问题吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-02
  • 1970-01-01
  • 1970-01-01
  • 2023-04-08
  • 1970-01-01
相关资源
最近更新 更多