unit MainUnit;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, IOGraphics, ExtCtrls, FileCtrl, FunUnit, Math, MyGlobal, TIFformat, FFT;

const
  Rows = 30;
  gamma = 2.2;
  lowestvalue = 3000;
  highestvalue = 9000;
  C = 3500;

type
    TMainForm = class(TForm)
    DriveComboBox1: TDriveComboBox;
    DirectoryListBox1: TDirectoryListBox;
    FileListBox1: TFileListBox;
    AverageButton: TButton;
    MedianButton: TButton;
    SigmaClippingButton: TButton;
    SigmaMedianClippingButton: TButton;
    NormaliseButton: TButton;
    procedure AverageButtonClick(Sender: TObject);
    procedure FileListBox1MouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure MedianButtonClick(Sender: TObject);
    procedure SigmaClippingButtonClick(Sender: TObject);
    procedure SigmaMedianClippingButtonClick(Sender: TObject);
    procedure NormaliseButtonClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  MainForm: TMainForm;

implementation

uses ImageUnit, ProgressUnit;

{$R *.dfm}

procedure TMainForm.AverageButtonClick(Sender: TObject);
var i, j, w, h, index, adr, cnt, row, ind, endind, hend, wend: Integer;
    SL: PByteArray;
begin
  cnt := 0;
  Stop := False;

  with FileListBox1 do
    begin
      if SelCount <= 1 then
        begin
          ShowMessage('Oznacte prosim alespon dva soubory.');
          Exit;
        end;
      for i := 0 to Count - 1 do
        begin
          if Selected[i] then
            break;
        end;

      LoadImageFromFile(Items[i], Info, InImg, 16, True, True); //prvni nacitani alokuje pamet samo

      with ImageForm do
        begin
          Caption := 'Result';
          Image.Width := Info.ImgWidth;
          Image.Height := Info.ImgHeight;
          Image.Picture.Bitmap.Width := Info.ImgWidth;
          Image.Picture.Bitmap.Height := Info.ImgHeight;
          Image.Picture.Bitmap.PixelFormat := pf24bit;
        end;
      ImageForm.Visible := True;  
      ProgressForm.Visible := True;
      ProgressForm.Gauge.Progress := 0;
      Application.ProcessMessages;

      hend := Info.ImgHeight div Rows;
      wend := Info.ImgWidth * Rows;

      for h := 0 to hend - 1 do     //pruchod po Rows radcich
        begin
          index := h * wend;  //index prvniho prvku na Rows*h-tem radku
          for i := 0 to Count - 1 do    //projde polozky listboxu
            if Selected[i] then      //dal projdou jen oznacene
              begin
                LoadImageFromFile(Items[i], Info, InImg, 16, False, True); //dalsi nacitani uz ma pamet alokovanou
                TempImg := InImg;
                for w := 0 to wend - 1 do  //nacitani hodnot v kazdem pixelu v radku
                  begin
                    //h * Info.ImgWidth * Rows + w... index Rows * h-teho radku a w-teho sloupce
                    PixelStack[w, cnt].R := TempImg^[index + w].R;
                    PixelStack[w, cnt].G := TempImg^[index + w].G;
                    PixelStack[w, cnt].B := TempImg^[index + w].B;
                  end;  //for w
                inc(cnt);
              end; //if Selected[i]
          for w := 0 to wend - 1 do    //prumer... ukladani do Img: TWColorArray
            begin                               //a naplneni scanlinu (z 16 na 8 bit)
              for j := 0 to cnt - 1 do
                begin
                  DataR[j] := PixelStack[w, j].R;
                  DataG[j] := PixelStack[w, j].G;
                  DataB[j] := PixelStack[w, j].B;
                end;

              R := Round(Avg(DataR, cnt));
              G := Round(Avg(DataG, cnt));
              B := Round(Avg(DataB, cnt));

              AdjustRGB(R, G, B, lowestvalue, highestvalue); //hodnota jasu potom bude v nasem intervalu

              // gamma korekce
              GammaCorrection(R, G, B, gamma, lowestvalue, highestvalue);

              Img[index + w].R := R;         //prirazeni vyslednych hodnot pixelu do obrazku
              Img[index + w].G := G;
              Img[index + w].B := B;
            end;  //for w
          ind := Rows * h;
          endind := ind + Rows - 1;
          for row := ind to endind do
            begin
              SL := ImageForm.Image.Picture.Bitmap.ScanLine[row];
              index := row * Info.ImgWidth; //index prvniho prvku na r-tem radku
              for w := 0 to Info.ImgWidth - 1 do
                begin
                  adr := 3 * w;
                  SL^[adr] := Img[index + w].B div 256;
                  SL^[succ(adr)] := Img[index + w].G div 256;
                  SL^[succ(succ(adr))] := Img[index + w].R div 256;
                end; //for w
            end; //for row
          if h mod 1 = 0 then
            begin
              ImageForm.Image.Repaint;
              ProgressForm.Gauge.Progress := Round((Rows * h / Info.ImgHeight) * 100);
              Application.ProcessMessages;
              if Stop then
                begin
                  ProgressForm.Visible := False;
                  Exit;
                end;  //if Stop
            end;  //if h mod 1 = 0
          cnt := 0;
        end; //for h
    end;  //with FileListBox1
  ImageForm.Image.Repaint;
  ProgressForm.Gauge.Progress := 100;
  Application.ProcessMessages;
  ImageToTIFF16(@Img, Info.ImgWidth, Info.ImgHeight, False, ResDir + 'AverageResult.tif');
  ProgressForm.Visible := False;
  Application.ProcessMessages;
