Как отмечает Кеногу Лабз в другом ответе, ваша проблема в том, что совпадение цвета совпадает с тоном, но цвета по краям изображения сглажены или деградированы кодеком исходного изображения (общая проблема с системами сжатия изображений с потерями таких как 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 и выполняете замену цвета, если нет, то замена не выполняется.
Дополнительно для специалистов:
Чтобы получить еще лучшие результаты, вы можете рассмотреть непосредственно не заменяя цвета совпадают, но вместо изменения цветового тона пикселей совпавших (сохраняя их насыщенность и значение), так что ваше изображение с измененным цветом не упрощается. Для этого потребуются значения H, S, V для цвета 1 и цвета 2, которые могут поддерживаться непосредственно в ALLEGRO или могут потребовать настраиваемый код.
Некоторые дополнительные комментарии
Обратите внимание, что ваш текущий код посещения каждый пиксель в изображении. Возможно, что некоторые непреднамеренные произвольные пиксели в изображении могут входить в ваш перенос и непреднамеренно перекрашиваться.
Чтобы избежать этого, вы можете заменить совпадение цветов с помощью метода повторного окрашивания FloodFill (т. Е. Paintbucket) (хотя это сложнее и ограничивает перекрашивание в смежные области), или вы можете работать с изображением в памяти где каждая перекрашиваемая секция предварительно подготовлена, чтобы иметь уникальный цвет с псевдонимом. Например, у вас может быть исходное изображение с зеленой гранью rgb (0,255,0) в буфере памяти, но отобразите цвет лица на выбранный оттенок.И когда пользователь выбирает изменить цвет, повторно переориентируйте исходное зеленое изображение снова. Надеюсь, это имеет смысл. Вот пример внеэкранного исходного изображения я описываю:
Примечание стороны: всегда предпочитают .png
файлов .jpg
, если вы хотите, чтобы избежать ухудшения качества изображения из-за формат файл изображения.
Для получения наилучших результатов я полностью рекомендую использовать цветное ключевое изображение, описанное выше. Он имеет дополнительное преимущество в том, что вы можете манипулировать исходным изображением и сохранять в виде формата без потерь, например .png
, чтобы вы могли выполнять точное сопоставление цветов в соответствии с вашим исходным кодом и не должны пытаться соответствовать цветовой гамме. У вас также никогда не будет ситуации, когда цвета фона слишком близки к вашему допуску и не будут случайно заменены цветом.
Тем не менее, я также внимательно рассмотрел документацию ALLEGRO для ALLEGRO_COLOR и следующий метод должен выполнить описанный выше метод SimilarColor с использованием этой библиотеки. В Allegro в этом случае вы не можете получить доступ отдельные компоненты 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);
}
Любой конкретный язык/окружающей среды? –
Yea C++ и Allegro – Claudia