Phương pháp lọc gauss, thuật toán viết dòng chữ chạy và đảo ảnh

Một phần của tài liệu Thuật toán xử lý ảnh trên kit DSP (Trang 101 - 113)

3.3.3.1. Phương pháp lọc gauss

Gaussian Blur là cách làm mờ một ảnh bằng hàm Gaussian. Phương pháp này được ứng dụng một cách rộng rãi và hiệu quả trong các phần mềm xử lý đồ họa. Nó cũng là công cụ phổ biến để thực hiện quá trình tiền xử lý (preprocessing) hình ảnh dùng làm dữ liệu đầu vào tốt cho các phân tích cao cấp hơn như trong Computer Vision, hoặc cho các giải thuật được thực hiện trong một tỉ lệ khác của hình được cho. Nó có thể giúp làm giảm nhiễu (Noise) và mức độ chi tiết (không mong muốn) của hình ảnh.

Một cách trực quan, đây được xem như là phương pháp làm mờ mịn cũng giống như hiệu ứng hình ảnh được đặt dưới một lớp màn trong suốt bị mờ. Nó không giống với trường hợp hình ảnh bị mờ do hậu quả của ống kính bị mất tiêu điểm (out of focus) hay do bóng của đối tượng dưới ánh sáng thường.

tính tích chập (Convolution) hình đó với hàm Gaussian. Vì biến đổi Fourier của một Gaussian sẽ tạo ra một Gaussian khác cho nên nếu xét trên miền tần số thì phương pháp này sẽ làm giảm các thành phần có tần số cao trong hình. Hay nói cách khác Gaussian Blur là một bộ lọc tần số cao (low pass filter : chỉ giữ lại các thành phần tần số thấp).

Như vậy phát biểu một cách thực hành hơn Gaussian blur là một loại bộ lọc làm mờ ảnh, sử dụng lý thuyết hàm Gaussian (cũng được biết đến như là dạng phân tán chuẩn (Normal Distribution) trong thống kê) để tính toán việc chuyển đổi (Transformation) mỗi Pixel của hình. Dưới đây là phương trình hàm Gaussian dùng trong không gian một chiều và hai chiều.

Trong đó x và y là tọa độ theo hai trục đứng và ngang còn σ là phương sai chuẩn của phân tán Gaussian hay là giá trị quyết định độ lệch giữa các điểm trên bề mặt Gaussian. Trong không gian hai chiều, công thức này sản sinh ra những đường viền là những đường tròn đồng tâm, tuân theo logic phân tán Gaussian từ điểm trung tâm. Giá trị từ hệ thống phân tán này sẽ được sử dụng để xây dựng một ma trận tích chập (Convolution) dùng tính tóan phép tích chập (Convolution) với hình ảnh gốc.

Giá trị mới của mỗi Pixel sau khi tính tích chập với kernel đại diện cho hàm Gaussian có thể coi là trung bình lượng giá của các pixel xung quanh nó. Ta thấy rằng giá trị lượng giá của phần tử trung tâm kernel tương ứng với pixel đang xét là lớn nhất, giá trị này sẽ nhỏ hơn đối với các phần tử tương ứng với những pixel kế cận một cách đối xứng và tỉ lệ thuận với khoảng cách của phần tử này với trung tâm. Tính chất này giúp giữ lại đường viền và biên cũng như làm mờ một cách đồng bộ hơn so với các phương pháp khác.

Trong lý thuyết, hàm Gaussian tại mỗi điểm trên hình là khác 0. Điều này có nghĩa là Gaussian Kernel nên có kích thước bằng với hình ảnh và giá trị tại mỗi phần tử luôn khác 0. Tuy nhiên trong thực hành, do việc tính tóan dựa trên xấp xỉ rời rạc (Discrete Approximation) cho nên giá trị của các phần tử trên bề mặt Gaussian ở khỏang cách lớn hơn 3σ so với trung tâm gần như không đáng kể (tiệm cận 0). Do vậy các phân tán Gaussian ngòai bán kính này sẽ bị bỏ qua, đó cũng là lý do mà thông thường Gaussian kernel có kích thước giới hạn 3, 5, 7... (Cái này còn tùy vào giá trị phương sai chuẩn mà bạn chọn). Khoảng cách giữa hai điểm gần nhau trong Gaussian Kernel là σ.

