合并图像直方图的相似区域

2024-10-02 02:27:49 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在使用Python(没有AI,只有经典工具)进行一个CV项目,但遇到了一个问题。 我试图从已知的ROI中检测手和皮肤的颜色,该ROI具有白色背景的手(因为使用网络摄像头时,颜色可能不准确-例如,灰色可能被视为白色)。我试着做一个颜色直方图,从那里我将提取手的颜色。 为了得到我使用的颜色列表Image.getcolors(width*height),并将其放入直方图中。不幸的是,我得到了一个巨大的颜色列表,其中许多颜色与其他颜色相似(例如,(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]

用于对颜色进行排序。 以及:

    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()

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

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

for color in toRemove:
    sortedColors.remove(color)

谢谢大家!


Tags: inimage列表for颜色直方图color白色
1条回答
网友
1楼 · 发布于 2024-10-02 02:27:49

通常使用直方图将颜色放入。例如,如果有256个强度和32个箱子,这意味着每个箱子的宽度为4。从0到3的强度被集中到第一个存储单元,从4到7的强度被集中到第二个存储单元,等等。这就是正式称为均匀颜色量化的东西,我们对像素进行量化,使其进入一组预定的存储单元中

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

由于图像已经以NumPy形式存储在coloredRoi中,因此我假设图像已经存储在三个平面中,因此通道是最后一个维度的3D数组。我还假设每个通道处理8位无符号整数值。像这样简单的方法可以奏效:

# 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箱的映射位置。这是一个唯一的元组,将映射到一维直方图中的单个位置。要计算最终的1D箱号,请考虑红色导航此空间的行,绿色导航此空间的列。假设我们只需要处理红色和绿色,每次我们需要去一个红色的新空间时,我们必须跳过num_green_bins,这就是为什么我们有num_green_bins * bin_red。每次转到绿色的新空间时,我们只需要偏移列,以便将bin_green添加到num_green_bins * bin_red + bin_green。最后,如果我们想使用蓝色,我们需要为每个蓝色空间跳过num_red_bins * num_green_bins,因为我们现在要使用3D,因此我们现在还添加了num_red_bins * num_green_bins * bin_blue。然后,我们使用^{}根据刚才计算的1D箱计算最终直方图

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

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

^{}获取二维数组并将其堆叠到第三维以生成一个整合的三维数组。如果你做得对,当你可视化存储在out_img中的量化结果时,颜色的微小变化就会消失。请注意,每个颜色通道的箱数是需要调整的参数。箱子的数量越高,颜色的纹理就越细,从而增加了所代表的动态范围,但使用颗粒颜色的代价是将非常相似的RGB像素视为不同。类似地,箱子的数量越小,在更大的值范围内,颜色越相似,这将使分类的辨别力变弱。我建议改变垃圾箱的数量,这样你就可以更多地夸大反映人类肤色的垃圾箱(红色/绿色),而减少对不反映人类肤色的颜色(蓝色)的强调

相关问题 更多 >

    热门问题