#!/usr/bin/env lua

--[[
  =========================
      Hranove detektory
  =========================

  ===============
  potrebne funkce
  ===============

    cv.LoadImage()        Nacitani obrazku ze souboru
    cv.CreateImage()      Vytvoreni obrazku
    cv.CreateMat()        Vytvoreni matice
    cv.GetSize()          Vraci rozmery obrazku
    cv.WarpAffine()       Afinni transformace
    cv.Copy()             Kopirovani matic/obrazku
    cv.Set2D()            Ulozeni vektoru do matice/obrazku
    cv.Sum()              Suma matice/obrazku
    cv.Mul()              Nasobeni matic prvek po prvku
    cv.Filter2D()         Filtrovani obrazu pomoci konvolucnich jader
    cv.Sobel()            Sobeluv hranovy detektor
    cv.Laplace()          Laplacuv hranovy detektor
    cv.Canny()            Cannyho hranovy detektor
    convolution()         uzivatelska funkce realizujici diskretni konvoluci
]]

local cv=require('luacv')

function convolution(img,out,kernel)
  if (not kernel) then error("convolution(src_image,dst_image,kernel_mat)") end

  -- Vytvorte matici rot_mat s sirkou 2 a vyskou 3 a typem cv.CV_32FC1
  
  local tmp=cv.CloneMat(kernel)

  cv.RotationMatrix(cv.Point2D32f(math.floor(kernel.width/2),math.floor(kernel.height/2)),-180,1,rot_mat)  

  -- Orotujte matici tmp pomoci rotacni matice rot_mat do promenne kernel, pouzijte afinni transformaci
  
  cv.ReleaseMat(rot_mat)

  local g={math.floor(kernel.width/2)+1,math.floor(kernel.height/2)+1}
  local ret=cv.CreateImage(cv.Size(img.width+kernel.width-1,img.height+kernel.height-1),cv.IPL_DEPTH_8U,1)

  local kern_t=cv.CreateMat(kernel.width,kernel.height,cv.CV_32FC1)

  cv.Zero(ret)

  cv.SetImageROI(ret,cv.Rect(g[1],g[2],g[1]+img.width-1,g[2]+img.height-1))

  -- Zkopirujte obrazek img do obrazku ret. 
  -- !!!! prirazeni   ret=img    je pouze melka kopie resp. ukazatel na img !!!
  
  cv.ResetImageROI(ret)
  cv.Zero(tmp)

  for k=0,img.width-1 do
    for l=0,img.height-1 do
      for a=k,k+kernel.width-1 do
        for b=l,l+kernel.height-1 do
          cv.Set2D(kern_t,a-k,b-l,cv.Get2D(ret,a,b))
        end
      end

   -- Vynasobte prvek po prvku matici okoli kern_t s matici jadra kernel do promenne tmp
    
   -- pro kazdy prvek indexu k,l ulozte do obrazku out sumu matice tmp
    
    end
  end

  cv.ReleaseImage(ret)
  cv.ReleaseMat(kern_t)
  cv.ReleaseMat(tmp)
  collectgarbage("collect")
end

-- Nactete zdrojovy obrazek lena.png nebo jiny do promenne img a pouzijte parametr cv.CV_LOAD_IMAGE_GRAYSCALE
-- pro nacteni v odstinech sedi

if (not img) then error("Can't load image") end

-- Do promenne size ulozte rozmery vstupniho obrazku img

local data={{-1,0,1,   -1,0,1,   -1,0,1},
            {1,0,-1,   2,0,-2,   1,0,-1},
            {1,1,-1,   1,-2,-1,  1,1,-1},
            {3,3,-5,   3,0,-5,   3,3,-5},
            {0,1,0,    1,-4,1,   0,1,0}}

MASK_SIZE=math.sqrt(#data[1])
KERNEL_COUNT=#data

local titles={"Prewitt","Sobel","Robinson","Kirsch","Laplace"}
local out=cv.CreateImage(size,cv.IPL_DEPTH_8U,1)

for i=1,KERNEL_COUNT do
  local kernel=cv.Mat(MASK_SIZE,MASK_SIZE,cv.CV_32FC1,data[i])
  if (i==1) then

  -- Doplnte vypocet konvolutorniho filtru kernel pomoci vyse definovane funkce convolution do obrazku out
  
  cv.ShowImage(titles[i],out)
  end

  -- Aplikujte konvolutorni jadro v matici kernel na obrazek img a ulozte do obrazku out pomoci OpenCV funkce

  cv.ShowImage(titles[i]..' cvFilter2D',out)
  cv.ReleaseMat(kernel)
end

-- Doplnte vypocet Cannyho detektoru s prahy 100 a 150 se vstupem obrazku img, vystup ulozte do promenne out

cv.ShowImage("Canny cvCanny",out)

cv.ReleaseImage(out)

-- Vytvorte obrazek out o velikosti obrazku img, s barevnou hloubkou cv.IPL_DEPTH_32F a 1 kanalem


-- Doplnte vypocet Laplaceova operatoru na obrazku img pomoci knihovni OpenCV funkce do obrazku out

cv.ShowImage("Laplace cvLaplace",out)

-- Doplnte vypocet Sobelova operatoru na obrzazku img do obrazku out

cv.ShowImage("Sobel cvSobel",out)

cv.ReleaseImage(img)
cv.ReleaseImage(out)

cv.WaitKey()
cv.DestroyAllWindows()
