Функция разложения цвета на оттенки. - страница 18

 
Реter Konow:

Насчет "R = Исходный_R" ты прав, но я оставил так, потому что так понятней принцип работы алгоритма. 

Над алгоритмом безусловно нужно еще работать. Он не идеален. Может быть, в конце я приду к такому же алгоритму, как у тебя. Но пройдя весь этот путь я получу несравненно больше. Ведь, я пройду путь познания и понимания, а значит творческая область в которой я реализую свой алгоритм будет гораздо шире, чем если бы просто скопировал чье то решение. Поэтому, я всегда выбираю свой путь.

строка 

StringToColor((string)MathRound(Первая_компонента) + "," + (string)MathRound(Вторая_компонента) + "," + (string)MathRound(Третья_компонента));

источник бешенных тормозов 

Попробуй попрофилируй.

так будет значительно быстрее:

((uint)MathRound(Первая_компонента))|((uint)MathRound(Вторая_компонента)<<8)|((uint)MathRound(Третья_компонента)<<16);
 
Nikolai Semko:

строка 

источник бешенных тормозов 

Попробуй попрофилируй.

так будет значительно быстрее:

Блин. Ну вот у моего алгоритма такая же скорость, как и у твоего.))

Спасибо, Николай!

Просто я незнаком с подобными операциями.
 
Реter Konow:

Блин. Ну вот у моего алгоритма такая же скорость, как и у твоего.))

Спасибо, Николай!

пока нет. Нужно еще пару моментов исправить.

 

Убрал лишние функции. Теперь только главная функция:

//+------------------------------------------------------------------+
//|                                              Gradient test 1.mq4 |
//|                                                      Peter Konow |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Peter Konow"
#property link      "https://www.mql5.com"
#property version   "1.00"
#include <Canvas\Canvas.mqh>
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
union rgb {uint clr; uchar c[4];};
rgb C,cc;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnStart()
  {
   CCanvas canvas;
   if(!canvas.CreateBitmapLabel("Gradient",200,200,768,256,COLOR_FORMAT_ARGB_NORMALIZE)) { Print("Error creating canvas: ",GetLastError()); }
   double d=5;
   uint Gradient[256];
   while(!IsStopped())
     {
      C.c[2]=uchar(127.5*(1+sin(d*1.2))+0.4999); C.c[1]=uchar(127.5*(1+sin(d*1.9))+0.4999); C.c[0]=uchar(127.5*(1+sin(d*2.8))+0.4999);  // генерируем новый цвет
      cc.clr=C.clr;
      ulong t=GetMicrosecondCount();
      Диапазон_оттенков(C.clr,Gradient);
      //Gradient(C.clr,Gradient,256);
      t=GetMicrosecondCount()-t;
      for(int y=0; y<256; y++)
        {
         //Alert(__FUNCTION__,"  Gradient[",y,"]  ",Gradient[y]);
         //canvas.LineHorizontal(0,767,y,ColorToARGB(StringToColor(Gradient[y]),255));
         canvas.LineHorizontal(0,767,y,ColorToARGB(Gradient[y],255));
         C.clr=Gradient[y];
         canvas.PixelSet((int)C.c[2]+(int)C.c[1]+(int)C.c[0],y,ColorToARGB(clrWhite));
         if (C.c[1]>0) canvas.PixelSet(int(50.0*(int)C.c[2]/(double)C.c[1]+50.0*(int)C.c[0]/(double)C.c[1]),y,ColorToARGB(clrGreen));
         if (C.c[2]>0) canvas.PixelSet(int(50.0*(int)C.c[1]/(double)C.c[2]+50.0*(int)C.c[0]/(double)C.c[2]),y,ColorToARGB(clrRed));
         if (C.c[0]>0) canvas.PixelSet(int(50.0*(int)C.c[2]/(double)C.c[0]+50.0*(int)C.c[1]/(double)C.c[0]),y,ColorToARGB(clrBlue));
        }
      canvas.FillRectangle(500,75,660,150,ColorToARGB(cc.clr,240));
      canvas.FontSet("Tahoma",20); 
      canvas.TextOut(510,85,"R = "+string(cc.c[2]),ColorToARGB(~cc.clr)); 
      canvas.TextOut(510,107,"G = "+string(cc.c[1]),ColorToARGB(~cc.clr)); 
      canvas.TextOut(510,129,"B = "+string(cc.c[0]),ColorToARGB(~cc.clr));
      canvas.FontSet("Times New Roman",15);
      canvas.TextOut(300,10,"Время формирования градиентного массива из 256 элементов = "+string(t)+" микросекунд",ColorToARGB(clrWhite));
      canvas.Update();
      d+=0.01;
      Sleep(30);
     }
   canvas.Destroy();
//------------------------
// for(int a1 = 0; a1 < 256; a1++)Alert(__FUNCTION__,"  Gradient[",a1,"]  ",Gradient[a1]);
  }
