Sunteți pe pagina 1din 18

PROIECT LA DISCIPLINA

Procesarea Imaginii

Procedura perimeter pentru calculul perimetrului unei


regiuni

2016

Cuprins

1.
2.
3.
4.
5.

Cerina proiectului .
Considerente teoretice
Proiectarea programului
Rularea programului .
Cod surs
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

3
3
5
10
12

6. Bibliografie
.
.
.
7. Mod de utilizare a aplicaiei .
8. Anex .
.
.
.

.
.
.

.
.
.

.
.
.

.
.
.

.
.
.

17
18
19

1 Cerina proiectului
2

Elaborai n C/C++ i testai pe imaginile de test procedura perimeter de calcul a perimetrului


unei regiuni.

2 Considerente teoretice

Perimetrul
Perimetrul unei regiuni pentru o imagine binar este alctuit din mulimea pixelilor care aparin
obiectului i au cel puin un vecin care aparine fondului.
Aceti pixeli se contorizeaz, iar valoarea rezultat poate fi folosit ca perimetru. Exist dou
variante de calcul n funcie de tipul conectrii, tetra-conectare sau octo-conectare.
Lum exemplul perimetrului unei regiuni circulare negre pe fond alb cu diametrul de 17 pixeli
(fig 1).

Fig 1. Disc, D=17


Calculnd perimetrul acestui cerc
= 53,407.

dup relaia P=2R, rezult P

n cazul tetra-conectrii,
alctuit numai din pixeli tetra(fig 2) se obine 64.

perimetrul unei regiuni este


conectai. Pentru exemplu

n cazul octo-conectrii, perimetrul unei regiuni este alctuit numai din pixeli octo-conectai.
Pentru exemplu (fig 3) se obine 54.

Fig 2. Regiune tetra-conectat

Fig 3. Regiune octo-conectat

Problema care apare la msurarea perimetrului este aceea c pixelii considerai reprezint de fapt
o arie i nu o distan liniar.
n acest caz trebuie introdus observaia legat de modul n care un pixel este traversat de linia
perimetrului.
Cazul cel mai simplu este acela n care linia perimetrului traverseaz un pixel P dup o direcie
vertical sau orizontal. Aportul unui astfel de pixel la calcularea perimetrului este 1.

n alte situaii linia perimetrului traverseaz un pixel dup o direcie diagonal. De aceast dat
contribuia acestui pixel este dat de diagonala ptratului

2 .

n alte cazuri linia perimetrului traverseaz pixelul considerat dup o direcie orizontal/vertical
i o direcie diagonal. n acest caz contribuia acestui pixel este

1
2 +

2
2

Cu aceste observaii, pentru determinarea perimetrului unei regiuni se parcurg urmtorii pai:
4

1. Se identific i se separ pixelii care alctuiesc conturul regiunii pentru care urmeaz s
calculm perimetrul.
2. Se testeaz fiecare pixel al perimetrului pentru a determina ponderea cu care va participa
la calculul perimetrului.
3. n final se nsumeaz toate aceste contribuii individuale ale pixelilor i valoarea obinut
este o valoare aproximativ a perimetrului.

3 Proiectarea programului
Pentru implementarea programului s-au folosit urmatoarele funcii:
void citire_imagine() citete informaia din fiierul text n care se afl matricea imaginii
void afisare()

afieaz imaginea

int findSeed()

gsete coordonatele pixelului seed i returneaz 0 dac nu mai exist


nicio regiune nou

void mark4(int val, int iseed, int jseed)

marcheaz o regiune cu valoarea val pornind de la


pixelul seed

int nay4(int i, int j) returneaz pixelii tetra-conectai cu pixelul [i][j]


int naz8(inti, int j) returneaz pixelii octo-conectai cu pixelul [i][j]
float perimeter(int reg) calculeaz i returneaz valoarea perimetrului regiunii marcate cu
valoarea reg

Pentru a determina coordonatele pixelului seed se execut urmtorii pai: parcurgem matricea
imaginii, cnd se determina primul pixel cu valoarea 1 cutarea se oprete i se reine poziia
pixelului. Funcia returneaz valoarea 0 dac nu mai exist regiuni noi.

