如何在Python中为Meta AI Segment Anything(SAM)生成透明分割掩码?
问题:为SAM生成透明分割掩码以保留原始图像色彩
我需要为Meta AI的Segment Anything(SAM)生成透明分割掩码,目的是保留分割区域的原始颜色。目前我用sv.MaskAnnotator(color=sv.Color.xyz)来指定掩码颜色,但不知道怎么设置成完全透明,从而让原始图像的颜色透出来。我以YOLOv8生成的边界框作为SAM的输入,相关代码如下:
import numpy as np import cv2 import supervision as sv from jupyter_bbox_widget import BBoxWidget widget = BBoxWidget() # default_box is going to be used if you will not draw any box on image above default_box = {'x': 68, 'y': 247, 'width': 555, 'height': 678, 'label': ''} mask_predictor = SamPredictor(sam) for image in yolo_test_data: box = widget.bboxes[0] if widget.bboxes else default_box box = yolo_convertor(image['tensor'])[0] image_bgr = cv2.imread(image['image_path']) image_rgb = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2RGB) mask_predictor.set_image(image_rgb) masks, scores, logits = mask_predictor.predict( box=box, multimask_output=True ) mask_annotator = sv.MaskAnnotator(color=sv.Color.red()) detections = sv.Detections( xyxy=sv.mask_to_xyxy(masks=masks), mask=masks ) detections2 = detections[detections.area == np.max(detections.area)] segmented_image = mask_annotator.annotate(scene=image_bgr.copy(), detections=detections2) # Save image to google drive cv2.imwrite(os.path.join("/content/drive/MyDrive/xxx/xxx", os.path.basename(image['image_path'])), segmented_image)
解决方案
要实现保留分割区域原始色彩的透明掩码,无需依赖sv.MaskAnnotator(它的作用是给掩码填充颜色后叠加到原图),直接通过OpenCV处理图像的alpha通道即可实现需求:
方法1:生成带透明背景的目标图像
核心逻辑是给原图添加alpha通道,将非分割区域的alpha值设为0(完全透明),分割区域保留原图色彩与不透明属性:
import numpy as np import cv2 import supervision as sv import os from jupyter_bbox_widget import BBoxWidget widget = BBoxWidget() default_box = {'x': 68, 'y': 247, 'width': 555, 'height': 678, 'label': ''} mask_predictor = SamPredictor(sam) for image in yolo_test_data: box = widget.bboxes[0] if widget.bboxes else default_box box = yolo_convertor(image['tensor'])[0] image_bgr = cv2.imread(image['image_path']) image_rgb = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2RGB) mask_predictor.set_image(image_rgb) masks, scores, logits = mask_predictor.predict( box=box, multimask_output=True ) detections = sv.Detections( xyxy=sv.mask_to_xyxy(masks=masks), mask=masks ) # 筛选面积最大的分割掩码 detections2 = detections[detections.area == np.max(detections.area)] target_mask = detections2.mask[0].astype(np.uint8) * 255 # 给原图添加alpha通道(BGRA格式) image_rgba = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2BGRA) # 将非掩码区域的alpha值设为0,实现透明效果 image_rgba[:, :, 3] = target_mask # 保存为PNG格式(JPG不支持透明通道) save_filename = os.path.basename(image['image_path']).replace('.jpg', '.png') save_path = os.path.join("/content/drive/MyDrive/xxx/xxx", save_filename) cv2.imwrite(save_path, image_rgba)
方法2:生成单独的透明掩码文件
如果仅需要单独的透明掩码(仅分割区域不透明,其余区域完全透明),可以直接处理掩码生成单通道alpha图:
# 承接上述代码,得到target_mask后执行: mask_rgba = np.zeros((target_mask.shape[0], target_mask.shape[1], 4), dtype=np.uint8) mask_rgba[:, :, 3] = target_mask # 仅alpha通道保留掩码信息 cv2.imwrite("transparent_mask.png", mask_rgba)
补充说明
- 虽然
sv.MaskAnnotator的color参数支持带透明度的颜色(比如sv.Color(r=255, g=0, b=0, a=0)),但这种设置会让掩码区域完全透明,非掩码区域仍显示原图,无法实现“仅保留分割区域、其余透明”的效果,因此更推荐使用alpha通道处理方案。 - 透明图像必须保存为PNG格式,JPEG格式不支持alpha通道,会丢失透明信息。
内容的提问来源于stack exchange,提问作者Milan van beek
相关产品推荐
相关产品推荐

