Julia - Obrada slike - Morfološka obrada slike

In [1]:
#Morfološka obrada slike predstavlja skup postupaka kojim se nad našom početnom slikom vrše modifikacije objekata
#na slici, sa ciljem lakše i preciznije obrade za naredne korake. Ona podrazumeva: glačanje ivica objekata, popravke
#oštećenih ili raskinutih delova na slici, popunjavanje razlivenih objekata (npr. iskreniranih slova i dokumenata), 
#popunjavanje rupa nad objektima, uklanjanje sitnih šumova malih površina na slici itd. Ovde ćemo raditi
#uglavnom morfološku obradu binarnih i grayscale slika.
In [2]:
#potrebno je najpre instalirati biblioteke za rad sa algoritmima za morfološku obradu slike 
import Pkg;
Pkg.add("ImageMorphology");
   Updating registry at `~/.julia/registries/General`

   Updating git-repo `https://github.com/JuliaRegistries/General.git`

  Resolving package versions...
   Updating `~/.julia/environments/v1.4/Project.toml`
 [no changes]
   Updating `~/.julia/environments/v1.4/Manifest.toml`
 [no changes]
In [3]:
Pkg.add("ImageView");
  Resolving package versions...
   Updating `~/.julia/environments/v1.4/Project.toml`
 [no changes]
   Updating `~/.julia/environments/v1.4/Manifest.toml`
 [no changes]
In [4]:
using Images, ImageView, ImageMorphology, Colors, ImageCore, StaticArrays, TestImages
Gtk-Message: 03:40:34.931: Failed to load module "canberra-gtk-module"
Gtk-Message: 03:40:34.932: Failed to load module "canberra-gtk-module"
In [5]:
sl1 = zeros(Gray{N0f8},1000,1000);

sl1[400:700,400:700] .= 1;

