Я занимался веселым проектом: Решением судоку из входного изображения с использованием OpenCV (как в Google Goggles и т. Д.). И я выполнил задание, но в конце обнаружил небольшую проблему, ради которой я пришел сюда.
Я занимался программированием с использованием Python API OpenCV 2.3.1.
Ниже то, что я сделал:
- Прочитайте изображение
- Найти контуры
- Выберите тот, который имеет максимальную площадь (и также несколько эквивалентен квадрату).
Найдите угловые точки.
например, дано ниже:
( Обратите внимание, что зеленая линия правильно совпадает с истинной границей судоку, поэтому судоку можно правильно деформировать . Проверьте следующее изображение)
деформировать изображение в идеальный квадрат
например, изображение:
Выполнить OCR (для которого я использовал метод, который я дал в Простом распознавании цифр OCR в OpenCV-Python )
И метод работал хорошо.
Проблема:
Проверьте это изображение.
Выполнение шага 4 на этом изображении дает следующий результат:
Красная линия - это оригинальный контур, который является истинным контуром границы судоку.
Нарисованная зеленая линия представляет собой приблизительный контур, который будет контуром искривленного изображения.
Что, конечно, есть разница между зеленой линией и красной линией на верхнем краю судоку. Таким образом, пока я не искажаю исходную границу судоку.
Мой вопрос :
Как можно деформировать изображение на правильной границе судоку, то есть на красной линии ИЛИ как убрать разницу между красной линией и зеленой линией? Есть ли способ для этого в OpenCV?
источник
Ответы:
У меня есть решение, которое работает, но вам придется самостоятельно перевести его на OpenCV. Это написано в Mathematica.
Первый шаг - настроить яркость изображения, разделив каждый пиксель в результате операции закрытия:
Следующий шаг - найти область судоку, чтобы я мог игнорировать (маскировать) фон. Для этого я использую анализ связанных компонентов и выбираю компонент с наибольшей выпуклой областью:
Заполняя это изображение, я получаю маску для сетки судоку:
Теперь я могу использовать производный фильтр 2-го порядка, чтобы найти вертикальные и горизонтальные линии в двух отдельных изображениях:
Я снова использую анализ связанных компонентов, чтобы извлечь линии сетки из этих изображений. Линии сетки намного длиннее цифр, поэтому я могу использовать длину штангенциркуля для выбора только компонентов, соединенных линиями сетки. Сортируя их по положению, я получаю маски 2х10 для каждой вертикальной / горизонтальной линии сетки на изображении:
Затем я беру каждую пару вертикальных / горизонтальных линий сетки, расширяю их, вычисляю пересечение пиксель за пикселем и вычисляю центр результата. Эти точки являются пересечениями линий сетки:
Последний шаг - определить две функции интерполяции для отображения X / Y через эти точки и преобразовать изображение с помощью этих функций:
Все операции являются основной функцией обработки изображений, поэтому это должно быть возможно и в OpenCV. Преобразование изображений на основе сплайнов может быть сложнее, но я не думаю, что оно вам действительно нужно. Вероятно, использование трансформации перспективы, которую вы используете сейчас в каждой отдельной ячейке, даст достаточно хорошие результаты.
источник
Ответ Ники решил мою проблему, но он был в Mathematica. Поэтому я подумал, что мне следует дать здесь адаптацию OpenCV. Но после реализации я увидел, что код OpenCV намного больше, чем код mathematica nikie. Кроме того, я не смог найти метод интерполяции, сделанный nikie в OpenCV (хотя это можно сделать с помощью scipy, я скажу это, когда придет время).
1. Предварительная обработка изображения (операция закрытия)
Результат:
2. Найти площадь Судоку и создать изображение маски
Результат:
3. Нахождение вертикальных линий
Результат:
4. Нахождение горизонтальных линий
Результат:
Конечно, этот не так хорош.
5. Нахождение точек сетки
Результат:
6. Исправление дефектов
Здесь Ники делает какую-то интерполяцию, о которой я мало что знаю. И я не мог найти соответствующую функцию для этого OpenCV. (может быть, это там, я не знаю).
Проверьте этот SOF, который объясняет, как сделать это с помощью SciPy, который я не хочу использовать: Преобразование изображений в OpenCV
Итак, здесь я взял 4 угла каждого квадрата и применил перспективу деформации к каждому.
Для этого сначала найдем центроиды.
Но получившиеся центроиды не будут отсортированы. Проверьте ниже изображение, чтобы увидеть их порядок:
Таким образом, мы сортируем их слева направо, сверху вниз.
Теперь смотрите ниже их порядок:
Наконец мы применяем преобразование и создаем новое изображение размером 450x450.
Результат:
Результат почти такой же, как у nikie, но длина кода велика. Может быть, есть лучшие методы, но до тех пор это работает хорошо.
С уважением ARK.
источник
Вы можете попытаться использовать какое-то сеточное моделирование произвольной деформации. А поскольку судоку уже является сеткой, это не должно быть слишком сложно.
Таким образом, вы можете попытаться определить границы каждого субрегиона 3х3, а затем деформировать каждый регион в отдельности. Если обнаружение пройдет успешно, это даст вам лучшее приближение.
источник
Я хочу добавить, что описанный выше метод работает только тогда, когда доска судоку стоит прямо, в противном случае проверка соотношения высоты / ширины (или наоборот), скорее всего, провалится, и вы не сможете обнаружить края судоку. (Я также хочу добавить, что если линии, которые не перпендикулярны границам изображения, операции sobel (dx и dy) будут по-прежнему работать, так как линии по-прежнему будут иметь края относительно обеих осей.)
Чтобы иметь возможность обнаруживать прямые линии, вы должны работать с контурным или пиксельным анализом, таким как contourArea / boundingRectArea, верхняя левая и нижняя правая точки ...
Изменить: мне удалось проверить, образует ли набор контуров линию или нет, применив линейную регрессию и проверив ошибку. Однако линейная регрессия выполняется плохо, когда наклон линии слишком велик (т. Е.> 1000) или очень близок к 0. Поэтому применение вышеуказанного теста отношения (в ответе с наибольшим количеством голосов) перед линейной регрессией логично и действительно работает для меня.
источник
Чтобы удалить незапятнанные углы, я применил гамма-коррекцию со значением гаммы 0,8.
Красный круг нарисован, чтобы показать недостающий угол.
Код является:
Это в дополнение к ответу Абида Рахмана, если отсутствуют некоторые угловые точки.
источник
Я думал, что это отличный пост и отличное решение от ARK; очень хорошо продуман и объяснен.
Я работал над аналогичной проблемой, и построил все это. Были некоторые изменения (например, xrange to range, аргументы в cv2.findContours), но это должно работать из коробки (Python 3.5, Anaconda).
Это компиляция вышеперечисленных элементов с добавлением некоторого недостающего кода (т. Е. Маркировка точек).
источник