图像遍历绘制Bounding Box及Pillow crop失效问题排查
我来帮你拆解下Pillow代码里的几个核心问题,这就是为什么只有第一个ROI有效,还出现多余实例的原因:
1. 图像尺寸的概念混淆
Pillow的image.size返回的是**(宽度, 高度)**,也就是对应你C++代码里的cols, rows,但你把它赋值给了original_rows, original_cols,相当于把行和列的概念搞反了。这会导致后续循环的范围完全不符合你的预期,让整个遍历逻辑乱掉。
2. 循环范围的错误计算
你没必要把rows和cols设为original_rows + step,这会让循环的终止边界超出图像实际尺寸。比如256+64=320,按64步长循环的话,会多跑几次迭代,这就是为什么你得到了24个<PIL.Image.Image>实例,远超过预期的16个(4×4)。
3. Crop方法的参数格式完全错误
这是最致命的问题:Pillow的crop()方法要求传入的四元组是(left, top, right, bottom),而不是你写的(left, top, width, height)。
你写的box = (col,row,step,step),只有当col=0且row=0时,right=64、bottom=64是正确的;但当col=64时,你传的right=64,这时候left >= right,crop出来的就是空图像!这就是为什么只有第一个ROI有效,其余全是空的原因。
修正后的Pillow代码
下面是调整后的代码,完全符合你的需求(遍历256×256图像,步长64,得到16个ROI):
from PIL import Image, ImageDraw import numpy as np path = "your_image_path.png" image = Image.open(path) draw = ImageDraw.Draw(image) step = 64 # 正确获取图像尺寸:width(列数), height(行数) original_width, original_height = image.size # 循环范围:从0开始,到图像尺寸-step,步长step for top in range(0, original_height - step + 1, step): for left in range(0, original_width - step + 1, step): # 正确构造crop的四元组:left, top, right, bottom right = left + step bottom = top + step box = (left, top, right, bottom) region = image.crop(box) # 计算灰度均值(如果是彩色图需要先转灰度,这里假设输入为灰度图) region_arr = np.asarray(region) mean_val = np.mean(region_arr) print(f"ROI ({left}, {top}) 均值: {mean_val}") print(region_arr) # 绘制Bounding Box,参数与crop的四元组格式一致 draw.rectangle(box, width=1, outline="#FFFFFF") image.show()
为什么NumPy实现没问题?
因为NumPy数组的索引是[行, 列],和你C++代码里的x(行)、y(列)逻辑一致,你直接按切片image_arr[x:x+step, y:y+step]就能正确取到子矩阵,不需要像Pillow那样处理left/top/right/bottom的坐标规则,所以不会出现参数格式错误的问题。
内容的提问来源于stack exchange,提问作者Curious

