unit MainUnit;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, openTIFF, ExtCtrls, Menus, MaticeUnit, GraphUnit,
  ComCtrls, ExtDlgs, ToolWin, ModelUnit, KonvKernelUnit;

const
  cPixel = 0.0018408425; //v mm
  cSnimek = 0.005; // v mm

type
  TMainForm = class(TForm)
    MainMenu1: TMainMenu;
    Soubor1: TMenuItem;
    ListBox1: TListBox;
    OpenDialog1: TOpenDialog;
    Panel2: TPanel;
    Image1: TImage;
    TrackBar1: TTrackBar;
    TrackBar2: TTrackBar;
    Label2: TLabel;
    ScrollBox1: TScrollBox;
    Shape1: TShape;
    Analzaobrazu1: TMenuItem;
    Otevt1: TMenuItem;
    Label1: TLabel;
    RadioGroup1: TRadioGroup;
    RadioGroup2: TRadioGroup;
    Exporthodnot1: TMenuItem;
    SaveTextFileDialog1: TSaveTextFileDialog;
    Graf1: TMenuItem;
    N2: TMenuItem;
    Otevt2: TMenuItem;
    Vytvoitvkovprofil1: TMenuItem;
    Konvoluce1: TMenuItem;
    Exportjakostl1: TMenuItem;
    N3Dmodel1: TMenuItem;
    Uloitaktulnsnmek1: TMenuItem;
    SavePictureDialog1: TSavePictureDialog;
    SaveTextFileDialog2: TSaveTextFileDialog;
    CheckBox1: TCheckBox;
    procedure Otevt1Click(Sender: TObject); //Načtení obrázků do pole Bitmap
    procedure ListBox1DblClick(Sender: TObject); //Vybrat vzorovy obrazek
    procedure Image1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer); //Hue v kliku a z intervalu
    procedure TrackBar1Change(Sender: TObject); //Zmena intervalu vyberu hue
    procedure RadioGroup1Click(Sender: TObject); //Nastavení tvaru okolí
    procedure RadioGroup2Click(Sender: TObject); //Nastavení velikosti okolí
    procedure Analzaobrazu1Click(Sender: TObject); //Analýza obrazu
    function ZobrazitTif(Image16Array: PImage16ArrayRGB; Tiffinf: TTIFFinfo): TBitmap;
    procedure ZobrazPixely(Image16Array: PImage16ArrayRGB; Tiffinf: TTIFFinfo; H: Double);
    procedure Konec1Click(Sender: TObject);
    procedure Exporthodnot1Click(Sender: TObject);
    procedure Otevt2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Vytvoitvkovprofil1Click(Sender: TObject);
    procedure N3Dmodel1Click(Sender: TObject);
    procedure Uloitaktulnsnmek1Click(Sender: TObject);
    procedure Konvoluce1Click(Sender: TObject);
    procedure Image1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
    procedure Image1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
    procedure Exportjakostl1Click(Sender: TObject);

  private
    { Private declarations }
    CisloVzor: Integer;
    bAnalyza,
    bKlik,
    bVysProf,
    bZobrVysProf,
    bPoKonv,
    bGraf: Boolean;
    HodnotySnimku: TMatice;
  public
    { Public declarations }
  end;

var
  MainForm: TMainForm;
  Indexes: TIndexes;
  obrazek: Array of PImage16ArrayRGB;
  snimek: PImage16ArrayRGB;
  VyskaVeSnimku, VyskaPoKonv: TMatice;
  //VyskaVeSnimku: Array of Array of Single;
  ZnamVysku: Array of Array of Boolean;
  TIFFinfo: Array of TTIFFinfo;
  Vzorovy, bmpVysProfil, bmpPoKonv: TBitmap;
  nacteni:bool;
  MinY,MaxY,MinX,MaxX:integer;
  apar, bpar, cpar, dpar, epar: Double;
  XproMereni, YProMereni: Integer;
  PrumerHue: TMatice;
  function MaximumRGB(R, G, B: Word): Word;
  function MinimumRGB(R, G, B: Word): Word;
  function Hue(R, G, B: Word): Double;
  function Jas(R, G, B: Word): Double;
implementation

uses Math;

{$R *.DFM}

procedure TMainForm.Otevt1Click(Sender: TObject);
var i: Integer;
begin
  OpenDialog1.Options := OpenDialog1.Options + [ofAllowMultiSelect];
  if OpenDialog1.Execute then begin
    ListBox1.Clear;
    for i:= 0 to OpenDialog1.Files.Count -1 do begin
      SetLength(obrazek, i + 1);
      SetLength(TIFFinfo, i + 1);
      ListBox1.Items.Add(extractfilename(OpenDialog1.Files[i]));
      TestTIFFile(OpenDialog1.Files[i],TIFFinfo[i]);
      LoadFromFileTIF(OpenDialog1.Files[i],1,obrazek[i],TIFFinfo[i]);
    end;
    bAnalyza := True;
    bGraf := False;
    PrumerHue := TMatice.Create(0,0);
  end;
end;

procedure TMainForm.Otevt2Click(Sender: TObject);
begin
  OpenDialog1.Options := OpenDialog1.Options - [ofAllowMultiSelect];
  if OpenDialog1.Execute then begin
    //SetLength(obrazek, 0);
    Shape1.Visible := False;
    ListBox1.Clear;
    SetLength(TIFFinfo, Length(TIFFinfo) + 1);
    ListBox1.Items.Add(extractfilename(OpenDialog1.FileName));
    TestTIFFile(OpenDialog1.FileName,TIFFinfo[Length(TIFFinfo)-1]);
    LoadFromFileTIF(OpenDialog1.FileName,1,snimek,TIFFinfo[Length(TIFFinfo) - 1]);
    bAnalyza := False;
    bZobrVysProf := False;
    bPoKonv := False;
    Vytvoitvkovprofil1.Enabled := True;
    Vzorovy := ZobrazitTif(snimek, TIFFinfo[Length(TIFFinfo) - 1]);
    Image1.Picture.Bitmap := Vzorovy;
  end;
end;

