使用OpenCV Python检测物体

5
我是一名新手,对于OpenCV并不熟悉。我正在阅读一些教程和文档,以便编写我的第一个小脚本。
我有一张图片,想要在上面检测物体:街灯、垃圾桶等等。 我的图片如下:

enter image description here

我写了这个脚本:

import cv2

img_filt = cv2.medianBlur(cv2.imread('ville.jpg',0), 5)
img_th = cv2.adaptiveThreshold(img_filt,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,11,2)
img_filt, contours, hierarchy = cv2.findContours(img_th, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)

display = cv2.imshow("Objects",img_filt)
wait_time = cv2.waitKey(0)

但是我如何用矩形显示图片结果呢?

非常感谢!


你想要检测哪些对象?请澄清。 - Nithin
您可以使用模板匹配来检测相同大小和方向的对象。这里是链接:http://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_template_matching/py_template_matching.html#template-matching - Vijay Kalmath
@nithin 是的,我很抱歉,这是我第一次使用OpenCV。目标是在图片上检测街灯、垃圾桶等物品。我没有找到一个非常好的教程来完成这个任务。 - user6051274
@VijayKalmath 谢谢!但是只有当我有图像数据库时它才有效吗? - user6051274
@Andro 是的,您需要在另一张图片中拥有要查找的图像。 - Vijay Kalmath
显示剩余3条评论
2个回答

3
我猜对于目标检测,我个人使用并推荐的是使用SIFT(尺度不变特征转换)或SURF算法,但请注意这些算法现在已被专利保护,不再包含在OpenCV 3中,仍然可在OpenCV2中使用。作为这个的良好替代方案,我更喜欢使用ORB,它是SIFT / SURF的开源实现。
使用SIFT描述符和比率测试的暴力匹配
在这里,我们使用BFMatcher.knnMatch()来获取k个最佳匹配项。在本例中,我们将取k=2,以便我们可以应用D.Lowe在他的论文中解释的比率测试。
import numpy as np
import cv2
from matplotlib import pyplot as plt

img1 = cv2.imread('box.png',0)          # queryImage
img2 = cv2.imread('box_in_scene.png',0) # trainImage

# Initiate SIFT detector
sift = cv2.SIFT()

# find the keypoints and descriptors with SIFT
kp1, des1 = sift.detectAndCompute(img1,None)
kp2, des2 = sift.detectAndCompute(img2,None)

# BFMatcher with default params
bf = cv2.BFMatcher()
matches = bf.knnMatch(des1,des2, k=2)

# Apply ratio test
good = []
for m,n in matches:
    if m.distance < 0.75*n.distance:
        good.append([m])

# cv2.drawMatchesKnn expects list of lists as matches.
img3 = cv2.drawMatchesKnn(img1,kp1,img2,kp2,good,flags=2)

plt.imshow(img3),plt.show()

上述代码的示例输出如下图所示:

使用FLANN进行匹配

FLANN代表Fast Library for Approximate Nearest Neighbors(快速最近邻库)。它包含一组针对大型数据集和高维特征的快速最近邻搜索优化算法。对于大型数据集,它比BFMatcher更快。我们将看到使用基于FLANN的匹配器的第二个示例。

对于基于FLANN的匹配器,我们需要传递两个字典,其中指定要使用的算法、相关参数等。第一个是IndexParams。对于各种算法,需要传递的信息在FLANN文档中有解释。总的来说,对于像SIFT、SURF等算法:

使用SIFT和FLANN的示例代码:

import numpy as np
import cv2
from matplotlib import pyplot as plt

img1 = cv2.imread('box.png',0)          # queryImage
img2 = cv2.imread('box_in_scene.png',0) # trainImage

# Initiate SIFT detector
sift = cv2.SIFT()

# find the keypoints and descriptors with SIFT
kp1, des1 = sift.detectAndCompute(img1,None)
kp2, des2 = sift.detectAndCompute(img2,None)

