Point Operators

Point operators are functions that work with individual pixels, as opposed to taking in information about surrounding pixels as well. For example, a pointwise addition of two images \(f\) and \(g\) to produce a new image \(h\):

\[\forall \v x \in \mathbb{R}^2: h(\v x) = f(\v x) + g(\v x)\]

We index points in images with a vector \(\v x\) in row-column order, with an origin in the top-left. The y-axis increases downward, the x-axis increases to the right.

In [1]: f = np.arange(64).reshape((8,8))

In [2]: plt.imshow(f, cmap='gray');

In [3]: plt.xticks(np.arange(8));

In [4]: plt.yticks(np.arange(8));
../_images/indexing-images.png

Note

If you’re wondering why the Python code on this page is littered with semicolons (;) – that is the way to supress some extra output you don’t want in the IPython Sphinx extension that I use.

Using operator overloading we can define some examples of point operators:

\(\alpha\)-blending

Blending two images with a weight factor \(\alpha\).

\[h = (1-\alpha)f + \alpha g\]
Thresholding

Creating a binary image by checking whether each pixel is above or below some threshold \(t\). The mathematical notation makes use of the Iverson Bracket.

\[h = \left[f > t \right]\]
Unsharp Masking

If we have an image \(f\) and a blurred version of it, \(g\), we can create a sharpening effect by adding the difference to \(f\), adjusting the harshness of the effect with a weight factor \(\beta\):

\[h = f + \beta (f-g)\]

This is equivalent to \(\alpha\)-blending \(f\) and \(g\) where \(\alpha = - \beta\).

Proof
\[\begin{aligned} (1-\alpha)f + \alpha g &= f + \beta (f-g)\\ f - \alpha f + \alpha g &= f + \beta f - \beta g\\ \alpha (g-f) &= \beta (f-g)\\ \alpha (g-f) &= -\beta (g-f)\\ \alpha &= - \beta \text{ if } g-f \neq 0\\ \end{aligned}\]
Normalization

If an image \(f\) does not use the full range of possible values that its format allows, such as \([0, 255]\) for some grayscale image, we may perceive it as a low-contrast image. A solution can be to normalize the pixel values to use the full range of available values. This can actually be used to transform any set of values to a new range:

\[g = \left(f - \text{currentMin} \right) \frac{\text{newMax} - \text{newMin}}{\text{currentMax} - \text{currentMin}} + \text{newMin}\\\]
In [5]: f = np.array([0,2,4,6,8])

In [6]: new_min, new_max = 0, 50

In [7]: g = new_min + (f - f.min()) \
   ...:     * (new_max - new_min) / (f.max() - f.min())
   ...: 

In [8]: print(g)
[ 0.  12.5 25.  37.5 50. ]
Histogram Equalization

Even if an image does use the full range of possible values, it may still be the case that most of the pixels have intensity values on the low end, the high end or somewhere in middle; its histogram of pixel intensities may have strong peaks and valleys. Histogram equalization is a non-linear operation that flattens the frequency distribution of pixel intensities:

  1. Compute the cumulative distribution function (cdf) of the pixel intensity values in original image.

  2. Each pixel in the new image gets its intensity value according to the percentile where it places in the cdf:

    \[\text{cdf}(f (\v x)) \cdot \text{maxIntensity} \]