Tải bản đầy đủ (.docx) (30 trang)

Tìm hiểu và cài đặt thuật toán tách shen castan

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (341.33 KB, 30 trang )

MỤC LỤC

LỜI MỞ ĐẦU...........................................................................................................2
CHƯƠNG I: KHÁI NIỆM PHƯƠNG PHÁP SHEN-CASTEN..........................3
1. Giới thiệu.........................................................................................................3
2. Khái niệm........................................................................................................4
3. Phương pháp và lý thuyết truyền thống.......................................................5
4. Thuận lợi và khó khăn...................................................................................7
CHƯƠNG II: THUẬT TỐN SHEN-CASTAN...................................................7
1. Nội dụng của thuật toán – xây dựng bộ lọc tối ưu.......................................8
2. Hoạt động của thuật toán.............................................................................10
2.1. Thuật toán...............................................................................................10
2.2. Giải thích thuật tốn..............................................................................10
CHƯƠNG III: CÀI ĐẶT THUẬT TỐN...........................................................12
KẾT LUẬN.............................................................................................................30

1


LỜI MỞ ĐẦU
Thời đại công nghệ thông tin phát triển như vũ bão đã đi vào từng ngõ ngách
của cuộc sống. Hiện nay, bất cứ sự phát triển của ngành cơng nghiệp nào đều có sự
hiện diện và đóng góp rất to lớn của công nghệ thông tin. Xử lý ảnh là một trong
những chuyên ngành quan trọng và lâu đời của Công nghệ thông tin. Xử lý ảnh
được áp dụng trong nhiều lĩnh khác nhau như y học, vật lý, hố học, tìm kiếm tội
phạm, trong qn sự và trong một số lĩnh vực khác....
Phần lớn con người thu nhận thơng tin bằng thị giác, cụ thể đó là các hình
ảnh. Vì vậy xử lý ảnh là vấn đề không thể thiếu và hết sức quan trọng để thu được
hình ảnh tốt hơn, đẹp hơn, nhằm đáp ứng yêu cầu thông tin khác nhau của người
nhận.
Trong xử lý ảnh, việc nhận dạng và phân lớp đối tượng cần trải qua các quá


trình và các thao tác khác nhau. Phát hiện biên là một giai đoạn rất quan trọng vì
các kỹ thuật phân đoạn ảnh chủ yếu dựa vào giai đoạn này. Mục đích của việc dị
biên sẽ đánh dấu những điểm trong một ảnh số mà có sự thay đổi đột ngột về độ
xám, tập hợp nhiều điểm biên tạo nên một đường bao quanh ảnh (đường biên). Nhờ
có đường biên mà chúng ta có thể phân biệt giữa đối tượng và nền, phân biệt giữa
các vùng khác nhau và định vị được đối tượng từ đó mà nhận dạng đối tượng. Đây
là cơ sở quan trọng trong việc ứng dụng phương pháp này vào thực tiễn của cuộc
sống, đặc biệt là trong điều kiện đất nước ta đang từng bước phát triển và đi lên nên
việc nghiên cứu các ứng dụng vấn đề này cần được quan tâm và phát triển. Xuất
phát từ thực tế đó, luận văn lựa chọn đề tài "Tìm hiểu và cài đặt thuật tốn tách
Shen-castan". Mục đích chính của đề tài là hệ thống hóa kiến thức về phương pháp
phát hiện biên, từ các kỹ thuật dị biên cài đặt chương trình để đưa ra các nhận xét,
so sánh, đánh giá về các phương pháp phát hiện biên. Qua đó có cái nhìn tổng quát
về các phương pháp phát hiện biên.
2


