The % (modulo) operator yields the remainder from the division of the first argument by the second. The numeric arguments are first converted to a common type. A zero right argument raises the ZeroDivisionError exception. The arguments may be floating point numbers, e.g., 3.14%0.7 equals 0.34 (since 3.14 equals 4*0.7 + 0.34.) The modulo operator always yields a result with the same sign as its second operand (or zero); the absolute value of the result is strictly smaller than the absolute value of the second operand .
6%2 evaluates to
0 because there"s no remainder if 6 is divided by 2 ( 3 times ).
7%2 evaluates to
1 because there"s a remainder of
1 when 7 is divided by 2 ( 3 times ).
So to summarise that, it returns the remainder of a division operation, or
0 if there is no remainder. So
6%2 means find the remainder of 6 divided by 2.
Option 1: Load both images as arrays (
scipy.misc.imread) and calculate an element-wise (pixel-by-pixel) difference. Calculate the norm of the difference.
Option 2: Load both images. Calculate some feature vector for each of them (like a histogram). Calculate distance between feature vectors rather than images.
However, there are some decisions to make first.
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 gray-scale 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.
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.
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) else: 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
if __name__ == "__main__": 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 compare.py 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 compare.py one.jpg one-blurred.jpg Manhattan norm: 92605183.67 / per pixel: 13.4210411116 Zero norm: 6900000 / per pixel: 1.0
P.S. Entire compare.py script.
As the question is about a video sequence, where frames are likely to be almost the same, and you look for something unusual, I"d like to mention some alternative approaches which may be relevant:
I strongly recommend taking a look at ‚ÄúLearning OpenCV‚Äù book, Chapters 9 (Image parts and segmentation) and 10 (Tracking and motion). The former teaches to use Background subtraction method, the latter gives some info on optical flow methods. All methods are implemented in OpenCV library. If you use Python, I suggest to use OpenCV ‚â• 2.3, and its
cv2 Python module.
The most simple version of the background subtraction:
More advanced versions make take into account time series for every pixel and handle non-static scenes (like moving trees or grass).
The idea of optical flow is to take two or more frames, and assign velocity vector to every pixel (dense optical flow) or to some of them (sparse optical flow). To estimate sparse optical flow, you may use Lucas-Kanade method (it is also implemented in OpenCV). Obviously, if there is a lot of flow (high average over max values of the velocity field), then something is moving in the frame, and subsequent images are more different.
Comparing histograms may help to detect sudden changes between consecutive frames. This approach was used in Courbon et al, 2010:
Similarity of consecutive frames. The distance between two consecutive frames is measured. If it is too high, it means that the second frame is corrupted and thus the image is eliminated. The Kullback‚ÄìLeibler distance, or mutual entropy, on the histograms of the two frames:
where p and q are the histograms of the frames is used. The threshold is fixed on 0.2.
All integers that can be represented by floating point numbers have an exact representation. So you can safely use
int on the result. Inexact representations occur only if you are trying to represent a rational number with a denominator that is not a power of two.
That this works is not trivial at all! It"s a property of the IEEE floating point representation that int‚àòfloor = ‚åä‚ãÖ‚åã if the magnitude of the numbers in question is small enough, but different representations are possible where int(floor(2.3)) might be 1.
To quote from Wikipedia,
Any integer with absolute value less than or equal to 224 can be exactly represented in the single precision format, and any integer with absolute value less than or equal to 253 can be exactly represented in the double precision format.
I noticed that in python there are two similar looking methods for finding the absolute value of a number:
import math math.fabs(-5)
How do these methods differ?
The role of adaptation, learning and optimization are becoming increasingly essen- tial and intertwined. The capability of a system to adapt either through modification of its physiological structure ...
Acquire and analyze data from all corners of the social web with Python. This book is for intermediate Python developers who want to engage with the use of public APIs to collect data from social m...
We live in an age of so-called Big Data. We hear terms like data scientist, and there is much talk about analytics and the mining of large amounts of corporate data for tidbits of business value. Ther...
Learning Correct Cryptography by Example. The interconnected world of the current era has drastically changed everything, including banking, entertainment, and even statecraft. Despite difference...