《opencv学习》 之 特征检测与匹配
这几天学习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学习》 之 特征检测与匹配的更多相关文章
- OpenCV 学习笔记(模板匹配)
OpenCV 学习笔记(模板匹配) 模板匹配是在一幅图像中寻找一个特定目标的方法之一.这种方法的原理非常简单,遍历图像中的每一个可能的位置,比较各处与模板是否"相似",当相似度足够 ...
- OpenCV 学习笔记 07 目标检测与识别
目标检测与识别是计算机视觉中最常见的挑战之一.属于高级主题. 本章节将扩展目标检测的概念,首先探讨人脸识别技术,然后将该技术应用到显示生活中的各种目标检测. 1 目标检测与识别技术 为了与OpenCV ...
- OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波
http://blog.csdn.net/chenyusiyuan/article/details/8710462 OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波 201 ...
- OpenCV 学习笔记 05 人脸检测和识别 AttributeError: module 'cv2' has no attribute 'face'
1 环境设置: win10 python 3.6.8 opencv 4.0.1 2 尝试的方法 在学习人脸识别中,遇到了没有 cv2 中没有 face 属性.在网上找了几个方法,均没有成功解决掉该问题 ...
- opencv学习笔记(七)SVM+HOG
opencv学习笔记(七)SVM+HOG 一.简介 方向梯度直方图(Histogram of Oriented Gradient,HOG)特征是一种在计算机视觉和图像处理中用来进行物体检测的特征描述子 ...
- opencv学习笔记(六)直方图比较图片相似度
opencv学习笔记(六)直方图比较图片相似度 opencv提供了API来比较图片的相似程度,使我们很简单的就能对2个图片进行比较,这就是直方图的比较,直方图英文是histogram, 原理就是就是将 ...
- opencv学习笔记(五)镜像对称
opencv学习笔记(五)镜像对称 设图像的宽度为width,长度为height.(x,y)为变换后的坐标,(x0,y0)为原图像的坐标. 水平镜像变换: 代码实现: #include <ios ...
- opencv学习笔记(四)投影
opencv学习笔记(四)投影 任选了一张图片用于测试,图片如下所示: #include <cv.h> #include <highgui.h> using namespace ...
- opencv学习笔记(三)基本数据类型
opencv学习笔记(三)基本数据类型 类:DataType 将C++数据类型转换为对应的opencv数据类型 OpenCV原始数据类型的特征模版.OpenCV的原始数据类型包括unsigned ch ...
随机推荐
- Texas Instruments matrix-gui-2.0 hacking -- submenu.php
<?php /* * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ * * * Redistrib ...
- ZOJ 3211dream city dp(效率优化)
Dream City Time Limit: 1 Second Memory Limit:32768 KB JAVAMAN is visiting Dream City and he see ...
- mongo dos操作
https://www.cnblogs.com/beileixinqing/p/8241822.html 基础1 https://blog.csdn.net/superjunjin/article/d ...
- 【java规则引擎】《Drools7.0.0.Final规则引擎教程》第4章 4.2 ruleflow-group&salience
转载至:https://blog.csdn.net/wo541075754/article/details/75299888 ruleflow-group 在使用规则流的时候要用到ruleflow-g ...
- 在Spark上通过BulkLoad快速将海量数据导入到Hbase
我们在<通过BulkLoad快速将海量数据导入到Hbase[Hadoop篇]>文中介绍了一种快速将海量数据导入Hbase的一种方法,而本文将介绍如何在Spark上使用Scala编写快速导入 ...
- hasura-graphql 集成 pipelinedb 1.0.0
pipelinedb 1.0.0 已经是一个标准的pg 扩展了,同时以前的语法也有变动,但是集成进hasura-graphql 更方便了 使用docker-compose 运行 环境准备 docker ...
- [转]Spring IOC详解
Spring框架的Spring的IoC(控制反转) .DI(依赖注入)这两个概念,对于初学Spring的人来说,总觉得IoC .DI这两个概念是模糊不清的,是很难理解的,今天和大家分享网上的一些技术大 ...
- SQL Server Reporting Service 报错:报表服务器无法解密用于访问报表服务器数据库中的敏感数据或加密数据的对称密钥,必须还原备份密钥或删除所有加密的内容。
出现这个问题,可以通过reporting services 配置管理工具来处理 首先,打开配置管理工具,连接. 在左侧的导航选项中选择Encryption Keys,将出现如图所示的界面,在右侧点击d ...
- Microsoft Dynamics CRM 2013 相关安装包下载
90-day trial keys:Microsoft Dynamics CRM Workgroup Server 2013 (5 CAL limit):NX77Y-BTBCV-JP3T3-8W7JH ...
- 从windows到linux的shell脚本编码和格式问题
从windows到linux的shell脚本编码和格式问题 从windows到Linux的shell脚本编码和格式问题 1.异常问题 :set ff=unix 启动脚本在启动时报错比如执行sh s ...