Как надежно обнаружить 4 угла штрих-кода?

Я пытаюсь обнаружить этот штрих-код Code128 с помощью модуля Python + zbar:

(Ссылка для скачивания изображения здесь).

Это работает:

import cv2, numpy
import zbar
from PIL import Image 
import matplotlib.pyplot as plt

scanner = zbar.ImageScanner()
pil = Image.open("000.jpg").convert('L')
width, height = pil.size    
plt.imshow(pil); plt.show()
image = zbar.Image(width, height, 'Y800', pil.tobytes())
result = scanner.scan(image)

for symbol in image:
    print symbol.data, symbol.type, symbol.quality, symbol.location, symbol.count, symbol.orientation

но обнаружена только одна точка: (596, 210).

Если я применяю черно-белое пороговое значение:

pil = Image.open("000.jpg").convert('L')
pil = pil .point(lambda x: 0 if x<100 else 255, '1').convert('L')    

лучше, и у нас 3 точки: (596, 210), (482, 211), (596, 212). Но это добавляет еще одну сложность (нахождение оптимального порога - здесь 100 - автоматически для каждого нового изображения).

Тем не менее, у нас нет 4 углов штрих-кода.

Вопрос: как надежно найти 4 угла штрих-кода на изображении с помощью Python? (и, может быть, OpenCV или другая библиотека?)

Примечания:

  • Возможно, это отличный пример (но, к сожалению, не с открытым исходным кодом, как упоминалось в комментариях):

    Обнаружение объектов, очень быстрое и надежное обнаружение размытых одномерных штрих-кодов для приложений, работающих в реальном времени

    Обнаружение углов кажется отличным и очень быстрым, даже если штрих-код является лишь небольшой частью всего изображения (для меня это важно).

  • Интересное решение: обнаружение штрих-кода в реальном времени. в видео с Python и OpenCV, но есть ограничения метода (см. в статье: штрих-код должен быть крупным планом и т. д.), которые ограничивают потенциальное использование. Также я больше ищу готовую библиотеку для этого.

  • Интересное решение 2: Обнаружение штрих-кодов на изображениях с помощью Python и OpenCV но опять же, это не похоже на готовое решение, а скорее на то, что оно находится в стадии исследования. Действительно, я попробовал их код на этом изображении, но обнаружение не дало успешного результата. Следует отметить, что при обнаружении не учитываются никакие характеристики штрих-кода (факт наличия символ запуска/остановки и т. д.)

    import numpy as np
    import cv2
    image = cv2.imread("000.jpg")
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    gradX = cv2.Sobel(gray, ddepth = cv2.CV_32F, dx = 1, dy = 0, ksize = -1)
    gradY = cv2.Sobel(gray, ddepth = cv2.CV_32F, dx = 0, dy = 1, ksize = -1)
    gradient = cv2.subtract(gradX, gradY)
    gradient = cv2.convertScaleAbs(gradient)
    blurred = cv2.blur(gradient, (9, 9))
    (_, thresh) = cv2.threshold(blurred, 225, 255, cv2.THRESH_BINARY)
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (21, 7))
    closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
    closed = cv2.erode(closed, None, iterations = 4)
    closed = cv2.dilate(closed, None, iterations = 4)
    (_, cnts, _) = cv2.findContours(closed.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    c = sorted(cnts, key = cv2.contourArea, reverse = True)[0]
    rect = cv2.minAreaRect(c)
    box = np.int0(cv2.boxPoints(rect))
    cv2.drawContours(image, [box], -1, (0, 255, 0), 3)
    cv2.imshow("Image", image)
    cv2.waitKey(0)
    

person Basj    schedule 23.05.2018    source источник
comment
Здесь есть статья о том, что вы спрашиваете: pyimagesearch.com/2014/11/24/   -  person Ywapom    schedule 24.05.2018
comment
@Ywapom Я уже упоминал об этом в вопросе.   -  person Basj    schedule 24.05.2018
comment
Ваша цель в этом вопросе найти область штрих-кода, повернуть ее и передать в zbar? Ожидаете ли вы, что штрих-код будет одинакового размера на каждом изображении? Сколько вариаций вы ожидаете от своих изображений? Я предполагаю, что урезанная версия последнего фрагмента кода может работать, но вам, возможно, придется искать более одного найденного прямоугольника, чтобы найти штрих-код.   -  person bfris    schedule 24.05.2018
comment
Цель @bfris: 1) прочитать число, закодированное штрих-кодом, с помощью zbar, это работает уже все время и легко, но, прежде всего, 2) использовать углы верхнего левого штрих-кода листа бумаги и нижнего правого штрих-кода для выполнения перспективы исправление   -  person Basj    schedule 24.05.2018
comment
Вам нужна коррекция перспективы на штрих-кодах или на всем листе бумаги? Если это целый лист бумаги, то вам понадобится 4 уголка бумаги. На представленном вами образце фотографии не весь лист бумаги, и мы не можем увидеть второй штрих-код.   -  person bfris    schedule 24.05.2018
comment
Из всего листа бумаги @bfris. Верхний левый угол верхнего левого штрих-кода + верхний правый угол верхнего левого штрих-кода + нижний левый угол нижнего правого штрих-кода + нижний правый угол нижнего правого штрих-кода = 4 балла и этого достаточно для коррекции перспективы/гомографии (пробовал вручную введите координаты и все работает).   -  person Basj    schedule 24.05.2018


