geometrijske transformacije na slikama

43
Sveučilište u Mostaru Fakultet Prirodoslovno-Matematičkih i odgojnih znanosti Odjel za Informatiku PROJEKTNI ZADATAK GEOMETRIJSKE TRANSFORMACIJE NA SLIKAMA ROTACIJA, ZRCALJENJE I SKALIRANJE MENTOR: STUDENTI: Dr.sc Sven Gotovac Ivan Kasalo 7647

Upload: ana-vila

Post on 05-Feb-2016

44 views

Category:

Documents


3 download

DESCRIPTION

Geometrijske transformacije na fotografijama, projektni zadatak iz paralelnog programiranjaAutori: Ana, Ivan, Branimir

TRANSCRIPT

Page 1: Geometrijske Transformacije Na Slikama

Sveučilište u Mostaru

Fakultet Prirodoslovno-Matematičkih i odgojnih znanosti

Odjel za Informatiku

PROJEKTNI ZADATAK

GEOMETRIJSKE TRANSFORMACIJE NA SLIKAMA

ROTACIJA, ZRCALJENJE I SKALIRANJE

MENTOR: STUDENTI:Dr.sc Sven Gotovac Ivan Kasalo 7647

Ana Vila 7649/I Branimir Boras 6860

Mostar, 2015

Page 2: Geometrijske Transformacije Na Slikama

SADRŽAJ

1. UVOD.................................................................................................................................1

2. LINEARNE GEOMETRIJSKE TRANSFORMACIJE NA SLIKAMA...........................2

2.1 Zrcaljenje......................................................................................................................3

2.2 Rotacija.........................................................................................................................4

2.3 Skaliranje......................................................................................................................5

3. IMPLEMENTACIJA ALGORITAMA ZA ROTACIJU, SKALIRANJE I ZRCALJENJE6

3.1 Sekvencijalni kod.........................................................................................................7

3.2 Paralelni kod po c11 standardu..................................................................................10

3.3 Paralelna izvedba upotrebom cuda programskog modela..........................................13

4. USPOREDBA BRZINE IZVOĐENJA PROGRAMA....................................................15

5. ZALJUČAK......................................................................................................................17

6. LITERATURA.................................................................................................................18

1

Page 3: Geometrijske Transformacije Na Slikama

1. UVOD

Obrada fotografija je oblik obrade signala gdje se kao ulazni podatak koristi

fotografija a izlaz može biti nova slika ili bilo koja druga vrsta relevantnih podataka. Rotirati

sliku za određeni broj stupnjeva ili joj pak smanjiti veličinu za određeni faktor su primjeri

uobičajene obrade fotografije.

U većini slučajeva obrada se vrši na cijeloj fotografijji i iste operacije se izvršavaju

nad svakim pikselom što zapravo znači mnogo ponavljanja istog posla. Napredovanjem

tehnologije fotografije postaju kvalitetnije što dovodi do većih datoteka a samim tim i

produljenja vremena potrebnog za njihovu obradu. Zbog velikog broja ponavljanja istih

operacija obrada fotografija spada u kategoriju visoko paralelnih zadataka te je pogodna za

implementaciju na GPU a njihova izvedba je uvelike brža nego na nego slična implementacija

na CPU.

U ovom radu obrađena su tri često korištene transformacije digitalnih fotografija:

rotacija, zrcaljenje i smanjivanje. Transformacije su odrađene korištenjem tri verzije koda za

transformaciju: klasični sekvencijalni C/C++ kod, C/C++ kod sa C11 standardom i upotrebom

dretvi te CUDA C kod za izvedbu na masivno paralelnim procesorima.

2

Page 4: Geometrijske Transformacije Na Slikama

2. LINEARNE GEOMETRIJSKE TRANSFORMACIJE NA SLIKAMA

Geometrijske transformacije su često korišten postupak za registraciju slika i

uklanjanje geometrijskih distorzija na slikama. Česte primjene uključuju stvaranje mozaika i

geografsko mapiranje a jedan od najčešće korištenih procesa su linearne geometrijske

transformacije.

Baza geometrijskih transformacija je mapiranje jednog koordinatnog sustava na drugi.

Ovo mapiranje se definira pomoću prostornih transformacija – funkcije mapiranja koja

uspostavlja linearnu prostornu vezu između svih točaka ulazne i izlazne fotografije. Za zadanu

prostornu transformaciju svaka točka u izlaznoj slici zauzima vrijednost odgovarajuće točke

ulazne fotografije. Veza između koordinata ulazne i izlazne slike pronalazi se primjenom

odgovarajuće funkcije prostorne transformacije.

Prema tome geometrijska transformacija je funkcija koja preslikava orginalnu točku ili

vektor u njenu sliku, znači da se koordinate piksela orginalne slike A (x,y) mapiraju u točku

(u,v) novog kordinatnog sustava gdje su u i v funkcije koordinata točke (x,y): u=f1(x,y),

v=f1(x,y).

Ovisno o primjeni, funkcije linearne transformacije mogu poprimiti više različitih

oblika a one najjednostavnije su određene analitičkim izrazima uključujući afine,

polinominalne i projektivne transformacije.

3

Page 5: Geometrijske Transformacije Na Slikama

slika 1. mapiranje iz točke (x,y) u (u,v)

Niz digitalne slike ima implicitnu mrežu koja se mapira u točke nove domene. Na slici

1. možemo vidjeti da ove točke ne moraju pasti u mrežu točaka nove domene. U neprekidnoj

domeni geometrijska transformacija je u potpunosti određena prostornom transformacijom, a

uzrok ovome je činjenica da je mapiranje bijektivno, no u domeni u kojoj mi radimo dolazi do

komplikacija zbog prirode digitalnih slika. Kod digitalnih slika, njeni diskretni elementi,

pikseli leže na mreži koja je u osnovi rešetka integera. Problem se javlja jer se izlazna mreža

za razliku od ulazne ne mora nužno poklapati sa rešetkom, upravo suprotno pozicije izlazne

mreže mogu biti bilo koja vrijednost koja je rezultat funkcije mapiranja.

Pošto je diskretni ulaz definiran samo vrijednostima integera provodi se interpolacija

da bi se neprekinuta površina uklopila u uzorke. Popularne interpolacijske funkcije su kubna

bilinearna i funkcija najbližeg susjeda no u ovom radu radi preglednosti i točnijeg mjerenja

interpolacija nije korištena.

2.1 Zrcaljenje

Zrcaljene slike je operacija rotiranja slike oko neke osi odnosno mjenjanje njenog

