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