#!/usr/bin/env lua

--[[
  =======================
     Prahovani obrazu 
  =======================

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

    cv.LoadImage()        Nacitani obrazku ze souboru
    cv.CloneImage()       Vytvori kopii obrazku
    cv.GetSubRect()       Extrahuje data obrazu urcena obdelnikem do hlavicky obrazku bez kopirovani
    cv.CreateHist()       Vytvori histogram obrazu, ale nepocita data.
    cv.CalcHist()         Vypocita histogram obrazku
    cv.Get1D()            Nacteni vektoru hodnot z obrazku.
    cv.GetReal1D()        Nacteni floating point hodnoty z obrazku
    cv.Set()              Naplneni obrazku/matice hodnotou danou vektorem
    cv.Scalar()           Vytvori vektor hodnot
    cv.Threshold()        Prahovani obrazu jednim prahem
    cv.AdaptiveThreshold  Adaptivni prahovani obrazu
    adaptiveThresh()      Uzivatelska funkce pro adaptivni prahovani
]]



local cv=require('luacv')

function adaptiveThresh(src,dst,subs)
  local sub_size=cv.Size(src.width/subs,src.height/subs)
  local src_header=cv.CreateMatHeader(sub_size.width,sub_size.height,cv.CV_8UC1)
  local dst_header=cv.CreateMatHeader(sub_size.width,sub_size.height,cv.CV_8UC1)
  local hist_size={255}
  local ranges={0,255}
  local hist_ranges={ranges}

  -- Vytvorte 1D histogram s parametry hist_size,hist_ranges a typem cv.CV_HIST_ARRAY  do promenne hist
  hist=cv.CreateHist(1,hist_size,cv.CV_HIST_ARRAY,hist_ranges,1)
  local deriv={}
  local deriv2={}
  local max=0
  local index=0
  for k=0,subs-1 do 
    max=0
    index=0
    for j=0,subs-1 do
      max=0
      index=0
      rect=cv.Rect(k*sub_size.width,j*sub_size.height,sub_size.width,sub_size.height)
      src_header=cv.GetSubRect(src,src_header,rect)
      -- Extrahujte z obrazku dst obdelnik o velikost danou ctvercem rect do hlavicky obrazku dst_header
      dst_header=cv.GetSubRect(dst,dst_header,rect)
      -- Vypocitejte histogram obrazku src_header
      cv.CalcHist(src_header,hist)

      for i=0,hist_size[1]-2 do
        -- Do pole deriv na pozici i ulozte rozdil "floating point hodnot" z histogramu na pozici i+1 a i,
        -- k extrahovani hodnot pouzijte promennou hist.bins
        deriv[i]=cv.GetReal1D(hist.bins,i+1)-cv.GetReal1D(hist.bins,i)
      end

      for i=0,hist_size[1]-3 do
        -- Do pole deriv2 na indexu i ulozte rozdil pole deriv na indexu  i+1 a i
        deriv2[i]=deriv[i+1]-deriv[i]
        if (deriv2[i]>max) then
          max=deriv2[i]
          index=i
        end
      end

      for i=0,dst_header.width*dst_header.height-1 do
        local scal=cv.Get1D(src_header,i)
        if (scal.val[1]>index) then
          cv.Set1D(dst_header,i,cv.Scalar(255))
        else 
          cv.Set1D(dst_header,i,cv.Scalar(0))
        end
      end
    end
  end
  cv.ReleaseHist(hist)
end

-- Nactete zdrojovy obrazek lena.png do promenne img a pouzijte parametr cv.CV_LOAD_IMAGE_GRAYSCALE 
-- pro nacteni v odstinech sedi
local img=cv.LoadImage((arg[1]~=nil and arg[1] or "lena.png"),cv.CV_LOAD_IMAGE_GRAYSCALE)
assert(img,"can't load image")
-- Vytvorte kopii vstupniho obrazu do promenne thresh
-- !!!! prirazeni   thresh=img    je pouze melka kopie resp. ukazatel na img !!!
local thresh=cv.CloneImage(img) 

for i=0,thresh.width*thresh.height-1 do
  -- Nactete hodnotu obrazku img na indexu i a ulozte do promenne scal
  local scal=cv.Get1D(thresh,i)
  if (scal.val[1]>100) then cv.Set1D(thresh,i,cv.Scalar(255))
  else cv.Set1D(thresh,i,cv.Scalar(0))
  end
end

cv.ShowImage("1 pevny prah",thresh)
-- Naplnte cely vystupni obrazek thresh hodnotou 127
cv.Set(thresh,cv.Scalar(127))
for i=0,thresh.width*thresh.height-1 do
  local scal=cv.Get1D(img,i)
  -- Do promenne val ulozte hodnotu objektu CvScalar, pristupujte k teto hodnote pres scal.val[index], 
  -- kde jsou hodnoty usporadany dle kanalu obrazku. Zakladni kanal je na pozici 1
  local val=cv.Round(scal.val[1])
  if (val>150) then cv.Set1D(thresh,i,cv.Scalar(255))
  elseif (val<100) then  cv.Set1D(thresh,i,cv.Scalar(0))
  end
end

cv.ShowImage("2 pevne prahy",thresh)
-- Zavolejte uzivatelskou funkci pro adaptivni prahovani s 1 prahem ze stupniho obrazu img do thresh 
adaptiveThresh(img,thresh,1)
cv.ShowImage("Adaptivni pevny prah 1",thresh)

-- Zavolejte uzivatelskou funkci pro adaptivni prahovani s 10x10 prahy ze stupniho obrazu img do thresh 
adaptiveThresh(img,thresh,10)
cv.ShowImage("Adaptivni pevny prah 10",thresh)

-- Naprahujte vstupni img obraz jednim prahem pomoci knihovni funkce s prahem 130, max hodnotou 255 
-- a parametrem cv.CV_THRESH_BINARY do obrazku thresh
cv.Threshold(img,thresh,130,255,cv.CV_THRESH_BINARY)
cv.ShowImage("Prahovani",thresh)

-- Vytvorte obraz po adaptivnim prahovani pomoci OpenCV funkce s defaultnimi parametry cv.CV_ADAPTIVE_TRESH_MEAN_C 
-- cv.CV_THRESH_BINARY a maximalni hodnotou 255
cv.AdaptiveThreshold(img,thresh,255,cv.CV_ADAPTIVE_THRESH_MEAN_C,cv.CV_THRESH_BINARY,3)
cv.ShowImage("Adaptivni prahovani",thresh)


cv.WaitKey()
cv.ReleaseImage(img)
cv.ReleaseImage(thresh)
cv.DestroyAllWindows()
