Home | History | Annotate | Download | only in b_ImageEm
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 /* ---- includes ----------------------------------------------------------- */
     18 
     19 #include "b_BasicEM/Math.h"
     20 #include "b_BasicEM/Memory.h"
     21 #include "b_BasicEM/Int16Arr.h"
     22 #include "b_BasicEM/Int32Arr.h"
     23 
     24 #include "b_ImageEM/ToneDownBGSupp.h"
     25 
     26 /* ------------------------------------------------------------------------- */
     27 
     28 /* ========================================================================= */
     29 /*                                                                           */
     30 /* ---- \ghd{ auxiliary functions } ---------------------------------------- */
     31 /*                                                                           */
     32 /* ========================================================================= */
     33 
     34 /* ------------------------------------------------------------------------- */
     35 
     36 /* ========================================================================= */
     37 /*                                                                           */
     38 /* ---- \ghd{ constructor / destructor } ----------------------------------- */
     39 /*                                                                           */
     40 /* ========================================================================= */
     41 
     42 /* ------------------------------------------------------------------------- */
     43 
     44 /* ========================================================================= */
     45 /*                                                                           */
     46 /* ---- \ghd{ operators } -------------------------------------------------- */
     47 /*                                                                           */
     48 /* ========================================================================= */
     49 
     50 /* ------------------------------------------------------------------------- */
     51 
     52 /* ========================================================================= */
     53 /*                                                                           */
     54 /* ---- \ghd{ query functions } -------------------------------------------- */
     55 /*                                                                           */
     56 /* ========================================================================= */
     57 
     58 /* ------------------------------------------------------------------------- */
     59 
     60 /* ========================================================================= */
     61 /*                                                                           */
     62 /* ---- \ghd{ modify functions } ------------------------------------------- */
     63 /*                                                                           */
     64 /* ========================================================================= */
     65 
     66 /* ------------------------------------------------------------------------- */
     67 
     68 /* ------------------------------------------------------------------------- */
     69 
     70 /* ========================================================================= */
     71 /*                                                                           */
     72 /* ---- \ghd{ I/O } -------------------------------------------------------- */
     73 /*                                                                           */
     74 /* ========================================================================= */
     75 
     76 /* ------------------------------------------------------------------------- */
     77 
     78 /* ========================================================================= */
     79 /*                                                                           */
     80 /* ---- \ghd{ exec functions } --------------------------------------------- */
     81 /*                                                                           */
     82 /* ========================================================================= */
     83 
     84 /* ------------------------------------------------------------------------- */
     85 
     86 void bim_ToneDownBGSupp_BGGreyLevelOutside( struct bim_UInt8Image* imgA,
     87 											struct bts_Int16Rect* rectA,
     88 											int16 rectExpansionA,
     89 											uint32* meanBGGrayLevelA )
     90 {
     91 	/* image access */
     92 	int16 iL, jL;
     93 	uint8 *imgPtrL = 0;
     94 	uint8 *imgPtrMaxL = 0;
     95 
     96 	/* the sum is possibly a large number. e.g. for a 512x512 byte image, maximum brightness, sumL is 7x10E7 */
     97 	uint32 sumL, ctrL;
     98 
     99 	/* the rectangle vertices */
    100 	int16 rectXMinL, rectXMaxL, rectYMinL, rectYMaxL;
    101 	int16 rectIxXMinL, rectIxXMaxL, rectIxYMinL, rectIxYMaxL;
    102 
    103 	/* expand the rectangle */
    104 
    105 	/* expand rectangle. the result is called the ROI */
    106 	rectXMinL = rectA->x1E + rectExpansionA;
    107 	rectXMaxL = rectA->x2E - rectExpansionA;
    108 	rectYMinL = rectA->y1E + rectExpansionA;
    109 	rectYMaxL = rectA->y2E - rectExpansionA;
    110 
    111 	rectIxXMinL = bbs_max( rectXMinL, ( int16 ) 0 );
    112 	rectIxXMaxL = bbs_max( rectXMaxL, ( int16 ) 0 );
    113 	rectIxXMaxL = bbs_min( rectXMaxL, ( int16 ) imgA->widthE );
    114 	rectIxYMinL = bbs_max( rectYMinL, ( int16 ) 0 );
    115 	rectIxYMaxL = bbs_min( rectYMaxL, ( int16 ) 0 );
    116 	rectIxYMaxL = bbs_min( rectYMaxL, ( int16 ) imgA->heightE );
    117 
    118 	/* avoid negative overlap */
    119 	rectIxXMinL = bbs_min( rectIxXMinL, rectIxXMaxL );
    120 	rectIxYMinL = bbs_min( rectIxYMinL, rectIxYMaxL );
    121 
    122 /*	printf( "new xmin=%d, xmax=%d, ymin=%d,ymax=%d \n", rectIxXMinL, rectIxXMaxL, rectIxYMinL, rectIxYMaxL ); */
    123 
    124 	/* part 1: sum up all the lines above the ROI */
    125 
    126 	sumL = 0;
    127 	ctrL = 0;
    128 
    129 	imgPtrL = &(imgA->arrE.arrPtrE[ 0 ]);
    130 	ctrL += rectIxYMinL * imgA->widthE;
    131 	imgPtrMaxL = imgPtrL + rectIxYMinL * imgA->widthE;
    132 	while ( imgPtrL < imgPtrMaxL )
    133 	{
    134 		sumL += *imgPtrL;
    135 		imgPtrL++;
    136 	}
    137 
    138 	/* part 2: sum up all the lines below the ROI */
    139 
    140 	ctrL += ( imgA->heightE - rectIxYMaxL ) * imgA->widthE;
    141 
    142 	imgPtrL = &(imgA->arrE.arrPtrE[ rectIxYMaxL * imgA->widthE ]);
    143 	imgPtrMaxL = &(imgA->arrE.arrPtrE[ imgA->heightE * imgA->widthE ]);
    144 	while ( imgPtrL < imgPtrMaxL )
    145 	{
    146 		sumL += *imgPtrL;
    147 		imgPtrL++;
    148 	}
    149 
    150 	/* part 3: sum over the two vertically adjacent blocks */
    151 
    152 	for ( jL = rectIxYMinL; jL < rectIxYMaxL; jL++ )
    153 	{
    154 		imgPtrL = &(imgA->arrE.arrPtrE[ rectIxYMinL * imgA->widthE ]);
    155 		ctrL += bbs_max( 0, rectIxXMinL );
    156 
    157 		for ( iL = 0; iL < rectIxXMinL; iL++ )
    158 		{
    159 			sumL += imgPtrL[ iL ];
    160 		}
    161 
    162 		if( ( int32 )imgA->widthE > ( int32 )rectIxXMaxL )
    163 		{
    164 			ctrL += ( int32 )imgA->widthE - ( int32 )rectIxXMaxL;
    165 		}
    166 
    167 		for ( iL = rectIxXMaxL; iL < ( int16 ) imgA->widthE; iL++ )
    168 		{
    169 			sumL += imgPtrL[ iL ];
    170 		}
    171 	}
    172 
    173 	/* printf( "new sum = %d, new ctr = %d \n", sumL, ctrL ); */
    174 
    175 	/* result is bpb=[16.16] */
    176 	*meanBGGrayLevelA = ( sumL << 16 ) / ( uint32 ) ctrL;
    177 
    178 	/* result is bpb=[16.16] */
    179 	*meanBGGrayLevelA = sumL / ctrL;								/* integer division */
    180 	sumL = sumL - *meanBGGrayLevelA * ctrL;							/* result always greater than or equal to zero */
    181 	*meanBGGrayLevelA = *meanBGGrayLevelA << 16;					/* shift to left */
    182 	*meanBGGrayLevelA = *meanBGGrayLevelA + ( sumL << 16 ) / ctrL;	/* add residue */
    183 
    184 }
    185 
    186 /* ------------------------------------------------------------------------- */
    187 
    188 void bim_ToneDownBGSupp_BGGreyLevelContour( struct bim_UInt8Image* imgA,
    189 											struct bts_Int16Rect* rectA,
    190 											uint32* meanBGGrayLevelA )
    191 {
    192 	/* image access */
    193 	int16 iL;
    194 	uint8 *imgPtr0L = 0;
    195 	uint8 *imgPtr1L = 0;
    196 
    197 	/* the sum is possibly a large number. e.g. for a 512x512 byte image, maximum brightness, sumL is 7x10E7 */
    198 	uint32 sumL, ctrL;
    199 
    200 	/* the rectangle vertices */
    201 	int16 rectXMinL, rectXMaxL, rectYMinL, rectYMaxL;
    202 	int16 rectIxXMinL, rectIxXMaxL, rectIxYMinL, rectIxYMaxL;
    203 	int16 rectMinWidthL = 10, rectMinHeightL = 10;
    204 	int16 rectXMidPointL, rectYMidPointL;
    205 	int16 shiftXRectL, shiftYRectL;
    206 
    207 	/* cut off the rectangle at the image bounaries
    208 	 * when its size becomes too small
    209 	 * the rectangle is shifted back inside the image */
    210 
    211 	/* cut off at image boundaries */
    212 	rectXMinL = rectA->x1E;
    213 	rectXMaxL = rectA->x2E;
    214 	rectYMinL = rectA->y1E;
    215 	rectYMaxL = rectA->y2E;
    216 
    217 	rectIxXMinL = bbs_max( rectXMinL, ( int16 ) 0 );
    218 	rectIxXMaxL = bbs_max( rectXMaxL, ( int16 ) 0 );
    219 	rectIxXMaxL = bbs_min( rectXMaxL, ( int16 ) imgA->widthE );
    220 	rectIxYMinL = bbs_max( rectYMinL, ( int16 ) 0 );
    221 	rectIxYMaxL = bbs_min( rectYMaxL, ( int16 ) 0 );
    222 	rectIxYMaxL = bbs_min( rectYMaxL, ( int16 ) imgA->heightE );
    223 
    224 	/* shift back into image */
    225 	shiftXRectL = 0;
    226 	shiftYRectL = 0;
    227 	if ( rectIxXMaxL - rectIxXMinL < rectMinWidthL )
    228 	{
    229 		rectXMidPointL = ( rectIxXMaxL + rectIxXMinL ) >> 1;
    230 		rectIxXMinL = rectXMidPointL - ( rectMinWidthL >> 1 );
    231 		rectIxXMaxL = rectXMidPointL + ( rectMinWidthL >> 1 );
    232 
    233 		if ( rectIxXMinL < 0 )
    234 		{
    235 			shiftXRectL = -rectIxXMinL;
    236 		}
    237 		if ( rectIxXMaxL > ( int16 ) imgA->widthE )
    238 		{
    239 			shiftXRectL = rectIxXMaxL - ( int16 ) imgA->widthE;
    240 		}
    241 	}
    242 	if ( rectIxYMaxL - rectIxYMinL < rectMinHeightL )
    243 	{
    244 		rectYMidPointL = ( rectIxYMaxL + rectIxYMinL ) >> 1;
    245 		rectIxYMinL = rectYMidPointL - ( rectMinWidthL >> 1 );
    246 		rectIxYMaxL = rectYMidPointL + ( rectMinWidthL >> 1 );
    247 
    248 		if ( rectIxYMinL < 0 )
    249 		{
    250 			shiftXRectL = -rectIxYMinL;
    251 		}
    252 		if ( rectIxYMaxL > ( int16 ) imgA->widthE )
    253 		{
    254 			shiftXRectL = rectIxYMaxL - ( int16 ) imgA->widthE;
    255 		}
    256 	}
    257 	rectIxXMinL += shiftXRectL;
    258 	rectIxXMaxL += shiftXRectL;
    259 	rectIxYMinL += shiftYRectL;
    260 	rectIxYMaxL += shiftYRectL;
    261 
    262 	/* when the image is small, there is a possibility that the shifted rectangle lies outside of the image.
    263 	 * => lop off the rectangle at image boundaries once again */
    264 	rectIxXMinL = bbs_max( rectXMinL, ( int16 ) 0 );
    265 	rectIxXMaxL = bbs_min( rectXMaxL, ( int16 ) imgA->widthE );
    266 	rectIxYMinL = bbs_max( rectYMinL, ( int16 ) 0 );
    267 	rectIxYMaxL = bbs_min( rectYMaxL, ( int16 ) imgA->heightE );
    268 
    269 
    270 	sumL = 0;
    271 	ctrL = 0;
    272 	ctrL += ( rectIxXMaxL - rectIxXMinL ) << 1;
    273 	ctrL += ( rectIxYMaxL - rectIxYMinL - 2 ) << 1;
    274 
    275 	/* loop over the contour */
    276 	imgPtr0L = &(imgA->arrE.arrPtrE[ rectIxYMinL * imgA->widthE ]);
    277 	imgPtr1L = &(imgA->arrE.arrPtrE[ ( rectIxYMaxL - 1 ) * imgA->widthE ]);
    278 	for ( iL = rectIxXMinL; iL < rectIxXMaxL; iL++ )
    279 	{
    280 		sumL += imgPtr0L[ iL ];
    281 		sumL += imgPtr1L[ iL ];
    282 	}
    283 	imgPtr0L = &(imgA->arrE.arrPtrE[ ( rectIxYMinL + 1 ) * imgA->widthE + rectIxXMinL ]);
    284 	imgPtr1L = &(imgA->arrE.arrPtrE[ ( rectIxYMinL + 1 ) * imgA->widthE + rectIxXMaxL - 1 ]);
    285 	for ( iL = rectIxYMinL + 1; iL < rectIxYMaxL - 1; iL++ )
    286 	{
    287 		sumL += *imgPtr0L;
    288 		sumL += *imgPtr1L;
    289 		imgPtr0L += imgA->widthE;
    290 		imgPtr1L += imgA->widthE;
    291 	}
    292 
    293 
    294 	/* printf( "new sum = %d, new ctr = %d \n", sumL, ctrL ); */
    295 
    296 	/* result is bpb=[16.16] */
    297 	*meanBGGrayLevelA = ( sumL << 16 ) / ( uint32 ) ctrL;
    298 
    299 	/* result is bpb=[16.16] */
    300 	*meanBGGrayLevelA = sumL / ctrL;								/* integer division */
    301 	sumL = sumL - *meanBGGrayLevelA * ctrL;							/* result always greater than or equal to zero */
    302 	*meanBGGrayLevelA = *meanBGGrayLevelA << 16;					/* shift to left */
    303 	*meanBGGrayLevelA = *meanBGGrayLevelA + ( sumL << 16 ) / ctrL;	/* add residue */
    304 }
    305 
    306 /* ------------------------------------------------------------------------- */
    307 
    308 void bim_ToneDownBGSupp_suppress( struct bim_UInt8Image* imgA,
    309 								  struct bts_Int16Rect* rectA,
    310 								  int16 rectShrinkageA,
    311 								  int32 toneDownFactorA,	/* ToDo: change to int16, bpb=[0.16] */
    312 								  int32 cutOffAccuracyA )
    313 {
    314 	/* ((( variable declarations begin ))) */
    315 
    316 	/* the rectangle vertices */
    317 	int16 rectXMinL, rectXMaxL, rectYMinL, rectYMaxL;
    318 	int16 rectIxXMinL, rectIxXMaxL, rectIxYMinL, rectIxYMaxL;
    319 	int16 rectShrinkageL;
    320 
    321 	/* the BG mean grey value */
    322 	uint8  meanBGGreyBBPL;
    323 	uint32 meanBGGreyLevelL;
    324 	uint32 meanBGGreyLevelByteL;
    325 	int32  meanBGGreyLevelLongL;
    326 
    327 	/* maximum reach of the ROI */
    328 	uint32 maxROIReachL;
    329 	int16  rOIReachXMinL, rOIReachXMaxL, rOIReachYMinL, rOIReachYMaxL;
    330 	int16  rOIReachIxXMinL, rOIReachIxXMaxL, rOIReachIxYMinL, rOIReachIxYMaxL;
    331 	int16  ridgeIxLeftL, ridgeIxRightL;
    332 
    333 	/* tone down table */
    334 	struct bbs_Int32Arr toneDownFactorsL;	/* ToDo: change int32 bpb=[16.16] to uint bpb=[0.16] */
    335 	int32 toneDownFactorPowA;
    336 	int32* toneDownFactorsPtrL;
    337 	int32 ctrL;
    338 
    339 	/* image access */
    340 	int16 iL, jL;
    341 	uint8 *imgPtrL = 0;	/* welcome back to the stoneage */
    342 
    343 	/* weighting formula */
    344 	int32 weightL, invWeightL;		/* R=[0.0...1.0], bpb=[16.16] */
    345 	int32 opSrcL, opBGL, sumL;		/* R=[0.0...255.0], bpb=[24,8] */
    346 
    347 	/* ((( variable declarations end ))) */
    348 
    349 	/* make sure that the width is smaller than the rectangle */
    350 	rectShrinkageL = rectShrinkageA;
    351 	rectShrinkageL = bbs_min( rectShrinkageL, ( rectA->x2E - rectA->x1E ) >> 1 );
    352 	rectShrinkageL = bbs_min( rectShrinkageL, ( rectA->y2E - rectA->y1E ) >> 1 );
    353 
    354 	/* shrink rectangle. the result is called the ROI */
    355 	rectXMinL = rectA->x1E + rectShrinkageL;
    356 	rectXMaxL = rectA->x2E - rectShrinkageL;
    357 	rectYMinL = rectA->y1E + rectShrinkageL;
    358 	rectYMaxL = rectA->y2E - rectShrinkageL;
    359 
    360 	rectIxXMinL = bbs_max( rectXMinL, 0 );
    361 	rectIxXMinL = bbs_min( rectIxXMinL, ( int16 ) imgA->widthE );
    362 	rectIxXMaxL = bbs_min( rectXMaxL, ( int16 ) imgA->widthE );
    363 	rectIxXMaxL = bbs_max( rectIxXMaxL, 0 );
    364 
    365 	rectIxYMinL = bbs_max( rectYMinL, 0 );
    366 	rectIxYMinL = bbs_min( rectIxYMinL, ( int16 ) imgA->heightE );
    367 	rectIxYMaxL = bbs_min( rectYMaxL, ( int16 ) imgA->heightE );
    368 	rectIxYMaxL = bbs_max( rectIxYMaxL, 0 );
    369 
    370 	/* exit function at exceptional cases */
    371 	if ( ( imgA->heightE == 0 ) || ( imgA->widthE == 0 ) ) return;
    372 	if ( rectShrinkageL == 0 ) return;
    373 
    374 	/* compute the mean gray level aloong the rectangle contour */
    375 	bim_ToneDownBGSupp_BGGreyLevelContour( imgA, rectA, &meanBGGreyLevelL );
    376 
    377 	/* printf( "new mean BG gray value = %f \n", ( float ) meanBGGreyLevelL / 65536.0f ); */
    378 
    379 	/* R=[0.0...255.0], bpb=[24.8] */
    380 	meanBGGreyBBPL = 16;
    381 	meanBGGreyLevelL = ( 128 << meanBGGreyBBPL );
    382 	meanBGGreyLevelByteL = meanBGGreyLevelL >> meanBGGreyBBPL;
    383 	meanBGGreyLevelLongL = ( 128 << meanBGGreyBBPL );
    384 	/* ToDo ToDo ToDo ToDo ToDo ToDo ToDo ToDo ToDo ToDo ToDo ToDo ToDo ToDo ToDo ToDo ToDo ToDo ToDo ToDo ToDo */
    385 
    386 	/* this function computes an image that moving away from the ROI gradually fades to
    387 	 * the background grey level BG according to the formula
    388 	 * tonedImg = w srcImg + (1-w) BG
    389 	 * w depends on the distance to the ROI.
    390 	 * there is a distance maxROIReachL beyond which
    391 	 * the importance of the source image
    392 	 * relative to the BG in the equation
    393 	 * falls below a small threshold.
    394 	 * in those regions the toned image is equal to
    395 	 * the mean BG grey value. i.e. w=0, tonedImg = BG */
    396 	maxROIReachL = bbs_max( imgA->widthE, imgA->heightE );
    397 
    398 	/* pre-compute an array of tone down factors. R=[0.0...1.0] => bpb=[0.16] (idealy, bpb=[16.16] due to missing uInt16Arr ) */
    399 	bbs_Int32Arr_init( &toneDownFactorsL );
    400 	bbs_Int32Arr_size( &toneDownFactorsL, maxROIReachL );
    401 	toneDownFactorPowA = toneDownFactorA;
    402 	toneDownFactorsPtrL = toneDownFactorsL.arrPtrE;
    403 	for( ctrL = 0; ctrL < ( int32 ) maxROIReachL && toneDownFactorPowA > cutOffAccuracyA; ctrL++ )
    404 	{
    405 		toneDownFactorsPtrL[ ctrL ] = toneDownFactorPowA;
    406 		toneDownFactorPowA = toneDownFactorPowA * ( toneDownFactorA >> 1 );
    407 		toneDownFactorPowA = toneDownFactorPowA >> 15;
    408 
    409 		/* make active to check the error that accumulates by recursively multiplying factors */
    410 		/* printf( "pow = %d, tonedown dec = %d, tonedown float = %f \n", ctrL + 2, toneDownFactorPowA, toneDownFactorPowA / 65536.0f ); */
    411 	}
    412 	maxROIReachL = ctrL;
    413 	/* printf( "maxROIReachL = %d, tonedown = %d \n", maxROIReachL, toneDownFactorPowA ); */
    414 
    415 	/* move across the image one row at a time.
    416 	 * (1) fill the outside frame with BG grey level
    417 	 * (2) blend in the original image moving towards the ROI
    418 	 */
    419 
    420 	rOIReachXMinL = rectXMinL - ( int32 ) maxROIReachL;
    421 	rOIReachXMaxL = rectXMaxL + ( int32 ) maxROIReachL;
    422 	rOIReachYMinL = rectYMinL - ( int32 ) maxROIReachL;
    423 	rOIReachYMaxL = rectYMaxL + ( int32 ) maxROIReachL;
    424 
    425 	rOIReachIxXMinL = bbs_max( rOIReachXMinL, ( int16 ) 0 );
    426 	rOIReachIxXMinL = bbs_min( rOIReachIxXMinL, ( int16 ) imgA->widthE );
    427 	rOIReachIxXMaxL = bbs_min( rOIReachXMaxL, ( int16 ) imgA->widthE );
    428 	rOIReachIxXMaxL = bbs_max( rOIReachIxXMaxL, ( int16 ) 0 );
    429 
    430 	rOIReachIxYMinL = bbs_max( rOIReachYMinL, ( int16 ) 0 );
    431 	rOIReachIxYMinL = bbs_min( rOIReachIxYMinL, ( int16 ) imgA->heightE );
    432 	rOIReachIxYMaxL = bbs_min( rOIReachYMaxL, ( int16 ) imgA->heightE );
    433 	rOIReachIxYMaxL = bbs_max( rOIReachIxYMaxL, ( int16 ) 0 );
    434 
    435 	/* (1) far from the ROI the image is filled with the BG grey value */
    436 
    437 	imgPtrL = 0;
    438 	for ( jL = 0; jL < rOIReachYMinL; jL++ )
    439 	{
    440 		imgPtrL = &( imgA->arrE.arrPtrE[ jL * imgA->widthE ] );
    441 		for ( iL = 0; iL <= ( int16 ) imgA->widthE; iL++ )
    442 		{
    443 			imgPtrL[ iL ] = meanBGGreyLevelByteL;
    444 		}
    445 	}
    446 	for ( jL = rOIReachYMaxL; jL < ( int16 ) imgA->heightE; jL++ )
    447 	{
    448 		imgPtrL = &( imgA->arrE.arrPtrE[ jL * imgA->widthE ] );
    449 		for ( iL = 0; iL <= ( int16 ) imgA->widthE; iL++ )
    450 		{
    451 			imgPtrL[ iL ] = meanBGGreyLevelByteL;
    452 		}
    453 	}
    454 	for ( jL = rOIReachIxYMinL; jL < rOIReachIxYMaxL; jL++ )
    455 	{
    456 		imgPtrL = &( imgA->arrE.arrPtrE[ jL * imgA->widthE ] );
    457 		for ( iL = 0; iL < rOIReachXMinL; iL++ )
    458 		{
    459 			imgPtrL[ iL ] = meanBGGreyLevelByteL;
    460 		}
    461 		for ( iL = rOIReachXMaxL; iL < ( int16 ) imgA->widthE; iL++ )
    462 		{
    463 			imgPtrL[ iL ] = meanBGGreyLevelByteL;
    464 		}
    465 	}
    466 
    467 	/* (2) blend from ROI to outside regions */
    468 
    469 	for ( jL = rOIReachIxYMinL; jL < rectIxYMinL; jL++ )
    470 	{
    471 		/* the factor for one row is a constant */
    472 		weightL = ( int32 ) toneDownFactorsPtrL[ maxROIReachL - 1 - ( jL - rOIReachYMinL ) ];
    473 		invWeightL = 0x00010000 - weightL;
    474 		opBGL = ( meanBGGreyLevelLongL >> 9 ) * invWeightL;				/* result is bpb=[8,24] */
    475 		opBGL = opBGL >> 7;
    476 		imgPtrL = &( imgA->arrE.arrPtrE[ jL * imgA->widthE ] );
    477 
    478 		/* compute the ridge position */
    479 		ridgeIxLeftL = bbs_max( 0, rOIReachXMinL + jL - rOIReachYMinL );
    480 		ridgeIxRightL = bbs_min( ( int16 ) imgA->widthE - 1, rOIReachXMaxL - 1 - ( jL - rOIReachYMinL ) );
    481 
    482 		/* loop over all elements from left ridge through right ridge */
    483 		for ( iL = ridgeIxLeftL; iL <= ridgeIxRightL; iL++ )
    484 		{
    485 			opSrcL = imgPtrL[ iL ];							/* leave at byte */
    486 			opSrcL = opSrcL * weightL;						/* result is bpb=[16,16] */
    487 			sumL = opSrcL + opBGL;							/* OF impossible */
    488 			imgPtrL[ iL ] = sumL >> 16;						/* round to byte */
    489 		}
    490 	}
    491 	for ( jL = rOIReachIxYMaxL - 1; jL >= rectIxYMaxL; jL-- )
    492 	{
    493 		/* the factor for one row is a constant */
    494 		weightL = ( int32 ) toneDownFactorsPtrL[ maxROIReachL - 1 - ( rOIReachYMaxL - 1 - jL ) ];
    495 		invWeightL = 0x00010000 - weightL;
    496 		opBGL = ( meanBGGreyLevelLongL >> 9 ) * invWeightL;				/* result is bpb=[8,24] */
    497 		opBGL = opBGL >> 7;
    498 		imgPtrL = &( imgA->arrE.arrPtrE[ jL * imgA->widthE ] );
    499 
    500 		/* compute the ridge position */
    501 		ridgeIxLeftL = bbs_max( 0, rOIReachXMinL + ( rOIReachYMaxL - 1 - jL ) );
    502 		ridgeIxRightL = bbs_min( ( int16 ) imgA->widthE - 1, rOIReachXMaxL - 1 - ( rOIReachYMaxL - 1 - jL ) );
    503 
    504 		/* loop over all elements from left ridge through right ridge */
    505 		for ( iL = ridgeIxLeftL; iL <= ridgeIxRightL; iL++ )
    506 		{
    507 			opSrcL = imgPtrL[ iL ];							/* leave at byte */
    508 			opSrcL = opSrcL * weightL;						/* result is bpb=[16,16] */
    509 			sumL = opSrcL + opBGL;							/* OF impossible */
    510 			imgPtrL[ iL ] = sumL >> 16;						/* round to byte */
    511 		}
    512 	}
    513 	for ( jL = rOIReachIxYMinL; jL < rOIReachIxYMaxL; jL++ )
    514 	{
    515 		imgPtrL = &( imgA->arrE.arrPtrE[ jL * imgA->widthE ] );
    516 
    517 		ridgeIxLeftL = bbs_min( rOIReachXMinL + ( jL - rOIReachYMinL ) - 1, rectXMinL - 1 );
    518 		ridgeIxLeftL = bbs_min( ridgeIxLeftL, rOIReachXMinL + ( rOIReachYMaxL - 1 - jL ) - 1 );
    519 		for ( iL = rOIReachIxXMinL; iL <= ridgeIxLeftL; iL++ )
    520 		{
    521 			weightL = ( int32 ) toneDownFactorsPtrL[ maxROIReachL - 1 - ( iL - rOIReachXMinL ) ];
    522 			invWeightL = 0x00010000 - weightL;
    523 			opBGL = ( meanBGGreyLevelLongL >> 9 ) * invWeightL;				/* result is bpb=[16,16] */
    524 			opBGL = opBGL >> 7;
    525 
    526 			opSrcL = imgPtrL[ iL ];											/* leave at byte */
    527 			opSrcL = opSrcL * weightL;										/* result is bpb=[16,16] */
    528 			sumL = opSrcL + opBGL;											/* OF impossible */
    529 			imgPtrL[ iL ] = sumL >> 16;										/* round to byte */
    530 		}
    531 
    532 		ridgeIxRightL = bbs_max( rOIReachXMaxL - 1 - ( jL - rOIReachYMinL ) + 1 , rectXMaxL );
    533 		ridgeIxRightL = bbs_max( ridgeIxRightL, rOIReachXMaxL - 1 - ( rOIReachYMaxL - 1 - jL ) + 1 );
    534 		for ( iL = ridgeIxRightL; iL < rOIReachIxXMaxL; iL++ )
    535 		{
    536 			weightL = ( int32 ) toneDownFactorsPtrL[ iL - rectXMaxL ];
    537 			invWeightL = 0x00010000 - weightL;
    538 			opBGL = ( meanBGGreyLevelLongL >> 9 ) * invWeightL;				/* result is bpb=[16,16] */
    539 			opBGL = opBGL >> 7;
    540 
    541 			opSrcL = imgPtrL[ iL ];											/* leave at byte */
    542 			opSrcL = opSrcL * weightL;										/* result is bpb=[16,16] */
    543 			sumL = opSrcL + opBGL;											/* OF impossible */
    544 			imgPtrL[ iL ] = sumL >> 16;										/* round to byte */
    545 		}
    546 	}
    547 }
    548 
    549 /* ------------------------------------------------------------------------- */
    550 
    551 /* ========================================================================= */
    552