安装labelme
1创建conda子环境
例如:conda create -n 子环境名 python=版本
conda create -n labelme python=3.7
输入y回车
2激活conda子环境
conda activate labelme
3安装labelme的依赖包
conda install pyqt
conda install pillow
4安装labelme工具包
pip install labelme
安装的错误
如果出现如下报错
WARNING: Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ConnectTimeoutError(<pip._vendor.urllib3.connection.HTTPSConnection object at 0x000002AA50DBB388>, 'Connection to pypi.org timed out. (connect timeout=15)')': /simple/labelme/ ERROR: Operation cancelled by user
使用下面这句话安装labelme(换安装源)
pip install labelme -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
用labelme打标签生成json文件
打开labelme
labelme
1、点击open dir选择包含所有图像的文件夹
2、一次按图片顺序对孔打标签
3、点击保存后,保存json文件
4、点击next image打下一张
所有图片打完标签之后,所有图片的json也就保存完了
根据json生成图像
激活labelme环境之后,
将cmd命令位置进入到生成的json所在文件夹内
然后输入下面命令生成标签图片
labelme_json_to_dataset 1.json -o label_json/1
得到的标签图如下:
注意,该命令也可以通过python批量生成:
import os
json_PATH = "D:\codespace\labelme\\data3\\Y101H2_7B\\16"
jsos_path_list = os.listdir(json_PATH)
jsos_path_list
for i, file_path in enumerate(jsos_path_list):
if 'json' in file_path:
path = 'labelme_json_to_dataset '+file_path+' -o label/'+str(i+1)
print(path)
将下面批量生成的命令行直接复制到json所在文件夹下即可自动生成标签文件夹,注意要提前新建一个label文件夹,该命令无法自动创建文件夹,下面的命令行有时候需要执行两次,我猜测是因为2、4、6这些下一级的文件夹也需要一个创建的过程,第一次执行创建完成后,第二次执行才会保存。
labelme_json_to_dataset 10_20.json -o label/2
labelme_json_to_dataset 10_4.json -o label/4
labelme_json_to_dataset 15_25.json -o label/6
labelme_json_to_dataset 16_8.json -o label/8
labelme_json_to_dataset 17_32.json -o label/10
labelme_json_to_dataset 17_34.json -o label/12
labelme_json_to_dataset 18_13.json -o label/14
labelme_json_to_dataset 19_14.json -o label/16
labelme_json_to_dataset 19_29.json -o label/18
labelme_json_to_dataset 19_31.json -o label/20
labelme_json_to_dataset 25_8.json -o label/22
labelme_json_to_dataset 26_20.json -o label/24
labelme_json_to_dataset 28_6.json -o label/26
labelme_json_to_dataset 29_26.json -o label/28
labelme_json_to_dataset 3_36.json -o label/30
labelme_json_to_dataset 4_14.json -o label/32
labelme_json_to_dataset 4_25.json -o label/34
labelme_json_to_dataset 4_36.json -o label/36
labelme_json_to_dataset 7_19.json -o label/38
labelme_json_to_dataset 9_22.json -o label/40
常用的图像处理库 opencv(cv2)和PIL.Image
一、PIL.Image.open
H×W×C,RGB,数据类型 PIL.JpegImagePlugin.JpegImageFile
通过 numpy.asarray(image_pil) 可转成 numpy.ndarray
二、cv2.imread
H×W×C,BGR,数据类型 numpy.ndarray
通过 cv2.cvtColor(image_cv2, cv2.COLOR_BGR2RGB) 可转成 RGB
注:以上两种库读取到的图片值不一定完全一样(就算都转成 RGB 的 ndarray 之后也),某些像素的值有可能会相差1。
将标签图像转换为二值图像(基于CV2和阈值)和图像移动操作
我实际代码操作中的图像转换,使用的是基于cv2和阈值的方法。
不转也可以,具体变1的过程,可以在代码的数据读取部分中修改
补充:
# img = cv2.imread('ImproveUnet195seg.png',cv2.IMREAD_GRAYSCALE)
cv2.IMREAD_COLOR:加载彩色图片,这个是默认参数,可以直接写1。
cv2.IMREAD_GRAYSCALE:以灰度模式加载图片,可以直接写0。
cv2.IMREAD_UNCHANGED:包括alpha(包括透明度通道),可以直接写-1
GRAY是灰度图,转换规则为: Gray = 0.299R + 0.587G + 0.114B # 单通道
具体使用代码如下
import os
import shutil
import cv2
label_from_PATH = "D:\codespace\labelme\original\label_json"
label_to_PATH = "D:\codespace\labelme\original\label"
filepath_list = os.listdir(label_from_PATH)
# filepath_list.remove("labelme_json_to_dataset.exe")
# 检查是否存在label文件夹
if not os.path.isdir(label_to_PATH):
os.mkdir(label_to_PATH)
# 是否图像二值化
# 如果True则,对图像使用cv2.threshold(灰度图,阈值,填充色,阈值类型)
# 其中填充色0-255是从纯黑色到纯白色
# RGB到灰度图转换公式:L = R * 299/1000 + G * 587/1000+ B * 114/1000
# 由于labelme官方代码本身得到的是RGB图,对于第一个类的配色是[R,G,B]=[128,0,0],因此我们将其转换成灰度图后,
# 得到的灰度矩阵中标签处的值为128*0.299=38.272,取整后为38。
# 因此我们的cv2.threshold中的阈值可以填0-38,均可,只要高于这个值就会复制为255纯白,低于这个值,就会为0,纯黑。
bin_img = True
for i, file_path in enumerate(filepath_list):
src_label = "{}/label.png".format(os.path.join(label_from_PATH, filepath_list[i]))
label_name = "{}.png".format(file_path)
if bin_img:
dest_label = cv2.imread(src_label) #cv2.imread()读取的图片默认是BGR的通道顺序dest_label[:,:,0]=B颜色通道
dest_label = cv2.cvtColor(dest_label, cv2.COLOR_BGR2GRAY)#该方法将读取的图片转为RGB格式
ret, dest_label = cv2.threshold(dest_label, 0, 255, cv2.THRESH_BINARY)
cv2.imwrite(os.path.join(label_to_PATH, label_name), dest_label)
else:
shutil.copy(src_label, os.path.join(label_to_PATH, label_name))
print("{} has been copied to {}".format(label_name, label_to_PATH))
print("All done!!!")
最终得到二值图像如下
经过灰度转换后的标签图如下:
未经过灰度转换后的标签图如下(是labelme默认的RGB[128,0,0]配色,近针对一个类别标签,其他标签配色会改变):
将标签图像转换为二值图像(基于PIL和阈值)
我测试了该方法,但实际代码实践中未采用。
from PIL import Image
import numpy as np
label_path = "/Users/XXX/Documents/codespace/imageSeg0907/data/label_data3_crop_deleted/3034.png"
lab=Image.open(label_path)
# 我们知道PIL中有九种不同模式。分别为1,L,P,RGB,RGBA,CMYK,YCbCr,I,F; 默认是RGB模式读取彩色图
print(np.array(lab).shape)
print(np.unique(np.array(lab)))
lab = np.array(lab)
lab[lab>=1]=255 # 这个值需要提前根据图片判断好
img_arr = np.array(lab)
img_arr[img_arr>=38]=255
print(img_arr)
print(np.unique(img_arr))
img2 = Image.fromarray(img_arr)
img.convert('L')
为灰度图像,每个像素用8个bit表示,0表示黑,255表示白,其他数字表示不同的灰度。
转换公式:L = R * 299/1000 + G * 587/1000+ B * 114/1000
img.convert('1')
The default method of converting a greyscale ("L") or "RGB"
image into a bilevel (mode "1") image uses Floyd-Steinberg
dither to approximate the original image luminosity levels. If
dither is :data:`NONE`, all values larger than 127 are set to 255 (white),
all other values to 0 (black). To use other thresholds, use the
:py:meth:`~PIL.Image.Image.point` method.
由官方代码说明可知, img.convert('1')的阈值默认是127,如果不想用这个阈值,则使用`~PIL.Image.Image.point` method方法,或者用上面代码中的方法,转化成矩阵之后手动修改。
图像切割操作
20张train图片,每张可以切成16张
一张1024*1024切成,16张 256✖️256
import pdb
import os
import shutil
from PIL import Image
import matplotlib.pyplot as plt
# crop_image_PATH = "D:\codespace\labelme\\0905img\label_json\\crop_train60"#没用到,在下面直接写了这个地址
image_PATH = "D:\codespace\labelme\\data3\\Y101H2_7B\\16\image"
filepath_list = os.listdir(image_PATH)
for i, file_path in enumerate(filepath_list):
src_label = "{}".format(os.path.join(image_PATH, filepath_list[i]))
# label_name = "D:\codespace\labelme\\0905img\label_json\\crop_train60\\{}".format('crop_'+filepath_list[i])
img = Image.open(src_label)
# plt.imshow(img) # 展示图片
for j in range(4):
for k in range(4):
label_name = "D:\codespace\labelme\\data3\\Y101H2_7B\\16\image_data3_crop\\{}".format(str(j)+str(k)+filepath_list[i])
crop_img = img.crop((k*256,j*256,(k+1)*256,(j+1)*256))
crop_img.save(label_name)
# break
print('finish')
手动挑选不用的图像
根据label观察全黑的图像(进行删除),其实有用,算是全负样本。
然后根据删除后的label 列表,删除image列表。生成最终的image_deleted和label_deleted文件夹。
注意:对于mac来说,会有一个叫做.DS_Store的文件在图片文件夹中,需要大家自动进入图片文件夹用命令行删除一下,命令行如下:
find ./ -name ".DS_Store" -depth -exec rm {} \;
# 根据手删的label图片文件夹中的文件名 删除 image图片文件夹中多余图片
import os
all_image_from_PATH = "/Users/XXX/Documents/codespace/imageSeg0907/data/label_data3_crop_deleted"
use_image_from_PATH = "/Users/XXX/Documents/codespace/imageSeg0907/data/image_data3_crop_deleted"
all_filepath_list = os.listdir(all_image_from_PATH)
use_filepath_list = os.listdir(use_image_from_PATH)
print(use_filepath_list)
print(len(all_filepath_list))
print(len(use_filepath_list))
i = 0
for image_name in all_filepath_list:
# 如果在可用的图像列表中,则继续循环,否则推出循环
if (image_name in use_filepath_list):
continue
else:
# print(image_name)
i = i+1 #不在的个数
os.remove(all_image_from_PATH+'/'+image_name)
# print(i)
后记:labelme生成的标注图像分析
我们以一张单一类别的标签为例。
一、PIL.Image.open
H×W×C,RGB,数据类型 PIL.JpegImagePlugin.JpegImageFile
通过 numpy.asarray(image_pil) 可转成 numpy.ndarray
二、cv2.imread
H×W×C,BGR,数据类型 numpy.ndarray
通过 cv2.cvtColor(image_cv2, cv2.COLOR_BGR2RGB) 可转成 RGB
注:以上两种库读取到的图片值不一定完全一样(就算都转成 RGB 的 ndarray 之后也),某些像素的值有可能会相差1。
CV2读取
import cv2 # open-cv
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('label.png') #默认BGR方式读取,得到三通道数据类型numpy.ndarray
注:
v2.IMREAD_COLOR:加载彩色图片,这个是默认参数,可以直接写1。
cv2.IMREAD_GRAYSCALE:以灰度模式加载图片,可以直接写0。
cv2.IMREAD_UNCHANGED:包括alpha(包括透明度通道),可以直接写-1
GRAY是灰度图,转换规则为: Gray = 0.299R + 0.587G + 0.114B # 单通道
CV2展示
import cv2 # open-cv
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('label.png') #默认BGR方式读取,得到三通道数据类型numpy.ndarray
plt.imshow(img) #展示
我们发现展示出的图片的标注格式为蓝色,与红色不同。这是因为原始的标注格式读取进来的时候是BGR,但是plt.imgshow(img)展示默认放入的图片是RGB,因此需要先转换再展示。
import cv2 # open-cv
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('label.png') #默认BGR方式读取,得到三通道数据
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.imshow(img) #展示
CV2读取的图片分析
参考资料:labelme批量生成label后,如何获取对应标注颜色的rgb值,用于语义分割训练时的标注颜色说明文件的书写
类别标签颜色,默认按照labelme中默认代码的颜色,背景默认RGB都为0,全黑。
其余的颜色按照labelme原始代码从r=128,g=0,b=0开始。
CV2默认读取进来的数据就是这种格式,通常我们用灰度方式读取,合并为单通道的numpy数组矩阵,
其转化方式为:Gray = 0.299R + 0.587G + 0.114B
#统计矩阵中的数值有哪些
from collections import Counter # 计数
print(img[:,:,0].shape)
print(Counter(img[:,:,0].flatten())) #结果是Counter({0: 1047396, 128: 1180})
print(Counter(img.flatten())) #结果是Counter({0: 3144548, 128: 1180})
PIL读取标签图
from PIL import Image
pilimg = Image.open('中期考核/label1-7/1_label.png')
# pilimg.show() #展示标签图
print(np.array(pilimg).shape) # 标签图转换为numpy.narray
print(Counter(np.array(pilimg).flatten())) # 用PIL读取得到的就是单通道的标签从1,2,3分别代表类别
#Counter({0: 1047396, 1: 1180})
因此在实际的工程中我们更常使用PIL来处理盒转化标签图。