CHƯƠNG I: KHÁI NIỆM PHƯƠNG PHÁP SHEN-CASTEN
1. Giới thiệu
Phát hiện cạnh là một trong những thao tác được sử dụng phổ biến nhất trong
phân tích tưởng tượng và có lẽ có nhiều thuật tốn trong tài liệu tiên đốn và
phát hiện các cạnh hơn bất kỳ chủ đề đơn lẻ nào khác. Lý do cho điều này là các
cạnh tạo thành phác thảo của một đối tượng. Một cạnh là liên kết giữa một đối
tượng và nền, và chỉ ra ranh giới giữa các đối tượng chồng chéo. Điều này có
nghĩa là nếu các cạnh trong hình ảnh được xác định chính xác, tất cả các đối
tượng có thể được định vị và các đặc tính cơ bản như diện tích, chu vi và hình
dạng có thể được đo. Tầm nhìn của máy tính liên quan đến việc xác định và
phân loại các đối tượng trong ảnh, phát hiện cạnh là một công cụ thiết yếu.
Về mặt kỹ thuật, phát hiện cạnh là q trình xác định vị trí các pixel cạnh và
tăng cường nêm sẽ tăng độ tương phản giữa các cạnh và mặt sau để các cạnh

trở nên rõ hơn.
Trong thực tế, các thuật ngữ được sử dụng thay thế cho nhau, vì hầu hết các
chương trình phát hiện cạnh cũng đặt các giá trị pixel theo mức độ màu hoặc
màu xám cụ thể để chúng có thể được nhìn thấy dễ dàng. Ngồi ra, theo dõi
cạnh là quá trình theo dõi các cạnh, thường thu thập các pixel cạnh vào một
danh sách. Điều này được thực hiện theo hướng nhất quán, theo chiều kim đồng
hồ hoặc ngược chiều kim đồng hồ xung quanh các đối tượng. Mã hóa chính là
một ví dụ về phương pháp dị tìm cạnh. Kết quả là đại diện anon-raster của các
đối tượng có thể được sử dụng để tính tốn các biện pháp hoặc xác định hoặc
phân loại đối tượng.

3


2. Khái niệm
Shen-Castan Edge Phát hiện là một trong những kỹ thuật phát hiện cạnh
được sử dụng trong xử lý hình ảnh với đầu vào nhiễu. Phát hiện cạnh là một
kỹ thuật xử lý hình ảnh để tìm ranh giới của các đối tượng trong ảnh. Phát
hiện cạnh được sử dụng để phân đoạn hình ảnh và trích xuất dữ liệu trong
các lĩnh vực như xử lý hình ảnh, thị giác máy tính và thị giác máy.

Chức năng này hoạt động cho hình ảnh 8 và 24 bit cho mỗi pixel. Máy dò
cạnh Shen-Castan sử dụng chức năng lọc tối ưu gọi là Bộ lọc số mũ đối xứng
vô hạn (ISEF). Điều này tạo ra tín hiệu tốt hơn cho tỷ lệ nhiễu và nội địa hóa
tốt hơn Canny. Bước đầu tiên là kết hợp hình ảnh đầu vào với ISEF, sau đó
định vị các cạnh bằng cách vượt 0 của Laplacian (tương tự như thuật toán
Marr-Hildreth). Giá trị gần đúng của Laplacian được tính bằng cách trừ hình
ảnh gốc từ hình ảnh được làm mịn. Kết quả là một hình ảnh Laplacian giới
hạn băng tần. Tiếp theo, một hình ảnh Laplacian nhị phân được tạo bằng
cách đặt tất cả các pixel có giá trị dương thành 1 và tất cả các pixel khác

thành 0. Các pixel ứng cử viên nằm trên ranh giới của các vùng trong hình
ảnh nhị phân thứ. Sau khi cải thiện chất lượng của các pixel cạnh bằng cách
triệt tiêu chéo không sai, ngưỡng ngưỡng thích ứng và ngưỡng ngưỡng trễ
được áp dụng cuối cùng.
4


