#include <bfxatom.h>
Inheritance diagram for BitmapEffectSILT:
Public Member Functions | |
virtual BOOL | Run () |
Runs a transform! | |
Private Member Functions | |
CC_DECLARE_DYNCREATE (BitmapEffectSILT) |
Definition at line 151 of file bfxatom.h.
|
|
|
Runs a transform!
Reimplemented from BitmapEffectBase. Definition at line 158 of file bfxatom.cpp. 00159 { 00160 KernelBitmap * Temp; 00161 INT32 Stage; 00162 double mDest,cDest,mAdd,cAdd,mCurrent,cCurrent; 00163 BfxALULUT * LUT; 00164 BfxALULUT * LUT2; 00165 BYTE CurrentZero, CurrentOne, AddZero, AddOne; // Byte values of areas of solid black and white 00166 00167 #define Stages 8 00168 #define TestSize 5 00169 double Coefficient[Stages+1]= 00170 // {-0.0946028, -1.00875, -2.06186, 5.24511, 10.9885, -12.2837, -19.5609, 12.3327, 15.0588}; //straight butterworth 00171 //{-0.153367, -0.538629, 0.288733, 0.543937, -3.11505, -1.00089, 6.76564, 4.81082, 0.0150588}; //butterworth+end pt norm 00172 {-0.153426, -0.538158, 0.291086, 0.539231, -3.12917, -0.989594, 6.792, 4.80329, 0};//like above but real norm 00173 //{2.12494, 1.2666, -0.917123, -0.599367, -0.062313, -0.0511883, -0.447152, -0.294161, 0.};//sharpen 00174 double t; 00175 00176 #if DEBUGSILT 00177 double TestVars[TestSize]; 00178 double RealVars[TestSize]; 00179 double ScaleVars[TestSize]; 00180 BYTE TestByte[256]; 00181 BYTE DestByte[256]; 00182 INT32 v; 00183 #endif 00184 00185 #if DEBUGSILT 00186 for (v=0; v<TestSize; v++) TestVars[v]=RealVars[v]=ScaleVars[v]=(((double)v) / (double)(TestSize-1)); 00187 00188 for (v=0; v<=255; v++) TestByte[v]=DestByte[v]=v; 00189 #endif 00190 00191 t=0; 00192 00193 for (Stage=0; Stage<=Stages; Stage++) 00194 t+=(Coefficient[Stage]);//= ((double)rand())/100.0-163.0); 00195 00196 for (Stage=0; Stage<=Stages; Stage++) Coefficient[Stage]=Coefficient[Stage]*1.0/t; 00197 00198 #if DEBUGSILT 00199 TRACEUSER( "Alex", _T("Coefficients ")); 00200 for (Stage=0; Stage<=Stages; Stage++) 00201 TRACEUSER( "Alex", _T("%d=%5f "),Stage,Coefficient[Stage]); 00202 TRACEUSER( "Alex", _T("\n")); 00203 #endif 00204 00205 if (!(LUT = new BfxALULUT)) return FALSE; 00206 if (!(LUT2 = new BfxALULUT)) 00207 { 00208 delete LUT; 00209 return FALSE; 00210 } 00211 00212 if (!(Temp = ALU->NewBitmap(Destination))) 00213 { 00214 delete LUT; 00215 delete LUT2; 00216 return FALSE; 00217 } 00218 00219 if (!(ALU->SetA(Temp) && 00220 ALU->ZeroA() && 00221 ALU->SetA(Destination) && 00222 ALU->ZeroA())) 00223 { 00224 delete LUT; 00225 delete LUT2; 00226 delete Temp; 00227 return FALSE; 00228 } 00229 00230 00231 // Initialise the fixed resolution parameters 00232 // realDest = mDest.Dest + cDest; 00233 00234 Stage=Stages; 00235 00236 if (Coefficient[Stage]>=0) 00237 { 00238 mAdd = Coefficient[Stage]; 00239 cAdd = 0; 00240 if (!(ALU->SetB(Source) && 00241 ALU->PlotB() 00242 )) 00243 { 00244 delete LUT; 00245 delete LUT2; 00246 delete Temp; 00247 return FALSE; 00248 } 00249 CurrentZero=0; 00250 CurrentOne=255; 00251 00252 #if DEBUGSILT 00253 for (v=0; v<TestSize; v++) 00254 { 00255 RealVars[v]=RealVars[v]*Coefficient[Stage]; 00256 ScaleVars[v]=ScaleVars[v]; 00257 } 00258 for (v=0; v<=255; v++) 00259 { 00260 DestByte[v]=TestByte[v]; 00261 } 00262 #endif 00263 00264 } 00265 else 00266 { 00267 mAdd = -Coefficient[Stage]; 00268 cAdd = -mAdd; 00269 if (!(ALU->SetB(Source) && 00270 LUT->LinearABK(0,-1,1) && 00271 ALU->PlotBLUT(LUT) 00272 )) 00273 { 00274 delete LUT; 00275 delete LUT2; 00276 delete Temp; 00277 return FALSE; 00278 } 00279 CurrentZero=255; 00280 CurrentOne=1; 00281 00282 #if DEBUGSILT 00283 for (v=0; v<TestSize; v++) 00284 { 00285 RealVars[v]=RealVars[v]*Coefficient[Stage]; 00286 ScaleVars[v]=1.0-ScaleVars[v]; 00287 } 00288 for (v=0; v<=255; v++) 00289 { 00290 DestByte[v]=LUT->GetLUT(0,TestByte[v]); 00291 } 00292 #endif 00293 00294 } 00295 00296 mDest=mAdd; 00297 cDest=cAdd; 00298 00299 #if DEBUGSILT 00300 TRACEUSER( "Alex", _T("Stage %d "),Stage); 00301 for (v=0; v<TestSize; v++) 00302 { 00303 TRACEUSER( "Alex", _T("%5f|%5f|%5f "),RealVars[v],ScaleVars[v]*mDest+cDest,ScaleVars[v]); 00304 } 00305 TRACEUSER( "Alex", _T(" .. %5f,%5f,%5f | %5f,%5f\n"),0.0,0.0,0.0,mDest,cDest); 00306 00307 TRACEUSER( "Alex", _T(" ")); 00308 for (v=0; v<=10; v++) TRACEUSER( "Alex", _T("%2x~%2x "),v,DestByte[v]); 00309 for (v=245; v<=255; v++) TRACEUSER( "Alex", _T("%2x~%2x "),v,DestByte[v]); 00310 TRACEUSER( "Alex", _T("\n")); 00311 #endif 00312 00313 if (!(LUT2->LinearABK(2.0,-0.5,0))) 00314 { 00315 delete LUT; 00316 delete LUT2; 00317 delete Temp; 00318 return FALSE; 00319 } 00320 00321 for (Stage = Stages-1; Stage>=0; Stage--) 00322 { 00323 #if 1 00324 if (!( 00325 ALU->SetA(Temp) && 00326 00327 /* 00328 ALU->SetB(Destination) && 00329 ALU->PlotB() && 00330 00331 ALU->SetA(Destination) && 00332 ALU->SetB(Temp) && 00333 ALU->PlotB() && 00334 */ 00335 ALU->ZeroA() && 00336 00337 // ALU->SetB(Destination) && 00338 // ALU->AddKAB(0x80) && 00339 00340 ALU->SetB(Destination,0,1) && 00341 ALU->AddKAB(0x20) && 00342 00343 ALU->SetB(Destination,0,-1) && 00344 ALU->AddKAB(0x20) && 00345 00346 ALU->SetB(Destination,1,0) && 00347 ALU->AddKAB(0x20) && 00348 00349 ALU->SetB(Destination,-1,0) && 00350 ALU->AddKAB(0x20) && 00351 00352 ALU->SetB(Destination,1,1) && 00353 ALU->AddKAB(0x10) && 00354 00355 ALU->SetB(Destination,-1,1) && 00356 ALU->AddKAB(0x10) && 00357 00358 ALU->SetB(Destination,1,-1) && 00359 ALU->AddKAB(0x10) && 00360 00361 ALU->SetB(Destination,-1,-1) && 00362 ALU->AddKAB(0x10) && 00363 00364 ALU->SetB(Destination) && 00365 ALU->PlotBLUT(LUT2) && 00366 00367 00368 ALU->SetA(Destination) && 00369 ALU->SetB(Temp) && 00370 ALU->PlotB() && 00371 00372 TRUE)) 00373 { 00374 delete LUT; 00375 delete LUT2; 00376 delete Temp; 00377 return FALSE; 00378 } 00379 #endif 00380 mAdd = 1; 00381 cAdd = 0; 00382 00383 mCurrent = mDest; 00384 cCurrent = cDest; 00385 AddZero=0; 00386 AddOne=255; 00387 00388 // Calculate cDest and mDest in the worse case situation. This finds the maximum range that an ouput 00389 // pixel may lie in (i.e. from cDest .. cDest+mDest). 00390 00391 /* Here's the maths: 00392 00393 We wish to represent x (a set which may have arbitrary magnitude) as x' where 0<=x'<=1 and two 00394 reals cx, mx (mx>0) so 00395 1 00396 x' = __ [ x - cx] x = mx.x' + cx (1) 00397 mx 00398 00399 We thus chose 00400 cx = min [x]; mx = max[x] - min[x] > 0 (2) 00401 00402 Now let us assume we have other similarly represented sets y, and z, where y is known, and 00403 z is unknown (as yet) but 00404 00405 z = alpha . x + beta . y (wouldn't this be a lot easier with mathgreek?) 00406 00407 We know y', cy, my obviously, but we want z', mz' and cz', and more importantly how to do 00408 the addition in the dash ("'") transformed space. 00409 00410 Let us consider: 00411 z= (alpha.mx)x' + (beta.my)y' + (cx.alpha) + (cy.beta) (3) 00412 00413 To find cz, mz we need to consider the extremites of the range of z as in (2) 00414 00415 00416 | cz | mz 00417 -------------|------------------------------|---------------------------- 00418 | | 00419 alpha>=0 | cx.alpha + cy.beta | (alpha) mx + (beta) my 00420 beta>=0 | | 00421 | | 00422 -------------|------------------------------|---------------------------- 00423 | | 00424 alpha<0 | cx.alpha + cy.beta | (-alpha) mx + (beta) my 00425 beta>=0 | + alpha.mx | 00426 | | 00427 -------------|------------------------------|---------------------------- 00428 | | 00429 alpha<0 | cx.alpha + cy.beta | (-alpha) mx + (-beta) my 00430 beta<0 | + alpha.mx + beta.my | 00431 | | 00432 -------------|------------------------------|---------------------------- 00433 | | 00434 alpha>=0 | cx.alpha + cy.beta | (alpha) mx + (-beta) my 00435 beta<0 | + beta.my | 00436 | | 00437 -------------|------------------------------|---------------------------- 00438 00439 00440 Note that in our current use alpha is always 1 which simplifies the equations and 00441 means we only need to consider two case. Beta corresponds to Coefficient[stage]. 00442 00443 Note we can actually use *any* valid value of cz, mz. The values above are those 00444 guaranteed to give the smallest output range which includes all possibilities (i.e. 00445 all combinations of values from the input domains). 00446 00447 The *full* range isn't really very useful. Of course there are going to be some pixels which will 00448 clip. Take (for example) the case of a sharpen on a full black to full white edge. Allowing full range 00449 through all the time with our fixed resolution of 255 sampling points will reduce the apparent bpp 00450 for solid colour areas (which are unaffected by the unit gain SILTs we are considering here). Thus 00451 we also work out the range of values obtainable in a sitatuion where x=y. 00452 00453 We do this by maintaining two BYTE values, CurrentZero and CurrentOne (the top & bottom of the range). 00454 These are what bytes areas of solid black and white would be represented by in the incoming bitmap. 00455 These come straight out of the LUT calculations. AddZero & AddOne do the same for the incoming 00456 bitmap. 00457 00458 00459 The output range will run between two numbers: 00460 LimitZ = ((CurrentZ * mx) + cx) * alpha + ((AddZ * my) + cy) * beta 00461 where Z is "Zero" or "One". But is LimitZero < LimitOne or vice-versa? 00462 00463 LimitOne-LimitZero = (CurrentOne-CurrentZero)*mx*alpha+(AddOne-AddZero)*my*beta 00464 00465 00466 In order to formulate z', we note 00467 00468 1 00469 x' = __ [ z - cz] (4) 00470 mz 00471 00472 And substitute (3) to give 00473 00474 alpha.mx beta.my cx . alpha + cy.beta - cz 00475 z' = -------- x + ------- y + ------------------------- (4) 00476 mz mz mz 00477 |________| |______| |_______________________| 00478 PropA PropB Offset 00479 00480 */ 00481 00482 if (Coefficient[Stage]>=0) // beta, alpha is 1 00483 { 00484 cDest = cCurrent + cAdd * Coefficient[Stage]; 00485 mDest = mCurrent + mAdd * Coefficient[Stage]; 00486 } 00487 else 00488 { 00489 cDest = cCurrent + (cAdd+mAdd) * Coefficient[Stage]; 00490 mDest = mCurrent - mAdd * Coefficient[Stage]; 00491 } 00492 00493 double mDestIso; 00494 double cDestIso; 00495 double LimitZero; 00496 double LimitOne; 00497 00498 00499 // The *full* range isn't really very useful. Of course there are going to be some pixels which will 00500 // clip. Take (for example) the case of a sharpen on a full black to full white edge. Allowing full range 00501 // through all the time with our fixed resolution of 255 sampling points will reduce the apparent bpp 00502 // for solid colour areas (which are unaffected by the unit gain SILTs we are considering here). Thus 00503 // we also work out the range of values obtainable in a sitatuion where x=y. 00504 00505 LimitZero=((((double)CurrentZero)/255.0*mCurrent)+cCurrent)+cAdd*Coefficient[Stage]; 00506 LimitOne=((((double)CurrentOne)/255.0*mCurrent)+cCurrent)+((1.0*mAdd)+cAdd)*Coefficient[Stage]; 00507 if (LimitOne>LimitZero) 00508 { 00509 cDestIso=LimitZero; 00510 mDestIso=LimitOne-LimitZero; 00511 } 00512 else 00513 { 00514 cDestIso=LimitOne; 00515 mDestIso=LimitZero-LimitOne; 00516 } 00517 00518 00519 // Now bodge the ranges together - note this isn't really a bodge, just that it should be calculated 00520 // accoridng to the dynamics of the image (complicated). 00521 // 00522 // Note the two forms of errors: 00523 // * If we use too much 'full range' stuff we will introduce errors at higher and higher bits in the 00524 // image. This occurs because when the 0..1 range is compressed, 2 grey levels become equal at 8bpp. 00525 // If we then subtract 0.1 x (original) which should still give an increasing image, if the rounding 00526 // turns bad, we get a downward step not an upward step. 00527 // 00528 // * If we use too little 'full range' stuff, we will not see details near the full range which are 00529 // brought out by the processing. 00530 // 00531 // Note always mDest=>mDestIso, cDest<=cDestIso, & cDest<=cDestIso<=cDestIso+mDestIso<=cDest+mDest 00532 // 00533 // The algorithm currently used is to chose an interpolation factor depending on the magnitude of 00534 // mDest compared to mDestIso, and interpolate between two range limited versions. 00535 // 00536 // STOP PRESS: Currently we're just using the IsoRange. Methinks I'm going to have to resort to the 00537 // mixture for different FIRs 00538 #if 0 00539 const double HighestIsoRange =9999.0; 00540 const double HighestRange = 4.0; 00541 double interp; 00542 00543 interp = 0.75 + 0.25 * (mDestIso/mDest); 00544 // Limit the two ranges 00545 00546 if (mDest<0.5/255.0) mDest = 0.5/255.0; 00547 if (mDestIso<0.5/255.0) mDestIso = 0.5/255.0; 00548 00549 if (mDestIso>HighestIsoRange) 00550 { 00551 cDestIso+=(mDestIso-HighestIsoRange)/2.0; 00552 mDestIso=HighestIsoRange; 00553 } 00554 00555 if (mDest>HighestRange) 00556 { 00557 cDest+=(mDest-HighestRange)/2.0; 00558 mDest=HighestRange; 00559 } 00560 00561 mDest = (1-interp) * mDest + interp * mDestIso; 00562 cDest = (1-interp) * cDest + interp * cDestIso; 00563 #endif 00564 00565 mDest=mDestIso; 00566 cDest=cDestIso; 00567 00568 // To reduce the possiblity of rounding errors, we ensure that 0 corresponds to an integer grey level 00569 // and that the gamut is an integer number of grey levels wide. This process should be guaranteed to 00570 // ensure that black stays as black, and white stays as white. 00571 double oldcDest = cDest; 00572 cDest=(floor(cDest * 255.0))/255.0; 00573 mDest = (ceil((oldcDest + mDest)*255.0))/255.0 - cDest; 00574 00575 double PropA; 00576 double PropB; 00577 double Offset; 00578 00579 00580 PropA = mCurrent / mDest; 00581 PropB = Coefficient[Stage] * mAdd / mDest; 00582 Offset = (cCurrent+cAdd * Coefficient[Stage]-cDest)/ mDest; 00583 00584 #if DEBUGSILT 00585 for (v=0; v<TestSize; v++) 00586 { 00587 RealVars[v]+=Coefficient[Stage]*TestVars[v]; 00588 ScaleVars[v]=PropA*ScaleVars[v]+PropB*TestVars[v]+Offset; 00589 } 00590 #endif 00591 00592 if (!(LUT->LinearABK(PropA, PropB, Offset) && 00593 ALU->SetA(Destination) && 00594 ALU->SetB(Source) && 00595 ALU->PlotBLUT(LUT) && 00596 TRUE)) 00597 { 00598 delete LUT; 00599 delete LUT2; 00600 delete Temp; 00601 return FALSE; 00602 } 00603 00604 CurrentZero=LUT->GetLUT(CurrentZero,0); 00605 CurrentOne=LUT->GetLUT(CurrentOne,255); 00606 00607 #if DEBUGSILT 00608 for (v=0; v<=255; v++) 00609 { 00610 DestByte[v]=LUT->GetLUT(DestByte[v],TestByte[v]); 00611 } 00612 00613 00614 TRACEUSER( "Alex", _T("Stage %d "),Stage); 00615 for (v=0; v<TestSize; v++) 00616 { 00617 TRACEUSER( "Alex", _T("%5f|%5f|%5f "),RealVars[v],ScaleVars[v]*mDest+cDest,ScaleVars[v]); 00618 } 00619 TRACEUSER( "Alex", _T(" .. %5f,%5f,%5f | %5f,%5f\n"),PropA,PropB,Offset,mDest,cDest); 00620 00621 TRACEUSER( "Alex", _T(" ")); 00622 for (v=0; v<=10; v++) TRACEUSER( "Alex", _T("%2x~%2x "),v,DestByte[v]); 00623 for (v=245; v<=255; v++) TRACEUSER( "Alex", _T("%2x~%2x "),v,DestByte[v]); 00624 TRACEUSER( "Alex", _T("\n")); 00625 #endif 00626 00627 00628 } 00629 00630 if (!(LUT->LinearABK(mDest, 0, cDest) // Accumulator already set up 00631 && ALU->PlotBLUT(LUT))) 00632 { 00633 delete LUT; 00634 delete LUT2; 00635 delete Temp; 00636 return FALSE; 00637 } 00638 00639 #if DEBUGSILT 00640 for (v=0; v<=255; v++) 00641 { 00642 DestByte[v]=LUT->GetLUT(DestByte[v],TestByte[v]); 00643 } 00644 00645 TRACEUSER( "Alex", _T("End ")); 00646 for (v=0; v<=10; v++) TRACEUSER( "Alex", _T("%2x~%2x "),v,DestByte[v]); 00647 for (v=245; v<=255; v++) TRACEUSER( "Alex", _T("%2x~%2x "),v,DestByte[v]); 00648 TRACEUSER( "Alex", _T("\n")); 00649 #endif 00650 00651 delete LUT; 00652 delete LUT2; 00653 delete Temp; 00654 return(TRUE); 00655 00656 }
|