图像平滑算法

图像平滑与图像模糊是同一概念,主要用于图像的去噪。平滑要使用滤波器。为不改变图像的相位信息,一般使用线性滤波器,其统一形式例如以下:

%20\Large%20g(i,j)=\sum_{k,l}f(i+k,j+l)h(k,l)" data-bd-imgshare-binded="1" style="margin: 0px; padding: 0px; border: 0px; max-width: 100%;" alt="" />

当中h称为滤波器的核函数。说白了就是权值。不同的核函数代表不同的滤波器,有不同的用途。

在图像处理中。常见的滤波器包含:

  1. 归一化滤波器(Homogeneous blur)

    也是均值滤波器,用输出像素点核窗体内的像素均值取代输出点像素值。

  2. 高斯滤波器(Guassian blur)

    是实际中最经常使用的滤波器。高斯滤波是将输入数组的每个像素点与 高斯内核 卷积将卷积和当作输出像素值。高斯核相当于对输出像素的邻域赋予不同的权值,输出像素点所在位置的权值最大(相应高斯函数的均值位置)。二维高斯函数为,

    %20\Large%20G(x,y)%20=%20Ae^{\frac{-(x-u_x)^2}{2\delta_x^2}+\frac{-(y-y_x)^2}{2\delta_y^2}" data-bd-imgshare-binded="1" style="margin: 0px; padding: 0px; border: 0px; max-width: 100%;" alt="" />

  1. 中值滤波器(median blur)

    中值滤波将图像的每个像素用邻域(以当前像素为中心的正方形区域)像素的中值取代。

    对椒盐噪声最有效的滤波器,去除跳变点很有效。

  2. 双边滤波器(Bilatrial blur)

    为避免滤波器平滑图像去噪的同一时候使边缘也模糊,这样的情况下使用双边滤波器。关于双边滤波器的解释參见http://homepages.inf.ed.ac.uk/rbf/CVonline/LOCAL_COPIES/MANDUCHI1/Bilateral_Filtering.html

以下的程序将先给标准Lena图像加入椒盐噪声。分别使用4种不同的滤波器进行平滑操作,请注意观察不同滤波器对椒盐噪声的去噪效果。

程序分析及结果

/*
* FileName : image_smoothing.cpp
* Author : xiahouzuoxin @163.com
* Version : v1.0
* Date : Wed 17 Sep 2014 08:30:25 PM CST
* Brief :
*
* Copyright (C) MICL,USTB
*/
#include "cv.h"
#include "imgproc/imgproc.hpp"
#include "highgui/highgui.hpp" using namespace std;
using namespace cv; const int MAX_KERNEL_LENGTH = 10; const char *wn_name = "Smoothing"; static void salt(Mat &I, int n);
static void disp_caption(const char *wn_name, Mat src, const char *caption);
static void disp_image(const char *wn_name, Mat I); /*
* @brief
* @inputs
* @outputs
* @retval
*/
int main(int argc, char *argv[])
{
if (argc<2) {
cout<<"Usage: ./image_smoothing [file name]"<<endl;
return -1;
} Mat I = imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE);
salt(I, 6000);
imshow(wn_name, I);
waitKey(0); Mat dst; // Result /* Homogeneous blur */
disp_caption(wn_name, I, "Homogeneous blur");
for (int i=1; i<MAX_KERNEL_LENGTH; i+=2) {
blur(I, dst, Size(i, i), Point(-1,-1));
disp_image(wn_name, dst);
} /* Guassian blur */
disp_caption(wn_name, I, "Gaussian blur");
for (int i=1; i<MAX_KERNEL_LENGTH; i+=2) {
GaussianBlur(I, dst, Size(i, i), 0, 0);
disp_image(wn_name, dst);
} /* Median blur */
disp_caption(wn_name, I, "Median blur");
for (int i=1; i<MAX_KERNEL_LENGTH; i+=2) {
medianBlur(I, dst, i);
disp_image(wn_name, dst);
} /* Bilatrial blur */
disp_caption(wn_name, I, "Bilatrial blur");
for (int i=1; i<MAX_KERNEL_LENGTH; i+=2) {
bilateralFilter(I, dst, i, i*2, i/2);
disp_image(wn_name, dst);
}
waitKey(0); return 0;
} /*
* @brief 显示提示文字(滤波方法)
* @inputs
* @outputs
* @retval
*/
static void disp_caption(const char *wn_name, Mat src, const char *caption)
{
Mat dst = Mat::zeros(src.size(), src.type()); putText(dst, caption, Point(src.cols/4, src.rows/2), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(255,255,255)); imshow(wn_name, dst);
waitKey(0);
} /*
* @brief 显示图像
* @inputs
* @outputs
* @retval
*/
static void disp_image(const char *wn_name, Mat I)
{
imshow(wn_name, I);
waitKey(1000);
} /*
* @brief 加入椒盐噪声
* @inputs
* @outputs
* @retval
*/
static void salt(Mat &I, int n=3000)
{
for (int k=0; k<n; k++) {
int i = rand() % I.cols;
int j = rand() % I.rows; if (I.channels()) {
I.at<uchar>(j,i) = 255;
} else {
I.at<Vec3b>(j,i)[0] = 255;
I.at<Vec3b>(j,i)[1] = 255;
I.at<Vec3b>(j,i)[2] = 255;
}
}
}

