0

I'm currently getting screenshots of web pages in order to identify differences between our old CMS and the new one. In order to do that I use Selenium to take the screenshot as PNG image:

driver.get_screenshot_as_file(filepath)

imageA imageB

Once I have the two screenshots, I try to compare them with opencv:

imageA = cv2.imread("screenshota.png")
imageB = cv2.imread("screenshotb.png")

grayA = cv2.cvtColor(imageA, cv2.COLOR_BGR2GRAY)
grayB = cv2.cvtColor(imageB, cv2.COLOR_BGR2GRAY)

(score, diff) = compare_ssim(grayA, grayB, full=True)

Then I want to draw rectangles around the differences found.

When I use:

thresh = cv2.threshold(diff, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]

I get the following error message:

OpenCV Error: Assertion failed (src.type() == (((0) & ((1 << 3) - 1)) + (((1)-1) << 3))) in threshold

Turning off the adaptive threshold:

thresh = cv2.threshold(diff, 0, 255, cv2.THRESH_BINARY_INV)[1]

I manage to get one step further.

But then, the code that detects contours fails:

cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

with the below error:

error: (-210) [Start]FindContours supports only CV_8UC1 images when mode != CV_RETR_FLOODFILL otherwise supports CV_32SC1 images only in function cvStartFindContours_Impl

I'm starting to wonder if the problem lies with the type of file used (png vs jpeg).

The complete, reproducible code is as follow:

imageA = cv2.imread("screenshota.png")
imageB = cv2.imread("screenshotb.png")

grayA = cv2.cvtColor(imageA, cv2.COLOR_BGR2GRAY)
grayB = cv2.cvtColor(imageB, cv2.COLOR_BGR2GRAY)

(score, diff) = compare_ssim(grayA, grayB, full=True)
thresh = cv2.threshold(diff, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

Sorry for the newbie question, but can someone point me in the right direction?

E. Jaep
  • 2,095
  • 1
  • 30
  • 56
  • 2
    Examine the result of `compare_ssim` and make sure that it is a numpy array of the correct data type (uint8) and shape (specifically the number of channels). Looks like it's not. Proper [mcve] wouldn't hurt. – Dan Mašek Feb 23 '18 at 22:01
  • @DanMašek Thanks for you comments. The results of ```compare_ssim``` are a ```float64``` for the score and ```ndarray``` for the diff. Since only the diff is used by the threshold calculation, I can't imagine that the type of the score makes a difference. You're right about the proper example. I'll edit my question. – E. Jaep Feb 26 '18 at 20:15
  • If you print `diff.dtype`, you'll notice that the individual elements of the `ndarray` are of type `float64`. OpenCV docs state that `threshold` with Otsu's method needs 8bit integer image and `findContours` also needs 8bit integer image. So, you'll have to perform some conversions -- e.g. `np.float32(diff)` and `np.uint8(thresh)`. – Dan Mašek Feb 27 '18 at 17:36
  • @DanMašek: Thanks for your input. Unfortunately, even when putting a ```diff = np.float32(diff)``` right before the threshold calculation, I get the following error ```thresh.cpp:1406: error: (-215) src.type() == (((0) & ((1 << 3) - 1)) + (((1)-1) << 3)) in function threshold```. On the up side, making the conversion while finding the contours (```cnts = cv2.findContours(np.uint8(thresh.copy()), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)```) did the trick. – E. Jaep Feb 27 '18 at 18:31
  • The first conversion only lets you do a non-Otsu's method threshold. To be able to use Otsu's method, you'd need to map the floating point values in range -1.0 .. 1.0 to unsigned 8 bit integers (i.e. 0 .. 255). – Dan Mašek Feb 27 '18 at 18:52
  • Thanks @DanMašek. You should probably mark your comment as answer so I can accept it. – E. Jaep Feb 27 '18 at 20:41
  • try: # https://stackoverflow.com/questions/56183201/detect-and-visualize-differences-between-two-images-with-opencv-python – rHenderson Mar 24 '20 at 00:17

0 Answers0