Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unusual histogram after image decimation

After simple image decimation using: img_decim_arr = img_arr[::2,::2], I obtained histogram very similar to original image histogram:enter image description here
Decimation using: skimage.measure.block_reduce(img_arr, block_size = (2,2), func=np.mean) (2x2 block averaging) which is recommended method for downsampling (found on stackoverflow in some discussion) produces very characteristic histogram:enter image description here
Every second bin is bigger. I am not sure maybe this is due to some aliasing effect. Can anyone please explain and give some theoretical hints about how downsampling affects image (2D signal) histogram?

like image 274
MarcinBurz Avatar asked Jun 25 '15 06:06

MarcinBurz


1 Answers

The problem is the np.mean function, because it does not round to integers and returns floats.

import numpy as np
import skimage.measure

a = (10 * np.random.randn(10,10) + 127).astype(np.uint8)
a
Out[4]: 
array([[121, 124, 139, 129, 130, 114, 127,  96, 114, 135],
       [127, 132, 102, 142, 119, 107, 138, 130, 141, 132],
       [113, 132, 132, 118, 121, 120, 142, 115, 124, 128],
       [127, 121, 129, 129, 121, 119, 126, 113, 128, 116],
       [144, 131, 123, 131, 130, 137, 140, 142, 127, 128],
       [127, 126, 124, 115, 127, 125, 122, 126, 147, 132],
       [118, 119, 117, 117, 133, 149, 122, 120, 116, 138],
       [147, 147, 127, 117, 123, 123, 136, 121, 139, 129],
       [142, 129, 113, 111, 130, 116, 137, 127, 106, 148],
       [132, 141, 141, 142, 119, 132, 126, 115, 131, 122]], dtype=uint8)

b = skimage.measure.block_reduce(a, block_size = (2,2), func=np.mean)
b
Out[6]: 
array([[ 126.  ,  128.  ,  117.5 ,  122.75,  130.5 ],
       [ 123.25,  127.  ,  120.25,  124.  ,  124.  ],
       [ 132.  ,  123.25,  129.75,  132.5 ,  133.5 ],
       [ 132.75,  119.5 ,  132.  ,  124.75,  130.5 ],
       [ 136.  ,  126.75,  124.25,  126.25,  126.75]])

That might give you interesting side-effects in your own logic. It definitely screws with matplotlibs histogram function, because having floats makes it think differently about how to place the bin borders.

Check this out:

a = (10 * np.random.randn(200,200) + 127).astype(np.uint8)
b = skimage.measure.block_reduce(a, block_size = (2,2), func=np.mean)
hist(b.ravel(), bins=255)

enter image description here

The white bits are actually zero in the array that the hist function returns. It gets even worse if you force rounding in my toy example:

hist(b.ravel().astype(np.uint8), bins=255)

Ugly histogram

Giving it the bins and the range solves the problem. Even if you zoom close

 hist(b.ravel().astype(np.uint8), bins=255, range=(0,255))

Good histogram

Zoomed good histogram

like image 89
P.R. Avatar answered Oct 19 '22 11:10

P.R.