Python修改图片尺寸、裁剪图片、拼接图片

该博客介绍了如何处理大尺寸医学图像以适应YOLO算法的输入要求。首先,通过加白边将图像扩展至10500×15500像素,然后切割成500×500的小图,解决PIL库的像素限制问题。接着,详细展示了使用Python的PIL库进行图像尺寸修改、切割和拼接的完整代码实现。最后,强调了检测完成后对小图进行拼接以恢复完整图像的必要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在YOLO算法中对输入的图片有尺寸大小要求,如果图片太大网络就提取不到特征,无法检测图片中的物体。

在进行医学图像处理的时候,一般医学影像拍出来的图片分辨率很大,细胞非常小,所以不能将图片直接拿去检测,需要做一些处理:

以我现有的图片为例,图像尺寸为10150×15050,可以切割为很多50×50的小方图,但是我觉得50×50尺寸较小,影响网络检测速度,所以先将图片尺寸通过加白边的方式扩展到10500×15500,再切割成651张500×500的小方图,再进行检测。

这里需要注意的是,由于我的图片尺寸太大,超过了PIL处理图片像素的限制,所以会报错:

DecompressionBombWarning: Image size (152757500 pixels) exceeds limit of 89478485 pixels, could be decompression bomb DOS attack.
  DecompressionBombWarning,

解决方法:手动修改PIL图片像素限制,在引入PIL包后加入下面一行代码:

Image.MAX_IMAGE_PIXELS = 2300000000

修改图片尺寸+裁剪图片+拼接图片完整代码如下:

# -*- coding: utf-8 -*-
'''
将一张图片修改到指定尺寸并切割为500*500等份的小图片最后再将所有小图拼接为一张完整的原图
Author:bobibo
'''
from PIL import Image
Image.MAX_IMAGE_PIXELS = 2300000000
import sys
import os

#修改尺寸
def add_white_edge(inImgPath, outImgPath, width, height):
    r"""
    给宽图片上下补白边,让其满足一定比例,然后缩放到指定尺寸
    inImgPath: 输入图片路径
    outImgPath: 输出图片路径
    width: 最终宽度
    height: 最终高度

    inImg = Image.open(inImgPath)
    print(inImg.size)

    对于手机、相机等设备拍摄的照片,由于手持方向的不同,拍出来的照片可能是旋转0°、90°、180°和270°。
    即使在电脑上利用软件将其转正,他们的exif信息中还是会保留方位信息。
    在用PIL读取这些图像时,读取的是原始数据,
    也就是说,即使电脑屏幕上显示是正常的照片,用PIL读进来后,
    也可能是旋转的图像,并且图片的size也可能与屏幕上的不一样。
    对于这种情况,可以利用PIL读取exif中的orientation信息,
    然后根据这个信息将图片转正后,再进行后续操作,具体如下。

    try:
     for orientation in ExifTags.TAGS.keys():
      if ExifTags.TAGS[orientation] == 'Orientation': break
     exif = dict(inImg._getexif().items())
     if exif[orientation] == 3:
      inImg = inImg.rotate(180, expand=True)
     elif exif[orientation] == 6:
      inImg = inImg.rotate(270, expand=True)
     elif exif[orientation] == 8:
      inImg = inImg.rotate(90, expand=True)
    except:
     pass
    width, height = inImg.size  # 获取原图像的水平方向尺寸和垂直方向尺寸。
    print(inImg.size)
    """
    print(f'{inImgPath}')
    inImg: Image.Image = Image.open(inImgPath)
    bgWidth = inImg.width
    bgHeight = inImg.height
    #if bgWidth > bgHeight:
        #bgHeight = math.ceil((bgWidth * height) / width)
    # 创建一个白色背景图片
    bgImg: Image.Image = Image.new("RGB", (bgWidth, bgHeight), (255, 255, 255))
    bgImg.paste(inImg, (0, round((bgHeight - inImg.height) / 2)))

    bgImg.resize((width, height), Image.LANCZOS).save(outImgPath)

#切图
def cut_image(image):
    width, height = image.size
    item_width = 500
    box_list = []
    # (left, upper, right, lower)
    for i in range(0,31):#两重循环,生成9张图片基于原图的位置,i是高,j是宽
        for j in range(0,21):
            #print((i*item_width,j*item_width,(i+1)*item_width,(j+1)*item_width))
            box = (j*item_width,i*item_width,(j+1)*item_width,(i+1)*item_width)
            box_list.append(box)

    image_list = [image.crop(box) for box in box_list]
    return image_list

#保存
def save_images(image_list):
    index = 1
    for image in image_list:
        image.save('./img_小图/'+str(index) + '.png', 'PNG')
        index += 1

