Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python OpenCV doesn't give same output at the same image

I'm trying to create a program that checks if 2 images are the same. I have the following code which gets executed with both the images:

img = cv2.imread('canvas.png')
mask = np.zeros(img.shape[:2],np.uint8)
bgdModel = np.zeros((1,65),np.float64)
fgdModel = np.zeros((1,65),np.float64)
rect = (70,70,300,250)
cv2.grabCut(img,mask,rect,bgdModel,fgdModel,5,cv2.GC_INIT_WITH_RECT)
mask2 = np.where((mask==2)|(mask==0),0,1).astype('uint8')
img = img*mask2[:,:,np.newaxis]
img = img[84:191, 84:203]
count = 1
cv2.imwrite("tmp/"+str(count)+".png", img)

First time I run this, I get the following output: First image. After some time ~7 seconds, I do it with exactly the same image, and I get the following output: Second image. I tried it again, and I again got a different output: Third try?

I'm trying to check if the image is the same (as in the contents), but I can't get this working. I'm using the following piece of code found on Stackoverflow to check similarities:

def is_similar(image1, image2):
    return image1.shape == image2.shape and not(np.bitwise_xor(image1,image2).any())

And that returns false when check the first with the second image. How can I make this work out?

Thanks for your time,

==== EDIT ====

Here is canvas.png

==== EDIT 2 ====

After looking at @Rotem their answer, I've tried it out, but it still shows a slight difference, which the function above return False on: Picture 1 and Picutre 2

like image 360
Aaron Avatar asked Jan 22 '26 23:01

Aaron


2 Answers

cv2.grabCut doesn't give deterministic results because the GrabCut algorithm uses built in randomness.

According to Wikipedia:

This is used to construct a Markov random field over the pixel labels...

You may avoid randomness by resetting the seed of the random generator of OpenCV before executing cv2.grabCut:

cv2.setRNGSeed(0)

Here is a code sample:

for count in range(10):
    cv2.setRNGSeed(0)
    img = cv2.imread('canvas.png')
    mask = np.zeros(img.shape[:2],np.uint8)
    bgdModel = np.zeros((1,65),np.float64)
    fgdModel = np.zeros((1,65),np.float64)
    rect = (70,70,300,250)
    cv2.grabCut(img,mask,rect,bgdModel,fgdModel,5,cv2.GC_INIT_WITH_RECT)
    mask2 = np.where((mask==2)|(mask==0),0,1).astype('uint8')
    img = img*mask2[:,:,np.newaxis]
    img = img[84:191, 84:203]
    cv2.imwrite(str(count)+".png", img)

Update:

You may use the following loop to compare the images:

# Verify that all images are the same
for count in range(10):
    im = cv2.imread(str(count)+".png")
    is_same = is_similar(im, img)
    if not is_same:
        print('Images are not the same, and it is strange!')

In my machine they are all the same.


Complete code:

import cv2
import numpy as np

# Disable OpenCL and disable multi-threading.
cv2.ocl.setUseOpenCL(False)
cv2.setNumThreads(1)


def is_similar(image1, image2):
    return image1.shape == image2.shape and not(np.bitwise_xor(image1,image2).any())

for count in range(10):
    cv2.setRNGSeed(0)
    img = cv2.imread('canvas.png')
    mask = np.zeros(img.shape[:2],np.uint8)
    bgdModel = np.zeros((1,65),np.float64)
    fgdModel = np.zeros((1,65),np.float64)
    rect = (70,70,300,250)
    cv2.grabCut(img,mask,rect,bgdModel,fgdModel,5,cv2.GC_INIT_WITH_RECT)
    mask2 = np.where((mask==2)|(mask==0),0,1).astype('uint8')
    img = img*mask2[:,:,np.newaxis]
    img = img[84:191, 84:203]
    cv2.imwrite(str(count)+".png", img)


# Verify that all images are the same
for count in range(10):
    im = cv2.imread(str(count)+".png")
    is_same = is_similar(im, img)
    if not is_same:
        print('Images are not the same, and it is strange!')
like image 140
Rotem Avatar answered Jan 25 '26 13:01

Rotem


There is an element of randomness in cv2.grabCut(). Gaussian Mixture Models are used to detect the foreground and background after initial labeling. More information here or in the cited paper for grabcut.

It's because of this randomness that you're seeing different results. You should consider using some noise reduction techniques like morphological operations (cv2.erode() and cv2.dilate()) to handle this.

like image 21
Shawn Mathew Avatar answered Jan 25 '26 12:01

Shawn Mathew