How would you calculate the input values (arguments) for this method directly from the existing Gamma Ramp? In other words, what would be the reverse method?
If I am going to provide these utilities to the user, I need to present them with their current settings prior to their making the adjustments.
I have tried for three days to come up with a solution, and must admit that this is beyond my capabilities.
--------------------------------------------------------------------------------------------------
After unsuccessfully trying to solve for a mathematical solution for a week I had to try some other way to derive the Gamma Ramp Settings directly from the GetDeviceGammaRamp call.
One early attempt involved a simple iteration of all possible settings. This gave correct results, but it took more than 20 minutes to complete the operation. My application needs to be able to do this in under a second.
I finally found a better, more efficient way to perform the iterations, and it meets my requirements. It may be an imperfect solution; but a win is a win.
I shaved a little more time off of this operation by testing for a positive or a negative curve in the Gamma setting (or no curve at all = neutral setting 10). This saves a few iterations going in. To do this I created two additional functions: PtToPtRngBrg and GetPtFromPt.
If you like, you can skip these; and simply iterate through all possible Gamma settings (2 to 50). This would greatly simplify the code.
Here is my C++ solution...
//---------------------------------------------------------------------------
#define DEG_RAD 0.017453292519943295769236907684886
//---------------------------------------------------------------------------
struct RngBrg{ //Struct for return values in the
double rng; //call to PtToPtRngBrg
double brg;
};
//---------------------------------------------------------------------------
void __fastcall TForm1::GetGammaRampSettings(void){
// level should be between 2 and 100
// gamma should be between 2 and 50
// brigntess should be between 0 and 100
// contrast should be between 0 and 100
double i,j,k,m,m4;
double s1,s2,s3,s4;
double gamma,bright,cntrst,level;
double value;
int d;
int x1,x2,x3,x4;
bool isFound=false;
RngBrg rb; //Range and Bearing struct for distance and vector
WORD GammaArray[3][256]; //Gamma Ramp Array buffer
WORD CompArray[256]; //Array buffer for comparison
double DArray[256]; //buffer used to hold gamma values
HDC GammaDC = GetDC( NULL ); //fetch the gamma ramp array
GetDeviceGammaRamp( GammaDC, GammaArray );
ReleaseDC( NULL, GammaDC );
//Calculate the Angle:
//Find two endpoints for the GammaArray
for( x1 = 0; x1 < 256; x1++ ){
if( GammaArray[0][x1] > 0){break;}
}
for( x2 = 0; x2 < 256; x2++ ){
if( GammaArray[0][x2] == 65535){isFound=true; break;}
}
if( !isFound ){ x2--; }
//normalize the gama ramp numbers
//so that a distance and vector can be calculated
s1 = ( (double) GammaArray[0][x1] + 1 ) / 256.0;
s2 = ( (double) GammaArray[0][x2] + 1 ) / 256.0;
//find the mid point array element from the line described above...
x3 = x1 + ( ( x2 - x1 ) / 2 );
s3 = ( (double) GammaArray[0][x3] + 1 ) / 256.0;
Memo1->Lines->Add( "x1 = " + IntToStr(x1) + " s1 = " + AnsiString(s1));
Memo1->Lines->Add( "x2 = " + IntToStr(x2) + " s2 = " + AnsiString(s2));
Memo1->Lines->Add( "x3 = " + IntToStr(x3) + " s3 = " + AnsiString(s3));
//caculate the strait line between
//the two endpoints discovered above
PtToPtRngBrg( &rb, x1, s1, x2, s2 );
//neutral settings are as follows...
//Bright = 50
//Contrast = 50
//Level = 50
//Gamma = 10
//rng = 359.210244842766 and brg = 45 with all neutral settings
Memo1->Lines->Add( "rng = " + AnsiString( rb.rng ) +
" brg = " + AnsiString( rb.brg ));
//what would be the value of the midpoint
//if it were a strait line (neutral gamma setting)?
GetPtFromPt(x1, s1, rb.rng / 2.0, rb.brg, &m4, &s4);
Memo1->Lines->Add("m4 = " + IntToStr( Round(m4) ) + " s4=" + AnsiString(s4));
Memo1->Lines->Add("s3 - s4 = " + AnsiString( s3-s4 ));
x4 = Round(m4); //Rounding function call
if(( s4 - s3 ) > 1 ){//we have a negative gamma curve (G<10)
Memo1->Lines->Add("Negative Gamma Curve");
for( i = 9; i > 1; i-- ){
gamma=i/10;
for( d = 0; d < 256; d++ ){
DArray[d] = ( pow( (double)(d * 256) / 65535, 1 / gamma) * 65535) + 0.5;
}
for( j = 2; j < 101 ; j++ ){//level //980,000 possible iterations
level = 1 + ((j - 50) / 100);
for( k = 0; k < 101; k++ ){//bright
bright = 1 + (((k - 50) / 100) * 65535);
for( m = 0; m < 101; m++ ){//contrast
cntrst = 1 + ((m - 50) / 100);
//Test only the mid-line value at first
//To see if a complete comparison is warranted
value = (((( DArray[x4] / 65535 ) - 0.5) * cntrst) + 0.5) * 65535;
value = value += bright;
value *= level;
if( value > 65535){ value = 65535; }
if( value < 0 ){ value = 0; }
if( (WORD) value == GammaArray[0][x4] ){
for( d = 0; d < 256; d++ ){
value = ((( (DArray[d] / 65535) - 0.5) * cntrst) + 0.5) * 65535;
value = value += bright;
value *= level;
if( value > 65535 ){ value = 65535;}
if( value < 0 ){ value = 0;}
CompArray[d] = (WORD) value;
}
if(memcmp( &CompArray[0], &GammaArray[0][0], 2*256) == 0){
goto ENDIT;
}
}
}
}
}
}
}else if((s3-s4)>1){//we have a positive gamma curve(G>10)
Memo1->Lines->Add("Positive Gamma Curve");
for( i = 11; i < 51; i++ ){
gamma=i/10;
for( d = 0; d < 256; d++ ){
DArray[d] = ( pow( (double)(d * 256) / 65535, 1 / gamma) * 65535) + 0.5;
}
for( j = 2; j < 101 ; j++ ){//level //980,000 possible iterations
level = 1 + ((j - 50) / 100);
for( k = 0; k < 101; k++ ){//bright
bright = 1 + (((k - 50) / 100) * 65535);
for( m = 0; m < 101; m++ ){//contrast
cntrst = 1 + ((m - 50) / 100);
//Test only the mid-line value at first
//To see if a complete comparison is warranted
value = (((( DArray[x4] / 65535 ) - 0.5) * cntrst) + 0.5) * 65535;
value = value += bright;
value *= level;
if( value > 65535){ value = 65535; }
if( value < 0 ){ value = 0; }
if( (WORD) value == GammaArray[0][x4] ){
for( d = 0; d < 256; d++ ){
value = ((( (DArray[d] / 65535) - 0.5) * cntrst) + 0.5) * 65535;
value = value += bright;
value *= level;
if( value > 65535 ){ value = 65535;}
if( value < 0 ){ value = 0;}
CompArray[d] = (WORD) value;
}
if(memcmp( &CompArray[0], &GammaArray[0][0], 2*256) == 0){
goto ENDIT;
}
}
}
}
}
}
}else{//no gamma curve (G=10)
Memo1->Lines->Add("No Gamma Curve");
i=10;
gamma=1; //same as 10 / 10
for( d = 0; d < 256; d++ ){
DArray[d] = ( pow( (double)(d * 256) / 65535, 1 / gamma) * 65535) + 0.5;
}
for( j = 2; j < 101 ; j++ ){//level //980,000 possible iterations
level = 1 + ((j - 50) / 100);
for( k = 0; k < 101; k++ ){//bright
bright = 1 + (((k - 50) / 100) * 65535);
for( m = 0; m < 101; m++ ){//contrast
cntrst = 1 + ((m - 50) / 100);
//Test only the mid-line value at first
//To see if a complete comparison is warranted
value = (((( DArray[x4] / 65535 ) - 0.5) * cntrst) + 0.5) * 65535;
value = value += bright;
value *= level;
if( value > 65535){ value = 65535; }
if( value < 0 ){ value = 0; }
if( (WORD) value == GammaArray[0][x4] ){
for( d = 0; d < 256; d++ ){
value = ((( (DArray[d] / 65535) - 0.5) * cntrst) + 0.5) * 65535;
value = value += bright;
value *= level;
if( value > 65535 ){ value = 65535;}
if( value < 0 ){ value = 0;}
CompArray[d] = (WORD)value;
}
if(memcmp( &CompArray[0], &GammaArray[0][0], 2*256) == 0){
goto ENDIT;
}
}
}
}
}
}
Memo1->Lines->Add("Values NOT Discovered - Checking All Values...");
//if for any reason we did not find a match, reiterate through
//all possible gamma settings...
for(i=2;i<51;i++){
gamma=i/10;
for( d = 0; d < 256; d++ ){
DArray[d] = ( pow( (double)(d * 256) / 65535, 1 / gamma) * 65535) + 0.5;
}
for( j = 2; j < 101 ; j++ ){//level //980,000 possible iterations
level = 1 + ((j - 50) / 100);
for( k = 0; k < 101; k++ ){//bright
bright = 1 + (((k - 50) / 100) * 65535);
for( m = 0; m < 101; m++ ){//contrast
cntrst = 1 + ((m - 50) / 100);
//Test only the mid-line value at first
//To see if a complete comparison is warranted
value = (((( DArray[x4] / 65535 ) - 0.5) * cntrst) + 0.5) * 65535;
value = value += bright;
value *= level;
if( value > 65535){ value = 65535; }
if( value < 0 ){ value = 0; }
if( (WORD) value == GammaArray[0][x4] ){
for( d = 0; d < 256; d++ ){
value = ((( (DArray[d] / 65535) - 0.5) * cntrst) + 0.5) * 65535;
value = value += bright;
value *= level;
if( value > 65535 ){ value = 65535;}
if( value < 0 ){ value = 0;}
CompArray[d] = (WORD) value;
}
if(memcmp( &CompArray[0], &GammaArray[0][0], 2*256) == 0){
goto ENDIT;
}
}
}
}
}
}
Memo1->Lines->Add("Values Still NOT Discovered!!!");
Memo1->Lines->Add("Discovery Operation Failed.");
return;
ENDIT:
Memo1->Lines->Add("Bright = " + IntToStr((int)k));
Memo1->Lines->Add("Cntrst = " + IntToStr((int)m));
Memo1->Lines->Add("Level = " + IntToStr((int)j));
Memo1->Lines->Add("Gamma = " + IntToStr((int)i));
}
//---------------------------------------------------------------------------
short __fastcall TForm1::Round(double flt){
short num=(short)flt;
if(flt>=0){
if(flt-num>=.5){num++;}
}else{
if(flt-num<=-.5){num--;}
}
return(num);
}
//----------------------------------------------------------------------------
bool __fastcall TForm1:
tToPtRngBrg(RngBrg *rb,double x1,double y1,double x2,double y2){//was PixToPixRngBrg
rb->rng=0;rb->brg=0;
//range is in pixels
double diffx,diffy,dangle;
if(x1>=x2){
if(x1>=0&&x2<0){diffx=x1+fabs(x2);}else{diffx=x1-x2;}
}else{
if(x2>=0&&x1<0){diffx=x2+fabs(x1);}else{diffx=x2-x1;}
}
if(y1>=y2){
if(y1>=0&&y2<0){diffy=y1+fabs(y2);}else{diffy=y1-y2;}
}else{
if(y2>=0&&y1<0){diffy=y2+fabs(y1);}else{diffy=y2-y1;}
}
if(diffx==0){
rb->brg=0;rb->rng=y2-y1;
return true;
}
if(diffy==0){
rb->brg=90;rb->rng=x2-x1;
return true;
}
dangle=atan(diffy/diffx);
rb->rng=diffx/cos(dangle);//hyp
dangle=dangle/DEG_RAD;
rb->brg=90-dangle;
return true;
}
//-----------------------------------------------------------------------
void __fastcall TForm1::GetPtFromPt(double x, double y,double rng,double brg,double *x2,double *y2){
//Gets a pix(coord) from a pix (coord)
//range is in absolute pixels
if(brg>=360){brg-=360;}
if(brg<0){brg+=360;}
if(brg==360||brg==0){*x2=x;*y2=y+rng;return;}
if(brg==270){*y2=y;*x2=x-rng;return;}
if(brg==90){*y2=y;*x2=x+rng;return;}
if(brg==180){*x2=x;*y2=y-rng;return;}
if(brg<90){
*x2=x+(rng*cos((90-brg)*DEG_RAD));
*y2=y+(rng*sin((90-brg)*DEG_RAD));
return;
}
}
//---------------------------------------------------------------------------