//+------------------------------------------------------------------+
//================================================================================================================================================================
void Диапазон_оттенков(color _Цвет, uint &Все_оттенки[])
{
 color R = 0, G = 0,  B = 0;
 int   q = 0, w1 = 0, w2 = 0;
 double Components[3];
 //------------------------------------------------------
 uint Этот_цвет;
 double Тангенс_угла_старшего_треугольника_1,      
        Тангенс_угла_среднего_треугольника_1,                  
        Тангенс_угла_младшего_треугольника_1,                       
        Значение_в_точке_преломления_старшей_компоненты,  
        Значение_в_точке_преломления_средней_компоненты,
        Значение_в_точке_преломления_младшей_компоненты,    
        Тангенс_угла_старшего_треугольника_2,
        Тангенс_угла_среднего_треугольника_2,    
        Тангенс_угла_младшего_треугольника_2;
 //------------------------------------------------------
 double pi = 3.1415926536,
        Comp_1,Comp_2,Comp_3,
        //-----------------------------------------------
        Первая_компонента = 0.0,
        Вторая_компонента = 0.0,
        Третья_компонента = 0.0,
        //-----------------------------------------------
        Исходный_R = (_Цвет)&0xff, 
        Исходный_G = (_Цвет>>8)&0xff, 
        Исходный_B = (_Цвет>>16)&0xff;        
        //-----------------------------------------------

   //-----------------------------------------------
   Components[0] = Исходный_R;
   Components[1] = Исходный_G;
   Components[2] = Исходный_B;
   //---------------------------
   ArraySort(Components);
   //---------------------------
   double Старшая_компонента         = Components[2]; 
   double Средняя_компонента         = Components[1]; 
   double Младшая_компонента         = Components[0]; 
//-----------------------------------------------
   double Координата_исходного_цвета=Старшая_компонента/tan((63.43989*pi)/180)+Младшая_компонента/2;
//-----------------------------------------------
 //-----------------------------------------------
 if(Старшая_компонента == Исходный_R)R = (color)Старшая_компонента;
 if(Старшая_компонента == Исходный_G)G = (color)Старшая_компонента; 
 if(Старшая_компонента == Исходный_B)B = (color)Старшая_компонента;     
 //------------------------
 if(Средняя_компонента == Исходный_R)R = (color)Средняя_компонента;
 if(Средняя_компонента == Исходный_G)G = (color)Средняя_компонента; 
 if(Средняя_компонента == Исходный_B)B = (color)Средняя_компонента; 
 //------------------------
 if(Младшая_компонента == Исходный_R)R = (color)Младшая_компонента;
 if(Младшая_компонента == Исходный_G)G = (color)Младшая_компонента; 
 if(Младшая_компонента == Исходный_B)B = (color)Младшая_компонента; 
 //------------------------------------------------
   
 //==========================================================================================
 if(Координата_исходного_цвета <= 127)
   {
    Тангенс_угла_старшего_треугольника_1  = Старшая_компонента/Координата_исходного_цвета;
    Тангенс_угла_среднего_треугольника_1  = Средняя_компонента/Координата_исходного_цвета;     
    Тангенс_угла_младшего_треугольника_1  = Младшая_компонента/Координата_исходного_цвета;
    //-----------------------------------------------
    Значение_в_точке_преломления_старшей_компоненты  = Тангенс_угла_старшего_треугольника_1*128;
    Значение_в_точке_преломления_средней_компоненты  = Тангенс_угла_среднего_треугольника_1*128;
    Значение_в_точке_преломления_младшей_компоненты  = Тангенс_угла_младшего_треугольника_1*128;    
    //-----------------------------------------------    
    Тангенс_угла_старшего_треугольника_2  = (255 - Значение_в_точке_преломления_старшей_компоненты)/128;
    Тангенс_угла_среднего_треугольника_2  = (255 - Значение_в_точке_преломления_средней_компоненты)/128;       
    Тангенс_угла_младшего_треугольника_2  = (255 - Значение_в_точке_преломления_младшей_компоненты)/128;
    //-----------------------------------------------    
    for(int a1 = 0; a1 < 128; a1++)
      {
       Comp_1 = Тангенс_угла_старшего_треугольника_1*a1;
       Comp_2 = Тангенс_угла_среднего_треугольника_1*a1;
       Comp_3 = Тангенс_угла_младшего_треугольника_1*a1;
       //---------------------------------------------------
       if(Comp_1 > 255)Comp_1 = 255;
       if(Comp_1 > 255)Comp_2 = 255;
       if(Comp_1 > 255)Comp_3 = 255;
       if(Comp_1 < 0 )Comp_1 = 0;
       if(Comp_2 < 0 )Comp_2 = 0;
       if(Comp_3 < 0 )Comp_3 = 0;           
       //---------------------------------------------------
       if(R == Старшая_компонента)Первая_компонента = Comp_1;
       if(R == Средняя_компонента)Первая_компонента = Comp_2;
       if(R == Младшая_компонента)Первая_компонента = Comp_3;
       //---------------------------------------------------
       if(G == Старшая_компонента)Вторая_компонента = Comp_1;
       if(G == Средняя_компонента)Вторая_компонента = Comp_2;
       if(G == Младшая_компонента)Вторая_компонента = Comp_3;
       //---------------------------------------------------
       if(B == Старшая_компонента)Третья_компонента = Comp_1;
       if(B == Средняя_компонента)Третья_компонента = Comp_2;
       if(B == Младшая_компонента)Третья_компонента = Comp_3;
       //---------------------------------------------------
       Все_оттенки[a1] = ((uint)MathRound(Первая_компонента))|((uint)MathRound(Вторая_компонента)<<8)|((uint)MathRound(Третья_компонента)<<16);
       //---------------------------------------------------------------------------    
       w1++;
      }
    //------------------------------------------------------------------------------
    for(int a2 = 255; a2 >= w1; a2--)
      {
       Comp_1 = 255 - Тангенс_угла_старшего_треугольника_2*q;
       Comp_2 = 255 - Тангенс_угла_среднего_треугольника_2*q;
       Comp_3 = 255 - Тангенс_угла_младшего_треугольника_2*q;
       //---------------------------------------------------
       if(Comp_1 > 255)Comp_1 = 255;
       if(Comp_1 > 255)Comp_2 = 255;
       if(Comp_1 > 255)Comp_3 = 255;
       if(Comp_1 < 0 )Comp_1 = 0;
       if(Comp_2 < 0 )Comp_2 = 0;
       if(Comp_3 < 0 )Comp_3 = 0;           
       //---------------------------------------------------       
       if(R == Старшая_компонента)Первая_компонента = Comp_1;
       if(R == Средняя_компонента)Первая_компонента = Comp_2;
       if(R == Младшая_компонента)Первая_компонента = Comp_3;
       //---------------------------------------------------
       if(G == Старшая_компонента)Вторая_компонента = Comp_1;
       if(G == Средняя_компонента)Вторая_компонента = Comp_2;
       if(G == Младшая_компонента)Вторая_компонента = Comp_3;
       //---------------------------------------------------
       if(B == Старшая_компонента)Третья_компонента = Comp_1;
       if(B == Средняя_компонента)Третья_компонента = Comp_2;
       if(B == Младшая_компонента)Третья_компонента = Comp_3;
       //---------------------------------------------------
       Все_оттенки[a2] = ((uint)MathRound(Первая_компонента))|((uint)MathRound(Вторая_компонента)<<8)|((uint)MathRound(Третья_компонента)<<16);
       //---------------------------------------------------------------------------
       q++;
      }
  } 
 //------------------------------------------------------------------------------
 if(Координата_исходного_цвета > 127)
   {
    Тангенс_угла_старшего_треугольника_1  = (255 - Старшая_компонента)/(255 - Координата_исходного_цвета);
    Тангенс_угла_среднего_треугольника_1  = (255 - Средняя_компонента)/(255 - Координата_исходного_цвета);       
    Тангенс_угла_младшего_треугольника_1  = (255 - Младшая_компонента)/(255 - Координата_исходного_цвета);
    //-----------------------------------------------
    Значение_в_точке_преломления_старшей_компоненты  = 255 - (Тангенс_угла_старшего_треугольника_1*128);
    Значение_в_точке_преломления_средней_компоненты  = 255 - (Тангенс_угла_среднего_треугольника_1*128);
    Значение_в_точке_преломления_младшей_компоненты  = 255 - (Тангенс_угла_младшего_треугольника_1*128);    
    //-----------------------------------------------    
    Тангенс_угла_старшего_треугольника_2  = Значение_в_точке_преломления_старшей_компоненты/128;
    Тангенс_угла_среднего_треугольника_2  = Значение_в_точке_преломления_средней_компоненты/128;      
    Тангенс_угла_младшего_треугольника_2  = Значение_в_точке_преломления_младшей_компоненты/128;
    //-----------------------------------------------    
    for(int b1 = 0; b1 < 128; b1++)
      {
       Comp_1 = Тангенс_угла_старшего_треугольника_2*b1;
       Comp_2 = Тангенс_угла_среднего_треугольника_2*b1;
       Comp_3 = Тангенс_угла_младшего_треугольника_2*b1;
       //---------------------------------------------------
       if(Comp_1 > 255)Comp_1 = 255;
       if(Comp_1 > 255)Comp_2 = 255;
       if(Comp_1 > 255)Comp_3 = 255;
       if(Comp_1 < 0 )Comp_1 = 0;
       if(Comp_2 < 0 )Comp_2 = 0;
       if(Comp_3 < 0 )Comp_3 = 0;           
       //---------------------------------------------------
       if(R == Старшая_компонента)Первая_компонента = Comp_1;
       if(R == Средняя_компонента)Первая_компонента = Comp_2;
       if(R == Младшая_компонента)Первая_компонента = Comp_3;
       //---------------------------------------------------
       if(G == Старшая_компонента)Вторая_компонента = Comp_1;
       if(G == Средняя_компонента)Вторая_компонента = Comp_2;
       if(G == Младшая_компонента)Вторая_компонента = Comp_3;
       //---------------------------------------------------
       if(B == Старшая_компонента)Третья_компонента = Comp_1;
       if(B == Средняя_компонента)Третья_компонента = Comp_2;
       if(B == Младшая_компонента)Третья_компонента = Comp_3;
       //---------------------------------------------------
       Все_оттенки[b1] = ((uint)MathRound(Первая_компонента))|((uint)MathRound(Вторая_компонента)<<8)|((uint)MathRound(Третья_компонента)<<16);
       //---------------------------------------------------------------------------    
       w2++;
      }
    //------------------------------------------------------------------------------
    for(int b2 = 255; b2 >= w2; b2--)
      {
       Comp_1 = 255 - Тангенс_угла_старшего_треугольника_1*q;
       Comp_2 = 255 - Тангенс_угла_среднего_треугольника_1*q;
       Comp_3 = 255 - Тангенс_угла_младшего_треугольника_1*q;
       //---------------------------------------------------
       if(Comp_1 > 255)Comp_1 = 255;
       if(Comp_1 > 255)Comp_2 = 255;
       if(Comp_1 > 255)Comp_3 = 255;
       if(Comp_1 < 0 )Comp_1 = 0;
       if(Comp_2 < 0 )Comp_2 = 0;
       if(Comp_3 < 0 )Comp_3 = 0;           
       //---------------------------------------------------       
       if(R == Старшая_компонента)Первая_компонента = Comp_1;
       if(R == Средняя_компонента)Первая_компонента = Comp_2;
       if(R == Младшая_компонента)Первая_компонента = Comp_3;
       //---------------------------------------------------
       if(G == Старшая_компонента)Вторая_компонента = Comp_1;
       if(G == Средняя_компонента)Вторая_компонента = Comp_2;
       if(G == Младшая_компонента)Вторая_компонента = Comp_3;
       //---------------------------------------------------
       if(B == Старшая_компонента)Третья_компонента = Comp_1;
       if(B == Средняя_компонента)Третья_компонента = Comp_2;
       if(B == Младшая_компонента)Третья_компонента = Comp_3;
       //---------------------------------------------------
       Этот_цвет = ((uint)MathRound(Первая_компонента))|((uint)MathRound(Вторая_компонента)<<8)|((uint)MathRound(Третья_компонента)<<16);
       //---------------------------------------------------------------------------    
       Все_оттенки[b2] = Этот_цвет; 
       //---------------------------------------------------------------------------
       q++;
      }
   }   
 //------------------------------------------------------------------------------  
}
//=============================================================================
 
