如何在选择图像中的轮廓时避免对图像(条形)进行分组?
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。没有给出想要的结果。以上是关于如何在选择图像中的轮廓时避免对图像(条形)进行分组?的主要内容,如果未能解决你的问题,请参考以下文章