图像处理:实时 FedEx 标志检测器的算法改进
Posted
技术标签:
【中文标题】图像处理:实时 FedEx 标志检测器的算法改进【英文标题】:Image Processing: Algorithm Improvement for Real-Time FedEx Logo Detector 【发布时间】:2019-08-23 06:24:22 【问题描述】:我一直在从事一个涉及用于徽标检测的图像处理的项目。具体来说,目标是为实时联邦快递卡车/标志检测器开发一个自动化系统,该系统从 IP 摄像头流中读取帧并发送检测通知。这是一个系统示例,其识别的徽标被绿色矩形包围。
项目的一些限制:
使用原始 OpenCV(无深度学习、AI 或经过训练的神经网络) 图像背景可能很嘈杂 图像的亮度变化很大(早上、下午、晚上) FedEx 卡车/徽标可以有任何比例、旋转或方向,因为它可以停在人行道上的任何地方 根据一天中的不同时间,徽标可能会模糊或带有不同的色调 同一车架中可能有许多其他尺寸或颜色相似的车辆 实时检测(IP 摄像头约 25 FPS) IP 摄像头处于固定位置,FedEx 卡车将始终处于同一方向(绝不会向后或倒置) 联邦快递卡车将始终是“红色”变体,而不是 "green" variation当前实施/算法
我有两个线程:
线程 #1 - 使用cv2.VideoCapture()
从 IP 摄像机捕获帧并调整帧大小以进行进一步处理。决定在单独的线程中处理抓取帧,以通过减少 I/O 延迟来提高 FPS,因为cv2.VideoCapture()
正在阻塞。通过专门用于捕获帧的独立线程,这将允许主处理线程始终拥有可用于执行检测的帧。
线程 #2 - 使用颜色阈值和轮廓检测来检测 FedEx 徽标的主处理/检测线程。
整体伪算法
For each frame:
Find bounding box for purple color of logo
Find bounding box for red/orange color of logo
If both bounding boxes are valid/adjacent and contours pass checks:
Combine bounding boxes
Draw combined bounding boxes on original frame
Play sound notification for detected logo
标识检测的颜色阈值
对于颜色阈值,我为紫色和红色定义了 HSV(低、高)阈值来检测徽标。
colors =
'purple': ([120,45,45], [150,255,255]),
'red': ([0,130,0], [15,255,255])
要找到每种颜色的边界框坐标,我遵循以下算法:
模糊框架 使用内核腐蚀和扩张帧以去除背景噪声 将帧从 BGR 转换为 HSV 颜色格式 使用具有设置颜色阈值的 HSV 颜色上下界在帧上执行遮罩 在掩码中查找最大轮廓并获取边界坐标执行遮罩后,我获得了徽标的这些孤立的紫色(左)和红色(右)部分。
误报检查
现在我有了两个蒙版,我执行检查以确保找到的边界框实际上形成了一个徽标。为此,我使用cv2.matchShapes()
比较两个轮廓并返回一个显示相似度的指标。结果越低,匹配度越高。此外,我使用cv2.pointPolygonTest()
来查找图像中的点与轮廓之间的最短距离,以进行额外验证。我的误报过程包括:
如果边界框通过了邻接和相似性度量测试,则边界框将被合并并触发 FedEx 通知。
结果
这种检查算法不是很健壮,因为有很多误报和失败的检测。例如,这些误报被触发了。
虽然这种颜色阈值和轮廓检测方法在徽标清晰的基本情况下有效,但在某些区域严重缺乏:
必须在每帧上计算边界框会导致延迟问题 它偶尔会在徽标不存在时进行错误检测 亮度和时间对检测精度有很大影响 当徽标处于倾斜角度时,颜色阈值检测工作但由于检查算法而无法检测到徽标。谁能帮助我改进我的算法或建议替代检测策略?由于颜色阈值高度依赖于精确校准,还有其他方法可以执行此检测吗?如果可能的话,我想摆脱颜色阈值和多层过滤器,因为它不是很健壮。非常感谢任何见解或建议!
【问题讨论】:
有一种思路是通过形状匹配过滤掉虚假轮廓,这意味着当你检测到紫色和红色轮廓时,你可以检查形状(紫色与紫色和红色与红色)是否正确匹配 (70%),因为徽标具有固定形状,可帮助您轻松检测徽标。 看看***.com/questions/10168686/… 基本上是同样的问题。还要注意***.com/questions/24299500/can-sift-run-in-realtime 颜色分割是一个好的开始,但我认为您应该尝试使用自定义训练的 Haar 级联。 Haar 特征是人脸检测的支柱。你需要一些正样本和负样本来训练模型。 IP 摄像机是否处于固定位置并注视单向街道?联邦快递卡车将在相同位置和相同方向显示徽标 - 卡车永远不会倒退或倒置。这些限制大大简化了问题。 @StephenMeschke IP 摄像机处于固定位置,并像第一张图片一样看着单向街道。是的,联邦快递卡车将始终以那个方向出现,它永远不会倒退或倒置。此外,FedEx 卡车将永远是图片中的“红色”变体,而不是"green" ground truck 【参考方案1】:您可能想看看特征匹配。目标是在两个图像、一个模板图像和一个噪声图像中找到特征并匹配它们。这将允许您在嘈杂的图像(相机图像)中找到模板(徽标)。
本质上,特征是人类会在图像中发现有趣的事物,例如角落或开放空间。我建议使用尺度不变特征变换 (SIFT) 作为特征检测算法。我建议使用 SIFT 的原因是它对图像平移、缩放和旋转保持不变,对光照变化部分保持不变,并且对局部几何失真具有鲁棒性。这符合您的规范。
我使用从OpenCV docs SIFT 特征检测文档修改的代码生成了上面的图像:
import numpy as np
import cv2
from matplotlib import pyplot as plt
img = cv2.imread('main.jpg',0) # target Image
# Create the sift object
sift = cv2.xfeatures2d.SIFT_create(700)
# Find keypoints and descriptors directly
kp, des = sift.detectAndCompute(img, None)
# Add the keypoints to the final image
img2 = cv2.drawKeypoints(img, kp, None, (255, 0, 0), 4)
# Show the image
plt.imshow(img2)
plt.show()
执行此操作时,您会注意到大量功能确实出现在 FedEx 徽标上(上图)。
接下来我尝试将视频源中的功能与 FedEx 徽标中的功能进行匹配。我使用 FLANN 特征匹配器做到了这一点。您可以采用多种方法(包括蛮力),但由于您正在处理视频源,这可能是您的最佳选择。下面的代码灵感来自OpenCV docs 的特征匹配:
import numpy as np
import cv2
from matplotlib import pyplot as plt
logo = cv2.imread('logo.jpg', 0) # query Image
img = cv2.imread('main2.jpg',0) # target Image
# Create the sift object
sift = cv2.xfeatures2d.SIFT_create(700)
# Find keypoints and descriptors directly
kp1, des1 = sift.detectAndCompute(img, None)
kp2, des2 = sift.detectAndCompute(logo,None)
# FLANN parameters
FLANN_INDEX_KDTREE = 1
index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
search_params = dict(checks=50) # or pass empty dictionary
flann = cv2.FlannBasedMatcher(index_params,search_params)
matches = flann.knnMatch(des1,des2,k=2)
# Need to draw only good matches, so create a mask
matchesMask = [[0,0] for i in range(len(matches))]
# ratio test as per Lowe's paper
for i,(m,n) in enumerate(matches):
if m.distance < 0.7*n.distance:
matchesMask[i]=[1,0]
# Draw lines
draw_params = dict(matchColor = (0,255,0),
singlePointColor = (255,0,0),
matchesMask = matchesMask,
flags = 0)
# Display the matches
img3 = cv2.drawMatchesKnn(img,kp1,logo,kp2,matches,None,**draw_params)
plt.imshow(img3, )
plt.show()
使用它,我能够获得以下匹配的功能,如下所示。你会注意到有异常值。但是大多数功能匹配:
最后一步就是简单地围绕该图像绘制一个边界框。我会将您链接到另一个 stack overflow question,它执行类似的操作,但使用了球体探测器。这是使用OpenCV docs 获取边界框的另一种方法。
我希望这会有所帮助!
【讨论】:
SIFT 特征检测似乎是一种非常好的方法,尤其是因为它似乎可以抵抗旋转和光照变化。我唯一关心的是使用这种方法的每一帧的处理时间。我一定会尝试将这种方法集成到当前系统中。谢谢你的回答! 很好,处理时间是一个问题。也许然后尝试使用加速鲁棒特征(SURF)检测器而不是使用 SIFT。它基本上做同样的事情,但是要快得多(这里是原始的paper,见表2)。我记得在某处读到 OpenCV 的 SURF 版本没有很好地实现(因此很慢),因此可能不是您想要的。以防万一,这里是原始来源code 的链接。无论如何,超级有趣的问题,祝你好运!【参考方案2】:您可以帮助检测器对图像进行预处理,这样就不需要那么多训练图像。
首先我们减少桶形失真。
import cv2
img = cv2.imread('fedex.jpg')
margin = 150
# add border as the undistorted image is going to be larger
img = cv2.copyMakeBorder(
img,
margin,
margin,
margin,
margin,
cv2.BORDER_CONSTANT,
0)
import numpy as np
width = img.shape[1]
height = img.shape[0]
distCoeff = np.zeros((4,1), np.float64)
k1 = -4.5e-5;
k2 = 0.0;
p1 = 0.0;
p2 = 0.0;
distCoeff[0,0] = k1;
distCoeff[1,0] = k2;
distCoeff[2,0] = p1;
distCoeff[3,0] = p2;
cam = np.eye(3, dtype=np.float32)
cam[0,2] = width/2.0 # define center x
cam[1,2] = height/2.0 # define center y
cam[0,0] = 12. # define focal length x
cam[1,1] = 12. # define focal length y
dst = cv2.undistort(img, cam, distCoeff)
然后我们以一种方式转换图像,就好像相机正对着联邦快递卡车一样。即卡车停在路边的任何地方,FedEx 标志的大小和方向几乎相同。
# use four points for homography estimation, coordinated taken from undistorted image
# 1. top-left corner of F
# 2. bottom-left corner of F
# 3. top-right of E
# 4. bottom-right of E
pts_src = np.array([[1083, 235], [1069, 343], [1238, 301],[1201, 454]])
pts_dst = np.array([[1069, 235],[1069, 320],[1201, 235],[1201, 320]])
h, status = cv2.findHomography(pts_src, pts_dst)
im_out = cv2.warpPerspective(dst, h, (dst.shape[1], dst.shape[0]))
【讨论】:
非常有趣的方法来确保徽标始终朝前。这种方法在检测和消除涉及徽标旋转的问题之前肯定是一个很好的预处理阶段以上是关于图像处理:实时 FedEx 标志检测器的算法改进的主要内容,如果未能解决你的问题,请参考以下文章