OpenCV中使用模板匹配識別空閑的貨架空間
但是點(diǎn)擊上方“小白學(xué)視覺”,選擇加"星標(biāo)"或“置頂”
重磅干貨,第一時(shí)間送達(dá)
假設(shè)你是一名在超市工作的員工,被要求在商店里四處走動(dòng),檢查需要重新進(jìn)貨的貨架。但是,超市有時(shí)會(huì)有多個(gè)區(qū)域來存放一種特定的產(chǎn)品,所以要跟蹤購物者購買產(chǎn)品的確切位置并不容易。最重要的是,報(bào)告庫存的空貨架空間可能非常耗時(shí),而且總是存在人為缺陷的可能性。這就是通過計(jì)算機(jī)視覺識別空的貨架空間可能會(huì)派上用場的地方。
我們創(chuàng)建兩個(gè)獨(dú)特的模板并遍歷圖像以找到足夠相似的多維數(shù)組。相似度是基于我們可配置的閾值。OpenCV的模板matchTemplate函數(shù)可以實(shí)現(xiàn)該操作。

有一些方法可以通過計(jì)算機(jī)視覺來實(shí)現(xiàn)這一點(diǎn),有些比其他的更好,然而,在這篇文章中,我們將嘗試OpenCV中的模板匹配。
模板匹配是一種在較大的圖像中搜索和查找模板圖像位置的方法。OpenCV附帶了一個(gè)函數(shù)cv.matchTemplate()為這個(gè)目的。它簡單地將模板圖像滑動(dòng)到輸入圖像上(就像在2D卷積中一樣),并在模板圖像下比較輸入圖像的模板和補(bǔ)丁。
模板匹配的第一步是創(chuàng)建我們的模板。當(dāng)看到上面的照片,我們可以立即識別出中間頂部的兩個(gè)架子有空余的空間。在最上面的架子上,我們可以確定有3-5個(gè)白色的bag產(chǎn)品需要重新進(jìn)貨。在第二個(gè)架子上,我們可以看到大約有兩種產(chǎn)品需要重新進(jìn)貨。
首先,讓我們用Python加載以下圖片:
import cv2import matplotlib.pyplot as pltimport numpy as npimg = cv2.imread("/content/drive/MyDrive/Computer Vision/new_shelf.jpg")plt.figure(figsize = (20,15))plt.imshow(img)
下面是創(chuàng)建特定模板的代碼(注意template_2由于空置面積較小,更窄):
template_1 = img[60:270, 1890:2010]plt.imshow(template_1)template_2 = img[300:500, 1825:1905]plt.imshow(template_2)
如果你想的話,你可以調(diào)整模板的大小,我覺得這些是最合適的。此外,如果你想知道為什么模板顏色看起來不同于原始圖像,這是因?yàn)镃V2作為加載圖像BGR而不是RGB。
匹配過程
現(xiàn)在我們有了模板,我們可以開始匹配過程了。為此,我們首先將模板存儲(chǔ)為一個(gè)具有不同屬性的類,例如標(biāo)簽(1,2)和顏色(以區(qū)分為不同模板繪制的矩形框)。再次,巨大的呼喊Jean Rovani’s模板匹配博客和代碼:
*******************************************************************/* Title: template_defenition.py* Author: Jean Rovani* Date: 2020* Code version: 3rd revision* Availability: https://gist.github.com/jrovani/012f0c6e66647b4e7b844797fa6ded22#file-template_definition-py*******************************************************************/DEFAULT_TEMPLATE_MATCHING_THRESHOLD = 0.85class Template:def __init__(self, label, template, color, matching_threshold=DEFAULT_TEMPLATE_MATCHING_THRESHOLD):self.label = labelself.color = colorself.template = templateself.template_height, self.template_width = self.template.shape[:2]self.matching_threshold = matching_thresholdimage = cv2.imread("/content/drive/MyDrive/Computer Vision/shelf_new.jpg")templates = [Template(label="1", template = template_1, color=(0, 0, 255)),Template(label="2", template = template_2, color=(0, 255, 0))]
接下來,我們遍歷圖像,并存儲(chǔ)滿足或超過閾值要求。
*******************************************************************/* Title: plot_bounding_boxes.py* Author: Jean Rovani* Date: 2020* Code version: 6th revision* Availability: https://gist.github.com/jrovani/099f80a5ee75657ff7aa6ed491568f04#file-plot_bounding_boxes-py*******************************************************************/detections_1 = []detections_2 = []for template in templates:template_matching = cv2.matchTemplate(template.template, image, cv2.TM_CCOEFF_NORMED)match_locations = np.where(template_matching >= template.matching_threshold)for (x, y) in zip(match_locations[1], match_locations[0]):match = {"TOP_LEFT_X": x,"TOP_LEFT_Y": y,"BOTTOM_RIGHT_X": x + template.template_width,"BOTTOM_RIGHT_Y": y + template.template_height,"MATCH_VALUE": template_matching[y, x],"LABEL": template.label,"COLOR": template.color}if match['LABEL'] == '1':detections_1.append(match)else:detections_2.append(match)
現(xiàn)在我們有了探測的所有數(shù)據(jù),讓我們看看它們在原始圖像上是什么樣子的cv2.rectangle功能:
image_with_detections = image.copy()for temp_d in [detections_1, detections_2]:for detection in temp_d:cv2.rectangle(image_with_detections,(detection["TOP_LEFT_X"], detection["TOP_LEFT_Y"]),(detection["BOTTOM_RIGHT_X"], detection["BOTTOM_RIGHT_Y"]),detection["COLOR"],2,)plt.figure(figsize = (20,15))plt.imshow(image_with_detections)
我們有發(fā)現(xiàn)了!這里的問題是檢測List正在存儲(chǔ)副本。為了解決這個(gè)問題,我們只需要確保我們只會(huì)使用一個(gè)不與其他矩形重疊的矩形:
消除重復(fù)檢測
#Sorting detections by BOTTOM_RIGHT_X coordinatedetections_1 = sorted(detections_1, key = lambda i: i['BOTTOM_RIGHT_X'])detections_2 = sorted(detections_2, key = lambda i: i['BOTTOM_RIGHT_X'])det_wo_dupl_1 = [detections_1[0]]det_wo_dupl_2 = [detections_2[0]]check = 1min_x_1 = templates[0].template.shape[1]min_x_2 = templates[1].template.shape[1]for d in range(1, len(detections_1)):min_x_check = detections_1[d]["BOTTOM_RIGHT_X"] - detections_1[d-check]["BOTTOM_RIGHT_X"]if min_x_check > min_x_1:det_wo_dupl_1.append(detections_1[d])check = 1else:check += 1check = 1for d in range(1, len(detections_2)):min_x_check = detections_2[d]["BOTTOM_RIGHT_X"] - detections_2[d-check]["BOTTOM_RIGHT_X"]if min_x_check > min_x_2:det_wo_dupl_2.append(detections_2[d])check = 1else:check += 1det_wo_dupl = det_wo_dupl_1 + det_wo_dupl_2print(len(det_wo_dupl))
過濾檢測
image_with_detections = image.copy()min_x = templates[0].template.shape[1]for detection in det_wo_dupl:cv2.rectangle(image_with_detections,(detection["TOP_LEFT_X"], detection["TOP_LEFT_Y"]),(detection["BOTTOM_RIGHT_X"], detection["BOTTOM_RIGHT_Y"]),detection["COLOR"],20,)plt.figure(figsize = (20,15))plt.imshow(image_with_detections)
有人可能會(huì)說,實(shí)際上應(yīng)該有5個(gè)矩形顯示在最上面的架子上,因?yàn)槠渲幸粋€(gè)袋子似乎是輕微傾斜/移動(dòng)。如果使用模板匹配,就很難找到這種方法。我們需要多個(gè)不同尺寸的模板來捕獲這張圖片中的所有空貨架區(qū)域。

盡管模板匹配在我們這里的用例中工作得很好,并且對于許多其他用例來說是一個(gè)很棒的計(jì)算機(jī)視覺過程,但它可能不是這個(gè)場景的最佳選擇。對于這樣的問題,我們需要一種算法,可以學(xué)習(xí)理解一個(gè)空區(qū)域的周圍乘積。這將允許更大的靈活性,因?yàn)樗鼘⒛軌蛱幚聿煌笮?顏色的空白區(qū)域。
交流群
歡迎加入公眾號讀者群一起和同行交流,目前有SLAM、三維視覺、傳感器、自動(dòng)駕駛、計(jì)算攝影、檢測、分割、識別、醫(yī)學(xué)影像、GAN、算法競賽等微信群(以后會(huì)逐漸細(xì)分),請掃描下面微信號加群,備注:”昵稱+學(xué)校/公司+研究方向“,例如:”張三 + 上海交大 + 視覺SLAM“。請按照格式備注,否則不予通過。添加成功后會(huì)根據(jù)研究方向邀請進(jìn)入相關(guān)微信群。請勿在群內(nèi)發(fā)送廣告,否則會(huì)請出群,謝謝理解~

