1 | /* |
2 | * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. |
3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 | * |
5 | * This code is free software; you can redistribute it and/or modify it |
6 | * under the terms of the GNU General Public License version 2 only, as |
7 | * published by the Free Software Foundation. Oracle designates this |
8 | * particular file as subject to the "Classpath" exception as provided |
9 | * by Oracle in the LICENSE file that accompanied this code. |
10 | * |
11 | * This code is distributed in the hope that it will be useful, but WITHOUT |
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
14 | * version 2 for more details (a copy is included in the LICENSE file that |
15 | * accompanied this code). |
16 | * |
17 | * You should have received a copy of the GNU General Public License version |
18 | * 2 along with this work; if not, write to the Free Software Foundation, |
19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
20 | * |
21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
22 | * or visit www.oracle.com if you need additional information or have any |
23 | * questions. |
24 | */ |
25 | |
26 | |
27 | /* |
28 | * FUNCTION |
29 | * mlib_ImageConvKernelConvert - Convert convolution kernel from |
30 | * floating point version to integer |
31 | * version. |
32 | * |
33 | * SYNOPSIS |
34 | * mlib_status mlib_ImageConvKernelConvert(mlib_s32 *ikernel, |
35 | * mlib_s32 *iscale, |
36 | * const mlib_d64 *fkernel, |
37 | * mlib_s32 m, |
38 | * mlib_s32 n, |
39 | * mlib_type type); |
40 | * |
41 | * ARGUMENT |
42 | * ikernel integer kernel |
43 | * iscale scaling factor of the integer kernel |
44 | * fkernel floating-point kernel |
45 | * m width of the convolution kernel |
46 | * n height of the convolution kernel |
47 | * type image type |
48 | * |
49 | * DESCRIPTION |
50 | * Convert a floating point convolution kernel to integer kernel |
51 | * with scaling factor. The result integer kernel and scaling factor |
52 | * can be used in convolution functions directly without overflow. |
53 | * |
54 | * RESTRICTION |
55 | * The type can be MLIB_BYTE, MLIB_SHORT, MLIB_USHORT or MLIB_INT. |
56 | */ |
57 | |
58 | #include <stdlib.h> |
59 | #include "mlib_image.h" |
60 | #include "mlib_SysMath.h" |
61 | #include "mlib_ImageConv.h" |
62 | |
63 | /***************************************************************/ |
64 | #ifdef __sparc |
65 | |
66 | #define CLAMP_S32(dst, src) \ |
67 | dst = (mlib_s32)(src) |
68 | |
69 | #else |
70 | |
71 | #define CLAMP_S32(dst, src) { \ |
72 | mlib_d64 s0 = (mlib_d64)(src); \ |
73 | if (s0 > (mlib_d64)MLIB_S32_MAX) s0 = (mlib_d64)MLIB_S32_MAX; \ |
74 | if (s0 < (mlib_d64)MLIB_S32_MIN) s0 = (mlib_d64)MLIB_S32_MIN; \ |
75 | dst = (mlib_s32)s0; \ |
76 | } |
77 | |
78 | #endif /* __sparc */ |
79 | |
80 | /***************************************************************/ |
81 | JNIEXPORT |
82 | mlib_status mlib_ImageConvKernelConvert(mlib_s32 *ikernel, |
83 | mlib_s32 *iscale, |
84 | const mlib_d64 *fkernel, |
85 | mlib_s32 m, |
86 | mlib_s32 n, |
87 | mlib_type type) |
88 | { |
89 | mlib_d64 sum_pos, sum_neg, sum, norm, max, f; |
90 | mlib_s32 isum_pos, isum_neg, isum, test; |
91 | mlib_s32 i, scale, scale1, chk_flag; |
92 | |
93 | if (ikernel == NULL || iscale == NULL || fkernel == NULL || m < 1 || n < 1) { |
94 | return MLIB_FAILURE; |
95 | } |
96 | |
97 | if ((type == MLIB_BYTE) || (type == MLIB_SHORT) || (type == MLIB_USHORT)) { |
98 | |
99 | if (type != MLIB_SHORT) { /* MLIB_BYTE, MLIB_USHORT */ |
100 | sum_pos = 0; |
101 | sum_neg = 0; |
102 | |
103 | for (i = 0; i < m * n; i++) { |
104 | if (fkernel[i] > 0) |
105 | sum_pos += fkernel[i]; |
106 | else |
107 | sum_neg -= fkernel[i]; |
108 | } |
109 | |
110 | sum = (sum_pos > sum_neg) ? sum_pos : sum_neg; |
111 | scale = mlib_ilogb(sum); |
112 | scale++; |
113 | |
114 | scale = 31 - scale; |
115 | } |
116 | else { /* MLIB_SHORT */ |
117 | sum = 0; |
118 | max = 0; |
119 | |
120 | for (i = 0; i < m * n; i++) { |
121 | f = mlib_fabs(fkernel[i]); |
122 | sum += f; |
123 | max = (max > f) ? max : f; |
124 | } |
125 | |
126 | scale1 = mlib_ilogb(max) + 1; |
127 | scale = mlib_ilogb(sum); |
128 | scale = (scale > scale1) ? scale : scale1; |
129 | scale++; |
130 | |
131 | scale = 32 - scale; |
132 | } |
133 | |
134 | if (scale <= 16) |
135 | return MLIB_FAILURE; |
136 | if (scale > 31) |
137 | scale = 31; |
138 | |
139 | *iscale = scale; |
140 | |
141 | chk_flag = mlib_ImageConvVersion(m, n, scale, type); |
142 | |
143 | if (!chk_flag) { |
144 | norm = (1u << scale); |
145 | for (i = 0; i < m * n; i++) { |
146 | CLAMP_S32(ikernel[i], fkernel[i] * norm); |
147 | } |
148 | |
149 | return MLIB_SUCCESS; |
150 | } |
151 | |
152 | /* try to round coefficients */ |
153 | #ifdef __sparc |
154 | scale1 = 16; /* shift of coefficients is 16 */ |
155 | #else |
156 | |
157 | if (chk_flag == 3) |
158 | scale1 = 16; /* MMX */ |
159 | else |
160 | scale1 = (type == MLIB_BYTE) ? 8 : 16; |
161 | #endif /* __sparc */ |
162 | norm = (1u << (scale - scale1)); |
163 | |
164 | for (i = 0; i < m * n; i++) { |
165 | if (fkernel[i] > 0) |
166 | ikernel[i] = (mlib_s32) (fkernel[i] * norm + 0.5); |
167 | else |
168 | ikernel[i] = (mlib_s32) (fkernel[i] * norm - 0.5); |
169 | } |
170 | |
171 | isum_pos = 0; |
172 | isum_neg = 0; |
173 | test = 0; |
174 | |
175 | for (i = 0; i < m * n; i++) { |
176 | if (ikernel[i] > 0) |
177 | isum_pos += ikernel[i]; |
178 | else |
179 | isum_neg -= ikernel[i]; |
180 | } |
181 | |
182 | if (type == MLIB_BYTE || type == MLIB_USHORT) { |
183 | isum = (isum_pos > isum_neg) ? isum_pos : isum_neg; |
184 | |
185 | if (isum >= (1 << (31 - scale1))) |
186 | test = 1; |
187 | } |
188 | else { |
189 | isum = isum_pos + isum_neg; |
190 | |
191 | if (isum >= (1 << (32 - scale1))) |
192 | test = 1; |
193 | for (i = 0; i < m * n; i++) { |
194 | if (abs(ikernel[i]) >= (1 << (31 - scale1))) |
195 | test = 1; |
196 | } |
197 | } |
198 | |
199 | if (test == 1) { /* rounding according scale1 cause overflow, truncate instead of round */ |
200 | for (i = 0; i < m * n; i++) |
201 | ikernel[i] = (mlib_s32) (fkernel[i] * norm) << scale1; |
202 | } |
203 | else { /* rounding is Ok */ |
204 | for (i = 0; i < m * n; i++) |
205 | ikernel[i] = ikernel[i] << scale1; |
206 | } |
207 | |
208 | return MLIB_SUCCESS; |
209 | } |
210 | else if ((type == MLIB_INT) || (type == MLIB_BIT)) { |
211 | max = 0; |
212 | |
213 | for (i = 0; i < m * n; i++) { |
214 | f = mlib_fabs(fkernel[i]); |
215 | max = (max > f) ? max : f; |
216 | } |
217 | |
218 | scale = mlib_ilogb(max); |
219 | |
220 | if (scale > 29) |
221 | return MLIB_FAILURE; |
222 | |
223 | if (scale < -100) |
224 | scale = -100; |
225 | |
226 | *iscale = 29 - scale; |
227 | scale = 29 - scale; |
228 | |
229 | norm = 1.0; |
230 | while (scale > 30) { |
231 | norm *= (1 << 30); |
232 | scale -= 30; |
233 | } |
234 | |
235 | norm *= (1 << scale); |
236 | |
237 | for (i = 0; i < m * n; i++) { |
238 | if (fkernel[i] > 0) { |
239 | CLAMP_S32(ikernel[i], fkernel[i] * norm + 0.5); |
240 | } |
241 | else { |
242 | CLAMP_S32(ikernel[i], fkernel[i] * norm - 0.5); |
243 | } |
244 | } |
245 | |
246 | return MLIB_SUCCESS; |
247 | } |
248 | else { |
249 | return MLIB_FAILURE; |
250 | } |
251 | } |
252 | |
253 | /***************************************************************/ |
254 | |