Trong bài này, chúng ta sẽ cùng thực hành viết một ứng dụng phát hiện đối tượng với mô hình đã được huấn luyện sẵn tại TensorFlow Hub sử dụng Google Colab.
Trước hết, chúng ta tiến hành cài đặt Object Detection API như sau (Quá trình cài đặt yêu cầu download TensorFlow Model Garden và cài đặt Protobuf. Các bạn tham khảo chi tiết tại đây )
1 2 |
# Clone the Tensorflow Model Garden and installing the object detection packages !git clone --depth 1 https://github.com/tensorflow/models |
1 2 3 4 5 6 7 8 |
# Installing the object detection packages %%bash sudo apt install -y protobuf-compiler cd models/research/ protoc object_detection/protos/*.proto --python_out=. cp object_detection/packages/tf2/setup.py . python -m pip install . |
Tiếp theo chúng ta tiến hành import các thư việc cần thiết cho việc phát hiện đối tượng:
1 2 3 4 5 6 7 8 |
# import library from PIL import Image from urllib.request import urlopen import numpy as np import tensorflow_hub as hub from matplotlib import pyplot as plt from object_detection.utils import visualization_utils as viz_utils from object_detection.utils import label_map_util |
Tiếp theo chúng ta viết hàm chuyển bức ảnh thành dữ liệu dưới dạng numpy array để làm inputs cho model. Ở đây chúng ta sử dụng hàm Image.open của PIL (Python Imaging Library) để đọc file ảnh và sử dụng thư viện numpy để chuyển bức ảnh về định dạng numpy array thích hợp (trong bài này, chúng ta sẽ sử dụng mô hình có sẵn là mask-RCNN tại Tensorflow Hub. Mô hình này, yêu cầu input có shape là [1, height, width, 3]). Chúng ta cũng viết hàm display_img() sử dụng matplotlib để hiển thị hình ảnh và kiểm tra dữ liệu hình ảnh dưới dạng numpy array.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
def img2numpy(img_path): # Open the image from its path img = Image.open(urlopen(img_path)) # Convert image to numpy array with shape (H, W, 3) image_array = np.array(img) # Convert the numppy array to the shape (1, H, W, 3) img_numpy= np.expand_dims(image_array,0) return img_numpy # Display image from its numpy array def display_img(numpy_array): plt.figure(figsize=(24,30)) plt.imshow(numpy_array) plt.show() |
Sử dụng hàm img2numpy() và display_img() ta được kết quả như sau:
1 2 3 4 5 6 7 |
# Using the function to read and display image %matplotlib inline img_path= 'https://static01.nyt.com/images/2020/06/22/opinion/20gillisWeb/merlin_173526783_192e498a-5699-411c-b1e5-64fa738eec17-superJumbo.jpg' img_numpy = img2numpy(img_path) print('Image data shape: ', img_numpy.shape) display_img(img_numpy[0]) |
Như vậy ta đã hoàn thành việc đọc và chuyển đổi hình ảnh thành numpy array với định dạng thích hợp (array có shape là (1, 1406, 2048, 3)). Tiếp theo ta sẽ sử dụng mô hình Object detection để nhận diện các đối tượng có trong bức ảnh. Ở bài này, thay vì huấn luyện mô hình từ đầu, chúng ta sẽ sử dụng mô hình đã được huấn luyện sẵn tại Tensorflow Hub (các bạn tham khảo các mô hình tại https://tfhub.dev). Chúng ta sử dụng tensorflow_hub để load model với dòng code sau:
1 2 |
# Load object detection model from Tensorflow Hub object_detector = hub.load("https://tfhub.dev/tensorflow/mask_rcnn/inception_resnet_v2_1024x1024/1") |
Tiếp theo chúng ta sử dụng mô hình ở trên để nhận diện đối tượng với dòng code sau:
1 2 |
# Using loaded model to detect image detector_output = object_detector(img_numpy) |
Kết quả trả về là một python dict với các cặp (key, value) được mô tả tại phần outputs của mô hình trên trang Tensor Flow hub.
1 2 3 4 5 6 7 |
# Example of detector_output print(detector_output.keys()) print('Detection boxes:', detector_output['detection_boxes'].shape) print('Detection classes:', detector_output['detection_classes'].shape) print('Detection scores:', detector_output['detection_scores'].shape) print('Detection classes:', detector_output['detection_classes'][0].numpy().astype(int)) print('Detection scores:', detector_output['detection_scores'][0].numpy()) |
Tại ví dụ này ta được kết quả trả về của Detection boxes có shape là (1, 100, 4). 1 là 1 hình ảnh đầu vào, 100 là số lượng bounding boxes, 4 là 4 giá trị thể hiện tọa độ của bounding box [ymin, xmin, ymax, xmax]. Tương ứng với mỗi một bounding box là class label của bounding box đó và prediction score của class label. Do đó, detection_classes và detection_scores có shape là (1, 100) tương ứng với 100 bounding boxes
Hiện tại, detection_classes là giá trị số tự nhiên 1, 2, 3 …Do đó, để biết tên của label đối với từng detection_class, chúng ta sử dụng hàm create_category_index_from_labelmap trong object_detection/utils/visualization_utils.py của Model Garden như sau:
1 2 3 4 |
# Map class label name with its id label_path = './models/research/object_detection/data/mscoco_label_map.pbtxt' category_index = label_map_util.create_category_index_from_labelmap(label_path, use_display_name=True) print('Category index:', category_index) |
Như vậy class 1 tương ứng là ‘person’, class 2 tương ứng là ‘bicycle’, class 3 là ‘car’ …
Cuối cùng ta sử dụng hàm visualize_boxes_and_labels_on_image_array() và matplotlib để hiện thị kết quả xác định đối tượng như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# overlay bounding boxes and its label on the image viz_utils.visualize_boxes_and_labels_on_image_array( img_numpy[0], detector_output['detection_boxes'][0].numpy(), detector_output['detection_classes'][0].numpy().astype(int), detector_output['detection_scores'][0].numpy(), category_index, use_normalized_coordinates=True, max_boxes_to_draw=100, min_score_thresh=.70, agnostic_mode=False, line_thickness=8) # Display the image plt.figure(figsize=(20,20)) plt.imshow(img_numpy[0]) plt.show() |
Ta được kết quả trả về là bức ảnh bao gồm bounding box của từng đối tượng cũng như class lable của từng đối tượng như sau:
Lưu ý: khác với các mô hình khác thuộc họ R-CNN (R-CNN, Fast R-CNN, Faster R-CNN), Mask-RCNN có thêm một output cho instance segmentation (các bạn xem thêm về Mask-RCNN tại bài Các mô hình sử dụng trong Instance Segmentation). Do đó, ta có thể sử dụng ‘detection_masks’ từ detector_output của Mask-RCNN để thực hiện instance segmentation cho bức ảnh như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# Using Mask-RCNN for Instance Segmentation import tensorflow as tf from object_detection.utils import ops as utils_ops # Get the detection_masks and detection_boxes from model output detection_masks = detector_output['detection_masks'][0] detection_boxes = detector_output['detection_boxes'][0] print('Detection masks shape: ', detection_masks.shape) # Reframe the the bounding box mask to the image size. detection_masks_reframed = utils_ops.reframe_box_masks_to_image_masks(detection_masks, detection_boxes, img_numpy.shape[1], img_numpy.shape[2]) print('Detection masks shape after reframing: ', detection_masks_reframed.shape) print('Image shape: ', img_numpy.shape) # Filter mask pixel values that are above a specified threshold detection_masks_reframed = detection_masks_reframed > 0.6 # Convert from bool to uint8 for visualize_boxes_and_labels_on_image_array() input detection_masks_reframed = tf.cast(detection_masks_reframed, tf.uint8) |
– Tương tự như object detection, chúng ta sẽ sử dụng hàm visualize_boxes_and_labels_on_image_array() để hiển thị instance segmentation của bức ảnh với tham sốinstance_masks. Tham số này yêu cầu dữ liệu là uint8 numpy array với shape [N, image_height, image_width].
– detection_masks từ detector_output có size là mask_height x mask_width (33 x 33). Do đó, ta cần sử dụng hàm reframe_box_masks_to_image_masks() để chuyển detection_masks về size của hình ảnh là image_height x image_width (trong ví dụ này là 1406 x 2048). Ngoài ra, ta cần sử dụng thêm hàm tf.cast() để chuyển đổi dữ liệu về định dạng uint8.
Việc hiển thị instance segmentation được thực hiện như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# overlay bounding boxes and its label on the image viz_utils.visualize_boxes_and_labels_on_image_array( img_numpy[0], detector_output['detection_boxes'][0].numpy(), detector_output['detection_classes'][0].numpy().astype(int), detector_output['detection_scores'][0].numpy(), category_index, instance_masks= detection_masks_reframed.numpy(), use_normalized_coordinates=True, max_boxes_to_draw=100, min_score_thresh=.6, line_thickness=2, mask_alpha=.6) # Display the image plt.figure(figsize=(20,20)) plt.imshow(img_numpy[0]) plt.show() |
Ta được kết quả như sau:
Như vậy chúng ta đã hoàn thành việc xây dựng một ứng dụng phát hiện đối tượng sử dụng mô hình đã được huấn luyện sẵn trên TensorFlow Hub. Các bạn có thể tham khảo Colab notebook của bài viết này trên trang Github của ITechSeeker tại đây.