#python #opencv #image-processing #raspberry-pi
#python #opencv #обработка изображений #raspberry-pi
Вопрос:
Это конвейерная лента, и моя область интересов — оранжевая полоса:
У меня есть система камер, которая будет делать снимки конвейерной ленты с размещенными на ней продуктами. Количество изображений составляет 500-2000 изображений за один производственный цикл. Что мне нужно убедиться, так это то, что оранжевая полоса конвейерной ленты всегда свободна от каких-либо объектов и не загораживается, чтобы производство проходило гладко. Здесь больше контекста, но просто знайте, что на картинке мне нужно, чтобы оранжевая полоса была оранжевой, и если ее нет, это означает, что она заблокирована.
Итак, мне нужна программа, которая могла бы считывать изображения и анализировать обе оранжевые полоски на картинке, чтобы при обнаружении чего-либо, загораживающего полосу, она отправляла сообщение об ошибке. Я имею в виду, что программа будет иметь прямоугольники вверху и внизу изображения, где находятся оранжевые полосы, и когда это будет закрыто, на изображении появится сообщение об ошибке.
Я понятия не имею, как называется этот процесс, но в настоящее время я смотрю на преобразование Хафа, сопоставление шаблонов и определение цвета. Проблема, с которой я сталкиваюсь, заключается в том, что, поскольку оранжевая полоса непрерывна, код считывает многочисленные дубликаты на изображении, которые будут перекрывать друг друга. и все изображение было бы просто цветным.
Я бы хотел, чтобы она анализировалась просто в виде прямоугольника в верхней и нижней полосах, который составлял бы 2/3 длины изображения от центра. Пожалуйста, помогите, и если это непонятно, пожалуйста, не стесняйтесь запрашивать детали, которые вам нужны.
Отредактировано: добавлено изображение примера препятствия. Белые точки могут быть пылью или любыми примесями.
Это мой прогресс на данный момент:
Я хотел бы проанализировать область в красном прямоугольнике, только если это возможно.
Это код, который я использую:
import cv2
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib import colors
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('sample02.jpg') # Read image
img = cv2.resize(img, (672, 672)) # Resize image
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
lower_gray = np.array([0, 0, 0], np.uint8)
upper_gray = np.array([0, 0, 45], np.uint8)
mask_gray = cv2.inRange(hsv, lower_gray, upper_gray)
img_res = cv2.bitwise_and(img, img, mask = mask_gray)
cv2.imshow('detected.jpg', mask_gray)
cv2.imwrite('5.jpg',mask_gray)
cv2.waitKey(0)
cv2.destroyAllWindows()
Я могу изолировать полосы, и инородное вещество / препятствие показано четко
Это код, который я использовал:
# importing cv2
import cv2
import numpy as np
# Reading an image in default mode
img = cv2.imread('f06.bmp') # Read image
img = cv2.resize(img, (672, 672)) # Resize image
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
lower_gray = np.array([0, 0, 0], np.uint8)
upper_gray = np.array([0, 0, 45], np.uint8)
mask_gray = cv2.inRange(hsv, lower_gray, upper_gray)
# 1) Start coordinate (Top rectangle)
# represents the top left corner of rectangle
start_point = (0, 0)
# Ending coordinate
# represents the bottom right corner of rectangle
end_point = (672, 200)
# color in BGR
color = (0, 0, 0)
# Line thickness
thickness = -1
# 2) Start coordinate (Mid rectangle)
start_point2 = (0, 240)
# Ending coordinate
# represents the bottom right corner of rectangle
end_point2 = (672, 478)
# color in BGR
color2 = (0, 0, 0)
# Line thickness
thickness2 = -1
# 3) Start coordinate (Bottom rectangle)
start_point3 = (0, 515)
# Ending coordinate
# represents the bottom right corner of rectangle
end_point3 = (672, 672)
# color in BGR
color3 = (0, 0, 0)
# Line thickness
thickness3 = -1
# 4) Start coordinate (Left rectangle)
start_point4 = (0, 180)
# Ending coordinate
# represents the bottom right corner of rectangle
end_point4 = (159, 672)
# color in BGR
color4 = (0, 0, 0)
# Line thickness
thickness4 = -1
# 5) Start coordinate (Right rectangle)
start_point5 = (485, 0)
# Ending coordinate
# represents the bottom right corner of rectangle
end_point5 = (672, 672)
# color in BGR
color5 = (0, 0, 0)
# Line thickness
thickness5 = -1
# Using cv2.rectangle() method
image1 = cv2.rectangle(mask_gray, start_point, end_point, color, thickness)
image2 = cv2.rectangle(mask_gray, start_point2, end_point2, color2, thickness2)
image3 = cv2.rectangle(mask_gray, start_point3, end_point3, color3, thickness3)
image4 = cv2.rectangle(mask_gray, start_point4, end_point4, color4, thickness4)
image5 = cv2.rectangle(mask_gray, start_point5, end_point5, color5, thickness5)
image = image1 image2 image3 image4 image5
# Displaying the image
cv2.imshow('test.jpg', image)
cv2.imwrite('almost02.jpg',image)
cv2.waitKey(0)
cv2.destroyAllWindows()
Это немного сложно и долго, потому что я вручную вставил прямоугольники в области, которые меня не интересуют, поскольку я уже использовал mask, но все еще остается много шума. итак, это лучшее, что я мог придумать.
Теперь он может подсчитывать белые пиксели!
Код, который я использовал для подсчета белых пикселей:
img = cv2.imread('almost05.jpg', cv2.IMREAD_GRAYSCALE)
n_white_pix = np.sum(img == 0)
print('Number of white pixels:', n_white_pix)
Мне придется поиграть с расширением или другими параметрами, чтобы сделать разницу более заметной и избежать ложного срабатывания.
Комментарии:
1. Совершенно ясно, чего вы пытаетесь достичь, но неясно, что вы пробовали и каковы ваши результаты. Пожалуйста, предоставьте 1. код 2. точный ввод 3. требуемый вывод для этого ввода.
2. Тем не менее, почему бы просто не сегментировать оранжевую область по цвету пикселя простое заполнение морфологических отверстий? просто проверьте, что на изображении примерно оранжевого цвета. разве этого было бы недостаточно? почему бы и нет?
3. Пожалуйста, добавьте несколько примеров изображений с препятствиями.
4. @MarkSetchell Я добавил пример препятствия
5. @Gulzar по сути, я просто скопировал код из видеороликов YouTube и онлайн-сайтов. pythonprogramming.net/template-matching-python-opencv-tutorial это похоже на это, но поскольку то, что я пытаюсь обнаружить, является линией, желтые прямоугольники бесконечно накладываются друг на друга
Ответ №1:
Сначала я бы начал тестирование с простейших возможных опций, а затем добавил бы другие функции сверху, если требуется.
Вот пара идей для тестирования:
1. определение цвета
- Используйте
cv2.inRange()
для сегментирования двух оранжевых полос - Используйте
cv2.countNonZero
для подсчета количества оранжевых пикселей перед любыми перекрытиями - Если есть перекрытие, оранжевых пикселей будет меньше: вы могли бы использовать пороговое значение с небольшим допуском и протестировать
2. связанные компоненты со статистикой
- Используйте
cv2.inRange()
для сегментирования двух оранжевых полос - Используйте
cv2.connectedComponentsWithStats()
для выделения оранжевых полос - Используйте статистику (область ширины, высоты), чтобы проверить, действительно ли есть две оранжевые полосы с ожидаемым соотношением ширины / высоты (в противном случае, если этого не происходит и в оранжевых полосах больше соединенных компонентов, чем в двух, потенциально что-то мешает)
Вы могли бы сделать что-то подобное с findCountours()
(и вы могли бы даже поместить эллипс / прямоугольники, получить углы и другие показатели), но имейте в виду, что это будет немного медленнее на Raspberry Pi. Подключенные компоненты немного ограничены, работают только с пикселями, но быстрее и, надеюсь, достаточно хороши.
Вот супер простой пример:
#!/usr/bin/env python
import cv2
import numpy as np
# test image (4 corners, a ring and a at the centre)
src = np.array([
[255,255, 0, 0, 0, 0, 0,255,255],
[255, 0, 0,255,255,255, 0, 0,255],
[ 0, 0,255, 0, 0, 0,255, 0, 0],
[ 0,255, 0, 0,255, 0, 0,255, 0],
[ 0,255, 0,255,255,255, 0,255, 0],
[ 0,255, 0, 0,255, 0, 0,255, 0],
[ 0, 0,255, 0, 0, 0,255, 0, 0],
[255, 0, 0,255,255,255, 0, 0,255],
[255,255, 0, 0, 0, 0, 0,255,255]
],dtype="uint8")
# connectivity type: 4 (N,E,S,W) or 8 (N,NE,E,SE,S,SW,W,NW)
connectivity = 8
# compute connected components with stats
(labelCount,labels,stats,centroids) = cv2.connectedComponentsWithStats(src, connectivity)
# number of labels
print("total number of labels",labelCount)
# labelled image
print("labels")
print(labels)
# stats
print("stats")
print(stats)
# centroid matrix
print("centroids")
print(centroids)
# visualise, 42 = (255 // (labelCount-1))
labelsVis = (np.ones((9,9),dtype="uint8") * labels * 42).astype('uint8')
cv2.imshow('labels',labelsVis)
cv2.waitKey(0)
# just connected components (no stats), 4 connectivity
(labelCount,labels) = cv2.connectedComponents(src, 4)
print("labels")
print(labels)
3. Используйте рентабельность инвестиций и вычитание различий в изображении / фоне
Учитывая статическую камеру / освещение, если вам просто интересно, выходит ли что-то за рамки, вы могли бы сделать что-то вроде:
- замаскируйте центральную область конвейерной ленты, оставив видимыми только верхнюю и нижнюю области, включая оранжевые полосы, и сохраните (в памяти или на диске) изображение без объектов на оранжевых полосах
- в основном цикле обработки выполняется абсолютная разница между новым замаскированным кадром камеры и исходным, сохраненным ранее
- любые объекты на пути будут белыми на черном фоне: можно использовать
countNonZero()
/connectedComponentsWithStats()
/findCountours()
/ etc. для настройки порогового условия.
OpenCV поставляется с довольно приличным средством вычитания фона. Возможно, стоит попробовать, хотя это будет более дорогостоящим в вычислительном отношении, и вам нужно будет настроить параметры (размер истории, скорость, с которой он забывает фон и т.д.), Чтобы наилучшим образом соответствовать вашему проекту.
Вы на правильном пути. Лично я бы не стал заморачиваться с сопоставлением шаблонов для этой задачи (я бы приберег это для обнаружения значков на рабочем столе или очень стабильного сценария, когда шаблон для поиска всегда будет выглядеть одинаково на целевом изображении, когда присутствует на изображении). У меня не было достаточно хорошего опыта работы с HoughLine: вы могли бы попробовать это, найти правильные параметры и надеяться, что обнаружение линий останется неизменным.
Комментарии:
1. Это ооочень полезно, я не могу вас отблагодарить. Я впервые имею дело с кодом, и он немного перегружен, но я стараюсь изо всех сил. Я попробую все это и сообщу вам о своем прогрессе. Спасибо!
2. Спасибо за голосование и добрые слова. Еще одно незначительное замечание по маскировке: альтернативой может быть использование двух областей интереса ( ROI ) (верхней и нижней, включая оранжевые полосы) и обработка каждой ROI, однако это не добавляет ничего дополнительного к идее маски: это просто другой способ взглянуть на проблему. Удачи
3. Спасибо. Кстати, я большой поклонник ваших ответов на bash / ImageMagick 🙂
4. Привет @GeorgeProfenza я пытался почти неделю, и я застрял на этапе, когда мне нужно изолировать 2 строки. Я обновил свой прогресс выше. Мне удалось обнаружить 2 строки, используя cv2.inRange, но все еще присутствует «шум», который включен, и я понятия не имею, как его замаскировать, поскольку я поиграл с кортежем. Я также не понимаю, как правильно закодировать cv2.connectedComponentsWithStats () и cv2.countNonZero, поскольку я использовал mange для подсчета количества пикселей изображения, но, как вы можете видеть, там много черных и белых пикселей. Я бы хотел, чтобы он подсчитывал область, которую я выделил
5. @Xeno Благодарим вас за публикацию фрагмента кода и изображений. Это полезно. Теперь я понимаю, что есть дополнительный бит информации, который мог бы пригодиться: использование морфологических фильтров . В вашем случае попробуйте поиграть с
cv2.dilate()
(илиcv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
гдеkernel
находится квадратный структурирующий элемент: напримерcv2.getStructuringElement(cv2.MORPH_RECT,(5,5))
), чтобы получить представление о черных пикселях на преимущественно белых полосах.