70 printf("\nPress any key to exit."); getch() ; exit(1); } nsq=filelength(fileno(fptr)); printf("Is this a square image ?"); printf("\n i.e. Is image_length=image width (y or n)? -> "); while(((ch=tolower(getch()))!='y')&&(ch!='n')); putch(ch); switch(ch) { case 'y': image_length=image_width=sqrt(nsq); printf("\n Image size = %d x %d",image_length, image_width); break; case 'n': printf("\nEnter image_width >"); scanf("%d",&image_width); image_length=nsq/image_width; printf("image length is %d", image_length); break; } printf("\nEnter file name for filtered image ->"); scanf("%s",file_name); ind=access(file_name,0); while(!ind) { gotoxy(1,6); printf("File exists. Wish to overwrite? (y or n) >"); while(((ch=tolower(getch()))!='y')&&(ch!='n')); putch(ch); switch(ch) { case 'Y': ind=1; break; case 'n': gotoxy(1,6); 71 printf(" "); gotoxy(1,5); printf(" "); gotoxy(1,5); printf("Enter file name >"); scanf("%s",file_name); ind=access(file_name,0); } } fptr1=fopen(file_name,"wb"); gotoxy(70,25); textattr(WHITE+(GREEN<<4)+BLINK); cputs("WAIT"); /* Allocating memory for Image Transfer Buffer, w. */ w=(unsigned char **)malloc(3*sizeof(char *)); for(i=0;i<3;i++) *(w+i)=(char *)calloc(image_width,sizeof(char)); /* Clear Image Transfer Buffer. */ for(i=0;i<3;i++) for(j=0;j<image_width;j++) *((*(w+i))+j)=(unsigned char)0; /* Algorithm */ for(n1=0; n1<image_length;n1++) { gotoxy(1,9); printf (" Transfered line %-4d to image transfer buffer. ",n1); /* Transfer row n2 of the image to the last row of W. */ for(j=0;j<image_width;j++) { ch=(char)fgetc(fptr); *((*(w+2))+j) = (unsigned char)ch; } for(n2=0; n2<image_width; n2++) 72 { y1=y2=(int)0; for(k1=-1; k1<=1; k1++) for(k2=-1; k2<=1; k2++) { if( ((n2+k2)<0) || ((n2+k2-1)>=image_width) ) continue; tmp=(*((*(w+1+k1))+(n2+k2-1))); y1+=S1[1+k1][1+k2]*tmp; y2+=S2[1+k1][1+k2]*tmp; } y1=abs(y1); y2=abs(y2); zn2=(y1>y2)?y1:y2; putc(zn2,fptr1); /* The buffer is imPlicit in this last statement. */ } /* Shift rows of w */ temp=*w; for(j=0; j<2; j++) *(w+j)=*(w+j+1); *(w+2)=temp; } gotoxy(70,25); textattr(WHITE+(BLACK<<4)); cputs ( " "); gotoxy(1,8); fclose(fptr); /* close input image file */ fclose(fptr1); /* close output-image file */ } Chương trình cho các phép xử lý Kirsh cũng được trình bày ở dưới đây. Chương trình 5.2 “KIRSH.C” Chương trình cho phát hiện đường biên ảnh dùng toán tử Kirsh. /*Program 5.2 "KIRSH.C". Program for edge detection using the Kirsh operators.*/ /* This program is for obtaining the edges using 73 Kirsh Compass operator. */ #include <stdio.h> #include <stdlib.h> #include <math.h> #include <alloc.h> #include <conio.h> #include <io.h> #include <ctype.h> /* Kirsh operators. */ int T[8][3][3]={ { {5,5,5}, {-3,0,-3}, {-3,-3,-3},}, {{5,5,-3}, {5,0,-3}, {-3,-3,-3}, }, {{5,-3,-3}, {5,0,-3}, {5,-3,-3},}, {{-3,-3,-3}, {5,0,-3}, {5,5,-3},}, {{-3,-3,-3}, {-3,0,-3}, {5,5,5},}, {{-3,-3,-3}, {-3,0,5}, {-3,5,5},}, {{-3,5,5}, {-3,0,5}, {-3,-3,5},}, {{-3,5,5}, 74 {-3,0,5}, {-3,-3,-3},} }; void main() { int i,j,n1,n2,image_width, image_length,k1,k2,ind; char file_name[14],ch; unsigned char **w; unsigned char *temp,tmp; int y[8] ; float nsq; unsigned int zn2; FILE *fptr, *fptr1; clrscr (); printf("Enter file name for input image ->"); scanf("%s",file_name); if((fptr=fopen(file_name,"rb"))==NULL) { printf("%s does not exist.", file_name); printf("\nPress any key to exit."); getch (); exit(1); } nsq=filelength(fileno(fptr)); printf("Is this a square image ?"); printf ("\n i.e. Is image_length=image_width (y or n)? ->"); while(((ch=tolower(getch()))!='y')&&(ch!='n')); putch(ch); switch(ch) { case 'y': image_length=image_width=sqrt(nsq); printf("\n Image size = %d x %d",image_length, image_width); break; case 'n': printf("\nEnter image_width >"); scanf("%d",&image_width); 75 image_length=nsq/image_width; printf("image length is %d", image_length); break; } printf("\nEnter file name for filtered image ->"); scanf("%s",file_name); ind=access(file_name,0); while(!ind) { gotoxy(1,6); printf("File exists. Wish to overwrite? (y or n) >"); while(((ch=tolower(getch()))!='Y')&&(ch!='n')); putch(ch); switch(ch) { case 'y': ind=1; break; case 'n': gotoxy(1,6); printf (" "); gotoxy(1,5); printf(" "); gotoxy(1,5); printf("Enter file name >"); scanf("%s",file_name); ind=access(file_name,0); } } fptr1=fopen(file_name,"wb"); gotoxy(70,25); textattr(WHITE+(GREEN<<4)+BLINK); cputs("WAIT"); /* Allocating memory for Image Transfer Buffer, w. */ w=(unsigned char **)malloc(3*sizeof(char *)); for(i=0;i<3;i++) *(w+i)=(char *)calloc(image_width,sizeof(char)); /* Clear Image Transfer Buffer. */ 76 for(i=0;i<3;i++) for(j=0;j<image_width;j++) *((*(w+i))+j)=(unsigned char)0; /* Algorithm */ for(n1=0; n1<image_length;n1++) { gotoxy(1,9); printf(" Transfered line %-4d to image transfer buffer. ",n1); /* Transfer row n2 of the image to the last row of w. */ for(j=0;j<image_width;j++) { ch=(char)fgetc(fptr); *((*(w+2))+j) = (unsigned char)ch; } for(n2=0; n2<image_width; n2++) { for(j=0;j<8;j++) y[j]=(int)0.0; for(k1=-1; k1<=1; k1++) for(k2=-1; k2<=1; k2++) { if( ((n2+k2)<0) || ((n2+k2-1)>=image_width) ) continue; tmp=(*((*(w+1+k1))+(n2+k2-1))); for(j=0;j<8;j++) y[j]+=T[j][1+k1][1+k2]*tmp; } for(j=0;j<8;j++) y[j]=abs(y[j]); zn2=y[0]; for(j=1;j<8;j++) if(y[j]>zn2) zn2=y[j]; putc(zn2,fptr1); /* The buffer is implicit in this last statement. */ } /* shift rows of w */ temp=*w; 77 for(j=0; j<2; j++) *(w+j)=*(w+j+1); *(w+2)=temp; } gotoxy(70,25); textattr(WHITE+(BLACK<<4)); cputs(" "); gotoxy(1,8); fclose(fptr); /* close input image file */ fclose(fptr1); /* close output-image file*/ } Để kiểm tra chương trình này, chúng ta dùng ảnh trong hình 4.19 chương 4. Kết quả dùng các phương pháp Sobel và Kirsh được cho trong hình 5.5 a và 5.5 b. Bạn sẽ nhận thấy rằng các xử lý của Kirsh có vẻ như cung cấp cho ta nhiều chi tiết hơn về ảnh. Cũng như thế ta nhận thấy rằng phương pháp dùng các xử lý không gian cho một kết quả tốt hơn là kỹ thuật dùng các bộ lọc thông cao. Mặc dù các mặt nạ trên dùng giả thiết là chỉ có kích thước 3 3, tuy nhiên ta có thể mở rộng để ảnh có kích thước bất kỳ nhưng thường là không quá lớn. Bài tập 5.1 Lập một chương trình C cho phép lựa chọn sử dụng các kỹ thuật phát hiện đường biên không gian. Bài tập 5.2 Phương pháp S. Sarker và K. L. Boyer được phát triển thành bộ lọc tách lấy đường biên tốt nhất sử dụng bộ lọc có đáp ứng xung vô hạn (IIR). Chúng ta sẽ nói về IIR trong chương 9; tuy nhiên, để hiểu được kết quả cho bởi Sarker và Boyer chúng ta chưa cần phải đọc chương 9. 1. Dựa trên kết quả phép lấy đạo hàm của chúng, phát triển bộ lọc FIR để phát hiện đường biên ảnh. 2. Sử dụng những bộ lọc này cho ảnh 4.19 của chương 4. 3. So sánh kết quả thu được qua việc tiếp cận với phương pháp được nói đến trong chương này. 78 Hình 5.5 (a) Kết quả thu được khi dùng xử lý Sobel trên hình 4.19. (b) Kết quả của xử lý Kirsh trên hình 4.19. 75 CHƯƠNG 6 BIẾN ĐỔI FOURIER RỜI RẠC 6.1 Chỉ dẫn Trong chương 2,chúng ta đã chứng minh rằng đáp ứng tần số của hệ thống của hệ thống tuyến tính bất biến (LSI ) 2-D được cho bởi: 1 2 2211 )( 2121 ),(),( k k kkj ekkhH (6.1) Nếu h(k 1 ,k 2 ) chỉ có chỉ tồn tại với k 1 0, k 2 0 và tổng quát được xác định trong miền hữu hạn có kích thước N N thì 1 0 1 0 )( 2121 1 2 2211 ),(),( N k N k kkj ekkhH (6.2) Công thức này chứng tỏ rằng H( , ) 1 2 là tuần hoàn, chu kỳ tuần hoàn là 2. Nếu chúng ta lấy mẫu dưới dạng 1 , 2 , và miền xác định là (0 1 2) và (0 2 2), N N mẫu, chúng ta có thể viết: 1 1 2 N n và 2 2 2 N n (6.3) vì thế 1 0 2 1 0 2121 1 2211 2 ),(),( N k knkn N j N k ekkhnnH (6.4) Biểu thức (6.4) được gọi là biến đổi Fourier rời rạc 2-D hay còn gọi là DFT. Công thức này được áp dụng vào nhiều ứng dụng như lọc, nén ảnh, phóng đại ảnh. Trong chương này chúng ta sẽ nghiên cứu 2-D DFT và các kỹ thuật tính toán. Đầu tiên, chúng ta sẽ xem xét 1-D DFT, sau đó mở rộng ra cho 2-D. 6.2 Biến đổi Fourier 1-D Biến đổi Fourier 1-D cho tín hiệu thời gian rời rạc f(kT) tính theo công thức : 1 0 2 )()( N k nk N j ekTfnF (6.5) Công thức này có thể viết lại dưới dạng . tmp=(*((*(w+1+k1))+(n2+k2-1))); y1 +=S1[1+k1][1+k2]*tmp; y2 +=S2[1+k1][1+k2]*tmp; } y1 =abs (y1 ); y2 =abs (y2 ); zn2= (y1 > ;y2 ) ?y1 :y2 ; putc(zn2,fptr1); /* The buffer is imPlicit in this. output-image file */ } Chương trình cho các phép xử lý Kirsh cũng được trình b y ở dưới đ y. Chương trình 5.2 “KIRSH.C” Chương trình cho phát hiện đường biên ảnh dùng toán tử Kirsh. /*Program. tmp=(*((*(w+1+k1))+(n2+k2-1))); for(j=0;j<8;j++) y[ j]+=T[j][1+k1][1+k2]*tmp; } for(j=0;j<8;j++) y[ j]=abs (y[ j]); zn2 =y[ 0]; for(j=1;j<8;j++) if (y[ j]>zn2) zn2 =y[ j]; putc(zn2,fptr1); /* The