PDA

Просмотр полной версии : быстрая попиксельная обработка bitmapData


miramax
25.10.2006, 16:33
Так и хотел назвать тему "ПОМОГИТЕ !!!!!", "ГОРЮ !!!!!!"," СРОКИ ЛЕТЯТ!!!!", "РЕБЯТА ПОДМОГНИТЕ".:)
Вобщем есть объект bitmapData. Составляется из других методом copyPixels при каждом кадре заново. По битмапдате разбросаны разноцветные пикселы.


t = getTimer();
var b:BitmapData = new BitmapData(2000, 2000);
//можно произвести какие-то действия по заливке битмап даты разными пикслеми. copyPixels из других битмапов и т.п.
var ar:Array = []
//назначаем массив с парами цветов которые будем заменять
obj = {}
obj.o = 0xff54d645;
obj.n = 0x2222dd33;
ar.push(obj)
//и так раз 100
//нужно произвести какие-то манипуляции по замене страых цветов на новые
trace(getTimer()-t) ///нужно меньше 30

Я нашёл три основных решения
1. threshold - как нельзя лучше подходит. Но эта функция слишком медленная. И ищет по одному цвету. Т.е. перерывает весь массив пикселов и заменяет требуемый цвет на другой. Вот если бы в одной функции задать поиск и замену сразу нескольких цветов..... Тогда скорость наверное была бы приемлимой.
2. Последовательный перебор и замена пикселов методами getPixel и setPixel. Картинка 1024*768 обрабатывается > 700 милисекунд. Если создать наследника класса bitmapData и вызывать наследованные функции то скорость немного подрастает.
3. Получить методом getPixels объект ByteArray и по байтово заменить все цвета. Но сам вызов методов setPixels (имея готовый ByteArray) намного медленне чем copyPixels.
По третьему пункту см. топик
http://flasher.ru/forum/showthread.php?t=86918
Вобщем хочу обработать пикселы со скоростью функции copyPixels. Которая очень быстро копирует пикселы. Возможно есть какие-то инкапсулированные возможности bitmapData? Например что бы расширить функцию threshold. Она работает только с одним цветом за время вызова. Но похоже обрабатывает все пикселы в поисках нужного цвета.
Было бы здорово если эта функция заменяла бы несколько цветов, не обрабатывая каждый раз все пикселы заново.

etc
25.10.2006, 16:41
Что-то мне подсказывает, что есть только первый вариант. Остальные явно медленнее…

Кстати, 700 мс не так уж и много.

miramax
25.10.2006, 16:45
Что-то мне подсказывает, что есть только первый вариант. Остальные явно медленнее…

Кстати, 700 мс не так уж и много.
Допустим есть битмапдата в которой всего один пиксел цвета ffffff а все остальные 000000. И в первом и во втором случае время обработки одинаковое, сл-но перебираются все пикселы. Как бы заставить функцию менять не один цвет а несколько?

MerlinTwi
25.10.2006, 16:58
Распиши конкретно задачу, возможно будут другие решения кроме копирования пикселей в лоб, как вариант создать несколько битмапов и накладывать друг на друга.

miramax
25.10.2006, 17:06
Распиши конкретно задачу, возможно будут другие решения кроме копирования пикселей в лоб, как вариант создать несколько битмапов и накладывать друг на друга.Это карта с битмап кэшированием. Есть эффект наведения и выделения страны, области и т.п. На картинке все страны имеют уникальный цвет, но в зависимости от того выделена страна или нет эти пикселы меняются на зелёный или на жёлтый. Из-за плавного зума и пана необходимо прорисовывать такую картинку довольно быстро. Вот именно с этой заменой возникают проблемы. Все методы что я пробовал - слишком медленные.
В принципе есть и другие пути решения, кроме присвоемия и замены уникальных цветов. Но этот самый короткий и удобный.

etc
25.10.2006, 17:12
А floodFill не катит?

miramax
25.10.2006, 17:29
Страна может быть извилистой, несколько раз выезжать из-за экрана. На стране, сверху есть реки. floodFill со всех сторон опробовал, подходит только частично и только для простых карт. Может просто я не могу найти правильного пути использования flooFill?.
Неизвестно где и какие пикселы появятся.

etc
25.10.2006, 17:30
Сделай карту рек отдельно и накладывай сверху.

