Python随机切割图像

前言

今天做荔枝果园冠层目标检测数据集,感觉无人机拍摄拼接后的图片面积太大。试着用Python做一下图像的随机切割,得到更多的数据。先实现一下简单的中心点切割。

思路

1.利用PIL库的image.size获取图像的宽高。

2.得到图像中心点像素坐标mid_point_x ,mid_point_y。

3.构建感兴趣区域BOX_LEFT, BOX_UP, BOX_RIGHT, BOX_DOWN。

4.利用PIL库的image.crop切割。保存图像。

源码

from PIL import Image
import os
import random


# 定义待批量裁剪图像的路径地址
IMAGE_INPUT_PATH = 'C:\\Users\\27651\Desktop\crops_canopy\Lab_me\img_jpg'
# 定义裁剪后的图像存放地址
IMAGE_OUTPUT_PATH = 'C:\\Users\\27651\Desktop\crops_canopy\Lab_me\img_crop'

for each_image in os.listdir(IMAGE_INPUT_PATH):
# 每个图像全路径
    image_input_fullname = IMAGE_INPUT_PATH + "/" + each_image
# PIL库打开每一张图像
    img = Image.open(image_input_fullname)
# 定义裁剪图片左、上、右、下的像素坐标
    x_max = img.size[0]
    y_max = img.size[1]
    
    mid_point_x = int(x_max/2)
    mid_point_y = int(y_max/2)

    down = mid_point_y+random.randint(0,mid_point_y)
    up = mid_point_y-(down-mid_point_y)
    right = mid_point_x+(down-mid_point_y)
    left = mid_point_x-(down-mid_point_y)

    BOX_LEFT, BOX_UP, BOX_RIGHT, BOX_DOWN = left,up,right,down
# 从原始图像返回一个矩形区域,区域是一个4元组定义左上右下像素坐标
    box = (BOX_LEFT, BOX_UP, BOX_RIGHT , BOX_DOWN )
# 进行roi裁剪
    roi_area = img.crop(box)
# 裁剪后每个图像的路径+名称
    image_output_fullname = IMAGE_OUTPUT_PATH + "/" + each_image
# 存储裁剪得到的图像
    roi_area.save(image_output_fullname)
    print('{0} crop done.'.format(each_image))

效果

原图

 切割后

总结

实现了简单的基于图像中心点的正方形切割,接着进一步优化可以将“中心点”随机移动增强感兴趣区边界的约束条件(如判断上下左右边界到“中心点”的区间范围)。

2021/11/18 更新

完善了中心点随机移动,并进行多轮次的随机切割输出。修改代码如下

for i in range(0,5):
        crop_x = mid_point_x+random.randint(int(-mid_point_x/5),int(mid_point_x/5))
        crop_y = mid_point_y+random.randint(int(-mid_point_y/5),int(mid_point_y/5)) #中心点移动
        
        dis_x = x_max-crop_x
        dis_y = y_max-crop_y 

        dis_min = min(dis_x,dis_y,crop_x,crop_y)#获取变动范围

        down = crop_y+random.randint(0,dis_min)
        up = crop_y-(down-crop_y)
        right = crop_x+(down-crop_y)
        left = crop_x-(down-crop_y)

        BOX_LEFT, BOX_UP, BOX_RIGHT, BOX_DOWN = left,up,right,down
# 从原始图像返回一个矩形区域,区域是一个4元组定义左上右下像素坐标
        box = (BOX_LEFT, BOX_UP, BOX_RIGHT , BOX_DOWN )
# 进行roi裁剪
        roi_area = img.crop(box)
# 裁剪后每个图像的路径+名称
        image_output_fullname = IMAGE_OUTPUT_PATH + "/" + str(i) + "_" + each_image
# 存储裁剪得到的图像
        roi_area.save(image_output_fullname)
        print('{0} crop done.'.format(each_image))

效果

 

### 实现图像随机裁剪与重新拼接 为了实现图像随机裁剪并将其重新拼接,在Python中有多种方法可以完成这一操作。这里介绍一种基于`OpenCV`和`NumPy`的方法来执行此任务。 #### 随机裁剪函数定义 首先,创建一个用于从原始图像中提取子图的功能模块。该功能会根据指定的高度宽度参数以及步长(即每次移动的距离),在原图内选取多个不重叠或部分重叠的小区域作为新的训练样本[^4]。 ```python import cv2 import numpy as np from random import randint def random_crop(image, crop_height, crop_width): max_x = image.shape[1] - crop_width max_y = image.shape[0] - crop_height if max_x <= 0 or max_y <= 0: raise ValueError('Image size is smaller than the specified crop dimensions.') x = randint(0, max_x) y = randint(0, max_y) cropped_image = image[y:y + crop_height, x:x + crop_width] return cropped_image ``` 上述代码实现了单次随机位置的选择,并从中截取固定大小的部分;当输入图片不足以满足所设条件时,则抛出异常提示错误信息。 #### 处理多张碎片化后的重组逻辑 接下来构建另一个辅助工具用来管理这些被切割出来的片段并将它们按照一定规律组合回去形成完整的图形。考虑到实际应用中的灵活性需求,下面给出的例子允许用户自定义最终输出画布的具体规格: ```python def reassemble_patches(patches_list, target_shape=(None, None)): rows = [] row_images = [] current_row_height = sum([p.shape[0] for p in patches_list]) total_cols = max([p.shape[1] for p in patches_list]) canvas_height = target_shape[0] if all(target_shape) else current_row_height canvas_width = target_shape[1] if all(target_shape) else total_cols * len(patches_list) empty_patch = np.zeros((canvas_height//len(patches_list), canvas_width)) index = 0 while True: try: patch = patches_list[index] if not row_images or sum([ri.shape[1] for ri in row_images]) + patch.shape[1] <= canvas_width: row_images.append(patch) elif any(row_images): combined_row = np.hstack(tuple(row_images)) padding_needed = canvas_width - combined_row.shape[1] padded_row = cv2.copyMakeBorder(combined_row, top=0,bottom=0,left=0,right=padding_needed, borderType=cv2.BORDER_CONSTANT,value=[0,0,0]) rows.append(padded_row) row_images.clear() index += 1 except IndexError: break last_combined_row = np.hstack(tuple(row_images)) if row_images else empty_patch remaining_space = canvas_height - last_combined_row.shape[0] final_canvas = cv2.vconcat(rows + [last_combined_row,cv2.copyMakeBorder(last_combined_row,top=remaining_space,bottom=0,left=0,right=0,borderType=cv2.BORDER_CONSTANT,value=[0,0,0])][:-(not bool(rows)+1)]) return final_canvas[:target_shape[0], :target_shape[1]] if all(target_shape) else final_canvas ``` 这个过程涉及到水平方向上的连接(`np.hstack`)和平铺式的垂直堆叠(`cv2.vconcat`)两个主要步骤。此外还加入了必要的边界填充以确保所有组件都能适配到预设的目标框架之内[^3]。 通过以上两段核心算法的支持,就可以方便地对任意给定的大尺寸影像文件实施多次不同方位/尺度下的局部采样动作,同时也能保证经过一系列变换之后的数据能够顺利恢复原型以便后续分析使用。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值