0

Running a python code to compare two images. It seems to compare most images well, that do not have white background but gets low results for equal images where white is not the same. Attaching the full code. original comparison I get a similarty of 50% or so which seems low since the images are identical.

import requests
import pandas as pd
import string
import time
import traceback
import os
import sys
import re
import os
import urllib.request
import io
import base64
import datetime
from lxml.html import fromstring
from functools import reduce
from itertools import cycle
from requests.exceptions import ConnectTimeout,ProxyError,ReadTimeout, ConnectionError
from bs4 import BeautifulSoup
from random import shuffle
from PIL import Image
from scipy.signal import gaussian
import numpy
from scipy.signal import fftconvolve
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.by import By
from PIL import Image, ImageChops
import cv2
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from selenium.webdriver.chrome.options import Options
from selenium import webdriver

file = r'Z:\Shared\Boto Egnyte\03 Resources\TOOLS\00 DESIGN rename\00 LIBRARY\TMP\orig.jpg'
a_to_z = string.ascii_uppercase
big_num = 0

def ssim(im1, im2, window, k=(0.01, 0.03), l=255):
    """See https://ece.uwaterloo.ca/~z70wang/research/ssim/"""
    # Check if the window is smaller than the images.
    for a, b in zip(window.shape, im1.shape):
        if a > b:
            return None, None
    # Values in k must be positive according to the base implementation.
    for ki in k:
        if ki < 0:
            return None, None

    c1 = (k[0] * l) ** 2
    c2 = (k[1] * l) ** 2
    window = window/numpy.sum(window)

    mu1 = fftconvolve(im1, window, mode='valid')
    mu2 = fftconvolve(im2, window, mode='valid')
    mu1_sq = mu1 * mu1
    mu2_sq = mu2 * mu2
    mu1_mu2 = mu1 * mu2
    sigma1_sq = fftconvolve(im1 * im1, window, mode='valid') - mu1_sq
    sigma2_sq = fftconvolve(im2 * im2, window, mode='valid') - mu2_sq
    sigma12 = fftconvolve(im1 * im2, window, mode='valid') - mu1_mu2

    if c1 > 0 and c2 > 0:
        num = (2 * mu1_mu2 + c1) * (2 * sigma12 + c2)
        den = (mu1_sq + mu2_sq + c1) * (sigma1_sq + sigma2_sq + c2)
        ssim_map = num / den
    else:
        num1 = 2 * mu1_mu2 + c1
        num2 = 2 * sigma12 + c2
        den1 = mu1_sq + mu2_sq + c1
        den2 = sigma1_sq + sigma2_sq + c2
        ssim_map = numpy.ones(numpy.shape(mu1))
        index = (den1 * den2) > 0
        ssim_map[index] = (num1[index] * num2[index]) / (den1[index] * den2[index])
        index = (den1 != 0) & (den2 == 0)
        ssim_map[index] = num1[index] / den1[index]

    mssim = ssim_map.mean()
    return mssim, ssim_map



def save_image_as_base64(browser, url):
    """

    """
    base = browser.execute_async_script("""
    var done = arguments[0];
    function toDataURL(url, callback) {
      var xhr = new XMLHttpRequest();
      xhr.onload = function() {
        var reader = new FileReader();
        reader.onloadend = function() {
          callback(reader.result);
        }
        reader.readAsDataURL(xhr.response);
      };
      xhr.open('GET', url);
      xhr.responseType = 'blob';
      xhr.send();
    }
    setTimeout(function(){
      done("notplayed");
    }, 12000);
    toDataURL('%s', done)""" % url)
    base = base.split(',')[-1]
    return base

def img_chk(img1, img2, big_num):
     # Create a 2d gaussian for the window parameter
    win = numpy.array([gaussian(11, 1.5)])
    win2d = win * (win.T)

    num_metrics = 2

    for band1, band2 in zip(img1.split(), img2.split()):
        b1 = numpy.asarray(band1, dtype=numpy.double)
        b2 = numpy.asarray(band2, dtype=numpy.double)
        # SSIM
        res, smap = ssim(b1, b2, win2d)
    print ("Result:", file, round(res,4))
    match_change = False
    if big_num == 0:
        big_num = round(res,4)
        row['Match'] = round(res,4)
        match_change = True
    if big_num < round(res,4):
        row['Match'] = round(res,4)
        big_num = round(res,4)
        match_change = True
    return match_change, big_num