Самым нижним слоем будет карта, на которой только обведены страны.

Можно и моря выше наложить. Т.е. склеить всё copyPixels-ом.

MerlinTwi
25.10.2006, 17:30
Что-то я не понял, почему
> Из-за плавного зума и пана необходимо прорисовывать такую картинку довольно быстро.
разве картинка меняется не при выделении страны? Зачем ее перерисовывать при зуме?

iNils
25.10.2006, 17:31
Мне интересно, а откуда copyPixels берет начальную инфу которая картинку формирует?

MerlinTwi
25.10.2006, 17:36
Можно в самом начале, при загрузке этой карты, взять ее getPixels, пробежаться по нему и составить маску для каждой страны. После чего использовать эту маску в copyPixels как alphaBitmapData.

miramax
25.10.2006, 17:37
Сделай карту рек отдельно и накладывай сверху.

Самым нижним слоем будет карта, на которой только обведены страны.

Можно и моря выше наложить. Т.е. склеить всё copyPixels-ом.
Карта очень большая, разбита на кусочки по битмапам. Страна может залазить на один кусочек в нескольких местах. х и у для floofFill не определить.

miramax
25.10.2006, 17:40
Можно в самом начале, при загрузке этой карты, взять ее getPixels, пробежаться по нему и составить маску для каждой страны. После чего использовать эту маску в copyPixels как alphaBitmapData.Стран много, вызов 100 раз подряд copyPixels убивает проц. Этот способ я сейчас и юзаю. Но очень не доволен им, тк. сейчас у меня 20 тсран еле обрабатывается.

miramax
25.10.2006, 17:43
Что-то я не понял, почему
> Из-за плавного зума и пана необходимо прорисовывать такую картинку довольно быстро.
разве картинка меняется не при выделении страны? Зачем ее перерисовывать при зуме?
Картинка генерится из векторной карты. Под каждый зум своя серия битмапов. Кстати говоря они кэширутся перед запуском программы. И памяти флеш плеер кушает около 300 мб ( ну во всяком случае на моей оперативке). Под каждый зум есть массив битмапов на которые разбита закэшированная карта. Потом во время пана определяются битмапы которые нужно совместить и методом copyPixels собрать ещё в один битмап , который будет показан на мониторе

etc
25.10.2006, 17:43
Ну тогда остаётся только threshold :)

MerlinTwi
25.10.2006, 17:54
Можно скриншот, чтобы нормально все себе представить, что получается в итоге.
Выделена может быть только одна страна?

Badim
25.10.2006, 18:49
Картинка генерится из векторной карты.
ну тогда нельзя ли сгенерить и еще отдельный битмап для каждой страны(битмап, размерами со страну, глобальные координаты начала битмапа)?
и при наведении показывать этот битмап в координатах где надо?

ну или в векторной форме все это делать, смотря какие исходные данные.

miramax
27.10.2006, 07:03
Остановился на следующем решении.
Метод floodFill самый быстрый. Но вот определить места где им заливать - не просто.
Так вот, перед тем как показывать картинку пользвателю нужно определить точки для floodFill из которых надо заливать.
Для этого нужно создать копию юитмап даты. И делать следущее:
Нашли пиксел нужного цвета, записали его координты в массив, залили floodFill, потом опять на битмапдате ищем пиксел нужного цвета заносим в массив и заливаем. Всё, теперь у нас есть массив точек , и при любом удобном случае иы можем поменять все пикселы одного цвета на любой другой цвет поочерёдно сделав floodFill для каждой точки из массива.
Для определения точек под floodFill, на первом этапе работы желатьльно рекурсивно юзать getColorBoundsRect. Сначала надо получить этот прямоугольник на все битмапдате, попробовать залить центр, если пиксел в центре искомого цвета. Если после заливки размеры getColorBoundsRect не изменились - разбиваем полученный прямоугольник на четыре части и вносим каждую часть в новую битмапдату и продолжаем тестировать центры прямоугольников цветовых границ далее. Иначе последовательный перебор getPixel займёт в несколько десятков раз больше времени, т.к. заливаются довольно обширные зоны. Хотя если у вас картинка сложна, например jpg фотография, то лучше юзать getPixel )))
Время флуд фила зависит от размера заливаемой области. Конечно залить методом floodFill одноцветную битмапдату 2880 на 2880 в один цвет займёт больше времени чем применить threshold для замены цвета. Но если нужно залить 100 мелких областей на большой плоскости, то threshold проиграет, т.к. он каждый раз проверяет всю битмап дату на наличей нужных пикселов и делает много лишней работы.

