Python如何裁剪图片,并且裁剪的图片如何变换原图坐标?

monkey_cici
  • 208
广东

Python如何裁剪图片
并且裁剪的图片如何变换原图坐标

需要滑窗裁剪图片
但是裁剪图片之后
识别的小框 在原图的坐标是怎么样的

比如 原图
1000*1000

裁剪N个小图

在其中一个小图
画框
但是这个小图里面的框 是小图的坐标

那么这个框 在 原图中的 坐标 是什么

回复
阅读 889
2 个回答
✓ 已被采纳

opencv 读取图片的话,是 numpy.ndarray 类型,可以用切片操作裁剪图片 img[y1:y2, x1:x2].copy(),也可以直接用 numpy.hsplit 分割图片,必须保证宽高能平分

import cv2
import numpy as np
from requests import get

img_url = 'https://avatar-static.segmentfault.com/569/558/569558099-1030000000094051_huge256'
img: np.ndarray = cv2.imdecode(np.frombuffer(get(img_url).content, np.uint8), cv2.IMREAD_COLOR)

h, w = img.shape[:2]

nRows, nCols = 4, 4
sub_h, sub_w = h//nRows, w//nCols

# 分割图片
sub_imgs = np.array(np.hsplit(np.array(np.hsplit(img, nCols)), nRows))

# 填充矩形
r, c, x1, y1, x2, y2 = 2, 3, 10, 20, 54, 44
sub_imgs[r, c, y1:y2, x1:x2] = (0, 0, 255)
img[sub_h*r+y1:sub_h*r+y2, sub_w*c+x1:sub_w*c+x2] = (0, 0, 255)

# 显示
div_w, div_color = 16, np.array([222, 222, 222], np.uint8)
img_split = np.ones((h+div_w*(nRows-1), w+div_w*(nCols-1), 3), np.uint8) * div_color
step_y, step_x = sub_h+div_w, sub_w+div_w
for i, row in enumerate(sub_imgs):
    for j, sub_img in enumerate(row):
        img_split[step_y*i:step_y*i+sub_h, step_x*j:step_x*j+sub_w] = sub_img

cv2.imshow('img', img)
cv2.imshow('img_split', img_split)
cv2.waitKey()

image.png image.png

如果不能平分,可以考虑换成 numpy.array_split 分割,它会把剩余宽高分给靠左的 w % nCols 列和靠上的 h % nRows 行,如 128 * 128 分成 3 行 3 列是

import cv2
import numpy as np
from requests import get

img_url = 'https://avatar-static.segmentfault.com/569/558/569558099-1030000000094051_huge128'
img: np.ndarray = cv2.imdecode(np.frombuffer(get(img_url).content, np.uint8), cv2.IMREAD_COLOR)

nRows, nCols = 3, 3
sub_imgs = [np.array_split(row, nCols, 1) for row in np.array_split(img, nRows, 0)]
print(*([f'{img.shape[1]} * {img.shape[0]}' for img in row] for row in sub_imgs), sep='\n')
# ['43 * 43', '43 * 43', '42 * 43']
# ['43 * 43', '43 * 43', '42 * 43']
# ['43 * 42', '43 * 42', '42 * 42']

再给个基于 pillow 库 crop 裁剪图片的图片分割函数

import os
from io import BytesIO
from itertools import chain

import PIL.Image as Images
from PIL.Image import Image
from requests import get


def split_box(box: tuple[int, int, int, int], ncols: int = 1, nrows: int = 1) -> list[list[tuple[int, int, int, int]]]:
    subw, extraw = divmod(box[2] - box[0], ncols)
    subh, extrah = divmod(box[3] - box[1], nrows)
    kx, ky = box[0] + (subw + 1) * extraw, box[1] + (subh + 1) * extrah
    lr1, lr2 = range(box[0], kx + 1, subw + 1), range(kx, box[2] + 1, subw)
    ul1, ul2 = range(box[1], ky + 1, subh + 1), range(ky, box[3] + 1, subh)
    return [[(left, upper, right, lower)
             for left, right in chain(zip(lr1[:-1], lr1[1:]), zip(lr2[:-1], lr2[1:]))]
            for upper, lower in chain(zip(ul1[:-1], ul1[1:]), zip(ul2[:-1], ul2[1:]))]


def split_image(img: Image, ncols: int = 1, nrows: int = 1) -> list[list[Image]]:
    return [[img.crop(box) for box in row] for row in split_box((0, 0, *img.size), ncols, nrows)]


img_url = 'https://avatar-static.segmentfault.com/569/558/569558099-1030000000094051_huge128'
img = Images.open(BytesIO(get(img_url).content))

# 分割图片
subimgs = split_image(img, 3, 3)

subboxs = split_box((0, 0, *img.size), 3, 3)

# 填充矩形
subimgs[1][2].paste((255, 0, 0), (10, 10, 20, 20))
subx, suby = subboxs[1][2][:2]
img.paste((255, 0, 0), (subx+10, suby+10, subx+20, suby+20))

# 输出大小
print(*([subimg.size for subimg in row] for row in subimgs), sep='\n')

# 显示
img_split = Images.new('RGB', (img.width + 16 * 2, img.height + 16 * 2), (222, 222, 222))
for i, row in enumerate(subimgs):
    for j, sub_img in enumerate(row):
        img_split.paste(sub_img, (subboxs[i][j][0] + 16 * j, subboxs[i][j][1] + 16 * i))
img.show()
img_split.show()

# 保存
# os.makedirs('img', exist_ok=True)
# img.save('img/img.png')
# for i, row in enumerate(subimgs):
#     for j, sub_img in enumerate(row):
#         sub_img.save(f'img/subimgs[{i}][{j}].png')

img.png tmp.png

宣传栏