horizontalnog ili vertikalnog smjera. Refleksija odnosno zrcaljenje može se vršiti oko točke ili

osi slike. U slučaju zrcaljenja oko osi najčešće korištene transformacije su:

-refleksija oko vertikalne osi x0 ulazne slike:

x2=-x1+(2*x0)

y2=y1

-refleksija oko horizontalne osi y0 ulazne slike:

x2=x1

y2=-y1+(2*x0)

Navedene formule vrše prebacivanje svakog piksela izvorne slike na suprotnu stranu gdje pri

4

Page 6: Geometrijske Transformacije Na Slikama

vertikalnom zrcaljenju horizontalna koordinata ostaje jednaka a pri horizontalnom ne mjenja

se vertikalna koordinata.

Najčešće se koristi radi vizualnog efekta i pri analizi simetričnosti ali svoje primjene nalazi i

kao operator pri zahtjevnijim operacijama. Primjer vertikalnog zrcaljenja oko osi može se

vidjeti na slici 2.

Slika 2. Orginal lena i nakon vertikalnog zrcaljenja

2.2 Rotacija

Rotacija fotografija je uobičajen proces kod digitalne obrade slika. Pošto sliku rotiramo oko

središta za zadani kut za računanje novih pozicija piksela korištene su formule:

r’ = r0 + (r – r0)cos(theta) – (c – c0)sin(theta)

c’ = c0 + (r - r0)sin(theta) + (c – c0)cos(theta)

gdje su r0 i c0 koordinate središta slike.

5

Page 7: Geometrijske Transformacije Na Slikama

Na slici ispod možemo vidjeti sliku lena rotiranu za 45 stupnjeva oko njenog središta.

Slika 3. Lena rotirana za 45 stupnjeva

Rotacija je znači funkcija definirana kutom rotacije i središtem rotacije te iako korisna sama

po sebi često se koristi u početnim stadijima sofisticiranijih operacija nad slikama. Na primjer

postoje mnogobrojni operatori smjera kao što su na primjer operatori kod detekcije rubova

koji rade samo na limitiranom skupu smjerova. Rotacijom slike za određeni kut prije primjene

operatora za detekciju rubova može se konstruirati hibridni operator koji će koji će djelovati u

smjeru u kojem želimo.

2.3 Skaliranje

Skaliranje fotografija je osnovna operacija bilo kojeg sustava za obradu fotografija. To je

takva transformacija kojom se može povećavati ili smanjivati širina ili visina slika, pa time

možemo dobiti razne efekte izduživanja ili zbijanja slika, ili pak smanjenje ili povećanje

canvas slika ako i visinu i širinu slika smanjujemo odnosno povećavamo proporcionalno.

Smanjivanje fotografija odnosno subsampling provodi se mijenjanjem vrijednosti grupe

6

Page 8: Geometrijske Transformacije Na Slikama

piksela jednom vrijednosti iz te grupe ili interpolacijom vrijednosti svih susjednih piksela.

Slika 4. subsampling metodom odabira piksela i interpolacijom

Na slici 4. možemo vidjeti dvije navedene metode za skaliranje fotografija. Dok je

interpolacija susjednih piksela točnija i vodi do kvalitetnijih izlaznih fotografija, odabir

piksela koji će predstavljati svoje okruženje je manje zahtjevna u pogledu izračuna te je

samim tim i brža.

U nastavku rada obrađene su rotacija, zrcaljenje i skaliranje slike u tri izvedbe: C/C++

sekvencijalno, C/C++ paralelno (C11 standard) i Cuda C za paralelnu izvedbu na GPU. Za

svaku izvedu napravljena su mjerenja vremena izvođenja te rezultati prikazani u tablici

3. IMPLEMENTACIJA ALGORITAMA ZA ROTACIJU, SKALIRANJE I ZRCALJENJE

Sa tisućama piksela kojima treba pratiti pozicije obrada digitalnih fotografija može se

činiti kao zahtjevan zadatak ali nakon kraćeg razmatranja možemo vidjeti da je svaka

fotografija zapravo jednostavna i dobro poznata struktura podataka. Za početak uzmimo

7

Page 9: Geometrijske Transformacije Na Slikama

jednostavnu fotografiju u sivim tonovima. Svaki piksel ovakve fotografije ima jednu

vrijednost a to je siva. Ako razmotrimo piksele kao obične brojeve a ne tonove boje dobijemo

2D niz koji je spremljen u .txt datoteku pa je sve što je potrebno uraditi zapravo učitati taj niz

i obaviti neke osnovne operacije nad njim.

Kada se slika pogleda kao dvodimenzionalni niz odnosno matrica izvršavanje osnovnih

geometrijskih transformacija zapravo se svodi na preslagivanje redaka i stupaca u matrici.

Tako se promjene u matrici kod zrcaljenja slike mogu vidjeti na slici ispod:

Slika 5. 4x4 matrica prije i poslije vertikalnog zrcaljenja

Za testiranje koda i mjerenje brzine korištena je slika lena.pgm dimenzija 2400x3000 px u

sivim tonovima.

3.1 Sekvencijalni kod

U sekvencijalnom kodu nakon učitavanja slike alociramo prostor u memoriji za slike koju

ćemo dobti rotacijom, zrcaljenjem i smanjivanje, te pozivamo funkcije:

void rotiraj(int theta, PGMImage &izvorna, PGMImage &rot);

8

Page 10: Geometrijske Transformacije Na Slikama

void smanji(int faktor, PGMImage &izvorna, PGMImage &resize);

void mirror (bool flag, PGMImage &izvorna,PGMImage &mirr);

a) rotacija

Funkcija rotiraj kroz dvije petlje pomoću već spomenute formule određuje novu poziciju

piksela te kopira vrijednosti piksela iz orginalne slike na nove pozicije.

for(int c = 0; c < stupac; c++)

for(int r = 0; r < red; r++)

{

r1 = (int) (r0 + ((r - r0) * cos(rads)) - ((c - c0) * sin(rads)));

c1 = (int) (c0 + ((r - r0) * sin(rads)) + ((c - c0) * cos(rads)))

mirr.grey[c1][r1] = izvorna.grey[c][r];

}

Nakon kopiranja piksela pokreće se nova petlja koja ispunjava “propadnute” piksele, koji se

javljaju zbog bijektivnosti mapiranja, vrijednostima iz njihovih desnih susjeda.

for(int i = 0; i < red; i++)

for(int j = 0; j < stupac; j++)

if(mirr.grey[i][j] == 0)

mirr.grey[i][j] = mirr.grey[i][j+1];

9

Page 11: Geometrijske Transformacije Na Slikama

