2017-12-01 5 views
2

ich große .pgm Bilder in C. Die Bilder zu verarbeiten versuchen zuerst im Format Bild zu lesen, als Matrizen unsigned char Elemente:Transponieren von Groß und Narrow Bildern in C

struct Matrix{ 
    int rows; 
    int cols; 
    unsigned char * data; 
    int widthStep; 
}; 
typedef struct Matrix Image; 

I bin mit der folgenden Funktion die Bilder, mit netpbm (netpbm/pam.h) zu lesen:

Image * loadPBM(char * fname){ 
    FILE * file; 
    struct pam inpam; 
    tuple * tuplerow; 
    unsigned int row; 
    Image * image; 
    int aux; 

    file=fopen(fname,"r"); 
    pnm_readpaminit(file, &inpam, /*PAM_STRUCT_SIZE(tuple_type)*/ 
    sizeof(struct pam)); 

    printf("Reading image\n"); 

    /* allocating image*/ 
    image=(Image*)malloc(sizeof(Image)); 
    image->cols=inpam.width; 
    image->rows=inpam.height; 
    image->widthStep=image->cols; 
    aux=image->cols & 0x3; 
    if (aux!=0){ 
    image->widthStep+=4-aux; 
    } 
    image->data=(unsigned char *)malloc(image->widthStep*image->rows); 

    tuplerow = pnm_allocpamrow(&inpam); 

    for (row = 0; row < inpam.height; row++) { 
    unsigned int column; 
    pnm_readpamrow(&inpam, tuplerow); 
    for (column = 0; column < inpam.width; ++column) { 
     unsigned int plane; 
     for (plane = 0; plane < inpam.depth; ++plane) { 
     image->data[image->widthStep*row+column]= tuplerow[column][plane]; 
      } 
     } 
     } 

    pnm_freepamrow(tuplerow); 
    fclose(file); 
    return image; 

} 

nach gelesen wird, werden die Bilder in das Format ImageF übersetzt werden, so dass ich die Elemente als Doppel verarbeiten kann Als solche:

struct MatrixF{ 
    int rows; 
    int cols; 
    double * data; 
    int widthStep; 
}; 
typedef struct MatrixF ImageF; 

Translation Bild ImageF:

for (int i = 0; i < in_img->rows; ++i){ 

    for (int j = 0; j < in_img->cols; ++j){ 

     in_aux->data[i*(in_img->cols)+j] = (double)in_img->data[i*(in_img->cols)+j]; 
    } 
} 

Für die eigentliche Bildverarbeitung muss ich die Bilder umsetzen, so habe ich die folgende Funktion geschrieben:

void transpose(ImageF *in_re, ImageF *out_re){ 

    int rows = in_re->rows; 
    int cols = in_re->cols; 

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

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

      out_re->data[j*rows+i] = in_re->data[i*cols+j]; 
     } 
    } 

    out_re->rows = in_re->cols; 
    out_re->cols = in_re->rows; 

    out_re->widthStep = out_re->cols * sizeof(double); 
} 

Nach dem Transponieren werden die Bilder von ImageF nach Image zurückübersetzt, um die Ergebnisse zu speichern (konvertieren Sie Double in vorzeichenloses Zeichen):

double val; 
    for (int i = 0; i < out_aux->rows; i++){ 

     for (int j = 0; j < out_aux->cols; j++){ 

      val = out_aux->data[i*out_aux->cols + j];///((in_img->rows)*(in_img->cols)); 

      if (val < 0) 
       val = 0.0; 
      else if (val > 255) 
       val = 255.0; 
      out_img->data[i * out_aux->cols + j] = (unsigned char)val; 
     } 
    } 

Und schließlich werden sie mit der folgenden Funktion gespeichert:

