再按照 https://github.com/opencv/opencv/blob/3.4.0/samples/dnn/fast_neural_style.py 改为 C++ 版的摄像头风格迁移
//摄像头或视频风格转换
//按空格存一图
//OpenCV:使用VideoCapture类进行视频读取和显示
#include <opencv2\opencv.hpp>
#include <opencv2\dnn.hpp>
#include <iostream>
using namespace std;
using namespace cv;
//数字转字符串:用C++的streanstream:
#include <sstream>
#include <string>
string num2str(double i)
{
stringstream ss;
ss << i;
return ss.str();
}
//----------------cv中取出 -----------------开始
const int CV_MAX_DIM = 32;
Mat getPlane(const Mat &m, int n, int cn)
{
CV_Assert(m.dims > 2);
int sz[CV_MAX_DIM];
for(int i = 2; i < m.dims; i++)
{
sz[i-2] = m.size.p[i];
}
return Mat(m.dims - 2, sz, m.type(), (void*)m.ptr<float>(n, cn));
}
//用于单图,如果多图还要再修改
void imagesFromBlob(const cv::Mat& blob_, OutputArrayOfArrays images_)
{
//blob 是浮点精度的4维矩阵
//blob_[0] = 批量大小 = 图像数
//blob_[1] = 通道数
//blob_[2] = 高度
//blob_[3] = 宽度
CV_Assert(blob_.depth() == CV_32F);
CV_Assert(blob_.dims == 4);
//images_.create(cv::Size(1, blob_.size[0]),blob_.depth() );//多图,不明白为什么?
images_.create(blob_.size[2],blob_.size[3],blob_.depth() );//创建一个图像
std::vector<Mat> vectorOfChannels(blob_.size[1]);
//for (int n = 0; n < blob_.size[0]; ++n) //多个图
{int n = 0; //只有一个图
//for (int c = 0; c < blob_.size[1]; ++c)
//{
// vectorOfChannels[c] = getPlane(blob_, n, c);
//}
vectorOfChannels[0] = getPlane(blob_, n, 0)+103.939;
vectorOfChannels[1] = getPlane(blob_, n, 1)+116.779;
vectorOfChannels[2] = getPlane(blob_, n, 2)+123.68;
//cv::merge(vectorOfChannels, images_.getMatRef(n));//这里会出错,是前面的create的原因?
cv::merge(vectorOfChannels, images_);//通道合并
}
}
//----------------cv中取出 -----------------结束
int main(int argc, char *argv[])
{
String model[]={"mosaic.t7","candy.t7","la_muse.t7","the_scream.t7","feathers.t7","udnie.t7",//instance_norm 6个
"the_wave.t7","starry_night.t7","la_muse_eccv16.t7","composition_vii.t7"};//eccv16 4个
//随机取一个模型
cv::RNG rng((unsigned)time(NULL));
int num=rng.uniform(0, 1000 )% 10;
cout<<num<<endl;
cout<<model[num]<<endl;
// 加载模型
dnn::Net net = cv::dnn::readNetFromTorch(model[num]);
//打开视频文件:其实就是建立一个VideoCapture结构
VideoCapture capture(0);
//检测是否正常打开:成功打开时,isOpened返回ture
if(!capture.isOpened()){
cout<<"出错了!"<<endl; return -1;}
//定义一个用来控制读取视频循环结束的变量
bool stop = false;
//承载每一帧的图像
Mat frame;
long currentFrame = 0;//记录用
while(!stop)
{
//读取下一帧
if(!capture.read(frame))
{
cout<<"读取视频失败"<<endl;
return -1;
}
size_t h=frame.rows;// 行数(高度)
size_t w=frame.cols;// 列数(宽度)
Mat inputBlob;//转换为 (1,3,h,w) 的矩阵 即:(图像数,通道,高,宽)
inputBlob = cv::dnn::blobFromImage(frame, 1.0, Size(200, 200*h/w), Scalar(103.939, 116.779, 123.680), false, false);//
// 前传
net.setInput(inputBlob);
Mat out = net.forward();
Mat Styled;//4维转回3维
//cv::dnn::imagesFromBlob(out, Styled);//由于这个函数会出错,已把它从dnn取出稍稍修改一下用
imagesFromBlob(out, Styled);
// 输出图片
Styled /=255;
Mat uStyled;
Styled.convertTo(uStyled,CV_8U,255);//转换格式
cv::imshow("风格图像", uStyled);
int c = waitKey(1);
//按下ESC或者到达指定的结束帧后退出读取视频
if((char) c == 27 )
{
stop = true;
break;
}
//按下空格键存图
if(c==32){//保存一张图,接片用
string jpg_file=""+num2str(currentFrame)+".jpg";//按位置设置文件名
currentFrame++;
for(unsigned int i=0,p=8-jpg_file.length();i<p;i++) //不足8个字符用0补
jpg_file="0"+jpg_file;
imwrite(jpg_file,uStyled);
}
}
//关闭视频文件
capture.release();
cout<<"已结束"<<endl;
return 0;
}
感觉速度有点慢