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 }