dantist86
29.10.2006, 02:47
Сегодня шеф демонстрировал гладкий zoom & pan карты без потери качества. Скорость чуть меньше чем при сниженном _quality, но мягкость движения хорошая. Не знаю этими методами или по другому он решал задачу, но прогресс есть.
Сказал, что движек еще не универсальный, но на Рождество закончит это дело и будем менять все демонстрашки на сайте и поднимать стоимость. :)

miramax
29.10.2006, 07:08
Сегодня шеф демонстрировал гладкий zoom & pan карты без потери качества. Скорость чуть меньше чем при сниженном _quality, но мягкость движения хорошая. Не знаю этими методами или по другому он решал задачу, но прогресс есть.
Сказал, что движек еще не универсальный, но на Рождество закончит это дело и будем менять все демонстрашки на сайте и поднимать стоимость. :)
Хм.... Давай тогда покажем всем, что у кого получится :)

dantist86
29.10.2006, 13:48
Я не решаю этих вопросов. Но раз менять демо на сайте, значит показывать будем.
ЗЫ. О стоимости, вот эти Амеры действительно продают свою продукцию по 5-10К. http://mapnetwork.com/.
ЗЫ1. Показали вариант без потери качества одному текущему клиенту - он не обратил на это никакого внимания. Похоже, что часть народа как брала недорогие старые варианты, так и будет брать.

__i
30.10.2006, 12:12
а на AS3|flex , не хотите попробывать?.
картинка 800х600 если по ней тупо пройтись getPixel и заменить какойто цвет на другой setPixel занимает приблизительно 70-150 мс (в зависимости от количетва замененых пикселей). Помоемому круто %)

dantist86
30.10.2006, 14:39
miramax похоже там и работает.
У нас же конвейерная продукция и мы не хотим пока терять клиента, который бурчит : " 9-й плейер не установлен в браузерах и половина пользователей не будут его подгружать".
После Нового Года планируем поставлять два варианта на АС1 и АС3 ( АС2 тормозит, у нас по крайней мере ).

etc
30.10.2006, 15:15
АС2 тормозит
Его не существует.
Или вы просто не умеете готовить :D

Базиль
31.10.2006, 18:40
А почему бы во флэше не использовать ВЕКТОРНУЮ карту? Нафига козе баян?

miramax
31.10.2006, 19:38
А почему бы во флэше не использовать ВЕКТОРНУЮ карту? Нафига козе баян?
А ты попробуй повертеть в плеере векторный рисунок кб на 150 ))))

Badim
07.11.2006, 18:55
casheAsBitmap, мне помогло.

miramax
07.11.2006, 19:07
casheAsBitmap, мне помогло.
Ага, а теперь сделай эту фиговину размером 20 000 на 12 000 и сделай на ней области реагирующие на маус овер изменением цвета. Без существенного ущерба производительности.

ALiEN_
18.07.2007, 21:56
Вобщем-то может уже и поздно сюда постить, но все таки я решил написать, так как больше не нашел нигде описанного способа =)

Я давно еще, когда компьютеры были 286 - самые продвинутые =) баловался на турбосях, и чуток на асме. И проблемы были те же - быстро сменить цвет пикселя можно было несколькими способами. И самый быстрый способ был - это работа с палитрой. т.е. мы берем один регистр палитры, правим его и вуаля, целый массив пикселей мгновенно меняет свой цвет.

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

Вобщем я тут подумал, может ли такая конструкция работать во флеше? Я решил поискать на эту тему в гугле, и не нашел ничего. На форумах тоже не нашел.

Вобщем я написал небольшой тестик, и! Ура, этот способ в среднем в 10-20 раз быстрее, самого быстрого способа известного всем флешерам =))) Прицепляю тестик здесь (http://***********/1472549).

Странно, почему еще никто не догадался таким образом менять цвет во Flash =)

P.S. Демка открывается браузером. После открытия, надо тыкнуть на планету.

iNils
19.07.2007, 07:44
Вы про paletteMap?

ALiEN_
20.07.2007, 16:51
да, именно.