Image processing 005_morphological transformation in OpenCV

The main content of this article comes from the image processing part of OpenCV in the OpenCV-Python tutorial . The main content of this part is as follows:

Target

In this chapter:

  • We will learn about different morphological operations such as erosion, dilation, opening, closing, etc.
  • We will see different functions such as: cv.erode() , cv.dilate() , cv.morphologyEx() and many more.

theory

Morphological transformations are some simple operations based on the shape of the image. It usually operates on binary images. It takes two inputs, one is our original image and the second is called the structuring element or kernel , which determines the nature of the operation. Two basic morphological operations are erosion and dilation. Then its variants like Opening, Closing, Gradient, etc. also come into play. We will look at them one by one with the help of the image below:
image

1. Erosion

The basic idea of ​​erosion is like soil erosion, it erodes the boundaries of foreground objects (always try to keep the foreground white). So what does it do? The kernel slides through the image (as in 2D convolution). A pixel (1 or 0) in the original image is considered to be 1 only if all pixels under the kernel are 1, otherwise it is eroded (becomes 0).

So what happens is that all pixels near the border will be discarded based on the size of the kernel. Therefore, the thickness or size of the foreground object is reduced, or just the white area in the image is reduced. It's useful for removing small white noise (as we saw in the color space chapter), separating two connected objects, etc.

Here, as an example, we use a 5x5 kernel with all ones. Let's see how it works:

import cv2 as cv
import numpy as np

def erosion():
    img = cv.imread("/home/zhangsan/j.png", 0)
    kernel = np.ones((5, 5), np.uint8)
    erosion = cv.erode(img, kezhangsanrnel, iterations=1)

    edge = np.full((img.shape[0], 3, 1), 255, np.uint8);

    images = [img, edge, erosion]
    dest = cv.hconcat(images)

    cv.imshow("Image", dest)
    cv.waitKey(-1)


if __name__ == "__main__":
    erosion()

The result is as follows:
Image

2. Expansion

It is the exact opposite of erosion. Here, a pixel element value is '1' if at least one of the elements under the kernel has a value of '1'. So it increases the white area in the image, or increases the size of the foreground object. Typically, in cases such as noise removal, erosion is followed by dilation. Because, erosion removes white noise, but it also shrinks our object. So we expand it. Since the noise is gone, they don't come back, but our object area increases. It can also be used to join damaged parts of an object.

    dilation = cv.dilate(img, kernel, iterations=1)

The result is as follows:
Image

3. open

Opening is just another name for expansion after erosion . As we explained above, it's useful in removing noise. Here we use the function cv.morphologyEx() .

def opening():
    img = cv.imread("/home/hanpfei/j.png", 0)

    for i in range(50):
        row = random.randint(0, img.shape[0] - 1)
        col = random.randint(0, img.shape[1] - 1)
        img[row][col] = 255

    kernel = np.ones((5, 5), np.uint8)
    opening = cv.morphologyEx(img, cv.MORPH_OPEN, kernel)

    edge = np.full((img.shape[0], 3, 1), 255, np.uint8);

    images = [img, edge, opening]
    dest = cv.hconcat(images)

    cv.imshow("Image", dest)
    cv.waitKey(-1)

If the image to be processed contains some white noise pixels, the effect will be more obvious. Here we first add some white noise pixels to the input image. The result is as follows:

Image

4. close

Closing is the reverse operation of opening, expansion followed by erosion . It's useful for closing small holes within foreground objects, or small black spots on objects.

def closing():
    img = cv.imread("/home/hanpfei/j.png", 0)

    for i in range(5000):
        row = random.randint(0, img.shape[0] - 1)
        col = random.randint(0, img.shape[1] - 1)
        img[row][col] = 0

    kernel = np.ones((5, 5), np.uint8)
    closing = cv.morphologyEx(img, cv.MORPH_CLOSE, kernel)

    edge = np.full((img.shape[0], 3, 1), 255, np.uint8);

    images = [img, edge, closing]
    dest = cv.hconcat(images)

    cv.imshow("Image", dest)
    cv.waitKey(-1)


if __name__ == "__main__":
    closing()

Here we also create some noise points on the input image, but this time they are black noise pixels. Since most black noise points will fall in the black background area and have no visible effect, more noise points are created here. The final result is as follows:
Image

5. Morphological gradient

It is the difference between the dilation and erosion of an image.

The result will look like the outline of the object.

    gradient = cv.morphologyEx(img, cv.MORPH_GRADIENT, kernel)

The result is as follows:
Image

6. Top hat

It is an open interpolation of the input image and the image. The following example is done for the 9x9 kernel.

def top_hat():
    img = cv.imread("/home/hanpfei/j.png", 0)

    kernel = np.ones((9, 9), np.uint8)
    tophat = cv.morphologyEx(img, cv.MORPH_TOPHAT, kernel)

    edge = np.full((img.shape[0], 3, 1), 255, np.uint8);

    images = [img, edge, tophat]
    dest = cv.hconcat(images)

    cv.imshow("Image", dest)
    cv.waitKey(-1)

The result is as follows:
Image

7. Black Hat

It is a closed interpolation of the input image and the image. The following example is done for the 9x9 kernel.

    tophat = cv.morphologyEx(img, cv.MORPH_BLACKHAT, kernel)

The result is as follows:
Image

Structural elements

We manually created the structural elements from the previous example with the help of Numpy. It is rectangular. But in some cases you may need an oval/round core. So for this purpose, OpenCV has a function, cv.getStructuringElement() . We just need to pass in the shape and size of the kernel to get the desired kernel.

# Rectangular Kernel
>>> cv.getStructuringElement(cv.MORPH_RECT,(5,5))
array([[1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1]], dtype=uint8)
# Elliptical Kernel
>>> cv.getStructuringElement(cv.MORPH_ELLIPSE,(5,5))
array([[0, 0, 1, 0, 0],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [0, 0, 1, 0, 0]], dtype=uint8)
# Cross-shaped Kernel
>>> cv.getStructuringElement(cv.MORPH_CROSS,(5,5))
array([[0, 0, 1, 0, 0],
       [0, 0, 1, 0, 0],
       [1, 1, 1, 1, 1],
       [0, 0, 1, 0, 0],
       [0, 0, 1, 0, 0]], dtype=uint8)

Other resources

  1. HIPR2 的 Morphological Operations

practise

Reference documentation

Morphological Transformations

Done.

Guess you like

Origin blog.csdn.net/tq08g2z/article/details/124307238