int findSeed()
{
5

int x=0;
int p;
for( i=1;i<=n;i++)
{
for( j=1;j<=m;j++)
{
p = imag[i][j];
if(p == 1)
{
iSeed=i;
jSeed=j;
x++;
break;
}
}
if(p == 1)
break;
}
return x; // daca x=0 atunci nu mai exista regiuni noi
}
Pentru a marca regiunea pentru care vom calcula perimetrul, folosim funcia mark4 care va
marca cu valoarea val toi pixelii din regiunea pentru care urmeaz s calculm perimetrul,
ncepnd de la pixelul de coordonate [iseed][jseed].
void mark4(int c, int iseed, int jseed)
{
if(imag[iseed - 1][jseed] == 1)
{
imag[iseed - 1][jseed] = c;
mark4(c, iseed - 1, jseed);
}
if(imag[iseed][jseed + 1] == 1)
{
imag[iseed][jseed + 1] = c;
mark4(c, iseed, jseed + 1);
}
if(imag[iseed + 1][jseed] == 1)
{
imag[iseed + 1][jseed] = c;
mark4(c, iseed + 1, jseed);
6

}
if(imag[iseed][jseed - 1] == 1)
{
imag[iseed][jseed - 1] = c;
mark4(c, iseed, jseed - 1);
}
}
Pentru a marca pixelii regiunii care nu fac parte din linia perimetrului i care sunt tetra-conectai
vom folosi funcia nay4. Aceasta verific pixelii tetra-conectai cu pixelul de coordonate [i][j] i
va returna numrul vecinilor. Dac numrul este 4, adic sunt 4 pixeli tetra-conectai, nseamn
ca pixelul nu face parte din linia perimetrului i l marcheaz pentru tergere.
int nay4(int i,int j)
{

// returneaza numarul pixelilor tetraconectati cu pixelul de coordonate [i][j]

if(imag[i-1][j] != 0)
nr++;
if(imag[i][j+1] != 0)
nr++;
if(imag[i+1][j] != 0)
nr++;
if(imag[i][j-1] != 0)
nr++;
return nr;
}
Pentru a marca pixelii regiunii care nu fac parte din linia perimetrului i care sunt octo-conectai
vom folosi funcia nay4. Aceasta verific pixelii octo-conectai cu pixelul de coordonate [i][j] i
va returna numrul vecinilor. Dac numrul este 8, adic sunt 8 pixeli octo-conectai, nseamn
ca pixelul nu face parte din linia perimetrului i l marcheaz pentru tergere.
int nay8(int i,int j)
{
int nr=0;
if(imag[i-1][j] != 0)
nr++;
if(imag[i][j+1] != 0)
nr++;
if(imag[i+1][j] != 0)
nr++;
7

if(imag[i][j-1] != 0)
nr++;
if(imag[i-1][j-1] != 0)
nr++;
if(imag[i-1][j+1] != 0)
nr++;
if(imag[i+1][j+1] != 0)
nr++;
if(imag[i+1][j-1] != 0)
nr++;
return nr;
}
Pentru a calcula perimetrul regiunii folosim funcia perimeter(int reg). n cazul n care avem o
regiune tetra-conectat, folosind funcia nay4 vom marca pixelii care nu fac parte din linia
perimetrului i i vom terge. Se testeaz fiecare pixel al perimetrului pentru a determina
ponderea cu care va participa la calculul perimetrului, n funcie de tipul vecinilor pixelului. n
final se nsumeaz toate aceste contribuii individuale ale pixelilor i valoarea obinut este o
valoare aproximativ a perimetrului
float perimeter(int reg)
{
for( i=1;i<=n;i++)
for( j=1;j<=m;j++)
if(imag[i][j]==reg)
if(nay8(i,j)==8) //nu apartine conturului
imag[i][j]=1; // marcam cu val 1 pentru a vedea pixelii care nu fac parte din perimetru
printf("\n Linia perimetrului = 2, interiorul cercului =1");
afisare();
for( i=1;i<=n;i++)
for( j=1;j<=m;j++)
if(imag[i][j]== 1)
imag[i][j]=0; // se sterg pixelii care nu apartin liniei perimetrului
printf("\n Pixelii care nu apartineau liniei perimetrului au fost stersi");
afisare();
float suma;
suma = 0.0;
for( i=1;i<=n;i++)
for( j=1;j<=m;j++)
{
int vo=0; //vecini verticala-orizontala
8

int d=0; //vecini pe diagonala


if(imag[i][j]==reg)
{
if(imag[i-1][j]==imag[i][j]) vo++;
if(imag[i+1][j]==imag[i][j]) vo++;
if(imag[i][j-1]==imag[i][j]) vo++;
if(imag[i][j+1]==imag[i][j]) vo++;
if(imag[i-1][j-1]==imag[i][j]) d++;
if(imag[i-1][j+1]==imag[i][j]) d++;
if(imag[i+1][j-1]==imag[i][j]) d++;
if(imag[i+1][j+1]==imag[i][j]) d++;
if (vo==2)
suma = suma + 1; //pondere 1 avem doar vecini pe oriz/verticala
if (d==2)
suma = suma + 1.414; //pondere sqrt(2) avem doar pe diagonala
if ((vo==1) && (d >=1))
suma = suma + 1.2; //pondere 0.5+sqrt(2)/2, unul pe diag unul pe oriz/vert
}
}
return suma;
}

