Самый быстрый способ перебирать пиксели на холсте и копировать некоторые из них в другой
Я в 2D/3D графическом проекте, и я столкнулся с проблемой производительности.
Мой алгоритм берет два изображения: изображение и карту глубины серого. У меня также есть массив из 10 холстов ("слоев"), изначально пустой. Примечание: все изображения имеют одинаковое измерение.
Мне нужно проверить каждый пиксель X;Y карты глубины и, в зависимости от его значения цвета, получить доступ к одному из 10 полотен и нарисовать на нем пиксель X;Y исходного изображения.
Результирующий алгоритм выглядит примерно так:
for (var y = 0; y < totalHeight; ++y) {
for (var x = 0; x < totalWidth; ++x) {
var index = (y * totalWidth + x) * 4; // index of the current pixel
// parse depth level using luminosity method
var depthLevel = Math.round(
0.21 * depthData[index] +
0.71 * depthData[index + 1] +
0.07 * depthData[index + 2]
);
// get the proper layer to modify
var layerIndex = Math.floor((layersCount / 256) * depthLevel);
var layerContext = layers[layerIndex].getContext("2d");
var layerData = layerContext.getImageData(0, 0, totalWidth, totalHeight);
layerData.data[index] = originalData[index];
layerData.data[index + 1] = originalData[index + 1];
layerData.data[index + 2] = originalData[index + 2];
layerData.data[index + 3] = originalData[index + 3];
layerContext.putImageData(layerData, 0, 0);
}
Такая петля занимает около 3 минут для изображения размером 200x200! Я уверен, что медлительность вызвана последней функцией, putImageData. Есть ли более быстрый способ рисовать пиксели так, как мне нужно? Спасибо
1 ответ
Не устанавливайте данные изображения на каждой итерации цикла. Это тяжелая операция, и вы ее выполняете 40.000
(200*200)
раз.
Это должно сэкономить вам немного вычислительной мощности:
var contexts = [];
var data = [];
// Save your contexts and data to 2 arrays.
for (var i = 0; i < layers.length; i++) {
contexts[i] = layers[i].getContext("2d");
data[i] = contexts[i].getImageData(0, 0, totalWidth, totalHeight);
}
for (var y = 0; y < totalHeight; ++y) {
for (var x = 0; x < totalWidth; ++x) {
var index = (y * totalWidth + x) * 4; // index of the current pixel
// parse depth level using luminosity method
var depthLevel = Math.round(
0.21 * depthData[index]
+ 0.71 * depthData[index + 1]
+ 0.07 * depthData[index + 2]);
// get the proper layer to modify
var layerIndex = Math.floor((layersCount / 256) * depthLevel);
data[layerIndex].data[index] = originalData[index];
data[layerIndex].data[index + 1] = originalData[index + 1];
data[layerIndex].data[index + 2] = originalData[index + 2];
data[layerIndex].data[index + 3] = originalData[index + 3];
}
}
// Apply your new data to the contexts.
for (var i = 0; i < layers.length; i++) {
contexts[i].putImageData(data[i]);
}
Я не проверял это, но это должно дать вам представление о том, как это сделать.