【问题标题】:How can I detect an object in image frame using OpenCV?如何使用 OpenCV 检测图像帧中的对象?
【发布时间】:2018-06-16 05:02:22
【问题描述】:

我正在使用 Raspberry Pi 开发漫游车,它会清扫房间并捡起掉在地上的物体。为了检测物体,我使用了一个参考图像,它是在流动站运行开始时拍摄的,以及一个每 10 秒点击一次的图像(新图像)。为了确定图像帧中是否有变化,我在参考图像和新图像之间进行了图像减法。如果发现任何差异,它将在其周围绘制轮廓,如果轮廓区域大于某个阈值(警告步骤),则得出存在对象的结论。

我正在使用以下代码 -

import numpy as np
import cv2,time

img=cv2.imread("object1.jpg")
img1=cv2.imread("object2.jpg")
sub=cv2.subtract(img,img1)

gray=cv2.cvtColor(sub,cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray,(3,3),0)
_, contours, _= cv2.findContours(blur,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
c=max(contours,key=cv2.contourArea)
print(cv2.contourArea(c))

if cv2.contourArea>20000:
   print("Object detected !")

以上代码仅使用 2 个图像来计算它们的差异并确定是否存在对象。请注意,我没有在此处发布我将在我的项目中使用的原始代码。

现在,上面的代码在非常受控的情况下工作得很好,例如,当图像背景非常恒定或其中没有阴影时。但考虑到漫游车将在房间内四处移动,即使帧中没有真实物体,照明变化也有可能触发错误的物体检测。由于阴影效果的错误轮廓可能会触发差异。

我想知道,是否有任何其他方法可以在不进行前景/背景图像减法的情况下实现此对象检测。我也考虑过使用超声波传感器来检测物体的存在,但这不是一个非常可靠的选择。我更喜欢基于图像处理的解决方案。

谢谢。

================================================ =============================

编辑 1 -

所以,我决定稍微改变一下算法。我已经对前景和背景图像进行了阈值处理,然后在二进制图像之间执行了 absdiff ,以获得任何帧变化(对象)。 代码如下——

import numpy as np
import cv2,time

img1=cv2.imread("back.jpeg")
blur1 = cv2.GaussianBlur(img1,(5,5),0)
gray1=cv2.cvtColor(blur1,cv2.COLOR_BGR2GRAY)
ret,thresh1 = cv2.threshold(gray1,65,255,cv2.THRESH_BINARY_INV)

img2=cv2.imread("front.jpeg")
blur2 = cv2.GaussianBlur(img2,(5,5),0)
gray2=cv2.cvtColor(blur2,cv2.COLOR_BGR2GRAY)
ret,thresh2 = cv2.threshold(gray2,65,255,cv2.THRESH_BINARY_INV)

diff=cv2.absdiff(thresh2,thresh1)
diff=cv2.bitwise_xor(diff,thresh1)

kernel = np.ones((2,2),np.uint8)
diff=cv2.erode(diff,kernel,iterations = 1)
diff=cv2.dilate(diff,kernel,iterations = 8)

_, contours, _= cv2.findContours(diff,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
c=max(contours,key=cv2.contourArea)
x,y,w,h = cv2.boundingRect(c)
cv2.rectangle(diff,(x,y),(x+w,y+h),(125,125,125),2)


cv2.imshow("thresh",diff)
cv2.waitKey(0)

"absdiff" 之后是 Erosion 和 Dilation 。之后,我找到最大的轮廓并确定是否有物体。算法中用到的图片如下-

  1. 背景图片 - Background Image

  2. 前景图像 - Foreground image

  3. 前景阈值 - Foreground threshold Image

  4. 背景阈值 - Background threshold Image

  5. 差异图像 - Final Image with contour and its boundary .

如您所见,检测工作正常。我有几个用于测试算法的其他前景图像。他们给出了令人满意的结果。我想知道,是否有任何其他方法可以以更高的效率达到相同的结果。

PS-所有的前景图像都是在闪光灯开启的情况下拍摄的。我尝试过关闭 Flash,但图像中似乎存在很多噪点。

================================================ ===============

编辑 2-

使用其他图片的算法性能 -

注意:- 背景图像保持不变。

  1. 对象 1 - Foreground Image 1
  2. 对象 1 检测 - Foreground Image 1 Result

【问题讨论】:

  • 对于对象模板图像,您可以使用像 sift/surf/orb 这样的关键点匹配,但您至少应该从对象的每一侧都有一个模板。
  • @Micka 嗯,对象会不时改变。它可以是瓶子、塑料或其他任何东西。如果您的解决方案涵盖了我提到的情况,请详细说明。我真的不知道 sift/orb 方法。
  • 您必须为每个对象提供模板。在一篇原始的 sift 论文中,描述了如何使用关键点匹配进行对象检测。但是如果没有足够的纹理(没有标签的透明瓶子?)关键点匹配可能不起作用。
  • @Micka 请检查编辑。

标签: python image opencv image-processing raspberry-pi


【解决方案1】:

我怀疑这个问题是否像你在问题中描述的那么简单,当我们在现实世界场景中移动时它会变得非常复杂。

但无论如何,假设您只有房间中存在小物体,那么您可以通过识别捕获的二进制图像中的连接组件来识别它们,并根据它们的相对像素大小选择它们。

这是相同的 Python 实现:

img = cv2.imread('D:/Image/objects.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# binarize the image
ret, bw = cv2.threshold(gray, 128, 255, 
cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)

# find connected components
connectivity = 4
nb_components, output, stats, centroids = 
cv2.connectedComponentsWithStats(bw, connectivity, cv2.CV_32S)
sizes = stats[1:, -1]; nb_components = nb_components - 1
min_size = 250 #threshhold value for objects in scene
img2 = np.zeros((img.shape), np.uint8)
for i in range(0, nb_components+1):
    # use if sizes[i] >= min_size: to identify your objects
    color = np.random.randint(255,size=3)
    # draw the bounding rectangele around each object
    cv2.rectangle(img2, (stats[i][0],stats[i][1]),(stats[i][0]+stats[i][2],stats[i][1]+stats[i][3]), (0,255,0), 2)
    img2[output == i + 1] = color

包含对象的图像:

使用连接组件标签检测到的对象:

【讨论】:

  • 我图像中的对象不会完全是黑色或白色。我知道我可以进行灰度图像转换,但它仍然不会产生完整的二进制图像。我需要做一个阈值来获得一个完整的二值图像。如果我进行阈值处理,只找到轮廓并找到具有一定大小的轮廓,检测和对象不是更好吗?这里连接组件有什么用?
  • 请检查编辑。 @flamelite
  • 好的,这些图像是您自己拍摄的,但是您如何让您的漫游车获得同一个地方的前景和背景图像?图像减法仅适用于相同位置的图像帧。
  • 是的,我知道这个缺点。但工作假设是背景图像不会突然改变。正如您在我的背景和前景图像中看到的那样,背景,即白色瓷砖几乎是恒定的,除了瓷砖边缘。我知道帧减法不会给出完全干净的结果。但是检测前景物体就足够了。此外,背景图像将在流动站启动时被点击,它会每 10 秒被前景图像交换和替换(如果对象不存在)。
  • 我不确定,可能你应该根据想法准备一个原型并测试哪个有效,然后你会得到算法的更多缺点并相应地更改/修改。跨度>
【解决方案2】:

您可以考虑的另一种方法是使用运动中的结构,重建环境/点云,地板表面上方的点簇属于您的对象。也可以将其与您的背景减法方法结合使用,以消除错误检测,例如导致该方法出现问题的阴影。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-07-18
    • 2020-04-18
    • 2023-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多