OpenCV-跟我一起学数字图像处理之拉普拉斯算子
https://www.cnblogs.com/german-iris/p/4840647.html
Laplace算子和Sobel算子一样,属于空间锐化滤波操作。起本质与前面的Spatial Filter操作大同小异,下面就通过Laplace算子来介绍一下空间锐化滤波,并对OpenCV中提供的Laplacian函数进行一些说明。
- 数学原理
离散函数导数
离散函数的导数退化成了差分,一维一阶差分公式和二阶差分公式分别为,


Laplace算子的差分形式
分别对Laplace算子x,y两个方向的二阶导数进行差分就得到了离散函数的Laplace算子。
在一个二维函数f(x,y)中,x,y两个方向的二阶差分分别为,


所以Laplace算子的差分形式为,

写成filter mask的形式如下,
| 0 | 1 | 0 |
| 1 | -4 | 1 |
| 0 | 1 | 0 |
| 1 | 1 | 1 |
| 1 | -8 | 1 |
| 1 | 1 | 1 |
注:
有时我们也会见到不同于上述结果的Laplace算子的filter mask,
| 0 | -1 | 0 |
| -1 | 4 | -1 |
| 0 | -1 | 0 |
| -1 | -1 | -1 |
| -1 | 8 | -1 |
| -1 | -1 | -1 |
其原因是在定义二阶导数的时候采用了相反的定义,这个无关紧要,但是要注意,当用Laplace算子滤波后的图像与原图叠加时,混合操作是加还是减因上述的定义而异。
图像的Laplace操作
如同本文开始时说的那样,将Laplace算子写成filter mask后,其操作大同小异于其他的空间滤波操作。将filter mask在原图上逐行移动,然后mask中数值与其重合的像素相乘后求和,赋给与mask中心重合的像素,对图像的第一,和最后的行和列无法做上述操作的像素赋值零,就得到了拉普拉斯操作结果。
拉普拉斯操作结果与原图的混合
因为Laplace算子是二阶导数操作,其在强调图像素中灰度不连续的部分的同时也不在强调灰度值连续的部分。这样会产生一个具有很明显的灰度边界,但是没有足够特征的黑色背景。背景特征可以通过原图像与Laplace算子操作后的图像混合恢复。用公式,

其中的参数c的取值和上面的两种mask定义有关,当mask中心的数值取正时c=-1,相反c=1;
- 基于OpenCV的Laplace算子的计算
OpenCV中Laplacian函数可以实现对图像的Laplace操作,具体用法如下,
Laplacian( src_gray, dst, ddepth, kernel_size, scale, delta, BORDER_DEFAULT );
参数意义为,
- src_gray,输入图像
- dst,Laplace操作结果
- ddepth,输出图像深度,因为输入图像一般为CV_8U,为了避免数据溢出,输出图像深度应该设置为CV_16S
- kernel_size,filter mask的规模,我们的mask时3x3的,所以这里应该设置为3
- scale,delta,BORDER_DEFAULT,默认设置就好
基于OpenCV的Laplace算子仿真代码段如下,

//load the Original Image and get some informations
Mat src = imread("012.jpg",0);
namedWindow("OriginalImage");
imshow("OriginalImage",src);
CV_Assert(src.depth() == CV_8U); //OpenCV solution - Laplacian
Mat dst,abs_dst_laplace;
Laplacian(src,dst,CV_16S,3);
convertScaleAbs(dst,abs_dst_laplace); //show the result
namedWindow("result_laplacian");
imshow("result_laplacian",abs_dst_laplace);

其中convertScaleAbs函数功能是将CV_16S型的输出图像转变成CV_8U型的图像。
仿真结果:
原图:

Laplace操作结果:

- 基于mask operation原理仿真
Laplace算子滤波仿真
根据数学原理中介绍的算法,编写相应代码,进行相关仿真。其中对Laplace操作结果进行了图像拉伸显示,因为Laplace操作结果的像素值范围可能落在了[0,255]之外,而计算机在显示的时候将赋值全部置为0,大于255的像素全部显示成255。
代码段如下,

