Changed energy preview inteface
[liblqr.git] / lqr / lqr_energy.c
blobf605c8103b1e6c4df54795a716a3fb67bc9c456f
1 /* LiquidRescaling Library
2 * Copyright (C) 2007-2009 Carlo Baldassi (the "Author") <carlobaldassi@gmail.com>.
3 * All Rights Reserved.
5 * This library implements the algorithm described in the paper
6 * "Seam Carving for Content-Aware Image Resizing"
7 * by Shai Avidan and Ariel Shamir
8 * which can be found at http://www.faculty.idc.ac.il/arik/imret.pdf
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Lesser General Public License as published by
12 * the Free Software Foundation; version 3 dated June, 2007.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, see <http://www.gnu.org/licenses/>
23 #include <glib.h>
24 #include <math.h>
25 #include <lqr/lqr_base.h>
26 #include <lqr/lqr_gradient.h>
27 #include <lqr/lqr_rwindow.h>
28 #include <lqr/lqr_energy.h>
29 #include <lqr/lqr_progress_pub.h>
30 #include <lqr/lqr_cursor_pub.h>
31 #include <lqr/lqr_vmap.h>
32 #include <lqr/lqr_vmap_list.h>
33 #include <lqr/lqr_carver_list.h>
34 #include <lqr/lqr_carver.h>
36 #ifdef __LQR_DEBUG__
37 #include <stdio.h>
38 #include <assert.h>
39 #endif /* __LQR_DEBUG__ */
41 /* read normalised pixel value from
42 * rgb buffer at the given index */
43 inline gdouble
44 lqr_pixel_get_norm (void * rgb, gint rgb_ind, LqrColDepth col_depth)
46 switch (col_depth)
48 case LQR_COLDEPTH_8I:
49 return (gdouble) AS_8I(rgb)[rgb_ind] / 0xFF;
50 case LQR_COLDEPTH_16I:
51 return (gdouble) AS_16I(rgb)[rgb_ind] / 0xFFFF;
52 case LQR_COLDEPTH_32F:
53 return (gdouble) AS_32F(rgb)[rgb_ind];
54 case LQR_COLDEPTH_64F:
55 return (gdouble) AS_64F(rgb)[rgb_ind];
56 default:
57 #ifdef __LQR_DEBUG__
58 assert(0);
59 #endif /* __LQR_DEBUG__ */
60 return 0;
64 inline gdouble
65 lqr_pixel_get_rgbcol (void *rgb, gint rgb_ind, LqrColDepth col_depth, LqrImageType image_type, gint channel)
67 gdouble black_fact = 0;
69 switch (image_type)
71 case LQR_RGB_IMAGE:
72 case LQR_RGBA_IMAGE:
73 return lqr_pixel_get_norm (rgb, rgb_ind + channel, col_depth);
74 case LQR_CMY_IMAGE:
75 return 1. - lqr_pixel_get_norm (rgb, rgb_ind + channel, col_depth);
76 case LQR_CMYK_IMAGE:
77 case LQR_CMYKA_IMAGE:
78 black_fact = 1 - lqr_pixel_get_norm(rgb, rgb_ind + 3, col_depth);
79 return black_fact * (1. - (lqr_pixel_get_norm (rgb, rgb_ind + channel, col_depth)));
80 default:
81 #ifdef __LQR_DEBUG__
82 assert(0);
83 #endif /* __LQR_DEBUG__ */
84 return 0;
88 inline gdouble
89 lqr_carver_read_brightness_grey (LqrCarver * r, gint x, gint y)
91 gint now = r->raw[y][x];
92 gint rgb_ind = now * r->channels;
93 return lqr_pixel_get_norm (r->rgb, rgb_ind, r->col_depth);
96 inline gdouble
97 lqr_carver_read_brightness_std (LqrCarver * r, gint x, gint y)
99 gdouble red, green, blue;
100 gint now = r->raw[y][x];
101 gint rgb_ind = now * r->channels;
103 red = lqr_pixel_get_rgbcol (r->rgb, rgb_ind, r->col_depth, r->image_type, 0);
104 green = lqr_pixel_get_rgbcol (r->rgb, rgb_ind, r->col_depth, r->image_type, 1);
105 blue = lqr_pixel_get_rgbcol (r->rgb, rgb_ind, r->col_depth, r->image_type, 2);
106 return (red + green + blue) / 3;
109 gdouble
110 lqr_carver_read_brightness_custom (LqrCarver * r, gint x, gint y)
112 gdouble sum = 0;
113 gint k;
114 gchar has_alpha = (r->alpha_channel >= 0 ? 1 : 0);
115 gchar has_black = (r->black_channel >= 0 ? 1 : 0);
116 guint col_channels = r->channels - has_alpha - has_black;
118 gdouble black_fact = 0;
120 gint now = r->raw[y][x];
122 if (has_black)
124 black_fact = lqr_pixel_get_norm(r->rgb, now * r->channels + r->black_channel, r->col_depth);
127 for (k = 0; k < r->channels; k++) if ((k != r->alpha_channel) && (k != r->black_channel))
129 gdouble col = lqr_pixel_get_norm(r->rgb, now * r->channels + k, r->col_depth);
130 sum += 1. - (1. - col) * (1. - black_fact);
133 sum /= col_channels;
135 if (has_black)
137 sum = 1 - sum;
140 return sum;
143 /* read average pixel value at x, y
144 * for energy computation */
145 gdouble
146 lqr_carver_read_brightness (LqrCarver * r, gint x, gint y)
148 gchar has_alpha = (r->alpha_channel >= 0 ? 1 : 0);
149 gdouble alpha_fact = 1;
151 gint now = r->raw[y][x];
153 gdouble bright = 0;
155 switch (r->image_type)
157 case LQR_GREY_IMAGE:
158 case LQR_GREYA_IMAGE:
159 bright = lqr_carver_read_brightness_grey (r, x, y);
160 break;
161 case LQR_RGB_IMAGE:
162 case LQR_RGBA_IMAGE:
163 case LQR_CMY_IMAGE:
164 case LQR_CMYK_IMAGE:
165 case LQR_CMYKA_IMAGE:
166 bright = lqr_carver_read_brightness_std (r, x, y);
167 break;
168 case LQR_CUSTOM_IMAGE:
169 bright = lqr_carver_read_brightness_custom (r, x, y);
170 break;
173 if (has_alpha)
175 alpha_fact = lqr_pixel_get_norm(r->rgb, now * r->channels + r->alpha_channel, r->col_depth);
178 return bright * alpha_fact;
181 inline gdouble
182 lqr_carver_read_luma_std (LqrCarver * r, gint x, gint y)
184 gdouble red, green, blue;
185 gint now = r->raw[y][x];
186 gint rgb_ind = now * r->channels;
188 red = lqr_pixel_get_rgbcol (r->rgb, rgb_ind, r->col_depth, r->image_type, 0);
189 green = lqr_pixel_get_rgbcol (r->rgb, rgb_ind, r->col_depth, r->image_type, 1);
190 blue = lqr_pixel_get_rgbcol (r->rgb, rgb_ind, r->col_depth, r->image_type, 2);
191 return 0.2126 * red + 0.7152 * green + 0.0722 * blue;
194 gdouble
195 lqr_carver_read_luma (LqrCarver * r, gint x, gint y)
197 gchar has_alpha = (r->alpha_channel >= 0 ? 1 : 0);
198 gdouble alpha_fact = 1;
200 gint now = r->raw[y][x];
202 gdouble bright = 0;
204 switch (r->image_type)
206 case LQR_GREY_IMAGE:
207 case LQR_GREYA_IMAGE:
208 bright = lqr_carver_read_brightness_grey (r, x, y);
209 break;
210 case LQR_RGB_IMAGE:
211 case LQR_RGBA_IMAGE:
212 case LQR_CMY_IMAGE:
213 case LQR_CMYK_IMAGE:
214 case LQR_CMYKA_IMAGE:
215 bright = lqr_carver_read_luma_std (r, x, y);
216 break;
217 case LQR_CUSTOM_IMAGE:
218 bright = lqr_carver_read_brightness_custom (r, x, y);
219 break;
222 if (has_alpha)
224 alpha_fact = lqr_pixel_get_norm(r->rgb, now * r->channels + r->alpha_channel, r->col_depth);
227 return bright * alpha_fact;
230 gdouble
231 lqr_carver_read_rgba (LqrCarver * r, gint x, gint y, gint channel)
233 gchar has_alpha = (r->alpha_channel >= 0 ? 1 : 0);
235 gint now = r->raw[y][x];
237 #ifdef __LQR_DEBUG__
238 assert(channel >= 0 && channel < 4);
239 #endif /* __LQR_DEBUG__ */
241 if (channel < 3)
243 switch (r->image_type)
245 case LQR_GREY_IMAGE:
246 case LQR_GREYA_IMAGE:
247 return lqr_carver_read_brightness_grey (r, x, y);
248 case LQR_RGB_IMAGE:
249 case LQR_RGBA_IMAGE:
250 case LQR_CMY_IMAGE:
251 case LQR_CMYK_IMAGE:
252 case LQR_CMYKA_IMAGE:
253 return lqr_pixel_get_rgbcol (r->rgb, now * r->channels, r->col_depth, r->image_type, channel);
254 case LQR_CUSTOM_IMAGE:
255 default:
256 #ifdef __LQR_DEBUG__
257 assert(0);
258 #endif /* __LQR_DEBUG__ */
259 return 0;
262 else if (has_alpha)
264 return lqr_pixel_get_norm(r->rgb, now * r->channels + r->alpha_channel, r->col_depth);
266 else
268 return 1;
272 gdouble
273 lqr_carver_read_custom (LqrCarver * r, gint x, gint y, gint channel)
275 gint now = r->raw[y][x];
277 return lqr_pixel_get_norm(r->rgb, now * r->channels + channel, r->col_depth);
283 #if 0
284 /* read average pixel value at x, y
285 * for energy computation */
286 inline gdouble
287 lqr_carver_read_brightness (LqrCarver * r, gint x, gint y)
289 gdouble sum = 0;
290 gint k;
291 gchar has_alpha = (r->alpha_channel >= 0 ? 1 : 0);
292 gchar has_black = (r->black_channel >= 0 ? 1 : 0);
293 guint col_channels = r->channels - has_alpha - has_black;
295 gdouble alpha_fact = 1;
296 gdouble black_fact = 0;
298 gint now = r->raw[y][x];
300 if (has_alpha)
302 alpha_fact = lqr_pixel_get_norm(r->rgb, now * r->channels + r->alpha_channel, r->col_depth);
305 if (has_black)
307 black_fact = lqr_pixel_get_norm(r->rgb, now * r->channels + r->black_channel, r->col_depth);
310 for (k = 0; k < r->channels; k++) if ((k != r->alpha_channel) && (k != r->black_channel))
312 gdouble col = lqr_pixel_get_norm(r->rgb, now * r->channels + k, r->col_depth);
313 sum += 1. - (1. - col) * (1. - black_fact);
316 sum /= col_channels;
318 switch (r->image_type)
320 case LQR_RGB_IMAGE:
321 case LQR_RGBA_IMAGE:
322 case LQR_GREY_IMAGE:
323 case LQR_GREYA_IMAGE:
324 break;
325 case LQR_CMY_IMAGE:
326 case LQR_CMYK_IMAGE:
327 case LQR_CMYKA_IMAGE:
328 sum = 1 - sum;
329 break;
330 case LQR_CUSTOM_IMAGE:
331 if (has_black)
333 sum = 1 - sum;
335 #ifdef __LQR_DEBUG__
336 default:
337 assert (0);
338 #endif /* __LQR_DEBUG__ */
341 if (has_alpha)
343 sum *= alpha_fact;
346 return sum;
348 #endif
350 #if 0
351 inline gdouble
352 lqr_carver_read_brightness_abs (LqrCarver * r, gint x1, gint y1, gint x2, gint y2)
354 gchar has_alpha = (r->alpha_channel > 0 ? 1 : 0);
355 gint p1, p2;
356 gdouble a1, a2;
357 gint k;
358 gdouble sum = 0;
359 p1 = r->raw[y1][x1];
360 p2 = r->raw[y2][x2];
361 if (has_alpha)
363 a1 = R_RGB(r->rgb, p1 * r->channels + r->alpha_channel) / R_RGB_MAX;
364 a2 = R_RGB(r->rgb, p2 * r->channels + r->alpha_channel) / R_RGB_MAX;
366 else
368 a1 = a2 = 1;
370 for (k = 0; k < r->channels; k++) if (k != r->alpha_channel)
372 sum += fabs(R_RGB(r->rgb, p1 * r->channels + 0) * a1 - R_RGB(r->rgb, p2 * r->channels + 0) * a2);
374 return sum / (R_RGB_MAX * (r->channels - has_alpha));
377 inline gdouble
378 lqr_carver_read_luma_abs (LqrCarver * r, gint x1, gint y1, gint x2, gint y2)
380 gint p1, p2;
381 gdouble a1, a2;
382 p1 = r->raw[y1][x1];
383 p2 = r->raw[y2][x2];
384 if (r->image_type == LQR_RGBA_IMAGE)
386 a1 = R_RGB(r->rgb, p1 * r->channels + 3) / R_RGB_MAX;
387 a2 = R_RGB(r->rgb, p2 * r->channels + 3) / R_RGB_MAX;
389 else
391 a1 = a2 = 1;
393 return (0.2126 * fabs(R_RGB(r->rgb, p1 * r->channels + 0) * a1 - R_RGB(r->rgb, p2 * r->channels + 0) * a2) +
394 0.7152 * fabs(R_RGB(r->rgb, p1 * r->channels + 1) * a1 - R_RGB(r->rgb, p2 * r->channels + 1) * a2) +
395 0.0722 * fabs(R_RGB(r->rgb, p1 * r->channels + 2) * a1 - R_RGB(r->rgb, p2 * r->channels + 2) * a2)) /
396 R_RGB_MAX;
398 #endif
400 gdouble
401 lqr_carver_read_cached_std (LqrCarver * r, gint x, gint y)
403 gint z0 = r->raw[y][x];
405 return r->rcache[z0];
408 gdouble
409 lqr_carver_read_cached_rgba (LqrCarver * r, gint x, gint y, gint channel)
411 gint z0 = r->raw[y][x];
413 return r->rcache[z0 * 4 + channel];
416 gdouble
417 lqr_carver_read_cached_custom (LqrCarver * r, gint x, gint y, gint channel)
419 gint z0 = r->raw[y][x];
421 return r->rcache[z0 * r->channels + channel];
424 gfloat
425 lqr_energy_builtin_grad_all (gint x, gint y, gint img_width, gint img_height, LqrReaderWindow * rwindow, LqrGradFunc gf)
427 gdouble gx, gy;
429 gdouble (*bread_func) (LqrReaderWindow *, gint, gint);
431 switch (lqr_rwindow_get_read_t(rwindow))
433 case LQR_ER_BRIGHT:
434 bread_func = lqr_rwindow_read_bright;
435 break;
436 case LQR_ER_LUMA:
437 bread_func = lqr_rwindow_read_luma;
438 break;
439 default:
440 #ifdef __LQR_DEBUG__
441 assert(0);
442 #endif /* __LQR_DEBUG__ */
443 return 0;
446 if (y == 0)
448 gy = bread_func(rwindow, 0, 1) - bread_func(rwindow, 0, 0);
450 else if (y < img_height - 1)
452 gy = (bread_func(rwindow, 0, 1) - bread_func(rwindow, 0, -1)) / 2;
454 else
456 gy = bread_func(rwindow, 0, 0) - bread_func(rwindow, 0, -1);
459 if (x == 0)
461 gx = bread_func(rwindow, 1, 0) - bread_func(rwindow, 0, 0);
463 else if (x < img_width - 1)
465 gx = (bread_func(rwindow, 1, 0) - bread_func(rwindow, -1, 0)) / 2;
467 else
469 gx = bread_func(rwindow, 0, 0) - bread_func(rwindow, -1, 0);
472 return gf(gx, gy);
475 gfloat
476 lqr_energy_builtin_grad_norm (gint x, gint y, gint img_width, gint img_height, LqrReaderWindow * rwindow, gpointer extra_data)
478 return lqr_energy_builtin_grad_all(x, y, img_width, img_height, rwindow, lqr_grad_norm);
481 gfloat
482 lqr_energy_builtin_grad_sumabs (gint x, gint y, gint img_width, gint img_height, LqrReaderWindow * rwindow, gpointer extra_data)
484 return lqr_energy_builtin_grad_all(x, y, img_width, img_height, rwindow, lqr_grad_sumabs);
487 gfloat
488 lqr_energy_builtin_grad_xabs (gint x, gint y, gint img_width, gint img_height, LqrReaderWindow * rwindow, gpointer extra_data)
490 return lqr_energy_builtin_grad_all(x, y, img_width, img_height, rwindow, lqr_grad_xabs);
493 gfloat
494 lqr_energy_builtin_null (gint x, gint y, gint img_width, gint img_height, LqrReaderWindow * rwindow, gpointer extra_data)
496 return 0;
500 #if 0
501 /* compute energy at x, y */
502 gfloat
503 lqr_energy_abs (LqrCarver * r, gint x, gint y)
505 gdouble gx, gy;
507 if (y == 0)
509 gy = (*(r->nrg_builtin->rfabs))(r, x, y + 1, x, y);
511 else if (y < r->h - 1)
513 gy = 0.5 * (*(r->nrg_builtin->rfabs))(r, x, y + 1, x, y - 1);
515 else
517 gy = (*(r->nrg_builtin->rfabs))(r, x, y, x, y - 1);
520 if (x == 0)
522 gx = (*(r->nrg_builtin->rfabs))(r, x + 1, y, x, y);
524 else if (x < r->w - 1)
526 gx = 0.5 * (*(r->nrg_builtin->rfabs))(r, x + 1, y, x - 1, y);
528 else
530 gx = (*(r->nrg_builtin->rfabs))(r, x, y, x - 1, y);
532 return (*(r->nrg_builtin->gf))(gx, gy);
534 #endif
536 /* gradient function for energy computation */
537 LQR_PUBLIC
538 LqrRetVal
539 lqr_carver_set_energy_function_builtin (LqrCarver * r, LqrEnergyFuncBuiltinType ef_ind)
541 switch (ef_ind)
543 case LQR_EF_GRAD_NORM:
544 CATCH (lqr_carver_set_energy_function (r, lqr_energy_builtin_grad_norm, 1, LQR_ER_BRIGHT, NULL));
545 break;
546 case LQR_EF_GRAD_SUMABS:
547 CATCH (lqr_carver_set_energy_function (r, lqr_energy_builtin_grad_sumabs, 1, LQR_ER_BRIGHT, NULL));
548 break;
549 case LQR_EF_GRAD_XABS:
550 CATCH (lqr_carver_set_energy_function (r, lqr_energy_builtin_grad_xabs, 1, LQR_ER_BRIGHT, NULL));
551 break;
552 case LQR_EF_LUMA_GRAD_NORM:
553 CATCH (lqr_carver_set_energy_function (r, lqr_energy_builtin_grad_norm, 1, LQR_ER_LUMA, NULL));
554 break;
555 case LQR_EF_LUMA_GRAD_SUMABS:
556 CATCH (lqr_carver_set_energy_function (r, lqr_energy_builtin_grad_sumabs, 1, LQR_ER_LUMA, NULL));
557 break;
558 case LQR_EF_LUMA_GRAD_XABS:
559 CATCH (lqr_carver_set_energy_function (r, lqr_energy_builtin_grad_xabs, 1, LQR_ER_LUMA, NULL));
560 break;
561 case LQR_EF_NULL:
562 CATCH (lqr_carver_set_energy_function (r, lqr_energy_builtin_null, 0, LQR_ER_BRIGHT, NULL));
563 break;
564 default:
565 return LQR_ERROR;
568 return LQR_OK;
571 LQR_PUBLIC
572 LqrRetVal
573 lqr_carver_set_energy_function (LqrCarver * r, LqrEnergyFunc en_func, gint radius,
574 LqrEnergyReaderType reader_type, gpointer extra_data)
576 CATCH_F (r->root == NULL);
578 r->nrg = en_func;
579 r->nrg_radius = radius;
580 r->nrg_read_t = reader_type;
581 r->nrg_extra_data = extra_data;
583 lqr_rwindow_destroy (r->rwindow);
585 if (reader_type == LQR_ER_CUSTOM)
587 CATCH_MEM (r->rwindow = lqr_rwindow_new_custom (radius, r->use_rcache, r->channels));
589 else
591 CATCH_MEM (r->rwindow = lqr_rwindow_new (radius, reader_type, r->use_rcache));
594 return LQR_OK;
597 gdouble *
598 lqr_carver_generate_rcache_bright (LqrCarver * r)
600 gdouble * buffer;
601 gint x, y;
602 gint z0;
604 TRY_N_N (buffer = g_try_new (gdouble, r->w0 * r->h0));
606 for (y = 0; y < r->h; y++)
608 for (x = 0; x < r->w; x++)
610 z0 = r->raw[y][x];
611 buffer[z0] = lqr_carver_read_brightness (r, x, y);
615 return buffer;
618 gdouble *
619 lqr_carver_generate_rcache_luma (LqrCarver * r)
621 gdouble * buffer;
622 gint x, y;
623 gint z0;
625 TRY_N_N (buffer = g_try_new (gdouble, r->w0 * r->h0));
627 for (y = 0; y < r->h; y++)
629 for (x = 0; x < r->w; x++)
631 z0 = r->raw[y][x];
632 buffer[z0] = lqr_carver_read_luma (r, x, y);
636 return buffer;
639 gdouble *
640 lqr_carver_generate_rcache_rgba (LqrCarver * r)
642 gdouble * buffer;
643 gint x, y, k;
644 gint z0;
646 TRY_N_N (buffer = g_try_new (gdouble, r->w0 * r->h0 * 4));
648 for (y = 0; y < r->h; y++)
650 for (x = 0; x < r->w; x++)
652 z0 = r->raw[y][x];
653 for (k = 0; k < 4; k++)
655 buffer[z0 * 4 + k] = lqr_carver_read_rgba (r, x, y, k);
660 return buffer;
663 gdouble *
664 lqr_carver_generate_rcache_custom (LqrCarver * r)
666 gdouble * buffer;
667 gint x, y, k;
668 gint z0;
670 TRY_N_N (buffer = g_try_new (gdouble, r->w0 * r->h0 * r->channels));
672 for (y = 0; y < r->h; y++)
674 for (x = 0; x < r->w; x++)
676 z0 = r->raw[y][x];
677 for (k = 0; k < r->channels; k++)
679 buffer[z0 * r->channels + k] = lqr_carver_read_custom (r, x, y, k);
684 return buffer;
687 gdouble *
688 lqr_carver_generate_rcache (LqrCarver * r)
690 #ifdef __LQR_DEBUG__
691 assert (r->w == r->w_start - r->max_level + 1);
692 #endif /* __LQR_DEBUG__ */
694 switch (r->nrg_read_t)
696 case LQR_ER_BRIGHT:
697 return lqr_carver_generate_rcache_bright(r);
698 case LQR_ER_LUMA:
699 return lqr_carver_generate_rcache_luma(r);
700 case LQR_ER_RGBA:
701 return lqr_carver_generate_rcache_rgba(r);
702 case LQR_ER_CUSTOM:
703 return lqr_carver_generate_rcache_custom(r);
704 default:
705 #ifdef __LQR_DEBUG__
706 assert(0);
707 #endif /* __LQR_DEBUG__ */
708 return NULL;
712 LQR_PUBLIC
713 LqrCarver *
714 lqr_energy_preview_new (void * buffer, gint width, gint height, gint channels, LqrColDepth colour_depth)
716 LqrCarver * r;
717 TRY_N_N (r = lqr_carver_new_ext (buffer, width, height, channels, colour_depth));
718 lqr_carver_set_preserve_input_image (r);
719 TRY_E_N (lqr_carver_init_energy_related (r));
720 lqr_carver_set_use_cache (r, TRUE);
721 return r;
724 LQR_PUBLIC
725 gfloat *
726 lqr_energy_preview_get_energy(LqrCarver * r, gint orientation)
728 gint x, y;
729 gint z0 = 0;
730 gint w, h;
731 gint buf_size;
732 gint data;
733 gfloat * nrg_buffer;
734 gfloat nrg;
735 gfloat nrg_min = G_MAXFLOAT;
736 gfloat nrg_max = 0;
738 TRY_E_N (orientation == 0 || orientation == 1);
739 TRY_F_N (r->nrg_active);
740 CATCH_CANC_N (r);
742 buf_size = r->w * r->h;
743 TRY_N_N (nrg_buffer = g_try_new (gfloat, buf_size));
745 if (orientation != lqr_carver_get_orientation(r))
747 TRY_E_N (lqr_carver_transpose(r));
749 TRY_E_N (lqr_carver_build_emap (r));
751 w = lqr_carver_get_width(r);
752 h = lqr_carver_get_height(r);
754 for (y = 0; y < h; y++)
756 for (x = 0; x < w; x++)
758 data = orientation == 0 ? r->raw[y][x] : r->raw[x][y];
759 nrg = r->en[data];
760 nrg_max = MAX (nrg_max, nrg);
761 nrg_min = MIN (nrg_min, nrg);
762 nrg_buffer[z0++] = r->en[data];
766 if (nrg_max > 0)
768 for (z0 = 0; z0 < buf_size; z0++)
770 nrg_buffer[z0] = (nrg_buffer[z0] - nrg_min) / (nrg_max - nrg_min);
774 return nrg_buffer;