def download_with_selenium(url):
    print('getting ',url)
    browser.get(url)
    time.sleep(1)
    html, title = browser.page_source, browser.title
    #open(urlparse(url).path[4:]+'.htmk','w',encoding='utf-8').write(html)
    return html, title

def expand2square(pil_img, background_color):
    width, height = pil_img.size
    if width == height:
        return pil_img
    elif width > height:
        result = Image.new(pil_img.mode, (width, width), background_color)
        result.paste(pil_img, (0, (width - height) // 2))
        return result
    else:
        result = Image.new(pil_img.mode, (height, height), background_color)
        result.paste(pil_img, ((height - width) // 2, 0))
        return result


chrome_options = Options()
chrome_options.headless = False
browser = webdriver.Chrome(
    service=Service(ChromeDriverManager().install()), options=chrome_options)
df = pd.DataFrame()

row = {}
ok_img = "https://m.media-amazon.com/images/I/51qVJ6oJ7sL._AC_.jpg"
big_num = 0

base = save_image_as_base64(browser, ok_img)
image_file = io.BytesIO(base64.b64decode(base))
img = Image.open(image_file)
wi, hi = img.size
if wi != hi:
    img = expand2square(img,(255,255,255))

orig = Image.open(file)
wi, hi = orig.size
if wi != hi:
    orig = expand2square(orig,(255,255,255))
if img.size != orig.size:
    orig = orig.resize(img.size, Image.ANTIALIAS)
match_change,big_num = img_chk(img, orig, big_num)
print(big_num)
Vaidas
  • 55
  • 6
  • I think you have to convert the images to `float32`. Something like `img1 = img1.astype(np.float32)` and `img2 = img2.astype(np.float32)`. I can't test it, because I can't execute the code you have posted. Please edit your question, and make sure we can execute the code (add the `import` statements, add the code that reads the images, make sure we have all the relevant inputs, and that the code is executable). – Rotem Mar 08 '23 at 21:32
  • Added the full code. One image is from online. Let me know if you know the issue. V. – Vaidas Mar 17 '23 at 15:41
  • There is a scale difference between `img` and `orig` when executing `img_chk(img, orig, big_num)`. For testing save the images: `img.save('new_img.png')` and `orig.save('new_orig.png')`. The images are: [new_img](https://i.stack.imgur.com/MVqTJ.png) and [new_orig](https://i.stack.imgur.com/BnkNv.png). As you can see, the shirt is larger in `new_img` image. For getting higher SSIM the size of the shirt should be as close as possible. We may find the scale differences using image matching techniques, but I think you better check why there is a scale difference in the first place. – Rotem Mar 17 '23 at 22:16
  • The SSIM computation is correct. I verified it using FFmpeg (command line interface): `ffmpeg -i new_orig.png -i new_img.png -lavfi "ssim;[0:v][1:v]psnr" -f null -` FFmpeg result is `0.5103` (very close to Python result of `0.5073`). – Rotem Mar 17 '23 at 22:21
  • I see. However the images are virtually the same. What algorithm can I use to find that the the images are actually showing the same object? – Vaidas Mar 20 '23 at 08:03
  • and also, i use extend2square to try to make the images the same size given that my original is square. is there a better way around it? I tried trimming it, to only the non white parts but got to the same place... – Vaidas Mar 20 '23 at 08:05
  • I am sure there is a solution, because Google has a feature that searches images that visually look the same. Google probably uses AI technology. I can't help you with that. For SSIM measurement the object size (in pixels) should be the same. – Rotem Mar 20 '23 at 09:09
  • For SSIM i use resizing orig = orig.resize(img.size, Image.ANTIALIAS) otherwise the code breaks. So the images are the same size. i'm still not sure why they end up so different - does SSIM compare pixel by pixel and if the image is a bit shifted to the left / right this is where de difference comes from? because if so maybe trimming whitespace instead of making it square would work better? – Vaidas Mar 20 '23 at 10:44
  • The shirt should be the same size and at the same position. – Rotem Mar 20 '23 at 10:57
  • Seems to have worked when I trimmed the white around instead of making it into a square - got 75% similarity. – Vaidas Mar 28 '23 at 07:41

0 Answers0