Image moments

Borrowing nomenclature from probability theory, we can define certain moments based on the intensity value of the image. Moments are useful for computing properties such as centroid and area of an object. We will list the general case, where is a discrete image taking grayscale values.

Raw moments

The raw moments of of order are defined as

From this, we can e.g. compute the centroid

where, in case of a binary image, is the area of the foreground object.

Central moments

Central moments are moments that are centered around the centroid, and thus invariant to translation

With this, we can compute the covariance matrix

from which we can compute eigenvectors. Now, the angle of eigenvector corresponding to the largest eigenvalue is the angle of the major axis of the object, which we can define as the orientation of the object.

We will here derive some of the lower central moments.

Obviously,

For the first order central moments,

and likewise, .

And, finaly for the second order moments

and in a similar manner, .

Normalized central moments

We can in addition to translation invariance obtain scale invariance with normalized central moments

Hu moments

Hu moments are invariant to translation, scale, and rotation, and are stated below for completion.

Example

In this example, we will find the centroid and the direction of a swarm of birds, or at least of the birds in the image bird_swarm.jpg, which can be found here.

Figure 1: Swarm of birds.

We first read in the image, and threshold it to get the birds as foreground.

import numpy as np
import matplotlib.pyplot as plt
import cv2

image_file = '../../bird_swarm.jpg' # Change this to your location
img = cv2.imread(image_file, cv2.IMREAD_COLOR)

gl_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
thresh_img = gl_img < 50
plt.imshow(thresh_img, cmap='gray')
plt.xticks([]), plt.yticks([])
plt.show()
Figure 2: Thresholded swarm, birds as foreground.

Then, we compute the moments, and note that for background and for foreground. Notice also that we use (, ) as in a regular cartesian coordinate convention.

m00 = m01 = m10 = m11 = m20 = m02 = m21 = m12 = 0
height, width = thresh_img.shape
for y in range(height):
  for x in range(width):
    m00 += thresh_img[y, x]
    m10 += x*thresh_img[y, x]
    m01 += y*thresh_img[y, x]
    m11 += x*y*thresh_img[y, x]
    m20 += x*x*thresh_img[y, x]
    m02 += y*y*thresh_img[y, x]
    m21 += x*x*y*thresh_img[y, x]
    m12 += x*y*y*thresh_img[y, x]

Next, we compute the centroid

cx = m10 / m00
cy = m01 / m00
print('Centriod: ({0:.2f}, {1:.2f})'.format(cx, cy))

which outputs Centriod: (1034.36, 654.48). Using the central moments above, we can also compute the angle of the major axis of the swarm, relative to the horizontal coordinate axis. Note that we use np.arctan2(...) to make our life easier, quadrant-wise.

mu00 = m00
mu11 = m11 - cx*m01
mu20 = m20 - cx*m10
mu02 = m02 - cy*m01
theta = 1/2*np.arctan2(2*mu11/mu00, (mu20 - mu02)/mu00)
print('Angle {0:.2f}'.format(theta*180/np.pi))

which prints Angle: 38.05. We now plot the major and minor axis (with arbitrary length) on top of the original image to illustrate the location of the centriod and the angle.

rho = 800
dx_major = rho*np.cos(theta)
dy_major = rho*np.sin(theta)
dx_minor = 0.3*rho*np.cos(theta - np.pi/2)
dy_minor = 0.3*rho*np.sin(theta - np.pi/2)

plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
plt.plot([cx-dx_minor, cx, cx+dx_minor], [cy-dy_minor, cy, cy+dy_minor], 'bo-')
plt.plot([cx-dx_major, cx, cx+dx_major], [cy-dy_major, cy, cy+dy_major], 'ro-')
plt.xticks([]), plt.yticks([])

# Remove redundant space left by the plt.plot() commands
axes = plt.gca()
axes.set_xlim([0, width])
axes.set_ylim([height, 0])

plt.show()
Figure 3: Bird swarm with centroid, major axis (red) and minor axis (blue).

Region properties

Based on the contour of an object, we will here show how to estimate the area and perimeter of this object. For reference, see e.g. (Yang, Albregtsen, Lønnestad, Grøttum (1994)) Methods to estimate areas and perimeters of blob-like objects: a comparison.

Properties from chain code

For 8-connected chain code, we can approximate the area an perimeter using the following formulas.

Here, is the length of the chain code, and indicates the change in direction of and , respectively, from chain code element . E.g. for , and . and is the number of even and odd chain code elements, and is the number of corners in the chain code. is the position at element (this can be initialized to an arbitrary value as the chain code should be translation invariant).

Freeman

Vossepoel and Smeulders

Kulpa

Properties from bit quads pattern matching

We can also estimate the area and perimeter of an object by matching local windows in an image with some patterns that we will define below. For a given list of patterns and a local window in an image, we match the window to any of the patterns in the pattern list. We do this for all local windows in an image, and accumulate the number of matches in a count variable . Explicitly, if our pattern is , we select a window, beginning with pixels , the next windown will be one pixel to the right, and we continue in this sliding fashion until the whole image is covered. Note that it is important that the region you are examining is filled.

Patterns

The following (list of) patterns is defined:

Single

Horizontal

Vertical

Qadratic 0

Qadratic 1

Qadratic 2

Qadratic 3

Qadratic 4

Qadratic diagonal

Property estimates

Referring to the patterns above, we can estimate the area and perimeter in a number of ways.

4-connected objects

Gray

Duda