SSIM---结构相似性算法

  • 一.SSIM算法原理
  • 二.skimage.metrics包下的SSIM算法


一.SSIM算法原理

SSIM(structural similarity),结构相似性,是一种衡量两幅图像相似度的指标。SSIM算法主要用于检测两张相同尺寸的图像的相似度、或者检测图像的失真程度。原论文中,SSIM算法主要通过分别比较两个图像的亮度,对比度,结构,然后对这三个要素加权并用乘积表示。

SSIM pytorch版本 ssim python_SSIM pytorch版本


常数𝑪𝟏, 𝑪𝟐, 𝑪𝟑是为了避免当分母为 0 时造成的不稳定问题。

𝝁𝒙为均值, 𝝈𝒙 为方差, 𝝈𝒙𝒚 表示协方差。

SSIM pytorch版本 ssim python_python_02


SSIM pytorch版本 ssim python_python_03

二.skimage.metrics包下的SSIM算法

  • 函数原型:
def structural_similarity(*, im1, im2,
                         win_size=None, gradient=False, data_range=None,
                         multichannel=False, gaussian_weights=False,
                         full=False, **kwargs)
  • 参数:
    :Ndarray,输入图像

参数

含义

im1,im2

Ndarray,输入图像

win_size

int or none,optional,滑动窗口的边长,必为奇数,默认值为7, 当gaussian_weights=True时,滑动窗口的大小取决于sigma

gradient

bool, optional,若为True,返回相对于im2的梯度

data_range

float,optional,图像灰度级数,图像灰度的最小值和最大可能值,默认情况----根据图像的数据类型进行估计

multichannel

bool, optional,值为True时将 img.shape[-1] 视为图像通道数,对每个通道单独计算,取平均值作为相似度

gaussian_weights

bool, optional,高斯权重,值为True时,平均值和方差在空间上的权重为归一化高斯核 宽度sigma=1.5

full

bool, optional,值为true时,返回完整的结构相似性图像

  • 其他参数:
    use_sample_covariance:若为True,则通过N-1归一化协方差,N是滑动窗口内的像素数
    K1,K2: float, 算法参数,默认值K1=0.01,K2=0.03
    sigma: float,当gaussian_weights=True时,决定滑动窗口大小
  • 返回值:
    mssim—平均结构相似度
    grad—结构相似性梯度 (gradient=True)
    S—结构相似性图像(full=True)

下面是通过调用skimage.metrics包下的SSIM算法,结合OpenCV中的阈值分割及轮廓提取算法,找出两幅图像的差异。

import cv2
import imutils
from skimage.metrics import structural_similarity
import time
from skimage import filters, img_as_ubyte
import numpy as np

start = time.time()
# 读入图像,转为灰度图像
src = cv2.imread('C:/Users/Hedgehog/Desktop/right.jpg')
img = cv2.imread('C:/Users/Hedgehog/Desktop/left.jpg')
grayA = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
grayB = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 计算两个灰度图像之间的结构相似度
(score, diff) = structural_similarity(grayA, grayB, win_size=101, full=True)
diff = (diff * 255).astype("uint8")
cv2.namedWindow("diff", cv2.WINDOW_NORMAL)
cv2.imshow("diff", diff)
print("SSIM:{}".format(score))

# 找到不同的轮廓以致于可以在表示为 '不同'的区域放置矩形
# 全局自适应阈值分割(二值化),返回值有两个,第一个是阈值,第二个是二值图像
dst = cv2.threshold(diff, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
cv2.namedWindow("threshold", cv2.WINDOW_NORMAL)
cv2.imshow('threshold', dst)
# findContours找轮廓,返回值有两个,第一个是轮廓信息,第二个是轮廓的层次信息(“树”状拓扑结构)
# cv2.RETR_EXTERNAL:只检测最外层轮廓
# cv2.CHAIN_APPROX_SIMPLE:压缩水平方向、垂直方向和对角线方向的元素,保留该方向的终点坐标,如矩形的轮廓可用4个角点表示
contours, hierarchy = cv2.findContours(dst.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
print(contours)
newimg = np.zeros(dst.shape, np.uint8)  # 定义一个和图像分割处理后相同大小的黑色图
# drawContours画轮廓,将找到的轮廓信息画出来
cv2.drawContours(newimg, contours, -1, (255, 255, 255), 1)
cv2.namedWindow("contours", cv2.WINDOW_NORMAL)
cv2.imshow('contours', newimg)
# cnts = cnts[0] if imutils.is_cv3() else cnts[0]    取findContours函数的第一个返回值,即取轮廓信息

# 找到一系列区域,在区域周围放置矩形
for c in contours:
    (x, y, w, h) = cv2.boundingRect(c)  # boundingRect函数:计算轮廓的垂直边界最小矩形,矩形是与图像上下边界平行的
    cv2.rectangle(src, (x, y), (x + w, y + h), (0, 255, 0), 2)  # rectangle函数:使用对角线的两点pt1,pt2画一个矩形轮廓
    cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)  # 画矩形的图, pt1, pt2,(对角线两点的坐标), 矩形边框的颜色,矩形边框的粗细

end = time.time()
print(end - start)
# 用cv2.imshow 展现最终对比之后的图片
cv2.namedWindow("right", cv2.WINDOW_NORMAL)
cv2.imshow('right', src)
cv2.namedWindow("left", cv2.WINDOW_NORMAL)
cv2.imshow('left', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

SSIM pytorch版本 ssim python_python_04


SSIM pytorch版本 ssim python_相似度_05


SSIM pytorch版本 ssim python_相似度_06


SSIM pytorch版本 ssim python_相似度_07