这几天学习SURF特征检测,直接看的视频和书本有点吃不消,现在是基本看懂了,如果写博客记录没有必要,因为网上都差不多,笔记都在书上了,以下是个人认为比较浅显易懂的文章,当然海有很多好文章我没看到。

看第一篇入门就可以,后面讲的不是很好: http://blog.csdn.net/jwh_bupt/article/details/7621681

harris:                  http://www.cnblogs.com/ronny/p/4009425.html

Harr:                 http://blog.csdn.net/zouxy09/article/details/7929570/

Box Filters:              http://blog.csdn.net/lanbing510/article/details/28696833

SIFT:                 http://blog.csdn.net/abcjennifer/article/details/7639681/                                             http://blog.csdn.net/pi9nc/article/details/23302075

Harr小波特征:             场合不同这个表示也不同,比如在SURF中表示dx、dy,当然也可以表示成其它样子,得看Harr的内核

SURF:                 看一下毛星云的那本书,其实网上说的差不多。

ORB:                 http://www.aiuxian.com/article/p-1728722.html,里面包括FAST特征点、BRIEF描述子

HOG:                 这个算法相对比较上面容易理解。

LBP:                  http://blog.csdn.net/quincuntial/article/details/50541815这个算法可以手写实现,上面基本自己都实现不了(难度很大)

双线性插值:             百度百科有(先有三角函数计算坐标位置,然后用双线性插值计算像素值)

LBP算子

 经典LBP算法:
1 int main(int argc, char**argv)
{
Mat input_image, Middle_image,threshold_image;
input_image = imread("1.jpg");
if (input_image.data == NULL) {
return -; cout << "can't open image.../";
}
cvtColor(input_image, input_image, CV_BGR2GRAY);
Mat output_image;
output_image.create(Size(input_image.rows - , input_image.cols - ), input_image.type());
output_image.setTo(, Mat());
int width = input_image.cols * input_image.channels();
int heigth = input_image.rows;
for (size_t i = ; i < heigth - ; i++)
{
//uchar *ptr = input_image.ptr<uchar>(i);
for (size_t j = ; j < width - ; j++)
{
uchar code = ;
uchar center = input_image.at<uchar>(i, j);
code |= (input_image.at<uchar>(i - , j - ) >= center) << ;
code |= (input_image.at<uchar>(i - , j ) >= center) << ;
code |= (input_image.at<uchar>(i - , j + ) >= center) << ;
code |= (input_image.at<uchar>(i , j - ) >= center) << ;
code |= (input_image.at<uchar>(i , j + ) >= center) << ;
code |= (input_image.at<uchar>(i + , j - ) >= center) << ;
code |= (input_image.at<uchar>(i + , j ) >= center) << ;
code |= (input_image.at<uchar>(i + , j + ) >= center) << ;
output_image.at<uchar>(i - , j - ) = code;
}
}
imshow("LineImage", input_image);
imshow("output_image", output_image); waitKey();
return ;
}

 CLBP:
