Processing math: 100%
INFO-H-500 Image Acquisition & Processing
  • Home
  • 1.Introduction
    • Biological vision
    • Image sensors
    • Image representation
  • 2.Low-level image processing
    • Histogram
    • Linear filtering
    • Rank based filters
    • Image restoration
    • Edge detection
  • 3.Image segmentation
    • Typical image processing pipelines
    • Histogram based segmentation
    • Border based segmentation
    • Region based segmentation
    • Model based segmentation
      • Model based segmentation
      • Active contours
    • Examples
  • 4.Detection
    • Hough transform
    • Detectors
  • 5.Morphomathematics
    • Morphomathematical operators
    • Combined operations
    • The watershed transform
    • Gray level morphology
  • 6.Objects features
    • Statistical features
    • Contour features
    • Object moments
    • Texture features
  • LABS
  • References
  • About
  • Search
  • Previous
  • Next
  • GitHub
  • Histogram
  • Look-Up-Table
    • Negative
    • Threshold
    • Semi-threshold
    • Gamma correction
    • Auto-level
    • Equalization
In [1]:
Copied!
%matplotlib inline

from IPython.display import HTML,Image,SVG,YouTubeVideo
%matplotlib inline from IPython.display import HTML,Image,SVG,YouTubeVideo

Histogram¶

In [2]:
Copied!
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
from skimage.data import camera,astronaut
plt.style.use('ggplot')
import numpy as np import matplotlib.pyplot as plt from matplotlib import cm from skimage.data import camera,astronaut plt.style.use('ggplot')
In [3]:
Copied!
def norm_hist(ima):
    hist,bins = np.histogram(ima.flatten(),range(256))  # histogram is computed on a 1D distribution --> flatten()
    return 1.*hist/np.sum(hist) # normalized histogram

def display_hist(ima,vmin=None,vmax=None):
    plt.figure(figsize=[10,5])
    if ima.ndim == 2:
        nh = norm_hist(ima)
    else:
        nh_r = norm_hist(ima[:,:,0])
        nh_g = norm_hist(ima[:,:,1])
        nh_b = norm_hist(ima[:,:,2])
    # display the results
    plt.subplot(1,2,1)
    plt.imshow(ima,cmap=cm.gray,vmin=vmin,vmax=vmax)
    plt.subplot(1,2,2)
    if ima.ndim == 2:
        plt.plot(nh,label='hist.')
    else:
        plt.plot(nh_r,color='r',label='r')
        plt.plot(nh_g,color='g',label='g')
        plt.plot(nh_b,color='b',label='b')
    plt.legend()
    plt.xlabel('gray level');
    
display_hist(camera())
display_hist(astronaut())
def norm_hist(ima): hist,bins = np.histogram(ima.flatten(),range(256)) # histogram is computed on a 1D distribution --> flatten() return 1.*hist/np.sum(hist) # normalized histogram def display_hist(ima,vmin=None,vmax=None): plt.figure(figsize=[10,5]) if ima.ndim == 2: nh = norm_hist(ima) else: nh_r = norm_hist(ima[:,:,0]) nh_g = norm_hist(ima[:,:,1]) nh_b = norm_hist(ima[:,:,2]) # display the results plt.subplot(1,2,1) plt.imshow(ima,cmap=cm.gray,vmin=vmin,vmax=vmax) plt.subplot(1,2,2) if ima.ndim == 2: plt.plot(nh,label='hist.') else: plt.plot(nh_r,color='r',label='r') plt.plot(nh_g,color='g',label='g') plt.plot(nh_b,color='b',label='b') plt.legend() plt.xlabel('gray level'); display_hist(camera()) display_hist(astronaut())
In [4]:
Copied!
def display_hist2(ima):
    nh = norm_hist(ima)
    cumul_hist = np.cumsum(nh)
    
    plt.figure(figsize=[10,5])
    plt.subplot(1,2,1)
    plt.imshow(ima,cmap=cm.gray)
    ax1 = plt.subplot(1,2,2)
    plt.plot(nh)
    ax2 = ax1.twinx()
    plt.plot(cumul_hist,label='cumul.',color='k')
    plt.legend()
    
display_hist2(camera())
def display_hist2(ima): nh = norm_hist(ima) cumul_hist = np.cumsum(nh) plt.figure(figsize=[10,5]) plt.subplot(1,2,1) plt.imshow(ima,cmap=cm.gray) ax1 = plt.subplot(1,2,2) plt.plot(nh) ax2 = ax1.twinx() plt.plot(cumul_hist,label='cumul.',color='k') plt.legend() display_hist2(camera())