b) zrcaljanje

Kod zrcaljenja fotografije na osnovu izbora korisnika vrši se vertikalni ili horizontalni mirror.

Kod horizontalnog mirrora vertikalne pozicije piksela se mjenjaju u odnosu na središnju

horizontalnu os:

for(int i = 0; i < red; i++)

for(int j = 0; j < stupac; j++)

mirr.grey[red - (i+1)][j] =izvorna.grey[i][j];

Kod vertikalnog zrcaljenja vrši se isti postupak samo što se mijenjaju horizontalne pozicije:

for(int i = 0; i < red; i++)

for(int j = 0; j < stupac; j++)

mirr.grey[i][stupac - (j + 1)] = izvorna.grey[i][j];

c) skaliranje

Kod skaliranja fotografija za određeni faktor nakon računanja novih dimenzija slike pikseli iz

orginalne slike se kopiraju na nove pozicije s tim da se npr za faktor 2 preskače svaki drugi

redak i stupac te se tako postiže efekt smanjivanja.

for(int i = 0; i < red; i++)

for(int j = 0; j < stupac; j++)

mirr.grey[i][j] = izvorna.grey[i * faktor][j * faktor];

10

Page 12: Geometrijske Transformacije Na Slikama

po završetku izvođenja slike se spremaju u .pgm fileove i zauzeta memorija se oslobađa.

11

Page 13: Geometrijske Transformacije Na Slikama

3.2 Paralelni kod po c11 standardu

C11 standard je je trenutni standard C programskog jezika. Uključuje detaljan memorijski

model za bolju podršku pri izvedbi programa upotrebom više dretvi. Funkcija za rotaciju po

C11 standardu malo se razlikuje od sekvencijalnog koda. Korištenjem podatkovne

dekompozicije promjena se dešava pri pozivu funkcije gdje sliku dijelimo na onoliko dijelova

koliko imamo dretvi.

a) rotacija

Funkcija za rotaciju fotografija u C11 standardu zapravo se ne razlikuje previše od

sekvencijalne verzije, u isječku koda ispod možemo vidjeti njen poziv na dretvi sa indexom 0.

if (i == 0)

{

poc = 0;

kraj = okvirna.y / 4;

t[i] = std::thread(rotiraj, kut, poc, kraj, okvirna, rotirana);

}

Glavna razlika je u tome što pri pozivu funkciji prosljeđujemo samo prvu četvrtinu slike te

ova dretva obavlja samo rotaciju samo ove četvrtine. Važno je napomenuti da iako rotaciju

obavljamo samo na četvrtini slike, nove pozicije piksela se računaju na osnovu pozicija

piksela kompletne slike a ne samo te četvrtine.

for (int r = poc; r < kraj; r++)

{

for (int c = 0; c < stupac; c++)

{

r1 = (int)(r0 + ((r - r0) * cos(rads)) - ((c - c0) * sin(rads)));

12

Page 14: Geometrijske Transformacije Na Slikama

c1 = (int)(c0 + ((r - r0) * sin(rads)) + ((c - c0) * cos(rads)));

if (r1 > 0 && r1 < red && c1 > 0 && c1 < stupac)

rotirana.grey[r1][c1] = okvirna.grey[r][c];

}

}

b) zrcaljenje

Funkcija za zrcaljenje fotografija upotrebom C11 standarda

void mirror(bool flag, int poc, int kraj, PGMImage &izvorna, PGMImage &mirr);

zrcali sliku vertikalno ili horizontalno na osnovu unosa korisnika te je skoro identična funkciji

za zrcaljenje kod sekvencijalne izvedbe. Glavna razlika je u parametrima jer da bi se

realizirala podatkovna dekompozicija pri pozivu funkcije prosljeđuje joj se samo četvrtina

slike na kojoj će radit dretva u kojoj je funkcija pozvana.

c) skaliranje

Pokretanjem programa na četiri dretve i korištenjem podatkovne dekompozicije može se

znatno ubrzati izvođenje programa. Umjesto pokretanja funkcije na cijeloj fotografiji svaka

dretva pokreće funkciju na jednoj četvrtini fotografije što se može vidjeti na isječku koda za

smanjivanje fotografije.

for (int i = 0; i<num_threads; i++){

if (i == 0){

poc = 0;

kraj = izvorna.y / 4

t[i] = thread(smanji, faktor, poc, kraj, izvorna, mirr);

13

Page 15: Geometrijske Transformacije Na Slikama

}

if (i == 1){

poc = izvorna.y / 4;

kraj = izvorna.y / 2;

t[i] = thread(smanji, faktor, poc, kraj, izvorna, mirr);

}

if (i == 2){

poc = izvorna.y / 2;

kraj = izvorna.y * (3 / 4.);

t[i] = thread(smanji, faktor, poc, kraj, izvorna, mirr);

}

if (i == 3){

poc = izvorna.y * (3 / 4.);

kraj = izvorna.y;

t[i] = thread(smanji, faktor, poc, kraj, izvorna, mirr);

}

}

Nakon završetka izvođenja dreve se ponovo spajaju u jednu te se program završava.

14

Page 16: Geometrijske Transformacije Na Slikama

3.3 Paralelna izvedba upotrebom cuda programskog modela

GPU je moderna računalna grafička tehnologija kod koje grafički procesor preuzima zadatke

visokog paralelizma i tako smanjuje opterećenje CPU-a. Zadatke pogodne za izvedbu na GPU

karakterizira visoki paralelizam, niska ovisnost između različitih elemenata i numerički

karakter s minimalnim grananjem a zbog velikog broja ponavljanja istih operacija nad

različitim pikselima obrada fotografija je baš takav zadatak. CUDA (Compute Unified Device

Arhitecture), je najpoznatiji programski model i arhitektura za visokoparalelne procesore.

Kod izrade paralelnih programa korištenjem CUDA-e, razlikujemo dvije vrste programskog

koda: kod koji se izvršava na centralnom procesoru , te kod koji se izvršava na grafičkom

procesoru. Osnovna ideja kod dizajniranja sustava je dio posla koji se mora sekvencijalno

izvršavati prilagoditi za izvođenje na centralnom procesoru, a dio posla koji uključuje

izvršavanje aritmetičkih operacija nad velikom količinom podataka istovremeno, prilagoditi

za izvođenje na grafičkom procesoru.

Izvođenje na CPU odnosno hostu sastoji se od učitavanja fotografije za obradu te kopiranja

podataka sa hosta na device. Samo kopiranje je jednostavno i intuitivno te se provodi

ugrađenom funkcijom cudaMemcpy.

