OpenCV. Отрисовка горизонтальной линии и её координаты

Lancellot

Новичок
Пользователь
Апр 30, 2020
22
4
3
Пытаюсь обрезать изображение по границе горизонтальной линии. Нужно обрезать всё то что выше линии. (см. изображение)

Безымянный.png

Python:
import cv2

font = cv2.FONT_HERSHEY_COMPLEX
image = cv2.imread("Screens/MKA-05-732-0-1.png")
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (15,1))
detected_lines = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, horizontal_kernel, iterations=2)

cnts = cv2.findContours(detected_lines, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]



for c in cnts:
    cv2.drawContours(image, [c], -1, (36,255,12), 3)


cv2.imshow('image', image)
cv2.waitKey()

Вопрос: как-то можно узнать координаты по Y горизонтальной линии? Чтобы потом я по значению Y выполнил .crop
 

Вложения

  • MKA-05-732-0-1.png
    MKA-05-732-0-1.png
    43,9 КБ · Просмотры: 4
  • Мне нравится
Реакции: Student

stud_55

Модератор
Команда форума
Модератор
Апр 3, 2020
1 522
672
113
Можно так попробовать:
Python:
import cv2

font = cv2.FONT_HERSHEY_COMPLEX
image = cv2.imread("MKA-05-732-0-1.png")
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (15,1))
detected_lines = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, horizontal_kernel, iterations=2)

cnts = cv2.findContours(detected_lines, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]

epsilon = cv2.arcLength(cnts[-1], True)
approx = cv2.approxPolyDP(cnts[-1], epsilon, True)


# тут будут координаты верхней линии (cnts[-1])
# для данного изображения [[[0 83]]]
print(approx) 

for c in cnts:
    cv2.drawContours(image, [c], -1, (0, 255, 0), 3)


cv2.imshow('image', image)
cv2.waitKey()
 
  • Я влюблен!
  • Мне нравится
Реакции: Student и Lancellot

stud_55

Модератор
Команда форума
Модератор
Апр 3, 2020
1 522
672
113
Как мне значению 130 присвоить переменную? y = approx[0] не даёт значение 130.
Можно так например:
Python:
y = approx[0][0][1]
print(y)
Я так понял Вы добавили только две строчки:
Первая строчка считает периметр контура верхней линии (cnts[-1]).
Вторая делает аппроксимацию (упрощение) контура методом Дугласа - Пекера и возвращает массив координат упрощенной формы. В данном случае только одну точку. Вот ссылка на документацию по теме: ссылка.
Потому что это контур верхней линии, cnts[0] будет контуром нижней.
 
  • Мне нравится
Реакции: Lancellot

stud_55

Модератор
Команда форума
Модератор
Апр 3, 2020
1 522
672
113
Прошу вашего совета.
Если при помощи верхней горизонтальной линии удалось обрезать изображение, удалив при этом "шумный контент" сверху, то как зачистить тот контент, что внизу под блоком почтового адреса?
Нужно как-то определить координаты верхней точки нижнего контента. Например, можно получить координаты контуров текста подходящих под определенное условие (например для данной картинки x < 100 и y > 215), а потом выбрать из них наивысшую координату (с минимальным значением y). И по этому значению уже обрезать картинку снизу.
Вот примерный код (переделанный пример из интернета):
Python:
import numpy as np
import cv2


font = cv2.FONT_HERSHEY_COMPLEX
img2 = cv2.imread('MKA.png', cv2.IMREAD_COLOR)
img = cv2.imread('MKA.png', cv2.IMREAD_GRAYSCALE)
_, threshold = cv2.threshold(img, 110, 255, cv2.THRESH_BINARY)