3. Phương pháp và lý thuyết truyền thống
Hầu hết các thuật toán tốt đều bắt đầu bằng một tuyên bố rõ ràng về vấn đề
cần giải quyết và phân tích tổng hợp các phương pháp có thể có của giải pháp
và thứ hai theo đó các phương thức sẽ hoạt động chính xác. Sử dụng phương
pháp này để xác định thuật tốn phát hiện cạnh có nghĩa là sử dụng cạnh đó là
gì, sau đó sử dụng định nghĩa này để đề xuất các phương pháp nâng cao. Một
trong những phiên bản phổ biến nhất và phổ biến nhất là cạnh bước lý tưởng,
được minh họa trong Hình 1:

Trong ví dụ một chiều này, cạnh chỉ đơn giản là một mức ingrey thay đổi xảy
ra tại một vị trí cụ thể. Sự thay đổi càng lớn thì cạnh càng dễ phát hiện, nhưng
trong trường hợp lý tưởng, bất kỳ sự thay đổi cấp độ nào cũng được nhìn thấy
5


khá dễ dàng. Biến chứng đầu tiên xảy ra do số hóa. Khơng chắc là hình ảnh sẽ
được lấy mẫu theo cách sao cho tất cả các cạnh xảy ra tương ứng chính xác với
một ranh giới pixel. Thật vậy, sự thay đổi trong levelmay mở rộng qua một số
pixel (Hình 1 b - d). Vị trí của cạnh được coi là trung tâm của đoạn đường nối
từ mức xám thấp đến mức cao.
*Toán tử phát sinh
Do một cạnh được xác định bởi sự thay đổi về mức độ màu xám, nên một
tốn tử có liên quan đến sự thay đổi này sẽ hoạt động như một máy dò cạnh.

Một vở opera-tor phái sinh làm điều này; một cách giải thích của một đạo hàm
là tốc độ thay đổi của hàm và tốc độ thay đổi của các mức xám trong một hình
ảnh lớn hơn một cạnh và nhỏ trong các vùng khơng đổi. Vì vậy, hình ảnh là hai
chiều, điều quan trọng là phải xem xét sự thay đổi mức độ trong nhiều hướng.
Vì lý do này, các đạo hàm riêng của theimage được sử dụng, liên quan đến các
hướng chính x và y. Một esti của hướng cạnh thực tế có thể thu được bằng cách
sử dụng các dẫn xuất x và y làm thành phần của hướng thực tế dọc theo các
trục, và tính tốn tổng vector:

4. Thuận lợi và khó khăn
6


 Tính năng độc đáo của Phát hiện cạnh Shen-Castan là nó có thể phát
hiện các cạnh của hình ảnh có nhiễu. Bằng cách sử dụng Bộ lọc hàm
mũ đối xứng vơ hạn, nhiễu sẽ được loại bỏ. Ngồi ra, Phát hiện cạnh
Shen-Castan cung cấp khả năng bản địa hóa tốt hơn tốn tử của Canny,
bởi vì việc triển khai thuật toán của Canny xấp xỉ bộ lọc tối ưu của anh
ta bằng đạo hàm của hàm Gaussian, trong khi Phát hiện cạnh ShenCastan sử dụng bộ lọc tối ưu trực tiếp.
 Nhược điểm của Phát hiện cạnh Shen-Castan là thời gian tính tốn /
xử lý dài hơn thuật tốn phát hiện cạnh khác.

CHƯƠNG II: THUẬT TỐN SHEN-CASTAN
Shen-castan có cùng quan điểm với Canny về một mẫu chung trong việc tách
các đường biên. Đó là nhân xoắn ảnh với một mặt nạ làm mịn, sau đó tìm ra điểm
biên. Tuy nhiên trong những phân tích của họ lại tạo ra một hàm khác để tối ưu, đó
là việc đề xuất cực tiểu hóa hàm sau trong khơng gian một chiều:

Nói một cách khác là hàm mà làm cực tiểu ở trên là bộ lọc mịn tối ưu cho
việc tách biên. Tuy nhiên, Shen-castan lại không đề cập đến việc thuật tốn sẽ nhận

ra được nhiều cạnh trong khi chỉ có một cạnh tồn tại.

1. Nội dụng của thuật toán – xây dựng bộ lọc tối ưu

