Learning OpenCV with iOS: 图像模糊--线性滤波

一、前言

上一篇我们讲解了OpenCV的图像亮度和对比度调整。本篇主要向大家介绍下图像模糊。按惯例,先来一张效果图。

铠玩模糊

二、模糊

所谓模糊,可以先简单理解为每一个像素都取周边像素的平均值。

模糊

上图中,2是中间点像素值,周边像素都是1。

模糊

中间点取周围点的平均值,就会变成1。在数值上叫平滑。在图形上,就产生了模糊效果,也就是中间点失去了细节。

模糊

三、图像模糊

图像模糊是opencv常见的操作,使用模糊操作的原因是为了给图像预处理时降低噪声影响。
Smooth和Blur是opencv图像模糊的API,其背后的原理其实是数学的卷积操作

卷积

其中权重核h(k,l) 为“滤波系数”。上面的式子可以简记为:

卷积

通常这些卷积算子计算都是线性操作,所以又叫线性滤波

四、线性滤波

1、均值滤波

均值滤波是典型的线性滤波算法,它是指在图像上对目标像素给一个模板,该模板包括了其周围的临近像素,再用模板中的全体像素的平均值来代替原来像素值。

还记得第二篇里所讲掩膜操作吧,均值滤波的过程跟掩膜操作极其相似。

均值滤波

滤波操作:在9x9上面有3x3的窗口,从左到右,从上到下移动,白色的每个像素点值之和取平均值赋给中心红色像素作为它处理之后的像素值。其中,模板就是3x3的窗口,红色格子为目标像素,白色格子为周围的临近像素

此类操作被称为卷积计算,而模板和kernel就是卷积计算中的卷积算子

opencv提供了均值滤波(模糊)的API

/** 
@param src 输入图像
@param dst 输出图像
@param ksize 模糊kernel大小
@param anchor 锚点; 默认值为Point(-1,-1) ,表示在锚点在kernel的中心
@param borderType 查看#BorderTypes
 */
blur( InputArray src, OutputArray dst,
                        Size ksize, Point anchor = Point(-1,-1),
                        int borderType = BORDER_DEFAULT );

铠玩模糊

铠玩模糊
+ (UIImage *)blur:(UIImage *)image sizeX:(int)sizeX sizeY:(int)sizeY {
    Mat src;
    UIImageToMat(image, src);
    
    Mat dst;
    blur(src, dst, cv::Size(sizeX, sizeY));
    
    UIImage* result = MatToUIImage(dst);
    
    return result;
}

class BlurViewController: UIViewController {

    @IBOutlet weak var imageView: UIImageView!
    @IBOutlet weak var resultImageView: UIImageView!
    
    private var sizeX: Int32 = 3
    private var sizeY: Int32 = 3
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    @IBAction func onSliderValueChanged(_ sender: UISlider) {
        sizeX = Int32(sender.value)
        transform()
    }
    
    @IBAction func onSlider2ValueChanged(_ sender: UISlider) {
        sizeY = Int32(sender.value)
        transform()
    }
    
    private func transform() {
        let image = OpenCV.blur(imageView.image, sizeX: sizeX, sizeY: sizeY)
        resultImageView.image = image
    }
}

一些思考

滤波操作为何能将图像模糊?

滤波操作其实是用周围的像素平均值作为目标像素的值,经过这样的处理后其实就是整个图像像素值差距缩小。差距缩小了自然就比较没有辨识度了,也就是模糊了。

为何在铠玩模糊中,只改变Size的x大小会让铠在x轴方向模糊?

这题就当讨论题吧,有兴趣的朋友可以在文章的评论处讨论。
提示:改变x的值其实就是改变kernel的形态,单独将x增加,就相当于kernel的形态变成宽度大于高度的长方形。

均值模糊有没有什么问题?

我们知道图像都是连续的越靠近的点关系越密切,越远离的点关系越疏远,均值模糊只是简单的取平均,没有分配权重,肯定存在不合理之处。相比之下,加权平均更合理,距离越近的点权重越大,距离越远的点权重越小。
下面我们就来看下带权重的高斯滤波。

2、高斯滤波

正态分布

正态分布

如上图,正态分布是一种钟摆形曲线,越接近中心,取值越大,越远离中心,取值越小。
计算平均值的时候,我们只需要将中心点作为原点,其他点按照其在正态曲线上的位置,分配权重,就可以得到一个加权平均值。

高斯函数

一维函数
一维高斯函数

σ:标准差,在这里又叫做高斯半径。
σ2:方差。
f(x):概率
μ:均值,即期望。

在计算平均值的时候,中心点就是原点,所以μ等于0。可得简化后的函数:

简化后的函数

根据一维函数,可以推导得到二维函数:

二维高斯函数

图像是二维的,所以通常处理图像时,我们使用二维高斯函数。

计算例子

假定中心点的坐标是(0,0),那么距离它最近的8个点的坐标如下:

坐标

假设σ=1.5,则权重矩阵如下:

权重矩阵

这9个点的权重总和等于0.4787147,归一化后得到最终的权重矩阵:

归一化

假设现有图像矩阵如下:

图像矩阵.jpg

与权重相乘后得到的矩阵如下:

矩阵

将这9个值相加就是中心点的最终值:13.9401236。而通过均值滤波得到的结果是13.5。

均值与高斯哪家强

@param sigmaX Gaussian kernel standard deviation in X direction.
@param sigmaY Gaussian kernel standard deviation in Y direction; if sigmaY is zero, it is set to be
equal to sigmaX, if both sigmas are zeros, they are computed from ksize.width and ksize.height,
respectively (see #getGaussianKernel for details); to fully control the result regardless of
possible future modifications of all this semantics, it is recommended to specify all of ksize,
sigmaX, and sigmaY.
@param borderType pixel extrapolation method, see #BorderTypes

@sa  sepFilter2D, filter2D, blur, boxFilter, bilateralFilter, medianBlur
 */
CV_EXPORTS_W void GaussianBlur( InputArray src, OutputArray dst, Size ksize,
                                double sigmaX, double sigmaY = 0,
                                int borderType = BORDER_DEFAULT );
+ (UIImage *)gaussianblur:(UIImage *)image sizeX:(int)sizeX sizeY:(int)sizeY {
    Mat src;
    UIImageToMat(image, src);
    
    Mat dst;
    GaussianBlur(src, dst, cv::Size(sizeX, sizeY), 11);
    
    UIImage* result = MatToUIImage(dst);
    
    return result;
}
均值
高斯

仔细观看可以看到,高斯模糊图像的轮廓较均值的清晰些,没有那么“模糊”。

五、小结

本篇主要介绍了图像模糊的概念,并通过例子讲解了均值模糊和高斯模糊。模糊经常在图像预处理降时使用到,需要好好掌握其原理,以便于应对不同情况。今天就到这了,有疑问的朋友可以给我留言,咱们下篇见!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容