procedure TMainForm.ListBox1DblClick(Sender: TObject);
begin
  if bAnalyza then begin
    CisloVzor:= ListBox1.ItemIndex;
    Vzorovy := ZobrazitTif(obrazek[CisloVzor], TIFFinfo[CisloVzor]);
  end else begin
    Vzorovy := ZobrazitTif(snimek, TIFFinfo[Length(TIFFinfo)-1]);
  end;
  Image1.Picture.Bitmap := Vzorovy;
  Image1.Visible := True;
  bZobrVysProf := False;
  bPoKonv := False;
end;

procedure TMainForm.N3Dmodel1Click(Sender: TObject);
var
  model3D: TModelForm;
  i, j, adr: Integer;
  Tiffinf: TTIFFinfo;
begin
  Tiffinf := TIFFinfo[Length(TiffInfo)-1];
  HodnotySnimku := TMatice.Create(TIFFinf[1].Height.Value,3*TIFFinf[1].Width.Value);
  for i:=0 to Tiffinf[1].Height.Value-1 do begin
    Adr:=i*Tiffinf[1].Width.Value*3;
    for j:=0 to Tiffinf[1].Width.Value*3-1 do begin
      HodnotySnimku.elem[i, j]:=Round(snimek^[Adr+j]/256);
    end; // for k
  end; // for j

  model3D := TModelForm.Create(Self);
  try
    model3D.MaticeVysek := VyskaPoKonv;
    model3D.MaticeHodnot := HodnotySnimku;
    model3D.ShowModal;
  finally
    FreeAndNil(model3D);
  end;

end;

// Procedura ListBox1DblClick

procedure TMainForm.Exporthodnot1Click(Sender: TObject);
var RozptylHue, MaticeHue: TMatice;
    i, j, k, c, Adr, Adr2: Integer;
    SLVzor: PByteArray;
    R, G, B: Word;
    StredX, StredY: Double;
    mr: TModalResult;
    Tiffinf: TTIFFinfo;
    Image16Array: PImage16ArrayRGB;
begin
  PrumerHue := TMatice.Create(ListBox1.Count,1);
  if (Shape1.Shape = stSquare) then begin
    for i := 0 to PrumerHue.m -1 do begin
      c := 0;
      Image16Array := obrazek[i];
      Tiffinf := TIFFinfo[i];
      for j := Shape1.Top+ScrollBox1.VertScrollBar.Position to Shape1.Top+Shape1.Height+ScrollBox1.VertScrollBar.Position do begin
        SLVzor := Image1.Picture.Bitmap.ScanLine[j];
        Adr := j * Tiffinf[1].Width.Value*3;
        for k := Shape1.Left+ScrollBox1.HorzScrollBar.Position to Shape1.Left+Shape1.Width+ScrollBox1.HorzScrollBar.Position do begin
          Adr2 := 3 * k;
          B:=SLVzor^[Adr2];
          G:=SLVzor^[Adr2+1];
          R:=SLVzor^[Adr2+2];
          if ((B = 255) and (G = 255) and (R = 255)) then begin
            B:=Image16Array^[Adr + Adr2];
            G:=Image16Array^[Adr + Adr2 + 1];
            R:=Image16Array^[Adr + Adr2 + 2];
            PrumerHue.elem[i,0] := PrumerHue.elem[i,0] + Hue(R,G,B);
            Inc(c);
          end;//if je na obrazku bila
        end; //k - sloupec
      end;//j - řádek
      try
        PrumerHue.elem[i,0] := PrumerHue.elem[i,0]/c;
      except
        ShowMessage('Špatně vybraná oblast');
        break;
      end;
    end;//i - prochazeni obrazku
  end// if square okolí

  else if (Shape1.Shape = stCircle ) then begin
    StredX := Shape1.Left+(Shape1.Width/2)+ScrollBox1.HorzScrollBar.Position;
    StredY := Shape1.Top+(Shape1.Height/2)+ScrollBox1.VertScrollBar.Position;
    for i := 0 to PrumerHue.m -1 do begin
      c := 0;
      Image16Array := obrazek[i];
      Tiffinf := TIFFinfo[i];
      for j := Shape1.Top+ScrollBox1.VertScrollBar.Position to Shape1.Top+Shape1.Height+ScrollBox1.VertScrollBar.Position do begin
          SLVzor := Image1.Picture.Bitmap.ScanLine[j];
          Adr := j * Tiffinf[1].Width.Value*3;
          for k := Shape1.Left+ScrollBox1.HorzScrollBar.Position to Shape1.Left+Shape1.Width+ScrollBox1.HorzScrollBar.Position do begin
            if (sqrt(sqr(k-StredX)+sqr(j-StredY))<= Shape1.Width) then begin
              Adr2 := 3 * k;
              B:=SLVzor^[Adr2];
              G:=SLVzor^[Adr2+1];
              R:=SLVzor^[Adr2+2];
              if ((B = 255) and (G = 255) and (R = 255)) then begin
                B:=Image16Array^[Adr + Adr2];
                G:=Image16Array^[Adr + Adr2 + 1];
                R:=Image16Array^[Adr + Adr2 + 2];
                PrumerHue.elem[i,0] := PrumerHue.elem[i,0] + Hue(R,G,B);
                Inc(c);
              end;//if je na obrazku bila
            end; // if vzdalenost
          end; //k - sloupec
      end;//j - řádek
      try
        PrumerHue.elem[i,0] := PrumerHue.elem[i,0]/c;
      except
        ShowMessage('Špatně vybraná oblast');
        break;
      end;
    end;//i - prochazeni obrazku
  end; // if circle okolí
  if SaveTextFileDialog1.Execute then begin
    PrumerHue.s_uloz(SaveTextFileDialog1.FileName);
  end;
end;

procedure TMainForm.Exportjakostl1Click(Sender: TObject);
var f:TExtFile;
  i, j: Integer;
  x, y: Double;