Do đặc tính có cấu trúc như những hình tròn đối xứng, với hình hai chiều, Gaussian blur có thể được áp dụng như là hai phép tính toán một chiều độc lập (Độc lập tuyến tính - Linearly Separable). Có nghĩa là hiệu quả thu được từ tính toán trên ma trận hai chiều có thể tương đương với cách ứng dụng tính toán một loạt các

Gaussian 1 chiều theo hướng ngang và đứng. Điều này rất hữu ích trong việc giảm chi phí tính toán thể hiện khá rỏ trong hai công thức tương ứng sau:

Một vấn đề cần quan tâm nữa của Gaussian blur là nếu bạn sử dụng lần lượt nhiều Gaussian cho một ảnh thì kết quả cũng tương đương với khi bạn dùng một Gaussian lớn hơn có bán kính bằng căn bậc hai tổng bình phương các bán kính của các Gaussian đã dùng.

Cũng vì mối quan hệ này mà thời gian tính toán sẽ không thể được tiết kiệm khi bạn chia nhỏ các Gaussian. Do đó khuyến cáo nên sử dụng Gaussian đơn trong tính toán nếu có thể.

Ngoài ra Gaussian blur cũng được sử dụng để giảm kích thước của hình ảnh. Khi tiến hành xử lý giảm tỉ lệ lấy mẩu tín hiệu cho ảnh (Downsampling) người ta thường áp dụng bộ lọc tần số cao (Low pass filter) trước khi tái lấy mẫu. Điều này là để chắc chắn những thông tin không mong muốn, tần số cao sẽ không xuất hiện trong hình đã được Downsampling... (loại bỏ răng cưa Aliasing).

Với những gì đã trình bày ở trên, chúng ta cũng đã nhắc tới bề mặt, ma trận Gaussian, đó chính là hiện thực hóa của hàm Gaussian trong thực hành. Hàm Gaussian được áp dụng vào ảnh thông qua phép Convolution giữa ma trận Gaussian và ma trận điểm ảnh 2 chiều. Dưới đây là ma trận Gaussian được sử dụng để chập với ma trận điểm ảnh thực hiện trong đồ án:

Sau đây là đoạn mã nguồn thể hiện phép lọc gauss:

