I think I fixed zones detection, still got memory leak

This commit is contained in:
Phuntsok Drak-pa 2018-11-24 21:33:47 +01:00
parent 0f1b59b159
commit a27a31a0ae
No known key found for this signature in database
GPG Key ID: 9CB34B6827C66D22
9 changed files with 74 additions and 111 deletions

2
.gitignore vendored
View File

@ -3,3 +3,5 @@ build
debug debug
!.gitignore !.gitignore
*.out *.out
\.idea/
cmake-build-debug/

View File

@ -11,7 +11,7 @@
* *
* \param[in] t_pixel Pointeur vers le pixel dont léligibilité est testée * \param[in] t_pixel Pointeur vers le pixel dont léligibilité est testée
* \param[in] t_zone Zone à laquelle le pixel est éligible ou non * \param[in] t_zone Zone à laquelle le pixel est éligible ou non
* \return Valeur booléenne, `true` si le pixel est éligible, `false` sinon * \return Valeur booléenne, `1` si le pixel est éligible, `0` sinon
*/ */
bool sameColor(Pixel* t_pixel, Zone* t_zone) { bool sameColor(Pixel* t_pixel, Zone* t_zone) {
return t_pixel->r == t_zone->r && t_pixel->g == t_zone->g && return t_pixel->r == t_zone->r && t_pixel->g == t_zone->g &&
@ -31,31 +31,42 @@ bool sameColor(Pixel* t_pixel, Zone* t_zone) {
* \param[in] t_idx Index du pixel actuel dans limage `t_img` * \param[in] t_idx Index du pixel actuel dans limage `t_img`
* \param[out] t_zone Zone à laquelle sera potentiellement ajouté le pixel * \param[out] t_zone Zone à laquelle sera potentiellement ajouté le pixel
*/ */
void addPixelToSelectedZone(Image* t_img, int t_idx, Zone* t_zone) { void addPixelToSelectedZone(Image *t_img, long t_idx, Zone *t_zone) {
Pixel *current_pixel = darrayGet(t_img->pixels, t_idx); const size_t img_size = darraySize(t_img->pixels);
int xd, xg, y = t_idx / (int)t_img->x; Pixel *current_pixel;
if (t_idx >= (int)darraySize(t_img->pixels) || const uint32_t y = (uint32_t)(t_idx / t_img->x);
t_idx < 0 || !sameColor(current_pixel, t_zone)) { long left_limit, right_limit;
const long xd_limit = (long)t_img->x * (y + 1);
if (t_idx >= (long)img_size || t_idx < 0) {
return; return;
} }
(*current_pixel).visited = true; current_pixel = darrayGet(t_img->pixels, (size_t)t_idx);
for(xd = t_idx; xd % (int)t_img->x != 0; ++xd) { /* fetch right limit of segment */ if (current_pixel->visited || !sameColor(current_pixel, t_zone)) {
current_pixel = darrayGet(t_img->pixels, xd); return;
if(!sameColor(current_pixel, t_zone)) {
break;
}
(*current_pixel).visited = true;
} }
for(xg = t_idx; xg - y >= 0; --xg) { /* fetch right limit of segment */ (*current_pixel).visited = 1;
current_pixel = darrayGet(t_img->pixels, xd); for (right_limit = t_idx; right_limit < xd_limit; ++right_limit) {
if(current_pixel->visited || !sameColor(current_pixel, t_zone)) { current_pixel = darrayGet(t_img->pixels, (size_t)right_limit);
if (!sameColor(current_pixel, t_zone)) {
break; break;
} }
(*current_pixel).visited = true; current_pixel->visited = 1;
}
for (left_limit = t_idx; left_limit - (y - 1) * (long)t_img->x >= 0;
--left_limit) { /* fetch right limit of segment */
current_pixel = darrayGet(t_img->pixels, (size_t)left_limit);
if (current_pixel->visited || !sameColor(current_pixel, t_zone)) {
break;
}
(*current_pixel).visited = 1;
} }
/* Add segment to its zone */ /* Add segment to its zone */
darrayPushBack(t_zone->segments, newSegment(xd, xg)); darrayPushBack(t_zone->segments,
for(; xg <= xd; ++xg) { /* process every pixel up and down the segment */ newSegment((uint32_t)right_limit, (uint32_t)left_limit));
for (; left_limit <= right_limit;
++left_limit) { /* process every pixel up and down the segment */
addPixelToSelectedZone(t_img, t_idx + t_img->x, t_zone); addPixelToSelectedZone(t_img, t_idx + t_img->x, t_zone);
} }
} }
@ -69,12 +80,12 @@ void addPixelToSelectedZone(Image* t_img, int t_idx, Zone* t_zone) {
* \param[in] t_idx Index du pixel à tester * \param[in] t_idx Index du pixel à tester
* \param[out] t_zones Liste des zones de limage * \param[out] t_zones Liste des zones de limage
*/ */
void chooseZoneForPixel(Image* t_img, int t_idx, darray *zones) { void chooseZoneForPixel(Image *t_img, long t_idx, darray *zones) {
Zone* current_zone; Zone *current_zone;
Pixel* pixel; Pixel *pixel;
size_t i; size_t i;
pixel = darrayGet(t_img->pixels, t_idx); pixel = darrayGet(t_img->pixels, (size_t)t_idx);
/* if the pixel has already been visited, no need to continue */ /* if the pixel has already been visited, no need to continue */
if (pixel->visited) { if (pixel->visited) {
return; return;
@ -82,7 +93,7 @@ void chooseZoneForPixel(Image* t_img, int t_idx, darray *zones) {
/* for each known zone, see if it matches the current pixel's color */ /* for each known zone, see if it matches the current pixel's color */
for (i = 0; i < darraySize(zones); ++i) { for (i = 0; i < darraySize(zones); ++i) {
current_zone = darrayGet(zones, i); current_zone = darrayGet(zones, i);
/* if it does, add selected pixel and its neighbourging pixels of the same /* if it does, add selected pixel and its neighbouring pixels of the same
* color */ * color */
if (sameColor(pixel, current_zone)) { if (sameColor(pixel, current_zone)) {
addPixelToSelectedZone(t_img, t_idx, current_zone); addPixelToSelectedZone(t_img, t_idx, current_zone);
@ -103,14 +114,14 @@ void chooseZoneForPixel(Image* t_img, int t_idx, darray *zones) {
* \param t_img Image à convertir en zones * \param t_img Image à convertir en zones
* \return Pointeur vers un \ref darray de structures \ref Zone * \return Pointeur vers un \ref darray de structures \ref Zone
*/ */
darray* imgToZones(Image* t_img) { darray *imgToZones(Image *t_img) {
darray *zones; darray *zones;
const size_t nb_pixels = darraySize(t_img->pixels); const size_t nb_pixels = darraySize(t_img->pixels);
size_t i; long i;
zones = darrayNew(sizeof(Zone)); zones = darrayNew(sizeof(Zone));
/* for each pixel, try to create a new zone */ /* for each pixel, try to create a new zone */
for (i = 0; i < nb_pixels; ++i) { for (i = 0; i < (long)nb_pixels; ++i) {
chooseZoneForPixel(t_img, i, zones); chooseZoneForPixel(t_img, i, zones);
} }
return zones; return zones;
@ -125,28 +136,16 @@ darray* imgToZones(Image* t_img) {
void compress(const char *t_input_file) { void compress(const char *t_input_file) {
Image *img; Image *img;
darray *zones; darray *zones;
Zone *current_zone;
size_t i; size_t i;
img = newImage(); img = newImage();
imageLoadPPM(t_input_file, img); imageLoadPPM(t_input_file, img);
zones = imgToZones(img); zones = imgToZones(img);
/* print segments for debug ************************************************/
DEBUG {
printf("Detected %zu zones\n", darraySize(zones));
for (i = 0; i < darraySize(zones); ++i) {
Zone *zone = darrayGet(zones, i);
printf("\n=== Zone %zu (%d %d %d) ===\n", i, zone->r, zone->g, zone->b);
for (size_t j = 0; j < darraySize(zone->segments); ++j) {
Segment *segm = darrayGet(zone->segments, j);
printf("[%zu: %d, %d]\t", segm->xg / img->x, segm->xg, segm->xd);
}
}
printf("\n");
}
deleteImage(img); deleteImage(img);
for(i = 0; i < darraySize(zones); ++i) { for(i = 0; i < darraySize(zones); ++i) {
deleteZoneContent(darrayGet(zones, i)); current_zone = darrayGet(zones, i);
darrayDelete(current_zone->segments);
} }
darrayDelete(zones); darrayDelete(zones);
} }

View File

@ -11,9 +11,9 @@
/// Teste léligibilité dun pixel à une zone /// Teste léligibilité dun pixel à une zone
bool sameColor(Pixel *t_pixel, Zone *t_zone); bool sameColor(Pixel *t_pixel, Zone *t_zone);
/// Ajoute un pixel et ses pixels connexes à une zone /// Ajoute un pixel et ses pixels connexes à une zone
void addPixelToSelectedZone(Image *t_img, int t_idx, Zone *t_zone); void addPixelToSelectedZone(Image *t_img, long t_idx, Zone *t_zone);
/// Sélectionne la zone correspondant à la couleur d'un pixel /// Sélectionne la zone correspondant à la couleur d'un pixel
void chooseZoneForPixel(Image *t_img, int t_idx, darray *zones); void chooseZoneForPixel(Image *t_img, long t_idx, darray *zones);
/// Créé les zones d'une image /// Créé les zones d'une image
darray *imgToZones(Image *t_img); darray *imgToZones(Image *t_img);
/// Compresse l'image d'entrée /// Compresse l'image d'entrée

View File

@ -44,8 +44,7 @@ void darrayInsert(darray *t_self, void *t_pos, void *t_elem) {
darrayExtend(t_self); darrayExtend(t_self);
} }
itr = (char *)t_self->begin + pos_aux; itr = (char *)t_self->begin + pos_aux;
memmove(itr + t_self->element_size, itr, memmove(itr + t_self->element_size, itr, ((char *)t_self->end - itr));
(unsigned long)((char *)t_self->end - itr));
memcpy(itr, t_elem, t_self->element_size); memcpy(itr, t_elem, t_self->element_size);
(*t_self).end = (char *)t_self->end + t_self->element_size; (*t_self).end = (char *)t_self->end + t_self->element_size;
} }
@ -84,8 +83,7 @@ void darrayExtend(darray *t_self) {
*/ */
void darrayErase(darray *t_self, void *t_pos) { void darrayErase(darray *t_self, void *t_pos) {
memmove(t_pos, (char *)t_pos + t_self->element_size, memmove(t_pos, (char *)t_pos + t_self->element_size,
(unsigned long)(((char *)t_self->end - t_self->element_size) - (((char *)t_self->end - t_self->element_size) - (char *)t_pos));
(char *)t_pos));
(*t_self).end = (char *)t_self->end - t_self->element_size; (*t_self).end = (char *)t_self->end - t_self->element_size;
} }
@ -144,6 +142,11 @@ size_t darraySize(darray* t_self) {
* \return Pointeur de type `void*` pointant sur lélément si lindex est valide, sur NULL sinon. * \return Pointeur de type `void*` pointant sur lélément si lindex est valide, sur NULL sinon.
*/ */
void *darrayGet(darray* t_self, size_t t_idx) { void *darrayGet(darray* t_self, size_t t_idx) {
if(t_idx >= darraySize(t_self)) {
fprintf(stderr, "Error in `darrayGet`, out of bound idx: %zu (max: %zu)\n",
t_idx, darraySize(t_self));
exit(PTR_ERROR);
}
void *itr; void *itr;
itr = (char *)t_self->begin + t_idx * t_self->element_size; itr = (char *)t_self->begin + t_idx * t_self->element_size;
return itr; return itr;

View File

@ -9,6 +9,7 @@
#define PTR_ERROR 2 #define PTR_ERROR 2
/// Constante pour les erreurs liées à la lecture et écriture de fichiers /// Constante pour les erreurs liées à la lecture et écriture de fichiers
#define FILE_IO_ERROR 3 #define FILE_IO_ERROR 3
/// Constante pour les erreurs liées au format de fichiers
#define FILE_FORMAT_ERROR 4 #define FILE_FORMAT_ERROR 4
#endif /* ERRORCODES_H */ #endif /* ERRORCODES_H */

View File

@ -8,7 +8,7 @@
* des fonctions cœures du programme. * des fonctions cœures du programme.
*/ */
#include "common.h" #include "compress.h"
#include <getopt.h> #include <getopt.h>
#include <string.h> #include <string.h>
@ -49,7 +49,7 @@ Options available:\n\
struct Argres { struct Argres {
char *input; /*!< Nom du fichier d'entrée */ char *input; /*!< Nom du fichier d'entrée */
char *output; /*!< Nom du fichier de sortie */ char *output; /*!< Nom du fichier de sortie */
bool compress; /*!< Le fichier d'entrée doit-il être compressé ? */ char compress; /*!< Le fichier d'entrée doit-il être compressé ? */
}; };
typedef struct Argres Argres; typedef struct Argres Argres;
@ -62,14 +62,14 @@ typedef struct Argres Argres;
* \param[out] t_args Result of the arguments processing * \param[out] t_args Result of the arguments processing
* \param[in] t_c Switch or option passed * \param[in] t_c Switch or option passed
*/ */
void get_args(Argres *t_args, int *t_c) { void get_args(Argres *t_args, const int * const t_c) {
switch (*t_c) { switch (*t_c) {
case 0: break; case 0: break;
case 'h': help(NOERROR); break; case 'h': help(NOERROR); break;
case 'i': (*t_args).input = optarg; break; case 'i': (*t_args).input = optarg; break;
case 'o': (*t_args).output = optarg; break; case 'o': (*t_args).output = optarg; break;
case 'c': (*t_args).compress = true; break; case 'c': (*t_args).compress = 1; break;
case 'u': (*t_args).compress = false; break; case 'u': (*t_args).compress = 0; break;
case '?': case '?':
default: help(ARGERROR); default: help(ARGERROR);
} }
@ -91,8 +91,9 @@ void get_args(Argres *t_args, int *t_c) {
Argres process_args(const int t_argc, char *t_argv[]) { Argres process_args(const int t_argc, char *t_argv[]) {
Argres res; Argres res;
res.input = NULL; res.input = NULL;
res.compress = 1;
res.output = "output.su"; res.output = "output.su";
while (true) { while (1) {
int option_index = 0; int option_index = 0;
static struct option long_options[] = { static struct option long_options[] = {
{"help", no_argument, NULL, 'h'}, {"input", required_argument, NULL, 'i'}, {"help", no_argument, NULL, 'h'}, {"input", required_argument, NULL, 'i'},

View File

@ -119,7 +119,7 @@ unsigned long read_data(FILE *t_fp, Image *t_img, unsigned char **t_data,
/* read pixel data from file */ /* read pixel data from file */
if (!fread(*t_data, (size_t)1, (size_t)size, t_fp)) { if (!fread(*t_data, (size_t)1, (size_t)size, t_fp)) {
fprintf(stderr, "Error loading image '%s'\n", t_filename); fprintf(stderr, "Error loading image '%s'\n", t_filename);
free(t_data); free(*t_data);
exit(FILE_IO_ERROR); exit(FILE_IO_ERROR);
} }
return size; return size;
@ -190,6 +190,7 @@ int imageLoadPPM(const char *t_filename, Image *t_img) {
read_rgb(fp, t_filename); /* read rgb component */ read_rgb(fp, t_filename); /* read rgb component */
size = read_data(fp, t_img, &data, t_filename); /* read data from file */ size = read_data(fp, t_img, &data, t_filename); /* read data from file */
dataToImage(t_img, data, size); dataToImage(t_img, data, size);
free(data);
fclose(fp); fclose(fp);
return 1; return 1;
} }

View File

@ -28,16 +28,6 @@ Pixel *newPixel(uint8_t t_r, uint8_t t_g, uint8_t t_b) {
return res; return res;
} }
/**
* Destructeur dun pixel. Étant donné quun pixel ne contient aucune donnée
* pointée par un pointeur, la seule action de la fonction sera de libérer la
* mémoire pointée par le pointeur de pixel en lui-même et donc le pixel passé
* en argument.
*
* \param[in] self Pointeur vers le pixel à détruire
*/
void deletePixel(Pixel *t_self) { free(t_self); }
/** /**
* Constructeur dun conteneur dimage. Les dimensions sont initialisées à zéro * Constructeur dun conteneur dimage. Les dimensions sont initialisées à zéro
* (0) et son tableau de pixels a é créé et initialisé en tableau vide. Le * (0) et son tableau de pixels a é créé et initialisé en tableau vide. Le
@ -80,23 +70,13 @@ void deleteImage(Image *t_self) {
* \param[in] xg Abscisse extrême gauche du segment * \param[in] xg Abscisse extrême gauche du segment
* \return Pointeur sur un conteneur de segment * \return Pointeur sur un conteneur de segment
*/ */
Segment *newSegment(uint16_t t_xd, uint16_t t_xg) { Segment *newSegment(uint32_t t_xd, uint32_t t_xg) {
Segment *res; Segment *res = (Segment *)malloc(sizeof(Segment));
res = (Segment *)malloc(sizeof(Segment));
res->xd = t_xd; res->xd = t_xd;
res->xg = t_xg; res->xg = t_xg;
return res; return res;
} }
/**
* Destructeur de conteneur de segment. Les conteneurs de segments ne contenant
* pas de pointeur propriétaire de données, le destructeur libérera simplement
* de la mémoire le conteneur pointé par le pointeur passé en argument.
*
* \param[in] self Conteneur de segment à détruire
*/
void deleteSegment(Segment *t_self) { free(t_self); }
/** /**
* \brief function description * \brief function description
* *
@ -110,8 +90,7 @@ void deleteSegment(Segment *t_self) { free(t_self); }
* \return Pointeur vers la structure créée * \return Pointeur vers la structure créée
*/ */
Zone *newZone(uint8_t t_r, uint8_t t_g, uint8_t t_b) { Zone *newZone(uint8_t t_r, uint8_t t_g, uint8_t t_b) {
Zone *res; Zone *res = (Zone *)malloc(sizeof(Zone));
res = (Zone *)malloc(sizeof(Zone));
res->r = t_r; res->r = t_r;
res->g = t_g; res->g = t_g;
res->b = t_b; res->b = t_b;
@ -120,22 +99,11 @@ Zone *newZone(uint8_t t_r, uint8_t t_g, uint8_t t_b) {
} }
/** /**
* Destructeur de zone, libère de la mémoire les segments contenus dans le * Destructeur de zone, libère la zone mémoire utilisée pour stocker les
* tableau de segments, puis le tableau en lui-même pour ultimement libérer * segments. Ne libère pas \p t_self lui-même mais son membre `segments`.
* de la mémoire le conteneur de zone en lui-même pointé par le pointeur passé
* en argument du destructeur.
* *
* \param[in] self Conteneur de zone à détruire * \param[in] self Conteneur de zone à détruire
*/ */
void deleteZone(Zone *t_self) { void deleteZoneContent(Zone *t_self) {
unsigned long i;
for (i = 0; i < darraySize(t_self->segments); ++i) {
deleteSegment(darrayGet(t_self->segments, i));
}
darrayDelete(t_self->segments); darrayDelete(t_self->segments);
free(t_self); }
}
Pixel *imgAt(Image *t_img, int t_x, int t_y) {
return (Pixel *)darrayGet(t_img->pixels, t_x + t_y * t_img->x);
}

View File

@ -22,14 +22,8 @@
#ifdef Debug #ifdef Debug
#define DEBUG if (1) #define DEBUG if (1)
#define PDEB \
if (1) \
printf
#else #else
#define DEBUG if (0) #define DEBUG if (0)
#define PDBEF \
if (0) \
printf
#endif #endif
/*****************************************************************************/ /*****************************************************************************/
@ -74,7 +68,7 @@ struct Pixel {
uint8_t r; /*!< Couleur rouge du pixel */ uint8_t r; /*!< Couleur rouge du pixel */
uint8_t g; /*!< Couleur verte du pixel */ uint8_t g; /*!< Couleur verte du pixel */
uint8_t b; /*!< Couleur bleue du pixel */ uint8_t b; /*!< Couleur bleue du pixel */
bool visited; /*!< Le pixel a-t-il été visité avant */ unsigned char visited; /*!< Le pixel a-t-il été visité avant */
}; };
/** /**
@ -98,8 +92,8 @@ struct Zone {
* à son extrême droite et à son extrême gauche. * à son extrême droite et à son extrême gauche.
*/ */
struct Segment { struct Segment {
uint16_t xd; /*!< extrême droit du segment */ uint32_t xd; /*!< extrême droit du segment */
uint16_t xg; /*!< extrême gauche du segment */ uint32_t xg; /*!< extrême gauche du segment */
}; };
/*****************************************************************************/ /*****************************************************************************/
@ -108,21 +102,15 @@ struct Segment {
/// \brief Création dun nouveau pixel /// \brief Création dun nouveau pixel
Pixel *newPixel(uint8_t t_r, uint8_t t_g, uint8_t t_b); Pixel *newPixel(uint8_t t_r, uint8_t t_g, uint8_t t_b);
/// \brief Destruction dun pointeur de pixel
void deletePixel(Pixel *t_self);
/// \brief Création dune nouvelle image /// \brief Création dune nouvelle image
Image *newImage(); Image *newImage();
/// \brief Destructeur dune image /// \brief Destructeur dune image
void deleteImage(Image *t_self); void deleteImage(Image *t_self);
/// \brief Constructeur dun segment de couleur unie /// \brief Constructeur dun segment de couleur unie
Segment *newSegment(uint16_t t_xd, uint16_t t_xg); Segment *newSegment(uint32_t t_xd, uint32_t t_xg);
/// \brief Destructeur dun segment de couleur unie
void deleteSegment(Segment *t_self);
/// \brief Constructeur de conteneur de zone /// \brief Constructeur de conteneur de zone
Zone* newZone(uint8_t t_r, uint8_t t_g, uint8_t t_b); Zone* newZone(uint8_t t_r, uint8_t t_g, uint8_t t_b);
/// \brief Destructeur de conteneur de zone /// \brief Destructeur de conteneur de zone
void deleteZone(Zone *t_self); void deleteZoneContent(Zone *t_self);
/// \brief Renvoie un pixel aux coordonnées `(x, y)` dans une image
Pixel *imgAt(Image *t_img, int t_x, int t_y);
#endif /* UTILITIES_H */ #endif /* UTILITIES_H */