(+84) 236.3827111 ex. 402

CÁNH CHỈNH TỰ ĐỘNG KHI IN CHỨNG MINH NHÂN DÂN BẰNG PYTHON - PHẦN 02 (Tiếp theo)


Như đã thấy ở bên trên chúng ta cần phải hậu xử lý lại kết quả thì output mới ngon được. Cách đầu tiên chúng ta có thể nghĩ đến đó là gộp những boxes có vị trí tương đối overlap với nhau và gộp chúng và cùng 1 class. Với bài toán này các boxes thường ở cách nhau khá xa nên hầu như hai boxes có tọa độ tương đối gần nhau thì thường cùng classs. Nếu không cùng thì nên xem lại dữ liệu có chỗ nào bị gán nhãn sai không.

Chúng ta sẽ thực hiện gộp các boxes có độ overlap nhất định đồng thời gán lại các labels tương ứng với các box đã được gộp đó. Chúng ta thực hiện chúng với hàm sau:

import numpy as np 

def non_max_suppression_fast(boxes, labels, overlapThresh):
    # if there are no boxes, return an empty list
    if len(boxes) == 0:
        return []

    # if the bounding boxes integers, convert them to floats --
    # this is important since we'll be doing a bunch of divisions
    if boxes.dtype.kind == "i":
        boxes = boxes.astype("float")
    #  
    # initialize the list of picked indexes   
    pick = []

    # grab the coordinates of the bounding boxes
    x1 = boxes[:,0]
    y1 = boxes[:,1]
    x2 = boxes[:,2]
    y2 = boxes[:,3]

    # compute the area of the bounding boxes and sort the bounding
    # boxes by the bottom-right y-coordinate of the bounding box
    area = (x2 - x1 + 1) * (y2 - y1 + 1)
    idxs = np.argsort(y2)

    # keep looping while some indexes still remain in the indexes
    # list
    while len(idxs) > 0:
        # grab the last index in the indexes list and add the
        # index value to the list of picked indexes
        last = len(idxs) - 1
        i = idxs[last]
        pick.append(i)

        # find the largest (x, y) coordinates for the start of
        # the bounding box and the smallest (x, y) coordinates
        # for the end of the bounding box
        xx1 = np.maximum(x1[i], x1[idxs[:last]])
        yy1 = np.maximum(y1[i], y1[idxs[:last]])
        xx2 = np.minimum(x2[i], x2[idxs[:last]])
        yy2 = np.minimum(y2[i], y2[idxs[:last]])

        # compute the width and height of the bounding box
        w = np.maximum(0, xx2 - xx1 + 1)
        h = np.maximum(0, yy2 - yy1 + 1)

        # compute the ratio of overlap
        overlap = (w * h) / area[idxs[:last]]

        # delete all indexes from the index list that have
        idxs = np.delete(idxs, np.concatenate(([last],
         np.where(overlap > overlapThresh)[0])))

    # return only the bounding boxes that were picked using the
    # integer data type
    
    final_labels = [labels[idx] for idx in pick]
    final_boxes = boxes[pick].astype("int")
    
    return final_boxes, final_labels

boxes và Chúng ta sẽ thu được kết quả như sau:


final_boxes 
>>>
array([[ 16, 647,  83, 711],
       [894, 636, 956, 701],
       [ 11,  87,  79, 149],
       [892,  80, 953, 139]])
       
final_labels
>>>
['bottom_left', 'bottom_right', 'top_left', 'top_right']

Perspective Transform

Trước tiên chúng ta cần xác định được tọa độ các điểm nguồn dựa vào vị trí của các bxoes đã detect được. Chúng ta đơn giản hóa quá trình này bằng cách lấy điểm chính giữa của từng box thành điểm nguồn. Sử dụng hàm sau


def get_center_point(box):
    xmin, ymin, xmax, ymax = box
    return (xmin + xmax) // 2, (ymin + ymax) // 2

final_points từ tập hợp các boxes thu được phía trên

final_points = list(map(get_center_point, final_boxes))

Transform sang tọa độ đích

Ở đây fix cứng tọa độ đích là ảnh 500x300 cho gần với kích thước của chứng minh thư. Bạn đọc có thể thay đổi nó. Tiếp theo chúng ta tiến hành transform

source_points = np.float32([
    label_boxes['top_left'], label_boxes['top_right'], label_boxes['bottom_right'], label_boxes['bottom_left']
])

# Transform 
crop = perspective_transoform(image, source_points)

Kết luận

Bài này khá đơn giản với mong muốn các bạn có thể hiểu đại khái các bước xử lý Alignment cho ảnh chứng minh thư như thế nào. Bằng việc sử dụng thư viện Detecto giúp cho việc training mô hình rất đơn giản và dần dần khiến chúng ta có cảm giác việc sử dụng Deep Learning cũng là một công cụ giúp chúng ta lập trình và giải quyết bài toán tốt hơn chứ không phải một cái gì đó khủng khiếp như người ta từng nghĩ cả. Chúc các bạn vui vẻ và hẹn gặp lại trong những bài viết sau