Вот мой подход.Я постараюсь быть как можно более подробным:
- Преобразование изображения в оттенки серого
- Выполнение обнаружения четных краев
- Удаление горизонтальных и вертикальных линий для выделения символов
- Выполнение морфологических операций для улучшения букв
- Поиск контуров
- Фильтрация контуров по площади контура и соотношению сторон
- Сортировка контуров слева направо для извлечения цифр по порядку
- Итерация по отсортированным контурам и извлечение ROI
Сначала мы выполняем обнаружение края Кэнни, используя cv2.Canny()
Следующей целью является удаление вертикальных и горизонтальных линий, которые мы можем выделить цифрами.Мы начинаем с создания различных ядер, каждое из которых нацелено на горизонтальную, вертикальную или общую ориентацию
vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,2))
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2,1))
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (3,3))
Мы начинаем с удаления горизонтальных линий с помощью cv2.erode()
Теперь мы расширили вертикальные линии с помощью cv2.dilate()
Далее мы удалим вертикальные линии
Теперь обратите внимание, что у нас почти ничего не осталось, поэтому мы должны восстановить цифры, расширив
Отсюда мы находим контуры, используя cv2.findContours()
.Мы фильтруем, используя cv2.contourArea()
и по соотношению сторон, чтобы получить ограничивающие рамки.
Теперь, чтобы извлечь цифры по порядку, мы используем imutils.contours.sort_contours()
Наконец, мы извлекаем ROI для каждой цифры и сохраняем изображение.Вот скриншот сохраненных областей интереса в следующем порядке:
import cv2
import numpy as np
from imutils import contours
image = cv2.imread('1.png')
original = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
canny = cv2.Canny(gray, 130, 255, 1)
vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,2))
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2,1))
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (3,3))
erode = cv2.erode(canny, vertical_kernel)
cv2.imshow('remove horizontal', erode)
dilate = cv2.dilate(erode, vertical_kernel, iterations=5)
cv2.imshow('dilate vertical', dilate)
erode = cv2.erode(dilate, horizontal_kernel, iterations=1)
cv2.imshow('remove vertical', erode)
dilate = cv2.dilate(erode, kernel, iterations=4)
cv2.imshow('dilate horizontal', dilate)
cnts = cv2.findContours(dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
digit_contours = []
for c in cnts:
area = cv2.contourArea(c)
peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.01 * peri, True)
x,y,w,h = cv2.boundingRect(approx)
aspect_ratio = w / float(h)
if (aspect_ratio >= 0.4 and aspect_ratio <= 1.3):
if area > 150:
ROI = original[y:y+h, x:x+w]
cv2.rectangle(image,(x,y),(x+w,y+h),(0,255,0),2)
digit_contours.append(c)
sorted_digit_contours = contours.sort_contours(digit_contours, method='left-to-right')[0]
contour_number = 0
for c in sorted_digit_contours:
x,y,w,h = cv2.boundingRect(c)
ROI = original[y:y+h, x:x+w]
cv2.imwrite('ROI_{}.png'.format(contour_number), ROI)
contour_number += 1
cv2.imshow('canny', canny)
cv2.imshow('image', image)
cv2.waitKey(0)