@@ -26,9 +26,13 @@ class SeamCarver {
26
26
// Simple implementation of energy matrix as array of arrays.
27
27
// Because we need to remove items, when removing the seam,
28
28
// maybe some sort of linked structure is more efficient.
29
- this . energy_matrix = new Array ( this . width ) ;
29
+ this . energyMatrix = new Array ( this . width ) ;
30
+ this . minsumMatrix = new Array ( this . width ) ;
31
+ this . minxMatrix = new Array ( this . width ) ;
30
32
for ( var i = 0 ; i < this . width ; i ++ ) {
31
- this . energy_matrix [ i ] = new Array ( this . height ) ;
33
+ this . energyMatrix [ i ] = new Float32Array ( this . height ) ;
34
+ this . minsumMatrix [ i ] = new Float32Array ( this . height ) ;
35
+ this . minxMatrix [ i ] = new Uint16Array ( this . height ) ;
32
36
}
33
37
34
38
console . time ( 'createEnergyMatrix' ) ;
@@ -128,20 +132,20 @@ class SeamCarver {
128
132
// last row
129
133
if ( y >= this . height - 1 ) {
130
134
energy_cell . vminsum = energy_cell . energy ;
131
- energy_cell . minx = 0 ;
135
+ energy_cell . minx = x ;
132
136
} else {
133
137
var cursum = 0 ;
134
138
var curminx = 0 ;
135
139
136
140
// below left
137
141
if ( x - 1 >= 0 ) {
138
- energy_cell . vminsum = this . energy_matrix [ x - 1 ] [ y + 1 ] . vminsum + energy_cell . energy ;
142
+ energy_cell . vminsum = this . minsumMatrix [ x - 1 ] [ y + 1 ] + energy_cell . energy ;
139
143
energy_cell . minx = x - 1 ;
140
144
}
141
145
142
146
// below
143
147
if ( x < this . width ) {
144
- cursum = this . energy_matrix [ x ] [ y + 1 ] . vminsum + energy_cell . energy ;
148
+ cursum = this . minsumMatrix [ x ] [ y + 1 ] + energy_cell . energy ;
145
149
if ( cursum < energy_cell . vminsum ) {
146
150
energy_cell . vminsum = cursum ;
147
151
energy_cell . minx = x ;
@@ -150,7 +154,7 @@ class SeamCarver {
150
154
151
155
// below right
152
156
if ( x + 1 < this . width ) {
153
- cursum = this . energy_matrix [ x + 1 ] [ y + 1 ] . vminsum + energy_cell . energy ;
157
+ cursum = this . minsumMatrix [ x + 1 ] [ y + 1 ] + energy_cell . energy ;
154
158
if ( cursum < energy_cell . vminsum ) {
155
159
energy_cell . vminsum = cursum ;
156
160
energy_cell . minx = x + 1 ;
@@ -182,7 +186,9 @@ class SeamCarver {
182
186
for ( var x = 0 ; x < this . width ; x ++ ) {
183
187
var energy = this . recalculate ( x , y ) ;
184
188
this . maxVminsum = Math . max ( energy . vminsum , this . maxVminsum ) ;
185
- this . energy_matrix [ x ] [ y ] = energy ;
189
+ this . energyMatrix [ x ] [ y ] = energy . energy ;
190
+ this . minsumMatrix [ x ] [ y ] = energy . vminsum ;
191
+ this . minxMatrix [ x ] [ y ] = energy . minx ;
186
192
}
187
193
}
188
194
}
@@ -199,8 +205,8 @@ class SeamCarver {
199
205
200
206
// Find smallest sum on first row
201
207
for ( var x = 0 ; x < this . width ; x ++ ) {
202
- if ( this . energy_matrix [ x ] [ 0 ] . vminsum < vminsum ) {
203
- vminsum = this . energy_matrix [ x ] [ 0 ] . vminsum ;
208
+ if ( this . minsumMatrix [ x ] [ 0 ] < vminsum ) {
209
+ vminsum = this . minsumMatrix [ x ] [ 0 ] ;
204
210
xminsum = x ;
205
211
}
206
212
}
@@ -210,7 +216,7 @@ class SeamCarver {
210
216
// Follow down to get array
211
217
var y = 0 ;
212
218
while ( y < this . height - 1 ) {
213
- xminsum = this . energy_matrix [ xminsum ] [ y ] . minx
219
+ xminsum = this . minxMatrix [ xminsum ] [ y ]
214
220
y ++ ;
215
221
vseam [ y ] = xminsum ;
216
222
}
@@ -249,13 +255,20 @@ class SeamCarver {
249
255
}
250
256
251
257
// copy across energy_matrix
252
- var val_right = this . energy_matrix [ col + 1 ] [ row ] ;
253
- val_right . minx -- ;
254
- this . energy_matrix [ col ] [ row ] = val_right ;
258
+ var energy_right = this . energyMatrix [ col + 1 ] [ row ] ;
259
+ var minx_right = this . minxMatrix [ col + 1 ] [ row ] ;
260
+ var minsum_right = this . minsumMatrix [ col + 1 ] [ row ] ;
261
+ minx_right -- ;
262
+ this . energyMatrix [ col + 1 ] [ row ] = energy_right ;
263
+ this . minxMatrix [ col + 1 ] [ row ] = minx_right ;
264
+ this . minsumMatrix [ col + 1 ] [ row ] = minsum_right ;
255
265
}
256
266
}
257
267
258
- this . energy_matrix . splice ( this . width - 1 , 1 )
268
+ // chop off last column
269
+ this . energyMatrix . splice ( this . width - 1 , 1 ) ;
270
+ this . minxMatrix . splice ( this . width - 1 , 1 ) ;
271
+ this . minsumMatrix . splice ( this . width - 1 , 1 ) ;
259
272
this . picture = this . imageData . data ;
260
273
this . width -- ;
261
274
}
@@ -281,9 +294,10 @@ class SeamCarver {
281
294
var col = deletedCol + i ;
282
295
283
296
if ( this . pixelInRange ( col , row ) ) {
284
- var oldValue = this . energy_matrix [ col ] [ row ] ;
285
297
var newValue = this . recalculate ( col , row ) ;
286
- this . energy_matrix [ col ] [ row ] = newValue ;
298
+ this . energyMatrix [ col ] [ row ] = newValue . energy ;
299
+ this . minxMatrix [ col ] [ row ] = newValue . minx ;
300
+ this . minsumMatrix [ col ] [ row ] = newValue . vminsum ;
287
301
// enqueue pixel in range
288
302
queue . push ( this . pixelToIndex ( col , row ) ) ;
289
303
}
@@ -317,23 +331,25 @@ class SeamCarver {
317
331
318
332
var col = this . indexToX ( pixelIndex ) ;
319
333
var row = this . indexToY ( pixelIndex ) ;
320
- var node = this . energy_matrix [ col ] [ row ] ;
321
- var oldVminsum = node . vminsum ;
322
- node . vminsum = Number . POSITIVE_INFINITY ;
334
+ var nodeEnergy = this . energyMatrix [ col ] [ row ] ;
335
+ var oldVminsum = this . minsumMatrix [ col ] [ row ] ;
336
+ this . minsumMatrix [ col ] [ row ] = Number . POSITIVE_INFINITY ;
323
337
324
338
// check three parents in row below
325
339
for ( var i = Math . max ( col - 1 , 0 ) ; i < Math . min ( col + 1 , lastCol ) ; i ++ ) {
326
- var parent = this . energy_matrix [ i ] [ row + 1 ] ;
327
- var new_vminsum = parent . vminsum + node . energy ;
340
+ var parentVminsum = this . minsumMatrix [ i ] [ row + 1 ] ;
341
+ var newVminsum = parentVminsum + nodeEnergy ;
328
342
329
343
// TODO: do I always need to update the vminsum for this node?
330
- if ( new_vminsum < node . vminsum ) {
331
- node . vminsum = new_vminsum ;
332
- node . minx = i ;
344
+ if ( newVminsum < this . minsumMatrix [ col ] [ row ] ) {
345
+ this . minsumMatrix [ col ] [ row ] = newVminsum ;
346
+ // TODO: check i is correct and does not need to be -1, 0, 1
347
+ // rather than actual col
348
+ this . minxMatrix [ col ] [ row ] = i ;
333
349
}
334
350
}
335
351
336
- if ( oldVminsum !== node . vminsum && row > 0 ) {
352
+ if ( oldVminsum !== this . minsumMatrix [ col ] [ row ] && row > 0 ) {
337
353
// TODO: do I need to enqueue all children
338
354
// found better path from parent
339
355
// so enqueue three affected children from row above
@@ -342,6 +358,17 @@ class SeamCarver {
342
358
}
343
359
}
344
360
}
361
+
362
+ // now update energy matrix
363
+ // for (var row = this.height - 1; row >= 0; row--) {
364
+ // for (var col = 0; col < this.width; col++) {
365
+ // // TODO recalculate energy only when necessary: pixels adjacent (up, down and both sides) to the removed seam.
366
+ // var energy = this.recalculate(col, row);
367
+ // this.energyMatrix[col][row] = energy.energy;
368
+ // this.minsumMatrix[col][row] = energy.vminsum;
369
+ // this.minxMatrix[col][row] = energy.minx;
370
+ // }
371
+ // }
345
372
}
346
373
347
374
/**
@@ -365,19 +392,32 @@ class SeamCarver {
365
392
this . canvas . width = this . imageData . width ;
366
393
this . canvas . height = this . imageData . height ;
367
394
395
+ this . canvas . style . width = this . imageData . width + 'px' ;
396
+ this . canvas . style . height = this . imageData . height + 'px' ;
397
+
368
398
if ( field === 'energy' || field === 'vminsum' || ( field !== this . imageData . dataField ) ) {
369
399
this . imageData = this . context . createImageData ( this . width , this . height ) ;
370
400
this . imageData . dataField = field ;
371
401
372
402
for ( var row = 0 ; row < this . height ; row ++ ) {
373
403
for ( var col = 0 ; col < this . width ; col ++ ) {
374
404
var pos = this . pixelToIndex ( col , row ) ;
375
- var val = this . energy_matrix [ col ] [ row ] [ field ] ;
376
405
377
406
if ( field === 'energy' ) {
407
+ var val = this . energyMatrix [ col ] [ row ] ;
378
408
var normalizedVal = Math . min ( 255 , ( ( val / 255 ) * 255 ) ) ;
379
- } else if ( field === 'vminsum' ) {
409
+ } else if ( field === 'minsum' ) {
410
+ var val = this . minsumMatrix [ col ] [ row ] ;
380
411
var normalizedVal = ( ( val - 1000 ) / ( this . maxVminsum - 1000 ) ) * 255
412
+ } else if ( field === 'minx' ) {
413
+ var val = this . minxMatrix [ col ] [ row ] ;
414
+ var direction = col - val + 1 ;
415
+ for ( var i = 0 ; i < 3 ; i ++ ) {
416
+ this . imageData . data [ pos + i ] = 0 ;
417
+ }
418
+ if ( direction >= 0 && direction <= 2 ) this . imageData . data [ pos + direction ] = 255 ;
419
+ this . imageData . data [ pos + 3 ] = 255 ;
420
+ continue ;
381
421
} else {
382
422
// rgb
383
423
for ( var i = 0 ; i < 4 ; i ++ ) {
@@ -427,12 +467,22 @@ class SeamCarver {
427
467
} else {
428
468
for ( var y = 0 ; y < this . height ; y ++ ) {
429
469
for ( var x = 0 ; x < this . width ; x ++ ) {
430
- var val = this . energy_matrix [ x ] [ y ] ;
431
- if ( val && field in val ) {
432
- lines += val [ field ] . toFixed ( 2 ) + "\t" ;
470
+ var val ;
471
+
472
+ if ( field === 'energy' ) {
473
+ val = this . energyMatrix [ x ] [ y ] ;
474
+ } else if ( field === 'minsum' ) {
475
+ val = this . minsumMatrix [ x ] [ y ] ;
476
+ } else if ( field === 'minx' ) {
477
+ val = this . minxMatrix [ x ] [ y ] ;
478
+ }
479
+
480
+ if ( val ) {
481
+ lines += val . toFixed ( 2 ) + "\t" ;
433
482
} else {
434
483
lines += '-----\t' ;
435
484
}
485
+
436
486
}
437
487
lines += '\n' ;
438
488
}
0 commit comments