从具有对象的框的图像中提取对象

xpr*_*edo 5 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()
Run Code Online (Sandbox Code Playgroud)

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

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

空盒子

对象1

对象2

m3h*_*h0w 6

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

图像之间的差异: 在此输入图像描述

差异阈值反转: 在此输入图像描述

以上两者合并: 在此输入图像描述

结果1: 在此输入图像描述

结果2: 在此输入图像描述

代码说明:

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)
Run Code Online (Sandbox Code Playgroud)

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

我还会考虑一下JeruLuke提到的GrabCut,它是用我的方法找到的轮廓的边界矩形.要确保对象包含在其中,只需展开矩形即可.