Время прочтения: 4 мин.
Множество объектов на изображении можно опознать по их форме, например, печати в сканах документов, как правило, круглые, развороты паспорта четырёхугольные и т.д. Зная простые свойства искомого объекта и отсутствие этих свойств у других объектов изображения, можно свести задачу детектирования на изображении к задаче поиска объекта, чей контур содержит в себе какое-то количество углов. Говоря проще: хочешь найти на фотографии стола книгу – найди что-то с четырьмя сторонами.
Подобный подход был продемонстрирован в статье, где, с помощью преобразования Хафа для поиска окружностей, был произведён поиск печатей среди всего синего на скане документа. Данный подход можно использовать не только для анализа синих объектов на изображении, однако нужно быть готовым к подбору оптимальных параметров функции поиска.
Однако, преобразование Хафа для окружностей хорошо применимо, очевидно, к окружностям и не найдёт печати или другие объекты, содержащие углы. Для задачи поиска изображений с «угловатым» контуром может прекрасно подойти использование детектора границ Кэнни. Примерный алгоритм:
- преобразовать изображение в градации серого,
- размыть изображение, чтобы очистить от шумов,
- применить оператор Кэнни для поиска границ,
- «закрыть» границы объектов
- найти контуры объектов
Пронаблюдаем работу алгоритма по изложенным выше шагам, используя для обработки opencv:
Загрузим изображение и применим функцию для перевода в градации серого:
import cv2 as cv
src = cv.imread('test.jpg')
gr = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
В данном случае, границы объектов чёткие и тонкие, размытие сделает только хуже, поэтому этот шаг нам не требуется:
bl = cv.medianBlur(gr, 5)
Далее, выделим границы объектов оператором Кэнни:
canny = cv.Canny(bl, 10, 250)
«Закроем границы»:
kernel = cv.getStructuringElement(cv.MORPH_RECT, (7, 7))
closed = cv.morphologyEx(canny, cv.MORPH_CLOSE, kernel)
Найдём контуры и выделим нужные объекты:
contours = cv.findContours(closed.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)[0]
for cont in contours:
#сглаживание и определение количества углов
sm = cv.arcLength(cont, True)
apd = cv.approxPolyDP(cont, 0.02*sm, True)
#выделение контуров
if len(apd) == 4:
cv.drawContours(src, [apd], -1, (0,255,0), 4)
cv.imwrite('result.jpg', src)
Также, возможен и поиск окружностей, которые выделяются как восьмиугольники:
Можно искать и в более сложных условиях:
Таким образом, был реализован простой алгоритм для поиска на изображении объектов с замкнутыми контурами.