phpcms v9网站建设入门/大亚湾发布
一、常见三种滤波器介绍
中值滤波:取卷积区域内的中位数
最大池化:取卷积区域内的最大值
平均池化:取卷积区域内的均值
边缘检测:边缘检测就是找到图像的边缘信息(轮廓)
二、故事背景
有一天,石原里美小姐姐出去玩,拍了一张美美的照片,回来的路上看到了路边有一个十元快速洗照片的摊,于是就花了十元把照片洗了下。回家之后掏出来一看,黑心的老板没有给照片加膜,照片出现了椒盐噪点,于是找你来求助。
三、修复图像(中值滤波)
聪明的你,立马想到了中值滤波,于是三下五除二就给搞好了。另外还实现了均值池化(滤波)、最大池化(滤波)。
import numpy as np
from PIL import Image
import copy
def Fliter(src,dst,k=3,filter_type='median'):# src: 读入图像路径# dst: 输出图像路径# k: 卷积核大小# filter_type: median, maxpooling, avgpoolingimarray = np.array(Image.open(src))new_img = copy.deepcopy(imarray)height, width, depth = imarray.shapefilter_dict = {'median':np.median,'maxpooling':np.max,'avgpooling':np.mean}if filter_type in filter_dict:filter_conv = filter_dict[filter_type]else:raise ValueError('filter_type: median, maxpooling, avgpooling')for i in range(height):for j in range(width):b_i = max(0,i-k//2)e_i = min(height-1,i+k//2)b_j = max(0,j-k//2)e_j = min(width-1,j+k//2)tmp = imarray[b_i:e_i+1,b_j:e_j+1,:]new_img[i][j][0] = filter_conv(tmp[:,:,0])new_img[i][j][1] = filter_conv(tmp[:,:,1])new_img[i][j][2] = filter_conv(tmp[:,:,2])new_img = Image.fromarray(new_img)new_img.save(dst)return new_img
中值滤波结果:
最大池化结果(怎么有点像卸妆了呢):
平均池化结果:
四、追求进步的石原里美(均值滤波加速)
石原里美用了均值滤波之后,总是感觉好慢,就说,均值滤波用一次耗时很长,能不能快一点。于是,聪明的你想到了累加和来做这个。思路就是,二维数组中每个位置保留为从左上角开始到当前位置的累加和。
array[i][j]=∑im∑jnarr[i][j]array[i][j] = ∑_i^{m}∑_j^{n}arr[i][j] array[i][j]=i∑mj∑narr[i][j]
那么在计算均值滤波时,每个滤波器的值就变成了如下表示,其中k表示滤波器大小:
avg[i][j]=(array[i][j]−array[i−k][j]−array[i][j−k]+array[i−k][j−k])/(k∗k)avg[i][j]=(array[i][j]-array[i-k][j]-array[i][j-k]+array[i-k][j-k])/(k*k) avg[i][j]=(array[i][j]−array[i−k][j]−array[i][j−k]+array[i−k][j−k])/(k∗k)
def AvgPooling(src,dst,k=3):# src: 读入图像路径# dst: 输出图像路径# k: 卷积核大小# filter_type: median, maxpooling, avgpoolingimarray = np.array(Image.open(src),dtype=int)new_img = copy.deepcopy(imarray)height, width, depth = imarray.shapetmp_array = np.zeros((height,width,depth))tmp_array[0,0,:] = imarray[0,0,:]for i in range(1,height):tmp_array[i,0,:] = tmp_array[i-1,0,:] + imarray[i,0,:]for j in range(1,width):tmp_array[0,j,:] = tmp_array[0,j-1,:] + imarray[0,j,:]for i in range(1,height):for j in range(1,width):tmp_array[i,j,:] = tmp_array[i-1,j,:] + tmp_array[i,j-1,:] + imarray[i,j,:] - tmp_array[i-1,j-1,:]for i in range(height):for j in range(width):b_i = max(0,i-k//2)e_i = min(height-1,i+k//2+1)b_j = max(0,j-k//2)e_j = min(width-1,j+k//2+1)kernel = (e_i-b_i)*(e_j-b_j)new_img[i,j,:] = (tmp_array[e_i,e_j,:] + tmp_array[b_i,b_j,:] - tmp_array[e_i,b_j,:] - tmp_array[b_i,e_j,:])/kernelnew_img = Image.fromarray(np.uint8(new_img))new_img.save(dst)return new_img
下面比较一下时间,用未优化的Fliter与Avgpooling进行速度比较。
t = time.time()
Fliter('shiyuan.png','avg_shiyuan.jpg',k=3,filter_type='avgpooling')
print('未优化的时间:',time.time()-t)
# 未优化的时间: 3.712080478668213
t = time.time()
AvgPooling('shiyuan.png','avg_shiyuan.jpg',k=3)
print('优化之后的时间:',time.time()-t)
# 优化之后的时间: 1.0790929794311523
五、故事反转(椒盐噪声)
其实,事实的真相是,十元小姐姐的照片根本就没有被椒盐噪声模糊,她只是喜欢技术宅而已。为了和你找话题,自己把照片添加了椒盐噪声,然后让你帮忙修复。
import numpy as np
from PIL import Image
def AddSalt(src,dst,probility=0.02):imarray = np.array(Image.open(src))height, width, detp = imarray.shapefor i in range(height):for j in range(width):if np.random.random(1) < probility:if np.random.random(1) < 0.5:imarray[i, j] = [0,0,0]else:imarray[i, j] = [255,255,255]new_im = Image.fromarray(imarray)new_im.save(dst)
原图:
六、续集(边缘检测)
经过上面的几次交流,石原里美小姐姐对你的好感大大增加,又找到一个理由想和你进一步交流。微信问你,有没有什么好的方法把我的照骗变成线条简笔画。身为技术宅的你,听到之后,大腿一拍,这明明就是边缘检测嘛。
canny边缘检测是通过卷积算子突出图像边缘部分,经典的有以下几种算子:
Prewitt算子:由水平梯度和垂直梯度两个方向计算得到,分别用于检测垂直边缘和水平边缘。
[−101−101−101][−1−1−1000111]\begin{bmatrix} -1 & 0 & 1 \\ -1 & 0 & 1 \\ -1 & 0 & 1 \end{bmatrix} \begin{bmatrix} -1 & -1 & -1 \\ 0 & 0 & 0 \\ 1 & 1 & 1 \end{bmatrix} ⎣⎡−1−1−1000111⎦⎤⎣⎡−101−101−101⎦⎤
Sobel算子:Sobel算子在Prewitt的基础上进行改进,增强中间位置的权重,检测垂直边缘和水平边缘分别为:
[−101−202−101][−1−2−1000121]\begin{bmatrix} -1 & 0 & 1 \\ -2 & 0 & 2 \\ -1 & 0 & 1 \end{bmatrix} \begin{bmatrix} -1 & -2 & -1 \\ 0 & 0 & 0 \\ 1 & 2 & 1 \end{bmatrix} ⎣⎡−1−2−1000121⎦⎤⎣⎡−101−202−101⎦⎤
def canny(src,dst,k=3,kernel='prewitt'):# kernel: prewitt, sobelimg = np.array(Image.open(src).convert('L'),'f')heigh, width = img.shapenew = np.zeros((heigh+2,width+2))if kernel == 'prewitt':kernel_x = np.array([[-1,0,1],[-1,0,1],[-1,0,1]])kernel_y = np.array([[-1,-1,-1],[0,0,0],[1,1,1]])elif kernel == 'sobel':kernel_x = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]])kernel_y = np.array([[-1, -2, -1], [0, 0, 0], [1, 2, 1]])else:raise ValueError('filter_type: prewitt, sobel')new[1:-1,1:-1] = img[:][:]for i in range(1,len(img)):for j in range(1,len(img[0])):tmp1 = new[i-k//2:i+k//2+1,j-k//2:j+k//2+1]*kernel_xtmp2 = new[i-k//2:i+k//2+1,j-k//2:j+k//2+1]*kernel_yimg[i][j] = np.sum(tmp1+tmp2)img = Image.fromarray(img)img = img.convert('L')img.save(dst)
Laplacian算子:上面两个算子用于线的检测,通常用于边缘检测,而Laplacian算子是用于检测特殊点的。滤波器如下:
[0101−41010]or[0−10−14−10−10]\begin{bmatrix} 0 & 1 & 0 \\ 1 & -4 & 1 \\ 0 & 1 & 0 \end{bmatrix} or \begin{bmatrix} 0 & -1 & 0 \\ -1 & 4 & -1 \\ 0 & -1 & 0 \end{bmatrix} ⎣⎡0101−41010⎦⎤or⎣⎡0−10−14−10−10⎦⎤对特殊点进行增强:
[1111−81111]or[−1−1−1−18−1−1−1−1]\begin{bmatrix} 1 & 1 & 1 \\ 1 & -8 & 1 \\ 1 & 1 & 1 \end{bmatrix} or \begin{bmatrix} -1 & -1 & -1 \\ -1 & 8 & -1 \\ -1 & -1 & -1 \end{bmatrix} ⎣⎡1111−81111⎦⎤or⎣⎡−1−1−1−18−1−1−1−1⎦⎤
def laplacian(src, dst, k=3,mode='high'):# mode: low, highimg = np.array(Image.open(src).convert('L'), 'f')heigh, width = img.shapenew = np.zeros((heigh + 2, width + 2))if mode=='low':kernel = np.array([[0, 1, 0], [1, -4, 1], [0, 1, 0]])elif mode == 'high':kernel = np.array([[1, 1, 1], [1, -8, 1], [1, 1, 1]])else:raise ValueError('')new[1:-1, 1:-1] = img[:][:]for i in range(1, len(img)):for j in range(1, len(img[0])):tmp = new[i - k // 2:i + k // 2 + 1, j - k // 2:j + k // 2 + 1] * kernelimg[i][j] = np.sum(tmp)img = Image.fromarray(img)img = img.convert('L')img.save(dst)