jeasonstudio / blog

Blog of Jeason
https://jeasonstudio.github.io/blog/
MIT License
3 stars 1 forks source link

Golang 图像处理上的一些实践 #12

Open jeasonstudio opened 6 years ago

jeasonstudio commented 6 years ago

Golang 图像处理上的一些实践

声明:本文以及图片为原创,转载请联系作者。

时至今日,openCV 已经出到了3.2版本,且其社区也足够庞大,其全面性已无需赘述。但我们用 Golang 这样一门待火不火的语言来造一些相关的轮子,也蛮有趣。

下面我分享一下用 Golang 实现一些图像处理过程中的收获。

高斯模糊效果

高斯模糊是一种比较常见的模糊效果,我们在各类图像处理软件或库、框架等地方会经常见到。首先看一下效果:

image

(左边为原图,右边为 Sigma=10 ,10 像素模糊后)

高斯模糊(英语:Gaussian Blur),也叫高斯平滑。简单点说,是将『二位正态分布』应用于图像处理,从算法的角度来说,十分的简单易懂。参考了阮一峰老师的文章:高斯模糊算法**后,我来班门弄斧,谈一下实现过程中的感悟。

一副图像,这里指非矢量图,一般由许多像素点构成,像素点内包含色值数据,一般为 RGBA 形式。为了将一副图片模糊处理,也就是说将某一点像素的 RGBA 值向周围像素「靠拢」,即受周围影响,从而达到模糊目的。

最简单的平均值方法如下图左,均等分配。但这样明显会对图片造成较大失真,所以我们又想到了如下图右的均值分法:

image

这种处理方式会使图像失去原来的性质,所以高斯模糊是一种不可逆处理。

在权重的分配上,我们采用了高斯的二维正态分布函数,这也是『高斯模糊』名字由来,下面咳咳(敲黑板,记笔记),我们来复习一维高斯函数:

image

其中,μ是x的均值,σ是x的方差。因为计算平均值的时候,中心点就是原点,所以μ等于0。由一维高斯函数可推导得二维高斯函数(可理解为沿 x=μ 旋转)。见下图。

image

Sigma 越大,图形越矮胖,越小越高瘦。下面是 Golang 的二维高斯模糊公式实现:

// GaussFunc 二维高斯函数
func GaussFunc(x, y int, Sigma float64) float64 {
    return (1.0 / (2.0 * math.Pi * Sigma * Sigma)) * math.Pow(math.E, ((-1.0)*(float64(x*x+y*y)/(2.0*Sigma*Sigma))))
}

由此设定 Sigema 的值后,可计算 x=y=n 像素,x*y 像素块内每个点的概率值,且所有值相加应等于1,如下图所示3X3像素块所示:

image

由于每次都进行概率运算效率较低,若固定像素固定 Sigma 处理模糊,可提前将概率矩阵算好打表使用,将提高处理速度。

接下来,将矩阵内像素的 RGBA 值分别乘对应的权重值相加,所得结果就是中心像素的 RGBA 值,我们只需将该像素填充到正确的位置。

处理完所有像素点,就能得到对应参数的高斯模糊效果图。如下:

image

这时我们应该考虑一个问题,那就是边缘处理,四个边缘的像素点无法向外计算。

目前有两种办法解决,一种是把已有的点拷贝到另一面的对应位置,模拟出完整的矩阵、或者将超出边界的点按边界点 RGBA 值处理。

如果出现边缘单色化,可采取切除相应像素边缘的方式优化。

如果你不关心这些,也可以直接使用该图形库:

go get github.com/jeasonstudio/GaussianBlur
// GaussianBlur 高斯模糊处理
// sourceImg \ tagImg 处理前 \ 后图片相对路径地址
// num 高斯模糊像素,单位 px,注意,此项过高将直接影响时间
// Sigma 塞个马,周围像素权重
func GaussianBlur(sourceImg, tagImg string, num int, Sigma float64)

留图不留种,菊花万人捅:GitHub: GaussianBlur/jeasonstudio**

欢迎大家关注我的专栏:知乎专栏-代码小白的日常

下一篇系列预告:Golang 图像处理实践之边缘检测算法

lvisei commented 3 years ago

@jeasonstudio 你这里计算量还是算比较简单,我遇到一个公式

func krigingVariogramGaussian(h, nugget, range_, sill, A float64) float64 {
    return nugget + ((sill-nugget)/range_)*
        (1.0-math.Exp(-(1.0/A)*math.Pow(h/range_, 2)))
}

数据量大了需要执行很多次,导致耗时操作都是math.Pow math.Exp 最后特别慢,比JS都慢 博主遇到这种情况怎么办呢