ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/JSOC/proj/lev0/apps/aia_despike.c
Revision: 1.3
Committed: Thu Dec 2 18:59:06 2010 UTC (12 years, 9 months ago) by jps
Content type: text/plain
Branch: MAIN
CVS Tags: Ver_6-0, Ver_6-1, Ver_6-2, Ver_6-3, Ver_6-4, Ver_9-1, Ver_5-14, Ver_5-13, Ver_5-12, Ver_8-8, Ver_8-2, Ver_8-3, Ver_8-0, Ver_8-1, Ver_8-6, Ver_8-7, Ver_8-4, Ver_8-5, Ver_7-1, Ver_7-0, Ver_8-10, Ver_8-11, Ver_8-12, Ver_9-0
Changes since 1.2: +22 -6 lines
Log Message:
Improved handling of negative pixel values.

File Contents

# Content
1 /* code pulled from ana for a standalone despike for radiation hits */
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <math.h>
5 #include <string.h>
6 #include <sys/types.h>
7 #include <sys/time.h>
8 #define ALN2I 1.442695022
9 #define TINY 1.0e-5
10 #define ABS(x) ((x)>=0?(x):-(x))
11 // double systime(); /* note that systime is defined elsewhere in the ana environment, remove
12 // all refs for standalone (or add func systime) */
13 /* 3/17/2010 - interface change to I*4, also work on locations to remove duplicates (some
14 pixels are despiked twice when iterated) and do not use output array, modify the input array */
15 /* 9/29/2010 - some mods to remove negative values from the data */
16 /* 11/20/10 - now want to keep neg values, so remove those mods and make sure
17 we don't get too many extra spikes by adjusting absmin (from 1 to 4), we
18 already had a test to avoid despiking neg pixels from 9/29/2010 mods */
19 /*---------------------------------------------------------------------------*/
20 int aia_despike(
21 int *array, unsigned char *mask, int nx, int ny, float frac, int level, int niter, /* void **outarray, */
22 int *badblobs, int sizeofbads,
23 int *nspikes, int **oldvalues, int **spikelocs, int **newvalues);
24 int mask_erode(unsigned char *pbase, unsigned char *qbase, int n, int m); /* erosion function */
25 /*------------------------------------------------------------------------- */
26 int aia_despike( /* despike function, modified heavily for AIA */
27 int *array, unsigned char *mask, int nx, int ny, float frac, int level, int niter, /* void **outarray, */
28 int *badblobs, int sizeofbads,
29 int *nspikes, int **oldvalues, int **spikelocs, int **newvalues)
30 /* the call is
31 int *ptr, *oldvalues, *newvalues;
32 int nx, ny, level=7, niter=3, *spikelocs;
33 float frac = 0.5;
34 unsigned char *mask;
35
36 stat = despike(ptr, mask, nx, ny, frac, level, niter,
37 &nspikes, &oldvalues, &spikelocs, &newvalues);
38
39 note that a NULL passed for mask implies full image (a fake mask is generated internally)
40 a 0 for sizeofbads implies no bad pixel correction
41
42 note that the nx by ny I*4 array in ptr will be despiked thereby modifying the original,
43 the original can be recovered using the offsets in spikelocs and the original values
44 in oldvalues, the new values are also available in the newvalues array, these 3 arrays
45 are malloc'ed here and the caller is responsible for free'ing them
46
47 The bad pixels are represented as bad "blobs" to allow for possible clusters. The badblobs
48 array is a null terminated packed list of these, the size of the list must also be
49 passed in sizeofbads to avoid any overflows (and allow for a quick check for none),
50 the format of the list is [nperim, perim_offsets, npix, pix_offsets] in series for
51 each "blob", nperim is the # of perimeter points (offsets in ptr) to use for averaging
52 to obtain a value to substitute for the bad pixels. perim_offsets is the list
53 of nperim offsets. npix is the count of bad pixels to be replaced by this average and
54 pix_offsets is the npix offsets. Note that all bad pixels are replaced by the same value
55 (no gradients or such) computed from the average of the perimeter. The length of each
56 in the the list is nperim + npix + 2. The code just steps through.
57 */
58 {
59 int iq, result_sym, n, m, sum, nc;
60 int lognb2, jj, jc;
61 float absmin = 4.0;
62 int nxc, nyc, offset, *lastiterendaddr;
63 int save_niter, ntotal, npix, nslocal, ndups, itercount;
64 float fsum, cfrac, tq, fdif;
65 int *p, *ptr, *p1, *p2, *p3, *spikeold, *oldptr;
66 unsigned char *mptr, *mp, mskv, *mskbase, *eroded, *eroded2;
67 int *spikebufadd, *sptradd;
68 int *spikenew, *newptr, *base;
69 int arr[16], *pps, *ss, *spikestarts[20], *spikeends[20];
70 //double t1, t2, t3, t4;
71 //t1 = systime();
72 lognb2 = (log((double) 16)*ALN2I+TINY); /* needed for median sort */
73
74 /* always an int array for this routine */
75 if (nx < 5 || ny < 5 ) {
76 printf("dimensions must be 5 or greater, nx, ny = %d %d\n", nx,ny);
77 return -1; }
78 /* bad pixel correction (if any), uses blob list as noted above */
79 if (sizeofbads > 0 && badblobs != 0 ) {
80 /* correction done in place, if badblobs not defined correctly, a memory access violation
81 could occur */
82 int countdown = sizeofbads;
83 int *pblob, nperim, npix, xq, offset;
84 float acc;
85 pblob = badblobs;
86 while (1) {
87 acc = 0.0;
88 nperim = *pblob++;
89 if (nperim <= 0 || nperim > countdown) break;
90 n = nperim;
91 /* this takes the average of the perimeter values, a median might be better */
92 while (n--) { offset = *pblob++; acc += *(array + offset); }
93 xq = rintf(acc/(float) nperim);
94 npix = *pblob++;
95 if (npix <= 0 || npix > countdown) break;
96 n = npix;
97 while (n--) { offset = *pblob++; *(array + offset) = xq; }
98 countdown = countdown - nperim - npix - 2;
99 if (countdown <= 0) break;
100 }
101 }
102
103 /* flip image */
104 {
105 int i, *toprow, *botrow, *tmprow;
106 botrow = array;
107 toprow = botrow + 4095*4096;
108 tmprow = (int *) malloc(sizeof(int)*4096);
109 for (i = 0; i < 2048; i++) {
110 memcpy(tmprow, toprow, 16384);
111 memcpy(toprow, botrow, 16384);
112 memcpy(botrow, tmprow, 16384);
113 botrow += 4096;
114 toprow -= 4096;
115 }
116 free(tmprow);
117 }
118 /* if no mask, we actually make one full of 1's, partly for testing */
119 eroded = malloc(nx*ny*sizeof(unsigned char));
120 if (!eroded) { printf("malloc error in local mask copy\n"); return 1; }
121 mp = eroded;
122 /* unfortunately, we need to check array for 0x80000000 values and avoid using
123 these for despike decisions and we must not modify them. This is done by zeroing
124 the mask for the corresponding points before erosion */
125 p = array;
126 /* 9/29/2010 - also catch any other negative values while we are looping and zero them */
127 if (mask == 0) {
128 int nq = nx * ny;
129 while (nq--) {
130 /* 9/29/2010 - change here to remove negative values (convert to 0) */
131 /* 11/20/10 - try leaving the negative values in */
132 //if (*p == 0x80000000) { *mp++ = 0; } else { *mp++ = 1; if (*p < 0) *p = 0; }
133 if (*p == 0x80000000) { *mp++ = 0; } else { *mp++ = 1; }
134 p++;
135 }
136 /* mask gets set to "eroded" further down */
137 } else {
138 /* have a real mask, need to erode it after checking for 0x80000000's */
139 int nq = nx * ny;
140 mp = mask;
141 while (nq--) {
142 /* 9/29/2010 - change here to remove negative values (convert to 0) */
143 /* 11/20/10 - try leaving the negative values in */
144 //if (*p == 0x80000000) { *mp++ = 0; } else { if (*p < 0) *p = 0; }
145 if (*p == 0x80000000) { *mp++ = 0; }
146 p++;
147 }
148 eroded2 = malloc(nx*ny*sizeof(unsigned char));
149 if (!eroded2) { printf("malloc error in local mask copy\n"); return 1; }
150 mask_erode(mask, eroded2, nx, ny);
151 mask_erode(eroded2, eroded, nx, ny);
152 /* leaves final result in eroded, so free eroded2 now and redefine mask */
153 free(eroded2);
154 }
155 mask = mp = eroded;
156 ptr = base = array;
157 /* and the mask */
158 mptr = mskbase = mask;
159 cfrac = 1.0/(1.0 + frac); /* 3/2/2010 changed from 1.0 - frac which had less range */
160 nc = ntotal = nslocal = 0;
161 niter = ABS(niter);
162 /* 4/7/2010 - add a check for niter < 0 to avoid runaways */
163 if (niter > 20 || niter < 0) { printf("DESPIKE - error, excessive # of iterations = %d\n",
164 niter); return 1; }
165
166 /* add internal iteration 10/8/98 */
167 save_niter = niter;
168 spikeold = oldptr = malloc(nx*ny*sizeof(int)); /* that allows every pixel */
169 spikenew = newptr = malloc(nx*ny*sizeof(int)); /* that allows every pixel */
170 spikebufadd = sptradd = malloc(nx*ny*sizeof(int)); /* that allows every pixel */
171 lastiterendaddr = spikebufadd;
172 ndups = 0;
173 //t2 = systime();
174 npix = 0;
175 itercount = 0;
176 spikestarts[itercount] = spikebufadd;
177 /* note that niter = 0 should not do any despike */
178 while (niter--) {
179 ptr = array + 2*nx;
180 /* and the mask */
181 mptr = mask + 2*nx;
182 /* skip the outer edges */
183 m = ny-4;
184 while (m--) {
185 /* skip the outer edges */
186 p = ptr;
187 p += 2;
188 /* and the mask */
189 mp = mptr + 2;
190 n = nx-4;
191 p2 = p - 1;
192 p1 = p2 - nx;
193 p3 = p2 + nx;
194 while (n--) {
195 npix++;
196 /* watch out for 0's, lots in test images */
197 /* 3/22/2010 - mask check finally added for each position */
198 /* 9/29/2010 - avoid processing negative values as well as zeroes */
199 if ( (*p > 0) && *mp ) {
200 /* add the 8 around this point */
201 tq = (cfrac * (float) *p);
202 sum = *p1 + *(p1+1) + *(p1+2) + *p2 + *(p2+2) + *p3 + *(p3+1) + *(p3+2);
203 /* note the absmin term, this is to avoid problems with data that has large
204 zones of zeroes, we then get too many hits and erosion of edges, mostly a problem
205 with artifical data */
206 fsum = (float) sum * 0.125;
207 /* now the test */
208 if ( (fsum < tq) && ((tq-fsum) > absmin) ) { /* we have a bad one, zap it */
209 nc++;
210 /* load up sort array and find the desired one */
211 ss = arr; pps = p - 2*nx -2;
212 *ss++ = *pps++; *ss++ = *pps++; *ss++ = *pps++; *ss++ = *pps++; *ss++ = *pps++;
213 *ss++ = *(p - nx -2); *ss++ = *(p - nx +2);
214 *ss++ = *(p -2); *ss++ = *(p +2);
215 *ss++ = *(p + nx -2); *ss++ = *(p + nx +2);
216 pps = p + 2 *nx - 2;
217 *ss++ = *pps++; *ss++ = *pps++; *ss++ = *pps++; *ss++ = *pps++; *ss++ = *pps++;
218 /* this is basically a median filter (adjustable using level value) to find
219 a "good" value from the surroundings, we do a median rather than an average to
220 try to avoid some effects of spike overflow on the CCD */
221 /* a built in sorter here */
222 { int nn,m,j,i,n=16;
223 int t;
224 m=n;
225 for (nn=1;nn<=lognb2;nn++) {
226 m >>= 1;
227 for (j=m;j<n;j++) {
228 i=j-m;
229 t=arr[j];
230 while (i >= 0 && arr[i] > t) {
231 arr[i+m]=arr[i];
232 i -= m;
233 }
234 arr[i+m]=t;
235 }
236 }
237 }
238 /* 3/11/2010 - log into various arrays */
239 *oldptr++ = *p; offset = p - base;
240 //if (nslocal == 0) printf("sptradd, offset = %d, %d\n", sptradd, offset);
241 *sptradd++ = offset;
242 nslocal++; /* yet another spike counter */
243 /* now get the indicated one using level, also save into spikenew */
244 *newptr++ = arr[level];
245 }
246 }
247 p++; mp++; p1++; p2++; p3++;
248
249 }
250 /* skip the outer edges */
251 //p = p + 2;
252 ptr = ptr + nx;
253 /* and the mask */
254 //mp = mp + 2;
255 mptr = mptr + nx;
256 }
257 /* skip the last 2 rows */
258 /* end of this iteration, reconfigure for next one, note that for
259 a single iteration we don't need out2 */
260 // printf("despike got %d spikes in iteration %d out of %d pixels\n", nc, itercount, npix);
261 // printf("nslocal = %d\n", nslocal);
262 ntotal += nc; nc = 0;
263 npix = 0;
264 if (niter < (save_niter - 1)) {
265 int *ip, *jp, *iplast = spikebufadd;
266 int ioff, joff, delta1, delta2, previter;
267 /* check the range spikebufadd to lastiterendaddr against lastiterendaddr+1 to sptradd-1,
268 the idea here is to check if any of our new spikes have the same location from a previous
269 iteration, this isn't a n*m operation because each set is monotonic, note however that
270 we have to scan each iteration set separately (which is annoying) */
271 int *jprevstart[20];
272 spikestarts[itercount] = spikeends[itercount-1] + 1;
273 for (previter=0; previter<itercount; previter++) { jprevstart[previter] = spikestarts[previter]; }
274 for (ip=spikestarts[itercount]; ip<sptradd; ip++) {
275 ioff = *ip;
276 /* now compare with all the previous ones */
277 for (previter=0; previter<itercount; previter++) {
278
279 for (jp=jprevstart[previter]; jp<=spikeends[previter]; jp++) {
280 joff = *jp;
281 if (joff == ioff) {
282 /* we want the new instance of this location to be the one used, it needs
283 the earlier old value, it already has the latest new value */
284 delta2 = jp - spikebufadd;
285 delta1 = ip - spikebufadd;
286 *(spikeold + delta1) = *(spikeold + delta2);
287 /* and zap the original location */
288 *jp = -1;
289 ndups++;
290 break;
291 }
292 if (joff > ioff) {
293 /* because both are monotonic, can't be any more now */
294
295 break;
296 }
297 }
298 /* reset the start to avoid wasting time on check for next jp since both are monotonic */
299 jprevstart[previter] = jp;
300 }
301 }
302 //printf("# of dups = %d\n", ndups);
303 }
304 spikeends[itercount] = sptradd - 1;
305 // printf("setting spikestarts[itercount], spikeends[itercount] = %d, %d\n", spikestarts[itercount],
306 // spikeends[itercount]);
307 /* and we now set the new values from this iteration in the input array */
308 {
309 int *ip, ioff, *snew, nq;
310 ip=spikestarts[itercount];
311 snew = spikenew + (ip - spikebufadd);
312 while ( ip<sptradd ) {
313 ioff = *ip++;
314 array[ioff] = *snew++;
315 }
316 }
317 itercount++;
318 }
319 /* wrap up the spike log */
320 *nspikes = nslocal;
321 // printf("# of spikes logged = %d, dups = %d\n", nslocal, ndups);
322 *nspikes = nslocal - ndups;
323 // printf("# of unique spikes logged = %d\n", *nspikes);
324 n = (nslocal - ndups)*sizeof(int);
325 /* the duplicates are tagged, copy only the unique ones for export */
326 if (n > 0) {
327 int i;
328 int *p1, *p2, *p3, *q1, *q2, *q3;
329 *oldvalues = p1 = malloc(n);
330 q1 = spikeold;
331 *newvalues = p2 = malloc(n);
332 q2 = spikenew;
333 *spikelocs = p3 = malloc(n);
334 q3 = spikebufadd;
335 for (i=0;i<nslocal;i++) {
336 if (*q3 > 0) { *p1++ = *q1; *p2++ = *q2; *p3++ = *q3; }
337 q1++; q2++; q3++;
338 }
339 } else {
340 *oldvalues = 0; *spikelocs = 0; *newvalues = 0;
341 }
342 /* free up (reverse order) */
343 free(spikebufadd); free(spikenew); free(spikeold); free(eroded);
344
345 // printf("despike got %d spikes in %d iterations\n", ntotal, save_niter);
346 // t3 = systime();
347
348 // printf("despike times, setup %10.6fs, iters %10.6fs, total %10.6fs\n", t2-t1,t3-t2,t3-t1);
349 return 0;
350 }
351 /*------------------------------------------------------------------------- */
352 /* a standalone erode function specialized for eroding the AIA masks prior to
353 despiking */
354 /*------------------------------------------------------------------------- */
355 int mask_erode(unsigned char *pbase, unsigned char *qbase, int n, int m) /* erosion function */
356 {
357 unsigned char *p, *q, *p_endline, *qabove, *qbelow;
358 int iq, mq, type;
359 double t1, t2, t3, t4;
360 // t1 = systime();
361 if ( n < 3 || m < 3 ) {
362 printf("ERODE: array too small, nx, ny = %d %d\n", n, m);
363 return -1; }
364
365 bcopy(pbase, qbase, n*m);
366 p = pbase;
367 q = qbase;
368
369 /* the edges and corners are done as special cases */
370 /* first corner */
371 if (*p == 0) { /* zap the 3 neighbors */
372 *q++; *q = 0; q = qbase + n; *q++ = 0; *q = 0;}
373 /* starting row */
374 p_endline = pbase + n - 2;
375 p++;
376 // t2 = systime();
377 while (1) {
378 if (*p == 0) {
379 /* got a hit, this means we need to clear 6 pixels in the output image */
380 q = (qbase - pbase - 1) + p; /* this is the q just before the corresponding p */
381 qabove = q + n;
382 *q++ = 0; q++; *q++ = 0;
383 *qabove++ = 0; *qabove++ = 0; *qabove++ = 0;
384 if (p >= p_endline) break;
385 p++;
386 /* if we continue to get consecutive hits, just need to set next 2 */
387 while (*p == 0) {
388 if (p >= p_endline) break;
389 *q++ = 0; *qabove++ = 0;
390 p++; }
391 }
392 if (p >= p_endline) break;
393 p++;
394 }
395 p++;
396 /* last point in starting row, set independent of previous so we may
397 set some pixels twice */
398 if (*p == 0) {
399 q = (qbase - pbase - 1) + p; /* this is the q just before the corresponding p */
400 qabove = q + n;
401 *q = 0;
402 *qabove++ = 0; *qabove = 0;
403 }
404 p++;
405
406
407 /* central area */
408 /* now the interior rows */
409 mq = m - 2;
410 while (mq-- > 0) {
411 /* start row, not top or bottom */
412 /* left hand edge */
413 if (*p == 0) { /* set 6 points */
414 q = (qbase - pbase - 1) + 1 + p; /* q at p */
415 qabove = q + n; qbelow = q - n;
416 *q++; *q = 0;
417 *qabove++ = 0; *qabove = 0;
418 *qbelow++ = 0; *qbelow = 0;
419 }
420 p_endline = p + n - 2;
421 p++;
422
423 /* done with left edge, now the middle */
424
425 while (1) {
426 if (*p == 0) {
427 /* got a hit, this means we need to clear 8 pixels in the output image */
428 q = (qbase - pbase - 1) + p;
429 qabove = q + n; qbelow = q - n;
430 *q++ = 0; q++; *q++ = 0;
431 *qabove++ = 0; *qabove++ = 0; *qabove++ = 0;
432 *qbelow++ = 0; *qbelow++ = 0; *qbelow++ = 0;
433 if (p >= p_endline) break;
434 p++;
435 /* if we continue to get consecutive hits, just need to clear next 3 */
436 while (*p == 0) {
437 if (p >= p_endline) break;
438 *q++ = 0; *qabove++ = 0; *qbelow++ = 0;
439 p++; }
440 }
441 if (p >= p_endline) break;
442 p++;
443 }
444 p++;
445
446
447 /* the last point in row */
448 if (*p == 0) {
449 q = (qbase - pbase - 1) + p; /* this is the q just before the corresponding p */
450 qabove = q + n; qbelow = q - n;
451 *q = 0;
452 *qabove++ = 0; *qabove++ = 0;
453 *qbelow++ = 0; *qbelow++ = 0;
454 }
455 p++;
456
457 }
458
459 /* at last, the last row */
460 /* left hand edge */
461 if (*p == 0) { /* set 4 points */
462 q = (qbase - pbase - 1) + 1 + p; /* q at p */
463 qbelow = q - n;
464 q++; *q = 0;
465 *qbelow++ = 0; *qbelow = 0;
466 }
467 p_endline = p + n - 2;
468 p++;
469
470 /* now the middle of the last row */
471
472 while (1) {
473 if (*p == 0) {
474 /* got a hit, this means we need to clear 9 pixels in the output image */
475 q = (qbase - pbase - 1) + p;
476 qbelow = q - n;
477 *q++ = 0; q++; *q++ = 0;
478 *qbelow++ = 0; *qbelow++ = 0; *qbelow++ = 0;
479 if (p >= p_endline) break;
480 p++;
481 /* if we continue to get consecutive hits, just need to set next 3 */
482 while (*p == 0) {
483 if (p >= p_endline) break;
484 *q++ = 0; *qbelow++ = 0; p++; }
485 }
486 if (p >= p_endline) break;
487 p++;
488 }
489 p++;
490 /* printf("pbase, p_endline, p = %#x, %#x, %#x\n", pbase, p_endline, p); */
491 /* the last point in last row */
492 /* printf("pbase, p = %#x, %#x\n", pbase, p); */
493 if (*p == 0) {
494 q = (qbase - pbase - 1) + p; /* this is the q just before the corresponding p */
495 qbelow = q - n;
496 *q = 0;
497 *qbelow++ = 0; *qbelow = 0;
498 }
499 // t3 = systime();
500 // printf("AIA erode total time = %10.2f ms, for setup = %10.2f ms, part 2 = %10.2f ms\n",
501 // 1.E3*(t3-t1), 1.E3*(t2-t1), 1.E3*(t3-t2));
502 return 0;
503 }