图像处理:实时FedEx徽标检测器的算法改进

nat*_*ncy 15 python algorithm opencv image-processing computer-vision

我一直在从事涉及徽标检测图像处理的项目。具体来说,目标是为实时FedEx卡车/徽标检测器开发一个自动化系统,该系统可从IP摄像机流中读取帧并发送检测通知。这是运行中的系统的示例,其中已识别的徽标被绿色矩形包围。

原始框架

Fedex徽标

对项目的一些限制:

  • 使用原始的OpenCV(不使用深度学习,人工智能或训练有素的神经网络)
  • 图像背景可能嘈杂
  • 图像的亮度变化很大(早晨,下午,晚上)
  • 由于FedEx卡车/徽标可以停在人行道上的任何地方,因此可以具有任意比例旋转或方向
  • 根据一天中的不同时间,徽标可能会模糊不清或带有不同阴影
  • 同一框架中可能还有许多其他具有相似尺寸或颜色的车辆
  • 实时检测(来自IP摄像机的〜25 FPS)
  • IP摄像头处于固定位置,FedEx卡车始终保持相同方向(切勿向后或倒置)
  • 联邦快递卡车将始终是“红色”变体,而不是“绿色”变体

当前实施/算法

我有两个线程:

  • 线程1-使用IP摄像机捕获帧cv2.VideoCapture()并调整帧大小以进行进一步处理。决定在单独的线程中处理抓取帧,以通过减少I / O延迟(由于cv2.VideoCapture()阻塞)来提高FPS 。通过专门用于捕获帧的独立线程,这将允许主处理线程始终具有可用于执行检测的帧。
  • 线程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
Run Code Online (Sandbox Code Playgroud)

颜色阈值用于徽标检测

对于颜色阈值,我为紫色和红色定义了HSV(低,高)阈值以检测徽标。

colors = {
    'purple': ([120,45,45], [150,255,255]),
    'red': ([0,130,0], [15,255,255]) 
}
Run Code Online (Sandbox Code Playgroud)

为了找到每种颜色的边界框坐标,我遵循以下算法:

  • 模糊框架
  • 用内核腐蚀并扩大帧以消除背景噪声
  • 将帧从BGR转换为HSV颜色格式
  • 使用具有设置的颜色阈值的HSV上下边界对帧执行遮罩
  • 在蒙版中找到最大轮廓并获取边界坐标

蒙版之后,我获得了徽标的这些孤立的紫色(​​左)和红色(右)部分。

误报检查

现在我有了两个遮罩,我将执行检查以确保找到的边界框实际上形成徽标。为此,我cv2.matchShapes()将比较两个轮廓并返回一个显示相似度的度量。结果越低,匹配度越高。另外,我使用cv2.pointPolygonTest()它查找图像中的点与轮廓之间的最短距离,以进行其他验证。我的误报过程涉及:

  • 检查边界框是否有效
  • 根据两个框的相对接近度,确保两个框相邻

如果边界框通过了邻接和相似性度量测试,则边界框将被合并并触发FedEx通知。

结果

在此处输入图片说明 在此处输入图片说明

由于存在许多误报和失败检测,因此该检查算法并不是真正可靠的算法。例如,这些误报被触发。

在此处输入图片说明 在此处输入图片说明

尽管此颜色阈值和轮廓检测方法在徽标清晰的基本情况下有效,但在某些方面仍然严重缺乏:

  • 由于必须在每个帧上计算边界框,因此存在延迟问题
  • 有时会错误地检测到何时不存在徽标
  • 亮度和时间对检测精度有很大影响
  • 当徽标倾斜时,可以使用颜色阈值检测,但是由于检查算法而无法检测到徽标。

谁能帮助我改善算法或提出替代检测策略?由于颜色阈值高度依赖于精确校准,还有其他方法可以执行此检测吗?如果可能的话,我不想使用颜色阈值和多层滤镜,因为它不是很可靠。任何见解或建议,将不胜感激!

Car*_*l H 11

您可能要看一下功能匹配。目标是在两个图像(模板图像和嘈杂的图像)中找到特征并将其匹配。这样,您就可以在嘈杂的图像(相机图像)中找到模板(徽标)。

本质上,特征是人类在图像中会发现有趣的事物,例如角落或开放空间。我建议使用尺度不变特征变换(SIFT)作为特征检测算法。我建议使用SIFT的原因是,它对于图像平移,缩放和旋转是不变的,对于照明变化部分不变,并且对局部几何变形具有鲁棒性。这符合您的规格。

特征检测示例

我使用从OpenCV docs 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()
Run Code Online (Sandbox Code Playgroud)

在执行此操作时,您会注意到FedEx徽标上有大量功能(上)。

我要做的下一件事是尝试将视频Feed中的功能与FedEx徽标中的功能进行匹配。我使用FLANN功能匹配器完成了此操作。您可能采用了许多方法(包括蛮力),但是由于您正在处理视频提要,因此这可能是您的最佳选择。以下代码的灵感来自OpenCV文档中的功能匹配:

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()
Run Code Online (Sandbox Code Playgroud)

使用此工具,我可以匹配以下功能,如下所示。您会发现有异常值。但是,大多数功能都可以匹配:

徽标匹配

然后,最后一步将是简单地在此图像周围绘制一个边界框。我将把您链接到另一个堆栈溢出问题,该问题与orb检测器类似。这是使用OpenCV docs获取边界框的另一种方法。

我希望这有帮助!


fir*_*ant 8

您可以帮助检测器对图像进行预处理,然后就不需要那么多的训练图像。

在此处输入图片说明

首先我们减少桶形失真。

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)
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

然后我们以某种方式转换图像,就好像相机正对着 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]))
Run Code Online (Sandbox Code Playgroud)