Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   метод getPixels возвращающий ByteArray (http://www.flasher.ru/forum/showthread.php?t=86918)

miramax 25.10.2006 16:11

метод getPixels возвращающий ByteArray
 
В АС 3 метод getPixels возвращает ByteArray. К тому же появились методы для работы с байтами.
Что мы можем изменить в полученном массиве? Как организован возвращаемый этой функцией массив?
Методы getPixel и setPixel слишком медленные что бы обработать большое количество пикселов, Можно ли манипулировать пикслемами в массиве что возвращает функция getPixels ? Как я понимаю обработать массив байтов можно намного быстрее чем последовательно вызывать функции getPixel и setPixel. И ещё
почему метод copyPixels в несколько раз быстрее чем вызов getPixels и setPixels у двух растровых объектов?

etc 25.10.2006 16:23

А что тебя конкретно интересует? Ты можешь изменить любой байт, если нужно. Или нужно послать массив байтов на сервер?

Код:

import flash.utils.ByteArray;
import flash.geom.Rectangle;
import flash.display.BitmapData;
var rect:Rectangle = new Rectangle(0,0,5,5);
var bitmap:BitmapData = new BitmapData(10,10,false,0xFF0000);
var byteArray:ByteArray = bitmap.getPixels(rect);
trace(byteArray[0],byteArray[1],byteArray[2]); // 255 255 0


miramax 25.10.2006 16:34

Цитата:

Сообщение от __etc
А что тебя конкретно интересует? Ты можешь изменить любой байт, если нужно. Или нужно послать массив байтов на сервер?

http://flasher.ru/forum/showthread.p...417#post581417
Хотелось бы заменить пикселы определённых цветов на пикселы других цветов. Только очень быстро

MerlinTwi 25.10.2006 16:39

Как я понимаю, вопрос был в каком формате хранятся пиксели в ByteArray.
Аналогично этому:
Код:

var ar:Array = new Array();
for (var y:int=0; y<bitmap.height; y++) {
        for (var x:int=0; x<bitmap.width; x++) {
                ar.push(bitmap.getPixel32(x,y));
        }
}

И поскольку в byteArray пиксели записываются как unsigned integer, то читах их следует не побайтно, а с помощью readUnsignedInt:
Код:

byteArray.position=0;
while (byteArray.position < byteArray.length) {
        trace(byteArray.readUnsignedInt().toString(16));
}

А то, что copyPixels работает быстрее надо просто принять как факт, скорее всего там происходит тупо копирование куска памяти в то время как в getPixels и setPixels создание нового объекта ByteArray с последовательным преобразованием пикселей туда обратно.

miramax 27.10.2006 06:26

Отлично :)
А как мне определить координаты пиксела? относительно прямоугольника из которого я взял эти пикселы.

MerlinTwi 27.10.2006 12:03

О! Появился. А я уж, по затянувшемуся молчанию решил, что тебя за сорванные сроки с картой заказчик порешил :)

Координаты просто, на каждую точку 4 байта, значит надо позиционироваться на 4*(y*ширина_прямоугольника + x) и читать значение.
Код:

// заливаем все красным
var bitmap:BitmapData = new BitmapData(10,10,false,0xFF0000);
// ставим синюю точку в 2:3
bitmap.setPixel(2,3,0x0000FF);
// считываем ByteArray прямоугольника 5 на 5
var rect:Rectangle = new Rectangle(0,0,5,5);
var byteArray:ByteArray = bitmap.getPixels(rect);
// показываем цвет точки в 2:3
trace(getPixel(2,3, byteArray,rect).toString(16));
// и на всякий случай в 3:3
trace(getPixel(3,3, byteArray,rect).toString(16));

// возвращает 32 цвет точки
function getPixel(x:Number, y:Number, b:ByteArray, r:Rectangle):Number {
        b.position = (y*r.width + x)*4;
        return b.readUnsignedInt();
}


miramax 27.10.2006 20:56

Цитата:

Сообщение от MerlinTwi
Координаты просто, на каждую точку 4 байта, значит надо позиционироваться на 4*(y*ширина_прямоугольника + x) и читать значение.

Получается ByteArray не несёт информации о размерах содержимого прямоугольника с пикселами (ширина, высота):confused:

etc 27.10.2006 21:05

miramax, а откуда ж там эти данные возьмутся?

Nirth 28.10.2006 20:18

Цитата:

Получается ByteArray не несёт информации о размерах содержимого прямоугольника с пикселами (ширина, высота)
У каждого рисунка, есть заголовок, где пишется всякая дребедень вроде кол-ва бит на пиксель, ширина высота, тэги, комментарии(если формат поддерживает).

