2014-12-07 121 views
0

我一直在研究模擬給某人改造的C++/Allegro程序。有一個選項可以改變膚色,我現在有這個代碼。如何使用特定顏色填充區域

無效doMakeup ::基金會(MakeupMap *的基礎上,ALLEGRO_BITMAP * BG) {

al_lock_bitmap(bg, al_get_bitmap_format(bg), ALLEGRO_LOCK_READWRITE); 
ALLEGRO_BITMAP* bmp = al_get_target_bitmap(); 
al_set_target_bitmap(bg); 

int w = al_get_bitmap_width(bg); 
int h = al_get_bitmap_height(bg); 

//ALLEGRO_COLOR c = al_get_pixel(bg, state.x, state.y); 
ALLEGRO_COLOR c2 = al_map_rgb(249, 230, 206); 

for (int i = 0; i < w; i++) 
{ 
    for (int j = 0; j < h; j++) 
    { 
     ALLEGRO_COLOR c = al_get_pixel(bg, i, j); 
     if (SameColour(c, c2)) 
      al_put_pixel(i, j, foundation->colour); 
    } 

} 

al_set_target_bitmap(bmp); 
//move bitmap back to video memory 
al_unlock_bitmap(bg); 

}

代碼有些我想要做什麼,因爲在變化的顏色,但每當它靠近邊緣不會改變顏色。請幫幫我!

This is what it looks like when I call the function

+0

任何特定的語言/環境? – 2014-12-07 23:34:14

+0

是的C++和Allegro – Claudia 2014-12-07 23:35:59

回答

1

正如Kenogu Labz在另一個答案中提到的那樣,您的問題是您的顏色匹配是確切的,但圖像邊緣周圍的顏色是反鋸齒的或被源圖像編解碼器降級(有損圖像壓縮系統如JPEG)。

而不是執行精確的顏色匹配,您需要匹配顏色範圍

完成此操作的最佳方法通常是設置色彩相互之間距離的公差。您還沒有上市代碼爲SameColor(),但你可以通過改變SameColor()SimilarColor()一個實現類似這樣可能會得到你想要的結果:

bool SimilarColor(color c1, color c2, int tolerance) 
{ 
    int rDiff = std::abs(c1.r - c2.r); 
    int gDiff = std::abs(c1.g - c2.g); 
    int bDiff = std::abs(c1.b - c2.b); 

    return (rDiff < tolerance && gDiff < tolerance && bDiff < tolerance); 
} 

NB。這是僞代碼。我現在在底部添加了一個兼容ALLEGRO的實現。

一般原理是,您可以計算紅色差異,綠色差異和藍色差異,並確保它低於您的容差值。如果是,則返回true並執行顏色替換,如果不是,則不執行替換。

額外專家:

爲了取得更好的效果,你可能要考慮不直接更換顏色匹配的,而是不斷變化的匹配像素的色相(保持他們的飽和度和值),使您的顏色更改圖像不會過度簡化。這需要顏色1和顏色2的H,S,V值,這可能直接在ALLEGRO中支持,或者可能需要自定義代碼。

一些補充意見

注意,目前的代碼訪問圖像中的每個像素。圖像中的某些意外的任意像素可能會在您的容忍範圍內,並無意中重新着色。

爲了避免這種情況,您可以使用FloodFill(即,paintbucket)類型的重新着色來替換顏色匹配(儘管這會更復雜並限制您重新着色到連續區域),或者您可以從內存圖像其中每個可重新着色部分預先準備好具有獨特的無混疊像素顏色。例如,您可以在內存緩衝區中使用rgb(0,255,0)綠色面部的源圖像,但會顯示重新着色到所選色調的面部。當用戶選擇更改顏色時,請重新重新上色原始綠色圖像。希望這是有道理的。這是我所描述的屏幕外源圖像的例子:

sample color key image

邊注:總是喜歡.png文件.jpg如果你想避免畫質下降,由於圖像的文件格式。

爲了獲得最佳效果我全建議使用我上述彩色鍵圖像。它具有額外的優勢,您可以操縱原始圖像並保存爲無損文件格式,如.png,以便您可以根據原始代碼執行精確的顏色匹配,並且不需要嘗試匹配顏色範圍。您也永遠不會有背景顏色太接近您的容差並無意中更換顏色的情況。

但是,我現在也快速瀏覽了ALLEGRO_COLOR的ALLEGRO文檔,以下方法應該使用該庫執行上面顯示的SimilarColor方法。在快板看來你不能直接訪問ALLEGRO_COLOR的單獨的組件,所以你必須執行al_unmap_rgb第一:

bool SimilarColor(ALLEGRO_COLOR c1, ALLEGRO_COLOR c2, int tolerance) 
{ 
    // unpack the colors into their r,g,b components: 
    unsigned char c1R, c1G, c1B, c2R, c2G, c2B; 
    al_unmap_rgb(c1, &c1R, &c1G, &c1B); 
    al_unmap_rgb(c2, &c2R, &c2G, &c2B); 

    // calculate the absolute red, green and blue differences: 
    int rDiff = std::abs((int)c1R - (int)c2R); 
    int gDiff = std::abs((int)c1G - (int)c2G); 
    int bDiff = std::abs((int)c1B - (int)c2B); 

    // return true only if ALL color channel diffs are below tolerance. 
    // NB. tolerance needs to be between 1 and 254, and a value of 35 
    // is probably a good start point for testing purposes 

    return (rDiff < tolerance && gDiff < tolerance && bDiff < tolerance); 
} 
+0

不客氣,我已經添加了一些代碼,顯示了可能的Allegro兼容的SimilarColor例程實現,並試圖更清楚地解釋一些事情。如前所述,如果您可以整理源圖像並使用無損圖像編解碼器,那麼使用原始代碼可能是最簡單的方法。 – 2014-12-08 01:08:25

0

在基本圖像的邊緣像素是不是由於anti-aliasing相同的顏色。

+0

什麼是處理抗鋸齒的好方法? – Claudia 2014-12-08 00:01:03