begin
  if SaveTextFileDialog2.Execute then begin
    AssignFile(f, SaveTextFileDialog2.FileName);
    Rewrite(f);
    WriteLn(f, 'solid OBJECT');
    for i := 0 to VyskaPoKonv.m - 2 do begin
      for j := 0 to VyskaPoKonv.n - 2 do begin
        WriteLn(f, 'facet normal 0 0 1');
        WriteLn(f, 'outer loop');
        WriteLn(f, 'vertex ' + FloatToStr((j)*cPixel).Replace(',','.') + ' ' + FloatToStr((i)*cPixel).Replace(',','.') + ' ' + FloatToStr(cSnimek*VyskaPoKonv.elem[VyskaPoKonv.m-1-i,j]).Replace(',','.'));
        WriteLn(f, 'vertex ' + FloatToStr((j+1)*cPixel).Replace(',','.') + ' ' + FloatToStr((i)*cPixel).Replace(',','.') + ' ' + FloatToStr(cSnimek*VyskaPoKonv.elem[VyskaPoKonv.m-1-i,j+1]).Replace(',','.'));
        WriteLn(f, 'vertex ' + FloatToStr((j+1)*cPixel).Replace(',','.') + ' ' + FloatToStr((i+1)*cPixel).Replace(',','.') + ' ' + FloatToStr(cSnimek*VyskaPoKonv.elem[VyskaPoKonv.m-1-i-1,j+1]).Replace(',','.'));
        WriteLn(f, 'endloop');
        WriteLn(f, 'endfacet');

        WriteLn(f, 'facet normal 0 0 1');
        WriteLn(f, 'outer loop');
        WriteLn(f, 'vertex ' + FloatToStr((j)*cPixel).Replace(',','.') + ' ' + FloatToStr((i)*cPixel).Replace(',','.') + ' ' + FloatToStr(cSnimek*VyskaPoKonv.elem[VyskaPoKonv.m-i-1,j]).Replace(',','.'));
        WriteLn(f, 'vertex ' + FloatToStr((j+1)*cPixel).Replace(',','.') + ' ' + FloatToStr((i+1)*cPixel).Replace(',','.') + ' ' + FloatToStr(cSnimek*VyskaPoKonv.elem[VyskaPoKonv.m-i-1-1,j+1]).Replace(',','.'));
        WriteLn(f, 'vertex ' + FloatToStr((j)*cPixel).Replace(',','.') + ' ' + FloatToStr((i+1)*cPixel).Replace(',','.') + ' ' + FloatToStr(cSnimek*VyskaPoKonv.elem[VyskaPoKonv.m-i-1-1,j]).Replace(',','.'));
        WriteLn(f, 'endloop');
        WriteLn(f, 'endfacet');
      end;
    end;
    for i := 0 to VyskaPoKonv.m - 2 do begin
      WriteLn(f, 'facet normal 0 -1 0');
      WriteLn(f, 'outer loop');
      WriteLn(f, 'vertex ' + FloatToStr(0) + ' ' + FloatToStr((i)*cPixel).Replace(',','.') + ' ' + FloatToStr(cSnimek*VyskaPoKonv.elem[VyskaPoKonv.m-i-1,0]).Replace(',','.'));
      WriteLn(f, 'vertex ' + FloatToStr(0) + ' ' + FloatToStr((i)*cPixel).Replace(',','.') + ' ' + FloatToStr(0));
      WriteLn(f, 'vertex ' + FloatToStr(0) + ' ' + FloatToStr((i+1)*cPixel).Replace(',','.') + ' ' + FloatToStr(0));
      WriteLn(f, 'endloop');
      WriteLn(f, 'endfacet');
      WriteLn(f, 'facet normal 0 -1 0');
      WriteLn(f, 'outer loop');
      WriteLn(f, 'vertex ' + FloatToStr(0) + ' ' + FloatToStr((i)*cPixel).Replace(',','.') + ' ' + FloatToStr(cSnimek*VyskaPoKonv.elem[VyskaPoKonv.m-i-1,0]).Replace(',','.'));
      WriteLn(f, 'vertex ' + FloatToStr(0) + ' ' + FloatToStr((i+1)*cPixel).Replace(',','.') + ' ' + FloatToStr(cSnimek*VyskaPoKonv.elem[VyskaPoKonv.m-i-1-1,0]).Replace(',','.'));
      WriteLn(f, 'vertex ' + FloatToStr(0) + ' ' + FloatToStr((i+1)*cPixel).Replace(',','.') + ' ' + FloatToStr(0));
      WriteLn(f, 'endloop');
      WriteLn(f, 'endfacet');

      WriteLn(f, 'facet normal 0 1 0');
      WriteLn(f, 'outer loop');
      WriteLn(f, 'vertex ' + FloatToStr((VyskaPoKonv.n-1)*cPixel).Replace(',','.') + ' ' + FloatToStr((i)*cPixel).Replace(',','.') + ' ' + FloatToStr(cSnimek*VyskaPoKonv.elem[VyskaPoKonv.m-i-1,VyskaPoKonv.n-1]).Replace(',','.'));
      WriteLn(f, 'vertex ' + FloatToStr((VyskaPoKonv.n-1)*cPixel).Replace(',','.') + ' ' + FloatToStr((i)*cPixel).Replace(',','.') + ' ' + FloatToStr(0));
      WriteLn(f, 'vertex ' + FloatToStr((VyskaPoKonv.n-1)*cPixel).Replace(',','.') + ' ' + FloatToStr((i+1)*cPixel).Replace(',','.') + ' ' + FloatToStr(0));
      WriteLn(f, 'endloop');
      WriteLn(f, 'endfacet');
      WriteLn(f, 'facet normal 0 1 0');
      WriteLn(f, 'outer loop');
      WriteLn(f, 'vertex ' + FloatToStr((VyskaPoKonv.n-1)*cPixel).Replace(',','.') + ' ' + FloatToStr((i)*cPixel).Replace(',','.') + ' ' + FloatToStr(cSnimek*VyskaPoKonv.elem[VyskaPoKonv.m-i-1,VyskaPoKonv.n-1]).Replace(',','.'));
      WriteLn(f, 'vertex ' + FloatToStr((VyskaPoKonv.n-1)*cPixel).Replace(',','.') + ' ' + FloatToStr((i+1)*cPixel).Replace(',','.') + ' ' + FloatToStr(cSnimek*VyskaPoKonv.elem[VyskaPoKonv.m-i-1-1,VyskaPoKonv.n-1]).Replace(',','.'));
      WriteLn(f, 'vertex ' + FloatToStr((VyskaPoKonv.n-1)*cPixel).Replace(',','.') + ' ' + FloatToStr((i+1)*cPixel).Replace(',','.') + ' ' + FloatToStr(0));
      WriteLn(f, 'endloop');
      WriteLn(f, 'endfacet');
    end;
    for j := 0 to VyskaPoKonv.n - 2 do begin
      WriteLn(f, 'facet normal -1 0 0');
      WriteLn(f, 'outer loop');
      WriteLn(f, 'vertex ' + FloatToStr((j)*cPixel).Replace(',','.') + ' ' + FloatToStr(0) + ' ' + FloatToStr(cSnimek*VyskaPoKonv.elem[VyskaPoKonv.m-1,j]).Replace(',','.'));
      WriteLn(f, 'vertex ' + FloatToStr((j)*cPixel).Replace(',','.') + ' ' + FloatToStr(0) + ' ' + FloatToStr(0));
      WriteLn(f, 'vertex ' + FloatToStr((j+1)*cPixel).Replace(',','.') + ' '+ FloatToStr(0) + ' ' + FloatToStr(0));
      WriteLn(f, 'endloop');
      WriteLn(f, 'endfacet');
      WriteLn(f, 'facet normal -1 0 0');
      WriteLn(f, 'outer loop');
      WriteLn(f, 'vertex ' + FloatToStr((j)*cPixel).Replace(',','.') + ' ' + FloatToStr(0) + ' ' + FloatToStr(cSnimek*VyskaPoKonv.elem[VyskaPoKonv.m-1,j]).Replace(',','.'));
      WriteLn(f, 'vertex ' + FloatToStr((j+1)*cPixel).Replace(',','.') + ' ' + FloatToStr(0) + ' ' + FloatToStr(cSnimek*VyskaPoKonv.elem[VyskaPoKonv.m-1,j+1]).Replace(',','.'));
      WriteLn(f, 'vertex ' + FloatToStr((j+1)*cPixel).Replace(',','.') + ' '+ FloatToStr(0) + ' ' + FloatToStr(0));
      WriteLn(f, 'endloop');
      WriteLn(f, 'endfacet');

      WriteLn(f, 'facet normal 1 0 0');
      WriteLn(f, 'outer loop');
      WriteLn(f, 'vertex ' + FloatToStr((j)*cPixel).Replace(',','.') + ' ' + FloatToStr((VyskaPoKonv.m-1)*cPixel).Replace(',','.') + ' ' + FloatToStr(cSnimek*VyskaPoKonv.elem[0,j]).Replace(',','.'));
      WriteLn(f, 'vertex ' + FloatToStr((j)*cPixel).Replace(',','.') + ' ' + FloatToStr((VyskaPoKonv.m-1)*cPixel).Replace(',','.') + ' ' + FloatToStr(0));
      WriteLn(f, 'vertex ' + FloatToStr((j+1)*cPixel).Replace(',','.') + ' '+ FloatToStr((VyskaPoKonv.m-1)*cPixel).Replace(',','.') + ' ' + FloatToStr(0));
      WriteLn(f, 'endloop');
      WriteLn(f, 'endfacet');
      WriteLn(f, 'facet normal 1 0 0');
      WriteLn(f, 'outer loop');
      WriteLn(f, 'vertex ' + FloatToStr((j)*cPixel).Replace(',','.') + ' ' + FloatToStr((VyskaPoKonv.m-1)*cPixel).Replace(',','.') + ' ' + FloatToStr(cSnimek*VyskaPoKonv.elem[0,j]).Replace(',','.'));
      WriteLn(f, 'vertex ' + FloatToStr((j+1)*cPixel).Replace(',','.') + ' ' + FloatToStr((VyskaPoKonv.m-1)*cPixel).Replace(',','.') + ' ' + FloatToStr(cSnimek*VyskaPoKonv.elem[0,j+1]).Replace(',','.'));
      WriteLn(f, 'vertex ' + FloatToStr((j+1)*cPixel).Replace(',','.') + ' '+ FloatToStr((VyskaPoKonv.m-1)*cPixel).Replace(',','.') + ' ' + FloatToStr(0));
      WriteLn(f, 'endloop');
      WriteLn(f, 'endfacet');
    end;
    WriteLn(f, 'facet normal 0 0 -1');
    WriteLn(f, 'outer loop');
    WriteLn(f, 'vertex ' + FloatToStr(0) + ' ' + FloatToStr(0) + ' ' + FloatToStr(0));
    WriteLn(f, 'vertex ' + FloatToStr(0) + ' '+ FloatToStr((VyskaPoKonv.m-1)*cPixel).Replace(',','.') + ' ' + FloatToStr(0));
    WriteLn(f, 'vertex ' + FloatToStr((VyskaPoKonv.n-1)*cPixel).Replace(',','.') + ' ' + FloatToStr(0) + ' ' + FloatToStr(0));
    WriteLn(f, 'endloop');
    WriteLn(f, 'endfacet');
    WriteLn(f, 'facet normal 0 0 -1');
    WriteLn(f, 'outer loop');
    WriteLn(f, 'vertex ' + FloatToStr(0) + ' '+ FloatToStr((VyskaPoKonv.m-1)*cPixel).Replace(',','.') + ' ' + FloatToStr(0));
    WriteLn(f, 'vertex ' + FloatToStr((VyskaPoKonv.n-1)*cPixel).Replace(',','.') + ' ' + FloatToStr((VyskaPoKonv.m-1)*cPixel).Replace(',','.') + ' ' + FloatToStr(0));
    WriteLn(f, 'vertex ' + FloatToStr((VyskaPoKonv.n-1)*cPixel).Replace(',','.') + ' '+ FloatToStr(0) + ' ' + FloatToStr(0));
    WriteLn(f, 'endloop');
    WriteLn(f, 'endfacet');

    WriteLn(f, 'endsolid OBJECT');
    CloseFile(f);
  end;
