在训练神经网络时,自己的数据可能分辨率过高,导致训练效果差,甚至还会爆显存,所以需要把图片进行裁剪
思路也非常简单,就是通过两层循环把每一裁剪子图的RGB提取出来,写入新文件
但是如果原图的尺寸不能整除子图的尺寸怎么办呢?
这里考虑进行填充
首先需要明确原始分辨率,和要裁剪成多大的图片,比如我的图片是2736*3648,目标分辨率为608。
其实这个尺寸还可以,因为2736 ÷ 608 = 4.5,3648 ÷ 608 = 6,也就是会有6张图片不足608*608,所以要进行填充操作。
填充思路也很简单,循环结束的条件就是当前x+裁剪后图像分辨率608>2736,此时会有一段图像未进行裁剪,那么就取从当前x一直到图片末尾的像素,并在其x方向填充(目标尺寸 - (图像原x - 当前x))
但如果有小伙伴x无法整除(目标尺寸),y也无法整除,只需要在最外层循环结束后,再判断一次y方向是否有剩余就好了,方法和判断x的一样。如果x方向最后有剩余,y方向也有剩余,那么到最后一张图片需要进行两个方向的填充。
2021年12月20日重写
空下来了看之前自己写的代码,觉得思路有很大的问题,于是用新思路重写了一遍。。
主要是大图无法等分成目标分辨率的小图,会涉及到填充操作。在之前的方法中我采用对裁剪后的小图进行填充,这样的操作是重复的。于是我在裁剪之前对图像进行判断,其宽与高是否为目标分辨率的整倍数,若不为整倍数则直接对大图进行填充,然后再对填充后的大图进行裁剪,便省去了每次裁剪时都要对填充的判断。
max_y, max_x = img.shape[0], img.shape[1]
# 若不能等分,则填充至等分
if max_x % target_size != 0:
padding_x = target_size - (max_x % target_size)
img = cv2.copyMakeBorder(img, 0, 0, 0, padding_x, cv2.BORDER_CONSTANT, value=padding)
max_x = img.shape[1]
if max_y % target_size != 0:
padding_y = target_size - (max_y % target_size)
img = cv2.copyMakeBorder(img, 0, padding_y, 0, 0, cv2.BORDER_CONSTANT, value=padding)
max_y = img.shape[0]
然后判断填充后的大图的宽与高分别能被目标分辨率分割成多少图
h_count = int(max_x / target_size)
v_count = int(max_y / target_size)
之后便用最传统的双层循环进行裁剪和保存
count = 0
for v in range(v_count):
for h in range(h_count):
x_begin = h * target_size
x_end = (h + 1) * target_size
y_begin = v * target_size
y_end = (v + 1) * target_size
cropImg = img[y_begin:y_end, x_begin:x_end] # 裁剪图像
target_path = pic_out_path + file_name + '_' + str(count) + '.jpg'
cv2.imwrite(target_path, cropImg) # 写入图像路径
count += 1
完整代码如下:
# ---------------------------------------------------#
# 裁剪:
# img:图片(cv格式)
# target_size: 目标尺寸(仅支持正方形)
# file_name: 不含扩展名的文件名
# pic_out_path: 输出文件夹
# padding: 填充颜色(B,G,R)
# ---------------------------------------------------#
def clip(img, target_size, file_name, pic_out_path, padding=(0, 0, 0)):
max_y, max_x = img.shape[0], img.shape[1]
# 若不能等分,则填充至等分
if max_x % target_size != 0:
padding_x = target_size - (max_x % target_size)
img = cv2.copyMakeBorder(img, 0, 0, 0, padding_x, cv2.BORDER_CONSTANT, value=padding)
max_x = img.shape[1]
if max_y % target_size != 0:
padding_y = target_size - (max_y % target_size)
img = cv2.copyMakeBorder(img, 0, padding_y, 0, 0, cv2.BORDER_CONSTANT, value=padding)
max_y = img.shape[0]
h_count = int(max_x / target_size)
v_count = int(max_y / target_size)
count = 0
for v in range(v_count):
for h in range(h_count):
x_start = h * target_size
x_end = (h + 1) * target_size
y_start = v * target_size
y_end = (v + 1) * target_size
cropImg = img[y_start:y_end, x_start:x_end] # 裁剪图像
target_path = pic_out_path + file_name + '_' + str(count) + '.jpg'
cv2.imwrite(target_path, cropImg) # 写入图像路径
count += 1