1 #include <opencv2/opencv.hpp>
#include <iostream> using namespace cv;
using namespace std; const int neighbor = ;//圆周上共几个像素
const int radius = ; int main(int argc, char**argv)
{
Mat input_image, output_image;
input_image = imread("1.jpg"); if (input_image.data == NULL) {
return -; cout << "can't open image.../";
}
cvtColor(input_image, input_image, CV_BGR2GRAY);
//Mat output_image = Mat::zeros(Size(input_image.cols - 2 * 30, input_image.rows - 2 * 30), CV_8UC1);
output_image.create(Size(input_image.cols - * radius, input_image.rows - *radius), CV_8UC1);
output_image.setTo();
int width = input_image.cols;
int height = input_image.rows; for (size_t n = ; n < neighbor; n++)
{
//-----计算圆边长点的坐标(这里x、y具体谁用cos和sin的结果一样,看后来计算双线性插值自己怎么理解了)
float x = static_cast<float>(radius) * cos(2.0 * CV_PI*n / static_cast<float>(neighbor));
float y = static_cast<float>(-radius) * sin(2.0 * CV_PI*n / static_cast<float>(neighbor));//这里加不加负号效果一样,因为是点的顺序而已。
//-----计算圆边上点的像素值,用双线性插值方法
int fx = static_cast<int>(floor(x));
int fy = static_cast<int>(floor(y));//上采样
int cx = static_cast<int>(ceil(x));
int cy = static_cast<int>(ceil(y));//下采样 float dx = x - fx;
float dy = y - fy; float w1 = ( - dx)*( - dy);
float w2 = dx*( - dy);
float w3 = ( - dx)*dy;
float w4 = dx*dy; for (size_t i = radius; i < height - radius; i++)
{
for (size_t j = radius; j < width - radius; j++)
{
float p1 = input_image.at<uchar>(i + fy, j + fx);
float p2 = input_image.at<uchar>(i + fy, j + cx);
float p3 = input_image.at<uchar>(i + cy, j + fx);
float p4 = input_image.at<uchar>(i + cy, j + cx); float Angle_data = p1*w1 + p2*w2 + p3*w3 + p4*w4;
output_image.at<uchar>(i - radius, j - radius) |= (((input_image.at<uchar>(i, j) >= Angle_data) && (std::abs(Angle_data-input_image.at<uchar>(i,j)) > numeric_limits<float>::epsilon())) << n);
} }
} imshow("LineImage", input_image);
imshow("output_image", output_image); waitKey();
return ;
}

LBP后面还有很多知识,现在不学习那么深,只是了解一下,以后用到再继续深入。

SIFT算子

 #if 1
#include <opencv2/opencv.hpp>
#include <opencv2/xfeatures2d.hpp>
#include <iostream>
#include "math.h" using namespace cv::xfeatures2d;
using namespace cv;
using namespace std; void calSIFTFeatureAndCompare(Mat& src1, Mat& src2); int main(int argc, char**argv)
{
Mat input_image1, input_image2;
input_image1 = imread("hand1.jpg");
input_image2 = imread("hand2.jpg"); if (!input_image1.data && !input_image2.data) {
return -; cout << "can't open image.../";
}
calSIFTFeatureAndCompare(input_image1, input_image2);
/*imshow("input_image1", input_image1);
imshow("input_image2", input_image2);*/ waitKey();
return ;
}
//-------------特征点:如同harris等检测的点一样(当然加了更多的约束)--------------//
//-------------描述子:点形成组织性,有方向和区域等,更能代表整副图像(也就是在特征点上加了更多的约束) --------------//
void calSIFTFeatureAndCompare(Mat& src1,Mat& src2)
{
Mat grayMat1, grayMat2;
cvtColor(src1, grayMat1, CV_BGR2GRAY);
cvtColor(src2, grayMat2, CV_BGR2GRAY);
normalize(grayMat1, grayMat1, , , CV_MINMAX);
normalize(grayMat2, grayMat2, , , CV_MINMAX);
/*//---定义SIFT描述子
SiftFeatureDetector detector; //计算特征点
SiftDescriptorExtractor extractor;//计算描述子
//---特征点检测
vector<KeyPoint> keypoints1;
vector<KeyPoint> keypoints2;
detector.detect(grayMat1, keypoints1, Mat());
detector.detect(grayMat2, keypoints2, Mat());
//---计算特征点描述子
Mat descriptors1, descriptors2;
extractor.compute(grayMat1, keypoints1, descriptors1);
extractor.compute(grayMat2, keypoints2, descriptors2);*/
//SURF* detector = SURF::create(100);//那道理说是可以的,但是奔溃,不知道原因
Ptr<SURF> detector = SURF::create();//这个参数hessianThreshold为海深矩阵的阈值T,看SIFT原理就可
vector<KeyPoint> keypoints1;
vector<KeyPoint> keypoints2;
Mat descriptors1, descriptors2;
//---特征点和描述子一起检测了
detector->detectAndCompute(grayMat1, Mat(), keypoints1, descriptors1);
detector->detectAndCompute(grayMat2, Mat(), keypoints2, descriptors2);
//---特征点匹配
vector<DMatch> matches;//存储匹配结果的类,和keypoint类似
BFMatcher matcher(NORM_L1); //NORM_L1:代表SIFT,NORM_L2:代表SURF,默认SURF
matcher.match(descriptors1, descriptors2, matches);
Mat resultMatch;
drawMatches(grayMat1, keypoints1, grayMat2, keypoints2, matches, resultMatch);
} #endif

