Gaussian Blur được triển khai như thế nào?


42

Tôi đã đọc rằng làm mờ được thực hiện trong đồ họa thời gian thực bằng cách thực hiện trên một trục và sau đó theo trục khác.

Tôi đã thực hiện một chút tích chập trong 1D trong quá khứ nhưng tôi không siêu thoải mái với nó, cũng không biết chính xác những gì để kết hợp trong trường hợp này.

Bất cứ ai cũng có thể giải thích một cách đơn giản làm thế nào một Gaussian Blur của hình ảnh được thực hiện?

Tôi cũng đã nghe nói rằng bán kính của Blur có thể ảnh hưởng đến hiệu suất. Đó có phải là do phải làm một tích chập lớn hơn?

Câu trả lời:


48

Trong tích chập, hai hàm toán học được kết hợp để tạo ra hàm thứ ba. Trong các chức năng xử lý hình ảnh thường được gọi là hạt nhân. Một hạt nhân không có gì khác ngoài một mảng (vuông) pixel (một hình ảnh nhỏ để nói). Thông thường, các giá trị trong kernel cộng lại thành một. Điều này là để đảm bảo không có năng lượng được thêm hoặc xóa khỏi hình ảnh sau khi hoạt động.

Cụ thể, hạt nhân Gaussian (được sử dụng cho mờ Gaussian) là một mảng pixel vuông trong đó các giá trị pixel tương ứng với các giá trị của đường cong Gaussian (ở dạng 2D).

Hình ảnh được liên kết từ http://homepages.inf.ed.ac.uk/rbf/HIPR2/gsmooth.htmlm

Mỗi pixel trong ảnh được nhân với nhân Gaussian. Điều này được thực hiện bằng cách đặt pixel trung tâm của kernel trên pixel hình ảnh và nhân các giá trị trong ảnh gốc với các pixel trong kernel trùng nhau. Các giá trị kết quả từ các phép nhân này được thêm vào và kết quả đó được sử dụng cho giá trị tại pixel đích. Nhìn vào hình ảnh, bạn sẽ nhân giá trị tại (0,0) trong mảng đầu vào với giá trị tại (i) trong mảng kernel, giá trị tại (1,0) trong mảng đầu vào với giá trị tại (h ) trong mảng kernel, v.v. và sau đó thêm tất cả các giá trị này để lấy giá trị cho (1,1) ở hình ảnh đầu ra.

Hình ảnh được liên kết từ http://www.songho.ca/dsp/convolution/convolution.html

Để trả lời câu hỏi thứ hai của bạn trước, hạt nhân càng lớn, thao tác càng tốn kém. Vì vậy, bán kính mờ càng lớn, thao tác sẽ mất nhiều thời gian hơn.

Để trả lời câu hỏi đầu tiên của bạn, như đã giải thích ở trên, tích chập có thể được thực hiện bằng cách nhân từng pixel đầu vào với toàn bộ kernel. Tuy nhiên, nếu hạt nhân đối xứng (mà là hạt nhân Gaussian), bạn cũng có thể nhân độc lập từng trục (x và y), điều này sẽ làm giảm tổng số phép nhân. Theo thuật ngữ toán học thích hợp, nếu một ma trận có thể tách rời, nó có thể được phân tách thành ma trận (M × 1) và (1 × N). Đối với nhân Gaussian ở trên, điều này có nghĩa là bạn cũng có thể sử dụng các hạt nhân sau:

1256[1464141624164624362464162416414641]= =1256[14641][14641]

Bây giờ bạn sẽ nhân từng pixel trong ảnh đầu vào với cả hai nhân và thêm các giá trị kết quả để lấy giá trị cho pixel đầu ra.

Để biết thêm thông tin về cách xem một hạt nhân có thể tách rời, hãy theo liên kết này .

Chỉnh sửa: hai hạt nhân hiển thị ở trên sử dụng các giá trị hơi khác nhau. Điều này là do tham số (sigma) được sử dụng cho đường cong Gaussian để tạo các hạt nhân này hơi khác nhau trong cả hai trường hợp. Để giải thích về các tham số ảnh hưởng đến hình dạng của đường cong Gaussian và do đó, các giá trị trong nhân theo liên kết này

