织梦CMS - 轻松建站从此开始!

罗索

GIMP的柔光(softglow)源码分析

落鹤生 发布于 2013-05-07 22:36 点击:次 
柔光效果可以把一张照片美白化,影楼应该用的比较多。打算把柔光效果用在自己软件中,看GIMP的代码,开始感觉牵扯的比较多,另外找了几个,比如tinyimage,imagestone等。效果也不错,不过看到处理图像大量使用了gdi+,stl,感觉不太合适。再回去认真看GIMP代
TAG:

前言:柔光效果可以把一张照片美白化,影楼应该用的比较多。

打算把柔光效果用在自己软件中,看GIMP的代码,开始感觉牵扯的比较多,另外找了几个,比如tinyimage,imagestone等。效果也不错,不过看到处理图像大量使用了gdi+,stl,感觉不太合适。再回去认真看GIMP代码,最终成功移植到vc和iOS下。

效果:

     

采用的是美图秀秀软件下面的一张图,如果有版权问题,请联系,及时删掉。不过说实话,美图秀秀还有很大可优化空间。尤其是处理图片的时候,能不能先对缩略图处理一下?直接对大图动手,什么CPU也受不了。

处理的参数是 SoftglowVals svals = {10, 0.5, 0.6};

有兴趣的朋友可以用GIMP自己处理到满意的程度,记住参数,再用程序来实现。这里只是演示功能,不考虑美观效果,有可能处理后比处理前还难看。

一 gimp softglow(柔光)分析

代码在 gimp-2.8.0\plug-ins\common\softglow.c里面。
1 选中显示图像的一部分
2 对选中部分进行亮度,锐度计算,保存在 width X height数组内。(图像的原始数据区是width X height X bytes per pixel)
3 高斯模糊计算

//  Calculate the standard deviations  
  radius  = fabs (svals.glow_radius) + 1.0;
  std_dev = sqrt (-(radius * radius) / (2 * log (1.0 / 255.0)));

  //  derive the constants for calculating the gaussian from the std dev  
  find_constants(n_p, n_m, d_p, d_m, bd_p, bd_m, std_dev);
根据半径算出高斯模板的矩阵值。find_constants里面计算的是5x5矩阵。
4 再根据原始图像数据,计算出目标图像数据。

计算公式:
255 - INT_MULT((255 - src_ptr[col * bytes + b]), (255 - blur_ptr[col]), tmp);

5 把目标数据保存成图,就得到了柔光的结果。

总结:
算法比较简单,需要注意的是,原程序里读原始图像数据,使用的是gimp提供的api,比如图像数据是drawable,需要改写成从DC里取值,或直接从文件里读。

二 改造