end;

procedure TMainForm.FormCreate(Sender: TObject);
begin
  bAnalyza := False;
  bKlik := False;
  bVysProf := False;
  bZobrVysProf := False;
  bPoKonv := False;
  bGraf := False;
  apar := 1;
  bpar := 0;
  cpar := 1;
  dpar := 0;
  epar := 1;
  PrumerHue := TMatice.Create(0,0);
  Label1.Caption:='Jas = '+ FloatToStr(TrackBar2.Position/100);
end;

procedure TMainForm.Image1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  SL:PByteArray;
  R, G, B: Word; //barvy a jejich maximum a minimum
  Image16Array: PImage16ArrayRGB;
  Tiffinf: TTIFFinfo;
  Adr, k: Integer;
  Hu: Double;
begin
  if (Button = mbLeft) and  not bZobrVysProf and not bPoKonv then begin
    if bAnalyza then begin
      Image16Array := obrazek[CisloVzor];
      Tiffinf := TIFFinfo[CisloVzor];
    end else begin
      Image16Array := Snimek;
      Tiffinf := TIFFinfo[Length(TiffInfo)-1];
    end;
    bKlik := True;
    Adr:=Y*Tiffinf[1].Width.Value*3;
    k := 3 * X;
    B:=Image16Array^[Adr + k];
    G:=Image16Array^[Adr + k + 1];
    R:=Image16Array^[Adr + k + 2];
    Hu:=Hue(R,G,B);
    Label2.Caption:='Hue = '+ FloatToStr(Hu) + '°';
    ZobrazPixely(Image16Array, Tiffinf, Hu);
  end else if (Button = mbLeft) and  bZobrVysProf then begin
    XproMereni := X;
    YProMereni := Y;
    bKlik := True;
  end; // Stisk levého tlačítka myši

  if (Button = mBRight) and bAnalyza then begin
    Shape1.Left:=X-ScrollBox1.HorzScrollBar.Position-Round((Shape1.Width-1)/2);
    Shape1.Top:=Y-ScrollBox1.VertScrollBar.Position-Round((Shape1.Height-1)/2);
    Shape1.Visible:=True;
    Exporthodnot1.Enabled := True;
    Graf1.Enabled := True;
  end; //Stisk pravého tlačítka myši