实际图片的匹配与寻找

在原图上截取的一个小图片进行测试---->>>>

                    本文利用SURF算子进行检测,利用FLANN进行匹配!

上代码:

 #if 1
#include <opencv2/opencv.hpp>
#include <opencv2/xfeatures2d.hpp>
#include <iostream>
#include "math.h" using namespace cv::xfeatures2d;
using namespace cv;
using namespace std; int main(int argc, char**argv)
{
Mat input_image1, input_image2;
input_image1 = imread("2.jpg");
input_image2 = imread("1.jpg"); if (!input_image1.data && !input_image2.data) {
return -; cout << "can't open image.../";
}
//-------------keypoints and descriptor detection
const int minHessian = ;
Ptr<SURF> detector = SURF::create(minHessian);
vector<KeyPoint> srcKeyPoint, dstKeyPoint;
Mat srcDescriptor, dstDescriptor;
detector->detectAndCompute(input_image1, Mat(), srcKeyPoint, srcDescriptor);
detector->detectAndCompute(input_image2, Mat(), dstKeyPoint, dstDescriptor);
//------------FLANN algorithm match
FlannBasedMatcher matcher;
vector<DMatch> matches;
matcher.match(srcDescriptor, dstDescriptor, matches);
Mat matchImage;
drawMatches(input_image1, srcKeyPoint, input_image2, dstKeyPoint, matches, matchImage);
//------------calculate best keypoint
double maxDistance = , minDistance = ;
for (size_t i = ; i < matches.size(); i++)
{
maxDistance = maxDistance < matches[i].distance ? matches[i].distance : maxDistance;
minDistance = minDistance < matches[i].distance ? minDistance : matches[i].distance;
}
vector<DMatch> bestMatches;
for (size_t i = ; i < matches.size(); i++)
{
if (matches[i].distance < * minDistance)
{
bestMatches.push_back(matches[i]);
}
}
Mat bestMatchImage;
drawMatches(input_image1, srcKeyPoint, input_image2, dstKeyPoint, bestMatches, bestMatchImage);
//-----------Find four corner points from bestMatches
vector<Point2f> srcPoint;
vector<Point2f> dstPoint;
for (size_t i = ; i < bestMatches.size(); i++)//save coordinate to srcPoint/dstPoint from bestMatches
{
srcPoint.push_back(srcKeyPoint[bestMatches[i].queryIdx].pt);
dstPoint.push_back(dstKeyPoint[bestMatches[i].trainIdx].pt);
}
Mat H = findHomography(srcPoint, dstPoint,CV_RANSAC);//detection perspective Mapping(H映射)
vector<Point2f> srcCorners();
vector<Point2f> dstCorners();
srcCorners[] = Point(, );
srcCorners[] = Point(input_image1.cols, );
srcCorners[] = Point(, input_image1.rows);
srcCorners[] = Point(input_image1.cols, input_image1.rows);
perspectiveTransform(srcCorners, dstCorners, H);//detection destination Corners
line(input_image2, dstCorners[], dstCorners[], Scalar(, , ), );
line(input_image2, dstCorners[], dstCorners[], Scalar(, , ), );
line(input_image2, dstCorners[], dstCorners[], Scalar(, , ), );
line(input_image2, dstCorners[], dstCorners[], Scalar(, , ), );
waitKey();
return ;
} #endif

