图像匹配:颜色、纹理、大小、形状
鲁棒性(Robust):是指控制系统在一定(结构,大小)的参数摄动下,维持其它某些性能的特性。
角点: 某点与周围的点的梯度。角点是纹理的最好反映
位置发生变化 纹理几乎不变。
角点检测
FAST:
取16个点 16个里有12是白的,其他为黑的,那么这个点为角点。(计算量大)
取四个点,只要其中有三个点和其中一个点不一样那么这个点为角点
缺点:初步提取,有很多是边缘点
#include <opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
bool isdif(uchar a, uchar b) {
if (abs(a - b) < 30) //可通过改变值调整判断条件
{
return false;
}
else
return true;
}
void main() {
VideoCapture cap(0);
while (true)
{
Mat frame;
cap >> frame;
/*
fast
*/
Mat frame_rgb;
frame.copyTo(frame_rgb);
cvtColor(frame, frame, CV_64FC1);
// cout << frame.at(uchar)(0.0);
int pos[4][2];//存储相对中心角点的位置
pos[0][0] = 0;
pos[0][1] = -3;
pos[1][0] = 3;
pos[1][1] = 0;
pos[2][0] = 0;
pos[2][1] = 3;
pos[3][0] = -3;
pos[3][1] = 0;
for (int i = 3; i < frame.rows-3; i++)//保证内存不会溢出
{
for (int j = 3; j < frame.cols-3; j++)
{
int num=0;//有几个角点和中-心角点不一样
uchar cen = frame.at<uchar>(i, j);
for (int k = 0; k < 4; k++) {
uchar temp = frame.at<uchar>(i + pos[k][0], j + pos[k][1]);
//判断temp和中心角点有没有变化
if (isdif(cen, temp)) {
num++;
}
}
if (num == 1 || num == 3 || num == 4) {
circle(frame_rgb,cvPoint(j, i), 2, CV_RGB(255, 0, 0), 2);
}
}
}
imshow("frame", frame_rgb);
waitKey(10);
}
}
HARRIS:
二维泰勒级数
/*
HARRIS:更多也是检测出来的边缘
*/
for (int i = 1; i < frame.rows-1; i++) {
for (int j = 1; j < frame.cols-1; j++) {
double IX, IY;//当前点的导数值
IX = frame.at<uchar>(i, j - 1) - frame.at<uchar>(i, j + 1);//x方向导数值
IY = frame.at<uchar>(i - 1, j) - frame.at<uchar>(i + 1, j);//y方向导数值
double R = IX*IX*IY*IY - 0.1*(IX*IX*IY*IY);//0.1可调 0.1-0.25
// cout << R << endl;
if (R > 10000)
{
circle(frame_rgb, cvPoint(j, i), 1, CV_RGB(255, 0, 0), 2);
}
}
}
角点检测后的二值效果图
Mat con;
Mat cornerStrength;
Mat frame_gray;
cvtColor(frame, frame_gray, CV_RGB2GRAY);
cornerHarris(frame_gray, cornerStrength, 2, 3, 0.2);
Mat harrisCorner;
threshold(cornerStrength, harrisCorner, 0.00001, 255, THRESH_BINARY);
imshow("角点检测后的二值效果图", harrisCorner);
waitKey(10);
怎么将两个点匹配在一起?
高维向量 梯度:一阶导
按主方向截取向量 //每个角点都有主方向
欧式空间距离
二维空间的公式
0ρ = sqrt( (x1-x2)^2+(y1-y2)^2 ) |x| = √( x2 + y2 )
三维空间的公式
0ρ = √( (x1-x2)^2+(y1-y2)^2+(z1-z2)^2 ) |x| = √( x2 + y2 + z2 )
n维空间的公式
|x| = √( x[1]^2 + x[2]^2 + … + x[n]^2 )
引入ratio比率
Ratio=次大点/最大点
图像金字塔:解决尺度问题
#include <opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
void FeatureMatch(Mat FrameROI1, Mat FrameROI2, vector <Point2f> &kp1, vector <Point2f> &kp2, int Flag, float ratio);
void DrawFeature(Mat &rematch, Mat Frame1, Mat Frame2, vector <Point2f> &kp1, vector <Point2f> &kp2);
void main() {
Mat img = imread("pipei.png", 1);
resize(img, img, cvSize(640,480));
Mat img_gray;
cvtColor(img, img_gray, CV_RGB2GRAY);
VideoCapture cap(0);
while (true)
{
Mat frame;
Mat frame_gray;
cap >> frame;
cvtColor(frame, frame_gray, CV_RGB2GRAY);
vector<Point2f>kp1;
vector<Point2f>kp2;
FeatureMatch(img_gray, frame_gray, kp1, kp2, 0, 0.8);
Mat rematch;
DrawFeature(rematch,img, frame, kp1, kp2);
// imshow("pipei",img );
// imshow("frame", frame);
imshow("rematch", rematch);
waitKey(10);
}
}
void FeatureMatch(Mat FrameROI1, Mat FrameROI2, vector <Point2f> &kp1, vector <Point2f> &kp2, int Flag, float ratio)
{
Mat des1;
Mat des2;
vector <KeyPoint> keypoint1;
vector <KeyPoint> keypoint2;
Ptr <FeatureDetector> dector = ORB::create(500, 1.2f, 8, 31, 0, 2, ORB::FAST_SCORE, 31, 30);
dector->detect(FrameROI1, keypoint1, Mat());
dector->detect(FrameROI2, keypoint2, Mat());
//Ptr <FeatureDetector> dector2 =ORB::create(50, 1.2f, 1, 31, 0, 2, ORB::FAST_SCORE, 31, 30);
if (Flag == 0)
{
Ptr<DescriptorExtractor> pd0 = ORB::create(500, 1.2f, 8, 31, 0, 2, ORB::FAST_SCORE, 31, 30);
pd0->compute(FrameROI1, keypoint1, des1);
pd0->compute(FrameROI2, keypoint2, des2);
}
if (Flag == 1)
{
Ptr<DescriptorExtractor> pd1 = BRISK::create();
pd1->compute(FrameROI1, keypoint1, des1);
pd1->compute(FrameROI2, keypoint2, des2);
}
if ((keypoint1.size()>1) && (keypoint2.size()>1))
{
vector <vector<DMatch> > Vmatch;
Ptr <DescriptorMatcher> matcher = DescriptorMatcher::create("BruteForce-Hamming");
matcher->knnMatch(des1, des2, Vmatch, 2);
vector <DMatch> KNmatch;
for (int i = 0; i < Vmatch.size(); i++)
{
double rat;
if (Vmatch.at(i).at(1).distance<0.05) {
rat = 1;
}
else {
rat = Vmatch.at(i).at(0).distance / Vmatch.at(i).at(1).distance;
}
if (rat < ratio) {
KNmatch.push_back(Vmatch.at(i).at(0));
}
}
kp1.clear();
kp2.clear();
if (KNmatch.size()>0)
{
for (int i = 0; i<KNmatch.size(); i++)
{
int quaryx = KNmatch.at(i).queryIdx;
int trainx = KNmatch.at(i).trainIdx;
float mx = keypoint1.at(quaryx).pt.x;
float my = keypoint1.at(quaryx).pt.y;
float kx = keypoint2.at(trainx).pt.x;
float ky = keypoint2.at(trainx).pt.y;
Point2f p1;
Point2f p2;
p1.x = mx;
p1.y = my;
p2.x = kx;
p2.y = ky;
if (abs(ky - my)<5)
{
kp1.push_back(p1);
kp2.push_back(p2);
}
}
}
}
else
{
kp1.clear();
kp2.clear();
}
}
//画出来
void DrawFeature(Mat &rematch, Mat Frame1, Mat Frame2, vector <Point2f> &kp1, vector <Point2f> &kp2)
{
rematch = Mat((Frame1.rows >= Frame2.rows) ? Frame1.rows : Frame2.rows, Frame1.cols + Frame2.cols, CV_8UC3);
Rect rectleft(0, 0, Frame1.cols, Frame1.rows);
Rect rectright(Frame1.cols, 0, Frame2.cols, Frame2.rows);
Frame1.copyTo(rematch(rectleft));
Frame2.copyTo(rematch(rectright));
for (int i = 0; i<kp1.size(); i++)
{
line(rematch, cvPoint(kp1[i].x, kp1[i].y), cvPoint(Frame1.cols + kp2[i].x, kp2[i].y), CV_RGB(255, 0, 0), 2);
}
}
测距//需两个摄像头
RANSAC算法