end;

procedure TMainForm.Image1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
var
  d: Double;
begin
  if bKlik and bZobrVysProf then begin
    if bPoKonv then
      Image1.Picture.Bitmap.Assign(bmpPoKonv)
    else
      Image1.Picture.Bitmap.Assign(bmpVysProfil);

    Image1.Canvas.Pen.Color := clYellow;
    Image1.Canvas.MoveTo(XproMereni, YProMereni);
    Image1.Canvas.LineTo(X, Y);
    d := Round(sqrt(sqr(X-XproMereni) + sqr(Y-YproMereni)));
    Image1.Canvas.TextOut(X+10, Y, FloatToStr(d) + ' px');
    Image1.Repaint;
  end else begin
    Image1.Hint := '[' + IntToStr(X) + ',' + IntToStr(Y)+ ']';
  end;
end;

procedure TMainForm.Image1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  if bZobrVysProf then
    bKlik := False;
end;

// Procedura Image1MouseDown

procedure TMainForm.TrackBar1Change(Sender: TObject);
begin
  Label1.Caption:='Jas = '+ FloatToStr(TrackBar2.Position/100);
  if bKlik and not bZobrVysProf and not bPoKonv then begin
    if bAnalyza then
      ZobrazPixely(obrazek[CisloVzor], TIFFinfo[CisloVzor], StrToFloat(Copy(Label2.Caption,7, Length(Label2.Caption) - 8)))
    else
      ZobrazPixely(snimek, TIFFinfo[Length(TIFFinfo)-1], StrToFloat(Copy(Label2.Caption,7, Length(Label2.Caption) - 8)))
  end;
end;

procedure TMainForm.Uloitaktulnsnmek1Click(Sender: TObject);
begin
  if SavePictureDialog1.Execute then begin
    Image1.Picture.SaveToFile(SavePictureDialog1.FileName);
  end;
end;

procedure TMainForm.Vytvoitvkovprofil1Click(Sender: TObject);
var
  info: TTIFFinfo;
  i, Adr, j, k, l: Integer;
  R, G, B: Word;
  Image16Array: PImage16ArrayRGB;
  SL: PByteArray;
  dHue, Max, Min, dJas, Posun, Meritko, limitHue: Double;
  mr: Integer;
  MatHue, Hist: TMatice;
  Barva: Byte;
  hodnota: Double;
  Graf: TGraphForm;
begin
  if bVysProf then begin
    mr := Application.MessageBox('Vyskovy profil byl jiz vytvoren!' + #13#10 + 'ANO - znovu vytvori vyskovy profil' +#13#10 + 'NE - zobrazi vyskovy profil', '',
                        MB_YESNOCANCEL);
//    mr := MessageDlg('Vyskovy profil byl jiz vytvoren!' + #13#10 + 'ANO - znovu vytvori vyskovy profil' +#13#10 + 'NE - zobrazi vyskovy profil',
//                        mtWarning, mbYesNoCancel, 0);
    case mr of
      mrYes: bVysProf := False;
      mrCancel: EXIT;
    end;
  end;
  if not bVysProf then begin
    info := TIFFinfo[Length(TIFFinfo)-1];
    SetLength(ZnamVysku, info[1].Height.Value, info[1].Width.Value);
    VyskaVeSnimku := TMatice.Create(info[1].Height.Value, info[1].Width.Value);
    //SetLength(VyskaVeSnimku, info[1].Height.Value, info[1].Width.Value);
    MatHue := TMatice.Create(info[1].Height.Value, info[1].Width.Value);
    limitHue :=  InvTransfY(Funkce(apar, bpar, cpar, dpar, epar, TransfX(0)));
    Hist := TMatice.Create(PrumerHue.m + 1, PrumerHue.n);
    Image16Array := snimek;
    for i:=0 to info[1].Height.Value-1 do begin
      Adr:=i*info[1].Width.Value*3;
      for j:= 0 to info[1].Width.Value-1 do begin
        k := 3 * j;
        B:=Image16Array^[Adr + k];
        G:=Image16Array^[Adr + k + 1];
        R:=Image16Array^[Adr + k + 2];
        Max:=MaximumRGB(R,G,B);
        Min:=MinimumRGB(R,G,B);
        dJas := Jas(R, G, B);
        dHue:=Hue(R, G, B);
        if (Max<>Min) and (dJas>=TrackBar2.Position/100) and (dHue > limitHue) then begin
          ZnamVysku[i, j] := True;
          MatHue.elem[i ,j] := dHue;
        end else
          ZnamVysku[i, j] := False;

        if ZnamVysku[i,j] then begin
          VyskaVeSnimku.elem[i, j] := InvTransfX(InvFunkce(apar, bpar, cpar, dpar, epar, TransfY(MatHue.elem[i, j])));
          l := Round(VyskaVeSnimku.elem[i, j]);
          if l > Hist.m then
            l := Hist.m - 1;
          Hist.elem[l, 0] := Hist.elem[l, 0] + 1;
        end;
      end; //for j
    end; //for i

    Graf := TGraphForm.Create(PrumerHue, Hist);
    Graf.Edit1.Text := FloatToStr(apar);
    Graf.Edit2.Text := FloatToStr(bpar);
    Graf.Edit3.Text := FloatToStr(cpar);
    Graf.Edit4.Text := FloatToStr(dpar);
    Graf.Edit5.Text := FloatToStr(epar);
    Graf.ShowModal;


    Posun := VyskaVeSnimku.MinimumBezNul;
    Meritko := VyskaVeSnimku.Maximum - Posun + 1;
    bmpVysProfil := TBitmap.Create;
    bmpVysProfil.PixelFormat := pf24bit;
    bmpVysProfil.SetSize(info[1].Width.Value, info[1].Height.Value);
    for i:=0 to MatHue.m - 1 do begin
      SL:=bmpVysProfil.ScanLine[i];
      for j:= 0 to MatHue.n - 1 do begin
        k := 3 * j;
        if ZnamVysku[i, j] then begin
          VyskaVeSnimku.elem[i, j] := VyskaVeSnimku.elem[i, j] - Posun + 1;
          Barva := Round((VyskaVeSnimku.elem[i, j]*255)/Meritko);
          SL^[k] := Barva;
          SL^[k+1] := Barva;
          SL^[k+2] := Barva;
        end else begin
          SL^[k] := 0;
          SL^[k+1] := 0;
          SL^[k+2] := 0;
        end;
      end; //for j
    end; //for i

    bVysProf := True;
  end;
  bZobrVysProf := True;
  bPoKonv := False;