end;

procedure TMainForm.FileListBox1MouseMove(Sender: TObject;  //aby se po najeti kurzorem na soubor zobrazil jeho cely nazev
  Shift: TShiftState; X, Y: Integer);
var lstIndex : Integer ;
begin
  with FileListBox1 do
  begin
    lstIndex:=SendMessage(Handle, LB_ITEMFROMPOINT, 0, MakeLParam(x,y)) ;
    if (lstIndex >= 0) and (lstIndex <= Items.Count) then
      Hint := Items[lstIndex]
    else
      Hint := ''
  end;
end;

procedure TMainForm.MedianButtonClick(Sender: TObject);
var i, j, w, h, index, adr, cnt, row, ind, endind, hend, wend: Integer;
    SL: PByteArray;
begin
  Stop := False;
  cnt := 0;

  with FileListBox1 do
    begin
      if SelCount <= 1 then
        begin
          ShowMessage('Oznacte prosim alespon dva soubory.');
          Exit;
        end;
      for i := 0 to Count - 1 do
        begin
          if Selected[i] then
            break;
        end;

      LoadImageFromFile(Items[i], Info, InImg, 16, True, True); //prvni nacitani alokuje pamet samo

      with ImageForm do
        begin
          Caption := 'Result';
          Image.Width := Info.ImgWidth;
          Image.Height := Info.ImgHeight;
          Image.Picture.Bitmap.Width := Info.ImgWidth;
          Image.Picture.Bitmap.Height := Info.ImgHeight;
          Image.Picture.Bitmap.PixelFormat := pf24bit;
        end;
      ImageForm.Visible := True;
      ProgressForm.Visible := True;
      ProgressForm.Gauge.Progress := 0;
      Application.ProcessMessages;

      hend := Info.ImgHeight div Rows;
      wend := Info.ImgWidth * Rows;

      for h := 0 to hend - 1 do     //pruchod po Rows radcich
        begin
          index := h * wend;  //index prvniho prvku na Rows * h-tem radku
          for i := 0 to Count - 1 do    //projde polozky listboxu
            if Selected[i] then      //dal projdou jen oznacene
              begin
                LoadImageFromFile(Items[i], Info, InImg, 16, False, True); //dalsi nacitani uz ma pamet alokovanou
                TempImg := InImg;
                for w := 0 to wend - 1 do  //nacitani hodnot v kazdem pixelu v radku
                  begin
                    //h * Info.ImgWidth * Rows + w... index Rows * h-teho radku a w-teho sloupce
                    PixelStack[w, cnt].R := TempImg^[index + w].R;
                    PixelStack[w, cnt].G := TempImg^[index + w].G;
                    PixelStack[w, cnt].B := TempImg^[index + w].B;
                  end;  //for w
                inc(cnt);
              end; //if Selected[i]
          for w := 0 to wend - 1 do    //median... ukladani do Img: TWColorArray
            begin                               //a naplneni scanlinu (z 16 na 8 bit)
              for j := 0 to cnt - 1 do
                begin
                  DataR[j] := PixelStack[w, j].R;
                  DataG[j] := PixelStack[w, j].G;
                  DataB[j] := PixelStack[w, j].B;
                end;

              R := QuickMedian(DataR, cnt);
              G := QuickMedian(DataG, cnt);
              B := QuickMedian(DataB, cnt);

              AdjustRGB(R, G, B, lowestvalue, highestvalue); //hodnota jasu potom bude v nasem intervalu

              // gamma korekce
              GammaCorrection(R, G, B, gamma, lowestvalue, highestvalue);

              Img[index + w].R := R;
              Img[index + w].G := G;
              Img[index + w].B := B;
            end;  //for w
          ind := Rows * h;
          endind := ind + Rows - 1;
          for row := ind to endind do
            begin
              SL := ImageForm.Image.Picture.Bitmap.ScanLine[row];
              index := row * Info.ImgWidth; //index prvniho prvku na row-tem radku
              for w := 0 to Info.ImgWidth - 1 do
                begin
                  adr := 3 * w;
                  SL^[adr] := Img[index + w].B div 256;
                  SL^[succ(adr)] := Img[index + w].G div 256;
                  SL^[succ(succ(adr))] := Img[index + w].R div 256;
                end; //for w
            end; //for row
          if h mod 1 = 0 then
            begin
              ImageForm.Image.Repaint;
              ProgressForm.Gauge.Progress := Round((Rows * h / Info.ImgHeight) * 100);
              Application.ProcessMessages;
              if Stop then
                begin
                  ProgressForm.Visible := False;
                  Exit;
                end;  //if Stop
            end;  //if h mod 1 = 0
          cnt := 0;
        end; //for h
    end;  //with FileListBox1
  ImageForm.Image.Repaint;
  ProgressForm.Gauge.Progress := 100;
  Application.ProcessMessages;
  ImageToTIFF16(@Img, Info.ImgWidth, Info.ImgHeight, False, ResDir + 'MedianResult.tif');
  ProgressForm.Visible := False;
  Application.ProcessMessages;
