2020年9月6日 星期日

Mask RCNN - COCO 模型執行圖片標記

本篇文章是試圖幫助自己簡化 MaskRCNN 的執行流程,只想要輸入一張圖片,並回傳結果。

環境準備

  • 安裝 CUDA,安裝對應 Tensorflow 版本的 CUDA。

    對應的版本,請參考官方說明: https://www.tensorflow.org/install/source#gpu

    本章節使用他人建置好的 MaskRCNN 環境: Tensorflow 2.0 ,所以安裝
    CUDA 10.1 Update  2

    並記得設定 CUDA_PATH
     
  • (Windows 建議要做) 安裝 Anaconda 並安裝 Python 3.6

    conda create -n mask_rcnn python=3.7

  • 在 MaskRCNN 先前的 release 中 (46f8ea5) 下載 mask_rcnn_coco.h5 權重模型
    https://github.com/matterport/Mask_RCNN/releases


環境建置

切換 conda 環境:

conda activate mask_rcnn


git clone 專案: 

git clone https://github.com/akTwelve/Mask_RCNN.git aktwelve_mask_rcnn


在 aktwelve_mask_rcnn 目錄下安裝依賴套件:

pip install -r requirements.txt


在 aktwelve_mask_rcnn 目錄下安裝 mask_rcnn:

python setup.py clean --all install


應用 - 直接輸入圖片跟模型,得到輸出

想要直接看到輸出,只能用 Jupyter Notebook, 或是直接到 mask_rcnn/visualize.py 修改。

以下是,改動 15 - 17 行參數,並可以直接得到輸出結果的方式:

  1.  INFERENCE_IMAGE: 要辨識的圖片
  2.  WEIGHTS_PATH: mask_rcnn_coco.h5 權重模型  的位置
  3. MASK_RCNN_PROJECT_PATH: 剛才 clone 的 MaskRCNN 目錄


討論部分 - 執行多張圖片如何進行?

不要直接把上一個小節的  Code 全部包成  Function ,這樣的話每一次呼叫 Function 就會重新載入模型,會浪費很多計算成本,而且速度又非常的慢。


所以,可以直接用 cv 把圖片載入,丟到 Line:76 - Line 83 去執行,每次更改 results 辨識的結果就好。


討論部分 - 可以讓他輸出成圖片嗎? 如果只有 Jupyter-Notebook 能看到結果,那我可以用哪些參數?

想要輸出成圖片,可以直接去原本官方的 code (visualize.py) 複製 display_instance 的 function,然後把裡面的 plot 改成 save 就能儲存辨識的結果,可是,這可能不會是大多應用程式會需要的。

我們真正關心的是能不能拿到辨識後的標籤、方框位置、Shape(多邊形) 資料,而這些資料正是 Line 81 套用的 r['rois'], r['masks'], r['class_ids'], classes, r['scores']。


正如以下的程式碼,我直接拿 visualize.py 修改了一個可以直接存成圖片的 function,可以直接把這段 code 跟上面的 Inference code 放在一起。

import os
import sys
import random
import itertools
import colorsys

import numpy as np
from skimage.measure import find_contours
import matplotlib.pyplot as plt
from matplotlib import patches,  lines
from matplotlib.patches import Polygon
import IPython.display

