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 /***************************************************************/