4 Rularea programului
Pentru a arta cum funcioneaz procedura perimeter vom lua exemplul discului cu D=17 i
regiune octo-conectat. Citirea se va face din fiierul cerc.txt. Coninutul acestui fiier este:
9

19 19
0000000000000000000
0000000111110000000
0000011111111100000
0001111111111111000
0001111111111111000
0011111111111111100
0011111111111111100
0111111111111111110
0111111111111111110
0111111111111111110
0111111111111111110
0111111111111111110
0011111111111111100
0011111111111111100
0001111111111111000
0001111111111111000
0000011111111100000
0000000111110000000
0000000000000000000
Pentru aceast imagine se va calcula perimetrul, folosind procedurile prezentate mai sus.
n momentul n care selectm Run programul va afia regiunea pentru care calculm perimetrul
(fig. 4),regiunea marcat cu valoarea 2 (fig. 5) i linia perimetrului pentru care s-a calculat
perimetrul (fig. 6), n acest exemplu fiind o regiune tetra-conectat.

Fig. 4 Imagine iniial

10

Fig. 5 Regiune marcat

Fig. 6 Calculul perimetrului

11

5 Codul surs
#include<process.h>
#include<conio.h>
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
FILE *f; //fisierul in care pastram imaginea binara
int n,m; //dimensiunile imaginii
int imag[25][25]; //matricea imaginii
int iSeed,jSeed; // coordonatele pixelului Seed
int markval; // valoarea cu care se marcheaza pixelii regiunii
int reg; // regiunea pentru care trebuie sa calculam perimetrul
int i,j,opt,val;
void citire_imagine()
{
if((f = fopen("cerc.txt","r"))==NULL)
printf("\n Fisierul nu a fost deschis!");
fscanf(f,"%d",&n);
fscanf(f,"%d",&m);
for( i=1;i<=n;i++)
for( j=1;j<=m;j++)
fscanf(f,"%d",&imag[i][j]);
fclose(f);
}
void afisare()
{
printf("\n");
for( i=1;i<=n;i++)
{
for( j=1;j<=m;j++)
printf("%d ", imag[i][j]);
printf("\n");
}
}
// functia determina primul pixel al regiunii
int findSeed()
{
12

int x=0;
int p;
for( i=1;i<=n;i++)
{
for( j=1;j<=m;j++)
{
p = imag[i][j];
if(p == 1)
{
iSeed=i;
jSeed=j;
x++;
break;
}
}
if(p == 1)
break;
}
return x; // daca x=0 atunci nu mai exista regiuni noi
}
//marcheaza regiunea cu val c
void mark4(int c, int iseed, int jseed)
{
if(imag[iseed - 1][jseed] == 1)
{
imag[iseed - 1][jseed] = c;
mark4(c, iseed - 1, jseed);
}
if(imag[iseed][jseed + 1] == 1)
{
imag[iseed][jseed + 1] = c;
mark4(c, iseed, jseed + 1);
}
if(imag[iseed + 1][jseed] == 1)
{
imag[iseed + 1][jseed] = c;
mark4(c, iseed + 1, jseed);
}
if(imag[iseed][jseed - 1] == 1)
{
imag[iseed][jseed - 1] = c;
13

mark4(c, iseed, jseed - 1);


}
}
int nay4(int i,int j) // returneaza numarul pixelilor tetraconectati cu pixelul de coordonate [i][j]
{
int nr=0;
if(imag[i-1][j] != 0)
nr++;
if(imag[i][j+1] != 0)
nr++;
if(imag[i+1][j] != 0)
nr++;
if(imag[i][j-1] != 0)
nr++;
return nr;
}
int nay8(int i,int j) //returneaza pixelii octo-conectati
{
int nr=0;
if(imag[i-1][j] != 0)
nr++;
if(imag[i][j+1] != 0)
nr++;
if(imag[i+1][j] != 0)
nr++;
if(imag[i][j-1] != 0)
nr++;
if(imag[i-1][j-1] != 0)
nr++;
if(imag[i-1][j+1] != 0)
nr++;
if(imag[i+1][j+1] != 0)
nr++;
if(imag[i+1][j-1] != 0)
nr++;
return nr;
}
14

