1 /*****************************************************************************
2 * This file is part of gfxprim library. *
4 * Gfxprim is free software; you can redistribute it and/or *
5 * modify it under the terms of the GNU Lesser General Public *
6 * License as published by the Free Software Foundation; either *
7 * version 2.1 of the License, or (at your option) any later version. *
9 * Gfxprim is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
12 * Lesser General Public License for more details. *
14 * You should have received a copy of the GNU Lesser General Public *
15 * License along with gfxprim; if not, write to the Free Software *
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
17 * Boston, MA 02110-1301 USA *
19 * Copyright (C) 2009-2013 Cyril Hrubis <metan@ucw.cz> *
21 *****************************************************************************/
25 #include "core/GP_Pixmap.h"
26 #include "core/GP_GetPutPixel.h"
27 #include "core/GP_TempAlloc.h"
28 #include "core/GP_Clamp.h"
30 #include "core/GP_Debug.h"
32 #include "GP_WeightedMedian.h"
36 static unsigned int sum_weights(GP_MedianWeights
*weights
)
41 for (i
= 0; i
< weights
->w
* weights
->h
; i
++)
42 sum
+= weights
->weights
[i
];
47 static inline void hist_add(unsigned int *hist
, unsigned int val
,
53 static inline unsigned int hist_med(unsigned int *hist
, unsigned int size
,
54 unsigned int threshold
)
59 for (i
= 0; i
< size
; i
++) {
65 GP_BUG("Threshold not reached");
69 static inline void hist_clear(unsigned int *hist
, unsigned int size
)
71 memset(hist
, 0, sizeof(unsigned int) * size
);
74 static inline unsigned int get_weight(GP_MedianWeights
*weights
,
75 unsigned int x
, unsigned int y
)
77 return weights
->weights
[y
* weights
->w
+ x
];
80 static int GP_FilterWeightedMedian_Raw(const GP_Pixmap
*src
,
81 GP_Coord x_src
, GP_Coord y_src
,
82 GP_Size w_src
, GP_Size h_src
,
84 GP_Coord x_dst
, GP_Coord y_dst
,
85 GP_MedianWeights
*weights
,
86 GP_ProgressCallback
*callback
)
88 int x
, y
, sum
= sum_weights(weights
);
91 if (src
->pixel_type
!= GP_PIXEL_RGB888
) {
96 GP_DEBUG(1, "Weighted Median filter size %ux%u xmed=%u ymed=%u sum=%u",
97 w_src
, h_src
, weights
->w
, weights
->h
, sum
);
99 unsigned int w
= w_src
+ weights
->w
;
100 unsigned int size
= w
* weights
->h
;
102 GP_TempAllocCreate(temp
, 3 * size
* sizeof(unsigned int));
104 unsigned int *R
= GP_TempAllocGet(temp
, size
* sizeof(unsigned int));
105 unsigned int *G
= GP_TempAllocGet(temp
, size
* sizeof(unsigned int));
106 unsigned int *B
= GP_TempAllocGet(temp
, size
* sizeof(unsigned int));
108 /* prefil the sampled array */
109 for (x
= 0; x
< (int)w
; x
++) {
110 int xi
= GP_CLAMP(x_src
+ x
- (int)weights
->w
/2, 0, (int)src
->w
- 1);
112 for (y
= 0; y
< (int)weights
->h
; y
++) {
113 int yi
= GP_CLAMP(y_src
+ y
- (int)weights
->h
, 0, (int)src
->h
- 1);
115 GP_Pixel pix
= GP_GetPixel_Raw_24BPP(src
, xi
, yi
);
117 R
[y
* w
+ x
] = GP_Pixel_GET_R_RGB888(pix
);
118 G
[y
* w
+ x
] = GP_Pixel_GET_G_RGB888(pix
);
119 B
[y
* w
+ x
] = GP_Pixel_GET_B_RGB888(pix
);
123 unsigned int hist_R
[256];
124 unsigned int hist_G
[256];
125 unsigned int hist_B
[256];
127 hist_clear(hist_R
, 256);
128 hist_clear(hist_G
, 256);
129 hist_clear(hist_B
, 256);
131 /* Apply the weighted median filter */
132 for (y
= 0; y
< (int)h_src
; y
++) {
133 for (x
= 0; x
< (int)w_src
; x
++) {
134 /* compute weighted histogram and then median */
135 for (x1
= 0; x1
< weights
->w
; x1
++) {
136 for (y1
= 0; y1
< weights
->h
; y1
++) {
137 unsigned int weight
= get_weight(weights
, x1
, y1
);
138 hist_add(hist_R
, R
[y1
* w
+ x
+ x1
], weight
);
139 hist_add(hist_G
, G
[y1
* w
+ x
+ x1
], weight
);
140 hist_add(hist_B
, B
[y1
* w
+ x
+ x1
], weight
);
144 unsigned int r
= hist_med(hist_R
, 256, sum
/2);
145 unsigned int g
= hist_med(hist_G
, 256, sum
/2);
146 unsigned int b
= hist_med(hist_B
, 256, sum
/2);
148 GP_PutPixel_Raw_24BPP(dst
, x_dst
+ x
, y_dst
+ y
,
149 GP_Pixel_CREATE_RGB888(r
, g
, b
));
151 hist_clear(hist_R
, 256);
152 hist_clear(hist_G
, 256);
153 hist_clear(hist_B
, 256);
156 for (x
= 0; x
< (int)w
; x
++) {
157 int xi
= GP_CLAMP(x_src
+ x
- (int)weights
->w
/2, 0, (int)src
->w
- 1);
159 for (y1
= 0; y1
< weights
->h
; y1
++) {
160 int yi
= GP_CLAMP(y_src
+ y
+ (int)y1
- (int)weights
->h
/2, 0, (int)src
->h
- 1);
162 GP_Pixel pix
= GP_GetPixel_Raw_24BPP(src
, xi
, yi
);
164 R
[y1
* w
+ x
] = GP_Pixel_GET_R_RGB888(pix
);
165 G
[y1
* w
+ x
] = GP_Pixel_GET_G_RGB888(pix
);
166 B
[y1
* w
+ x
] = GP_Pixel_GET_B_RGB888(pix
);
170 if (GP_ProgressCallbackReport(callback
, y
, h_src
, w_src
)) {
171 GP_TempAllocFree(temp
);
176 GP_TempAllocFree(temp
);
177 GP_ProgressCallbackDone(callback
);
182 int GP_FilterWeightedMedianEx(const GP_Pixmap
*src
,
183 GP_Coord x_src
, GP_Coord y_src
,
184 GP_Size w_src
, GP_Size h_src
,
186 GP_Coord x_dst
, GP_Coord y_dst
,
187 GP_MedianWeights
*weights
,
188 GP_ProgressCallback
*callback
)
190 GP_CHECK(src
->pixel_type
== dst
->pixel_type
);
192 /* Check that destination is large enough */
193 GP_CHECK(x_dst
+ (GP_Coord
)w_src
<= (GP_Coord
)dst
->w
);
194 GP_CHECK(y_dst
+ (GP_Coord
)h_src
<= (GP_Coord
)dst
->h
);
196 //GP_CHECK(xmed >= 0 && ymed >= 0);
198 return GP_FilterWeightedMedian_Raw(src
, x_src
, y_src
, w_src
, h_src
,
199 dst
, x_dst
, y_dst
, weights
, callback
);
202 GP_Pixmap
*GP_FilterWeightedMedianExAlloc(const GP_Pixmap
*src
,
203 GP_Coord x_src
, GP_Coord y_src
,
204 GP_Size w_src
, GP_Size h_src
,
205 GP_MedianWeights
*weights
,
206 GP_ProgressCallback
*callback
)
210 //GP_CHECK(xmed >= 0 && ymed >= 0);
212 GP_Pixmap
*dst
= GP_PixmapAlloc(w_src
, h_src
, src
->pixel_type
);
217 ret
= GP_FilterWeightedMedian_Raw(src
, x_src
, y_src
, w_src
, h_src
,
218 dst
, 0, 0, weights
, callback
);