cudaMemcpy(d_izvorna.grey, h_izvorna.grey, size, cudaMemcpyHostToDevice);

akon kopiranja podataka poziva se kernel pri čijem pozivu definiramo veličinu i broj blokova

dretvi za obradu podataka

rotirajKernel<<<numBlock,blkSize>>>(theta, d_okvirna, d_rotiraj);

Nakon poziva kernela posao se vrši na device-u odnosno GPU. Glavna razlika između kernela

i prije navedenih funkcija je to da ulogu petlje u CUDI preuzimaju dretve te svaka od njih vrši

zadanu operaciju nad jednim pikselom slike.

a) rotacija

Pri rotaciji fotografija korištenjem CUDA programskog modela posebnu pažnju trebalo je

posvetiti na postavljanje blokada, odnosno sinkronizaciju dretvi koja osigurava da se podatci

ne čitaju prije upisivanja. Kao što je prije spomenuto ulogu petlje preuzimaju dretve te je u

kodu samo potrebno provjeriti da ne dolazi do čitanja podataka kojima nemamo pristup što je

odrađeno jednostavnim uvjetima.

15

Page 17: Geometrijske Transformacije Na Slikama

__syncthreads();

if(row<d_izvorna.y && col<d_izvorna.x&&row>0&&col>0){

int r1 = ceil (r0 + ((row - r0) * cos(rads)) - ((col - c0) * sin(rads)));

int c1 = ceil (c0 + ((row - r0) * sin(rads)) + ((col - c0) * cos(rads)));

__syncthreads();

if (r1<d_izvorna.y&&r1>0&&c1<d_izvorna.x&&c1>0){

d_rotiraj[r1*num+c1] = d_izvorna.grey[row*num+col];

b) zrcaljenje

Za razliku od rotacije kod zrcaljenja fotografije sinkronizacija dretvi nije potrabna pošto nove

pozicije piksela ovise samo o dretvi koja radi s tim pikselom a ne o drugim dretvama.

__global__ void mirrorKernel(Image1D d_izvorna,float *d_mirror){

int row=blockIdx.y*blockDim.y+threadIdx.y;

int col=blockIdx.x*blockDim.x+threadIdx.x;

int num=d_izvorna.x;

int m=row*num+col, k= (d_izvorna.y - (row+1)) * num + col;

if(col<d_izvorna.x && row<d_izvorna.y&&col>0&&row>0)

d_mirror[k]=d_izvorna.grey[m];

}

c) skaliranje

U kernelu za smanjivanje fotografija kao i kod zrcaljenja nije potrebno raditi sinkronizaciju te

se pomoću uvjeta provjerava jeli potrebno brisati piksel na čijoj se poziciji nalazimo.

if(row<d_izvorna.y&&col<d_izvorna.x)

16

Page 18: Geometrijske Transformacije Na Slikama

if(col%faktor==0 && row%faktor==0)

{

int k=row/faktor*num/faktor+col/faktor;

d_smanji[k]=d_izvorna.grey[m];

}

Na primjer za faktor 2 to je svaki drugi redak i stupac, dok bi za faktor 3 to bio svaki treći

redak i stupac i tako dalje.

4. USPOREDBA BRZINE IZVOĐENJA PROGRAMA

U ovom dijelu će mo napraviti usporedbu performansi kodova za rotaciju, zrcaljenje i

skaliranje fotografije lena.pgm već spomenutih dimenzija 2400x3000 px. Sekvencijalna i

paralelna C11 implementacija transformacija su testirane na procesoru Intel Core i7

frekvencije 2.4 GHz sa osam jezgri. CUDA izvedba je testirana na Nvidia Geforce 740

GDDR5 grafičkoj kartici preko testnog servera. Veličina memorije na kartici je 1024 Mb

GDDR5 sa 1072 MHz frekvencijom. Grafička kartica sastoji se od 384 jezgre, sa baznim

taktom od 993 Mhz.

SEKVENCIJALNO C11 CUDA

rotacija 9,21709 s 5,566576 s 0,579

skaliranje 0,666859 s 0,34922 s 0,500

zrcaljenje 2,472057 s 2,337600 s 0,569

Tablica 1. Brzine izvođenja

17

Page 19: Geometrijske Transformacije Na Slikama

rotacija skaliranje zrcaljenje0

1

2

3

4

5

6

7

8

9

10

SekvencijalnoC11CUDA

Graf 1. Brzine izvođenja

Na grafu 1 i tablici 1 prikazana su mjerenja vremena izvedbe. Može se vidjeti da je kod

rotacije koja je procesorski najzahtjevnija transformacija, izvođenje na grafičkom procesoru je

deset puta kraće od izvođenja koda na četiri dretve napravljeno napravljeno upotrebom C11

standarda i čak dvadeset puta brže od sekvencijalne izvedbe.

Kod zrcaljenja fotografija paralelna izvedba na četiri dretve zapravo ne skraćuje pretjerano

vrijeme izvedbe u odnosu na sekvencijalnu izvdbu dok je kod CUDA verzije vrijeme

izvođenja oko pet puta kraće u odnosu na prethodne.

18

Page 20: Geometrijske Transformacije Na Slikama

5. ZALJUČAK

U današnjem svijetu programeri se konstantno suočavaju sa zahtjevima za poboljšanjem

performansi i bržim rješavanjem problema. Korištenjem jezika visoke razine CUDA

omogućuje paralelno programiranje bez potrebe za prevelikim prilagođavanjem koda. GPU

programiranje danas je moguće jer su današnji grafički procesori u mogućnosti odraditi

mnogo više od iscrtavanja grafike.

Zahvaljujući teraflopima floating point performansi svoju primjenu nalaze u svemu od

financija do medicine. Naš primjer geometrijskih transformacija samo je mali dio CUDA eko

sustava koji svakodnevno raste zahvaljujući tvrtkama koje stvaraju vrhunske alate, usluge i

rješenja te pretvraju GPU računarstvo u računarstvo budućnosti.

19

Page 21: Geometrijske Transformacije Na Slikama

6. LITERATURA

www.gpucomputing.net/sites/default/files/papers/5207/AMR.216.708.pdf

www.kky.zcu.cz/en/publications/1/SudhakarSah_2012_GPUAcceleratedReal.pdf

www.nvidia.com/object/cuda_home_new

CUDA by Example: An Introduction to General-purpose GPU Programming

20

Page 22: Geometrijske Transformacije Na Slikama

DODATAK

Sekvencijalno:

#define _CRT_SECURE_NO_WARNINGS#include <iostream>#include "loading.h"#include "mjerenje.h"#include <math.h>#include <thread>using namespace std;

