opencv2 Canny + findContours не работает на некоторых изображениях - PullRequest
0 голосов
/ 06 марта 2019

Я пытаюсь создать программу, которая будет обнаруживать и удалять границы на изображении, цель состоит в том, чтобы обнаружить документ на изображении и очистить его ...

Вот мой код:

import sys
import cv2
import numpy as np
import rect

image = cv2.imread('./test.jpg')

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.medianBlur(gray, 9)
ret, gray = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)

edges = cv2.Canny(gray, 10, 250)
contours, _ = cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contours = sorted(contours, key=cv2.contourArea, reverse=True)

#x,y,w,h = cv2.boundingRect(contours[0])
#cv2.rectangle(image,(x,y),(x+w,y+h),(0,0,255),0)

# get approximate contour
for c in contours:
    p = cv2.arcLength(c, True)
    approx = cv2.approxPolyDP(c, 0.02 * p, True)

    if len(approx) == 4:
        target = approx
        break


cv2.drawContours(image, [target], -1, (0, 255, 0), 2)
cv2.imwrite('./final.jpg', image)

Изображение teste.jpg: enter image description here

, но сейчас ... единственное, что он может найти:

enter image description here

... и по запросу, вот изображение, которое работает:

enter image description here

Ответы [ 2 ]

1 голос
/ 07 марта 2019

Как обсуждалось в чате, я бы посоветовал вам использовать Описание функций и соответствие для этого.По моему опыту, это быстрее, чем контуры, и вы сможете обойти проблемы с изменением освещения, перспектив и т. Д.

Вот что я пробовал:

import cv2
import numpy as np


def locater(image, source, num=0):
    def resize(im, new_width):
        r = float(new_width) / im.shape[1]
        dim = (new_width, int(im.shape[0] * r))
        return cv2.resize(im, dim, interpolation=cv2.INTER_AREA)
    #width = 300
    #source = resize(source, new_width=width)
    #image = resize(image, new_width=width)

    hsv = cv2.cvtColor(image, cv2.COLOR_BGR2LUV)
    image, u, v = cv2.split(hsv)

    hsv = cv2.cvtColor(source, cv2.COLOR_BGR2LUV)
    source, u, v = cv2.split(hsv)

    MIN_MATCH_COUNT = 10
    orb = cv2.ORB_create()
    kp1, des1 = orb.detectAndCompute(image, None)
    kp2, des2 = orb.detectAndCompute(source, None)

    flann = cv2.DescriptorMatcher_create(cv2.DescriptorMatcher_FLANNBASED)

    des1 = np.asarray(des1, dtype=np.float32)
    des2 = np.asarray(des2, dtype=np.float32)

    matches = flann.knnMatch(des1, des2, k=2)

    # store all the good matches as per Lowe's ratio test
    good = []
    for m, n in matches:
        if m.distance < 0.7 * n.distance:
            good.append(m)

    if len(good) >= MIN_MATCH_COUNT:
        src_pts = np.float32([kp1[m.queryIdx].pt for m in good]).reshape(-1, 1, 2)
        dst_pts = np.float32([kp2[m.trainIdx].pt for m in good]).reshape(-1, 1, 2)

        M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)
        matchesMask = mask.ravel().tolist()

        h,w = image.shape
        pts = np.float32([[0, 0], [0, h-1], [w-1, h-1], [w-1, 0]]).reshape(-1, 1, 2)
        dst = cv2.perspectiveTransform(pts, M)
        source_bgr = cv2.cvtColor(source, cv2.COLOR_GRAY2BGR)
        img2 = cv2.polylines(source_bgr, [np.int32(dst)], True, (0,0,255), 3, 
                             cv2.LINE_AA)
        cv2.imwrite("out"+str(num)+".jpg", img2)
    else:
        print("Not enough matches." + str(len(good)))
        matchesMask = None

    draw_params = dict(matchColor=(0, 255, 0), # draw matches in green color
                       singlePointColor=None,
                       matchesMask=matchesMask, # draw only inliers
                       flags=2)
    img3 = cv2.drawMatches(image, kp1, source, kp2, good, None, **draw_params)
    cv2.imwrite("ORB"+str(num)+".jpg", img3)

image = cv2.imread('contour.jpg')
source = cv2.imread('contour_source.jpg')
locater(source, image, num=1)

Исходное изображение:

Source

Результаты:

Result 1

Result 2

Некоторые примечания : Поскольку изображение source было не очень хорошим, гомография очень хорошая .Вы можете сделать его более точным, добившись лучшего качества изображения - отсканировав оригинал приличным сканером, изменив размеры изображения (я добавил функцию для этого) и используя другое цветовое пространство (здесь я использую LUV).

Надеюсь, это поможет!

0 голосов
/ 06 марта 2019

Если вы посмотрите документацию на docs.opencv.org , вы обнаружите, что в ней есть ряд параметров, которые вы можете указать, например:

  1. threshold1: первый порог для процедуры гистерезиса.
  2. threshold2: второй порог для процедуры гистерезиса.
  3. apertureSize: размер апертуры для оператора Собеля.
  4. L2gradient: флаг, указывающий, следует ли использовать более точную норму L2 для расчета величины градиента изображения (L2gradient=true) или достаточно ли значения по умолчанию L1 norm =|dI/dx|+|dI/dy| (L2gradient=false).

Я бы предложил поиграть с ними, чтобы получить желаемые результаты.

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