Ở bài trước, chúng ta đã cùng tìm hiểu về thuật toán SIFT descriptor, một thuật toán được sử dụng rộng rãi trong image descriptor.
Nhưng các nhà phát triển và nhà nghiên cứu về thị giác máy tính đang bắt đầu sử dụng RootSIFT thay vì SIFT.
RootSIFT được xem như là một extension của SIFT, được sử dụng để tăng đáng kể độ chính xác nhận dạng đối tượng, lượng tử hóa và độ chính xác truy xuất. Tuy nhiên, việc implement vô cùng đơn giản và bạn không cần phải thay đổi source code của thuật toán SIFT ban đầu
RootSift hoạt động như thế nào?
Vậy tại sao RootSift lại tốt hơn nhiều so với Sift?
Như bạn có thể thấy rõ , khi so sánh biểu đồ, Euclide distance thường mang lại hiệu suất thấp hơn so với khi sử dụng chi-squared distance hoặc Hellinger-kernel [Arandjelovic et al. 2012; Trang 2, Mục 3].
Vậy tại sao chúng ta thường sử dụng Euclide distance để so sánh SIFT descriptor khi matching với các keypoint?
Hãy nhớ rằng, trong khi bài báo SIFT ban đầu thảo luận về việc so sánh các descriptors sử dụng khoảng cách Euclide, SIFT vẫn là một biểu đồ vì nó lập bảng độ dốc (trọng số) vào các ô định hướng. Từ đây chúng ta đặt ra câu hỏi, liệu các số liệu khoảng cách khác có cung cấp độ chính xác cao không?
Hóa ra, câu trả lời là có. Và thay vì so sánh các bộ SIFT descriptors bằng một số liệu khác nhau, chúng ta chỉ cần sửa đổi bộ descriptor 128-dim được trả về trực tiếp từ SIFT.
Bạn thấy đấy, Arandjelovic gợi ý một phần mở rộng của SIFT: RootSIFT, cho phép SIFT descriptor được so sánh với nhau sử dụng Hellinger-kernel - nhưng vẫn sử dụng khoảng cách Euclide.
Đây là thuật toán đơn giản để mở rộng SIFT sang RootSift:
- Bước 1: Tính toán các SIFT descriptor bằng thư viện SIFT yêu thích của bạn (chẳng hạn như OpenCV).
- Bước 2: L1-normalize cho mỗi vectơ SIFT.
- Bước 3: Lấy căn bậc hai của mỗi phần tử trong vectơ SIFT.
Nó có một phần mở rộng đơn giản. Nhưng sửa đổi nhỏ này có thể cải thiện đáng kể kết quả. Arandjelovic đã chỉ ra rằng RootSift có thể dễ dàng được sử dụng trong các tình huống tương tự như SIFT trong khi cải thiện kết quả.
RootSIFT trong Python
Chúng ta cùng tạo ra một class RootSIFT
như bên dưới:
import numpy as np
import cv2
import imutils
class RootSIFT:
def __init__(self):
# initialize the SIFT feature extractor for OpenCV 2.4
if imutils.is_cv2():
self.extractor = cv2.DescriptorExtractor_create("SIFT")
# otherwise, initialize the SIFT feature extractor for OpenCV 3+
else:
self.extractor = cv2.xfeatures2d.SIFT_create()
def compute(self, image, kps, eps=1e-7):
# compute SIFT descriptors for OpenCV 2.4
if imutils.is_cv2:
(kps, descs) = self.extractor.compute(image, kps)
# otherwise, computer SIFT descriptors for OpenCV 3+
else:
(kps, descs) = self.extractor.detectAndCompute(image, None)
# if there are no keypoints or descriptors, return an empty tuple
if len(kps) == 0:
return ([], None)
# apply the Hellinger kernel by first L1-normalizing and taking the
# square-root
descs /= (descs.sum(axis=1, keepdims=True) + eps)
descs = np.sqrt(descs)
# return a tuple of the keypoints and descriptors
return (kps, descs)
Điều đầu tiên chúng ta sẽ làm là import các thư viện cần thiết.
Sau đó, chúng ta tạo class RootSift
của mình trên Dòng 6 và hàm constructor trên Dòng 7-14. Hàm constructor chỉ đơn giản khởi tạo SIFT descriptor.
Hàm compute
trên Dòng 16 sau đó xử lý tính toán của bộ mô tả RootSIFT. Hàm này yêu cầu hai arguments và argument thứ ba tùy chọn.
Argument đầu tiên cho hàm compute
là hình ảnh mà chúng ta muốn trích xuất các mô tả RootSIFT từ đó. Argument thứ hai là danh sách các keypoints hoặc các vùng cục bộ, từ đó các mô tả RootSift sẽ được trích xuất. Và cuối cùng, một biến epsilon, eps, có thể được cung cấp để ngăn chặn mọi lỗi chia cho 0.
Từ đó, chúng ta trích xuất các mô tả Sift ban đầu trên Dòng 19 hoặc 23 tùy thuộc vào phiên bản OpenCV của chúng ta.
Chúng tôi thực hiện kiểm tra trên Dòng 26 và 27 - nếu không có keypoints hoặc descriptors, chúng ta chỉ cần trả lại một tuple trống.
Việc chuyển đổi SIFT ban đầu thành RootSift diễn ra trên Dòng 31 và 32. Trước tiên, chúng ta L1-normalize cho từng vectơ trong mảng descs (Dòng 31). Từ đó, chúng ta lấy căn bậc hai của mỗi phần tử trong vectơ SIFT (Dòng 32).
Cuối cùng, tất cả những gì chúng ta phải làm là trả lại bộ dữ liệu keypoints và bộ RootSIFT descriptor.
Sử dụng RootSIFT
Sau khi đã tạo được class RootSIFT,
việc tiếp theo là chúng ta sẽ sử dụng nó.
# import the necessary packages
from __future__ import print_function
from pyimagesearch.descriptors import RootSIFT
import argparse
import cv2
import imutils
# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True, help="Path to the image")
args = vars(ap.parse_args())
# load the input image, convert it to grayscale
image = cv2.imread(args["image"])
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# handle if we are using OpenCV 2.4
if imutils.is_cv2():
# initialize the keypoint detector and local invariant descriptor
detector = cv2.FeatureDetector_create("SIFT")
extractor = RootSIFT()
# detect keypoints
kps = detector.detect(gray)
# handle if we are using OpenCV 3+
else:
# initialize the keypoint detector and local invariant descriptor
detector = cv2.xfeatures2d.SIFT_create()
extractor = RootSIFT()
# detect keypoints
(kps, _) = detector.detectAndCompute(gray, None)
# extract local invariant descriptors
(kps, descs) = extractor.compute(gray, kps)
# show the shape of the keypoints and local invariant descriptors array
print("[INFO] # of keypoints detected: {}".format(len(kps)))
print("[INFO] feature vector shape: {}".format(descs.shape))
Sau khi chạy thử đoạn code vừa rồi, chúng ta đã thu đươcj kết quả
[INFO] # of keypoints detected: 522
[INFO] feature vector shape: (522, 128)
Chúc bạn thành đạt trong công việc và hạnh phúc trong cuộc sống !
Hotline / Zalo: 0903 666 014
Website: https://uniduc.com/vi
-------------////--------------------------------------------////------------
HUMANOID ROBOT CỦA CÔNG TY UNIDUC SẢN XUẤT PHÁT TRIỂN.