参考CalculateRamp - 如何从现有的Gamma Ramp中导出入口参数 - 我的最佳解决方案

时间:2016-09-03 14:39:01

标签: c# c++

参考广泛使用的CalculateRamp代码: Changing image contrast with GDI+ and C#

    public static void CalculateRamp(double level, double gamma, double brightness, double contrast)
    {
        ramp.Red = new ushort[256];
        ramp.Green = new ushort[256];
        ramp.Blue = new ushort[256];

        gamma /= 10;
        brightness = 1 + (((brightness - 50) / 100) * 65535);
        contrast = 1 + ((contrast - 50) / 100);
        level = 1 + ((level - 50) / 100);

        for (int i = 0; i < 256; i++)
        {
            double value = i * 256;
            value = (Math.Pow(value / 65535, 1 / gamma) * 65535) + 0.5;
            value = ((((value / 65535) - 0.5) * contrast) + 0.5) * 65535;
            value = value += brightness;
            value *= level;
            ramp.Red[i] = ramp.Green[i] = ramp.Blue[i] = (ushort)Math.Min((double)65535, Math.Max((double)0, value));
        }
        SetDeviceGammaRamp(GetDC(IntPtr.Zero), ref ramp);
    }

如何直接从现有的Gamma Ramp计算此方法的输入值(参数)?换句话说,反向方法是什么?

如果我要向用户提供这些实用程序,我需要在进行调整之前向他们提供当前设置。

我已经尝试了三天来提出解决方案,并且必须承认这超出了我的能力范围。

2016年9月8日更新 - 我最好的解决方案......

虽然我长期努力地寻找数学解决方案,但我终于回过头来使用迭代方法。

计算每个可能设置然后检查匹配的钝力迭代将运行超过20分钟;这是不可接受的。

我发现我可以在数组中间取一个样本点,然后快速迭代所有可能的设置以找到该样本的匹配项;然后执行数组的所有256个计算,看看我们是否完全匹配。此操作通常在不到一秒的时间内完成。

但我意识到还有另一个问题。如果没有使用CalculateRamp算法(例如出厂设置)编程Gamma Ramp,那么我们不太可能找到与我们的设置完全匹配的内容;我们的解决方案将失败。

因此,我设计了一个备用计划,该计划使用来自伽马斜坡阵列的四个采样点;然后设置一个可接受值的“跨度”,它将为我们的设置提供近似的近似值。每次失败后,“span”的标准会变宽,并重新进入搜索范围。这种情况通常会在大约三秒内产生Gamma斜坡设置的近似值。这是可以接受的,因为我的主程序可以在程序启动序列期间执行此操作。