Ответы (1)


Решение 2 довольно хорошее. Критическим фактором, из-за которого он не работал с вашим изображением, был порог. Если вы уменьшите параметр 225 до 55, вы получите гораздо лучшие результаты.

Я переработал код, сделав некоторые изменения здесь и там. Исходный код подойдет, если вы предпочитаете. документация по OpenCV довольно хороша, и есть очень хорошие учебники по Python.

import numpy as np
import cv2

image = cv2.imread("barcode.jpg")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# equalize lighting
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
gray = clahe.apply(gray)

# edge enhancement
edge_enh = cv2.Laplacian(gray, ddepth = cv2.CV_8U, 
                         ksize = 3, scale = 1, delta = 0)
cv2.imshow("Edges", edge_enh)
cv2.waitKey(0)
retval = cv2.imwrite("edge_enh.jpg", edge_enh)

# bilateral blur, which keeps edges
blurred = cv2.bilateralFilter(edge_enh, 13, 50, 50)

# use simple thresholding. adaptive thresholding might be more robust
(_, thresh) = cv2.threshold(blurred, 55, 255, cv2.THRESH_BINARY)
cv2.imshow("Thresholded", thresh)
cv2.waitKey(0)
retval = cv2.imwrite("thresh.jpg", thresh)

# do some morphology to isolate just the barcode blob
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 9))
closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
closed = cv2.erode(closed, None, iterations = 4)
closed = cv2.dilate(closed, None, iterations = 4)
cv2.imshow("After morphology", closed)
cv2.waitKey(0)
retval = cv2.imwrite("closed.jpg", closed)

# find contours left in the image
(_, cnts, _) = cv2.findContours(closed.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
c = sorted(cnts, key = cv2.contourArea, reverse = True)[0]
rect = cv2.minAreaRect(c)
box = np.int0(cv2.boxPoints(rect))
cv2.drawContours(image, [box], -1, (0, 255, 0), 3)
print(box)
cv2.imshow("found barcode", image)
cv2.waitKey(0)
retval = cv2.imwrite("found.jpg", image)

edge.jpg введите здесь описание изображения

thresh.jpg введите здесь описание изображения

закрытый.jpg введите здесь описание изображения

found.jpgвведите здесь описание изображения

вывод из консоли:

[[596 249]
 [470 213]
 [482 172]
 [608 209]]
person bfris    schedule 24.05.2018
comment
Спасибо большое. Несколько замечаний: 1) If you drop the parameter 225 way down to 55: есть ли способ автоматически использовать лучший параметр thresh? Потому что изображения должны обрабатываться автоматически без установки какого-либо ручного параметра ползунка порогового значения. - person Basj; 25.05.2018
comment
2) Страница потенциально может содержать много текста, и фильтр морфологии также может обнаружить большой блок текста с высокой плотностью в виде прямоугольника. Итак, есть ли дополнительные функции, которые мы можем проверить, чтобы убедиться, что это штрих-код (например, расстояние между последовательными штрихами или символ начала/остановки), а не блок текста? - person Basj; 25.05.2018
comment
@Basj: шаг выравнивания CLAHE предназначен для более равномерного освещения. Но вы также можете использовать адаптивный порог. Что касается текста, то морфологические операции должны истончать текст. Если оставшиеся капли достаточно больше или меньше, вы можете отклонить их по размеру. Вы также можете передать прямоугольные части в zbar, чтобы увидеть, являются ли они штрих-кодами (похоже, это может быть дорого). Вы также можете попробовать сопоставление признаков и омографию. - person bfris; 25.05.2018
comment
Как этот метод можно применить для захвата видео в реальном времени? stackoverflow.com/questions/65078167/ - person e.iluf; 30.11.2020