void gauss_atp( unsigned char *ys, unsigned char *mask, int cot){

int sum;

sum = (2* *(mask) + 4* *(mask+1) + 5* *(mask+2) +

2* *(mask + 4) + 4* *(mask+3)+ 4* *(mask+5) + 9* *(mask+6) + 12* *(mask+7) + 4* *(mask + 9) + 9* *(mask+8)+ 5* *(mask+10) + 12* *(mask+11) + 15* *(mask+12) + 5* *(mask + 14) + 12* *(mask+13)+ 4* *(mask+15) + 9* *(mask+16) + 12* *(mask+17) + 4* *(mask + 19) + 9* *(mask+18)+ 2* *(mask+20) + 4* *(mask+21) + 5* *(mask+22) + 2* *(mask + 24) + 4*

*(mask+23))/159;

3.3.3.2. Thuật toán hiển thị và dịch dòng chữ trên màn hình

 Ý tưởng:

Khi ghi dữ liệu video đã xử lý vào bộ đệm lưu ảnh đầu ra disLinePitch, ta dành một vùng nhớ có kích thước 32x640 bytes để làm nơi chứa dữ liệu các kí tự chữ cái ( trong chương trình, mỗi pixel được biểu diễn bằng 16 bits chứa thông tin RGB của pixel đó, do vậy, với vùng nhớ 32x640 bytes, ta có thể lưu giá trị màu sắc của 32x320 pixels trên màn hình).

Hình 3.3.3.1 Bố cục màn hình hiển thị

Mỗi ký tự có kích thước hiển thị trên màn hình là 17x 24 pixels. Tuy nhiên, để tiện cho việc hiển thị, ta mở rộng ký tự thành 20x24 pixels để chứa thêm dấu cách:

Hình 3.3.3.2 : Kích thước của một chữ

Vì dữ liệu mà ta xử lý là các mẫu dữ liệu Y, Cb và Cr, sau đó qua hàm chuyển đổi để chuyển YCbCr thành 16 bits dữ liệu RGB, nên ta cần đến ba mảng phục vụ cho việc lưu giá trị Y, Cb và Cr ( trong đó, mảng lưu mẫu dữ liệu Y có kích thước gấp đôi các mảng lưu mẫu dữ liệu Cb và Cr). Để việc trình bày trở nên đơn giản, chúng ta chỉ xét mảng chứa mẫu dữ liệu Y, các mảng lưu mẫu dữ liệu Cb và Cr là tương tự.

Thay vì sử dụng một mảng 20x24 phần tử để lưu trữ mẫu dữ liệu Y cho mỗi ký tự, ta có thể dùng một mảng 20 phần tử để chứa dữ liệu mẫu Y của từng dòng của ký tự, nhờ vậy có thể tiết kiệm bố nhớ chương trình. Tuy nhiên, ta sẽ phải gán dữ liệu mẫu Y của từng dòng của ký tự vào mảng rồi hiển thị, sau đó lặp lại việc này với dòng khác. Sau 24 lần gán và hiển thị liên tục, ta sẽ được một ký tự đầy đủ trên màn hình.

Tiếp theo, sau khi thực hiện việc hiển thị tất cả các ký tự cần thiết, ta sẽ dịch dòng chữ sang trái bằng cách lưu lại tất cả các thông tin về tất cả các dòng của tất cả các ký tự vào các ô nhớ lân cận trái của chúng và cách chúng 4 ô nhớ trong bộ đệm dữ liệu đầu ra.

Hình 3.3.3.3 Cách chuyển dữ liệu của một dòng của ký tự thành giá trị trung gian sử dụng trong hàm gán giá trị cho mảng.

 Cách thực hiện:

Bước 1: Khai báo một mảng letter gồm 20 phần tử để lưu dữ liệu mẫu Y của từng dòng của ký tự.

Bước 2: Xây dựng hàm gán giá trị cho mảng letter ( tên của hàm là truyen_du_lieu_cho_mang) với các tham số như sau:

Con trỏ array : Đại diện cho mảng cần được gán giá trị. Khi gọi hàm trong chương trình, array sẽ đại diện cho mảng letter truyền vào hàm, array là con trỏ

kiểu unsigned char.

Số nguyên không dấu nume : Biểu diễn số lượng pixel sẽ được hiển thị và không được hiển thị xen kẽ nhau. VD: từ hình 3.3.4.2, để hiển thị dòng thứ 12 của ký tự ‘N’, ta truyền vào hàm truyen_du_lieu_cho_mang giá trị nume = 205030502, sau đó, khi hàm truyen_du_lieu_cho_mang thực thi, nume sẽ được phân tách thành 5 trường số là t1 = 2; t2 = 05; t3 = 03; t4 = 05 và t5 = 02. Trong đó, t1, t3, t5 sẽ hiển thị giống nhau trên màn hình và t2, t4 sẽ hiển thị giống nhau trên màn hình.

Tham số enable: quy định trình tự hiển thị của các trường số chứa trong tham số nume. Nếu enable =0, trường dữ liệu đầu tiên của nume sẽ không được hiển thị ( màu đen) . Ngược lại, nếu enable khác 0 thì trường dữ liệu đầu tiên của nume sẽ được hiển thị. Như vậy, nếu tham số enable khác 0 thì kết quả thu được của 20 pixels trên màn hình ( với nume = 205030502 ) lần lượt là: 2 pixels hiển thị (màu trắng ) rồi đến 5 pixels không hiển thị ( màu đen), sau đó hiển thị 3 pixels, không hiển thị 5 pixels rồi cuối cùng hiển thị 2 pixels. Ngược lại, nếu enable = 0, kết quả thu được của dòng thứ 12 của ký tự ‘N’ sẽ ngược lại.

Dưới đây là mã nguồn của hàm truyen_du_lieu_cho_mang :

void truyen_du_lieu_cho_mang(unsigned char *array,

unsigned int nume, unsigned char enable )

{ unsigned char i, t1, t2, t3, t4, t5; t1 = (nume/100000000); t2 = (nume - t1 * 100000000)/1000000; t3 = (nume - t1 * 100000000 - t2 * 1000000)/10000; t4 = (nume - t1 * 100000000 - t2 * 1000000 - t3 * 10000)/100; t5 = nume - t1 * 100000000 - t2 * 1000000 - t3 * 10000 - t4 * 100; if (enable ==0) {

for(i=0; i< t1; i++)

*( array +i +1)= 0;

for(i=0; i< t2; i++)

for(i=0; i< t3; i++)

*( array +i +1 + t1 + t2)= 0;

for(i=0; i< t4; i++)

*( array +i +1 + t1 + t2 + t3)= 235;

for(i=0; i< t5; i++)

*( array +i + t1 +1+ t2 + t3 + t4)= 0;

}

else

{

for(i=0; i< t1; i++)

*( array +1 +i)= 235;

for(i=0; i< t2; i++)

*( array +i +1 + t1)= 0;

for(i=0; i< t3; i++)

*( array +i +1 + t1 + t2)= 235;

for(i=0; i< t4; i++)

*( array +i + t1 +1+ t2 + t3)= 0;

for(i=0; i< t5; i++)

*( array +i + t1 +1 + t2 + t3 + t4)= 235;

}

}

Bước 3: Thực hiện lặp đi lặp lại việc gọi hàm gán dữ liệu cho mảng và hiển thị chúng trong chương trình chính cho đến khi các ký tự đã được hiển thị hết.

Ví dụ: // Chu T

truyen_du_lieu_cho_mang (g,116010000 ,0);//1, 2

yc2rgb16(coeffs, g,a ,a ,disFrameBuf->frame.rpFrm.buf +

(disLinePitch* 2) * (numLines -10) + 838- offset,20);

yc2rgb16(coeffs, g,a ,a ,disFrameBuf->frame.rpFrm.buf +

(disLinePitch* 2) * (numLines -9) + 838- offset,20);

truyen_du_lieu_cho_mang (g, 802080000,0);

for(ti=-8; ti< 14; ti++)

yc2rgb16(coeffs, g,a ,a ,disFrameBuf->frame.rpFrm.buf +

(disLinePitch* 2) * (numLines + ti) + 838- offset,20);

3.3.3.3. Phương pháp đảo ảnh 180 ͦ :

 Ý tưởng:

Để hiển thị một ảnh xoay ngược 180 ͦ , ta sẽ sử dụng thuật toán đảo ngược dữ liệu của một mảng. Ở đây ta có thể dùng trực tiếp mảng chứa dữ liệu mẫu Y, Cb và Cr từ bộ đệm ảnh đầu vào rồi qua hàm đảo ngược mảng để được một mảng chứa các dữ liệu mẫu Y, Cb và Cr đối ngược với giá trị ban đầu của chúng. Sau đó, ta thực hiện chuyển đổi những màng này thành các dữ liệu RGB và lưu vào bộ đệm ảnh đầu ra. Cuối cùng, ta lại thực hiện lại việc đảo ngược các mảng chứa dữ liệu mẫu Y, Cb và Cr một lần nữa để chúng trở lại trạng thái đầu tiên như khi chưa được tác động. Chú ý, mỗi mảng dữ liệu mẫu mà ta tác động chỉ lưu trữ dữ liệu của một dòng của ảnh đầu vào, vì thế, để hiển thị toàn bộ ảnh, ta phải dùng một vòng lặp để thực hiện thuật toán trên trên tất cả các dòng của ảnh đầu vào.

 Các bước thực hiện:

Bước 1: Xây dựng hàm đảo ngược dữ liệu của một mảng ( tên của hàm này là dao_mang )với các tham số:

+ Con trỏ picture : Đại diện cho mảng chứa dữ liệu mẫu Y, Cb hoặc Cr sẽ được đảo ngược dữ liệu.

+ Tham số size: Đây là một số nguyên không dấu cho biết kích thước của mảng ( hay chính là kích thước của mỗi dòng ảnh đầu vào).

+ Tham số line: Tham số này giúp ta xác định dòng ảnh đầu vào nào sẽ được đảo ngược dữ liệu.

Mã nguồn của hàm dao_mang như sau:

void dao_mang (unsigned char *picture,int size, int line ) {

int ti, tj;

unsigned char temp;

// Dao mang anh de hien thi anh nguoc 180* atp for(ti=0, tj= (size-1); ti< (size/2), tj>((size-2)/2); ti++, tj--)

{

*(picture + line * (size) + ti)= *(picture + line * (size) + tj);

*(picture + line * (size) + tj)= temp; }

}

Bước 2: Gọi hàm đảo ngược mảng trong chương trình chính. Ví dụ:

dao_mang(capFrameBuf->frame.iFrm.y1,capLinePitch, i);

dao_mang(capFrameBuf->frame.iFrm.cr1,capLinePitch, i);

dao_mang(capFrameBuf->frame.iFrm.cb1,capLinePitch, i);

Chú ý, trong chương trình chúng ta chỉ đảo ngược một ảnh grayscale nên chỉ cần đảo ngược mảng dữ liệu mẫu Y.

Bước 3: Gọi hàm chuyển đổi dữ liệu mẫu Y, Cb, Cr thành dữ liệu RGB: yc2rgb16(coeffs, capFrameBuf->frame.iFrm.y1 + i* (capLinePitch) ,

a, a,

disFrameBuf->frame.rpFrm.buf + (disLinePitch) + (disLinePitch* 2) * i +(disLinePitch* 2) * (numLines+16), (disLinePitch/2));

Bước 4: Gọi hàm đảo ngược mảng trong chương trình chính để dữ liệu mẫu Y, Cb. Cr trở về trạng thái ban đầu.

Chương trình trong chương trình chính sẽ như sau:

dao_mang(capFrameBuf->frame.iFrm.y1, capLinePitch, i);

//Hien thi 1/4 man hinh duoi cung, ben phai the hien anh grayscale

(

coeffs, capFrameBuf->frame.iFrm.y1 + i* (capLinePitch),

a, a,

disFrameBuf->frame.rpFrm.buf + (disLinePitch) +

(disLinePitch* 2) * i +(disLinePitch* 2) *

(numLines+16), disLinePitch/2)

);

