Python实现:如何将绘制的ROI蒙版保存为无背景PNG
问题:提取并保存ROI区域(无背景)
我用Python做图像处理,已经实现了ROI绘制功能,也写了保存ROI的代码,但当前生成的roi_region和原图尺寸完全一致,只想单独保存ROI本身(不带背景区域)。试过添加alpha通道、改用plt.figsave都没解决问题,相关代码如下:
if index == 2: fig_all_roi, ax_all_roi = plt.subplots() ax_all_roi.set_title('Extracted ROIs') for i, (verts_list, color) in enumerate(zip(roi_verts_list, roi_colors)): for verts in verts_list: # Create a Path object from the vertices path = Path(verts) # Create a mask for the region inside the ROI x, y = np.meshgrid(np.arange(image.shape[1]), np.arange(image.shape[0])) points = np.column_stack((x.flatten(), y.flatten())) mask = path.contains_points(points).reshape(image.shape[:2]) # Extract the region inside the ROI from the original image roi_region = np.zeros_like(image, dtype=np.uint8) for channel in range(image.shape[2]): roi_region[:, :, channel] = (image[:, :, channel] * mask).astype(np.uint8) roi_region[:,:, 3] = (mask*255).astype(np.uint8) # Save the extracted ROI as an image save_roi_image(roi_region, i) # Display the extracted region in the new figure ax_all_roi.imshow(roi_region, extent=[0, image.shape[1], 0, image.shape[0]])
解决方案
核心思路是先裁剪出ROI的最小包围矩形,再结合alpha通道实现背景透明,具体步骤如下:
1. 定位ROI的边界范围
根据生成的mask,找到ROI区域的最小/最大坐标,确定裁剪范围:
# 找到mask中非零区域的坐标 y_coords, x_coords = np.where(mask) # 处理空ROI的特殊情况 if len(y_coords) == 0: continue # 确定ROI的上下左右边界 x_min, x_max = x_coords.min(), x_coords.max() y_min, y_max = y_coords.min(), y_coords.max()
2. 裁剪并生成带透明通道的ROI
把原图和mask都裁剪到上述边界内,再拼接alpha通道:
# 裁剪原图的ROI区域 cropped_image = image[y_min:y_max+1, x_min:x_max+1] # 裁剪对应的mask cropped_mask = mask[y_min:y_max+1, x_min:x_max+1] # 生成带alpha通道的RGBA图像(仅保留ROI区域,背景透明) cropped_roi = np.dstack((cropped_image, cropped_mask.astype(np.uint8)*255))
3. 调整保存逻辑
保存时要选择支持透明通道的格式(比如PNG),示例修改save_roi_image函数:
from PIL import Image def save_roi_image(roi_array, index): # 将numpy数组转换为PIL图像对象 img = Image.fromarray(roi_array) # 保存为PNG格式(JPG不支持透明通道) img.save(f"roi_{index}.png")
完整修改后的代码片段
if index == 2: fig_all_roi, ax_all_roi = plt.subplots() ax_all_roi.set_title('Extracted ROIs') for i, (verts_list, color) in enumerate(zip(roi_verts_list, roi_colors)): for verts in verts_list: # Create a Path object from the vertices path = Path(verts) # Create a mask for the region inside the ROI x, y = np.meshgrid(np.arange(image.shape[1]), np.arange(image.shape[0])) points = np.column_stack((x.flatten(), y.flatten())) mask = path.contains_points(points).reshape(image.shape[:2]) # 新增:定位ROI边界 y_coords, x_coords = np.where(mask) if len(y_coords) == 0: continue x_min, x_max = x_coords.min(), x_coords.max() y_min, y_max = y_coords.min(), y_coords.max() # 裁剪ROI区域 cropped_image = image[y_min:y_max+1, x_min:x_max+1] cropped_mask = mask[y_min:y_max+1, x_min:x_max+1] # 生成带透明通道的ROI cropped_roi = np.dstack((cropped_image, cropped_mask.astype(np.uint8)*255)) # Save the extracted ROI as an image save_roi_image(cropped_roi, i) # Display the extracted region in the new figure ax_all_roi.imshow(cropped_roi)
内容的提问来源于stack exchange,提问作者MoBedick
相关产品推荐
相关产品推荐

