Python下尝试算法做到图片的高斯模糊

高斯模糊是什么?

(先来看一下维基百科对它的定义)

高斯模糊是模糊图像的结果.它是一种广泛使用的图形软件的影响,通常会减少图像噪声和减少细节。这个模糊技术的视觉效果是一个平滑的模糊相似,查看图片通过一个半透明的屏幕,从明显不同散景在通常的照明的聚焦透镜或物体的阴影产生的影响。高斯平滑也被用来作为一个预处理阶段计算机视觉算法以提高图像在不同尺度的结构见尺度空间表示和尺度空间的实现。

在数学上,应用高斯模糊图像是一样的卷积一个图像高斯函数。这也被称为一个二维维尔斯特拉斯变换。相比之下,通过循环卷积\能更准确地再现散景功效自傅里叶变换一个高斯是另一个高斯,应用高斯模糊具有降低图像的高频成分的影响;高斯模糊是一个低通滤波器.

高斯模糊的应用

  • 在程序的背景设计中,我们总想用一些图片来对程序进行美化,但是直接用图片会发现和字,控件等不是很和谐;这个时候,在我们需要的地方或者说整一张背景进行适当的高斯模糊,就能提升我们程序的颜值了.
  • 高斯模糊还被用于边缘检测,用来使图片平滑化,以此来移除细节.以及应用于图片降噪.

高斯模糊处理的结果(样例)

这里我就把我们博客园上102实验室的班级图标拿来用PS高斯模糊了一下来举个例子.(后文的实际操作也拿它来举例子了)

高斯模糊名词解释

高斯模糊将正态分布作用于图像处理的方面.”高斯模糊"的算法,是一种数据平滑技术,适用于很多的场合和情景,但是在这里,图像处理恰好是一个很直观的应用实例.

高斯模糊的过程和数据平滑技术

模糊的本质,实际上就是每一个图片中的像素取周边像素的均值.如下图所示:

图一(原像素)                                                   图二(平滑化)

中心处点的值取附近所有点值的平均值,就会变成了值1.这样在数值上,可以看作是一种平滑化.那么在二维图像上,也可以看作是有了“模糊”的效果,中心点失去了自己本身的像素值,相当于细节丢失.而图像的模糊程度就完全取决于图像的模糊半径了.从值德角度来说,数值更加的趋向于平滑.

总结:

高斯模糊的核心就是取中心点周围所有像素点的均值作为自己的像素值,以此来达到平滑效果,在算法上,涉及到很多问题,从这些问题也是影响高斯模糊速度(模糊效率)的重要方面因素

高斯模糊的所需时间

由于要对所有的点进行计算,所以高斯模糊是一个相对而言较为耗时的作用,而模糊所需的时间取决点也有很多,诸如算法,以及图片自身属性以及人的要求,机器性能都是影响到高斯模糊时间.
其中对高斯模糊的时间影响最大的是以下两个因素:

  • 模糊半径
  • 像素点数量(图片大小)

像素点(图像)这个因素很好理解,越大的图片意味着运算的点越多,而模糊半径可以大致上这样理解,如下图:

图一(r=1)                                                      图二(r=2)

从上图我们就能看出图一中半径为1,中心点参考的只有周围8个格子中的像素值,而图二半径为2就要参考24个格子的像素值,以此类推可以得到:(其中n为半径)

像素点计算公式                                                  二次函数图像

增速是递增的(网上看到有的说是处理的像素点的个数是指数上升,对于这个问题可能我理解的不是很到位,但是结论也是半径越大处理的点越多,好的时间也就越多.)
综上所述:模糊半径和图像的大小是影响高斯模糊速度的最大因素,而一般程序要求高斯模糊的速度在ms级(像PS几乎察觉不到模糊的时间,就是算法的重要性),否则会影响用户体验.这里我们在后文中会做一些尝试.

高斯模糊的公式以及理解

首先,高斯模糊需要数学概率中的正态分布公式,这也是高斯模糊名称的由来,因为正态分布的别名就是“高斯分布”.

  • 正态分布
    公式(一维)图像以及参数含义:

正态分布的图像如下:

  • 正态分布的两个参数:

即均数μ. &. 标准差σ,σ^2为方差

图像&正态分布的关系:

我们都知道,图像都是二维的,而上面的正态分布则是一维的,这个时候我们先引入一维的高斯函数:

推导过程(百度百科):

二维高斯分布图像:

(图片来自百度图片)

二维高斯函数

N维高斯函数的通项公式:

里面的参数中,r就是模糊半径,而在二维坐标系中,模糊半径就是x^2+y^2,σ 是正态分布的标准偏差,所以代入通项公式我们就可以得到二维的高斯函数公式,如下:

二维高斯函数公式生成的曲面的高线是从中心开始以正态分布辐向的同心圆.不为零的像素组成的矩阵(卷积)在原来的图像矩阵像素作做变换,每个像素的值都是相邻一圈的像素值的加权平均数.

高斯函数的权重矩阵和举例

  • 我们要先计算出权重矩阵(所以要先得到矩阵的坐标,我们在这里以中间点的格子的坐标设置为(0,0)原点)

  • 我们要通过高斯函数计算出图像的权重矩阵(我们定义半径为1)

     

  • 由于我们要使得这个矩阵的所有数据的和为1,所以我们要计算出和的数据

      

  • 将矩阵中的九个数数据都除以所有数据的和,就可得到最终的权重矩阵,最终结果如下图:

  • 我们已经得到了权重矩阵,就可以通过它来计算出各个像素的灰度值或者是RGB三通道值了.

灰度图像灰度矩阵的计算

  • 假设我们随意创建一个任意灰度值(0-255)的矩阵

  • 那么现在新的矩阵的计算方式很简单,就是每个点的像素乘以自己对应的权重值,如下图:

  • 最后一步:将这九个点的数值加起来后就是中心点的高斯模糊后的值了,然后对于所有的点重复着这一个过程就可以得到高斯模糊化的图像.如下:

引申为彩色图像

如果原图是彩色图片,则可以对彩色图像的RGB三个通道分别进行高斯模糊,这样得到的就会是彩色图像高斯模糊化后的图像.

代码范例

#对上文高斯模糊的方法阐释的相关代码  -xlxw
from PIL import Image as p
import numpy as np
from time import clock
import math

#define
sizepic = [0,0]
timer = [0,0,0,0]
PI = 3.1415926

def getrgb(path):#得到图像中各个点像素的RGB三通道值
    timer[0]=clock()
    pd = p.open(path)
    sizepic[0] = pd.size[0]
    sizepic[1] = pd.size[1]
    nr = np.empty((sizepic[0],sizepic[1]))
    ng = np.empty((sizepic[0],sizepic[1]))
    nb = np.empty((sizepic[0],sizepic[1]))
    for i in range(0,sizepic[0]):
        for j in range(0,sizepic[1]):
            nr[i][j] = pd.getpixel((i,j))[0]
            ng[i][j] = pd.getpixel((i,j))[1]
            nb[i][j] = pd.getpixel((i,j))[2]
    print("已经得到所有像素的R,G,B的值,所花时间为{:.3f}s".format(clock()-timer[0]))
    return nr,ng,nb

def Matrixmaker(r):#通过半径和坐标计算高斯函数矩阵
    summat = 0
    timer[1] = clock()
    ma = np.empty((2*r+1,2*r+1))
    for i in range(0,2*r+1):
        for j in range(0,2*r+1):
            gaussp = (1/(2*PI*(r**2))) * math.e**(-((i-r)**2+(j-r)**2)/(2*(r**2)))
            ma[i][j] = gaussp
            summat += gaussp
    print(ma)
    print(summat)
    for i in range(0,2*r+1):
        for j in range(0,2*r+1):
            ma[i][j] = ma[i][j]/summat
    print("已经计算出高斯函数矩阵,所花时间为{:.3f}s".format(clock()-timer[1]))
    print("矩阵如下:")
    return ma

def newrgb(ma,nr,ng,nb,r):#生成新的像素rgb矩阵
    timer[2] = clock()
    newr = np.empty((sizepic[0],sizepic[1]))
    newg = np.empty((sizepic[0],sizepic[1]))
    newb = np.empty((sizepic[0],sizepic[1]))
    for i in range(r+1,sizepic[0]-r):
        for j in range(r+1,sizepic[1]-r):
            o = 0
            for x in range(i-r,i+r+1):
                p = 0
                for y in range(j-r,j+r+1):
                    #print("x{},y{},o{},p{}".format(x,y,o,p))
                    newr[i][j] += nr[x][y]*ma[o][p]
                    newg[i][j] += ng[x][y]*ma[o][p]
                    newb[i][j] += nb[x][y]*ma[o][p]
                    p += 1
                o += 1
    print("已经计算出新的三通道矩阵,所花时间为{:.3f}s".format(timer[2]))
    return newr,newg,newb

