我写了一个代码片段来计算结构相似性指数(SSIM),像素相似性,用于测量相似性的筛分功能以及两个图像之间的推土机距离。我想结合使用这四个指标来找到相似度百分比。
我尝试了度量标准中所有值的平均值,并将其转换为百分比。但是我对此方法非常怀疑
import warnings
from skimage.measure import compare_ssim
from skimage.transform import resize
from scipy.stats import wasserstein_distance
from scipy.misc import imsave
from scipy.ndimage import imread
import numpy as np
import cv2
##
# Globals
##
warnings.filterwarnings('ignore')
# specify resized image sizes
height = 2**10
width = 2**10
##
# Functions
##
def get_img(path, norm_size=True, norm_exposure=False):
'''
Prepare an image for image processing tasks
'''
# flatten returns a 2d grayscale array
img = imread(path, flatten=True).astype(int)
# resizing returns float vals 0:255; convert to ints for downstream tasks
if norm_size:
img = resize(img, (height, width), anti_aliasing=True, preserve_range=True)
if norm_exposure:
img = normalize_exposure(img)
return img
def get_histogram(img):
'''
Get the histogram of an image. For an 8-bit, grayscale image, the
histogram will be a 256 unit vector in which the nth value indicates
the percent of the pixels in the image with the given darkness level.
The histogram's values sum to 1.
'''
h, w = img.shape
hist = [0.0] * 256
for i in range(h):
for j in range(w):
hist[img[i, j]] += 1
return np.array(hist) / (h * w)
def normalize_exposure(img):
'''
Normalize the exposure of an image.
'''
img = img.astype(int)
hist = get_histogram(img)
# get the sum of vals accumulated by each position in hist
cdf = np.array([sum(hist[:i+1]) for i in range(len(hist))])
# determine the normalization values for each unit of the cdf
sk = np.uint8(255 * cdf)
# normalize each position in the output image
height, width = img.shape
normalized = np.zeros_like(img)
for i in range(0, height):
for j in range(0, width):
normalized[i, j] = sk[img[i, j]]
return normalized.astype(int)
def earth_movers_distance(path_a, path_b):
'''
Measure the Earth Mover's distance between two images
@args:
{str} path_a: the path to an image file
{str} path_b: the path to an image file
@returns:
TODO
'''
img_a = get_img(path_a, norm_exposure=True)
img_b = get_img(path_b, norm_exposure=True)
hist_a = get_histogram(img_a)
hist_b = get_histogram(img_b)
return wasserstein_distance(hist_a, hist_b)
def structural_sim(path_a, path_b):
'''
Measure the structural similarity between two images
@args:
{str} path_a: the path to an image file
{str} path_b: the path to an image file
@returns:
{float} a float {-1:1} that measures structural similarity
between the input images
'''
img_a = get_img(path_a)
img_b = get_img(path_b)
sim, diff = compare_ssim(img_a, img_b, full=True) # if 1 they are similar
return sim
def pixel_sim(path_a, path_b):
'''
Measure the pixel-level similarity between two images
@args:
{str} path_a: the path to an image file
{str} path_b: the path to an image file
@returns:
{float} a float {-1:1} that measures structural similarity
between the input images
'''
img_a = get_img(path_a, norm_exposure=True)
img_b = get_img(path_b, norm_exposure=True)
return np.sum(np.absolute(img_a - img_b)) / float(height*width) / 255
def sift_sim(path_a, path_b):
'''
Use SIFT features to measure image similarity
@args:
{str} path_a: the path to an image file
{str} path_b: the path to an image file
@returns:
TODO
'''
# initialize the sift feature detector
orb = cv2.ORB()
# get the images
img_a = cv2.imread(path_a, 0)
img_b = cv2.imread(path_b, 0)
# find the keypoints and descriptors with SIFT
kp_a, desc_a = orb.detectAndCompute(img_a, None)
kp_b, desc_b = orb.detectAndCompute(img_b, None)
# initialize the bruteforce matcher
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
# match.distance is a float between {0:100} - lower means more similar
matches = bf.match(desc_a, desc_b)
similar_regions = [i for i in matches if i.distance < 70]
if len(matches) == 0:
return 0
return len(similar_regions) / float(len(matches))
if __name__ == '__main__':
img_a = 'sample/image1.png'
img_b = 'sample/image2.png' #sample/087_GR_ALL_RS_036.png
# get the similarity values
structural_sim = structural_sim(img_a, img_b) # 1 is perfect structural similarity. A value of -1 indicates no structural similarity
pixel_sim = pixel_sim(img_a, img_b) # 0 is similar
sift_sim = sift_sim(img_a, img_b) # 1 is similar
emd = earth_movers_distance(img_a, img_b) # 0.0 is similar
print(structural_sim, pixel_sim, sift_sim, emd)
我希望结果的百分比为75%,88%,90%。
[EDIT]考虑来自https://imgur.com/Ys2xXJu的image1 并考虑来自https://imgur.com/881sz0V
的image2