上面程序的逻辑很清晰:

  1. 读入灰度图,并加入椒盐噪声(6000个噪声点):

    Mat I = imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE);
    salt(I, 6000);

  2. disp_captiondisp_image函数各自是用于显示提示文字和平滑过程中的变化图像的,平滑过程中图像的变化例如以下图:

    注意观察上面的图。中值滤波(Median Blur)对椒盐噪声的效果最好!

  3. 四种滤波方法分别使用到4个OpenCV函数,这些函数的声明都在imgproc.hpp中。这些函数的前2个參数都是原图像和滤波后图像。

    归一化滤波器blur的第3个參数为滤波核窗体的大小。Size(i,i)表示ixi大小的窗体。

    高斯滤波器GaussianBlur第3个參数也是滤波核窗体的大小,第4、第5个參数分辨表示x方向和y方向的δ。

    中值滤波器medianBlur第3个參数是滤波器的长度,该滤波器的窗体为正方形。

    双边滤波器的函数原型例如以下:

    //! smooths the image using bilateral filter
    CV_EXPORTS_W void bilateralFilter( InputArray src, OutputArray dst, int d,
    double sigmaColor, double sigmaSpace,
    int borderType=BORDER_DEFAULT );
  4. 本程序使用的Makefile文件为:

     TARG=image_smoothing
    SRC=image_smoothing.cpp
    LIB=-L/usr/local/lib/
    INC=-I/usr/local/include/opencv/ -I/usr/local/include/opencv2
    CFLAGS= $(TARG):$(SRC)
    g++ -g -o $@ ${CFLAGS} $(LIB) $(INC) \
    -lopencv_core -lopencv_highgui -lopencv_imgproc \
    $^ .PHONY:clean clean:
    -rm $(TARG) tags -f