Chỉnh sửa: trong hình ảnh thứ hai ở trên, nó nói kernel được sử dụng được lật. Điều này tất nhiên chỉ làm cho bất kỳ sự khác biệt nếu hạt nhân bạn sử dụng không đối xứng. Lý do tại sao bạn cần lật hạt nhân phải làm với các thuộc tính toán học của hoạt động tích chập (xem liên kết để được giải thích sâu hơn về tích chập). Nói một cách đơn giản: nếu bạn không lật kernel, kết quả của thao tác tích chập sẽ được lật. Bằng cách lật kernel, bạn sẽ có được kết quả chính xác.


1
Bạn có thể thêm một ghi chú ngắn gọn để giải thích tại sao hai hạt nhân 5 x 5 khác nhau có số hơi khác nhau (một tổng là 273, còn lại là 256) không? Có vẻ như một sự nhầm lẫn tiềm năng cho một người mới làm điều này.
trichoplax

Tương tự, bạn có thể giải thích tại sao kernel bị lật trong sơ đồ thứ hai của bạn không? Tôi không nghĩ nó có liên quan đến lời giải thích, nhưng thực tế rằng đó là một bước bổ sung rõ ràng có thể cản trở sự hiểu biết với người không biết rằng điều đó là không cần thiết.
trichoplax

đừng quên làm việc trong không gian màu tuyến tính để có kết quả chính xác.
v.oddou

16

Đây là bài viết tốt nhất mà tôi đã đọc về chủ đề: Làm mờ hiệu quả Gaussian với lấy mẫu tuyến tính . Nó giải quyết tất cả các câu hỏi của bạn và thực sự có thể truy cập.

Đối với người giải thích rất ngắn gọn: Gaussian là một hàm có đặc tính tốt là có thể tách rời, có nghĩa là hàm Gaussian 2D có thể được tính bằng cách kết hợp hai hàm Gaussian 1D.

Vì vậy, đối với kích thước ( ), bạn chỉ cần đánh giá giá trị ( ), ít hơn đáng kể. Nếu thao tác của bạn bao gồm đọc một phần tử kết cấu (thường được gọi là "vòi" ), thì đó là một tin tốt: ít vòi hơn rẻ hơn vì tìm nạp kết cấu có chi phí.viết sai rồi×viết sai rồiÔi(viết sai rồi2)2×viết sai rồiÔi(viết sai rồi)

Đó là lý do tại sao các thuật toán làm mờ sử dụng thuộc tính đó bằng cách thực hiện hai lần chuyền, một để làm mờ theo chiều ngang bằng cách thu thập pixel ngang và một để làm mờ theo chiều dọc bằng cách thu thập pixel dọc. Kết quả là màu pixel bị mờ cuối cùng.viết sai rồiviết sai rồi


13

Nói chung, tích chập được thực hiện bằng cách lấy tích phân của hai hàm trong một cửa sổ trượt, nhưng nếu bạn không đến từ nền toán học, đó không phải là một lời giải thích rất hữu ích và chắc chắn sẽ không cung cấp cho bạn một trực giác hữu ích cho nó. Trực giác hơn, tích chập cho phép nhiều điểm trong tín hiệu đầu vào ảnh hưởng đến một điểm duy nhất trên tín hiệu đầu ra.

Vì bạn không thực sự thoải mái với các kết cấu, trước tiên, hãy xem lại ý nghĩa của một tích chập trong một bối cảnh riêng biệt như thế này, và sau đó đi qua một vệt mờ đơn giản hơn.

Trong bối cảnh riêng biệt của chúng tôi, chúng tôi có thể nhân hai tín hiệu của mình bằng cách nhân từng mẫu tương ứng. Tích phân cũng đơn giản để thực hiện một cách riêng biệt, chúng tôi chỉ cần thêm từng mẫu trong khoảng thời gian chúng tôi tích hợp. Một tích chập rời rạc đơn giản là tính trung bình động. Nếu bạn muốn lấy trung bình di chuyển của 10 mẫu, điều này có thể được coi là kết hợp tín hiệu của bạn bằng cách phân phối 10 mẫu dài và 0,1, mỗi mẫu trong cửa sổ trước tiên được nhân với 0,1, sau đó tất cả 10 mẫu được thêm vào để tạo ra Trung bình. Điều này cũng cho thấy một sự khác biệt thú vị và quan trọng, khi bạn làm mờ với tích chập, phân phối mà bạn sử dụng phải tổng bằng 1.0 trên tất cả các mẫu của nó, nếu không, nó sẽ tăng hoặc giảm độ sáng tổng thể của hình ảnh khi bạn áp dụng nó.

