UNet圖像分割模型相關總結
1.制作圖像分割數據集
1.1使用labelme進行標注
(注:labelme與labelImg類似,都屬於對圖像數據集進行標注的軟件。但不同的是,labelme更關心對象的邊緣和輪廓細節,也即通過生成和訓練圖像對應的mask來實現圖像分割的目的。這里的分割一般使用的是閉合多邊形折線來進行標注,每張圖片標注完成后,按下Ctrl+S來進行保存,此時存儲的文件是與圖片同名的.json格式文件。)
我們要得到的結果是mask,保存生成的.json文件還需要通過轉換得到對應的mask圖像。
(這里的轉換有兩種方式,一種是找到當前python環境下的labelme_json_to_dataset.py進行修改,二是直接在命令行中調用對應的接口labelme_json_to_dataset {file}生成mask,由於單命令行直接執行一個文件的生成,因此這里考慮編寫對應的腳本,對當前目錄下的.json進行批量處理。)
1.2生成mask文件
使用第二種方式,步驟如下:
1.新建.sh腳本文件
touch json2mask.sh
2.編輯.sh腳本文件
將下列內容復制進.sh腳本文件中
gedit json2mask.sh
#!/bin/bash
let i=1
path=./
cd ${path}
for file in *.json
do
labelme_json_to_dataset ${file}
let i=i+1
done
3.執行腳本
bash json2mask.sh
對.json文件進行轉換生成之后,會得到對應名稱的文件夾
如圖所示

