PageRenderTime 56ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 1ms

/gimp-plugin-dcamnoise2/dcamnoise2-0.64.cpp

https://bitbucket.org/axil42/aur-mirror
C++ | 1333 lines | 889 code | 297 blank | 147 comment | 100 complexity | ace7859517a7d161abe47b6f0eb4281a MD5 | raw file
Possible License(s): IPL-1.0, Apache-2.0, LGPL-2.0, Unlicense, MPL-2.0-no-copyleft-exception, LGPL-2.1, JSON, GPL-3.0, MPL-2.0, CC0-1.0, CC-BY-SA-3.0, LGPL-3.0, WTFPL, BSD-2-Clause, 0BSD, BitTorrent-1.0, Cube, EPL-1.0, ISC, BSD-3-Clause, AGPL-3.0, GPL-2.0, MIT, AGPL-1.0, CC-BY-3.0
  1. /*
  2. * Copyright (C) 2005 Peter Heckert
  3. * <peter /dot/ heckert /at/ arcor /dot/ de>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  18. */
  19. /*
  20. * =========Version History=============
  21. * Version 0.64 24.Apr. 2006
  22. * Started major rewrite.
  23. * Move to c++.
  24. * Removed IIR filter,implemented FIR filter
  25. * Better sharpness, easier to adjust.
  26. *
  27. *
  28. */
  29. #define STANDALONE
  30. #ifndef STANDALONE
  31. #include "config.h"
  32. #endif
  33. #include <stdlib.h>
  34. #include <string.h>
  35. #include <stdio.h>
  36. #include <gtk/gtk.h>
  37. #include <libgimp/gimp.h>
  38. #include <libgimp/gimpui.h>
  39. #ifdef STANDALONE
  40. #define INIT_I18N voidproc
  41. void voidproc(void){};
  42. #define _(x) (x)
  43. #define N_(x) (x)
  44. #else
  45. #include "libgimp/stdplugins-intl.h"
  46. #endif
  47. #define PLUG_IN_VERSION "0.64"
  48. #define SCALE_WIDTH 150
  49. #define ENTRY_WIDTH 4
  50. // This is for testing only!
  51. //#define float double
  52. //#define gfloat gdouble
  53. /* Uncomment this line to get a rough estimate of how long the plug-in
  54. * takes to run.
  55. */
  56. /* #define TIMER */
  57. typedef struct
  58. {
  59. gdouble radius;
  60. gdouble lsmooth;
  61. gdouble csmooth;
  62. gdouble effect;
  63. gdouble lookahead;
  64. gdouble gamma;
  65. gdouble damping;
  66. gdouble phase;
  67. gdouble texture;
  68. gdouble sharp;
  69. gboolean update_preview;
  70. }
  71. UnsharpMaskParams;
  72. typedef struct
  73. {
  74. gboolean run;
  75. }
  76. UnsharpMaskInterface;
  77. /* local function prototypes */
  78. static void query (void);
  79. static void run (const gchar *name,
  80. gint nparams,
  81. const GimpParam *param,
  82. gint *nreturn_vals,
  83. GimpParam **return_vals);
  84. static void blur_line (gfloat * const data,
  85. gfloat * const data2,
  86. gfloat * const buffer,
  87. gfloat *rbuf,
  88. gfloat *tbuf,
  89. const guchar *src,
  90. guchar *dest,
  91. gint len,
  92. glong bytes);
  93. static void unsharp_region (GimpPixelRgn *srcPTR,
  94. GimpPixelRgn *dstPTR,
  95. gint bytes,
  96. gdouble radius,
  97. gdouble lsmooth,
  98. gint x1,
  99. gint x2,
  100. gint y1,
  101. gint y2,
  102. gboolean show_progress);
  103. static void noise_filter (GimpDrawable *drawable,
  104. gdouble radius,
  105. gdouble lsmooth);
  106. static gboolean unsharp_mask_dialog (GimpDrawable *drawable);
  107. static void preview_update (GimpPreview *preview);
  108. /* create a few globals, set default values */
  109. static UnsharpMaskParams unsharp_params =
  110. {
  111. 5.0, /* default radius = 5 */
  112. 1.0, /* Luminance Tolerance */
  113. 1.0, /* RGB Tolerance */
  114. 0.13, /* Adaptive filter-effect threshold */
  115. 2.0, /* Lookahead */
  116. 1.4, /* Filter gamma */
  117. 5.0, /* Phase jitter Damping */
  118. 2.0, /* Edge Erosion */
  119. 0.0, /* Texture Detail */
  120. 0.25, /* Sharpness factor */
  121. TRUE /* default is to update the preview */
  122. /* These values are values that I used for a test image with some success.
  123. They are not optimal for every image*/
  124. };
  125. /* Setting PLUG_IN_INFO */
  126. GimpPlugInInfo PLUG_IN_INFO =
  127. {
  128. NULL, /* init_proc */
  129. NULL, /* quit_proc */
  130. query, /* query_proc */
  131. run, /* run_proc */
  132. };
  133. static inline gdouble bsq(gdouble val)
  134. {
  135. return fabs(val) * val;
  136. }
  137. static inline gdouble sq(gdouble val)
  138. {
  139. return val*val;
  140. }
  141. class class_Gauss
  142. {
  143. public:
  144. void init(float val){
  145. for(int i=0;i<257;i++) curve[i+1] = exp(-sq((float)i)/(2.0*val*val));
  146. curve[0]=curve[2];
  147. }
  148. inline float g(float val)
  149. {
  150. const float * const lut = curve+1;
  151. val = fabs(val);
  152. if (val >= 1.0) return 0.0;
  153. const int idx = lrint (val*255.0);
  154. const float xv = (val-(float) idx/255.0)/255.0;
  155. const float yenv = (lut[idx-1] + lut[idx+1])/2.0;
  156. const float y0=lut[idx];
  157. //calculate result using stirlings interpolation
  158. return (y0 + (((yenv) +(yenv-y0)*0.5)*xv)*xv);
  159. }
  160. private:
  161. float curve[258];
  162. };
  163. class_Gauss gausst,gausst2;
  164. class Lut
  165. {
  166. public:
  167. inline float g(float val){return _gamma(val,lut+1);}
  168. inline float g_inv(float val){return _gamma(val,inv_lut+1);}
  169. void init(float);
  170. private:
  171. float _gamma(float, float const * const);
  172. float lut[258];
  173. float inv_lut[258];
  174. };
  175. void Lut::init(float val)
  176. {
  177. for (int i=0; i<=257; i++)
  178. {
  179. lut[i+1] = pow((float) i/255.0,val);
  180. inv_lut[i+1] = pow((float) i/255.0,1.0/val);
  181. }
  182. lut[0] = -lut[2];
  183. inv_lut[0] = -inv_lut[2];
  184. }
  185. float Lut::_gamma(float val, float const * const lut)
  186. {
  187. const float s = (val < 0.0 ? -1.0:1.0);
  188. val = fabs(val);
  189. if (val >= 1.0) return s;
  190. const int idx = lrint (val*255.0);
  191. const float xv = 0.5*(val-(float) idx/255.0)/255.0;
  192. const float yenv = (lut[idx-1] + lut[idx+1]);
  193. const float y0=lut[idx];
  194. //calculate result using stirlings interpolation
  195. return (y0 + (yenv-(yenv-y0-y0)*xv)*xv)*s;
  196. }
  197. Lut image_gamma,texture_gamma;
  198. MAIN ()
  199. static void query (void)
  200. {
  201. static GimpParamDef args[] =
  202. {
  203. { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
  204. { GIMP_PDB_IMAGE, "image", "(unused)" },
  205. { GIMP_PDB_DRAWABLE, "drawable", "Drawable to draw on" },
  206. { GIMP_PDB_FLOAT, "radius", "Radius of gaussian blur (in pixels)" },
  207. { GIMP_PDB_FLOAT, "lsmooth", "Luminance Tolerance" },
  208. { GIMP_PDB_FLOAT, "csmooth", "Color Tolerance" },
  209. { GIMP_PDB_FLOAT, "effect", "Threshold for 2nd derivative of luminance" },
  210. { GIMP_PDB_FLOAT, "lookahead", "Sharpness" } ,
  211. { GIMP_PDB_FLOAT, "gamma", "Gamma" } ,
  212. { GIMP_PDB_FLOAT, "damping", "Phase jitter damping" },
  213. { GIMP_PDB_FLOAT, "phase", "Phase shift for edges" },
  214. { GIMP_PDB_FLOAT, "texture", "Texture accuracy" },
  215. { GIMP_PDB_FLOAT, "sharp", "Edge accuracy" }
  216. };
  217. gimp_install_procedure ("plug_in_dcamnoise2-"PLUG_IN_VERSION,
  218. "A Digital Camera Noise filter",
  219. "It is commonly "
  220. "used on photographic images, and is provides a much "
  221. "more pleasing result than the standard denoising "
  222. "filters.",
  223. "This is an experimental version. ",
  224. "",
  225. "",
  226. N_("_Dcam Noise 2 "PLUG_IN_VERSION" ..."),
  227. "GRAY*, RGB*",
  228. GIMP_PLUGIN,
  229. G_N_ELEMENTS (args), 0,
  230. args, NULL);
  231. gimp_plugin_menu_register ("plug_in_dcamnoise2-"PLUG_IN_VERSION,
  232. "<Image>/Filters/Enhance");
  233. }
  234. static void
  235. run (const gchar *name,
  236. gint nparams,
  237. const GimpParam *param,
  238. gint *nreturn_vals,
  239. GimpParam **return_vals)
  240. {
  241. static GimpParam values[1];
  242. GimpPDBStatusType status = GIMP_PDB_SUCCESS;
  243. GimpDrawable *drawable;
  244. GimpRunMode run_mode;
  245. #ifdef TIMER
  246. GTimer *timer = g_timer_new ();
  247. #endif
  248. run_mode = (GimpRunMode) param[0].data.d_int32;
  249. *return_vals = values;
  250. *nreturn_vals = 1;
  251. values[0].type = GIMP_PDB_STATUS;
  252. values[0].data.d_status = status;
  253. INIT_I18N ();
  254. /*
  255. * Get drawable information...
  256. */
  257. drawable = gimp_drawable_get (param[2].data.d_drawable);
  258. gimp_tile_cache_ntiles (2 * (drawable->width / gimp_tile_width () + 1));
  259. switch (run_mode)
  260. {
  261. case GIMP_RUN_INTERACTIVE:
  262. gimp_get_data ("plug_in_dcamnoise2-"PLUG_IN_VERSION, &unsharp_params);
  263. /* Reset default values show preview unmodified */
  264. /* initialize pixel regions and buffer */
  265. if (! unsharp_mask_dialog (drawable))
  266. return;
  267. break;
  268. case GIMP_RUN_NONINTERACTIVE:
  269. if (nparams != 13)
  270. {
  271. status = GIMP_PDB_CALLING_ERROR;
  272. }
  273. else
  274. {
  275. unsharp_params.radius = param[3].data.d_float;
  276. unsharp_params.lsmooth = param[4].data.d_float;
  277. unsharp_params.csmooth = param[5].data.d_float;
  278. unsharp_params.effect = param[6].data.d_float;
  279. unsharp_params.lookahead = param[7].data.d_float;
  280. unsharp_params.gamma = param[8].data.d_float;
  281. unsharp_params.damping = param[9].data.d_float;
  282. unsharp_params.phase = param[10].data.d_float;
  283. unsharp_params.texture = param[11].data.d_float;
  284. unsharp_params.sharp = param[12].data.d_float;
  285. /* make sure there are legal values */
  286. if ((unsharp_params.radius < 0.0) ||
  287. (unsharp_params.lsmooth < 0.0))
  288. status = GIMP_PDB_CALLING_ERROR;
  289. }
  290. break;
  291. case GIMP_RUN_WITH_LAST_VALS:
  292. gimp_get_data ("plug_in_dcamnoise2-"PLUG_IN_VERSION, &unsharp_params);
  293. break;
  294. default:
  295. break;
  296. }
  297. if (status == GIMP_PDB_SUCCESS)
  298. {
  299. drawable = gimp_drawable_get (param[2].data.d_drawable);
  300. /* here we go */
  301. noise_filter (drawable, unsharp_params.radius, unsharp_params.lsmooth);
  302. gimp_displays_flush ();
  303. /* set data for next use of filter */
  304. gimp_set_data ("plug_in_dcamnoise2-"PLUG_IN_VERSION, &unsharp_params,
  305. sizeof (UnsharpMaskParams));
  306. gimp_drawable_detach(drawable);
  307. values[0].data.d_status = status;
  308. }
  309. #ifdef TIMER
  310. g_printerr ("%f seconds\n", g_timer_elapsed (timer, NULL));
  311. g_timer_destroy (timer);
  312. #endif
  313. }
  314. static inline gdouble bsqrt(gdouble val)
  315. {
  316. if (val >= 0.0) return sqrt(val);
  317. else return -sqrt(-val);
  318. }
  319. static inline gdouble mypow( gdouble val,gdouble ex)
  320. {
  321. //TODO: The mypow function needs 50% of runtime.
  322. // Develop faster approximation method for speedup.
  323. // No need for more accuracy as 10% here, however
  324. // the approximation mut be smooth and the inverse
  325. // must be accurate
  326. // e.g. mypow(mypow(x,1/y),y) must give 1.0 with at least 0.1 % accuracy
  327. if (fabs(val) < 1e-16) return 0;
  328. if (val > 0.0) return exp2(log2(val)*ex);
  329. return -exp2(log2(-val)*ex);
  330. }
  331. #if 0
  332. static void box_filter(float *src, float *end, float * dest, float radius)
  333. /* src and dest must be different */
  334. {
  335. gfloat fbw = 2.0 * radius;
  336. if (fbw < 1.0) fbw = 1.0;
  337. gfloat box = (*src);
  338. gint boxwidth=1;
  339. while(boxwidth+2 <= (int) fbw) boxwidth+=2, box += (src[boxwidth/2]) + (src[-boxwidth/2]);
  340. gdouble frac = (fbw - (gdouble) boxwidth)/2.0;
  341. gint bh = boxwidth/2, bh1 =boxwidth/2+1;
  342. for ( ; src <= end; src++, dest++)
  343. {
  344. *dest = (box + frac * ((src[bh1])+(src[-bh1])))/fbw;
  345. box = box - (src[-bh]) + (src[bh1]);
  346. }
  347. }
  348. #endif
  349. static float *scratch;
  350. static void fir_filter(float * const start,
  351. float * const end,
  352. float * dstart,
  353. float radius,
  354. const gint type)
  355. {
  356. if (!dstart) dstart = start;
  357. gfloat *src = start;
  358. gfloat *dest = dstart;
  359. gfloat *dend = dstart + (end - start);
  360. gfloat gain;
  361. if (type == 2)
  362. memcpy(scratch,start,sizeof(*start)*(end-start));
  363. {
  364. const float boxwidth = radius *2.0;
  365. const int intboxwidth = (int) boxwidth;
  366. const float fracboxwidth = boxwidth-(float) intboxwidth;
  367. const int tail=intboxwidth+1;
  368. float box = *src;
  369. //forward pass 1
  370. for (int i = 0; i < intboxwidth;i++)
  371. box += *(++src);
  372. dest += intboxwidth;
  373. while (++src <=end )
  374. {
  375. box = box - src[-tail]+src[0];
  376. (++dest)[-tail] = box +src[-tail]*fracboxwidth;
  377. }
  378. for (dest -= tail,src -= tail; src <= end; src++,dest++)
  379. *dest = *src * boxwidth;
  380. // backward pass 1
  381. box = *(--dest);
  382. for (int i = 0; i < intboxwidth;i++)
  383. box += *(--dest);
  384. while (--dest >= dstart )
  385. {
  386. box = box - dest[tail]+dest[0];
  387. dest[tail] = box + dest[tail]*fracboxwidth;
  388. }
  389. for (dest += tail; dest >= dstart;dest--)
  390. *dest *= boxwidth;
  391. gain= sq(1.0+boxwidth);
  392. }
  393. {
  394. const float boxwidth = radius*1.5;
  395. const int intboxwidth = (int) boxwidth;
  396. const float fracboxwidth = boxwidth-(float) intboxwidth;
  397. const int tail=intboxwidth+1;
  398. float box = 0.0;
  399. gain *= sq(1.0+boxwidth);
  400. const float gaincompensation = 1.0/gain;
  401. // forward pass 2
  402. box = *(++dest);
  403. for (int i = 0; i < intboxwidth;i++)
  404. box += *(++dest);
  405. while (++dest <= dend )
  406. {
  407. box = box - dest[-tail]+dest[0];
  408. dest[-tail] = box + dest[-tail]*fracboxwidth;
  409. }
  410. for (dest -= tail; dest <= dend;dest++)
  411. *dest *= boxwidth;
  412. //backward pass 2
  413. box = *(--dest);
  414. for (int i = 0; i < intboxwidth;i++)
  415. box += *(--dest);
  416. while (--dest >= dstart )
  417. {
  418. box = box - dest[tail]+dest[0];
  419. dest[tail] = (box + dest[tail]*fracboxwidth)*gaincompensation;
  420. }
  421. for (dest += tail; dest >= dstart;dest--)
  422. *dest *= boxwidth;
  423. switch(type)
  424. {
  425. case 0: break;
  426. case 1: break;
  427. // Unsharp-Mask type highpassfilter
  428. case 2:
  429. src= scratch;
  430. dest = dstart;
  431. for ( ;dest<=dend;dest++,src++)
  432. {
  433. *dest = fabs(*dest - *src);
  434. }
  435. break;
  436. #if 0
  437. //2nd derivative
  438. case 2:
  439. gint ofs = (int) radius;
  440. if (ofs < 1) ofs=1;
  441. dest += ofs+1;
  442. while (++dest <= dend)
  443. dest[-ofs] -= *dest;
  444. dest -= ofs-1;
  445. while (--dest >= dstart)
  446. dest[ofs] = fabs(dest[ofs]-*dest);
  447. break;
  448. #endif
  449. }
  450. }
  451. }
  452. //define FR 0.3
  453. //define FG 0.59
  454. //#define FB 0.11
  455. #define FR 0.212671
  456. #define FG 0.715160
  457. #define FB 0.072169
  458. static void filter(gfloat *buffer, gfloat *data, gfloat *data2, gfloat *rbuf, gfloat *tbuf, gint width, gint color)
  459. /*
  460. * A forward-backward box filter is used here and the radius is adapted to luminance jump.
  461. * Radius is calculated from 2nd derivative of intensity values.
  462. * (Its not exactly 2nd derivative, but something similar, optimized by experiment)
  463. * The radius variations are filtered. This reduces spatial phase jitter.
  464. *
  465. */
  466. {
  467. gfloat *lp = data, *rp = data + width-1;
  468. gfloat *lp2 = data2;
  469. gfloat *blp = buffer, *brp = buffer + width-1;
  470. gfloat *rbuflp = rbuf, *rbufrp = rbuf + width-1;
  471. gfloat *p1,*p2;
  472. gfloat fboxwidth = unsharp_params.radius*2.0;
  473. gfloat fradius = unsharp_params.radius;
  474. if (fboxwidth < 1.0) fboxwidth = 1.0 ;
  475. if (fradius < 0.5) fradius = 0.5;
  476. gint i;
  477. gint ofs,ofs2;
  478. gfloat maxrad;
  479. gfloat fbw;
  480. gfloat val;
  481. gdouble rfact = sq(unsharp_params.effect);
  482. gdouble sharp=unsharp_params.sharp;
  483. ofs2 = (int) floor(unsharp_params.damping*2.0+0.1);
  484. ofs = (int) floor(unsharp_params.lookahead*2.0+0.1);
  485. gint pass,w=(int) (fboxwidth*2+unsharp_params.damping+unsharp_params.lookahead+unsharp_params.phase + 2.0);
  486. for (i=1; i <= w; i++) blp[-i]=blp[i]; /* Mirror image edges */
  487. for (i=1; i <= w; i++) brp[i] = brp[-i];
  488. if (color < 0)
  489. {
  490. /* Calc 2nd derivative */
  491. for (p1 = blp,p2=rbuflp;p1<= brp;p1++,p2++)
  492. { /* boost high frequency in rbuf */
  493. *p2 = (sharp+1.0) * p1[0] - sharp * 0.5 * (p1[-ofs]+p1[ofs]);
  494. }
  495. fir_filter(rbuflp-w,rbufrp+w,blp-w,unsharp_params.lookahead,2);
  496. for (i=1; i <= w; i++) blp[-i]=blp[i]; /* Mirror image edges */
  497. for (i=1; i <= w; i++) brp[i] = brp[-i];
  498. // for (p1 = blp,p2=rbuflp;p1<= brp;p1++,p2++)
  499. // { /* boost high frequency in rbuf */
  500. // *p2 = ((sharp+1.0) * (p1[0]) - sharp * 0.5 * ((p1[-ofs])+(p1[ofs])));
  501. // }
  502. memcpy(rbuflp,blp,(brp-blp)*sizeof(*blp));
  503. for (i=1; i <= w; i++) rbuflp[-i]=rbuflp[i]; /* Mirror rbuf edges */
  504. for (i=1; i <= w; i++) rbufrp[i] = rbufrp[-i];
  505. /* Lowpass (gauss) filter rbuf, remove phase jitter */
  506. fir_filter(rbuflp-w+5,rbufrp+w-5,rbuflp-w+5,unsharp_params.damping,0);
  507. for (i=-w+5; i< width-1+w-5;i++)
  508. {
  509. // val = rbuflp[i];
  510. val = rbuflp[i]-rfact;
  511. if (val < rfact/fradius) val=rfact/fradius; /* Avoid division by zero, clip negative filter overshoot */
  512. val = rfact/val;
  513. // val = mypow(val/fradius,unsharp_params.phase)*fradius;
  514. if (val < 0.5) val = 0.5;
  515. rbuflp[i] = val*2.0;
  516. }
  517. for (i=1; i <= w; i++) rbuflp[-i]=rbuflp[i]; /* Mirror rbuf edges */
  518. for (i=1; i <= w; i++) rbufrp[i] = rbufrp[-i];
  519. return;
  520. } /* if color < 0 */
  521. /* Calc lowpass filtered input signal */
  522. fir_filter(blp-w+1,brp+w-1,lp2-w+1,unsharp_params.radius,0);
  523. /* Subtract low frequency from input signal (aka original image data)
  524. * and predistort this signal
  525. */
  526. val = unsharp_params.texture+1.0;
  527. for (i = -w+1;i <= width-1+w-1;i++)
  528. {
  529. blp[i] = texture_gamma.g(blp[i]- lp2[i]);
  530. }
  531. gfloat *src, *dest;
  532. val = unsharp_params.texture+1.0;
  533. pass = 2;
  534. while (pass--)
  535. {
  536. gint ibw;
  537. src = blp;
  538. dest =lp;
  539. gfloat sum;
  540. maxrad = 0.0;
  541. for (i=1; i <= w; i++) src[-i]=src[i]; /* Mirror left edge */
  542. sum = (src[-1] += src[-2]);
  543. /* forward pass */
  544. for (rbuf = rbuflp - (int) unsharp_params.phase; rbuf <= rbufrp; src++, dest++, rbuf++)
  545. {
  546. //fbw = fabs( rbuf[-ofs2]*ll2+rbuf[-ofs2-1]*rl2);
  547. fbw = *rbuf;
  548. if (fbw > (maxrad += 1.0)) fbw = maxrad;
  549. else if (fbw < maxrad) maxrad = fbw;
  550. ibw = (gint) fbw;
  551. *src = sum += *src;
  552. *dest = (sum-src[-ibw]+(src[-ibw]-src[-ibw-1])*(fbw-ibw))/fbw;
  553. }
  554. src = rp;
  555. dest = brp;
  556. maxrad = 0.0;
  557. for (i=1; i <= w; i++) src[i] = src[-i]; /* Mirror right edge */
  558. sum = (src[1] += src[2]);
  559. /* backward pass */
  560. for ( rbuf = rbufrp + (int) unsharp_params.phase; rbuf >= rbuflp; src--, dest--, rbuf--)
  561. {
  562. //fbw = fabs( rbuf[ofs2]*ll2+rbuf[ofs2+1]*rl2);
  563. fbw = *rbuf;
  564. if (fbw > (maxrad +=1.0)) fbw = maxrad;
  565. else if (fbw < maxrad) maxrad = fbw;
  566. ibw = (gint) fbw;
  567. *src = sum += *src;
  568. *dest = (sum-src[ibw]+(src[ibw]-src[ibw+1])*(fbw-ibw))/fbw;
  569. }
  570. } /* Next pass */
  571. for (i = -w+1;i <= width-1+w-1;i++)
  572. {
  573. /* Undo predistortion */
  574. blp[i]= texture_gamma.g_inv(blp[i]);
  575. blp[i] += lp2[i]; /* Add in low frequency */
  576. // if (blp[i] >= 0.0) blp[i] = mypow(blp[i],val);
  577. // else blp[i] = 0.0;
  578. }
  579. }
  580. /* This function is written as if it is blurring a column at a time,
  581. * even though it can operate on rows, too. There is no difference
  582. * in the processing of the lines, at least to the blur_line function.
  583. */
  584. static void
  585. blur_line (gfloat * const data,
  586. gfloat * const data2,
  587. gfloat * const buffer,
  588. gfloat * rbuf,
  589. gfloat * tbuf,
  590. const guchar *src,
  591. guchar *dest,
  592. gint len, /* length of src and dest */
  593. glong bytes) /* Bits per plane */
  594. {
  595. gint b;
  596. gint row;
  597. gint colors = 3;
  598. if (bytes < 3) colors = 1;
  599. gint idx;
  600. /* Calculate radius factors */
  601. if (colors < 3)
  602. {
  603. for (row =0, idx=0 ; idx < len; row +=bytes, idx++) data[idx] = image_gamma.g((float) dest[row]/255.0);
  604. filter(data, data2, buffer,rbuf,tbuf, len, -1);
  605. }
  606. else
  607. {
  608. for (row =0, idx=0 ; idx < len; row +=bytes, idx++)
  609. {
  610. /* Color weigths are choosen proportional to Bayer Sensor pixel count */
  611. data[idx] = (gfloat) dest[row] / 255.0 * 0.25; /* Red color */
  612. data[idx] += (gfloat) dest[row+1] / 255.0 * 0.5; /* Green color */
  613. data[idx] += (gfloat) dest[row+2] / 255.0 * 0.25; /* Blue color */
  614. data[idx] = image_gamma.g(data[idx]);
  615. }
  616. filter(data, data2, buffer,rbuf,tbuf, len, -1);
  617. }
  618. /* Do actual filtering */
  619. for (b = 0; b<colors; b++)
  620. {
  621. for (row =b, idx=0 ; idx < len; row +=bytes, idx++) data[idx] = image_gamma.g(src[row]/255.0);
  622. filter(data, data2, buffer,rbuf,tbuf, len, b);
  623. for (row =b, idx=0; idx < len; row +=bytes, idx++)
  624. {
  625. gint value = (int) (image_gamma.g_inv(data[idx])*255.0+0.5);
  626. dest[row] = CLAMP( value, 0, 255);
  627. }
  628. }
  629. }
  630. static void
  631. noise_filter (GimpDrawable *drawable,
  632. gdouble radius,
  633. gdouble lsmooth)
  634. {
  635. GimpPixelRgn srcPR, destPR;
  636. gint x1, y1, x2, y2;
  637. /* initialize pixel regions */
  638. gimp_pixel_rgn_init (&srcPR, drawable,
  639. 0, 0, drawable->width, drawable->height, FALSE, FALSE);
  640. gimp_pixel_rgn_init (&destPR, drawable,
  641. 0, 0, drawable->width, drawable->height, TRUE, TRUE);
  642. /* Get the input */
  643. gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2);
  644. unsharp_region (&srcPR, &destPR, drawable->bpp,
  645. radius, lsmooth,
  646. x1, x2, y1, y2,
  647. TRUE);
  648. gimp_drawable_flush (drawable);
  649. gimp_drawable_merge_shadow (drawable->drawable_id, TRUE);
  650. gimp_drawable_update (drawable->drawable_id, x1, y1, x2 - x1, y2 - y1);
  651. }
  652. /* Remove noise on the region, given a source region, dest.
  653. * region, width and height of the regions, and corner coordinates of
  654. * a subregion to act upon. Everything outside the subregion is unaffected.
  655. */
  656. static void
  657. unsharp_region (GimpPixelRgn *srcPR,
  658. GimpPixelRgn *destPR,
  659. gint bytes, /* Bytes per pixel */
  660. gdouble radius,
  661. gdouble lsmooth,
  662. gint x1, /* Corners of subregion */
  663. gint x2,
  664. gint y1,
  665. gint y2,
  666. gboolean show_progress)
  667. {
  668. guchar *src;
  669. guchar *dest;
  670. gint width = x2 - x1;
  671. gint height = y2 - y1;
  672. gfloat *data, *data2;
  673. gfloat *buffer=NULL;
  674. gint row, col,i;
  675. gfloat prob = 0.0;
  676. gint w = (int)((radius*5+unsharp_params.lookahead+unsharp_params.damping+unsharp_params.phase) * 4.0 + 40.0);
  677. // if (radius < unsharp_params.lookahead) w = unsharp_params.lookahead * 4.0 + 40.0;
  678. image_gamma.init(unsharp_params.gamma);
  679. texture_gamma.init(unsharp_params.texture+1.0);
  680. gfloat csmooth = unsharp_params.csmooth;
  681. if (csmooth >= 0.99) csmooth = 1.0; /* Raw Filter preview */
  682. if (show_progress)
  683. gimp_progress_init (_("Blurring..."));
  684. /* allocate buffers */
  685. src = g_new (guchar, MAX (width, height) * bytes);
  686. dest = g_new (guchar, MAX (width, height) * bytes);
  687. data = g_new(gfloat, MAX (width, height) + 2*w);
  688. data2 = g_new(gfloat, MAX (width, height) + 2*w);
  689. buffer = g_new(gfloat, MAX (width, height) + 2*w);
  690. float *rbuf = g_new(float,MAX (width, height) + 2*w);
  691. float *tbuf = g_new(float,MAX (width, height) + 2*w);
  692. scratch = g_new(float,MAX (width, height) + 2*w);
  693. for (i=0;i<MAX(width,height)+2*w-1;i++) data[i]=data2[i]=buffer[i]=rbuf[i]=tbuf[i]=0.0;
  694. /* Initialize the damping filter coefficients */
  695. /* blur the rows */
  696. for (row = 0; row < height; row++)
  697. {
  698. gimp_pixel_rgn_get_row (srcPR, src, x1, y1 + row, width);
  699. memcpy(dest,src,width*bytes);
  700. // gimp_pixel_rgn_get_row (srcPR, dest, x1, y1 + row, width);
  701. blur_line (data+w, data2+w, buffer+w, rbuf+w, tbuf+w, src, dest, width, bytes);
  702. gimp_pixel_rgn_set_row (destPR, dest, x1, y1 + row, width);
  703. if (show_progress && row % 8 == 0)
  704. gimp_progress_update ((gdouble) row / (3 * height));
  705. }
  706. /* blur the cols */
  707. for (col = 0; col < width; col++)
  708. {
  709. gimp_pixel_rgn_get_col (destPR, src, x1 + col, y1, height);
  710. gimp_pixel_rgn_get_col (srcPR, dest, x1 + col, y1, height);
  711. blur_line (data+w, data2+w, buffer+w, rbuf+w, tbuf+w, src, dest, height, bytes);
  712. gimp_pixel_rgn_set_col (destPR, dest, x1 + col, y1, height);
  713. if (show_progress && col % 8 == 0)
  714. gimp_progress_update ((gdouble) col / (3 * width) + 0.33);
  715. }
  716. if (show_progress)
  717. gimp_progress_init (_("Merging..."));
  718. #define MERGE
  719. #ifdef MERGE
  720. /* merge the source and destination (which currently contains
  721. the blurred version) images */
  722. gfloat t=csmooth;
  723. gfloat t2 = lsmooth;
  724. t*=t; /* Easier adjustment for small values */
  725. t2*=t2;
  726. //gausst.init(t);
  727. //gausst2.init(t2);
  728. for (row = 0; row < height; row++)
  729. {
  730. guchar *s = src;
  731. guchar *d = dest;
  732. gfloat value;
  733. gint u, v;
  734. /* get source row */
  735. gimp_pixel_rgn_get_row (srcPR, src, x1, y1 + row, width);
  736. gimp_pixel_rgn_get_row (destPR, dest, x1, y1 + row, width);
  737. /* get dest row */
  738. /* combine the two */
  739. for (u = 0; u < width; u++)
  740. {
  741. gfloat dpix[3],spix[3];
  742. gfloat lum,red,green,blue;
  743. gfloat lum2,red2,green2,blue2;
  744. red = (gfloat) s[0]/255.0;
  745. if (bytes > 2)
  746. {
  747. green = (gfloat) s[1]/255.0;
  748. blue = (gfloat) s[2]/255.0;
  749. }
  750. else green = blue = red;
  751. spix[0] = red;
  752. spix[1] = green;
  753. spix[2] = blue;
  754. lum = (FR*red + FG*green + FB*blue);
  755. red2 = (gfloat) d[0]/255.0;
  756. if (bytes > 2)
  757. {
  758. green2 = (gfloat) d[1]/255.0;
  759. blue2 = (gfloat) d[2]/255.0;
  760. }
  761. else green2 = blue2 = red2;
  762. lum2 = (FR*red2 + FG*green2 + FB*blue2);
  763. /*
  764. * Calculate luminance error (contrast error) for filtered template.
  765. * This error is biggest, where edges are. Edges anyway cannot be filtered.
  766. * Therefore we can correct luminance error in edges without increasing noise.
  767. * Should be adjusted carefully, or not so carefully if you intentionally want to add noise.
  768. * Noise, if not colorized, /can/ look good, so this makes sense.
  769. */
  770. gfloat dl = lum - lum2;
  771. /* Multiply dl with first derivative of gamma curve divided by derivative value for midtone 0.5
  772. * So bright tones will be corrected more (get more luminance noise and -information) than darker values
  773. * Because bright parts of image generally are less noisy, this is what we want.
  774. */
  775. //!!!dl *= mypow(lum2/0.5,lut_gamma-1.0);
  776. if (t2 >= 0.0) dl *= (1.0 - exp(-dl*dl/(2.0*t2*t2)));
  777. // if (dl > p) dl = p;
  778. // if (dl < -p) dl = -p;
  779. dpix[0] = red2 + dl;
  780. dpix[1] = green2 + dl;
  781. dpix[2] = blue2 + dl;
  782. for (v = 0; v < bytes; v++)
  783. {
  784. gfloat value = spix[v];
  785. gfloat fvalue = dpix[v];
  786. gfloat mvalue = (value + fvalue)/2.0;
  787. gfloat diff = (value) - (fvalue);
  788. /* Multiply diff with first derivative of gamma curve divided by derivative value for midtone 0.5
  789. * So midtones will stay unchanged, darker values get more blur and brighter values get less blur
  790. * when we increase gamma.
  791. */
  792. //!!!!diff *= mypow(mvalue/0.5,lut_gamma-1.0);
  793. /* Calculate noise probability for pixel
  794. * Ok, probably it's not probability but an
  795. * arbitrary curve ;-)
  796. * Probably we should provide a GUI-interface for this
  797. */
  798. if (t > 0.0) prob = exp(-diff*diff/(2.0*t*t));
  799. else prob = 0.0;
  800. if (t >= 0.99) prob = 1.0; /* Allow viewing of raw filter output */
  801. dpix[v] = value = fvalue * prob + value * (1.0 - prob);
  802. }
  803. value = dpix[0]*255.0+0.5;
  804. d[0] = (guchar) CLAMP(value,0,255);
  805. if (bytes > 2)
  806. {
  807. value = dpix[1]*255.0+0.5;
  808. d[1] = (guchar) CLAMP(value,0,255);
  809. value = dpix[2]*255.0+0.5;
  810. d[2] = (guchar) CLAMP(value,0,255);
  811. }
  812. d += bytes;
  813. s +=bytes;
  814. }
  815. if (show_progress && row % 8 == 0)
  816. gimp_progress_update ((gdouble) row / (3 * height) + 0.67);
  817. gimp_pixel_rgn_set_row (destPR, dest, x1, y1 + row, width);
  818. }
  819. #endif
  820. if (show_progress)
  821. gimp_progress_update (0.0);
  822. g_free (data);
  823. g_free (data2);
  824. g_free (buffer);
  825. g_free (rbuf);
  826. g_free (tbuf);
  827. g_free (dest);
  828. g_free (src);
  829. g_free (scratch);
  830. }
  831. static gboolean
  832. unsharp_mask_dialog (GimpDrawable *drawable)
  833. {
  834. GtkWidget *dialog;
  835. GtkWidget *main_vbox;
  836. GtkWidget *preview;
  837. GtkWidget *table;
  838. GtkObject *adj;
  839. gboolean run;
  840. #define MAX_RAD 0
  841. #define F_THRESH 1
  842. #define TEXTURE 2
  843. #define SHARP 3
  844. #define CLIP 4
  845. #define L_AHEAD 5
  846. #define PHASE 6
  847. #define GAMMA 7
  848. #define LUM_TOL 8
  849. #define COL_TOL 9
  850. gimp_ui_init ("unsharp", TRUE);
  851. dialog = gimp_dialog_new (_("Dcam Noise 2 V "PLUG_IN_VERSION), "dcamnoise2-"PLUG_IN_VERSION,
  852. NULL, (GtkDialogFlags) 0,
  853. gimp_standard_help_func, "plug-in-dcamnoise2-"PLUG_IN_VERSION,
  854. GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
  855. GTK_STOCK_OK, GTK_RESPONSE_OK,
  856. NULL);
  857. main_vbox = gtk_vbox_new (FALSE, 12);
  858. gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
  859. gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), main_vbox);
  860. gtk_widget_show (main_vbox);
  861. preview = gimp_drawable_preview_new (drawable,
  862. &unsharp_params.update_preview);
  863. gtk_box_pack_start (GTK_BOX (main_vbox), preview, TRUE, TRUE, 0);
  864. gtk_widget_show (preview);
  865. g_signal_connect (preview, "invalidated",
  866. G_CALLBACK (preview_update),
  867. NULL);
  868. table = gtk_table_new (3, 3, FALSE);
  869. gtk_table_set_col_spacings (GTK_TABLE (table), 6);
  870. gtk_table_set_row_spacings (GTK_TABLE (table), 6);
  871. gtk_box_pack_start (GTK_BOX (main_vbox), table, FALSE, FALSE, 0);
  872. gtk_widget_show (table);
  873. adj = gimp_scale_entry_new (GTK_TABLE (table), 0, MAX_RAD,
  874. _("_Filter max. Radius:"), SCALE_WIDTH, ENTRY_WIDTH,
  875. unsharp_params.radius, 0.5, 50.0, 0.5, 0.5, 1,
  876. TRUE, 0, 0,
  877. NULL, NULL);
  878. // gimp_scale_entry_set_logarithmic(adj,TRUE);
  879. g_signal_connect (adj, "value_changed",
  880. G_CALLBACK (gimp_double_adjustment_update),
  881. &unsharp_params.radius);
  882. g_signal_connect_swapped (adj, "value_changed",
  883. G_CALLBACK (gimp_preview_invalidate),
  884. preview);
  885. adj = gimp_scale_entry_new (GTK_TABLE (table), 0, LUM_TOL,
  886. _("_Luminance tolerance:"), SCALE_WIDTH, ENTRY_WIDTH,
  887. unsharp_params.lsmooth, 0.0, 1.0, 0.1, 0.1, 2,
  888. TRUE, 0, 0,
  889. NULL, NULL);
  890. gimp_scale_entry_set_logarithmic(adj,TRUE);
  891. g_signal_connect (adj, "value_changed",
  892. G_CALLBACK (gimp_double_adjustment_update),
  893. &unsharp_params.lsmooth);
  894. g_signal_connect_swapped (adj, "value_changed",
  895. G_CALLBACK (gimp_preview_invalidate),
  896. preview);
  897. adj = gimp_scale_entry_new (GTK_TABLE (table), 0, COL_TOL,
  898. _("_Color tolerance:"), SCALE_WIDTH, ENTRY_WIDTH,
  899. unsharp_params.csmooth,
  900. 0.0, 1.0, 0.1, 0.1, 2,
  901. TRUE, 0, 0,
  902. NULL, NULL);
  903. gimp_scale_entry_set_logarithmic(adj,TRUE);
  904. g_signal_connect (adj, "value_changed",
  905. G_CALLBACK (gimp_double_adjustment_update),
  906. &unsharp_params.csmooth);
  907. g_signal_connect_swapped (adj, "value_changed",
  908. G_CALLBACK (gimp_preview_invalidate),
  909. preview);
  910. adj = gimp_scale_entry_new (GTK_TABLE (table), 0, F_THRESH,
  911. "_Filter Threshold:", SCALE_WIDTH, ENTRY_WIDTH,
  912. unsharp_params.effect,
  913. 0.0, 1.0, 0.01, 0.01, 2,
  914. TRUE, 0, 0,
  915. NULL, NULL);
  916. gimp_scale_entry_set_logarithmic(adj,TRUE);
  917. g_signal_connect (adj, "value_changed",
  918. G_CALLBACK (gimp_double_adjustment_update),
  919. &unsharp_params.effect);
  920. g_signal_connect_swapped (adj, "value_changed",
  921. G_CALLBACK (gimp_preview_invalidate),
  922. preview);
  923. adj = gimp_scale_entry_new (GTK_TABLE (table), 0, L_AHEAD,
  924. "_Lookahead:", SCALE_WIDTH, ENTRY_WIDTH,
  925. unsharp_params.lookahead,
  926. 0.5, 20.0, 0.01, 0.01, 2,
  927. TRUE, 0, 0,
  928. NULL, NULL);
  929. //gimp_scale_entry_set_logarithmic(adj,TRUE);
  930. g_signal_connect (adj, "value_changed",
  931. G_CALLBACK (gimp_double_adjustment_update),
  932. &unsharp_params.lookahead);
  933. g_signal_connect_swapped (adj, "value_changed",
  934. G_CALLBACK (gimp_preview_invalidate),
  935. preview);
  936. adj = gimp_scale_entry_new (GTK_TABLE (table), 0, GAMMA,
  937. "_Gamma:", SCALE_WIDTH, ENTRY_WIDTH,
  938. unsharp_params.gamma,
  939. 0.02, 5.0, 0.01, 0.1, 2,
  940. TRUE, 0, 0,
  941. NULL, NULL);
  942. g_signal_connect (adj, "value_changed",
  943. G_CALLBACK (gimp_double_adjustment_update),
  944. &unsharp_params.gamma);
  945. g_signal_connect_swapped (adj, "value_changed",
  946. G_CALLBACK (gimp_preview_invalidate),
  947. preview);
  948. adj = gimp_scale_entry_new (GTK_TABLE (table), 0, PHASE,
  949. "_Phase Jitter damping:", SCALE_WIDTH, ENTRY_WIDTH,
  950. unsharp_params.damping,
  951. 0.0, 20.0, 0.5, 0.5, 1,
  952. TRUE, 0, 0,
  953. NULL, NULL);
  954. g_signal_connect (adj, "value_changed",
  955. G_CALLBACK (gimp_double_adjustment_update),
  956. &unsharp_params.damping);
  957. g_signal_connect_swapped (adj, "value_changed",
  958. G_CALLBACK (gimp_preview_invalidate),
  959. preview);
  960. #if 1
  961. adj = gimp_scale_entry_new (GTK_TABLE (table), 0, CLIP,
  962. "_Edge Erosion:", SCALE_WIDTH, ENTRY_WIDTH,
  963. unsharp_params.phase,
  964. 0.0, 10.0, 1.0, 1.0, 0,
  965. TRUE, 0, 0,
  966. NULL, NULL);
  967. g_signal_connect (adj, "value_changed",
  968. G_CALLBACK (gimp_double_adjustment_update),
  969. &unsharp_params.phase);
  970. g_signal_connect_swapped (adj, "value_changed",
  971. G_CALLBACK (gimp_preview_invalidate),
  972. preview);
  973. //gimp_scale_entry_set_logarithmic(adj,TRUE);
  974. #endif
  975. adj = gimp_scale_entry_new (GTK_TABLE (table), 0, TEXTURE,
  976. "_Texture Detail:", SCALE_WIDTH, ENTRY_WIDTH,
  977. unsharp_params.texture,
  978. -1.0, 1.0, 0.01, 0.1, 2,
  979. TRUE, 0, 0,
  980. NULL, NULL);
  981. g_signal_connect (adj, "value_changed",
  982. G_CALLBACK (gimp_double_adjustment_update),
  983. &unsharp_params.texture);
  984. g_signal_connect_swapped (adj, "value_changed",
  985. G_CALLBACK (gimp_preview_invalidate),
  986. preview);
  987. adj = gimp_scale_entry_new (GTK_TABLE (table), 0, SHARP,
  988. "_Sharpness:", SCALE_WIDTH, ENTRY_WIDTH,
  989. unsharp_params.sharp,
  990. 0.0, 1.0, 0.01, 0.1, 2,
  991. TRUE, 0, 0,
  992. NULL, NULL);
  993. g_signal_connect (adj, "value_changed",
  994. G_CALLBACK (gimp_double_adjustment_update),
  995. &unsharp_params.sharp);
  996. g_signal_connect_swapped (adj, "value_changed",
  997. G_CALLBACK (gimp_preview_invalidate),
  998. preview);
  999. // gimp_scale_entry_set_logarithmic(adj,TRUE);
  1000. gtk_widget_show (dialog);
  1001. run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
  1002. gtk_widget_destroy (dialog);
  1003. return run;
  1004. }
  1005. static void
  1006. preview_update (GimpPreview *preview)
  1007. {
  1008. GimpDrawable *drawable;
  1009. gint x1, x2;
  1010. gint y1, y2;
  1011. gint x, y;
  1012. gint width, height;
  1013. gint border;
  1014. GimpPixelRgn srcPR;
  1015. GimpPixelRgn destPR;
  1016. drawable =
  1017. gimp_drawable_preview_get_drawable (GIMP_DRAWABLE_PREVIEW (preview));
  1018. gimp_pixel_rgn_init (&srcPR, drawable,
  1019. 0, 0, drawable->width, drawable->height, FALSE, FALSE);
  1020. gimp_pixel_rgn_init (&destPR, drawable,
  1021. 0, 0, drawable->width, drawable->height, TRUE, TRUE);
  1022. gimp_preview_get_position (preview, &x, &y);
  1023. gimp_preview_get_size (preview, &width, &height);
  1024. /* enlarge the region to avoid artefacts at the edges of the preview */
  1025. border = (int) (2.0 * unsharp_params.radius + 0.5);
  1026. x1 = MAX (0, x - border);
  1027. y1 = MAX (0, y - border);
  1028. x2 = MIN (x + width + border, (int) drawable->width);
  1029. y2 = MIN (y + height + border, (int) drawable->height);
  1030. unsharp_region (&srcPR, &destPR, drawable->bpp,
  1031. unsharp_params.radius, unsharp_params.lsmooth,
  1032. x1, x2, y1, y2,
  1033. FALSE);
  1034. gimp_pixel_rgn_init (&destPR, drawable, x, y, width, height, FALSE, TRUE);
  1035. gimp_drawable_preview_draw_region (GIMP_DRAWABLE_PREVIEW (preview), &destPR);
  1036. }