Nikolai Semko:
Подколол, Андрей. :)
На самом деле интересная задача получить палитру цвета без цветовых сгустков и минимальным искажением цвета. Очевидно, что дельта между составляющими цвета не должна быть константой и должна плавно меняться  . В приведенных выше примерах она имеет два значения : от чёрного и от белого. Поэтому это меня и зацепило.

Ну да, именно обсуждению задачи посвящено 18 страниц. И ни слова об ООП, русских названиях переменных, и будущем автотрейдинга )

 
Andrey Khatimlianskii:

Ну да, именно обсуждению задачи посвящено 18 страниц. И ни слова об ООП, русских названиях переменных, и будущем автотрейдинга )

Почему, я говорил про кириллицу несколько раз только в этой ветке. Но Петр непрошибаемый в вопросе ООП и кириллицы, что я уже махнул рукой и думаю, что моё "шевство" над ним закончилось до тех пор, пока не увижу от него код с его собственными классами без кириллицы и использующего отладку. Я ему уже неоднократно говорил, что без ООП и стиля с возможностью отладки (т.е. без кириллицы)  ГУИ его никогда не увидит света, а если и увидит, то туж же будет освистано и закинуто тухлыми яйцами с помидорами. Что поделать, если Пётр при его фантастической настойчивости и работоспособности (что код умудряется писать без отладчика) имеет такую же фантастическую степень консерватизма и упертости. 