# FLANN parameters
FLANN_INDEX_KDTREE = 0
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 xrange(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_params = dict(matchColor = (0,255,0),
                   singlePointColor = (255,0,0),
                   matchesMask = matchesMask,
                   flags = 0)

img3 = cv2.drawMatchesKnn(img1,kp1,img2,kp2,matches,None,**draw_params)



plt.imshow(img3,),plt.show()

请看下面的结果:

请参见下面的结果:

enter image description here

但我建议使用ORB描述符进行暴力匹配

在此示例中,我使用ORB和Bruteforce匹配器。该代码从实时摄像头捕获帧,并从输入帧计算关键点、描述符并将其与存储的查询图像进行比较,通过执行相同的操作并返回匹配关键点长度,可以将其应用于上述使用SIFT算法而不是ORB的代码中。

import numpy as np
import cv2
from imutils.video import WebcamVideoStream
from imutils.video import FPS

MIN_MATCH_COUNT = 10

img1 = cv2.imread('input_query.jpg', 0)


orb = cv2.ORB()
kp1, des1 = orb.detectAndCompute(img1, None)

webcam = WebcamVideoStream(src=0).start()
fps = FPS().start()

while True:
    img2 = webcam.read()
    key = cv2.waitKey(10)
    cv2.imshow('',img2)
    if key == 1048603:
        break
    kp2, des2 = orb.detectAndCompute(img2, None)

    bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)

    matches = bf.match(des1, des2)
    matches = sorted(matches, key=lambda x: x.distance)  # compute the descriptors with ORB

    if not len(matches) > MIN_MATCH_COUNT:
        print "Not enough matches are found - %d/%d" % (len(matches), MIN_MATCH_COUNT)
        matchesMask = None

    #simg2 = cv2.polylines(img2,[np.int32(dst)],True,255,3, cv2.LINE_AA)

    print len(matches)
    #img3 = cv2.drawMatches(img1, kp1, img2, kp2, matches[:10], None, flags=2)

    fps.update()

fps.stop()

更详细的视频教程可以在这里找到:https://www.youtube.com/watch?v=ZW3nrP2OyLQ,而且它是开源的:https://gitlab.com/josemariasoladuran/object-recognition-opencv-python.git

谢谢您的非常详细的回答。对我来说有点困难,因为我对这种库还很陌生。 - user6051274
在我的回答中,我使用标准的计算机视觉算法来寻找给定输入图像/帧中最佳的相似关键点,并将其与我们想要比较的图像进行比较,简单地找到一些我们已经拥有其图像的对象,并将输入图像与存储的图像进行比较,因此在这种情况下,我们只需要知道可以在给定的输入图像中找到的最大匹配关键点数量。 - U.Swap
看看这个视频:https://www.youtube.com/watch?v=ZW3nrP2OyLQ 它也是开源的,所以从这里克隆它,git clone https://gitlab.com/josemariasoladuran/object-recognition-opencv-python.git ,只要确保在opencv3中运行,我想这正是你要找的! - U.Swap
是的,这正是我正在寻找的,只有一个区别:我没有视频作为起点,而是一张图片。所以我认为用图片会更容易?我会仔细研究你的答案的 ;) - user6051274
是的,您可以修改代码,仅比较图片!该代码流来自网络摄像头并与相机帧进行比较,而不是您要寻找的隐形图片。 - U.Swap
谢谢!我会用这种方式搜索的 ;) - user6051274

0

我把代码作为答案发布了,但它只显示了通过您的过滤器检索到的轮廓。如果您的图像是黑白的且不是超级复杂的,则该类型的过滤器非常适合轮廓检索。否则,我认为您要寻找的是物体周围的边界框。这需要比一些过滤器更多的工作。

我还添加了matplotlib显示,因为这是您最初请求的,但正如您所看到的,它并不是非常有用。

import cv2
import matplotlib.pyplot as plt

img_orig = cv2.imread('ville.jpg',0)
img_filt = cv2.medianBlur(img_orig, 5)
img_th = cv2.adaptiveThreshold(img_filt,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,11,2)
contours, hierarchy = cv2.findContours(img_th, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)

plt.imshow(img_orig)

cv2.drawContours(img_orig,contours,-1,(128,255,0),1)
display = cv2.imshow("Objects",img_orig)
wait_time = cv2.waitKey(0)
cv2.destroyAllWindows()

其他有用的链接: http://docs.opencv.org/3.1.0/dd/d49/tutorial_py_contour_features.html http://docs.opencv.org/3.1.0/dd/d49/tutorial_py_contour_features.html

后来编辑:你可以在这里找到一些有用的文献,帮助您开始高级物体检测:http://www.cs.utoronto.ca/~fidler/teaching/2015/CSC2523.html

注意:这更多地涉及到有意义的物体检测,而不仅仅是描述形状的简单轮廓检测。


我非常理解你的脚本,谢谢!我进行了一些修改尝试,但是我遇到了这个错误:Traceback (most recent call last): File "image.py", line 17, in <module> contours, hierarchy = cv2.findContours(img_th, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) ValueError: too many values to unpack - user6051274
你使用的是哪个版本的Python?尝试像你最初的例子中那样使用3个参数进行调用。例如:image, contours, hierarchy = cv2... 在我的Python 2.7中,我只能使用带有2个参数的cv2.findContours,即 contours, hierarchy = cv2.findContours() - RMS
@Andro 使用以下代码来解决这个错误:contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)[-2:] - Vijay Kalmath
奇怪,因为我正在使用和你一样的版本。如果我得到解决方案,我会尝试一些东西并返回结果;) - user6051274

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接