質問のタイトルは、比較する 2 つの正確な画像があることを示唆しており、それは簡単に行われます。ここで、比較する類似の画像がある場合、完全に満足のいく答えが見つからなかった理由が説明されます。期待される結果をもたらすすべての問題に適用できるメトリックはありません (期待される結果はアプリケーションによって異なることに注意してください)。問題の 1 つは、カラー画像のように、複数のバンドを持つ画像を比較することが (共通の合意がないという意味で) 難しいことです。それを処理するために、各バンドで特定のメトリックの適用を検討し、そのメトリックの結果が最低の結果値になります。これは、メトリックが [0, 1] のように十分に確立された範囲を持っていることを前提としています。この範囲の最大値は、イメージが (指定されたメトリックによって) 同一であることを意味します。逆に、
したがって、ここで行うことは、2 つの指標を提供することだけです。それらの 1 つはSSIMで、もう 1 つは NRMSE (平均二乗誤差の根の正規化) と呼びます。それは非常に単純な方法であり、あなたの問題には十分かもしれないので、私は2番目のものを提示することにしました.
例から始めましょう。画像の順序は次のとおりです。f = PNG の元の画像、g1 = 50% の品質の JPEG f
(で作成convert f -quality 50 g
)、g2 = JPEG の 1% の品質f
、h = 「明るくした」g2。

結果 (四捨五入):
- NRMSE(f, g1) = 0.96
- NRMSE(f, g2) = 0.88
- NRMSE(f, h) = 0.63
- SSIM(f, g1) = 0.98
- SSIM(f, g2) = 0.81
- SSIM(f, h) = 0.55
ある意味では、両方のメトリクスは変更を適切に処理しましたがSSIM
、画像が実際に視覚的に異なる場合は低い類似性を報告し、画像が視覚的に非常に類似している場合は高い値を報告することで、より賢明であることが示されました. 次の例では、カラー画像 (f = 元の画像、g = 5% 品質の JPEG) を考えます。

- NRMSE(f, g) = 0.92
- SSIM(f, g) = 0.61
そのため、優先するメトリックとそのしきい値を決定するのはユーザー次第です。
さて、指標です。私が NRMSE と呼んでいるのは、単純に 1 - [RMSE / ( maxval
- minval
)] です。どこmaxval
で比較されている2つの画像からの最大強度であり、それぞれについて同じですminval
。RMSE は MSE の平方根で与えられます: sqrt[(sum(A - B) ** 2) / |A|]、ここで |A| は A の要素数を意味します。これにより、RMSE によって与えられる最大値はmaxval
です。画像内の MSE の意味をさらに理解したい場合は、たとえばhttps://ece.uwaterloo.ca/~z70wang/publications/SPM09.pdfを参照してください。メトリック SSIM (構造的類似性) はより複雑であり、以前に含まれていたリンクで詳細を確認できます。メトリクスを簡単に適用するには、次のコードを検討してください。
import numpy
from scipy.signal import fftconvolve
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 nrmse(im1, im2):
a, b = im1.shape
rmse = numpy.sqrt(numpy.sum((im2 - im1) ** 2) / float(a * b))
max_val = max(numpy.max(im1), numpy.max(im2))
min_val = min(numpy.min(im1), numpy.min(im2))
return 1 - (rmse / (max_val - min_val))
if __name__ == "__main__":
import sys
from scipy.signal import gaussian
from PIL import Image
img1 = Image.open(sys.argv[1])
img2 = Image.open(sys.argv[2])
if img1.size != img2.size:
print "Error: images size differ"
raise SystemExit
# Create a 2d gaussian for the window parameter
win = numpy.array([gaussian(11, 1.5)])
win2d = win * (win.T)
num_metrics = 2
sim_index = [2 for _ in xrange(num_metrics)]
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)
m = [res, nrmse(b1, b2)]
for i in xrange(num_metrics):
sim_index[i] = min(m[i], sim_index[i])
print "Result:", sim_index
指定された値がそれらよりも大きいssim
場合、画像の比較を拒否することに注意してください。window
はwindow
通常非常に小さく、デフォルトは 11x11 であるため、画像がそれよりも小さい場合、(メトリックの名前から) 比較する「構造」があまりないため、他のもの (他の関数などnrmse
) を使用する必要があります。ssim
おそらく、Matlab ではこれがはるかに高速に実行されるため、を実装するためのより良い方法があります。