KẾT LUẬN

Sau một thời gian nghiên cứu và thực hiện đồ án, đồ án đã đạt được một số chỉ tiêu kỹ thuật đặt ra ban đầu . Những thuật toán chạy trên kit đã cho những kết quả gần dúng với lý thuyết. Tuy nhiên vì một số trục trặc về thiết bị nên nhóm chưa kịp ghi lại nhiều những kết qủa đã thực hiện. Hướng phát triển của đồ án trong tương lai là sẽ không chỉ dừng lại ở mức nghiên cứu những thuật toán cơ bản,mà sẽ thực hiện nghiên cứu những vấn đề phục vụ nhiều cho thực tiễn,những ứng dụng của ngành khoa học xử lý video hình ảnh vẫn đang nghiên cứu và hoàn thiện.

Do hạn chế về thời gian, khuôn khổ của đồ án cũng như kinh nghiệm thực tiễn của nhóm chưa nhiều nên không tránh khỏi những sai sót và nhầm lẫn, vì vậy sự đóng góp của thầy cô và các bạn không chỉ giúp đồ án của nhóm có chất lượng cao hơn mà còn trang bị cho chúng em một kiến thức vững vàng hơn trong nghiên cứu và công tác sau này.

DANH MỤC TÀI LIỆU THAM KHẢO

