这篇文章介绍了怎么通过源码编译opencv。其实Opencv在3.3版本之后就加入了深度神经网络模块的支持,可以导入caffe,tensorflow,pytorch等主流框架的模型。
我们大多项目都是在后台或者移动端部署的,这篇介绍下opencv_dnn模块的python和C++的使用,以及在PC端如何部署模型。
Opencv_dnn应用
我的模型是使用tensorflow框架训练的,Opencv导入pb格式的模型,所以首先我们需要把ckpt转为pb。
opencv_dnn使用流程:
- 读取图像
- dnn.readNetFromTensorflow读取pb模型
- dnn.blobFromImage对图像进行resize,减均值等预处理并转为blob
- blob作为网络输入
- dnn的forward接口进行inference计算
- 得到网络输出进行后处理输出最终结果
python版本:
安装opencv-python>3.3,我安装的最新版本4.1
pip install opencv-python
直接上代码~
# -*- coding: utf-8 -*-
import cv2
import numpy as np
from PIL import Image
#预处理
def preprocessing(file):
pic = cv2.imread(file)
return pic
def test_dnn_module():
""" Function to test OpenCV DNN module. """
model = './model/test/opencv/seg.pb'
file = "test.jpg"
frame = preprocessing(file)
print("frame", frame.shape)
#读取pb模型
net = cv2.dnn.readNetFromTensorflow(model)
#输入图像img转为blob
blob = cv2.dnn.blobFromImage(frame, 1.0/255.0, (320,320), swapRB=False, crop=False)
#blob作为网络输入
net.setInput(blob)
#进行inference
raw_output = net.forward()
raw_output = np.squeeze(raw_output)
# print("raw_output",raw_output[:,0,0],raw_output.shape)
#argmax得到分割结果
output = np.argmax(raw_output, axis=0)
#保存分割图
image = output * 255.0
images = np.asarray(image, np.uint8)
im_o = Image.fromarray(images)
im_o.save("./reslut_opencv.png")
if __name__ == '__main__':
test_dnn_module()
效果图
C++版本:
我使用的win10系统+VS2017+编译安装Opencv3.3以上版本
VS2017新建工程
配置引用Opencv目录和库,可以看我opencv专栏文章配置
处理流程和上面一样,上代码~
#include <iostream>
#include <opencv2/dnn.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
using namespace cv;
using namespace dnn;
void get_segResult(cv::Mat output,cv::Mat &result)
{
//NCHW
const int rows = output.size[2];
const int cols = output.size[3];
const int chns = output.size[1];
result = Mat::zeros(rows, cols, CV_8UC1);
//get label result
Mat maxVal(rows, cols, CV_32FC1, output.data);
for (int ch = 0; ch < chns; ch++) {
for (int row = 0; row < rows; row++) {
const float *ptrout = output.ptr<float>(0, ch, row);
uint8_t *ptrMaxCl = result.ptr<uint8_t>(row);
float *ptrMaxVal = maxVal.ptr<float>(row);
for (int col = 0; col < cols; col++) {
if (ptrout[col] > ptrMaxVal[col]) {
ptrMaxVal[col] = ptrout[col];
ptrMaxCl[col] = (uchar)ch * 255;
}
}
}
}
}
void infer_image(String win_name,cv::Mat img, cv::dnn::Net net) {
cv::Scalar mean{ 0, 0, 0 };
bool swapRB{ false };
int inputW = 320;
int inputH = 320;
//image to blob
cv::Mat blob = cv::dnn::blobFromImage(img, 1.0 / 255.0, cv::Size(inputW, inputH), mean, swapRB, false);
//setInput
net.setInput(blob);
//infer image
cv::Mat output = net.forward();
std::cout << ",output size:" << output.size << std::endl; //[1,3,320,320]
//求argmax
cv::Mat result;
get_segResult(output, result);
imshow(win_name, img);
imshow(win_name+"_label", result);
}
int main()
{
String model = "res/seg.pb";
//读取网络pb
cv::dnn::Net net = cv::dnn::readNetFromTensorflow(model);
int backendId = cv::dnn::DNN_BACKEND_OPENCV;
net.setPreferableBackend(backendId);
//单张图片infer
cv::Mat img = cv::imread("E:\\resize.jpg");
infer_image("out",img,net);
waitKey();
return 0;
}
C++要注意的问题是cv::Scalar mean{ 0, 0, 0 };一定要定位为scalar结构,不要直接一个数值,不然会导致结果不一致。