/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* ---- includes ----------------------------------------------------------- */
#include "b_BasicEM/Math.h"
#include "b_BasicEM/Memory.h"
#include "b_BasicEM/Int16Arr.h"
#include "b_BasicEM/Int32Arr.h"
#include "b_ImageEM/ToneDownBGSupp.h"
/* ------------------------------------------------------------------------- */
/* ========================================================================= */
/* */
/* ---- \ghd{ auxiliary functions } ---------------------------------------- */
/* */
/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/* ========================================================================= */
/* */
/* ---- \ghd{ constructor / destructor } ----------------------------------- */
/* */
/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/* ========================================================================= */
/* */
/* ---- \ghd{ operators } -------------------------------------------------- */
/* */
/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/* ========================================================================= */
/* */
/* ---- \ghd{ query functions } -------------------------------------------- */
/* */
/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/* ========================================================================= */
/* */
/* ---- \ghd{ modify functions } ------------------------------------------- */
/* */
/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
/* ========================================================================= */
/* */
/* ---- \ghd{ I/O } -------------------------------------------------------- */
/* */
/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/* ========================================================================= */
/* */
/* ---- \ghd{ exec functions } --------------------------------------------- */
/* */
/* ========================================================================= */
/* ------------------------------------------------------------------------- */
void bim_ToneDownBGSupp_BGGreyLevelOutside( struct bim_UInt8Image* imgA,
struct bts_Int16Rect* rectA,
int16 rectExpansionA,
uint32* meanBGGrayLevelA )
{
/* image access */
int16 iL, jL;
uint8 *imgPtrL = 0;
uint8 *imgPtrMaxL = 0;
/* the sum is possibly a large number. e.g. for a 512x512 byte image, maximum brightness, sumL is 7x10E7 */
uint32 sumL, ctrL;
/* the rectangle vertices */
int16 rectXMinL, rectXMaxL, rectYMinL, rectYMaxL;
int16 rectIxXMinL, rectIxXMaxL, rectIxYMinL, rectIxYMaxL;
/* expand the rectangle */
/* expand rectangle. the result is called the ROI */
rectXMinL = rectA->x1E + rectExpansionA;
rectXMaxL = rectA->x2E - rectExpansionA;
rectYMinL = rectA->y1E + rectExpansionA;
rectYMaxL = rectA->y2E - rectExpansionA;
rectIxXMinL = bbs_max( rectXMinL, ( int16 ) 0 );
rectIxXMaxL = bbs_max( rectXMaxL, ( int16 ) 0 );
rectIxXMaxL = bbs_min( rectXMaxL, ( int16 ) imgA->widthE );
rectIxYMinL = bbs_max( rectYMinL, ( int16 ) 0 );
rectIxYMaxL = bbs_min( rectYMaxL, ( int16 ) 0 );
rectIxYMaxL = bbs_min( rectYMaxL, ( int16 ) imgA->heightE );
/* avoid negative overlap */
rectIxXMinL = bbs_min( rectIxXMinL, rectIxXMaxL );
rectIxYMinL = bbs_min( rectIxYMinL, rectIxYMaxL );
/* printf( "new xmin=%d, xmax=%d, ymin=%d,ymax=%d \n", rectIxXMinL, rectIxXMaxL, rectIxYMinL, rectIxYMaxL ); */
/* part 1: sum up all the lines above the ROI */
sumL = 0;
ctrL = 0;
imgPtrL = &(imgA->arrE.arrPtrE[ 0 ]);
ctrL += rectIxYMinL * imgA->widthE;
imgPtrMaxL = imgPtrL + rectIxYMinL * imgA->widthE;
while ( imgPtrL < imgPtrMaxL )
{
sumL += *imgPtrL;
imgPtrL++;
}
/* part 2: sum up all the lines below the ROI */
ctrL += ( imgA->heightE - rectIxYMaxL ) * imgA->widthE;
imgPtrL = &(imgA->arrE.arrPtrE[ rectIxYMaxL * imgA->widthE ]);
imgPtrMaxL = &(imgA->arrE.arrPtrE[ imgA->heightE * imgA->widthE ]);
while ( imgPtrL < imgPtrMaxL )
{
sumL += *imgPtrL;
imgPtrL++;
}
/* part 3: sum over the two vertically adjacent blocks */
for ( jL = rectIxYMinL; jL < rectIxYMaxL; jL++ )
{
imgPtrL = &(imgA->arrE.arrPtrE[ rectIxYMinL * imgA->widthE ]);
ctrL += bbs_max( 0, rectIxXMinL );
for ( iL = 0; iL < rectIxXMinL; iL++ )
{
sumL += imgPtrL[ iL ];
}
if( ( int32 )imgA->widthE > ( int32 )rectIxXMaxL )
{
ctrL += ( int32 )imgA->widthE - ( int32 )rectIxXMaxL;
}
for ( iL = rectIxXMaxL; iL < ( int16 ) imgA->widthE; iL++ )
{
sumL += imgPtrL[ iL ];
}
}
/* printf( "new sum = %d, new ctr = %d \n", sumL, ctrL ); */
/* result is bpb=[16.16] */
*meanBGGrayLevelA = ( sumL << 16 ) / ( uint32 ) ctrL;
/* result is bpb=[16.16] */
*meanBGGrayLevelA = sumL / ctrL; /* integer division */
sumL = sumL - *meanBGGrayLevelA * ctrL; /* result always greater than or equal to zero */
*meanBGGrayLevelA = *meanBGGrayLevelA << 16; /* shift to left */
*meanBGGrayLevelA = *meanBGGrayLevelA + ( sumL << 16 ) / ctrL; /* add residue */
}
/* ------------------------------------------------------------------------- */
void bim_ToneDownBGSupp_BGGreyLevelContour( struct bim_UInt8Image* imgA,
struct bts_Int16Rect* rectA,
uint32* meanBGGrayLevelA )
{
/* image access */
int16 iL;
uint8 *imgPtr0L = 0;
uint8 *imgPtr1L = 0;
/* the sum is possibly a large number. e.g. for a 512x512 byte image, maximum brightness, sumL is 7x10E7 */
uint32 sumL, ctrL;
/* the rectangle vertices */
int16 rectXMinL, rectXMaxL, rectYMinL, rectYMaxL;
int16 rectIxXMinL, rectIxXMaxL, rectIxYMinL, rectIxYMaxL;
int16 rectMinWidthL = 10, rectMinHeightL = 10;
int16 rectXMidPointL, rectYMidPointL;
int16 shiftXRectL, shiftYRectL;
/* cut off the rectangle at the image bounaries
* when its size becomes too small
* the rectangle is shifted back inside the image */
/* cut off at image boundaries */
rectXMinL = rectA->x1E;
rectXMaxL = rectA->x2E;
rectYMinL = rectA->y1E;
rectYMaxL = rectA->y2E;
rectIxXMinL = bbs_max( rectXMinL, ( int16 ) 0 );
rectIxXMaxL = bbs_max( rectXMaxL, ( int16 ) 0 );
rectIxXMaxL = bbs_min( rectXMaxL, ( int16 ) imgA->widthE );
rectIxYMinL = bbs_max( rectYMinL, ( int16 ) 0 );
rectIxYMaxL = bbs_min( rectYMaxL, ( int16 ) 0 );
rectIxYMaxL = bbs_min( rectYMaxL, ( int16 ) imgA->heightE );
/* shift back into image */
shiftXRectL = 0;
shiftYRectL = 0;
if ( rectIxXMaxL - rectIxXMinL < rectMinWidthL )
{
rectXMidPointL = ( rectIxXMaxL + rectIxXMinL ) >> 1;
rectIxXMinL = rectXMidPointL - ( rectMinWidthL >> 1 );
rectIxXMaxL = rectXMidPointL + ( rectMinWidthL >> 1 );
if ( rectIxXMinL < 0 )
{
shiftXRectL = -rectIxXMinL;
}
if ( rectIxXMaxL > ( int16 ) imgA->widthE )
{
shiftXRectL = rectIxXMaxL - ( int16 ) imgA->widthE;
}
}
if ( rectIxYMaxL - rectIxYMinL < rectMinHeightL )
{
rectYMidPointL = ( rectIxYMaxL + rectIxYMinL ) >> 1;
rectIxYMinL = rectYMidPointL - ( rectMinWidthL >> 1 );
rectIxYMaxL = rectYMidPointL + ( rectMinWidthL >> 1 );
if ( rectIxYMinL < 0 )
{
shiftXRectL = -rectIxYMinL;
}
if ( rectIxYMaxL > ( int16 ) imgA->widthE )
{
shiftXRectL = rectIxYMaxL - ( int16 ) imgA->widthE;
}
}
rectIxXMinL += shiftXRectL;
rectIxXMaxL += shiftXRectL;
rectIxYMinL += shiftYRectL;
rectIxYMaxL += shiftYRectL;
/* when the image is small, there is a possibility that the shifted rectangle lies outside of the image.
* => lop off the rectangle at image boundaries once again */
rectIxXMinL = bbs_max( rectXMinL, ( int16 ) 0 );
rectIxXMaxL = bbs_min( rectXMaxL, ( int16 ) imgA->widthE );
rectIxYMinL = bbs_max( rectYMinL, ( int16 ) 0 );
rectIxYMaxL = bbs_min( rectYMaxL, ( int16 ) imgA->heightE );
sumL = 0;
ctrL = 0;
ctrL += ( rectIxXMaxL - rectIxXMinL ) << 1;
ctrL += ( rectIxYMaxL - rectIxYMinL - 2 ) << 1;
/* loop over the contour */
imgPtr0L = &(imgA->arrE.arrPtrE[ rectIxYMinL * imgA->widthE ]);
imgPtr1L = &(imgA->arrE.arrPtrE[ ( rectIxYMaxL - 1 ) * imgA->widthE ]);
for ( iL = rectIxXMinL; iL < rectIxXMaxL; iL++ )
{
sumL += imgPtr0L[ iL ];
sumL += imgPtr1L[ iL ];
}
imgPtr0L = &(imgA->arrE.arrPtrE[ ( rectIxYMinL + 1 ) * imgA->widthE + rectIxXMinL ]);
imgPtr1L = &(imgA->arrE.arrPtrE[ ( rectIxYMinL + 1 ) * imgA->widthE + rectIxXMaxL - 1 ]);
for ( iL = rectIxYMinL + 1; iL < rectIxYMaxL - 1; iL++ )
{
sumL += *imgPtr0L;
sumL += *imgPtr1L;
imgPtr0L += imgA->widthE;
imgPtr1L += imgA->widthE;
}
/* printf( "new sum = %d, new ctr = %d \n", sumL, ctrL ); */
/* result is bpb=[16.16] */
*meanBGGrayLevelA = ( sumL << 16 ) / ( uint32 ) ctrL;
/* result is bpb=[16.16] */
*meanBGGrayLevelA = sumL / ctrL; /* integer division */
sumL = sumL - *meanBGGrayLevelA * ctrL; /* result always greater than or equal to zero */
*meanBGGrayLevelA = *meanBGGrayLevelA << 16; /* shift to left */
*meanBGGrayLevelA = *meanBGGrayLevelA + ( sumL << 16 ) / ctrL; /* add residue */
}
/* ------------------------------------------------------------------------- */
void bim_ToneDownBGSupp_suppress( struct bim_UInt8Image* imgA,
struct bts_Int16Rect* rectA,
int16 rectShrinkageA,
int32 toneDownFactorA, /* ToDo: change to int16, bpb=[0.16] */
int32 cutOffAccuracyA )
{
/* ((( variable declarations begin ))) */
/* the rectangle vertices */
int16 rectXMinL, rectXMaxL, rectYMinL, rectYMaxL;
int16 rectIxXMinL, rectIxXMaxL, rectIxYMinL, rectIxYMaxL;
int16 rectShrinkageL;
/* the BG mean grey value */
uint8 meanBGGreyBBPL;
uint32 meanBGGreyLevelL;
uint32 meanBGGreyLevelByteL;
int32 meanBGGreyLevelLongL;
/* maximum reach of the ROI */
uint32 maxROIReachL;
int16 rOIReachXMinL, rOIReachXMaxL, rOIReachYMinL, rOIReachYMaxL;
int16 rOIReachIxXMinL, rOIReachIxXMaxL, rOIReachIxYMinL, rOIReachIxYMaxL;
int16 ridgeIxLeftL, ridgeIxRightL;
/* tone down table */
struct bbs_Int32Arr toneDownFactorsL; /* ToDo: change int32 bpb=[16.16] to uint bpb=[0.16] */
int32 toneDownFactorPowA;
int32* toneDownFactorsPtrL;
int32 ctrL;
/* image access */
int16 iL, jL;
uint8 *imgPtrL = 0; /* welcome back to the stoneage */
/* weighting formula */
int32 weightL, invWeightL; /* R=[0.0...1.0], bpb=[16.16] */
int32 opSrcL, opBGL, sumL; /* R=[0.0...255.0], bpb=[24,8] */
/* ((( variable declarations end ))) */
/* make sure that the width is smaller than the rectangle */
rectShrinkageL = rectShrinkageA;
rectShrinkageL = bbs_min( rectShrinkageL, ( rectA->x2E - rectA->x1E ) >> 1 );
rectShrinkageL = bbs_min( rectShrinkageL, ( rectA->y2E - rectA->y1E ) >> 1 );
/* shrink rectangle. the result is called the ROI */
rectXMinL = rectA->x1E + rectShrinkageL;
rectXMaxL = rectA->x2E - rectShrinkageL;
rectYMinL = rectA->y1E + rectShrinkageL;
rectYMaxL = rectA->y2E - rectShrinkageL;
rectIxXMinL = bbs_max( rectXMinL, 0 );
rectIxXMinL = bbs_min( rectIxXMinL, ( int16 ) imgA->widthE );
rectIxXMaxL = bbs_min( rectXMaxL, ( int16 ) imgA->widthE );
rectIxXMaxL = bbs_max( rectIxXMaxL, 0 );
rectIxYMinL = bbs_max( rectYMinL, 0 );
rectIxYMinL = bbs_min( rectIxYMinL, ( int16 ) imgA->heightE );
rectIxYMaxL = bbs_min( rectYMaxL, ( int16 ) imgA->heightE );
rectIxYMaxL = bbs_max( rectIxYMaxL, 0 );
/* exit function at exceptional cases */
if ( ( imgA->heightE == 0 ) || ( imgA->widthE == 0 ) ) return;
if ( rectShrinkageL == 0 ) return;
/* compute the mean gray level aloong the rectangle contour */
bim_ToneDownBGSupp_BGGreyLevelContour( imgA, rectA, &meanBGGreyLevelL );
/* printf( "new mean BG gray value = %f \n", ( float ) meanBGGreyLevelL / 65536.0f ); */
/* R=[0.0...255.0], bpb=[24.8] */
meanBGGreyBBPL = 16;
meanBGGreyLevelL = ( 128 << meanBGGreyBBPL );
meanBGGreyLevelByteL = meanBGGreyLevelL >> meanBGGreyBBPL;
meanBGGreyLevelLongL = ( 128 << meanBGGreyBBPL );
/* ToDo ToDo ToDo ToDo ToDo ToDo ToDo ToDo ToDo ToDo ToDo ToDo ToDo ToDo ToDo ToDo ToDo ToDo ToDo ToDo ToDo */
/* this function computes an image that moving away from the ROI gradually fades to
* the background grey level BG according to the formula
* tonedImg = w srcImg + (1-w) BG
* w depends on the distance to the ROI.
* there is a distance maxROIReachL beyond which
* the importance of the source image
* relative to the BG in the equation
* falls below a small threshold.
* in those regions the toned image is equal to
* the mean BG grey value. i.e. w=0, tonedImg = BG */
maxROIReachL = bbs_max( imgA->widthE, imgA->heightE );
/* pre-compute an array of tone down factors. R=[0.0...1.0] => bpb=[0.16] (idealy, bpb=[16.16] due to missing uInt16Arr ) */
bbs_Int32Arr_init( &toneDownFactorsL );
bbs_Int32Arr_size( &toneDownFactorsL, maxROIReachL );
toneDownFactorPowA = toneDownFactorA;
toneDownFactorsPtrL = toneDownFactorsL.arrPtrE;
for( ctrL = 0; ctrL < ( int32 ) maxROIReachL && toneDownFactorPowA > cutOffAccuracyA; ctrL++ )
{
toneDownFactorsPtrL[ ctrL ] = toneDownFactorPowA;
toneDownFactorPowA = toneDownFactorPowA * ( toneDownFactorA >> 1 );
toneDownFactorPowA = toneDownFactorPowA >> 15;
/* make active to check the error that accumulates by recursively multiplying factors */
/* printf( "pow = %d, tonedown dec = %d, tonedown float = %f \n", ctrL + 2, toneDownFactorPowA, toneDownFactorPowA / 65536.0f ); */
}
maxROIReachL = ctrL;
/* printf( "maxROIReachL = %d, tonedown = %d \n", maxROIReachL, toneDownFactorPowA ); */
/* move across the image one row at a time.
* (1) fill the outside frame with BG grey level
* (2) blend in the original image moving towards the ROI
*/
rOIReachXMinL = rectXMinL - ( int32 ) maxROIReachL;
rOIReachXMaxL = rectXMaxL + ( int32 ) maxROIReachL;
rOIReachYMinL = rectYMinL - ( int32 ) maxROIReachL;
rOIReachYMaxL = rectYMaxL + ( int32 ) maxROIReachL;
rOIReachIxXMinL = bbs_max( rOIReachXMinL, ( int16 ) 0 );
rOIReachIxXMinL = bbs_min( rOIReachIxXMinL, ( int16 ) imgA->widthE );
rOIReachIxXMaxL = bbs_min( rOIReachXMaxL, ( int16 ) imgA->widthE );
rOIReachIxXMaxL = bbs_max( rOIReachIxXMaxL, ( int16 ) 0 );
rOIReachIxYMinL = bbs_max( rOIReachYMinL, ( int16 ) 0 );
rOIReachIxYMinL = bbs_min( rOIReachIxYMinL, ( int16 ) imgA->heightE );
rOIReachIxYMaxL = bbs_min( rOIReachYMaxL, ( int16 ) imgA->heightE );
rOIReachIxYMaxL = bbs_max( rOIReachIxYMaxL, ( int16 ) 0 );
/* (1) far from the ROI the image is filled with the BG grey value */
imgPtrL = 0;
for ( jL = 0; jL < rOIReachYMinL; jL++ )
{
imgPtrL = &( imgA->arrE.arrPtrE[ jL * imgA->widthE ] );
for ( iL = 0; iL <= ( int16 ) imgA->widthE; iL++ )
{
imgPtrL[ iL ] = meanBGGreyLevelByteL;
}
}
for ( jL = rOIReachYMaxL; jL < ( int16 ) imgA->heightE; jL++ )
{
imgPtrL = &( imgA->arrE.arrPtrE[ jL * imgA->widthE ] );
for ( iL = 0; iL <= ( int16 ) imgA->widthE; iL++ )
{
imgPtrL[ iL ] = meanBGGreyLevelByteL;
}
}
for ( jL = rOIReachIxYMinL; jL < rOIReachIxYMaxL; jL++ )
{
imgPtrL = &( imgA->arrE.arrPtrE[ jL * imgA->widthE ] );
for ( iL = 0; iL < rOIReachXMinL; iL++ )
{
imgPtrL[ iL ] = meanBGGreyLevelByteL;
}
for ( iL = rOIReachXMaxL; iL < ( int16 ) imgA->widthE; iL++ )
{
imgPtrL[ iL ] = meanBGGreyLevelByteL;
}
}
/* (2) blend from ROI to outside regions */
for ( jL = rOIReachIxYMinL; jL < rectIxYMinL; jL++ )
{
/* the factor for one row is a constant */
weightL = ( int32 ) toneDownFactorsPtrL[ maxROIReachL - 1 - ( jL - rOIReachYMinL ) ];
invWeightL = 0x00010000 - weightL;
opBGL = ( meanBGGreyLevelLongL >> 9 ) * invWeightL; /* result is bpb=[8,24] */
opBGL = opBGL >> 7;
imgPtrL = &( imgA->arrE.arrPtrE[ jL * imgA->widthE ] );
/* compute the ridge position */
ridgeIxLeftL = bbs_max( 0, rOIReachXMinL + jL - rOIReachYMinL );
ridgeIxRightL = bbs_min( ( int16 ) imgA->widthE - 1, rOIReachXMaxL - 1 - ( jL - rOIReachYMinL ) );
/* loop over all elements from left ridge through right ridge */
for ( iL = ridgeIxLeftL; iL <= ridgeIxRightL; iL++ )
{
opSrcL = imgPtrL[ iL ]; /* leave at byte */
opSrcL = opSrcL * weightL; /* result is bpb=[16,16] */
sumL = opSrcL + opBGL; /* OF impossible */
imgPtrL[ iL ] = sumL >> 16; /* round to byte */
}
}
for ( jL = rOIReachIxYMaxL - 1; jL >= rectIxYMaxL; jL-- )
{
/* the factor for one row is a constant */
weightL = ( int32 ) toneDownFactorsPtrL[ maxROIReachL - 1 - ( rOIReachYMaxL - 1 - jL ) ];
invWeightL = 0x00010000 - weightL;
opBGL = ( meanBGGreyLevelLongL >> 9 ) * invWeightL; /* result is bpb=[8,24] */
opBGL = opBGL >> 7;
imgPtrL = &( imgA->arrE.arrPtrE[ jL * imgA->widthE ] );
/* compute the ridge position */
ridgeIxLeftL = bbs_max( 0, rOIReachXMinL + ( rOIReachYMaxL - 1 - jL ) );
ridgeIxRightL = bbs_min( ( int16 ) imgA->widthE - 1, rOIReachXMaxL - 1 - ( rOIReachYMaxL - 1 - jL ) );
/* loop over all elements from left ridge through right ridge */
for ( iL = ridgeIxLeftL; iL <= ridgeIxRightL; iL++ )
{
opSrcL = imgPtrL[ iL ]; /* leave at byte */
opSrcL = opSrcL * weightL; /* result is bpb=[16,16] */
sumL = opSrcL + opBGL; /* OF impossible */
imgPtrL[ iL ] = sumL >> 16; /* round to byte */
}
}
for ( jL = rOIReachIxYMinL; jL < rOIReachIxYMaxL; jL++ )
{
imgPtrL = &( imgA->arrE.arrPtrE[ jL * imgA->widthE ] );
ridgeIxLeftL = bbs_min( rOIReachXMinL + ( jL - rOIReachYMinL ) - 1, rectXMinL - 1 );
ridgeIxLeftL = bbs_min( ridgeIxLeftL, rOIReachXMinL + ( rOIReachYMaxL - 1 - jL ) - 1 );
for ( iL = rOIReachIxXMinL; iL <= ridgeIxLeftL; iL++ )
{
weightL = ( int32 ) toneDownFactorsPtrL[ maxROIReachL - 1 - ( iL - rOIReachXMinL ) ];
invWeightL = 0x00010000 - weightL;
opBGL = ( meanBGGreyLevelLongL >> 9 ) * invWeightL; /* result is bpb=[16,16] */
opBGL = opBGL >> 7;
opSrcL = imgPtrL[ iL ]; /* leave at byte */
opSrcL = opSrcL * weightL; /* result is bpb=[16,16] */
sumL = opSrcL + opBGL; /* OF impossible */
imgPtrL[ iL ] = sumL >> 16; /* round to byte */
}
ridgeIxRightL = bbs_max( rOIReachXMaxL - 1 - ( jL - rOIReachYMinL ) + 1 , rectXMaxL );
ridgeIxRightL = bbs_max( ridgeIxRightL, rOIReachXMaxL - 1 - ( rOIReachYMaxL - 1 - jL ) + 1 );
for ( iL = ridgeIxRightL; iL < rOIReachIxXMaxL; iL++ )
{
weightL = ( int32 ) toneDownFactorsPtrL[ iL - rectXMaxL ];
invWeightL = 0x00010000 - weightL;
opBGL = ( meanBGGreyLevelLongL >> 9 ) * invWeightL; /* result is bpb=[16,16] */
opBGL = opBGL >> 7;
opSrcL = imgPtrL[ iL ]; /* leave at byte */
opSrcL = opSrcL * weightL; /* result is bpb=[16,16] */
sumL = opSrcL + opBGL; /* OF impossible */
imgPtrL[ iL ] = sumL >> 16; /* round to byte */
}
}
}
/* ------------------------------------------------------------------------- */
/* ========================================================================= */