【问题标题】:Python analyzing a specific area in an imagePython分析图像中的特定区域
【发布时间】:2020-08-18 08:15:49
【问题描述】:

这是一条传送带,我感兴趣的区域是橙色带:

我有一个摄像系统,可以拍摄带有产品的传送带的照片。每次生产运行的图片数量为 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()

这有点严格和漫长,因为我在我不感兴趣的区域手动插入了矩形,因为我已经使用了蒙版,但仍然有很多噪音。所以这是我能想到的最好的了。

现在可以计算白色像素了!

我用来计算白色像素的代码:

img = cv2.imread('almost05.jpg', cv2.IMREAD_GRAYSCALE)
n_white_pix = np.sum(img == 0)
print('Number of white pixels:', n_white_pix)

我将不得不使用膨胀或其他参数来使差异更加明显,以避免误报。

【问题讨论】:

  • 很清楚你想要完成什么,但不清楚你尝试了什么以及你的结果是什么。请提供 1. 代码 2. 准确输入 3. 该输入所需的输出。
  • 也就是说,为什么不按像素颜色分割橙色区域+一些简单的形态孔填充?只需检查图像中大致橙色的部分。还不够吗?为什么不呢?
  • 请添加一些带有障碍物的示例图片。
  • @MarkSetchell 我添加了一个阻塞示例
  • @Gulzar 基本上我只是从 youtube 视频和在线网站复制代码。 pythonprogramming.net/template-matching-python-opencv-tutorial 与此类似,但由于我试图检测的是一条线,因此黄色框彼此无限重叠

标签: python opencv image-processing raspberry-pi


【解决方案1】:

我会先从最简单的选项开始测试,然后在需要时添加其他功能。

这里有几个想法要测试:

1.颜色检测

  • 使用cv2.inRange() 分割两个橙色条
  • 使用cv2.countNonZero 计算任何遮挡之前的橙色像素数
  • 如果有遮挡,橙色像素会减少:您可以使用具有一点容差的阈值并进行测试

2。具有统计信息的连接组件

  • 使用cv2.inRange()分割两个橙色条
  • 使用cv2.connectedComponentsWithStats() 隔离橙色条
  • 使用统计信息(宽度、高度区域)检查是否确实存在两个具有预期宽度/高度比的橙色条(否则,如果没有出现这种情况并且橙色条中的连接组件多于两个可能有东西在路上)

您可以使用 findCountours() 进行类似的操作(甚至可以拟合椭圆/矩形、获取角度和其他指标),但请记住,在 Raspberry Pi 上它会慢一些。 Connected Components 有点受限,仅使用像素,但速度更快,希望足够好。

这是一个超级基本的例子:

#!/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.使用 ROI 和图像差分/背景减法

鉴于静态相机/照明,如果您只是对超出范围的内容感兴趣,您可以执行以下操作:

  • mask 传送带的中心区域,只留下顶部和底部区域,包括橙色带可见,并存储(在内存或磁盘中)橙色带上没有物体的图像
  • 在主处理循环中,在新的蒙版相机帧和之前存储的原始帧之间执行absolute difference
  • 任何挡道的物体都会是黑底白字:可以使用countNonZero()/connectedComponentsWithStats()/findCountours()/等来设置阈值条件。

OpenCV 带有一个相当不错的Background Subtractor。可能值得一试,尽管它的计算成本会更高,并且您需要调整参数(历史大小、忘记背景的速率等)以最适合您的项目。

你在正确的轨道上。就我个人而言,我不会为这个任务的模板匹配而烦恼(我会保存它以检测桌面上的图标或非常稳定的场景,其中要搜索的模板在图像中出现时在目标图像中总是看起来相同) .我对HoughLine的体验还不够好:你可以试试,找到合适的参数,希望线路检测保持一致。

【讨论】:

  • 这太有帮助了,我感激不尽。这是我第一次处理代码,有点不知所措,但我正在尽我所能。我会尝试所有这些,并在我的进展情况下回复您。谢谢!
  • 感谢您的投票和客气话。关于掩蔽的另一个小注意事项:另一种方法可能是使用两个感兴趣区域 (ROI)(顶部和底部,包括橙色带)并处理每个 ROI,但是它对掩蔽的想法没有任何额外的意义:它只是另一种方式的看问题。祝你好运
  • 谢谢。顺便说一句,你的 bash/ImageMagick 的忠实粉丝回答了 :)
  • 嗨@GeorgeProfenza 我已经尝试了将近一个星期,但我被困在需要隔离两条线的阶段。我已经在上面更新了我的进度。我设法使用 cv2.inRange 检测到 2 行,但仍然包含“噪音”,我不知道如何再掩盖它,因为我已经玩过元组。我也对如何正确编码 cv2.connectedComponentsWithStats() 和 cv2.countNonZero 感到迷茫,因为我确实计算了图像的像素数,但如您所见,有很多黑白像素。我想要的是让它计算我突出显示的区域
  • @Xeno 感谢您发布代码 sn-p 和图像。这很有用。我现在意识到还有一些额外的信息会派上用场:using morphological filters。在您的情况下,尝试使用cv2.dilate()(或cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel),其中kernel 是方形结构元素:例如cv2.getStructuringElement(cv2.MORPH_RECT,(5,5)))应该可以读取大部分白色条上的黑色像素。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多