裁剪
import os
import cv2 as cv
import numpy as np
from tqdm import tqdm
# 单幅影像裁剪
def clip(img_path, save_img, size, repetition):
img = cv.imread(img_path, -1) # 加载原图
save_img = save_img # 存储路径
file_name_all = os.path.basename(img_path)
file_name = file_name_all.split('.')[0]
end = "." + file_name_all.split('.')[1]
shape = img.shape
channels = shape[2]
if not os.path.exists(save_img):
os.makedirs(save_img)
print(f'原图像(h, w, ch):', img.shape)
size = size # 裁剪大小: 500x500
repetition = repetition # 重复像素
h, w = (
img.shape[0],
img.shape[1],
) # img.shape[0]是高, img.shape[1]是宽, img.shape[2]是通道数
num_h = (h - repetition) // (size - repetition) # 裁剪后行数
num_w = (w - repetition) // (size - repetition) # 裁剪后列数
img = np.array(img) # to array
print(f'不考虑右、下情况下,每行生成{num_w}幅小图')
print(f'不考虑右、下情况下,每列生成{num_h}幅小图')
if end == str('.jpg') or end == str('.JPG'):
flag = [cv.IMWRITE_JPEG_QUALITY, 100]
elif end == str('.png'):
flag = [cv.IMWRITE_PNG_COMPRESSION, 0]
else:
raise ValueError(" end must be 'jpg' or 'png' ! ")
# 1.正常范围裁剪:
if channels == 3:
shape = (size, size, channels)
elif channels == 1:
shape = (size, size)
else:
raise ValueError(" channel must be '1' or '3' ! ")
img_crop = np.zeros(shape)
image = []
i, j, k = 0, 0, 0
for i in range(0, num_h):
for j in range(0, num_w):
img_crop = img[
i * size - i * repetition : i * size - i * repetition + size,
j * size - j * repetition : j * size - j * repetition + size,
]
image.append(img_crop)
for k in range(0, (num_h * num_w)):
image_k = image[k]
path_image_k = os.path.join(save_img, file_name + '_' + str(k + 1) + end)
cv.imwrite(path_image_k, image_k, flag)
print(f'正常裁剪{num_h * num_w}幅图')
# 2.最下面一行的裁剪:
img_crop_down = np.zeros(shape)
image_down = []
i, j, k = 0, 0, 0
for j in range(0, num_w):
img_crop_down = img[
h - size : h, j * size - j * repetition : j * size - j * repetition + size
]
image_down.append(img_crop_down)
for k in range(0, num_w):
image_k = image_down[k]
path_image_k = os.path.join(
save_img, file_name + '_' + str(k + 1 + num_h * num_w) + end
)
cv.imwrite(path_image_k, image_k, flag)
print(f'最下面一行裁剪{num_w}幅图')
# 2.最右边一列的裁剪:
img_crop_right = np.zeros(shape)
image_right = []
i, j, k = 0, 0, 0
for i in range(0, num_h):
img_crop_right = img[
i * size - i * repetition : i * size - i * repetition + size, w - size : w
]
image_right.append(img_crop_right)
for k in range(0, num_h):
image_k = image_right[k]
path_image_k = os.path.join(
save_img, file_name + '_' + str(k + 1 + num_h * num_w + num_w) + end
)
cv.imwrite(path_image_k, image_k, flag)
print(f'最右边一列裁剪{num_h}幅图')
# 3.最右下角的一幅小图:
image_d_r = []
i, j, k = 0, 0, 0
img_crop_d_r = img[h - size : h, w - size : w]
image_d_r.append(img_crop_right)
path_image = os.path.join(
save_img, file_name + '_' + str(k + 1 + num_h * num_w + num_w + num_h) + end
)
cv.imwrite(path_image, img_crop_d_r, flag)
print(f'最右下角裁剪1幅图')
# 批量裁剪某一文件夹下所有的图像,保存在指定某一文件夹下
def batch_clip(img_dir, save_dir, size, repetition):
file_names = [
filename
for filename in os.listdir(img_dir)
if filename.endswith("jpg")
or filename.endswith("JPG")
or filename.endswith("png")
]
print('图像加载完毕!开始裁剪!')
for file_name in tqdm(file_names):
img_path = os.path.join(img_dir, file_name)
clip(
img_path, # 选择要裁剪的图像
save_dir, # 裁剪后小图的存储路径
size=size, # 裁剪正方形的大小
repetition=repetition, # 像素重合距离
)
if __name__ == "__main__":
img_dir = 'test'
save_dir = 'test_results'
size = 512
repetition = 128
batch_clip(img_dir, save_dir, size=size, repetition=repetition)
拼接
import os
import numpy as np
import cv2 as cv
def main(ori_img, croped_path, output_path, output_name, size, repetition):
ori_img = cv.imread(ori_img, -1)
croped_path = croped_path
output_path = output_path
output_name = output_name
size = size
repetition = repetition
h, w = ori_img.shape[0], ori_img.shape[1] # 获取原始图像的高和宽
num_h = (h - repetition) // (size - repetition) # 裁剪后行数
num_w = (w - repetition) // (size - repetition) # 裁剪后列数
img = np.zeros((h, w)) # 创建与原始图像等大的画布
from natsort import natsorted
all_img = natsorted(os.listdir(croped_path)) # ['1.jpg', '10.jpg', '100.jpg', ...]
all_img.sort(key=lambda x: int(x[:-4])) # ['1.jpg', '2.jpg', '3.jpg', ...]
# 1.正常范围拼接
i, j = 0, 0
for i in range(0, num_h):
for j in range(0, num_w):
small_img_path = os.path.join(croped_path, all_img[i * num_w + j])
print(f'正常范围拼接:{all_img[i * num_w + j]}')
small_img = cv.imread(small_img_path, -1)
small_img = np.array(small_img)
img[
i * (size - repetition):i * (size - repetition) + size,
j * (size - repetition):j * (size - repetition) + size
] = small_img[0:size, 0:size]
# 2.最下面一行的拼接:
i, j = 0, 0
for j in range(0, num_w):
small_img_path = os.path.join(croped_path, all_img[num_h * num_w + j])
print(f'最下面一行的拼接:{all_img[num_h * num_w + j]}')
small_img = cv.imread(small_img_path, -1)
small_img = np.array(small_img)
img[
h - size:h,
j * (size - repetition):j * (size - repetition) + size
] = small_img[0:size, 0:size]
# 3.最右边一列的拼接
i, j = 0, 0
for i in range(0, num_h):
small_img_path = os.path.join(croped_path, all_img[num_h * num_w + num_w + i])
print(f'最右边一列的拼接:{all_img[num_h * num_w + num_w + i]}')
small_img = cv.imread(small_img_path, -1)
small_img = np.array(small_img)
img[
i * (size - repetition):i * (size - repetition) + size,
w - size:w
] = small_img[0:size, 0:size]
# 4.最右下角的一幅小图
small_img_path = os.path.join(croped_path, all_img[-1])
print(f'最右下角的一幅小图拼接:{all_img[-1]}')
small_img = cv.imread(small_img_path, -1)
small_img = np.array(small_img)
img[
h - size:h,
w - size:w
] = small_img[0:size, 0:size]
if not os.path.exists(output_path):
os.makedirs(output_path)
cv.imwrite(os.path.join(output_path, output_name), img, [cv.IMWRITE_PNG_COMPRESSION, 0])
if __name__ == '__main__':
main(ori_img='80.JPG', # 读取原图,用于创建画布
croped_path='pic', # 读取存放小图的路径
output_path='results', # 设置结果输出路径
output_name='80.png', # 设置拼接后的图像名
size=256, # 小图大小
repetition=50 # 像素重合距离
)