1 /*
   2  * Copyright (c) 2003, 2013, 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_ImageConvMxN - image convolution with edge condition
  30  *
  31  * SYNOPSIS
  32  *      mlib_status mlib_ImageConvMxN(mlib_image       *dst,
  33  *                                    const mlib_image *src,
  34  *                                    const mlib_s32   *kernel,
  35  *                                    mlib_s32         m,
  36  *                                    mlib_s32         n,
  37  *                                    mlib_s32         dm,
  38  *                                    mlib_s32         dn,
  39  *                                    mlib_s32         scale,
  40  *                                    mlib_s32         cmask,
  41  *                                    mlib_edge        edge)
  42  *
  43  * ARGUMENTS
  44  *      dst       Pointer to destination image.
  45  *      src       Pointer to source image.
  46  *      m         Kernel width (m must be not less than 1).
  47  *      n         Kernel height (n must be not less than 1).
  48  *      dm, dn    Position of key element in convolution kernel.
  49  *      kernel    Pointer to convolution kernel.
  50  *      scale     The scaling factor to convert the input integer
  51  *                coefficients into floating-point coefficients:
  52  *                floating-point coefficient = integer coefficient * 2^(-scale)
  53  *      cmask     Channel mask to indicate the channels to be convolved.
  54  *                Each bit of which represents a channel in the image. The
  55  *                channels corresponded to 1 bits are those to be processed.
  56  *      edge      Type of edge condition.
  57  *
  58  * DESCRIPTION
  59  *      2-D convolution, MxN kernel.
  60  *
  61  *      The center of the source image is mapped to the center of the
  62  *      destination image.
  63  *      The unselected channels are not overwritten. If both src and dst have
  64  *      just one channel, cmask is ignored.
  65  *
  66  *      The edge condition can be one of the following:
  67  *              MLIB_EDGE_DST_NO_WRITE  (default)
  68  *              MLIB_EDGE_DST_FILL_ZERO
  69  *              MLIB_EDGE_DST_COPY_SRC
  70  *              MLIB_EDGE_SRC_EXTEND
  71  *
  72  * RESTRICTION
  73  *      The src and the dst must be the same type and have same number
  74  *      of channels (1, 2, 3, or 4).
  75  *      m >= 1, n >= 1,
  76  *      0 <= dm < m, 0 <= dn < n.
  77  *      For data type MLIB_BYTE:   16 <= scale <= 31 (to be compatible with VIS version)
  78  *      For data type MLIB_USHORT: 17 <= scale <= 32 (to be compatible with VIS version)
  79  *      For data type MLIB_SHORT:  17 <= scale <= 32 (to be compatible with VIS version)
  80  *      For data type MLIB_INT:    scale >= 0
  81  */
  82 
  83 #include "mlib_image.h"
  84 #include "mlib_ImageConv.h"
  85 
  86 /***************************************************************/
  87 static void mlib_ImageConvMxNMulAdd_S32(mlib_d64       *dst,
  88                                         const mlib_s32 *src,
  89                                         const mlib_d64 *dkernel,
  90                                         mlib_s32       n,
  91                                         mlib_s32       m,
  92                                         mlib_s32       nch);
  93 
  94 static void mlib_ImageConvMxNMedian_S32(mlib_s32 *dst,
  95                                         mlib_d64 *src,
  96                                         mlib_s32 n,
  97                                         mlib_s32 nch);
  98 
  99 static void mlib_ImageConvMxNS322S32_ext(mlib_s32       *dst,
 100                                          const mlib_s32 *src,
 101                                          mlib_s32       n,
 102                                          mlib_s32       nch,
 103                                          mlib_s32       dx_l,
 104                                          mlib_s32       dx_r);
 105 
 106 /***************************************************************/
 107 #ifdef MLIB_USE_FTOI_CLAMPING
 108 
 109 #define CLAMP_S32(dst, src)                                     \
 110   dst = (mlib_s32)(src)
 111 
 112 #else
 113 
 114 #define CLAMP_S32(dst, src) {                                   \
 115   mlib_d64 s0 = (mlib_d64)(src);                                \
 116   if (s0 > (mlib_d64)MLIB_S32_MAX) s0 = (mlib_d64)MLIB_S32_MAX; \
 117   if (s0 < (mlib_d64)MLIB_S32_MIN) s0 = (mlib_d64)MLIB_S32_MIN; \
 118   dst = (mlib_s32)s0;                                           \
 119 }
 120 
 121 #endif /* MLIB_USE_FTOI_CLAMPING */
 122 
 123 /***************************************************************/
 124 void mlib_ImageConvMxNMulAdd_S32(mlib_d64       *dst,
 125                                  const mlib_s32 *src,
 126                                  const mlib_d64 *dkernel,
 127                                  mlib_s32       n,
 128                                  mlib_s32       m,
 129                                  mlib_s32       nch)
 130 {
 131   mlib_d64 *dst1 = dst + 1;
 132   mlib_s32 i, j;
 133 
 134   for (j = 0; j < m; j += 3, src += 3 * nch, dkernel += 3) {
 135     const mlib_s32 *src2 = src + 2 * nch;
 136     mlib_d64 hval0 = dkernel[0];
 137     mlib_d64 hval1 = dkernel[1];
 138     mlib_d64 hval2 = dkernel[2];
 139     mlib_d64 val0 = src[0];
 140     mlib_d64 val1 = src[nch];
 141     mlib_d64 dval = dst[0];
 142 
 143     if (j == m - 2) {
 144       hval2 = 0.f;
 145     }
 146     else if (j == m - 1) {
 147       hval1 = 0.f;
 148       hval2 = 0.f;
 149     }
 150 
 151 #ifdef __SUNPRO_C
 152 #pragma pipeloop(0)
 153 #endif /* __SUNPRO_C */
 154     for (i = 0; i < n; i++) {
 155       mlib_d64 dval0 = val0 * hval0 + dval;
 156       mlib_d64 val2 = src2[i * nch];
 157 
 158       dval = dst1[i];
 159       dval0 += val1 * hval1;
 160       dval0 += val2 * hval2;
 161       val0 = val1;
 162       val1 = val2;
 163 
 164       dst[i] = dval0;
 165     }
 166   }
 167 }
 168 
 169 /***************************************************************/
 170 void mlib_ImageConvMxNMedian_S32(mlib_s32 *dst,
 171                                  mlib_d64 *src,
 172                                  mlib_s32 n,
 173                                  mlib_s32 nch)
 174 {
 175   mlib_s32 i;
 176 
 177 #ifdef __SUNPRO_C
 178 #pragma pipeloop(0)
 179 #endif /* __SUNPRO_C */
 180   for (i = 0; i < n; i++) {
 181     mlib_s32 res;
 182 
 183     CLAMP_S32(res, src[i]);
 184     src[i] = 0.5;
 185     dst[i * nch] = res;
 186   }
 187 }
 188 
 189 /***************************************************************/
 190 void mlib_ImageConvMxNS322S32_ext(mlib_s32       *dst,
 191                                   const mlib_s32 *src,
 192                                   mlib_s32       n,
 193                                   mlib_s32       nch,
 194                                   mlib_s32       dx_l,
 195                                   mlib_s32       dx_r)
 196 {
 197   mlib_s32 i;
 198   mlib_d64 val = src[0];
 199 
 200   for (i = 0; i < dx_l; i++)
 201     dst[i] = (mlib_s32) val;
 202 #ifdef __SUNPRO_C
 203 #pragma pipeloop(0)
 204 #endif /* __SUNPRO_C */
 205   for (; i < n - dx_r; i++)
 206     dst[i] = src[nch * (i - dx_l)];
 207   val = dst[n - dx_r - 1];
 208   for (; i < n; i++)
 209     dst[i] = (mlib_s32) val;
 210 }
 211 
 212 /***************************************************************/
 213 mlib_status mlib_convMxNext_s32(mlib_image       *dst,
 214                                 const mlib_image *src,
 215                                 const mlib_s32   *kernel,
 216                                 mlib_s32         m,
 217                                 mlib_s32         n,
 218                                 mlib_s32         dx_l,
 219                                 mlib_s32         dx_r,
 220                                 mlib_s32         dy_t,
 221                                 mlib_s32         dy_b,
 222                                 mlib_s32         scale,
 223                                 mlib_s32         cmask)
 224 {
 225   mlib_d64 dspace[1024], *dsa = dspace;
 226   mlib_d64 akernel[256], *dkernel = akernel, fscale = 1.0;
 227   mlib_s32 wid_e = mlib_ImageGetWidth(src);
 228   mlib_d64 *dsh, *dsv;
 229   mlib_s32 *isa;
 230   mlib_s32 *da = mlib_ImageGetData(dst);
 231   mlib_s32 *sa = mlib_ImageGetData(src);
 232   mlib_s32 dlb = mlib_ImageGetStride(dst) >> 2;
 233   mlib_s32 slb = mlib_ImageGetStride(src) >> 2;
 234   mlib_s32 dw = mlib_ImageGetWidth(dst);
 235   mlib_s32 dh = mlib_ImageGetHeight(dst);
 236   mlib_s32 nch = mlib_ImageGetChannels(dst);
 237   mlib_s32 i, j, j1, k, mn;
 238 
 239   /* internal buffer */
 240 
 241   if (3 * wid_e + m > 1024) {
 242     dsa = mlib_malloc((3 * wid_e + m) * sizeof(mlib_d64));
 243 
 244     if (dsa == NULL)
 245       return MLIB_FAILURE;
 246   }
 247 
 248   isa = (mlib_s32 *) dsa;
 249 
 250   /* load kernel */
 251   mn = m * n;
 252 
 253   if (mn > 256) {
 254     dkernel = mlib_malloc(mn * sizeof(mlib_d64));
 255 
 256     if (dkernel == NULL) {
 257       if (dsa != dspace) mlib_free(dsa);
 258       return MLIB_FAILURE;
 259     }
 260   }
 261 
 262   while (scale > 30) {
 263     fscale /= (1 << 30);
 264     scale -= 30;
 265   }
 266 
 267   fscale /= (1 << scale);
 268 
 269   for (i = 0; i < mn; i++) {
 270     dkernel[i] = ((mlib_s32 *) kernel)[i] * fscale;
 271   }
 272 
 273   dsh = dsa + dw + m;
 274   dsv = dsh + dw;
 275 
 276   for (i = 0; i < dw; i++) {
 277     dsh[i] = 0.5;
 278     dsv[i] = 0.5;
 279   }
 280 
 281   for (j = 0; j < dh; j++, da += dlb) {
 282     for (k = 0; k < nch; k++)
 283       if (cmask & (1 << (nch - 1 - k))) {
 284         mlib_s32 *sa1 = sa + k;
 285         mlib_d64 *dkernel1 = dkernel;
 286 
 287         for (j1 = 0; j1 < n; j1++, dkernel1 += m) {
 288           mlib_ImageConvMxNS322S32_ext(isa, sa1, dw + m - 1, nch, dx_l, dx_r);
 289           mlib_ImageConvMxNMulAdd_S32(dsh, isa, dkernel1, dw, m, 1);
 290 
 291           if ((j + j1 >= dy_t) && (j + j1 < dh + n - dy_b - 2))
 292             sa1 += slb;
 293         }
 294 
 295         mlib_ImageConvMxNMedian_S32(da + k, dsh, dw, nch);
 296       }
 297 
 298     if ((j >= dy_t) && (j < dh + n - dy_b - 2))
 299       sa += slb;
 300   }
 301 
 302   if (dkernel != akernel)
 303     mlib_free(dkernel);
 304   if (dsa != dspace)
 305     mlib_free(dsa);
 306   return MLIB_SUCCESS;
 307 }
 308 
 309 /***************************************************************/