使用numpy meshgrid裁剪图像多边形及尺寸匹配问题求助
解决使用NumPy Meshgrid和Matplotlib Path裁剪多边形区域的问题
我来帮你一步步解决这些问题,核心问题主要是坐标系统对齐、多边形点范围匹配和数组维度顺序这几个关键点:
1. 初始尝试:掩码边界不正确的修正
你的第一版代码里,问题大概率出在图像坐标与Matplotlib Path坐标的y轴方向差异:图像的y轴通常是从上到下递增(y=0是顶部),而Matplotlib Path的y轴是从下到上递增(y=0是底部)。所以需要把多边形的y坐标反转,对齐图像的坐标系。
另外,确保多边形点的顺序是连续的顺时针/逆时针闭合路径(你的点顺序是对的,但要确认没有交叉)。
修正后的代码:
import numpy as np from matplotlib.path import Path # 原图像尺寸(包含所有像素的数量) img_width = 19542 # x从0到19541,共19542个像素 img_height = 14395 # y从0到14394,共14395个像素 # 目标裁剪区域的原图像坐标 xmin, xmax = 4692, 12720 ymin, ymax = 4273, 10117 # 多边形顶点(原图像坐标),反转y轴以匹配Path的坐标系 sar_ver = [ (4692, img_height - 1 - 10117), (12720, img_height - 1 - 10117), (12658, img_height - 1 - 4274), (4769, img_height - 1 - 4273), (4692, img_height - 1 - 10117) ] # 生成裁剪区域的网格(对应原图像的x,y坐标) x_grid, y_grid = np.meshgrid(np.arange(xmin, xmax + 1), np.arange(ymin, ymax + 1)) # 转换为Path需要的坐标系(反转y轴) y_grid_reversed = img_height - 1 - y_grid # 扁平化并生成点集 points = np.vstack((x_grid.flatten(), y_grid_reversed.flatten())).T # 创建路径并生成掩码 path = Path(sar_ver) mask = path.contains_points(points) mask = mask.reshape(x_grid.shape) # shape: (5845, 8029) 与裁剪区域尺寸匹配
2. 更新尝试:掩码原点未偏移的修正
第二版代码的问题有两个:
- 多边形顶点的
x=16886超出了np.arange(nx)的范围(nx=16886对应x从0到16885),导致路径边界错误; - 没有明确对齐掩码与目标裁剪区域的坐标原点——如果掩码是针对裁剪后的子图像生成的,需要把多边形顶点的坐标减去裁剪区域的原图像原点。
假设你要裁剪原图像的(x0, y0)到(x0+nx-1, y0+ny-1)区域,修正后的代码:
import numpy as np from matplotlib.path import Path from PIL import Image # 原图像尺寸 img_width = 19542 img_height = 14395 # 目标裁剪区域的原图像原点和尺寸 crop_x0, crop_y0 = 0, 0 # 假设从原图像左上角裁剪nx*ny的区域 nx, ny = 16886, 10079 # 多边形顶点(原图像坐标),转换为裁剪后子图像的相对坐标 sar_ver_original = [ (16886, 1085), (15139, 2122), (14475, 5226), (8419, 5601), (14046, 6876), (14147, 10079), (16816, 3748), (16886, 1085) ] # 转换为子图像的相对坐标(减去裁剪原点),同时反转y轴适配Path sar_ver_relative = [ (x - crop_x0, (img_height - 1 - y) - (img_height - 1 - (crop_y0 + ny - 1))) for x, y in sar_ver_original ] # 生成子图像的网格(相对坐标) x_grid, y_grid = np.meshgrid(np.arange(nx), np.arange(ny)) # 扁平化并生成点集 points = np.vstack((x_grid.flatten(), y_grid.flatten())).T # 创建路径并生成掩码 path = Path(sar_ver_relative) mask = path.contains_points(points) mask = mask.reshape((ny, nx)) # 与子图像shape一致:(10079, 16886) # 转换为图像保存 mask_img = Image.fromarray((mask * 255).astype(np.uint8)) mask_img.save('grid_image.png')
3. 图像与掩码尺寸不匹配的解决
这个问题的核心是混淆了数组的维度顺序:图像数组的shape是(高度, 宽度),对应(y轴像素数, x轴像素数),而你在裁剪时错误地把x轴放在了第一维度。
另外,确保掩码和图像的shape完全一致后,再进行相乘操作。修正后的代码:
import numpy as np from PIL import Image # 加载原图像 binary_file_path = "your_file.bin" img_width = 19542 img_height = 14395 im = np.fromfile(binary_file_path, dtype='>f4').astype(np.float32) im = im.reshape((img_height, img_width)) # 注意:shape是(高度, 宽度)=(y, x) # 假设已经生成了正确的掩码mask,shape与目标子图像一致:(10079, 16886) # 先裁剪原图像到与掩码相同的尺寸 crop_y0, crop_y1 = 0, 10079 crop_x0, crop_x1 = 0, 16886 im_cropped = im[crop_y0:crop_y1, crop_x0:crop_x1] # 第一维是y,第二维是x # 掩码与图像相乘提取目标区域 bb_list = im_cropped * mask.astype(np.float32) # 裁剪出非零区域(正确的维度顺序) slice_rows = np.any(bb_list, axis=1) # 按行(y轴)检查非零 slice_cols = np.any(bb_list, axis=0) # 按列(x轴)检查非零 ymin, ymax = np.where(slice_rows)[0][[0, -1]] xmin, xmax = np.where(slice_cols)[0][[0, -1]] # 提取目标区域 answer = bb_list[ymin:ymax+1, xmin:xmax+1] # 转换为图像保存(需要归一化到0-255范围) int_ans = (answer / answer.max() * 255).astype(np.uint8) fin_img = Image.fromarray(int_ans) fin_img.save('test_this.jpeg')
关键注意事项总结
- 坐标系统对齐:始终明确是使用原图像坐标还是裁剪后子图像的相对坐标,同时注意图像y轴与Matplotlib Path y轴的方向差异;
- 维度顺序:图像数组的shape是
(高度, 宽度)(y在前,x在后),所有网格、掩码的shape必须与此保持一致; - 多边形点范围:确保多边形顶点的坐标在生成的网格范围内,避免超出边界导致掩码错误。
内容的提问来源于stack exchange,提问作者Atihska
相关产品推荐
相关产品推荐