contours, _ = cv2.findContours(threshold, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

min_value = None

for cnt in contours:
    approx = cv2.approxPolyDP(cnt, cv2.arcLength(cnt, True), True)
    cv2.drawContours(img2, [approx], 0, (0, 0, 255), 5)
    n = approx.ravel()
    i = 0

    for j in n:
        if(i % 2 == 0):
            x = n[i]
            y = n[i + 1]

            # вот здесь задаем условие для нужных координат
            if x < 100 and y > 215:
                if min_value is None:
                    min_value = y
                elif y < min_value:
                    min_value = y

# результат
print(min_value) # 291

cv2.imshow('image2', img2)
cv2.waitKey()
 
  • Мне нравится
Реакции: Lancellot

Lancellot

Новичок
Пользователь
Апр 30, 2020
22
4
3
Можно так попробовать:

Действительно всё работает! Спасибо.


Код:
print(approx)
Выдаёт:
Код:
[[[  0 130]]]

Как мне значению 130 присвоить переменную? y = approx[0] не даёт значение 130.


Я так понял Вы добавили только две строчки:
Python:
epsilon = cv2.arcLength(cnts[-1], True)
approx = cv2.approxPolyDP(cnts[-1], epsilon, True)

Я гуглил, но всё расписано очень научно и с математических уклоном. Для гуманитария весьма сложно :D
Если Вам не трудно, то сможете кратко пояснить их суть? и почему cnts[-1], а не 0?
 
Последнее редактирование:

Lancellot

Новичок
Пользователь
Апр 30, 2020
22
4
3
Можно так попробовать:
Прошу вашего совета.
Если при помощи верхней горизонтальной линии удалось обрезать изображение, удалив при этом "шумный контент" сверху, то как зачистить тот контент, что внизу под блоком почтового адреса?
 

Вложения

  • MKA-20-9698-0-1.png
    MKA-20-9698-0-1.png
    56,7 КБ · Просмотры: 4

Lancellot

Новичок
Пользователь
Апр 30, 2020
22
4
3
Нужно как-то определить координаты верхней точки нижнего контента. Например, можно получить координаты контуров текста подходящих под определенное условие (например для данной картинки x < 100 и y > 215)

Метод рабочий! Но , к сожалению, если есть разрывы между строками, то даёт осечку☹

А что если, реализовать такую логику:

1) Распознать текст, на выходе получаю:
Код:
text = "Ленину В.И.
ул. Крупской, д. 12, кв. 22
141500, Москва

Шумный текст, шумный текст"

2) Определить нижнюю границу наличием строки с индексом.
(т.е. всё что ниже строки, содержащий индекс - удалять. Индекс всегда будет стоять на самой нижней строке)
Идущие подряд 6 чисел - есть индекс:
Python:
zip_code =  re.findall(r"\b(\d{6})\b", text)

Нужно после строки с индексом вставить новую строку (по типу прожать Enter) и туда вбить слово-маркер: УДАЛИТЬ.


3) Затем уже, используя Ваш код с предыдущей моей темы, можно вырезать необходимый контент:
Python:
i1 = s.index('МАРКЕР_1')
l1 = len('МАРКЕР_1')
i2 = s.index('УДАЛИТЬ')

s = s[i1 + l1: i2].strip()

Вопросы у меня возникают только касательно пункта 2.
Можете подсказать? Кидать весь код целиком не обязательно, только в рамках пункта.
 

stud_55

Модератор
Команда форума
Модератор
Апр 3, 2020
1 522
672
113
Вопросы у меня возникают только касательно пункта 2.
Есть два варианта:
Python:
def zip_code(text):
    zip_code = re.findall(r"\b(\d{6})\b", text)
    return bool(zip_code)


s = '''Ленину В.И.
ул. Крупской, д. 12, кв. 22
141500, Москва

Шумный текст, шумный текст'''

# первый вариант - добавить в текст маркер
s = s.split('\n') # разбиваем текст на строки
for i, item in enumerate(s): # проходим в цикле по ним
    if zip_code(item): # если индекс в строке
        break # останавливаем цикл

s.insert(i + 1, 'УДАЛИТЬ') # вставляем в следующую строку маркер

s = '\n'.join(s) # собираем текст из строк
print(s)

# второй вариант - обрезать текст сразу в цикле
s = s.split('\n') # разбиваем текст на строки
s2 = [] # список нужных строк
for i, item in enumerate(s): # цикл
    s2.append(item) # добавление строки в список
    if zip_code(item): # если в строке был индекс
        break # остановка цикла

s = '\n'.join(s2) # собираем текст из нужных строк
print(s)
 
  • Мне нравится
Реакции: Lancellot

Lancellot

Новичок
Пользователь
Апр 30, 2020
22
4
3
Есть два варианта:

Без осечек! ?
Второй вариант грамотен!
 
Последнее редактирование:

Форум IT Специалистов