19年1月份的慕尼黑,大雪纷飞...
各位看官,最近在线特征相关的研究,本文把直线特征的提取和匹配的源码贴一下,希望对大家有所帮助,在下使用 OpenCV下的LSD 提取特征,LBD进行特征描述, KNNMatch做特征描述。同时,还有特征质量的简单筛选。
#include <iostream>
#include <chrono>
#include <cv.h>
#include <opencv2/core/core.hpp>
#include <opencv2/core/utility.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/line_descriptor/descriptor.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <iostream>
using namespace cv;
using namespace std;
using namespace cv::line_descriptor;
struct sort_descriptor_by_queryIdx
{
inline bool operator()(const vector<DMatch>& a, const vector<DMatch>& b){
return ( a[0].queryIdx < b[0].queryIdx );
}
};
struct sort_lines_by_response
{
inline bool operator()(const KeyLine& a, const KeyLine& b){
return ( a.response > b.response );
}
};
void ExtractLineSegment(const Mat &img, const Mat &image2, vector<KeyLine> &keylines,vector<KeyLine> &keylines2);
int main(int argc, char**argv)
{
if(argc != 3)
{
cerr << endl << "Usage: ./Line path_to_image1 path_to_image2" << endl;
return 1;
}
string imagePath1=string(argv[1]);
string imagePath2=string(argv[2]);
cout<<"import two images"<<endl;
Mat image1=imread(imagePath1);
Mat image2=imread(imagePath2);
imshow("ima1",image1);
imshow("ima2",image2);
waitKey(0);
if(image1.data==NULL)
{
cout<<"the path is wrong"<<endl;
}
vector<KeyLine> keylines,keylines2;
ExtractLineSegment(image1,image2,keylines,keylines2);
return 0;
}
void ExtractLineSegment(const Mat &img, const Mat &image2, vector<KeyLine> &keylines,vector<KeyLine> &keylines2)
{
Mat mLdesc,mLdesc2;
vector<vector<DMatch>> lmatches;
Ptr<BinaryDescriptor> lbd = BinaryDescriptor::createBinaryDescriptor();
Ptr<line_descriptor::LSDDetector> lsd = line_descriptor::LSDDetector::createLSDDetector();
cout<<"extract lsd line segments"<<endl;
lsd->detect(img, keylines, 1.2,1);
lsd->detect(image2,keylines2,1.2,1);
int lsdNFeatures = 50;
cout<<"filter lines"<<endl;
if(keylines.size()>lsdNFeatures)
{
sort(keylines.begin(), keylines.end(), sort_lines_by_response());
keylines.resize(lsdNFeatures);
for( int i=0; i<lsdNFeatures; i++)
keylines[i].class_id = i;
}
if(keylines2.size()>lsdNFeatures)
{
sort(keylines2.begin(), keylines2.end(), sort_lines_by_response());
keylines2.resize(lsdNFeatures);
for(int i=0; i<lsdNFeatures; i++)
keylines2[i].class_id = i;
}
cout<<"lbd describle"<<endl;
lbd->compute(img, keylines, mLdesc);
lbd->compute(image2,keylines2,mLdesc2);//计算特征线段的描述子
BFMatcher* bfm = new BFMatcher(NORM_HAMMING, false);
bfm->knnMatch(mLdesc, mLdesc2, lmatches, 2);
vector<DMatch> matches;
for(size_t i=0;i<lmatches.size();i++)
{
const DMatch& bestMatch = lmatches[i][0];
const DMatch& betterMatch = lmatches[i][1];
float distanceRatio = bestMatch.distance / betterMatch.distance;
if (distanceRatio < 0.75)
matches.push_back(bestMatch);
}
cv::Mat outImg;
std::vector<char> mask( lmatches.size(), 1 );
drawLineMatches( img, keylines, image2, keylines2, matches, outImg, Scalar::all( -1 ), Scalar::all( -1 ), mask,
DrawLinesMatchesFlags::DEFAULT );
imshow( "Matches", outImg );
waitKey();
}
CMakeLists.txt的代码如下。实际上,如果只是线提取 没有必要写这个复杂,里面的内容大家可以自行删减,在下就不改了:
cmake_minimum_required(VERSION 2.8)
project(BaseExperimentForPLSLAM)
IF(NOT CMAKE_BUILD_TYPE)
SET(CMAKE_BUILD_TYPE Release)
ENDIF()
MESSAGE("Build type: " ${CMAKE_BUILD_TYPE})
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -O3 -march=native ")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -O3 -march=native")
# Check C++11 or C++0x support
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
if(COMPILER_SUPPORTS_CXX11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
add_definitions(-DCOMPILEDWITHC11)
message(STATUS "Using flag -std=c++11.")
elseif(COMPILER_SUPPORTS_CXX0X)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
add_definitions(-DCOMPILEDWITHC0X)
message(STATUS "Using flag -std=c++0x.")
else()
message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
endif()
LIST(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake_modules)
find_package(OpenCV 3.0 QUIET)
if(NOT OpenCV_FOUND)
find_package(OpenCV 2.4.3 QUIET)
if(NOT OpenCV_FOUND)
message(FATAL_ERROR "OpenCV > 2.4.3 not found.")
endif()
endif()
include_directories(
${PROJECT_SOURCE_DIR}
${PROJECT_SOURCE_DIR}/include
)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib)
add_library(${PROJECT_NAME} SHARED
src/Blur.cc
)
target_link_libraries(${PROJECT_NAME}
${OpenCV_LIBS}
)
# Build examples
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/example/)
add_executable(Line example/baseExperiment.cc)
target_link_libraries(Line ${PROJECT_NAME})
最后提取的结果是下图展示的。最后大家觉得这种线提取方式,有什么优缺点,可以在下方评论或私信我,一起交流讨论。
————————————C++(上),matlab(下)————————————————
在MATLAB中,我们调用OpenCV同样可以做图像处理,一些非计算机专业的同学可能有这样的需求。这里我们介绍一个matlab使用lsd的repo。
这是github上开源项目,可以自行下载
guiyuliu/lsd
(1)编译(ubuntu下的,windows我不熟)
如果你之前在matlab平台上使用过Opencv,你一定下载过mexopencv-x (x表示版本),为matlab做opencv库就不介绍了,大家可以去找教程。会做OpenCV之后,就简单了
cd lsd-1.6
mex -O -output lsd lsd_matlab.c lsd.c
就可以了。
(2)调用
add('~/xx/lsd-1.5')%你自己的路径
lines=lsd(double(Image))
___________________________打_完_收_工___________________