PDA

Просмотр полной версии : Как правильно сложить BitmapData нужным способом?


DEAFFF
06.06.2008, 15:18
Привет!

Есть два объекта BitmapData одинакового размера(bmp1 и bmp2). На них что то нарисовано, это может быть и картинка, не важно.

Нужно получить третий объект BitmapData (bmp3) являющийся результатом сложения двух первых, с таким условием:


if(bmp2.getPixel(x,y) > bmp1.getPixel(x,y))
{
bmp3.setPixel(x,y, bmp2.getPixel(x,y));
}


Можно конечно без проблем пробежаться по всем точкам, но это будет очень медленно.

Меня интересует способ сложения BitmapData , будь то комбинация BlendMode или фильтр... или бог знает что :)

Заранее спасибо за ответы!

Psycho Tiger
06.06.2008, 15:53
Отрисовать в 3 бмп дату сначало 1, потом 2... или 2, потом 1...
Отрисовывается методом draw

DEAFFF
06.06.2008, 15:59
методом draw будет складываться по альфаканалу, а мне нужно по цвету

т.е. если у меня


color1 = 0xff0000;
color2 = 0xffff00;


то результатом будет



color3 = color2; //т.к. color2 > color1


Нужен какой то другой способ, более быстрый.

Alex Lexcuk
06.06.2008, 16:23
грузим рисунки
http://dnadillo.dn.ua/images/imag/magna_carta_131.JPG
http://dnadillo.dn.ua/images/imag/magna_carta_127.JPG
в бит мапу
ставим бленд моде blendMode="darken";
складываем их
http://dnadillo.dn.ua/fla/in-2-1.swf
http://dnadillo.dn.ua/fla/in-2-1.zip

DEAFFF
06.06.2008, 20:56
не помогает...
blendMode он сравнивает по каналам... а мне нужно что бы сразу по всему числу цвета...

MerlinTwi
07.06.2008, 11:05
Если по точкам медленно, то можно по байтовому массиву. Надо уточнить, какое время обработки вас устроит.
Здесь в тесте, для двух картинок размером 2400x2400 время генерации результирующей: 2814 мс.

var bmp1:BitmapData = new TestBmp1(0,0); //2400x2400
var bmp2:BitmapData = new TestBmp2(0,0); //2400x2400

var tm:int = getTimer();

var b1:ByteArray = bmp1.getPixels(bmp1.rect);
var b2:ByteArray = bmp2.getPixels(bmp2.rect);
var b3:ByteArray = new ByteArray();

b1.position=0;
b2.position=0;
var len:int = b1.bytesAvailable / 4;
while (len--) {
var c1:uint = b1.readUnsignedInt();
var c2:uint = b2.readUnsignedInt();
b3.writeUnsignedInt((c1 & 0xFFFFFF) > (c2 & 0xFFFFFF) ? c1 : c2); // не учитывая alpha
}
var bmp3:BitmapData = new BitmapData(bmp1.width, bmp1.height);
b3.position = 0;
bmp3.setPixels(bmp3.rect, b3);

trace("time:", getTimer()-tm); // time: 2814

addChild(new Bitmap(bmp3));

iNils
07.06.2008, 12:02
blendMode он сравнивает по каналам... а мне нужно что бы сразу по всему числу цвета...А смысл этой затеи можно узнать? Ведь зеленый цвет всегда больше синего, а красный больше зеленого и результирующий битмап будет более красным, меньше зеленым и еще меньше синим.

DEAFFF
07.06.2008, 15:13
Если по точкам медленно, то можно по байтовому массиву. Надо уточнить, какое время обработки вас устроит.
Здесь в тесте, для двух картинок размером 2400x2400 время генерации результирующей: 2814 мс.


Да интересный вариант! Но все равно тут перебор а он кушает очень много времени!

DEAFFF
07.06.2008, 15:24
А смысл этой затеи можно узнать? Ведь зеленый цвет всегда больше синего, а красный больше зеленого и результирующий битмап будет более красным, меньше зеленым и еще меньше синим.

