173 lines
6.6 KiB
MQL5
173 lines
6.6 KiB
MQL5
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| L1TrendImageDenoise.mq5 |
|
||
|
|
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||
|
|
//| http://www.mql5.com |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
#property copyright "Copyright 2000-2026, MetaQuotes Ltd."
|
||
|
|
#property link "https://www.mql5.com"
|
||
|
|
#property version "1.00"
|
||
|
|
|
||
|
|
#include <Canvas\Canvas.mqh>
|
||
|
|
#include <Graphics\Graphic.mqh>
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Convert BMP image to double vectors RGB |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool PreprocessImage(vector<double> &red,vector<double> &green,vector<double> &blue,uint &image_data[],int width,int height)
|
||
|
|
{
|
||
|
|
red.Resize(width*height);
|
||
|
|
green.Resize(width*height);
|
||
|
|
blue.Resize(width*height);
|
||
|
|
|
||
|
|
for(int y=0; y<height; y++)
|
||
|
|
for(int x=0; x<width; x++)
|
||
|
|
{
|
||
|
|
int offset = y*width + x;
|
||
|
|
uint clr = image_data[offset];
|
||
|
|
red[offset] = double((clr>>16)&0xFF)/255.0;
|
||
|
|
green[offset] = double((clr>>8)&0xFF)/255.0;
|
||
|
|
blue[offset] = double(clr&0xFF)/255.0;
|
||
|
|
}
|
||
|
|
return(true);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Clamp value to range |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
double clamp(double value,double minValue,double maxValue)
|
||
|
|
{
|
||
|
|
return(MathMin(MathMax(value,minValue),maxValue));
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Convert double vectors back to image |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool PostprocessImage(const vector<double> &red,const vector<double>&green,const vector<double> &blue,uint &image_data[],int width,int height)
|
||
|
|
{
|
||
|
|
ArrayResize(image_data,width*height);
|
||
|
|
|
||
|
|
for(int y=0; y<height; y++)
|
||
|
|
for(int x=0; x<width; x++)
|
||
|
|
{
|
||
|
|
int offset = y*width + x;
|
||
|
|
uchar r = uchar(clamp(red[offset]*255.0,0,255));
|
||
|
|
uchar g = uchar(clamp(green[offset]*255.0,0,255));
|
||
|
|
uchar b = uchar(clamp(blue[offset]*255.0,0,255));
|
||
|
|
image_data[offset] = XRGB(r,g,b);
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| L1 Trend Filter for single channel using vector<double> |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool L1FilterChannel(vector<double> &channel,int width,int height,double lambda)
|
||
|
|
{
|
||
|
|
vector<double> row;
|
||
|
|
row.Resize(width);
|
||
|
|
//--- rows
|
||
|
|
for(int y=0; y<height; y++)
|
||
|
|
{
|
||
|
|
for(int x=0; x<width; x++)
|
||
|
|
row[x] = channel[y*width+x];
|
||
|
|
row.L1TrendFilter(lambda,true,row);
|
||
|
|
for(int x=0; x<width; x++)
|
||
|
|
channel[y*width+x]=row[x];
|
||
|
|
}
|
||
|
|
vector<double> col;
|
||
|
|
col.Resize(height);
|
||
|
|
//--- columns
|
||
|
|
for(int x=0; x<width; x++)
|
||
|
|
{
|
||
|
|
for(int y=0; y<height; y++)
|
||
|
|
col[y] = channel[y*width+x];
|
||
|
|
col.L1TrendFilter(lambda,true,col);
|
||
|
|
for(int y=0; y<height; y++)
|
||
|
|
channel[y*width+x]=col[y];
|
||
|
|
}
|
||
|
|
//---
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Show image on canvas |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool ShowImage(CCanvas &canvas,string name,int x0,int y0,int width,int height,uint &image_data[])
|
||
|
|
{
|
||
|
|
canvas.CreateBitmapLabel(name,x0,y0,width,height,COLOR_FORMAT_XRGB_NOALPHA);
|
||
|
|
for(int y=0; y<height; y++)
|
||
|
|
for(int x=0; x<width; x++)
|
||
|
|
canvas.PixelSet(x,y,image_data[y*width+x]);
|
||
|
|
canvas.Update(true);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Script start |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void OnStart()
|
||
|
|
{
|
||
|
|
string image_path[1];
|
||
|
|
if(FileSelectDialog("Select BMP image",NULL,"Bitmap files (*.bmp)|*.bmp",FSD_FILE_MUST_EXIST,image_path,"a.bmp") != 1)
|
||
|
|
{
|
||
|
|
Print("File not selected");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
//--- load BMP into array
|
||
|
|
uint image_data[];
|
||
|
|
int width,height;
|
||
|
|
if(!CCanvas::LoadBitmap(image_path[0],image_data,width,height))
|
||
|
|
{
|
||
|
|
PrintFormat("CCanvas::LoadBitmap failed with error %d", GetLastError());
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
//--- prepare channels
|
||
|
|
vector<double> red,green,blue;
|
||
|
|
PreprocessImage(red,green,blue,image_data,width,height);
|
||
|
|
//--- perform 4 filters with different lambda
|
||
|
|
double lambda_factors[4] = {0.00001, 0.00005, 0.0001, 0.0002};
|
||
|
|
vector<double> red_f[4],green_f[4],blue_f[4];
|
||
|
|
for(int i=0; i<4; i++)
|
||
|
|
{
|
||
|
|
red_f[i] = red;
|
||
|
|
green_f[i] = green;
|
||
|
|
blue_f[i] = blue;
|
||
|
|
//---
|
||
|
|
L1FilterChannel(red_f[i],width,height,lambda_factors[i]);
|
||
|
|
L1FilterChannel(green_f[i],width,height,lambda_factors[i]);
|
||
|
|
L1FilterChannel(blue_f[i],width,height,lambda_factors[i]);
|
||
|
|
}
|
||
|
|
//--- post processing
|
||
|
|
uint filtered_data1[];
|
||
|
|
uint filtered_data2[];
|
||
|
|
uint filtered_data3[];
|
||
|
|
uint filtered_data4[];
|
||
|
|
//---
|
||
|
|
PostprocessImage(red_f[0],green_f[0],blue_f[0],filtered_data1,width,height);
|
||
|
|
PostprocessImage(red_f[1],green_f[1],blue_f[1],filtered_data2,width,height);
|
||
|
|
PostprocessImage(red_f[2],green_f[2],blue_f[2],filtered_data3,width,height);
|
||
|
|
PostprocessImage(red_f[3],green_f[3],blue_f[3],filtered_data4,width,height);
|
||
|
|
//--- show all images: original + 4 filteres
|
||
|
|
CCanvas canvas;
|
||
|
|
canvas.CreateBitmapLabel("Comparison",0,0,width*5,height,COLOR_FORMAT_XRGB_NOALPHA);
|
||
|
|
//--- original
|
||
|
|
for(int y=0; y<height; y++)
|
||
|
|
for(int x=0; x<width; x++)
|
||
|
|
canvas.PixelSet(x,y,image_data[y*width + x]);
|
||
|
|
//--- 4 filtered
|
||
|
|
int i=0;
|
||
|
|
for(int y=0; y<height; y++)
|
||
|
|
for(int x=0; x<width; x++)
|
||
|
|
canvas.PixelSet(x+width*(i+1),y,filtered_data1[y*width+x]);
|
||
|
|
i=1;
|
||
|
|
for(int y=0; y<height; y++)
|
||
|
|
for(int x=0; x<width; x++)
|
||
|
|
canvas.PixelSet(x+width*(i+1),y,filtered_data2[y*width+x]);
|
||
|
|
i=2;
|
||
|
|
for(int y=0; y<height; y++)
|
||
|
|
for(int x=0; x<width; x++)
|
||
|
|
canvas.PixelSet(x+width*(i+1),y,filtered_data3[y*width+x]);
|
||
|
|
i=3;
|
||
|
|
for(int y=0; y<height; y++)
|
||
|
|
for(int x=0; x<width; x++)
|
||
|
|
canvas.PixelSet(x + width*(i+1),y,filtered_data4[y*width+x]);
|
||
|
|
//---
|
||
|
|
canvas.Update(true);
|
||
|
|
DebugBreak();
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|