//  if SaveTextFileDialog1.Execute then begin
//    VyskaVeSnimku.s_uloz(SaveTextFileDialog1.FileName);
//  end;
  Image1.Picture.Bitmap.Assign(bmpVysProfil);
  Image1.Repaint;
  Konvoluce1.Enabled := True;
  bKlik := False;
  //N3Dmodel1.Enabled := True;
  FreeAndNil(Graf);
end;

function TMainForm.ZobrazitTif(Image16Array: PImage16ArrayRGB; Tiffinf: TTIFFinfo): TBitmap;
var
  SL: PByteArray;
  j, k, Adr: Integer;
begin
  Result := TBitmap.Create;
  Result.PixelFormat := pf24bit;
  Result.Width := TIFFinf[1].Width.Value;
  Result.Height := TIFFinf[1].Height.Value;
  for j:=0 to Tiffinf[1].Height.Value-1 do begin
    SL:=Result.ScanLine[j];
    Adr:=j*Tiffinf[1].Width.Value*3;
    for k:=0 to Tiffinf[1].Width.Value*3-1 do begin
      SL^[k]:=Round(Image16Array^[Adr+k]/256);
    end; // for k
  end; // for j
end;

procedure TMainForm.ZobrazPixely(Image16Array: PImage16ArrayRGB; Tiffinf: TTIFFinfo; H: Double);
var i, j, k, Adr:Integer;
    SL:PByteArray;
    R, G, B, Max, Min:Word;
    HVyp, Huelimit: Double;
begin
  Image1.Picture.Bitmap := Vzorovy;
  if CheckBox1.Checked then
    Huelimit := 360
  else
    Huelimit := TrackBar1.Position/30;

  for i:=0 to Tiffinf[1].Height.Value-1 do begin
      Adr:=i*Tiffinf[1].Width.Value*3;
      SL:=Image1.Picture.Bitmap.ScanLine[i];
      for j:= 0 to Tiffinf[1].Width.Value-1 do begin
        k := 3 * j;
        B:=Image16Array^[Adr + k];
        G:=Image16Array^[Adr + k + 1];
        R:=Image16Array^[Adr + k + 2];
        Max:=MaximumRGB(R,G,B);
        Min:=MinimumRGB(R,G,B);
        if (Max<>Min) and (Jas(R, G, B)>=TrackBar2.Position/100) then begin
          HVyp:=Hue(R, G, B);
          if (HVyp>=H-HueLimit)
            and (HVyp<=H+HueLimit) then begin
            SL^[j*3]:=255;
            SL^[j*3+1]:=255;
            SL^[j*3+2]:=255;
          end;
        end;
      end; //for j
    end; //for i
  Image1.Repaint;
end;

function MaximumRGB(R, G , B: Word): Word;
var MaxCislo: Word;
begin
  MaxCislo := R;
  if (MaxCislo < G) then MaxCislo := G;
  if (MaxCislo < B) then MaxCislo := B;
  Result := MaxCislo;
end;

function MinimumRGB(R ,G, B: Word): Word;
var MinCislo: Word;
begin
  MinCislo := R;
  if (MinCislo > G) then MinCislo := G;
  if (MinCislo > B) then MinCislo := B;
  Result := MinCislo;
end;

function Hue(R, G, B: Word): Double;
var MaxCislo,MinCislo:Word;
    h: Double;
begin
  MaxCislo := MaximumRGB(R, G, B);
  MinCislo := MinimumRGB(R, G, B);
  if (MaxCislo = R) then begin
    if (G >= B) then h := (G - B)/(MaxCislo - MinCislo)
    else  h:=(G - B)/(MaxCislo - MinCislo) + 6;
  end;
  if (MaxCislo = G) then h := 2 + (B - R)/(MaxCislo - MinCislo);
  if (MaxCislo = B) then h := 4 + (R - G)/(MaxCislo - MinCislo);
  Result := 60 * h;
end;

function Jas(R, G, B: Word): Double;
begin
  Result := ((R + G + B)/3)/(255*255);
end;

//Nastavení tvaru a velikosti okolí
procedure TMainForm.RadioGroup1Click(Sender: TObject);
begin
  if (RadioGroup1.ItemIndex = 0) then Shape1.Shape := stSquare;
  if (RadioGroup1.ItemIndex = 1) then Shape1.Shape := stCircle;
end;

procedure TMainForm.RadioGroup2Click(Sender: TObject);
begin
  Shape1.Height := 2*StrToInt(RadioGroup2.Items[RadioGroup2.ItemIndex])+1;
  Shape1.Width := 2*StrToInt(RadioGroup2.Items[RadioGroup2.ItemIndex])+1;
