[Python Practical Combat]---- Implement batch image cutting

1. Demand scenario

In actual development, we will encounter a very boring but necessary requirement, such as a protocol, a large number of promotional pages, a large number of static introduction pages, or a large number of static pages, but the page height is very high, or even highly possible It will reach 50000px, but for rendering-friendly needs, the pictures need to be cut into small sizes. For example, if the height is 300px for each picture, more than a hundred pictures need to be cut. Imagine if you make an introduction page for each county in a province. , there are dozens of pages. A page with a small number has to be cut into dozens of pages, and a page with a large number of hundreds of pages is not a crushing demand, but as developers, we must learn to develop some small tools ourselves, let us Liberate yourself from these boring yet unavoidable needs. Gadget development! The most common thing I have encountered is cutting pictures by myself and developing more than 40 static introduction pages. I didn’t know Python at the time, and I felt sick while cutting. Sometimes the psd would freeze and crash one day!

2. Requirement realization

  1. There are many image cutting methods, such as PIL and OPENCV. Since I have learned opencv before, this article uses opencv to implement it;
  2. Get the fixed height we need to cut the image;
  3. Screening of pictures that need to be cut;
  4. Complete cutting of the picture;
  5. Save the cut image.

3. Need to cut picture preview

Enter image description

4. Filter the pictures that need to be cut

  1. Get all files under the path;
  2. Filter the image files and return a list of image names.
# 获取文件夹下所有图片文件名称
def get_all_image_names(path):
  # 获取路径下的所有文件
  names = os.listdir(path)
  # 筛选其中的图片文件,返回图片名称列表
  image_names = list(filter(lambda x : x.split('.').pop() in ['jpg', 'png', 'jpeg', 'bmp'], names))
  return image_names

5. Single picture cutting

  1. Get the fixed height of the image to be cut;
  2. The storage path of the images to be cut;
  3. The storage location of the cut pictures;
  4. Read the names of all pictures that need to be cut;
  5. Loop to get image names;
  6. Get the image name separately;
  7. Process the current need to cut the picture individually.
if __name__ == "__main__":
  # 获取需要切割图片的固定高度
  init_img_h = int(input("请输入切割图片的固定高度:"))
  # 所需要切割图片的存放路径
  path = './images'
  # 切割后图片的存放位置
  if not os.path.exists(f'./out_images/'):
    os.makedirs(f'./out_images/')
  # 读取全部需要切割的图片名称
  images = get_all_image_names(path)
  # 循环获取图片名称
  for name in images:
    # 单独获取图片名称
    key_name = name.split('.')[0]
    # 单独处理当前需要切割图片
    handle_single_image(f'{path}/{name}', init_img_h, key_name)

6. Image processing

  1. Read the image and get the width and height of the image;
  2. Calculate the number of pictures to be cut based on the fixed height and picture height;
  3. Calculate the end Y coordinate of the cut picture;
  4. If the calculated end coordinate is greater than the image height, use the image height directly as the end coordinate;
  5. Call the cutting and encapsulating method of opencv to obtain the cut image object;
  6. Save the cut image.
# 处理切割单张图片
def handle_single_image(path, init_img_h, key_name):
  # 读取图片,获取图片的宽高
  img = cv.imread(path)
  h,w,c = img.shape
  # 根据固定高度和图片高度计算需要切割的图片张数
  for val in range(math.ceil(h / init_img_h)):
    # 计算切割图片的结束Y坐标
    end_h = (val + 1) * init_img_h
    # 如果计算的结束坐标大于图片高度,直接使用图片高度作为结束坐标
    if end_h > h:
      end_h = h
    # 调用opencv的切割封装方法,获取切割后的图片对象
    crop_img = crop_image(img, 0, val * init_img_h, w, end_h)
    # 保存切割后的图像
    cv.imwrite(f"./out_images/{key_name}{'%05d'%val}.png",crop_img)

7. Cutting and packaging

# 切割图片
def crop_image(img,startX,startY,endX,endY):
  # 根据传入的坐标值,进行图像切割
  crop_img = img[startY:endY, startX:endX]
  return crop_img

8. Complete code

import cv2 as cv
import os
import math

# 获取文件夹下所有图片文件名称
def get_all_image_names(path):
  # 获取路径下的所有文件
  names = os.listdir(path)
  # 筛选其中的图片文件,返回图片名称列表
  image_names = list(filter(lambda x : x.split('.').pop() in ['jpg', 'png', 'jpeg', 'bmp'], names))
  return image_names

# 处理切割单张图片
def handle_single_image(path, init_img_h, key_name):
  # 读取图片,获取图片的宽高
  img = cv.imread(path)
  h,w,c = img.shape
  # 根据固定高度和图片高度计算需要切割的图片张数
  for val in range(math.ceil(h / init_img_h)):
    # 计算切割图片的结束Y坐标
    end_h = (val + 1) * init_img_h
    # 如果计算的结束坐标大于图片高度,直接使用图片高度作为结束坐标
    if end_h > h:
      end_h = h
    # 调用opencv的切割封装方法,获取切割后的图片对象
    crop_img = crop_image(img, 0, val * init_img_h, w, end_h)
    # 保存切割后的图像
    cv.imwrite(f"./out_images/{key_name}{'%05d'%val}.png",crop_img)

# 切割图片
def crop_image(img,startX,startY,endX,endY):
  # 根据传入的坐标值,进行图像切割
  crop_img = img[startY:endY, startX:endX]
  return crop_img

if __name__ == "__main__":
  # 获取需要切割图片的固定高度
  init_img_h = int(input("请输入切割图片的固定高度:"))
  # 所需要切割图片的存放路径
  path = './images'
  # 切割后图片的存放位置
  if not os.path.exists(f'./out_images/'):
    os.makedirs(f'./out_images/')
  # 读取全部需要切割的图片名称
  images = get_all_image_names(path)
  # 循环获取图片名称
  for name in images:
    # 单独获取图片名称
    key_name = name.split('.')[0]
    # 单独处理当前需要切割图片
    handle_single_image(f'{path}/{name}', init_img_h, key_name)

9. Cutting results

Enter image description

10. Summary

  1. You can also create a function and integrate the code that generates static pages, so that dozens of pages can be completed directly at once. Due to different needs, the development pages are different, so there is no integration here.
  2. The initial solution is to give the number of cuts and then calculate the height of each one. However, there is a problem with this solution. The calculated height is a floating point number, so there are many accuracy problems. The two pictures before and after will be spliced. It is not equal, so a fixed height scheme is adopted. When it is less than the fixed height, the remaining height is used as the height.

Guess you like

Origin blog.csdn.net/m0_38082783/article/details/132813529