簡體   English   中英

圖像處理:實時FedEx徽標檢測器的算法改進

[英]Image Processing: Algorithm Improvement for Real-Time FedEx Logo Detector

我一直致力於一個涉及圖像處理的徽標檢測項目。 具體而言,目標是為實時FedEx卡車/徽標檢測器開發自動化系統,該檢測器從IP攝像機流中讀取幀並在檢測時發送通知。 以下是綠色矩形中包含識別徽標的系統示例。

原始框架

Fedex標志

對項目的一些限制:

  • 使用原始OpenCV(沒有深度學習,AI或經過訓練的神經網絡)
  • 圖像背景可能很吵
  • 圖像的亮度可能差異很大(早上,下午,晚上)
  • 聯邦快遞卡車/徽標可以有任何比例旋轉或方向,因為它可以停在人行道上的任何地方
  • 徽標可能會模糊或模糊,具有不同的陰影,具體取決於一天中的時間
  • 在同一框架中可能存在許多具有相似尺寸或顏色的其他車輛
  • 實時檢測(IP攝像機~25 FPS)
  • IP攝像機處於固定位置,FedEx卡車始終處於相同方向(從不向后或顛倒)
  • 聯邦快遞卡車將始終是“紅色”變體而不是“綠色”變體

當前的實現/算法

我有兩個主題:

  • 線程#1 - 使用cv2.VideoCapture()從IP攝像機捕獲幀並調整幀大小以進行進一步處理。 決定在單獨的線程中處理抓取幀,以通過減少因cv2.VideoCapture()阻塞而cv2.VideoCapture() I / O延遲來改善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

用於徽標檢測的顏色閾值處理

對於顏色閾值處理,我已經定義了紫色和紅色的HSV(低,高)閾值來檢測徽標。

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

要查找每種顏色的邊界框坐標,我遵循以下算法:

  • 模糊框架
  • 用內核腐蝕和擴張框架以消除背景噪音
  • 將幀從BGR轉換為HSV顏色格式
  • 使用具有設定顏色閾值的下部和上部HSV顏色邊界在框架上執行遮罩
  • 在掩模中找到最大輪廓並獲得邊界坐標

在執行掩碼后,我獲得了徽標的這些孤立的紫色(​​左)和紅色(右)部分。

誤報檢查

現在我有兩個掩碼,我執行檢查以確保找到的邊界框實際上形成一個徽標。 為此,我使用cv2.matchShapes()比較兩個輪廓並返回顯示相似性的度量。 結果越低,匹配越高。 另外,我使用cv2.pointPolygonTest()找到圖像中一個點與輪廓之間的最短距離,以進行額外的驗證。 我的誤報過程包括:

  • 檢查邊界框是否有效
  • 確保兩個邊界框基於它們的相對接近度而相鄰

如果邊界框通過鄰接和相似性度量測試,則組合邊界框並觸發FedEx通知。

結果

在此輸入圖像描述 在此輸入圖像描述

由於存在許多誤報和檢測失敗,因此該檢查算法不是很穩健。 例如,這些誤報被觸發了。

在此輸入圖像描述 在此輸入圖像描述

雖然這種顏色閾值和輪廓檢測方法適用於徽標清晰的基本情況,但在某些方面嚴重缺乏:

  • 由於必須在每個幀上計算邊界框,因此存在延遲問題
  • 偶爾會錯誤地檢測到徽標何時不存在
  • 亮度和時間對檢測精度有很大影響
  • 當徽標處於傾斜角度時,顏色閾值檢測有效但由於檢查算法無法檢測到徽標。

有人能幫我改進算法或建議其他檢測策略嗎? 有沒有其他方法可以執行此檢測,因為顏色閾值高度依賴於精確校准? 如果可能的話,我想擺脫顏色閾值和多層濾波器,因為它不是很強大。 任何見解或建議都非常感謝!

您可能想看一下功能匹配。 目標是在兩個圖像,模板圖像和嘈雜圖像中找到特征並匹配它們。 這將允許您在嘈雜的圖像(相機圖像)中找到模板(徽標)。

從本質上講,一個特征是人類在圖像中會感興趣的東西,例如角落或開放空間。 我建議使用比例不變特征變換(SIFT)作為特征檢測算法。 我建議使用SIFT的原因是它對於圖像平移,縮放和旋轉是不變的,對於光照變化是部分不變的並且對局部幾何失真是魯棒的。 這符合您的規格。

特征檢測示例

我使用從SIFT特征檢測的OpenCV docs文檔修改的代碼生成了上面的圖像:

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徽標上方(上圖)。

我接下來要做的是嘗試將視頻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()

使用這個我能夠獲得以下匹配的以下功能。 你會注意到有異常值。 但是大多數功能都匹配:

徽標匹配

最后一步是簡單地在該圖像周圍繪制一個邊界框。 我將鏈接到另一個堆棧溢出問題 ,它使用orb檢測器執行類似的操作。 這是使用OpenCV文檔獲取邊界框的另一種方法。

我希望這有幫助!

您可以幫助探測器預處理圖像,然后您不需要那么多的訓練圖像。

在此輸入圖像描述

首先,我們減少桶形失真。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM