  # Python – abs vs fabs

absolute value | fabs | StackOverflow

I noticed that in python there are two similar looking methods for finding the absolute value of a number:

First

``````abs(-5)
``````

Second

``````import math
math.fabs(-5)
``````

How do these methods differ?

## Python - abs vs fabs: StackOverflow Questions

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 .

Example 1: `6%2` evaluates to `0` because there"s no remainder if 6 is divided by 2 ( 3 times ).

Example 2: `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.

## General idea

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.

## Questions

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.

## Example

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.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)
# 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)
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
``````

Run the `main` function:

``````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.

## Update: relevant techniques

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:

• background subtraction and segmentation (to detect foreground objects)
• sparse optical flow (to detect motion)
• comparing histograms or some other statistics instead of images

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:

• learn the average value Œº and standard deviation œÉ for every pixel of the background
• compare current pixel values to the range of (Œº-2œÉ,Œº+2œÉ) or (Œº-œÉ,Œº+œÉ)

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.

## Python - abs vs fabs

I noticed that in python there are two similar looking methods for finding the absolute value of a number:

First

``````abs(-5)
``````

Second

``````import math
math.fabs(-5)
``````

How do these methods differ?