float perimeter(int reg)


{
for( i=1;i<=n;i++)
for( j=1;j<=m;j++)
if(imag[i][j]==reg)
if(nay4(i,j)==4) //nu apartine conturului
imag[i][j]=1; // pentru a nu pierde din pixeli
for( i=1;i<=n;i++)
for( j=1;j<=m;j++)
if(imag[i][j]== 1)
imag[i][j]=0; // se sterg pixeli care nu apartin perimetrului
printf("\n \n Calculul perimetrului pentru regiunea octo-conectata");
afisare();
float suma;
suma = 0;
for( i=1;i<=n;i++)
for( j=1;j<=m;j++)
{
int vo=0; //vecini verticala-orizontala
int d=0; //vecini pe diagonala
if(imag[i][j]==reg)
{
if(imag[i-1][j]==imag[i][j]) vo++;
if(imag[i+1][j]==imag[i][j]) vo++;
if(imag[i][j-1]==imag[i][j]) vo++;
if(imag[i][j+1]==imag[i][j]) vo++;
if(imag[i-1][j-1]==imag[i][j]) d++;
if(imag[i-1][j+1]==imag[i][j]) d++;
if(imag[i+1][j-1]==imag[i][j]) d++;
if(imag[i+1][j+1]==imag[i][j]) d++;
if (vo==2)
suma = suma + 1; //pondere 1
if (d==2)
suma = suma + 1.414; //pondere sqrt(2)
if ((vo==1) && (d >=1))
suma = suma + 1.2; //pondere 0.5+sqrt(2)/2
}
}
return suma;
}
15

void main()
{clrscr();
citire_imagine();
printf("\n Matricea pentru care calculam perimetrul este:\n\n");
afisare();
int copie;
for(int i = 1;i <= n;i++)
{
for(int j = 1;j <= m;j++)
{
copie = imag[i][j];
if (copie == 1)
{
iSeed = i;
jSeed = j;
break;
}
}
if (copie == 1)
break;
}
printf("\n\n\n Regiunea a fost marcata cu valoarea 2");
mark4(2,iSeed,jSeed);
afisare();
float p;
p = perimeter(2);
printf("\n\nPerimetrul regiunii este: %2.f", p);
getch();

7 Mod de utilizare al aplicaiei


16

Pentru a rula aplicaia se efectueaz urmtorii pai:


1. Se introduce CD-ul n unitatea optic a calculatorului.
2. Se copiaz de pe CD fiierul surs perimetr.cpp i fiierul text n care se afl imaginea de
test cerc.txt ntr-un director de lucru la alegere.
3. Se lanseaz mediul de programare Turbo C++.
4. Din meniul File Open File se ncarc fiierul surs din directorul n care s-a salvat.
5. Din meniul Debug Run se ruleaz aplicaia.

8 Anex
17

Exemplu de rulare pentru regiune octo-conectat.

18

S-ar putea să vă placă și