Tất tần tật về Object Detection: Từ các thuật toán cơ bản đến deep learning (phần 1)
Nhắc đến Computer vision thì không thể không nhắc đến một bài toán cực kì phổ biến là Object detection. Cho đến hiện tại, vẫn rất nhiều thuật toán, mô hình được đề xuất để cải thiện bài toán này. Trong series này, chúng ta cùng tìm hiểu từ những thuật toán cơ bản nhất đến phức tạp để giải quyết bài toán này.
Image Gradient Vector
Trước hết ta cần phân biệt một số khái niệm được nêu trong bài viết, chúng có vẻ na ná nhau nhưng không thật sự giống nhau Các khái niệm này mình sẽ để nguyên bằng tiếng Anh
- Derivative:
- Kiểu dữ liệu: Scalar
- Định nghĩa: The rate of change of a function f(x,y,z,...) at a point (x0, y0, z0), which is the slope of the tangent line at the point.
- Directional Derivative:
- Kiểu dữ liệu: Scalar
- Định nghĩa: The instantaneous rate of change of f(x,y,z,...) in the direction of an unit vector u.
- Gradient:
- Kiểu dữ liệu: Vector
- Định nghĩa: It points in the direction of the greatest rate of increase of the function, containing all the partial derivative information of a multivariable function.
Trong quá trình xử lý hình ảnh, chúng ta muốn biết hướng thay đổi của màu sắc từ cực này sang cực khác (tức là từ đen sang trắng trên hình ảnh thang độ xám). Do đó, chúng ta muốn tính "gradient" trên các pixel màu. Gradient trên hình ảnh là rời rạc vì mỗi pixel là độc lập và không thể chia nhỏ thêm.
Image gradient vector được định nghĩa là metric cho mỗi pixel riêng lẻ, chứa các thay đổi về màu sắc pixel ở cả trục x và trục y. Định nghĩa này phù hợp với gradient của một hàm nhiều biến liên tục, là một vectơ đạo hàm riêng của tất cả các biến. Giả sử f (x, y) ghi lại màu của pixel tại vị trí (x, y), vectơ gradient của pixel (x, y) được xác định như sau:
là đạo hàm riêng theo phương x, được tính bằng sự khác biệt về màu sắc giữa các pixel liền kề ở bên trái và bên phải của mục tiêu, f (x + 1, y) - f (x-1, y). Tương tự, là đạo hàm riêng trên phương y, được đo bằng f (x, y + 1) - f (x, y-1), sự khác biệt về màu sắc giữa các pixel liền kề ở trên và dưới mục tiêu.
Có hai thuộc tính quan trọng của image gradient:
- Magnitude là L2-norm của vector
- Direction là là hàm arctan của tỷ số giữa các đạo hàm riêng trên hai phương,
Ví dụ, gradient vector cho hình trên là
Do đó,
- Magnitude có giá trị
- Direction có giá trị .
Việc lặp đi lặp lại quá trình tính toán gradient cho mỗi pixel là rất mất thời gian Thay vào đó, nó có thể được chuyển thành áp dụng toán tử convolution (conv) cho toàn bộ ma trận ảnh.
Thử bắt đầu với phương x trong ví dụ đầu, sử dụng kernel [-1, 0, 1] trượt qua trục x và * là toán tử conv, ta có:
Tương tự, theo phương y, ta sử dụng kernel :
Code:
import numpy as np
import scipy.signal as sig
data = np.array([[0, 105, 0], [40, 255, 90], [0, 55, 0]])
G_x = sig.convolve2d(data, np.array([[-1, 0, 1]]), mode='valid')
G_y = sig.convolve2d(data, np.array([[-1], [0], [1]]), mode='valid')
2 hàm sẽ trare về array([[0], [-50], [0]])
và array([[0, 50, 0]])
tương ứng. (Chú ý rằng trong biểu diễn array, 40 đứng trước 90 nên -1 đưng trước 1 trong kernel tương ứng)
Một số Image Processing Kernels phổ biến
Gọi ma trận ảnh là ta có một số toán tử phổ biến hay dùng như sau:
- Prewitt operator: Thay vì chỉ dựa vào bốn điểm ảnh lân cận trực tiếp, toán tử Prewitt sử dụng tám pixel xung quanh để có kết quả mượt mà hơn.
- Sobel operator: Để nhấn mạnh tác động của các pixel liền kề một cách trực tiếp, chúng được gán với trọng số cao hơn.
Các kernel được tạo ra với các mục đích khác nhau, ví dụ nhận diện cạnh, làm mờ, làm sắc nét và nhiều ứng dụng khác.
Ví dụ
Hãy cùng thử chạy một ví dụ đơn giản trên ảnh sau
Để đơn giản, trước tiên ảnh được chuyển sang thang độ xám. Đối với hình ảnh màu, chúng ta chỉ cần lặp lại quá trình tương tự trong từng kênh màu tương ứng.
import numpy as np
import scipy
import scipy.signal as sig
# With mode="L", we force the image to be parsed in the grayscale, so it is
# actually unnecessary to convert the photo color beforehand.
img = scipy.misc.imread("manu-2004.jpg", mode="L")
# Define the Sobel operator kernels.
kernel_x = np.array([[-1, 0, 1],[-2, 0, 2],[-1, 0, 1]])
kernel_y = np.array([[1, 2, 1], [0, 0, 0], [-1, -2, -1]])
G_x = sig.convolve2d(img, kernel_x, mode='same')
G_y = sig.convolve2d(img, kernel_y, mode='same')
# Plot them!
fig = plt.figure()
ax1 = fig.add_subplot(121)
ax2 = fig.add_subplot(122)
# Actually plt.imshow() can handle the value scale well even if I don't do
# the transformation (G_x + 255) / 2.
ax1.imshow((G_x + 255) / 2, cmap='gray'); ax1.set_xlabel("Gx")
ax2.imshow((G_y + 255) / 2, cmap='gray'); ax2.set_xlabel("Gy")
plt.show()
Bạn có thể nhận thấy rằng hầu hết các khu vực có màu xám. Bởi vì sự khác biệt giữa hai pixel là từ -255 đến 255 và chúng ta cần chuyển đổi chúng trở lại [0, 255] cho mục đích hiển thị. Một phép biến đổi tuyến tính đơn giản (G + 255) / 2 sẽ diễn giải tất cả các số không (tức là nền có màu không đổi cho biết gradient không thay đổi) là 125 (được hiển thị dưới dạng màu xám).
Tham khảo
[0] Source: https://lilianweng.github.io/posts/2017-10-29-object-recognition-part-1/#image-gradient-vector
All rights reserved