毕竟gimp不是通常用c/c++库,如果用在自己项目里,是需要进行一些处理的。
改造从几个方面进行:
1 读写图像:推荐用FreeImage
2 显示图像:使用到drawable和rgn的地方要改。
3 算法:基本不用动,只是要加一些注释,源码过于简洁,比如

  1. double       n_p[5], n_m[5]; 
  2. double       d_p[5], d_m[5]; 
  3. double       bd_p[5], bd_m[5]; 
  4.  
  5.  
  6. static void 
  7. find_constants (gdouble n_p[], 
  8.                 gdouble n_m[], 
  9.                 gdouble d_p[], 
  10.                 gdouble d_m[], 
  11.                 gdouble bd_p[], 
  12.                 gdouble bd_m[], 
  13.                 gdouble std_dev) 
  14.   gint    i; 
  15.   gdouble constants [8]; 
  16.   gdouble div; 
  17.  
  18.  
  19.   /*  The constants used in the implemenation of a casual sequence 
  20.    *  using a 4th order approximation of the gaussian operator 
  21.    */ 
  22.  
  23.  
  24.   div = sqrt(2 * G_PI) * std_dev; 
  25.  
  26.  
  27.   constants [0] = -1.783  / std_dev; 
  28.   constants [1] = -1.723  / std_dev; 
  29.   constants [2] =  0.6318 / std_dev; 
  30.   constants [3] =  1.997  / std_dev; 
  31.   constants [4] =  1.6803 / div; 
  32.   constants [5] =  3.735  / div; 
  33.   constants [6] = -0.6803 / div; 
  34.   constants [7] = -0.2598 / div; 
  35.  
  36.  
  37.   n_p [0] = constants[4] + constants[6]; 
  38.   n_p [1] = exp (constants[1]) * 
  39.     (constants[7] * sin (constants[3]) - 
  40.      (constants[6] + 2 * constants[4]) * cos (constants[3])) + 
  41.        exp (constants[0]) * 
  42.          (constants[5] * sin (constants[2]) - 
  43.           (2 * constants[6] + constants[4]) * cos (constants[2])); 
  44.   n_p [2] = 2 * exp (constants[0] + constants[1]) * 
  45.     ((constants[4] + constants[6]) * cos (constants[3]) * cos (constants[2]) - 
  46.      constants[5] * cos (constants[3]) * sin (constants[2]) - 
  47.      constants[7] * cos (constants[2]) * sin (constants[3])) + 
  48.        constants[6] * exp (2 * constants[0]) + 
  49.          constants[4] * exp (2 * constants[1]); 
  50.   n_p [3] = exp (constants[1] + 2 * constants[0]) * 
  51.     (constants[7] * sin (constants[3]) - constants[6] * cos (constants[3])) + 
  52.       exp (constants[0] + 2 * constants[1]) * 
  53.         (constants[5] * sin (constants[2]) - constants[4] * cos (constants[2])); 
  54.   n_p [4] = 0.0; 
  55.  
  56.  
  57.   d_p [0] = 0.0; 
  58.   d_p [1] = -2 * exp (constants[1]) * cos (constants[3]) - 
  59.     2 * exp (constants[0]) * cos (constants[2]); 
  60.   d_p [2] = 4 * cos (constants[3]) * cos (constants[2]) * exp (constants[0] + constants[1]) + 
  61.     exp (2 * constants[1]) + exp (2 * constants[0]); 
  62.   d_p [3] = -2 * cos (constants[2]) * exp (constants[0] + 2 * constants[1]) - 
  63.     2 * cos (constants[3]) * exp (constants[1] + 2 * constants[0]); 
  64.   d_p [4] = exp (2 * constants[0] + 2 * constants[1]); 
  65.  
  66.  
  67. #ifndef ORIGINAL_READABLE_CODE 
  68.   memcpy(d_m, d_p, 5 * sizeof(gdouble)); 
  69. #else 
  70.   for (i = 0; i <= 4; i++) 
  71.     d_m [i] = d_p [i]; 
  72. #endif 
  73.  
  74.  
  75.   n_m[0] = 0.0; 
  76.   for (i = 1; i <= 4; i++) 
  77.     n_m [i] = n_p[i] - d_p[i] * n_p[0]; 
  78.  
  79.  
  80.   { 
  81.     gdouble sum_n_p, sum_n_m, sum_d; 
  82.     gdouble a, b; 
  83.  
  84.  
  85.     sum_n_p = 0.0; 
  86.     sum_n_m = 0.0; 
  87.     sum_d   = 0.0; 
  88.  
  89.  
  90.     for (i = 0; i <= 4; i++) 
  91.       { 
  92.         sum_n_p += n_p[i]; 
  93.         sum_n_m += n_m[i]; 
  94.         sum_d += d_p[i]; 
  95.       } 
  96.  
  97.  
  98. #ifndef ORIGINAL_READABLE_CODE 
  99.     sum_d++; 
  100.     a = sum_n_p / sum_d; 
  101.     b = sum_n_m / sum_d; 
  102. #else 
  103.     a = sum_n_p / (1 + sum_d); 
  104.     b = sum_n_m / (1 + sum_d); 
  105. #endif 
  106.  
  107.  
  108.     for (i = 0; i <= 4; i++) 
  109.       { 
  110.         bd_p[i] = d_p[i] * a; 
  111.         bd_m[i] = d_m[i] * b; 
  112.       } 
  113.   } 

总结:刚看gimp代码时,的确一头雾水。这时需要九方皋相马的方式,透过现象看本质。

比如:

  1. guchar *src_ptr  = src_rgn.data; 
  2. guchar *dest_ptr = dest_rgn.data;  

 

如果修改成标准c的写法就是:

  1. uint8_t* src_ptr = image_src.accessPixels(); 
  2. uint8_t*dest_ptr = new uint8_t[image_src.getImageSize()];  

//以上假设是对整图处理,如果对部分处理的话,自己定义个矩形,选中图像数据,比如可以使用FreeImage的crop函数读选中区域。

(sxcong)
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/201305/16620.html]
本文出处:ChinaUnix 作者:sxcong 原文
顶一下
(1)
100%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容