Мне нужно это, не с точки зрения изображений и цветов или фильтров или смешиваний.

Суть такая есть два массива числовых данных, надо получить третий массив по указанному выше условию...
Просто эти данные рисуются в битмап дате... так быстрее их генерить!
А вот сравнивать не очень быстро...

mikleb
09.06.2008, 13:58
Хм у меня получилось получить 3й битмап где то в 4-5 раз быстрее чем через byteArray.

iNils
09.06.2008, 14:48
mikleb, запятые придумали, чтобы они облегчали читать текст, а не для того, чтобы их пропускать.

О логике blendMode (http://murejib.com/?p=49).

DEAFFF
09.06.2008, 15:11
как????

mikleb
09.06.2008, 15:13
как????

Через бленд моды:)

Вот код


Map1 = new BitmapData(Cmp1Map.width, Cmp1Map.height);
h1 = new BitmapData(Cmp1Map.width, Cmp1Map.height);
h2 = new BitmapData(Cmp1Map.width, Cmp1Map.height);
h = new BitmapData(Cmp1Map.width, Cmp1Map.height);
var redArray:Array = new Array(256);
var greenArray:Array = new Array(256);
var blueArray:Array = new Array(256);

var redArray2:Array = new Array(256);
var greenArray2:Array = new Array(256);
var blueArray2:Array = new Array(256);

redArray[0] = 0x00000000; greenArray[0] = 0x00000000; blueArray[0] = 0x00000000;
redArray2[0] = 0x00FF0000; greenArray2[0] = 0x0000FF00; blueArray2[0] = 0x000000FF;
for (i = 1; i <= 255; i++)
{
redArray[i] = 0x00FF0000; greenArray[i] = 0x0000FF00; blueArray[i] = 0x000000FF;
redArray2[i] = 0x00000000; greenArray2[i] = 0x00000000; blueArray2[i] = 0x00000000;
}


t = getTimer();

h1.copyPixels(Cmp2Map, new Rectangle (0,0,h1.width,h1.height),new Point(0,0));
h1.draw (Cmp1Map, null, null, "subtract");
h1.paletteMap(h1, new Rectangle (0, 0, h1.width, h1.height), new Point(0, 0), redArray, greenArray, blueArray);

h2.copyPixels(Cmp1Map, new Rectangle (0,0,h2.width,h2.height),new Point(0,0));
h2.draw (Cmp2Map, null, null, "subtract");
h2.paletteMap(h2, new Rectangle (0, 0, h2.width, h2.height), new Point(0, 0), redArray2, greenArray2, blueArray2);

h.copyChannel(h1, new Rectangle (0, 0, h1.width, h1.height), new Point (0, 0), BitmapDataChannel.BLUE, BitmapDataChannel.GREEN);
h.draw(h2, null, null, "darken");
h.draw(h1, null, null, "lighten");

h.copyChannel(h, new Rectangle (0, 0, h.width, h.height), new Point (0, 0), BitmapDataChannel.GREEN, BitmapDataChannel.RED);
h.draw(h2, null, null, "darken");
h.draw(h1, null, null, "lighten");

h.copyChannel(h, new Rectangle (0, 0, h.width, h.height), new Point (0, 0), BitmapDataChannel.RED, BitmapDataChannel.ALPHA);

Map1 = Cmp1Map.clone();
Map1.copyPixels(Cmp2Map, new Rectangle (0, 0, h.width, h.height), new Point (0, 0), h, null, true);

trace (getTimer() - t);


Сmp1Map, Cmp2Map - две исходные мапы
Map1 - результат сравнения
h,h1,h2 - вспомогательные мапы.

iNils
09.06.2008, 15:50
mikleb, надо использовать кнопку http://www.flasher.ru/forum/images/russian/style3/buttons/edit.gif, а не создавать несколько сообщений подряд.

DEAFFF
09.06.2008, 17:27
mikleb спасибо! ваш способ наиболее быстрый!