Bây giờ chúng tôi đã xem xét các kết luận, chúng tôi có thể chuyển sang làm mờ. Làm mờ Gaussian được thực hiện bằng cách tạo một hình ảnh bằng phân phối Gaussian. Các hiệu ứng làm mờ khác thường được thực hiện bằng cách tạo hình ảnh bằng các bản phân phối khác. Làm mờ đơn giản nhất là làm mờ hộp và nó sử dụng cùng một phân phối mà chúng tôi đã mô tả ở trên, một hộp có diện tích đơn vị. Nếu chúng ta muốn làm mờ một khu vực 10 x 10, thì chúng ta nhân mỗi mẫu trong hộp với 0,01, sau đó tổng hợp tất cả chúng lại với nhau để tạo ra pixel trung tâm. Chúng tôi vẫn cần đảm bảo rằng tổng số của tất cả các mẫu trong phân phối mờ của chúng tôi là 1.0 để đảm bảo hình ảnh không bị sáng hơn hoặc tối hơn.

Làm mờ Gaussian theo quy trình rộng tương tự như làm mờ hộp, nhưng nó sử dụng một công thức phức tạp hơn để xác định các trọng số. Phân phối có thể được tính dựa trên khoảng cách từ tâm r, bằng cách đánh giá Tổng của tất cả các mẫu trong Gaussian cuối cùng sẽ là xấp xỉ 1.0 nếu bạn lấy mẫu từng pixel, nhưng thực tế là Gaussian có hỗ trợ vô hạn (nó có giá trị ở mọi nơi) có nghĩa là bạn cần sử dụng một phiên bản sửa đổi một chút, tổng bằng 1.0 chỉ sử dụng một vài giá trị.

e-x2/22π

Tất nhiên cả hai quá trình này có thể rất tốn kém nếu bạn thực hiện chúng trên bán kính rất lớn, vì bạn cần lấy mẫu rất nhiều pixel để tính toán độ mờ. Đây là nơi mà mẹo cuối cùng xuất hiện: cả mờ Gaussian và mờ hộp là những gì được gọi là mờ "có thể tách rời". Điều này có nghĩa là nếu bạn thực hiện làm mờ dọc theo một trục và sau đó thực hiện nó dọc theo trục kia, nó sẽ tạo ra kết quả chính xác giống như khi bạn thực hiện nó dọc theo cả hai trục cùng một lúc. Điều này có thể rất quan trọng. Nếu độ mờ của bạn là 10px, nó yêu cầu 100 mẫu ở dạng ngây thơ, nhưng chỉ 20 khi tách ra. Sự khác biệt chỉ trở nên lớn hơn, vì độ mờ kết hợp là , trong khi dạng tách biệt là .O ( n )Ôi(viết sai rồi2)Ôi(viết sai rồi)


1
Nhìn vào câu trả lời khác của bạn, có vẻ như nền tảng toán học của bạn tốt hơn tôi đã làm việc cùng, nhưng tôi hy vọng rằng nó vẫn đi sâu vào chi tiết đầy đủ để có ích. Tôi muốn nó hữu ích cho mọi người ở bất kỳ nền tảng nào.
porglezomp

1
Nếu bạn đang nói chuyện với tôi, không phải tất cả. Câu trả lời của bạn và của Bert là giác ngộ đáng kinh ngạc. Cảm ơn bạn rất nhiều! Bây giờ hãy tiêu hóa thông tin một chút (:
Alan Wolfe

11

Ôi(viết sai rồi2)Ôi(viết sai rồi)

Nhưng có hai thủ thuật nữa bạn có thể muốn xem xét khi triển khai thực tế:

Bộ lọc có bán kính nhất định và do đó, tại các đường viền, bạn sẽ cần tính toán với các pixel nằm ngoài hình ảnh. Trong trường hợp như vậy, bạn có thể thử một trong các cách sau: đối với các pixel bên ngoài, bạn chỉ cần lấy giá trị cuối cùng có thể (nghĩa là pixel ở chính viền, như trong max(x, 0). Hoặc bạn có thể "phản chiếu" hình ảnh ra bên ngoài (như trong x < 0 ? -x : x). Hoặc bạn có thể chỉ cần dừng lại ở đường viền nhưng sau đó bạn sẽ cần điều chỉnh mẫu số trong bộ lọc tích chập để nó tính tổng đến 1. Ví dụ:

tổng1256[1464141624164624362464162416414641]= =tổng1225[0000001624160024361600162416000000]= =1.
     1
    1 1
   1 2 1
  1 3 3 1
[1 4 6 4 1]
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.