Но без Петра этот форум был бы не столь харизматичен. ))
 
TheXpert:

наверное так быстрее немного будет:

void Gradient(uint clr1,uint clr2,uint &arr[],uint size)
  {
   if(size==0) return;
   ArrayResize(arr,size);
   arr[0]=clr1; 
   rgb c1,c2;
   c1.clr=clr1;
   c2.clr=clr2;
   double R1=c1.c[2],G1=c1.c[1],B1=c1.c[0];
   double R2=c2.c[2],G2=c2.c[1],B2=c2.c[0];
   double deltaR=(R2-R1)/(size-1);
   double deltaG=(G2-G1)/(size-1);
   double deltaB=(B2-B1)/(size-1);
   R1 += 0.4999;
   G1 += 0.4999;
   B1 += 0.4999;
   for(uint i=1;i<size;i++)
     {
      R1+=deltaR; c1.c[2]=uchar (R1);
      G1+=deltaG; c1.c[1]=uchar (G1);
      B1+=deltaB; c1.c[0]=uchar (B1);
      arr[i]=c1.clr;
     }
  }

Согласен. 

 
Nikolai Semko:

Согласен. 

Николай, будем объективны. 

Убрав неактуальное в этом тесте рисование, я сделал скрипт максимально простым, и выявил следующие расхождения:

Как ты видишь, центр диапазона цвета в твоем алгоритме смещен наверх. Самая яркая полоса должна находится в центре. Это подтверждает палитра Виндоус:

 


Ниже, прилагаю скрипт для тестирования:

Файлы:
 

Ячейка 127 - это центр массива оттенков. В этой ячейке, должен находится тот же цвет, что и в палитре. У меня погрешность 1, у тебя  63. 

Мельтешение и излишнее рисование мешало сконцентрироваться на проверке правильности работы алгоритма. Поэтому, я и предлагал проверять по распечатке в Alert.

ЗЫ. Вообще, центр массива - ячейка 128, но сути это не меняет.
 

Новые интересные факты:

  • Цвет синий - C'0,0,255'

  • Цвет зеленый  - C'0,255,0'

  • Цвет серый  - C'128,128,128' (оба варианта совпадают)

  • Цвет  - C'128,64,0' (огромная разница)



Без обид Николай, но твой алгоритм быстрее и короче (факт), но работает он неправильно (тоже факт). Ему нехватает продуманной концептуальной базы.

Моему алгоритму изначально нехватало скорости (но ты помог), и отлаженности. При этом, в его работу была изначально заложена продуманная и правильная концепция.

Поэтому, такая получилась разница.