imshow(sl1)
Out[5]:
Dict{String,Any} with 4 entries:
  "gui"         => Dict{String,Any}("window"=>GtkWindowLeaf(name="", parent, wi…
  "roi"         => Dict{String,Any}("redraw"=>37: "map(clim-mapped image, input…
  "annotations" => 3: "input-2" = Dict{UInt64,Any}() Dict{UInt64,Any} 
  "clim"        => 2: "CLim" = CLim{Normed{UInt8,8}}(0.0, 1.0) CLim{Normed{UInt…

Dilatacija

In [6]:
#Dilatacija predstavlja postupak raširenja našeg objekta, sa ciljem da se izvrši proširenje njegovih ivica.
#Ona radi na jednostavnom principu prolaskom maske kroz našu sliku, i ukoliko se dogodi da se postoji bar jedno 
#preklapanje maske na nekoj svojoj poziciji sa pikselom slike nad kojim je ta pozicija trenutno, onda se centralni 
#piksel tj. piksel koji se u datom trenutku po poziciji poklapa sa centralnim elementom maske postavlja na neku
#predefinisanu vrednost (obično je to 1)
In [7]:
sl1_dil = dilate(sl1);
imshow(sl1_dil)
Out[7]:
Dict{String,Any} with 4 entries:
  "gui"         => Dict{String,Any}("window"=>GtkWindowLeaf(name="", parent, wi…
  "roi"         => Dict{String,Any}("redraw"=>74: "map(clim-mapped image, input…
  "annotations" => 40: "input-14" = Dict{UInt64,Any}() Dict{UInt64,Any} 
  "clim"        => 39: "CLim" = CLim{Normed{UInt8,8}}(0.0, 1.0) CLim{Normed{UIn…
In [8]:
imshow(sl1_dil-sl1)
Out[8]:
Dict{String,Any} with 4 entries:
  "gui"         => Dict{String,Any}("window"=>GtkWindowLeaf(name="", parent, wi…
  "roi"         => Dict{String,Any}("redraw"=>111: "map(clim-mapped image, inpu…
  "annotations" => 77: "input-26" = Dict{UInt64,Any}() Dict{UInt64,Any} 
  "clim"        => 76: "CLim" = CLim{Normed{UInt8,8}}(0.0, 1.0) CLim{Normed{UIn…
In [9]:
#Kao što možemo videti izvršeno je proširivanje našeg kvadrata sa svih strana

Erozija

In [10]:
#Erozija predstavlja proces kod koga se vrši "uklanjanje viškova sa objekta". Kod erozije se, kao i kod dilatacije
#prelazi čitavom, predefinisanom maskom preko naše slike, i da bi se sačuvao centralni piksel tj. onaj nad kojim je
#u datom trenutku postavljena naša maska, potrebno je da se izvrši poklapanje naše maske sa svim elementima kojima
#odgovaraju njeni elementi

sl1_erod = erode(sl1);
imshow(sl1_erod)
Out[10]:
Dict{String,Any} with 4 entries:
  "gui"         => Dict{String,Any}("window"=>GtkWindowLeaf(name="", parent, wi…
  "roi"         => Dict{String,Any}("redraw"=>148: "map(clim-mapped image, inpu…
  "annotations" => 114: "input-38" = Dict{UInt64,Any}() Dict{UInt64,Any} 
  "clim"        => 113: "CLim" = CLim{Normed{UInt8,8}}(0.0, 1.0) CLim{Normed{UI…
In [11]:
imshow(sl1 - sl1_erod)
Out[11]:
Dict{String,Any} with 4 entries:
  "gui"         => Dict{String,Any}("window"=>GtkWindowLeaf(name="", parent, wi…
  "roi"         => Dict{String,Any}("redraw"=>185: "map(clim-mapped image, inpu…
  "annotations" => 151: "input-50" = Dict{UInt64,Any}() Dict{UInt64,Any} 
  "clim"        => 150: "CLim" = CLim{Normed{UInt8,8}}(0.0, 1.0) CLim{Normed{UI…
In [12]:
#Erozija i dilatacija same po sebi nisu mnogo bitne operacije, međutim njihova višetruka primena ili kombinovana 
#primena predstavljaju polaznu građu za najbitnije algoritme morfološke obrade slike

Otvaranje

In [13]:
#Otvaranje je operacija koja se sastoji od sukcesivne primene operacije erozije, pa operacije dilatacije. Njena
#namena predstavlja raskidanje uskih prevlaka između objekata, glačanje nedovoljno glatkih
#ivica objekata, ali i eliminisanje tankih izbočina.
#Ona predstavlja odličan algoritam koji služi kako bi se popravili rezultati izdvajanje ivica ili izdvajanja objekata
#koji su potencijalno delom narušeni ovim obradama
In [14]:
for i in 700:710
   sl1[i:i+1,i:i+1] .= 1;
end
sl1[710:900,710:900] .= 1;
imshow(sl1)
sl1_ot = opening(sl1);
imshow(sl1_ot)
Out[14]:
Dict{String,Any} with 4 entries:
  "gui"         => Dict{String,Any}("window"=>GtkWindowLeaf(name="", parent, wi…
  "roi"         => Dict{String,Any}("redraw"=>259: "map(clim-mapped image, inpu…
  "annotations" => 225: "input-74" = Dict{UInt64,Any}() Dict{UInt64,Any} 
  "clim"        => 224: "CLim" = CLim{Normed{UInt8,8}}(0.0, 1.0) CLim{Normed{UI…
In [15]:
imshow(sl1_ot - sl1) #vidimo da se raskinula uska prevlaka između ova dva kvadrata
Out[15]:
Dict{String,Any} with 4 entries:
  "gui"         => Dict{String,Any}("window"=>GtkWindowLeaf(name="", parent, wi…
  "roi"         => Dict{String,Any}("redraw"=>296: "map(clim-mapped image, inpu…
  "annotations" => 262: "input-86" = Dict{UInt64,Any}() Dict{UInt64,Any} 
  "clim"        => 261: "CLim" = CLim{Normed{UInt8,8}}(0.0, 0.004) CLim{Normed{…

Zatvaranje

In [16]:
#Zatvaranje predstavlja postupak koji se sastovi od sukcesivne primene operacije dilatacije, pa erozije.
#Ona pre svega za cilj ima popunjavanje  spajanje uskih prekida, sitnijih rupa u objektu, 
#ali i glačanje nedovoljno glatkih ivica  
#Ona, kao i otvaranje, predstavlja odličan algoritam koji služi kako bi se 
#popravili rezultati izdvajanje ivica ili izdvajanja objekata
#koji su potencijalno delom narušeni ovim obradama
In [17]:
sl2 = zeros(Gray{N0f8},200,200);
#sl2 .= 1;
sl2[40:100,40:100] .= 1;
sl2[170:190,170:190] .= 1;

for i in 102:168
   sl2[i,i:i+1] .= 1;
end

sl2[45:48, 45:46] .= 0;
sl2[178:182, 178] .= 0;

imshow(sl2)
sl2_zt = closing(sl2);
imshow(sl2_zt)
Out[17]:
Dict{String,Any} with 4 entries:
  "gui"         => Dict{String,Any}("window"=>GtkWindowLeaf(name="", parent, wi…
  "roi"         => Dict{String,Any}("redraw"=>370: "map(clim-mapped image, inpu…
  "annotations" => 336: "input-110" = Dict{UInt64,Any}() Dict{UInt64,Any} 
  "clim"        => 335: "CLim" = CLim{Normed{UInt8,8}}(0.0, 1.0) CLim{Normed{UI…
In [18]:
imshow(sl2_zt - sl2)   #Zaista, vidimo da će sve manje rupice biti popunjene, ali veza između ova dva objekata neće
                      #biti popunjena, jer je razmak između njih dosta dugačak
Out[18]:
Dict{String,Any} with 4 entries:
  "gui"         => Dict{String,Any}("window"=>GtkWindowLeaf(name="", parent, wi…
  "roi"         => Dict{String,Any}("redraw"=>407: "map(clim-mapped image, inpu…
  "annotations" => 373: "input-122" = Dict{UInt64,Any}() Dict{UInt64,Any} 
  "clim"        => 372: "CLim" = CLim{Normed{UInt8,8}}(0.0, 1.0) CLim{Normed{UI…

Morfološko glačanje

In [19]:
#Morfološko glačanje je operacija koja se sastoji od sukcesivne primene otvaranja slike, a onda potom njenog 
#zatvaranja. Ona za cilj ima uklanjanje
In [20]:
sl3 = load("slikaizo.jpg")
Out[20]:
In [21]:
sl3_ot = opening(sl3);
sl3_mg = closing(sl3_ot);

mosaicview(sl3, sl3_mg)
┌ Warning: `mosaicview(A1::AbstractArray, A2::AbstractArray; kwargs...)` is deprecated, use `mosaic(A1, A2; kwargs...)` instead.
│   caller = top-level scope at In[21]:3
└ @ Core In[21]:3
Out[21]:
In [22]:
#Kao što vidimo, glačanje je odlično uradilo posao, jer je ublažilo ivice i potisnulo detalje na slici.

Top Hat transformacija

In [23]:
#Top Hat transformacija predstavlja transformaciju koja vrši ekstrakciju sitnih detalja iz slika. 
#Ona se veoma efikasno
#izvršava pomoću već ugrađene funkcije tophat() u programskom jeziku Julia. 
#Ona predstavlja linearnu kombinaciju
#naše slike i neke od operacija otvaranja primenjenoj nad našom slikom - od originalne 
#slike se oduzimanje ona koja je dobijena
#otvaranjem nad njom

sl3_th = tophat(sl3)
mosaicview(sl3, sl3_th)
┌ Warning: `mosaicview(A1::AbstractArray, A2::AbstractArray; kwargs...)` is deprecated, use `mosaic(A1, A2; kwargs...)` instead.
│   caller = top-level scope at In[23]:7
└ @ Core In[23]:7
Out[23]: