General idea

Load both images as arrays (scipy.misc.imread) and calculate an element-wise difference. Calculate the norm of the difference.

However, there are some decisions to make.


You should answer these questions first:

  • Are images of the same shape and dimension?

    If not, you may need to resize or crop them. PIL library will help to do it in Python.

    If they are taken with the same settings and the same device, they are probably the same.

  • Are images well-aligned?

    If not, you may want to run cross-correlation first, to find the best alignment first. SciPy has functions to do it.

    If the camera and the scene are still, the images are likely to be well-aligned.

  • Is exposure of the images always the same? (Is lightness/contrast the same?)

    If not, you may want to normalize images.

    But be careful, in some situations this may do more wrong than good. For example, a single bright pixel on a dark background will make the normalized image very different.

  • Is color information important?

    If you want to notice color changes, you will have a vector of color values per point, rather than a scalar value as in grayscale image. You need more attention when writing such code.

  • Are there distinct edges in the image? Are they likely to move?

    If yes, you can apply edge detection algorithm first (e.g. calculate gradient with Sobel or Prewitt transform, apply some threshold), then compare edges on the first image to edges on the second.

  • Is there noise in the image?

    All sensors pollute the image with some amount of noise. Low-cost sensors have more noise. You may wish to apply some noise reduction before you compare images. Blur is the most simple (but not the best) approach here.

  • What kind of changes do you want to notice?

    This may affect the choice of norm to use for the difference between images.

    Consider using Manhattan norm (the sum of the absolute values) or zero norm (the number of elements not equal to zero) to measure how much the image has changed. The former will tell you how much the image is off, the latter will tell only how many pixels differ.


I assume your images are well-aligned, the same size and shape, possibly with different exposure. For simplicity, I convert them to grayscale even if they are color (RGB) images.

You will need these imports:

import sys

from scipy.misc import imread
from scipy.linalg import norm
from scipy import sum, average

Main function, read two images, convert to grayscale, compare and print results:

def main():
    file1, file2 = sys.argv[1:1+2]
    # read images as 2D arrays (convert to grayscale for simplicity)
    img1 = to_grayscale(imread(file1).astype(float))
    img2 = to_grayscale(imread(file2).astype(float))
    # compare
    n_m, n_0 = compare_images(img1, img2)
    print "Manhattan norm:", n_m, "/ per pixel:", n_m/img1.size
    print "Zero norm:", n_0, "/ per pixel:", n_0*1.0/img1.size

How to compare. img1 and img2 are 2D SciPy arrays here:

def compare_images(img1, img2):
    # normalize to compensate for exposure difference, this may be unnecessary
    # consider disabling it
    img1 = normalize(img1)
    img2 = normalize(img2)
    # calculate the difference and its norms
    diff = img1 - img2  # elementwise for scipy arrays
    m_norm = sum(abs(diff))  # Manhattan norm
    z_norm = norm(diff.ravel(), 0)  # Zero norm
    return (m_norm, z_norm)

If the file is a color image, imread returns a 3D array, average RGB channels (the last array axis) to obtain intensity. No need to do it for grayscale images (e.g. .pgm):

def to_grayscale(arr):
    "If arr is a color image (3D array), convert it to grayscale (2D array)."
    if len(arr.shape) == 3:
        return average(arr, -1)  # average over the last axis (color channels)
        return arr

Normalization is trivial, you may choose to normalize to [0,1] instead of [0,255]. arr is a SciPy array here, so all operations are element-wise:

def normalize(arr):
    rng = arr.max()-arr.min()
    amin = arr.min()
    return (arr-amin)*255/rng

Run the main function:

if __name__ == "__main__":

Now you can put this all in a script and run against two images. If we compare image to itself, there is no difference:

$ python one.jpg one.jpg
Manhattan norm: 0.0 / per pixel: 0.0
Zero norm: 0 / per pixel: 0.0

If we blur the image and compare to the original, there is some difference:

$ python one.jpg one-blurred.jpg 
Manhattan norm: 92605183.67 / per pixel: 13.4210411116
Zero norm: 6900000 / per pixel: 1.0

Manhattan norm: 모든 이미지에서의 절대값 컬러들의 변화를 나타낸다. 따라서 픽셀당 어느정도의 차이를 나타내는지를 알 수 있다.

Zero norm: 같지 않은 픽셀의 수이다.


In image processingnormalization is a process that changes the range of pixel intensity values.

Application에서 사용되어지는 이미지들은 떄때로 약한 차이를 보이게 된다. (poor contrast) 왜냐하면, glare (눈부심)  때문이다. 

Normarlization이란 때때로 contrast stretching 또는 histogram stretching이라고 불리워 진다.

좀 더, 일반적인 Data processing에서는 예를들면, Digital signal processing과 같은 곳에서는 이러한 처리를 Dynamic range expansion으로 나타낸다.

하나의 예로, 신문기사에서의 그림은 모두 흑백이기 때문에 차이가 거의 없다. 따라서 그 경우에 정규화를 실행 하게 된다. 그렇게 해서 차이를 좀더 분명하게 한다.

실제 예를 들어서 설명하도록 하겠다.

linear normalization of a grayscale digital image is performed according to the formula



새로운 Image Pixel I_n은 = 기존의 이미지 픽셀에서 최소값을 뺀것에 새로운 픽셀 이미지 범위가 0~255라면 255/ Max-Min + 0 로 곲해서 구한다.

어떤 예제의 실제이미지 범위가 50~180 이 일때 원하는 범위(desired range) 0~255 

이렇게 될 경우 현재 모든 이미지의 픽셀들에서 최소값인 50을 빼게된다.

그럼 실제값의 범위가 0~130으로 조정이 된다. 이것을 다시 0~255로 늘리려면,

새로운 실제값 (I-Min)  X  255/ 130 을 하면 된다.

130 * 255/130 =  255 이기 때문이다. 즉 180이 255으로 변했다. 

50의 경우

0 * 255/130 = 0 이기 때문에 0으로 변하게 된다.


그렇게 되면 50~180 ---> 0~130으로 변경되어진다.

그 다음에 multiplied by 255/130으로 해서 0~255새로운 범위로 제작한다.

위 과정을 요약하면 아래와 같다.

1) 50~180 // 처음 이미지 범위.

2) 0~130 // min뺀 새로운 이미지 범위.

3) 0~255 // contrast stretching을 한 새로운 이미지 범위.

결론: 따라서 new Image Range가 똑같다면, 비교하는 값은 같게 된다.

P.S. Entire script.


Conversion of a color image to grayscale is not unique 

참고 사이트

+ Recent posts