本篇文章是試圖幫助自己簡化 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 行參數,並可以直接得到輸出結果的方式:
- INFERENCE_IMAGE: 要辨識的圖片
- WEIGHTS_PATH: mask_rcnn_coco.h5 權重模型 的位置
- 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
沒有留言:
張貼留言