从具有对象

时间:2017-03-28 05:19:03

标签: python opencv image-processing

我有一个盒子,从前面是透明的,我将相机放在前透明面板上以捕捉内部图像,大多数时候盒子是空的,但是假设有人将一个物体放在这个盒子里,那么我必须从捕获的图像中提取此对象。

(我的真正目的是识别放置在盒子内的物体,但第一步是提取物体,然后提取特征以生成训练模型,现在我只专注于从图像中提取物体)

我是OpenCV的新手,并在Python中使用它,我找到了一些可以帮助我的OpenCV函数。

  • GrabCut,这对我很有效,我能够提取出来 对象,只要我在对象上标记矩形,但是 对象可以在框内的任何位置,因此无法绘制 对象的确切大小矩形,如果有办法,请建议我。
  • 图像的差异,因为我有空腔盒图像和时间 对象存在,我可以使用cv2.absdiff函数来计算 图像之间的差异,但这在大多数情况下都无法正常工作 这些情况,因为它使用逐像素差异计算,和 由于这个结果很奇怪,加上光线条件的变化也是如此 让事情变得困难。
  • Back Ground Subtraction,我在这里读了几篇帖子,看起来就是这样 我需要什么,但我得到的例子是视频,我没有 了解如何使用两个图像,一个空盒子和另一个带对象的图像。

背景减法的代码如下,即使短距离也不能正常工作

cap = cv2.VideoCapture(0)
fgbg = cv2.createBackgroundSubtractorMOG2()
fgbg2 = cv2.createBackgroundSubtractorKNN()

while True:
    ret, frame = cap.read()
    cv2.namedWindow('Real', cv2.WINDOW_NORMAL)
    cv2.namedWindow('MOG2', cv2.WINDOW_NORMAL)
    cv2.namedWindow('KNN', cv2.WINDOW_NORMAL)
    cv2.namedWindow('MOG2_ERODE', cv2.WINDOW_NORMAL)
    cv2.namedWindow('KNN_ERODE', cv2.WINDOW_NORMAL)
    cv2.imshow('Real', frame)
    fgmask = fgbg.apply(frame)
    fgmask2 = fgbg2.apply(frame)
    kernel = np.ones((3,3), np.uint8)
    fgmask_erode = cv2.erode(fgmask,kernel,iterations = 1)
    fgmask2_erode = cv2.erode(fgmask2,kernel,iterations = 1)

    cv2.imshow('MOG2',fgmask)
    cv2.imshow('KNN',fgmask2)
    cv2.imshow('MOG2_ERODE',fgmask_erode)
    cv2.imshow('KNN_ERODE',fgmask2_erode)
    k = cv2.waitKey(30) & 0xff
    if k == 27:
        break
cap.release()
cv2.destroyAllWindows()

任何人都可以请帮助这个主题,以及如何修改上面的代码只是使用这两个图像,当我尝试我得到空白图像。在此先感谢

来自相机的示例图像如下: (我使用800万像素摄像头,这就是为什么图像尺寸很大,我减小了尺寸,然后在这里上传)

Empty Box

Object-1

Object-2

2 个答案:

答案 0 :(得分:6)

你提到过减法,我相信在这种情况下它是最好的方法。我已经实现了一个非常简单的算法来处理你提供给我们的案例。我用注释解释了代码。在图像上,我提出了你遇到的最重要的步骤 - 算法的线索。

图像之间的差异: enter image description here

差异阈值反转: enter image description here

以上两者合并: enter image description here

结果1: enter image description here

结果2: enter image description here

带解释的代码:

import cv2
import numpy as np

# load the images
empty = cv2.imread("empty.jpg")
full = cv2.imread("full_2.jpg")

# save color copy for visualization
full_c = full.copy()

# convert to grayscale
empty_g = cv2.cvtColor(empty, cv2.COLOR_BGR2GRAY)
full_g = cv2.cvtColor(full, cv2.COLOR_BGR2GRAY)

# blur to account for small camera movement
# you could try if maybe different values will maybe
# more reliable for broader cases
empty_g = cv2.GaussianBlur(empty_g, (41, 41), 0)
full_g = cv2.GaussianBlur(full_g, (41, 41), 0)

# get the difference between full and empty box
diff = full_g - empty_g
cv2.imwrite("diff.jpg", diff)

# inverse thresholding to change every pixel above 190
# to black (that means without the bag)
_, diff_th = cv2.threshold(diff, 190, 255, 1)
cv2.imwrite("diff_th.jpg", diff_th)

# combine the difference image and the inverse threshold
# will give us just the bag
bag = cv2.bitwise_and(diff, diff_th, None)
cv2.imwrite("just_the_bag.jpg", bag)

# threshold to get the mask instead of gray pixels
_, bag = cv2.threshold(bag, 100, 255, 0)

# dilate to account for the blurring in the beginning
kernel = np.ones((15, 15), np.uint8)
bag = cv2.dilate(bag, kernel, iterations=1)

# find contours, sort and draw the biggest one
_, contours, _ = cv2.findContours(bag, cv2.RETR_TREE,
                                  cv2.CHAIN_APPROX_SIMPLE)
contours = sorted(contours, key=cv2.contourArea, reverse=True)[:3]
cv2.drawContours(full_c, [contours[0]], -1, (0, 255, 0), 3)

# show and save the result
cv2.imshow("bag", full_c)
cv2.imwrite("result2.jpg", full_c)
cv2.waitKey(0)

现在,当然可以改进算法,并且必须根据您需要处理的任何条件进行调整。例如,你已经提到了光照的不同之处 - 你必须处理它以确保减去图像的背景相似。要做到这一点,你可能不得不看一些对比度增强算法,如果相机移动可能会注册 - 这可能是一个完全独立的问题。

我也会考虑GrabCut,JeruLuke提到了我的方法找到的轮廓的边界矩形。要确保对象包含在其中,只需展开矩形。

答案 1 :(得分:3)

我有一个粗略的解决方案。如果您希望进一步改进,则必须对其进行改进以满足您的需求。

首先,我在灰度图像的模糊版本上使用cv2.Canny()执行边缘检测

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) #---convert image to gray---
blur = cv2.GaussianBlur(gray, (5, 5), 0)   #---blurred the image---
edges = cv2.Canny(blur, lower, upper)   #---how to find perfect edges see link below---

enter image description here

enter image description here

我扩大了边缘以使它们更加明显:

kernel = np.ones((3, 3), np.uint8)
dilated = cv2.morphologyEx(edges, cv2.MORPH_DILATE, kernel)

接下来,我发现边缘检测到的图像上存在轮廓。

_, contours, hierarchy = cv2.findContours(king, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)  

注意我使用cv2.RETR_EXTERNAL仅获取外轮廓

然后我发现具有最大面积的轮廓a围绕它放置了一个边界框。

enter image description here

enter image description here

现在我使用 GrabCut算法来分割午餐盒。为此,我从THIS LINK HERE

获得了我需要的所有帮助

我在找到轮廓作为 GrabCut算法

的输入后,使用了我获得的边界矩形的坐标

最终产出:

enter image description here

enter image description here

你可以看到它并不完美,但这是我能做到的最好的。

希望它有所帮助。如果你有更好的解决方案,请发帖! :d