INK• 16.11.2006 06:55

http://ink.envisionext.com/swf2png/
я тут запостил отчёт о сохранение картинки на сервер. т.е. BitmapData в byteArray (PNG картинка) и отправка готовой картинки для записи на сервер.

Dendroid 16.11.2006 13:55

Цитата:

Сообщение от INK•
http://ink.envisionext.com/swf2png/
я тут запостил отчёт о сохранение картинки на сервер. т.е. BitmapData в byteArray (PNG картинка) и отправка готовой картинки для записи на сервер.

Отличная статья. :)

Sneg 16.11.2006 16:11

2INK•: Спасибо, познавательно :)

vapes 27.11.2006 20:48

Может кто знает как лучше и рациональней выводить картинку(представленную byte array) по случайным пикселам? И за скока она вся прорисуется?

miramax 27.11.2006 21:12

Цитата:

Сообщение от vapes
Может кто знает как лучше и рациональней выводить картинку(представленную byte array) по случайным пикселам? И за скока она вся прорисуется?

метод setPixels() - специально предназначен для выводва byteArray в битмапдату.

vapes 28.11.2006 11:50

Как с помощью setPixels вывести 100 случайных пикселей в картинке?

etc 28.11.2006 14:10

vapes, для этого есть noise

vapes 28.11.2006 17:04

Написал я вот такую штуку:
Код:

private function createArray ():void{
                var myBitmapData:BitmapData = new  BitmapData(this.WIDTH, this.HEIGHT,true);
            myBitmapData.draw(this.imageContainer);
            var mn:int= 0;
            var j:int=0;
                        for (var i:int = 0; i < this.WIDTH*this.HEIGHT; i++){
                                        if ((i%this.WIDTH==0)&&(i!=0)) {mn+=this.WIDTH};
                                    this.myarray[i] = new Object();
                                        this.myarray[i].x=i-mn;//coord x of image array
                                        this.myarray[i].y=j;//coord y of image array
                                        this.myarray[i].color=myBitmapData.getPixel(i-mn, j);//get pixels from image
                                        if ((i-mn==0)&&(i!=0)){j++};                                       
                        }       
                                        this.showImages();                       
        }
        private function showImages():void{
                var myTimer:Timer = new Timer(1, 1895);
            myTimer.addEventListener("timer", showImage);
            myTimer.start();
        }       
        private function showImage(event:TimerEvent):void{
                var myBitmapData:BitmapData = new  BitmapData(this.WIDTH, this.HEIGHT,true);
                var pixelNumber:Number;
                myBitmapData.draw(this.bmp.bitmapData);
                        for (var i:int = 0;i<1000;i++){
                        pixelNumber=Math.round(Math.random()*this.myarray.length);
                        myBitmapData.setPixel(this.myarray[pixelNumber].x,this.myarray[pixelNumber].y,this.myarray[pixelNumber].color);       
                        this.myarray.splice(pixelNumber-1,1);
                        }
                this.bmp.bitmapData=myBitmapData;
        }

педалит просто ужас(правда картинка 500х379) Подскажите как лучше сделать?

etc 28.11.2006 17:06

А зачем ты создал массив?

vapes 28.11.2006 17:13

Чтобы выбирать потом из него случайные пикселы и выводить

vapes 28.11.2006 17:15

Смысл в том , что надо выводить 1000 случайных пикселей картинки за 1/10 сек

etc 28.11.2006 17:31

А зачем их копировать из картинки в массив, чтобы потом в другую картинку вставлять? Не проще напрямую getPixel из одной и setPixel в другую?

vapes 28.11.2006 17:52

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

etc 28.11.2006 17:53

Всё, у меня вывих мозга.

vapes 28.11.2006 18:14

Ух ты убираешь: this.myarray.splice(pixelNumber-1,1);
и производительность в раз 5 возрастает

vapes 28.11.2006 18:15

теперь вопрос:как избежать повторения пикселов?

MerlinTwi 28.11.2006 19:26

Цитата:

Сообщение от vapes
теперь вопрос:как избежать повторения пикселов?

Если я правильно понял задачу, то я бы сделал так:
Код:

// массив с точками
var ar:Array = new Array();
// размеры картинки
var bitmapWidth:Number = 100;
var bitmapHeight:Number = 100;
// собираем в массив координаты всех точек
for (var i:Number=0; i<bitmapHeight; i++) {
        for (var j:Number=0; j<bitmapWidth; j++) ar.push(new Point(j, i));
}