end;

procedure TMainForm.SigmaClippingButtonClick(Sender: TObject);
var i, j, w, h, index, adr, cnt, cntR, cntG, cntB, it, NumOfIt, row, ind, endind, hend, wend: Integer;
    SL: PByteArray;
    sHigh, sLow: Real;
    med: TWColor;
    UpBound, LowBound, sigma: TWRealColor;
begin
  Stop := False;
  cnt := 0;
  sLow := 1;
  sHigh := 1;
  NumOfIt := 3;

  with FileListBox1 do
    begin
      if SelCount <= 7 then
        begin
          ShowMessage('Oznacte prosim alespon osm souboru.');
          Exit;
        end;
      for i := 0 to Count - 1 do
        begin
          if Selected[i] then
            break;
        end;

      LoadImageFromFile(Items[i], Info, InImg, 16, True, True); //prvni nacitani alokuje pamet samo

      with ImageForm do
        begin
          Caption := 'Result';
          Image.Width := Info.ImgWidth;
          Image.Height := Info.ImgHeight;
          Image.Picture.Bitmap.Width := Info.ImgWidth;
          Image.Picture.Bitmap.Height := Info.ImgHeight;
          Image.Picture.Bitmap.PixelFormat := pf24bit;
        end;
      ImageForm.Visible := True;
      ProgressForm.Visible := True;
      ProgressForm.Gauge.Progress := 0;
      Application.ProcessMessages;

      hend := Info.ImgHeight div Rows;
      wend := Info.ImgWidth * Rows;

      for h := 0 to hend - 1 do     //pruchod po Rows radcich
        begin
          index := h * wend;  //index prvniho prvku na Rows * h-tem radku
          for i := 0 to Count - 1 do    //projde polozky listboxu
            if Selected[i] then      //dal projdou jen oznacene
              begin
                LoadImageFromFile(Items[i], Info, InImg, 16, False, True); //dalsi nacitani uz ma pamet alokovanou
                TempImg := InImg;
                for w := 0 to wend - 1 do  //nacitani hodnot v kazdem pixelu v radku
                  begin
                    //h * Info.ImgWidth * Rows + w... index Rows * h-teho radku a w-teho sloupce
                    PixelStack[w, cnt].R := TempImg^[index + w].R;
                    PixelStack[w, cnt].G := TempImg^[index + w].G;
                    PixelStack[w, cnt].B := TempImg^[index + w].B;
                  end;  //for w
                inc(cnt);
              end; //if Selected[i]
          for w := 0 to wend - 1 do    //sigma clipping a prumer... ukladani do Img: TWColorArray
            begin                               //a naplneni scanlinu (z 16 na 8 bit) - gamma korekce
              for j := 0 to cnt - 1 do
                begin
                  DataR[j] := PixelStack[w, j].R;
                  DataG[j] := PixelStack[w, j].G;
                  DataB[j] := PixelStack[w, j].B;
                end;

              cntR := cnt;
              cntG := cnt;
              cntB := cnt;
              //sigma clipping s iteracemi
              for it := 0 to NumOfIt - 1 do
                begin
                  med.R := QuickMedian(DataR, cntR);
                  med.G := QuickMedian(DataG, cntG);
                  med.B := QuickMedian(DataB, cntB);

                  sigma.R := MedDev(DataR, cntR);   //smerodatna odchylka
                  sigma.G := MedDev(DataG, cntG);
                  sigma.B := MedDev(DataB, cntB);

                  UpBound.R := med.R + sHigh * sigma.R;       //stanoveni hornich a dolnich hranic
                  UpBound.G := med.G + sHigh * sigma.G;
                  UpBound.B := med.B + sHigh * sigma.B;
                  LowBound.R := med.R - sLow * sigma.R;
                  LowBound.G := med.G - sLow * sigma.G;
                  LowBound.B := med.B - sLow * sigma.B;

                  j := 0;  //kdyz hodnota nesplnuje podminku, vymaze se a Data se presunou o jednu pozici doleva namisto ni
                  while (j <= cntR - 1) do
                    if (DataR[j] < LowBound.R) OR (DataR[j] > UpBound.R) then
                      MoveLeft(DataR, j, cntR)
                      else inc(j);
                  j := 0;
                  while (j <= cntG - 1) do
                    if (DataG[j] < LowBound.G) OR (DataG[j] > UpBound.G) then
                      MoveLeft(DataG, j, cntG)
                      else inc(j);
                  j := 0;
                  while (j <= cntB - 1) do
                    if (DataB[j] < LowBound.B) OR (DataB[j] > UpBound.B) then
                      MoveLeft(DataB, j, cntB)
                      else inc(j);
                end;

              R := Round(Avg(DataR, cntR));
              G := Round(Avg(DataG, cntG));
              B := Round(Avg(DataB, cntB));

              AdjustRGB(R, G, B, lowestvalue, highestvalue); //hodnota jasu potom bude v nasem intervalu

              // gamma korekce
              GammaCorrection(R, G, B, gamma, lowestvalue, highestvalue);

              Img[index + w].R := R;
              Img[index + w].G := G;
              Img[index + w].B := B;
            end;  //for w
          ind := Rows * h;
          endind := ind + Rows - 1;
          for row := ind to endind do
            begin
              SL := ImageForm.Image.Picture.Bitmap.ScanLine[row];
              index := row * Info.ImgWidth; //index prvniho prvku na row-tem radku
              for w := 0 to Info.ImgWidth - 1 do
                begin
                  adr := 3 * w;
                  SL^[adr] := Img[index + w].B div 256;
                  SL^[succ(adr)] := Img[index + w].G div 256;
                  SL^[succ(succ(adr))] := Img[index + w].R div 256;
                end; //for w
            end; //for row
          if h mod 1 = 0 then
            begin
              ImageForm.Image.Repaint;
              ProgressForm.Gauge.Progress := Round((Rows * h / Info.ImgHeight) * 100);
              Application.ProcessMessages;
              if Stop then
                begin
                  ProgressForm.Visible := False;
                  Exit;
                end;  //if Stop
            end;  //if h mod 1 = 0
          cnt := 0;
        end; //for h
    end;  //with FileListBox1
  ImageForm.Image.Repaint;
  ProgressForm.Gauge.Progress := 100;
  Application.ProcessMessages;
  ImageToTIFF16(@Img, Info.ImgWidth, Info.ImgHeight, False, ResDir + 'SigmaClippingResult.tif');
  ProgressForm.Visible := False;
  Application.ProcessMessages;