def cpic(r,g,b,path,rd):
    timer[3] = clock()
    pd = p.open(path)
    for i in range(rd+1,sizepic[0]-rd+1):
        for j in range(rd+1,sizepic[1]-rd+1):
            pd.putpixel((i,j),(int(r[i][j]),int(g[i][j]),int(b[i][j])))
    print("已经完成生成,所花时间为{:.3f}s".format(timer[3]))
    print("正在导出图片..")
    pd.save("blurred.jpg")

def main():
    rd = eval(input("请输入模糊的半径:"))
    path = input("请输入图片的地址(包括后缀):")
    nr,ng,nb = getrgb(path)
    matx = Matrixmaker(rd)
    print(matx)
    print("正在转换..")
    newr,newg,newb = newrgb(matx,nr,ng,nb,rd)
    print("正在准备输出..")
    cpic(newr,newg,newb,path,rd)
    print("{} - >> {}".format(path.split(‘/‘)[-1],"blurred.png"))
    print("总计耗时:{:.3f}s,感谢您的使用.".format(timer[0]+timer[1]+timer[2]+timer[3]))
main()

程序运行的截图:

程序运行的结果

(bt.png就是对博客园102实验室的图标进行高斯模糊)本次测试的模糊半径为3

高斯模糊的缺点&优化方案

用这种方法对图片进行高斯模糊,有几个缺点:

  • 第一:由上一章程序的截图可知高斯模糊全过程总计花费2.82s,这个时间虽然是因为为了详细展示高斯模糊过程没有优化,但是和我们上文中提到的200ms相差甚远,这里就是因为有些地方需要改进.
  • 第二:这种模糊办法无法有效解决边缘化问题,所以当模糊半径过大时会有明显的分界线的出现,这也是需要改进的地方

优化方案:

  • 1.在速度上,主要用于改进算法,但是我们还可以从图像角度考虑,由于图像进行模糊后会丢失细节,这时候和我们直接对图片缩放有相似之处,所以我们如果将图片缩小一半,在再进行模糊,之后再方法到原图,我们会发现图片模糊的效果和直接模糊没有太大区别.这个时候我们就能采用这样的方法优化.
  • 2.另外在速度上,我们可以发现纯色模糊后是没有变化的,那么我们可以先找到大块的纯色区域模糊时跳过他们,这样子也能对时间进行优化.
  • 3.优化算法.(利用对一个像素点权重的计算可以化简为两个一维高斯积分的乘积)的特性,这是国外的论坛上给出的一个优化方案.等等.
时间: 2024-08-01 10:46:03

Python下尝试算法做到图片的高斯模糊的相关文章

python下PCA算法与人脸识别

关于这部分主要是想在python下试验一下主成分分析(PCA)算法以及简单的人脸识别.曾经详述过matlab下的PCA以及SVM算法进行人脸识别技术,参考如下: 主成分分析法-简单人脸识别(一) 主成分分析-简单人脸识别(二) PCA实验人脸库-人脸识别(四) PCA+支持向量机-人脸识别(五) 主成分分析(PCA)算法主要是对高维数据进行降维,最大限度的找到数据间的相互关系,在机器学习.数据挖掘上很有用.在机器学习领域算法众多,贴一个: 大神博客索引 关于PCA的核心思想与原理介绍上述已经给出

Python 数据结构和算法

一.写在前面 这篇文章主要介绍了python 内置的数据结构(list.set以及字典),从一些实际的场景中来说明解决方案,主要是阅读<python cookbook>时写下的阅读记录,提高自己在Python开发方面的理解,记录在这里是为了方便可以随时查阅使用.因为时间仓促以及个人理解有限,固有错误的地方请指出,谢谢! 如果转载,请保留作者信息. 邮箱地址:[email protected] 个人博客:http://www.smallartisan.site/ CSDN博客:http://bl

python实现爬虫下载美女图片

