python⾼斯噪声怎么去除_OpenCV常⽤总结(Python)最近⼀直在⽤cv2,记录⼀下常⽤的⼀些操作和代码吧。
⾸先放OpenCV 的python官⽅⽂档链接:
Welcome to OpenCV-Python Tutorials’s documentation!
OpenCV 教程 - OpenCV 2.3.2 documentation
主要⽤的模块⼤概分为以下⼏类:
1. 图⽚读写,
2. 图像滤波,
3.图像增强,
4.阈值分割,
5.形态学操作,当然还有其他。。。
绪论:
⼯作环境Linux Ubuntu 16.04, Python 3.6, OpenCV 4.0。因为OpenCV的数据结构是基于numpy的,所以也要对numpy有⼤概的了解。
⾸先导⼊必要的库:
import
由于Ubuntu下cv2的imshow展⽰图⽚功能会有bug,因此使⽤matplotlib来展⽰图⽚。
⼀,图⽚读写:
Basic
图⽚读⼊:
image = cv2.imread('test.jpg', -1)
没什么好说的,第⼀个参数⽂件路径,第⼆个参数是通道数,-1代表原图与原图保持⼀致,0代表转换为灰度图,1代表使⽤BGR通道读⼊。
需要注意的就是读⼊的图⽚是以np.ndarray类型存储的,且彩⾊图像的通道为BGR与常见的RGB不同。
图⽚展⽰:
cv2.imshow('image', image)
cv2.WaitKey(0)
cv2.destroyAllWindows()
imshow第⼀个参数是窗⼝名,string类。第⼆个是np.ndarray的数组。注意在下⾯要使⽤WaitKey,不然展⽰窗⼝就会闪⼀下,程序就继续运⾏了,参数代表停多长时间,0的话是除⾮⼲扰不然⼀直展⽰。
在Ubuntu下cv2的imshow会出bug, 使程序崩溃,因此使⽤pyplot展⽰图⽚,但需要注意pyplot的彩⾊图⽚是RGB的格式,所以展⽰图像时需要先转换通道。
对于灰度图像:
plt.imshow(image, cmap='gray')
plt.show()
对于彩⾊图像:
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
plt.imshow(image)
plt.show()
图⽚写出:
cv2.imwrite('image.jpg', image)
这边需要注意的是第⼀个参数⽂件名要加格式,⽐如.jpg .png 之类的。
More
多的话只对⽂件读⼊加⼀些。
读取某个⽂件夹下所有jpg或其他图⽚可以使⽤glob,但⽆法读取⼦⽂件夹下的。
import glob
PATH = ''
for file in glob.glob(PATH + '*.jpg'):
img = cv2.imread(file, -1)
也可以把jpg改为png等等。
那么如何读取⼀个⽂件夹内包括其⼦⽂件夹下的所有图⽚呢?这个时候要⽤os和fnmatch了。
import os
import fnmatch
def find_files(directory, pattern):
"""
Method to find target files in one directory, including subdirectory
:param directory: path
:param pattern: filter pattern
:
return: target file path
"""
for root, dirs, files in os.walk(directory):
for basename in files:
if fnmatch.fnmatch(basename, pattern):
filename = os.path.join(root, basename)
yield filename
for filename in find_files('Home/Leon', '*.jpg'):
img = cv2.imread(filename, -1)
这个看⼀下应该就知道怎么回事了把?find_files引⽤了⼀个⽹上的代码我忘了哪个了,,,
然后对读⼊的图⽚⾊彩空间转换,常⽤cvtColor
img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
第⼆个参数很多种,常⽤的⾊彩空间也就是把BGR转成RGB或者Gray,偶尔会⽤HSV,因为HSV不会有很多颜⾊的参数,对于图⽚的纹理啊这些特征的提取和处理很有⽤。HSV三个通道分别是:⾊调(H),饱和度(S),明度(V)。具体释义可以看的
实话讲对HSV我理解的不多,反正就是H跟颜⾊有关,是⼀种对于RGB的⾮线性变换,饱和度的话就是我们有时候会说有些颜⾊好艳啊之类的,我会⽤来提取纹理,V明度我⼀直就认为是类似灰度值了。印象中有专门的矩阵来乘可以完成两个⾊彩空间的变换。
⼆,图像滤波
图像降噪:
降噪第⼀步是估计噪声,只有知道是什么样⼦的噪声类型才可以到好的降噪⽅法。估计噪声的话⼀般先观察直⽅图,也就是Histogram。⼀般有两种⽅法,⼀种是opencv⾃带的,还有⼀个matplotlib的,我个⼈倾向第⼆种,因为简单。
plt.hist(img.ravel(), 256, [0, 256])
plt.show()
python怎么读的对于如何估计噪声不说了,主要是写应⽤的。
# 6.2 补充
上⾯只是看直⽅图的,但在程序中如果想使⽤直⽅图的信息怎么办呢?建议还是使⽤cv2⾃带的⽅法,这个速度很快。(我⾃⼰写的计算直⽅图⽅法速度的10倍,也可能是因为我⾃⼰写的太辣鸡了)
代码如下所⽰:
hist = cv2.calcHist([img], [0], None, [256], [0, 256])
返回的是⼀个length=256的列表,分别是像素值为0--255的统计个数。
# 补充完毕
对于降噪常⽤的⽅法有均值滤波,⾼斯滤波,中值滤波,双边滤波等,当然你也可以定义⾃⼰的滤波函数。
blur = cv2.blur(img,(5,5))
gau_blur = cv2.GaussianBlur(img,(5,5),0)
median = dianBlur(img,5)
bi_blur = cv2.bilateralFilter(img,9,75,75)
从上到下分别是均值滤波,⾼斯滤波,中值滤波,双边滤波。下⾯说⼀下应⽤场景:
1. 均值滤波我反正不怎么⽤,了解滤波概念学习下就好了。
2. ⾼斯滤波⼀般都会有⼀些效果,当我实在不到最好的滤波⽅法时我⼀般使⽤⾼斯滤波,不保证效果但不会出问题。主要滤⾼斯噪声
的,就是直⽅图看着正态分布那样。但现实图⽚中并没有⾼斯噪声,⾼斯只是⽐较适合去拟合现实中的⼀些噪声。(不确定欢迎指正)
3. 均值滤波我⽤的⽐较多,对于椒盐噪声有很好的效果,就是直⽅图上会有⼀些孤⽴的⾼点那样的。当然滤出椒盐噪声的话维纳滤波也
会有很好效果,但较为⿇烦所以不怎么⽤。
4. 双边滤波相当于把⼤图⽚分⼩再⼀块⼀块滤波,很多时候效果也不错,⽹上看说美颜会经常⽤。他⽐较好的⼀点是可以保留原始图像
的纹理边缘等细节。
对于函数具体参数可以参看
Smoothing Images
除此之外还有局部均值滤波等,non-local-means,我个⼈感觉和bilateralFilter⽐较相似,⽤于⼀张⼤图上有⼀些相似部分的滤波,速度很慢⽽且占⽤内存也挺⼤,不建议⽤。
Image Denoising - OpenCV-Python Tutorials 1 documentation
边缘检测:
实际应⽤中我⽤的⽐较多的是边界,findContours。
contours, _ = cv2.findContours(img_close, 1, 2)
其中contours保存了图像中所有的contour信息,是⼀个列表。
这⾥注意下opencv版本更新,⽼版finContours是返回三个参数,现在是两个参数。还有Contour都是闭合的。但很多时候Contour会有⼤有⼩,我们可以设置阈值来滤出⼀些我们不想要的边界,最常⽤的
是根据包围的⾯积⼤⼩来看,偶尔也会根据周长。在滤出contour后经常会话bounding box, 因为Contour通常是不规则的。
for contour in contours:
if area_thresh_max > urArea(contour) > area_thresh_min:
x, y, w, h = cv2.boundingRect(contour)
boundingRect返回的分别是Contour左上⾓坐标x,y和矩形框的宽⾼w,h。
另外对于Contour还可以根据其area或len排个序,取前⼏位这样。
contours = sorted(contours, urArea, reverse=True)[:1]
此外边缘检测还经常⽤⼀些算⼦,Canny, Sobel, Laplacian等。其中Canny对边缘检测效果最好,但是很多时候也会受到噪⾳的⼲扰。Laplacian经常⽤来做边缘增强。
我建议⼤家可以根据实际情况⾃⼰定义kernel算⼦,然后使⽤filter2D来做。
⽐如求上下的边缘就可以定义:
KERNEL_HORIZON = np.asarray([[1, 2, 1],
[0, 0, 0],
[-1, -2, -1]], dtype=np.int)
然后使⽤:
img = cv2.filter2D(img, -1, KERNEL_HORIZON)
左右边缘的话可以:
KERNEL_VERTICAL = np.asarray([[1, 0, -1],
[2, 0, -2],
[1, 0, -1]], dtype=np.int)
反正算⼦随便定,你3X3,5X5,数值也随意,反正多试试哪个好⽤哪个。
不过需要注意⼀点是矫正,你⽐如我的KERNEL_HORIZON就有可能让边缘向上或向下偏⼀个像素值,虽然很⼩,但如果是做cutting的话就不是那么精确了。
还有线检测圆检测等,使⽤Hough⽅法,该⽅法原理⽐较简单,很容易懂,建议⼤家看看原理。但在Hough前要先将图像⼆值化,即⾮⿊即⽩。好像是后⾯我要说的,可以跳着看。
edges = cv2.Canny(gray_img,50,150,apertureSize = 3)
lines = cv2.HoughLines(edges,1,np.pi/180,200)
cimg = cv2.cvtColor(img,cv2.COLOR_GRAY2BGR)
circles = cv2.HoughCircles(img,cv2.HOUGH_GRADIENT,1,20,
param1=50,param2=30,minRadius=0,maxRadius=0)
在实际应⽤中碰到的问题往往与纯粹的直线会有些偏差,所以我⼀般会⾃⼰仿照着Hough的原理写⼀下针对性的函数。所以还是看看原理吧兄弟们。
三,图像增强
图像增强,其实也就是对⽐度增强,还是先看⼀眼直⽅图然后决定怎么增强吧。最简单的⽆外乎线性变换,⽐如你原图的直⽅图灰度分布0-128就到顶了,那就可以img = img*2,对⽐度就增强了两倍。这也是全局化的增强,叫直⽅图均衡化(Histogram Equalization)。
OpenCV⾥有直接的函数
img_equ = cv2.equalizeHist(img)
还有局部⾃适应直⽅图均衡化,叫CLAHE(Contrast Limited Adaptive Histogram Equalization),这也是我⽤的⽐较多的。
clahe = ateCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
img = clahe.apply(img)
第⼀个参数是对⽐度的limited,第⼆个参数是局部的窗⼝⼤⼩。官⽅⽂档也写得很清晰了:
Histograms - 2: Histogram Equalization
增强这⼀部分其实很多类,上⾯说的都是对⽐度的增强,当然还有边缘增强,就是锐化,这种⼀般先
使⽤边缘检测提取出边缘的特征图,再拿边缘特征图与原图相加就可以是边缘部分得到增强。常⽤的是⾼斯边缘检测。
四,阈值分割
阈值分割其实也就是⼆值化,⾸先我觉得⼤家都知道现在⼏乎所有图⽚都是256个灰度级吧,⼆值化就是变成⾮⿊即⽩,就是只有两个灰度级。
最简单的阈值分割就是,⽐如127这个灰度吧,你让⼤于127的变成255,⼩于等于127的变成0就好了,这个可以直接⽤numpy的数据结构操作的,不需要⽤什么OpenCV的函数,反正建议⼤家尽量不要过于依赖OpenCV已有的函数,要活学活⽤是吧。
img[img > 127] = 255
img[img < 128] = 0
可以看出numpy是很⽅便的,需要说明下这⾥最好不要⽤两个for循环来遍历图⽚,⽐⼤⼩,然后赋值0或255,这样速度太慢了。numpy ⾥是矩阵运算的,速度会快很多。
上⾯这个其实就是OpenCV⾥的THRESH_BINARY,⾥⾯还有inverse就是⿊⽩换⼀下,这玩意直接拿255减原图不就妥了嘛,反正简单的⼆值化建议直接⽤numpy做。
OpenCV⾥还有Adaptive Threshold,有两个参数分别是mean和gaussian,反正我理解的就是,先做个均值滤波或者⾼斯滤波完了再简单的Threshold,所以我也不怎么⽤。不过还是放⼀下⽂档链接吧,随缘看。
Image Thresholding
OK,上⾯的都不怎么⽤那我阈值分割平常⽤什么啊?我觉得利器就是OTSU,这种阈值分割是⾃适应的阈值,会根据Histogram计算出最⼩⽅差差的灰度值,然后⽤那个灰度值来做简单的阈值分割。这种对于直⽅图有个波浪起伏那种特别好⽤,就是下⾯第三个。因为很多时候我们很难去确定到底⽤哪个阈值,⽐如上⾯说127是随意说的,对不同图⽚就阈值不⼀样。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论