如何判断两个物体是不是同一个?
那么,如何检测纹理?
接着,什么是角点?
最后,如何进行角点检测与匹配?
1.优点:
可以进行实时的特征检测。
2.原理:
-在图像中任选一像素点p,设其像素值为I
-设定一个阈值t
-以3为半径画圆,覆盖p点周围的16个像素点(如图所示)
-如果这周围的16个像素中有连续的n个像素的像素值都小于I-t,或者有连续的n个像素都大于I+t,那么这个点就被判断为角点。opencv中n被设定为12。
-对以上步骤进行优化,可以先检测p点周围的四个点,即1, 5, 9, 12四个点中是否有三个点满足超过I+t,如果不满足,则直接跳过,如果满足,则继续使用前面的算法,全部判断16个点中是否有12个满足条件。
图片如下:
3.代码:
#include
#include
using namespace std;
using namespace cv;
//判断两个像素点的像素值的绝对值是否小于30的函数
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;
Mat frame_rgb;
frame.copyTo(frame_rgb);
cvtColor(frame, frame, CV_64FC1);
//cout<(0, 0);
//定义待检测点周围四个点的相对位置,pos[x][y],x取4表示4个点,y取0或1表示x轴和y轴的变化
int pos[4][2];
//第0号点在x轴不变,y轴变
pos[0][0] = 0;
pos[0][1] = -3;
//第1号点在x轴变,y轴不变
pos[1][0] = 3;
pos[1][1] = 0;
//第2号点在x轴不变,y轴变
pos[2][0] = 0;
pos[2][1] = 3;
//第3号点在x轴变,y轴不变
pos[3][0] = -3;
pos[3][1] = 0;
//边缘3个点无法检测,从3开始循环,防止溢出
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(i, j);//中心像素点
for (int k = 0; k < 4; k++)
{
uchar temp = frame.at(i + pos[k][0], j + pos[k][1]);//周围几个点的坐标等于中心像素点的坐标加上相对位置
if (isdif(cen, temp))
{
num++;
}
}
if ((num == 1) || (num == 3) || (num == 4))
//差别很大的点有1或3或4个时均为角点
{
circle(frame_rgb, cvPoint(j, i), 2, CV_RGB(255, 0, 0), 2);//圈出这个点
}
}
}
imshow("frame", frame_rgb);
waitKey(10);
1.原理:
简单说,角点在各个方向的变化都是最大的,而边缘区域在只是某一方向有明显变化,如下图所示
从数学上讲,基本公式如下
w(x,y)表示移动窗口,I(x,y)表示像素灰度值强度,范围为0~255。
根据泰勒级数展开计算偏导数可得Harris矩阵,如下图
再计算Harris角点响应值,R=det(M)-k*(trace(M)^2),据学长实际操作,发现实际运算只计算k*(trace(M)^2),并不需要前半部分。
根据下图加以理解
个人还不是很理解这个算法,以上解释不保证正确。
2.代码:
一般算法:
#include
#include
using namespace std;
using namespace cv;
void main()
{
VideoCapture cap(0);
while (true)
{
Mat frame;
cap >> frame;
Mat frame_rgb;
frame.copyTo(frame_rgb);
cvtColor(frame, frame, CV_64FC1);
//cout<(0, 0);
for (int i = 1; i < frame.rows-1; i++)
{
for (int j = 1; j < frame.cols-1; j++)
{
double IX, IY;
IX = frame.at(i, j - 1) - frame.at(i, j + 1);
IY = frame.at(i - 1, j) - frame.at(i + 1, j);
double R = IX*IX*IY*IY - 0.23*(IX*IX + IY*IY);
//套用公式,其中0.23的值可变,范围0.1-0.5
//cout << R << endl;
if (R > 10000)//这里的10000的值也可变
{
circle(frame_rgb, cvPoint(j, i), 1, CV_RGB(255, 0, 0));
//圈出这个点
}
}
}
imshow("frame", frame_rgb);
waitKey(10);
}
调用API的算法:
#include
#include
using namespace std;
using namespace cv;
void main()
{
VideoCapture cap(0);
while (true)
{
Mat frame;
cap >> frame;
cvtColor(frame, frame, CV_64FC1);
Mat con;
Mat cornerStrength;
cornerHarris(frame, cornerStrength, 2, 3, 0.1);
Mat harrisCorner;
threshold(cornerStrength, harrisCorner, 0.00001, 255, THRESH_BINARY);
imshow("角点检测后的二值效果图", harrisCorner);
waitKey(10);
}
1.原理:
首先用Harris fast算法进行角点检测,再进行角点匹配,从而完成图像匹配;
在角点检测步骤,先用fast算法选取一定量的可能点,再用Harris算法进一步筛选,得到更为精确的角点。
2.代码:
暂且放上调用API的版本:
#include
#include
using namespace std;
using namespace cv;
void FeatureMatch(Mat FrameROI1, Mat FrameROI2, vector &kp1, vector &kp2, int Flag, float ratio);
void DrawFeature(Mat &rematch, Mat Frame1, Mat Frame2, vector &kp1, vector &kp2);
void main()
{
Mat img = imread("pipei.jpg", 1);
//记得把匹配图片命名为"pipei.jpg"(名字和格式均可自定义)放在程序对应文件夹中(可右键项目名称,选择在文件资源管理器中打开文件夹)
resize(img, img, cvSize(640, 480));
Mat img_gray;
cvtColor(img, img_gray, CV_RGB2GRAY);
VideoCapture cap(0);
while (true)
{
Mat frame;
cap >> frame;
Mat frame_gray;
cvtColor(frame, frame_gray, CV_RGB2GRAY);
vector kp1;
vector kp2;
FeatureMatch(img_gray, frame_gray, kp1, kp2, 0, 0.8);
Mat rematch;
DrawFeature(rematch, img, frame, kp1, kp2);
imshow("frame", rematch);
waitKey(10);
}
}
void FeatureMatch(Mat FrameROI1, Mat FrameROI2, vector &kp1, vector &kp2, int Flag, float ratio)
{
Mat des1;
Mat des2;
vector keypoint1;
vector keypoint2;
Ptr 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 dector2 =ORB::create(50, 1.2f, 1, 31, 0, 2, ORB::FAST_SCORE, 31, 30);
if (Flag == 0)
{
Ptr 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 pd1 = BRISK::create();
pd1->compute(FrameROI1, keypoint1, des1);
pd1->compute(FrameROI2, keypoint2, des2);
}
if ((keypoint1.size()>1) && (keypoint2.size()>1))
{
vector <vector > Vmatch;
Ptr matcher = DescriptorMatcher::create("BruteForce-Hamming");
matcher->knnMatch(des1, des2, Vmatch, 2);
vector 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; iint 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 &kp1, vector &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; i255, 0, 0), 2);
}
}