diff --git a/picmatching/CMakeLists.txt b/picmatching/CMakeLists.txt new file mode 100644 index 0000000..3dcae69 --- /dev/null +++ b/picmatching/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 2.8) + +SET(CMAKE_BUILD_TYPE Release CACHE STRING "set build type to release") +SET(CMAKE_INSTALL_PREFIX /tmp CACHE STRING "install prefix") +add_definitions(-std=c++11) +remove_definitions(-g) +project( picmatch ) + +SET(Boost_USE_STATIC_LIBS TRUE) +SET(Boost_USE_MULTITHREADED TRUE) +SET(Boost_USE_STATIC_RUNTIME TRUE) + +SET(OpenCV_DIR /opt/opencv/share/OpenCV) +find_package(Boost REQUIRED serialization iostreams ) +find_package(OpenCV REQUIRED ) + +include_directories(${Boost_INCLUDE_DIR} ${OpenCV_INCLUDE_DIRS} ) +add_executable(picmatch archiverhelper.cpp picmatch.cpp) +target_link_libraries( picmatch ${Boost_LIBRARIES} ${OpenCV_LIBS} ) + +add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD COMMAND objcopy -N -S -R .comment -R .jcr ${PROJECT_NAME}) diff --git a/picmatching/README.md b/picmatching/README.md new file mode 100644 index 0000000..83c47c2 --- /dev/null +++ b/picmatching/README.md @@ -0,0 +1,16 @@ +## Picture Matching + +拿到源码你们也编译不了=。= + +opencv的demo,拿来玩玩就好,想逆……别太当真了,好几m呢光opencv和boost的封装就看吐你,而且源码里在干嘛你看懂了吗,那不就是了…… + +程序其实有3个选项,见源码,你可以试试找张图片detect下来keypoints然后把这图旋转缩放一下再match,图像最好大一点复杂一点 + +根据特征点来分析图像特征什么的……哈哈哈哈哈 + +题目给了本体和detect出来的特征点,这题我觉得找到test选项,把test那个drawimage的参数改成default然后对照着特征点的位置试试是什么字母,手动画出图后再用match选项比对一下画的图可能还比rop容易,毕竟这两个matching算法就是用来匹配图像在变换/扭曲/模糊之后的结果的 不过这样的话……算是什么类型的题呢 + +------- + + + diff --git a/picmatching/archiverhelper.cpp b/picmatching/archiverhelper.cpp new file mode 100644 index 0000000..9e20320 --- /dev/null +++ b/picmatching/archiverhelper.cpp @@ -0,0 +1,2 @@ +#include "archiverhelper.h" + diff --git a/picmatching/archiverhelper.h b/picmatching/archiverhelper.h new file mode 100644 index 0000000..9f044b5 --- /dev/null +++ b/picmatching/archiverhelper.h @@ -0,0 +1,89 @@ +#ifndef ARCHIVERHELPER_H +#define ARCHIVERHELPER_H + +#include +#include "opencv2/core.hpp" +using std::vector; + +template +class ArchiveHelper +{ + +public: + ArchiveHelper(T & any):mVector(any) + { + + } + + operator T &() + { + return mVector; + } +private: + T & mVector; + friend class boost::serialization::access; + template + void serialize(Archive & ar, const unsigned int version) + { + ar & mVector; + } + +}; +BOOST_SERIALIZATION_SPLIT_FREE(cv::Mat) +namespace boost { +namespace serialization { + +template +void serialize(Archive & ar, cv::KeyPoint & keypoint, const unsigned int version) +{ + ar & keypoint.class_id; + ar & keypoint.angle; + ar & keypoint.octave; + ar & keypoint.pt; + ar & keypoint.response; + ar & keypoint.size; +} +template +void serialize(Archive & ar, cv::Point_<_Tp> & p, const unsigned int version) +{ + ar & p.x; + ar & p.y; +} +/** Serialization support for cv::Mat */ +template +void save(Archive & ar, const cv::Mat & m, const unsigned int version) +{ + size_t elem_size = m.elemSize(); + size_t elem_type = m.type(); + + ar & m.cols; + ar & m.rows; + ar & elem_size; + ar & elem_type; + + const size_t data_size = m.cols * m.rows * elem_size; + ar & boost::serialization::make_array(m.ptr(), data_size); +} + +/** Serialization support for cv::Mat */ +template +void load(Archive & ar, cv::Mat & m, const unsigned int version) +{ + int cols, rows; + size_t elem_size, elem_type; + + ar & cols; + ar & rows; + ar & elem_size; + ar & elem_type; + + m.create(rows, cols, elem_type); + + size_t data_size = m.cols * m.rows * elem_size; + ar & boost::serialization::make_array(m.ptr(), data_size); +} + +} // namespace serialization +} // namespace boost + +#endif // ARCHIVERHELPER_H diff --git a/picmatching/generate.py b/picmatching/generate.py new file mode 100644 index 0000000..92df629 --- /dev/null +++ b/picmatching/generate.py @@ -0,0 +1,32 @@ +#!/usr/bin/python +#encoding:utf-8 +import Image as IM +import ImageDraw as IMDW +import ImageFont as IMF +from time import time,sleep +from random import random,seed +import sys +import json +ss = 'ABEFGHJKMNRSTVWXYZabdefghjmnpqrstu23456789' +w = 430 +h = 130 +seed(time()) +for j in xrange(int(sys.argv[1])): + rs = '' + r = int(random()*100)%14-7 + for i in range(5): + rs += ss[int(random()*100)%len(ss)] + seed(time()*random()) + img = IM.new('RGB',(w,h)) + ft = IMF.truetype('msyh.ttc',80+r) + dw = IMDW.Draw(img) + dw.text((5,0),rs,font=ft,fill=(255,255,255)) + seed(random()*time()) + rr = int(random()*1000)%160/10.0 - 8 #+ (int(random()*10)%2)*180 + rx = int(random()*100)%30 + ry = int(random()*100)%20 + fn = ''.join(rs.split(' ')) + print fn + img.offset(rx,ry+8).rotate(rr,IM.BICUBIC).point(lambda p:(255-p)).save('/tmp/pic/{}.png'.format(fn)) + import os + os.system('./picmatch detect /tmp/pic/{0}.png /tmp/pic/kp/kpsample{1}'.format(fn,str(j))) diff --git a/picmatching/picmatch b/picmatching/picmatch new file mode 100755 index 0000000..cfde501 Binary files /dev/null and b/picmatching/picmatch differ diff --git a/picmatching/picmatch.cpp b/picmatching/picmatch.cpp new file mode 100644 index 0000000..efd1ec2 --- /dev/null +++ b/picmatching/picmatch.cpp @@ -0,0 +1,218 @@ +#include +#include +#include + +#include +#include +#include +#include + +#include "opencv2/core.hpp" +#include "opencv2/xfeatures2d.hpp" +#include "opencv2/highgui.hpp" +#include "archiverhelper.h" + +#define minHessian 400 +#define siftPoints 0 + +using namespace std; +using namespace cv; +using namespace cv::xfeatures2d; + +using namespace boost; +using namespace boost::archive; + + +void readme(); +/* @function main */ + +int main( int argc, char** argv ) +{ + if( argc != 4 ) + { readme(); return -1; } + namespace io = boost::iostreams; + if(strncmp(argv[1],"detect",6)==0) + { + const char* fname_pic = argv[2]; + const char* fname_kps = argv[3]; + Mat img = imread(fname_pic,IMREAD_GRAYSCALE); + if(!img.data) + { + cout<< "Error reading images!" << std::endl; + return -1; + } + Ptr sift_detector = SIFT::create(siftPoints); + Ptr surf_detector = SURF::create(minHessian); + vector surf_keypoints,sift_keypoints; + Mat sift_descriptors,surf_descriptors; + sift_detector->detectAndCompute(img, Mat(),sift_keypoints, sift_descriptors); + surf_detector->detectAndCompute(img, Mat(),surf_keypoints, surf_descriptors); + + ofstream ofs(fname_kps,ios_base::binary); + { + io::filtering_streambuf out; + out.push(io::zlib_compressor(io::zlib::best_compression)); + out.push(ofs); + binary_oarchive oa(out); + ArchiveHelper > sift_archiver(sift_keypoints); + ArchiveHelper > surf_archiver(surf_keypoints); + ArchiveHelper ar1(sift_descriptors); + ArchiveHelper ar2(surf_descriptors); + oa << sift_archiver; + oa << surf_archiver; + oa << ar1; + oa< isift_keypoints,isurf_keypoints,psift_keypoints,psurf_keypoints; + Mat isift_descriptors,isurf_descriptors; + + ifstream ifs(fname_kps,ios_base::binary); + { + io::filtering_streambuf in; + in.push(iostreams::zlib_decompressor()); + in.push(ifs); + binary_iarchive ia(in); + ArchiveHelper > sift_archiver(isift_keypoints),surf_archiver(isurf_keypoints); + ArchiveHelper ar1(isift_descriptors),ar2(isurf_descriptors); + + ia>>sift_archiver; + ia>>surf_archiver; + ia>>ar1; + ia>>ar2; + } + ifs.close(); + Mat img = imread(fname_pic,IMREAD_GRAYSCALE); + Ptr sift_detector = SIFT::create(siftPoints); + Ptr surf_detector = SURF::create(minHessian); + Mat psift_descriptors, psurf_descriptors; + + sift_detector->detectAndCompute(img, Mat(),psift_keypoints, psift_descriptors); + surf_detector->detectAndCompute(img, Mat(),psurf_keypoints, psurf_descriptors); + + BFMatcher matcher; + vector< DMatch > sift_matches,surf_matches; + vector > sift_knnMatches,surf_knnMatches; + matcher.knnMatch(psift_descriptors,isift_descriptors,sift_knnMatches,2); + matcher.knnMatch(psurf_descriptors,isurf_descriptors,surf_knnMatches,2); + + for( size_t i = 0; i < sift_knnMatches.size(); i++ ) + { + const DMatch& bestMatch = sift_knnMatches[i][0]; + const DMatch& betterMatch1 = sift_knnMatches[i][1]; + float distanceRatio = bestMatch.distance / betterMatch1.distance; + if(distanceRatio<0.61) + { + sift_matches.push_back(bestMatch); + } + } + for( size_t i = 0; i < surf_knnMatches.size(); i++ ) + { + const DMatch& bestMatch = surf_knnMatches[i][0]; + const DMatch& betterMatch1 = surf_knnMatches[i][1]; + float distanceRatio = bestMatch.distance/betterMatch1.distance; + if(distanceRatio<0.65) + { + surf_matches.push_back(bestMatch); + } + } + printf("-- SIFT KNN Matching rate:%f\n",sift_matches.size()/(0.0+psift_keypoints.size())); + printf("-- SURF KNN Matching rate:%f\n\n",surf_matches.size()/(0.0+psurf_keypoints.size())); + //-- Quick calculation of max and min distances between keypoints + double mx_sift_dist = 0; double mn_sift_dist = 999; + double mx_surf_dist = 0; double mn_surf_dist = 999; + for( size_t i = 0; i < sift_matches.size(); i++ ) + { + double dist = sift_matches[i].distance; + if( dist < mn_sift_dist ) mn_sift_dist = dist; + if( dist > mx_sift_dist ) mx_sift_dist = dist; + } + for( size_t i = 0; i < surf_matches.size(); i++ ) + { + double dist = surf_matches[i].distance; + if( dist < mn_surf_dist ) mn_surf_dist = dist; + if( dist > mx_surf_dist ) mx_surf_dist = dist; + } + + std::vector< DMatch > final_sift_matches,final_surf_matches; + + for( size_t i = 0; i < sift_matches.size(); i++ ) + { + if( sift_matches[i].distance <= max(1.8*mn_sift_dist+1,90.0)) + { + final_sift_matches.push_back(sift_matches[i]); + } + } + for( size_t i = 0; i < surf_matches.size(); i++ ) + { + if( surf_matches[i].distance <= max(1.8*mn_surf_dist+0.0016,0.16)) + { + final_surf_matches.push_back(surf_matches[i]); + } + } + + printf("-- SIFT Max dist: %f \n", mx_sift_dist); + printf("-- SIFT Min dist: %f \n", mn_sift_dist); + printf("-- SIFT Total matches: %d, good matches: %d\n",sift_matches.size(),final_sift_matches.size()); + printf("-- SIFT Matching rate: %f\n\n",(final_sift_matches.size()+0.0) / sift_matches.size()); + + printf("-- SURF Max dist: %f \n", mx_surf_dist); + printf("-- SURF Min dist: %f \n", mn_surf_dist); + printf("-- SURF Total matches: %d, good matches: %d\n",surf_matches.size(),final_surf_matches.size()); + printf("-- SURF Matching rate: %f\n\n",(final_surf_matches.size()+0.0) / surf_matches.size()); + + Mat img_white(img.rows,img.cols,CV_8UC3,cv::Scalar(255,255,255)); + Mat img_matches1,img_matches2; + drawMatches(img,psift_keypoints,img_white,isift_keypoints,final_sift_matches,img_matches1); + //-- Show detected matches + namedWindow("SIFT Matches",WINDOW_FREERATIO|WINDOW_NORMAL); + imshow( "SIFT Matches", img_matches1 ); + + drawMatches(img,psurf_keypoints,img_white,isurf_keypoints,final_surf_matches,img_matches2); + //-- Show detected matches + namedWindow("SURF Matches",WINDOW_FREERATIO|WINDOW_NORMAL); + imshow( "SURF Matches", img_matches2 ); + } + else if(strncmp(argv[1],"test",4)==0) + { + vector sift_keypoints,surf_keypoints; + ifstream ifs(argv[3],ios_base::binary); + { + io::filtering_streambuf in; + in.push(iostreams::zlib_decompressor()); + in.push(ifs); + binary_iarchive ia(in); + ArchiveHelper > sift_archiver(sift_keypoints),surf_archiver(surf_keypoints); + ia>>sift_archiver; + ia>>surf_archiver; + } + ifs.close(); + printf("-- SIFT key points:%d\n",sift_keypoints.size()); + printf("-- SURF key points:%d\n",surf_keypoints.size()); + + Mat img = imread(argv[2],IMREAD_GRAYSCALE); + Mat img_kp_sift; Mat img_kp_surf; + + drawKeypoints( img, sift_keypoints, img_kp_sift, Scalar::all(-1), DrawMatchesFlags::DRAW_RICH_KEYPOINTS); + drawKeypoints( img, surf_keypoints, img_kp_surf, Scalar::all(-1), DrawMatchesFlags::DRAW_RICH_KEYPOINTS); + namedWindow("SIFT Keypoints",WINDOW_NORMAL); + imshow("SIFT Keypoints", img_kp_sift ); + namedWindow("SURF Keypoints",WINDOW_NORMAL); + imshow("SURF Keypoints", img_kp_surf ); + } + else + { + readme(); + return -1; + } + waitKey(0); + return 0; +} +/* @function readme */ +void readme() +{ std::cout << " Usage: ./picmatch " << std::endl; }