Computer Vision

Convolutions with OpenCV and Python

Convolutions are one of the most critical, fundamental building-blocks in computer vision and image processing.

Chúng ta đã biết, image cũng chính là một ma trận nhiều chiều, gồm width (số cột), height (số hàng) và depth (số channel). Như vậy, image là một ma trận lớn, còn kernel hay convolutional matrix là một ma trận bé hơn được dùng cho blurring, sharpening, edge detection và một số image processing functions khác.

Về bản chất, ma trận kernel nằm trong ma trận image, di chuyển từ trái qua phải, từ trên xuống dưới và áp dụng một phép toán (một convolution) tại tọa độ (x, y) của ma trận image.

Chúng ta đã làm quen với các phương pháp blurring (Averaging, Gaussian, Median và Bilateral), edge detection (Laplacian, Sobel, Scharr, Prewitt, etc.) và sharpening. Tất cả chúng đều sử dụng các kernel đặc biệt để thực hiện các chức năng đặc biệt. Chúng ta sẽ xem xét điều này ở các ví dụ.


KERNELS

Nhắc lại một lần nữa, image là một ma trận lớn, còn kernel hay convolutional matrix là một ma trận bé hơn nằm bên trong ma trận image.

kernel

Figure 1 – Image matrix and Kernel matrix

Chúng ta di chuyển kernel từ trái sang phải, từ trên xuống dưới khắp ma trận image. Tại mỗi pixel tọa độ (x, y) của ma trận image, ta dừng lại và khảo sát các pixels lận cận của pixel nằm tại trung tâm của kernel (pixel trung tâm). Với giá trị của các pixel này, áp dụng vào kernel, chúng ta nhận được một giá trị output. Giá trị này sẽ thay thế cho giá trị của pixel trung tâm.

kernelSample

Figure 2 – Kernel 5×5 for Averaging Blurring

Kích thước của kernel phải là số lẻ (để có được pixel trung tâm), thông thường ta chọn kernel có row = column.


UNDERSTANDING IMAGE CONVOLUTIONS

Trong Image Processing, convolution yêu cầu 3 thành phần:

  1. Một input image.
  2. Một ma trận Kernel.
  3. Một output image để lưu giữ kết quả convolution.

Algorithm:

  1. Chọn một pixel có tọa độ (x, y) trong input image.
  2. Đặt trung tâm của kernel vào pixel vừa được chọn.
  3. Thực hiện phép toán element-wise multiplication giữa Kernel và vùng image tương ứng, sau đó tính tổng các giá trị đó lại – giá trị tổng này chính là output.
  4. Lưu giá trị output vừa nhận được vào pixel có tọa độ (x, y) được chọn ở bước #1.

Cần lưu ý rằng, phép element-wise multiplicaton là phép nhân giữa các phần tử trong 2 ma trận, không phải tích vô hướng của 2 ma trận (dot product).

convolutions_example_01

Figure 3 – Element-wise multiplicaton giữa Kernel 3×3 và vùng image tương ứng

convolutions_example_02

Figure 4 – Output


IMPLEMENTING CONVOLUTIONS WITH PYTHON

Chúng ta vừa tìm hiểu về giải thuật của convolution, bây giờ là phần “How to apply convolutions to images?”

OpenCV provides a function cv2.filter2D() to convolve a kernel with an image:

dest = cv2.filter2D(sourceImage, depth, kernel)

Trong đó:

  • sourceImage – input image.
  • depth – desired depth of the destination image; if it is negative, it will be the same as sourceImage.depth().
  • kernel – convolution kernel.
  • dest – output image of the same size and the same number of channels as sourceImage.

Example:

from skimage.exposure import rescale_intensity
import numpy as np
import argparse
import cv2

def convolve(image, kernel):
    (iH, iW) = image.shape[:2]
    (kH, kW) = kernel.shape[:2]

    # allocate memory for the output image, taking care to
    # "pad" the borders of the input image so the spatial
    # size (i.e., width and height) are not reduced
    pad = (kW - 1) / 2
    image = cv2.copyMakeBorder(image, pad, pad, pad, pad, cv2.BORDER_REPLICATE)
    output = np.zeros((iH, iW), dtype="float32")

    # loop over the input image, "sliding" the kernel across
    # each (x, y)-coordinate from left-to-right and top to bottom
    for y in np.arange(pad, iH + pad):
        for x in np.arange(pad, iW + pad):
            # extract the ROI of the image by extracting the
            # *center* region of the current (x, y)-coordinates
            # dimensions
            roi = image[y - pad:y + pad + 1, x - pad:x + pad + 1]
            # perform the actual convolution by taking the
            # element-wise multiplicate between the ROI and

            # the kernel, then summing the matrix
            k = (roi * kernel).sum()

            # store the convolved value in the output (x,y)- coordinate
            output[y - pad, x - pad] = k

    # rescale the output image to be in the range [0, 255]
    output = rescale_intensity(output, in_range=(0, 255))
    output = (output * 255).astype("uint8")
    return output

# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True, help="path to the input image")
args = vars(ap.parse_args())

# construct average blurring kernels used to smooth an image
smallBlur = np.ones((7, 7), dtype="float") * (1.0 / (7 * 7))
largeBlur = np.ones((21, 21), dtype="float") * (1.0 / (21 * 21))

# construct a sharpening filter
sharpen = np.array(([0, -1, 0],
                    [-1, 5, -1],
                    [0, -1, 0]), dtype="int")
# construct the Laplacian kernel used to detect edge-like
# regions of an image
laplacian = np.array(([0, 1, 0],
                      [1, -4, 1],
                      [0, 1, 0]), dtype="int")

# construct the Sobel x-axis kernel
sobelX = np.array(([-1, 0, 1],
                   [-2, 0, 2],
                   [-1, 0, 1]), dtype="int")

# construct the Sobel y-axis kernel
sobelY = np.array(([-1, -2, -1],
                   [0, 0, 0],
                   [1, 2, 1]), dtype="int")
# construct the kernel bank, a list of kernels we're going
# to apply using both our custom `convole` function and
# OpenCV's `filter2D` function
kernelBank = (("small_blur", smallBlur),
              ("large_blur", largeBlur),
              ("sharpen", sharpen),
              ("laplacian", laplacian),
              ("sobel_x", sobelX),
              ("sobel_y", sobelY))

# load the input image and convert it to grayscale
image = cv2.imread(args["image"])
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# loop over the kernels
for (kernelName, kernel) in kernelBank:
    # apply the kernel to the grayscale image using both
    # our custom 'convole' function and OpenCV's `filter2D`
    # function
    print("[INFO] applying {} kernel".format(kernelName))
    convoleOutput = convolve(gray, kernel)
    opencvOutput = cv2.filter2D(gray, -1, kernel)

    # show the output images
    cv2.imshow("original", gray)
    cv2.imshow("{} - convole".format(kernelName), convoleOutput)
    cv2.imshow("{} - opencv".format(kernelName), opencvOutput)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

Output:

output


SUMMARY

Qua bài viết này chúng ta đã tìm hiểu về Convolution Matrix trong Image Processing và cách thực hiện Convolution trên Python. Cảm ơn các bạn đã theo dõi bài viết.

Thân ái và quyết thắng.

Reference:
[1] Convolutions with openCV and Python.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s