#define BLACK 0 //definiramo konstante 0 - crna boja#define WHITE 255 // 255 je bijela boja - korisno kod funkcije praznaSlika()

void rotiraj(int theta, PGMImage &izvorna, PGMImage &mirr);void smanji(int faktor, PGMImage &izvorna, PGMImage &resize);void mirror(bool flag, PGMImage &izvorna, PGMImage &mirr); //dodan parametar koji će vratiti mirror sliku

void praznaSlika(PGMImage &empty, int rowN, int colN, int color);void pasteSlika(PGMImage &empty, PGMImage &izvorna);//pomoćna funkcija koja stvara sliku određene boje dimenzije rowN * colN//služi da spasite frame kod smanjivanja slike i kod proizvoljnog rotiranja

int main(){

PGMImage izvorna, mirr, resize, rotirana, okvirna; //struktura u koju ucitavamo sliku

resize.grey = NULL; //ako želimo prenijeti neinicijaliziranu strukturu u funkciju moramo dodati NULL

char filename[1024] = "C:\Users\Amy\Documents\Visual Studio 2012\Projects\sek\sek\Lena.pgm";

ucitajPGM("Lena.pgm", &izvorna); //funkcija alocira memoriju i èita sliku fpmoz01.pgm u strukturu izvorna

mirr.x = izvorna.x;mirr.y = izvorna.y;alloc_matrix(&mirr.grey, mirr.y, mirr.x); //alociramo memoriju za mirror

sliku

int dim = ceil(sqrt(izvorna.y*izvorna.y + izvorna.x*izvorna.x));//diagonala izvorne slike

int faktor = 2;

praznaSlika(okvirna, dim, dim, BLACK);//stvaramo praznu okvirnu sliku s dimenzijama diagonale izvorne i alociramo prostor za nju

praznaSlika(rotirana, dim, dim, BLACK);//stvaramo praznu okvirnu sliku s dimenzijama diagonale izvorne i alociramo prostor za nju

praznaSlika(resize, izvorna.y / faktor, izvorna.x / faktor, BLACK);

pasteSlika(okvirna, izvorna);//lijepi piksele iz izvorne slike na sredinu okvirne

//printf("Pritisnite 1 za rotiranje slike, 2 za umanjenje slike, 3 za zrcaljenje slike ili \nneku drugu tipku za izlaz: ");

int c, kut = 75, z;

21

Page 23: Geometrijske Transformacije Na Slikama

bool provjera = false;//std::cin >> c;

double wall0 = get_wall_time();//Početak mjerenja

//rotiraj(kut, okvirna, rotirana);//zapisiPGM("rotirana.pgm", &rotirana); //funkcija zapisuje

piksele iz strukture mirror u novu sliku fpmoz02.pgm

smanji(faktor, izvorna, resize);zapisiPGM("resize.pgm", &resize); //funkcija zapisuje

piksele iz strukture mirror u novu sliku fpmoz02.pgm

//mirror(provjera, izvorna, mirr);//zapisiPGM("mirror.pgm", &mirr); //funkcija zapisuje

piksele iz strukture mirror u novu sliku fpmoz02.pgm

double wall1 = get_wall_time();//Završetak mjerenja

//funkcija dealocira memoriju format(matrica, broj redaka ,broj stupaca)disalloc_matrix(izvorna.grey, izvorna.y, izvorna.x);disalloc_matrix(okvirna.grey, okvirna.y, okvirna.x);disalloc_matrix(rotirana.grey, rotirana.y, rotirana.x);printf("Vrijeme izvodenja Sekvencijalno. %lf s\n", wall1 - wall0);printf("Press any key...");int k;std::cin >> k;

}

void pasteSlika(PGMImage &okvirna, PGMImage &izvorna){int pocx = ((okvirna.x - izvorna.x) / 2);int pocy = ((okvirna.y - izvorna.y) / 2);

for (int j = 0; j < izvorna.x; j++)for (int i = 0; i < izvorna.y; i++)

okvirna.grey[i+pocy][j+pocx] = izvorna.grey[i][j];

}//funkcija formira sliku proizvoljne dimenzije i bojevoid praznaSlika(PGMImage &empty, int rowN, int colN, int color){

alloc_matrix(&empty.grey, rowN, colN);

empty.y = rowN;empty.x = colN;for (int i = 0; i<rowN; i++)for (int j = 0; j<colN; j++)

empty.grey[i][j] = color;

}

void mirror(bool flag, PGMImage &izvorna, PGMImage &mirr)// zrcali sliku na osnovu unosa korisnika{

int red = mirr.y; //y koordinata označava broj redakaint stupac = mirr.x; // x koordinata označava broj stupaca

//printf("%d %d",red,stupac);if (flag == true) //horizontalni mirror{

22

Page 24: Geometrijske Transformacije Na Slikama

for (int i = 0; i < red; i++){

for (int j = 0; j < stupac; j++)mirr.grey[red - (i + 1)][j] = izvorna.grey[i][j];

}cout << "Broj redaka = " << red << " ili " << mirr.y;

}else //vertikalni mirror{

for (int i = 0; i < red; i++){

for (int j = 0; j < stupac; j++)mirr.grey[i][stupac - (j + 1)] = izvorna.grey[i][j];

}}

}

void smanji(int faktor, PGMImage &izvorna, PGMImage &resize){

int red = izvorna.y;int stupac = izvorna.x;

//dovoljno je iterirati petlje za određeni faktorfor (int i = 0; i < red-1; i=i+faktor){

for (int j = 0; j < stupac-1; j=j+faktor){//resize.grey[i / faktor][j / faktor] = izvorna.grey[i][j];

int k=i/faktor;int m=j/faktor;resize.grey[k][m] = izvorna.grey[i][j];

}}

}

void rotiraj(int theta, PGMImage &okvirna, PGMImage &rotirana)// na osnovu unosa korisnika za kut rotiranja, rotira sliku oko njenog sredista{

int r0, c0; //srediste slikeint r1, c1;int red, stupac;red = okvirna.y;stupac = okvirna.x;

float rads = (theta * 3.14159265) / 180.0;

r0 = red / 2;c0 = stupac / 2;

for (int r = 0; r < red; r++){

for (int c = 0; c < stupac; c++){

r1 = (int)(r0 + ((r - r0) * cos(rads)) - ((c - c0) * sin(rads))); c1 = (int)(c0 + ((r - r0) * sin(rads)) + ((c - c0) * cos(rads)));

if (r1 > 0 && r1 < red && c1 > 0 && c1 < stupac)rotirana.grey[r1][c1] = okvirna.grey[r][c];

}}

