Хотя это старо, это может, по крайней мере, помочь всем, у кого есть такая же проблема. В дополнение к ответу Натанси это должно позволить вам находить очень размытые углы с гораздо большей точностью:
Псевдокод
- Измените размер, если хотите, но не обязательно
- Преобразовать в оттенки серого
- Применение размытия или двусторонней фильтрации
- Примените порог Оцу, чтобы получить бинарное изображение
- Найдите контур, из которого состоит прямоугольник
- Примерный контур в виде прямоугольника
- Точки сближения - это углы вашего прямоугольника!
Код для этого
- Изменение размера:
Функция принимает новую ширину и высоту, поэтому я просто делаю изображение в 5 раз больше, чем сейчас.
img = cv2.resize(img, (img.shape[0] * 5, img.shape[1] * 5))
![измененный размер](https://i.stack.imgur.com/LoKaq.jpg)
- Преобразование оттенков серого:
просто преобразование в оттенки серого из цветового пространства OpenCV по умолчанию BGR.
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
а>
- Размытие/двусторонняя фильтрация.
Вы можете использовать любое количество методов, чтобы еще больше смягчить это изображение, если это необходимо. Может быть, размытие по Гауссу или, как предположила Натанси, двусторонний фильтр, но не нужно и то, и другое.
# choose one, or a different function
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
blurred = cv2.bilateralFilter(gray, 9, 75, 75)
![размыто](https://i.stack.imgur.com/ngxCh.jpg)
- Порог Оцу
Используя функцию порога, передайте 0
и 255
в качестве аргументов для порогового значения и максимального значения. Мы передаем 0
, потому что мы используем технику пороговой обработки cv2.THRESH_OTSU
, которая определяет значение для нас. Это возвращается вместе с самим порогом, но я просто установил его на _
, потому что он нам не нужен.
_, thresh = cv2.threshold(blurred, 0, 255, cv2.THRESH_OTSU)
![молоть](https://i.stack.imgur.com/hW38t.jpg)
- Поиск контура
Контуры — это гораздо больше, чем я объясню здесь, не стесняйтесь проверить документы. Нам важно знать, что он возвращает список контуров вместе с иерархией. Нам не нужна иерархия, поэтому она устанавливается на _
, и нам нужен только один найденный контур, поэтому мы устанавливаем contour = contours[0]
.
contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contour = contours[0]
![контур](https://i.stack.imgur.com/LEaGT.jpg)
- Примерный контур в виде прямоугольника
Сначала вычисляем периметр контура. Затем мы аппроксимируем ее функцией cv2.approxPolyDP
и сообщаем ей максимальное расстояние между исходной кривой и ее аппроксимацией функцией 0.05 * perimeter
. Возможно, вам придется поиграть с десятичной дробью для лучшего приближения.
approx
— это пустой массив формы (num_points, 1, 2)
, который в данном случае равен (4, 1, 2)
, потому что он нашел 4 угла прямоугольника.
Не стесняйтесь читать больше в документы.
perimeter = cv2.arcLength(contour, True)
approx = cv2.approxPolyDP(contour, 0.05 * perimeter, True)
- Найдите свой перекошенный прямоугольник!
Готово! Вот как можно нарисовать эти точки. Сначала мы рисуем круги, зацикливая их, затем захватывая координаты x и y, а затем рисуем сам прямоугольник.
# drawing points
for point in approx:
x, y = point[0]
cv2.circle(img, (x, y), 3, (0, 255, 0), -1)
# drawing skewed rectangle
cv2.drawContours(img, [approx], -1, (0, 255, 0))
![готовый продукт](https://i.stack.imgur.com/etBm8.jpg)
Готовый код
import cv2
img = cv2.imread("rect.png")
img = cv2.resize(img, (img.shape[0] * 5, img.shape[1] * 5))
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blurred = cv2.bilateralFilter(gray, 9, 75, 75)
_, thresh = cv2.threshold(blurred, 0, 255, cv2.THRESH_OTSU)
contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contour = contours[0]
perimeter = cv2.arcLength(contour, True)
approx = cv2.approxPolyDP(contour, 0.05 * perimeter, True)
for point in approx:
x, y = point[0]
cv2.circle(img, (x, y), 3, (0, 255, 0), -1)
cv2.drawContours(img, [approx], -1, (0, 255, 0))
person
Ani Aggarwal
schedule
14.02.2021