这是我的C ++解决方案......

    //---------------------------------------------------------------------------
    int __fastcall TForm1::Round( double flt ){
       int num = (int) flt;
       if( flt >= 0 ){
          if( flt - num >= .5 ){ num++;}
       }else{
          if( flt - num <= -.5 ){ num--;}
       }
       return( num );
    }
    //----------------------------------------------------------------------------
    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;
       double gamma,bright,cntrst,level;
       double v1,v2,v3,v4;
       double c1,c2,c3,c4;
       double a1,a2,a3,a4,b1,b2,b3,b4; //for best estimate criteria
       int x1,x2,x3,x4,x5;
       int d,n;
       WORD span = 8;
       bool tog = false;

       TDateTime strt, end;

       WORD GammaArray[3][256]; //Gamma Ramp Array buffer
       WORD CompArray[256];     //Array buffer for comparison

       HDC GammaDC = GetDC( NULL );  //fetch the gamma ramp array
       GetDeviceGammaRamp( GammaDC, GammaArray );
       ReleaseDC( NULL, GammaDC );

       strt=Now();

       //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 ){ break;}
       }
       if( x2 == 256 ){ x2 = 255; }

       x5 = x1 + Round( (double)( x2 - x1 ) / 2.0 );

       Memo1->Lines->Add( "x1 = " + IntToStr( x1 )); //start
       Memo1->Lines->Add( "x2 = " + IntToStr( x2 )); //end
       Memo1->Lines->Add( "x5 = " + IntToStr( x5 )); //mid

       //neutral settings are as follows...
       //Bright = 50
       //Contrast = 50
       //Level = 50
       //Gamma = 10

       //The following code will look for an exact match to the settings
       //but it may fail if the gamma ramp was not programmed using the
       //original CalculateRamp code. ie: A factory setting, or other

       for(n=0;n<=40;){//gamma
          if( n < 9 ){         //gamma begins with a neutral setting of 10 and
             if( tog ){        //then increments high and low depending on tog
                i = ( 10 - n );
                tog = false; n++;
                if( i == 10 ){ continue;}
             }else{
                i = ( 10 + n );
                tog = true;
             }
          }else{
             i = ( 10 + n++ );
          }
          gamma = i / 10;
          v1 = ( pow( (double)(x5 * 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
                   c1 = (((( v1 / 65535 ) - 0.5) * cntrst) + 0.5) * 65535;
                   c1 = c1 += bright;
                   c1 *= level;
                   if( c1 > 65535){ c1 = 65535; }
                   if( c1 < 0 ){ c1 = 0; }
             if( (WORD) c1 == GammaArray[0][x5] ){
                      for( d = 0; d < 256; d++ ){
                         c1 = ( pow( (double)(d * 256) / 65535, 1 / gamma) * 65535) + 0.5;
                         c1 = ((( (c1 / 65535) - 0.5) * cntrst) + 0.5) * 65535;
                         c1 = c1 += bright;
                         c1 *= level;
                         if( c1 > 65535 ){ c1 = 65535;}
                         if( c1 < 0 ){ c1 = 0;}
                         CompArray[d] = (WORD) c1;
                      }
                      if(memcmp( &CompArray[0], &GammaArray[0][0], 2*256) == 0){
                         goto ENDIT;
                      }
                   }
                }
             }
          }
       }

       //Since an exact match could not be found for the current
       //gamma ramp settings, we will broaden our criteria and
       //search for the best match for our gamma ramp settings.

       //Here our search is based on the start and end values,
       //plus two additional values that are 1/4 of the overall distance
       //above the start point; and 1/4 the distance below the end point.

       Memo1->Lines->Add("Values NOT Discovered!!!");
       Memo1->Lines->Add("Widening the Search....");

       x3 = x1 + Round( (double)( x2 - x1 ) / 4.0 );
       x4 = x1 + Round(( (double)( x2 - x1 ) / 4.0 )*3);

       Memo1->Lines->Add( "x1 = " + IntToStr( x1 )); //start
       Memo1->Lines->Add( "x2 = " + IntToStr( x2 )); //end
       Memo1->Lines->Add( "x3 = " + IntToStr( x3 )); // 1/4
       Memo1->Lines->Add( "x4 = " + IntToStr( x4 )); // 3/4

       BROADEN:

       a1 = GammaArray[0][x1]+span; //these are our high and low
       b1 = GammaArray[0][x1]-span; //values that the ramp values must
                                    //fall within to be accepted
       a2 = GammaArray[0][x2]+span;
       b2 = GammaArray[0][x2]-span; //span begins at 8 and increments upwards
                                    //with each loop, ever widening the
       a3 = GammaArray[0][x3]+span; //the search criteria
       b3 = GammaArray[0][x3]-span;

       a4 = GammaArray[0][x4]+span;
       b4 = GammaArray[0][x4]-span;

       tog=false;
       for(n=0;n<=40;){//gamma
          if( n < 9 ){         //gamma begins with a neutral setting of 10 and
             if( tog ){        //then increments high and low depending on tog
                i = ( 10 - n );
                tog = false; n++;
                if( i == 10 ){ continue;} //prevents two instances of i == 10
             }else{
                i = ( 10 + n );
                tog = true;
             }
          }else{
             i = ( 10 + n++ );
          }
          gamma = i / 10;
          v1 = ( pow( (double)(x1 * 256) / 65535, 1 / gamma) * 65535) + 0.5;
          v2 = ( pow( (double)(x2 * 256) / 65535, 1 / gamma) * 65535) + 0.5;
          v3 = ( pow( (double)(x3 * 256) / 65535, 1 / gamma) * 65535) + 0.5;
          v4 = ( pow( (double)(x4 * 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 the four sample values to see if the
                   //results falls within our acceptance criteria.
                   c1 = (((( v1 / 65535 ) - 0.5) * cntrst) + 0.5) * 65535;
                   c1 = c1 += bright;
                   c1 *= level;
                   c2 = (((( v2 / 65535 ) - 0.5) * cntrst) + 0.5) * 65535;
                   c2 = c2 += bright;
                   c2 *= level;
                   c3 = (((( v3 / 65535 ) - 0.5) * cntrst) + 0.5) * 65535;
                   c3 = c3 += bright;
                   c3 *= level;
                   c4 = (((( v4 / 65535 ) - 0.5) * cntrst) + 0.5) * 65535;
                   c4 = c4 += bright;
                   c4 *= level;
             if( c1 <= a1 && c1 >= b1 &&  c2 <= a2 && c2 >= b2 &&
                       c3 <= a3 && c3 >= b3 &&  c4 <= a4 && c4 >= b4 ){
                       Memo1->Lines->Add("Best Estimate +/- " + IntToStr( span ));
                       goto ENDIT;
                   }
                }
             }
          }
       }

       if( span < 256){
          span *= 2;
          goto BROADEN;
       }else if( span <= 4096 ){ //set the maximum allowance for "span"
          span += 128;           //which is the basis for the allowable
          goto BROADEN;          //search criteria
       }

       //if we get to this point then we have utterly failed.
       Memo1->Lines->Add("Values STILL NOT Discovered.");
       Memo1->Lines->Add("GetGammaRampSettings Failed.");
       return;

       ENDIT:
       end=Now();
       Memo1->Lines->Add("Execution duration was "+
             FormatDateTime("nn:ss:zzz",end-strt));

       //Report on findings...
       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 ));

    }
    //---------------------------------------------------------------------------

0 个答案:

没有答案