之前一直在Ubuntu16.04环境下使用OpenCV开发,但是需要来回切换双系统,或者打开虚拟机,很不方便,于是将开发平台转移到了Win10平台。
OpenCV有Windows环境下的安装包,但是是使用msvc编译器编译的,不能够跨平台,于是萌生了在Windows下使用MinGW编译OpenCV的想法。
下面是从编译OpenCV的过程,如果觉得麻烦可以直接看最后,下载我已经编译好的OpenCV4.3.0的包,可以直接使用。
首先从github上下载OpenCV和contrib包,鉴于一系列原因直接从github下载速度会很慢,可以从release上复制下载链接,复制到这个网址,然后下载会很快。
在Windows环境下,我们要像在Ubuntu环境下cmake
然后make
去编译一个开源包,需要下载MinGW编译器,它给我们封装好了gcc和g++等编译器。
MinGW安装网上教程很多,但如果在线安装可能会非常费时,我把我安装好的文件夹分享出来,大家可以直接把该文件夹解压缩后复制到一个地方,并且把其中的bin目录添加到环境变量中。我把里面的mingw32-make.exe重命名为了make,以后可以直接输入make来编译。
MinGW蓝奏云网盘分享网址
还需要安装CMake,这个直接从官网下载安装最新版本安装即可。
上面已经配置好后MinGW后,我们可以开始编译OpenCV。
打开cmake-gui,上面两个路径自己选择,一个是源码路径,下面是build的路径。
cmake-gui参数设置:
然后点击configure,在配置过程中会下载一些文件(见下),由于一些原因会下载失败,这时候需要我们自己下载然后放到指定的文件夹下(opencv_contrib-4.3.0\modules\xfeatures2d\src)。
boostdesc_bgm.i
boostdesc_bgm_bi.i
boostdesc_bgm_hd.i
boostdesc_lbgm.i
boostdesc_binboost_064.i
boostdesc_binboost_128.i
boostdesc_binboost_256.i
vgg_generated_120.i
vgg_generated_64.i
vgg_generated_80.i
vgg_generated_48.i
我把上面这些文件放在网盘中,分享网址
还有一个文件可能会下载失败,那就是opencv_videoio_ffmpeg.dll,同理,我把该文件放在网盘,分享网址。放置的文件夹可以查看build文件夹下的CMakeDownloadLog.txt文件,里面会详细介绍该文件从哪里下载放置在哪个位置,我们复制过去就行。同时需要注意的是,文件名字可能要改变,要加上前面的哈希值,但我们只需要把cmake下载的文件名字复制过去就行。
按理来说应该configure没问题了,点击generate生成makefile。
打开cmd,把路径转到build路径下,输入make -j8
,我电脑cpu是8核。输入该命令的前提是上面步骤把MinGW中的bin目录添加到了系统环境变量。如果你没有把mingw32-make改为make,改名字,那么你应该输入mingw32-make -j8
,
等待make编译。
make完成后,输入make install
,安装完成,所有的库文件和头文件都在自定义安装路径下面。
最后把安装文件夹下的\x64\mingw\bin路径添加到系统环境变量。
安装完成,测试一个surf例程试试。
编译过程中可能会出现HDF5包的错误,我电脑中装了anaconda3,在cmake时添加了anaconda中hdf5的路径,因此编译报错(很奇怪,无论是windows还是Ubuntu只要添加了anaconda中包的路径就报错,可能版本太低)。
这时我们需要自己去官网下载HDF5包去编译。我把我下载过的HDF5包传到网盘,分享网址,解压缩后使用cmake设置好安装路径,然后configure和generate,done好后打开cmd在build文件夹下输入make
编译,编译成功后,输入make install
会将编译好后的文件复制到自定义安装的路径下面。
然后再重新打开opencv的cmake配置,将hdf5库路径和头文件路径设置为刚刚安装好后的路径。再次对opencv进行make,直至成功。
如果您觉得上述步骤太麻烦,可以直接拷贝我已经编译好后的opencv文件夹,分享网址。我的文件夹如下:
把bin目录添加到环境变量即可。
在Ubuntu下我喜欢使用clion编程,Windows环境同样也可以使用。前面安装了MinGW工具后,安装Clion时会自动把MinGW编译器添加到路径中。如果先安装的clion后安装的MinGW,那么需要自己添加MinGW工具。
编写CMakeLists.txt,指定OpenCV路径:
cmake_minimum_required(VERSION 3.15)
project(opencv_test_cmake)
set(CMAKE_CXX_STANDARD 14)
# 这里需要指定自己的OpenCV路径
set(OpenCV_DIR E:/Software/OpenCV4.3.0/install)
find_package( OpenCV REQUIRED )
include_directories(${OpenCV_INCLUDE_DIRS})
message(${OpenCV_INCLUDE_DIRS})
message(${OpenCV_LIBS})
add_executable(opencv_test_cmake main.cpp)
target_link_libraries( opencv_test_cmake ${OpenCV_LIBS})
然后编写main文件,从网上找一个surf程序,试一下是否安装成功。
#include
#include
#include
using namespace std;
using namespace cv;
using namespace cv::xfeatures2d;
Mat Flannfeaturecompare(Mat srcImage1, Mat srcImage2)
{
int hessPara = 400;
Ptr detector = SURF::create(hessPara);
vector keypoints1, keypoints2;
Mat descriptors1, descriptors2;
detector->detectAndCompute(srcImage1, Mat(), keypoints1, descriptors1);
detector->detectAndCompute(srcImage2, Mat(), keypoints2, descriptors2);
FlannBasedMatcher matcher;
//FlannBasedMatcher matcher(new flann::LshIndexParams(20, 10, 2));
vector matches;
//BFMatcher matcher;
matcher.match(descriptors1, descriptors2, matches);
double max_dist = 0;
double min_dist = 1000;
//距离判断--最优匹配点
for (int i = 0; i < descriptors1.rows; i++)
{
double dist = matches[i].distance;
if (dist < min_dist)
min_dist = dist;
if (dist > max_dist)
max_dist = dist;
}
cout << "max_dist=" << max_dist << endl << "min_dist=" << min_dist << endl;
//最佳匹配点
vector matchVec;
for (int i = 0; i < descriptors1.rows; i++)
{
if (matches[i].distance < 5 * min_dist)
{
matchVec.push_back(matches[i]); //push_back 将满足条件的值赋值给matchVec数组
}
}
Mat matchMat, matchMat2;
drawMatches(srcImage1, keypoints1, srcImage2, keypoints2, matchVec, matchMat, Scalar::all(-1), Scalar::all(-1), vector(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
//imshow("matchMat", matchMat);
//特征点一致性检测
vector obj, scene;
for (int i = 0; i < matchVec.size(); i++)
{
obj.push_back(keypoints1[matchVec[i].queryIdx].pt); //为前图进行特征点索引 pt代表point(pt.x,pt.y);
scene.push_back(keypoints2[matchVec[i].trainIdx].pt); //为模板进行特征点索引
}
Mat H = findHomography(obj, scene, RANSAC); //随机点匹配
vector objCorner(4), sceneCors(4);
objCorner[0] = Point(0, 0);
objCorner[1] = Point(srcImage1.cols, 0);
objCorner[2] = Point(srcImage1.cols, srcImage1.rows);
objCorner[3] = Point(0, srcImage1.rows);
perspectiveTransform(objCorner, sceneCors, H); //映射矩阵
Point2f offset((float)srcImage1.cols, 0); //偏移量的增加
//line(matchMat, sceneCors[0] + offset, sceneCors[1] + offset, Scalar(0, 255, 0), 2);
//line(matchMat, sceneCors[1] + offset, sceneCors[2] + offset, Scalar(0, 255, 0), 2);
//line(matchMat, sceneCors[2] + offset, sceneCors[3] + offset, Scalar(0, 255, 0), 2);
//line(matchMat, sceneCors[3] + offset, sceneCors[0] + offset, Scalar(0, 255, 0), 2);
float min_x = 1000, min_y = 1000;
float max_x = 0, max_y = 0;
for (int i = 0; i < 4; i++)
{
if (sceneCors[i].x < min_x)
min_x = sceneCors[i].x;
if (sceneCors[i].y < min_y)
min_y = sceneCors[i].y;
for (int j = i; j < 3; j++)
{
float max_dis_x = abs(sceneCors[i].x - sceneCors[j + 1].x);
if (max_dis_x > max_x)
max_x = max_dis_x;
float max_dis_y = abs(sceneCors[i].y - sceneCors[j + 1].y);
if (max_dis_y > max_y)
max_y = max_dis_y;
}
}
//通过两张图片进行对比特征点匹配
//添加偏移量区域图的横向坐标偏移
rectangle(matchMat, Rect(min_x + srcImage1.cols, min_y, max_x, max_y), Scalar(0, 0, 255), 2, 8, 0);
Mat dst = srcImage2.clone();
rectangle(dst,
Rect(sceneCors[0].x, sceneCors[0].y, sceneCors[1].x - sceneCors[0].x, sceneCors[3].y - sceneCors[0].y),
Scalar(0, 0, 255), 2, 8, 0);
imshow("ObjectMat", matchMat);
imshow("dst", dst);
return matchMat;
}
int main()
{
Mat Image1 = imread("1.jpg");
Mat Image2 = imread("2.jpg");
Mat feature = Flannfeaturecompare(Image1, Image2);
waitKey(0);
return 0;
}