L1Trend/Scripts/L1TrendImageDenoise.mq5

173 lines
6.6 KiB
MQL5
Raw Permalink Normal View History

//+------------------------------------------------------------------+
//| 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();
}
//+------------------------------------------------------------------+