// перетасовываем массив по алгоритму Fisher-Yates
var a:Number = ar.length;
var b:Point, c:Number;
while(a--) {
        c = Math.floor(Math.random()*(a+1));
        b = ar[c];
        ar[c] = ar[a];
        ar[a] = b;
};
 
// Тестируем что получилось

// Сделаем текстовые картинки
var myBitmapData:BitmapData = new BitmapData(bitmapWidth, bitmapHeight, false, 0xFF0000);
var resultBitmapData:BitmapData = new BitmapData(bitmapWidth, bitmapHeight, false, 0xFF);
addChild(new Bitmap(resultBitmapData))
// выводим случайные точки по enterFrame
addEventListener(Event.ENTER_FRAME, onDraw);

function onDraw(e:Event):void {
        var n:int = 200; // выводим 200 точек
        while (n-- && ar.length) {
                // берем следующую точку
                var pixel:Point = ar.pop();
                // рисуем ее
                trace("Draw:", pixel.x, pixel.y);
                resultBitmapData.setPixel(pixel.x, pixel.y, myBitmapData.getPixel(pixel.x, pixel.y));
        }
}


__i 28.11.2006 19:55

Цитата:

Сообщение от MerlinTwi
Если я правильно понял задачу, то я бы сделал так:
Код:

...............
function onDraw(e:Event):void {
        var n:int = 200; // выводим 200 точек
        while (n-- && ar.length) {
                // берем следующую точку
                var pixel:Point = ar.pop();
                // рисуем ее
                trace("Draw:", pixel.x, pixel.y);
                resultBitmapData.setPixel(pixel.x, pixel.y, myBitmapData.getPixel(pixel.x, pixel.y));
        }
}


кхм тоже правильно, но не рационально... именно в этой части
Код:

        var n:int = 200; // выводим 200 точек
        while (n-- && ar.length) {
                // берем следующую точку
                var pixel:Point = ar.pop();

лишний поп, лишнее вычисление ar.length, ......

в идеале для скорости было красиво просто хранить начальный индекс в массиве и количество выводимых точек.

Код:

var currentPos : number = 0;
........
var countPoint : number  =  ((currentPos+200)> ar.length) ? 200 : ar.length-currentPos
var pixel:Point;
while (countPoint >0) {
 pixel = ar[countPoint + currentPos ];
trace("Draw:", pixel.x, pixel.y);
                resultBitmapData.setPixel(pixel.x, pixel.y, myBitmapData.getPixel(pixel.x, pixel.y));
countPoint--;
}
currentPos+=countPoint ;
if (currentPos>ar.length) trace ("the end");
)

ну а в самом конце просто бахать наш массив и все

miramax 28.11.2006 20:22

юзайте byteArray для хранения больших массивов чисел - там сумасшедшая скорость....

MerlinTwi 28.11.2006 22:32

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

resultBitmapData.lock();
while (n-- && ar.length) {
 ...
}
resultBitmapData.unlock();

P.S.
Кстати, можно устроить соревнование на создание наиболее быстрого алгоритма для решения этой задачи, есть желающие? ;)

miramax 28.11.2006 22:40

Цитата:

Сообщение от MerlinTwi
P.S.
Кстати, можно устроить соревнование на создание наиболее быстрого алгоритма для решения этой задачи, есть желающие? ;)

Если будут хорошие идеи, обязательно выложу здесь :)

MerlinTwi 28.11.2006 23:25

Думал заюзать BitmapData.noise, чтобы создать рандомные точки для копирования, а он оказывается довольно тормознутый (функция ниже работает в 2раза медленней, чем предложеный вариант выше), но эффект получился довольно красивый! Точки не сразу ставятся на свои места, а плавно проявляются.

Код:

var cnt:int = 0;
function onDraw2(e:Event):void {
        var alphaBitmap:BitmapData = new BitmapData(bitmapWidth, bitmapHeight, true);
        alphaBitmap.noise(cnt++, 0,50, BitmapDataChannel.ALPHA);
       
        resultBitmapData.copyPixels(myBitmapData, new Rectangle(0,0, bitmapWidth, bitmapHeight),
                new Point(0,0), alphaBitmap,new Point(0,0), false);
}


etc 29.11.2006 01:48

Хотел как лучше, получилась всякая чушь:
Код:

var bitmapWidth:Number = 550;
var bitmapHeight:Number = 400;
var startBitmap:BitmapData = new BitmapData(bitmapWidth,bitmapHeight,false,0xFFFF00);
var endBitmap:BitmapData = new BitmapData(bitmapWidth,bitmapHeight,false,0xFF0000);
this.addChild(new Bitmap(endBitmap));

