[gegl] common-cxx: new denoise-dct operation



commit 1655651fd1201d2ea6e0f4e9570af990f3735230
Author: Thomas Manni <thomas manni free fr>
Date:   Mon Apr 11 12:54:57 2022 +0200

    common-cxx: new denoise-dct operation
    
    This denoising operation decomposes the input buffer to sliding overlapping
    patches, calculates the DCT denoising in each patch, and then aggregates the
    denoised patches to the output buffer averaging the overlapped pixels.

 operations/common-cxx/dct-basis.inc  | 357 +++++++++++++++++++++++++
 operations/common-cxx/denoise-dct.cc | 486 +++++++++++++++++++++++++++++++++++
 operations/common-cxx/meson.build    |   1 +
 po/POTFILES.in                       |   1 +
 4 files changed, 845 insertions(+)
---
diff --git a/operations/common-cxx/dct-basis.inc b/operations/common-cxx/dct-basis.inc
new file mode 100644
index 000000000..2cfddf20e
--- /dev/null
+++ b/operations/common-cxx/dct-basis.inc
@@ -0,0 +1,357 @@
+/* Following matrices come from the implementation provided by
+ * https://www.ipol.im/pub/art/2011/ys-dct/
+ * Copyright (c) 2010, Guoshen Yu <yu cmap polytechnique fr>,
+ *                     Guillermo Sapiro <guille umn edu>
+ */
+
+/* A 8x8 1D DCT basis (each ROW is a vector of the forward transform basis */
+
+const gfloat DCTbasis8x8[8][8] = {
+  {  0.35355339059327373085750423342688009142875671386719,
+     0.35355339059327373085750423342688009142875671386719,
+     0.35355339059327373085750423342688009142875671386719,
+     0.35355339059327373085750423342688009142875671386719,
+     0.35355339059327373085750423342688009142875671386719,
+     0.35355339059327373085750423342688009142875671386719,
+     0.35355339059327373085750423342688009142875671386719,
+     0.35355339059327373085750423342688009142875671386719,  },
+
+  {  0.49039264020161521528962111915461719036102294921875,
+     0.41573480615127261783570133957255166023969650268555,
+     0.27778511650980114433551193542371038347482681274414,
+     0.09754516100806412404189416065491968765854835510254,
+    -0.09754516100806412404189416065491968765854835510254,
+    -0.27778511650980114433551193542371038347482681274414,
+    -0.41573480615127261783570133957255166023969650268555,
+    -0.49039264020161521528962111915461719036102294921875,  },
+
+  {  0.46193976625564336924156805253005586564540863037109,
+     0.19134171618254489088961634024599334225058555603027,
+    -0.19134171618254489088961634024599334225058555603027,
+    -0.46193976625564336924156805253005586564540863037109,
+    -0.46193976625564336924156805253005586564540863037109,
+    -0.19134171618254489088961634024599334225058555603027,
+     0.19134171618254489088961634024599334225058555603027,
+     0.46193976625564336924156805253005586564540863037109,  },
+
+  {  0.41573480615127261783570133957255166023969650268555,
+    -0.09754516100806417955304539191274670884013175964355,
+    -0.49039264020161521528962111915461719036102294921875,
+    -0.27778511650980108882436070416588336229324340820312,
+     0.27778511650980108882436070416588336229324340820312,
+     0.49039264020161521528962111915461719036102294921875,
+     0.09754516100806417955304539191274670884013175964355,
+    -0.41573480615127261783570133957255166023969650268555,  },
+
+  {  0.35355339059327378636865546468470711261034011840820,
+    -0.35355339059327378636865546468470711261034011840820,
+    -0.35355339059327378636865546468470711261034011840820,
+     0.35355339059327378636865546468470711261034011840820,
+     0.35355339059327378636865546468470711261034011840820,
+    -0.35355339059327378636865546468470711261034011840820,
+    -0.35355339059327378636865546468470711261034011840820,
+     0.35355339059327378636865546468470711261034011840820,  },
+
+  {  0.27778511650980114433551193542371038347482681274414,
+    -0.49039264020161532631192358167027123272418975830078,
+     0.09754516100806412404189416065491968765854835510254,
+     0.41573480615127261783570133957255166023969650268555,
+    -0.41573480615127261783570133957255166023969650268555,
+    -0.09754516100806412404189416065491968765854835510254,
+     0.49039264020161532631192358167027123272418975830078,
+    -0.27778511650980114433551193542371038347482681274414,  },
+
+  {  0.19134171618254491864519195587490685284137725830078,
+    -0.46193976625564336924156805253005586564540863037109,
+     0.46193976625564336924156805253005586564540863037109,
+    -0.19134171618254491864519195587490685284137725830078,
+    -0.19134171618254491864519195587490685284137725830078,
+     0.46193976625564336924156805253005586564540863037109,
+    -0.46193976625564336924156805253005586564540863037109,
+     0.19134171618254491864519195587490685284137725830078,  },
+
+  {  0.09754516100806416567525758409828995354473590850830,
+    -0.27778511650980108882436070416588336229324340820312,
+     0.41573480615127267334685257083037868142127990722656,
+    -0.49039264020161521528962111915461719036102294921875,
+     0.49039264020161521528962111915461719036102294921875,
+    -0.41573480615127267334685257083037868142127990722656,
+     0.27778511650980108882436070416588336229324340820312,
+    -0.09754516100806416567525758409828995354473590850830   }
+};
+
+/* A 16x16 1D DCT basis (each ROW is a vector of the forward transform basis */
+
+const gfloat DCTbasis16x16[16][16] = {
+  {  0.25000000000000000000000000000000000000000000000000,
+     0.25000000000000000000000000000000000000000000000000,
+     0.25000000000000000000000000000000000000000000000000,
+     0.25000000000000000000000000000000000000000000000000,
+     0.25000000000000000000000000000000000000000000000000,
+     0.25000000000000000000000000000000000000000000000000,
+     0.25000000000000000000000000000000000000000000000000,
+     0.25000000000000000000000000000000000000000000000000,
+     0.25000000000000000000000000000000000000000000000000,
+     0.25000000000000000000000000000000000000000000000000,
+     0.25000000000000000000000000000000000000000000000000,
+     0.25000000000000000000000000000000000000000000000000,
+     0.25000000000000000000000000000000000000000000000000,
+     0.25000000000000000000000000000000000000000000000000,
+     0.25000000000000000000000000000000000000000000000000,
+     0.25000000000000000000000000000000000000000000000000,  },
+
+  {  0.35185093438159564804834644746733829379081726074219,
+     0.33832950029358815902114088203234132379293441772461,
+     0.31180625324666783049210039280296768993139266967773,
+     0.27330046675043939696791994720115326344966888427734,
+     0.22429189658565909515353098413470434024930000305176,
+     0.16666391461943663721001485100714489817619323730469,
+     0.10263113188058936575686175274313427507877349853516,
+     0.03465429229977286945674208595846721436828374862671,
+    -0.03465429229977286945674208595846721436828374862671,
+    -0.10263113188058936575686175274313427507877349853516,
+    -0.16666391461943663721001485100714489817619323730469,
+    -0.22429189658565909515353098413470434024930000305176,
+    -0.27330046675043939696791994720115326344966888427734,
+    -0.31180625324666783049210039280296768993139266967773,
+    -0.33832950029358815902114088203234132379293441772461,
+    -0.35185093438159564804834644746733829379081726074219,  },
+
+  {  0.34675996133053688108560663749813102185726165771484,
+     0.29396890060483971129912106334813870489597320556641,
+     0.19642373959677555950165128706430550664663314819336,
+     0.06897484482073575062788250988887739367783069610596,
+    -0.06897484482073575062788250988887739367783069610596,
+    -0.19642373959677555950165128706430550664663314819336,
+    -0.29396890060483971129912106334813870489597320556641,
+    -0.34675996133053688108560663749813102185726165771484,
+    -0.34675996133053688108560663749813102185726165771484,
+    -0.29396890060483971129912106334813870489597320556641,
+    -0.19642373959677555950165128706430550664663314819336,
+    -0.06897484482073575062788250988887739367783069610596,
+     0.06897484482073575062788250988887739367783069610596,
+     0.19642373959677555950165128706430550664663314819336,
+     0.29396890060483971129912106334813870489597320556641,
+     0.34675996133053688108560663749813102185726165771484,  },
+
+  {  0.33832950029358815902114088203234132379293441772461,
+     0.22429189658565906739795536850579082965850830078125,
+     0.03465429229977286251784818205123883672058582305908,
+    -0.16666391461943663721001485100714489817619323730469,
+    -0.31180625324666783049210039280296768993139266967773,
+    -0.35185093438159559253719521620951127260923385620117,
+    -0.27330046675043934145676871594332624226808547973633,
+    -0.10263113188058933800128613711422076448798179626465,
+     0.10263113188058933800128613711422076448798179626465,
+     0.27330046675043934145676871594332624226808547973633,
+     0.35185093438159559253719521620951127260923385620117,
+     0.31180625324666783049210039280296768993139266967773,
+     0.16666391461943663721001485100714489817619323730469,
+    -0.03465429229977286251784818205123883672058582305908,
+    -0.22429189658565906739795536850579082965850830078125,
+    -0.33832950029358815902114088203234132379293441772461,  },
+
+  {  0.32664074121909414394338000420248135924339294433594,
+     0.13529902503654925305376366395648801699280738830566,
+    -0.13529902503654925305376366395648801699280738830566,
+    -0.32664074121909414394338000420248135924339294433594,
+    -0.32664074121909414394338000420248135924339294433594,
+    -0.13529902503654925305376366395648801699280738830566,
+     0.13529902503654925305376366395648801699280738830566,
+     0.32664074121909414394338000420248135924339294433594,
+     0.32664074121909414394338000420248135924339294433594,
+     0.13529902503654925305376366395648801699280738830566,
+    -0.13529902503654925305376366395648801699280738830566,
+    -0.32664074121909414394338000420248135924339294433594,
+    -0.32664074121909414394338000420248135924339294433594,
+    -0.13529902503654925305376366395648801699280738830566,
+     0.13529902503654925305376366395648801699280738830566,
+     0.32664074121909414394338000420248135924339294433594,  },
+
+  {  0.31180625324666783049210039280296768993139266967773,
+     0.03465429229977286251784818205123883672058582305908,
+    -0.27330046675043939696791994720115326344966888427734,
+    -0.33832950029358821453229211329016834497451782226562,
+    -0.10263113188058936575686175274313427507877349853516,
+     0.22429189658565906739795536850579082965850830078125,
+     0.35185093438159564804834644746733829379081726074219,
+     0.16666391461943663721001485100714489817619323730469,
+    -0.16666391461943663721001485100714489817619323730469,
+    -0.35185093438159564804834644746733829379081726074219,
+    -0.22429189658565906739795536850579082965850830078125,
+     0.10263113188058936575686175274313427507877349853516,
+     0.33832950029358821453229211329016834497451782226562,
+     0.27330046675043939696791994720115326344966888427734,
+    -0.03465429229977286251784818205123883672058582305908,
+    -0.31180625324666783049210039280296768993139266967773,  },
+
+  {  0.29396890060483971129912106334813870489597320556641,
+    -0.06897484482073579226124593333224765956401824951172,
+    -0.34675996133053688108560663749813102185726165771484,
+    -0.19642373959677553174607567143539199605584144592285,
+     0.19642373959677553174607567143539199605584144592285,
+     0.34675996133053688108560663749813102185726165771484,
+     0.06897484482073579226124593333224765956401824951172,
+    -0.29396890060483971129912106334813870489597320556641,
+    -0.29396890060483971129912106334813870489597320556641,
+     0.06897484482073579226124593333224765956401824951172,
+     0.34675996133053688108560663749813102185726165771484,
+     0.19642373959677553174607567143539199605584144592285,
+    -0.19642373959677553174607567143539199605584144592285,
+    -0.34675996133053688108560663749813102185726165771484,
+    -0.06897484482073579226124593333224765956401824951172,
+     0.29396890060483971129912106334813870489597320556641,  },
+
+  {  0.27330046675043939696791994720115326344966888427734,
+    -0.16666391461943663721001485100714489817619323730469,
+    -0.33832950029358821453229211329016834497451782226562,
+     0.03465429229977287639563598986569559201598167419434,
+     0.35185093438159564804834644746733829379081726074219,
+     0.10263113188058935187907394492867751978337764739990,
+    -0.31180625324666783049210039280296768993139266967773,
+    -0.22429189658565909515353098413470434024930000305176,
+     0.22429189658565909515353098413470434024930000305176,
+     0.31180625324666783049210039280296768993139266967773,
+    -0.10263113188058935187907394492867751978337764739990,
+    -0.35185093438159564804834644746733829379081726074219,
+    -0.03465429229977287639563598986569559201598167419434,
+     0.33832950029358821453229211329016834497451782226562,
+     0.16666391461943663721001485100714489817619323730469,
+    -0.27330046675043939696791994720115326344966888427734,  },
+
+  {  0.25000000000000005551115123125782702118158340454102,
+    -0.25000000000000005551115123125782702118158340454102,
+    -0.25000000000000005551115123125782702118158340454102,
+     0.25000000000000005551115123125782702118158340454102,
+     0.25000000000000005551115123125782702118158340454102,
+    -0.25000000000000005551115123125782702118158340454102,
+    -0.25000000000000005551115123125782702118158340454102,
+     0.25000000000000005551115123125782702118158340454102,
+     0.25000000000000005551115123125782702118158340454102,
+    -0.25000000000000005551115123125782702118158340454102,
+    -0.25000000000000005551115123125782702118158340454102,
+     0.25000000000000005551115123125782702118158340454102,
+     0.25000000000000005551115123125782702118158340454102,
+    -0.25000000000000005551115123125782702118158340454102,
+    -0.25000000000000005551115123125782702118158340454102,
+     0.25000000000000005551115123125782702118158340454102,  },
+
+  {  0.22429189658565909515353098413470434024930000305176,
+    -0.31180625324666783049210039280296768993139266967773,
+    -0.10263113188058937963464956055759103037416934967041,
+     0.35185093438159564804834644746733829379081726074219,
+    -0.03465429229977282088448475860786857083439826965332,
+    -0.33832950029358815902114088203234132379293441772461,
+     0.16666391461943658169886361974931787699460983276367,
+     0.27330046675043934145676871594332624226808547973633,
+    -0.27330046675043934145676871594332624226808547973633,
+    -0.16666391461943658169886361974931787699460983276367,
+     0.33832950029358815902114088203234132379293441772461,
+     0.03465429229977282088448475860786857083439826965332,
+    -0.35185093438159564804834644746733829379081726074219,
+     0.10263113188058937963464956055759103037416934967041,
+     0.31180625324666783049210039280296768993139266967773,
+    -0.22429189658565909515353098413470434024930000305176,  },
+
+  {  0.19642373959677558725722690269321901723742485046387,
+    -0.34675996133053693659675786875595804303884506225586,
+     0.06897484482073573675009470207442063838243484497070,
+     0.29396890060483971129912106334813870489597320556641,
+    -0.29396890060483971129912106334813870489597320556641,
+    -0.06897484482073573675009470207442063838243484497070,
+     0.34675996133053693659675786875595804303884506225586,
+    -0.19642373959677558725722690269321901723742485046387,
+    -0.19642373959677558725722690269321901723742485046387,
+     0.34675996133053693659675786875595804303884506225586,
+    -0.06897484482073573675009470207442063838243484497070,
+    -0.29396890060483971129912106334813870489597320556641,
+     0.29396890060483971129912106334813870489597320556641,
+     0.06897484482073573675009470207442063838243484497070,
+    -0.34675996133053693659675786875595804303884506225586,
+     0.19642373959677558725722690269321901723742485046387,  },
+
+  {  0.16666391461943669272116608226497191935777664184570,
+    -0.35185093438159559253719521620951127260923385620117,
+     0.22429189658565901188680413724796380847692489624023,
+     0.10263113188058929636792271367085049860179424285889,
+    -0.33832950029358821453229211329016834497451782226562,
+     0.27330046675043939696791994720115326344966888427734,
+     0.03465429229977293190678722112352261319756507873535,
+    -0.31180625324666777498094916154514066874980926513672,
+     0.31180625324666777498094916154514066874980926513672,
+    -0.03465429229977293190678722112352261319756507873535,
+    -0.27330046675043939696791994720115326344966888427734,
+     0.33832950029358821453229211329016834497451782226562,
+    -0.10263113188058929636792271367085049860179424285889,
+    -0.22429189658565901188680413724796380847692489624023,
+     0.35185093438159559253719521620951127260923385620117,
+    -0.16666391461943669272116608226497191935777664184570,  },
+
+  {  0.13529902503654928080933927958540152758359909057617,
+    -0.32664074121909414394338000420248135924339294433594,
+     0.32664074121909414394338000420248135924339294433594,
+    -0.13529902503654928080933927958540152758359909057617,
+    -0.13529902503654928080933927958540152758359909057617,
+     0.32664074121909414394338000420248135924339294433594,
+    -0.32664074121909414394338000420248135924339294433594,
+     0.13529902503654928080933927958540152758359909057617,
+     0.13529902503654928080933927958540152758359909057617,
+    -0.32664074121909414394338000420248135924339294433594,
+     0.32664074121909414394338000420248135924339294433594,
+    -0.13529902503654928080933927958540152758359909057617,
+    -0.13529902503654928080933927958540152758359909057617,
+     0.32664074121909414394338000420248135924339294433594,
+    -0.32664074121909414394338000420248135924339294433594,
+     0.13529902503654928080933927958540152758359909057617,  },
+
+  {  0.10263113188058933800128613711422076448798179626465,
+    -0.27330046675043939696791994720115326344966888427734,
+     0.35185093438159564804834644746733829379081726074219,
+    -0.31180625324666788600325162406079471111297607421875,
+     0.16666391461943666496559046663605840876698493957520,
+     0.03465429229977289027342379768015234731137752532959,
+    -0.22429189658565906739795536850579082965850830078125,
+     0.33832950029358821453229211329016834497451782226562,
+    -0.33832950029358821453229211329016834497451782226562,
+     0.22429189658565906739795536850579082965850830078125,
+    -0.03465429229977289027342379768015234731137752532959,
+    -0.16666391461943666496559046663605840876698493957520,
+     0.31180625324666788600325162406079471111297607421875,
+    -0.35185093438159564804834644746733829379081726074219,
+     0.27330046675043939696791994720115326344966888427734,
+    -0.10263113188058933800128613711422076448798179626465,  },
+
+  {  0.06897484482073577838345812551779090426862239837646,
+    -0.19642373959677555950165128706430550664663314819336,
+     0.29396890060483971129912106334813870489597320556641,
+    -0.34675996133053688108560663749813102185726165771484,
+     0.34675996133053688108560663749813102185726165771484,
+    -0.29396890060483971129912106334813870489597320556641,
+     0.19642373959677555950165128706430550664663314819336,
+    -0.06897484482073577838345812551779090426862239837646,
+    -0.06897484482073577838345812551779090426862239837646,
+     0.19642373959677555950165128706430550664663314819336,
+    -0.29396890060483971129912106334813870489597320556641,
+     0.34675996133053688108560663749813102185726165771484,
+    -0.34675996133053688108560663749813102185726165771484,
+     0.29396890060483971129912106334813870489597320556641,
+    -0.19642373959677555950165128706430550664663314819336,
+     0.06897484482073577838345812551779090426862239837646,  },
+
+  {  0.03465429229977292496789331721629423554986715316772,
+    -0.10263113188058928249013490585639374330639839172363,
+     0.16666391461943666496559046663605840876698493957520,
+    -0.22429189658565903964237975287687731906771659851074,
+     0.27330046675043939696791994720115326344966888427734,
+    -0.31180625324666771946979793028731364756822586059570,
+     0.33832950029358815902114088203234132379293441772461,
+    -0.35185093438159559253719521620951127260923385620117,
+     0.35185093438159559253719521620951127260923385620117,
+    -0.33832950029358815902114088203234132379293441772461,
+     0.31180625324666771946979793028731364756822586059570,
+    -0.27330046675043939696791994720115326344966888427734,
+     0.22429189658565903964237975287687731906771659851074,
+    -0.16666391461943666496559046663605840876698493957520,
+     0.10263113188058928249013490585639374330639839172363,
+    -0.03465429229977292496789331721629423554986715316772  }
+};
\ No newline at end of file
diff --git a/operations/common-cxx/denoise-dct.cc b/operations/common-cxx/denoise-dct.cc
new file mode 100644
index 000000000..b44bfae10
--- /dev/null
+++ b/operations/common-cxx/denoise-dct.cc
@@ -0,0 +1,486 @@
+/* This file is an image processing operation for GEGL
+ *
+ * GEGL is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * GEGL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GEGL; if not, see <https://www.gnu.org/licenses/>.
+ *
+ * Copyright (C) 2022 Thomas Manni <thomas manni free fr>
+ *
+ * following the paper (without channels decorellation)
+ *   Guoshen Yu, and Guillermo Sapiro
+ *   DCT Image Denoising: a Simple and Effective Image Denoising Algorithm
+ */
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+
+#ifdef GEGL_PROPERTIES
+
+enum_start (gegl_denoise_dct_patchsize)
+    enum_value (GEGL_DENOISE_DCT_8X8,  "8x8", "8x8")
+    enum_value (GEGL_DENOISE_DCT_16X16, "16x16", "16x16")
+enum_end (GeglDenoiseDctPatchsize)
+
+property_enum (patch_size, _("Patch size"),
+               GeglDenoiseDctPatchsize, gegl_denoise_dct_patchsize,
+               GEGL_DENOISE_DCT_8X8)
+    description (_("Size of patches used to denoise"))
+
+property_double (sigma, _("Strength"), 5.0)
+    description (_("Noise standart deviation"))
+    value_range (1., 100.)
+
+#else
+
+#define GEGL_OP_FILTER
+#define GEGL_OP_NAME     denoise_dct
+#define GEGL_OP_C_SOURCE denoise-dct.cc
+#include "gegl-op.h"
+#include "dct-basis.inc"
+
+/* 1 dimensional Discret Cosine Transform of a signal of size 8x1. */
+
+static void
+dct_1d_8x8 (gfloat  *in,
+            gfloat  *out,
+            gboolean forward)
+{
+  gint  i, j;
+
+  if (forward)
+    {
+      for (j = 0; j < 8; j++)
+        {
+          for (i = 0; i < 8; i++)
+            {
+              out[0] += in[i*3]   * DCTbasis8x8[j][i];
+              out[1] += in[i*3+1] * DCTbasis8x8[j][i];
+              out[2] += in[i*3+2] * DCTbasis8x8[j][i];
+            }
+
+          out += 3;
+        }
+    }
+  else
+    {
+      for (j = 0; j < 8; j++)
+        {
+          for (i = 0; i < 8; i ++)
+            {
+              out[0] += in[i*3]   * DCTbasis8x8[i][j];
+              out[1] += in[i*3+1] * DCTbasis8x8[i][j];
+              out[2] += in[i*3+2] * DCTbasis8x8[i][j];
+            }
+
+          out += 3;
+        }
+    }
+}
+
+/* 1 dimensional Discret Cosine Transform of a signal of size 16x1. */
+
+static void
+dct_1d_16x16 (gfloat  *in,
+              gfloat  *out,
+              gboolean forward)
+{
+  gint  i, j;
+
+  if (forward)
+    {
+      for (j = 0; j < 16; j++)
+        {
+          for (i = 0; i < 16; i++)
+            {
+              out[0] += in[i*3]   * DCTbasis16x16[j][i];
+              out[1] += in[i*3+1] * DCTbasis16x16[j][i];
+              out[2] += in[i*3+2] * DCTbasis16x16[j][i];
+            }
+
+          out += 3;
+        }
+    }
+  else
+    {
+      for (j = 0; j < 16; j++)
+        {
+          for (i = 0; i < 16; i ++)
+            {
+              out[0] += in[i*3]   * DCTbasis16x16[i][j];
+              out[1] += in[i*3+1] * DCTbasis16x16[i][j];
+              out[2] += in[i*3+2] * DCTbasis16x16[i][j];
+            }
+
+          out += 3;
+        }
+    }
+}
+
+/* 2 dimensional DCT of a 8x8 (or 16x16) patch */
+
+static void
+dct_2d (gfloat   *patch,
+        gint      patch_size,
+        gboolean  forward)
+{
+  gfloat  *tmp1;
+  gfloat  *tmp2;
+  gint     x, y;
+
+  tmp1 = g_new0 (gfloat, patch_size * patch_size * 3);
+  tmp2 = g_new (gfloat, patch_size * patch_size * 3);
+
+  /* transform row by row */
+
+  if (patch_size == 8)
+    {
+      for (y = 0; y < 8; y++)
+        {
+          dct_1d_8x8 (patch + y * 8 * 3,
+                      tmp1 + y * 8 * 3,
+                      forward);
+        }
+    }
+  else
+    {
+      for (y = 0; y < 16; y++)
+        {
+          dct_1d_16x16 (patch + y * 16 * 3,
+                        tmp1 + y * 16 * 3,
+                        forward);
+        }
+    }
+
+  /* transform column by column (by transposing the matrix, transforming row by
+   * row, and transposing again the matrix.)
+   */
+
+  for (y = 0; y < patch_size; y++)
+    {
+      for (x = 0; x < patch_size; x++)
+        {
+          tmp2[(y + x * patch_size) * 3]   = tmp1[(x + y * patch_size) * 3];
+          tmp2[(y + x * patch_size) * 3+1] = tmp1[(x + y * patch_size) * 3+1];
+          tmp2[(y + x * patch_size) * 3+2] = tmp1[(x + y * patch_size) * 3+2];
+        }
+    }
+
+  memset (tmp1, 0.f, patch_size * patch_size * 3 * sizeof(gfloat));
+
+  if (patch_size == 8)
+    {
+      for (y = 0; y < 8; y++)
+        {
+          dct_1d_8x8 (tmp2 + y * 8 * 3,
+                      tmp1 + y * 8 * 3,
+                      forward);
+        }
+    }
+  else
+    {
+      for (y = 0; y < 16; y++)
+        {
+          dct_1d_16x16 (tmp2 + y * 16 * 3,
+                        tmp1 + y * 16 * 3,
+                        forward);
+        }
+    }
+
+  for (y = 0; y < patch_size; y++)
+    {
+      for (x = 0; x < patch_size; x++)
+        {
+          patch[(y + x * patch_size) * 3]   = tmp1[(x + y * patch_size) * 3];
+          patch[(y + x * patch_size) * 3+1] = tmp1[(x + y * patch_size) * 3+1];
+          patch[(y + x * patch_size) * 3+2] = tmp1[(x + y * patch_size) * 3+2];
+        }
+    }
+
+  g_free (tmp1);
+  g_free (tmp2);
+}
+
+static void
+threshold_patch_coefficients (gfloat  *patch,
+                              gint     patch_n_pixels,
+                              gfloat   threshold)
+{
+  gint     i;
+  gfloat  *p = patch;
+
+  for (i = 0; i < patch_n_pixels; i++)
+    {
+      p[0] = ABS (p[0]) < threshold ? 0.f : p[0];
+      p[1] = ABS (p[1]) < threshold ? 0.f : p[1];
+      p[2] = ABS (p[2]) < threshold ? 0.f : p[2];
+      p += 3;
+    }
+}
+
+static void
+prepare (GeglOperation *operation)
+{
+  const Babl *space  = gegl_operation_get_source_space (operation, "input");
+  const Babl *format = babl_format_with_space ("R'G'B'A float", space);
+
+  gegl_operation_set_format (operation, "input", format);
+  gegl_operation_set_format (operation, "output", format);
+}
+
+static GeglRectangle
+get_cached_region (GeglOperation       *operation,
+                   const GeglRectangle *roi)
+{
+  const GeglRectangle *in_rect =
+      gegl_operation_source_get_bounding_box (operation, "input");
+
+  if (! in_rect || gegl_rectangle_is_infinite_plane (in_rect))
+    return *roi;
+
+  return *in_rect;
+}
+
+static GeglRectangle
+get_required_for_output (GeglOperation       *operation,
+                         const gchar         *input_pad,
+                         const GeglRectangle *roi)
+{
+  return get_cached_region (operation, roi);
+}
+
+static gboolean
+process (GeglOperation       *operation,
+         GeglBuffer          *input,
+         GeglBuffer          *output,
+         const GeglRectangle *result,
+         gint                 level)
+{
+  GeglProperties *o  = GEGL_PROPERTIES (operation);
+  const Babl *space  = gegl_operation_get_source_space (operation, "input");
+  const Babl *rgb_f  = babl_format_with_space ("R'G'B' float", space);
+  const Babl *rgba_f = babl_format_with_space ("R'G'B'A float", space);
+
+  GeglBuffer  *sum;
+  gint    width, height;
+  gint    patch_size;
+  gint    patch_len;
+  gfloat  threshold;
+  gdouble progress;
+  gint   *patch_n_x;
+  gint   *patch_n_y;
+  gint    i;
+
+  width  = gegl_buffer_get_width (input);
+  height = gegl_buffer_get_height (input);
+  patch_size = o->patch_size == GEGL_DENOISE_DCT_8X8 ? 8 : 16;
+  patch_len = patch_size * patch_size;
+  threshold = 3.f * (gfloat) o->sigma / 255.;
+
+  sum = gegl_buffer_new (GEGL_RECTANGLE(0, 0, width, height), rgb_f);
+
+  patch_n_x = g_new (gint, width);
+  patch_n_y = g_new (gint, height);
+
+  GeglBufferIterator  *iter;
+  gint                 x_offset;
+
+  gegl_operation_progress (operation, 0.0, (gchar *) "");
+
+  for (x_offset = 0; x_offset < patch_size; x_offset++)
+    {
+      /* Input buffer is split into vertical non-overlapping regions.
+       * Regions are distributed among threads.
+       */
+
+      gint n_regions = (width - x_offset) / patch_size;
+
+      gegl_parallel_distribute_range (
+        n_regions, gegl_operation_get_pixels_per_thread (operation)
+           / (height * patch_size),
+        [=] (gint region0, gint n)
+        {
+          gint     x, y, j;
+          gfloat  *in_buf;
+          gfloat  *sum_buf;
+          gfloat  *patch_buf;
+
+          in_buf    = g_new (gfloat, patch_size * height * 3);
+          sum_buf   = g_new (gfloat, patch_size * height * 3);
+          patch_buf = g_new (gfloat, patch_len * 3);
+
+          for (x = region0; x < region0 + n; x++)
+            {
+              /* Threads manage one region at a time:
+               * for each overlapping patch from top to bottom:
+               *    1. extract patch
+               *    2. dc transform, thresholding, inverse transform
+               *    3. sum the patch result into the sum memory buffer
+               * set the gegl buffer with the sum memory buffer
+               */
+
+              GeglRectangle  roi = {x * patch_size + x_offset,
+                                    0,
+                                    patch_size,
+                                    height};
+              gint patch_offset  = 0;
+
+              gegl_buffer_get (input, &roi, 1.0, rgb_f, in_buf,
+                               GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
+
+              gegl_buffer_get (sum, &roi, 1.0, rgb_f, sum_buf,
+                               GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
+
+              for (y = 0; y < height - patch_size + 1; y++)
+                {
+                  gfloat  *sum_p   = sum_buf + patch_offset;
+                  gfloat  *patch_p = patch_buf;
+
+                  memcpy (patch_buf, in_buf + patch_offset,
+                          patch_len * 3 * sizeof(gfloat));
+                  dct_2d (patch_buf, patch_size, TRUE);
+                  threshold_patch_coefficients (patch_buf, patch_len, threshold);
+                  dct_2d (patch_buf, patch_size, FALSE);
+
+                  for (j = 0; j < patch_len * 3; j++)
+                    {
+                      *sum_p++ += *patch_p++;
+                    }
+
+                  patch_offset += patch_size * 3;
+                }
+
+              gegl_buffer_set (sum, &roi, 0, rgb_f, sum_buf,
+                               GEGL_AUTO_ROWSTRIDE);
+            }
+
+          g_free (in_buf);
+          g_free (sum_buf);
+          g_free (patch_buf);
+        });
+
+      progress = (gdouble) (x_offset + 1) / (gdouble) patch_size;
+      gegl_operation_progress (operation, progress, (gchar *) "");
+    }
+
+  /* Finally, average the accumulated values of the sum buffer, given the
+   *  appropriate number of patches a pixel belongs to.
+   *  Put the result in the ouput buffer with the original alpha value.
+   */
+
+  for (i = 0; i < patch_size; i++)
+    {
+      patch_n_x[i] = patch_n_x[width -1 - i] = i+1;
+      patch_n_y[i] = patch_n_y[height -1 -i] = i+1;
+    }
+
+  for (i = patch_size; i <= width - patch_size; i++)
+    patch_n_x[i] = patch_size;
+
+  for (i = patch_size; i <= height - patch_size; i++)
+    patch_n_y[i] = patch_size;
+
+  iter = gegl_buffer_iterator_new (input, NULL, 0, rgba_f,
+                                   GEGL_ACCESS_READ, GEGL_ABYSS_NONE, 3);
+
+  gegl_buffer_iterator_add (iter, sum, NULL, 0, rgb_f,
+                            GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
+
+  gegl_buffer_iterator_add (iter, output, NULL, 0, rgba_f,
+                            GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE);
+
+  while (gegl_buffer_iterator_next (iter))
+    {
+      gfloat  *in   = (gfloat *) iter->items[0].data;
+      gfloat  *sum  = (gfloat *) iter->items[1].data;
+      gfloat  *out  = (gfloat *) iter->items[2].data;
+      GeglRectangle *roi = &iter->items[0].roi;
+      gint     x, y;
+
+      for (y = roi->y; y < roi->y + roi->height; y++)
+        {
+          for (x = roi->x; x < roi->x + roi->width; x++)
+            {
+              gint   n_patches = patch_n_x[x] * patch_n_y[y];
+              gfloat n = 1.f / (gfloat) n_patches;
+
+              out[0] = sum[0] * n;
+              out[1] = sum[1] * n;
+              out[2] = sum[2] * n;
+              out[3] = in[3];
+
+              in  += 4;
+              sum += 3;
+              out += 4;
+            }
+        }
+    }
+
+  gegl_operation_progress (operation, 1.0, (gchar *) "");
+
+  g_object_unref (sum);
+  g_free (patch_n_x);
+  g_free (patch_n_y);
+
+  return TRUE;
+}
+
+static gboolean
+operation_process (GeglOperation        *operation,
+                   GeglOperationContext *context,
+                   const gchar          *output_prop,
+                   const GeglRectangle  *result,
+                   gint                  level)
+{
+  GeglOperationClass  *operation_class;
+
+  const GeglRectangle *in_rect =
+    gegl_operation_source_get_bounding_box (operation, "input");
+
+  if (in_rect && gegl_rectangle_is_infinite_plane (in_rect))
+    {
+      gpointer in = gegl_operation_context_get_object (context, "input");
+      gegl_operation_context_take_object (context, "output",
+                                          G_OBJECT(g_object_ref (in)));
+      return TRUE;
+    }
+
+  operation_class = GEGL_OPERATION_CLASS (gegl_op_parent_class);
+
+  return operation_class->process (operation, context, output_prop, result,
+                                   gegl_operation_context_get_level (context));
+}
+
+static void
+gegl_op_class_init (GeglOpClass *klass)
+{
+  GeglOperationClass       *operation_class;
+  GeglOperationFilterClass *filter_class;
+
+  operation_class = GEGL_OPERATION_CLASS (klass);
+  filter_class    = GEGL_OPERATION_FILTER_CLASS (klass);
+
+  operation_class->threaded                = FALSE;
+  operation_class->prepare                 = prepare;
+  operation_class->process                 = operation_process;
+  operation_class->get_cached_region       = get_cached_region;
+  operation_class->get_required_for_output = get_required_for_output;
+  filter_class->process                    = process;
+
+  gegl_operation_class_set_keys (operation_class,
+    "name",        "gegl:denoise-dct",
+    "title",       _("Denoise DCT"),
+    "categories",  "enhance:noise-reduction",
+    "description", _("Denoising algorithm using a per-patch DCT thresholding"),
+    NULL);
+}
+
+#endif
diff --git a/operations/common-cxx/meson.build b/operations/common-cxx/meson.build
index 2d6c18b58..146967fae 100644
--- a/operations/common-cxx/meson.build
+++ b/operations/common-cxx/meson.build
@@ -1,5 +1,6 @@
 
 gegl_common_cxx_sources = files(
+  'denoise-dct.cc',
   'distance-transform.cc',
   'focus-blur.c',
   'lens-blur.cc',
diff --git a/po/POTFILES.in b/po/POTFILES.in
index b47dc97c9..fce3d1232 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -132,6 +132,7 @@ operations/common/weighted-blend.c
 operations/common/write-buffer.c
 operations/common-cxx/distance-transform.cc
 operations/common-cxx/focus-blur.c
+operations/common-cxx/denoise-dct.cc
 operations/common-cxx/lens-blur.cc
 operations/common-cxx/piecewise-blend.cc
 operations/common-cxx/variable-blur.c


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]