《opencv学习》 之 特征检测与匹配的更多相关文章

  1. OpenCV 学习笔记(模板匹配)

    OpenCV 学习笔记(模板匹配) 模板匹配是在一幅图像中寻找一个特定目标的方法之一.这种方法的原理非常简单,遍历图像中的每一个可能的位置,比较各处与模板是否"相似",当相似度足够 ...

  2. OpenCV 学习笔记 07 目标检测与识别

    目标检测与识别是计算机视觉中最常见的挑战之一.属于高级主题. 本章节将扩展目标检测的概念,首先探讨人脸识别技术,然后将该技术应用到显示生活中的各种目标检测. 1 目标检测与识别技术 为了与OpenCV ...

  3. OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波

    http://blog.csdn.net/chenyusiyuan/article/details/8710462 OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波 201 ...

  4. OpenCV 学习笔记 05 人脸检测和识别 AttributeError: module 'cv2' has no attribute 'face'

    1 环境设置: win10 python 3.6.8 opencv 4.0.1 2 尝试的方法 在学习人脸识别中,遇到了没有 cv2 中没有 face 属性.在网上找了几个方法,均没有成功解决掉该问题 ...

  5. opencv学习笔记(七)SVM+HOG

    opencv学习笔记(七)SVM+HOG 一.简介 方向梯度直方图(Histogram of Oriented Gradient,HOG)特征是一种在计算机视觉和图像处理中用来进行物体检测的特征描述子 ...

  6. opencv学习笔记(六)直方图比较图片相似度

    opencv学习笔记(六)直方图比较图片相似度 opencv提供了API来比较图片的相似程度,使我们很简单的就能对2个图片进行比较,这就是直方图的比较,直方图英文是histogram, 原理就是就是将 ...

  7. opencv学习笔记(五)镜像对称

    opencv学习笔记(五)镜像对称 设图像的宽度为width,长度为height.(x,y)为变换后的坐标,(x0,y0)为原图像的坐标. 水平镜像变换: 代码实现: #include <ios ...

  8. opencv学习笔记(四)投影

    opencv学习笔记(四)投影 任选了一张图片用于测试,图片如下所示: #include <cv.h> #include <highgui.h> using namespace ...

  9. opencv学习笔记(三)基本数据类型

    opencv学习笔记(三)基本数据类型 类:DataType 将C++数据类型转换为对应的opencv数据类型 OpenCV原始数据类型的特征模版.OpenCV的原始数据类型包括unsigned ch ...

随机推荐

  1. FREESWITCH 填坑指南

    转接 1.查看网关注册状态 sofia status 2.桥接(未实践) http://wiki.freeswitch.org.cn/wiki/Mod_lua.html#jump10237 frees ...

  2. Luogu 3245 大数

    Luogu 3245 大数 开始就想 \(10\) 进制 \(hash\) ,\(Hash(r)\equiv Hash(l-1)\cdot 10^{r-l+1}\) ,感觉没什么美妙的性质啊... 然 ...

  3. java反射机制的作用与优点

    java的反射机制就是增加程序的灵活性,避免将程序写死到代码里,例如: 实例化一个 person()对象, 不使用反射, new person(); 如果想变成 实例化 其他类, 那么必须修改源代码, ...

  4. Ubuntu 18.10安装Firefox 和 Google Chrome

    ================================ 工作环境迁移到Linux上,操作系统使用Linux Mint19.1(基于Ubuntu的), 自带的浏览器器是低版本的英文版,现在使用 ...

  5. (领悟)第一个servlet

    //这个代码不可以写在javase的project文件里面//要写在动态web工程里面,不需要配置文件,不需要jsp,只需jar包的帮助(url跳转的必须是java-web文件) import jav ...

  6. js实现表格行的动态加入------Day56

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/marSmile_tbo/article/details/36752655 现代页面通常都是用div+ ...

  7. C#处理Exception的常用方法总结

     在.NET中,异常是指成员没有完成它的名称宣称可以完成的行动.在异常的机制中,异常和某件事情的发生频率无关. 异常处理四要素包括:一个表示异常详细信息的类类型:一个向调用者引发异常类实例的成员:调用 ...

  8. summernote 如何设置为只读?

    从 summernote 的文档看到以下信息. disable, enable You can disable editor by API. $('#summernote').summernote(' ...

  9. BeanUtils Object 取值赋值

    /** * 将结果集导出为Excel * * @param response * @param fsc * @param columns * @param bizType * @throws Exce ...

  10. openwrt设置默认登陆密码

    1.修改dropbear配置文件 找到package/network/services/dropbear/files/dropbear.config 修改如下: config dropbear opt ...