var bitmapArray:Array = new Array();
var lineArray:Array = new Array();
var rowArray:Array = new Array();
var tempArray:Array = new Array();
for (var i:Number = 0;i<bitmapWidth;i++) {
        lineArray.push(i);
}
for (var j:Number = 0;j<bitmapHeight;j++) {
        tempArray = (new Array()).concat(lineArray);
        bitmapArray.push(tempArray);
        rowArray.push(j);
}
lineArray = null;
var rand:Number;
var pixelCounter:Number = 0;
var pixelX:Number;
var pixelY:Number;
var randX:Number;
var randY:Number;
var line:Array;
var defaultRand:Number = 2000;
var t:Number = getTimer();
var enterFrameHandler:Function = function(event:Event):void {
        rand = defaultRand;
        while(--rand&&rowArray.length) {
                randY = Math.floor(Math.random()*rowArray.length);
                pixelY = rowArray[randY];
               
                line = bitmapArray[pixelY];
               
                randX = Math.floor(Math.random()*line.length);
                pixelX = line.splice(randX,1);
                line.shift();
                line.pop();
               
                endBitmap.setPixel(pixelX,pixelY,startBitmap.getPixel(pixelX,pixelY));
                if (!line.length) {
                        rowArray.splice(randY,1);
                }
        }
       
        if (rand==defaultRand-1) {
                removeEventListener(Event.ENTER_FRAME,enterFrameHandler);
                trace(getTimer()-t);
        }
}
this.addEventListener(Event.ENTER_FRAME,enterFrameHandler);

На мусор, чушь и лишнее в коде не смотреть :D

__i 29.11.2006 12:57

Цитата:

Сообщение от __etc
Код:

pixelX = line.splice(randX,1);
line.shift();
line.pop();


:o

это ОЧЕНЬ плохо в цикле!.

splice, shift очень ресурсоемкие операции, pop вроде не очень... но тоже занимает больше времени чем простое обращение по индексу []. Кнут сказал "90% времени выполнения программа находится в циклах, поэтому следует оптимизировать именно их"

Ну, а по практике нужно думать %) Врядли я рожу тут оптимальную идею по тому как это сделать быстро(

В принципе первый способ который предложен MerlinTwi Претендует на оптимальность если в него добавить мои советы %). Единственное, что я незнаю/непридумал как это создание массива с рендомными точками/получение не повторяющихся точек. %(

etc 29.11.2006 13:07

Дык, я же не собирался демонстировать вариант оптимизации, я просто показал, какой эффект получается (а его, как раз, и дают shift, pop и splice).
Если убрать shift и pop, то мой вариант при 2000 итераций отстает от варианта MerlinTwi где-то на 50 мс. С другой стороны, длинные массивы, например, Flash 8 очень не любит — гораздо быстрее работает с множеством коротких, чем с одним длинным.

etc 29.11.2006 13:38

WindWalker, а прочитать первой пост темы по ссылке совесть не позволила?

etc 29.11.2006 13:45

В том, что прочитана была только первая строчка. Про threshold там упоминалось несколько раз, но он не подходит из-за своей медлительности, внимательнее нужно быть.

__i 29.11.2006 13:59

Цитата:

Сообщение от __etc
С другой стороны, длинные массивы, например, Flash 8 очень не любит — гораздо быстрее работает с множеством коротких, чем с одним длинным.

Смотря как с ними работать %)

На я как-то подымал тему работы с массивами и с ассоциативными массивами. Там были тесты для разных плееров.

Ну и продолжая разговор, делал я проект там была работа я ОГРОМНЫМИ массивами. Допустим подгружались статистические данные посекундно/минутно/часово для нескольких месяцев/лет... (ну естественно не все сразу :D, а по запросу некоторое их количество). Но все хранилось в массиве, посчитай его виртуальную длинну :D реально канешно он был чуть поменьше (флеш как показывает практика хранит их по типу ассоциативных...), но все равно огромные массивы. А работало шустро %).

ЗЫ проект был на мх2004.

vapes 29.11.2006 14:05

Ого теперь у меня вывих мозга :bb:

MerlinTwi 29.11.2006 14:09

__etc, в твоем примере замещается не вся картинка?

etc 29.11.2006 14:18

MerlinTwi, вся, если убрать shift и pop. Просто с ними прикольный градиент получается :)

__i, вместе с Дембицким делали что-то подобное, что в этой теме, так вот один длинный массив тормозил много больше, чем двумерный.


Часовой пояс GMT +4, время: 16:18.

Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.