23

Page 25: Geometrijske Transformacije Na Slikama

for (int i = 0; i < red; i++){

for (int j = 0; j < stupac; j++){

if (rotirana.grey[i][j] == 0)rotirana.grey[i][j] = rotirana.grey[i][j + 1];

}}

}

Paralelno C11:

#define _CRT_SECURE_NO_WARNINGS#include <iostream>#include <stdio.h>#include "loading.h"#include "mjerenje.h"#include "rotate.h"#include "resize.h"#include "mirror.h"#include <thread>//#include <math.h>

#define BLACK 0#define WHITE 255

void praznaSlika(PGMImage &empty, int rowN, int colN, int color);void pasteSlika(PGMImage &empty, PGMImage &izvorna);int main(){

PGMImage izvorna, mirr, rotirana, okvirna, resize; resize.grey = NULL;char filename[1024] = "C:\Users\Amy\Documents\Visual Studio 2012\

Projects\PAR_11\PAR_11\Lena.pgm";

ucitajPGM("Lena.pgm", &izvorna); mirr.x = izvorna.x;mirr.y = izvorna.y;

int dim = ceil(sqrt(izvorna.y*izvorna.y + izvorna.x*izvorna.x));int faktor = 2;

alloc_matrix(&mirr.grey, mirr.y, mirr.x); praznaSlika(okvirna, dim, dim, BLACK);praznaSlika(rotirana, dim, dim, BLACK);praznaSlika(resize, izvorna.y / faktor, izvorna.x / faktor, BLACK);

pasteSlika(okvirna, izvorna);int c, kut = 75, z;

bool provjera = false;double wall0 = get_wall_time();//Početak mjerenja

rotirajsliku(kut, okvirna, rotirana);zapisiPGM("rotirana.pgm", &rotirana); //smanjisliku(faktor, izvorna, resize);//zapisiPGM("resize.pgm", &resize);

24

Page 26: Geometrijske Transformacije Na Slikama

//zrcalisliku(provjera, izvorna, mirr);//zapisiPGM("mirror.pgm", &mirr);

double wall1 = get_wall_time();//Završetak mjerenja//funkcija dealocira memoriju format(matrica, broj redaka ,broj stupaca)disalloc_matrix(izvorna.grey, izvorna.y, izvorna.x);disalloc_matrix(resize.grey, resize.y, resize.x);disalloc_matrix(okvirna.grey, okvirna.y, okvirna.x);disalloc_matrix(mirr.grey, mirr.y, mirr.x);disalloc_matrix(rotirana.grey, rotirana.y, rotirana.x);printf("Vrijeme izvodenja paralelno. %lf s\n", wall1 - wall0);printf("Press any key...");int k;std::cin >> k;

}

void pasteSlika(PGMImage &okvirna, PGMImage &izvorna){int pocx = ((okvirna.x - izvorna.x) / 2);int pocy = ((okvirna.y - izvorna.y) / 2);

for (int j = 0; j < izvorna.x; j++)for (int i = 0; i < izvorna.y; i++)

okvirna.grey[i + pocy][j + pocx] = izvorna.grey[i][j];

}void praznaSlika(PGMImage &empty, int rowN, int colN, int color){

alloc_matrix(&empty.grey, rowN, colN);

empty.y = rowN;empty.x = colN;for (int i = 0; i<rowN; i++)for (int j = 0; j<colN; j++)

empty.grey[i][j] = color;

}

Miror.h:

#include <math.h>#include <thread>void mirror(bool flag, int poc, int kraj, PGMImage &izvorna, PGMImage &mirr{

int red = mirr.y; int stupac = mirr.x; if (flag == true) {

for (int i = poc; i < kraj; i++){

for (int j = 0; j < stupac; j++)mirr.grey[red - (i + 1)][j] = izvorna.grey[i][j];

}}else {

for (int i = 0; i < red; i++){

for (int j = poc; j < kraj; j++)mirr.grey[i][stupac - (j + 1)] = izvorna.grey[i][j];

}}

}void zrcalisliku(bool flag, PGMImage izvorna, PGMImage mirr){

25

Page 27: Geometrijske Transformacije Na Slikama

int poc1, kraj1, poc, kraj;std::thread t[4];for (int i = 0; i < 4; i++){

if (i == 0){

poc = 0;kraj = izvorna.x / 4;poc1 = 0;kraj1 = izvorna.y / 4;if (flag == true)

t[i] = std::thread(mirror, flag, poc1, kraj1, izvorna, mirr);

elset[i] = std::thread(mirror, flag, poc, kraj, izvorna,

mirr);}if (i == 1){

poc = izvorna.x / 4;kraj = izvorna.x / 2;poc1 = izvorna.y / 4;kraj1 = izvorna.y / 2;if (flag == true)

t[i] = std::thread(mirror, flag, poc1, kraj1, izvorna, mirr);

elset[i] = std::thread(mirror, flag, poc, kraj, izvorna,

mirr);}if (i == 2){

poc = izvorna.x / 2;kraj = izvorna.x * (3 / 4.);poc1 = izvorna.y / 2;kraj1 = izvorna.y * (3 / 4.);if (flag == true)

t[i] = std::thread(mirror, flag, poc1, kraj1, izvorna, mirr);

elset[i] = std::thread(mirror, flag, poc, kraj, izvorna,

mirr);}if (i == 3){

poc = izvorna.x * (3 / 4.);kraj = izvorna.x;poc1 = izvorna.y * (3 / 4.);kraj1 = izvorna.y;if (flag == true)

t[i] = std::thread(mirror, flag, poc1, kraj1, izvorna, mirr);

elset[i] = std::thread(mirror, flag, poc, kraj, izvorna,

mirr);}

}

for (int i = 0; i < 4; i++)t[i].join();

}

Resize.h:

26

Page 28: Geometrijske Transformacije Na Slikama

#include <math.h>#include <thread>void smanji(int faktor, int poc, int kraj, PGMImage &izvorna, PGMImage &resize){

int red = izvorna.y;int stupac = izvorna.x;

