如何用Numpy计算图像各分割区域的中位数?
问题描述
我想计算图像中每个分割区域的中位数,第一步用skimage的felzenszwalb做图像分割,但返回的mask是100100的单通道数组,不是预期的100100*3。想结合numpy maskedarray的中位数计算方法实现,有没有简便解法?原代码片段如下:
from skimage.segmentation import felzenszwalb, slic, quickshift, watershed np.random.seed(seed=777) img = np.random.randint(low=0, high = 255, size=(100,100, 3)) segments_fz = felzenszwalb(img, scale=100, sigma=0.5, min_size=50) label_image, num = label(segments_fz, return_num = True) for i in num: mask_arr = np.ma.masked_array(img, mask = ??? ) out_arr1 = ma.median(mask_arr, axis = 0)
解决方案
核心问题说明
felzenszwalb返回的分割结果是区域标签图——每个像素位置的值代表该像素所属的分割区域编号,因此是单通道(H×W)格式,而非和原图一致的三通道。计算每个区域的中位数无需将mask转成三通道,直接针对区域标签提取对应像素计算即可。
简化实现代码
import numpy as np from skimage.segmentation import felzenszwalb from skimage.measure import label np.random.seed(seed=777) img = np.random.randint(low=0, high=255, size=(100, 100, 3)) # 执行分割得到区域标签图 segments_fz = felzenszwalb(img, scale=100, sigma=0.5, min_size=50) label_image, num_labels = label(segments_fz, return_num=True) # 存储每个区域的RGB中位数 region_medians = {} # 遍历每个区域标签(label从1开始,0为未标记区域) for label_id in range(1, num_labels + 1): # 提取当前区域的所有RGB像素 region_pixels = img[label_image == label_id] # 按通道计算中位数,axis=0对应RGB通道维度 median = np.median(region_pixels, axis=0) region_medians[label_id] = median # 示例:打印第一个区域的中位数 print(f"区域1的RGB中位数: {region_medians[1]}")
关键细节解释
- 区域像素提取:用
label_image == label_id生成单通道布尔掩码,直接索引原图即可提取该区域的所有RGB像素(形状为(N,3),N为区域内像素数量),操作高效直观。 - 中位数计算:直接调用
np.median对提取到的像素数组按axis=0计算,即可得到每个颜色通道的中位数,无需额外使用maskedarray。 - 标签遍历范围:
label函数返回的有效区域标签从1开始,0代表背景/未标记区域,因此遍历范围需从1到num_labels+1。
基于maskedarray的实现方式
如果一定要用numpy maskedarray实现,可修改原代码中的mask生成逻辑:
# 循环内替换mask生成与中位数计算部分 mask = (label_image != label_id)[..., np.newaxis] # 将单通道掩码扩展为三通道,匹配原图维度 mask_arr = np.ma.masked_array(img, mask=mask) # 按空间维度(0,1)计算未屏蔽区域的中位数 median = np.ma.median(mask_arr, axis=(0,1))
这里通过[..., np.newaxis]将H×W的布尔掩码扩展为H×W×3,与原图维度对齐后,用maskedarray屏蔽非当前区域的像素,最终计算目标区域的中位数。
内容的提问来源于stack exchange,提问作者user16971617
相关产品推荐
相关产品推荐

