Data_Aug(数据增强)
1 python+OpenCV (备用)
github:https://github.com/tranleanh/data-augmentation
wechat:https://mp.weixin.qq.com/s/UFx4AGNEF_qBTBNYsLfZXQ
import os
import cv2
import numpy as np
import random
def file_lines_to_list(path):
'''
### Convert Lines in TXT File to List ###
path: path to file
'''
with open(path) as f:
content = f.readlines()
content = [(x.strip()).split() for x in content]
return content
def get_file_name(path):
'''
### Get Filename of Filepath ###
path: path to file
'''
basename = os.path.basename(path)
onlyname = os.path.splitext(basename)[0]
return onlyname
def write_anno_to_txt(boxes, filepath):
'''
### Write Annotation to TXT File ###
boxes: format [[obj x1 y1 x2 y2],...]
filepath: path/to/file.txt
'''
txt_file = open(filepath, "w")
for box in boxes:
print(box[0], int(box[1]), int(box[2]), int(box[3]), int(box[4]), file=txt_file)
txt_file.close()
def cutout(img, gt_boxes, amount=0.5):
'''
### Cutout ###
img: image
gt_boxes: format [[obj x1 y1 x2 y2],...]
amount: num of masks / num of objects
'''
out = img.copy()
ran_select = random.sample(gt_boxes, round(amount*len(gt_boxes)))
for box in ran_select:
x1 = int(box[1])
y1 = int(box[2])
x2 = int(box[3])
y2 = int(box[4])
mask_w = int((x2 - x1)*0.5)
mask_h = int((y2 - y1)*0.5)
mask_x1 = random.randint(x1, x2 - mask_w)
mask_y1 = random.randint(y1, y2 - mask_h)
mask_x2 = mask_x1 + mask_w
mask_y2 = mask_y1 + mask_h
cv2.rectangle(out, (mask_x1, mask_y1), (mask_x2, mask_y2), (0, 0, 0), thickness=-1)
return out
def colorjitter(img, cj_type="b"):
'''
### Different Color Jitter ###
img: image
cj_type: {b: brightness, s: saturation, c: constast}
'''
if cj_type == "b":
# value = random.randint(-50, 50)
value = np.random.choice(np.array([-50, -40, -30, 30, 40, 50]))
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(hsv)
if value >= 0:
lim = 255 - value
v[v > lim] = 255
v[v <= lim] += value
else:
lim = np.absolute(value)
v[v < lim] = 0
v[v >= lim] -= np.absolute(value)
final_hsv = cv2.merge((h, s, v))
img = cv2.cvtColor(final_hsv, cv2.COLOR_HSV2BGR)
return img
elif cj_type == "s":
# value = random.randint(-50, 50)
value = np.random.choice(np.array([-50, -40, -30, 30, 40, 50]))
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(hsv)
if value >= 0:
lim = 255 - value
s[s > lim] = 255
s[s <= lim] += value
else:
lim = np.absolute(value)
s[s < lim] = 0
s[s >= lim] -= np.absolute(value)
final_hsv = cv2.merge((h, s, v))
img = cv2.cvtColor(final_hsv, cv2.COLOR_HSV2BGR)
return img
elif cj_type == "c":
brightness = 10
contrast = random.randint(40, 100)
dummy = np.int16(img)
dummy = dummy * (contrast/127+1) - contrast + brightness
dummy = np.clip(dummy, 0, 255)
img = np.uint8(dummy)
return img
def noisy(img, noise_type="gauss"):
'''
### Adding Noise ###
img: image
cj_type: {gauss: gaussian, sp: salt & pepper}
'''
if noise_type == "gauss":
image=img.copy()
mean=0
st=0.7
gauss = np.random.normal(mean,st,image.shape)
gauss = gauss.astype('uint8')
image = cv2.add(image,gauss)
return image
elif noise_type == "sp":
image=img.copy()
prob = 0.05
if len(image.shape) == 2:
black = 0
white = 255
else:
colorspace = image.shape[2]
if colorspace == 3: # RGB
black = np.array([0, 0, 0], dtype='uint8')
white = np.array([255, 255, 255], dtype='uint8')
else: # RGBA
black = np.array([0, 0, 0, 255], dtype='uint8')
white = np.array([255, 255, 255, 255], dtype='uint8')
probs = np.random.random(image.shape[:2])
image[probs < (prob / 2)] = black
image[probs > 1 - (prob / 2)] = white
return image
def filters(img, f_type = "blur"):
'''
### Filtering ###
img: image
f_type: {blur: blur, gaussian: gaussian, median: median}
'''
if f_type == "blur":
image=img.copy()
fsize = 9
return cv2.blur(image,(fsize,fsize))
elif f_type == "gaussian":
image=img.copy()
fsize = 9
return cv2.GaussianBlur(image, (fsize, fsize), 0)
elif f_type == "median":
image=img.copy()
fsize = 9
return cv2.medianBlur(image, fsize)
def randomcrop(img, gt_boxes, scale=0.5):
'''
### Random Crop ###
img: image
gt_boxes: format [[obj x1 y1 x2 y2],...]
scale: percentage of cropped area
'''
# Crop image
height, width = int(img.shape[0]*scale), int(img.shape[1]*scale)
x = random.randint(0, img.shape[1] - int(width))
y = random.randint(0, img.shape[0] - int(height))
cropped = img[y:y+height, x:x+width]
resized = cv2.resize(cropped, (img.shape[1], img.shape[0]))
# Modify annotation
new_boxes=[]
for box in gt_boxes:
obj_name = box[0]
x1 = int(box[1])
y1 = int(box[2])
x2 = int(box[3])
y2 = int(box[4])
x1, x2 = x1-x, x2-x
y1, y2 = y1-y, y2-y
x1, y1, x2, y2 = x1/scale, y1/scale, x2/scale, y2/scale
if (x1<img.shape[1] and y1<img.shape[0]) and (x2>0 and y2>0):
if x1<0: x1=0
if y1<0: y1=0
if x2>img.shape[1]: x2=img.shape[1]
if y2>img.shape[0]: y2=img.shape[0]
new_boxes.append([obj_name, x1, y1, x2, y2])
return resized, new_boxes
if __name__ == "__main__":
# Load Image and Its Annotation
img_name = "tr03-14-18-1-FRONT"
img_path = f"data/{img_name}.jpg"
anno_apth = f"data/{img_name}.txt"
image = cv2.imread(img_path)
gt_boxes = file_lines_to_list(anno_apth)
# Create Output Folder
dir_path = f"outputs"
if not os.path.exists(dir_path):
os.makedirs(dir_path)
# Cutout
cutout = cutout(image, gt_boxes, amount=0.5)
cv2.imwrite(f"{dir_path}/{img_name}_cutout.jpg", cutout)
# ColorJitter
b_img = colorjitter(image, cj_type="b")
s_img = colorjitter(image, cj_type="s")
c_img = colorjitter(image, cj_type="c")
cv2.imwrite(f"{dir_path}/{img_name}_brightness.jpg", b_img)
cv2.imwrite(f"{dir_path}/{img_name}_saturation.jpg", s_img)
cv2.imwrite(f"{dir_path}/{img_name}_contrast.jpg", c_img)
# Adding Noise
gaussn_img = noisy(image, noise_type="gauss")
sp_img = noisy(image, noise_type="sp")
cv2.imwrite(f"{dir_path}/{img_name}_gaussnoise.jpg", gaussn_img)
cv2.imwrite(f"{dir_path}/{img_name}_spnoise.jpg", sp_img)
# Filtering
blur_img = filters(image, f_type = "blur")
gaussf_img = filters(image, f_type = "gaussian")
median_img = filters(image, f_type = "median")
cv2.imwrite(f"{dir_path}/{img_name}_blur.jpg", blur_img)
cv2.imwrite(f"{dir_path}/{img_name}_gaussblur.jpg", gaussf_img)
cv2.imwrite(f"{dir_path}/{img_name}_median.jpg", median_img)
# Random Crop
rancrop, new_boxes = randomcrop(image, gt_boxes, scale=0.5)
cv2.imwrite(f"{dir_path}/{img_name}_rancrop.jpg", rancrop)
filepath = f"{dir_path}/{img_name}_rancrop.txt"
write_anno_to_txt(new_boxes, filepath)
print("Generating Done!")
View Code
2 imague模块(推荐)
文档参考:
Doc:https://imgaug.readthedocs.io/en/latest/source/installation.html
Github:https://github.com/aleju/imgaug
示例:
'''
该程序用于查看imgaug中的增广算法的作用效果
1. 修改代码第四行的 op 后的增广算法
2. 修改操作的图片的路径
3. 通过显示的图像可以观察到增广效果
4. 该效果是经过op 和 op_ 两种操作叠加而成的图片
5. op_ 操作为剪切和填充
6. 如果想单独看 op 效果可以将代码12行[op, op_]中的op_去掉
'''
from imgaug import augmenters as iaa
import imgaug as ia
import matplotlib.pyplot as plt
import cv2
op = iaa.CoarseDropout(0.02, size_percent=0.15, per_channel=0.5) # 可修改成别的增广算法
op_ = iaa.CropAndPad( #剪切和填充
percent=(0, 0.2),
pad_mode=["constant", "edge"],
pad_cval=(0, 255)
)
seq = iaa.Sequential([ op , op_])
imgList = [cv2.imread("images/001.jpg"),cv2.imread("images/002.jpg")] # 修改成图片路径
img_aug = seq.augment_images(imgList)
plt.figure(figsize=(8,8))
plt.subplot(2,2,1)
plt.imshow(cv2.cvtColor(imgList[0],cv2.COLOR_BGR2RGB))
plt.subplot(2,2,2)
plt.imshow(cv2.cvtColor(img_aug[0],cv2.COLOR_BGR2RGB))
plt.subplot(2,2,3)
plt.imshow(cv2.cvtColor(imgList[1],cv2.COLOR_BGR2RGB))
plt.subplot(2,2,4)
plt.imshow(cv2.cvtColor(img_aug[1],cv2.COLOR_BGR2RGB))
plt.show()
test_aug
"""
#链接:https://www.cnblogs.com/xxmmqg/p/13062556.html
#https://blog.csdn.net/lly1122334/article/details/88944589?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase
"""
#github :https://github.com/aleju/imgaug
#Doc:https://imgaug.readthedocs.io/en/latest/source/examples_basics.html#a-standard-use-case
from imgaug import augmenters as iaa
import imgaug as ia
import os
import cv2
# 1定义多种增广操作,图片处理的不同操作
def img_operation_list():
# 将图像转换为HSV,然后将每个像素的H值增加10到50
op_1 = iaa.WithColorspace(
to_colorspace="HSV",
from_colorspace="RGB",
children=iaa.WithChannels(0, iaa.Add((10, 50)))
)
op_2 = iaa.WithChannels(0, iaa.Add((10,50))) # BGR中的B值随机增加10-50,因为cv2读取的图片为BGR顺序,下同
op_3 = iaa.WithChannels(1, iaa.Add((10,50))) # BGR中的G值随机增加10-50
op_4 = iaa.WithChannels(2, iaa.Add((10,50))) # BGR中的R值随机增加10-50
op_5 = iaa.WithChannels(0, iaa.Affine((10, 180))) # BGR中的B值随机旋转10-180°
op_6 = iaa.WithChannels(1, iaa.Affine((10, 180))) # BGR中的G值随机旋转10-180°
op_7 = iaa.WithChannels(2, iaa.Affine((10, 180))) # BGR中的R值随机旋转10-180°
op_8 = iaa.Noop() # 无操作增广
# 用黑色像素替换每个图像的每5行
def img_func(images, random_state, parents, hooks):
for img in images:
img[::5] = 0
return images
def keypoint_func(keypoints_on_images, random_state, parents, hooks):
return keypoints_on_images
op_9 = iaa.Lambda(img_func, keypoint_func)
# 裁剪并填充 负则裁剪,正则填充
op_10 = iaa.CropAndPad(percent=(-0.2, 0.2))
op_11 = iaa.CropAndPad(
percent=(0, 0.2), # 每边填充0至20%
pad_mode=["constant", "edge"], # 填充方式为恒定值(constant)或边缘值(edge)
pad_cval=(0, 255) # 若为恒定值,则从0-255中随机取值
)
op_12 = iaa.CropAndPad(
px=((0, 30), (0, 10), (0, 30), (0, 10)), # 顶部填充0-30px,右侧0-10px,底部0-30px,左侧0-10px
pad_mode=ia.ALL,
pad_cval=(0, 255)
)
op_13 = iaa.Fliplr() # 水平翻转所有图片
op_14 = iaa.Flipud(0.2) # 垂直反转图片20%
# 每个图像生成16到128个超像素。 用平均像素颜色替换每个超像素的概率在10到50%之间(每个图像采样一次)
op_15 = iaa.Superpixels(p_replace=(0.1, 0.5), n_segments=(16, 128))
# 将图像更改为灰度,并通过改变强度将其与原始图像叠加,有效地删除0到80%的颜色
op_16 = iaa.Grayscale(alpha=(0.0, 0.8))
op_17 = iaa.GaussianBlur(sigma=(0.0, 2.0)) # 高斯模糊,σ=0-2
# 在图像中添加-50到50之间的随机值。
#在50%的图像中,每个通道的值不同(3个采样值)。
#在剩下的50%图像中,所有通道的值都相同
op_18 = iaa.Add((-50, 50),per_channel=0.5)
# 添加高斯噪音
# 每个像素从正态分布N(0,s)采样一次,s对每个图像采样并在0和0.1 * 255之间变化
op_19 = iaa.AdditiveGaussianNoise(scale=(0, 0.1*255))
# 丢弃2%的图像,但是在具有原始大小的50%的图像的较低分辨率版本上执行此操作,丢弃2x2个正方形。
# 此外,在50%的图像通道中执行此操作,以便仅将某些通道的信息设置为0,而其他通道保持不变
op_20 = iaa.CoarseDropout(0.02, size_percent=0.15, per_channel=0.5)
operation_list = [op_1, op_7, op_8, op_9, op_10,
op_11, op_12, op_13, op_14, op_16, op_17, op_18, op_19, op_20,]
return operation_list
# 2将图片分批
#说明:图片数据量大时,可调用此方法实现分批效果
def img_batchs_list(imgpath_file,batch_size=10):
"""
:param imgpath_file: 保存图片路径的txt文件
:param batch_size: 每个batch大小默认为10
:return: img_batchs:[[image1,image2,..image10],...]
"""
with open(imgpath_file) as img_info:
batch_size = batch_size # 每个batch的大小
img_batchs = []
flag = 0
while True:
if flag % batch_size == 0:
img_batchs.append([])
img = img_info.readline().strip("\n")
if(img == ""):
break
img_batchs[-1].append(img)
flag += 1
if flag >=10000: # 避免进入死循环而必须重启项目
break
if img_batchs[-1] == []:
img_batchs.pop()
return img_batchs
# 3 数据增广
def data_augment(imagepath_text,NewImageDir,epochs=10,start_img_num=100):
operation_list=img_operation_list()
img_batchs=img_batchs_list(imagepath_text)
print(img_batchs)
img_name = start_img_num # 每张图片的名字,依次递增
with open(imagepath_text,"a") as img_text:
for epoch in range(epochs): # 原始图片循环增广epochs*4次
for someof_n in [1, 1, 2, 2]: # 对应于SomeOf中的参数someof_n
seq = iaa.SomeOf(someof_n, operation_list) # 使用的是SomeOf,区别于Sequential
for batch_ind, img_batch in enumerate(img_batchs):
img_batch = [cv2.imread(path) for path in img_batch]
imgs_aug = seq.augment_images(img_batch)
for i, save_img in enumerate(imgs_aug):
save_img_path = fr"{NewImageDir}\{str(img_name)}.jpg" # 保存路径
cv2.imwrite(save_img_path, save_img) # 保存图片
img_text.write(save_img_path+" "+"\n") # 保存图像列表
print(save_img_path,"保存成功!")
img_name += 1
print("Data augment Scccess!!")
#收集图片路径,生成txt文件
def generate_imgpath_txt(imgpath_dir,target_file):
image_name_list = sorted(os.listdir(imgpath_dir))
print("total image:", len(image_name_list))
with open(file=target_file, mode="w", encoding="utf-8") as f:
for imgname in image_name_list:
if not imgname.endswith("jpg"):
continue
img_path = os.path.join(imgpath_dir, imgname)
f.write(img_path + "\n")
print("success!!")
if __name__ == '__main__':
#1 生成图片路径文件
#测试
# imgpath_dir =r"D:\rsrc\code\script\images"
# target_file =r"D:\rsrc\code\script\images\images.txt"
# generate_imgpath_txt(imgpath_dir,target_file)
imgpath_dir = r"D:\rsrc\data\coal-project\truck\shadunzi\JPEGImage"
target_file = r"D:\rsrc\data\coal-project\truck\shadunzi\imgpath.txt"
generate_imgpath_txt(imgpath_dir, target_file)
# 2 数据增强处理
print("Data Enhancement............")
imagepath_text=target_file
start_img_num=16 #新增图片开始序号
epochs =5 # 原始图片增广epochs*4张
NewImageDir=r"D:\rsrc\data\coal-project\truck\shadunzi\JPEGImage"
data_augment(imagepath_text,NewImageDir,epochs,start_img_num)
data_augmentation
3 PP
飞浆数据增广参考:https://www.paddlepaddle.org.cn/tutorials/projectdetail/2412195
作者:华王