iT邦幫忙

2021 iThome 鐵人賽

DAY 12
0
AI & Data

觀賞魚辨識的YOLO全餐系列 第 12

標籤圖片的方法與實作 - Day 12

標籤圖片的方法與實作 - Day 12

資料增量 (Data Augmentation) 的部份因為 YOLOV3 可以透過 cfg 檔的設定來自動進行資料增量,所以我們就不在這邊進行資料增量的前置處理。

接著進行的是圖片標籤 (Labeling/Annotation) 的動作,這是一個很乏味的動作,主要就是把原始圖片中要訓練的圖片標示出來,並說明標示物件標籤,而把這些資訊存成文字檔。光是標籤就可以分成三類需要考慮的因素:

  1. 圖片標註的類型 (Image Annotation Types):可以是邊界框 (Bounding boxes),多邊形分割 (Polygonal Segmentation),語義分割 (Semantic Segmentation),3D 長方體 (3D cuboids),關鍵點和界標 (Key-Point and Landmark),直線和樣條 (Lines and Splines)。下圖顯示邊界框與關鍵點和界標的圖型。使用邊界框來標註物件是很常見的標註方式,將目標物件用矩型標註出來,YOLOV3也是使用這種方式。

https://ithelp.ithome.com.tw/upload/images/20210912/2012951080AIf55DGN.png
圖 1、 使用邊界框來標註物件 (Original Photo by Patricia Jekki on Unsplash)

很明顯的,使用關鍵點和界標的標註對於檢測面部特徵、面部表情、情緒、人體部位和姿勢很有用。

https://ithelp.ithome.com.tw/upload/images/20210912/20129510TX3JWOqvrE.jpg
圖 2、 使用關鍵點和界標來標註物件 (Original Photo from COCO dataset)

  1. 圖片標註的格式 (Image Annotation Formats):可以分成 COCO,Pascal VOC 與 YOLO 三種不同的格式。簡單來區分是 COCO 使用的是 JSON 的格式;Pascal VOC 使用 XML 格式;而 YOLO 則是一般文字格式,可以說是類似 CSV 格式,只是都是以空白來進行不同欄位。以下分別是他們的簡單樣板。

COCO format

annotation{
"id" : int,
"image_id": int,
"category_id": int,
"segmentation": RLE or [polygon],
"area": float,
"bbox": [x,y,width,height],
"iscrowd": 0 or 1,
}
categories[{
"id": int,
"name": str,
"supercategory": str,
}]

Pascal VOC

<annotation> 
  <folder>Train</folder> 
  <filename>01.png</filename>      
  <path>/path/Train/01.png</path> 
  <source>  
    <database>Unknown</database> 
  </source>
  <size>  
    <width>224</width>  
    <height>224</height>  
    <depth>3</depth>   
  </size> 
  <segmented>0</segmented> 
  <object>  
    <name>36</name>  
    <pose>Frontal</pose>  
    <truncated>0</truncated>  
    <difficult>0</difficult>  
    <occluded>0</occluded>  
    <bndbox>   
      <xmin>90</xmin>   
      <xmax>190</xmax>   
      <ymin>54</ymin>   
      <ymax>70</ymax>  
    </bndbox> 
  </object>
</annotation>

而 YOLO 的格式如下所示,每一行代表一個物件,分別表示物件名稱 (object-class),物件中心 x 位在整張圖片寬 (image_width) 的比例,物件中心 y 位在整張圖片高 (image_height) 的比例,物件寬度 (target_width) 佔整張圖片寬度 (image_width) 的比例,物件長度 (target_height) 佔整張圖片長度 (image_height) 的比例。物件中心點座標 (x,y),物件的

<object-class> <x_iw_ratio> <y_ih_ratio> <tw_iw_ratio> <th_ih_ratio>

兩者的換算公式如下:

# Pascal VOC
ymin, xmin, ymax, xmax, image_w, image_h = PascalVOC

# 將 Pascal VOC 中的資料轉換成 YOLO 格式 
(x_iw_ratio, y_ih_ratio) = ( ( (xmin + xmax) * 0.5 ) / image_w, ((ymin + ymax) * 0.5 ) / image_h)
tw_iw_ratio = (xmax - xmin) * 1. / image_w
th_ih_ratio = (ymax - ymin) * 1. / image_h
  1. 標籤工具:標籤工作可以簡單的分成半自動跟手動,半自動的標籤工具有:Anno-Mage,顯示出來的自動標示功能還不錯,只是已經 1,2 年沒有繼續維護了;而大多數是用手動工具 labelImg

這邊就不介紹如何使用 labelImg,可以參閱 目标检测使用LabelImg标注VOC数据格式和YOLO数据格式——LabelImg使用详细教程,這邊先測試當取得標籤檔時,如何確認標籤檔是否可以正確的在圖片上生成邊界框。

下圖是我們標籤了下方的兩隻魚,而 YOLO 標籤內容如下,通常我們不會把物件名稱直接打出來,因為這只是對應之用,所以我們給定標籤為 0。

00-frame-0001.txt

0 0.962963 0.447917 0.414815 0.137500
0 0.263889 0.422917 0.416667 0.122917

https://ithelp.ithome.com.tw/upload/images/20210912/20129510ydwT8TNrva.png
圖 3、標籤後的圖片

接著我們試著根據 YOLO 的標籤內容,將 YOLO 格式轉換成邊界框的左上角 (min_x, min_y) 和右下角 (max_x, max_y),重新畫上邊界框,以確保標籤內容的正確性。

./utils/yoloDrawLabel.py

import cv2

# 設定輸入與輸出
inputLabelPath = '../labels/00-frame-0001.txt'
inputImgPath = '../images/00-frame-608x608-0001.jpg'
outputImgPath = '../labels/00-frame-608x608-0001.jpg'
# 圖片大小固定為 608*608
img_w= img_h = 608
# 載入圖片
cv2image = cv2.imread(inputImgPath)

with open(inputLabelPath) as f:
  for line in f:
    line = line.strip() # 刪除多餘的空白
    data = line.split() # 將 YOLO 一列的內容轉成一維陣列
    # 將 YOLO 格式轉換為邊界框的左上角和右下角座標
    bbox_width = float(data[3]) * img_w
    bbox_height = float(data[4]) * img_h
    center_x = float(data[1]) * img_w
    center_y = float(data[2]) * img_h
    min_x, min_y = center_x - (bbox_width / 2), center_y - (bbox_height / 2)
    max_x, max_y = center_x + (bbox_width / 2), center_y + (bbox_height / 2)
    print(min_x,min_y,max_x,max_y)
    # 在圖片上寫上物件名稱
    cv2.putText(cv2image, 'Altolamprologus compressiceps', (int(min_x), int(min_y-6)), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 1, cv2.LINE_AA)
    # 畫出邊界框
    cv2.rectangle(cv2image, (int(min_x),int(min_y)), (int(max_x),int(max_y)), (0,255,255), 2)
    # 將檔案另存新圖片檔
    cv2.imwrite(r'{}'.format(outputImgPath), cv2image)
  f.close()

下圖為輸出結果,可以確認 YOLO 文字檔中的內容是正確的。

https://ithelp.ithome.com.tw/upload/images/20210912/20129510HJeCW3I2W8.jpg
圖 4、讀取 YOLO 文件檔驗證標籤是否正確的圖片

參考資料


上一篇
# 將影片轉換成圖片 - Day 11
下一篇
Day 13 - 半自動標籤圖片的方法與實作
系列文
觀賞魚辨識的YOLO全餐38

尚未有邦友留言

立即登入留言