如何在选择图像中的轮廓时避免对图像(条形)进行分组?

Posted

技术标签:

【中文标题】如何在选择图像中的轮廓时避免对图像(条形)进行分组?【英文标题】:How to avoid grouping images (bars) while selecting contours in an image? 【发布时间】:2019-05-27 14:31:48 【问题描述】:

我正在从图表图像中提取单个条形的长度。它在大多数情况下都可以正常工作,但在某些情况下,轮廓将 2 个条分组为 1,这对我的事业有害。我尝试了精明、扩张、侵蚀和配色方案的不同组合。它仅略微改善了结果。如何避免分组?这是完整的代码和一张图片。您可以使用此图像运行也可以查看问题。

from scipy.spatial import distance as dist
from imutils import perspective
from imutils import contours
import numpy as np
import argparse
import imutils
import cv2

def midpoint(ptA, ptB):
    return ((ptA[0] + ptB[0]) * 0.5, (ptA[1] + ptB[1]) * 0.5)

image = cv2.imread("somefile.png")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (7, 7), 0)

#edged=cv2.Laplacian(gray, cv2.CV_8U, gray, ksize=7)

edged = cv2.Canny(gray, 30, 50)
cv2.imwrite("test00.png", edged)
edged = cv2.dilate(edged, None, iterations=1)
cv2.imwrite("test01.png", edged)
edged = cv2.erode(edged, None, iterations=1)
cv2.imwrite("test02.png", edged)

cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)


pixelsPerMetric = 100

for c in cnts:
    orig = image.copy()
    box = cv2.minAreaRect(c)
    box = cv2.cv.BoxPoints(box) if imutils.is_cv2() else cv2.boxPoints(box)
    box = np.array(box, dtype="int")
    print(box)

    box = perspective.order_points(box)
    cv2.drawContours(orig, [box.astype("int")], -1, (0, 255, 0), 2)

    for (x, y) in box:
        cv2.circle(orig, (int(x), int(y)), 5, (0, 0, 255), -1)

    (tl, tr, br, bl) = box
    (tltrX, tltrY) = midpoint(tl, tr)
    (blbrX, blbrY) = midpoint(bl, br)

    (tlblX, tlblY) = midpoint(tl, bl)
    (trbrX, trbrY) = midpoint(tr, br)

    cv2.circle(orig, (int(tltrX), int(tltrY)), 5, (255, 0, 0), -1)
    cv2.circle(orig, (int(blbrX), int(blbrY)), 5, (255, 0, 0), -1)
    cv2.circle(orig, (int(tlblX), int(tlblY)), 5, (255, 0, 0), -1)
    cv2.circle(orig, (int(trbrX), int(trbrY)), 5, (255, 0, 0), -1)

    cv2.line(orig, (int(tltrX), int(tltrY)), (int(blbrX), int(blbrY)),
             (255, 0, 255), 2)
    cv2.line(orig, (int(tlblX), int(tlblY)), (int(trbrX), int(trbrY)),
             (255, 0, 255), 2)

    dA = dist.euclidean((tltrX, tltrY), (blbrX, blbrY))
    dB = dist.euclidean((tlblX, tlblY), (trbrX, trbrY))


    dimA = dA / pixelsPerMetric
    dimB = dB / pixelsPerMetric

    cv2.putText(orig, ":.1fin".format(dimA),
                (int(tltrX - 15), int(tltrY - 10)), cv2.FONT_HERSHEY_SIMPLEX,
                0.65, (255, 255, 255), 2)
    cv2.putText(orig, ":.1fin".format(dimB),
                (int(trbrX + 10), int(trbrY)), cv2.FONT_HERSHEY_SIMPLEX,
                0.65, (255, 255, 255), 2)

    cv2.imshow("Image", orig)
    cv2.waitKey(0)

【问题讨论】:

【参考方案1】:

这张图片很容易分割。条形的颜色正好是RGB=(245,222,179)。您可以使用 OpenCV 的函数inRange 来查找这种颜色的像素。在这个函数中,我们需要按照 BGR 顺序给出颜色,因为这是 OpenCV 默认读取图像的方式。在这里,如果图像使用 JPEG 压缩(这是有损的,因此会稍微改变像素值),我会选择一个稍大的范围:

image = cv2.imread("somefile.png")
mask = cv2.inRange(image, (177, 220, 243), (181, 224, 247))

这张图片mask 现在有完美分隔的条:

【讨论】:

试过了。不行。也许我错过了什么。 如果我直接在图像上使用自定义边缘检测功能而不使用扩张和侵蚀,它就可以工作。但这会导致很多额外的片段应该合并在一起。 @AmitAgarwal:它对我有用。正如我所怀疑的那样,我确实需要反转 RGB 三元组,但之后代码运行良好。请注意,您应该以彩色加载图像,而不是转换为灰度值。 面具的东西现在可以工作了。你是如何得到准确的像素颜色的?对于蓝色部分,我从颜色选择器站点获得了 R: 93 G: 188 B: 210。我正在为蓝色创建一个新蒙版,并添加两个蒙版以获得最终蒙版。但是,如果我通过对值使用减去和添加 2 个像素来指定范围,则不会生成蓝色蒙版。 mask_orange = cv2.inRange(image, (177, 220, 243), (181, 224, 247)) mask_blue = cv2.inRange(image, (208,186,91), (212,190,95) )) final_mask = mask_orange + mask_blue。没有给出想要的结果。

以上是关于如何在选择图像中的轮廓时避免对图像(条形)进行分组?的主要内容,如果未能解决你的问题,请参考以下文章

使用 OpenCv 和 Python 在线条上分组轮廓

如何在图像时间序列中一致地对轮廓进行编号?

利用OpenCV进行图像的轮廓检测

图像识别中的图像特征类别

在多列上分组时如何绘制条形图?

从 Swift 中的属性检查器列表更改条形按钮图像