• Thứ Sáu, 15/05/2009 14:29 (GMT+7)

    Cách đọc thông tin 1 file ảnh

    Câu hỏi :
    Code dưới đây là một chương trình ứng dụng thuật toán Sobel để tìm kiếm biên của ảnh. Đưa vào 1 ảnh lấy các thông tin từ ảnh đó view ra dưới dạng ma trận pixel rồi dùng ma trận mặt nạ 3x3 để xử lý và in ra ma trận biên của ảnh. Xin hỏi cách thức đưa ảnh vào và lấy thông tin ảnh như thế nào (bmpInput, bmpOutput).


    Trả lời :
     #include <stdio.h>
     #include <stdlib.h>
     #include <math.h>
     #include <malloc.h>
     #include <conio.h>
     
     /* khai báo các kiểu dữ liệu & hàm cần dùng */
     typedef struct {int rows; int cols; unsigned char* data;} sImage;
     long thongtinanh(FILE*, long, int );
     void copythongtinanh(FILE* inputFile, FILE* outputFile);
     void copybangmau(FILE* inputFile, FILE* outputFile, int nColors);
     /* điểm nhập của chương trình */
     void main(int argc, char* argv[]){
     /* khai báo các biến cần dùng */
     FILE *bmpInput, *bmpOutput;
     sImage anhgoc;
     sImage anhbien;
     unsigned int X, Y;
     int I, J;
     long sumX, sumY;
     int nColors, SUM;
     unsigned long vectorSize;
     unsigned long fileSize;
     int GX[3][3];int GY[3][3];
     unsigned char *pChar, someChar;
     unsigned int row, col;
     someChar = '0';
     pChar = &someChar;
     /* 3x3 GX Mat na Sobel.*/
     GX[0][0] = -1; GX[0][1] = 0; GX[0][2] = 1;
     GX[1][0] = -2; GX[1][1] = 0; GX[1][2] = 2;
     GX[2][0] = -1; GX[2][1] = 0; GX[2][2] = 1;
     /* 3x3 GY Mat na Sobel.*/
     GY[0][0] = 1; GY[0][1] = 2; GY[0][2] = 1;
     GY[1][0] = 0; GY[1][1] = 0; GY[1][2] = 0;
     GY[2][0] = -1; GY[2][1] = -2; GY[2][2] = -1;
     if (argc < 2) {
     printf('Su dung : %s bmpInput.bmp\n', argv[0]);
     exit(0);
     };
     printf('Dang doc file %s\n', argv[1]);
     /*---INPUT & OUTPUT FILES---*/
     bmpInput = fopen(argv[1], 'rb');
     bmpOutput = fopen('xla.bmp', 'wb');
     /*---SET POINTER TO BEGINNING OF FILE---*/
     fseek(bmpInput, 0L, SEEK_END);
     /*---GET INPUT BMP DATA---*/
     fileSize = thongtinanh(bmpInput, 2, 4);
     anhgoc.cols = (int)thongtinanh(bmpInput, 18, 4);
     anhgoc.rows = (int)thongtinanh(bmpInput, 22, 4);
     anhbien.rows = anhgoc.rows;
     anhbien.cols = anhgoc.cols;
     /*---PRint DATA TO SCREEN---*/
     printf('Chieu rong : %d\n', anhgoc.cols);
     printf('Chieu cao : %d\n', anhgoc.rows);
     printf('Co anh : %lu\n', fileSize);
     nColors = (int)thongtinanh(bmpInput, 46, 4);
     printf('nColors : %d\n', nColors);
     /*---ALLOCATE MEMORY FOR FILES---*/
     vectorSize = fileSize - (14+40+4*nColors);
     printf('vectorSize : %lu\n', vectorSize);
     anhbien.data =(unsigned char*)malloc(vectorSize*sizeof(unsigned char));
     if(anhbien.data == NULL) {
     printf('Failed to malloc anhbien.data\n');
     exit(0);
     }
     printf('%lu bytes malloc'ed for anhbien.data\n', vectorSize);
     anhgoc.data =(unsigned char*)malloc(vectorSize*sizeof(unsigned char));
     if(anhgoc.data == NULL) {
     printf('Failed to malloc anhgoc.data\n');
     exit(0);
     }
     printf('%lu bytes malloc'ed for anhgoc.data\n', vectorSize);
     /*---COPY HEADER AND COLOR TABLE---*/
     copythongtinanh(bmpInput, bmpOutput);
     copybangmau(bmpInput, bmpOutput, nColors);
     fseek(bmpInput, (14+40+4*nColors), SEEK_SET);
     fseek(bmpOutput, (14+40+4*nColors), SEEK_SET);
     /* Doc input.bmp luu thong tin toi anhgoc.data */
     for(row=0; row<=anhgoc.rows-1; row++) {
     for(col=0; col<=anhgoc.cols-1; col++) {
     fread(pChar, sizeof(char), 1, bmpInput);
     *(anhgoc.data + row*anhgoc.cols + col) = *pChar;
     }
     }
     /*---CAC PHEP TOAN SOBEL---*/
     for (Y=0; Y<=(anhgoc.rows-1); Y++){
     for (X=0; X<=(anhgoc.cols-1); X++){
     sumX = 0;sumY = 0;
     /* image boundaries */
     if (Y==0 || Y==anhgoc.rows-1) SUM = 0;
     else if (X==0 || X==anhgoc.cols-1) SUM = 0;
     /* Convolution starts here */
     else {/*---X GRADIENT APPROXIMATION---*/
     for(I=-1; I<=1; I++){
     for(J=-1; J<=1; J++){
     sumX = sumX + (int)( (*(anhgoc.data + X + I + (Y + J)*anhgoc.cols)) * GX[I+1][J+1]);
     }
     }
     /*---Y GRADIENT APPROXIMATION---*/
     for(I=-1; I<=1; I++){
     for(J=-1; J<=1; J++){
     sumY = sumY + (int)( (*(anhgoc.data + X + I + (Y + J)*anhgoc.cols)) * GY[I+1][J+1]);
     }
     }
     /*---GRADIENT MAGNITUDE APPROXIMATION (Myler p.218)---*/
     SUM = abs(sumX) + abs(sumY);
     }
     if(SUM>255) SUM=255;
     if(SUM<0) SUM=0;*(anhbien.data + X + Y*anhgoc.cols) = 255 - (unsigned char)(SUM);
     fwrite((anhbien.data + X + Y*anhgoc.cols), sizeof(char), 1, bmpOutput);
     }
     }
     printf('Xet xla.bmp cho ket qua\n');
     fclose(bmpInput);
     fclose(bmpOutput);
     free(anhbien.data);
     /* Ket thuc anhbien.data */
     free(anhgoc.data);
     /* Ket thuc anhgoc.data */
     getch();
     }
     
     /*---GET IMAGE INFO SUBPROGRAM---*/
     long thongtinanh(FILE* inputFile, long offset, int numberOfChars){
     unsigned char *ptrC;
     long value = 0L;
     unsigned char dummy;
     int i;
     dummy = '0';
     ptrC = &dummy;
     fseek (inputFile, offset, SEEK_SET);
     for (i=1; i<=numberOfChars; i++){
     fread(ptrC, sizeof(char), 1, inputFile);
     value = (long)(value + (*ptrC)*(pow(256, (i-1))));
     /* Tinh gia tri co ban tren cac byte them vao */
     }
     return(value);
     }
     
     /*---COPIES HEADER AND INFO HEADER---*/
     void copythongtinanh(FILE* inputFile, FILE* outputFile){
     unsigned char *ptrC;
     unsigned char dummy;
     int i;
     dummy = '0';
     ptrC = &dummy;
     fseek(inputFile, 0L, SEEK_SET);
     fseek(outputFile, 0L, SEEK_SET);
     for(i=0; i<=50; i++){
     fread(ptrC, sizeof(char), 1, inputFile);
     fwrite(ptrC, sizeof(char), 1, outputFile);
     }
     }
     
     /*---COPIES COLOR TABLE---*/
     void copybangmau(FILE* inputFile, FILE* outputFile, int nColors){
     unsigned char *ptrC;
     unsigned char dummy;
     int i;
     dummy = '0';
     ptrC = &dummy;
     fseek(inputFile, 54L, SEEK_SET);
     fseek(outputFile, 54L, SEEK_SET);
     for(i=0; i<=(4*nColors); i++){
     fread(ptrC, sizeof(char), 1, inputFile);
     fwrite(ptrC, sizeof(char), 1, outputFile);
     }
     }
     
     Nếu muốn nắm vững công việc mà chương trình trên thực hiện, trước hết bạn hãy tìm tài liệu giới thiệu thuật toán Sobel dưới dạng ngôn ngữ tự nhiên (tiếng Anh, tiếng Việt,...) và đọc để hiểu rõ ràng ý nghĩa của thuật toán Sobel trước. Sau đó bạn cần học và nắm vững cú pháp ngôn ngữ lập trình C. Nếu đã trang bị được kiến thức chi tiết về thuật toán Sobel và ngôn ngữ C, bạn bắt đầu đọc từng lệnh chương trình trên theo thứ tự từ đầu đến cuối. Hy vọng lúc ấy bạn sẽ hiểu rõ cách hoạt động cụ thể của chương trình.
     Nếu chỉ muốn dùng chương trình trên, bạn chỉ cần biết các thông tin tối thiểu về cách dùng nó. Đây là chương trình viết bằng ngôn ngữ C chạy ở chế độ dòng lệnh (command line), nó nhận 1 tham số dòng lệnh miêu tả đường dẫn file ảnh bitmap (theo định dạng *.bmp), tìm đường biên của các phần tử ảnh trong file rồi tạo ra file xla.bmp chứa kết quả bitmap miêu tả đường biên của các phần tử ảnh trong file gốc. Nếu dùng VC++ để dịch chương trình, bạn có thể thực hiện các bước sau:
     1. Chạy trình VC++ 6.0, chọn menu File.New để hiển thị cửa sổ New, chọn tag 'Project' để hiển thị danh sách các loại Project, chọn mục 'Win32 Console Application', nhập vào hay chọn thư mục chứa Project (thí dụ c:\), nhập tên Project quản lý chương trình (thí dụ FindImageBound) rồi chọn button OK để tiếp tục.
     2. Khi cửa sổ 'Wizard Step 1' hiển thị, chọn mục 'An empty project' rồi chọn button Finish, OK để tạo Project mới theo các thông số vừa thiết lập được.
     3. Chọn menu File.New để hiển thị cửa sổ New, chọn tag 'Files' để hiển thị danh sách các loại files, chọn mục 'C++ Source File', nhập tên 'main' vào textbox 'File name' rồi OK để tạo file mã nguồn tên là main.cpp.
     4. Khi cửa sổ soạn mã nguồn cho file main.cpp hiển thị, bạn nhập tuần tự từng lệnh của chương trình trên (hãy tập trung và cẩn thận nhập đúng từng dòng lệnh, từng từ, từng ký tự vì chỉ cần sai 1 ký tự cũng có thể làm chương trình bị lỗi).
     5. Chọn menu Build.Set Active Configuration để hiển thị cửa sổ 'Set Active Project Configuration'. Chọn mục Win32 Release rồi OK.
     6. Chọn menu Build.Rebuild All để dịch Project và tạo file khả thi.
     7. Nếu bạn thao tác đúng các bước trên thì file khả thi FindImageBound.exe sẽ được tạo ra trong thư mục Release nằm trong thư mục chứa Project chương trình (cụ thể là c:\FindImageBound\Release\FindImageBound.exe).
     8. Để chạy thử chương trình, bạn chọn Start.All Programs.Accessories.Command Prompt để tạo 1 cửa sổ dòng lệnh dạng Text-mode rồi nhập tuần tự các lệnh sau:
     c:\....>cd \
     c:\>cd FindImageBound\Release
     c:\FindImageBound\Release>FindImageBound winnt.bmp
     
     Giả sử bạn đã copy file ảnh bitmap tên là winnt.bmp vào thư mục chương trình. Chương trình sẽ chạy và tạo ra file chứa đường biên có tên là xla.bmp.

     Lưu ý là chương trình trên chỉ xử lý file ảnh theo định dạng *.bmp, kết quả đường biên phụ thuộc nhiều vào ảnh gốc, thường đường biên tìm được có chất lượng kém.
     
    Chuyên mục: Lập trình