end;

procedure TMainForm.SigmaMedianClippingButtonClick(Sender: TObject);
var i, j, w, h, index, adr, cnt, it, NumOfIt, row, ind, endind, hend, wend: Integer;
    SL: PByteArray;
    sHigh, sLow: Real;
    med: TWColor;
    UpBound, LowBound, sigma: TWRealColor;
begin
  Stop := False;
  cnt := 0;
  sLow := 1;
  sHigh := 1;
  NumOfIt := 3;

  with FileListBox1 do
    begin
      if SelCount <= 7 then
        begin
          ShowMessage('Oznacte prosim alespon osm souboru.');
          Exit;
        end;
      for i := 0 to Count - 1 do
        begin
          if Selected[i] then
            break;
        end;

      LoadImageFromFile(Items[i], Info, InImg, 16, True, True); //prvni nacitani alokuje pamet samo

      with ImageForm do
        begin
          Caption := 'Result';
          Image.Width := Info.ImgWidth;
          Image.Height := Info.ImgHeight;
          Image.Picture.Bitmap.Width := Info.ImgWidth;
          Image.Picture.Bitmap.Height := Info.ImgHeight;
          Image.Picture.Bitmap.PixelFormat := pf24bit;
        end;
      ImageForm.Visible := True;
      ProgressForm.Visible := True;
      ProgressForm.Gauge.Progress := 0;
      Application.ProcessMessages;

      hend := Info.ImgHeight div Rows;
      wend := Info.ImgWidth * Rows;

      for h := 0 to hend - 1 do     //pruchod po Rows radcich
        begin
          index := h * wend;  //index prvniho prvku na Rows * h-tem radku
          for i := 0 to Count - 1 do    //projde polozky listboxu
            if Selected[i] then      //dal projdou jen oznacene
              begin
                LoadImageFromFile(Items[i], Info, InImg, 16, False, True); //dalsi nacitani uz ma pamet alokovanou
                TempImg := InImg;
                for w := 0 to wend - 1 do  //nacitani hodnot v kazdem pixelu v radku
                  begin
                    //h * Info.ImgWidth * Rows + w... index Rows * h-teho radku a w-teho sloupce
                    PixelStack[w, cnt].R := TempImg^[index + w].R;
                    PixelStack[w, cnt].G := TempImg^[index + w].G;
                    PixelStack[w, cnt].B := TempImg^[index + w].B;
                  end;  //for w
                inc(cnt);
              end; //if Selected[i]
          for w := 0 to wend - 1 do    //sigma median clipping a prumer... ukladani do Img: TWColorArray
            begin                               //a naplneni scanlinu (z 16 na 8 bit) - gamma korekce
              for j := 0 to cnt - 1 do
                begin
                  DataR[j] := PixelStack[w, j].R;
                  DataG[j] := PixelStack[w, j].G;
                  DataB[j] := PixelStack[w, j].B;
                end;

              //sigma median clipping s iteracemi
              for it := 0 to NumOfIt - 1 do
                begin
                  med.R := QuickMedian(DataR, cnt);
                  med.G := QuickMedian(DataG, cnt);
                  med.B := QuickMedian(DataB, cnt);

                  sigma.R := MedDev(DataR, cnt);   //smerodatna odchylka
                  sigma.G := MedDev(DataG, cnt);
                  sigma.B := MedDev(DataB, cnt);

                  UpBound.R := med.R + sHigh * sigma.R;       //stanoveni hornich a dolnich hranic
                  UpBound.G := med.G + sHigh * sigma.G;
                  UpBound.B := med.B + sHigh * sigma.B;
                  LowBound.R := med.R - sLow * sigma.R;
                  LowBound.G := med.G - sLow * sigma.G;
                  LowBound.B := med.B - sLow * sigma.B;

                 //kdyz hodnota nesplnuje podminku, nahradi se medianem
                  for j := 0 to cnt - 1 do
                    if (DataR[j] < LowBound.R) OR (DataR[j] > UpBound.R) then
                      DataR[j] := med.R;
                  for j := 0 to cnt - 1 do
                    if (DataG[j] < LowBound.G) OR (DataG[j] > UpBound.G) then
                      DataG[j] := med.G;
                  for j := 0 to cnt - 1 do
                    if (DataB[j] < LowBound.B) OR (DataB[j] > UpBound.B) then
                      DataB[j] := med.B;
                end;

              R := Round(Avg(DataR, cnt));
              G := Round(Avg(DataG, cnt));
              B := Round(Avg(DataB, cnt));

              AdjustRGB(R, G, B, lowestvalue, highestvalue); //hodnota jasu potom bude v nasem intervalu

              // gamma korekce
              GammaCorrection(R, G, B, gamma, lowestvalue, highestvalue);

              Img[index + w].R := R;
              Img[index + w].G := G;
              Img[index + w].B := B;
            end;  //for w
          ind := Rows * h;
          endind := ind + Rows - 1;
          for row := ind to endind do
            begin
              SL := ImageForm.Image.Picture.Bitmap.ScanLine[row];
              index := row * Info.ImgWidth; //index prvniho prvku na row-tem radku
              for w := 0 to Info.ImgWidth - 1 do
                begin
                  adr := 3 * w;
                  SL^[adr] := Img[index + w].B div 256;
                  SL^[succ(adr)] := Img[index + w].G div 256;
                  SL^[succ(succ(adr))] := Img[index + w].R div 256;
                end; //for w
            end; //for row
          if h mod 1 = 0 then
            begin
              ImageForm.Image.Repaint;
              ProgressForm.Gauge.Progress := Round((Rows * h / Info.ImgHeight) * 100);
              Application.ProcessMessages;
              if Stop then
                begin
                  ProgressForm.Visible := False;
                  Exit;
                end;  //if Stop
            end;  //if h mod 1 = 0
          cnt := 0;
        end; //for h
    end;  //with FileListBox1
  ImageForm.Image.Repaint;
  ProgressForm.Gauge.Progress := 100;
  Application.ProcessMessages;
  ImageToTIFF16(@Img, Info.ImgWidth, Info.ImgHeight, False, ResDir + 'SigmaMedianClippingResult.tif');
  ProgressForm.Visible := False;
  Application.ProcessMessages;
