2014-12-07 118 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