簡體   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