繁体   English   中英

合并图像直方图的相似分箱

[英]Merge Similar Bins of Image Histogram

我正在使用 Python(没有 AI,仅限经典工具)进行 CV 项目,但遇到了问题。 我正在尝试从已知 ROI 中检测手部和肤色,该 ROI 手部位于白色背景上(因为它使用网络摄像头,所以颜色可能不准确 - 例如,灰色对我来说可能被视为白色)。 我试着做一个 colors 的直方图,从那里我将提取手的颜色。 为了获得 colors 的列表,我使用了Image.getcolors(width*height) ,并将其放入直方图中。 不幸的是,我得到了一个庞大的 colors 列表,其中很多都与其他类似(例如,(255,0,0)和(255,0,1)在分开的箱子中表示)(由于相机质量差、照明等)。 我的问题是如何合并这些箱并获得一个可靠的直方图,我可以从中提取肤色。 这是我写的一些代码:

pilRoi = Image.fromarray(coloredRoi)
w,h = pilRoi.size
colorsInRoi = pilRoi.getcolors(w*h)
sortedColors = sorted(colorsInRoi, key=lambda tup: tup[0])[::-1]

用于对 colors 进行排序。 和:

    for idx, color in enumerate(sortedColors):
    if(idx<config.NUM_COLORS):
        plt.bar(idx, color[0], color=helper.toHex(color[1]),edgecolor=helper.toHex(color[1]))
    else:
        break
plt.show()

为直方图。 我确实尝试删除白色范围像素的总和,其他 colors 仍然存在问题:

    for color in sortedColors:
    if isInWhiteRange(color[1]) or color[1] == config.BLUE:
        toRemove.append(color)

for color in toRemove:
    sortedColors.remove(color)

谢谢你!

通常使用直方图,您可以将颜色放入bin中。 例如,如果您有 256 个强度和 32 个 bin,这意味着每个 bin 的宽度为 4。0-3 范围内的强度集中到第一个 bin 中,4-7 范围内的强度集中到第二个 bin 中,等等. 这就是所谓的统一颜色量化,我们量化一个像素,使其进入一组预定的 bin 之一。

在您的特定情况下,您可以指定每个颜色通道的箱数,然后您可以简单地计算一维直方图,这样对于每个颜色通道,您可以确定它属于该通道的哪个箱,然后转换这个 3 个箱的序列成单个值。 我提倡一维直方图的原因是为了更容易计算图像之间的相似性度量。

由于您的图像已经以 NumPy 形式存储在coloredRoi中,因此我假设您已经在三个平面中拥有该图像,因此 3D 数组是最后一个维度。 我还假设您正在处理每个通道的 8 位无符号 integer 值。 像这样简单的东西可以工作:

# Define number of bins per channel
num_red_bins = 8
num_green_bins = 8
num_blue_bins = 8

# Define threshold per bin
thresh_red = 256 // num_red_bins
thresh_green = 256 // num_green_bins
thresh_blue = 256 // num_blue_bins

# Extract planes
red = coloredRoi[..., 0]
green = coloredRoi[..., 1]
blue = coloredRoi[..., 2]

# Calculate bin number per location
bin_red = red // thresh_red
bin_green = green // thresh_green
bin_blue = blue // thresh_blue

# Calculate 1D bin locations
bins = num_red_bins * num_green_bins * bin_blue + num_green_bins * bin_red + bin_green

# Calculate histogram
histo = np.bincount(bins, minlength=num_red_bins * num_green_bins * num_blue_bins)

该代码非常不言自明,但最后两行可能会令人困惑。 在此之前,我们已经将 RGB 像素转换为它们在红色、绿色和蓝色通道中的 bin 位置。 这些集合将为我们提供该像素相对于最终 3D bin 的位置。 这是一个独特的元组,它将 map 到一维直方图中的单个位置。 要计算最终的一维 bin 编号,请考虑红色导航此空间的行,绿色导航此空间的列。 假设我们只需要处理红色和绿色,每次我们需要 go 到一个新的红色空间时,我们必须跳过num_green_bins ,这就是我们有num_green_bins * bin_red的原因。 每次我们 go 到一个新的绿色空间时,我们只需要偏移列,这样我们就可以将bin_green添加到num_green_bins * bin_red + bin_green 最后,如果我们想将 go 变为蓝色,我们需要为每个我们想要的蓝色空间num_red_bins * num_green_bins ,因为我们现在要去 3D,因此我们现在还添加num_red_bins * num_green_bins * bin_blue 然后我们使用numpy.bincount根据我们刚刚计算的一维 bin 计算最终的直方图。

现在您有了这个 1D 直方图,您可以使用任何直方图相似性度量来查看您期望从手上得到的颜色分布是否与感兴趣的补丁匹配。 最后一点,如果您想看看这个量化图像是什么样子,只需将您的 bin 值乘以 bin 值乘以我上面概述的每个 bin 的阈值,然后将所有内容堆叠成最终图像。

out_img = np.dstack((thresh_red * bin_red, thresh_green * bin_green, thresh_blue * bin_blue))

numpy.dstack采用 2D arrays 并将它们堆叠在第三维中以生成合并的 3D 数组。 如果你做对了,当你可视化存储在out_img中的量化结果时,颜色的微小变化将会消失。 请注意,每个颜色通道的 bin 数量是您需要调整的参数。 bin 的数量越多,颜色的细粒度就越细,从而增加了所代表的动态范围,但是使用细粒度颜色的代价是将非常相似的 RGB 像素视为不同的像素。 同样,bin 的数量越少,在更广泛的值范围内看起来就越相似的颜色,这将使您的分类的辨别力更弱。 我建议更改垃圾箱的数量,以便您在反映人类肤色(红色/绿色)的垃圾箱上更加夸张,而较少强调不反映人类肤色的颜色(蓝色)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM