边缘检测

1、Sobel

2、Laplace

3、Roberts

4、Canny


Marr-Hildreth

简单来说,就是先对图像进行(1)高斯滤波,再进行拉普拉斯变换,(2)由于拉普拉斯变换是二阶偏导,边缘点对应的一阶偏导为局部极值,那么其二阶偏导则为0点,(3)所以最后一步为0点检测

相关数学证明请参见:

https://blog.csdn.net/songzitea/article/details/12851079

http://homepages.inf.ed.ac.uk/rbf/HIPR2/log.htm

下面给出拉普拉斯算子:

高斯核模版如下:

而这里的算法就是,经过研究, Marr 和Hildreth发现,可以将这两个算子融合在一齐得到的算子称LOG算子,这样就不用经过两次运算,直接进行一次卷积即可达到结果。而最终结果是LOG算子中高斯部分对图像进行了滤波平滑处理,而拉普拉斯部分对图像进行了二阶偏导,现在是时候给出LOG算子模版了。

这里先给出LOG函数(墨西哥草帽)的真容

那么,对应的5*5 LOG算子为:


实现代码:

#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<iostream>
using namespace std;
using namespace cv;
void marrEdge(const Mat src, Mat &result, int kerValue,double delta)
{//计算LOG算子Mat kernel;//半径int kerLen = kerValue / 2;kernel = Mat_<double>(kerValue, kerValue);//滑窗for (int i = -kerLen; i <= kerLen; i++){for (int j = -kerLen; j <= kerLen; j++){//生成核因子kernel.at<double>(i + kerLen, j + kerLen) =exp(-((pow(j, 2) + pow(i, 2)) /(pow(delta, 2) * 2)))*(((pow(j, 2) + pow(i, 2) - 2 *pow(delta, 2)) / (2 * pow(delta, 4))));}}//设置输出参数int kerOffset = kerValue / 2;Mat laplacian = (Mat_<double>(src.rows - kerOffset * 2,src.cols - kerOffset * 2));result = Mat::zeros(src.rows - kerOffset * 2,src.cols - kerOffset * 2, src.type());double sumLaplacian;//遍历计算卷积图像的拉普拉斯算子for (int i = kerOffset; i < src.rows - kerOffset; ++i){for (int j = kerOffset; j < src.cols - kerOffset; ++j){sumLaplacian = 0;for (int k = -kerOffset; k <= kerOffset; ++k){for (int m = -kerOffset; m <= kerOffset; ++m){//计算图像卷积sumLaplacian += src.at<uchar>(i + k, j + m)*kernel.at<double>(kerOffset + k, kerOffset + m);}}//生成该像素下的拉普拉斯结果laplacian.at<double>(i - kerOffset,j - kerOffset) = sumLaplacian;}}//过零点交叉(寻找零点),寻找边缘点for (int y = 1; y < result.rows - 1; ++y){for (int x = 1; x < result.cols - 1; ++x){result.at<uchar>(y, x) = 0;//邻域判定 4个方向if (laplacian.at<double>(y - 1, x)*laplacian.at<double>(y + 1, x) < 0){result.at<uchar>(y, x) = 255;}if (laplacian.at<double>(y, x-1)*laplacian.at<double>(y , x+ 1) < 0){result.at<uchar>(y, x) = 255;}if (laplacian.at<double>(y +1, x-1)*laplacian.at<double>(y - 1, x+1) < 0){result.at<uchar>(y, x) = 255;}if (laplacian.at<double>(y - 1, x-1)*laplacian.at<double>(y + 1, x+1) < 0){result.at<uchar>(y, x) = 255;}}}
}void main()
{Mat srcImage = imread("F:\\opencv_re_learn\\2.jpg");if (!srcImage.data){cout << "failed to read" << endl;system("pause");return;}Mat srcGray;cvtColor(srcImage, srcGray, CV_BGR2GRAY);Mat edge;//第3个参数为核的大小,一般从5开始marrEdge(srcGray, edge, 5, 1);imshow("srcImage", srcImage);imshow("edge", edge);waitKey(0);
}

实现效果:

这个算法调用起来比较卡,貌似是O(n^4)复杂度?


代码优化:

运行了几次,发现速度实在太慢,想了一下,能不能用filter2D去代替函数中的卷积操作部分?

实现代码:

#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<iostream>
using namespace std;
using namespace cv;void marrEdge2(const Mat src, Mat &result, int kerValue,double delta)
{//计算LOG算子Mat kernel;//半径int kerLen = kerValue / 2;kernel = Mat_<double>(kerValue, kerValue);//滑窗for (int i = -kerLen; i <= kerLen; i++){for (int j = -kerLen; j <= kerLen; j++){//生成核因子kernel.at<double>(i + kerLen, j + kerLen) =exp(-((pow(j, 2) + pow(i, 2)) /(pow(delta, 2) * 2)))*(((pow(j, 2) + pow(i, 2) - 2 *pow(delta, 2)) / (2 * pow(delta, 4))));}}int kerOffset = kerValue / 2;Mat laplacian;filter2D(src, laplacian, src.depth(), kernel);imshow("laplacian", laplacian);//过零点交叉(寻找零点),寻找边缘点for (int y = 1; y < result.rows - 1; ++y){for (int x = 1; x < result.cols - 1; ++x){result.at<uchar>(y, x) = 0;//邻域判定 4个方向if (laplacian.at<double>(y - 1, x)*laplacian.at<double>(y + 1, x) < 0){result.at<uchar>(y, x) = 255;}if (laplacian.at<double>(y, x - 1)*laplacian.at<double>(y, x + 1) < 0){result.at<uchar>(y, x) = 255;}if (laplacian.at<double>(y + 1, x - 1)*laplacian.at<double>(y - 1, x + 1) < 0){result.at<uchar>(y, x) = 255;}if (laplacian.at<double>(y - 1, x - 1)*laplacian.at<double>(y + 1, x + 1) < 0){result.at<uchar>(y, x) = 255;}}}//卷积后的二值化threshold(laplacian, result, 1, 255, CV_THRESH_BINARY);
}
void main()
{Mat srcImage = imread("F:\\opencv_re_learn\\2.jpg");if (!srcImage.data){cout << "failed to read" << endl;system("pause");return;}Mat srcGray;cvtColor(srcImage, srcGray, CV_BGR2GRAY);Mat edge;//第3个参数为核的大小,一般从5开始marrEdge2(srcGray, edge, 5, 1);imshow("srcImage", srcImage);imshow("edge", edge);waitKey(0);
}

优化后的效果:

处理速度蹭蹭的上来了。。不过貌似少了最后一个步骤就是交叉零点检测,代码中取而代之的是二值化。

对比:https://blog.csdn.net/dieju8330/article/details/82813592 中的直接用拉普拉斯算子,发现周边的星星噪点确实少了。

Opencv2.4学习::边缘检测(6)Marr-Hildreth算法(LOG算法)相关推荐

  1. 09 Marr算子(LoG算法)

    文章目录 前言 一.高斯拉普拉斯方法 二.代码实现 1.LoG滤波器 2.和图像进行卷积 前言 拉普拉斯检测算子结合在一起进行边缘检测的方法:先对图像进行平滑,然后再用Laplacian算子检测边缘. ...

  2. 数字图像处理学习笔记(三):ORB算法(尺度不变特征变换)Oriented FAST and Rotated BRIEF

    数字图像处理学习笔记(三):ORB算法(尺度不变特征变换)Oriented FAST and Rotated BRIEF 一.概述 参考:特征点匹配+特征检测方法汇总 ORB的全称是Oriented ...

  3. 深度学习多变量时间序列预测:Encoder-Decoder LSTM算法构建时间序列多变量模型预测交通流量+代码实战

    深度学习多变量时间序列预测:Encoder-Decoder LSTM算法构建时间序列多变量模型预测交通流量+代码实战 LSTM是一种时间递归神经网络,适合于处理和预测时间序列中间隔和延迟相对较长的重要 ...

  4. 【HLSL学习笔记】WPF Shader Effect Library算法解读之[DirectionalBlur]

    原文:[HLSL学习笔记]WPF Shader Effect Library算法解读之[DirectionalBlur] 方位模糊是一个按照指定角度循环位移并叠加纹理,最后平均颜色值并输出的一种特效. ...

  5. DDos攻击,使用深度学习中 栈式自编码的算法

    转自:http://www.airghc.top/2016/11/10/Dection-DDos/ 最近研究了一篇论文,关于检测DDos攻击,使用了深度学习中 栈式自编码的算法,现在简要介绍一下内容 ...

  6. 深度学习目标检测系列:RCNN系列算法图解

    在生活中,经常会遇到这样的一种情况,上班要出门的时候,突然找不到一件东西了,比如钥匙.手机或者手表等.这个时候一般在房间翻一遍各个角落来寻找不见的物品,最后突然一拍大脑,想到在某一个地方,在整个过程中 ...

  7. 强化学习—— TD算法(Sarsa算法+Q-learning算法)

    强化学习-- TD算法(Sarsa算法+Q-learning算法) 1. Sarsa算法 1.1 TD Target 1.2 表格形式的Sarsa算法 1.3 神经网络形式的Sarsa算法 2. Q- ...

  8. 机器学习 集成学习篇——python实现Bagging和AdaBOOST算法

    机器学习 集成学习篇--python实现Bagging和AdaBOOST算法 摘要 Bagging算法 Adaboost算法 摘要 本文通过python实现了集成学习中的Bagging和AdaBOOS ...

  9. 强化学习之基于伪计数的探索算法

    ©作者|王治海 学校|中国科学技术大学硕士生 研究方向|强化学习与机器博弈 强化学习基于智能体与环境的交互,以最大化累积奖励为目标,学习状态到动作的映射(即策略).本文将主要围绕强化学习中的探索问题展 ...

最新文章

  1. ADPRL - 近似动态规划和强化学习 - Note 3 - Stochastic Infinite Horizon Problem
  2. Java集合框架系列教程三:Collection接口
  3. Developer FAQ: Building | 开发人员常遇到的问题:构建
  4. Spring Security——SessionManagement中InvalidSessionStrategy自定义——简单跳过Fitter过滤刷新Session
  5. 市场定位和硬件设计的错误-浅谈GM8126的封装
  6. 容器源码分析之ArrayList(二)
  7. [ JS 进阶 ] Repaint 、Reflow 的基本认识和优化 (2)
  8. android 自定义弹窗diss,Android中自定义PopupWindow,动态弹窗。
  9. 【Android实战】Gallary+ImageSwicther图片查看器
  10. 什么是机器学习?有哪些应用?终于有人讲明白了
  11. 【数据结构、算法】八大排序算法概述(算法复杂度、稳定性)
  12. php 邮件收发 (乱码)
  13. Windows Phone7 手机越狱教程
  14. TTC - Building a Better Vocabulary
  15. c语言mfc步骤,C语言工程MFC
  16. python解释器配置_Python解释器的配置
  17. 偷窥桌面程序和IE浏览器的密码编辑框
  18. 135微信编辑html语言,135微信编辑器怎么在拉入的模板框框里添加文字
  19. odoo13 学习 Actions 动作的定义
  20. csv是什么文件(ofd是什么文件)

热门文章

  1. 使用RTX3080显卡搭建基于Pycharm+Python+Cuda+cuDNN+TensorFlow的深度学习开发环境
  2. openjdk java字体库_java - 在Linux上为Openjdk Java定义/安装的字体在哪里
  3. 宝讯网捷:抖音618活动有什么玩法?
  4. 超轻量级 Javascript 框架,暂且取名为MYJS
  5. Jenkins 忘记admin用户名以及密码
  6. Java架构师的8个技术要求标准,你知道吗?
  7. vue基础二(组件)
  8. 验证工程师需要get技能有那些呢?
  9. Box2D在VS2010上面的配置
  10. android拍照模糊,解决Android拍照并显示在ImageView中变模糊