end;

//Analýza obrazu
procedure TMainForm.Analzaobrazu1Click(Sender: TObject);
var
    i, j, k, c, Adr, Adr2, PocatekX, PocatekY: Integer;
    SLVzor: PByteArray;
    R, G, B: Word;
    Graf: TGraphForm;
    StredX, StredY, Pomoc, polomer: Double;
    mr: TModalResult;
    Tiffinf: TTIFFinfo;
    Image16Array: PImage16ArrayRGB;
    Pole: Array of Array of Boolean;
    Vyska: TMatice;
begin
  if not bGraf and (PrumerHue.m = 0) then begin
    if (Shape1.Shape = stSquare) then begin
      PocatekX := Shape1.Left+ScrollBox1.HorzScrollBar.Position;
      PocatekY := Shape1.Top+ScrollBox1.VertScrollBar.Position;
      c := 0;
      SetLength(Pole, Shape1.Height, Shape1.Width);
      for i := 0 to Shape1.Height-1 do
        for j := 0 to Shape1.Width-1 do
          Pole[i, j] := False;
      for j := PocatekY to PocatekY+Shape1.Height - 1 do begin
        SLVzor := Image1.Picture.Bitmap.ScanLine[j];
        for k := PocatekX to PocatekX+Shape1.Width - 1 do begin
          Adr2 := 3 * k;
          B:=SLVzor^[Adr2];
          G:=SLVzor^[Adr2+1];
          R:=SLVzor^[Adr2+2];
          if ((B = 255) and (G = 255) and (R = 255)) then begin
            Pole[j - PocatekY, k - PocatekX] := True;
            Inc(c);
          end;//if je na obrazku bila
        end; //k - sloupec
      end;//j - řádek

      PrumerHue.Recreate(Length(obrazek),c);
      for i := 0 to PrumerHue.m -1 do begin
        Image16Array := obrazek[i];
        Tiffinf := TIFFinfo[i];
        c := 0;
        for j := PocatekY to PocatekY+Shape1.Height - 1 do begin
          Adr := j * Tiffinf[1].Width.Value*3;
          for k := PocatekX to PocatekX+Shape1.Width - 1 do begin
            Adr2 := 3 * k;
            if Pole[j - PocatekY, k - PocatekX] then begin
              B:=Image16Array^[Adr + Adr2];
              G:=Image16Array^[Adr + Adr2 + 1];
              R:=Image16Array^[Adr + Adr2 + 2];
              PrumerHue.elem[i, c] := Hue(R,G,B);
              Inc(c);
            end;//if je na obrazku bila
          end; //k - sloupec
        end;//j - řádek
//        try
//          PrumerHue.elem[i,0] := TransfY(PrumerHue.elem[i,0]/c);
//        except
//          ShowMessage('Špatně vybraná oblast');
//          break;
//        end;
      end;//i - prochazeni obrazku
//      SetLength(obrazek, 0);

    end// if square okolí

    else if (Shape1.Shape = stCircle ) then begin
      PocatekX := Shape1.Left+ScrollBox1.HorzScrollBar.Position;
      PocatekY := Shape1.Top+ScrollBox1.VertScrollBar.Position;
      StredX := Shape1.Left+(Shape1.Width/2)+ScrollBox1.HorzScrollBar.Position;
      StredY := Shape1.Top+(Shape1.Height/2)+ScrollBox1.VertScrollBar.Position;
      polomer := Shape1.Width/2;
      c := 0;
      SetLength(Pole, Shape1.Height+1, Shape1.Width+1);
      for i := 0 to Shape1.Height do
        for j := 0 to Shape1.Width do
          Pole[i, j] := False;
      for j := PocatekY to PocatekY+Shape1.Height do begin
        SLVzor := Image1.Picture.Bitmap.ScanLine[j];
        for k := PocatekX to PocatekX+Shape1.Width do begin
          if (Vzdalenost(StredX, StredY, k, j)<= polomer) then begin
            Adr2 := 3 * k;
            B:=SLVzor^[Adr2];
            G:=SLVzor^[Adr2+1];
            R:=SLVzor^[Adr2+2];
            if ((B = 255) and (G = 255) and (R = 255)) then begin
              Pole[j - PocatekY, k - PocatekX] := True;
              Inc(c);
            end;//if je na obrazku bila
          end;
        end; //k - sloupec
      end;//j - řádek

      PrumerHue.Recreate(Length(obrazek),c);
      for i := 0 to PrumerHue.m -1 do begin
        Image16Array := obrazek[i];
        Tiffinf := TIFFinfo[i];
        c := 0;
        for j := PocatekY to PocatekY+Shape1.Height do begin
          Adr := j * Tiffinf[1].Width.Value*3;
          for k := PocatekX to PocatekX+Shape1.Width do begin
            Adr2 := 3 * k;
            if Pole[j - PocatekY, k - PocatekX] then begin
              B:=Image16Array^[Adr + Adr2];
              G:=Image16Array^[Adr + Adr2 + 1];
              R:=Image16Array^[Adr + Adr2 + 2];
              PrumerHue.elem[i, c] := Hue(R,G,B);
              Inc(c);
            end;//if je na obrazku bila
          end; //k - sloupec
        end;//j - řádek
      end;//i - prochazeni obrazku
    end; // if circle okolí
    bGraf := True;
  end;

//  if SaveTextFileDialog1.Execute then begin
//    PrumerHue.s_uloz(SaveTextFileDialog1.FileName);
//  end;

  Graf := TGraphForm.Create(PrumerHue);
  Graf.Edit1.Text := FloatToStr(apar);
  Graf.Edit2.Text := FloatToStr(bpar);
  Graf.Edit3.Text := FloatToStr(cpar);
  Graf.Edit4.Text := FloatToStr(dpar);
  Graf.Edit5.Text := FloatToStr(epar);
  try
  mr := Graf.ShowModal;
  if mr = mrOk then begin
    apar := StrToFloat(Graf.Edit1.Text);
    bpar := StrToFloat(Graf.Edit2.Text);
    cpar := StrToFloat(Graf.Edit3.Text);
    dpar := StrToFloat(Graf.Edit4.Text);
    epar := StrToFloat(Graf.Edit5.Text);
    Soubor1.Enabled := True;
  end;
  finally
    FreeAndNil(Graf);
  end;
  Vyska := TMatice.Create(PrumerHue.m, PrumerHue.n);
  for i := 0 to Vyska.m-1 do
    for j := 0 to Vyska.n-1 do begin
      Vyska.elem[i, j] := InvTransfX(InvFunkce(apar, bpar, cpar, dpar, epar, TransfY(PrumerHue.elem[i, j])));
    end;
