Skip to content

Commit

Permalink
Replace each loop with a chunk of Promises.
Browse files Browse the repository at this point in the history
This is an attempt to parallelise the function.
  • Loading branch information
BritishWerewolf committed Dec 19, 2024
1 parent e02128b commit 7ed50f0
Showing 1 changed file with 59 additions and 33 deletions.
92 changes: 59 additions & 33 deletions src/utils/image.js
Original file line number Diff line number Diff line change
Expand Up @@ -687,11 +687,13 @@ export class RawImage {
* Performs a Gaussian blur on the image.
* @param {number} kernelSize - Kernel size (must be odd).
* @param {number} sigma - Standard deviation of the Gaussian.
* @param {number} numChunks - Number of chunks to divide the image into for parallel processing.
* @returns {Promise<RawImage>} - The blurred image.
*/
async gaussianBlur(kernelSize = 3, sigma = 1) {
async gaussianBlur(kernelSize = 3, sigma = 1, numChunks = 4) {
const kernel = this.generateGaussianKernel(kernelSize, sigma);
const halfSize = Math.floor(kernelSize / 2);

const width = this.width;
const height = this.height;
const channels = this.channels;
Expand All @@ -703,43 +705,67 @@ export class RawImage {
const horizontalPass = new Float32Array(this.data.length);
const verticalPass = new Uint8ClampedArray(this.data.length);

// Horizontal pass.
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
for (let c = 0; c < channels; c++) {
let sum = 0;

for (let kx = -halfSize; kx <= halfSize; kx++) {
const pixelX = Math.min(Math.max(x + kx, 0), width - 1);
const dataIndex = ((y * width) + pixelX) * channels + c;
const kernelValue = kernel[kx + halfSize];
sum += this.data[dataIndex] * kernelValue;
const chunkHeight = Math.ceil(height / numChunks);

// Process horizontal pass in chunks.
const horizontalPassPromises = Array.from({ length: numChunks }, (_, chunkIndex) => {
return new Promise(resolve => {
const startY = chunkIndex * chunkHeight;
const endY = Math.min(startY + chunkHeight, height);

for (let y = startY; y < endY; y++) {
for (let x = 0; x < width; x++) {
for (let c = 0; c < channels; c++) {
let sum = 0;

for (let kx = -halfSize; kx <= halfSize; kx++) {
const pixelX = Math.min(Math.max(x + kx, 0), width - 1);
const dataIndex = (((y * width) + pixelX) * channels) + c;
const kernelValue = kernel[kx + halfSize];
sum += this.data[dataIndex] * kernelValue;
}

const outputIndex = (((y * width) + x) * channels) + c;
horizontalPass[outputIndex] = sum;
}
}

const outputIndex = ((y * width) + x) * channels + c;
horizontalPass[outputIndex] = sum;
}
}
}

// Vertical pass.
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
for (let c = 0; c < channels; c++) {
let sum = 0;
resolve();
});
});

for (let ky = -halfSize; ky <= halfSize; ky++) {
const pixelY = Math.min(Math.max(y + ky, 0), height - 1);
const dataIndex = ((pixelY * width) + x) * channels + c;
const kernelValue = kernel[ky + halfSize];
sum += horizontalPass[dataIndex] * kernelValue;
// Wait for all horizontal chunks to complete.
await Promise.all(horizontalPassPromises);

// Process vertical pass in chunks.
const verticalPassPromises = Array.from({ length: numChunks }, (_, chunkIndex) => {
return new Promise(resolve => {
const startY = chunkIndex * chunkHeight;
const endY = Math.min(startY + chunkHeight, height);

for (let y = startY; y < endY; y++) {
for (let x = 0; x < width; x++) {
for (let c = 0; c < channels; c++) {
let sum = 0;

for (let ky = -halfSize; ky <= halfSize; ky++) {
const pixelY = Math.min(Math.max(y + ky, 0), height - 1);
const dataIndex = (((pixelY * width) + x) * channels) + c;
const kernelValue = kernel[ky + halfSize];
sum += horizontalPass[dataIndex] * kernelValue;
}

const outputIndex = (((y * width) + x) * channels) + c;
verticalPass[outputIndex] = sum;
}
}

const outputIndex = ((y * width) + x) * channels + c;
verticalPass[outputIndex] = sum;
}
}
}
resolve();
});
});

// Wait for all vertical chunks to complete.
await Promise.all(verticalPassPromises);

this.data = verticalPass;
return this;
Expand Down

0 comments on commit 7ed50f0

Please sign in to comment.