查看文件夾,發現存在四個文件:
分別為以下:
- img.png,源文件圖像
- label.png,標簽圖像
- label_names.txt,標簽中的各個類別的名稱
- label_viz.png,源文件與標簽融合文件
其中的label.png即是我們要的想要的標簽文件。如果本來的源文件圖像為jpg格式,我們會發現生成的png格式源文件圖像大小會大很多,不必驚慌。JPG質量不會有變化,但大小通常會增加幾倍左右,這是因為JPG是有損壓縮,而PNG是無損壓縮。
1.3 轉換二值圖像並批量整理
-
得到以上這些結果是不是意味着結束了呢?
事實上,到這里才僅僅完成的一半,我們還需要對label.png圖片進行轉換為二值圖片,最后我們可以遍歷文件夾內所有小文件夾,分別對其中的img和轉換后的label進行重命名存儲到對應的imgs和masks文件目錄下,到這一步整個數據集制作才算全部完成。
通過執行下面代碼可以批量的對各個小文件夾下的圖片進行重命名和整理:
'''
@author: linxu
@contact: 17746071609@163.com
@time: 2021-08-21 上午11:54
@desc: 將多通道mask圖像批量轉換為單通道二值化圖像並存放到指定位置
'''
import cv2
import numpy as np
import os
import os
def os_mkdir(path):
# 去除首位空格
path = path.strip()
# 去除尾部/符號
path = path.rstrip("/")
# 判斷路徑是否存在
isExists = os.path.exists(path)
# 判斷結果
if not isExists:
# 如果不存在則創建目錄
# 創建目錄操作函數
os.makedirs(path)
print(path + ' 創建成功')
return True
else:
# 如果目錄存在則不創建,並提示目錄已存在
print(path + ' 目錄已存在')
return False
def mask2binimg(path,show=False):
for root, dirs, files in os.walk(path):
print('################################################################')
for name in files:
# 遍歷label生成的{x}_json目錄
if len(dirs) == 0:
# print('root', root)
# 字符分割,得到label排序序號
filepath = os.path.split(root)[0]
numname = os.path.split(root)[1]
n_name = numname.replace('_json','')
# 處理原圖img
if name == 'img.png':
fname = os.path.join(root, name)
print('INFO[img]', fname)
img = cv2.imread(fname)
img_dst = cv2.resize(img, (640, 480))
# img = cv2.resize(img, (0, 0), fx=0.3, fy=0.3, interpolation=cv2.INTER_NEAREST)
if show:
cv2.imshow('img', img_dst)
cv2.waitKey()
# 根據指定路徑存取二值化圖片
img_path = filepath + '/imgs/'
os_mkdir(img_path)
cv2.imwrite(img_path + str(n_name) + '.png', img_dst)
# 處理label標簽圖
if name == 'label.png':
fname = os.path.join(root, name)
print('INFO[label]', fname)
label = cv2.imread(fname)
label = cv2.resize(label, (640, 480))
gray = cv2.cvtColor(label, cv2.COLOR_BGR2GRAY)
retVal, dst = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU)
# 顯示圖片
if show:
cv2.imshow('label', label)
cv2.imshow('dst', dst)
if cv2.waitKey(1) & 0xff == ord("q"):
break
# 根據指定路徑存取二值化圖片
mask_path = filepath + '/masks/'
os_mkdir(mask_path)
cv2.imwrite(mask_path + str(n_name) + '.png', dst)
print('當前圖片轉換完成...')
pass
if __name__ == '__main__':
path = '/home/linxu/下載/flow_dataset/image/'
mask2binimg(path,False)
運行結束后,會發現目錄下多了兩個文件夾,一個是imgs,用來存放原圖;另外一個是masks,用來存放二值化標注圖像。
文件目錄imgs下內容如下圖所示:
文件目錄masks下內容如下圖所示:
確認imgs與masks內容無誤之后,將這兩個文件夾拷貝到UNet模型源碼目錄下的data路徑,如下圖所示:
至此,數據集制作完畢並放置到指定訓練路徑下。
2.Train訓練
制作完數據集之后,下一步就是對數據集進行訓練
python train.py -h
2.1 用法
train.py [-h] [-e E] [-b [B]] [-l [LR]] [-f LOAD] [-s SCALE] [-v VAL]
在圖像和目標掩碼上訓練 UNet
可選參數:
- -h , --help 顯示此幫助信息並退出
- -e E, --epochs E 時期數(默認值:5)
- -b [B], --batch-size [B]
批量大小(默認值:1) - -l [LR], --learning-rate [LR]
學習率(默認:0.1) - -f LOAD, --load LOAD 從 .pth 文件加載模型(默認:False)
- -s SCALE, --scale SCALE
圖像的縮小因子(默認值:0.5) - -v VAL, --validation VAL
用作驗證的數據百分比 (0-100)
(默認值:10.0)
默認情況下,該scale
值為 0.5,因此如果您希望獲得更好的結果(但使用更多內存),請將其設置為 1。
輸入圖像和目標掩碼應分別位於data/imgs
和data/masks
文件夾中。
2.2 調用示例
python train.py -e 200 -b 1 -l 0.1 -s 0.5 -v 15.0
3.Predict預測
python predict.py -h
3.1 用法
predict.py [-h] [--model FILE] --input INPUT [INPUT ...]
[--output INPUT [INPUT ...]] [--viz] [ --no-save]
[--mask-threshold MASK_THRESHOLD] [--scale SCALE]
可選參數:-h , --help 顯示此幫助消息並退出
-
--model FILE, -m FILE
指定文件在該模型被存儲(默認值:MODEL.pth) -
--input INPUT [INPUT ...],-i INPUT [INPUT ...]
的輸入圖像的文件名(默認值:無) -
--output INPUT [INPUT ...], -o INPUT [INPUT ...]
輸出圖像的文件名(默認值:無)--
viz,-v 在處理圖像時可視化(默認值:False) -
-- no -save, -n 不保存輸出掩碼 (默認: False)
-
--mask-threshold MASK_THRESHOLD, -t MASK_THRESHOLD
考慮掩碼像素 白色的最小概率值(默認: 0.5) -
--scale SCALE, -s SCALE 比例因子對於輸入圖像(默認值:0.5)
3.2 調用示例
- 要預測單個圖像並保存它:
python predict.py -i image.jpg -o output.jpg
- 要預測多個圖像並顯示它們而不保存它們:
python predict.py -i image1.jpg image2.jpg --viz --no-save
3.3 融合預覽
為更加直觀地感受分割后得到的結果,下面采用圖像融合的方式進行預覽
(說明:其中img1為圖像原圖,img2為預測的二值圖像,image為兩者根據一定比例融合之后得到的結果。)
- 下面一並附上圖像融合代碼
import cv2
import numpy as np
src = "/home/linxu/下載/flow_dataset/image/30.jpg"
mask = "/home/linxu/下載/flow_dataset/output.png"
# 使用opencv疊加圖片
img1 = cv2.imread(src)
img2 = cv2.imread(mask)
alpha = 1
meta = 0.4
gamma = 0
cv2.imshow('img1', img1)
cv2.imshow('img2', img2)
image = cv2.addWeighted(img1,alpha,img2,meta,gamma)
cv2.imshow('image', image)
cv2.waitKey(0)