Нахождение углов прямоугольника - PullRequest
2 голосов
/ 04 февраля 2020

Я пытаюсь получить углы этого прямоугольника:

this rectangle.

Я пытался использовать cv2.cornerHarris(rectangle, 2, 3, 0.04), но левые края не отображаются из-за яркости изображения, Я полагаю. Поэтому я попытался применить пороговое значение перед использованием cornerHarris, но на полученном изображении было много вершин по краям, что было невозможно отфильтровать углы.

Я знаю, что мне нужно отфильтровать его перед использованием cornerHarris, но Я не знаю как Может ли кто-нибудь помочь мне с этой проблемой?

Ps. Я уже пытался использовать размытие, но оно также не работает.

import cv2
import numpy as np
import matplotlib.pyplot as plt

rectangle = cv2.imread('rectangle.png', cv2.IMREAD_GRAYSCALE)
rectangle = np.where(rectangle > np.mean(rectangle), 255, 0).astype(np.uint8)

dst_rectangle = cv2.cornerHarris(rectangle, 2, 3, 0.04)
dst_rectangle = cv2.dilate(dst_rectangle, None)

mask = np.where(dst_rectangle > 0.01*np.max(dst_rectangle), 255, 0).astype(np.uint8)
points = np.nonzero(mask)

plt.imshow(dst_rectangle, cmap='gray')
plt.plot(points[1], points[0], 'or')
plt.show()

Ответы [ 4 ]

4 голосов
/ 05 февраля 2020

image image

Вот простой подход:

  • Получение бинарного изображения. Загружаем изображение, оттенки серого, гауссовский размытие, затем адаптивный порог.

  • Морфологические операции. Мы создаем прямоугольное angular ядро ​​и открываем его, чтобы удалить небольшой шум

  • Найти искаженный контур прямоугольника и нарисовать на маске. Найти контуры, определить повернутую ограничивающую рамку и нарисовать на пустой маске

  • Найти углы. Мы используем детектор углов Ши-Томази, уже реализованный как cv2.goodFeaturesToTrack, который предположительно показывает лучшие результаты по сравнению с детектором углов Харриса


Вот визуализация каждого шага:

Двоичное изображение

image

Морфинг открыт

image

Найдите повернутый контур прямоугольника и нарисуйте / заполните на пустой маске

image

Нарисуйте повернутый прямоугольник и углы, чтобы получить Sult

image

Угловые координаты

(448.0, 337.0)
(164.0, 332.0)
(452.0, 123.0)
(168.0, 118.0)

Код

import cv2
import numpy as np

# Load image, grayscale, Gaussian blur, adaptive threshold
image = cv2.imread("1.png")
mask = np.zeros(image.shape, dtype=np.uint8)
gray = 255 - cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (3,3), 0)
thresh = cv2.adaptiveThreshold(blur, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY_INV, 51, 3)

# Morph open
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=1)

# Find distorted rectangle contour and draw onto a mask
cnts = cv2.findContours(opening, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
rect = cv2.minAreaRect(cnts[0])
box = cv2.boxPoints(rect)
box = np.int0(box)
cv2.drawContours(image,[box],0,(36,255,12),2)
cv2.fillPoly(mask, [box], (255,255,255))

# Find corners on the mask
mask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
corners = cv2.goodFeaturesToTrack(mask, maxCorners=4, qualityLevel=0.5, minDistance=150)

for corner in corners:
    x,y = corner.ravel()
    cv2.circle(image,(x,y),8,(255,120,255),-1)
    print("({}, {})".format(x,y))

cv2.imshow("thresh", thresh)
cv2.imshow("opening", opening)
cv2.imshow("mask", mask)
cv2.imshow("image", image)
cv2.waitKey(0)
4 голосов
/ 04 февраля 2020

Я бы подошел к этому по-другому, получив углы повернутой ограничительной рамки контура после адаптивного порога. Вот мой код в Python / OpenCV.

Ввод:

enter image description here

import cv2
import numpy as np

# read image
img = cv2.imread("rectangle.png")

# convert img to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = 255-gray

# do adaptive threshold on gray image
thresh = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 17, 1)
thresh = 255-thresh

# apply morphology
kernel = np.ones((3,3), np.uint8)
morph = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
morph = cv2.morphologyEx(morph, cv2.MORPH_CLOSE, kernel)

# separate horizontal and vertical lines to filter out spots outside the rectangle
kernel = np.ones((7,3), np.uint8)
vert = cv2.morphologyEx(morph, cv2.MORPH_OPEN, kernel)
kernel = np.ones((3,7), np.uint8)
horiz = cv2.morphologyEx(morph, cv2.MORPH_OPEN, kernel)

# combine
rect = cv2.add(horiz,vert)

# thin
kernel = np.ones((3,3), np.uint8)
rect = cv2.morphologyEx(rect, cv2.MORPH_ERODE, kernel)

