Обнаружение краев карты с размытыми краями и различным фоном - PullRequest
1 голос
/ 03 марта 2020

Это моя тестовая фотография

enter image description here

Я пытаюсь найти края карты. Однако, как вы можете видеть, края несколько размыты.

Чтобы найти края, я сначала усиливаю контраст изображения, так что, надеюсь, размытые края будут менее размытыми и их будет намного легче найти: enter image description here Затем я использовал Gaussian Blur, чтобы немного сгладить его (я попытался удалить размытие по Гауссу, но детектор контуров обнаружил множество деталей на фоне + на карте).

Затем я использовал canny с «Dynami c thresholds» и получил следующий результат: enter image description here Как видите, я обнаружил, что я нашел все края карты (кроме левого, что было легко из-за темного фона) ). Есть ли надежный (я не хочу «перебирать» на этом изображении) метод, позволяющий находить прямые размытые края?

Найдены некоторые предложения здесь: Распознавание размытых краев Как чтобы найти точные угловые положения искаженного прямоугольника из размытого изображения в python? , но ни один из них не дал удовлетворительных краев.

Полный код:

def auto_canny(image, sigma=0.5):
    v = np.median(image)
    lower = int(max(0, (1.0 - sigma) * v))
    upper = int(min(255, (1.0 + sigma) * v))
    return cv2.Canny(image, lower, upper)

def add_contrast(img, contrast_level=8):
    lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)

    l, a, b = cv2.split(lab)

    clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(contrast_level, contrast_level))
    cl = clahe.apply(l)

    limg = cv2.merge((cl, a, b))

    final = cv2.cvtColor(limg, cv2.COLOR_LAB2BGR)

    return final

# ------------------------------------------ #
# FIND EDGES
# ------------------------------------------ #
img = add_contrast(img=img, contrast_level=8)

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imshow("gray", gray)

kernel_size = 5
blur_gray = cv2.GaussianBlur(gray, (kernel_size, kernel_size), 0)

edges = auto_canny(image=blur_gray) 

# Show images for testing
cv2.imshow('edges', edges)
cv2.waitKey(0)
cv2.destroyAllWindows()

Ответы [ 2 ]

3 голосов
/ 04 марта 2020

Это также не полное решение, но если красные части проблемные c, вы можете сначала закрасить эти части, используя функцию cv2.inpaint(). Затем вы можете применить оставшуюся часть вашего подхода, чтобы найти края карты.

# create an inpainting mask with "red-enough" pixels
mask = cv2.inRange(img_src_rgb, np.array([200,0,0]), np.array([255,50,50]))
# enlarge the mask to cover the borders
kernel = np.ones((3,3),np.uint8)
mask = cv2.dilate(mask,kernel,iterations = 1)
# inpaint the red parts using Navier-Stokes based approach
img_dst = cv2.inpaint(img_src, mask,50,cv2.INPAINT_NS)
cv2.imshow("no_red", img_dst)

Полученное изображение ниже.

enter image description here

РЕДАКТИРОВАТЬ: Теперь, когда мы знаем, о чем вы спрашиваете, ниже приведено полное решение.

После окраски вы можете применить преобразование Хафа, чтобы найти сильные прямые линии на изображении.

gray = cv2.cvtColor(img_dst, cv2.COLOR_RGB2GRAY)
edges = auto_canny(gray) # your auto_canny function, WITHOUT blur
lines = cv2.HoughLines(edges, 1, np.pi/90, 50)
for line in lines:
    rho,theta = line[0]
    a = np.cos(theta)
    b = np.sin(theta)
    x0 = a*rho
    y0 = b*rho
    x1 = int(x0 + 10000*(-b))
    y1 = int(y0 + 10000*(a))
    x2 = int(x0 - 10000*(-b))
    y2 = int(y0 - 10000*(a))
    cv2.line(img_dst,(x1,y1),(x2,y2),(0,255,0),1)

cv2.imwrite('linesDetected.jpg', img_dst)

Снова, результирующие строки приведены ниже.

enter image description here

1 голос
/ 04 марта 2020

Вы можете улучшить решение, заполнив части фона, используя cv2.floodFill.

Хорошая идея - улучшить контраст перед нахождением краев, но похоже, что он создает некоторые артефакты, которые затрудняют поиск краев.

Вот пример кода:

import numpy as np
import cv2


def auto_canny(image, sigma=0.5):
    v = np.median(image)
    lower = int(max(0, (1.0 - sigma) * v))
    upper = int(min(255, (1.0 + sigma) * v))
    return cv2.Canny(image, lower, upper)


img = cv2.imread('card.png')

h, w = img.shape[0], img.shape[1]

# Seed points for floodFill (use few points at each corner for improving robustness)
seedPoints = ((5, 5), (w-5, 5), (5, h-5), (w-5, h-5), 
              (w//2, 5), (w//2, h-5), (5, h//2), (w-5, h//2), 
              (w//4, 5), (w//4, h-5), (5, h//4),  (w-5, h//4),
              (w*3//4, 5), (w*3//4, h-5), (5, h*3//4),  (w-5, h*3//4))

# Fill parts of the background with black color
for seed in seedPoints:
    cv2.floodFill(img, None, seedPoint=seed, newVal=(0, 0, 0), loDiff=(2, 2, 2), upDiff=(2, 2, 2))

# ------------------------------------------ #
# FIND EDGES
# ------------------------------------------ #
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imshow("gray", gray)

kernel_size = 5
blur_gray = cv2.GaussianBlur(gray, (kernel_size, kernel_size), 0)

# Second, process edge detection use Canny.
edges = auto_canny(image=blur_gray)

# Show images for testing
cv2.imshow('edges', edges)
cv2.waitKey(0)
cv2.destroyAllWindows()

Результат:
enter image description here

Я знаю, что это не полное решение, но Надеюсь, это поможет ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...