Ⅰ brief特徵描述子演算法用matlab來編寫的話怎麼實現點對的選擇
以下是遺傳演算法的偽代碼。
BEGIN:
I = 0; //進化種群代數
Initialize P(I); //初始化種群
Fitness P(I); //「適者生存」遺傳選擇
While(not Terminate-Condition) //不滿足終止條件時,循環
{
I ++; //循環
GA-Operation P(I); //遺傳演算法運算or操作
Fitness P(I); //「適者生存」遺傳選擇
}
END. //結束演算法
Ⅱ 誰知道用C++實現後綴變中綴的演算法呀
後綴式轉中綴式么?
下面是代碼,如有幫助,謝謝採納
#include <iostream>
#include <string>
#include <stack>
using namespace std;
/* 運算符類,含符號和優先順序,目前只支持四則運算 */
struct exp_symbol{
char op;
int priority;
exp_symbol(char op=0)
{
this->op = 0;
priority = 255;
if( '+' == op || '-' == op )
{
this->op = op;
priority = 1;
}
else if( '*' == op || '/' == op )
{
this->op = op;
priority = 2;
}
}
exp_symbol(const exp_symbol &sym):op(sym.op),priority(sym.priority){ }
friend bool operator < (const exp_symbol &l_sym, const exp_symbol &r_sym)
{
return (l_sym.priority < r_sym.priority) ? true : false;
}
exp_symbol & operator = (const exp_symbol &r_sym)
{
if( this != &r_sym )
{
op = r_sym.op;
priority = r_sym.priority;
}
return *this;
}
};
/* 表達式類,表達式字元串和運算符構成 */
struct expression{
string expr;
exp_symbol ex_sym;
expression(double x):ex_sym(0)
{
char buffer[64];
sprintf(buffer,"%g", x);
expr = buffer;
}
expression(const exp_symbol &sym, const string &l_expr, const exp_symbol &l_sym, const string &r_expr, const exp_symbol &r_sym):ex_sym(sym)
{
char op = sym.op;
if( l_sym < sym )
expr = "( " + l_expr + " ) " + op + ' ';
else
expr = l_expr + ' ' + op + ' ';
if( sym < r_sym )
expr += r_expr;
else
expr = expr + "( " + r_expr + " )";
}
expression(const expression &exp):expr(exp.expr), ex_sym(exp.ex_sym){ }
};
/* 從字元串中輸入一個運算符 */
static int getsymbol(const char * &src_expr, exp_symbol &op_sym)
{
char op=0;
int len=0;
do {
if(0 == sscanf(src_expr, "%c%n", &op, &len))
break;
src_expr += len;
} while( ' ' == op );
op_sym = exp_symbol(op);
return (int)op_sym.op;
}
/**
* @brief 後綴表達式轉中綴表達式
* @note <表達式>=<常數>|<表達式><運算符><表達式>
* @note 遇到常數,壓棧;遇到運算符,從棧中彈出兩個表達式,與運算符合成新的表達式,壓棧;直到輸入結束
*/
int PostToMiddleExpr(const char * src_expr, string & dst_expr)
{
double x = 0.0;
int len=0, bValid=1;
exp_symbol op_sym(0);
std::stack<expression> stExpr;
while( bValid )
{
bValid = 0;
if( sscanf(src_expr, "%lf%n", &x, &len) > 0 ) /* 運算數,直接入棧 */
{
src_expr += len;
stExpr.push( expression(x) );
bValid = 1;
}
else if( getsymbol(src_expr, op_sym) > 0 ) /* 運算符,出棧兩個表達式,組成新的表達式 */
{
if(!stExpr.empty())
{
const expression &expr2 = stExpr.top();
string r_expr = expr2.expr;
exp_symbol r_sym = expr2.ex_sym;
stExpr.pop();
if(!stExpr.empty())
{
const expression &expr1 = stExpr.top();
string l_expr = expr1.expr;
exp_symbol l_sym = expr1.ex_sym;
stExpr.pop();
stExpr.push(expression(op_sym, l_expr,l_sym, r_expr, r_sym));
bValid = 1;
}
}
}
}
/* 判斷表達式棧並返回中綴表達式 */
if(stExpr.empty())
return -1;
dst_expr = stExpr.top().expr;
stExpr.pop();
if(!stExpr.empty())
{
do{
stExpr.pop();
}while(!stExpr.empty());
return -1;
}
return 0;
}
/**
* 後綴表達式轉中綴表達式的試驗程序~
*/
int main( void )
{
string dst_expr;
const char *src_str = "19.3 23.4 - 3.5 * 1.7 + 1.4 / 3.4 *";
PostToMiddleExpr( src_str, dst_expr);
cout << "dst_expr = "<< dst_expr << endl;
return 0;
}
Ⅲ opencv提供了多少個特徵點的descriptor
OpenCV 中和 2D 特徵檢測相關的演算法的頭文件位於
opencv\moles\features2d\include\opencv2\features2d.hpp,除SIFT、SURF以外的特徵。
opencv\moles\nonfree\include\opencv2\nonfree\features2d.hpp,只包含SIFT、SURF這兩個受專利保護的特徵,因此不是免費的(nonfree)。
我們來看具體的類
DescriptorExtractor 的子類都是描述子提取器,包含
FREAKBriefDescriptorExtractor
FeatureDetector 的子類都是特徵檢測器,包含
MSER
StarDetector,又名 StarFeatureDetector
FastFeatureDetector
GFTTDetector,又名 GoodFeaturesToTrackDetector
SimpleBlobDetector
DenseFeatureDetector
FeatureDetector 還提供一系列特殊的適配器子類,用於增強或加速之前的 FeatureDetector 類
GridAdaptedFeatureDetector
PyramidAdaptedFeatureDetector
AdjusterAdapter
DynamicAdaptedFeatureDetector
FastAdjuster
StarAdjuster
SurfAdjuster
Feature2D 的子類既是 FeatureDetector,又是 DescriptorExtractor,包含
BRISK
ORB
SIFT
SURF
希望這個回答可以授之以漁。
Ⅳ 小波演算法
Function wavelet(s,wname,n,options);
Begin
{
功能:
一維序列小波消噪。
參數:
s:一維序列
wname:小波函數名
現有小波函數名(小波函數的選取依靠經驗)
Daubechies:
'db1' , 'db2', ... ,'db45' 'db1' 就是haar 小波函數
Coiflets :
'coif1', ... , 'coif5'
Symlets :
'sym2' , ... , 'sym8'
Biorthogonal:
'bior1.1', 'bior1.3' , 'bior1.5'
'bior2.2', 'bior2.4' , 'bior2.6', 'bior2.8'
'bior3.1', 'bior3.3' , 'bior3.5', 'bior3.7'
'bior3.9', 'bior4.4' , 'bior5.5', 'bior6.8'.
Reverse Biorthogonal:
'rbio1.1', 'rbio1.3' , 'rbio1.5'
'rbio2.2', 'rbio2.4' , 'rbio2.6', 'rbio2.8'
'rbio3.1', 'rbio3.3' , 'rbio3.5', 'rbio3.7'
'rbio3.9', 'rbio4.4' , 'rbio5.5', 'rbio6.8'.
n :分解層數
options : 選項
選擇欄位說明
array('brief':1, // 默認為1 採用簡單剔除高頻諧波 達到消噪的目的
// 如果為 0 採用估計序列噪音標准差剔除噪音,
'sigma':0, // 為0 默認採用 序列的高階諧波估計標准差;也可自己輸入值
'which':1, // 以 某一層諧波作為噪音估計的數據,默認第一層
'alpha':2, // 閾值懲罰系數,默認為2
"thr":0, // 閾值大小,默認0 採用諧波估計,也可以直接給出
'sorh':'s', // 閾值方式設置,'s' 軟閾值,'h'硬閾值 默認為's'
);
返回結果:
一維數字數組,消噪後的序列。
範例:
s := array(2484.82690429688,2479.05493164063,2482.34301757813,2437.794921875,
2447.7548828125,2512.962890625,2443.05688476563,2433.15893554688,
2393.18310546875,2415.05395507813,2392.06201171875,2365.34301757813,
2359.21997070313,2344.787109375,2348.51611328125,2420.00,2438.7900390625,
2431.375,2440.40209960938,2383.48510742188,2377.51196289063,2331.36596679688,
2317.27490234375,2370.3330078125,2409.67211914063,2427.47998046875,
2435.61401367188,2473.40991210938,2468.25,2470.01904296875,2504.10791015625,
2508.09008789063,2528.2939453125,2509.79907226563,2503.8359375,2524.9189453125,
2479.53588867188,2481.083984375,2528.71411132813,2529.76098632813,2466.958984375,
2463.0458984375,2416.56201171875,2415.1298828125,2412.625,2395.06494140625,
2397.55395507813,2380.22412109375,2383.03393554688,2412.39306640625,
2333.4140625,2386.86010742188,2360.6640625,2333.22900390625,2325.90502929688,
2332.72998046875,2329.82006835938,2315.27001953125,2291.544921875,2248.59008789063,
2228.52490234375,2180.89501953125,2224.84008789063,2218.23510742188,2215.92993164063,
2191.14794921875,2186.29711914063,2204.78393554688,2190.11010742188,2166.205078125,
2170.01293945313,2173.56103515625,2199.4169921875,2169.38989257813,2148.45190429688,
2163.39501953125,2225.88989257813,2285.74389648438,2276.0458984375,2275.01000976563,
2244.580078125,2206.19311523438,2298.3759765625,2266.38403320313,2296.07495117188,
2319.11791992188,2285.0380859375,2292.61010742188,2268.080078125,2312.55590820313,
2330.40502929688,2331.13598632813,2291.90209960938,2347.53002929688,2349.58911132813,
2351.98095703125,2351.85498046875,2344.77099609375,2366.70190429688,2356.86010742188,
2357.18090820313,2363.59692382813,2381.42993164063,2403.5869140625,2409.55395507813,
2439.6279296875,2447.05688476563,2451.85693359375,2428.48706054688,2426.11499023438,
2460.69311523438);
n := 2;
options := array('brief':1,'sigma':0,'which':1,'alpha':2,"thr":0,'sorh':'s');
return wavelet(s,wname,n,options) ;
天軟數學組
20120627
}
if not ifarray(options) then options := array();
defaut := wavedefaut() union options;
cout := 4;
cl:=wavedec(s,n,wname); //小波分解
if defaut['brief']=1 then
ret :=wrcoef('a',cl[0],cl[1],wname,n);
else
begin
//***************小波消噪*************************************************
k := defaut['which']; //標准差估計選項 ,k 為 1 到 n的整數 默認為1;
if defaut['sigma']=0 then sigma := wnoisest(cl[0],cl[1],k);
else //通過小波第k層細節系數(諧波)估計 ,噪音標准差
sigma := defaut['segma'];
if defaut['alpha']=0 then alpha :=2; // alpha 懲罰因子 大於1 的數 一般為默認2;
else alpha := defaut['alpha'];
if defaut['thr']=0 then
thr := wbmpen(cl[0],cl[1],sigma,alpha); //噪音信號全局閾值
else thr := defaut['thr'];
sorh := defaut['sorh'];
ret:=wdencmp('gbl',cl[0],cl[1],wname,n,thr,sorh)[0]; //採用軟閾值和近似信號進行消噪;
end //第一個參數為'gbl'為擴展介面備用,可以隨意輸入
return ret;
end;
function wavedefaut();
begin
return array('brief':1,'sigma':0,'which':1,'alpha':2,
"thr":0,'sorh':'s'
);
end
Ⅳ opencv surf演算法連線顏色怎麼設置一樣
/**
* @file SURF_Homography
* @brief SURF detector + descriptor + FLANN Matcher + FindHomography
* @author A. Huaman
*/
#include <stdio.h>
#include <iostream>
#include <cv.h>
#include "opencv2/core/core.hpp"
#include <opencv2/opencv.hpp>
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/nonfree/features2d.hpp"
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/nonfree/nonfree.hpp>
using namespace cv;
using namespace std;
#ifdef _DEBUG
#pragma comment (lib, "opencv_calib3d246d.lib")
#pragma comment (lib, "opencv_contrib246d.lib")
#pragma comment (lib,"opencv_imgproc246d.lib")
#pragma comment (lib, "opencv_core246d.lib")
#pragma comment (lib, "opencv_features2d246d.lib")
#pragma comment (lib, "opencv_flann246d.lib")
#pragma comment (lib, "opencv_gpu246d.lib")
#pragma comment (lib, "opencv_highgui246d.lib")
#pragma comment (lib, "opencv_legacy246d.lib")
#pragma comment (lib, "opencv_ml246d.lib")
#pragma comment (lib, "opencv_objdetect246d.lib")
#pragma comment (lib, "opencv_ts246d.lib")
#pragma comment (lib, "opencv_video246d.lib")
#pragma comment (lib, "opencv_nonfree246d.lib")
#else
#pragma comment (lib, "opencv_calib3d246.lib")
#pragma comment (lib, "opencv_contrib246.lib")
#pragma comment (lib, "opencv_imgproc246.lib")
#pragma comment (lib, "opencv_core246.lib")
#pragma comment (lib, "opencv_features2d246.lib")
#pragma comment (lib, "opencv_flann246.lib")
#pragma comment (lib, "opencv_gpu246.lib")
#pragma comment (lib, "opencv_highgui246.lib")
#pragma comment (lib, "opencv_legacy246.lib")
#pragma comment (lib, "opencv_ml246.lib")
#pragma comment (lib, "opencv_objdetect246.lib")
#pragma comment (lib, "opencv_ts246.lib")
#pragma comment (lib, "opencv_video246.lib")
#pragma comment (lib, "opencv_nonfree246.lib")
#endif
int main()
{
initMole_nonfree();//初始化模塊,使用SIFT或SURF時用到
Ptr<FeatureDetector> detector = FeatureDetector::create( "SURF" );//創建SIFT特徵檢測器,可改成SURF/ORB
Ptr<DescriptorExtractor> descriptor_extractor = DescriptorExtractor::create( "SURF" );//創建特徵向量生成器,可改成SURF/ORB
Ptr<DescriptorMatcher> descriptor_matcher = DescriptorMatcher::create( "BruteForce" );//創建特徵匹配器
if( detector.empty() || descriptor_extractor.empty() )
cout<<"fail to create detector!";
//讀入圖像
Mat img1 = imread("1.jpg");
Mat img2 = imread("2.jpg");
//特徵點檢測
double t = getTickCount();//當前滴答數
vector<KeyPoint> m_LeftKey,m_RightKey;
detector->detect( img1, m_LeftKey );//檢測img1中的SIFT特徵點,存儲到m_LeftKey中
detector->detect( img2, m_RightKey );
cout<<"圖像1特徵點個數:"<<m_LeftKey.size()<<endl;
cout<<"圖像2特徵點個數:"<<m_RightKey.size()<<endl;
//根據特徵點計算特徵描述子矩陣,即特徵向量矩陣
Mat descriptors1,descriptors2;
descriptor_extractor->compute( img1, m_LeftKey, descriptors1 );
descriptor_extractor->compute( img2, m_RightKey, descriptors2 );
t = ((double)getTickCount() - t)/getTickFrequency();
cout<<"SIFT演算法用時:"<<t<<"秒"<<endl;
cout<<"圖像1特徵描述矩陣大小:"<<descriptors1.size()
<<",特徵向量個數:"<<descriptors1.rows<<",維數:"<<descriptors1.cols<<endl;
cout<<"圖像2特徵描述矩陣大小:"<<descriptors2.size()
<<",特徵向量個數:"<<descriptors2.rows<<",維數:"<<descriptors2.cols<<endl;
//畫出特徵點
Mat img_m_LeftKey,img_m_RightKey;
drawKeypoints(img1,m_LeftKey,img_m_LeftKey,Scalar::all(-1),0);
drawKeypoints(img2,m_RightKey,img_m_RightKey,Scalar::all(-1),0);
//imshow("Src1",img_m_LeftKey);
//imshow("Src2",img_m_RightKey);
//特徵匹配
vector<DMatch> matches;//匹配結果
descriptor_matcher->match( descriptors1, descriptors2, matches );//匹配兩個圖像的特徵矩陣
cout<<"Match個數:"<<matches.size()<<endl;
//計算匹配結果中距離的最大和最小值
//距離是指兩個特徵向量間的歐式距離,表明兩個特徵的差異,值越小表明兩個特徵點越接近
double max_dist = 0;
double min_dist = 100;
for(int i=0; i<matches.size(); i++)
{
double dist = matches[i].distance;
if(dist < min_dist) min_dist = dist;
if(dist > max_dist) max_dist = dist;
}
cout<<"最大距離:"<<max_dist<<endl;
cout<<"最小距離:"<<min_dist<<endl;
//篩選出較好的匹配點
vector<DMatch> goodMatches;
for(int i=0; i<matches.size(); i++)
{
if(matches[i].distance < 0.2 * max_dist)
{
goodMatches.push_back(matches[i]);
}
}
cout<<"goodMatch個數:"<<goodMatches.size()<<endl;
//畫出匹配結果
Mat img_matches;
//紅色連接的是匹配的特徵點對,綠色是未匹配的特徵點
drawMatches(img1,m_LeftKey,img2,m_RightKey,goodMatches,img_matches,
Scalar::all(-1)/*CV_RGB(255,0,0)*/,CV_RGB(0,255,0),Mat(),2);
imshow("MatchSIFT",img_matches);
IplImage result=img_matches;
waitKey(0);
//RANSAC匹配過程
vector<DMatch> m_Matches=goodMatches;
// 分配空間
int ptCount = (int)m_Matches.size();
Mat p1(ptCount, 2, CV_32F);
Mat p2(ptCount, 2, CV_32F);
// 把Keypoint轉換為Mat
Point2f pt;
for (int i=0; i<ptCount; i++)
{
pt = m_LeftKey[m_Matches[i].queryIdx].pt;
p1.at<float>(i, 0) = pt.x;
p1.at<float>(i, 1) = pt.y;
pt = m_RightKey[m_Matches[i].trainIdx].pt;
p2.at<float>(i, 0) = pt.x;
p2.at<float>(i, 1) = pt.y;
}
// 用RANSAC方法計算F
Mat m_Fundamental;
vector<uchar> m_RANSACStatus; // 這個變數用於存儲RANSAC後每個點的狀態
findFundamentalMat(p1, p2, m_RANSACStatus, FM_RANSAC);
// 計算野點個數
int OutlinerCount = 0;
for (int i=0; i<ptCount; i++)
{
if (m_RANSACStatus[i] == 0) // 狀態為0表示野點
{
OutlinerCount++;
}
}
int InlinerCount = ptCount - OutlinerCount; // 計算內點
cout<<"內點數為:"<<InlinerCount<<endl;
// 這三個變數用於保存內點和匹配關系
vector<Point2f> m_LeftInlier;
vector<Point2f> m_RightInlier;
vector<DMatch> m_InlierMatches;
m_InlierMatches.resize(InlinerCount);
m_LeftInlier.resize(InlinerCount);
m_RightInlier.resize(InlinerCount);
InlinerCount=0;
float inlier_minRx=img1.cols; //用於存儲內點中右圖最小橫坐標,以便後續融合
for (int i=0; i<ptCount; i++)
{
if (m_RANSACStatus[i] != 0)
{
m_LeftInlier[InlinerCount].x = p1.at<float>(i, 0);
m_LeftInlier[InlinerCount].y = p1.at<float>(i, 1);
m_RightInlier[InlinerCount].x = p2.at<float>(i, 0);
m_RightInlier[InlinerCount].y = p2.at<float>(i, 1);
m_InlierMatches[InlinerCount].queryIdx = InlinerCount;
m_InlierMatches[InlinerCount].trainIdx = InlinerCount;
if(m_RightInlier[InlinerCount].x<inlier_minRx) inlier_minRx=m_RightInlier[InlinerCount].x; //存儲內點中右圖最小橫坐標
InlinerCount++;
}
}
// 把內點轉換為drawMatches可以使用的格式
vector<KeyPoint> key1(InlinerCount);
vector<KeyPoint> key2(InlinerCount);
KeyPoint::convert(m_LeftInlier, key1);
KeyPoint::convert(m_RightInlier, key2);
// 顯示計算F過後的內點匹配
Mat OutImage;
drawMatches(img1, key1, img2, key2, m_InlierMatches, OutImage);
cvNamedWindow( "Match features", 1);
cvShowImage("Match features", &IplImage(OutImage));
waitKey(0);
cvDestroyAllWindows();
//矩陣H用以存儲RANSAC得到的單應矩陣
Mat H = findHomography( m_LeftInlier, m_RightInlier, RANSAC );
//存儲左圖四角,及其變換到右圖位置
std::vector<Point2f> obj_corners(4);
obj_corners[0] = Point(0,0); obj_corners[1] = Point( img1.cols, 0 );
obj_corners[2] = Point( img1.cols, img1.rows ); obj_corners[3] = Point( 0, img1.rows );
std::vector<Point2f> scene_corners(4);
perspectiveTransform( obj_corners, scene_corners, H);
//畫出變換後圖像位置
Point2f offset( (float)img1.cols, 0);
line( OutImage, scene_corners[0]+offset, scene_corners[1]+offset, Scalar( 0, 255, 0), 4 );
line( OutImage, scene_corners[1]+offset, scene_corners[2]+offset, Scalar( 0, 255, 0), 4 );
line( OutImage, scene_corners[2]+offset, scene_corners[3]+offset, Scalar( 0, 255, 0), 4 );
line( OutImage, scene_corners[3]+offset, scene_corners[0]+offset, Scalar( 0, 255, 0), 4 );
imshow( "Good Matches & Object detection", OutImage );
waitKey(0);
imwrite("warp_position.jpg",OutImage);
int drift = scene_corners[1].x; //儲存偏移量
Ⅵ 8點演算法 需要哪些sift數據
一、特徵點(角點)匹配圖像匹配能夠應用的場合非常多,如目標跟蹤,檢測,識別,圖像拼接等,而角點匹配最核心的技術就要屬角點匹配了,所謂角點匹配是指尋找兩幅圖像之間的特徵像素點的對應關系,從而確定兩幅圖像的位置關系。角點匹配可以分為以下四個步驟:1、提取檢測子:在兩張待匹配的圖像中尋找那些最容易識別的像素點(角點),比如紋理豐富的物體邊緣點等。2、提取描述子:對於檢測出的角點,用一些數學上的特徵對其進行描述,如梯度直方圖,局部隨機二值特徵等。檢測子和描述子的常用提取方法有:sift,harris,surf,fast,agast,brisk,freak,brisk,brief/orb等。3、匹配:通過各個角點的描述子來判斷它們在兩張圖像中的對應關系,常用方法如flann等。4、消噪:去除錯誤匹配的外點,保留正確的匹配點。常用方法有KDTREE,BBF,Ransac,GTM等。二、SIFT匹配方法的提出為了排除因為圖像遮擋和背景混亂而產生的無匹配關系的關鍵點,SIFT的作者Lowe提出了比較最近鄰距離與次近鄰距離的SIFT匹配方式:取一幅圖像中的一個SIFT關鍵點,並找出其與另一幅圖像中歐式距離最近的前兩個關鍵點,在這兩個關鍵點中,如果最近的距離除以次近的距離得到的比率ratio少於某個閾值T,則接受這一對匹配點。因為對於錯誤匹配,由於特徵空間的高維性,相似的距離可能有大量其他的錯誤匹配,從而它的ratio值比較高。顯然降低這個比例閾值T,SIFT匹配點數目會減少,但更加穩定,反之亦然。Lowe推薦ratio的閾值為0.8,但作者對大量任意存在尺度、旋轉和亮度變化的兩幅圖片進行匹配,結果表明ratio取值在0.4~0.6之間最佳,小於0.4的很少有匹配點,大於0.6的則存在大量錯誤匹配點,所以建議ratio的取值原則如下:ratio=0.4:對於准確度要求高的匹配;ratio=0.6:對於匹配點數目要求比較多的匹配;ratio=0.5:一般情況下。三、常見的SIFT匹配代碼1、vlfeat中sifttoolbox中的vl_ubcmatch.c使用的是普通的歐氏距離進行匹配(該SIFT代碼貢獻自AndreaVedaldi)。2、Lowe的C++代碼中使用的是歐氏距離,但是在matlab代碼中為了加速計算,使用的是向量夾角來近似歐氏距離:先將128維SIFT特徵向量歸一化為單位向量(每個數除以平方和的平方根),然後點乘來得到向量夾角的餘弦值,最後利用反餘弦(acos函數)求取向量夾角。實驗證明Lowe的法正確率和耗時都很不錯。同樣,也可以採用knnsearch函數求最近點和次近點:knnsearch採用euclidean距離時得到的結果與lowe採用的近似方法結果幾乎一致,正好印證了模擬歐氏距離的效果。3、RobHess的OpenSIFT採用了KDTREE來對匹配進行優化。4、CSDN大神v_JULY_v實現了KDTREE+BBF對SIFT匹配的優化和消除錯誤匹配:從K近鄰演算法、距離度量談到KD樹、SIFT+BBF演算法-結構之法演算法之道-博客頻道-CSDN.NET。5、OpenCV中features2d實現的SIFT匹配有多種matcher:VectorDescriptorMatcher,BFMatcher(Brute-forcedescriptormatcher),FernDescriptorMatcher,OneWayDescriptorMatcher,FlannBasedMatcher等等。目前只知道採用knnsearch,提供了多種距離度量方式,具體區別不懂。
Ⅶ 請教如何在delpih中使用HMAC-SHA1演算法
* @brief 使用HMAC-SHA1演算法生成oauth_signature簽名值
*
* @param $key 密鑰
* @param $str 源串
*
* @return 簽名值
*/
function getSignature($str, $key) {
$signature = "";
if (function_exists('hash_hmac')) {
$signature = base64_encode(hash_hmac("sha1", $str, $key, true));
} else {
$blocksize = 64;
$hashfunc = 'sha1';
if (strlen($key) > $blocksize) {
$key = pack('H*', $hashfunc($key));
}
$key = str_pad($key, $blocksize, chr(0x00));
$ipad = str_repeat(chr(0x36), $blocksize);
$opad = str_repeat(chr(0x5c), $blocksize);
$hmac = pack(
'H*', $hashfunc(
($key ^ $opad) . pack(
'H*', $hashfunc(
($key ^ $ipad) . $str
)
)
)
);
$signature = base64_encode($hmac);
}
return $signature;
}
Ⅷ 120由淺入深學網路--靜態路由與動態路由
我們在 VLAN 的實驗中學習到 VLAN 能夠很好的隔離網路,減小廣播域,但是隔離了網路的廣播域也就意味著它們將處於不同的網路之中,這樣僅僅依靠數據鏈路層的幀是無法相互通信的。所以若是我們需要 VLAN 間能夠相互通信就必須得依靠網路的第三層網路層,通過路由的功能來連接兩個不同網路使之相互通信。
使兩個 VLAN 相互通信我們稱之為 VLAN 間的路由,而實現這一功能的方法有兩個:
單臂路由
SVI 介面
單臂路由(one-armed router 或者 router-on-a-stick)是指在路由器的一個介面上通過配置子介面(或「邏輯介面」,並不存在真正物理介面)的方式,實現原來相互隔離的不同 VLAN(虛擬區域網)之間的互聯互通。
單臂路由就是依靠的路由器的路由功能,因為二層交換機沒有辦法實現路由。同時一個介面只能接收來自一個 VLAN 的數據(因為一個介面不能隸屬於多個 VLAN),傳統的 VLAN 間路由方式便是在 Switch 與 Router 之間連接多個埠以保證多個接收多個 VLAN 的數據,但是當 VLAN 很多的情況下,Router 不可能滿足這么多埠,所以出現了子埠的實現,這是一種依靠軟體實現的邏輯上的埠。這樣便只需要通過一根物理連接線來實現多個 VLAN 介面的連接。
我們通過這樣的一個實驗來實現單臂路由的功能:
實驗目的:配置實現單臂路由
實驗材料:三台交換機、一台路由器
實驗方法:
拖動三台交換機、一台路由器至畫布,兩台用作模擬PC,一台用所模擬 Switch,一台用作 Router
配置路由器、交換機的名字與連接線路
配置交換機中的 vlan,以及三個介面的模式
配置兩台 PC 的 IP 地址與默認網關(下文詳解),他們處於不同的 VLAN 中
配置路由器的子介面,以及子介面的 IP 地址
嘗試使用 PC 相互 ping 通
1.構建實驗環境,在畫布中拖出三台交換機與一台路由器,並修改他們的設備名稱,同時修改兩台用作模擬 PC 的交換機圖標,然後相互連接。結構如圖所示:
2.配置交換機相關的內容,在 Switch1 中配置兩個 VLAN,分別為 vlan 2:test2、vlan 3:test3。同時將與 PC 連接的兩個埠分別配置為 access vlan 2 與 access vlan 3,還有與路由器相連接的埠配置為 trunk 模式。若是與路由器相連接的埠不配置成 trunk 模式將無法發送多個 vlan 的數據包。
3.修改 PC 埠的 IP 地址
此時我們可以嘗試通過 PC1 去 ping PC2,我們會發現肯定是 ping 不通的,因為他們處於不同的網段同時處於不同的 VLAN 中。
3.為兩台 PC 配置默認網關(默認網關用於將數據包發送至路由埠,下文詳解)
可用回到特權模式中,通過 show ip route 查看,是否成功配置:
4.在路由器中配置邏輯子介面,分別用於接收 vlan2 與 vlan3 的數據。因為是接收來自交換機發來的信息,所以該子介面的數據封裝模式與交換機中的相同,交換機此處 trunk 模式使用的是 dot1q 的封裝方法,所以子介面中的也必須是這個方法。(還記得在 VLAN 劃分實驗中我們將到 trunk 模式主要作用是添加 VLAN 標簽)
這樣我們就成功的配置好了我們的子埠,我們可以通過 show ip int brief 查看介面信息中是否有這兩個子介面的配置,還可以通過 show vlans 查看子介面的狀態,以及通過 show ip route 命令來查看當前的路由信息,若是有兩個直連路由表項,說明我們配置成功的生效了:
5.完成了所有的配置,准備工作,我們再次嘗試通過使用 PC1 去 Ping PC2 發現 5個點都變成了感嘆號,表示所有的 ICMP 包(ping 工具使用的是 ICMP 協議)都得到了響應,PC1 可以與 PC2 正常通信了:
由上述的兩個原因,為此出現了一種新的功能,便是在三層交換上的 SVI 介面,這樣便不需要單獨添加一台路由器了。
SVI 是 Switch Virtual Interface 的簡稱。它是三層交換機上的一個虛擬埠,類似於 Router 上的子埠,由軟體實現。每個 SVI 只能關聯一個 VLAN,設置一個 IP 地址。
基於上個實驗,我們做出這樣的修改:
去除 Router 設備
設置 SVI 介面地址
我們將去除 Router 設備,由我們的三層交換機來實現相關的功能,將之前的網關地址設置為 SVI 的 IP 地址即可
1.去除 Router 設備,關閉 Switch 上的 e0/0 介面,同時配置 SVI 的 IP 地址:
如此便完成了 SVI 的配置,我們可以在 Switch 的特權模式中使用 show ip route 可以看到此時我們有兩個直連的路由信息。同時我們還可以嘗試使用 PC1 去 ping PC2。(若是配置與我完全一致,但是 ping 不通,可以嘗試在 Switch 的全局模式中使用 no ip cef 命令)
此處使用 no ip cef 命令關閉轉發機制便是該版本的鏡像並沒有很好的在 Linux 中實現其提供的功能,可能該鏡像的設備本是使用硬體輔助實現該功能等等。若是不關閉 cef 的轉發機制,將導致你明明配置無誤,卻無法正常的通信。
由此我們便成功的配置了單臂路由與 SVI 介面來成功的實現 VLAN 之間的相互通信了。
在之前的實驗中我們經常提到默認網關之一名詞,接下來我們便來了解一下該名詞的含義。
默認網關由兩個片語成默認與網關。其中什麼叫做網關呢?
網關(Gateway)就是一個網路與另一個網路連接的關口。
比如成都市與廣州市都只有一個郵局,而每個郵局前都會有一個專職的負責人,此時若是成都市的小明想與廣州市的小紅聯系只能通過這樣的一個過程:
首先將寫好的信交給郵局的專職負責人,
郵局的專職負責人查看信封上的地址,發現該地址並不是本省中的地址,並且郵編寫的是廣東省的地址。
成都的郵局專職負責人便將該消息轉發送給廣州的郵局專職負責人,讓他交給收件人
廣州的郵局專職負責人收到信封後,發現目的地址便是本省中的地址,便尋找該地址將消息送到收件人的手中。
在這個例子中郵局的專職負責人便是網關。負責將本網段中的消息發送給其他網段的網關的介面。
默認網關的意思是一台主機如果找不到可用的網關,就把數據包發給默認指定的網關,由這個網關來處理數據包。只要指定了默認網關之後,只要主機在發送數據包之前由目的地址與其子網掩碼做 AND 運算得出的網路號與本機的網路號不同,便將數據發送給默認網關,由默認網關處理數據該如何發送。
在全局模式中我們可以通過這樣的命令來實現默認網關的配置:
通過 show ip route 我們可以看到這樣的結果:
我們了解到數據包發送到其他網段是通過查詢路由表,然後決定下一跳發送的路徑。而路由表中的表項是如何得來的呢?
首先以路由的角度將協議分為:
可路由協議(Routed Protocol):利用網路層完成通信的協議,例如 IP、IPX 等,該對象是被路由的。
路由協議(Routing Protocol):主要用於創建與維護路由表,本質是實現路由功能,該對象是路由其他對象的,例如 RIP、OSPF、IGRP、IS-IS 等等。
而路由表中的信息分為兩大類:
直連路由:也就是該設備中的介面所配置的 IP 地址與其所處的網路
遠程路由:也就是發向其他路由設備所處的 IP 地址與其所處的網路
直連路由是在 IP 介面地址配置後便自動添加的,而遠程路由的信息來源又會分為兩大類:
靜態路由:由人工配置的下一跳地址,在網路拓撲發生變化時同樣需要人工修改,但是配置完成之後並不會佔用過多的系統資源,與網路的帶寬。在靜態路由中有預設路由(也就是默認路由)、浮動路由的存在。適用於小型網路與末梢網路
動態路由:通過動態路由協議,設備與設備之間相互通信,相互學習。再由某種路由演算法計算出下一跳的路徑,當有多條路徑的時候還有優先順序的排序,並且在網路拓撲發生變化的時候,會自動學習網路中的變化適當改變路徑,適用於大型網路。
其中動態路由協議有這樣幾種分類的標准:
按演算法分為:距離矢量(典型的協議有 RIP、IGRP、BGP)、鏈路狀態(典型的協議有 OSPF IS-IS)、混合演算法(典型的協議有 EIGRP)
按照是否發送子網掩碼分為:有類(典型的有 RIP、IGRP)與無類(支持子網劃分與路由匯總,典型的有 OSPF 等)
按照使用的網路規模分為:IGP(Interior gateway protocol),內部網關協議,幾乎所有的路由協議都屬於內部網關協議)與 EGP(Exterior Gateway Protocol),外部網關協議,BGP 用於自治系統之間的路由計算)
其中按照演算法分的距離矢量表示的是根據源到目的的跳數來計算(之前有提過,下一跳錶示去往下一個路由);所謂的鏈路狀態便是多方面考慮如鏈路的開銷、鏈路上的所有的相鄰路由器、網路帶寬,網路擁塞等等綜合考慮;所謂的混合演算法便是這兩個的結合考慮。
其中的自治系統是表示屬於某一個特定的網路機構中路由集合。在自治系統內部使用的路由協議就是內部網關協議,而自治系統之間的是外部網關協議。
反應路由性能的參考對象主要還是收斂時間與管理距離(在上一節實驗我們都提到過):
收斂時間(convergence time):從網路拓撲變化到網路中所有的路由器都知道這個變化的時間就叫收斂時間;
管理距離(administrative distance):用於綜合評價路由協議性能參數,描述路由協議計算路由條目的准確度與可信度。
所謂的靜態路由便是由純手工的配置在路由表項中,這樣的配置路由方式非常的耗時,效率不高,並且在網路拓撲發生改變的時候需要手工的一項一項的修改,十分的麻煩,事情總是利弊雙面的,有弊就有利,雖然麻煩但是就因為不會自動學習修改所以不會發送通告佔用帶寬,也不會佔用太多的 CPU 與 RAM 這樣的系統資源。並且可以手工控制數據包的轉發路徑,因此靜態路由在小型企業中還是十分常用。
靜態路由的配置很簡單,只需要通過這樣的一條命令即可:
我們可以通過這樣的例子來學習靜態路由的配置:
還是使用上述 SVI 的實驗環境,我們在 Switch 上添加一個路由,並且配置為 202.203.0.0 這個網段下:
此時 PC 肯定是無法 ping 通 202.203.0.2 地址的,因為雖然在 Switch 中有該網段的路由表項(因為是直連網段),但是數據包在 Router 接收到之後,響應時發現路由表中無 192.168.1.0 網段表項,不知道怎麼轉發回來,便只有丟棄該數據包了。
通過 show ip route 我們可以看到靜態路由成功的添加了:
並且此時可以 ping 通對端的 IP 地址:
這只是一條記錄,並且只是 192.168.1.0 網段可以 ping 通,若是 PC2 去 ping 還是會不通,因為 PC2 在 192.168.2.0 網段,路由表中沒有可以匹配的項。此時我們發現所有的地址都會通過 Switch,基本設備都是圍繞它來的,他知道所有的路由路徑,我便可以直接設置一個默認路由,也就是只要路由表中沒有目的地址所匹配的表項,就都丟給默認路由。
既然如此也就代表著默認路由要匹配所有項,因為表中一旦無匹配就讓他路由,換個角度就代表他得匹配所有項,而匹配所有項的地址便是 0.0.0.0,同時子網掩碼也是這個值。因為 0 表示的是任意的(wildcard)
默認路由就是一種特殊的靜態路由,所以若是要配置默認路由只需要將上述的命令中的目的地址與子網掩碼改成 0.0.0.0 0.0.0.0 即可。
我們可以在剛剛的環境中實驗一次,先擦除原先的靜態路由然後再配置:
這就是便是默認路由只要路由表中沒有匹配的項就讓它來路由。
當然按照我們之前所說的冗餘思想,避免單點故障使得一個數據包到達目的地可能有多條路徑,此時我們便可以配置浮動路由,所謂的浮動路由便是當優先順序較高的路徑出現問題時,還有一條路徑能夠及時的替補上來。而優先順序的體現在於我們上節實驗中所提到的 AD,當值越小的時候其優先順序便越高。
浮動路由的配置很簡單,就是在添加備選路徑時,把靜態路由命令的網關地址修改以及後面添加 AD 值,該值的取值范圍是 0~255。例如:
但是三層交換機並不支持浮動路由,需要路由器才能實現。
在畫布中拖動兩台路由器,實現這樣的拓撲結構,同時配置浮動路由使得在一條線路斷掉時,還是可以工作。(需要藉助環回介面,在全局模式中 int loopback 0(這個為編號,自取) 便可以像配置埠一般為其配置 IP 地址了)
驗證方式:
首先查看路由表中的靜態路由是 192.168.1.2,並且能夠 Router 設備能夠 ping 通 202.204.1.1
然後 shutdown s2/0 埠,再次 ping 202.204.1.1 還是能通,並且此時的路由表的靜態路由項發生變化
注意:此處使用的兩個都是串口,因為 GNS3 的路由串口實現沒有問題,浮動路由只需要一個埠斷開,另外一邊不通就知道斷開了便啟用浮動路由。但是若是使用的以太口,GNS3 實現出來與真實設備不同,不同之處在 GNS3 用以太口實現的話檢測不出對端斷開了,必須同時斷開此埠與對端埠才行,所以此處使用串口。