File indexing completed on 2024-04-28 03:43:53

0001 /*
0002     This file is part of SEP
0003 
0004     SPDX-FileCopyrightText: 1993-2011 Emmanuel Bertin -- IAP /CNRS/UPMC
0005     SPDX-FileCopyrightText: 2014 SEP developers
0006 
0007     SPDX-License-Identifier: LGPL-3.0-or-later
0008 */
0009 
0010 #include <stdlib.h>
0011 #include <stdio.h>
0012 #include <string.h>
0013 #include <math.h>
0014 #include "sep.h"
0015 #include "sepcore.h"
0016 #include "extract.h"
0017 
0018 /* Convolve one line of an image with a given kernel.
0019  *
0020  * buf : arraybuffer struct containing buffer of data to convolve, and image
0021          dimension metadata.
0022  * conv : convolution kernel
0023  * convw, convh : width and height of conv
0024  * buf : output convolved line (buf->dw elements long)
0025  */
0026 int convolve(arraybuffer *buf, int y, float *conv, int convw, int convh,
0027              PIXTYPE *out)
0028 {
0029   int convw2, convn, cx, cy, i, dcx, y0;
0030   PIXTYPE *line;    /* current line in input buffer */
0031   PIXTYPE *outend;  /* end of output buffer */
0032   PIXTYPE *src, *dst, *dstend;
0033 
0034   outend = out + buf->dw;
0035   convw2 = convw/2;
0036   y0 = y - convh/2;  /* start line in image */
0037 
0038   /* Cut off top of kernel if it extends beyond image */
0039   if (y0 + convh > buf->dh)
0040     convh = buf->dh - y0;
0041 
0042   /* cut off bottom of kernel if it extends beyond image */
0043   if (y0 < 0)
0044     {
0045       convh = convh + y0;
0046       conv += convw*(-y0);
0047       y0 = 0;
0048     }
0049 
0050   /* check that buffer has needed lines */
0051   if ((y0 < buf->yoff) || (y0+convh > buf->yoff + buf->bh))
0052     return LINE_NOT_IN_BUF;
0053 
0054   memset(out, 0, buf->dw*sizeof(PIXTYPE));  /* initialize output to zero */
0055 
0056   /* loop over pixels in the convolution kernel */
0057   convn = convw * convh;
0058   for (i=0; i<convn; i++)
0059     {
0060       cx = i % convw;  /* x index in conv kernel */
0061       cy = i / convw;  /* y index in conv kernel */
0062       line = buf->bptr + buf->bw * (y0 - buf->yoff + cy); /* start of line */
0063 
0064       /* get start and end positions in the source and target line */
0065       dcx = cx - convw2; /* offset of conv pixel from conv center;
0066                             determines offset between in and out line */
0067       if (dcx >= 0)
0068     {
0069       src = line + dcx;
0070       dst = out;
0071       dstend = outend - dcx;
0072     }
0073       else
0074     {
0075       src = line;
0076       dst = out - dcx;
0077       dstend = outend;
0078     }
0079 
0080       /* multiply and add the values */
0081       while (dst < dstend)
0082     *(dst++) += conv[i] * *(src++);
0083     }
0084 
0085   return RETURN_OK;
0086 }
0087 
0088 
0089 /* Apply a matched filter to one line of an image with a given kernel.
0090  *
0091  * Calculates
0092  *
0093  *        sum(conv_i * f_i / n_i^2) / sqrt(sum(conv_i^2 / n_i^2))
0094  *
0095  * at each pixel in the line, where the sums are over i (pixels in the
0096  * convolution kernel).
0097  *
0098  * imbuf : arraybuffer for data array
0099  * nbuf : arraybuffer for noise array
0100  * y : line to apply the matched filter to in an image
0101  * conv : convolution kernel
0102  * convw, convh : width and height of conv
0103  * work : work buffer (`imbuf->dw` elements long)
0104  * out : output line (`imbuf->dw` elements long)
0105  * noise_type : indicates contents of nbuf (std dev or variance)
0106  *
0107  * imbuf and nbuf should have same data dimensions and be on the same line
0108  * (their `yoff` fields should be the same).
0109  */
0110 int matched_filter(arraybuffer *imbuf, arraybuffer *nbuf, int y,
0111                    float *conv, int convw, int convh,
0112                    PIXTYPE *work, PIXTYPE *out, int noise_type)
0113 {
0114   int convw2, convn, cx, cy, i, dcx, y0;
0115   PIXTYPE imval, varval;
0116   PIXTYPE *imline, *nline;    /* current line in input buffer */
0117   PIXTYPE *outend;            /* end of output buffer */
0118   PIXTYPE *src_im, *src_n, *dst_num, *dst_denom, *dst_num_end;
0119 
0120   outend = out + imbuf->dw;
0121   convw2 = convw/2;
0122   y0 = y - convh/2;  /* start line in image */
0123 
0124   /* Cut off top of kernel if it extends beyond image */
0125   if (y0 + convh > imbuf->dh)
0126     convh = imbuf->dh - y0;
0127 
0128   /* cut off bottom of kernel if it extends beyond image */
0129   if (y0 < 0)
0130     {
0131       convh = convh + y0;
0132       conv += convw*(-y0);
0133       y0 = 0;
0134     }
0135 
0136   /* check that buffer has needed lines */
0137   if ((y0 < imbuf->yoff) || (y0+convh > imbuf->yoff + imbuf->bh) ||
0138       (y0 < nbuf->yoff)  || (y0+convh > nbuf->yoff + nbuf->bh))
0139     return LINE_NOT_IN_BUF;
0140 
0141   /* check that image and noise buffer match */
0142   if ((imbuf->yoff != nbuf->yoff) || (imbuf->dw != nbuf->dw))
0143     return LINE_NOT_IN_BUF;  /* TODO new error status code */
0144 
0145   /* initialize output buffers to zero */
0146   memset(out, 0, imbuf->bw*sizeof(PIXTYPE));
0147   memset(work, 0, imbuf->bw*sizeof(PIXTYPE));
0148 
0149   /* loop over pixels in the convolution kernel */
0150   convn = convw * convh;
0151   for (i=0; i<convn; i++)
0152     {
0153       cx = i % convw;  /* x index in conv kernel */
0154       cy = i / convw;  /* y index in conv kernel */
0155       imline = imbuf->bptr + imbuf->bw * (y0 - imbuf->yoff + cy);
0156       nline = nbuf->bptr + nbuf->bw * (y0 - nbuf->yoff + cy);
0157 
0158       /* get start and end positions in the source and target line */
0159       dcx = cx - convw2; /* offset of conv pixel from conv center;
0160                             determines offset between in and out line */
0161       if (dcx >= 0)
0162     {
0163       src_im = imline + dcx;
0164           src_n = nline + dcx;
0165       dst_num = out;
0166           dst_denom = work;
0167       dst_num_end = outend - dcx;
0168     }
0169       else
0170     {
0171       src_im = imline;
0172           src_n = nline;
0173       dst_num = out - dcx;
0174           dst_denom = work - dcx;
0175       dst_num_end = outend;
0176     }
0177 
0178       /* actually calculate values */
0179       while (dst_num < dst_num_end)
0180         {
0181           imval = *src_im;
0182           varval = (noise_type == SEP_NOISE_VAR)? (*src_n): (*src_n)*(*src_n);
0183           if (varval != 0.0)
0184             {
0185               *dst_num   += conv[i] * imval / varval;
0186               *dst_denom += conv[i] * conv[i] / varval;
0187             }
0188           src_im++;
0189           src_n++;
0190           dst_num++;
0191           dst_denom++;
0192         }
0193     }  /* close loop over convolution kernel */
0194 
0195   /* take the square root of the denominator (work) buffer and divide the
0196    * numerator by it. */
0197   for (dst_num=out, dst_denom=work; dst_num < outend; dst_num++, dst_denom++)
0198       *dst_num = *dst_num / sqrt(*dst_denom);
0199 
0200   return RETURN_OK;
0201 }