for (int i = poc; i < kraj - 1; i = i + faktor){

for (int j = 0; j < stupac - 1; j = j + faktor){

int k = i / faktor;int m = j / faktor;resize.grey[k][m] = izvorna.grey[i][j];

}}

}void smanjisliku(int faktor, PGMImage izvorna, PGMImage resize){

int poc1, kraj1;std::thread t[4];for (int i = 0; i < 4; i++){

if (i == 0){

poc1 = 0;kraj1 = izvorna.y / 4;t[i] = std::thread(smanji, faktor, poc1, kraj1, izvorna,

resize);}if (i == 1){

poc1 = izvorna.y / 4;kraj1 = izvorna.y / 2;t[i] = std::thread(smanji, faktor, poc1, kraj1, izvorna,

resize);}if (i == 2){

poc1 = izvorna.y / 2;kraj1 = izvorna.y * (3 / 4.);t[i] = std::thread(smanji, faktor, poc1, kraj1, izvorna,

resize);}if (i == 3){

poc1 = izvorna.y * (3 / 4.);kraj1 = izvorna.y;t[i] = std::thread(smanji, faktor, poc1, kraj1, izvorna,

resize);}

}

for (int i = 0; i < 4; i++)t[i].join();

}

Rotate.h:

#include <math.h>#include <thread>void rotiraj(int theta, int poc, int kraj, PGMImage &okvirna, PGMImage

27

Page 29: Geometrijske Transformacije Na Slikama

&rotirana){

int r0, c0; //srediste slikeint r1, c1;int red, stupac;red = okvirna.y;stupac = okvirna.x;

float rads = (theta * 3.14159265) / 180.0;

r0 = red / 2;c0 = stupac / 2;

for (int r = poc; r < kraj; r++){

for (int c = 0; c < stupac; c++){

r1 = (int)(r0 + ((r - r0) * cos(rads)) - ((c - c0) * sin(rads)));

c1 = (int)(c0 + ((r - r0) * sin(rads)) + ((c - c0) * cos(rads)));

if (r1 > 0 && r1 < red && c1 > 0 && c1 < stupac)rotirana.grey[r1][c1] = okvirna.grey[r][c];

}}for (int i = 0; i < red; i++){

for (int j = 0; j < stupac; j++){

if (rotirana.grey[i][j] == 0)rotirana.grey[i][j] = rotirana.grey[i][j + 1];

}}

}void rotirajsliku(int kut, PGMImage okvirna, PGMImage rotirana){

std::thread t[4];int poc, kraj;for (int i = 0; i < 4; i++){

if (i == 0){

poc = 0;kraj = okvirna.y / 4;t[i] = std::thread(rotiraj, kut, poc, kraj, okvirna,

rotirana);

}if (i == 1){

poc = okvirna.y / 4;kraj = okvirna.y / 2;t[i] = std::thread(rotiraj, kut, poc, kraj, okvirna,

rotirana);}if (i == 2){

poc = okvirna.y / 2;kraj = okvirna.y * (3 / 4.);t[i] = std::thread(rotiraj, kut, poc, kraj, okvirna,

rotirana);}if (i == 3)

28

Page 30: Geometrijske Transformacije Na Slikama

{poc = okvirna.y * (3 / 4.);kraj = okvirna.y;t[i] = std::thread(rotiraj, kut, poc, kraj, okvirna,

rotirana);}

}

for (int i = 0; i < 4; i++)t[i].join();

}

CUDA:

ZRCALJENJE I SKALIRANJE

#include "loading.h"#include "cuda_runtime.h"#include "device_launch_parameters.h"#include "mjerenje.h"#include <cmath>

const int xSize=32;const int ySize=32;

typedef struct { int x, y;

float *grey; } Image1D;

__global__ void mirrorKernel(Image1D d_izvorna,float *d_mirror, bool flag){

int row=blockIdx.y*blockDim.y+threadIdx.y;int col=blockIdx.x*blockDim.x+threadIdx.x;int num=d_izvorna.x; //broj elemenata u jednom retku

int m=row*num+col;int i = row*num+(d_izvorna.x-(col+1)); //nove lokacije piksela

za vertikalni mirrorint k= (d_izvorna.y - (row+1)) * num + col; //nove lokacije za

horizontalni

if(col<d_izvorna.x && row<d_izvorna.y&&col>0&&row>0){if (flag) // horizontalni mirror

d_mirror[k]=d_izvorna.grey[m];else //inače vertikalni

d_mirror[i]=d_izvorna.grey[m];}

}

__global__ void smanjiKernel(int faktor, Image1D d_izvorna, float *d_smanji){

int row=blockIdx.y*blockDim.y+threadIdx.y;int col=blockIdx.x*blockDim.x+threadIdx.x;

29

Page 31: Geometrijske Transformacije Na Slikama

int num=d_izvorna.x;

int m=row*num+col;

if(row<d_izvorna.y&&col<d_izvorna.x){

if(col%faktor==0 && row%faktor==0){

int k=row/faktor*num/faktor+col/faktor;d_smanji[k]=d_izvorna.grey[m];

}}

}

int main(){

PGMImage mirror, izvorna;PGMImage smanji;

Image1D d_izvorna,h_izvorna;float *d_mirror;float *d_smanji;int faktor=2;

float *pom;int theta=45;char file1[1024] ="lena_org.pgm";char file2[1024] ="fpmoz02.pgm";char file3[1024] ="fpmoz03.pgm";

ucitajPGM(file1,&izvorna);

alloc_matrix(&(mirror.grey),izvorna.y,izvorna.x);alloc_matrix(&(smanji.grey),izvorna.y/faktor, izvorna.x/faktor);

mirror.x=izvorna.x;mirror.y=izvorna.y;

smanji.x=izvorna.x/faktor;smanji.y=izvorna.y/faktor;

h_izvorna.grey=(float *)malloc(izvorna.x*izvorna.y*sizeof(float));pom=(float *)malloc(mirror.x*mirror.y*sizeof(float));

d_izvorna.x=izvorna.x;d_izvorna.y=izvorna.y;

h_izvorna.x=izvorna.x;h_izvorna.y=izvorna.y;

for(int i=0;i<izvorna.y;i++)for(int j=0;j<izvorna.x;j++)

h_izvorna.grey[i*izvorna.x+j]=izvorna.grey[i][j];

int size=mirror.x*mirror.y*sizeof(float);

cudaMalloc((void **)& d_izvorna.grey, size);cudaMalloc((void **)& d_mirror,size);cudaMalloc((void **)& d_smanji,size);

30

Page 32: Geometrijske Transformacije Na Slikama

cudaMemcpy(d_izvorna.grey, h_izvorna.grey, size, cudaMemcpyHostToDevice);

dim3 blkSize(xSize,ySize);dim3 numBlock(ceil((float)izvorna.x/xSize),ceil((float)izvorna.y/ySize));double wall0 = get_wall_time(); //pocetak mjerenja

mirrorKernel<<<numBlock,blkSize>>>(d_izvorna, d_mirror, false);double wall1 = get_wall_time(); //pocetak mjerenjacudaThreadSynchronize();cudaMemcpy(pom, d_mirror, size, cudaMemcpyDeviceToHost);

for(int i=0;i<mirror.y;i++)for(int j=0;j<mirror.x;j++)

mirror.grey[i][j]=pom[i*mirror.x+j];double wall2 = get_wall_time(); //pocetak mjerenja

smanjiKernel<<<numBlock,blkSize>>>(2,d_izvorna,d_smanji);double wall3 = get_wall_time(); //pocetak mjerenja

cudaThreadSynchronize();cudaMemcpy(pom,d_smanji, size, cudaMemcpyDeviceToHost);

for(int i=0;i<smanji.y;i++)for(int j=0;j<smanji.x;j++)

smanji.grey[i][j]=pom[i*smanji.x+j];printf("Vrijeme izvodjenja kernel funkcije mirror iznosi %f \n", (wall1 -

wall0) * 1000);printf("Vrijeme izvodjenja kernel funkcije resize iznosi %f ", (wall3 -

wall2) * 1000);zapisiPGM(file2,&mirror);zapisiPGM(file3,&smanji);

cudaFree(d_izvorna.grey);cudaFree(d_mirror);cudaFree(d_smanji);

free(pom);disalloc_matrix(izvorna.grey,izvorna.y,izvorna.x);disalloc_matrix(smanji.grey,smanji.y,smanji.x);disalloc_matrix(mirror.grey,mirror.y,mirror.x);

printf("Press any key..."); getchar();}