7


Hàm lọc tối ưu được đưa ra là bộ lọc số mũ đối xứng vô cùng Infinite
Symmetric Exponential Filter (ISEF)

Theo Shen và Castan, bộ lọc này cho tỉ lệ giữa tín hiệu và nhiễu tốt hơn so
với bộ lọc của Canny và cho giá trị Localization tốt hơn. Điều này có thể là bởi
vì trong thuật tốn Canny bộ lọc tối ưu được xấp xỉ bằng đạo hàm của bộ lọc
Gauss, trong khi đó Shen và Castan sử dụng bộ lọc tối ưu một cách trực tiếp,
hoặc cũng có thể là do những tiêu chuẩn tối ưu khác nhau được thể hiện khác
nhau trong thực tế. Tuy nhiên Shen - Castan lại không đưa ra những tiêu chuẩn
đa đáp ứng (multiple- reponse), nên rất có thể phương pháp của họ có thể sinh
ra nhiễu và làm mờ biên.
Bộ lọc ISEF trong khơng gian hai chiều có cơng thức:

Hàm lọc này là hàm thực hiện liên tục. Cơng thức này có thể được áp dụng
vào hình ảnh theo cách tương tự đã làm với đạo hàm của bộ lọc Gauss, như là
lọc theo hướng x và theo hướng y. Tuy nhiên Shen-castan đã cải tiến theeo một
bước khi đưa ra bộ lọc của họ như một hàm lọc đệ quy một chiều.
Trong trường hợp khơng liên tục, hàm lọc có dạng:

