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

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

在进行医学图像处理的时候,一般医学影像拍出来的图片分辨率很大,细胞非常小,所以不能将图片直接拿去检测,需要做一些处理:
Python修改图片尺寸、裁剪图片、拼接图片_第1张图片
以我现有的图片为例,图像尺寸为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,计算机视觉,图像处理)