十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
python filter内建函数
站在用户的角度思考问题,与客户深入沟通,找到镇坪网站设计与镇坪网站推广的解决方案,凭借多年的经验,让设计与互联网技术结合,创造个性化、用户体验好的作品,建站类型包括:成都网站设计、成都做网站、外贸网站建设、企业官网、英文网站、手机端网站、网站推广、域名注册、虚拟主机、企业邮箱。业务覆盖镇坪地区。
filter函数是python内建函数,可以操作任何可迭代类型,如list,tuple,string.
filter需要带上一个函数function和一个可迭代序列作为参数。filter()将调用该function作用于每一个可迭代序列的元素,并返回一个由该function验证后返回值为true的元素组成新的可迭代序列,新序列的类型保持与filter参数序列的类型一致
2.filter与数字
下面用这个例子来说明:
#建个数字列表
numbers = [1,5,9,8,4,6,3,7]
#定义一个过滤标准,取小于5的数
def lessThanFive(element):
return element 5
print filter(lessThanFive, numbers)
输出结果是列表:[1,4,3]
解说:此处的过滤函数lessThanFive必需带入一个参数(filter()会调用lessThanFive,参数是列表nembers中的每一个元素,一次一个)。filter()返回所有值都是小于5的列表
3.filter与字符串
下面用如下例子说明:
#定义元组类型
names = ('Jack', 'Jill, 'Steve', '')
#筛选出名字
new_names = filter(None, names)
print new_names
输出结果是元组:
('Jack', 'Jill, 'Steve')
在元组names最后一个名字是空字符串,而filter的第一个参数是None,这说明需要使用identity函数(该函数是简单的返回该元素的)
因为python对空字符串,0和None作为False,所以上面的filter的语句就是移除空元素。
4.filter和函数
目的:找出以J开头的名字
def startsWithJ(element):
if element:
return element[0] == 'J'
return False
j_names = filter(startsWithJ, names)
print j_names
输出结果是元组:('Jack', 'Jill')
注意到了吗,上面的2个结果都是tuple而不是list,再一次说明fliter的返回值类型与参数序列的类型保持一致
原始数据是[1 9 2 8 3 7]
嵌入:
比如选择的窗口长度L为3,得到的矩阵就是:
[1 9 2]
[9 2 8]
[2 8 3]
[8 3 7]
SVD分解:
Python里自带一个函数进行分解,就不用它参考文献上写的啥X乘X的转置了,函数是这个:
u, s, v = np.linalg.svd(嵌入得到的矩阵)
得到的三个结果是这样的
u是个形状为(4, 4)的矩阵,为啥是4我不知道
[-0.34748861 -0.67722177 0.41306458 -0.5 ]
[-0.62332023 0.4373678 -0.41253036 -0.5 ]
[-0.38669102 -0.52074809 -0.57383924 0.5 ]
[-0.58411781 0.28089413 0.57437346 0.5 ]
s是,形状为(3,)
[18.29004176 9.97102473 0.23030046]
奇艺谱就是s里取最大值,这里为 18.29004175999194
v是,形状是(3, 3)
[-0.62349202 -0.50409505 -0.59761683]
[ 0.44777196 -0.85683898 0.25559193]
[ 0.64090402 0.10823653 -0.7599519 ]
重构:
重构矩阵的计算方法是 newMatrix = value * u1 * v1
value就是奇艺谱,SVD分解里得到的s里的最大值,上面也提了一下,这里value是: 18.29004175999194
u1是在u的基础上,取第一行,为
[-0.34748861 -0.62332023 -0.38669102 -0.58411781]
v1是在u的基础上,取第一行,为
[-0.62349202 -0.50409505 -0.59761683]
计算时需要对u1进行转置,转置后的u1是:
[-0.34748861]
[-0.62332023]
[-0.38669102]
[-0.58411781]
重构完的矩阵就是:
[3.96265415 3.203817 3.79820225]
[7.10815385 5.74696232 6.81316231]
[4.40970654 3.56526011 4.22670177]
[6.66110146 5.38551921 6.3846628 ]
最后把重构完的矩阵再转变为一维数组:
设这个一维数组叫ret[],对于重构完的矩阵,对每一条次对角线进行计算,并把结果添加到ret[]里
利用两个动态的变量,这里分别叫sigma和alpha,sigma是每条次对角线的数据的和,alpha是次对角线长度
ret.append(sigma/alpha)
就相当于添加了每条次对角线的平均值。
过程大概是这样的:
pos is( 0 , 0 ) sigma+
alpha is 1 now
ret[] append
pos is( 1 , 0 ) sigma+,
pos is( 0 , 1 ) sigma+
alpha is 2 now
ret[] append
pos is( 2 , 0 ) sigma+
pos is( 1 , 1 ) sigma+
pos is( 0 , 2 ) sigma+
alpha is 3 now
ret[] append
pos is( 3 , 0 ) sigma+
pos is( 2 , 1 ) sigma+
pos is( 1 , 2 ) sigma+
alpha is 3 now
ret[] append
pos is( 3 , 1 ) sigma+
pos is( 2 , 2 ) sigma+
alpha is 2 now
ret[] append
pos is( 3 , 2 ) sigma+
alpha is 1 now
ret[] append
处理后的数据ret[]为:
[3.9626541544632476 5.155985423726059 4.651623704998423 5.67984129396347 4.806110489242382 6.384662797164128]
就是最终结果
备注:
因为窗口长度L的选择不宜超过数据长度的1/3,这里数据长度是6,L为了为了算着方便选的3,所以这个例子的效果不好,但是领会精神。
做为参考的话,处理数据的时候,数据长度是300+,L选的4。
源码访问:
参考文献
数字信号是通过对连续的模拟信号采样得到的离散的函数。它可以简单看作一个以时间为下标的数组。比如,x[n],n为整数。比如下图是一个正弦信号(n=0,1, ..., 9):
对于任何的音频文件,实际上都是用这种存储方式,比如,下面是对应英文单词“skip”的一段信号(只不过由于点太多,笔者把点用直线连接了起来):
衡量数字信号的 能量(强度) ,只要简单的求振幅平方和即可:
我们知道,声音可以看作是不同频率的正弦信号叠加。那么给定一个声音信号(如上图),怎么能够知道这个信号在不同频率区段上的强度呢?答案是使用离散傅里叶变换。对信号x[n], n=0, ..., N-1,通常记它的离散傅里叶变换为X[n],它是一个复值函数。
比如,对上述英文单词“skip”对应的信号做离散傅里叶变换,得到它在频域中的图像是:
可以看到能量主要集中在中低音部分(约16000Hz以下)。
在频域上,也可以计算信号的强度,因为根据Plancherel定理,有:
对于一般的语音信号,长度都至少在1秒以上,有时候我们需要把其中比如25毫秒的一小部分单独拿出来研究。将一个信号依次取小段的操作,就称作分帧。技术上,音频分帧是通过给信号加一系列的 窗 函数 实现的。
我们把一种特殊的函数w[n],称作窗函数,如果对所有的n,有0=w[n]=1,且只有有限个n使得w[n]0。比如去噪要用到的汉宁窗,三角窗。
汉宁窗
三角窗
我们将平移的窗函数与原始信号相乘,便得到信号的“一帧”:
w[n+d]*x[n]
比如用长22.6毫秒的汉宁窗加到“skip”信号大约中间部位上,得到一帧的信号:
可见除一有限区间之外,加窗后的信号其他部分都是0。
对一帧信号可以施加离散傅里叶变换(也叫短时离散傅里叶变换),来获取信号在这一帧内(通常是很短时间内),有关频率-能量的分布信息。
如果我们把信号按照上述方法分成一帧一帧,又将每一帧用离散傅里叶变换转换到频域中去,最后将各帧在频域的图像拼接起来,用横坐标代表时间,纵坐标代表频率,颜色代表能量强度(比如红色代表高能,蓝色代表低能),那么我们就构造出所谓 频谱图 。比如上述“skip”发音对应的信号的频谱图是:
(使用5.8毫秒的汉宁窗)
从若干帧信号中,我们又可以恢复出原始信号。只要我们适当选取窗口大小,以及窗口之间的平移距离L,得到 ..., w[n+2L], w[n+L], w[n], w[n-L], w[n-2L], ...,使得对k求和有:
从而简单的叠加各帧信号便可以恢复出原始信号:
最后,注意窗函数也可以在频域作用到信号上,从而可以起到取出信号的某一频段的作用。
下面简单介绍一下3种音效。
1. 扩音
要扩大信号的强度,只要简单的增大信号的“振幅”。比如给定一个信号x[n],用a1去乘,便得到声音更大的增强信号:
同理,用系数0a1去乘,便得到声音变小的减弱信号。
2. 去噪(降噪)
对于白噪音,我们可以简单的用“移动平均滤波器”来去除,虽然这也会一定程度降低声音的强度,但效果的确不错。但是,对于成分较为复杂,特别是频段能量分布不均匀的噪声,则需要使用下面的 噪声门 技术,它可以看作是一种“多带通滤波器”。
这个特效的基本思路是:对一段噪声样本建模,然后降低待降噪信号中噪声的分贝。
更加细节的说,是在信号的若干频段f[1], ..., f[M]上,分别设置噪声门g[1], ..., g[M],每个门都有一个对应的阈值,分别是t[1], ..., t[M]。这些阈值时根据噪声样本确定的。比如当通过门g[m]的信号强度超过阈值t[m]时,门就会关闭,反之,则会重新打开。最后通过的信号便会只保留下来比噪声强度更大的声音,通常也就是我们想要的声音。
为了避免噪声门的开合造成信号的剧烈变动,笔者使用了sigmoid函数做平滑处理,即噪声门在开-关2个状态之间是连续变化的,信号通过的比率也是在1.0-0.0之间均匀变化的。
实现中,我们用汉宁窗对信号进行分帧。然后对每一帧,又用三角窗将信号分成若干频段。对噪声样本做这样的处理后,可以求出信号每一频段对应的阈值。然后,又对原始信号做这样的处理(分帧+分频),根据每一帧每一频段的信号强度和对应阈值的差(diff = energy-threshold),来计算对应噪声门的开合程度,即通过信号的强度。最后,简单的将各频段,各帧的通过信号叠加起来,便得到了降噪信号。
比如原先的“skip”语音信号频谱图如下:
可以看到有较多杂音(在高频,低频段,蓝色部分)。采集0.25秒之前的声音作为噪声样本,对信号作降噪处理,得到降噪后信号的频谱图如下:
可以明显的看到大部分噪音都被清除了,而语音部分仍完好无损,强度也没有减弱,这是“移动平均滤波器”所做不到的。
3. 静音剪切
在对音频进行上述降噪处理后,我们还可以进一步把多余的静音去除掉。
剪切的原理十分简单。首先用汉宁窗对信号做分帧。如果该帧信号强度过小,则舍去该帧。最后将保留的帧叠加起来,便得到了剪切掉静音部分的信号。
比如,对降噪处理后的“skip”语音信号做静音剪切,得到的新信号的频谱图为:
使用opencv-python的内置函数,对图片进行降噪处理。
8Fourier变换的应用——图像去噪
给出的图片是RGB图片,也就是需要有三个通道。
下面的函数用来去噪。
img=np.uint8(cv2.fastNlMeansDenoisingColored(img,None,10,10,7,21))
对这个图片进行局部自适应二值化处理:
img=hui(img)
th1 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,31,5)
另一种局部自适应二值化处理:
th2 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,31,5)
在第一步连续执行两次去噪,得到的三幅图片是:
执行三次降噪。
连续10次降噪。