Python анализирует определенную область в изображении

#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()
  

Наконец-то удалось изолировать 2 полосы и обнаружить посторонние вещества

Я могу изолировать полосы, и инородное вещество / препятствие показано четко

Это код, который я использовал:

 # 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)
  

тестировалось с хорошими и плохими изображениями. У хорошего было бы больше белых пикселей, которые варьировались бы в пределах 437000-439000, а у плохого было бы меньше на уровне 435000-436000

Мне придется поиграть с расширением или другими параметрами, чтобы сделать разницу более заметной и избежать ложного срабатывания.

Комментарии:

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)) ), чтобы получить представление о черных пикселях на преимущественно белых полосах.