Skip to content

Commit 51201de

Browse files
committed
move energy sum and min seam calculations into their own functions
This makes the main loop easier to read and doesn't seem to affect performance at all. In some cases it's even faster, although I haven't been able to repro that reliably.
1 parent a42c31c commit 51201de

2 files changed

Lines changed: 190 additions & 165 deletions

File tree

build/index.js

Lines changed: 84 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -7,94 +7,22 @@ function findSeams(data, width, height, removeCount, onRemoveSeam) {
77
let energy = calcEnergy(data, width, height);
88
let workingData = data.slice();
99
for (let i = 0; i < removeCount; i++) {
10-
// populate the first row in energySum
11-
for (let j = 0; j < energy.length; j++) {
12-
energySum[j] = energy[j];
13-
}
14-
// populate the rest of the rows
15-
for (let y = 1; y < height; y++) {
16-
for (let x = 0; x < width; x++) {
17-
const left = energySum[(y - 1) * width + Math.max(x - 1, 0)];
18-
const mid = energySum[(y - 1) * width + x];
19-
const right = energySum[(y - 1) * width + Math.min(x + 1, width - 1)];
20-
energySum[y * width + x] = energy[y * width + x] + Math.min(left, mid, right);
21-
}
22-
}
23-
// find the min on the last row
24-
let min = Infinity;
25-
let minx = 0;
26-
for (let x = 0; x < width; x++) {
27-
if (energySum[(height - 1) * width + x] < min) {
28-
min = energySum[(height - 1) * width + x];
29-
minx = x;
30-
}
31-
}
32-
remove[(height - 1)] = minx;
33-
// walk from the bottom up picking the min each time
34-
for (let y = height - 1; y >= 1; y--) {
35-
const leftx = Math.max(minx - 1, 0);
36-
const left = energySum[(y - 1) * width + leftx];
37-
const mid = energySum[(y - 1) * width + minx];
38-
const rightx = Math.min(minx + 1, width - 1);
39-
const right = energySum[(y - 1) * width + rightx];
40-
if (left < mid && left < right) {
41-
minx = leftx;
42-
}
43-
else if (right < mid && right < left) {
44-
minx = rightx;
45-
}
46-
remove[(y - 1)] = minx;
47-
}
10+
calcEnergySum(energySum, energy, width, height);
11+
findMinSeam(remove, energySum, width, height);
4812
workingData = removeSeam(workingData, width, height, remove);
4913
energy = recalcEnergy(workingData, width - 1, height, energy, remove);
5014
width--;
5115
if (onRemoveSeam) {
5216
onRemoveSeam(workingData, width);
5317
}
5418
}
19+
workingData = workingData.slice(0, width * height * 4);
5520
return workingData;
5621
}
5722
exports.findSeams = findSeams;
58-
// debug functions
59-
// replace the return of findSeams to return energy or energySum instead
60-
function dbgEnergy(energy) {
61-
const newData = new Uint8ClampedArray(energy.length * 4);
62-
const buf32 = new Uint32Array(newData.buffer);
63-
for (let i = 0; i < energy.length; i++) {
64-
const nrg = energy[i];
65-
buf32[i] =
66-
(0xff << 24) |
67-
(nrg << 16) |
68-
(nrg << 8) |
69-
nrg;
70-
}
71-
return newData;
72-
}
73-
function dbgEnergySum(energySum) {
74-
const newData = new Uint8ClampedArray(energySum.length * 4);
75-
const buf32 = new Uint32Array(newData.buffer);
76-
let nrgMax = -Infinity;
77-
for (let i = 0; i < energySum.length; i++) {
78-
if (energySum[i] > nrgMax) {
79-
nrgMax = energySum[i];
80-
}
81-
}
82-
for (let i = 0; i < energySum.length; i++) {
83-
const nrg = (energySum[i] / nrgMax) * 255;
84-
buf32[i] =
85-
(0xff << 24) |
86-
(nrg << 16) |
87-
(nrg << 8) |
88-
nrg;
89-
}
90-
return newData;
91-
}
9223
// remove seams in remove from data, returning a new array.
93-
// TODO mutate data instead of allocating a new array
9424
function removeSeam(data, width, height, remove) {
9525
const data32 = new Uint32Array(data.buffer);
96-
const newData = new Uint8ClampedArray((width - 1) * height * 4);
97-
const buf32 = new Uint32Array(newData.buffer);
9826
let offset = 0;
9927
for (let y = 0; y < height; y++) {
10028
let removex = remove[y];
@@ -103,12 +31,12 @@ function removeSeam(data, width, height, remove) {
10331
// pixels been removed, skip over it
10432
offset++;
10533
}
106-
if (x < width) {
107-
buf32[y * (width - 1) + x] = data32[y * (width - 1) + x + offset];
34+
if (x < width && offset > 0) {
35+
data32[y * (width - 1) + x] = data32[y * (width - 1) + x + offset];
10836
}
10937
}
11038
}
111-
return newData;
39+
return data;
11240
}
11341
function diff(pixel1, pixel2) {
11442
const r1 = pixel1 & 0xff;
@@ -189,3 +117,81 @@ function recalcEnergy(data, width, height, energy, removed) {
189117
}
190118
return energy;
191119
}
120+
function calcEnergySum(energySum, energy, width, height) {
121+
// populate the first row in energySum
122+
for (let j = 0; j < energy.length; j++) {
123+
energySum[j] = energy[j];
124+
}
125+
// populate the rest of the rows
126+
for (let y = 1; y < height; y++) {
127+
// const removex = remove[y];
128+
// for (let x = Math.max(removex - y, 0); x < Math.min(removex + y, width); x++) {
129+
for (let x = 0; x < width; x++) {
130+
const left = energySum[(y - 1) * width + Math.max(x - 1, 0)];
131+
const mid = energySum[(y - 1) * width + x];
132+
const right = energySum[(y - 1) * width + Math.min(x + 1, width - 1)];
133+
energySum[y * width + x] = energy[y * width + x] + Math.min(left, mid, right);
134+
}
135+
}
136+
}
137+
function findMinSeam(remove, energySum, width, height) {
138+
// find the min on the last row
139+
let min = Infinity;
140+
let minx = 0;
141+
for (let x = 0; x < width; x++) {
142+
if (energySum[(height - 1) * width + x] < min) {
143+
min = energySum[(height - 1) * width + x];
144+
minx = x;
145+
}
146+
}
147+
remove[(height - 1)] = minx;
148+
// walk from the bottom up picking the min each time
149+
for (let y = height - 1; y >= 1; y--) {
150+
const leftx = Math.max(minx - 1, 0);
151+
const left = energySum[(y - 1) * width + leftx];
152+
const mid = energySum[(y - 1) * width + minx];
153+
const rightx = Math.min(minx + 1, width - 1);
154+
const right = energySum[(y - 1) * width + rightx];
155+
if (left < mid && left < right) {
156+
minx = leftx;
157+
}
158+
else if (right < mid && right < left) {
159+
minx = rightx;
160+
}
161+
remove[(y - 1)] = minx;
162+
}
163+
}
164+
// debug functions
165+
// replace the return of findSeams to return energy or energySum instead
166+
function dbgEnergy(energy) {
167+
const newData = new Uint8ClampedArray(energy.length * 4);
168+
const buf32 = new Uint32Array(newData.buffer);
169+
for (let i = 0; i < energy.length; i++) {
170+
const nrg = energy[i];
171+
buf32[i] =
172+
(0xff << 24) |
173+
(nrg << 16) |
174+
(nrg << 8) |
175+
nrg;
176+
}
177+
return newData;
178+
}
179+
function dbgEnergySum(energySum) {
180+
const newData = new Uint8ClampedArray(energySum.length * 4);
181+
const buf32 = new Uint32Array(newData.buffer);
182+
let nrgMax = -Infinity;
183+
for (let i = 0; i < energySum.length; i++) {
184+
if (energySum[i] > nrgMax) {
185+
nrgMax = energySum[i];
186+
}
187+
}
188+
for (let i = 0; i < energySum.length; i++) {
189+
const nrg = (energySum[i] / nrgMax) * 255;
190+
buf32[i] =
191+
(0xff << 24) |
192+
(nrg << 16) |
193+
(nrg << 8) |
194+
nrg;
195+
}
196+
return newData;
197+
}

0 commit comments

Comments
 (0)