//get some informations of original image
int nr = src.rows;
int nc = src.cols;
int n = nr*nc;
int arr[9] = {0}; //scan the whole pixels of original image
//and do Laplacian Operation
int* table_lap = new int[n];
int* table_orig = new int[n];
int l;
for (int i=0;i<n;i++)
{
table_lap[i] = 0;
table_orig[i] = 0;
}
for (int i=1;i<nr-1;i++)
{
const uchar* previous = src.ptr<uchar>(i-1);
const uchar* current = src.ptr<uchar>(i);
const uchar* next = src.ptr<uchar>(i+1);
for (int j=1;j<nc-1;j++)
{
for (int k=0;k<3;k++)
{
arr[k] = previous[j+k-1];
arr[k+3] = current[j+k-1];
arr[k+6] = next[j+k-1];
}
l = nc*i+j; //calculate the location in the table of current pixel
Lmaskoperation(table_lap,arr,l);
table_orig[l] = arr[4];
}
} //pixels scale
uchar* La_scaled = new uchar[n];
table_scale(table_lap,La_scaled,n); //padding values
Mat LaResult_own;
LaResult_own.create(src.size(),src.type());
uchar* p = NULL;
for (int i=0;i<nr;i++)
{
p = LaResult_own.ptr<uchar>(i);
for (int j=0;j<nc;j++)
{
l = nc*i+j;
p[j] = La_scaled[l];
}
} //show results
namedWindow("LaResult_own");
imshow("LaResult_own",LaResult_own);

其中Lmaskoperation是我写的mask为Laplace mask的mask operation操作函数,函数段如下,

//**********************//
//Laplacian mask operation
//**********************//
void Lmaskoperation(int* table,int* arr,int l)
{
int tmp[9] = {-1,-1,-1,-1,8,-1,-1,-1,-1};
for (int i=0;i<9;i++)
{
table[l] = table[l] + tmp[i]*arr[i];
}
}

tabel_scale函数就是我写的图像拉伸函数,将Laplace操作结果拉伸到[0,255],具体函数段如下,

//*****************************//
//scale the pixels to [0 255]
//*****************************//
void table_scale(int* table,uchar* result,int n)
{
int min = table[0];
int max = table[0];
for (int i=0;i<n;i++)
{
if(min>table[i])
{
min = table[i];
}
if(max<table[i])
{
max = table[i];
}
}
for (int i=0;i<n;i++)
{
result[i] = (uchar)(255*(table[i]-min)/(max-min));
}
}

仿真结果,拉伸后Laplace算子的操作结果

以灰色为主色调的显示结果就是Laplace算子操作拉伸后显示的一大特点。
Laplace滤波图像与原图像的混合
我使用的mask中心值为正,所以混合操作需要原图减去Laplace滤波图像,代码段如下,

//blending with the original image using Eq g(x,y)=f(x,y)+c*Lap(x,y)
int* table_blend = new int[n];
for(int i=0;i<n;i++)
{
table_blend[i] = table_orig[i] - table_lap[i];
if(table_blend[i]<0)
{
table_blend[i] = 0;
}
else if (table_blend[i]>255)
{
table_blend[i] = 255;
}
} //padding values to blending result
Mat Blresult;
Blresult.create(src.size(),src.type());
for (int i=0;i<nr;i++)
{
p = Blresult.ptr<uchar>(i);
for(int j=0;j<nc;j++)
{
l = nc*i+j;
p[j] = table_blend[l];
}
} //show blending result
namedWindow("blending result_laplacian");
imshow("blending result_laplacian",Blresult);

仿真结果:

