Как избежать группировки изображений (полос) при выборе контуров на изображении? - PullRequest
0 голосов
/ 27 мая 2019

Я извлекаю длину отдельных баров из изображения графика. В большинстве случаев он работает нормально, но в некоторых случаях контурная группа группирует 2 столбца как 1, что наносит ущерб моей причине. Я пробовал разные комбинации canny, dlate, erode и color layout Это немного улучшило результат. Как можно избежать группировки? Вот полный код и одно изображение. Вы можете запустить с помощью этого изображения тоже увидеть проблему. enter image description here

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, "{:.1f}in".format(dimA),
                (int(tltrX - 15), int(tltrY - 10)), cv2.FONT_HERSHEY_SIMPLEX,
                0.65, (255, 255, 255), 2)
    cv2.putText(orig, "{:.1f}in".format(dimB),
                (int(trbrX + 10), int(trbrY)), cv2.FONT_HERSHEY_SIMPLEX,
                0.65, (255, 255, 255), 2)

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

enter image description here

1 Ответ

1 голос
/ 28 мая 2019

Это изображение тривиально для сегмента.Цвет баров ровно 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 теперь имеет идеально разделенные полосы:

bars

...