ROTACIJA

#include "loading.h"#include "cuda_runtime.h"#include "device_launch_parameters.h"#include "gputimer.h"#include "mjerenje.h"#include <cmath>

#define BLACK 0 //definiramo konstante 0 - crna boja#define WHITE 255 // 255 je bijela boja - korisno kod funkcije praznaSlika()

const int xSize=32;const int ySize=32;

31

Page 33: Geometrijske Transformacije Na Slikama

typedef struct { int x, y;

float *grey; } Image1D;

void pasteSlika(PGMImage &okvirna, PGMImage &izvorna){int pocx = ((okvirna.x - izvorna.x) / 2);int pocy = ((okvirna.y - izvorna.y) / 2);

for (int j = 0; j < izvorna.x; j++)for (int i = 0; i < izvorna.y; i++)

okvirna.grey[i+pocy][j+pocx] = izvorna.grey[i][j];

}

void praznaSlika(PGMImage &empty, int rowN, int colN, int color){

alloc_matrix(&empty.grey, rowN, colN);

empty.y = rowN;empty.x = colN;for (int i = 0; i<rowN; i++)for (int j = 0; j<colN; j++)

empty.grey[i][j] = color;

}

__global__ void rotirajKernel(int theta, Image1D d_izvorna, float *d_rotiraj){

int row=blockIdx.y*blockDim.y+threadIdx.y;int col=blockIdx.x*blockDim.x+threadIdx.x;float rads = (theta * 3.14159265)/180.0;int num=d_izvorna.x;int r0=d_izvorna.y/2;int c0=num/2;

__syncthreads();if(row<d_izvorna.y && col<d_izvorna.x&&row>0&&col>0){

int r1 = ceil (r0 + ((row - r0) * cos(rads)) - ((col - c0) * sin(rads))); //racuna novu poziciju piksela

int c1 = ceil (c0 + ((row - r0) * sin(rads)) + ((col - c0) * cos(rads)));

__syncthreads();if (r1<d_izvorna.y&&r1>0&&c1<d_izvorna.x&&c1>0){

d_rotiraj[r1*num+c1] = d_izvorna.grey[row*num+col];

__syncthreads();if(d_rotiraj[row*num+col] == 0){

float temp = d_rotiraj[row*num+col+1];__syncthreads();d_rotiraj[row*num+col] = temp;}

} }

}

32

Page 34: Geometrijske Transformacije Na Slikama

int main(){

PGMImage izvorna, rotirana;PGMImage okvirna;

Image1D d_izvorna,h_izvorna;float *d_rotiraj;float *pom;int theta=90;char file1[1024] ="lena_org.pgm";char file2[1024] ="fpmoz02a.pgm";ucitajPGM(file1,&izvorna);

int dim = ceil(sqrt(izvorna.y*izvorna.y + izvorna.x*izvorna.x));//diagonala izvorne slike

praznaSlika(okvirna, dim, dim, BLACK);praznaSlika(rotirana, dim, dim, BLACK);//dvije praznw slike za rotaciju

pasteSlika(okvirna, izvorna);//lijepi piksele iz izvorne slike na sredinu okvirne

h_izvorna.grey=(float *)malloc(dim*dim*sizeof(float));pom=(float *)malloc(dim*dim*sizeof(float));

d_izvorna.x=dim;d_izvorna.y=dim;

h_izvorna.x=dim;h_izvorna.y=dim;

//kopira piksele iz 2D okvirne u 1D izvornufor(int i=0;i<dim;i++)

for(int j=0;j<dim;j++)h_izvorna.grey[i*dim+j]=okvirna.grey[i][j];

int size=dim*dim*sizeof(float);

cudaMalloc((void **)& d_izvorna.grey, size);cudaMalloc((void **)& d_rotiraj,size);

cudaMemcpy(d_izvorna.grey, h_izvorna.grey, size, cudaMemcpyHostToDevice);

dim3 blkSize(xSize,ySize);dim3 numBlock(ceil((float)dim/xSize),ceil((float)dim/ySize));

double wall0 = get_wall_time(); //pocetak mjerenjarotirajKernel<<<numBlock,blkSize>>>(theta, d_izvorna, d_rotiraj);double wall1 = get_wall_time(); //pocetak mjerenjacudaThreadSynchronize();cudaMemcpy(pom, d_rotiraj, size, cudaMemcpyDeviceToHost);

for(int i=0;i<rotirana.y;i++)for(int j=0;j<rotirana.x;j++)

rotirana.grey[i][j]=pom[i*dim+j];

33

Page 35: Geometrijske Transformacije Na Slikama

zapisiPGM(file2,&rotirana);cudaFree(d_izvorna.grey);cudaFree(d_rotiraj);

printf("Vrijeme izvodjenja kernel funkcije rotiraj iznosi %f \n", (wall1 - wall0) * 1000);

free(pom);disalloc_matrix(izvorna.grey,izvorna.y,izvorna.x);disalloc_matrix(rotirana.grey,rotirana.y,rotirana.x);disalloc_matrix(okvirna.grey,okvirna.y,okvirna.x);

printf("Press any key..."); getchar();}

34