2 * Wavelet Denoise filter for GIMP - The GNU Image Manipulation Program
4 * Copyright (C) 2008 Monty
5 * Code based on research by Crystal Wagner and Prof. Ivan Selesnik,
6 * Polytechnic University, Brooklyn, NY
7 * See: http://taco.poly.edu/selesi/DoubleSoftware/
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
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 General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 #include <libgimp/gimp.h>
31 #include <libgimp/gimpui.h>
33 /* convolution code below assumes FSZ is even */
36 static float analysis_fs
[2][3][FSZ
]={
139 static float analysis
[2][3][FSZ
]={
243 static float synthesis_fs
[2][3][FSZ
]={
346 static float synthesis
[2][3][FSZ
]={
459 static m2D
alloc_m2D(int m
, int n
){
463 ret
.x
= calloc(m
*n
,sizeof(*(ret
.x
)));
467 static void free_m2D(m2D
*c
){
472 static void complex_threshold(m2D set
[4], float T
, int soft
, int pt
, int *pc
, int pi
, int(*check
)(void)){
474 int N
= set
[0].rows
*set
[0].cols
;
481 for(j
=0;j
<set
[0].cols
;i
++,j
++){
482 float v00
= (set
[0].x
[i
] + set
[3].x
[i
]) * .7071067812;
483 float v11
= (set
[0].x
[i
] - set
[3].x
[i
]) * .7071067812;
484 float v01
= (set
[1].x
[i
] + set
[2].x
[i
]) * .7071067812;
485 float v10
= (set
[1].x
[i
] - set
[2].x
[i
]) * .7071067812;
487 if(v00
*v00
+ v10
*v10
< TT
){
491 float y
= sqrt(v00
*v00
+ v10
*v10
);
492 float scale
= y
/(y
+T
);
496 if(v01
*v01
+ v11
*v11
< TT
){
500 float y
= sqrt(v01
*v01
+ v11
*v11
);
501 float scale
= y
/(y
+T
);
506 set
[0].x
[i
] = (v00
+ v11
) * .7071067812;
507 set
[3].x
[i
] = (v00
- v11
) * .7071067812;
508 set
[1].x
[i
] = (v01
+ v10
) * .7071067812;
509 set
[2].x
[i
] = (v01
- v10
) * .7071067812;
511 if(check
&& check())return;
515 for(j
=0;j
<set
[0].cols
;i
++,j
++){
516 float v00
= (set
[0].x
[i
] + set
[3].x
[i
]) * .7071067812;
517 float v11
= (set
[0].x
[i
] - set
[3].x
[i
]) * .7071067812;
518 float v01
= (set
[1].x
[i
] + set
[2].x
[i
]) * .7071067812;
519 float v10
= (set
[1].x
[i
] - set
[2].x
[i
]) * .7071067812;
521 if(v00
*v00
+ v10
*v10
< TT
){
525 if(v01
*v01
+ v11
*v11
< TT
){
530 set
[0].x
[i
] = (v00
+ v11
) * .7071067812;
531 set
[3].x
[i
] = (v00
- v11
) * .7071067812;
532 set
[1].x
[i
] = (v01
+ v10
) * .7071067812;
533 set
[2].x
[i
] = (v01
- v10
) * .7071067812;
535 if(check
&& check())return;
539 if(pt
)gimp_progress_update((gfloat
)((*pc
)+=pi
)/pt
);
542 /* assume the input is padded, return output that's padded for next stage */
543 /* FSZ*2-2 padding, +1 additional padding if vector odd */
545 static m2D
convolve_padded(const m2D x
, float *f
, int pt
, int *pc
, int pi
, int(*check
)(void)){
549 int comp_N
= (in_N
- FSZ
+ 3) / 2;
550 int out_N
= (comp_N
+1)/2*2+FSZ
*2-2;
552 m2D y
=alloc_m2D(M
,out_N
);
553 if(check
&& check())return y
;
556 float *xrow
= x
.x
+i
*in_N
;
557 float *yrow
= y
.x
+i
*out_N
+FSZ
-1;
558 for(j
=0;j
<comp_N
;j
++){
561 a
+=xrow
[k
]*f
[FSZ
-k
-1];
565 if(check
&& check())return y
;
567 /* extend output padding */
568 for(j
=0;j
<FSZ
-1;j
++){
572 for(j
=FSZ
-1+comp_N
;j
<out_N
;j
++)
575 if(check
&& check())return y
;
578 if(pt
)gimp_progress_update((gfloat
)((*pc
)+=pi
)/pt
);
582 static m2D
convolve_transpose_padded(const m2D x
, float *f
, int pt
, int *pc
, int pi
, int(*check
)(void)){
586 int comp_N
= (in_N
- FSZ
+ 3) / 2;
587 int out_N
= (comp_N
+1)/2*2+FSZ
*2-2;
589 m2D y
=alloc_m2D(out_N
,M
);
590 if(check
&& check())return y
;
593 float *xrow
= x
.x
+i
*in_N
;
594 float *ycol
= y
.x
+ i
+ M
*(FSZ
-1);
595 for(j
=0;j
<comp_N
;j
++){
598 a
+=xrow
[k
]*f
[FSZ
-k
-1];
602 if(check
&& check())return y
;
604 /* extend output padding */
605 for(j
=0;j
<FSZ
-1;j
++){
609 for(j
=FSZ
-1+comp_N
;j
<out_N
;j
++)
610 ycol
[j
*M
] = ycol
[(j
-1)*M
];
612 if(check
&& check())return y
;
615 if(pt
)gimp_progress_update((gfloat
)((*pc
)+=pi
)/pt
);
619 /* discards the padding added by the matching convolution */
621 /* y will often be smaller than a full x expansion due to preceeding
622 rounds of padding out to even values; this padding is also
624 static void deconvolve_padded(m2D y
, m2D x
, float *f
, int pt
, int *pc
, int pi
, int(*check
)(void)){
631 for(i
=0;i
<out_M
;i
++){
632 float *xrow
= x
.x
+i
*in_N
+FSZ
/2;
633 float *yrow
= y
.x
+i
*out_N
;
635 for(j
=0;j
<out_N
;j
+=2){
638 a
+=xrow
[k
>>1]*f
[FSZ
-k
-1];
642 a
+=xrow
[k
>>1]*f
[FSZ
-k
];
646 if(check
&& check()) return;
649 if(pt
)gimp_progress_update((gfloat
)((*pc
)+=pi
)/pt
);
652 /* discards the padding added by the matching convolution */
654 /* y will often be smaller than a full x expansion due to preceeding
655 rounds of padding out to even values; this padding is also
657 static void deconvolve_transpose_padded(m2D y
, m2D x
, float *f
, int pt
, int *pc
, int pi
, int(*check
)(void)){
664 for(i
=0;i
<out_N
;i
++){
665 float *xrow
= x
.x
+i
*in_N
+FSZ
/2;
667 for(j
=0;j
<out_M
;j
+=2){
670 a
+=xrow
[k
>>1]*f
[FSZ
-k
-1];
674 a
+=xrow
[k
>>1]*f
[FSZ
-k
];
675 ycol
[(j
+1)*out_N
]+=a
;
678 if(check
&& check()) return;
681 if(pt
)gimp_progress_update((gfloat
)((*pc
)+=pi
)/pt
);
684 /* consumes and replaces lo if free_input set, otherwise overwrites */
685 static void forward_threshold(m2D lo
[4], m2D y
[4],
686 float af
[2][3][FSZ
], float sf
[2][3][FSZ
],
688 int free_input
, int pt
, int *pc
, int pi
,
690 m2D x
[4] = {{NULL
,0,0},{NULL
,0,0},{NULL
,0,0},{NULL
,0,0}};
691 m2D temp
[4] = {{NULL
,0,0},{NULL
,0,0},{NULL
,0,0},{NULL
,0,0}};
692 m2D tempw
[4] = {{NULL
,0,0},{NULL
,0,0},{NULL
,0,0},{NULL
,0,0}};
693 m2D temp2
[4] = {{NULL
,0,0},{NULL
,0,0},{NULL
,0,0},{NULL
,0,0}};
698 lo
[i
] = (m2D
){NULL
,0,0};
702 temp
[i
] = convolve_transpose_padded(x
[i
], af
[i
>>1][2], pt
, pc
, pi
, check
);
703 if(check
&& check())goto cleanup
;
704 tempw
[i
] = convolve_padded(temp
[i
], af
[i
&1][2], pt
, pc
, pi
, check
); /* w 7 */
705 if(check
&& check())goto cleanup
;
710 complex_threshold(tempw
, T
, soft
, pt
, pc
, pi
, check
);
711 if(check
&& check())goto cleanup
;
714 temp2
[i
]=alloc_m2D(c
*2 - FSZ
*3 + 2, r
);
715 y
[i
] = alloc_m2D(temp2
[i
].rows
, temp2
[i
].cols
*2 - FSZ
*3 + 2);
716 if(check
&& check())goto cleanup
;
717 deconvolve_transpose_padded(temp2
[i
],tempw
[i
],sf
[i
&1][2], pt
, pc
, pi
, check
);
718 if(check
&& check())goto cleanup
;
720 tempw
[i
] = convolve_padded(temp
[i
], af
[i
&1][1], pt
, pc
, pi
, check
); /* w6 */
721 if(check
&& check())goto cleanup
;
723 complex_threshold(tempw
, T
, soft
, pt
, pc
, pi
, check
);
724 if(check
&& check())goto cleanup
;
727 deconvolve_transpose_padded(temp2
[i
],tempw
[i
],sf
[i
&1][1], pt
, pc
, pi
, check
);
728 if(check
&& check())goto cleanup
;
730 tempw
[i
] = convolve_padded(temp
[i
], af
[i
&1][0], pt
, pc
, pi
, check
); /* w5 */
731 if(check
&& check())goto cleanup
;
734 complex_threshold(tempw
, T
, soft
, pt
, pc
, pi
, check
);
735 if(check
&& check())goto cleanup
;
738 deconvolve_transpose_padded(temp2
[i
],tempw
[i
],sf
[i
&1][0], pt
, pc
, pi
, check
);
739 if(check
&& check())goto cleanup
;
741 deconvolve_padded(y
[i
],temp2
[i
],sf
[i
>>1][2], pt
, pc
, pi
, check
);
742 if(check
&& check())goto cleanup
;
744 temp
[i
] = convolve_transpose_padded(x
[i
], af
[i
>>1][1], pt
, pc
, pi
, check
);
745 if(check
&& check())goto cleanup
;
746 temp2
[i
] = alloc_m2D(c
*2 - FSZ
*3 + 2, r
);
747 if(check
&& check())goto cleanup
;
748 tempw
[i
] = convolve_padded(temp
[i
], af
[i
&1][2], pt
, pc
, pi
, check
); /* w4 */
749 if(check
&& check())goto cleanup
;
751 complex_threshold(tempw
, T
, soft
, pt
, pc
, pi
, check
);
752 if(check
&& check())goto cleanup
;
755 deconvolve_transpose_padded(temp2
[i
],tempw
[i
],sf
[i
&1][2], pt
, pc
, pi
, check
);
756 if(check
&& check())goto cleanup
;
758 tempw
[i
] = convolve_padded(temp
[i
], af
[i
&1][1], pt
, pc
, pi
, check
); /* w3 */
759 if(check
&& check())goto cleanup
;
761 complex_threshold(tempw
, T
, soft
, pt
, pc
, pi
, check
);
762 if(check
&& check())goto cleanup
;
765 deconvolve_transpose_padded(temp2
[i
],tempw
[i
],sf
[i
&1][1], pt
, pc
, pi
, check
);
766 if(check
&& check())goto cleanup
;
768 tempw
[i
] = convolve_padded(temp
[i
], af
[i
&1][0], pt
, pc
, pi
, check
); /* w2 */
769 if(check
&& check())goto cleanup
;
772 complex_threshold(tempw
, T
, soft
, pt
, pc
, pi
, check
);
773 if(check
&& check())goto cleanup
;
776 deconvolve_transpose_padded(temp2
[i
],tempw
[i
],sf
[i
&1][0], pt
, pc
, pi
, check
);
777 if(check
&& check())goto cleanup
;
779 deconvolve_padded(y
[i
],temp2
[i
],sf
[i
>>1][1], pt
, pc
, pi
, check
);
780 if(check
&& check())goto cleanup
;
782 temp
[i
] = convolve_transpose_padded(x
[i
], af
[i
>>1][0], pt
, pc
, pi
, check
);
783 if(check
&& check())goto cleanup
;
784 if(free_input
) free_m2D(x
+i
);
785 temp2
[i
] = alloc_m2D(c
*2 - FSZ
*3 + 2, r
);
786 if(check
&& check())goto cleanup
;
787 tempw
[i
] = convolve_padded(temp
[i
], af
[i
&1][2], pt
, pc
, pi
, check
); /* w1 */
788 if(check
&& check())goto cleanup
;
790 complex_threshold(tempw
, T
, soft
, pt
, pc
, pi
, check
);
791 if(check
&& check())goto cleanup
;
794 deconvolve_transpose_padded(temp2
[i
],tempw
[i
],sf
[i
&1][2], pt
, pc
, pi
, check
);
795 if(check
&& check())goto cleanup
;
797 tempw
[i
] = convolve_padded(temp
[i
], af
[i
&1][1], pt
, pc
, pi
, check
); /* w0 */
798 if(check
&& check())goto cleanup
;
800 complex_threshold(tempw
, T
, soft
, pt
, pc
, pi
, check
);
801 if(check
&& check())goto cleanup
;
804 deconvolve_transpose_padded(temp2
[i
],tempw
[i
],sf
[i
&1][1], pt
, pc
, pi
, check
);
805 if(check
&& check())goto cleanup
;
806 deconvolve_padded(y
[i
],temp2
[i
],sf
[i
>>1][0], pt
, pc
, pi
, check
);
807 if(check
&& check())goto cleanup
;
808 lo
[i
] = convolve_padded(temp
[i
], af
[i
&1][0], pt
, pc
, pi
, check
); /* lo */
809 if(check
&& check())goto cleanup
;
815 if(free_input
)free_m2D(x
+i
);
822 /* consumes/replaces lo */
823 static void finish_backward(m2D lo
[4], m2D y
[4], float sf
[2][3][FSZ
], int pt
, int *pc
, int pi
, int(*check
)(void)){
824 int r
=lo
[0].rows
,c
=lo
[0].cols
,i
;
825 m2D temp
= {NULL
,0,0};
828 temp
=alloc_m2D(c
*2 - FSZ
*3 + 2, r
);
829 deconvolve_transpose_padded(temp
,lo
[i
],sf
[i
&1][0], pt
, pc
, pi
, check
);
831 if(check
&& check()){
835 deconvolve_padded(y
[i
],temp
,sf
[i
>>1][0], pt
, pc
, pi
, check
);
838 y
[i
]=(m2D
){NULL
,0,0};
839 if(check
&& check()) return;
843 static m2D
transform_threshold(m2D x
, int J
, float T
[16], int soft
, int pt
, int *pc
, int (*check
)(void)){
850 partial_y
[j
][i
]=(m2D
){NULL
,0,0};
852 lo
[0] = lo
[1] = lo
[2] = lo
[3] = x
;
854 forward_threshold(lo
, partial_y
[0], analysis_fs
, synthesis_fs
, T
[0], soft
, 0, pt
, pc
, (1<<18), check
);
855 if(check
&& check()) goto cleanup3
;
858 forward_threshold(lo
, partial_y
[j
], analysis
, synthesis
, T
[j
], soft
, 1, pt
, pc
, (1<<(9-j
>0?(9-j
)*2:1)), check
);
859 if(check
&& check()) goto cleanup3
;
863 finish_backward(lo
, partial_y
[j
], synthesis
, pt
, pc
, (1<<(9-j
>0?(9-j
)*2:1)), check
);
864 if(check
&& check()) goto cleanup3
;
867 finish_backward(lo
, partial_y
[0], synthesis_fs
, pt
, pc
, (1<<18), check
);
868 if(check
&& check()) goto cleanup3
;
871 int end
= lo
[0].rows
*lo
[0].cols
;
878 y
[j
]+=p1
[j
]+p2
[j
]+p3
[j
];
880 if(check
&& check()) goto cleanup3
;
887 free_m2D(&partial_y
[j
][i
]);
896 static int wavelet_filter(int width
, int height
, float *buffer
,
897 int pr
, float T
[16], int soft
, int (*check
)(void)){
907 if(check
&& check())goto abort
;
909 /* we want J to be as 'deep' as the image to eliminate
910 splotchiness with deep coarse settings */
913 int mult
= 1 << (J
+1);
914 if(width
/mult
< 1) break;
915 if(height
/mult
< 1) break;
922 pt
+=108*(1<<(9-i
>0?(9-i
)*2:1));
924 /* Input matrix must be pre-padded for first stage convolutions;
925 odd->even padding goes on the bottom/right */
927 xc
= alloc_m2D((height
+1)/2*2+FSZ
*2-2,
928 (width
+1)/2*2+FSZ
*2-2),yc
;
929 if(check
&& check())goto abort
;
931 /* populate and pad input matrix */
932 for(i
=0;i
<height
;i
++){
933 float *row
=xc
.x
+ (i
+FSZ
-1)*xc
.cols
;
940 for(;j
<width
+FSZ
-1;j
++){
951 for(i
=FSZ
-2;i
>=0;i
--){
952 float *pre
=xc
.x
+ (i
+1)*xc
.cols
;
953 float *row
=xc
.x
+ i
*xc
.cols
;
954 for(j
=0;j
<xc
.cols
;j
++)
957 for(i
=xc
.rows
-FSZ
+1;i
<xc
.rows
;i
++){
958 float *pre
=xc
.x
+ (i
-1)*xc
.cols
;
959 float *row
=xc
.x
+ i
*xc
.cols
;
960 for(j
=0;j
<xc
.cols
;j
++)
964 if(check
&& check())goto abort
;
965 yc
=transform_threshold(xc
,J
,T
,soft
,pt
,&pc
,check
);
966 if(check
&& check())goto abort
;
968 /* pull filtered values back out of padded matrix */
970 for(i
=0;i
<height
;i
++){
971 float *row
= yc
.x
+ (i
+FSZ
-1)*yc
.cols
+ FSZ
-1;
980 return (check
&& check());