Look-Up-Table¶

Example are given for 8-bits images but can of course be generalized for any kind of integer image, however, due to memory limitation, LUT method will be used only with bit-depth limited images.

In [5]:
Copied!
def apply_lut(ima,lut,vmin=None,vmax=None):
    nh = norm_hist(ima)
    lima = lut[ima]
    nh_lima = norm_hist(lima)
    
    plt.figure(figsize=[10,5])
    plt.subplot(1,2,1)
    plt.imshow(lima,cmap=cm.gray,vmin=vmin,vmax=vmax)
    ax1 = plt.subplot(1,2,2)
    plt.plot(nh,label='ima')
    plt.plot(nh_lima,label='lut[ima]')
    plt.legend(loc='upper left')
    ax2 = ax1.twinx()
    plt.plot(lut,label='lut',color='k')
    plt.legend()
def apply_lut(ima,lut,vmin=None,vmax=None): nh = norm_hist(ima) lima = lut[ima] nh_lima = norm_hist(lima) plt.figure(figsize=[10,5]) plt.subplot(1,2,1) plt.imshow(lima,cmap=cm.gray,vmin=vmin,vmax=vmax) ax1 = plt.subplot(1,2,2) plt.plot(nh,label='ima') plt.plot(nh_lima,label='lut[ima]') plt.legend(loc='upper left') ax2 = ax1.twinx() plt.plot(lut,label='lut',color='k') plt.legend()

Negative¶

gout=255−gin

To apply this inversion tp the complete image, one use the Look Up Table (LUT) method which consist in pre-computng the transformed levels for all the 255 possible gray level into one vector. Image transformation is then a simple vector addressing.

lut = np.arange(255,-1,-1) g_out = lut[g_in]

In [6]:
Copied!
# LUT invertion    
ima = camera()
lut = np.arange(255,-1,-1)
apply_lut(ima,lut)
# LUT invertion ima = camera() lut = np.arange(255,-1,-1) apply_lut(ima,lut)

Threshold¶

Look up table for a simple threshold is:

gout={255,if gin>th0,otherwise
In [7]:
Copied!
def lut_threshold(th):
    lut = np.arange(0,256)
    lut = 255 * (lut > th)
    return lut 

apply_lut(ima,lut_threshold(128))
def lut_threshold(th): lut = np.arange(0,256) lut = 255 * (lut > th) return lut apply_lut(ima,lut_threshold(128))

Semi-threshold¶

Look up table for a simple threshold is:

gout={gin,if gin>th0,otherwise
In [8]:
Copied!
def lut_semi_threshold(th):
    lut = np.arange(0,256)
    lut[lut < th] = 0
    return lut 

apply_lut(ima,lut_semi_threshold(128))
def lut_semi_threshold(th): lut = np.arange(0,256) lut[lut < th] = 0 return lut apply_lut(ima,lut_semi_threshold(128))

Gamma correction¶

Gamma transform is used to reinforce contrast of the image, level trasform is given by:

gout=Agγin

where A=255(1−γ)

if γ<1 the low-level are contrasted, reversely if γ>1 bright part of the image gains in contrast.

In [9]:
Copied!
def lut_gamma(gamma):
    lut = np.power(np.arange(0,256),gamma) * np.power(255,1-gamma)
    return lut 

apply_lut(ima,lut_gamma(.3))
apply_lut(ima,lut_gamma(1.7))
def lut_gamma(gamma): lut = np.power(np.arange(0,256),gamma) * np.power(255,1-gamma) return lut apply_lut(ima,lut_gamma(.3)) apply_lut(ima,lut_gamma(1.7))

Auto-level¶

Auto-level map the complete image dynamic to the full dynamic scale:

gout=255gin−gmingmax−gmin

where gmin and gmax are respectively minimimal and maximal value present in the image.

In [10]:
Copied!
def lut_autolevel(ima):
    g_min = np.min(ima)
    g_max = np.max(ima)
    lut = 255*(np.arange(0,256)-g_min)/(1.*g_max-g_min)
    lut[0:g_min]=0
    lut[g_max:] = 255
    return lut

ima=camera()
t_ima = (ima/4+64).astype(np.uint8)
display_hist(t_ima,vmin=0,vmax=255)
apply_lut(t_ima,lut_autolevel(t_ima))
def lut_autolevel(ima): g_min = np.min(ima) g_max = np.max(ima) lut = 255*(np.arange(0,256)-g_min)/(1.*g_max-g_min) lut[0:g_min]=0 lut[g_max:] = 255 return lut ima=camera() t_ima = (ima/4+64).astype(np.uint8) display_hist(t_ima,vmin=0,vmax=255) apply_lut(t_ima,lut_autolevel(t_ima))

Equalization¶

One may be interested in using as many gray levels possible for frequent levels, and in grouping rare levels. This is called histogram equalization since, after the operation, the histogram distribution is more equal.

The next figure illustrate equalization done of the cameraman picture.

In [11]:
Copied!
def lut_equalization(ima):
    nh = norm_hist(ima)
    ch = np.append(np.array(0),np.cumsum(nh))
    lut = 255*ch
    return lut
apply_lut(ima,lut_equalization(ima))
def lut_equalization(ima): nh = norm_hist(ima) ch = np.append(np.array(0),np.cumsum(nh)) lut = 255*ch return lut apply_lut(ima,lut_equalization(ima))

We can see that levels frequently observed (in the sky) are now more spread (more contrast is visible), the same inside the cameraman where details are now visible (hand). The histogram is not perctly equal, this is due to the technique used (the look up table), indeed pixel having an equal gray level are transform similarily, they cannot be separated.

If we look to the code used to achieve the equalization, we see that we simply used, as look up table, the summed histogram !

Here is the justification of that:

  • the gray level(arbitrarily set in [0,1]) probability is given by:
pr(r)=nrn0≤r≤1

where nr is the number of pixels having the value r anf n the total number of image pixels.

  • let's consider a transform T that maps graylevels r to graylevel s, T(r) is considered as monotically increasing on 0≤r≤1.
s=T(r)0≤T(r)≤1r=T−1(s)

We also assume that T−1(s) is monotically increasing on 0≤s≤1 and bounded to [0,1].

  • from probability theory, the probability density function of the transformed gray level is:
ps(s)=[pr(r)drds]r=T−1(s)
  • if we consider the following transform function:
s=T(r)=∫r0pr(w)dw0≤r≤1
  • then
dsdr=pr(r)
  • we can substitute this fraction in the previous equation:
ps(s)=[pr(r)1pr(r)]r=T−1(s)=[1]r=T−1(s)=10≤s≤1

which is uniform on the interval.

In [12]:
Copied!
#other example
from skimage.io import imread
ima = imread('../data/Lung_Cancer_on_Chest_X-Ray.jpg')[:,:,0]
lut = lut_equalization(ima)
plt.figure(figsize=[10,10])
plt.imshow(ima,cmap=cm.gray)
plt.figure(figsize=[10,10])
plt.imshow(lut[ima],cmap=cm.gray);
#other example from skimage.io import imread ima = imread('../data/Lung_Cancer_on_Chest_X-Ray.jpg')[:,:,0] lut = lut_equalization(ima) plt.figure(figsize=[10,10]) plt.imshow(ima,cmap=cm.gray) plt.figure(figsize=[10,10]) plt.imshow(lut[ima],cmap=cm.gray);

if we need to increase the conrtrast in a certain part of the image, equalization LUT may be restricted to a certain area:

In [13]:
Copied!
roi = [(400,200),100,100]
sample = ima[roi[0][1]:roi[0][1]+roi[2],roi[0][0]:roi[0][0]+roi[1]]
lut = lut_equalization(sample)

plt.figure(figsize=[10,10])
plt.imshow(ima,cmap=cm.gray)
rect = plt.Rectangle(*roi, facecolor=None,alpha=.25)
plt.gca().add_patch(rect)


plt.figure(figsize=[10,10])
plt.imshow(lut[ima],cmap=cm.gray);
rect = plt.Rectangle(*roi, facecolor=None,alpha=.25)

plt.gca().add_patch(rect);
roi = [(400,200),100,100] sample = ima[roi[0][1]:roi[0][1]+roi[2],roi[0][0]:roi[0][0]+roi[1]] lut = lut_equalization(sample) plt.figure(figsize=[10,10]) plt.imshow(ima,cmap=cm.gray) rect = plt.Rectangle(*roi, facecolor=None,alpha=.25) plt.gca().add_patch(rect) plt.figure(figsize=[10,10]) plt.imshow(lut[ima],cmap=cm.gray); rect = plt.Rectangle(*roi, facecolor=None,alpha=.25) plt.gca().add_patch(rect);

see also:

  • histogram based methods IPAMV pp58-61
In [ ]:
Copied!


Creative Commons License maintained by Olivier Debeir and contributors.

Documentation built with MkDocs.

Search

From here you can search these documents. Enter your search terms below.

Keyboard Shortcuts

Keys Action
? Open this help
n Next page
p Previous page
s Search