繁体   English   中英

如何使用优化算法找到可能的最佳参数

[英]How to use an optimization algorithm to find the best possible parameter

我试图找到一个很好的 colors 间隔进行颜色遮罩,以便从图像中提取皮肤。

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

示例图像

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

掩蔽样本结果

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

这是我为此使用的代码:

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)

从不同皮肤中提取所有色调后,我正在创建一个直方图,让我可以查看哪些 colors 更常见。 该代码对于创建直方图来说太长了,但结果如下:

在此处输入图像描述

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

在此处输入图像描述

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

R:

  • 转折点:142
  • 距离:61
  • 间隔:[81, 203]

G:

  • 转折点:155
  • 距离:10
  • 间隔:[145, 165]

乙:

  • 转折点:109
  • 距离:14
  • 间隔:[95, 123]

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

在此处输入图像描述

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

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:

  • 转折点:142
  • 距离:61
  • 间隔:[81, 203]

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

新 R:

  • 转折点:142
  • 距离:43
  • 间隔:[99, 185]
  • 为了获得更高的间隔,我将乘以]1, 2] 中的一个数字
  • 为了获得更小的间隔,我将乘以 ]0, 1[ 中的一个数字

现在,我的问题:

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

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

一种快速收敛但可能不会产生全局最优值的基本方法是爬山法。

Hillclimbing 是一种可以在这种情况下使用的本地搜索形式。
爬山的工作方式是从一个 state 或解决方案转到下一个,具体取决于 state 的分数性能 如果没有更好的 state 可以发现 state 作为解决方案返回。

有多种实现爬山的方法,在你的情况下,我会做这样的事情:

The State : In your case an item containing the Min and Max numpy arrays and the accuracy or f-measure of the mask created with these arrays applied on the image as score property.

现在我建议你只采用对称范围来大量减少搜索空间。

启动 State
您可以随机创建一个起始 state,为每个通道(红色、绿色、蓝色)采用随机间隔。 如果您多次运行此算法,这将特别有用。 根据您的直方图确定每个间隔的最大值和最小值。

迭代过程(这是完成搜索的地方)
您想创建一个无限循环,在其中为当前 state 创建后续状态。 使用当前 state 中的10来增加或减少每个通道的间隔,然后这些新间隔的每个组合都可以是后继 state。
另一种方法可能是每次迭代切换通道。 So in the first iteration you create a successor state that has the Red channel of the current state decreased with 10, and a successor state that has the Red channel of the current state increased with 10. The second iteration you change the Green channel, the第三次迭代蓝色通道等。

然后,您基于每个后继 state 创建一个掩码并将它们应用到图像上,从而确定每个后继 state 的性能。
Select 是性能最好的后继产品 state,如果性能更好,则将其作为当前的 state。

重复这个过程,直到最好的后继 state 的性能比当前的 state 差,然后你就知道你已经达到了局部最优。 将此 state 作为解决方案返回。

问题
如上一行所示,该算法将找到起始 state 的局部最优值。 这是因为该算法的贪心。
因此,您可能希望在不同的起始位置重新启动此算法,从而允许探索更多的搜索空间,从而增加找到全局最大值的机会。
如果您有多个线程,您可以并行运行多个实例,然后最终从每个实例的结果中返回最佳 state。

Hillclimbing 不是最好的优化算法,但它非常快速且易于实现。

我建议使用遗传优化,它可以很容易地解决像你这样简单的问题。 由于问题相对“小”,与@Leander 建议的一些局部优化方法(如 Hillclimb)相比,找到最优解应该不会花费太多时间。 遗传算法是一种元启发式搜索,因此不能保证找到最佳解决方案,但它应该让您非常接近。 事实上,对于这样一个小问题,您找到全局最优值的机会非常高。

作为开始,我建议您看一下 DEAP,这样您就不必自己实现任何东西( https://deap.readthedocs.io/en/master/ )。 它包含许多遗传算法变体的非常好的实现,并且有很好的示例教程。 通过一些努力,您应该能够在一两天内编写一个简单的优化算法。

为简单起见,从现在起遗传算法将被表示为GA

从哪里开始的一些提示:

  • 我建议您从 DEAP 中最简单的变体eaSimple开始。 当这不能令人满意时,您总是可以转向更复杂的东西,但我认为这没有必要。
  • 您在 GA 中的Individual将有 6 个组件 -> [blue_low, blue_high, green_low, green_high, red_low, red_high] 这也将解决@Leander 在评论中提到的不对称间隔问题
  • mutations将通过随机改变个体的元素来完成
  • 对于健身fittness您可以使用您的准确度,因为您现在正在计算它

这基本上就是为您的问题构建 GA 所需的全部内容。 这里的这个例子https://deap.readthedocs.io/en/master/examples/ga_onemax.html应该让你启动并运行。 您只需要定义自己的个人、运营商和健身评估 function 就像我在前面的步骤中提到的那样

关于使用任何一般优化方法的最后说明。 据我了解,这是一个 6 个维度的离散问题,因为您有 6 个组件:blue_low、blue_high、green_low、green_high、red_low、red_high,每个组件只有 255 个可能值。 这将阻止使用大多数优化方法,因为它们要求问题是连续的。

在您当前的算法中,您正在查找颜色空间数据的模式(即峰值),然后围绕模式对称地获取箱(颜色值)。

对于正态分布曲线,您将根据平均值周围的标准偏差数获得总体百分比,如下所示:

正态分布曲线

在正态分布中,均值、中位数和众数将相同。 但是,如果您的分布有偏差,则均值左侧的总体与均值右侧的总体将不同。 因此,您可以进行的简单调整如下:

p_left为峰值左侧的人口百分比,而p_right为峰值右侧的人口百分比。 例如:让p_left = 40%p_right = 60% 您可以设置另一个参数,即% of selected population (例如 15%),而不是使用(-20,20)的固定间隔宽度 40。 这是我们想要的模式周围的总人口(包括模式)。 然后,您可以将这 15% 划分为左右人口的比例。

left proportion = 15% x 40% = 6%
right proportion = 15% x 60% = 9%

您应该通过计算mode % of population并从中取出一半来纠正这 6% 和 9%。 例如:如果众数为人口的5%,则应从6%和9%中扣除2.5%。 这给出了调整后p_leftp_right为:

p_left = 6% - 2.5% = 3.5%
p_right = 9% - 2.5% = 6.5%

您不是在平均值周围均匀地划分区间,而是计算需要包含左右多少个 bin 才能确定范围。 例如:您可能会发现在左侧添加 5 个垃圾箱占总人口的 3.5%,在右侧添加 3 个垃圾箱大约占人口的 6.5%。

因此,您的范围变为(x - 5, x + 3) ,其中 x 是模式的 x 坐标。

参数估计:要确定人口模式百分比的正确百分比(上例中的 15%),您可以在一组标准蒙版图像上计算直方图,并使用它来确定良好的初始估计。 基本上计算蒙版图像中未蒙版的像素并将其除以总像素

实际上,找到给定数据集的全局最优值并不太复杂。 为简单起见,我们首先假设您有灰度图像,因为每个 colors 都是独立处理的(我相信)。 如果您根据所有 3 个 colors 对一个像素进行评分,那么这会有点复杂,但您似乎不是。

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

顺便说一句,您目前计算掩码和地面实况之间的准确性的方式非常低效。 经验法则几乎总是尽可能使用 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))

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

暂无
暂无

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

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