end;

procedure TMainForm.NormaliseButtonClick(Sender: TObject);
var h, w, i, len, cnt, row, col, index, newindex, NumOfRows, NumOfCols, RectHeight, RectWidth, hind, hendind, wind, wendind, red, green, blue: Integer;
    med, average: TWColor;
    ImgWidth, ImgHeight: Word;
begin
  Stop := False;
  cnt := 0;
  NumOfRows := N;
  NumOfCols := N;
  //ImgWidth := 3600;
  //ImgHeight := 3600;
  ProgressForm.Visible := True;
  ProgressForm.Gauge.Progress := 0;
  Application.ProcessMessages;
  with FileListBox1 do
    begin
      if SelCount < 2 then
        begin
          ShowMessage('Oznacte prosim alespon dva soubory.');
          Exit;
        end;
      for i := 0 to Count - 1 do    //projde polozky listboxu
        if Selected[i] then      //dal projdou jen oznacene
          begin
            if cnt = SelCount div 2 then
              break;
            inc(cnt);
          end; //if Selected[i]
      LoadImageFromFile(Items[i], Info, InImg, 16, True, True); //prvni nacitani - alokuje se pamet automaticky
      TempImg := InImg;
      ImgWidth := Info.ImgWidth;
      ImgHeight := Info.ImgHeight;
      RectHeight := ImgHeight div NumOfRows;
      RectWidth := ImgWidth div NumOfCols;
      ImgHeight := NumOfRows * RectHeight;
      ImgWidth := NumOfCols * RectWidth;
      for row := 0 to NumOfRows - 1 do
        for col := 0 to NumOfCols - 1 do
          begin
            len := 0;
            hind := row * RectHeight;
            hendind := hind + RectHeight;
            wind := col * RectWidth;
            wendind := wind + RectWidth;
            for h := hind to hendind - 1 do
              begin
                index := h * Info.ImgWidth; //index prvniho prvku na h - tem radku
                for w := wind to wendind - 1 do
                  begin
                    BigData[len] := TempImg^[index + w].R;
                    inc(len);
                  end; //for w
              end; //for h
            FFTImgR[row + 1, col + 1] := QuickMedian(BigData, len);
            len := 0;
            for h := hind to hendind - 1 do
              begin
                index := h * Info.ImgWidth; //index prvniho prvku na h - tem radku
                for w := wind to wendind - 1 do
                  begin
                    BigData[len] := TempImg^[index + w].G;
                    inc(len);
                  end; //for w
              end; //for h
            FFTImgG[row + 1, col + 1] := QuickMedian(BigData, len);
            len := 0;
            for h := hind to hendind - 1 do
              begin
                index := h * Info.ImgWidth; //index prvniho prvku na h - tem radku
                for w := wind to wendind - 1 do
                  begin
                    BigData[len] := TempImg^[index + w].B;
                    inc(len);
                  end; //for w
              end; //for h
            FFTImgB[row + 1, col + 1] := QuickMedian(BigData, len);
          end; //for col
      FourierTransform(FFTImgR, SpcR);  //Fourierova transformace kazde slozky
      FourierTransform(FFTImgG, SpcG);
      FourierTransform(FFTImgB, SpcB);

      for h := 1 to M do              //naplneni spektra nulami do matice M x M
        for w := 1 to M do
          begin
            BigSpc[h, w].Re := 0;
            BigSpc[h, w].Im := 0;
          end;
      for h := 1 to N do                //kopirovani hodnot z maleho do velkeho spektra pro R
        for w := 1 to N do
          begin
            BigSpc[h, w].Re := SpcR[h, w].Re;
            BigSpc[h, w].Im := SpcR[h, w].Im;
          end;
      InverseFourierTransform(BigSpc, BigFFTImgR); //inverzni FT - roztahnuti obrazku
      for h := 1 to N do                //kopirovani hodnot z maleho do velkeho spektra pro G
        for w := 1 to N do
          begin
            BigSpc[h, w].Re := SpcG[h, w].Re;
            BigSpc[h, w].Im := SpcG[h, w].Im;
          end;
      InverseFourierTransform(BigSpc, BigFFTImgG);
      for h := 1 to N do                //kopirovani hodnot z maleho do velkeho spektra pro B
        for w := 1 to N do
          begin
            BigSpc[h, w].Re := SpcB[h, w].Re;
            BigSpc[h, w].Im := SpcB[h, w].Im;
          end;
      InverseFourierTransform(BigSpc, BigFFTImgB);

      cnt := 0;
      for i := 0 to Count - 1 do    //projde polozky listboxu
        if Selected[i] then      //dal projdou jen oznacene
          begin
            LoadImageFromFile(Items[i], Info, InImg, 16, False, True);
            TempImg := InImg;
            for row := 0 to NumOfRows - 1 do
              for col := 0 to NumOfCols - 1 do
                begin
                  hind := row * RectHeight;
                  hendind := hind + RectHeight;
                  wind := col * RectWidth;
                  wendind := wind + RectWidth;
                  for h := hind to hendind - 1 do     //naplneni noveho obrazku
                    begin
                      newindex := h * ImgWidth; //index prvniho prvku na h - tem radku v novem obrazku
                      index := h * Info.ImgWidth; //index prvniho prvku na h - tem radku
                      for w := wind to wendind - 1 do
                        begin
                          red := TempImg^[index + w].R - BigFFTImgR[h + 1, w + 1] + C;
                          green := TempImg^[index + w].G - BigFFTImgG[h + 1, w + 1] + C;
                          blue := TempImg^[index + w].B - BigFFTImgB[h + 1, w + 1] + C;
                          if (red < 0) then Img[newindex + w].R := 0                  //ochrana proti pod a preteceni
                            else if (red > 65535) then Img[newindex + w].R := 65535
                              else Img[newindex + w].R := red;
                          if (green < 0) then Img[newindex + w].G := 0
                            else if (green > 65535) then Img[newindex + w].G := 65535
                              else Img[newindex + w].G := green;
                          if (blue < 0) then Img[newindex + w].B := 0
                            else if (blue > 65535) then Img[newindex + w].B := 65535
                              else Img[newindex + w].B := blue;
                        end;
                    end;
                end; //for col
            ImageToTIFF16(@Img, ImgWidth, ImgHeight, False, NormDir + Info.FileName);
            inc(cnt);
            ProgressForm.Gauge.Progress := Round((cnt / SelCount) * 100);
            Application.ProcessMessages;
            if Stop then
              begin
                ProgressForm.Visible := False;
                Exit;
              end;  //if Stop
          end; //if Selected[i]
    end; //with FileListBox1
    ProgressForm.Visible := False;
    Application.ProcessMessages;
end;

end.
