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 
bim_ToneDownBGSupp_BGGreyLevelOutside(struct bim_UInt8Image * imgA,struct bts_Int16Rect * rectA,int16 rectExpansionA,uint32 * meanBGGrayLevelA)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 
bim_ToneDownBGSupp_BGGreyLevelContour(struct bim_UInt8Image * imgA,struct bts_Int16Rect * rectA,uint32 * meanBGGrayLevelA)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 
bim_ToneDownBGSupp_suppress(struct bim_UInt8Image * imgA,struct bts_Int16Rect * rectA,int16 rectShrinkageA,int32 toneDownFactorA,int32 cutOffAccuracyA)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