với b là tham só lọc (0
8



Để nhân xoắn một ảnh cùng với hàm lọc này thì việc lọc đệ quy được làm
trước tạo r (i, j)

Cùng với các điều kiện sau:

Sau đó việc lọc được thực hiện theo hướng y và những tính tốn riêng r (i, j)
sẽ tạo ra kết quả y (i, j)

Cùng với các điều kiện sau:

Sử dụng bộ lcoj đệ quy làm tăng tốc độ nhân xoắn lên nhiều.
Sau khi nhận được ảnh lọc, vấn đề đặt ra là phải phát hiện được các
điểm biên.
9


Biên được nhận dạng bằng việc tìm các điểm giao không trong đạo hàm bậc
hai, những điểm ảnh tại vị trí này được đánh dấu.
Giao điểm khơng tại điểm P có nghĩa rằng hai điểm láng giềng đối nhau qua
giao điểm khơng có tín hiệu khác nhau. Ví dụ, nếu biên di qua P là dọc thì điểm
ảnh bên trái P sẽ có tín hiệu khác so với điểm ảnh ở bên phải P. Vì thế, có 4
trường hợp để kiểm tra đó là: trên/dưới, trái/phải và hai đường chéo. Sự kiểm
tra này được thực hiện bằng hàm Zezo-cross. Sau đó q trình phân ngưỡng
được thực hiện.

2. Hoạt động của thuật tốn
2.1. Thuật tốn
Dựa trên những phân tích ở trên, ta có thể đưa ra một thuật tốn phát
hiện biên Shen-castan gồm các bước xử lý sau:

B1: Đọc ảnh từ tệp để xử lý
B2: Lọc ảnh bằng phương pháp lọc đệ quy
B3: Tìm các giao điểm khơng sau khi áp dụng tốn tử Laplace
B4: Thực hiện q trình phân ngưỡng
2.2.

Giải thích thuật tốn
-Đọc ảnh cần xử lý, rồi tiến hành lọc ảnh theo bước 2 bằng đệ quy

hàm ISEF.
Việc lọc được thực hiện theo chiều dọc và cả chiều ngang, giá trị b là tham
số để lọc và được nhập bởi người sử dụng.
Để tìm ra được biên ảnh (B3) ta áp dụng tốn tử Laplace rồi tìm các
giao điểm khơng. Tuy nhiên theo Shen-castan thì sự xấp xỉ tốn tử Laplace
10


có thể thu được một cách nhanh chóng bằng việc lấy ảnh gốc trừ đi ảnh đã
được làm mịn và tạo ra ảnh nhị phân. Nếu S là ảnh lọc và I là ảnh gốc, ta có:

Ảnh kết quả B=S-I được nhị phân hóa bằng cách đặt các điểm có giá trị
dương trong ảnh B là 1 và các điểm khác là 0, các điểm khác nằm trên đường
biên giữa vùng có thể được coi là những điểm cạnh.
Tuy nhiên, ta có thể nâng cao chất lượng của việc nhận dạng các điểm
biên bằng các phương pháp khác nhau như:
+Phương pháp loại bỏ giao điểm không lỗi
Phương pháp này tương đương với nommax_suppress tròn Canny: tại
mỗi điểm được coi là biên, đạo hàm bậc hai tại điểm này sẽ là giao điểm
khơng. Tức là Gradient tại điểm đó hoặc là Max hoặc Min. Nếu lấy dấu đạo
hàm bậc hai thay đổi từ (+) sang (-) thì giao điểm khơng đó là giao điểm

không âm, giả thiết rằng những giao điểm khơng dương sẽ có Gradient
dương, những giao điểm khơng âm sẽ có Gradient âm. Tất cả các điểm khơng
khác đều là sai và không được coi là điểm biên.
-Bước thú 4 trong thuật toán là phân ngưỡng: áp dụng phân ngưỡng trễ
tương tự như thuật toán của Canny.

11


CHƯƠNG III: CÀI ĐẶT THUẬT TOÁN
#include <stdio.h>
#include <string.h>
#include <math.h>
#define MAX
#include “lib.h”
#define OUTLINE 25
/ * Nguyên mẫu hàm * /
void main( int argc, char **argv);
void shen(IMAGE im, IMAGE res);
void compute_ISEF (float **x, float **y, int nrows, int ncols);
float ** f2d (int nr, int nc);
void apply_ISEF_vertical (float **x, float **y, float **A, float **B,
int nrows, int ncols);
void apply_ISEF_horizontal (float **x, float **y, float **A, float **B,
int nrows, int ncols);
IMAGE compute_bli (float **buff1, float **buff2, int nrows, int ncols);
void locate_zero_crossings (float **orig, float **smoothed, IMAGE bli,
int nrows, int ncols);
void threshold_edges (float **in, IMAGE out, int nrows, int ncols);
int mark_connected (int i, int j,int level);

int is_candidate_edge (IMAGE buff, float **orig, int row, int col);
float compute_adaptive_gradient (IMAGE BLI_buffer, float **orig_buffer,
int row, int col);
void estimate_thresh (double *low, double *hi, int nr, int nc);
void debed (IMAGE im, int width);
void embed (IMAGE im, int width);
*/Toán tử shen*/
12


double b = 0.9;

/* Hệ số làm mịn 0
double low_thresh=20, high_thresh=22

/* Ngưỡng cho độ trễ */

double ratio = 0.99;
int window_size = 7;
int do_hysteresis = 1;
float **lap;
int nr, nc;

/* Theo dõi laplacian của hình ảnh */
/* nrows, ncols */

IMAGE edges;

/ * Theo dõi các điểm cạnh (ngưỡng) */


int thinFactor;
void main(int argc, char **argv)
{
int i,j,n,m;
IMAGE im, res;
FILE *params;
/ * Dịng lệnh args - tên tệp, có thể sigma */
if (argc < 2)
{
printf (“USAGE: shen <inmagefile>\n”);
exit (1);
}
im = Input_PBM (argv[1]);
if (im == 0)
{
printf (“Can’t read input image from ‘%s’.\n”, argv[1]);
exit (2);
}
13


/* Tìm tệp tham số */
params = fopen (“shen.par”, “r”);
if (params)
{
fscanf (params, “%lf”, &ratio);
fscanf (params, “%lf”, &b);
if (b<0) b = 0;
else if (b>1.0) b = 1.0;

fscanf (params, “%d”, &window_size);
fscanf (params, “%d”, &thinFactor);
fscanf (params, “%d”, &do_hysteresis);
printf (“Parameters:\n”);
printf (“ %% of pixels to be above HIGH threshold: %7.3f\n”, ratio);
printf (“ Size of window for adaptive gradient : %3d\n”,
window_size);
printf (“ Thinning factor
printf (“Smoothing factor

: %d\n”, thinFactor);
: %7.4f\n”, b);

if (do_hysteresis) printf (“Hysteresis thresholding turned on.\n”);
else printf (“Hysteresis thresholding turned off.\n”);
fclose (params);
}
else printf (“Parameter file ‘shen.par’ does not exist.\n”);
embed (im, OUTLINE);
res = newimage (im->info->nr, im->info->nc);
shen (im, res);
debed (res, OUTLINE);
Output_PBM (res, “shen.pgm”);
printf (“Output file is ‘shen.pgm’\n”);
14


}
void shen (IMAGE im, IMAGE res)
{

register int i,j;
float **buffer;
float **smoothed_buffer;
IMAGE bli_buffer;
/ * Chuyển đổi hình ảnh đầu vào thành điểm nổi */
buffer = f2d (im->info->nr, im->info->nc);
for (i=0; i<im->info->nr; i++)
for (j=0; j<im->info->nc; j++)
buffer[i][j] = (float)(im->data[i][j]);
/ * Làm mịn hình ảnh đầu vào bằng bộ lọc ISEF được triển khai đệ quy */
smoothed_buffer = f2d( im->info->nr, im->info->nc);
compute_ISEF (buffer, smoothed_buffer, im->info->nr, im->info->nc);
/* Tính tốn hình ảnh laplacian giới hạn băng hình ảnh từ hình ảnh được làm
mịn */
bli_buffer = compute_bli(smoothed_buffer,
buffer,im->info->nr,im->info->nc);
/*Thực hiện phát hiện cạnh bằng cách sử dụng ngưỡng bli và gradient */
locate_zero_crossings (buffer, smoothed_buffer, bli_buffer,
im->info->nr, im->info->nc);
free(smoothed_buffer[0]); free(smoothed_buffer);
15


freeimage (bli_buffer);
threshold_edges (buffer, res, im->info->nr, im->info->nc);
for (i=0; i<im->info->nr; i++)
for (j=0; j<im->info->nc; j++)
if (res->data[i][j] > 0) res->data[i][j] = 0;
else res->data[i][j] = 255;
free(buffer[0]); free(buffer);

}
/ * Hiện thực hóa bộ lọc đệ quy của ISEF*/
void compute_ISEF (float **x, float **y, int nrows, int ncols)
{
float **A, **B;
A = f2d(nrows, ncols); / * lưu trữ thành phần nhân quả * /
B = f2d(nrows, ncols); / * lưu trữ thành phần chống nhân quả * /
/ * Trước tiên áp dụng bộ lọc theo hướng dọc (cho các hàng)*/
apply_ISEF_vertical (x, y, A, B, nrows, ncols);
/ *Bây giờ áp dụng bộ lọc theo hướng ngang (cho các cột) và áp dụng bộ lọc
này cho kết quả của bộ trước đó * /
apply_ISEF_horizontal (y, y, A, B, nrows, ncols);
/* Giải phóng bộ nhớ */
free (B[0]); free(B);
free (A[0]); free(A);
}
void apply_ISEF_vertical (float **x, float **y, float **A, float **B,
16


int nrows, int ncols)
{
register int row, col;
float b1, b2;
b1 = (1.0 - b)/(1.0 + b);
b2 = b*b1;
/* Tính tốn điều kiện biên */
for (col=0; col{
/*Ranh giới tồn tại cho cột thứ 1 và cuối cùng*/

A[0][col] = b1 * x[0][col];
B[nrows-1][col] = b2 * x[nrows-1][col];
}
/ * tính thành phần nguyên nhân*/
for (row=1; rowfor (col=0; colA[row][col] = b1 * x[row][col] + b * A[row-1][col];
/ * Tính thành phần chống nhân quả */
for (row=nrows-2; row>=0; row--)
for (col=0; colB[row][col] = b2 * x[row][col] + b * B[row+1][col];
/ * Trường hợp ranh giới cho đầu ra tính tốn của bộ lọc đầu tiên */
for (col=0; col17


y[nrows-1][col] = A[nrows-1][col];
/ * Bây giờ tính tốn đầu ra của bộ lọc đầu tiên và lưu trữ trong y * /
/ * Đây là tổng của các thành phần nhân quả và chống nhân quả * /
for (row=0; rowfor (col=0; coly[row][col] = A[row][col] + B[row+1][col];
}
void apply_ISEF_horizontal (float **x, float **y, float **A, float **B,
int nrows, int ncols)
{
register int row, col;
float b1, b2;
b1 = (1.0 - b)/(1.0 + b);
b2 = b*b1;

/ * Tính các điều kiện biên * /
for (row=0; row{
A[row][0] = b1 * x[row][0];
B[row][ncols-1] = b2 * x[row][ncols-1];
}
/ * Tính thành phần nguyên nhân * /
for (col=1; colfor (row=0; rowA[row][col] = b1 * x[row][col] + b * A[row][col-1];
/ * Tính thành phần chống nguyên nhân * /
for (col=ncols-2; col>=0; col--)
for (row=0; row18


B[row][col] = b2 * x[row][col] + b * B[row][col+1];
/ * Trường hợp ranh giới cho đầu ra tính tốn của bộ lọc đầu tiên */
for (row=0; rowy[row][ncols-1] = A[row][ncols-1];
/ * Bây giờ tính tốn đầu ra của bộ lọc thứ hai và lưu trữ trong y */
/ * Đây là tổng của các thành phần nhân quả và chống nhân quả */
for (row=0; rowfor (col=0; coly[row][col] = A[row][col] + B[row][col+1];
}
/ * Tính tốn laplacian giới hạn băng tần của hình ảnh đầu vào */
IMAGE compute_bli (float **buff1, float **buff2, int nrows, int ncols)
{
register int row, col;

IMAGE bli_buffer;

bli_buffer = newimage(nrows, ncols);
for (row=0; row19


for (col=0; colbli_buffer->data[row][col] = 0;
for (row=0; rowfor (col=0; col{
if (row<OUTLINE || row >= nrows-OUTLINE ||
col<OUTLINE || col >= ncols-OUTLINE) continue;
bli_buffer->data[row][col] =
((buff1[row][col] - buff2[row][col]) > 0.0);
}
return bli_buffer;
}
void locate_zero_crossings (float **orig, float **smoothed, IMAGE bli,
int nrows, int ncols)
{
register int row, col;
for (row=0; row{
for (col=0; col{
/ * Bỏ qua các pixel xung quanh đường biên của hình ảnh */
if (row<OUTLINE || row >= nrows-OUTLINE ||
col<OUTLINE || col >= ncols-OUTLINE)

{
orig[row][col] = 0.0;
}
20


/ * Kiểm tra tiếp theo nếu pixel là điểm giao nhau của laplacian */
else if (is_candidate_edge (bli, smoothed, row, col))
{
/*Bây giờ làm ngưỡng */
float grad = compute_adaptive_gradient (bli, smoothed, row, col);
orig[row][col] = grad;
}
else orig[row][col] = 0.0;
}
}
}
void threshold_edges (float **in, IMAGE out, int nrows, int ncols)
{
register int i, j;
lap = in;
edges = out;
nr = nrows;
nc = ncols;
estimate_thresh (&low_thresh, &high_thresh, nr, nc);
if (!do_hysteresis)
low_thresh = high_thresh;
for (i=0; ifor (j=0; jedges->data[i][j] = 0;

for (i=0; ifor (j=0; j{
21


if (i<OUTLINE || i >= nrows-OUTLINE ||
j<OUTLINE || j >= ncols-OUTLINE) continue;
/ * Chỉ kiểm tra một đường viền nếu nó ở trên high_thresh */
if ((lap[i][j]) > high_thresh)
/ * Đánh dấu tất cả các điểm được kết nối trên ngưỡng thấp */
mark_connected (i,j,0);
}
/* Xóa tất cả các điểm là 255*/
for (i=0; ifor (j=0; jif (edges->data[i][j] == 255) edges->data[i][j] = 0;
}
/* Trả về true nếu đánh dấu thứ gì đó */
int mark_connected (int i, int j, int level)
{
int notChainEnd;
/* Dừng lại nếu đi ra khỏi cạnh của hình ảnh */
if (i >= nr || i < 0 || j >= nc || j < 0) return 0;
/* Dừng lại nếu điểm đã được truy cập */
if (edges->data[i][j] != 0) return 0;
/* Dừng lại khi chạm vào một ranh giới hình ảnh */
22



if (lap[i][j] == 0.0) return 0;
if ((lap[i][j]) > low_thresh)
{
edges->data[i][j] = 1;
}
else
{
edges->data[i][j] = 255;
}
notChainEnd =0;
notChainEnd |= mark_connected(i ,j+1, level+1);
notChainEnd |= mark_connected(i ,j-1, level+1);
notChainEnd |= mark_connected(i+1,j+1, level+1);
notChainEnd |= mark_connected(i+1,j , level+1);
notChainEnd |= mark_connected(i+1,j-1, level+1);
notChainEnd |= mark_connected(i-1,j-1, level+1);
notChainEnd |= mark_connected(i-1,j , level+1);
notChainEnd |= mark_connected(i-1,j+1, level+1);
if (notChainEnd && ( level > 0 ) )
{
/*Làm một số đường viền mỏng*/
if ( thinFactor > 0 )
if ( (level%thinFactor) != 0 )
{
/* Xóa điểm này*/
edges->data[i][j] = 255;
23


}

}
return 1;
}
* Tìm thấy điểm giao nhau bằng 0 trong nguồn gốc laplacian (buff) là hình
ảnh được làm mịn*/
int is_candidate_edge (IMAGE buff, float **orig, int row, int col)
{
/* Một z-c dương phải có đạo hàm 1 dương, trong đó dương
z-c có nghĩa là đạo hàm thứ hai đi từ + đến - khi chúng ta vượt qua cạnh
*/
if (buff->data[row][col] == 1 && buff->data[row+1][col] == 0) /* z-c dương */
{
if (orig[row+1][col] - orig[row-1][col] > 0) return 1;
else return 0;
}
else if (buff->data[row][col] == 1 && buff->data[row][col+1] == 0 ) /*z-c dương*/
{
if (orig[row][col+1] - orig[row][col-1] > 0) return 1;
else return 0;
}
else if ( buff->data[row][col] == 1 && buff->data[row-1][col] == 0) /*z-c âm */
{
if (orig[row+1][col] - orig[row-1][col] < 0) return 1;
else return 0;
}
24


else if (buff->data[row][col] == 1 && buff->data[row][col-1] == 0 ) /*z-c dương*/
{

if (orig[row][col+1] - orig[row][col-1] < 0) return 1;
else return 0;
}
else /* Không phải là z-c*/
return 0;
}
float compute_adaptive_gradient (IMAGE BLI_buffer, float **orig_buffer,
int row, int col)
{
register int i, j;
float sum_on, sum_off;
float avg_on, avg_off;
int num_on, num_off;
sum_on = sum_off = 0.0;
num_on = num_off = 0;
for (i= (-window_size/2); i<=(window_size/2); i++)
{
for (j=(-window_size/2); j<=(window_size/2); j++)
{
if (BLI_buffer->data[row+i][col+j])
{
sum_on += orig_buffer[row+i][col+j];
num_on++;
}
else
{
25