1.原理

Difference of Gaussian(DOG)是高斯函数的差分。将两幅图像在不同参数下的高斯滤波结果相减,得到DoG图。步骤:

  • 处理一幅图像在不同高斯参数下的DoG

    用两个不同的5x5高斯核对图像进行卷积,然后再相减的操作。重复三次得到三个差分图A,B,C。

  • 根据DoG求角点

    计算出的A,B,C三个DOG图中求图B中是极值的点。图B的点在当前由A,B,C共27个点组成的block中是否为极大值或者极小值。若满足此条件则认为是角点。

![](http://my.csdn.net/uploads/201206/06/1338983859_7860.jpg)

2.实现细节

2.1 差分得到DoG图

Mat Process(Mat &A, double sig1, double sig2, Size Ksize)
{
Mat AF, out, out1, out2;
A.convertTo(AF, CV_32FC1);
GaussianBlur(AF, out1, Ksize, sig1, 0);
GaussianBlur(AF, out2, Ksize, sig2, 0);
subtract(out1, out2, out);
return out;
}
  • converTo()

    直接读取灰度图会得到CV_8UC1类型的mat,是单通道uchar型矩阵,因此高斯滤波后相减都是整型非负数据,影响后面进行比较取极值的步骤。所以需要将原本的数据类型转化为CV_32FC1即单通道float型数据。再进行后续的操作
  • subtract()

    两个mat类型相减直接用这个就好了。刚开始查到cvSub函数是老版本的,里面的指针乱七八糟的都挺复杂的,后在官方说明上找到这个c++版本的函数。现在的操作基本都是这个了。

2.2 求取当前block极值得到角点

Mat getExtrema(Mat &A, Mat &B, Mat &C, int thresh)
{
Mat block;
Mat extr = Mat::zeros(A.rows, A.cols, CV_32FC1);
double minv, maxv;
Point minLoc, maxLoc;
for (int i = 1; i < A.rows - 2; i++)
{
for (int j = 1; j < A.cols - 2; j++)
{
block.release();
block.push_back(A(Range(i - 1, i + 2), Range(j - 1, j + 2)));
block.push_back(B(Range(i - 1, i + 2), Range(j - 1, j + 2)));
block.push_back(C(Range(i - 1, i + 2), Range(j - 1, j + 2)));
minMaxLoc(block, &minv, &maxv, &minLoc, &maxLoc);
if ((maxLoc.x == 1 && maxLoc.y == 4) && maxv >(double)thresh)
extr.at<float>(i, j) = 1;
if ((minLoc.x == 1 && minLoc.y == 4) && minv < (double)(-thresh))
extr.at<float>(i, j) = -1;
}
}
return extr;
}

取出A,B,C中3x3的小块存放在一个mat里,然后利用自带的求取最大最小值函数minMaxLoc得到最大最小值和其位置。然后判断该点\((i,j)\)是否为极值点。每个循环刷新释放block。

2.3 求取当前block极值得到角点

void drawExtrema(Mat &imgB, Mat &extr)

将得到的极值点在原图像中显示。由于imread(img,0)得到的是单通道灰度图 ,opencv提供的cirle()line()函数在img上无法显示,所以用imread(imgB)得到一个三通道的灰度图,然后在这个imgB上画出标记点。

2.4 讨论

用样例测试图600x1200像素点的时候,运算速度很慢,逐步运行发现时间主要消耗在getExtrema()函数上。原因可能是:

  • mat.push_back()截取矩阵然后合并得到新矩阵用这个操作比较费时间。如果改进的话可以直接用一个数组,将三个3x3矩阵的数据直接放进去。
  • minMaxLoc()求取当前矩阵最大最小值和响应位置。这个函数涉及到排序可能也费时间。因为只用判断当前\((i,j)\)点是否是极值,其实可以将这27个数据直接减去mat.at(i,j)根据是否都大于或者小于零来判断极值。

然而我已经懒得改了……需要优化速度的话再动手。

3.测试结果

输入图像:

![](http://ww3.sinaimg.cn/mw690/db2e1667gw1f3hcrrc5dzj20xc0goq2w.jpg)
输出结果:
![](http://ww3.sinaimg.cn/mw690/db2e1667gw1f3yphp0gtwj20xc0goweh.jpg)

参考

  1. DoG (Difference of Gaussian)角点检测
  2. 斑点检测
  3. 将mat数据输出到文件

关于opencv的函数,官方说明十分好,直接google之看一下就知道用法了。调试时将mat输出到文件用到了参考链接3。

5.代码

#include <iostream>
#include <fstream>
#include "opencv2/core/core.hpp"
#include "highgui.h"
#include "opencv2/imgproc/imgproc.hpp" using namespace cv;
using namespace std;
Mat Process(Mat &A, double sig1, double sig2, Size Ksize)
{
Mat AF, out, out1, out2;
A.convertTo(AF, CV_32FC1);
GaussianBlur(AF, out1, Ksize, sig1, 0);
GaussianBlur(AF, out2, Ksize, sig2, 0);
subtract(out1, out2, out);
return out;
} Mat getExtrema(Mat &A, Mat &B, Mat &C, int thresh)
{
Mat block;
Mat extr = Mat::zeros(A.rows, A.cols, CV_32FC1);
double minv, maxv;
Point minLoc, maxLoc;
for (int i = 1; i < A.rows - 2; i++)
{
for (int j = 1; j < A.cols - 2; j++)
{
block.release();
block.push_back(A(Range(i - 1, i + 2), Range(j - 1, j + 2)));
block.push_back(B(Range(i - 1, i + 2), Range(j - 1, j + 2)));
block.push_back(C(Range(i - 1, i + 2), Range(j - 1, j + 2)));
minMaxLoc(block, &minv, &maxv, &minLoc, &maxLoc);
if ((maxLoc.x == 1 && maxLoc.y == 4) && maxv >(double)thresh)
extr.at<float>(i, j) = 1;
if ((minLoc.x == 1 && minLoc.y == 4) && minv < (double)(-thresh))
extr.at<float>(i, j) = -1;
}
}
return extr;
} void drawExtrema(Mat &img, Mat &extr)
{
Point center;
int r = 2;
for (int i = 0; i < img.rows; i++)
{
for (int j = 0; j < img.cols; j++)
{
if (extr.at<float>(i, j) == -1)
{
center = Point(j, i);
circle(img, center, r, Scalar(0, 255, 0));
}
if (extr.at<float>(i, j) == 1)
{
center = Point(j, i);
circle(img, center, r, Scalar(0, 0, 255));
}
}
} namedWindow("DoG");
imshow("DoG", img);
waitKey(0);
} int main(int argc, char** argv)
{
char file_name[] = "result1.png";
Mat img = imread(file_name, 0);
Mat A, B, C, a;
int threshold = 3;
A = Process(img, 0.3, 0.4, Size(5, 5));
B = Process(img, 0.6, 0.7, Size(5, 5));
C = Process(img, 0.7, 0.8, Size(5, 5));
a = getExtrema(A, B, C, threshold);
//const char* filename = "output.txt";
//writeMatToFile(B, filename);
Mat imgB = imread(file_name);
drawExtrema(imgB, a);
return 0;
}

DOG角点检测——opencv实现的更多相关文章

  1. opencv笔记6:角点检测

    time:2015年10月09日 星期五 23时11分58秒 # opencv笔记6:角点检测 update:从角点检测,学习图像的特征,这是后续图像跟踪.图像匹配的基础. 角点检测是什么鬼?前面一篇 ...

  2. OpenCV计算机视觉学习(13)——图像特征点检测(Harris角点检测,sift算法)

    如果需要处理的原图及代码,请移步小编的GitHub地址 传送门:请点击我 如果点击有误:https://github.com/LeBron-Jian/ComputerVisionPractice 前言 ...

  3. 图像金字塔、高斯金字塔、差分金字塔(DOG金字塔)、尺度空间、DoG (Difference of Gaussian)角点检测

    [图像金字塔] 图像金字塔是一种以多分辨率来解释图像的结构,通过对原始图像进行多尺度像素采样的方式,生成N个不同分辨率的图像.把具有最高级别分辨率的图像放在底部,以金字塔形状排列,往上是一系列像素(尺 ...

  4. OpenCV探索之路(十五):角点检测

    角点检测是计算机视觉系统中用来获取图像特征的一种方法.我们都常说,这幅图像很有特点,但是一问他到底有哪些特点,或者这幅图有哪些特征可以让你一下子就识别出该物体,你可能就说不出来了.其实说图像的特征,你 ...

  5. OpenCV角点检测源代码分析(Harris和ShiTomasi角点)

    OpenCV中常用的角点检测为Harris角点和ShiTomasi角点. 以OpenCV源代码文件 .\opencv\sources\samples\cpp\tutorial_code\Trackin ...

  6. OpenCV角点检测goodFeaturesToTrack()源代码分析

    上面一篇博客分析了HARRIS和ShiTomasi角点检测的源代码.而为了提取更准确的角点,OpenCV中提供了goodFeaturesToTrack()这个API函数,来获取更加准确的角点位置.这篇 ...

  7. cv2.cornerHarris()详解 python+OpenCV 中的 Harris 角点检测

    参考文献----------OpenCV-Python-Toturial-中文版.pdf 参考博客----------http://www.bubuko.com/infodetail-2498014. ...

  8. Opencv学习笔记------Harris角点检测

    image算法测试iteratoralgorithmfeatures 原创文章,转载请注明出处:http://blog.csdn.net/crzy_sparrow/article/details/73 ...

  9. opencv学习之路(32)、角点检测

    一.角点检测的相关概念 二.Harris角点检测——cornerHarris() 参考网址: http://www.cnblogs.com/ronny/p/4009425.html #include ...

随机推荐

  1. linux sar 命令详解(转载)

    linux sar 命令详解 2013-04-01 11:05 [小 大] 来源: 开源中国社区 评论: 0 分享至: 百度权重查询 词库网 网站监控 服务器监控 SEO监控 手机游戏 iPhone游 ...

  2. visual studio code, asp.net5, mvc6资料汇总

    最近在试探性地跟随微软最新发布的一些产品,现列下某些挺好的文章和链接 code.visualstudio.com http://blogs.msdn.com/b/cesardelatorre/arch ...

  3. iOS基础 - 通知中心(NSNotificationCenter)

    通知中心(NSNotificationCenter) 每一个应用程序都有一个通知中心(NSNotificationCenter)实例,专门负责协助不同对象之间的消息通信 任何一个对象都可以向通知中心发 ...

  4. Leetcode::JumpGame

    Description: Given an array of non-negative integers, you are initially positioned at the first inde ...

  5. Session、Application、Cache

    [Asp.Net]状态管理(Session.Application.Cache) 上篇博文介绍了在客户端状态管理的两种方式:http://www.cnblogs.com/wolf-sun/p/3329 ...

  6. C++11标准后的C++阅读书目

    C++11标准后的C++阅读书目 投递人 itwriter 发布于 2013-09-25 19:44 评论(2) 有285人阅读  原文链接  [收藏]  « » 英文原文:C++ Reading L ...

  7. Xilinx-Zynq Linux内核源码编译过程

    本文内容依据http://www.wiki.xilinx.com网址编写,编译所用操作系统为ubuntu 14 1.交叉编译环境的安装配置 1)http://www.wiki.xilinx.com/I ...

  8. sql 清除日志空间

    USE DBCenter GO SELECT file_id, name FROM sys.database_files; 查找日志名称 USE DBCenter ; GO ALTER DATABAS ...

  9. 玩下Javascript

    玩下Javascript 前言 好久没有更新博客了,也蛮少捣弄javascript,今儿看到一个题目,关于给你一个面板,你可以随意的在上面画矩形,可以移动和删除任意一个你创建的矩形,心血来潮搞着玩哈, ...

  10. java正则表达式验证标点符号

    统计标点符号个数 String str = "\""..,!,"; int count = 0; Pattern pattern = Pattern.compi ...