def saveimg(image, boxes, masks, class_ids, class_names,
                      scores=None, title="",
                      figsize=(16, 16), ax=None,
                      show_mask=True, show_bbox=True,
                      colors=None, captions=None,filename=None):
    """
    boxes: [num_instance, (y1, x1, y2, x2, class_id)] in image coordinates.
    masks: [height, width, num_instances]
    class_ids: [num_instances]
    class_names: list of class names of the dataset
    scores: (optional) confidence scores for each box
    title: (optional) Figure title
    show_mask, show_bbox: To show masks and bounding boxes or not
    figsize: (optional) the size of the image
    colors: (optional) An array or colors to use with each object
    captions: (optional) A list of strings to use as captions for each object
    """
    # Number of instances
    N = boxes.shape[0]
    if not N:
        print("\n*** No instances to display *** \n")
    else:
        assert boxes.shape[0] == masks.shape[-1] == class_ids.shape[0]

    # If no axis is passed, create one and automatically call show()
    auto_show = False
    if not ax:
        _, ax = plt.subplots(1, figsize=figsize)
        auto_show = True

    # Generate random colors
    colors = colors or visualize.random_colors(N)

    # Show area outside image boundaries.
    height, width = image.shape[:2]
    ax.set_ylim(height + 10, -10)
    ax.set_xlim(-10, width + 10)
    ax.axis('off')
    ax.set_title(title)

    masked_image = image.astype(np.uint32).copy()
    for i in range(N):
        color = colors[i]

        # Bounding box
        if not np.any(boxes[i]):
            # Skip this instance. Has no bbox. Likely lost in image cropping.
            continue
        y1, x1, y2, x2 = boxes[i]
        if show_bbox:
            p = patches.Rectangle((x1, y1), x2 - x1, y2 - y1, linewidth=2,
                                alpha=0.7, linestyle="dashed",
                                edgecolor=color, facecolor='none')
            ax.add_patch(p)

        # Label
        if not captions:
            class_id = class_ids[i]
            score = scores[i] if scores is not None else None
            label = class_names[class_id]
            caption = "{} {:.3f}".format(label, score) if score else label
        else:
            caption = captions[i]
        ax.text(x1, y1 + 8, caption,
                color='w', size=11, backgroundcolor="none")

        # Mask
        mask = masks[:, :, i]
        if show_mask:
            masked_image = visualize.apply_mask(masked_image, mask, color)

        # Mask Polygon
        # Pad to ensure proper polygons for masks that touch image edges.
        padded_mask = np.zeros(
            (mask.shape[0] + 2, mask.shape[1] + 2), dtype=np.uint8)
        padded_mask[1:-1, 1:-1] = mask
        contours = find_contours(padded_mask, 0.5)
        for verts in contours:
            # Subtract the padding and flip (y, x) to (x, y)
            verts = np.fliplr(verts) - 1
            p = Polygon(verts, facecolor="none", edgecolor=color)
            ax.add_patch(p)
    ax.imshow(masked_image.astype(np.uint8))
    plt.savefig(filename)

在這裡可以注意到最後一行直接讓 plt 變成 savefig,如此一來原本的程式只要把 display_instances() 換成 saveimg 就行了。


原本的 visualize.display_instance 用法:

# Display results
ax = get_ax(1)
r = results[0]
visualize.display_instances(im, r['rois'], r['masks'], r['class_ids'], 
                            classes, r['scores'], ax=ax,
                            title="Predictions"

改成:

# Display results
ax = get_ax(1)
r = results[0]
saveimg(im, r['rois'], r['masks'], r['class_ids'], 
                            classes, r['scores'], ax=ax,
                            title="Predictions",filename="./test.png")

就會在指定路徑儲存了。


討論部分 - 針對原本的腳本執行,移植內容

在這邊,我直接移植了 classes, MaskRCNN 訓練都需要類別 (label) 的標籤,裡面是除了 'BG' (背景也是標籤) 以外,該模型訓練對應的標籤值,如果照原本官方的 sample 去跑,可能會需要下載到一個很大的 .json 檔案,裡面是放 coco 標記的資料,因為太麻煩,我就直接把所有標籤寫此在上面的工具中。




Reference:

https://www.immersivelimit.com/tutorials/mask-rcnn-for-windows-10-tensorflow-2-cuda-101

https://github.com/akTwelve/tutorials/blob/master/mask_rcnn/MaskRCNN_TrainAndInference.ipynb

https://www.itread01.com/content/1545048486.html

沒有留言:

張貼留言

© Mac Taylor, 歡迎自由轉貼。
Background Email Pattern by Toby Elliott
Since 2014