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