Tag Archives: digital image processing

Image Moments

In this blog, we will discuss how to find different features of contours such as area, centroid, orientation, etc. With the help of these features/statistics, we can do some sort of recognition. So, in this blog, we will refer to a very old fundamental work in computer vision known as Image moments that helps us to calculate these statistics. So, let’s first discuss what are image moments and how to calculate them.

In simple terms, image moments are a set of statistical parameters to measure the distribution of where the pixels are and their intensities. Mathematically, the image moment Mij of order (i,j) for a greyscale image with pixel intensities I(x,y) is calculated as

Here, x, y refers to the row and column index and I(x,y) refers to the intensity at that location (x,y). Now, let’s discuss how simple image properties are calculated from image moments.

Area:

For a binary image, the zeroth order moment corresponds to the area. Let’s discuss how?

Using the above formulae, the zeroth order moment (M00) is given by

For a binary image, this corresponds to counting all the non-zero pixels and that is equivalent to the area. For greyscale image, this corresponds to the sum of pixel intensity values.

Centroid:

Centroid simply is the arithmetic mean position of all the points. In terms of image moments, centroid is given by the relation

This is simple to understand. For instance, for a binary image M10 corresponds to the sum of all non-zero pixels (x-coordinate) and M00 is the total number of non-zero pixels and that is what the centroid is.

Let’s take a simple example to understand how to calculate image moments for a given image.

Below are the area and centroid calculation for the above image

OpenCV-Python

OpenCV provides a function cv2.moments() that outputs a dictionary containing all the moment values up to 3rd order.

Below is the sample code that shows how to use cv2.moments().

From this moments dictionary, we can easily extract the useful features such as area, centroid etc. as shown below.

That’s all about image moments. Hope you enjoy reading.

If you have any doubt/suggestion please feel free to ask and I will do my best to help or improve myself. Good-bye until next time.

Simple Shape Detection using Contour approximation

In the previous blog, we learned how to find and draw contours using OpenCV. In this blog, we will discuss how to detect simple geometric shapes by approximating the contours. So, let’s first discuss what is meant by contour approximation.

This means approximating a contour shape to another shape with less number of vertices so that the distance between both the shapes is less or equal to the specified precision. The below figure shows the curve approximation for different precisions (epsilon). See how the shape is approximated to a rectangle with epsilon =10% in the below image.

Contour approximation for different epsilon
Source: OpenCV

This is widely used in robotics for pattern classification and scene analysis. OpenCV provides a builtin function that approximates the polygonal curves with the specified precision. Its implementation is based on the Douglas-Peucker algorithm.

  • curve“: contour/polygon we want to approximate.
  • epsilon“: This is the maximum distance between the original curve and its approximation.
  • closed“: If true, the approximated curve is closed otherwise, not.

This function returns the approximated contour with the same type as that of the input curve. Now, let’s detect simple shapes using this concept. Let’s take the below image to perform shape detection.

Steps

  • Load the image and convert to greyscale
  • Apply thresholding and find contours
  • For each contour
    • First, approximate its shape using cv2.approxPolyDP()
    • if len(shape) == 3; shape is Triangle
    • else if len(shape) == 4; shape is Rectangle
    • else if len(shape) == 5; shape is Pentagon
    • else if 6< len(shape) <15; shape is Ellipse
    • else; shape is circle

Code

Below is the final result.

Contour approximation for shape detection

Hope you enjoy reading.

If you have any doubts/suggestion please feel free to ask and I will do my best to help or improve myself. Good-bye until next time.

Find and Draw Contours using OpenCV-Python

In the previous blog, we discussed various contour tracing algorithms like Moore, radial sweep, etc. and then we also covered Suzuki’s algorithm, the one that OpenCV uses for border following or contour tracing. In this blog, we will discuss the builtin functions provided by OpenCV for finding and drawing contours. So, let’s get started.

Finding the contours

OpenCV provides the following builtin function for finding the contour

Here, the first argument “image” should be an 8-bit single-channel image. For better accuracy use a binary image. If you didn’t provide a binary image, then this method will convert it into a binary image by treating all the nonzero pixels as ‘1’ and zero remains ‘0’.

The second argument “mode” specifies how you want to retrieve the contours. This means whether you want to extract the outer contours only or retrieve contours without establishing any hierarchical relationships. Below are the several options available

  • cv2.RETR_EXTERNAL – retrieves only the extreme outer contours.
  • cv2.RETR_LIST – retrieves contours without establishing any hierarchical relationships.
  • cv2.RETR_TREE – constructs a full hierarchy of nested contours.
  • cv2.RETR_CCOMP – arranges all the contours into a 2-level hierarchy – outer contours and hole contours.