[1] Dwayne Phillips , Image Processing in C , second edition, R & D

Publications ,2000

[2] Shehrzad Qureshi, Embedded image processing on the TMS320C6000 DSP & Example in Code Composer Studio and MATLAB , Springer Science+ Business

Media, 2005

[3] Nguyễn Chí Hướng, Đồ án tốt nghiệp đề tài: “Lập trình một số bài toán cơ bản trong xử lý ảnh số”, Lớp tin học trắc địa K50, Đại học Mỏ Địa Chất

[4] Evaluation Module (EVM)for the TMS320DM642 – Quick start guide, author : www.spectrumdigital.com , truy nhập cuối cùng ngày 04/06/2013

[5] Texas Instruments - The TMS320DM642 Video Port Mini-Driver.

[6] Texas Instruments - TMS320DM642 Video/Imaging Fixed-Point Digital Signal Processor.

[7] Texas Instruments - Driver Examples on the DM642 EVM.

[8] Rulph Chassaing - Digital Signal Processing and Applications with the C6713 and C6416 DSK : Worcester Polytechnic Institute

[9] Texas Instruments - Literature Number: SPRU328B - “ Code Composer Studio

User’s Guide” February 2000.

[10] TS Nguyễn Thanh Bình , ThS Võ Nguyễn Quốc Bảo : Giáo trình xử lý âm thanh và hình ảnh - Học viện công nghệ bưu chính viễn thông.

Một phần của tài liệu Thuật toán xử lý ảnh trên kit DSP (Trang 101 - 113)

Tải bản đầy đủ (PDF)

(113 trang)