2013-02-08 83 views
14

Tôi muốn cố gắng viết một hàm đơn giản để làm mịn hình ảnh được nhập. Tôi đã cố gắng để làm điều này bằng cách sử dụng hình ảnh và thư viện uể oải. Tôi đã nghĩ rằng sử dụng một mặt nạ chập chững sẽ là một cách tiếp cận cho vấn đề này và tôi biết numpy có một chức năng convolve xây dựng inLàm mịn hình ảnh bằng Python

Làm cách nào để sử dụng numpy.convolve để làm mịn hình ảnh?

+2

Bạn có lẽ sẽ cần một dây leo 2d, ví dụ 'scipy.signal.convolve2d' – wim

Trả lời

16

Câu hỏi hay! tcaswell đăng ở đây là một gợi ý tuyệt vời, nhưng bạn sẽ không học nhiều theo cách này bởi vì scipy đang làm tất cả công việc cho bạn! Vì câu hỏi của bạn nói rằng bạn muốn thử và viết hàm, tôi sẽ cho bạn thấy một cách thô lỗ và cơ bản hơn để làm tất cả bằng tay với hy vọng rằng bạn sẽ hiểu rõ hơn về toán học sau convolution, v.v. có thể cải thiện nó bằng những ý tưởng và nỗ lực của riêng bạn!

Lưu ý: Bạn sẽ nhận được kết quả khác nhau với các hình dạng/kích thước khác nhau của hạt nhân, Gaussian là cách thông thường nhưng bạn có thể thử một số khác cho vui (cosin, tam giác, v.v.). Tôi vừa tạo ra cái này ngay tại chỗ, tôi nghĩ đó là một loại hình kim tự tháp.

import scipy.signal 
import numpy as np 
import matplotlib.pyplot as plt 

im = plt.imread('example.jpg') 
im /= 255. # normalise to 0-1, it's easier to work in float space 

# make some kind of kernel, there are many ways to do this... 
t = 1 - np.abs(np.linspace(-1, 1, 21)) 
kernel = t.reshape(21, 1) * t.reshape(1, 21) 
kernel /= kernel.sum() # kernel should sum to 1! :) 

# convolve 2d the kernel with each channel 
r = scipy.signal.convolve2d(im[:,:,0], kernel, mode='same') 
g = scipy.signal.convolve2d(im[:,:,1], kernel, mode='same') 
b = scipy.signal.convolve2d(im[:,:,2], kernel, mode='same') 

# stack the channels back into a 8-bit colour depth image and plot it 
im_out = np.dstack([r, g, b]) 
im_out = (im_out * 255).astype(np.uint8) 

plt.subplot(2,1,1) 
plt.imshow(im) 
plt.subplot(2,1,2) 
plt.imshow(im_out) 
plt.show() 

enter image description here

+0

bạn có biết nếu có một sự khác biệt thực sự giữa' scipy.signals.convolve2d' và 'scipy.ndimage.convolve', vì cả hai dường như làm điều tương tự với các đối số hơi khác nhau. – tacaswell

+0

Tôi nghĩ rằng sau này được khái quát hóa với kích thước cao hơn, trước đây là chỉ định cho mảng 2d. Tuy nhiên, bạn thường không muốn 'bôi nhọ' các kênh màu vào nhau, vì vậy sẽ rất lạ khi sử dụng hạt nhân 3D cho một hình ảnh. – wim

+0

xin lỗi, câu hỏi ngu ngốc sau khi tôi nhận xét trong câu trả lời của tôi rằng 'convolve' đi đến kích thước cao hơn ..... nghĩ rằng đó là thời gian để đi ngủ. – tacaswell

16

Bạn muốn xem ndimage, là một mô-đun trong scipy. Nó có một số bộ lọc tất cả được thiết lập làm chức năng và trình bao bọc đẹp cho các hạt nhân tùy ý xoay vòng.

Ví dụ,

img_gaus = ndimage.filters.gaussian_filter(img, 2, mode='nearest') 

convolves hình ảnh của bạn với một Guassian với sigma của 2.

Nếu bạn muốn Convolve một hạt nhân tùy ý, nói một chéo

k = np.array([[0, 1, 0], 
       [1, 1, 1], 
       [0, 1, 0]]) 

img2 = ndimage.convolve(img, k, mode='constant') 

Những chức năng cũng tốt cho các kích thước cao hơn, vì vậy bạn có thể sử dụng mã gần như giống hệt nhau (chỉ cần mở rộng kích thước của hạt nhân) để làm mịn dữ liệu ở kích thước cao hơn. Các thông số

Các tham số modecval kiểm soát cách các giao thức xử lý pixel ở cạnh hình ảnh của bạn (đối với pixel trên cạnh, một nửa diện tích hạt nhân cần xem không tồn tại, vì vậy bạn cần chọn một cái gì đó để pad hình ảnh của bạn ra với).

4

Nếu bạn không muốn sử dụng scipy, bạn có ba lựa chọn:

1), bạn có thể sử dụng định lý chập kết hợp với biến đổi Fourier từ NumPy có 2D FFT.

2) bạn có thể sử dụng một hạt nhân có thể phân tách và sau đó bạn có thể thực hiện hai chuyển đổi 1D trên các mảng phẳng, một ở hướng x và hướng khác theo hướng y (ravel transpose). kết quả là sự chuyển đổi 2D.

3) nếu bạn có một hạt nhân nhỏ, nói rằng, 3x3, thật dễ dàng chỉ để viết ra các chập như nhân và tổng. Điều này nghe có vẻ phức tạp nhưng nó không quá tệ.

Nếu bạn muốn sử dụng scipy, bạn có thể sử dụng ngimage, như tcaswell gợi ý. scipy cũng có convolve2d.

Các vấn đề liên quan