The third argument “method” denotes the contour approximation method. We don’t need to store all the points of a contour as the same thing can also be represented in a compact manner. For instance, a straight line can be represented by the endpoints. There is no need to store all the points as that would be redundant. OpenCV provides various options for this.

  • cv2.CHAIN_APPROX_NONE – stores all the boundary points.
  • cv2.CHAIN_APPROX_SIMPLE – removes all the redundant points and thus saves memory.
  • cv2.CHAIN_APPROX_TC89_L1 – applies one of the variants of the Teh-Chin chain approximation algorithm

The first output “contours” is a Python list of all the contours in the image. Each individual contour is a Numpy array of (x,y) coordinates of boundary points of the object.

The second output “hierarchy” represents the relationship among the contours like, is it a child of some other contour, or is it a parent, etc. OpenCV represents it as an array of four values : [Next, Previous, First_Child, Parent]

  • Next denotes the next contour at the same hierarchical level.”
  • Previous denotes the previous contour at the same hierarchical level.”
  • First_Child denotes its first child contour.”
  • Parent denotes index of its parent contour.”

Depending upon the contour retrieval mode argument hierarchy array can take different values. You can read more about it here.

Drawing the Contours

OpenCV provides the following builtin function for drawing the contour.

The first argument is the destination image on which to draw the contours, the second argument is the contours which should be passed as a Python list, the third argument is the index of contours that we want to draw(To draw all contours, pass -1). If the thickness ≥ 0, it draws contour outlines in the image otherwise, fills the area bounded by the contours. The optional argument hierarchy and the max-level specify up to which hierarchy level to draw the contours.

Now, let’s take an example to understand the above two functions.

Below is the output of the above code.

Contours OpenCV

Hope you enjoy reading.

If you have any doubts/suggestion please feel free to ask and I will do my best to help or improve myself. Good-bye until next time.

Suzuki’s Contour tracing algorithm OpenCV-Python

In the previous blog, we discussed various contour tracing algorithms like radial sweep, Moore’s, etc. In this blog, we will discuss another famous contour tracing algorithm known as Suzuki’s algorithm. Many of the image processing libraries such as OpenCV uses this border following algorithm for the topological structural analysis of the image. This was one of the first algorithms that define the hierarchical relationships among the borders. This algorithm also differentiates between the outer boundary or the hole boundary. Before discussing this algorithm, let’s understand what is the outer and hole border. The below figure explains this pretty well. (Here we will be dealing with binary images (0 or 1)).

outer and hole border

Now, let’s understand the algorithm using the following image.

image to perform suzuki algorithm

Let’s say fij denotes the value of the pixel at location (i,j). The uppermost row, the lowermost row, the leftmost column, and the rightmost column of a picture compose its frame. In this, we assign a unique number to every new border found and we denote it by NBD. We assume the NBD of the frame as 1. Rest borders are numbered sequentially. We save the information of the parent of any border in LNBD or last NBD.

Steps:

  • Start scanning the image from left to right until you find the object pixel. Decide whether it is an outer border or hole border. The criteria for checking the outer or hole border is shown in the image below. Thus while scanning if we found the situation as shown in the image below, we can easily tell whether it is the starting point of the outer or the hole border.
Criteria for outer or hole border

Perform the following steps only for pixels >0. Every time we begin to scan a new row, reset LNBD to 1.

Step-1

  1. If it’s an outer border (i.e. fij = 1 and fi,j-1 = 0) then increment the NBD and set (i2, j2) as (i, j-1).
  2. Else if it is a hole border, increment NBD. Set (i2, j2) as (i, j+1) and LNBD = fij in case fij > 1.
  3. Otherwise, go to step 3.

Step-2

Now, from this starting point, we will trace the border. This can be done as

  1. Starting from (i2, j2) look around clockwise the pixels in the neighborhood of (i, j) and find a nonzero pixel and denote it as (i1, j1). If no nonzero pixels are found, set fij = -NBD and go to step 4.
  2. Set (i2, j2) = (i1, j1) and (i3, j3) = (i,j).
  3. Starting from the next element of the pixel (i2, j2) in the counterclockwise order, again traverse the neighborhood of the (i3, j3) in the counterclockwise direction to find the first nonzero pixel and set it to (i4, j4).
  4. Change the value of the current pixel (i3, j3) as
    1. if the pixel at (i3, j3 +1) is a 0-pixel belonging to the region outside the boundary, set the current pixel value to -NBD.
    2. if the pixel at (i3, j3 +1) is not a 0-pixel and the current pixel value is 1, set the current pixel value to NBD.
    3. Otherwise, do not change the current pixel value.
  5. if in step 2.3, we return to the starting point again i.e (i4, j4) = (i, j) and (i3, j3) = (i1, j1) go to step 3. Otherwise, set (i2, j2) = (i3, j3) and (i3, j3) = (i4, j4) and go back to step 2.3.

Step-3

If fij != 1 then set LNBD = |fij| and start scanning from the next pixel (i, j+1). Stopping criteria is when we reached the bottom right corner of the image.

