Skip to content

Instantly share code, notes, and snippets.

@georgescumihai
Created December 23, 2020 12:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save georgescumihai/db0ea992cbce79737a9b5a899fac7c98 to your computer and use it in GitHub Desktop.
Save georgescumihai/db0ea992cbce79737a9b5a899fac7c98 to your computer and use it in GitHub Desktop.
Compare two screenshots for differences and highlight the differences
import base64
from dataclasses import dataclass
from typing import Any
import cv2
import imutils
import numpy as np
from skimage.metrics import structural_similarity
@dataclass
class ImageDifference:
score: float
original: Any
compare: Any
def write_images(self, original_file_path="original", difference_file_path="difference"):
cv2.imwrite(str(original_file_path), self.original)
cv2.imwrite(str(difference_file_path), self.compare)
class Image(object):
def __init__(self, cv_image):
if not isinstance(cv_image, np.ndarray):
raise TypeError("parameter must be a cv2 image")
self.image = cv_image
@classmethod
def from_path(cls, file_path):
return cls(cv2.imread(str(file_path)))
@classmethod
def from_base64(cls, base64_image):
im_bytes = base64.b64decode(base64_image)
im_arr = np.frombuffer(im_bytes, dtype=np.uint8) # im_arr is one-dim Numpy array
img = cv2.imdecode(im_arr, flags=cv2.IMREAD_COLOR)
return cls(img)
class ImageCompare:
@staticmethod
def compare_images(lhs: Image, rhs: Image, threshold: int = 0.95) -> ImageDifference:
# https://www.pyimagesearch.com/2017/06/19/image-difference-with-opencv-and-python/
# convert the images to grayscale
lhs_gray = cv2.cvtColor(lhs.image, cv2.COLOR_BGR2GRAY)
rhs_gray = cv2.cvtColor(rhs.image, cv2.COLOR_BGR2GRAY)
# compute the Structural Similarity Index (SSIM) between the two
# images, ensuring that the difference image is returned
(score, diff) = structural_similarity(
lhs_gray, rhs_gray, gaussian_weights=True, full=True, sigma=1.5, use_sample_covariance=False
)
if score >= threshold:
return None
diff = (diff * 255).astype("uint8")
# threshold the difference image, followed by finding contours to
# obtain the regions of the two input images that differ
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)
cnts = imutils.grab_contours(cnts)
# loop over the contours
for c in cnts:
# compute the bounding box of the contour and then draw the
# bounding box on both input images to represent where the two
# images differ
(x, y, w, h) = cv2.boundingRect(c)
cv2.rectangle(lhs.image, (x, y), (x + w, y + h), (0, 0, 255), 2)
cv2.rectangle(rhs.image, (x, y), (x + w, y + h), (0, 0, 255), 2)
return ImageDifference(score=score, original=lhs.image, compare=rhs.image)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment