0

I am trying to remove a fixed background from an image with a single free-falling object. The image has a single free falling object and it has a white background with a circular patch in the middle.

Test cases worked

Below is my code for the above task. I have used OpenCV BackgroundSubtractorKNN and BackgroundSubtractorMOG2 algorithm to achieve this task. The left images should be given as input and the code should produce the right images as output.

import numpy as np
import cv2
import sys
import os

#backgroundSubtractor = cv2.createBackgroundSubtractorMOG2()

backgroundSubtractor = cv2.createBackgroundSubtractorKNN()

# apply the algorithm for background images using learning rate > 0
for i in range(1, 16):
    bgImageFile = "background/BG.png" 
    print("Opening background", bgImageFile)
    bg = cv2.imread(bgImageFile)
    backgroundSubtractor.apply(bg, learningRate=0.5)

# apply the algorithm for detection image using learning rate 0

dirc = os.getcwd()
filepath = os.path.join(dirc,'data')
if not os.path.exists('saved_bgRemoved'):
    os.makedirs('saved_bgRemoved')

for file in os.listdir(filepath):
    stillFrame = cv2.imread(os.path.join(filepath,file))
    fgmask = backgroundSubtractor.apply(stillFrame, learningRate=0)
   
    bgImg = cv2.bitwise_and(stillFrame,stillFrame,mask=fgmask)
    # show both images
    cv2.imshow("original", stillFrame)
    cv2.imshow("mask", fgmask)
    cv2.imshow("Cut Image", bgImg)
    cv2.waitKey()
    cv2.destroyAllWindows()
    cv2.imwrite(os.path.join('saved_bgRemoved',file), bgImg)

My code works very well with the above dataset, but it fails to work with the image data below:

Test Case that doesn't work

It also doesn't work if the object is colored in greyish texture. I think it works well when the pixel distribution of the object is uniform and different from the background (i.e. the circular patch).

Is there any other best way to achieve this task, so that it can subtract the background even from the hollow area of the object, without subtracting parts of the object?

James Z
  • 12,209
  • 10
  • 24
  • 44
Neil
  • 59
  • 1
  • 7

1 Answers1

1

use below code, I think it now works

import cv2, os

def remove_bg(bg_path,im_path):
    bg = cv2.imread(bg_path)
    im = cv2.imread(im_path)
    row,col,_ = im.shape
    for i in range(0,row):
        for j in range(0,col):
            if ( bg[i][j][0] == im[i][j][0] and bg[i][j][1] == im[i][j][1] and bg[i][j][2] == im[i][j][2] ):
                im[i][j] = [0,0,0] #it will replace background with black color, you can change it for example to [255,0,0] to replace it with red
    return(im)

directory,_=os.path.split(__file__)
bg_path = directory + "\\background.png"
im_path = directory + "\\data6.png"
result = remove_bg(bg_path,im_path)
cv2.imshow("result", result)
cv2.waitKey()
cv2.imwrite(directory + "\\Result.png", result)
Shoaib Mirzaei
  • 512
  • 4
  • 11
  • Instead of using for loops, using compare function and obtaining a mask will be much faster. In C++, these operations correspond to `operator ==` and `copytTo` with mask. I don't know numpy funcions though. – Burak Nov 11 '20 at 17:14
  • Your code is not working. It outputs all black. Here is the link to the actual image and background: https://drive.google.com/drive/folders/1FO69gl49mWh4XBBnGqAq76lDdGwDFZxO?usp=sharing – Neil Nov 12 '20 at 13:51
  • 1
    @Neil you are right. problem was in condition I used. I updated the answer, see if it works now – Shoaib Mirzaei Nov 12 '20 at 15:15
  • 1
    @Neil just keep in mind that this only works in two conditions: both images (bg and im) have the same dimension (you can check this out by `print(bg.shape == im.shape)`), and bg is fixed in every image, meaning if you shift background of an image just a pixel to any direction it won't work. – Shoaib Mirzaei Nov 13 '20 at 04:50