2013-01-31 22 views
6

Wyzwanie, które sam sobie stworzyłem, jest takie.JavaScript - Przetwarzanie danych obrazu i renderowanie div

Mam zdjęcie źródło:

Source Photo http://f.cl.ly/items/012t1M250f0T101F2L0n/unicorn.jpg

, że jestem mapowania wartości kolorów i tworzenia piksele reprezentację nim za pomocą div

oto wynik:

Result Photo http://f.cl.ly/items/2t1F2Q0Y2w0K250L0t0v/Screen%20Shot%202013-01-31%20at%2010.52.19%20AM.png

Kod, który wykonuję to jest:

'use strict'; 

var imageSource = 'images/unicorn.jpg'; 

var img = new Image(); 
img.src = imageSource; 
var canvas = $('<canvas/>')[0]; 
canvas.width = img.width; 
canvas.height = img.height; 
canvas.getContext('2d').drawImage(img, 0, 0, img.width, img.height); 
var context = canvas.getContext('2d'); 

console.log('img height: ' + img.height); 
console.log('img width: ' + img.width); 

var pixelDensity = 70; 

var timerStart = new Date(); 


for (var i = pixelDensity/2; i < img.height; i += (img.height/pixelDensity)) { 
    $('.container').append($('<div class="row">')); 
    for(var j = pixelDensity/2; j < img.width; j += img.height/pixelDensity) { 
     var value = context.getImageData(j, i, 1, 1).data; 
     var colorValue = 'rgb(' + value[0] + ', ' + value[1] + ', ' + value[2] + ')'; 
     $('.row:last').append($('<div class="block">').css({'background-color' : colorValue})); 
    } 
} 

var timerStop = new Date(); 

console.log(timerStop - timerStart + ' ms'); 

Zmienna pixelDensity określa, jak blisko siebie znajdują się próbki kolorów. Im mniejsza liczba, tym mniej próbek, tym mniej czasu na uzyskanie wyniku. W miarę zwiększania liczby próbki wzrastają, a funkcja znacznie się zwalnia.

Jestem ciekawa, co sprawia, że ​​to zajmuje tak długo. Przyjrzałem się nieco podobnym projektom - w szczególności Jscii - które przetwarzają dane obrazu znacznie szybciej, ale nie mogę zrozumieć, jaka jest różnica, która oferuje dodatkową wydajność.

Dzięki za pomoc!

+0

Nie dotykać DOM chyba trzeba. Zbuduj swój model obiektu poza ekranem, a następnie dołącz go raz. Przypuszczalnie im więcej próbek, tym więcej elementów div, tym więcej edytuje dom. Tak więc, zbudowałem wszystko poza ekranem, dodałem je wszystkie naraz, jeden raz. –

+0

To było to, co pierwotnie robiłem, ale odkryłem, że ciągnięcie danych obrazu było tym, co zabierało najwięcej czasu. Spróbuję jeszcze raz, biorąc pod uwagę porady poniżej. Dzięki za pomoc! – tylerdavis

+0

Kolejna sprawa. Kiedy próbujesz wyczuć każdą możliwą wydajność, wtedy każda drobna rzecz pomaga. Buforuj warunki pętli for. 'Do (zmienna J = pixelDensity/2 j

Odpowiedz

1

Głównym problemem jest to, że dołączanie elementów DOM do prawej strony w pętli. Byłoby to znacznie szybsze, jeśli utworzysz element opakowania ze wszystkimi danymi przed dodaniem go do strony.

Edit: Zauważyłam również zadzwonić context.getImageData dla każdego piksela, to co zajmuje większość czasu. Zamiast tego należy buforować dane obrazu w zmiennej i uzyskiwać z niej wartości kolorów.Trzeba także buforować warunki pętli jako @Travis J wymienione i wokół nich:

var wrapper = $('<div class="container">'); 
var imgData = context.getImageData(0, 0, img.width, img.height).data; 
var getRGB = function(i) { return [imgData[i], imgData[i+1], imgData[i+2]]; }; 
var start = Math.round(pixelDensity/2), 
    inc = Math.round(img.height/pixelDensity); 

for (var i = start; i < img.height; i += inc) { 
    var row = $('<div class="row">'); 
    for(var j = start; j < img.width; j += inc) { 
     var colorValue = getRGB((i * (img.width*4)) + (j*4)); 
     row.append($('<div class="block">').css({'background-color' : 'rgb('+(colorValue.join(','))+')'})); 
    } 
    wrapper.append(row); 
} 

$('body').append(wrapper); 

To skraca czas od 6-9 sekund do 600-1000 milisekund. Możesz również użyć zwykłego javascript do manipulowania elementami DOM zamiast jquery, aby było jeszcze szybciej.

+0

To był problem. Dziękuję bardzo za odpowiedź! – tylerdavis

1

Dlaczego nie wziąć pod uwagę rysowania wyniku na płótnie zamiast tworzenia tak wielu elementów div? Teoretycznie powinno być znacznie szybciej ...

0

Już wcześniej miałem podobne problemy z szybkością - powodem, dla którego trwa to tak długo, jest to, że dodajesz elementy, podając kod HTML w postaci tekstu, który oznacza, że ​​musi analizować ten tekst za każdym razem. Jeśli użyjesz JavaScript DOM do dołączenia nowych elementów, zauważysz znaczny wzrost prędkości.

EDIT: W przypadku, gdy nie jesteś zaznajomiony z tworzenia nowych elementów w ten sposób, składnia wygląda następująco:

var newPixel = document.createElement('div'); 
newPixel.style.height = 3; 
newPixel.style.backgroundColor = 'black'; 
// etc... 
parentElement.appendChild(newPixel); 
0

Można przyspieszyć nieco przez zmniejszenie liczby wyszukiwań jQuery. Na przykład, przed swoim pierwszym starcie w pętli, to zrobić:

var $container = $('.container'); 

Teraz nie trzeba zajrzeć do pojemnika za każdym razem.

Również podczas tworzenia wiersza, należy użyć tej samej sztuczki, aby uniknąć „wiersz: ostatni” odnośnika:

var $row = $('<div class="row">'); 
$container.append($row); 
... 
$row.append($('<div class="block">')...