Professional Documents
Culture Documents
Geometrijske Transformacije Na Slikama
Geometrijske Transformacije Na Slikama
PROJEKTNI ZADATAK
GEOMETRIJSKE TRANSFORMACIJE NA
SLIKAMA
ROTACIJA, ZRCALJENJE I SKALIRANJE
MENTOR:
Dr.sc Sven Gotovac
STUDENTI:
Ivan Kasalo 7647
Ana Vila 7649/I
Branimir Boras 6860
Mostar, 2015
SADRAJ
1.
UVOD.................................................................................................................................1
2.
3.
2.1
Zrcaljenje......................................................................................................................3
2.2
Rotacija.........................................................................................................................4
2.3
Skaliranje......................................................................................................................5
Sekvencijalni kod.........................................................................................................7
3.2
3.3
4.
5.
ZALJUAK......................................................................................................................17
6.
LITERATURA..................................................................................................................18
1. UVOD
Obrada fotografija je oblik obrade signala gdje se kao ulazni podatak koristi
fotografija a izlaz moe biti nova slika ili bilo koja druga vrsta relevantnih podataka. Rotirati
sliku za odreeni broj stupnjeva ili joj pak smanjiti veliinu za odreeni faktor su primjeri
uobiajene obrade fotografije.
U veini sluajeva obrada se vri na cijeloj fotografijji i iste operacije se izvravaju
nad svakim pikselom to zapravo znai mnogo ponavljanja istog posla. Napredovanjem
tehnologije fotografije postaju kvalitetnije to dovodi do veih 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 bra nego na nego slina implementacija
na CPU.
U ovom radu obraena su tri esto koritene transformacije digitalnih fotografija:
rotacija, zrcaljenje i smanjivanje. Transformacije su odraene koritenjem tri verzije koda za
transformaciju: klasini sekvencijalni C/C++ kod, C/C++ kod sa C11 standardom i upotrebom
dretvi te CUDA C kod za izvedbu na masivno paralelnim procesorima.
Niz digitalne slike ima implicitnu mreu koja se mapira u toke nove domene. Na slici
1. moemo vidjeti da ove toke ne moraju pasti u mreu toaka nove domene. U neprekidnoj
domeni geometrijska transformacija je u potpunosti odreena 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 lee na mrei koja je u osnovi reetka integera. Problem se javlja jer se izlazna mrea
za razliku od ulazne ne mora nuno poklapati sa reetkom, upravo suprotno pozicije izlazne
mree mogu biti bilo koja vrijednost koja je rezultat funkcije mapiranja.
Poto je diskretni ulaz definiran samo vrijednostima integera provodi se interpolacija
da bi se neprekinuta povrina uklopila u uzorke. Popularne interpolacijske funkcije su kubna
bilinearna i funkcija najblieg susjeda no u ovom radu radi preglednosti i tonijeg mjerenja
interpolacija nije koritena.
2.1 Zrcaljenje
Zrcaljene slike je operacija rotiranja slike oko neke osi odnosno mjenjanje njenog
horizontalnog ili vertikalnog smjera. Refleksija odnosno zrcaljenje moe se vriti oko toke ili
osi slike. U sluaju zrcaljenja oko osi najee koritene 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 vre prebacivanje svakog piksela izvorne slike na suprotnu stranu gdje pri
2.2 Rotacija
Rotacija fotografija je uobiajen proces kod digitalne obrade slika. Poto sliku rotiramo oko
sredita za zadani kut za raunanje novih pozicija piksela koritene 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 sredita slike.
Na slici ispod moemo vidjeti sliku lena rotiranu za 45 stupnjeva oko njenog sredita.
Rotacija je znai funkcija definirana kutom rotacije i sreditem rotacije te iako korisna sama
po sebi esto se koristi u poetnim 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 odreeni kut prije primjene
operatora za detekciju rubova moe 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 moe poveavati ili smanjivati irina ili visina slika, pa time
moemo dobiti razne efekte izduivanja ili zbijanja slika, ili pak smanjenje ili poveanje
canvas slika ako i visinu i irinu slika smanjujemo odnosno poveavamo proporcionalno.
Smanjivanje fotografija odnosno subsampling provodi se mijenjanjem vrijednosti grupe
piksela jednom vrijednosti iz te grupe ili interpolacijom vrijednosti svih susjednih piksela.
jednostavnu fotografiju u sivim tonovima. Svaki piksel ovakve fotografije ima jednu
vrijednost a to je siva. Ako razmotrimo piksele kao obine brojeve a ne tonove boje dobijemo
2D niz koji je spremljen u .txt datoteku pa je sve to je potrebno uraditi zapravo uitati taj niz
i obaviti neke osnovne operacije nad njim.
Kada se slika pogleda kao dvodimenzionalni niz odnosno matrica izvravanje 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:
a) rotacija
Funkcija rotiraj kroz dvije petlje pomou ve spomenute formule odreuje novu poziciju
piksela te kopira vrijednosti piksela iz orginalne slike na nove pozicije.
Nakon kopiranja piksela pokree 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];
b) zrcaljanje
Kod zrcaljenja fotografije na osnovu izbora korisnika vri se vertikalni ili horizontalni mirror.
Kod horizontalnog mirrora vertikalne pozicije piksela se mjenjaju u odnosu na sredinju
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 vri 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 odreeni faktor nakon raunanja novih dimenzija slike pikseli iz
orginalne slike se kopiraju na nove pozicije s tim da se npr za faktor 2 preskae svaki drugi
redak i stupac te se tako postie 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];
a) rotacija
Funkcija za rotaciju fotografija u C11 standardu zapravo se ne razlikuje previe od
sekvencijalne verzije, u isjeku koda ispod moemo 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 prosljeujemo samo prvu etvrtinu slike te
ova dretva obavlja samo rotaciju samo ove etvrtine. Vano je napomenuti da iako rotaciju
obavljamo samo na etvrtini slike, nove pozicije piksela se raunaju 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)));
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 identina funkciji
za zrcaljenje kod sekvencijalne izvedbe. Glavna razlika je u parametrima jer da bi se
realizirala podatkovna dekompozicija pri pozivu funkcije prosljeuje joj se samo etvrtina
slike na kojoj e radit dretva u kojoj je funkcija pozvana.
c) skaliranje
Pokretanjem programa na etiri dretve i koritenjem podatkovne dekompozicije moe se
znatno ubrzati izvoenje programa. Umjesto pokretanja funkcije na cijeloj fotografiji svaka
dretva pokree funkciju na jednoj etvrtini fotografije to se moe vidjeti na isjeku 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);
}
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 zavretka izvoenja dreve se ponovo spajaju u jednu te se program zavrava.
__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 poto 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 pomou uvjeta provjerava jeli potrebno brisati piksel na ijoj se poziciji nalazimo.
if(row<d_izvorna.y&&col<d_izvorna.x)
Na primjer za faktor 2 to je svaki drugi redak i stupac, dok bi za faktor 3 to bio svaki trei
redak i stupac i tako dalje.
SEKVENCIJALNO
rotacija
C11
CUDA
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
10
9
8
7
6
Sekvencijalno
C11
CUDA
3
2
1
0
rotacija
skaliranje
zrcaljenje
Kod zrcaljenja fotografija paralelna izvedba na etiri dretve zapravo ne skrauje pretjerano
vrijeme izvedbe u odnosu na sekvencijalnu izvdbu dok je kod CUDA verzije vrijeme
izvoenja oko pet puta krae u odnosu na prethodne.
5. ZALJUAK
U dananjem svijetu programeri se konstantno suoavaju sa zahtjevima za poboljanjem
performansi i brim rjeavanjem problema. Koritenjem jezika visoke razine CUDA
omoguuje paralelno programiranje bez potrebe za prevelikim prilagoavanjem koda. GPU
programiranje danas je mogue jer su dananji grafiki procesori u mogunosti odraditi
mnogo vie od iscrtavanja grafike.
Zahvaljujui 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 zahvaljujui tvrtkama koje stvaraju vrhunske alate, usluge i
rjeenja te pretvraju GPU raunarstvo u raunarstvo budunosti.
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
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);
//pomona funkcija koja stvara sliku odreene boje dimenzije rowN * colN
//slui 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);
}
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];
}
}
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(){
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){
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);
else
t[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,
else
t[i] = std::thread(mirror,
}
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,
else
t[i] = std::thread(mirror,
}
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,
else
t[i] = std::thread(mirror,
}
}
for (int i = 0; i < 4; i++)
t[i].join();
}
Resize.h:
#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,
}
if (i == 1)
{
poc1 = izvorna.y / 4;
kraj1 = izvorna.y / 2;
t[i] = std::thread(smanji, faktor, poc1, kraj1,
}
if (i == 2)
{
poc1 = izvorna.y / 2;
kraj1 = izvorna.y * (3 / 4.);
t[i] = std::thread(smanji, faktor, poc1, kraj1,
}
if (i == 3)
{
poc1 = izvorna.y * (3 / 4.);
kraj1 = izvorna.y;
t[i] = std::thread(smanji, faktor, poc1, kraj1,
}
}
izvorna, resize);
izvorna, resize);
izvorna, resize);
izvorna, resize);
Rotate.h:
#include <math.h>
#include <thread>
void rotiraj(int theta, int poc, int kraj, PGMImage &okvirna, PGMImage &rotirana)
{
int r0, c0;
//srediste slike
int 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++)
{
}
}
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)
{
poc = okvirna.y * (3 / 4.);
kraj = okvirna.y;
t[i] = std::thread(rotiraj, kut, poc, kraj, okvirna, rotirana);
}
CUDA:
ZRCALJENJE I SKALIRANJE
#include "loading.h"
#include
#include
#include
#include
"cuda_runtime.h"
"device_launch_parameters.h"
"mjerenje.h"
<cmath>
int m=row*num+col;
int i = row*num+(d_izvorna.x-(col+1));
mirror
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);
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 mjerenja
cudaThreadSynchronize();
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
#include
#include
#include
#include
#include
"loading.h"
"cuda_runtime.h"
"device_launch_parameters.h"
"gputimer.h"
"mjerenje.h"
<cmath>
__syncthreads();
if(d_rotiraj[row*num+col] == 0){
float temp = d_rotiraj[row*num+col+1];
__syncthreads();
d_rotiraj[row*num+col] = temp;
}
}
}
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 izvornu
for(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 mjerenja
rotirajKernel<<<numBlock,blkSize>>>(theta, d_izvorna, d_rotiraj);
double wall1 = get_wall_time(); //pocetak mjerenja
cudaThreadSynchronize();
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];
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);