mikleb
09.06.2008, 20:43
mikleb спасибо! ваш способ наиболее быстрый!
Незачто:)
Но только тут 24битные числа, для 32 битных будет раза в два тормазнее потому что subtract не вычитает альфу, и придется дополнительно получить маски для > и >= альфы.

DEAFFF
10.06.2008, 11:57
да нет все нормально мне хватает 24 битных!
Вот тока не мог бы ты объяснить что это за метод такой ?
Как он работает?

mikleb
10.06.2008, 15:25
да нет все нормально мне хватает 24 битных!
Вот тока не мог бы ты объяснить что это за метод такой ?
Как он работает?
Нужно получить маску где числа RGB от второй картинки > RGB от первой.
Сперва я получил 3 маски: R от второй > чем R от первой картинки, и тоже самое для G и B, эти три маски удобно хранить в одной картинке. (там где > будет 255 а где <= будет 0). Это легко реализовать с помошью blendmode subtract. Т.е вычтаем из второй картинки первую там где вторая > будет не ноль. Ну а потом с помощью палитры все не нулевые числа(компоненты цвета) переводим в 255. Эти три маски хранятся в h1.
Еще нужно получить такие же маски но только для >=. Ясно что >= это отрицание к <, поэтому делаю тоже самое только картинки меняю местами, ну и палитра инверснутая (там где было 255 делаю 0 там где было 0 делаю 255). Это будет h2.

Пусть теперь надо сравнить картинки только по GB.
G2B2 > G1B1 Если:
G2 > G1 или G1 = G2 и B2>B1 это эквивалентно
G2 > G1 или G2 >= G1 и B2>B1
Получается чтобы получить маску где GB от второй картинки больше GB от первой нужно объединить маску где G2>G1 c маской где G2>=G1 и B2>B1. Вторая маска (где G2>=G1 и B2>B1) это пересечение маски G2>=G1 и маски B2>B1.
Объединение масок делается с помощью blendmode lighten (максимум)
Пересечение масок делается с помощью blendmode darken (минимум).
Ну вот т.е сперва перевожу маску B2>B1 в G компоненту ( c помощью copychannel) потом беру darken с маской G2>=G1 а потом беру lighten с маской где G2>G1.
Дальше аналогично.

DEAFFF
10.06.2008, 18:00
Да оригинальный способ! Спасибо за объяснение!

mikleb
10.06.2008, 19:00
Вобщем можно намного проще сделать, и будет быстре чем в лоб в 7-8 раз:).

DEAFFF
14.06.2008, 22:17
интересно а как тут еще быстрее?

mikleb
15.06.2008, 03:57
Вот код:

redArray[0] = 0x00000000;
greenArray[0] = 0x00000000;
blueArray[0] = 0x00000000;
redArray2[0] = 0x00000000;
greenArray2[0] = 0x00000000;
blueArray2[0] = 0x00000000;
alphaArray2[0] = 0x00000000;


for (i = 1; i <= 255; i++)
{
redArray[i] = 0x00400000;
greenArray[i] = 0x00200000;
blueArray[i] = 0x00100000;
redArray2[i] = 0xFF000000;
greenArray2[i] = 0x00000000;
blueArray2[i] = 0x00000000;
alphaArray2[i] = 0x00000000;
}

t1 = getTimer();
h1.copyPixels(Cmp2Map, h1.rect,new Point(0,0));
h1.draw (Cmp1Map, null, null, "subtract");
h1.paletteMap(h1, h1.rect, new Point(0, 0), redArray, greenArray, blueArray);

h2.copyPixels(Cmp1Map, h2.rect,new Point(0,0));
h2.draw (Cmp2Map, null, null, "subtract");
h2.paletteMap(h2, h2.rect, new Point(0, 0), redArray, greenArray, blueArray);

h1.draw(h2, null, null, "subtract");
h1.paletteMap(h1, h1.rect, new Point(0, 0), redArray2,greenArray2,blueArray2,alphaArray2);


Map1 = Cmp1Map.clone();
Map1.copyPixels(Cmp2Map, h1.rect, new Point (0, 0), h1, null, true);

Если интересно могу объяснить, что там происходит:)