void savePBM(char * fname, Image * image){ 
    FILE * file; 
    struct pam outpam; 
    tuple * tuplerow; 
    unsigned int row; 

    int aux; 

    file=fopen(fname,"w"); 
    outpam.file=file; 
    outpam.size=sizeof(struct pam); 
    outpam.len=sizeof(struct pam); 
    outpam.format=RPGM_FORMAT; 
    outpam.plainformat=0; 
    outpam.height=image->rows; 
    outpam.width=image->cols; 
    outpam.depth=1; 
    outpam.maxval=255; 
    strcpy(outpam.tuple_type,PAM_PGM_TUPLETYPE); 

    pnm_writepaminit(&outpam); 

    printf("Writing image\n"); 

    tuplerow = pnm_allocpamrow(&outpam); 

    for (row = 0; row < outpam.height; row++) { 
    unsigned int column; 
    for (column = 0; column < outpam.width; ++column) { 
     unsigned int plane; 
     for (plane = 0; plane < outpam.depth; ++plane) { 
    tuplerow[column][plane]=image->data[image->widthStep*row+column]; 
     } 
    } 
    pnm_writepamrow(&outpam, tuplerow); 
    } 

    pnm_freepamrow(tuplerow); 
    fclose(file); 
} 

Bildspeicherplatzzuweisung ich es richtig gemacht glauben, nachdem das Eingangsbild mit loadPBM Laden, als solche:

out_img = (Image *)malloc(sizeof(Image)); 
    out_img->rows = in_img->cols; 
    out_img->cols = in_img->rows; 
    out_img->widthStep = out_img->cols * sizeof(unsigned char); 
    out_img->data = (unsigned char *)malloc((out_img->rows)*(out_img->cols)*sizeof(unsigned char)); 

/*Auxiliary variables*/ 
in_aux = (ImageF *)malloc(sizeof(ImageF)); 
    in_aux->rows = in_img->rows; 
    in_aux->cols = in_img->cols; 
    in_aux->widthStep = in_aux->cols * sizeof(double); 
    in_aux->data = (double *)malloc((in_aux->rows)*(in_aux->cols)*sizeof(double)); 

out_aux = (ImageF *)malloc(sizeof(ImageF)); 
    out_aux->rows = in_img->rows; 
    out_aux->cols = in_img->cols; 
    out_aux->widthStep = out_aux->cols * sizeof(double); 
    out_aux->data = (double *)malloc((out_aux->rows)*(out_aux->cols)*sizeof(double)); 

Aus irgendeinem Grund funktioniert dies gut für quadratische Bilder oder sogar Bilder mit einer Auflösung von ca. 450x700. Aber wenn Bilder schmaler werden (zum Beispiel 170x500), funktioniert dieser Algorithmus nicht mehr richtig. Bilder werden verzerrt, und ich habe keine Ahnung warum, denn sie funktioniert für andere nicht-quadratische Matrizen, die nicht so schmal sind. Wenn jemand sehen kann, wo ich falsch gelaufen bin oder einen Rat oder etwas hat, wäre es sehr geschätzt!

Vielen Dank im Voraus!

+0

Wirklich funktionieren, sind alle Ideen willkommen Jungs – Vylst

Antwort

0

Nach einiger Mahl- und Diskussion mit a good friend, haben wir herausgefunden, dass die Polsterung von der Funktion loadPBM eingefügt, für Speicherausrichtung, diesen Abschnitt:

aux=image->cols & 0x3; 
    if (aux!=0){ 
    image->widthStep+=4-aux; 
    } 

wurde das Schreiben von Bytes an jedem Matrixelement verursacht zu gehen überbord zum nächsten Element, für Bilder, deren Breite nicht ein Vielfaches von 4 ist, verzerren sie, aufgrund der Änderung ihrer BreiteStep. Das erklärt, warum der Algorithmus für einige nichtquadratische Matrizen funktioniert hat, aber nicht für alle. Für diejenigen, die den Beitrag gesehen haben und sich auch gefragt haben, warum das passiert ist, hoffe das hilft! Sie können nur diese zusätzliche Polsterung entfernen, und es wird wie ein Charme