1 /* 2 * Copyright (c) 2003, 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 mlib_status JNICALL mlib_ImageConvKernelConvert(mlib_s32 *ikernel, 82 mlib_s32 *iscale, 83 const mlib_d64 *fkernel, 84 mlib_s32 m, 85 mlib_s32 n, 86 mlib_type type) 87 { 88 mlib_d64 sum_pos, sum_neg, sum, norm, max, f; 89 mlib_s32 isum_pos, isum_neg, isum, test; 90 mlib_s32 i, scale, scale1, chk_flag; 91 92 if (ikernel == NULL || iscale == NULL || fkernel == NULL || m < 1 || n < 1) { 93 return MLIB_FAILURE; 94 } 95 96 if ((type == MLIB_BYTE) || (type == MLIB_SHORT) || (type == MLIB_USHORT)) { 97 98 if (type != MLIB_SHORT) { /* MLIB_BYTE, MLIB_USHORT */ 99 sum_pos = 0; 100 sum_neg = 0; 101 102 for (i = 0; i < m * n; i++) { 103 if (fkernel[i] > 0) 104 sum_pos += fkernel[i]; 105 else 106 sum_neg -= fkernel[i]; 107 } 108 109 sum = (sum_pos > sum_neg) ? sum_pos : sum_neg; 110 scale = mlib_ilogb(sum); 111 scale++; 112 113 scale = 31 - scale; 114 } 115 else { /* MLIB_SHORT */ 116 sum = 0; 117 max = 0; 118 119 for (i = 0; i < m * n; i++) { 120 f = mlib_fabs(fkernel[i]); 121 sum += f; 122 max = (max > f) ? max : f; 123 } 124 125 scale1 = mlib_ilogb(max) + 1; 126 scale = mlib_ilogb(sum); 127 scale = (scale > scale1) ? scale : scale1; 128 scale++; 129 130 scale = 32 - scale; 131 } 132 133 if (scale <= 16) 134 return MLIB_FAILURE; 135 if (scale > 31) 136 scale = 31; 137 138 *iscale = scale; 139 140 chk_flag = mlib_ImageConvVersion(m, n, scale, type); 141 142 if (!chk_flag) { 143 norm = (1u << scale); 144 for (i = 0; i < m * n; i++) { 145 CLAMP_S32(ikernel[i], fkernel[i] * norm); 146 } 147 148 return MLIB_SUCCESS; 149 } 150 151 /* try to round coefficients */ 152 #ifdef __sparc 153 scale1 = 16; /* shift of coefficients is 16 */ 154 #else 155 156 if (chk_flag == 3) 157 scale1 = 16; /* MMX */ 158 else 159 scale1 = (type == MLIB_BYTE) ? 8 : 16; 160 #endif /* __sparc */ 161 norm = (1u << (scale - scale1)); 162 163 for (i = 0; i < m * n; i++) { 164 if (fkernel[i] > 0) 165 ikernel[i] = (mlib_s32) (fkernel[i] * norm + 0.5); 166 else 167 ikernel[i] = (mlib_s32) (fkernel[i] * norm - 0.5); 168 } 169 170 isum_pos = 0; 171 isum_neg = 0; 172 test = 0; 173 174 for (i = 0; i < m * n; i++) { 175 if (ikernel[i] > 0) 176 isum_pos += ikernel[i]; 177 else 178 isum_neg -= ikernel[i]; 179 } 180 181 if (type == MLIB_BYTE || type == MLIB_USHORT) { 182 isum = (isum_pos > isum_neg) ? isum_pos : isum_neg; 183 184 if (isum >= (1 << (31 - scale1))) 185 test = 1; 186 } 187 else { 188 isum = isum_pos + isum_neg; 189 190 if (isum >= (1 << (32 - scale1))) 191 test = 1; 192 for (i = 0; i < m * n; i++) { 193 if (abs(ikernel[i]) >= (1 << (31 - scale1))) 194 test = 1; 195 } 196 } 197 198 if (test == 1) { /* rounding according scale1 cause overflow, truncate instead of round */ 199 for (i = 0; i < m * n; i++) 200 ikernel[i] = (mlib_s32) (fkernel[i] * norm) << scale1; 201 } 202 else { /* rounding is Ok */ 203 for (i = 0; i < m * n; i++) 204 ikernel[i] = ikernel[i] << scale1; 205 } 206 207 return MLIB_SUCCESS; 208 } 209 else if ((type == MLIB_INT) || (type == MLIB_BIT)) { 210 max = 0; 211 212 for (i = 0; i < m * n; i++) { 213 f = mlib_fabs(fkernel[i]); 214 max = (max > f) ? max : f; 215 } 216 217 scale = mlib_ilogb(max); 218 219 if (scale > 29) 220 return MLIB_FAILURE; 221 222 if (scale < -100) 223 scale = -100; 224 225 *iscale = 29 - scale; 226 scale = 29 - scale; 227 228 norm = 1.0; 229 while (scale > 30) { 230 norm *= (1 << 30); 231 scale -= 30; 232 } 233 234 norm *= (1 << scale); 235 236 for (i = 0; i < m * n; i++) { 237 if (fkernel[i] > 0) { 238 CLAMP_S32(ikernel[i], fkernel[i] * norm + 0.5); 239 } 240 else { 241 CLAMP_S32(ikernel[i], fkernel[i] * norm - 0.5); 242 } 243 } 244 245 return MLIB_SUCCESS; 246 } 247 else { 248 return MLIB_FAILURE; 249 } 250 } 251 252 /***************************************************************/