如何使用Python OpenCV2减去两个图像以获取前景对象

15

有没有办法在Python OpenCV2中减去两个图像?

  • 图像1:任何图像(例如房屋图像)(静态图像)
  • 图像2:带有对象的相同图像(在房子里,一个人正在站立...)(静态图像+动态物体)
  • 图像3 = 图像2-图像1

如果我们从Image1中减去Image2,那么Image3应该仅给出Object(person)

6个回答

42

尝试使用背景减除

使用cv2.subtract(img1, img2)代替算术运算,因为cv2将处理负值。


背景减法用于视频处理。通常需要几帧“空闲场景”来学习外观。 - Christoph Rackwitz

11
如果两张图片的背景完全相同,您可以像您在帖子中提到的那样将它们相减。
image1 = imread("/path/to/image1")
image2 = imread("/path/to/image2")
image3 = image1 - image2

13
不应使用“-”运算符,因为它无法处理负值(在图像中没有意义)。请改用@viki提供的这个答案 - Rick Smith
4
希望你好运,但如果使用uint8图像,结果将完全错误。 - Mehdi

9

@dvigneshwr的回答对负值进行减法运算,结果为负数时会被舍入为0。@Taha Anwar M-Holmes的回答保留了负数,但更改了结果数组的数据类型,因此不再是传统的图像类型。

对于那些想要基于值的绝对差异来识别前景和背景图像,并返回与输入相同数据类型的数组(这就是我来到这里的原因),请使用absdiff

假设数组具有相同的宽度和高度...

import cv2 as cv

image3 = cv.absdiff(image1, image2)

值得注意的是,OP没有提供有关这里所减去的图像的任何细节...根据图像的内容,所有这些方法都可能回答OP的问题。

1

cv2.subtract不起作用,它只是将值绑定在0-255之间,因此如果您想要获得负值,只需将图像从unit8转换为int32或int64即可。请注意,unint8只能取0-255的值,因此无法处理负值。

image1= np.int32(image1)

image2= np.int32(image2)

image3 = image1 - image2

在识别前景对象的情况下,为什么在减去两个图像后会出现负值呢?(我想知道您是否使用了我不熟悉的某些对象检测算法) - RTbecard
无法保证从前景中减去背景后会留下正的前景值,前景强度值很容易比之前存在的背景低。因此,您需要使用前景和背景像素之间的绝对差异。 - Ahmed
是的,我同意你计算绝对差的方法,但是opencv已经提供了一个函数来实现这个功能(请看我的回答)。我更想知道是否有保留负数的原因(即计算差而不是绝对差),就像你的答案一样。 - RTbecard
灰色背景。前景物体可能是白色(正差异)或黑色(负差异)。这对于进一步处理(比如分类)可能是相关的。--无论如何,都必须处理负差异,可以通过保留、剪切(饱和数学)或取绝对值来处理。 - Christoph Rackwitz

0
在处理灰度图像时,我犯了一个错误,就是忘记了0代表黑色,255代表白色,这与印刷媒体上的预期相反。
正确的减法应该在每一步都使用bitwise_not()进行操作: image3 = bitwise_not( bitwise_not(image1) - bitwise_not(image2) )

-2
# find moving image.
#
# running the program pops up a window to watch the video.
# the program video window shows the first monitor,
# but watch the program video window on second extended monitor

import cv2
import numpy as np

# Path to video file
cap = cv2.VideoCapture(
    1,
    apiPreference=cv2.CAP_ANY,
    params=[cv2.CAP_PROP_FRAME_WIDTH, 1280, cv2.CAP_PROP_FRAME_HEIGHT, 720],
)  # I made cap = 1280, 720 resolution to speed the program up on my computer. I have a rtx 3060, obs studio at 60 fps

# Used as counter variable
count = 1

# checks whether frames were extracted
success = 1

# create frame_1 and frame_2 to be able to use the frames between if conditions
frame_1 = 0
frame_2 = 0

# get 2 frames to start with
count_subtraction = 0

while success:

    # function extract frames
    success, image = cap.read()

    if count_subtraction == 0:
        if count <= 2:
            # Saves the frames with frame-count
            cv2.imwrite("frame_%d.jpg" % count, image, [int(cv2.IMWRITE_JPEG_QUALITY), 100])  # jpg 100% quality

            count += 1

        if count == 3:

            frame_1 = cv2.imread("frame_1.jpg", 0)
            frame_2 = cv2.imread("frame_2.jpg", 0)

            # use the frames below

            # Create the sharpening kernel
            kernel = np.array([[0, -1, 0], [-1, 5, -1], [0, -1, 0]])

            # Sharpen the image
            frame_1 = cv2.filter2D(frame_1, -1, kernel)
            frame_2 = cv2.filter2D(frame_2, -1, kernel)

            # subtract the images
            subtracted = cv2.subtract(frame_2, frame_1)

            subtracted_sharpened = cv2.filter2D(subtracted, -1, kernel)

            # TO show the output
            cv2.imshow("image", subtracted_sharpened)

            # the else condition to count_subtraction needs a first frame
            frame_1 = frame_2

            count = 1
            count_subtraction = 1

    else:

        cv2.imwrite("frame_2.jpg", image, [int(cv2.IMWRITE_JPEG_QUALITY), 100])  # jpg 100% quality

        frame_2 = cv2.imread("frame_2.jpg", 0)

        # use the frames below

        # Create the sharpening kernel
        kernel = np.array([[0, -1, 0], [-1, 5, -1], [0, -1, 0]])

        # Sharpen the image
        frame_2 = cv2.filter2D(frame_2, -1, kernel)

        # subtract the images
        subtracted = cv2.subtract(frame_2, frame_1)

        subtracted_sharpened = cv2.filter2D(subtracted, -1, kernel)

        # TO show the output
        cv2.imshow("image", subtracted_sharpened)

        # the second frame becomes a first frame
        frame_1 = frame_2


    if cv2.waitKey(1) & 0xFF == ord("q"):
        break

# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()


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