Mac 使用VS Code 通过cmake 配置 OpenCV和Pytorch C++ API

前情

由于pytorch的1.0正式版发布不久,同时较为稳定的c++的API也是在正式版中提供支持,网上的教程不多,因此可供参考的资料只有官方文档和零零散散的博客。不过由于Mac和Linux本身相差不大,一些Linux的配置教程同样值得参考。
以下给出链接:


Oldpan的个人博客(特别感谢Oldpan老哥的帖子给我的巨大帮助):

开始

所需安装的工具有:
1.VS Code:这个官网下载即可
2.OpenCV 4.0.1:终端输入

1
brew install opencv

即可安装
3.Pytorch1.0:可参考上面给出的Pytorch源码编译简明指南,首先在终端输入
1
git clone --recursive https://github.com/pytorch/pytorch

获取最新源码,然后通过编译得到Mac可以读取的.dylib文件(注意:在官方文档中下载的libtorch-shared-with-deps-latest.zip文件解压后所得到的文件夹里的动态库文件是以.so结尾,是Linux下的动态库文件,Mac识别不了)编译时应该先进入到刚刚下载好的Pytorch文件夹(默认的路径应该是/Users/用户名/pytorch)下,然后终端执行
1
2
3
mkdir build
cd build
python ../tools/build_libtorch.py

进行libtorch(即c++ API)的编译,时间较长。
4.编译好之后打开VS Code新建一个工程,在这里我引用Oldpan老哥的例子

工程名叫simnet,然后在simnet文件夹下新建一个CMakeLists.txt和一个test.cpp(build先不建),CMakeLists.txt中的代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
project(simnet)

find_package(Torch REQUIRED) # 查找libtorch
find_package(OpenCV REQUIRED) # 查找OpenCV

if(NOT Torch_FOUND)
message(FATAL_ERROR "Pytorch Not Found!")
endif(NOT Torch_FOUND)

message(STATUS "Pytorch status:")
message(STATUS " libraries: ${TORCH_LIBRARIES}")

message(STATUS "OpenCV library status:")
message(STATUS " version: ${OpenCV_VERSION}")
message(STATUS " libraries: ${OpenCV_LIBS}")
message(STATUS " include path: ${OpenCV_INCLUDE_DIRS}")

add_executable(simnet test.cpp)
target_link_libraries(simnet ${TORCH_LIBRARIES} ${OpenCV_LIBS})
set_property(TARGET simnet PROPERTY CXX_STANDARD 11)

test.cpp中的代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include <opencv2/opencv.hpp>
#include "torch/script.h"
#include "torch/torch.h"

#include <iostream>
#include <memory>

using namespace std;

// resize并保持图像比例不变
cv::Mat resize_with_ratio(cv::Mat& img)
{
cv::Mat temImage;
int w = img.cols;
int h = img.rows;

float t = 1.;
float len = t * std::max(w, h);
int dst_w = 224, dst_h = 224;
cv::Mat image = cv::Mat(cv::Size(dst_w, dst_h), CV_8UC3, cv::Scalar(128,128,128));
cv::Mat imageROI;
if(len==w)
{
float ratio = (float)h/(float)w;
cv::resize(img,temImage,cv::Size(224,224*ratio),0,0,cv::INTER_LINEAR);
imageROI = image(cv::Rect(0, ((dst_h-224*ratio)/2), temImage.cols, temImage.rows));
temImage.copyTo(imageROI);
}
else
{
float ratio = (float)w/(float)h;
cv::resize(img,temImage,cv::Size(224*ratio,224),0,0,cv::INTER_LINEAR);
imageROI = image(cv::Rect(((dst_w-224*ratio)/2), 0, temImage.cols, temImage.rows));
temImage.copyTo(imageROI);
}

return image;
}
int main(int argc, const char* argv[]){
if (argc != 2) {
std::cerr << "usage: example-app <path-to-exported-script-module>\n";
return -1;
}

cv::VideoCapture stream(0);
cv::namedWindow("Gesture Detect", cv::WINDOW_AUTOSIZE);

std::shared_ptr<torch::jit::script::Module> module = torch::jit::load(argv[1]);
module->to(at::kCUDA);

cv::Mat frame;
cv::Mat image;
cv::Mat input;

while(1)
{
stream>>frame;
image = resize_with_ratio(frame);

imshow("resized image",image); //显示摄像头的数据
cv::cvtColor(image, input, cv::COLOR_BGR2RGB);

// 下方的代码即将图像转化为Tensor,随后导入模型进行预测
torch::Tensor tensor_image = torch::from_blob(input.data, {1,input.rows, input.cols,3}, torch::kByte);
tensor_image = tensor_image.permute({0,3,1,2});
tensor_image = tensor_image.toType(torch::kFloat);
tensor_image = tensor_image.div(255);
tensor_image = tensor_image.to(torch::kCUDA);
torch::Tensor result = module->forward({tensor_image}).toTensor();

auto max_result = result.max(1, true);
auto max_index = std::get<1>(max_result).item<float>();
if(max_index == 0)
cv::putText(frame, "paper", {40, 50}, cv::FONT_HERSHEY_PLAIN, 2.0, cv::Scalar(0, 255, 0), 2);
else if(max_index == 1)
cv::putText(frame, "scissors", {40, 50}, cv::FONT_HERSHEY_PLAIN, 2.0, cv::Scalar(0, 255, 0), 2);
else
cv::putText(frame, "stone", {40, 50}, cv::FONT_HERSHEY_PLAIN, 2.0, cv::Scalar(0, 255, 0), 2);

imshow("Gesture Detect",frame); //显示摄像头的数据
cv::waitKey(30);
}

保存。

5.终端cd进入simnet工程文件夹,然后执行

1
2
3
4
mkdir build
cd build
cmake -DCMAKE_PREFIX_PATH=/absolute/path/to/pytorch ..
make

其中/absolute/path/to/pytorch是pytorch文件夹的绝对路径,一般是/Users/用户名/pytorch
这样就编译完成了
可以执行
1
./simnet

来运行你的工程了!

后记

由于这是我第一次写教程,很多地方可能有所疏漏,并且配置的过程中踩了无数的坑,可能很多地方起了效果但是我根本没有注意到,还有前期的一些准备工作我也没有提及(比如说anaconda的安装,pip、conda、brew的安装和更新),这些网上有很多大佬写的非常详尽的教程,大家可以多多参考,我这里只是提供了一个自己的思路,如果没有安装成功还望见谅!