//  if SaveTextFileDialog1.Execute then begin
//    Vyska.s_uloz(SaveTextFileDialog1.FileName);
//  end;
end;

// Uzavření formu pomocí Položky Konec v Menu Soubor
procedure TMainForm.Konec1Click(Sender: TObject);
begin
  MainForm.Close;
end;

procedure TMainForm.Konvoluce1Click(Sender: TObject);
var
  formik: TKonvKernellForm;
  mr: TModalResult;
  Jadro, MPomocna: TMatice;
  i, j, x, y, nulaX, nulaY, k: Integer;
  d, vaha, Posun: Double;
  SL: PByteArray;
  Barva: Word;
  Meritko: Double;
  Znam: Array of Array of Boolean;
begin
//  if bPoKonv then begin
//    mr := Application.MessageBox('Provest kovoluci na puvodnim vyskovem profilu?', '',
//                        MB_YESNOCANCEL);
//    case mr of
//      mrYes:
//        bPoKonv := False;
//      mrNo: begin
//        bPoKonv := True;
//        MPomocna := TMatice.Create(VyskaPoKonv.m, VyskaPoKonv.n);
//        for i := 0 to MPomocna.m - 1 do
//          for j := 0 to MPomocna.n - 1 do
//            MPomocna.elem[i, j] := VyskaPoKonv.elem[i, j];
//        SetLength(Znam, Length(ZnamVysku), Length(ZnamVysku[0]));
//        for i := 0 to High(Znam) do
//          for j := 0 to High(Znam[i]) do
//            Znam[i, j] := False;
//      end;
//      mrCancel: EXIT;
//    end;
//  end;

  if not bPoKonv then begin
    MPomocna := TMatice.Create(VyskaVeSnimku.m, VyskaVeSnimku.n);
    for i := 0 to MPomocna.m - 1 do
      for j := 0 to MPomocna.n - 1 do
        MPomocna.elem[i, j] := VyskaVeSnimku.elem[i, j];
    SetLength(Znam, Length(ZnamVysku), Length(ZnamVysku[0]));
    for i := 0 to High(Znam) do
      for j := 0 to High(Znam[i]) do
        Znam[i, j] := False;
  end else begin
    MPomocna := TMatice.Create(VyskaPoKonv.m, VyskaPoKonv.n);
    for i := 0 to MPomocna.m - 1 do
      for j := 0 to MPomocna.n - 1 do
        MPomocna.elem[i, j] := VyskaPoKonv.elem[i, j];
    SetLength(Znam, Length(ZnamVysku), Length(ZnamVysku[0]));
    for i := 0 to High(Znam) do
      for j := 0 to High(Znam[i]) do
        Znam[i, j] := False;
  end;
  N3Dmodel1.Enabled := True;
  Exportjakostl1.Enabled := True;
  formik := TKonvKernellForm.Create(Self);
  VyskaPoKonv := TMatice.Create(MPomocna.m, MPomocna.n);
  try
    mr := formik.ShowModal;
    if mr = mrOk then begin
      Jadro := TMatice.Create(formik.MaticeJadra.m, formik.MaticeJadra.n);
      for i := 0 to Jadro.m - 1 do
        for j := 0 to Jadro.n - 1 do
          Jadro.elem[i, j] := formik.MaticeJadra.elem[i, j];
      NulaX := Round((Jadro.m - 1)/2);
      NulaY := Round((Jadro.n - 1)/2);
      for x := 0 to MPomocna.m - 1 do begin
        for y := 0 to MPomocna.n - 1 do begin
          vaha := 0;
          d := 0;
          for i := -NulaX to NulaX do begin
            for j := -NulaY to NulaY do begin
              if ((x+i) >= 0) and ((y+j) >= 0) and ((x+i)<=MPomocna.m-1) and ((y+j)<=MPomocna.n-1) then begin
                if ZnamVysku[x + i, y + j] then begin
                  d := d + (MPomocna.elem[x + i, y + j]*Jadro.elem[i + NulaX, j + NulaY]);
                  vaha := vaha + Jadro.elem[i + NulaX, j + NulaY];
                end;
              end;
            end;
          end;
          if vaha <> 0 then begin
            VyskaPoKonv.elem[x, y] := d/vaha;
            Znam[x, y] := True;
          end;
        end;
      end;

      bmpPoKonv := TBitmap.Create;
      bmpPoKonv.PixelFormat := pf24bit;
      bmpPoKonv.SetSize(bmpVysProfil.Width, bmpVysProfil.Height);
      Posun := VyskaVeSnimku.MinimumBezNul;
      Meritko := VyskaVeSnimku.Maximum - Posun + 1;
//      Posun := VyskaPoKonv.Minimum;
//      Meritko := VyskaPoKonv.Maximum - Posun + 1;
      //Meritko := VyskaPoKonv.Maximum - VyskaPoKonv.MinimumBezNul;
      for i := 0 to VyskaPoKonv.m - 1 do begin
        SL:=bmpPoKonv.ScanLine[i];
        for j:= 0 to VyskaPoKonv.n - 1 do begin
          k := 3 * j;
          //VyskaPoKonv.elem[i, j] := VyskaPoKonv.elem[i, j] - Posun + 1;
          Barva := Round((VyskaPoKonv.elem[i, j]/Meritko)*255);
          SL^[k] := Barva;
          SL^[k+1] := Barva;
          SL^[k+2] := Barva;
        end; //for j
      end; //for i
//      if SaveTextFileDialog1.Execute then begin
//        VyskaPoKonv.s_uloz(SaveTextFileDialog1.FileName);
//      end;
      Image1.Picture.Bitmap.Assign(bmpPoKonv);
      Image1.Repaint;
      bKlik := False;
      bPoKonv := True;
    end;

    for i := 0 to High(Znam) do
          for j := 0 to High(Znam[i]) do
            ZnamVysku[i, j] := Znam[i, j];
  finally
    FreeAndNil(formik);
  end;
end;

end.