OpenCV-跟我一起学数字图像处理之拉普拉斯算子的更多相关文章
- OpenCV-跟我一起学数字图像处理之直方图均衡化
从这篇博文开始,小生正式从一个毫不相干专业转投数字图像处理.废话不多说了,talk is cheap. show me the code. 直方图均衡化目的 由于一些图像灰度的分布过于集中,这样会导致 ...
- OpenCV-跟我学一起学数字图像处理之中值滤波
中值滤波(median filter)在数字图像处理中属于空域平滑滤波的内容(spatial filtering).对消除椒盐噪声具有很好的效果. 数学原理 为了讲述的便捷,我们以灰度图为例.RGB三 ...
- 【OpenCV】像素操作的数字图像处理
之前几天捣鼓matlab,用来处理数字图像,矩阵操作什么的,如果忘记线性代数就真的GG了. 在用了matlab被深深地吐槽之后,决定改用opencv,C++貌似也是处理数字图像的很好的工具 1. 在u ...
- 数字图像处理作业使用OpenCV - 使用笔记
数字图像处理作业的输入图像全部都是灰度图像,所以汇总一下自己遇到的问题答案. OCV的图像容器是Mat<typename>,可以用imread(filename)读取图像,filename ...
- python数字图像处理(1):环境安装与配置
一提到数字图像处理编程,可能大多数人就会想到matlab,但matlab也有自身的缺点: 1.不开源,价格贵 2.软件容量大.一般3G以上,高版本甚至达5G以上. 3.只能做研究,不易转化成软件. 因 ...
- 数字图像处理笔记与体会(一)——matlab编程基础
最近开始学习数字图像处理,使用matlab实现,下面我就来记录笔记和体会,一方面是给大家提供参考,另一方面是防止我忘记了. 复习一下: 1.数字图像是用一个数字矩阵来表示的,数字阵列中的每个数字,表示 ...
- 数字图像处理:基于MATLAB的车牌识别项目 标签: 图像处理matlab算法 2017-06-24 09:17 98人阅读 评论(0)
学过了数字图像处理,就进行一个综合性强的小项目来巩固一下知识吧.前阵子编写调试了一套基于MATLAB的车牌识别的项目的代码.今天又重新改进了一下代码,识别的效果好一点了,也精简了一些代码.这里没有使用 ...
- 初始----python数字图像处理--:环境安装与配置
一提到数字图像处理编程,可能大多数人就会想到matlab,但matlab也有自身的缺点: 1.不开源,价格贵 2.软件容量大.一般3G以上,高版本甚至达5G以上. 3.只能做研究,不易转化成软件. 因 ...
- 【数字图像处理】六.MFC空间几何变换之图像平移、镜像、旋转、缩放具体解释
本文主要讲述基于VC++6.0 MFC图像处理的应用知识,主要结合自己大三所学课程<数字图像处理>及课件进行解说,主要通过MFC单文档视图实现显示BMP图片空间几何变换.包含图像平移.图形 ...
随机推荐
- 慕课网,vue高仿饿了吗ASP源码视频笔记
1.源码笔记 我的源码+笔记(很重要):http://pan.baidu.com/s/1geI4i2Z 感谢麦子学院项目相关视频 2.参考资料 Vue.js官网(https://vuejs.org.c ...
- Python面向对象之方法
普通方法要执行类里面的方法是通过对象触发的 触发的时候把自己赋值给self 类方法 vim day7-7.py #!/usr/bin/python # -*- coding:utf-8 -*- cla ...
- java 中方法的重写
方法的重写 1.在子类中可以根据需要对从基类中继承来的方法进行重写. 2.方法重写必须要和被重写方法具有相同方法名称.参数列表和返回类型. 3.重写方法不能使用比被重写方法更严格的访问权限 4.注意与 ...
- linux下pip安装pygame
在学习python的过程中要用到pygame,在安装过程中遇到一些问题,经百度解决.因为使用的版本为python3,故以下教程针对python3版本.安装教程如下: 一.首先你要确保你已经安装了pip ...
- CodeForces - 586C Gennady the Dentist 模拟(数学建模的感觉)
http://codeforces.com/problemset/problem/586/C 题意:1~n个孩子排成一排看病.有这么一个模型:孩子听到前面的哭声自信心就会减弱:第i个孩子看病时会发出v ...
- python 经验:把全局变量放在一个类中
注:红色是我增加的注释 add by zhj:其实python中的import, from-import语句是创建新的同名变量指向引入的模块和模块属性,这也就解释了下面的情况. 我们应尽量不用全局变量 ...
- python 线程,GIL 和 ctypes(转)
原文:http://zhuoqiang.me/python-thread-gil-and-ctypes.html GIL 与 Python 线程的纠葛 GIL 是什么东西?它对我们的 python 程 ...
- kubernetes实战(十六):k8s高可用集群平滑升级 v1.11.x 到v1.12.x
1.基本概念 升级之后所有的containers会重启,因为hash值会变. 不可跨版本升级. 2.升级Master节点 当前版本 [root@k8s-master01 ~]# kubeadm ver ...
- 编码问题:python写入文件
方法一:(推荐) line1 = "我爱中国111" line2 = u"我爱祖国222" with open('1.txt','w',encoding='ut ...
- JS DOM节点
html代码: <body onload ="loaded12()"> <form name="form1" action="htt ...