# get largest contour
contours = cv2.findContours(rect, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
for c in contours:
    area_thresh = 0
    area = cv2.contourArea(c)
    if area > area_thresh:
        area = area_thresh
        big_contour = c

# get rotated rectangle from contour
rot_rect = cv2.minAreaRect(big_contour)
box = cv2.boxPoints(rot_rect)
box = np.int0(box)
print(box)

# draw rotated rectangle on copy of img
rot_bbox = img.copy()
cv2.drawContours(rot_bbox,[box],0,(0,0,255),2)

# write img with red rotated bounding box to disk
cv2.imwrite("rectangle_thresh.png", thresh)
cv2.imwrite("rectangle_outline.png", rect)
cv2.imwrite("rectangle_bounds.png", rot_bbox)

# display it
cv2.imshow("IMAGE", img)
cv2.imshow("THRESHOLD", thresh)
cv2.imshow("MORPH", morph)
cv2.imshow("VERT", vert)
cv2.imshow("HORIZ", horiz)
cv2.imshow("RECT", rect)
cv2.imshow("BBOX", rot_bbox)
cv2.waitKey(0)


Предел изображения:

enter image description here

Извлеченная область прямоугольника:

enter image description here

Вращающаяся ограничивающая рамка на изображении:

enter image description here

Углы поворота ограничительной коробки:

[[446 335]
 [163 328]
 [168 117]
 [451 124]]


ДОПОЛНЕНИЕ:

Вот немного более короткая версия кода, которая достижима путем добавления некоторого размытия по Гауссу перед установкой порога.

import cv2
import numpy as np

# read image
img = cv2.imread("rectangle.png")

# convert img to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = 255-gray

# blur image
blur = cv2.GaussianBlur(gray, (3,3), 0)

# do adaptive threshold on gray image
thresh = cv2.adaptiveThreshold(blur, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 75, 2)
thresh = 255-thresh

# apply morphology
kernel = np.ones((5,5), np.uint8)
rect = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
rect = cv2.morphologyEx(rect, cv2.MORPH_CLOSE, kernel)

# thin
kernel = np.ones((5,5), np.uint8)
rect = cv2.morphologyEx(rect, cv2.MORPH_ERODE, kernel)

# get largest contour
contours = cv2.findContours(rect, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
for c in contours:
    area_thresh = 0
    area = cv2.contourArea(c)
    if area > area_thresh:
        area = area_thresh
        big_contour = c

# get rotated rectangle from contour
rot_rect = cv2.minAreaRect(big_contour)
box = cv2.boxPoints(rot_rect)
box = np.int0(box)
for p in box:
    pt = (p[0],p[1])
    print(pt)

# draw rotated rectangle on copy of img
rot_bbox = img.copy()
cv2.drawContours(rot_bbox,[box],0,(0,0,255),2)

# write img with red rotated bounding box to disk
cv2.imwrite("rectangle_thresh.png", thresh)
cv2.imwrite("rectangle_outline.png", rect)
cv2.imwrite("rectangle_bounds.png", rot_bbox)

# display it
cv2.imshow("IMAGE", img)
cv2.imshow("THRESHOLD", thresh)
cv2.imshow("RECT", rect)
cv2.imshow("BBOX", rot_bbox)
cv2.waitKey(0)


Изображение с порогом:

enter image description here

Извлеченная область прямоугольника:

enter image description here

Вращающаяся ограничивающая рамка на изображении:

enter image description here

Вращающиеся ограничительные углы:

(444, 335)
(167, 330)
(170, 120)
(448, 125)
2 голосов
/ 04 февраля 2020

Мне удалось найти 3 из 4 точек, 4-ую точку легко найти, учитывая остальные три точки, так как это прямоугольник. Вот мое решение:

import cv2
import numpy as np

img = cv2.imread('6dUIr.png',1)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

#smooth the image
kernel = np.ones((5,5),np.float32)/25
gray = cv2.filter2D(gray,-1,kernel)

#histogram equalization
clahe = cv2.createCLAHE(clipLimit=1.45, tileGridSize=(4,4))
cl1 = clahe.apply(gray)

#find edges
edges = cv2.Canny(cl1,4,100)

#find corners
dst = cv2.cornerHarris(edges,2,3,0.04)
#result is dilated for marking the corners, not important
dst = cv2.dilate(dst,None)
# Threshold for an optimal value, it may vary depending on the image.
img[dst>0.25*dst.max()]=[0,0,255]

cv2.imshow('edges', edges)
cv2.imshow('output', img)
# cv2.imshow('Histogram equalized', img_output)

cv2.waitKey(0)

Код имеет много жестко заданных порогов, но это хорошее начало.

2 голосов
/ 04 февраля 2020

Можно попробовать с адаптивным порогом . Тогда вы можете использовать cornerHarris, если вам нужны только углы, или в зависимости от того, что вам нужно делать дальше, вы также можете найти полезную findContours , которая возвращает список ограничивающих рамок

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