OpenCV图像处理篇之图像平滑的更多相关文章

  1. OpenCV图像处理篇之边缘检测算子

    OpenCV图像处理篇之边缘检测算子 转载: http://xiahouzuoxin.github.io/notes/ 3种边缘检测算子 一阶导数的梯度算子 高斯拉普拉斯算子 Canny算子 Open ...

  2. OpenCV图像处理篇之边缘检測算子

    3种边缘检測算子 灰度或结构等信息的突变位置是图像的边缘,图像的边缘有幅度和方向属性.沿边缘方向像素变化缓慢,垂直边缘方向像素变化剧烈.因此,边缘上的变化能通过梯度计算出来. 一阶导数的梯度算子 对于 ...

  3. OpenCV图像处理篇之腐蚀与膨胀

    转载请注明出处:http://xiahouzuoxin.github.io/notes 腐蚀与膨胀 腐蚀和膨胀是图像的形态学处理中最主要的操作,之后遇见的开操作和闭操作都是腐蚀和膨胀操作的结合运算. ...

  4. OpenCV图像处理篇之阈值操作函数

    阈值操作类型 这5种阈值操作类型保留opencv tutorials中的英文名称.依次为: Threshold Binary:即二值化,将大于阈值的灰度值设为最大灰度值.小于阈值的值设为0. Thre ...

  5. OPENCV第一篇

    了解过之前老版本OpenCV的童鞋们都应该清楚,对于OpenCV1.0时代的基于 C 语言接口而建的图像存储格式IplImage*,如果在退出前忘记release掉的话,就会照成内存泄露.而且用起来超 ...

  6. 《OpenCV图像处理编程实例》

    <OpenCV图像处理编程实例>例程复现 随书代码下载:http://www.broadview.com.cn/28573 总结+遇到的issue解决: 第一章 初识OpenCV 1.VS ...

  7. 【OpenCV第一篇】安装OpenCV

    [OpenCV第一篇]安装OpenCV 本篇主要介绍如何下载OpenCV安装程序,如何在VS2008下安装配置OpenCV,文章最后还介绍了一个使用OpenCV的简单小例子. <OpenCV入门 ...

  8. Python+OpenCV图像处理(一)

    Python+OpenCV图像处理(一): 读取,写入和展示图片 调用摄像头拍照 调用摄像头录制视频 1. 读取.写入和展示图片 图像读入:cv2.imread() 使用函数cv2.imread() ...

  9. Python+OpenCV图像处理(一)——读取显示一张图片

    先在此处先声明,后面学习python+opencv图像处理时均参考这位博主的博文https://blog.csdn.net/u011321546/article/category/7495016/2? ...

随机推荐

  1. g++使用总结

    学习C和C++的同学应该都知道,gcc是一款跨平台的C/C++编译器,可以在Linux/Windows平台下使用,具有十分强大的功能,结构也十分灵活,并且可以通过不同的前端模块来支持各种语言,如Jav ...

  2. noip2019——动态规划刷题历程

    加粗的是值得总结的 从洛谷的普及题开始刷题: 背包式dp(有些技巧的) 1.p2639[USACO09OCT]Bessie的体重问题 -p1049取模意义下01背包 技巧:重量=价值 2.金明的预算问 ...

  3. python-opencv遍历图片像素,并对像素进行操作

    看代码: def access_pixels(frame): print(frame.shape) #shape内包含三个元素:按顺序为高.宽.通道数 height = frame.shape[0] ...

  4. OVOO

    题目描述: $zhx$有一个棵$n$个点的树,每条边有个权值. 定义一个连通块为一个点集与使这些点连通的所有边(这些点必须连通). 定义一个连通块的权值为这个连通块的边权和(如果一个连通块只包含一个点 ...

  5. 深入Linux内核架构——进程管理和调度(上)

    如果系统只有一个处理器,那么给定时刻只有一个程序可以运行.在多处理器系统中,真正并行运行的进程数目取决于物理CPU的数目.内核和处理器建立了多任务的错觉,是通过以很短的间隔在系统运行的应用程序之间不停 ...

  6. LeetCode(18)4Sum

    题目 Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = ...

  7. c和c++如何把一个整数转化为string

    c和c++如何把一个整数转化为string C++: 一.string转int的方式 采用最原始的string, 然后按照十进制的特点进行算术运算得到int,但是这种方式太麻烦,这里不介绍了. 采用标 ...

  8. Android开发——查询/杀死手机里正在运行的进程

    0. 前言 以前有同学好像做过一个叫"自习君"的App,开启后自动检测用户这一天的自习时间,在学校里宣传广告还打了不少.其实实现原理非常简单,在SQlite数据库(也可以通过文件) ...

  9. LayUI分页基于ASP.NET MVC

    ---恢复内容开始--- 今天写了挺久的分页,百度了很多都没有很好的.Net实例,今天我来更新一期关于layuiTable分页 首先你得理解layui的官方文档的Table分页部分,我在这里附上地址 ...

  10. php 正则匹配包含字母、数字以及下划线,且至少包含2种

    新系统注册功能需对用户名和密码做以下要求:包含字母.数字以及下划线,且至少包含2种: 在网上没有搜到符合要求的代码,于是自己对他人代码做了一点修改,经测试满足要求.代码如下: if (!preg_ma ...