SDDSlib
Loading...
Searching...
No Matches
sddsspotanalysis.c
Go to the documentation of this file.
1/**
2 * @file sddsspotanalysis.c
3 * @brief Analyzes spot images from SDDS (Self Describing Data Sets) files.
4 *
5 * This program performs analysis on spot images provided in SDDS format. It allows users to define regions of interest,
6 * apply various filters, and compute statistical parameters related to the spot's intensity and shape. The results
7 * are output to a new SDDS file, and optionally, images of the spots can be saved for further visualization.
8 *
9 * ## Usage
10 * ```
11 * sddsspotanalysis [<input>] [<output>] [OPTIONS]
12 * ```
13 *
14 * ## Options
15 *
16 * -pipe[=in][,out]
17 * -ROI
18 * -spotROIsize
19 * -imagecolumns
20 * -xyz
21 * -singleSpot
22 * -centerOn
23 * -levels
24 * -blankOut
25 * -sizeLines
26 * -background
27 * -despike
28 * -hotpixelFilter
29 * -clipNegative
30 * -spotImage
31 * -majorOrder
32 *
33 * @copyright
34 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
35 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
36 *
37 * @license
38 * This file is distributed under the terms of the Software License Agreement
39 * found in the file LICENSE included with this distribution.
40 *
41 * @author L. Emery, M. Borland, R. Soliday
42 */
43
44#include "mdb.h"
45#include "scan.h"
46#include "SDDS.h"
47#include "SDDSutils.h"
48#include "fftpackC.h"
49
50/* Enumeration for option types */
51enum option_type {
52 SET_ROI,
53 SET_SPOTROISIZE,
54 SET_IMAGECOLUMNS,
55 SET_DESPIKE,
56 SET_PIPE,
57 SET_SIZELINES,
58 SET_LEVELS,
59 SET_BLANKOUT,
60 SET_BACKGROUND,
61 SET_SPOTIMAGE,
62 SET_SINGLESPOT,
63 SET_CENTERON,
64 SET_MAJOR_ORDER,
65 SET_CLIP_NEGATIVE,
66 SET_XYZ,
67 SET_HOTPIXELS,
68 N_OPTIONS
69};
70
71static char *option[N_OPTIONS] = {
72 "roi",
73 "spotroi",
74 "imagecolumns",
75 "despike",
76 "pipe",
77 "sizeLines",
78 "levels",
79 "blankout",
80 "background",
81 "spotimage",
82 "singlespot",
83 "centeron",
84 "majorOrder",
85 "clipnegative",
86 "xyz",
87 "hotpixelfilter"
88};
89
90char *USAGE1 = "Usage: sddsspotanalysis [<input>] [<output>] [-pipe[=in][,out]] \n\
91[-ROI=[{xy}{01}value=<value>][,{xy}{01}parameter=<name>]]\n\
92[-spotROIsize=[{xy}value=<value>][,{xy}parameter=<name>]]\n\
93[-centerOn={{xy}centroid | {xy}peak} | {xy}Parameter=<name>}]\n\
94{-imageColumns=<listOfNames> | -xyz=<ix>,<iy>,<Intensity>} [-singleSpot]\n\
95[-levels=[intensityLevels=<integer>][,saturationLevel=<integer>]]\n\
96[-blankOut=[{xy}{01}value=<value>][,{xy}{01}parameter=<name>]]\n\
97[-sizeLines=[{xy}value=<value>][,{xy}parameter=<name>]]\n\
98[-background=[halfwidth=<value>][,symmetric][,antihalo][,antiloner[,lonerThreshold=<value>]]\n\
99[-despike=[neighbors=<integer>][,passes=<integer>][,averageOf=<integer>][,threshold=<value>][,keep]]\n\
100[-hotpixelFilter=level=<fraction>,distance=<integer>[,passes=<integer>]]\n\
101[-clipNegative] [-spotImage=<filename>] [-majorOrder=row|column] \n\n";
102char *USAGE2 = "Options:\n"
103 " -pipe[=in][,out] Use the standard SDDS Toolkit pipe option.\n"
104 " -ROI Define the region of interest in pixel units.\n"
105 " All data outside this region is ignored.\n"
106 " -spotROIsize Specify the size in pixels of the ROI around the spot.\n"
107 " This ROI is used for computing spot properties.\n"
108 " -imagecolumns <list> List names of columns containing image data.\n"
109 " Wildcards are supported.\n"
110 " -xyz <ix>,<iy>,<Intensity> Specify columns for x and y pixel indices and intensity.\n"
111 " -singleSpot Eliminate multiple spots by retaining only the most intense connected pixels.\n"
112 " -centerOn <method> Center the analysis on the peak value, centroid, or a specified parameter for both x and y axes.\n"
113 " -levels intensityLevels=<int>, saturationLevel=<int>\n"
114 " Set intensity levels and saturation level.\n"
115 " -blankOut <parameters> Define regions to blank out based on pixel values or parameters.\n"
116 " -sizeLines <parameters> Number of lines to use for analyzing the beam size. Default is 3.\n"
117 " -background <parameters> Configure background subtraction with options like halfwidth, symmetric,\n"
118 " antihalo, antiloner, and lonerThreshold.\n"
119 " -despike <parameters> Apply despiking to smooth the data with options for neighbors, passes,\n"
120 " averageOf, threshold, and keep.\n"
121 " -hotpixelFilter <parameters> Apply a hot pixel filter with level, distance, and passes parameters.\n"
122 " -clipNegative Set negative pixel values to zero.\n"
123 " -spotImage <filename> Specify a file to save images of the spots for plotting with sddscontour.\n"
124 " -majorOrder <row|column> Define the output file order as either row or column.\n\n";
125
126char *USAGE3 = "Program by Michael Borland. (" __DATE__ " " __TIME__ ", SVN revision: " SVN_VERSION ")\n";
127
128#define DESPIKE_AVERAGEOF 0x0001U
129#define DESPIKE_KEEP (DESPIKE_AVERAGEOF << 1)
130
131#define X0VALUE 0x0001U
132#define X1VALUE (X0VALUE << 1)
133#define Y0VALUE (X1VALUE << 1)
134#define Y1VALUE (Y0VALUE << 1)
135#define X0PARAM (Y1VALUE << 1)
136#define X1PARAM (X0PARAM << 1)
137#define Y0PARAM (X1PARAM << 1)
138#define Y1PARAM (Y0PARAM << 1)
139#define OPTGIVEN (Y1PARAM << 1)
140
141typedef struct
142{
143 double backgroundLevel, integratedSpotIntensity, peakSpotIntensity;
144 double saturationCount, backgroundKilledPositive, backgroundKilledNegative;
145 int32_t ROI[4], spotROI[4], spotCenter[2];
146 double spotSigma[2], spotRange50[2], spotRange65[2], spotRange80[2], spotCentroid[2];
147 double S11, S33, rmsCrossProduct, phi, majorAxis, minorAxis;
149
150typedef struct
151{
152 unsigned long flags;
153 double fraction;
154 long passes, distance;
156
157void replaceWithNearNeighbors(double **image, long iy0, long iy1, long ix0, long ix1, long iyc, long ixc, long distance);
158
159typedef struct
160{
161 unsigned long flags;
162 int32_t neighbors, passes, averageOf;
163 double threshold;
165
166long SetUpOutputFile(SDDS_DATASET *SDDSout, char *outputFile, SDDS_DATASET *SDDSin, char ***copyParamName,
167 long *copyParamNames, short columnMajorOrder);
168long DetermineQuadLongValues(int32_t *ROI, unsigned long flags, char **parameter, SDDS_DATASET *SDDSin, long nx, long ny, long isROI);
169long DetermineDualLongValues(int32_t *spotROISize, unsigned long flags, char **parameter, SDDS_DATASET *SDDSin, long defaultValue);
170void BlankOutImageData(double **image, long nx, long ny, int32_t *region);
171long GetImageData(long *nx, double ***image, char **imageColumn, long ny, SDDS_DATASET *SDDSin);
172long GetXYZImageData(long *nx, long *ny, double ***image, char *ixName, char *iyName, char *intensityName, SDDS_DATASET *SDDSin);
173
174#define SYMMETRIC_BGREMOVAL 0x0001U
175#define ANTIHALO_BGREMOVAL 0x0002U
176#define REMOVE_LONERS 0x0004U
177#define SINGLE_SPOT 0x0008U
178#define XCENTER_PEAK 0x0010U
179#define YCENTER_PEAK 0x0020U
180#define XCENTER_CENTROID 0x0040U
181#define YCENTER_CENTROID 0x0080U
182#define CLIP_NEGATIVE 0x0100U
183#define XCENTER_PARAM 0x0200U
184#define YCENTER_PARAM 0x0400U
185
186long AnalyzeImageData(double **image, long nx, long ny, int32_t *ROI, int32_t *spotROISize,
187 int32_t *sizeLines, DESPIKE_SETTINGS *despikeSettings, HOTPIXEL_SETTINGS *hotpixelSettings,
188 long intensityLevels, long saturationLevel, long backgroundHalfWidth, long lonerThreshold,
189 long lonerPasses, unsigned long flags, IMAGE_ANALYSIS *analysisResults, SDDS_DATASET *SDDSspim,
190 double *centerValue);
191
192void DetermineBeamSizes(double *sigma, double *spotRange50, double *spotRange65, double *spotRange80,
193 double *lineBuffer, long i0, long i1);
194void DetermineBeamParameters(double **image, long *spotROI, long nx, long ny, double *S11, double *S33,
195 double *rmsCrossProduct, double *phi, double *majorAxis, double *minorAxis);
196
197int main(int argc, char **argv) {
198 SCANNED_ARG *scArg;
199 long iArg, imageColumns = 0, i, ip;
200 char **imageColumn = NULL;
201 char *ixName, *iyName, *IntensityName;
202 short xyzMode = 0;
203 unsigned long pipeFlags = 0, ROIFlags = 0, spotROIFlags = 0, blankOutFlags = 0;
204 int32_t intensityLevels = 256, saturationLevel = 254, backgroundHalfWidth = 3, lonerThreshold = 1, lonerPasses = 1;
205 long despike = 0;
206 DESPIKE_SETTINGS despikeSettings;
207 HOTPIXEL_SETTINGS hotpixelSettings;
208 short hotpixelFilter = 0;
209 char *inputFile = NULL, *outputFile = NULL;
210 int32_t ROI[4] = {-1, -1, -1, -1};
211 int32_t spotROISize[2] = {-1, -1};
212 char *ROIParameter[4] = {NULL, NULL, NULL, NULL};
213 int32_t blankOut[4] = {-1, -1, -1, -1};
214 char *blankOutParameter[4] = {NULL, NULL, NULL, NULL};
215 char *spotROISizeParameter[2] = {NULL, NULL};
216 SDDS_DATASET SDDSin, SDDSout;
217 long readStatus, nx, ny, outputRow, maxPages = 0;
218 double **image;
219 IMAGE_ANALYSIS analysisResults;
220 unsigned long sizeLinesFlags = 0, dummyFlags = 0, backgroundFlags = 0, centerFlags = 0, majorOrderFlag;
221 int32_t sizeLines[2] = {-1, -1};
222 char *sizeLinesParameter[2] = {NULL, NULL};
223 char *centerParameter[2] = {NULL, NULL};
224 double centerValue[2];
225 char **copyParamName;
226 long copyParamNames, copyBuffer[32];
227 char *spotImageFile = NULL;
228 short columnMajorOrder = -1;
229 SDDS_DATASET SDDSspim;
230
231 if (argc < 2) {
232 fprintf(stderr, "%s%s%s", USAGE1, USAGE2, USAGE3);
233 exit(EXIT_FAILURE);
234 }
235
236 ixName = iyName = IntensityName = NULL;
237
238 argc = scanargsg(&scArg, argc, argv);
239 for (iArg = 1; iArg < argc; iArg++) {
240 if (scArg[iArg].arg_type == OPTION) {
241 delete_chars(scArg[iArg].list[0], "_");
242 /* process options here */
243 switch (match_string(scArg[iArg].list[0], option, N_OPTIONS, 0)) {
244 case SET_MAJOR_ORDER:
245 majorOrderFlag = 0;
246 scArg[iArg].n_items--;
247 if (scArg[iArg].n_items > 0 &&
248 (!scanItemList(&majorOrderFlag, scArg[iArg].list + 1, &scArg[iArg].n_items, 0,
249 "row", -1, NULL, 0, SDDS_ROW_MAJOR_ORDER,
250 "column", -1, NULL, 0, SDDS_COLUMN_MAJOR_ORDER, NULL)))
251 SDDS_Bomb("invalid -majorOrder syntax/values");
252 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER)
253 columnMajorOrder = 1;
254 else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER)
255 columnMajorOrder = 0;
256 break;
257 case SET_IMAGECOLUMNS:
258 if (scArg[iArg].n_items < 2)
259 SDDS_Bomb("invalid -imagecolumns syntax");
260 if (imageColumns)
261 SDDS_Bomb("give one and only one -imagecolumns option");
262 imageColumns = scArg[iArg].n_items - 1;
263 imageColumn = tmalloc(sizeof(*imageColumn) * imageColumns);
264 for (i = 0; i < imageColumns; i++)
265 imageColumn[i] = scArg[iArg].list[i + 1];
266 xyzMode = 0;
267 break;
268 case SET_ROI:
269 if (ROIFlags & OPTGIVEN)
270 SDDS_Bomb("give -ROI only once");
271 ROIFlags = OPTGIVEN;
272 scArg[iArg].n_items--;
273 if (scArg[iArg].n_items < 1 ||
274 (!scanItemList(&ROIFlags, scArg[iArg].list + 1, &scArg[iArg].n_items, 0,
275 "x0value", SDDS_LONG, ROI + 0, 1, X0VALUE,
276 "x1value", SDDS_LONG, ROI + 1, 1, X1VALUE,
277 "y0value", SDDS_LONG, ROI + 2, 1, Y0VALUE,
278 "y1value", SDDS_LONG, ROI + 3, 1, Y1VALUE,
279 "x0parameter", SDDS_STRING, ROIParameter + 0, 1, X0PARAM,
280 "x1parameter", SDDS_STRING, ROIParameter + 1, 1, X1PARAM,
281 "y0parameter", SDDS_STRING, ROIParameter + 2, 1, Y0PARAM,
282 "y1parameter", SDDS_STRING, ROIParameter + 3, 1, Y1PARAM,
283 NULL) ||
284 ((ROIFlags & X0VALUE) && ROI[0] < 0) || ((ROIFlags & X1VALUE) && ROI[1] < 0) ||
285 ((ROIFlags & Y0VALUE) && ROI[2] < 0) || ((ROIFlags & Y1VALUE) && ROI[3] < 0) ||
286 ((ROIFlags & X0PARAM) && (!ROIParameter[0] || !strlen(ROIParameter[0]))) ||
287 ((ROIFlags & X1PARAM) && (!ROIParameter[1] || !strlen(ROIParameter[1]))) ||
288 ((ROIFlags & Y0PARAM) && (!ROIParameter[2] || !strlen(ROIParameter[2]))) ||
289 ((ROIFlags & Y1PARAM) && (!ROIParameter[3] || !strlen(ROIParameter[3])))))
290 SDDS_Bomb("invalid -ROI syntax/values");
291 break;
292 case SET_BLANKOUT:
293 if (blankOutFlags & OPTGIVEN)
294 SDDS_Bomb("give -blankout only once");
295 blankOutFlags = OPTGIVEN;
296 scArg[iArg].n_items--;
297 if (scArg[iArg].n_items < 1 ||
298 (!scanItemList(&blankOutFlags, scArg[iArg].list + 1, &scArg[iArg].n_items, 0,
299 "x0value", SDDS_LONG, blankOut + 0, 1, X0VALUE,
300 "x1value", SDDS_LONG, blankOut + 1, 1, X1VALUE,
301 "y0value", SDDS_LONG, blankOut + 2, 1, Y0VALUE,
302 "y1value", SDDS_LONG, blankOut + 3, 1, Y1VALUE,
303 "x0parameter", SDDS_STRING, blankOutParameter + 0, 1, X0PARAM,
304 "x1parameter", SDDS_STRING, blankOutParameter + 1, 1, X1PARAM,
305 "y0parameter", SDDS_STRING, blankOutParameter + 2, 1, Y0PARAM,
306 "y1parameter", SDDS_STRING, blankOutParameter + 3, 1, Y1PARAM,
307 NULL) ||
308 ((blankOutFlags & X0VALUE) && blankOut[0] < 0) || ((blankOutFlags & X1VALUE) && blankOut[1] < 0) ||
309 ((blankOutFlags & Y0VALUE) && blankOut[2] < 0) || ((blankOutFlags & Y1VALUE) && blankOut[3] < 0) ||
310 ((blankOutFlags & X0PARAM) && (!blankOutParameter[0] || !strlen(blankOutParameter[0]))) ||
311 ((blankOutFlags & X1PARAM) && (!blankOutParameter[1] || !strlen(blankOutParameter[1]))) ||
312 ((blankOutFlags & Y0PARAM) && (!blankOutParameter[2] || !strlen(blankOutParameter[2]))) ||
313 ((blankOutFlags & Y1PARAM) && (!blankOutParameter[3] || !strlen(blankOutParameter[3])))))
314 SDDS_Bomb("invalid -blankOut syntax/values");
315 break;
316 case SET_SPOTROISIZE:
317 if (spotROIFlags & OPTGIVEN)
318 SDDS_Bomb("give -spotROIsize only once");
319 spotROIFlags = OPTGIVEN;
320 scArg[iArg].n_items--;
321 if (scArg[iArg].n_items < 1 ||
322 (!scanItemList(&spotROIFlags, scArg[iArg].list + 1, &scArg[iArg].n_items, 0,
323 "xvalue", SDDS_LONG, spotROISize + 0, 1, X0VALUE,
324 "yvalue", SDDS_LONG, spotROISize + 1, 1, Y0VALUE,
325 "xparameter", SDDS_STRING, spotROISizeParameter + 0, 1, X0PARAM,
326 "yparameter", SDDS_STRING, spotROISizeParameter + 1, 1, Y0PARAM,
327 NULL) ||
328 ((spotROIFlags & X0VALUE) && spotROISize[0] < 0) ||
329 ((spotROIFlags & Y0VALUE) && spotROISize[1] < 0) ||
330 ((spotROIFlags & X0PARAM) && (!spotROISizeParameter[0] || !strlen(spotROISizeParameter[0]))) ||
331 ((spotROIFlags & Y0PARAM) && (!spotROISizeParameter[1] || !strlen(spotROISizeParameter[1])))))
332 SDDS_Bomb("invalid -spotROIsize syntax/values");
333 break;
334 case SET_SIZELINES:
335 if (sizeLinesFlags & OPTGIVEN)
336 SDDS_Bomb("give -sizeLines only once");
337 sizeLinesFlags = OPTGIVEN;
338 scArg[iArg].n_items--;
339 if (scArg[iArg].n_items < 1 ||
340 (!scanItemList(&sizeLinesFlags, scArg[iArg].list + 1, &scArg[iArg].n_items, 0,
341 "xvalue", SDDS_LONG, sizeLines + 0, 1, X0VALUE,
342 "yvalue", SDDS_LONG, sizeLines + 1, 1, Y0VALUE,
343 "xparameter", SDDS_STRING, sizeLinesParameter + 0, 1, X0PARAM,
344 "yparameter", SDDS_STRING, sizeLinesParameter + 1, 1, Y0PARAM,
345 NULL) ||
346 ((sizeLinesFlags & X0VALUE) && sizeLines[0] < 0) ||
347 ((sizeLinesFlags & Y0VALUE) && sizeLines[1] < 0) ||
348 ((sizeLinesFlags & X0PARAM) && (!sizeLinesParameter[0] || !strlen(sizeLinesParameter[0]))) ||
349 ((sizeLinesFlags & Y0PARAM) && (!sizeLinesParameter[1] || !strlen(sizeLinesParameter[1])))))
350 SDDS_Bomb("invalid -sizeLines syntax/values");
351 break;
352 case SET_DESPIKE:
353 scArg[iArg].n_items--;
354 despikeSettings.neighbors = 4;
355 despikeSettings.passes = 1;
356 despikeSettings.threshold = 0;
357 despikeSettings.averageOf = 2;
358 despikeSettings.flags = 0;
359 if (scArg[iArg].n_items > 0 &&
360 (!scanItemList(&despikeSettings.flags, scArg[iArg].list + 1, &scArg[iArg].n_items, 0,
361 "neighbors", SDDS_LONG, &despikeSettings.neighbors, 1, 0,
362 "passes", SDDS_LONG, &despikeSettings.passes, 1, 0,
363 "averageOf", SDDS_LONG, &despikeSettings.averageOf, 1, DESPIKE_AVERAGEOF,
364 "threshold", SDDS_DOUBLE, &despikeSettings.threshold, 1, 0,
365 "keep", -1, NULL, 0, DESPIKE_KEEP, NULL) ||
366 despikeSettings.neighbors < 2 || despikeSettings.passes < 1 ||
367 despikeSettings.averageOf < 2 || despikeSettings.threshold < 0))
368 SDDS_Bomb("invalid -despike syntax/values");
369 if (!(despikeSettings.flags & DESPIKE_AVERAGEOF))
370 despikeSettings.averageOf = despikeSettings.neighbors;
371 if (despikeSettings.averageOf > despikeSettings.neighbors)
372 SDDS_Bomb("invalid -despike syntax/values: averageOf>neighbors");
373 despike = 1;
374 break;
375 case SET_HOTPIXELS:
376 scArg[iArg].n_items--;
377 hotpixelSettings.passes = 1;
378 hotpixelSettings.distance = 1;
379 hotpixelSettings.fraction = -1;
380 if (scArg[iArg].n_items > 0 &&
381 (!scanItemList(&hotpixelSettings.flags, scArg[iArg].list + 1, &scArg[iArg].n_items, 0,
382 "fraction", SDDS_DOUBLE, &hotpixelSettings.fraction, 1, 0,
383 "passes", SDDS_LONG, &hotpixelSettings.passes, 1, 0,
384 "distance", SDDS_LONG, &hotpixelSettings.distance, 1, 0, NULL) ||
385 hotpixelSettings.fraction <= 0 || hotpixelSettings.passes < 1 || hotpixelSettings.distance < 1))
386 SDDS_Bomb("invalid -hotpixelFilter syntax/values");
387 hotpixelFilter = 1;
388 break;
389 case SET_PIPE:
390 if (!processPipeOption(scArg[iArg].list + 1, scArg[iArg].n_items - 1, &pipeFlags))
391 SDDS_Bomb("invalid -pipe syntax");
392 break;
393 case SET_LEVELS:
394 scArg[iArg].n_items--;
395 if (scArg[iArg].n_items < 1 ||
396 !scanItemList(&dummyFlags, scArg[iArg].list + 1, &scArg[iArg].n_items, 0,
397 "intensityLevels", SDDS_LONG, &intensityLevels, 1, 0,
398 "saturationLevel", SDDS_LONG, &saturationLevel, 1, 0, NULL) ||
399 intensityLevels <= 10 || saturationLevel <= 0)
400 SDDS_Bomb("invalid -levels syntax/values");
401 break;
402 case SET_BACKGROUND:
403 scArg[iArg].n_items--;
404 if (scArg[iArg].n_items < 1 ||
405 !scanItemList(&backgroundFlags, scArg[iArg].list + 1, &scArg[iArg].n_items, 0,
406 "halfwidth", SDDS_LONG, &backgroundHalfWidth, 1, 0,
407 "symmetric", -1, NULL, 0, SYMMETRIC_BGREMOVAL,
408 "antihalo", -1, NULL, 0, ANTIHALO_BGREMOVAL,
409 "antiloner", -1, NULL, 0, REMOVE_LONERS,
410 "lonerthreshold", SDDS_LONG, &lonerThreshold, 1, 0,
411 "lonerpasses", SDDS_LONG, &lonerPasses, 1, 0, NULL) ||
412 backgroundHalfWidth < 0)
413 SDDS_Bomb("invalid -background syntax/values");
414 break;
415 case SET_SINGLESPOT:
416 if (scArg[iArg].n_items != 1)
417 SDDS_Bomb("invalid -singleSpot syntax/values");
418 backgroundFlags |= SINGLE_SPOT;
419 break;
420 case SET_SPOTIMAGE:
421 if (scArg[iArg].n_items != 2 || !(spotImageFile = scArg[iArg].list[1]))
422 SDDS_Bomb("invalid -spotImage syntax/values");
423 break;
424 case SET_CLIP_NEGATIVE:
425 backgroundFlags |= CLIP_NEGATIVE;
426 break;
427 case SET_CENTERON:
428 scArg[iArg].n_items--;
429
430 if (scArg[iArg].n_items < 1 ||
431 !scanItemList(&centerFlags, scArg[iArg].list + 1, &scArg[iArg].n_items, 0,
432 "xcentroid", -1, NULL, 0, XCENTER_CENTROID,
433 "ycentroid", -1, NULL, 0, YCENTER_CENTROID,
434 "xpeak", -1, NULL, 0, XCENTER_PEAK,
435 "ypeak", -1, NULL, 0, YCENTER_PEAK,
436 "xparameter", SDDS_STRING, centerParameter + 0, 1, XCENTER_PARAM,
437 "yparameter", SDDS_STRING, centerParameter + 1, 1, YCENTER_PARAM, NULL) ||
438 bitsSet(centerFlags & (XCENTER_CENTROID + XCENTER_PEAK + XCENTER_PARAM)) != 1 ||
439 bitsSet(centerFlags & (YCENTER_CENTROID + YCENTER_PEAK + YCENTER_PARAM)) != 1)
440 SDDS_Bomb("invalid -centerOn syntax");
441 break;
442 case SET_XYZ:
443 if (scArg[iArg].n_items != 4 ||
444 !strlen(ixName = scArg[iArg].list[1]) ||
445 !strlen(iyName = scArg[iArg].list[2]) ||
446 !strlen(IntensityName = scArg[iArg].list[3]))
447 SDDS_Bomb("invalid -xyz syntax");
448 xyzMode = 1;
449 break;
450 default:
451 fprintf(stderr, "unknown option %s given\n", scArg[iArg].list[0]);
452 exit(EXIT_FAILURE);
453 break;
454 }
455 } else {
456 /* argument is input filename */
457 if (!inputFile) {
458 inputFile = scArg[iArg].list[0];
459 } else if (!outputFile) {
460 outputFile = scArg[iArg].list[0];
461 } else
462 SDDS_Bomb("too many filenames");
463 }
464 }
465
466 processFilenames("sddsspotanalysis", &inputFile, &outputFile, pipeFlags, 0, NULL);
467
468 if (!imageColumns && !IntensityName)
469 SDDS_Bomb("you must give either the -imageColumns or -xyz option");
470 if (imageColumns && IntensityName)
471 SDDS_Bomb("you must give either the -imageColumns or -xyz option, not both");
472
473 if (!SDDS_InitializeInput(&SDDSin, inputFile)) {
474 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
475 exit(EXIT_FAILURE);
476 }
477
478 if (spotImageFile &&
479 (!SDDS_InitializeOutput(&SDDSspim, SDDS_BINARY, 0, NULL, "sddsspotanalysis spot image", spotImageFile) ||
480 SDDS_DefineColumn(&SDDSspim, "ix", NULL, NULL, NULL, NULL, SDDS_SHORT, 0) < 0 ||
481 SDDS_DefineColumn(&SDDSspim, "iy", NULL, NULL, NULL, NULL, SDDS_SHORT, 0) < 0 ||
482 SDDS_DefineColumn(&SDDSspim, "Image", NULL, NULL, NULL, NULL, SDDS_DOUBLE, 0) < 0 ||
483 SDDS_DefineParameter(&SDDSspim, "nx", NULL, NULL, NULL, NULL, SDDS_SHORT, 0) < 0 ||
484 SDDS_DefineParameter(&SDDSspim, "ny", NULL, NULL, NULL, NULL, SDDS_SHORT, 0) < 0 ||
485 !SDDS_WriteLayout(&SDDSspim))) {
486 SDDS_SetError("Problem setting up spot image output file.");
487 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
488 exit(EXIT_FAILURE);
489 }
490
491 if (!xyzMode) {
492 if ((imageColumns = expandColumnPairNames(&SDDSin, &imageColumn, NULL, imageColumns, NULL, 0, FIND_NUMERIC_TYPE, 0)) <= 0) {
493 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
494 SDDS_Bomb("No quantities selected to analyze");
495 }
496 ny = imageColumns;
497 outputRow = 0;
498 if (!(image = calloc(ny, sizeof(*image))))
499 SDDS_Bomb("Memory allocation failure");
500 nx = 0;
501 } else
502 ny = nx = 0;
503
504 if (!SetUpOutputFile(&SDDSout, outputFile, &SDDSin, &copyParamName, &copyParamNames, columnMajorOrder) ||
505 !SDDS_StartPage(&SDDSout, maxPages = 10))
506 SDDS_Bomb("Problem setting up output file.");
507
508 while ((readStatus = SDDS_ReadPage(&SDDSin)) > 0) {
509 if (readStatus > maxPages) {
510 if (!SDDS_LengthenTable(&SDDSout, 10))
511 SDDS_Bomb("Problem lengthening output file.");
512 maxPages += 10;
513 }
514 /* Get image into array.
515 * N.B.: pixel (ix, iy) is accessed as image[iy][ix].
516 */
517 if (!xyzMode) {
518 if (!GetImageData(&nx, &image, imageColumn, ny, &SDDSin))
519 SDDS_Bomb("Problem getting image data.");
520 if (!nx)
521 continue;
522 } else {
523 if (!GetXYZImageData(&nx, &ny, &image, ixName, iyName, IntensityName, &SDDSin))
524 SDDS_Bomb("Problem getting image data.");
525 if (!nx || !ny)
526 continue;
527 }
528 if (!DetermineQuadLongValues(ROI, ROIFlags, ROIParameter, &SDDSin, nx, ny, 1)) {
529 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
530 SDDS_Bomb("Problem determining region of interest---verify that you gave sufficient information.");
531 }
532 if (blankOutFlags && !DetermineQuadLongValues(blankOut, blankOutFlags, blankOutParameter, &SDDSin, nx, ny, 0))
533 SDDS_Bomb("Problem determining blankout region---verify that you gave sufficient information.");
534 if (!DetermineDualLongValues(spotROISize, spotROIFlags, spotROISizeParameter, &SDDSin, 150))
535 SDDS_Bomb("Problem determine size of spot region of interest---verify that you gave sufficient information.");
536 if (!DetermineDualLongValues(sizeLines, sizeLinesFlags, sizeLinesParameter, &SDDSin, 3))
537 SDDS_Bomb("Problem determine size of number of lines to use for spot size computation---verify that you gave sufficient information.");
538 centerValue[0] = centerValue[1] = -1;
539 if (centerFlags & XCENTER_PARAM && !SDDS_GetParameterAsDouble(&SDDSin, centerParameter[0], centerValue + 0))
540 SDDS_Bomb("Problem getting center parameter value for x.");
541 if (centerFlags & YCENTER_PARAM && !SDDS_GetParameterAsDouble(&SDDSin, centerParameter[1], centerValue + 1))
542 SDDS_Bomb("Problem getting center parameter value for y.");
543 if (blankOutFlags)
544 BlankOutImageData(image, nx, ny, blankOut);
545 if (!AnalyzeImageData(image, nx, ny, ROI, spotROISize, sizeLines,
546 despike ? &despikeSettings : NULL, hotpixelFilter ? &hotpixelSettings : NULL, intensityLevels,
547 saturationLevel, backgroundHalfWidth, lonerThreshold, lonerPasses, backgroundFlags | centerFlags,
548 &analysisResults, spotImageFile ? &SDDSspim : NULL, centerValue))
549 continue;
550 for (ip = 0; ip < copyParamNames; ip++) {
551 if (!SDDS_GetParameter(&SDDSin, copyParamName[ip], copyBuffer))
552 SDDS_Bomb("Problem reading parameter data from input file.");
553 if (!SDDS_SetRowValues(&SDDSout, SDDS_SET_BY_NAME | SDDS_PASS_BY_REFERENCE, outputRow, copyParamName[ip], copyBuffer, NULL)) {
554 SDDS_Bomb("Problem copying parameter data from input file.");
555 }
556 }
557 if (!SDDS_SetRowValues(&SDDSout, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE, outputRow++,
558 "ImageIndex", readStatus - 1,
559 "xROILower", analysisResults.ROI[0],
560 "xROIUpper", analysisResults.ROI[1],
561 "yROILower", analysisResults.ROI[2],
562 "yROIUpper", analysisResults.ROI[3],
563 "xSpotROILower", analysisResults.spotROI[0],
564 "xSpotROIUpper", analysisResults.spotROI[1],
565 "ySpotROILower", analysisResults.spotROI[2],
566 "ySpotROIUpper", analysisResults.spotROI[3],
567 "xSpotCenter", analysisResults.spotCenter[0],
568 "ySpotCenter", analysisResults.spotCenter[1],
569 "xSpotCentroid", analysisResults.spotCentroid[0],
570 "ySpotCentroid", analysisResults.spotCentroid[1],
571 "xSpotSigma", analysisResults.spotSigma[0],
572 "xSpotRange50", analysisResults.spotRange50[0],
573 "xSpotRange65", analysisResults.spotRange65[0],
574 "xSpotRange80", analysisResults.spotRange80[0],
575 "ySpotSigma", analysisResults.spotSigma[1],
576 "ySpotRange50", analysisResults.spotRange50[1],
577 "ySpotRange65", analysisResults.spotRange65[1],
578 "ySpotRange80", analysisResults.spotRange80[1],
579 "BackgroundLevel", analysisResults.backgroundLevel,
580 "BackgroundKilledPositive", analysisResults.backgroundKilledPositive,
581 "BackgroundKilledNegative", analysisResults.backgroundKilledNegative,
582 "IntegratedSpotIntensity", analysisResults.integratedSpotIntensity,
583 "PeakSpotIntensity", analysisResults.peakSpotIntensity,
584 "SaturationCount", analysisResults.saturationCount,
585 "phi", analysisResults.phi,
586 "rmsCrossProduct", analysisResults.rmsCrossProduct,
587 "majorAxis", analysisResults.majorAxis,
588 "minorAxis", analysisResults.minorAxis,
589 "S11", analysisResults.S11,
590 "S33", analysisResults.S33,
591 "S13", analysisResults.rmsCrossProduct, NULL)) {
592 SDDS_SetError("Problem setting values into output file.");
593 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
594 }
595 }
596 if (!SDDS_WritePage(&SDDSout) || !SDDS_Terminate(&SDDSout) || !SDDS_Terminate(&SDDSin))
597 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
598 if (spotImageFile && !SDDS_Terminate(&SDDSspim))
599 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
600 for (i = 0; i < ny; i++)
601 free(image[i]);
602 if (!xyzMode) {
603 for (i = 0; i < ny; i++)
604 free(imageColumn[i]);
605 free(imageColumn);
606 }
607 for (i = 0; i < copyParamNames; i++)
608 free(copyParamName[i]);
609 free(copyParamName);
610 free(image);
611 return EXIT_SUCCESS;
612}
613
614long SetUpOutputFile(SDDS_DATASET *SDDSout, char *outputFile, SDDS_DATASET *SDDSin, char ***copyParamName,
615 long *copyParamNames, short columnMajorOrder) {
616 char **paramName;
617 int32_t paramNames;
618
619 if (!SDDS_InitializeOutput(SDDSout, SDDS_BINARY, 0, NULL, "sddsspotanalysis output", outputFile) ||
620 SDDS_DefineColumn(SDDSout, "xROILower", NULL, NULL, NULL, NULL, SDDS_LONG, 0) < 0 ||
621 SDDS_DefineColumn(SDDSout, "xROIUpper", NULL, NULL, NULL, NULL, SDDS_LONG, 0) < 0 ||
622 SDDS_DefineColumn(SDDSout, "xSpotROILower", NULL, NULL, NULL, NULL, SDDS_LONG, 0) < 0 ||
623 SDDS_DefineColumn(SDDSout, "xSpotROIUpper", NULL, NULL, NULL, NULL, SDDS_LONG, 0) < 0 ||
624 SDDS_DefineColumn(SDDSout, "xSpotCenter", NULL, NULL, NULL, NULL, SDDS_LONG, 0) < 0 ||
625 SDDS_DefineColumn(SDDSout, "xSpotCentroid", NULL, NULL, NULL, NULL, SDDS_DOUBLE, 0) < 0 ||
626 SDDS_DefineColumn(SDDSout, "xSpotSigma", NULL, NULL, NULL, NULL, SDDS_DOUBLE, 0) < 0 ||
627 SDDS_DefineColumn(SDDSout, "xSpotRange50", NULL, NULL, NULL, NULL, SDDS_DOUBLE, 0) < 0 ||
628 SDDS_DefineColumn(SDDSout, "xSpotRange65", NULL, NULL, NULL, NULL, SDDS_DOUBLE, 0) < 0 ||
629 SDDS_DefineColumn(SDDSout, "xSpotRange80", NULL, NULL, NULL, NULL, SDDS_DOUBLE, 0) < 0 ||
630 SDDS_DefineColumn(SDDSout, "yROILower", NULL, NULL, NULL, NULL, SDDS_LONG, 0) < 0 ||
631 SDDS_DefineColumn(SDDSout, "yROIUpper", NULL, NULL, NULL, NULL, SDDS_LONG, 0) < 0 ||
632 SDDS_DefineColumn(SDDSout, "ySpotROILower", NULL, NULL, NULL, NULL, SDDS_LONG, 0) < 0 ||
633 SDDS_DefineColumn(SDDSout, "ySpotROIUpper", NULL, NULL, NULL, NULL, SDDS_LONG, 0) < 0 ||
634 SDDS_DefineColumn(SDDSout, "ySpotCenter", NULL, NULL, NULL, NULL, SDDS_LONG, 0) < 0 ||
635 SDDS_DefineColumn(SDDSout, "ySpotCentroid", NULL, NULL, NULL, NULL, SDDS_DOUBLE, 0) < 0 ||
636 SDDS_DefineColumn(SDDSout, "ySpotSigma", NULL, NULL, NULL, NULL, SDDS_DOUBLE, 0) < 0 ||
637 SDDS_DefineColumn(SDDSout, "ySpotRange50", NULL, NULL, NULL, NULL, SDDS_DOUBLE, 0) < 0 ||
638 SDDS_DefineColumn(SDDSout, "ySpotRange65", NULL, NULL, NULL, NULL, SDDS_DOUBLE, 0) < 0 ||
639 SDDS_DefineColumn(SDDSout, "ySpotRange80", NULL, NULL, NULL, NULL, SDDS_DOUBLE, 0) < 0 ||
640 SDDS_DefineColumn(SDDSout, "ImageIndex", NULL, NULL, NULL, NULL, SDDS_LONG, 0) < 0 ||
641 SDDS_DefineColumn(SDDSout, "BackgroundLevel", NULL, NULL, NULL, NULL, SDDS_DOUBLE, 0) < 0 ||
642 SDDS_DefineColumn(SDDSout, "BackgroundKilledNegative", NULL, NULL, NULL, NULL, SDDS_DOUBLE, 0) < 0 ||
643 SDDS_DefineColumn(SDDSout, "BackgroundKilledPositive", NULL, NULL, NULL, NULL, SDDS_DOUBLE, 0) < 0 ||
644 SDDS_DefineColumn(SDDSout, "IntegratedSpotIntensity", NULL, NULL, NULL, NULL, SDDS_DOUBLE, 0) < 0 ||
645 SDDS_DefineColumn(SDDSout, "PeakSpotIntensity", NULL, NULL, NULL, NULL, SDDS_DOUBLE, 0) < 0 ||
646 SDDS_DefineColumn(SDDSout, "SaturationCount", NULL, NULL, NULL, NULL, SDDS_DOUBLE, 0) < 0 ||
647 SDDS_DefineColumn(SDDSout, "phi", NULL, "degree", NULL, NULL, SDDS_DOUBLE, 0) < 0 ||
648 SDDS_DefineColumn(SDDSout, "rmsCrossProduct", NULL, NULL, NULL, NULL, SDDS_DOUBLE, 0) < 0 ||
649 SDDS_DefineColumn(SDDSout, "majorAxis", NULL, NULL, NULL, NULL, SDDS_DOUBLE, 0) < 0 ||
650 SDDS_DefineColumn(SDDSout, "minorAxis", NULL, NULL, NULL, NULL, SDDS_DOUBLE, 0) < 0 ||
651 SDDS_DefineColumn(SDDSout, "S11", NULL, NULL, NULL, NULL, SDDS_DOUBLE, 0) < 0 ||
652 SDDS_DefineColumn(SDDSout, "S33", NULL, NULL, NULL, NULL, SDDS_DOUBLE, 0) < 0 ||
653 SDDS_DefineColumn(SDDSout, "S13", NULL, NULL, NULL, NULL, SDDS_DOUBLE, 0) < 0) {
654 SDDS_SetError("Problem setting up output file.");
655 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
656 exit(EXIT_FAILURE);
657 }
658 if (columnMajorOrder != -1)
659 SDDSout->layout.data_mode.column_major = columnMajorOrder;
660 else
661 SDDSout->layout.data_mode.column_major = SDDSin->layout.data_mode.column_major;
662
663 *copyParamNames = 0;
664 *copyParamName = NULL;
665 if ((paramName = SDDS_GetParameterNames(SDDSin, &paramNames)) && paramNames > 0) {
666 long ip;
667 if (!(*copyParamName = calloc(sizeof(**copyParamName), paramNames)))
668 SDDS_Bomb("memory allocation failure");
669 for (ip = 0; ip < paramNames; ip++) {
670 if (SDDS_GetColumnIndex(SDDSout, paramName[ip]) >= 0) {
671 free(paramName[ip]);
672 continue;
673 }
674 if (!SDDS_DefineColumnLikeParameter(SDDSout, SDDSin, paramName[ip], NULL)) {
675 SDDS_SetError("Problem setting up output file.");
676 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
677 exit(EXIT_FAILURE);
678 }
679 (*copyParamName)[*copyParamNames] = paramName[ip];
680 (*copyParamNames)++;
681 }
682 }
683 free(paramName);
684 if (!SDDS_WriteLayout(SDDSout)) {
685 SDDS_SetError("Problem setting up output file.");
686 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
687 exit(EXIT_FAILURE);
688 }
689 return 1;
690}
691
692long DetermineQuadLongValues(int32_t *ROI, unsigned long flags, char **parameter, SDDS_DATASET *SDDSin, long nx, long ny, long isROI) {
693 long i;
694 double value;
695 double defaultROI[4];
696 if (isROI) {
697 defaultROI[0] = defaultROI[2] = 0;
698 defaultROI[1] = nx - 1;
699 defaultROI[3] = ny - 1;
700 } else
701 defaultROI[0] = defaultROI[2] = defaultROI[1] = defaultROI[3] = -1;
702 for (i = 0; i < 4; i++) {
703 if (flags & (X0VALUE << i))
704 continue;
705 if (flags & (X0PARAM << i)) {
706 if (!SDDS_GetParameterAsDouble(SDDSin, parameter[i], &value)) {
707 SDDS_SetError("parameter is nonexistent or nonnumeric");
708 return 0;
709 }
710 ROI[i] = value + 0.5;
711 } else
712 ROI[i] = defaultROI[i];
713 }
714 if (ROI[0] < 0 || ROI[2] < 0) {
715 SDDS_SetError("lower bound of region less than zero");
716 return 0;
717 }
718 if (ROI[1] > nx - 1 || ROI[3] > ny - 1) {
719 SDDS_SetError("upper bound of region too large");
720 return 0;
721 }
722 if (ROI[0] >= ROI[1]) {
723 SDDS_SetError("x region has zero or negative width");
724 return 0;
725 }
726 if (ROI[2] >= ROI[3]) {
727 SDDS_SetError("y region has zero or negative width");
728 return 0;
729 }
730 return 1;
731}
732
733long DetermineDualLongValues(int32_t *returnValue, unsigned long flags, char **parameter, SDDS_DATASET *SDDSin, long defaultValue) {
734 long i;
735 double value;
736
737 for (i = 0; i < 2; i++) {
738 if (flags & (X0VALUE << (2 * i)))
739 continue;
740 if (flags & (X0PARAM << (2 * i))) {
741 if (!SDDS_GetParameterAsDouble(SDDSin, parameter[i], &value)) {
742 SDDS_SetError("parameter is nonexistent or nonnumeric");
743 return 0;
744 }
745 returnValue[i] = (int32_t)value;
746 } else
747 returnValue[i] = defaultValue;
748 }
749 if (returnValue[0] <= 0 || returnValue[1] <= 0) {
750 SDDS_SetError("determined value is nonpositive");
751 return 0;
752 }
753 return 1;
754}
755
756long GetImageData(long *nx, double ***image, char **imageColumn, long ny, SDDS_DATASET *SDDSin) {
757 /* Note that because each column is a horizontal line, the pixels are
758 * accessed as image[iy][ix]. I could swap it, but that would mean
759 * doubling the amount of memory used.
760 */
761 long i;
762 *nx = 0;
763 for (i = 0; i < ny; i++) {
764 if ((*image)[i]) {
765 free((*image)[i]);
766 (*image)[i] = NULL;
767 }
768 if (!((*image)[i] = SDDS_GetColumnInDoubles(SDDSin, imageColumn[i]))) {
769 SDDS_Bomb("Unable to get data from columns");
770 }
771 }
772 *nx = SDDS_RowCount(SDDSin);
773 return 1;
774}
775
776long GetXYZImageData(long *nx, long *ny, double ***image, char *ixName, char *iyName, char *intensityName, SDDS_DATASET *SDDSin) {
777 int32_t *ixData, *iyData;
778 double *intensityData;
779 long ixMin, iyMin, ixMax, iyMax, i, ix, iy, nRows;
780 char *ixIndexCheck, *iyIndexCheck;
781
782 if ((nRows = SDDS_RowCount(SDDSin)) <= 0 ||
783 !(ixData = SDDS_GetColumnInLong(SDDSin, ixName)) ||
784 !(iyData = SDDS_GetColumnInLong(SDDSin, iyName)) ||
785 !(intensityData = SDDS_GetColumnInDoubles(SDDSin, intensityName)))
786 return 0;
787
788 ixMax = iyMax = -(ixMin = iyMin = LONG_MAX);
789
790 for (i = 0; i < nRows; i++) {
791 if (ixMax < ixData[i])
792 ixMax = ixData[i];
793 if (ixMin > ixData[i])
794 ixMin = ixData[i];
795 if (iyMax < iyData[i])
796 iyMax = iyData[i];
797 if (iyMin > iyData[i])
798 iyMin = iyData[i];
799 }
800 if (ixMax == ixMin)
801 return 0;
802 if (iyMax == iyMin)
803 return 0;
804
805 ixIndexCheck = calloc((*nx = ixMax - ixMin + 1), sizeof(*ixIndexCheck));
806 iyIndexCheck = calloc((*ny = iyMax - iyMin + 1), sizeof(*iyIndexCheck));
807
808 *image = calloc(*ny, sizeof(**image));
809 for (iy = 0; iy < *ny; iy++)
810 (*image)[iy] = calloc(*nx, sizeof(***image));
811
812 for (i = 0; i < nRows; i++) {
813 ix = ixData[i] - ixMin;
814 iy = iyData[i] - iyMin;
815 ixIndexCheck[ix] = 1;
816 iyIndexCheck[iy] = 1;
817 (*image)[iy][ix] = intensityData[i];
818 }
819
820 for (i = 0; i <= (ixMax - ixMin); i++) { // Changed from < to <=
821 if (!ixIndexCheck[i]) {
822 fprintf(stderr, "Error: image file is missing some x index values\n");
823 /* Free allocated memory before returning */
824 for (long y = 0; y < *ny; y++) {
825 free((*image)[y]);
826 }
827 free(*image);
828 free(ixIndexCheck);
829 free(iyIndexCheck);
830 free(ixData);
831 free(iyData);
832 free(intensityData);
833 return 0;
834 }
835 }
836 for (i = 0; i <= (iyMax - iyMin); i++) { // Changed from < to <=
837 if (!iyIndexCheck[i]) {
838 fprintf(stderr, "Error: image file is missing some y index values\n");
839 /* Free allocated memory before returning */
840 for (long y = 0; y < *ny; y++) {
841 free((*image)[y]);
842 }
843 free(*image);
844 free(ixIndexCheck);
845 free(iyIndexCheck);
846 free(ixData);
847 free(iyData);
848 free(intensityData);
849 return 0;
850 }
851 }
852
853 free(ixIndexCheck);
854 free(iyIndexCheck);
855 free(ixData);
856 free(iyData);
857 free(intensityData);
858
859 return 1;
860}
861
862long AnalyzeImageData(double **image, long nx, long ny, int32_t *ROI, int32_t *spotROISize, int32_t *sizeLines,
863 DESPIKE_SETTINGS *despikeSettings, HOTPIXEL_SETTINGS *hotpixelSettings,
864 long intensityLevels, long saturationLevel, long backgroundHalfWidth, long lonerThreshold,
865 long lonerPasses, unsigned long flags, IMAGE_ANALYSIS *analysisResults,
866 SDDS_DATASET *SDDSspim, double *centerValue) {
867 long ix, iy, iy0, iy1, ix0, ix1, nxROI, nyROI;
868 double maxValue, minValue, background, value, sum1, sum2;
869 long ixCenter, iyCenter;
870 int64_t ixMax, ixMin;
871 int32_t i;
872 double *intensityHistogram, *lineBuffer = NULL, *x = NULL, *y = NULL;
873 long spotROI[4];
874 double mean, sum;
875
876 /* Steps in image analysis:
877 * . "Apply" the ROI
878 * . Remove hot pixels, if requested
879 * . Find the spot:
880 * optionally despike the image to remove noise
881 * scan each line for maximum until the maximum maximum is found
882 * . Determine and subtract the background:
883 * accumulate histogram of pixel intensities.
884 * find the mode
885 * . If requested, run "single-spot" filter.
886 * . Check that ixCenter and iyCenter are consistent with having the
887 * spot ROI inside the pixel map. If not, adjust.
888 * . Sum over the spot ROI and subtract background*nx*ny.
889 */
890
891 /* set the ROI */
892 if (ROI[0] >= 0 && ROI[1] >= 0 && ROI[0] < ROI[1]) {
893 ix0 = ROI[0];
894 ix1 = ROI[1];
895 if (ix1 >= nx)
896 ix1 = nx - 1;
897 } else {
898 ix0 = 0;
899 ix1 = nx - 1;
900 }
901 nxROI = ix1 - ix0 + 1;
902
903 if (ROI[2] >= 0 && ROI[3] >= 0 && ROI[2] < ROI[3]) {
904 iy0 = ROI[2];
905 iy1 = ROI[3];
906 if (iy1 >= ny)
907 iy1 = ny - 1;
908 } else {
909 iy0 = 0;
910 iy1 = ny - 1;
911 }
912 nyROI = iy1 - iy0 + 1;
913
914 if ((nyROI) < spotROISize[1] || (nxROI) < spotROISize[0])
915 SDDS_Bomb("spot ROI is larger than ROI");
916
917 /* Find the spot */
918 if (despikeSettings)
919 if (!(lineBuffer = SDDS_Malloc(sizeof(*lineBuffer) * (nx > ny ? nx : ny))))
920 SDDS_Bomb("memory allocation failure");
921 minValue = DBL_MAX;
922 maxValue = -DBL_MAX;
923 ixCenter = iyCenter = -1;
924
925 for (ix = ix0; ix <= ix1; ix++) {
926 for (iy = iy0; iy <= iy1; iy++) {
927 if ((flags & CLIP_NEGATIVE) && image[iy][ix] < 0)
928 image[iy][ix] = 0;
929 if (image[iy][ix] < 0 || image[iy][ix] >= intensityLevels)
930 SDDS_Bomb("image intensity outside intensity level range");
931 }
932 }
933
934 if (despikeSettings && (despikeSettings->flags & DESPIKE_KEEP)) {
935 /* despike vertical lines */
936 for (ix = ix0; ix <= ix1; ix++) {
937 for (iy = iy0; iy <= iy1; iy++)
938 lineBuffer[iy - iy0] = image[iy][ix];
939 despikeData(lineBuffer, nyROI, despikeSettings->neighbors, despikeSettings->passes, despikeSettings->averageOf,
940 despikeSettings->threshold, 0);
941 for (iy = iy0; iy <= iy1; iy++)
942 image[iy][ix] = lineBuffer[iy - iy0];
943 }
944 }
945
946 /* despike horizontal lines, also find point of max intensity */
947 for (iy = iy0; iy <= iy1; iy++) {
948 if (despikeSettings) {
949 memcpy(lineBuffer, image[iy] + ix0, nxROI * sizeof(*lineBuffer));
950 despikeData(lineBuffer, nxROI, despikeSettings->neighbors, despikeSettings->passes, despikeSettings->averageOf,
951 despikeSettings->threshold, 0);
952 if (despikeSettings->flags & DESPIKE_KEEP)
953 memcpy(image[iy] + ix0, lineBuffer, nxROI * sizeof(*lineBuffer));
954 } else
955 lineBuffer = image[iy] + ix0;
956 index_min_max(&ixMin, &ixMax, lineBuffer, nxROI);
957 if (lineBuffer[ixMax] > maxValue) {
958 maxValue = lineBuffer[ixMax];
959 ixCenter = ixMax + ix0; /* since lineBuffer copy starts at ix=ix0 */
960 iyCenter = iy;
961 }
962 if (lineBuffer[ixMin] < minValue)
963 minValue = lineBuffer[ixMin];
964 }
965 if (despikeSettings) {
966 free(lineBuffer);
967 lineBuffer = NULL;
968 }
969 if (flags & XCENTER_PARAM)
970 ixCenter = centerValue[0];
971 else
972 centerValue[0] = ixCenter;
973 if (flags & YCENTER_PARAM)
974 iyCenter = centerValue[1];
975 else
976 centerValue[1] = iyCenter;
977 if (ixCenter == -1 || iyCenter == -1)
978 return 0;
979
980 /* Determine the background */
981 if (!(intensityHistogram = calloc(intensityLevels, sizeof(*intensityHistogram))))
982 SDDS_Bomb("memory allocation failure");
983 for (iy = iy0; iy <= iy1; iy++)
984 make_histogram(intensityHistogram, intensityLevels, -0.5, intensityLevels + 0.5, image[iy] + ix0, nxROI, iy == iy0);
985 index_min_max(&ixMin, &ixMax, intensityHistogram, intensityLevels);
986 sum1 = sum2 = 0;
987 for (i = ixMax - backgroundHalfWidth; i <= ixMax + backgroundHalfWidth; i++) {
988 if (i < 0 || i >= intensityLevels)
989 continue;
990 sum1 += intensityHistogram[i];
991 sum2 += intensityHistogram[i] * i;
992 }
993 if (sum1)
994 background = sum2 / sum1;
995 else
996 background = ixMax;
997 if (background < 0)
998 background = 0;
999 free(intensityHistogram);
1000
1001 if (hotpixelSettings) {
1002 long min, max, pass;
1003 /* remove hot pixels:
1004 * 1. Histogram the intensity levels
1005 * 2. Identify pixels with levels that are >defined fraction below max
1006 * 3. Replace identified intensities with average of near neighbors
1007 */
1008 pass = hotpixelSettings->passes;
1009 while (pass--) {
1010 max = -(min = LONG_MAX);
1011 for (iy = iy0; iy <= iy1; iy++) {
1012 for (ix = ix0; ix <= ix1; ix++) {
1013 if (image[iy][ix] > max)
1014 max = image[iy][ix];
1015 if (image[iy][ix] < min)
1016 min = image[iy][ix];
1017 }
1018 }
1019 if (min >= max)
1020 SDDS_Bomb("Can't apply hotpixel filter (min=max). Are data non-integer?");
1021 for (iy = iy0; iy <= iy1; iy++)
1022 for (ix = ix0; ix <= ix1; ix++)
1023 if ((image[iy][ix] - min) > (max - min) * hotpixelSettings->fraction)
1024 replaceWithNearNeighbors(image, iy0, iy1, ix0, ix1, iy, ix, hotpixelSettings->distance);
1025 }
1026 }
1027
1028 /* Compute new ROI for spot only */
1029 if (flags & XCENTER_CENTROID) {
1030 mean = sum = 0;
1031 for (ix = ix0; ix <= ix1; ix++)
1032 for (iy = iy0; iy <= iy1; iy++) {
1033 sum += image[iy][ix];
1034 mean += image[iy][ix] * ix;
1035 }
1036 mean /= sum;
1037 spotROI[0] = mean - spotROISize[0] / 2;
1038 } else {
1039 spotROI[0] = ixCenter - spotROISize[0] / 2;
1040 }
1041 spotROI[1] = spotROI[0] + spotROISize[0] - 1;
1042 if (spotROI[0] < ix0) {
1043 spotROI[0] = ix0;
1044 spotROI[1] = ix0 + spotROISize[0] - 1;
1045 } else if (spotROI[1] > ix1) {
1046 spotROI[1] = ix1;
1047 spotROI[0] = ix1 - spotROISize[0] + 1;
1048 }
1049 if (spotROI[0] < ix0 || spotROI[1] > ix1)
1050 SDDS_Bomb("spot ROI is larger than ROI for x"); /* shouldn't ever see this */
1051
1052 if (flags & XCENTER_CENTROID) {
1053 mean = sum = 0;
1054 for (ix = ix0; ix <= ix1; ix++)
1055 for (iy = iy0; iy <= iy1; iy++) {
1056 sum += image[iy][ix];
1057 mean += image[iy][ix] * iy;
1058 }
1059 mean /= sum;
1060 spotROI[2] = mean - spotROISize[1] / 2;
1061 } else {
1062 spotROI[2] = iyCenter - spotROISize[1] / 2;
1063 }
1064
1065 spotROI[3] = spotROI[2] + spotROISize[1] - 1;
1066 if (spotROI[2] < iy0) {
1067 spotROI[2] = iy0;
1068 spotROI[3] = iy0 + spotROISize[1] - 1;
1069 } else if (spotROI[3] > iy1) {
1070 spotROI[3] = iy1;
1071 spotROI[2] = iy1 - spotROISize[1] + 1;
1072 }
1073 if (spotROI[2] < iy0 || spotROI[3] > iy1)
1074 SDDS_Bomb("spot ROI is larger than ROI for y"); /* shouldn't ever see this */
1075
1076 /* perform background removal */
1077 analysisResults->saturationCount = 0;
1078 analysisResults->integratedSpotIntensity = 0;
1079 analysisResults->backgroundKilledNegative = 0;
1080 analysisResults->backgroundKilledPositive = 0;
1081 saturationLevel -= (long)background; // Cast to long to avoid implicit conversion warning
1082 for (ix = spotROI[0]; ix <= spotROI[1]; ix++) {
1083 for (iy = spotROI[2]; iy <= spotROI[3]; iy++) {
1084 if ((value = image[iy][ix] - background) <= 0) {
1085 analysisResults->backgroundKilledNegative += 1;
1086 value = 0;
1087 }
1088 image[iy][ix] = value;
1089 }
1090 }
1091 if (flags & SYMMETRIC_BGREMOVAL) {
1092 for (ix = spotROI[0]; ix <= spotROI[1]; ix++) {
1093 for (iy = spotROI[2]; iy <= spotROI[3]; iy++) {
1094 long ox, oy, goodPixels;
1095 long ox0, ox1, oy0, oy1;
1096 if (image[iy][ix] > 0 && image[iy][ix] <= backgroundHalfWidth) {
1097 /* if no more than one of the pixels around this pixel are >backgroundHalfWidth, then
1098 * set this pixel to zero
1099 */
1100 ox0 = (ix == spotROI[0] ? 0 : -1);
1101 ox1 = (ix == spotROI[1] ? 0 : 1);
1102 oy0 = (iy == spotROI[2] ? 0 : -1);
1103 oy1 = (iy == spotROI[3] ? 0 : 1);
1104 /* the pixel itself is counted but guaranteed to be subtracted off, too */
1105 /* this avoids an extra test in the loop */
1106 goodPixels = (ox1 - ox0 + 1) * (oy1 - oy0 + 1);
1107 for (ox = ox0; ox <= ox1; ox++) {
1108 for (oy = oy0; oy <= oy1; oy++) {
1109 if (image[iy + oy][ix + ox] <= backgroundHalfWidth)
1110 goodPixels--;
1111 }
1112 }
1113 if (goodPixels <= 1) {
1114 analysisResults->backgroundKilledPositive += 1;
1115 image[iy][ix] = 0;
1116 }
1117 }
1118 }
1119 }
1120 }
1121 if (flags & REMOVE_LONERS) {
1122 while (lonerPasses-- > 0) {
1123 for (ix = spotROI[0]; ix <= spotROI[1]; ix++) {
1124 for (iy = spotROI[2]; iy <= spotROI[3]; iy++) {
1125 long ox, oy, company;
1126 long ox0, ox1, oy0, oy1;
1127 if (image[iy][ix] > 0) {
1128 /* if none of the pixels around this pixel are nonzero, then set it to zero.
1129 */
1130 ox0 = (ix == spotROI[0] ? 0 : -1);
1131 ox1 = (ix == spotROI[1] ? 0 : 1);
1132 oy0 = (iy == spotROI[2] ? 0 : -1);
1133 oy1 = (iy == spotROI[3] ? 0 : 1);
1134 /* the pixel itself is counted but guaranteed to be subtracted off, too */
1135 /* this avoids an extra test in the loop */
1136 company = (ox1 - ox0 + 1) * (oy1 - oy0 + 1);
1137 for (ox = ox0; ox <= ox1; ox++) {
1138 for (oy = oy0; oy <= oy1; oy++) {
1139 if (image[iy + oy][ix + ox] == 0)
1140 company--;
1141 }
1142 }
1143 if (company <= lonerThreshold) {
1144 analysisResults->backgroundKilledPositive += 1;
1145 image[iy][ix] = 0;
1146 }
1147 }
1148 }
1149 }
1150 }
1151 }
1152 if (flags & ANTIHALO_BGREMOVAL) {
1153 long tryCount; // Renamed from 'try' to avoid confusion with C++ keyword
1154 for (tryCount = 0; tryCount < 2; tryCount++) {
1155 for (ix = spotROI[0]; ix <= spotROI[1]; ix++) {
1156 for (iy = spotROI[2]; iy < spotROI[3]; iy++) {
1157 if (image[iy][ix] > backgroundHalfWidth || image[iy + 1][ix] > backgroundHalfWidth)
1158 break;
1159 if (image[iy][ix]) {
1160 image[iy][ix] = 0;
1161 analysisResults->backgroundKilledPositive += 1;
1162 }
1163 }
1164 if (iy != spotROI[3])
1165 for (iy = spotROI[3]; iy > spotROI[2]; iy--) {
1166 if (image[iy][ix] > backgroundHalfWidth || image[iy - 1][ix] > backgroundHalfWidth)
1167 break;
1168 if (image[iy][ix]) {
1169 image[iy][ix] = 0;
1170 analysisResults->backgroundKilledPositive += 1;
1171 }
1172 }
1173 }
1174 for (iy = spotROI[2]; iy <= spotROI[3]; iy++) {
1175 for (ix = spotROI[0]; ix < spotROI[1]; ix++) {
1176 if (image[iy][ix] > backgroundHalfWidth || image[iy][ix + 1] > backgroundHalfWidth)
1177 break;
1178 if (image[iy][ix]) {
1179 image[iy][ix] = 0;
1180 analysisResults->backgroundKilledPositive += 1;
1181 }
1182 }
1183 if (ix != spotROI[1])
1184 for (ix = spotROI[1]; ix > spotROI[0]; ix--) {
1185 if (image[iy][ix] > backgroundHalfWidth || image[iy][ix - 1] > backgroundHalfWidth)
1186 break;
1187 if (image[iy][ix]) {
1188 image[iy][ix] = 0;
1189 analysisResults->backgroundKilledPositive += 1;
1190 }
1191 }
1192 }
1193 }
1194 }
1195 if (flags & SINGLE_SPOT) {
1196 short **connected, changed;
1197 double maxVal;
1198 long ix_max = 0, iy_max = 0;
1199
1200 connected = tmalloc(sizeof(*connected) * nx);
1201 for (ix = 0; ix < nx; ix++)
1202 connected[ix] = tmalloc(sizeof(**connected) * ny);
1203 maxVal = -HUGE_VAL;
1204 for (ix = spotROI[0]; ix <= spotROI[1]; ix++)
1205 for (iy = spotROI[2]; iy <= spotROI[3]; iy++) {
1206 connected[ix][iy] = 0;
1207 if (image[iy][ix] > maxVal) { // Changed from image[ix][iy] to image[iy][ix]
1208 ix_max = ix;
1209 iy_max = iy;
1210 maxVal = image[iy][ix];
1211 }
1212 }
1213 connected[ix_max][iy_max] = 1;
1214
1215 do {
1216 changed = 0;
1217 for (ix = spotROI[0]; ix <= spotROI[1]; ix++)
1218 for (iy = spotROI[2]; iy <= spotROI[3]; iy++) {
1219 if (!image[iy][ix] || connected[ix][iy])
1220 continue;
1221 if (ix > spotROI[0] && connected[ix - 1][iy]) {
1222 changed += (connected[ix][iy] = 1);
1223 continue;
1224 }
1225 if (ix < spotROI[1] && connected[ix + 1][iy]) {
1226 changed += (connected[ix][iy] = 1);
1227 continue;
1228 }
1229 if (iy > spotROI[2] && connected[ix][iy - 1]) {
1230 changed += (connected[ix][iy] = 1);
1231 continue;
1232 }
1233 if (iy < spotROI[3] && connected[ix][iy + 1]) {
1234 changed += (connected[ix][iy] = 1);
1235 continue;
1236 }
1237 }
1238 for (ix = spotROI[1]; ix >= spotROI[0]; ix--)
1239 for (iy = spotROI[3]; iy >= spotROI[2]; iy--) {
1240 if (!image[iy][ix] || connected[ix][iy])
1241 continue;
1242 if (ix > spotROI[0] && connected[ix - 1][iy]) {
1243 changed += (connected[ix][iy] = 1);
1244 continue;
1245 }
1246 if (ix < spotROI[1] && connected[ix + 1][iy]) {
1247 changed += (connected[ix][iy] = 1);
1248 continue;
1249 }
1250 if (iy > spotROI[2] && connected[ix][iy - 1]) {
1251 changed += (connected[ix][iy] = 1);
1252 continue;
1253 }
1254 if (iy < spotROI[3] && connected[ix][iy + 1]) {
1255 changed += (connected[ix][iy] = 1);
1256 continue;
1257 }
1258 }
1259 } while (changed);
1260
1261 for (ix = spotROI[0]; ix <= spotROI[1]; ix++)
1262 for (iy = spotROI[2]; iy <= spotROI[3]; iy++)
1263 if (!connected[ix][iy])
1264 image[iy][ix] = 0;
1265
1266 /* Free connected memory */
1267 for (ix = 0; ix < nx; ix++) {
1268 free(connected[ix]);
1269 }
1270 free(connected);
1271 }
1272
1273 /* check for saturation */
1274 for (ix = spotROI[0]; ix <= spotROI[1]; ix++)
1275 for (iy = spotROI[2]; iy <= spotROI[3]; iy++)
1276 if (image[iy][ix] > saturationLevel)
1277 analysisResults->saturationCount += 1;
1278
1279 /* find the spot intensity and centroids */
1280 analysisResults->spotCentroid[0] = analysisResults->spotCentroid[1] = 0;
1281 for (ix = spotROI[0]; ix <= spotROI[1]; ix++)
1282 for (iy = spotROI[2]; iy <= spotROI[3]; iy++) {
1283 analysisResults->integratedSpotIntensity += image[iy][ix];
1284 analysisResults->spotCentroid[0] += image[iy][ix] * ix;
1285 analysisResults->spotCentroid[1] += image[iy][ix] * iy;
1286 }
1287 if (analysisResults->integratedSpotIntensity)
1288 for (i = 0; i < 2; i++)
1289 analysisResults->spotCentroid[i] /= analysisResults->integratedSpotIntensity;
1290
1291 /* find the spot size in y using central lines around the peak */
1292 if (!(lineBuffer = calloc(ny, sizeof(*lineBuffer))))
1293 SDDS_Bomb("memory allocation failure");
1294 if (!(x = calloc(ny, sizeof(*x))))
1295 SDDS_Bomb("memory allocation failure");
1296 if (!(y = calloc(ny, sizeof(*y))))
1297 SDDS_Bomb("memory allocation failure");
1298 for (ix = ixCenter - sizeLines[0] / 2; ix <= ixCenter + sizeLines[0] / 2; ix++) {
1299 if (ix < ix0 || ix > ix1)
1300 continue;
1301 for (iy = spotROI[2]; iy <= spotROI[3]; iy++)
1302 lineBuffer[iy] += image[iy][ix];
1303 }
1304 for (iy = spotROI[2]; iy <= spotROI[3]; iy++)
1305 y[iy] = lineBuffer[iy];
1306
1307 DetermineBeamSizes(&analysisResults->spotSigma[1], &analysisResults->spotRange50[1], &analysisResults->spotRange65[1],
1308 &analysisResults->spotRange80[1], lineBuffer, spotROI[2], spotROI[3]);
1309 free(lineBuffer);
1310 /* find the spot size in x using central lines around the peak */
1311 if (!(lineBuffer = calloc(nx, sizeof(*lineBuffer))))
1312 SDDS_Bomb("memory allocation failure");
1313 for (iy = iyCenter - sizeLines[1] / 2; iy <= iyCenter + sizeLines[1] / 2; iy++) {
1314 if (iy < iy0 || iy > iy1)
1315 continue;
1316 for (ix = spotROI[0]; ix <= spotROI[1]; ix++)
1317 lineBuffer[ix] += image[iy][ix];
1318 }
1319 DetermineBeamSizes(&analysisResults->spotSigma[0], &analysisResults->spotRange50[0], &analysisResults->spotRange65[0],
1320 &analysisResults->spotRange80[0], lineBuffer, spotROI[0], spotROI[1]);
1321 free(lineBuffer);
1322 DetermineBeamParameters(image, spotROI, nx, ny, &analysisResults->S11, &analysisResults->S33, &analysisResults->rmsCrossProduct,
1323 &analysisResults->phi, &analysisResults->majorAxis, &analysisResults->minorAxis);
1324 /* put results in the structure for return */
1325 analysisResults->peakSpotIntensity = maxValue - background;
1326 analysisResults->spotCenter[0] = ixCenter;
1327 analysisResults->spotCenter[1] = iyCenter;
1328 analysisResults->backgroundLevel = background;
1329 analysisResults->ROI[0] = ix0;
1330 analysisResults->ROI[1] = ix1;
1331 analysisResults->ROI[2] = iy0;
1332 analysisResults->ROI[3] = iy1;
1333 for (i = 0; i < 4; i++)
1334 analysisResults->spotROI[i] = spotROI[i];
1335 if (x)
1336 free(x);
1337 if (y)
1338 free(y);
1339
1340 if (SDDSspim) {
1341 long i_row;
1342 if (!SDDS_StartPage(SDDSspim, (spotROI[1] - spotROI[0] + 1) * (spotROI[3] - spotROI[2] + 1)))
1343 SDDS_Bomb("Problem starting page for spot image output file.");
1344 if (!SDDS_SetParameters(SDDSspim, SDDS_PASS_BY_VALUE | SDDS_SET_BY_NAME, "nx", (short)(spotROI[1] - spotROI[0] + 1),
1345 "ny", (short)(spotROI[3] - spotROI[2] + 1), NULL))
1346 SDDS_Bomb("Problem setting parameter values for spot image output file.");
1347 i_row = 0;
1348 for (iy = spotROI[2]; iy <= spotROI[3]; iy++) {
1349 for (ix = spotROI[0]; ix <= spotROI[1]; ix++) {
1350 if (!SDDS_SetRowValues(SDDSspim, SDDS_PASS_BY_VALUE | SDDS_SET_BY_NAME, i_row++, "ix", (short)ix,
1351 "iy", (short)iy, "Image", image[iy][ix], NULL)) {
1352 SDDS_Bomb("Problem setting row values for spot image output file.");
1353 }
1354 }
1355 }
1356 if (!SDDS_WritePage(SDDSspim)) {
1357 SDDS_Bomb("Problem writing page for spot image output file.");
1358 }
1359 }
1360 return 1;
1361}
1362
1363void DetermineBeamSizes(double *sigma, double *Range50, double *Range65, double *Range80, double *lineBuffer, long i0, long i1) {
1364 double centroid, sum;
1365 long i, j;
1366 double pLevel[6] = {.10, .175, .25, .75, .825, .90};
1367 double pValue[6];
1368
1369 centroid = sum = 0;
1370 *sigma = *Range80 = *Range65 = *Range50 = 0;
1371 for (i = i0; i <= i1; i++) {
1372 sum += lineBuffer[i];
1373 centroid += lineBuffer[i] * i;
1374 }
1375 if (sum) {
1376 centroid = centroid / sum;
1377 for (i = i0; i <= i1; i++)
1378 *sigma += lineBuffer[i] * sqr(i - centroid);
1379 *sigma = sqrt(*sigma / sum);
1380
1381 /* integrate the intensity */
1382 for (i = i0 + 1; i <= i1; i++)
1383 lineBuffer[i] += lineBuffer[i - 1];
1384 if (lineBuffer[i1]) {
1385 for (i = i0; i <= i1; i++)
1386 lineBuffer[i] /= lineBuffer[i1];
1387 i = i0 + 1;
1388 for (j = 0; j < 6; j++) {
1389 pValue[j] = 0;
1390 while (i <= i1 && lineBuffer[i] < pLevel[j])
1391 i++;
1392 if (i > i1) { // Added check to prevent out-of-bounds access
1393 pValue[j] = i1;
1394 } else if (lineBuffer[i] == lineBuffer[i - 1])
1395 pValue[j] = i - 0.5;
1396 else
1397 pValue[j] = i - (lineBuffer[i] - pLevel[j]) / (lineBuffer[i] - lineBuffer[i - 1]);
1398 }
1399 *Range80 = pValue[5] - pValue[0];
1400 *Range65 = pValue[4] - pValue[1];
1401 *Range50 = pValue[3] - pValue[2];
1402 }
1403 }
1404}
1405
1406void BlankOutImageData(double **image, long nx, long ny, int32_t *region) {
1407 long ix, iy, count = 0;
1408 for (ix = region[0]; ix <= region[1]; ix++)
1409 for (iy = region[2]; iy <= region[3]; iy++, count++)
1410 image[iy][ix] = 0;
1411}
1412
1413void DetermineBeamParameters(double **image, long *spotROI, long nx, long ny, double *S11, double *S33,
1414 double *rmsCrossProduct, double *phi, double *majorAxis, double *minorAxis) {
1415 long i, j;
1416 long x1, x2, y1, y2;
1417 double imageArea = 0, x2Ave = 0, y2Ave = 0, xyAve = 0, dominator = 0, xcentroid = 0, ycentroid = 0;
1418
1419 x1 = spotROI[0];
1420 x2 = spotROI[1];
1421 y1 = spotROI[2];
1422 y2 = spotROI[3];
1423
1424 /*calcuate the area of image(x,y) in a square defined by (x1,y1), (x1,y2), (x2,y2) and (x2,y1) */
1425 for (i = y1; i <= y2; i++)
1426 for (j = x1; j <= x2; j++) {
1427 imageArea += image[i][j];
1428 xcentroid += image[i][j] * j;
1429 ycentroid += image[i][j] * i;
1430 }
1431 if (imageArea == 0) {
1432 *rmsCrossProduct = *majorAxis = *minorAxis = DBL_MAX;
1433 } else {
1434 xcentroid = xcentroid / imageArea;
1435 ycentroid = ycentroid / imageArea;
1436 for (i = y1; i <= y2; i++)
1437 for (j = x1; j <= x2; j++) {
1438 x2Ave += sqr(j - xcentroid) * image[i][j];
1439 y2Ave += sqr(i - ycentroid) * image[i][j];
1440 xyAve += (i - ycentroid) * (j - xcentroid) * image[i][j];
1441 }
1442 x2Ave = x2Ave / imageArea;
1443 y2Ave = y2Ave / imageArea;
1444 xyAve = xyAve / imageArea;
1445 dominator = x2Ave * y2Ave - xyAve * xyAve;
1446 *S11 = x2Ave;
1447 *S33 = y2Ave;
1448 *rmsCrossProduct = xyAve;
1449 *phi = 0.5 * atan2(2 * xyAve, x2Ave - y2Ave) / PI * 180;
1450 if ((x2Ave + y2Ave - sqrt(sqr(x2Ave - y2Ave) + 4 * sqr(xyAve))) != 0) {
1451 *majorAxis = sqrt(2 * dominator / (x2Ave + y2Ave - sqrt(sqr(x2Ave - y2Ave) + 4 * sqr(xyAve))));
1452 } else {
1453 *majorAxis = DBL_MAX;
1454 }
1455 if ((x2Ave + y2Ave + sqrt(sqr(x2Ave - y2Ave) + 4 * sqr(xyAve))) != 0) {
1456 *minorAxis = sqrt(2 * dominator / (x2Ave + y2Ave + sqrt(sqr(x2Ave - y2Ave) + 4 * sqr(xyAve))));
1457 } else {
1458 *minorAxis = DBL_MAX;
1459 }
1460 }
1461}
1462
1463void replaceWithNearNeighbors(double **image, long iy0, long iy1, long ix0, long ix1, long iyc, long ixc, long distance) {
1464 long ix, iy, nnn;
1465 double sum;
1466
1467 if ((iyc - distance) > iy0)
1468 iy0 = iyc - distance;
1469 if ((iyc + distance) < iy1)
1470 iy1 = iyc + distance;
1471
1472 if ((ixc - distance) > ix0)
1473 ix0 = ixc - distance;
1474 if ((ixc + distance) < ix1)
1475 ix1 = ixc + distance;
1476
1477 sum = 0;
1478 nnn = 0;
1479 for (iy = iy0; iy <= iy1; iy++)
1480 for (ix = ix0; ix <= ix1; ix++) {
1481 if (ix == ixc && iy == iyc)
1482 continue;
1483 sum += image[iy][ix];
1484 nnn++;
1485 }
1486
1487 if (nnn > 0)
1488 image[iyc][ixc] = sum / nnn;
1489}
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
int32_t SDDS_LengthenTable(SDDS_DATASET *SDDS_dataset, int64_t n_additional_rows)
int32_t SDDS_SetRowValues(SDDS_DATASET *SDDS_dataset, int32_t mode, int64_t row,...)
int32_t SDDS_StartPage(SDDS_DATASET *SDDS_dataset, int64_t expected_n_rows)
int32_t SDDS_SetParameters(SDDS_DATASET *SDDS_dataset, int32_t mode,...)
double * SDDS_GetParameterAsDouble(SDDS_DATASET *SDDS_dataset, char *parameter_name, double *memory)
Retrieves the value of a specified parameter as a double from the current data table of an SDDS datas...
int32_t * SDDS_GetColumnInLong(SDDS_DATASET *SDDS_dataset, char *column_name)
Retrieves the data of a specified numerical column as an array of 32-bit integers,...
void * SDDS_GetParameter(SDDS_DATASET *SDDS_dataset, char *parameter_name, void *memory)
Retrieves the value of a specified parameter from the current data table of a data set.
double * SDDS_GetColumnInDoubles(SDDS_DATASET *SDDS_dataset, char *column_name)
Retrieves the data of a specified numerical column as an array of doubles, considering only rows mark...
int32_t SDDS_InitializeInput(SDDS_DATASET *SDDS_dataset, char *filename)
Definition SDDS_input.c:49
int32_t SDDS_Terminate(SDDS_DATASET *SDDS_dataset)
int32_t SDDS_ReadPage(SDDS_DATASET *SDDS_dataset)
int32_t SDDS_InitializeOutput(SDDS_DATASET *SDDS_dataset, int32_t data_mode, int32_t lines_per_row, const char *description, const char *contents, const char *filename)
Initializes the SDDS output dataset.
int32_t SDDS_WritePage(SDDS_DATASET *SDDS_dataset)
Writes the current data table to the output file.
int32_t SDDS_DefineColumn(SDDS_DATASET *SDDS_dataset, const char *name, const char *symbol, const char *units, const char *description, const char *format_string, int32_t type, int32_t field_length)
Defines a data column within the SDDS dataset.
int32_t SDDS_WriteLayout(SDDS_DATASET *SDDS_dataset)
Writes the SDDS layout header to the output file.
int32_t SDDS_DefineParameter(SDDS_DATASET *SDDS_dataset, const char *name, const char *symbol, const char *units, const char *description, const char *format_string, int32_t type, char *fixed_value)
Defines a data parameter with a fixed string value.
int32_t SDDS_DefineColumnLikeParameter(SDDS_DATASET *target, SDDS_DATASET *source, char *name, char *newName)
Defines a column in the target dataset based on a parameter definition from the source dataset.
void SDDS_SetError(char *error_text)
Records an error message in the SDDS error stack.
Definition SDDS_utils.c:379
char ** SDDS_GetParameterNames(SDDS_DATASET *SDDS_dataset, int32_t *number)
Retrieves the names of all parameters in the SDDS dataset.
int32_t SDDS_GetColumnIndex(SDDS_DATASET *SDDS_dataset, char *name)
Retrieves the index of a named column in the SDDS dataset.
void SDDS_PrintErrors(FILE *fp, int32_t mode)
Prints recorded error messages to a specified file stream.
Definition SDDS_utils.c:432
void * SDDS_Malloc(size_t size)
Allocates memory of a specified size.
Definition SDDS_utils.c:639
void SDDS_Bomb(char *message)
Terminates the program after printing an error message and recorded errors.
Definition SDDS_utils.c:342
#define SDDS_STRING
Identifier for the string data type.
Definition SDDStypes.h:85
#define SDDS_LONG
Identifier for the signed 32-bit integer data type.
Definition SDDStypes.h:61
#define SDDS_SHORT
Identifier for the signed short integer data type.
Definition SDDStypes.h:73
#define SDDS_DOUBLE
Identifier for the double data type.
Definition SDDStypes.h:37
void * tmalloc(uint64_t size_of_block)
Allocates a memory block of the specified size with zero initialization.
Definition array.c:59
long bitsSet(unsigned long data)
Counts the number of set bits (1s) in the given data.
Definition binary.c:52
char * delete_chars(char *s, char *t)
Removes all occurrences of characters found in string t from string s.
int index_min_max(int64_t *imin, int64_t *imax, double *list, int64_t n)
Finds the indices of the minimum and maximum values in a list of doubles.
Definition findMinMax.c:116
long make_histogram(double *hist, long n_bins, double lo, double hi, double *data, int64_t n_pts, long new_start)
Compiles a histogram from data points.
long match_string(char *string, char **option, long n_options, long mode)
Matches a given string against an array of option strings based on specified modes.
int scanargsg(SCANNED_ARG **scanned, int argc, char **argv)
Definition scanargs.c:163
long processPipeOption(char **item, long items, unsigned long *flags)
Definition scanargs.c:356
void processFilenames(char *programName, char **input, char **output, unsigned long pipeFlags, long noWarnings, long *tmpOutputUsed)
Definition scanargs.c:390
long scanItemList(unsigned long *flags, char **item, long *items, unsigned long mode,...)
Scans a list of items and assigns values based on provided keywords and types.
long despikeData(double *data, long rows, long neighbors, long passes, long averageOf, double threshold, long countLimit)
Remove spikes from a data array by comparing each point to its neighbors.
Definition smooth.c:86