python实现爬虫下载美女图片 本次爬取的贴吧是百度的美女吧,给广大男同胞们一些激励 在爬取之前需要在浏览器先登录百度贴吧的帐号,各位也可以在代码中使用post提交或者加入cookie 爬行地址:http://tieba.baidu.com/f?kw=%E7%BE%8E%E5%A5%B3&ie=utf-8&pn=0 #-*- coding:utf-8 -*- import urllib2 import re import requests from lxml import etree 这

使用python实现森林算法方法步骤详解

本文和大家分享的是使用python实现森林算法相关内容,一起来看看吧,希望对大家学习python有所帮助. 算法描述 随机森林算法 决策树运行的每一步都涉及到对数据集中的最优**点(best split point)进行贪婪选择(greedy selection). 这个机制使得决策树在没有被剪枝的情况下易产生较高的方差.整合通过提取训练数据库中不同样本(某一问题的不同表现形式)构建的复合树及其生成的预测值能够稳定并降低这样的高方差.这种方法被称作引导**算法(bootstrap aggrega

python数据结构与算法 38 分析树

分析树 树的结构完成以后,该是时候看看它能做点什么实事儿了.这一节里,我们研究一下分析树.分析树能够用于真实世界的结构表示,象语法或数学表达式一类的. 图1 一个简单语句的分析树 图1所示是一个简单语句的层级结构,把语句表示为树结构可以让我们用子树来分析句子的组成部分. 图2 ((7+3)?(5?2))的分析树 我们也可以把数学表达式如((7+3)?(5?2))表示为分析树,如图2.此前我们研究过完全括号表达式,这个表达式表达了什么呢?我们知道乘法的优先级比加减要高,但因为括号的关系,在做乘法之

Python下探究随机数的产生方法

资源下载 #本文PDF版下载 Python下探究随机数的产生方法(或者单击我博客园右上角的github小标,找到lab102的W7目录下即可) #本文代码下载 几种随机数算法集合(和下文出现过的相同) 前言 我们对于随机数肯定不会陌生,随机数早已成为了我们经常要用到的一个方法,比如用于密码加密,数据生成,蒙特卡洛算法等等都需要随机数的参与.那么我们的电脑是怎么才能够产生随机数的呢?是电脑自己的物理存在还是依靠算法?它到底是如何工作的呢?所以我也对这些问题有着好奇心,所以找到了许多资料学习了一下,

算法抽象及用Python实现具体算法

一.算法抽象 它们一般是在具体算法的基础上总结.提炼.分析出来的,再反过来用于指导解决其它问题.它们适用于某一类问题的解决,用辩 证法的观点看,抽象的算法和具体的算法就是抽象与具体.普遍性与特殊性.共性和个性的关系.马是白马的抽象,无论是白马还是红 马,都是马,我们用马的唯一本质属性--染色体来决定一种动物是否是马,这个本质属性就是马的抽象. (1)分治法 分治法的基本思想是先分割原问题,将原问题分割成一个或多个简单的子问题,这些子问题的解经过一定组合得到原问题的解,而求 解这些子问题时,常常会

python数据结构与算法 36 树的基本概念

树 学习目标 理解什么是树及使用方法 学会使用树实现映射 用列表实现树 用类和引用实现树 用递归实现树 用堆实现优先队列 树的例子 前面我们学习过栈和队列这类线性数据结构,并且体验过递归,现在我们学习另一种通用数据结构,叫做树.树在计算机科学中应用广泛,象操作系统.图形学.数据库系统.网络等都要用到树.树和他们在自然界中的表哥--植物树--非常相似,树也有根,有分枝,有叶子.不同之处是,数据结构的树,根在顶上,而叶子在底部. 在开始学习之前,我们来研究几个普通的例子.第一个是生物学上的分级树.图

python数据结构与算法 37 树的实现

树的实现 记住上一节树的定义,在定义的基础上,我们用以下的函数创建并操作二叉树: BinaryTree() 创建一个二叉树实例 getLeftChild() 返回节点的左孩子 getRightChild() 返回节点的右孩子 setRootVal(val) 把val变量值赋给当前节点 getRootVal() 返回当前节点对象. insertLeft(val) 创建一个新二叉树作为当前节点的左孩子 insertRight(val) 创建一个新二叉树作为当前节点的右孩子. 实现树的关键点是合适的存