Python如何裁剪圖片
並且裁剪的圖片如何變換原圖坐標
需要滑窗裁剪圖片
但是裁剪圖片之後
識別的小框 在原圖的坐標是怎麼樣的
比如 原圖
1000*1000
裁剪N個小圖
在其中一個小圖
畫框
但是這個小圖裡面的框 是小圖的坐標
那麼這個框 在 原圖中的 坐標 是什麼
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()
如果不能平分,可以考慮換成 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')