#拼接
IMAGES_PATH = 'F:/研究生/研一/计算机视觉/图片剪切与拼接/img_小图/'  # 图片集地址
IMAGES_FORMAT = ['.png']  # 图片格式
IMAGE_SIZE = 500  # 每张小图片的大小
IMAGE_ROW = 31  # 图片间隔,也就是合并成一张图后,一共有几行
IMAGE_COLUMN = 21  # 图片间隔,也就是合并成一张图后,一共有几列
IMAGE_SAVE_PATH = 'F:/研究生/研一/计算机视觉/图片剪切与拼接/最终整图.png'  # 图片转换后的地址

# 获取图片集地址下的所有图片名称
image_names = [name for name in os.listdir(IMAGES_PATH) for item in IMAGES_FORMAT if
               os.path.splitext(name)[1] == item]

# 简单的对于参数的设定和实际图片集的大小进行数量判断
if len(image_names) != IMAGE_ROW * IMAGE_COLUMN:
    raise ValueError("合成图片的参数和要求的数量不能匹配!")


# 定义图像拼接函数
def image_compose():
    to_image = Image.new('RGB', (IMAGE_COLUMN * IMAGE_SIZE, IMAGE_ROW * IMAGE_SIZE))  # 创建一个新图
    # 循环遍历,把每张图片按顺序粘贴到对应位置上
    for y in range(1, IMAGE_ROW + 1):
        for x in range(1, IMAGE_COLUMN + 1):
            from_image = Image.open(IMAGES_PATH + image_names[IMAGE_COLUMN * (y - 1) + x - 1]).resize(
                (IMAGE_SIZE, IMAGE_SIZE), Image.ANTIALIAS)
            to_image.paste(from_image, ((x - 1) * IMAGE_SIZE, (y - 1) * IMAGE_SIZE))
    return to_image.save(IMAGE_SAVE_PATH)  # 保存新图


if __name__ == '__main__':
    add_white_edge('手指血现测.jpg', '手指血现测加白边.jpg', 10500, 15500)
    file_path = "手指血现测加白边.jpg"
    image = Image.open(file_path)
    #image.show()
    image_list = cut_image(image)
    save_images(image_list)
    image_compose()  # 调用函数

因为最后检测完输出也必须是一张完整的图片,所以在分块检测完成后再对651张小方图进行拼接,然后输出。

### 使用Python实现图片裁剪拼接及尺寸调整 为了完成这些任务,可以利用`Pillow`库,这是一个强大的图像处理工具。下面分别介绍如何通过该库来进行图片裁剪拼接以及尺寸调整。 #### 图片裁剪 要对图片进行裁剪操作,可以通过指定坐标范围来截取所需部分: ```python from PIL import Image img = Image.open('example.jpg') # 打开原始图片文件 cropped_img = img.crop((left, upper, right, lower)) # 定义裁剪区域并执行裁剪 cropped_img.save('output_cropped.png') # 将裁剪后的图片保存到新路径 ``` 这里`(left, upper)`表示左上角位置而`(right, lower)`则代表右下角的位置[^2]。 #### 调整图片尺寸 对于改变图片大小的需求,可以直接调用`resize()`方法,并传入目标宽度和高度组成的元组作为参数: ```python resized_image = img.resize((new_width, new_height), resample=Image.LANCZOS) resized_image.save('output_resized.png') ``` 其中`LANCZOS`是一种高质量重采样滤波器选项,在缩小图片时能提供较好的视觉效果[^1]。 #### 多张图片水平或垂直拼接 当涉及到多张图片之间的组合时,可以根据需求选择横向或者纵向排列方式。以下是创建一个新的空白画布并将几张图按顺序放置上去的例子: ```python def concatenate_images(image_paths, direction='horizontal'): images = [Image.open(x) for x in image_paths] widths, heights = zip(*(i.size for i in images)) if direction == 'horizontal': total_width = sum(widths) max_height = max(heights) new_im = Image.new('RGB', (total_width, max_height)) offset_x = 0 for im in images: new_im.paste(im, (offset_x, 0)) offset_x += im.width elif direction == 'vertical': total_height = sum(heights) max_width = max(widths) new_im = Image.new('RGB', (max_width, total_height)) offset_y = 0 for im in images: new_im.paste(im, (0, offset_y)) offset_y += im.height return new_im image_list = ['path_to_first_image.jpg', 'path_to_second_image.jpg'] concatenated_image = concatenate_images(image_list, 'horizontal') concatenated_image.show() ``` 这段代码定义了一个函数用于接收一系列图片路径列表,并根据给定的方向(默认为水平方向)将它们连接起来形成新的合成图像。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值