// *********************************************************************** // * FILE: convolucao2.c // * DATE: 25 August 2000 // * AUTHOR: Antonio Esteves, GEC-DI-UM // * // *********************************************************************** // * // * //// IMAGE CONVOLUTION WITH A SOBEL FILTER //// // * //// //// // * //// S/W PART OF THE HW/SW IMPLEMENTATION //// // * // *********************************************************************** #include "convolucao.h" #include // *********************************************************************** // * TASK: allocate memory to a data structure of type 'Image' with size // * (Xsize * Ysize). // * IN: image size // * OUT: pointer to the allocated memory or NULL if allocation failed // *********************************************************************** Image *CreateImage (WORD Xsize, WORD Ysize) { Image *img; img = (Image*) malloc(sizeof(Image)); if (img == NULL) return img; img->Xsize = Xsize; img->Ysize = Ysize; img->data = (BYTE *) malloc((long)Xsize * (long)Ysize * sizeof(BYTE)); if(img->data == NULL) { free(img); return NULL; } else return img; // return pointer to the allocated memory } // *********************************************************************** // * TASK: free memory allocated to a data structure of type 'Image'. // * IN: pointer to the data structure. // * OUT: none. // *********************************************************************** void DestroyImage(Image *img) { free(img->data); // free data free(img); // free pointer } // *********************************************************************** // * TASK: allocate memory to a data structure of type 'ImageSWORD' with // * (Xsize * Ysize) elements of type SWORD. // * IN: image size // * OUT: pointer to the allocated memory or NULL if allocation failed // *********************************************************************** ImageSWORD *CreateImageSWORD (WORD Xsize, WORD Ysize) { ImageSWORD *img; img = (ImageSWORD*) malloc(sizeof(ImageSWORD)); if (img == NULL) return img; img->Xsize = Xsize; img->Ysize = Ysize; img->data = (SWORD *) malloc((long)Xsize*(long)Ysize*sizeof(SWORD)); if(img->data == NULL) { free(img); return NULL; } else return img; // return pointer to the allocated memory } // *********************************************************************** // * TASK: free memory allocated for a data structure of type 'ImageSWORD' // * IN: pointer to the data structure. // * OUT: none. // *********************************************************************** void DestroyImageSWORD(ImageSWORD *img) { free(img->data); // free data free(img); // free pointer } // *********************************************************************** // * TASK: read from a file and store the read information into the data // structure Image // * IN: pointer to the string with file name // * OUT: pointer to the data structure Image or NULL if allocation // failed // *********************************************************************** Image* Readfile(BYTE *nome) { FILE *fp; WORD alt, lar; Image *img_r; fp = fopen(nome,"rb"); if(fp == NULL) { printf("\nError reading file %s !",nome); getchar(); return (NULL); } if(fread(&lar,sizeof(WORD),1,fp) != 1) { printf("\nError reading file %s !",nome); getchar(); fclose(fp); return (NULL); } if(fread((void*)&alt,sizeof(WORD),1,fp) != 1) { printf("\nError reading file %s !",nome); getchar(); fclose(fp); return (NULL); } img_r = CreateImage(lar,alt); if(img_r == NULL) { printf("\nNo space was allocated !"); getchar(); fclose(fp); return (NULL); } if(fread(img_r->data,img_r->Xsize,img_r->Ysize,fp) != img_r->Ysize) { printf("\nError reading file %s !",nome); getchar(); fclose(fp); return (NULL); } fclose(fp); return (img_r); } // *********************************************************************** // * TASK: save image into file // * IN: pointer to the data structure Image and pointer to the string // with file name // * OUT: 1 (success), 0 (failure) // *********************************************************************** int savefile(Image *img, BYTE *nome) { FILE *fp; fp = fopen(nome,"wb"); if(fp == NULL) { printf("Error opening file %s ! ",nome); return (0); } if(fwrite(&img->Xsize,sizeof(WORD),1,fp) != 1) { printf(" Error writing file %s ! ",nome); fclose(fp); return (0); } if(fwrite(&img->Ysize,sizeof(WORD),1,fp) != 1) { printf(" Error writing file %s ! ",nome); fclose(fp); return (0); } if(fwrite((void *)img->data,img->Xsize,img->Ysize,fp) != img->Ysize) { printf(" Error writing file %s ! ",nome); fclose(fp); return (0); } fclose(fp); return (1); } // *********************************************************************** // lines_in1,2,3,4: sinal onde se guardam 'maskY' parcelas (de 'maskY' // linhas diferentes) de tamanho 'colunas' da imagem // original, a usar na FPGA 1/2/3/4 e em cada iteracao da // convolucao. // line_out1,2,3,4: sinal onde se guarda uma parcela de linha (tamanho // 'colunas') da imagem convoluida, obtida em cada // iteracao do algoritmo de convolucao. // img_in: imagem original a convoluir (a ler dum ficheiro). // img_out: imagem resultante da convolucao nao normalizada (a // escrever num ficheiro). // tx: numero de colunas da imagem original. // ty: numero de linhas da imagem original. // maskY: numero de linhas da mascara a aplicar. // max: 4 valores maximos das convolucoes parcelares por // normalizar. // min: 4 valores minimos das convolucoes parcelares por // normalizar. // read_done: indica fim de leitura (dum ficheiro) da imagem a // processar. // write_done: indica fim de escrita (num ficheiro) da imagem // convoluida. // convol_done: 4 sinais que indicam fim de convolucao das 4 parcelas // da imagem. // max_global: sinal onde se guarda o maximo para toda a imagem // convoluida nao normalizada. // min_global: sinal onde se guarda o minimo para toda a imagem // convoluida nao normalizada. // conv1line_done: 4 semaforos que indicam que as 4 parcelas pertencentes // a uma linha de convolucao foram geradas (activados por // processa_convol()); por isso o seu armazenamento na // imagem convoluida pode iniciar-se. // wr_finished: semaforo que indica que uma linha da convolucao foi // escrita na imagem de saida (img_out); por isso uma // nova convolucao (que vai gera uma linha) pode // iniciar-se (tarefa executada por processa_convol()). // written3l: semaforo que indica que ja' estao disponiveis 'maskY' // parcelas de linha para ser convoluidas. // accept3l: semaforo que indica que a convolucao esta' pronta para // aceitar novas parcelas de linha para convolucao. // *********************************************************************** int read_write (EDGAR2A_HANDLE hEDGAR2A, EDGAR2A_ADDR e2addrSpace) { Image *img_in, *img_out2; ImageSWORD *img_out; SWORD max_global, min_global; SWORD max[5]; SWORD min[5]; WORD tx, ty, halfmaskY; int i, j, k, linha; int colunas; int colInicial1, colInicial2, colInicial3, colInicial4; DWORD valRead, val2send; SWORD val1, val2, val3, val4; SWORD tmp0, gama, fimg; float fesc; int tmp1, tmp2, tmp3, tmp4, tmp; // ****** optimization ******* //-------------------------------------------------------------------- // RESET H/W AND ORDER (RE)START CONVOLUTION PROCESS //-------------------------------------------------------------------- // Reset all h/w system EDGAR2A_WriteDword(hEDGAR2A, e2addrSpace, ADD_W_RESET_FF, TRUE_RESET_FF); // ***** HW WRITE ***** // Deassert the reset f/f EDGAR2A_WriteDword(hEDGAR2A, e2addrSpace, ADD_W_RESET_FF, FALSE_RESET_FF); // ***** HW WRITE ***** // Order to (re)start the convolution process EDGAR2A_WriteDword(hEDGAR2A, e2addrSpace, ADD_W_START_FSM, TRUE_START_FSM); // ***** HW WRITE ***** // Deassert the (re)start convolution f/f EDGAR2A_WriteDword(hEDGAR2A, e2addrSpace, ADD_W_START_FSM, FALSE_START_FSM); // ***** HW WRITE ***** //-------------------------------------------------------------------- // START THE CONVOLUTION PROCESS //-------------------------------------------------------------------- EDGAR2A_WriteDword(hEDGAR2A, e2addrSpace, ADD_W_READ_DONE, FALSE_READ_DONE); // ***** HW WRITE ***** EDGAR2A_WriteDword(hEDGAR2A, e2addrSpace, ADD_W_WRITE_DONE, FALSE_WRITE_DONE); // ***** HW WRITE ***** EDGAR2A_WriteDword(hEDGAR2A, e2addrSpace, ADD_W_WR_FINISHED, FALSE_WR_FINISHED); // ***** HW WRITE ***** EDGAR2A_WriteDword(hEDGAR2A, e2addrSpace, ADD_W_WRITTEN3L, FALSE_WRITTEN3L); // ***** HW WRITE ***** max_global = 1; min_global = 0; halfmaskY = maskY/2; //-------------------------------------------------------------------- // READ THE IMAGE TO CONVOLVE FROM FILE //-------------------------------------------------------------------- img_in = Readfile(NAME_FILE_IN); if (img_in ==NULL) { printf("Error reading from file %s !\n", NAME_FILE_IN); return (0); } tx = img_in->Xsize; ty = img_in->Ysize; //-------------------------------------------------------------------- // ALLOCATE MEMORY TO THE OUTPUT IMAGE BUFFERs //-------------------------------------------------------------------- img_out = CreateImageSWORD(tx, ty); if(img_out == NULL) { printf("Error on memory allocation to 'img_out' ! \n"); return (0); } img_out2 = CreateImage(tx, ty); if(img_out2 == NULL) { printf("Error on memory allocation to 'img_out2' ! \n"); return (0); } // ***** HW WRITE ***** EDGAR2A_WriteDword(hEDGAR2A, e2addrSpace, ADD_W_READ_DONE, TRUE_READ_DONE); //-------------------------------------------------------------------- colunas = (tx/4)+2; colInicial1 = 0; colInicial2 = (tx/4)-1; colInicial3 = (2*(tx/4))-1; colInicial4 = (3*(tx/4))-2; for(linha=1; linha<=(ty-2); ++linha) { do { // ***** HW READ ***** valRead = TRUE_ACCEPT3L & EDGAR2A_ReadDword(hEDGAR2A, e2addrSpace, ADD_R_ACCEPT3L); } while (valRead != TRUE_ACCEPT3L); // ------------------------------------------------------------- // For each of the 4 FPGAs, save 'maskY' parts (from 'maskY' // different rows). These parts are needed on the convolution // with a filter of size [maskX][maskY] and to obtain the 4 // parts of the same row on the output convolution matrix. This // writing operation is done here because the FPGAs can't read // from s/w (EDgAR-2 does not implement PCI master functionality). // // HW/SW IMPLEMENTATION: bytes are sent simultaneously to the 4 // FPGAs using the 32 bits of the PCI bus (MSByte=FPGA4 and // LSByte=FPGA1) // ------------------------------------------------------------- for (j=(linha-halfmaskY), k=0; j<=(linha+halfmaskY); ++j) { // ------------------------------------------------------------ // OPTIMIZATION // ------------------------------------------------------------ tmp = j * img_in->Xsize; tmp4 = tmp + colInicial4; tmp3 = tmp + colInicial3; tmp2 = tmp + colInicial2; tmp1 = tmp + colInicial1; for (i=0; i<=(colunas-1); ++i) { val2send = (DWORD)img_in->data[i + tmp4]; val2send = val2send << 8; val2send = val2send | (DWORD)img_in->data[i + tmp3]; val2send = val2send << 8; val2send = val2send | (DWORD)img_in->data[i + tmp2]; val2send = val2send << 8; val2send = val2send | (DWORD)img_in->data[i + tmp1]; EDGAR2A_WriteDword(hEDGAR2A, e2addrSpace, ADD_W_LINES_IN(k), val2send); // ***** HW WRITE ***** k += 4; } } EDGAR2A_WriteDword(hEDGAR2A, e2addrSpace, ADD_W_WRITTEN3L, TRUE_WRITTEN3L); // ***** HW WRITE ***** do { // ***** HW READ ***** valRead = TRUE_CONV1LINE_DONE & EDGAR2A_ReadDword(hEDGAR2A, e2addrSpace, ADD_R_CONV1LINE_DONE); } while (valRead != TRUE_CONV1LINE_DONE); EDGAR2A_WriteDword(hEDGAR2A, e2addrSpace, ADD_W_WRITTEN3L, FALSE_WRITTEN3L); // ***** HW WRITE ***** // ----------------------------------------------------------- // Store one convolved line into the output image buffer // // HW/SW IMPLEMENTATION: the bytes from the 4 FPGAs are read // simultaneously using the 32 bits of the PCI bus. This way, // the reading of a pixel is done in two operations: one reads // the LSByte from the 4 FPGAs and the other reads the MSByte // from the 4 FPGAs. // ------------------------------------------------------------ // ------------------------------------------------------------ // OPTIMIZATION // ------------------------------------------------------------ tmp = linha*img_in->Xsize; tmp4 = tmp + colInicial4; tmp3 = tmp + colInicial3; tmp2 = tmp + colInicial2; tmp1 = tmp + colInicial1; for (j=1,k=4; j<=(colunas-2); ++j) { // Read MSByte of 4 convolved pixels valRead = EDGAR2A_ReadDword(hEDGAR2A, e2addrSpace, ADD_R_MSB_LINE_OUT(k)); val1 = (SWORD)(valRead & 0xFF); val1 = val1 << 8; valRead = valRead >> 8; val2 = (SWORD)(valRead & 0xFF); val2 = val2 << 8; valRead = valRead >> 8; val3 = (SWORD)(valRead & 0xFF); val3 = val3 << 8; valRead = valRead >> 8; val4 = (SWORD)valRead; val4 = val4 << 8; // Read LSByte of 4 convolved pixels valRead = EDGAR2A_ReadDword(hEDGAR2A, e2addrSpace, ADD_R_LSB_LINE_OUT(k)); img_out->data[j+tmp1] = val1 | (SWORD)(valRead & 0xFF); valRead = valRead >> 8; img_out->data[j+tmp2] = val2 | (SWORD)(valRead & 0xFF); valRead = valRead >> 8; img_out->data[j+tmp3] = val3 | (SWORD)(valRead & 0xFF); valRead = valRead >> 8; img_out->data[j+tmp4] = val4 | (SWORD)valRead; k += 4; } EDGAR2A_WriteDword(hEDGAR2A, e2addrSpace, ADD_W_WR_FINISHED, TRUE_WR_FINISHED); // ***** HW WRITE ***** do { // ***** HW READ ***** valRead = TRUE_CONV1LINE_DONE & EDGAR2A_ReadDword(hEDGAR2A, e2addrSpace, ADD_R_CONV1LINE_DONE); } while (valRead != FALSE_CONV1LINE_DONE); EDGAR2A_WriteDword(hEDGAR2A, e2addrSpace, ADD_W_WR_FINISHED, FALSE_WR_FINISHED); // ***** HW WRITE ***** } // End of loop using 'linha' // ----------------------------------------------------------- // Write convolved image to file (line-by-line) // ----------------------------------------------------------- do { // ***** HW READ ***** valRead = TRUE_CONVOL_DONE & EDGAR2A_ReadDword(hEDGAR2A, e2addrSpace, ADD_R_CONVOL_DONE); } while (valRead != TRUE_CONVOL_DONE); EDGAR2A_WriteDword(hEDGAR2A, e2addrSpace, ADD_W_READ_DONE, FALSE_READ_DONE); // ***** HW WRITE ***** // ------------------------------------------------------------ // Compute the maximum among the 4 partial convolution maxima // ------------------------------------------------------------ // Read MSByte of the 4 partial maxima // ***** HW READ ***** valRead = EDGAR2A_ReadDword(hEDGAR2A, e2addrSpace, ADD_R_MSB_MAX); max[1] = (SWORD)(valRead & 0xFF); max[1] = max[1] << 8; valRead = valRead >> 8; max[2] = (SWORD)(valRead & 0xFF); max[2] = max[2] << 8; valRead = valRead >> 8; max[3] = (SWORD)(valRead & 0xFF); max[3] = max[3] << 8; valRead = valRead >> 8; max[4] = (SWORD)valRead; max[4] = max[4] << 8; // Read LSByte of the 4 partial maxima // ***** HW READ ***** valRead = EDGAR2A_ReadDword(hEDGAR2A, e2addrSpace, ADD_R_LSB_MAX); max[1] = max[1] | (SWORD)(valRead & 0xFF); valRead = valRead >> 8; max[2] = max[2] | (SWORD)(valRead & 0xFF); valRead = valRead >> 8; max[3] = max[3] | (SWORD)(valRead & 0xFF); valRead = valRead >> 8; max[4] = max[4] | (SWORD)valRead; if(max[2] > max[1]) max_global = max[2]; else max_global = max[1]; if(max[4] > max[3]) tmp0 = max[4]; else tmp0 = max[3]; if(tmp0 > max_global) max_global = tmp0; else ; // ------------------------------------------------------------ // Compute the minimum among the 4 partial convolution minima // ------------------------------------------------------------ // Read MSByte of the 4 partial minima // ***** HW READ ***** valRead = EDGAR2A_ReadDword(hEDGAR2A, e2addrSpace, ADD_R_MSB_MIN); min[1] = (SWORD)(valRead & 0xFF); min[1] = min[1] << 8; valRead = valRead >> 8; min[2] = (SWORD)(valRead & 0xFF); min[2] = min[2] << 8; valRead = valRead >> 8; min[3] = (SWORD)(valRead & 0xFF); min[3] = min[3] << 8; valRead = valRead >> 8; min[4] = (SWORD)valRead; min[4] = min[4] << 8; // Read LSByte of the 4 partial minima // ***** HW READ ***** valRead = EDGAR2A_ReadDword(hEDGAR2A, e2addrSpace, ADD_R_LSB_MIN); min[1] = min[1] | (SWORD)(valRead & 0xFF); valRead = valRead >> 8; min[2] = min[2] | (SWORD)(valRead & 0xFF); valRead = valRead >> 8; min[3] = min[3] | (SWORD)(valRead & 0xFF); valRead = valRead >> 8; min[4] = min[4] | (SWORD)valRead; if(min[2] < min[1]) min_global = min[2]; else min_global = min[1]; if(min[4] < min[3]) tmp0 = min[4]; else tmp0 = min[3]; if(tmp0 < min_global) min_global = tmp0; else ; // ------------------------------------------------------------ // Normalize the convolved image // ------------------------------------------------------------ gama = max_global - min_global; fesc = ((float)GRAYLEVELS-1.0F)/(float)gama; for (i=1; i<=(ty-2); ++i) { tmp = i*img_out->Xsize; for (j=1; j<=(tx-2); ++j) { fimg = img_out->data[j+tmp] - min_global; img_out2->data[j+tmp] = (BYTE)((float)fimg*fesc); } } // ------------------------------------------------------------ // Write convolved and normalized image into the file // ------------------------------------------------------------ savefile(img_out2, NAME_FILE_OUT); EDGAR2A_WriteDword(hEDGAR2A, e2addrSpace, ADD_W_WRITE_DONE, TRUE_WRITE_DONE); // ***** HW WRITE ***** //-------------------------------------------------------------------- // FREE MEMORY ALLOCATED TO THE INPUT AND OUTPUT IMAGE BUFFERS //-------------------------------------------------------------------- DestroyImage(img_out2); DestroyImageSWORD(img_out); DestroyImage(img_in); } // =======================================================================