Мягкая заливка ведра с краской: цветовое равенство

Я делаю небольшое приложение, в котором дети могут раскрашивать предустановленные иллюстрации цветами. Я успешно реализовал ведро с краской в ​​​​стиле MS-paint, используя алгоритм заливки. Однако вблизи краев элементов изображения пиксели остаются незаполненными, поскольку линии сглажены. Это связано с тем, что текущим условием заполнения является colourAtCurrentPixel == colourToReplace, которое не работает со смешанными пикселями на линиях. (цвета RGB)

Я хотел бы добавить параметр сглаживания/порога, как в Photoshop и других сложных инструментах, но каков алгоритм определения равенства/расстояния между двумя цветами?

if (match(pixel(x,y), colourToReplace) setpixel(x,y,colourToReplaceWith)

Как заполнить match()?

Здесь изображение (слева ситуация, справа разыскивается)

http://www.freeimagehosting.net/uploads/6aa7b4ad53.png

Вот мой текущий полный код:

            var b:BitmapData = settings.background;
            b.lock();

            var from:uint = b.getPixel(x,y);


            var q:Array = [];


            var xx:int;
            var yy:int;
            var w:int = b.width;
            var h:int = b.height;
            q.push(y*w + x);
            while (q.length != 0) {
                var xy:int = q.shift();
                xx = xy % w;
                yy = (xy - xx) / w;
                if (b.getPixel(xx,yy) == from) { //<- want to replace this line
                    b.setPixel(xx,yy,to);
                    if (xx != 0) q.push(xy-1);
                    if (xx != w-1) q.push(xy+1);
                    if (yy != 0) q.push(xy-w);
                    if (yy != h-1) q.push(xy+w);
                }
            }
            b.unlock(null);

person Bart van Heukelom    schedule 31.03.2010    source источник


Ответы (2)


ну, я думаю, самый естественный подход - вычислить разницу между цветами. для достижения разумного значения следует вычислить разницу на канал. не проверял, но должно работать следующее:

const perChanThreshold:uint = 5;
const overallThreshold:uint = perChanThreshold * perChanThreshold * 3;
function match(source:uint, target:uint):Boolean {
    var diff:uint = 0, chanDiff:uint;
    for (var i:int = 0; i < 3; i++) {
        chanDiff = (source >> (i * 8)) & 0xFF;
        diff += chanDiff * chanDiff;
    }
    return diff <= overallThreshold;
}
person back2dos    schedule 31.03.2010
comment
Спасибо, сейчас делаю что-то подобное. Смотри мой ответ - person Bart van Heukelom; 31.03.2010

Сделал что-то работающее:

                c = b.getPixel(xx,yy);
                if (c == to) continue;
                if (c != from) d = 
                    Math.pow(f1 - (c & 0xFF), 2) +
                    Math.pow(f2 - (c >> 8 & 0xFF), 2) +
                    Math.pow(f3 - (c >> 16 & 0xFF), 2)
                if (c == from || d < tres) {
person Bart van Heukelom    schedule 31.03.2010
comment
да, должно работать идеально. однако обратите внимание, что это не будет работать очень хорошо, если вы будете вызывать его часто (что может быть в случае заливки). Переход туда и обратно между числами с плавающей запятой и целыми числами не очень быстр, равно как и вызовы статических функций. - person back2dos; 31.03.2010