The below images shows step by step the result of one iteration of Suzuki’s algorithm on the above image.

Step1 Suzuki algorithm
Step 2.1 Suzuki algorithm
Step 2.2 Suzuki algorithm
Step 2.3 Suzuki algorithm
Step 2.4.2 Suzuki algorithm
Step 2.5 Suzuki algorithm

Similarly repeating the above steps, we will get the following output. The hierarchy relationship among borders is also shown below.

Final output Suzuki algorithm

They also proposed another algorithm that only extracts the outermost border. OpenCV supports both hierarchical and plane variants of the Suzuki algorithm. You can find the full code here.

References Paper: Topological structural analysis of digitized binary images by border following

So, that’s it for Suzuki’s algorithm. Hope you enjoy reading.

If you have any doubts/suggestion please feel free to ask and I will do my best to help or improve myself. Good-bye until next time.

Read, Write and Display Videos with OpenCV Python

In this blog, we will see how to Read, Write and Display Videos using OpenCV. Since a video is made up of images, most of the commands we learned in the previous blog also applies here.

Let’s see by an example how to capture video from the camera and display it.

cv2.VideoCapture(0) will open the default camera. You can select the second camera by passing 1, third by passing 2 and so on. This creates a VideoCapture object (“cap” here).

cap.read() capture frame by frame. This returns two values, frame and ret. If the frame is read correctly, ret will be True otherwise False.

cv2.waitKey(1) & 0xFF == ord(‘q’) will exit the video when ‘q’ is pressed.

cap.release() closes video file or capturing device.

If you want to play a video from a file, just change the cv2.VideoCapture(0) function in the above code by giving the file path as cv2.VideoCapture(‘F:/downloads/Python.mp4’). Also, use the appropriate time for cv2.waitKey() function (25 will be OK).

Saving a Video:

First, create a VideoWriter object with cv2.VideoWriter(output filename, fourcc, fps, frameSize). fourcc(4-character code of codec) is used to compress the frames. After creating this object, use object.write() to save the video. Let’s see an example

Now, you might have got some feeling about the basic video commands in OpenCV. Hope you enjoy reading.

If you have any doubt/suggestion please feel free to ask and I will do my best to help or improve myself. Good-bye until next time.

What is a Digital Image?

In this blog, we will try to understand what is a digital image and how it is formed. We will also learn about image sensors and pixels in this blog.

What is a Digital Image?

A Digital Image is a numeric representation of a two-dimensional image and is made of picture elements called pixels, arranged in rows and columns. These numeric values are the intensity or brightness values that are associated with the pixels.

Digital Image

Now, let’s understand what is a pixel and how the intensity value is calculated?

The concept of pixel is closely related with image sensors. So, by understanding image sensors I hope you will get a feel of what a pixel is.

Image Sensor: It is a device that converts the light energy into an electric signal. The figure below shows a single image sensor.

source: R. C. GonzalezR. E. Woods, Digital Image Processing

In digital cameras, these sensors are arranged in the form of a 2D array on a chip. Mostly there is a 1-to-1 correspondence between a pixel and a sensor meaning each sensor produces 1 pixel. Thus, the total number of pixels in an image = total number of sensors on a chip. Sometimes, multiple sensors are used to produce a pixel of information.

8MP camera means there are 8×106 image sensors in the camera chip and if there is a 1-to-1 correspondence between a pixel and a sensor then the image contains 8×106 pixels.

Note: Larger the pixel, better will be the image quality.

How the Digital Image is formed?

There are basically two types of image sensors used in digital cameras: CCD or CMOS. The CCD sensor is a silicon chip that contains a 2D array of photosensitive sites or sensors. Each sensor has a PN diode and a storage cell. Each sensor outputs a pixel value through these steps

  1. Light energy or photons(>1.2eV) falls on the silicon layer of the sensor and electrons are released(stored in potential well until the shutter is open).
  2. After the camera shutter closes, these electrons are moved to the storage cell (by applying +ve voltage on vertical shift register).
  3. These electrons are then transferred to the serial shift register.
  4. These electrons are converted into the analog voltage that is amplified using an amplifier.
  5. The output voltage signal is immediately converted to a digital signal by means of an analog-to-digital converter (ADC) in digital cameras, either on or off-chip. This digital quantity obtained is the intensity value of a pixel.

These steps are for the CCD sensor. For CMOS sensor, step 3 is not performed and voltage conversion and amplification (Step 4) is done in the sensor itself. This voltage is sent to ADC with the help of switch from each sensor and outputs the intensity value of a pixel.

Repeat these steps for all the sensors on a chip to get the intensity values corresponding to each pixel and thus we get a digital image.

Now, you might have got some feeling about the image sensors, pixel, and digital image. Hope you enjoy reading.

If you have any doubt/suggestion please feel free to ask and I will do my best to help or improve myself. Good-bye until next time.