1 /*******************************************************************************
2
3 License:
4 This software was developed at the National Institute of Standards and
5 Technology (NIST) by employees of the Federal Government in the course
6 of their official duties. Pursuant to title 17 Section 105 of the
7 United States Code, this software is not subject to copyright protection
8 and is in the public domain. NIST assumes no responsibility whatsoever for
9 its use by other parties, and makes no guarantees, expressed or implied,
10 about its quality, reliability, or any other characteristic.
11
12 Disclaimer:
13 This software was developed to promote biometric standards and biometric
14 technology testing for the Federal Government in accordance with the USA
15 PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act.
16 Specific hardware and software products identified in this software were used
17 in order to perform the software development. In no case does such
18 identification imply recommendation or endorsement by the National Institute
19 of Standards and Technology, nor does it imply that the products and equipment
20 identified are necessarily the best available for the purpose.
21
22 *******************************************************************************/
23
24 /***********************************************************************
25 LIBRARY: LFS - NIST Latent Fingerprint System
26
27 FILE: MAPS.C
28 AUTHOR: Michael D. Garris
29 DATE: 03/16/1999
30 UPDATED: 10/04/1999 Version 2 by MDG
31 UPDATED: 10/26/1999 by MDG
32 To permit margin blocks to be flagged in
33 low contrast and low flow maps.
34 UPDATED: 03/16/2005 by MDG
35
36 Contains routines responsible for computing various block-based
37 maps (including directional ridge flow maps) from an arbitrarily-
38 sized image as part of the NIST Latent Fingerprint System (LFS).
39
40 ***********************************************************************
41 ROUTINES:
42 gen_image_maps()
43 gen_initial_maps()
44 interpolate_direction_map()
45 morph_TF_map()
46 pixelize_map()
47 smooth_direction_map()
48 gen_high_curve_map()
49 gen_initial_imap()
50 primary_dir_test()
51 secondary_fork_test()
52 remove_incon_dirs()
53 test_top_edge()
54 test_right_edge()
55 test_bottom_edge()
56 test_left_edge()
57 remove_dir()
58 average_8nbr_dir()
59 num_valid_8nbrs()
60 smooth_imap()
61 vorticity()
62 accum_nbr_vorticity()
63 curvature()
64
65 ***********************************************************************/
66
67 #include <stdio.h>
68 #include <stdlib.h>
69 #include <string.h>
70 #include <lfs.h>
71 #include <morph.h>
72 #include <log.h>
73
74 /*************************************************************************
75 **************************************************************************
76 #cat: gen_image_maps - Computes a set of image maps based on Version 2
77 #cat: of the NIST LFS System. The first map is a Direction Map
78 #cat: which is a 2D vector of integer directions, where each
79 #cat: direction represents the dominant ridge flow in a block of
80 #cat: the input grayscale image. The Low Contrast Map flags
81 #cat: blocks with insufficient contrast. The Low Flow Map flags
82 #cat: blocks with insufficient ridge flow. The High Curve Map
83 #cat: flags blocks containing high curvature. This routine will
84 #cat: generate maps for an arbitrarily sized, non-square, image.
85
86 Input:
87 pdata - padded input image data (8 bits [0..256) grayscale)
88 pw - padded width (in pixels) of the input image
89 ph - padded height (in pixels) of the input image
90 dir2rad - lookup table for converting integer directions
91 dftwaves - structure containing the DFT wave forms
92 dftgrids - structure containing the rotated pixel grid offsets
93 lfsparms - parameters and thresholds for controlling LFS
94 Output:
95 odmap - points to the created Direction Map
96 olcmap - points to the created Low Contrast Map
97 olfmap - points to the Low Ridge Flow Map
98 ohcmap - points to the High Curvature Map
99 omw - width (in blocks) of the maps
100 omh - height (in blocks) of the maps
101 Return Code:
102 Zero - successful completion
103 Negative - system error
104 **************************************************************************/
gen_image_maps(int ** odmap,int ** olcmap,int ** olfmap,int ** ohcmap,int * omw,int * omh,unsigned char * pdata,const int pw,const int ph,const DIR2RAD * dir2rad,const DFTWAVES * dftwaves,const ROTGRIDS * dftgrids,const LFSPARMS * lfsparms)105 int gen_image_maps(int **odmap, int **olcmap, int **olfmap, int **ohcmap,
106 int *omw, int *omh,
107 unsigned char *pdata, const int pw, const int ph,
108 const DIR2RAD *dir2rad, const DFTWAVES *dftwaves,
109 const ROTGRIDS *dftgrids, const LFSPARMS *lfsparms)
110 {
111 int *direction_map, *low_contrast_map, *low_flow_map, *high_curve_map;
112 int mw, mh, iw, ih;
113 int *blkoffs;
114 int ret; /* return code */
115
116 /* 1. Compute block offsets for the entire image, accounting for pad */
117 /* Block_offsets() assumes square block (grid), so ERROR otherwise. */
118 if(dftgrids->grid_w != dftgrids->grid_h){
119 fprintf(stderr,
120 "ERROR : gen_image_maps : DFT grids must be square\n");
121 return(-540);
122 }
123 /* Compute unpadded image dimensions. */
124 iw = pw - (dftgrids->pad<<1);
125 ih = ph - (dftgrids->pad<<1);
126 if((ret = block_offsets(&blkoffs, &mw, &mh, iw, ih,
127 dftgrids->pad, lfsparms->blocksize))){
128 return(ret);
129 }
130
131 /* 2. Generate initial Direction Map and Low Contrast Map*/
132 if((ret = gen_initial_maps(&direction_map, &low_contrast_map,
133 &low_flow_map, blkoffs, mw, mh,
134 pdata, pw, ph, dftwaves, dftgrids, lfsparms))){
135 /* Free memory allocated to this point. */
136 free(blkoffs);
137 return(ret);
138 }
139
140 if((ret = morph_TF_map(low_flow_map, mw, mh, lfsparms))){
141 return(ret);
142 }
143
144 /* 3. Remove directions that are inconsistent with neighbors */
145 remove_incon_dirs(direction_map, mw, mh, dir2rad, lfsparms);
146
147
148 /* 4. Smooth Direction Map values with their neighbors */
149 smooth_direction_map(direction_map, low_contrast_map, mw, mh,
150 dir2rad, lfsparms);
151
152 /* 5. Interpolate INVALID direction blocks with their valid neighbors. */
153 if((ret = interpolate_direction_map(direction_map, low_contrast_map,
154 mw, mh, lfsparms))){
155 return(ret);
156 }
157
158 /* May be able to skip steps 6 and/or 7 if computation time */
159 /* is a critical factor. */
160
161 /* 6. Remove directions that are inconsistent with neighbors */
162 remove_incon_dirs(direction_map, mw, mh, dir2rad, lfsparms);
163
164 /* 7. Smooth Direction Map values with their neighbors. */
165 smooth_direction_map(direction_map, low_contrast_map, mw, mh,
166 dir2rad, lfsparms);
167
168 /* 8. Set the Direction Map values in the image margin to INVALID. */
169 set_margin_blocks(direction_map, mw, mh, INVALID_DIR);
170
171 /* 9. Generate High Curvature Map from interpolated Direction Map. */
172 if((ret = gen_high_curve_map(&high_curve_map, direction_map, mw, mh,
173 lfsparms))){
174 return(ret);
175 }
176
177 /* Deallocate working memory. */
178 free(blkoffs);
179
180 *odmap = direction_map;
181 *olcmap = low_contrast_map;
182 *olfmap = low_flow_map;
183 *ohcmap = high_curve_map;
184 *omw = mw;
185 *omh = mh;
186 return(0);
187 }
188
189 /*************************************************************************
190 **************************************************************************
191 #cat: gen_initial_maps - Creates an initial Direction Map from the given
192 #cat: input image. It very important that the image be properly
193 #cat: padded so that rotated grids along the boundary of the image
194 #cat: do not access unkown memory. The rotated grids are used by a
195 #cat: DFT-based analysis to determine the integer directions
196 #cat: in the map. Typically this initial vector of directions will
197 #cat: subsequently have weak or inconsistent directions removed
198 #cat: followed by a smoothing process. The resulting Direction
199 #cat: Map contains valid directions >= 0 and INVALID values = -1.
200 #cat: This routine also computes and returns 2 other image maps.
201 #cat: The Low Contrast Map flags blocks in the image with
202 #cat: insufficient contrast. Blocks with low contrast have a
203 #cat: corresponding direction of INVALID in the Direction Map.
204 #cat: The Low Flow Map flags blocks in which the DFT analyses
205 #cat: could not determine a significant ridge flow. Blocks with
206 #cat: low ridge flow also have a corresponding direction of
207 #cat: INVALID in the Direction Map.
208
209 Input:
210 blkoffs - offsets to the pixel origin of each block in the padded image
211 mw - number of blocks horizontally in the padded input image
212 mh - number of blocks vertically in the padded input image
213 pdata - padded input image data (8 bits [0..256) grayscale)
214 pw - width (in pixels) of the padded input image
215 ph - height (in pixels) of the padded input image
216 dftwaves - structure containing the DFT wave forms
217 dftgrids - structure containing the rotated pixel grid offsets
218 lfsparms - parameters and thresholds for controlling LFS
219 Output:
220 odmap - points to the newly created Direction Map
221 olcmap - points to the newly created Low Contrast Map
222 Return Code:
223 Zero - successful completion
224 Negative - system error
225 **************************************************************************/
gen_initial_maps(int ** odmap,int ** olcmap,int ** olfmap,int * blkoffs,const int mw,const int mh,unsigned char * pdata,const int pw,const int ph,const DFTWAVES * dftwaves,const ROTGRIDS * dftgrids,const LFSPARMS * lfsparms)226 int gen_initial_maps(int **odmap, int **olcmap, int **olfmap,
227 int *blkoffs, const int mw, const int mh,
228 unsigned char *pdata, const int pw, const int ph,
229 const DFTWAVES *dftwaves, const ROTGRIDS *dftgrids,
230 const LFSPARMS *lfsparms)
231 {
232 int *direction_map, *low_contrast_map, *low_flow_map;
233 int bi, bsize, blkdir;
234 int *wis, *powmax_dirs;
235 double **powers, *powmaxs, *pownorms;
236 int nstats;
237 int ret; /* return code */
238 int dft_offset;
239 int xminlimit, xmaxlimit, yminlimit, ymaxlimit;
240 int win_x, win_y, low_contrast_offset;
241
242 print2log("INITIAL MAP\n");
243
244 /* Compute total number of blocks in map */
245 bsize = mw * mh;
246
247 /* Allocate Direction Map memory */
248 direction_map = (int *)malloc(bsize * sizeof(int));
249 if(direction_map == (int *)NULL){
250 fprintf(stderr,
251 "ERROR : gen_initial_maps : malloc : direction_map\n");
252 return(-550);
253 }
254 /* Initialize the Direction Map to INVALID (-1). */
255 memset(direction_map, INVALID_DIR, bsize * sizeof(int));
256
257 /* Allocate Low Contrast Map memory */
258 low_contrast_map = (int *)malloc(bsize * sizeof(int));
259 if(low_contrast_map == (int *)NULL){
260 free(direction_map);
261 fprintf(stderr,
262 "ERROR : gen_initial_maps : malloc : low_contrast_map\n");
263 return(-551);
264 }
265 /* Initialize the Low Contrast Map to FALSE (0). */
266 memset(low_contrast_map, 0, bsize * sizeof(int));
267
268 /* Allocate Low Ridge Flow Map memory */
269 low_flow_map = (int *)malloc(bsize * sizeof(int));
270 if(low_flow_map == (int *)NULL){
271 free(direction_map);
272 free(low_contrast_map);
273 fprintf(stderr,
274 "ERROR : gen_initial_maps : malloc : low_flow_map\n");
275 return(-552);
276 }
277 /* Initialize the Low Flow Map to FALSE (0). */
278 memset(low_flow_map, 0, bsize * sizeof(int));
279
280 /* Allocate DFT directional power vectors */
281 if((ret = alloc_dir_powers(&powers, dftwaves->nwaves, dftgrids->ngrids))){
282 /* Free memory allocated to this point. */
283 free(direction_map);
284 free(low_contrast_map);
285 free(low_flow_map);
286 return(ret);
287 }
288
289 /* Allocate DFT power statistic arrays */
290 /* Compute length of statistics arrays. Statistics not needed */
291 /* for the first DFT wave, so the length is number of waves - 1. */
292 nstats = dftwaves->nwaves - 1;
293 if((ret = alloc_power_stats(&wis, &powmaxs, &powmax_dirs,
294 &pownorms, nstats))){
295 /* Free memory allocated to this point. */
296 free(direction_map);
297 free(low_contrast_map);
298 free(low_flow_map);
299 free_dir_powers(powers, dftwaves->nwaves);
300 return(ret);
301 }
302
303 /* Compute special window origin limits for determining low contrast. */
304 /* These pixel limits avoid analyzing the padded borders of the image. */
305 xminlimit = dftgrids->pad;
306 yminlimit = dftgrids->pad;
307 xmaxlimit = pw - dftgrids->pad - lfsparms->windowsize - 1;
308 ymaxlimit = ph - dftgrids->pad - lfsparms->windowsize - 1;
309
310 /* max limits should not be negative */
311 xmaxlimit = MAX(xmaxlimit, 0);
312 ymaxlimit = MAX(ymaxlimit, 0);
313
314 /* Foreach block in image ... */
315 for(bi = 0; bi < bsize; bi++){
316 /* Adjust block offset from pointing to block origin to pointing */
317 /* to surrounding window origin. */
318 dft_offset = blkoffs[bi] - (lfsparms->windowoffset * pw) -
319 lfsparms->windowoffset;
320
321 /* Compute pixel coords of window origin. */
322 win_x = dft_offset % pw;
323 win_y = (int)(dft_offset / pw);
324
325 /* Make sure the current window does not access padded image pixels */
326 /* for analyzing low contrast. */
327 win_x = max(xminlimit, win_x);
328 win_x = min(xmaxlimit, win_x);
329 win_y = max(yminlimit, win_y);
330 win_y = min(ymaxlimit, win_y);
331 low_contrast_offset = (win_y * pw) + win_x;
332
333 print2log(" BLOCK %2d (%2d, %2d) ", bi, bi%mw, bi/mw);
334
335 /* If block is low contrast ... */
336 if((ret = low_contrast_block(low_contrast_offset, lfsparms->windowsize,
337 pdata, pw, ph, lfsparms))){
338 /* If system error ... */
339 if(ret < 0){
340 free(direction_map);
341 free(low_contrast_map);
342 free(low_flow_map);
343 free_dir_powers(powers, dftwaves->nwaves);
344 free(wis);
345 free(powmaxs);
346 free(powmax_dirs);
347 free(pownorms);
348 return(ret);
349 }
350
351 /* Otherwise, block is low contrast ... */
352 print2log("LOW CONTRAST\n");
353 low_contrast_map[bi] = TRUE;
354 /* Direction Map's block is already set to INVALID. */
355 }
356 /* Otherwise, sufficient contrast for DFT processing ... */
357 else {
358 print2log("\n");
359
360 /* Compute DFT powers */
361 if((ret = dft_dir_powers(powers, pdata, low_contrast_offset, pw, ph,
362 dftwaves, dftgrids))){
363 /* Free memory allocated to this point. */
364 free(direction_map);
365 free(low_contrast_map);
366 free(low_flow_map);
367 free_dir_powers(powers, dftwaves->nwaves);
368 free(wis);
369 free(powmaxs);
370 free(powmax_dirs);
371 free(pownorms);
372 return(ret);
373 }
374
375 /* Compute DFT power statistics, skipping first applied DFT */
376 /* wave. This is dependent on how the primary and secondary */
377 /* direction tests work below. */
378 if((ret = dft_power_stats(wis, powmaxs, powmax_dirs, pownorms, powers,
379 1, dftwaves->nwaves, dftgrids->ngrids))){
380 /* Free memory allocated to this point. */
381 free(direction_map);
382 free(low_contrast_map);
383 free(low_flow_map);
384 free_dir_powers(powers, dftwaves->nwaves);
385 free(wis);
386 free(powmaxs);
387 free(powmax_dirs);
388 free(pownorms);
389 return(ret);
390 }
391
392 #ifdef LOG_REPORT /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
393 { int _w;
394 fprintf(logfp, " Power\n");
395 for(_w = 0; _w < nstats; _w++){
396 /* Add 1 to wis[w] to create index to original dft_coefs[] */
397 fprintf(logfp, " wis[%d] %d %12.3f %2d %9.3f %12.3f\n",
398 _w, wis[_w]+1,
399 powmaxs[wis[_w]], powmax_dirs[wis[_w]], pownorms[wis[_w]],
400 powers[0][powmax_dirs[wis[_w]]]);
401 }
402 }
403 #endif /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
404
405 /* Conduct primary direction test */
406 blkdir = primary_dir_test(powers, wis, powmaxs, powmax_dirs,
407 pownorms, nstats, lfsparms);
408
409 if(blkdir != INVALID_DIR)
410 direction_map[bi] = blkdir;
411 else{
412 /* Conduct secondary (fork) direction test */
413 blkdir = secondary_fork_test(powers, wis, powmaxs, powmax_dirs,
414 pownorms, nstats, lfsparms);
415 if(blkdir != INVALID_DIR)
416 direction_map[bi] = blkdir;
417 /* Otherwise current direction in Direction Map remains INVALID */
418 else
419 /* Flag the block as having LOW RIDGE FLOW. */
420 low_flow_map[bi] = TRUE;
421 }
422
423 } /* End DFT */
424 } /* bi */
425
426 /* Deallocate working memory */
427 free_dir_powers(powers, dftwaves->nwaves);
428 free(wis);
429 free(powmaxs);
430 free(powmax_dirs);
431 free(pownorms);
432
433 *odmap = direction_map;
434 *olcmap = low_contrast_map;
435 *olfmap = low_flow_map;
436 return(0);
437 }
438
439 /*************************************************************************
440 **************************************************************************
441 #cat: interpolate_direction_map - Take a Direction Map and Low Contrast
442 #cat: Map and attempts to fill in INVALID directions in the
443 #cat: Direction Map based on a blocks valid neighbors. The
444 #cat: valid neighboring directions are combined in a weighted
445 #cat: average inversely proportional to their distance from
446 #cat: the block being interpolated. Low Contrast blocks are
447 #cat: used to prempt the search for a valid neighbor in a
448 #cat: specific direction, which keeps the process from
449 #cat: interpolating directions for blocks in the background and
450 #cat: and perimeter of the fingerprint in the image.
451
452 Input:
453 direction_map - map of blocks containing directional ridge flow
454 low_contrast_map - map of blocks flagged as LOW CONTRAST
455 mw - number of blocks horizontally in the maps
456 mh - number of blocks vertically in the maps
457 lfsparms - parameters and thresholds for controlling LFS
458 Output:
459 direction_map - contains the newly interpolated results
460 Return Code:
461 Zero - successful completion
462 Negative - system error
463 **************************************************************************/
interpolate_direction_map(int * direction_map,int * low_contrast_map,const int mw,const int mh,const LFSPARMS * lfsparms)464 int interpolate_direction_map(int *direction_map, int *low_contrast_map,
465 const int mw, const int mh, const LFSPARMS *lfsparms)
466 {
467 int x, y, new_dir;
468 int n_dir, e_dir, s_dir, w_dir;
469 int n_dist = 0, e_dist = 0, s_dist = 0, w_dist = 0, total_dist;
470 int n_found, e_found, s_found, w_found, total_found;
471 int n_delta = 0, e_delta = 0, s_delta = 0, w_delta = 0, total_delta;
472 int nbr_x, nbr_y;
473 int *omap, *dptr, *cptr, *optr;
474 double avr_dir;
475
476 print2log("INTERPOLATE DIRECTION MAP\n");
477
478 /* Allocate output (interpolated) Direction Map. */
479 omap = (int *)malloc(mw*mh*sizeof(int));
480 if(omap == (int *)NULL){
481 fprintf(stderr,
482 "ERROR : interpolate_direction_map : malloc : omap\n");
483 return(-520);
484 }
485
486 /* Set pointers to the first block in the maps. */
487 dptr = direction_map;
488 cptr = low_contrast_map;
489 optr = omap;
490
491 /* Foreach block in the maps ... */
492 for(y = 0; y < mh; y++){
493 for(x = 0; x < mw; x++){
494
495 /* If image block is NOT LOW CONTRAST and has INVALID direction ... */
496 if((!*cptr) && (*dptr == INVALID_DIR)){
497
498 /* Set neighbor accumulators to 0. */
499 total_found = 0;
500 total_dist = 0;
501
502 /* Find north neighbor. */
503 if((n_found = find_valid_block(&n_dir, &nbr_x, &nbr_y,
504 direction_map, low_contrast_map,
505 x, y, mw, mh, 0, -1)) == FOUND){
506 /* Compute north distance. */
507 n_dist = y - nbr_y;
508 /* Accumulate neighbor distance. */
509 total_dist += n_dist;
510 /* Bump number of neighbors found. */
511 total_found++;
512 }
513
514 /* Find east neighbor. */
515 if((e_found = find_valid_block(&e_dir, &nbr_x, &nbr_y,
516 direction_map, low_contrast_map,
517 x, y, mw, mh, 1, 0)) == FOUND){
518 /* Compute east distance. */
519 e_dist = nbr_x - x;
520 /* Accumulate neighbor distance. */
521 total_dist += e_dist;
522 /* Bump number of neighbors found. */
523 total_found++;
524 }
525
526 /* Find south neighbor. */
527 if((s_found = find_valid_block(&s_dir, &nbr_x, &nbr_y,
528 direction_map, low_contrast_map,
529 x, y, mw, mh, 0, 1)) == FOUND){
530 /* Compute south distance. */
531 s_dist = nbr_y - y;
532 /* Accumulate neighbor distance. */
533 total_dist += s_dist;
534 /* Bump number of neighbors found. */
535 total_found++;
536 }
537
538 /* Find west neighbor. */
539 if((w_found = find_valid_block(&w_dir, &nbr_x, &nbr_y,
540 direction_map, low_contrast_map,
541 x, y, mw, mh, -1, 0)) == FOUND){
542 /* Compute west distance. */
543 w_dist = x - nbr_x;
544 /* Accumulate neighbor distance. */
545 total_dist += w_dist;
546 /* Bump number of neighbors found. */
547 total_found++;
548 }
549
550 /* If a sufficient number of neighbors found (Ex. 2) ... */
551 if(total_found >= lfsparms->min_interpolate_nbrs){
552
553 /* Accumulate weighted sum of neighboring directions */
554 /* inversely related to the distance from current block. */
555 total_delta = 0.0;
556 /* If neighbor found to the north ... */
557 if(n_found){
558 n_delta = total_dist - n_dist;
559 total_delta += n_delta;
560 }
561 /* If neighbor found to the east ... */
562 if(e_found){
563 e_delta = total_dist - e_dist;
564 total_delta += e_delta;
565 }
566 /* If neighbor found to the south ... */
567 if(s_found){
568 s_delta = total_dist - s_dist;
569 total_delta += s_delta;
570 }
571 /* If neighbor found to the west ... */
572 if(w_found){
573 w_delta = total_dist - w_dist;
574 total_delta += w_delta;
575 }
576
577 avr_dir = 0.0;
578
579 if(n_found){
580 avr_dir += (n_dir*(n_delta/(double)total_delta));
581 }
582 if(e_found){
583 avr_dir += (e_dir*(e_delta/(double)total_delta));
584 }
585 if(s_found){
586 avr_dir += (s_dir*(s_delta/(double)total_delta));
587 }
588 if(w_found){
589 avr_dir += (w_dir*(w_delta/(double)total_delta));
590 }
591
592 /* Need to truncate precision so that answers are consistent */
593 /* on different computer architectures when rounding doubles. */
594 avr_dir = trunc_dbl_precision(avr_dir, TRUNC_SCALE);
595
596 /* Assign interpolated direction to output Direction Map. */
597 new_dir = sround(avr_dir);
598
599 print2log(" Block %d,%d INTERP numnbs=%d newdir=%d\n",
600 x, y, total_found, new_dir);
601
602 *optr = new_dir;
603 }
604 else{
605 /* Otherwise, the direction remains INVALID. */
606 *optr = *dptr;
607 }
608 }
609 else{
610 /* Otherwise, assign the current direction to the output block. */
611 *optr = *dptr;
612 }
613
614 /* Bump to the next block in the maps ... */
615 dptr++;
616 cptr++;
617 optr++;
618 }
619 }
620
621 /* Copy the interpolated directions into the input map. */
622 memcpy(direction_map, omap, mw*mh*sizeof(int));
623 /* Deallocate the working memory. */
624 free(omap);
625
626 /* Return normally. */
627 return(0);
628 }
629
630 /*************************************************************************
631 **************************************************************************
632 #cat: morph_tf_map - Takes a 2D vector of TRUE and FALSE values integers
633 #cat: and dialates and erodes the map in an attempt to fill
634 #cat: in voids in the map.
635
636 Input:
637 tfmap - vector of integer block values
638 mw - width (in blocks) of the map
639 mh - height (in blocks) of the map
640 lfsparms - parameters and thresholds for controlling LFS
641 Output:
642 tfmap - resulting morphed map
643 **************************************************************************/
morph_TF_map(int * tfmap,const int mw,const int mh,const LFSPARMS * lfsparms)644 int morph_TF_map(int *tfmap, const int mw, const int mh,
645 const LFSPARMS *lfsparms)
646 {
647 unsigned char *cimage, *mimage, *cptr;
648 int *mptr;
649 int i;
650
651
652 /* Convert TRUE/FALSE map into a binary byte image. */
653 cimage = (unsigned char *)malloc(mw*mh);
654 if(cimage == (unsigned char *)NULL){
655 fprintf(stderr, "ERROR : morph_TF_map : malloc : cimage\n");
656 return(-660);
657 }
658
659 mimage = (unsigned char *)malloc(mw*mh);
660 if(mimage == (unsigned char *)NULL){
661 fprintf(stderr, "ERROR : morph_TF_map : malloc : mimage\n");
662 return(-661);
663 }
664
665 cptr = cimage;
666 mptr = tfmap;
667 for(i = 0; i < mw*mh; i++){
668 *cptr++ = *mptr++;
669 }
670
671 dilate_charimage_2(cimage, mimage, mw, mh);
672 dilate_charimage_2(mimage, cimage, mw, mh);
673 erode_charimage_2(cimage, mimage, mw, mh);
674 erode_charimage_2(mimage, cimage, mw, mh);
675
676 cptr = cimage;
677 mptr = tfmap;
678 for(i = 0; i < mw*mh; i++){
679 *mptr++ = *cptr++;
680 }
681
682 free(cimage);
683 free(mimage);
684
685 return(0);
686 }
687
688 /*************************************************************************
689 **************************************************************************
690 #cat: pixelize_map - Takes a block image map and assigns each pixel in the
691 #cat: image its corresponding block value. This allows block
692 #cat: values in maps to be directly accessed via pixel addresses.
693
694 Input:
695 iw - the width (in pixels) of the corresponding image
696 ih - the height (in pixels) of the corresponding image
697 imap - input block image map
698 mw - the width (in blocks) of the map
699 mh - the height (in blocks) of the map
700 blocksize - the dimension (in pixels) of each block
701 Output:
702 omap - points to the resulting pixelized map
703 Return Code:
704 Zero - successful completion
705 Negative - system error
706 **************************************************************************/
pixelize_map(int ** omap,const int iw,const int ih,int * imap,const int mw,const int mh,const int blocksize)707 int pixelize_map(int **omap, const int iw, const int ih,
708 int *imap, const int mw, const int mh, const int blocksize)
709 {
710 int *pmap;
711 int ret, x, y;
712 int *blkoffs, bw, bh, bi;
713 int *spptr, *pptr;
714
715 pmap = (int *)malloc(iw*ih*sizeof(int));
716 if(pmap == (int *)NULL){
717 fprintf(stderr, "ERROR : pixelize_map : malloc : pmap\n");
718 return(-590);
719 }
720
721 if((ret = block_offsets(&blkoffs, &bw, &bh, iw, ih, 0, blocksize))){
722 return(ret);
723 }
724
725 if((bw != mw) || (bh != mh)){
726 free(blkoffs);
727 fprintf(stderr,
728 "ERROR : pixelize_map : block dimensions do not match\n");
729 return(-591);
730 }
731
732 for(bi = 0; bi < mw*mh; bi++){
733 spptr = pmap + blkoffs[bi];
734 for(y = 0; y < blocksize; y++){
735 pptr = spptr;
736 for(x = 0; x < blocksize; x++){
737 *pptr++ = imap[bi];
738 }
739 spptr += iw;
740 }
741 }
742
743 /* Deallocate working memory. */
744 free(blkoffs);
745 /* Assign pixelized map to output pointer. */
746 *omap = pmap;
747
748 /* Return normally. */
749 return(0);
750 }
751
752 /*************************************************************************
753 **************************************************************************
754 #cat: smooth_direction_map - Takes a vector of integer directions and smooths
755 #cat: them by analyzing the direction of adjacent neighbors.
756
757 Input:
758 direction_map - vector of integer block values
759 mw - width (in blocks) of the map
760 mh - height (in blocks) of the map
761 dir2rad - lookup table for converting integer directions
762 lfsparms - parameters and thresholds for controlling LFS
763 Output:
764 imap - vector of smoothed input values
765 **************************************************************************/
smooth_direction_map(int * direction_map,int * low_contrast_map,const int mw,const int mh,const DIR2RAD * dir2rad,const LFSPARMS * lfsparms)766 void smooth_direction_map(int *direction_map, int *low_contrast_map,
767 const int mw, const int mh,
768 const DIR2RAD *dir2rad, const LFSPARMS *lfsparms)
769 {
770 int mx, my;
771 int *dptr, *cptr;
772 int avrdir, nvalid;
773 double dir_strength;
774
775 print2log("SMOOTH DIRECTION MAP\n");
776
777 /* Assign pointers to beginning of both maps. */
778 dptr = direction_map;
779 cptr = low_contrast_map;
780
781 /* Foreach block in maps ... */
782 for(my = 0; my < mh; my++){
783 for(mx = 0; mx < mw; mx++){
784 /* If the current block does NOT have LOW CONTRAST ... */
785 if(!*cptr){
786
787 /* Compute average direction from neighbors, returning the */
788 /* number of valid neighbors used in the computation, and */
789 /* the "strength" of the average direction. */
790 average_8nbr_dir(&avrdir, &dir_strength, &nvalid,
791 direction_map, mx, my, mw, mh, dir2rad);
792
793 /* If average direction strength is strong enough */
794 /* (Ex. thresh==0.2)... */
795 if(dir_strength >= lfsparms->dir_strength_min){
796 /* If Direction Map direction is valid ... */
797 if(*dptr != INVALID_DIR){
798 /* Conduct valid neighbor test (Ex. thresh==3)... */
799 if(nvalid >= lfsparms->rmv_valid_nbr_min){
800
801 #ifdef LOG_REPORT /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
802 fprintf(logfp, " BLOCK %2d (%2d, %2d)\n",
803 mx+(my*mw), mx, my);
804 fprintf(logfp, " Average NBR : %2d %6.3f %d\n",
805 avrdir, dir_strength, nvalid);
806 fprintf(logfp, " 1. Valid NBR (%d >= %d)\n",
807 nvalid, lfsparms->rmv_valid_nbr_min);
808 fprintf(logfp, " Valid Direction = %d\n", *dptr);
809 fprintf(logfp, " Smoothed Direction = %d\n", avrdir);
810 #endif /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
811
812 /* Reassign valid direction with average direction. */
813 *dptr = avrdir;
814 }
815 }
816 /* Otherwise direction is invalid ... */
817 else{
818 /* Even if DIRECTION_MAP value is invalid, if number of */
819 /* valid neighbors is big enough (Ex. thresh==7)... */
820 if(nvalid >= lfsparms->smth_valid_nbr_min){
821
822 #ifdef LOG_REPORT /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
823 fprintf(logfp, " BLOCK %2d (%2d, %2d)\n",
824 mx+(my*mw), mx, my);
825 fprintf(logfp, " Average NBR : %2d %6.3f %d\n",
826 avrdir, dir_strength, nvalid);
827 fprintf(logfp, " 2. Invalid NBR (%d >= %d)\n",
828 nvalid, lfsparms->smth_valid_nbr_min);
829 fprintf(logfp, " Invalid Direction = %d\n", *dptr);
830 fprintf(logfp, " Smoothed Direction = %d\n", avrdir);
831 #endif /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
832
833 /* Assign invalid direction with average direction. */
834 *dptr = avrdir;
835 }
836 }
837 }
838 }
839 /* Otherwise, block has LOW CONTRAST, so keep INVALID direction. */
840
841 /* Bump to next block in maps. */
842 dptr++;
843 cptr++;
844 }
845 }
846 }
847
848 /*************************************************************************
849 **************************************************************************
850 #cat: gen_high_curve_map - Takes a Direction Map and generates a new map
851 #cat: that flags blocks with HIGH CURVATURE.
852
853 Input:
854 direction_map - map of blocks containing directional ridge flow
855 mw - the width (in blocks) of the map
856 mh - the height (in blocks) of the map
857 lfsparms - parameters and thresholds for controlling LFS
858 Output:
859 ohcmap - points to the created High Curvature Map
860 Return Code:
861 Zero - successful completion
862 Negative - system error
863 **************************************************************************/
gen_high_curve_map(int ** ohcmap,int * direction_map,const int mw,const int mh,const LFSPARMS * lfsparms)864 int gen_high_curve_map(int **ohcmap, int *direction_map,
865 const int mw, const int mh, const LFSPARMS *lfsparms)
866 {
867 int *high_curve_map, mapsize;
868 int *hptr, *dptr;
869 int bx, by;
870 int nvalid, cmeasure, vmeasure;
871
872 mapsize = mw*mh;
873
874 /* Allocate High Curvature Map. */
875 high_curve_map = (int *)malloc(mapsize * sizeof(int));
876 if(high_curve_map == (int *)NULL){
877 fprintf(stderr,
878 "ERROR: gen_high_curve_map : malloc : high_curve_map\n");
879 return(-530);
880 }
881 /* Initialize High Curvature Map to FALSE (0). */
882 memset(high_curve_map, 0, mapsize*sizeof(int));
883
884 hptr = high_curve_map;
885 dptr = direction_map;
886
887 /* Foreach row in maps ... */
888 for(by = 0; by < mh; by++){
889 /* Foreach column in maps ... */
890 for(bx = 0; bx < mw; bx++){
891
892 /* Count number of valid neighbors around current block ... */
893 nvalid = num_valid_8nbrs(direction_map, bx, by, mw, mh);
894
895 /* If valid neighbors exist ... */
896 if(nvalid > 0){
897 /* If current block's direction is INVALID ... */
898 if(*dptr == INVALID_DIR){
899 /* If a sufficient number of VALID neighbors exists ... */
900 if(nvalid >= lfsparms->vort_valid_nbr_min){
901 /* Measure vorticity of neighbors. */
902 vmeasure = vorticity(direction_map, bx, by, mw, mh,
903 lfsparms->num_directions);
904 /* If vorticity is sufficiently high ... */
905 if(vmeasure >= lfsparms->highcurv_vorticity_min)
906 /* Flag block as HIGH CURVATURE. */
907 *hptr = TRUE;
908 }
909 }
910 /* Otherwise block has valid direction ... */
911 else{
912 /* Measure curvature around the valid block. */
913 cmeasure = curvature(direction_map, bx, by, mw, mh,
914 lfsparms->num_directions);
915 /* If curvature is sufficiently high ... */
916 if(cmeasure >= lfsparms->highcurv_curvature_min)
917 *hptr = TRUE;
918 }
919 } /* Else (nvalid <= 0) */
920
921 /* Bump pointers to next block in maps. */
922 dptr++;
923 hptr++;
924
925 } /* bx */
926 } /* by */
927
928 /* Assign High Curvature Map to output pointer. */
929 *ohcmap = high_curve_map;
930
931 /* Return normally. */
932 return(0);
933 }
934
935 /*************************************************************************
936 **************************************************************************
937 #cat: gen_initial_imap - Creates an initial IMAP from the given input image.
938 #cat: It very important that the image be properly padded so
939 #cat: that rotated grids along the boudary of the image do not
940 #cat: access unkown memory. The rotated grids are used by a
941 #cat: DFT-based analysis to determine the integer directions
942 #cat: in the IMAP. Typically this initial vector of directions will
943 #cat: subsequently have weak or inconsistent directions removed
944 #cat: followed by a smoothing process.
945
946 Input:
947 blkoffs - offsets to the pixel origin of each block in the padded image
948 mw - number of blocks horizontally in the padded input image
949 mh - number of blocks vertically in the padded input image
950 pdata - padded input image data (8 bits [0..256) grayscale)
951 pw - width (in pixels) of the padded input image
952 ph - height (in pixels) of the padded input image
953 dftwaves - structure containing the DFT wave forms
954 dftgrids - structure containing the rotated pixel grid offsets
955 lfsparms - parameters and thresholds for controlling LFS
956 Output:
957 optr - points to the newly created IMAP
958 Return Code:
959 Zero - successful completion
960 Negative - system error
961 **************************************************************************/
gen_initial_imap(int ** optr,int * blkoffs,const int mw,const int mh,unsigned char * pdata,const int pw,const int ph,const DFTWAVES * dftwaves,const ROTGRIDS * dftgrids,const LFSPARMS * lfsparms)962 int gen_initial_imap(int **optr, int *blkoffs, const int mw, const int mh,
963 unsigned char *pdata, const int pw, const int ph,
964 const DFTWAVES *dftwaves, const ROTGRIDS *dftgrids,
965 const LFSPARMS *lfsparms)
966 {
967 int *imap;
968 int bi, bsize, blkdir;
969 int *wis, *powmax_dirs;
970 double **powers, *powmaxs, *pownorms;
971 int nstats;
972 int ret; /* return code */
973
974 print2log("INITIAL MAP\n");
975
976 /* Compute total number of blocks in IMAP */
977 bsize = mw * mh;
978
979 /* Allocate IMAP memory */
980 imap = (int *)malloc(bsize * sizeof(int));
981 if(imap == (int *)NULL){
982 fprintf(stderr, "ERROR : gen_initial_imap : malloc : imap\n");
983 return(-70);
984 }
985
986 /* Allocate DFT directional power vectors */
987 if((ret = alloc_dir_powers(&powers, dftwaves->nwaves, dftgrids->ngrids))){
988 /* Free memory allocated to this point. */
989 free(imap);
990 return(ret);
991 }
992
993 /* Allocate DFT power statistic arrays */
994 /* Compute length of statistics arrays. Statistics not needed */
995 /* for the first DFT wave, so the length is number of waves - 1. */
996 nstats = dftwaves->nwaves - 1;
997 if((ret = alloc_power_stats(&wis, &powmaxs, &powmax_dirs,
998 &pownorms, nstats))){
999 /* Free memory allocated to this point. */
1000 free(imap);
1001 free_dir_powers(powers, dftwaves->nwaves);
1002 return(ret);
1003 }
1004
1005 /* Initialize the imap to -1 */
1006 memset(imap, INVALID_DIR, bsize * sizeof(int));
1007
1008 /* Foreach block in imap ... */
1009 for(bi = 0; bi < bsize; bi++){
1010
1011 print2log(" BLOCK %2d (%2d, %2d)\n", bi, bi%mw, bi/mw);
1012
1013 /* Compute DFT powers */
1014 if((ret = dft_dir_powers(powers, pdata, blkoffs[bi], pw, ph,
1015 dftwaves, dftgrids))){
1016 /* Free memory allocated to this point. */
1017 free(imap);
1018 free_dir_powers(powers, dftwaves->nwaves);
1019 free(wis);
1020 free(powmaxs);
1021 free(powmax_dirs);
1022 free(pownorms);
1023 return(ret);
1024 }
1025
1026 /* Compute DFT power statistics, skipping first applied DFT */
1027 /* wave. This is dependent on how the primary and secondary */
1028 /* direction tests work below. */
1029 if((ret = dft_power_stats(wis, powmaxs, powmax_dirs, pownorms, powers,
1030 1, dftwaves->nwaves, dftgrids->ngrids))){
1031 /* Free memory allocated to this point. */
1032 free(imap);
1033 free_dir_powers(powers, dftwaves->nwaves);
1034 free(wis);
1035 free(powmaxs);
1036 free(powmax_dirs);
1037 free(pownorms);
1038 return(ret);
1039 }
1040
1041 #ifdef LOG_REPORT /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
1042 { int _w;
1043 fprintf(logfp, " Power\n");
1044 for(_w = 0; _w < nstats; _w++){
1045 /* Add 1 to wis[w] to create index to original dft_coefs[] */
1046 fprintf(logfp, " wis[%d] %d %12.3f %2d %9.3f %12.3f\n",
1047 _w, wis[_w]+1,
1048 powmaxs[wis[_w]], powmax_dirs[wis[_w]], pownorms[wis[_w]],
1049 powers[0][powmax_dirs[wis[_w]]]);
1050 }
1051 }
1052 #endif /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
1053
1054 /* Conduct primary direction test */
1055 blkdir = primary_dir_test(powers, wis, powmaxs, powmax_dirs,
1056 pownorms, nstats, lfsparms);
1057
1058 if(blkdir != INVALID_DIR)
1059 imap[bi] = blkdir;
1060 else{
1061 /* Conduct secondary (fork) direction test */
1062 blkdir = secondary_fork_test(powers, wis, powmaxs, powmax_dirs,
1063 pownorms, nstats, lfsparms);
1064 if(blkdir != INVALID_DIR)
1065 imap[bi] = blkdir;
1066 }
1067
1068 /* Otherwise current block direction in IMAP remains INVALID */
1069
1070 } /* bi */
1071
1072 /* Deallocate working memory */
1073 free_dir_powers(powers, dftwaves->nwaves);
1074 free(wis);
1075 free(powmaxs);
1076 free(powmax_dirs);
1077 free(pownorms);
1078
1079 *optr = imap;
1080 return(0);
1081 }
1082
1083 /*************************************************************************
1084 **************************************************************************
1085 #cat: primary_dir_test - Applies the primary set of criteria for selecting
1086 #cat: an IMAP integer direction from a set of DFT results
1087 #cat: computed from a block of image data
1088
1089 Input:
1090 powers - DFT power computed from each (N) wave frequencies at each
1091 rotation direction in the current image block
1092 wis - sorted order of the highest N-1 frequency power statistics
1093 powmaxs - maximum power for each of the highest N-1 frequencies
1094 powmax_dirs - directions associated with each of the N-1 maximum powers
1095 pownorms - normalized power for each of the highest N-1 frequencies
1096 nstats - N-1 wave frequencies (where N is the length of dft_coefs)
1097 lfsparms - parameters and thresholds for controlling LFS
1098 Return Code:
1099 Zero or Positive - The selected IMAP integer direction
1100 INVALID_DIR - IMAP Integer direction could not be determined
1101 **************************************************************************/
primary_dir_test(double ** powers,const int * wis,const double * powmaxs,const int * powmax_dirs,const double * pownorms,const int nstats,const LFSPARMS * lfsparms)1102 int primary_dir_test(double **powers, const int *wis,
1103 const double *powmaxs, const int *powmax_dirs,
1104 const double *pownorms, const int nstats,
1105 const LFSPARMS *lfsparms)
1106 {
1107 int w;
1108
1109 print2log(" Primary\n");
1110
1111 /* Look at max power statistics in decreasing order ... */
1112 for(w = 0; w < nstats; w++){
1113 /* 1. Test magnitude of current max power (Ex. Thresh==100000) */
1114 if((powmaxs[wis[w]] > lfsparms->powmax_min) &&
1115 /* 2. Test magnitude of normalized max power (Ex. Thresh==3.8) */
1116 (pownorms[wis[w]] > lfsparms->pownorm_min) &&
1117 /* 3. Test magnitude of power of lowest DFT frequency at current */
1118 /* max power direction and make sure it is not too big. */
1119 /* (Ex. Thresh==50000000) */
1120 (powers[0][powmax_dirs[wis[w]]] <= lfsparms->powmax_max)){
1121
1122 #ifdef LOG_REPORT /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
1123 /* Add 1 to wis[w] to create index to original dft_coefs[] */
1124 fprintf(logfp,
1125 " Selected Wave = %d\n", wis[w]+1);
1126 fprintf(logfp,
1127 " 1. Power Magnitude (%12.3f > %12.3f)\n",
1128 powmaxs[wis[w]], lfsparms->powmax_min);
1129 fprintf(logfp,
1130 " 2. Norm Power Magnitude (%9.3f > %9.3f)\n",
1131 pownorms[wis[w]], lfsparms->pownorm_min);
1132 fprintf(logfp,
1133 " 3. Low Freq Wave Magnitude (%12.3f <= %12.3f)\n",
1134 powers[0][powmax_dirs[wis[w]]], lfsparms->powmax_max);
1135 fprintf(logfp,
1136 " PASSED\n");
1137 fprintf(logfp,
1138 " Selected Direction = %d\n",
1139 powmax_dirs[wis[w]]);
1140 #endif /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
1141
1142 /* If ALL 3 criteria met, return current max power direction. */
1143 return(powmax_dirs[wis[w]]);
1144
1145 }
1146 }
1147
1148 /* Otherwise test failed. */
1149
1150 #ifdef LOG_REPORT /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
1151 fprintf(logfp, " 1. Power Magnitude ( > %12.3f)\n",
1152 lfsparms->powmax_min);
1153 fprintf(logfp, " 2. Norm Power Magnitude ( > %9.3f)\n",
1154 lfsparms->pownorm_min);
1155 fprintf(logfp, " 3. Low Freq Wave Magnitude ( <= %12.3f)\n",
1156 lfsparms->powmax_max);
1157 fprintf(logfp, " FAILED\n");
1158 #endif /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
1159
1160 return(INVALID_DIR);
1161 }
1162
1163 /*************************************************************************
1164 **************************************************************************
1165 #cat: secondary_fork_test - Applies a secondary set of criteria for selecting
1166 #cat: an IMAP integer direction from a set of DFT results
1167 #cat: computed from a block of image data. This test
1168 #cat: analyzes the strongest power statistics associated
1169 #cat: with a given frequency and direction and analyses
1170 #cat: small changes in direction to the left and right to
1171 #cat: determine if the block contains a "fork".
1172
1173 Input:
1174 powers - DFT power computed from each (N) wave frequencies at each
1175 rotation direction in the current image block
1176 wis - sorted order of the highest N-1 frequency power statistics
1177 powmaxs - maximum power for each of the highest N-1 frequencies
1178 powmax_dirs - directions associated with each of the N-1 maximum powers
1179 pownorms - normalized power for each of the highest N-1 frequencies
1180 nstats - N-1 wave frequencies (where N is the length of dft_coefs)
1181 lfsparms - parameters and thresholds for controlling LFS
1182 Return Code:
1183 Zero or Positive - The selected IMAP integer direction
1184 INVALID_DIR - IMAP Integer direction could not be determined
1185 **************************************************************************/
secondary_fork_test(double ** powers,const int * wis,const double * powmaxs,const int * powmax_dirs,const double * pownorms,const int nstats,const LFSPARMS * lfsparms)1186 int secondary_fork_test(double **powers, const int *wis,
1187 const double *powmaxs, const int *powmax_dirs,
1188 const double *pownorms, const int nstats,
1189 const LFSPARMS *lfsparms)
1190 {
1191 int ldir, rdir;
1192 double fork_pownorm_min, fork_pow_thresh;
1193
1194 #ifdef LOG_REPORT
1195 { int firstpart = 0; /* Flag to determine if passed 1st part ... */
1196 fprintf(logfp, " Secondary\n");
1197 #endif
1198
1199 /* Relax the normalized power threshold under fork conditions. */
1200 fork_pownorm_min = lfsparms->fork_pct_pownorm * lfsparms->pownorm_min;
1201
1202 /* 1. Test magnitude of largest max power (Ex. Thresh==100000) */
1203 if((powmaxs[wis[0]] > lfsparms->powmax_min) &&
1204 /* 2. Test magnitude of corresponding normalized power */
1205 /* (Ex. Thresh==2.85) */
1206 (pownorms[wis[0]] >= fork_pownorm_min) &&
1207 /* 3. Test magnitude of power of lowest DFT frequency at largest */
1208 /* max power direction and make sure it is not too big. */
1209 /* (Ex. Thresh==50000000) */
1210 (powers[0][powmax_dirs[wis[0]]] <= lfsparms->powmax_max)){
1211
1212 #ifdef LOG_REPORT /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
1213 /* First part passed ... */
1214 firstpart = 1;
1215 fprintf(logfp,
1216 " Selected Wave = %d\n", wis[0]+1);
1217 fprintf(logfp,
1218 " 1. Power Magnitude (%12.3f > %12.3f)\n",
1219 powmaxs[wis[0]], lfsparms->powmax_min);
1220 fprintf(logfp,
1221 " 2. Norm Power Magnitude (%9.3f >= %9.3f)\n",
1222 pownorms[wis[0]], fork_pownorm_min);
1223 fprintf(logfp,
1224 " 3. Low Freq Wave Magnitude (%12.3f <= %12.3f)\n",
1225 powers[0][powmax_dirs[wis[0]]], lfsparms->powmax_max);
1226 #endif /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
1227
1228 /* Add FORK_INTERVALs to current direction modulo NDIRS */
1229 rdir = (powmax_dirs[wis[0]] + lfsparms->fork_interval) %
1230 lfsparms->num_directions;
1231
1232 /* Subtract FORK_INTERVALs from direction modulo NDIRS */
1233 /* For example, FORK_INTERVAL==2 & NDIRS==16, then */
1234 /* ldir = (dir - (16-2)) % 16 */
1235 /* which keeps result in proper modulo range. */
1236 ldir = (powmax_dirs[wis[0]] + lfsparms->num_directions -
1237 lfsparms->fork_interval) % lfsparms->num_directions;
1238
1239 print2log(" Left = %d, Current = %d, Right = %d\n",
1240 ldir, powmax_dirs[wis[0]], rdir);
1241
1242 /* Set forked angle threshold to be a % of the max directional */
1243 /* power. (Ex. thresh==0.7*powmax) */
1244 fork_pow_thresh = powmaxs[wis[0]] * lfsparms->fork_pct_powmax;
1245
1246 /* Look up and test the computed power for the left and right */
1247 /* fork directions.s */
1248 /* The power stats (and thus wis) are on the range [0..nwaves-1) */
1249 /* as the statistics for the first DFT wave are not included. */
1250 /* The original power vectors exist for ALL DFT waves, therefore */
1251 /* wis indices must be added by 1 before addressing the original */
1252 /* powers vector. */
1253 /* LFS permits one and only one of the fork angles to exceed */
1254 /* the relative power threshold. */
1255 if(((powers[wis[0]+1][ldir] <= fork_pow_thresh) ||
1256 (powers[wis[0]+1][rdir] <= fork_pow_thresh)) &&
1257 ((powers[wis[0]+1][ldir] > fork_pow_thresh) ||
1258 (powers[wis[0]+1][rdir] > fork_pow_thresh))){
1259
1260 #ifdef LOG_REPORT /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
1261 fprintf(logfp,
1262 " 4. Left Power Magnitude (%12.3f > %12.3f)\n",
1263 powers[wis[0]+1][ldir], fork_pow_thresh);
1264 fprintf(logfp,
1265 " 5. Right Power Magnitude (%12.3f > %12.3f)\n",
1266 powers[wis[0]+1][rdir], fork_pow_thresh);
1267 fprintf(logfp, " PASSED\n");
1268 fprintf(logfp,
1269 " Selected Direction = %d\n", powmax_dirs[wis[0]]);
1270 #endif /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
1271
1272 /* If ALL the above criteria hold, then return the direction */
1273 /* of the largest max power. */
1274 return(powmax_dirs[wis[0]]);
1275 }
1276 }
1277
1278 /* Otherwise test failed. */
1279
1280 #ifdef LOG_REPORT /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
1281 if(!firstpart){
1282 fprintf(logfp,
1283 " 1. Power Magnitude ( > %12.3f)\n",
1284 lfsparms->powmax_min);
1285 fprintf(logfp,
1286 " 2. Norm Power Magnitude ( > %9.3f)\n",
1287 fork_pownorm_min);
1288 fprintf(logfp,
1289 " 3. Low Freq Wave Magnitude ( <= %12.3f)\n",
1290 lfsparms->powmax_max);
1291 }
1292 else{
1293 fprintf(logfp, " 4. Left Power Magnitude (%12.3f > %12.3f)\n",
1294 powers[wis[0]+1][ldir], fork_pow_thresh);
1295 fprintf(logfp, " 5. Right Power Magnitude (%12.3f > %12.3f)\n",
1296 powers[wis[0]+1][rdir], fork_pow_thresh);
1297 }
1298 fprintf(logfp, " FAILED\n");
1299 } /* Close scope of firstpart */
1300 #endif /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
1301
1302 return(INVALID_DIR);
1303 }
1304
1305 /*************************************************************************
1306 **************************************************************************
1307 #cat: remove_incon_dirs - Takes a vector of integer directions and removes
1308 #cat: individual directions that are too weak or inconsistent.
1309 #cat: Directions are tested from the center of the IMAP working
1310 #cat: outward in concentric squares, and the process resets to
1311 #cat: the center and continues until no changes take place during
1312 #cat: a complete pass.
1313
1314 Input:
1315 imap - vector of IMAP integer directions
1316 mw - width (in blocks) of the IMAP
1317 mh - height (in blocks) of the IMAP
1318 dir2rad - lookup table for converting integer directions
1319 lfsparms - parameters and thresholds for controlling LFS
1320 Output:
1321 imap - vector of pruned input values
1322 **************************************************************************/
remove_incon_dirs(int * imap,const int mw,const int mh,const DIR2RAD * dir2rad,const LFSPARMS * lfsparms)1323 void remove_incon_dirs(int *imap, const int mw, const int mh,
1324 const DIR2RAD *dir2rad, const LFSPARMS *lfsparms)
1325 {
1326 int cx, cy;
1327 int *iptr;
1328 int nremoved;
1329 int lbox, rbox, tbox, bbox;
1330
1331 #ifdef LOG_REPORT
1332 { int numpass = 0;
1333 fprintf(logfp, "REMOVE MAP\n");
1334 #endif
1335
1336 /* Compute center coords of IMAP */
1337 cx = mw>>1;
1338 cy = mh>>1;
1339
1340 /* Do pass, while directions have been removed in a pass ... */
1341 do{
1342
1343 #ifdef LOG_REPORT
1344 /* Count number of complete passes through IMAP */
1345 ++numpass;
1346 fprintf(logfp, " PASS = %d\n", numpass);
1347 #endif
1348
1349 /* Reinitialize number of removed directions to 0 */
1350 nremoved = 0;
1351
1352 /* Start at center */
1353 iptr = imap + (cy * mw) + cx;
1354 /* If valid IMAP direction and test for removal is true ... */
1355 if((*iptr != INVALID_DIR)&&
1356 (remove_dir(imap, cx, cy, mw, mh, dir2rad, lfsparms))){
1357
1358 /* Set to INVALID */
1359 *iptr = INVALID_DIR;
1360 /* Bump number of removed IMAP directions */
1361 nremoved++;
1362 }
1363
1364 /* Initialize side indices of concentric boxes */
1365 lbox = cx-1;
1366 tbox = cy-1;
1367 rbox = cx+1;
1368 bbox = cy+1;
1369
1370 /* Grow concentric boxes, until ALL edges of imap are exceeded */
1371 while((lbox >= 0) || (rbox < mw) || (tbox >= 0) || (bbox < mh)){
1372
1373 /* test top edge of box */
1374 if(tbox >= 0)
1375 nremoved += test_top_edge(lbox, tbox, rbox, bbox, imap, mw, mh,
1376 dir2rad, lfsparms);
1377
1378 /* test right edge of box */
1379 if(rbox < mw)
1380 nremoved += test_right_edge(lbox, tbox, rbox, bbox, imap, mw, mh,
1381 dir2rad, lfsparms);
1382
1383 /* test bottom edge of box */
1384 if(bbox < mh)
1385 nremoved += test_bottom_edge(lbox, tbox, rbox, bbox, imap, mw, mh,
1386 dir2rad, lfsparms);
1387
1388 /* test left edge of box */
1389 if(lbox >=0)
1390 nremoved += test_left_edge(lbox, tbox, rbox, bbox, imap, mw, mh,
1391 dir2rad, lfsparms);
1392
1393 /* Resize current box */
1394 lbox--;
1395 tbox--;
1396 rbox++;
1397 bbox++;
1398 }
1399 }while(nremoved);
1400
1401 #ifdef LOG_REPORT
1402 } /* Close scope of numpass */
1403 #endif
1404
1405 }
1406
1407 /*************************************************************************
1408 **************************************************************************
1409 #cat: test_top_edge - Walks the top edge of a concentric square in the IMAP,
1410 #cat: testing directions along the way to see if they should
1411 #cat: be removed due to being too weak or inconsistent with
1412 #cat: respect to their adjacent neighbors.
1413
1414 Input:
1415 lbox - left edge of current concentric square
1416 tbox - top edge of current concentric square
1417 rbox - right edge of current concentric square
1418 bbox - bottom edge of current concentric square
1419 imap - vector of IMAP integer directions
1420 mw - width (in blocks) of the IMAP
1421 mh - height (in blocks) of the IMAP
1422 dir2rad - lookup table for converting integer directions
1423 lfsparms - parameters and thresholds for controlling LFS
1424 Return Code:
1425 Positive - direction should be removed from IMAP
1426 Zero - direction should NOT be remove from IMAP
1427 **************************************************************************/
test_top_edge(const int lbox,const int tbox,const int rbox,const int bbox,int * imap,const int mw,const int mh,const DIR2RAD * dir2rad,const LFSPARMS * lfsparms)1428 int test_top_edge(const int lbox, const int tbox, const int rbox,
1429 const int bbox, int *imap, const int mw, const int mh,
1430 const DIR2RAD *dir2rad, const LFSPARMS *lfsparms)
1431 {
1432 int bx, by, sx, ex;
1433 int *iptr, *sptr, *eptr;
1434 int nremoved;
1435
1436 /* Initialize number of directions removed on edge to 0 */
1437 nremoved = 0;
1438
1439 /* Set start pointer to top-leftmost point of box, or set it to */
1440 /* the leftmost point in the IMAP row (0), whichever is larger. */
1441 sx = max(lbox, 0);
1442 sptr = imap + (tbox*mw) + sx;
1443
1444 /* Set end pointer to either 1 point short of the top-rightmost */
1445 /* point of box, or set it to the rightmost point in the IMAP */
1446 /* row (lastx=mw-1), whichever is smaller. */
1447 ex = min(rbox-1, mw-1);
1448 eptr = imap + (tbox*mw) + ex;
1449
1450 /* For each point on box's edge ... */
1451 for(iptr = sptr, bx = sx, by = tbox;
1452 iptr <= eptr;
1453 iptr++, bx++){
1454 /* If valid IMAP direction and test for removal is true ... */
1455 if((*iptr != INVALID_DIR)&&
1456 (remove_dir(imap, bx, by, mw, mh, dir2rad, lfsparms))){
1457 /* Set to INVALID */
1458 *iptr = INVALID_DIR;
1459 /* Bump number of removed IMAP directions */
1460 nremoved++;
1461 }
1462 }
1463
1464 /* Return the number of directions removed on edge */
1465 return(nremoved);
1466 }
1467
1468 /*************************************************************************
1469 **************************************************************************
1470 #cat: test_right_edge - Walks the right edge of a concentric square in the
1471 #cat: IMAP, testing directions along the way to see if they
1472 #cat: should be removed due to being too weak or inconsistent
1473 #cat: with respect to their adjacent neighbors.
1474
1475 Input:
1476 lbox - left edge of current concentric square
1477 tbox - top edge of current concentric square
1478 rbox - right edge of current concentric square
1479 bbox - bottom edge of current concentric square
1480 imap - vector of IMAP integer directions
1481 mw - width (in blocks) of the IMAP
1482 mh - height (in blocks) of the IMAP
1483 dir2rad - lookup table for converting integer directions
1484 lfsparms - parameters and thresholds for controlling LFS
1485 Return Code:
1486 Positive - direction should be removed from IMAP
1487 Zero - direction should NOT be remove from IMAP
1488 **************************************************************************/
test_right_edge(const int lbox,const int tbox,const int rbox,const int bbox,int * imap,const int mw,const int mh,const DIR2RAD * dir2rad,const LFSPARMS * lfsparms)1489 int test_right_edge(const int lbox, const int tbox, const int rbox,
1490 const int bbox, int *imap, const int mw, const int mh,
1491 const DIR2RAD *dir2rad, const LFSPARMS *lfsparms)
1492 {
1493 int bx, by, sy, ey;
1494 int *iptr, *sptr, *eptr;
1495 int nremoved;
1496
1497 /* Initialize number of directions removed on edge to 0 */
1498 nremoved = 0;
1499
1500 /* Set start pointer to top-rightmost point of box, or set it to */
1501 /* the topmost point in IMAP column (0), whichever is larger. */
1502 sy = max(tbox, 0);
1503 sptr = imap + (sy*mw) + rbox;
1504
1505 /* Set end pointer to either 1 point short of the bottom- */
1506 /* rightmost point of box, or set it to the bottommost point */
1507 /* in the IMAP column (lasty=mh-1), whichever is smaller. */
1508 ey = min(bbox-1,mh-1);
1509 eptr = imap + (ey*mw) + rbox;
1510
1511 /* For each point on box's edge ... */
1512 for(iptr = sptr, bx = rbox, by = sy;
1513 iptr <= eptr;
1514 iptr+=mw, by++){
1515 /* If valid IMAP direction and test for removal is true ... */
1516 if((*iptr != INVALID_DIR)&&
1517 (remove_dir(imap, bx, by, mw, mh, dir2rad, lfsparms))){
1518 /* Set to INVALID */
1519 *iptr = INVALID_DIR;
1520 /* Bump number of removed IMAP directions */
1521 nremoved++;
1522 }
1523 }
1524
1525 /* Return the number of directions removed on edge */
1526 return(nremoved);
1527 }
1528
1529 /*************************************************************************
1530 **************************************************************************
1531 #cat: test_bottom_edge - Walks the bottom edge of a concentric square in the
1532 #cat: IMAP, testing directions along the way to see if they
1533 #cat: should be removed due to being too weak or inconsistent
1534 #cat: with respect to their adjacent neighbors.
1535 Input:
1536 lbox - left edge of current concentric square
1537 tbox - top edge of current concentric square
1538 rbox - right edge of current concentric square
1539 bbox - bottom edge of current concentric square
1540 imap - vector of IMAP integer directions
1541 mw - width (in blocks) of the IMAP
1542 mh - height (in blocks) of the IMAP
1543 dir2rad - lookup table for converting integer directions
1544 lfsparms - parameters and thresholds for controlling LFS
1545 Return Code:
1546 Positive - direction should be removed from IMAP
1547 Zero - direction should NOT be remove from IMAP
1548 **************************************************************************/
test_bottom_edge(const int lbox,const int tbox,const int rbox,const int bbox,int * imap,const int mw,const int mh,const DIR2RAD * dir2rad,const LFSPARMS * lfsparms)1549 int test_bottom_edge(const int lbox, const int tbox, const int rbox,
1550 const int bbox, int *imap, const int mw, const int mh,
1551 const DIR2RAD *dir2rad, const LFSPARMS *lfsparms)
1552 {
1553 int bx, by, sx, ex;
1554 int *iptr, *sptr, *eptr;
1555 int nremoved;
1556
1557 /* Initialize number of directions removed on edge to 0 */
1558 nremoved = 0;
1559
1560 /* Set start pointer to bottom-rightmost point of box, or set it to the */
1561 /* rightmost point in the IMAP ROW (lastx=mw-1), whichever is smaller. */
1562 sx = min(rbox, mw-1);
1563 sptr = imap + (bbox*mw) + sx;
1564
1565 /* Set end pointer to either 1 point short of the bottom- */
1566 /* lefttmost point of box, or set it to the leftmost point */
1567 /* in the IMAP row (x=0), whichever is larger. */
1568 ex = max(lbox-1, 0);
1569 eptr = imap + (bbox*mw) + ex;
1570
1571 /* For each point on box's edge ... */
1572 for(iptr = sptr, bx = sx, by = bbox;
1573 iptr >= eptr;
1574 iptr--, bx--){
1575 /* If valid IMAP direction and test for removal is true ... */
1576 if((*iptr != INVALID_DIR)&&
1577 (remove_dir(imap, bx, by, mw, mh, dir2rad, lfsparms))){
1578 /* Set to INVALID */
1579 *iptr = INVALID_DIR;
1580 /* Bump number of removed IMAP directions */
1581 nremoved++;
1582 }
1583 }
1584
1585 /* Return the number of directions removed on edge */
1586 return(nremoved);
1587 }
1588
1589 /*************************************************************************
1590 **************************************************************************
1591 #cat: test_left_edge - Walks the left edge of a concentric square in the IMAP,
1592 #cat: testing directions along the way to see if they should
1593 #cat: be removed due to being too weak or inconsistent with
1594 #cat: respect to their adjacent neighbors.
1595
1596 Input:
1597 lbox - left edge of current concentric square
1598 tbox - top edge of current concentric square
1599 rbox - right edge of current concentric square
1600 bbox - bottom edge of current concentric square
1601 imap - vector of IMAP integer directions
1602 mw - width (in blocks) of the IMAP
1603 mh - height (in blocks) of the IMAP
1604 dir2rad - lookup table for converting integer directions
1605 lfsparms - parameters and thresholds for controlling LFS
1606 Return Code:
1607 Positive - direction should be removed from IMAP
1608 Zero - direction should NOT be remove from IMAP
1609 **************************************************************************/
test_left_edge(const int lbox,const int tbox,const int rbox,const int bbox,int * imap,const int mw,const int mh,const DIR2RAD * dir2rad,const LFSPARMS * lfsparms)1610 int test_left_edge(const int lbox, const int tbox, const int rbox,
1611 const int bbox, int *imap, const int mw, const int mh,
1612 const DIR2RAD *dir2rad, const LFSPARMS *lfsparms)
1613 {
1614 int bx, by, sy, ey;
1615 int *iptr, *sptr, *eptr;
1616 int nremoved;
1617
1618 /* Initialize number of directions removed on edge to 0 */
1619 nremoved = 0;
1620
1621 /* Set start pointer to bottom-leftmost point of box, or set it to */
1622 /* the bottommost point in IMAP column (lasty=mh-1), whichever */
1623 /* is smaller. */
1624 sy = min(bbox, mh-1);
1625 sptr = imap + (sy*mw) + lbox;
1626
1627 /* Set end pointer to either 1 point short of the top-leftmost */
1628 /* point of box, or set it to the topmost point in the IMAP */
1629 /* column (y=0), whichever is larger. */
1630 ey = max(tbox-1, 0);
1631 eptr = imap + (ey*mw) + lbox;
1632
1633 /* For each point on box's edge ... */
1634 for(iptr = sptr, bx = lbox, by = sy;
1635 iptr >= eptr;
1636 iptr-=mw, by--){
1637 /* If valid IMAP direction and test for removal is true ... */
1638 if((*iptr != INVALID_DIR)&&
1639 (remove_dir(imap, bx, by, mw, mh, dir2rad, lfsparms))){
1640 /* Set to INVALID */
1641 *iptr = INVALID_DIR;
1642 /* Bump number of removed IMAP directions */
1643 nremoved++;
1644 }
1645 }
1646
1647 /* Return the number of directions removed on edge */
1648 return(nremoved);
1649 }
1650
1651 /*************************************************************************
1652 **************************************************************************
1653 #cat: remove_dir - Determines if an IMAP direction should be removed based
1654 #cat: on analyzing its adjacent neighbors
1655
1656 Input:
1657 imap - vector of IMAP integer directions
1658 mx - IMAP X-coord of the current direction being tested
1659 my - IMPA Y-coord of the current direction being tested
1660 mw - width (in blocks) of the IMAP
1661 mh - height (in blocks) of the IMAP
1662 dir2rad - lookup table for converting integer directions
1663 lfsparms - parameters and thresholds for controlling LFS
1664 Return Code:
1665 Positive - direction should be removed from IMAP
1666 Zero - direction should NOT be remove from IMAP
1667 **************************************************************************/
remove_dir(int * imap,const int mx,const int my,const int mw,const int mh,const DIR2RAD * dir2rad,const LFSPARMS * lfsparms)1668 int remove_dir(int *imap, const int mx, const int my,
1669 const int mw, const int mh, const DIR2RAD *dir2rad,
1670 const LFSPARMS *lfsparms)
1671 {
1672 int avrdir, nvalid, dist;
1673 double dir_strength;
1674
1675 /* Compute average direction from neighbors, returning the */
1676 /* number of valid neighbors used in the computation, and */
1677 /* the "strength" of the average direction. */
1678 average_8nbr_dir(&avrdir, &dir_strength, &nvalid, imap, mx, my, mw, mh,
1679 dir2rad);
1680
1681 /* Conduct valid neighbor test (Ex. thresh==3) */
1682 if(nvalid < lfsparms->rmv_valid_nbr_min){
1683
1684 #ifdef LOG_REPORT /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
1685 fprintf(logfp, " BLOCK %2d (%2d, %2d)\n",
1686 mx+(my*mw), mx, my);
1687 fprintf(logfp, " Average NBR : %2d %6.3f %d\n",
1688 avrdir, dir_strength, nvalid);
1689 fprintf(logfp, " 1. Valid NBR (%d < %d)\n",
1690 nvalid, lfsparms->rmv_valid_nbr_min);
1691 #endif /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
1692
1693 return(1);
1694 }
1695
1696 /* If stregnth of average neighbor direction is large enough to */
1697 /* put credence in ... (Ex. thresh==0.2) */
1698 if(dir_strength >= lfsparms->dir_strength_min){
1699
1700 /* Conduct direction distance test (Ex. thresh==3) */
1701 /* Compute minimum absolute distance between current and */
1702 /* average directions accounting for wrapping from 0 to NDIRS. */
1703 dist = abs(avrdir - *(imap+(my*mw)+mx));
1704 dist = min(dist, dir2rad->ndirs-dist);
1705 if(dist > lfsparms->dir_distance_max){
1706
1707 #ifdef LOG_REPORT /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
1708 fprintf(logfp, " BLOCK %2d (%2d, %2d)\n",
1709 mx+(my*mw), mx, my);
1710 fprintf(logfp, " Average NBR : %2d %6.3f %d\n",
1711 avrdir, dir_strength, nvalid);
1712 fprintf(logfp, " 1. Valid NBR (%d < %d)\n",
1713 nvalid, lfsparms->rmv_valid_nbr_min);
1714 fprintf(logfp, " 2. Direction Strength (%6.3f >= %6.3f)\n",
1715 dir_strength, lfsparms->dir_strength_min);
1716 fprintf(logfp, " Current Dir = %d, Average Dir = %d\n",
1717 *(imap+(my*mw)+mx), avrdir);
1718 fprintf(logfp, " 3. Direction Distance (%d > %d)\n",
1719 dist, lfsparms->dir_distance_max);
1720 #endif /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
1721
1722 return(2);
1723 }
1724 }
1725
1726 /* Otherwise, the strength of the average direciton is not strong enough */
1727 /* to put credence in, so leave the current block's directon alone. */
1728
1729 return(0);
1730 }
1731
1732 /*************************************************************************
1733 **************************************************************************
1734 #cat: average_8nbr_dir - Given an IMAP direction, computes an average
1735 #cat: direction from its adjacent 8 neighbors returning
1736 #cat: the average direction, its strength, and the
1737 #cat: number of valid direction in the neighborhood.
1738
1739 Input:
1740 imap - vector of IMAP integer directions
1741 mx - IMAP X-coord of the current direction
1742 my - IMPA Y-coord of the current direction
1743 mw - width (in blocks) of the IMAP
1744 mh - height (in blocks) of the IMAP
1745 dir2rad - lookup table for converting integer directions
1746 Output:
1747 avrdir - the average direction computed from neighbors
1748 dir_strenght - the strength of the average direction
1749 nvalid - the number of valid directions used to compute the
1750 average
1751 **************************************************************************/
average_8nbr_dir(int * avrdir,double * dir_strength,int * nvalid,int * imap,const int mx,const int my,const int mw,const int mh,const DIR2RAD * dir2rad)1752 void average_8nbr_dir(int *avrdir, double *dir_strength, int *nvalid,
1753 int *imap, const int mx, const int my,
1754 const int mw, const int mh,
1755 const DIR2RAD *dir2rad)
1756 {
1757 int *iptr;
1758 int e,w,n,s;
1759 double cospart, sinpart;
1760 double pi2, pi_factor, theta;
1761 double avr;
1762
1763 /* Compute neighbor coordinates to current IMAP direction */
1764 e = mx+1; /* East */
1765 w = mx-1; /* West */
1766 n = my-1; /* North */
1767 s = my+1; /* South */
1768
1769 /* Intialize accumulators */
1770 *nvalid = 0;
1771 cospart = 0.0;
1772 sinpart = 0.0;
1773
1774 /* 1. Test NW */
1775 /* If NW point within IMAP boudaries ... */
1776 if((w >= 0) && (n >= 0)){
1777 iptr = imap + (n*mw) + w;
1778 /* If valid direction ... */
1779 if(*iptr != INVALID_DIR){
1780 /* Accumulate cosine and sine components of the direction */
1781 cospart += dir2rad->cos[*iptr];
1782 sinpart += dir2rad->sin[*iptr];
1783 /* Bump number of accumulated directions */
1784 (*nvalid)++;
1785 }
1786 }
1787
1788 /* 2. Test N */
1789 /* If N point within IMAP boudaries ... */
1790 if(n >= 0){
1791 iptr = imap + (n*mw) + mx;
1792 /* If valid direction ... */
1793 if(*iptr != INVALID_DIR){
1794 /* Accumulate cosine and sine components of the direction */
1795 cospart += dir2rad->cos[*iptr];
1796 sinpart += dir2rad->sin[*iptr];
1797 /* Bump number of accumulated directions */
1798 (*nvalid)++;
1799 }
1800 }
1801
1802 /* 3. Test NE */
1803 /* If NE point within IMAP boudaries ... */
1804 if((e < mw) && (n >= 0)){
1805 iptr = imap + (n*mw) + e;
1806 /* If valid direction ... */
1807 if(*iptr != INVALID_DIR){
1808 /* Accumulate cosine and sine components of the direction */
1809 cospart += dir2rad->cos[*iptr];
1810 sinpart += dir2rad->sin[*iptr];
1811 /* Bump number of accumulated directions */
1812 (*nvalid)++;
1813 }
1814 }
1815
1816 /* 4. Test E */
1817 /* If E point within IMAP boudaries ... */
1818 if(e < mw){
1819 iptr = imap + (my*mw) + e;
1820 /* If valid direction ... */
1821 if(*iptr != INVALID_DIR){
1822 /* Accumulate cosine and sine components of the direction */
1823 cospart += dir2rad->cos[*iptr];
1824 sinpart += dir2rad->sin[*iptr];
1825 /* Bump number of accumulated directions */
1826 (*nvalid)++;
1827 }
1828 }
1829
1830 /* 5. Test SE */
1831 /* If SE point within IMAP boudaries ... */
1832 if((e < mw) && (s < mh)){
1833 iptr = imap + (s*mw) + e;
1834 /* If valid direction ... */
1835 if(*iptr != INVALID_DIR){
1836 /* Accumulate cosine and sine components of the direction */
1837 cospart += dir2rad->cos[*iptr];
1838 sinpart += dir2rad->sin[*iptr];
1839 /* Bump number of accumulated directions */
1840 (*nvalid)++;
1841 }
1842 }
1843
1844 /* 6. Test S */
1845 /* If S point within IMAP boudaries ... */
1846 if(s < mh){
1847 iptr = imap + (s*mw) + mx;
1848 /* If valid direction ... */
1849 if(*iptr != INVALID_DIR){
1850 /* Accumulate cosine and sine components of the direction */
1851 cospart += dir2rad->cos[*iptr];
1852 sinpart += dir2rad->sin[*iptr];
1853 /* Bump number of accumulated directions */
1854 (*nvalid)++;
1855 }
1856 }
1857
1858 /* 7. Test SW */
1859 /* If SW point within IMAP boudaries ... */
1860 if((w >= 0) && (s < mh)){
1861 iptr = imap + (s*mw) + w;
1862 /* If valid direction ... */
1863 if(*iptr != INVALID_DIR){
1864 /* Accumulate cosine and sine components of the direction */
1865 cospart += dir2rad->cos[*iptr];
1866 sinpart += dir2rad->sin[*iptr];
1867 /* Bump number of accumulated directions */
1868 (*nvalid)++;
1869 }
1870 }
1871
1872 /* 8. Test W */
1873 /* If W point within IMAP boudaries ... */
1874 if(w >= 0){
1875 iptr = imap + (my*mw) + w;
1876 /* If valid direction ... */
1877 if(*iptr != INVALID_DIR){
1878 /* Accumulate cosine and sine components of the direction */
1879 cospart += dir2rad->cos[*iptr];
1880 sinpart += dir2rad->sin[*iptr];
1881 /* Bump number of accumulated directions */
1882 (*nvalid)++;
1883 }
1884 }
1885
1886 /* If there were no neighbors found with valid direction ... */
1887 if(*nvalid == 0){
1888 /* Return INVALID direction. */
1889 *dir_strength = 0;
1890 *avrdir = INVALID_DIR;
1891 return;
1892 }
1893
1894 /* Compute averages of accumulated cosine and sine direction components */
1895 cospart /= (double)(*nvalid);
1896 sinpart /= (double)(*nvalid);
1897
1898 /* Compute directional strength as hypotenuse (without sqrt) of average */
1899 /* cosine and sine direction components. Believe this value will be on */
1900 /* the range of [0 .. 1]. */
1901 *dir_strength = (cospart * cospart) + (sinpart * sinpart);
1902 /* Need to truncate precision so that answers are consistent */
1903 /* on different computer architectures when comparing doubles. */
1904 *dir_strength = trunc_dbl_precision(*dir_strength, TRUNC_SCALE);
1905
1906 /* If the direction strength is not sufficiently high ... */
1907 if(*dir_strength < DIR_STRENGTH_MIN){
1908 /* Return INVALID direction. */
1909 *dir_strength = 0;
1910 *avrdir = INVALID_DIR;
1911 return;
1912 }
1913
1914 /* Compute angle (in radians) from Arctan of avarage */
1915 /* cosine and sine direction components. I think this order */
1916 /* is necessary because 0 direction is vertical and positive */
1917 /* direction is clockwise. */
1918 theta = atan2(sinpart, cospart);
1919
1920 /* Atan2 returns theta on range [-PI..PI]. Adjust theta so that */
1921 /* it is on the range [0..2PI]. */
1922 pi2 = 2*M_PI;
1923 theta += pi2;
1924 theta = fmod(theta, pi2);
1925
1926 /* Pi_factor sets the period of the trig functions to NDIRS units in x. */
1927 /* For example, if NDIRS==16, then pi_factor = 2(PI/16) = .3926... */
1928 /* Dividing theta (in radians) by this factor ((1/pi_factor)==2.546...) */
1929 /* will produce directions on the range [0..NDIRS]. */
1930 pi_factor = pi2/(double)dir2rad->ndirs; /* 2(M_PI/ndirs) */
1931
1932 /* Round off the direction and return it as an average direction */
1933 /* for the neighborhood. */
1934 avr = theta / pi_factor;
1935 /* Need to truncate precision so that answers are consistent */
1936 /* on different computer architectures when rounding doubles. */
1937 avr = trunc_dbl_precision(avr, TRUNC_SCALE);
1938 *avrdir = sround(avr);
1939
1940 /* Really do need to map values > NDIRS back onto [0..NDIRS) range. */
1941 *avrdir %= dir2rad->ndirs;
1942 }
1943
1944 /*************************************************************************
1945 **************************************************************************
1946 #cat: num_valid_8nbrs - Given a block in an IMAP, counts the number of
1947 #cat: immediate neighbors that have a valid IMAP direction.
1948
1949 Input:
1950 imap - 2-D vector of directional ridge flows
1951 mx - horizontal coord of current block in IMAP
1952 my - vertical coord of current block in IMAP
1953 mw - width (in blocks) of the IMAP
1954 mh - height (in blocks) of the IMAP
1955 Return Code:
1956 Non-negative - the number of valid IMAP neighbors
1957 **************************************************************************/
num_valid_8nbrs(int * imap,const int mx,const int my,const int mw,const int mh)1958 int num_valid_8nbrs(int *imap, const int mx, const int my,
1959 const int mw, const int mh)
1960 {
1961 int e_ind, w_ind, n_ind, s_ind;
1962 int nvalid;
1963
1964 /* Initialize VALID IMAP counter to zero. */
1965 nvalid = 0;
1966
1967 /* Compute neighbor coordinates to current IMAP direction */
1968 e_ind = mx+1; /* East index */
1969 w_ind = mx-1; /* West index */
1970 n_ind = my-1; /* North index */
1971 s_ind = my+1; /* South index */
1972
1973 /* 1. Test NW IMAP value. */
1974 /* If neighbor indices are within IMAP boundaries and it is VALID ... */
1975 if((w_ind >= 0) && (n_ind >= 0) && (*(imap + (n_ind*mw) + w_ind) >= 0))
1976 /* Bump VALID counter. */
1977 nvalid++;
1978
1979 /* 2. Test N IMAP value. */
1980 if((n_ind >= 0) && (*(imap + (n_ind*mw) + mx) >= 0))
1981 nvalid++;
1982
1983 /* 3. Test NE IMAP value. */
1984 if((n_ind >= 0) && (e_ind < mw) && (*(imap + (n_ind*mw) + e_ind) >= 0))
1985 nvalid++;
1986
1987 /* 4. Test E IMAP value. */
1988 if((e_ind < mw) && (*(imap + (my*mw) + e_ind) >= 0))
1989 nvalid++;
1990
1991 /* 5. Test SE IMAP value. */
1992 if((e_ind < mw) && (s_ind < mh) && (*(imap + (s_ind*mw) + e_ind) >= 0))
1993 nvalid++;
1994
1995 /* 6. Test S IMAP value. */
1996 if((s_ind < mh) && (*(imap + (s_ind*mw) + mx) >= 0))
1997 nvalid++;
1998
1999 /* 7. Test SW IMAP value. */
2000 if((w_ind >= 0) && (s_ind < mh) && (*(imap + (s_ind*mw) + w_ind) >= 0))
2001 nvalid++;
2002
2003 /* 8. Test W IMAP value. */
2004 if((w_ind >= 0) && (*(imap + (my*mw) + w_ind) >= 0))
2005 nvalid++;
2006
2007 /* Return number of neighbors with VALID IMAP values. */
2008 return(nvalid);
2009 }
2010
2011 /*************************************************************************
2012 **************************************************************************
2013 #cat: smooth_imap - Takes a vector of integer directions and smooths them
2014 #cat: by analyzing the direction of adjacent neighbors.
2015
2016 Input:
2017 imap - vector of IMAP integer directions
2018 mw - width (in blocks) of the IMAP
2019 mh - height (in blocks) of the IMAP
2020 dir2rad - lookup table for converting integer directions
2021 lfsparms - parameters and thresholds for controlling LFS
2022 Output:
2023 imap - vector of smoothed input values
2024 **************************************************************************/
smooth_imap(int * imap,const int mw,const int mh,const DIR2RAD * dir2rad,const LFSPARMS * lfsparms)2025 void smooth_imap(int *imap, const int mw, const int mh,
2026 const DIR2RAD *dir2rad, const LFSPARMS *lfsparms)
2027 {
2028 int mx, my;
2029 int *iptr;
2030 int avrdir, nvalid;
2031 double dir_strength;
2032
2033 print2log("SMOOTH MAP\n");
2034
2035 iptr = imap;
2036 for(my = 0; my < mh; my++){
2037 for(mx = 0; mx < mw; mx++){
2038 /* Compute average direction from neighbors, returning the */
2039 /* number of valid neighbors used in the computation, and */
2040 /* the "strength" of the average direction. */
2041 average_8nbr_dir(&avrdir, &dir_strength, &nvalid,
2042 imap, mx, my, mw, mh, dir2rad);
2043
2044 /* If average direction strength is strong enough */
2045 /* (Ex. thresh==0.2)... */
2046 if(dir_strength >= lfsparms->dir_strength_min){
2047 /* If IMAP direction is valid ... */
2048 if(*iptr != INVALID_DIR){
2049 /* Conduct valid neighbor test (Ex. thresh==3)... */
2050 if(nvalid >= lfsparms->rmv_valid_nbr_min){
2051
2052 #ifdef LOG_REPORT /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
2053 fprintf(logfp, " BLOCK %2d (%2d, %2d)\n",
2054 mx+(my*mw), mx, my);
2055 fprintf(logfp, " Average NBR : %2d %6.3f %d\n",
2056 avrdir, dir_strength, nvalid);
2057 fprintf(logfp, " 1. Valid NBR (%d >= %d)\n",
2058 nvalid, lfsparms->rmv_valid_nbr_min);
2059 fprintf(logfp, " Valid Direction = %d\n", *iptr);
2060 fprintf(logfp, " Smoothed Direction = %d\n", avrdir);
2061 #endif /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
2062
2063 /* Reassign valid IMAP direction with average direction. */
2064 *iptr = avrdir;
2065 }
2066 }
2067 /* Otherwise IMAP direction is invalid ... */
2068 else{
2069 /* Even if IMAP value is invalid, if number of valid */
2070 /* neighbors is big enough (Ex. thresh==7)... */
2071 if(nvalid >= lfsparms->smth_valid_nbr_min){
2072
2073 #ifdef LOG_REPORT /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
2074 fprintf(logfp, " BLOCK %2d (%2d, %2d)\n",
2075 mx+(my*mw), mx, my);
2076 fprintf(logfp, " Average NBR : %2d %6.3f %d\n",
2077 avrdir, dir_strength, nvalid);
2078 fprintf(logfp, " 2. Invalid NBR (%d >= %d)\n",
2079 nvalid, lfsparms->smth_valid_nbr_min);
2080 fprintf(logfp, " Invalid Direction = %d\n", *iptr);
2081 fprintf(logfp, " Smoothed Direction = %d\n", avrdir);
2082 #endif /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
2083
2084 /* Assign invalid IMAP direction with average direction. */
2085 *iptr = avrdir;
2086 }
2087 }
2088 }
2089
2090 /* Bump to next IMAP direction. */
2091 iptr++;
2092 }
2093 }
2094 }
2095
2096 /*************************************************************************
2097 **************************************************************************
2098 #cat: vorticity - Measures the amount of cummulative curvature incurred
2099 #cat: among the IMAP neighbors of the given block.
2100
2101 Input:
2102 imap - 2D vector of ridge flow directions
2103 mx - horizontal coord of current IMAP block
2104 my - vertical coord of current IMAP block
2105 mw - width (in blocks) of the IMAP
2106 mh - height (in blocks) of the IMAP
2107 ndirs - number of possible directions in the IMAP
2108 Return Code:
2109 Non-negative - the measured vorticity among the neighbors
2110 **************************************************************************/
vorticity(int * imap,const int mx,const int my,const int mw,const int mh,const int ndirs)2111 int vorticity(int *imap, const int mx, const int my,
2112 const int mw, const int mh, const int ndirs)
2113 {
2114 int e_ind, w_ind, n_ind, s_ind;
2115 int nw_val, n_val, ne_val, e_val, se_val, s_val, sw_val, w_val;
2116 int vmeasure;
2117
2118 /* Compute neighbor coordinates to current IMAP direction */
2119 e_ind = mx+1; /* East index */
2120 w_ind = mx-1; /* West index */
2121 n_ind = my-1; /* North index */
2122 s_ind = my+1; /* South index */
2123
2124 /* 1. Get NW IMAP value. */
2125 /* If neighbor indices are within IMAP boundaries ... */
2126 if((w_ind >= 0) && (n_ind >= 0))
2127 /* Set neighbor value to IMAP value. */
2128 nw_val = *(imap + (n_ind*mw) + w_ind);
2129 else
2130 /* Otherwise, set the neighbor value to INVALID. */
2131 nw_val = INVALID_DIR;
2132
2133 /* 2. Get N IMAP value. */
2134 if(n_ind >= 0)
2135 n_val = *(imap + (n_ind*mw) + mx);
2136 else
2137 n_val = INVALID_DIR;
2138
2139 /* 3. Get NE IMAP value. */
2140 if((n_ind >= 0) && (e_ind < mw))
2141 ne_val = *(imap + (n_ind*mw) + e_ind);
2142 else
2143 ne_val = INVALID_DIR;
2144
2145 /* 4. Get E IMAP value. */
2146 if(e_ind < mw)
2147 e_val = *(imap + (my*mw) + e_ind);
2148 else
2149 e_val = INVALID_DIR;
2150
2151 /* 5. Get SE IMAP value. */
2152 if((e_ind < mw) && (s_ind < mh))
2153 se_val = *(imap + (s_ind*mw) + e_ind);
2154 else
2155 se_val = INVALID_DIR;
2156
2157 /* 6. Get S IMAP value. */
2158 if(s_ind < mh)
2159 s_val = *(imap + (s_ind*mw) + mx);
2160 else
2161 s_val = INVALID_DIR;
2162
2163 /* 7. Get SW IMAP value. */
2164 if((w_ind >= 0) && (s_ind < mh))
2165 sw_val = *(imap + (s_ind*mw) + w_ind);
2166 else
2167 sw_val = INVALID_DIR;
2168
2169 /* 8. Get W IMAP value. */
2170 if(w_ind >= 0)
2171 w_val = *(imap + (my*mw) + w_ind);
2172 else
2173 w_val = INVALID_DIR;
2174
2175 /* Now that we have all IMAP neighbors, accumulate vorticity between */
2176 /* the neighboring directions. */
2177
2178 /* Initialize vorticity accumulator to zero. */
2179 vmeasure = 0;
2180
2181 /* 1. NW & N */
2182 accum_nbr_vorticity(&vmeasure, nw_val, n_val, ndirs);
2183
2184 /* 2. N & NE */
2185 accum_nbr_vorticity(&vmeasure, n_val, ne_val, ndirs);
2186
2187 /* 3. NE & E */
2188 accum_nbr_vorticity(&vmeasure, ne_val, e_val, ndirs);
2189
2190 /* 4. E & SE */
2191 accum_nbr_vorticity(&vmeasure, e_val, se_val, ndirs);
2192
2193 /* 5. SE & S */
2194 accum_nbr_vorticity(&vmeasure, se_val, s_val, ndirs);
2195
2196 /* 6. S & SW */
2197 accum_nbr_vorticity(&vmeasure, s_val, sw_val, ndirs);
2198
2199 /* 7. SW & W */
2200 accum_nbr_vorticity(&vmeasure, sw_val, w_val, ndirs);
2201
2202 /* 8. W & NW */
2203 accum_nbr_vorticity(&vmeasure, w_val, nw_val, ndirs);
2204
2205 /* Return the accumulated vorticity measure. */
2206 return(vmeasure);
2207 }
2208
2209 /*************************************************************************
2210 **************************************************************************
2211 #cat: accum_nbor_vorticity - Accumlates the amount of curvature measures
2212 #cat: between neighboring IMAP blocks.
2213
2214 Input:
2215 dir1 - first neighbor's integer IMAP direction
2216 dir2 - second neighbor's integer IMAP direction
2217 ndirs - number of possible IMAP directions
2218 Output:
2219 vmeasure - accumulated vorticity among neighbors measured so far
2220 **************************************************************************/
accum_nbr_vorticity(int * vmeasure,const int dir1,const int dir2,const int ndirs)2221 void accum_nbr_vorticity(int *vmeasure, const int dir1, const int dir2,
2222 const int ndirs)
2223 {
2224 int dist;
2225
2226 /* Measure difference in direction between a pair of neighboring */
2227 /* directions. */
2228 /* If both neighbors are not equal and both are VALID ... */
2229 if((dir1 != dir2) && (dir1 >= 0)&&(dir2 >= 0)){
2230 /* Measure the clockwise distance from the first to the second */
2231 /* directions. */
2232 dist = dir2 - dir1;
2233 /* If dist is negative, then clockwise distance must wrap around */
2234 /* the high end of the direction range. For example: */
2235 /* dir1 = 8 */
2236 /* dir2 = 3 */
2237 /* and ndirs = 16 */
2238 /* 3 - 8 = -5 */
2239 /* so 16 - 5 = 11 (the clockwise distance from 8 to 3) */
2240 if(dist < 0)
2241 dist += ndirs;
2242 /* If the change in clockwise direction is larger than 90 degrees as */
2243 /* in total the total number of directions covers 180 degrees. */
2244 if(dist > (ndirs>>1))
2245 /* Decrement the vorticity measure. */
2246 (*vmeasure)--;
2247 else
2248 /* Otherwise, bump the vorticity measure. */
2249 (*vmeasure)++;
2250 }
2251 /* Otherwise both directions are either equal or */
2252 /* one or both directions are INVALID, so ignore. */
2253 }
2254
2255 /*************************************************************************
2256 **************************************************************************
2257 #cat: curvature - Measures the largest change in direction between the
2258 #cat: current IMAP direction and its immediate neighbors.
2259
2260 Input:
2261 imap - 2D vector of ridge flow directions
2262 mx - horizontal coord of current IMAP block
2263 my - vertical coord of current IMAP block
2264 mw - width (in blocks) of the IMAP
2265 mh - height (in blocks) of the IMAP
2266 ndirs - number of possible directions in the IMAP
2267 Return Code:
2268 Non-negative - maximum change in direction found (curvature)
2269 Negative - No valid neighbor found to measure change in direction
2270 **************************************************************************/
curvature(int * imap,const int mx,const int my,const int mw,const int mh,const int ndirs)2271 int curvature(int *imap, const int mx, const int my,
2272 const int mw, const int mh, const int ndirs)
2273 {
2274 int *iptr;
2275 int e_ind, w_ind, n_ind, s_ind;
2276 int nw_val, n_val, ne_val, e_val, se_val, s_val, sw_val, w_val;
2277 int cmeasure, dist;
2278
2279 /* Compute neighbor coordinates to current IMAP direction */
2280 e_ind = mx+1; /* East index */
2281 w_ind = mx-1; /* West index */
2282 n_ind = my-1; /* North index */
2283 s_ind = my+1; /* South index */
2284
2285 /* 1. Get NW IMAP value. */
2286 /* If neighbor indices are within IMAP boundaries ... */
2287 if((w_ind >= 0) && (n_ind >= 0))
2288 /* Set neighbor value to IMAP value. */
2289 nw_val = *(imap + (n_ind*mw) + w_ind);
2290 else
2291 /* Otherwise, set the neighbor value to INVALID. */
2292 nw_val = INVALID_DIR;
2293
2294 /* 2. Get N IMAP value. */
2295 if(n_ind >= 0)
2296 n_val = *(imap + (n_ind*mw) + mx);
2297 else
2298 n_val = INVALID_DIR;
2299
2300 /* 3. Get NE IMAP value. */
2301 if((n_ind >= 0) && (e_ind < mw))
2302 ne_val = *(imap + (n_ind*mw) + e_ind);
2303 else
2304 ne_val = INVALID_DIR;
2305
2306 /* 4. Get E IMAP value. */
2307 if(e_ind < mw)
2308 e_val = *(imap + (my*mw) + e_ind);
2309 else
2310 e_val = INVALID_DIR;
2311
2312 /* 5. Get SE IMAP value. */
2313 if((e_ind < mw) && (s_ind < mh))
2314 se_val = *(imap + (s_ind*mw) + e_ind);
2315 else
2316 se_val = INVALID_DIR;
2317
2318 /* 6. Get S IMAP value. */
2319 if(s_ind < mh)
2320 s_val = *(imap + (s_ind*mw) + mx);
2321 else
2322 s_val = INVALID_DIR;
2323
2324 /* 7. Get SW IMAP value. */
2325 if((w_ind >= 0) && (s_ind < mh))
2326 sw_val = *(imap + (s_ind*mw) + w_ind);
2327 else
2328 sw_val = INVALID_DIR;
2329
2330 /* 8. Get W IMAP value. */
2331 if(w_ind >= 0)
2332 w_val = *(imap + (my*mw) + w_ind);
2333 else
2334 w_val = INVALID_DIR;
2335
2336 /* Now that we have all IMAP neighbors, determine largest change in */
2337 /* direction from current block to each of its 8 VALID neighbors. */
2338
2339 /* Initialize pointer to current IMAP value. */
2340 iptr = imap + (my*mw) + mx;
2341
2342 /* Initialize curvature measure to negative as closest_dir_dist() */
2343 /* always returns -1=INVALID or a positive value. */
2344 cmeasure = -1;
2345
2346 /* 1. With NW */
2347 /* Compute closest distance between neighboring directions. */
2348 dist = closest_dir_dist(*iptr, nw_val, ndirs);
2349 /* Keep track of maximum. */
2350 if(dist > cmeasure)
2351 cmeasure = dist;
2352
2353 /* 2. With N */
2354 dist = closest_dir_dist(*iptr, n_val, ndirs);
2355 if(dist > cmeasure)
2356 cmeasure = dist;
2357
2358 /* 3. With NE */
2359 dist = closest_dir_dist(*iptr, ne_val, ndirs);
2360 if(dist > cmeasure)
2361 cmeasure = dist;
2362
2363 /* 4. With E */
2364 dist = closest_dir_dist(*iptr, e_val, ndirs);
2365 if(dist > cmeasure)
2366 cmeasure = dist;
2367
2368 /* 5. With SE */
2369 dist = closest_dir_dist(*iptr, se_val, ndirs);
2370 if(dist > cmeasure)
2371 cmeasure = dist;
2372
2373 /* 6. With S */
2374 dist = closest_dir_dist(*iptr, s_val, ndirs);
2375 if(dist > cmeasure)
2376 cmeasure = dist;
2377
2378 /* 7. With SW */
2379 dist = closest_dir_dist(*iptr, sw_val, ndirs);
2380 if(dist > cmeasure)
2381 cmeasure = dist;
2382
2383 /* 8. With W */
2384 dist = closest_dir_dist(*iptr, w_val, ndirs);
2385 if(dist > cmeasure)
2386 cmeasure = dist;
2387
2388 /* Return maximum difference between current block's IMAP direction */
2389 /* and the rest of its VALID neighbors. */
2390 return(cmeasure);
2391 }
2392