首页 > 解决方案 > 如何使用优化算法找到可能的最佳参数

问题描述

我正在尝试为颜色遮罩找到一个好的颜色间隔,以便从图像中提取皮肤。

我有一个包含图像和蒙版的数据库,可以从这些图像中提取皮肤。这是一个示例:

示例图像

我正在为每个图像应用蒙版以获得如下效果:

掩蔽样本结果

我从所有蒙面图像中获取所有像素并删除黑色像素,以便仅保留包含皮肤的像素。使用这种方法,我能够从不同的人那里收集包含不同肤色的不同颜色的不同像素。

这是我为此使用的代码:

for i, (img_color, img_mask) in enumerate ( zip(COLORED_IMAGES, MASKS) ) :

    # masking
    img_masked = cv2.bitwise_and(img_color, img_mask)
    
    # transforming into pixels array
    img_masked_pixels = img_masked.reshape(len(img_masked) * len(img_masked[0]), len(img_masked[0][0]))
 
    # merging all pixels from all samples
    if i == 0:
        all_pixels = img_masked_pixels
    else:
        all_pixels = np.concatenate((all_pixels, img_masked_pixels), axis = 0)

# removing black
all_pixels = all_pixels[ ~ (all_pixels == 0).all(axis = 1) ]

# sorting pixels
all_pixels = np.sort(all_pixels)

# reshape into 1 NB_PIXELSx1 image in order to create histogram
all_pixels = all_pixels.reshape(len(all_pixels), 1, 3)

# creating image NB_PIXELSx1 image containing all skin colors from dataset samples
all_pixels = cv2.cvtColor(all_pixels, cv2.COLOR_BGR2YCR_CB)

从不同的皮肤中提取所有颜色深浅后,我正在创建一个直方图,让我可以看到哪些颜色更常见。代码太长,无法创建直方图,但结果如下:

在此处输入图像描述

然后,我使用每个颜色空间图的转折点,并为该颜色空间选择一个距离,例如 20。该颜色空间的间隔是通过执行 [转折点 - 20,转折点 +20] 获得的

在此处输入图像描述

假设我们得到了以下内容:

:

G :

乙:

我将使用这些间隔从数据集中创建彩色图像的蒙版,以提取皮肤(左:我的间隔蒙版,右:真实蒙版):

在此处输入图像描述

使用我的间隔提取的掩码与数据集先前存在的掩码进行比较,并计算准确性,以查看我得到的间隔的有效性和良好程度:

precision_moy = 0
accuracy_moy = 0

for i, (image, img) in enumerate ( zip(COLORED, GROUND_TRUTH) ) :
    Min = np.array([81, 145, 95], np.uint8)
    Max = np.array([203, 165, 123], np.uint8)

    mask = cv2.inRange (image, Min, Max)

    TP = 0 # True Positive
    TN = 0 # True Negative
    FP = 0 # False Positive
    FN = 0 # False Negative

    for i in range(mask.shape[0]) :
        for j in range(mask.shape[1]) :
            if mask[i,j] == 255 and img[i,j,0] == 255:
                TP = TP + 1
            if mask[i,j] == 0 and img[i,j,0] == 0:
                TN = TN+1
            if mask[i,j] == 255 and img[i,j,0] == 0:
                FP = FP+1
            if mask[i,j] == 0 and img[i,j,0] == 255:
                FN = FN+1

    precision = TP/(TP+FP)
    accuracy = (TP+TN)/(TP+TN+FP+FN)
    
    precision_moy = precision_moy + precision
    accuracy_moy = accuracy_moy + accuracy

precision_moy = precision_moy / len(COLORED)
accuracy_moy = accuracy_moy / len(COLORED)

我不断更改间隔,测试和计算准确性,以便为每个颜色空间找到最佳间隔。这种变化是通过将距离乘以 0 到 2 之间的数字来完成的。例如:

老R:

新距离 = 旧距离 * 0.7 = 61 * 0.7 = 43

新R:

现在,我的问题:

我想使用优化方法找到每个颜色空间的最佳间隔,而不是手动和随机更改间隔。我应该使用什么优化方法以及如何使用它?

感谢您抽出宝贵时间。感谢您的帮助。

标签: pythonoptimizationmask

解决方案


实际上,找到给定数据集的全局最优值并不太复杂。为简单起见,我们首先假设您有灰度图像,因为每种颜色都是独立处理的(我相信)。如果您根据落在所需间隔内的所有 3 种颜色对像素进行评分,那会有点复杂,但看起来您不是。

因此,无论如何,您可以根据数据集的大小,彻底检查每个图像的每个间隔。例如,如果每个像素只取 [0,255] 中的整数值,那么您甚至只需要考虑大约 100 个间隔大小。因此,您可以计算每个候选区间大小和每个图像的准确度,并简单地采用产生最高平均准确度的区间。重复所有颜色。这肯定是蛮力方法,但除非您的数据集非常大,否则使用优化的矩阵运算在计算上不应该是昂贵的。如果您的数据集很大,使用此技术的足够大的随机图像样本将产生近似值(尽管不是全局最优解)。

顺便说一句,您目前计算掩码和地面实况之间的准确性的方式非常低效。经验法则几乎是尽可能始终使用 numpy 矩阵运算,因为它们效率更高(有一些很酷的算法技巧可以节省矩阵运算的时间,并且它们是用 C 编写的,因此速度更快,因为出色地。

你可以替换这个:

 for i in range(mask.shape[0]) :
    for j in range(mask.shape[1]) :
        if mask[i,j] == 255 and img[i,j,0] == 255:
            TP = TP + 1
        if mask[i,j] == 0 and img[i,j,0] == 0:
            TN = TN+1
        if mask[i,j] == 255 and img[i,j,0] == 0:
            FP = FP+1
        if mask[i,j] == 0 and img[i,j,0] == 255:
            FN = FN+1

使用等价矩阵运算:

ones = np.ones(img.shape)
zeros = np.zeros(img.shape)
diff = mask - img
TP = sum(np.where(np.multiply(diff,img) == 1,ones,zeros))
TN = sum(np.where(np.multiply(diff,1-img) == 1,ones,zeros))
FP = sum(np.where(diff == -1,ones,zeros))
FN = sum(np.where(diff == 1,ones,zeros))

这将节省您的时间,特别是如果您使用我建议的那种蛮力方法,但通常也是一种很好的做法


推荐阅读