OpenCV4.0 运行快速风格迁移(Torch)

从《Python 图像风格迁移(模仿名画)》一文中看到 OpenCV 可以运行Torch 模型。也来试试,

先用vs2008编译一个cv3.3,

再下一个"fast-neural-style-master"包,按包中地址下载几个模型,下面是其中一个:

"http://cs.stanford.edu/people/jcjohns/fast-neural-style/models/instance_norm/candy.t7"

运行:

	// 加载模型
	dnn::Net net = cv::dnn::readNetFromTorch("candy.t7");

这里出错了,candy.t7中的部分Torch层在CV3.3不支持。

先来看一下模型的各层名称,和 fast-neural-style-tensorflow-master 比一比、有什么不同:

nn.Sequential
nn.SpatialReflectionPadding	补边
nn.SpatialConvolution		卷积		3-->16扩维
nn.InstanceNormalization	实例正则化
nn.SpatialBatchNormalization	批正则化
nn.ReLU				relu激励
nn.SpatialConvolution		卷积		16-->32扩维,并2倍下采样
nn.InstanceNormalization
nn.SpatialBatchNormalization
nn.ReLU
nn.SpatialConvolution		卷积		32-->64扩维,并2倍下采样
nn.InstanceNormalization
nn.SpatialBatchNormalization
nn.ReLU
--------------------------------残差块 1
nn.Sequential
nn.ConcatTable
nn.Sequential
nn.SpatialConvolution		卷积		64-->64维不变
nn.InstanceNormalization
nn.SpatialBatchNormalization
nn.ReLU
nn.SpatialConvolution		卷积		64-->64维不变
nn.InstanceNormalization
nn.SpatialBatchNormalization
nn.ShaveImage			去边(边宽=补边宽/残差块数)
nn.CAddTable			矩阵相加
--------------------------------残差块 2
nn.Sequential
nn.ConcatTable
nn.Sequential
nn.SpatialConvolution
nn.InstanceNormalization
nn.SpatialBatchNormalization
nn.ReLU
nn.SpatialConvolution
nn.InstanceNormalization
nn.SpatialBatchNormalization
nn.ShaveImage
nn.CAddTable
--------------------------------残差块 3
nn.Sequential
nn.ConcatTable
nn.Sequential
nn.SpatialConvolution
nn.InstanceNormalization
nn.SpatialBatchNormalization
nn.ReLU
nn.SpatialConvolution
nn.InstanceNormalization
nn.SpatialBatchNormalization
nn.ShaveImage
nn.CAddTable
--------------------------------残差块 4
nn.Sequential
nn.ConcatTable
nn.Sequential
nn.SpatialConvolution
nn.InstanceNormalization
nn.SpatialBatchNormalization
nn.ReLU
nn.SpatialConvolution
nn.InstanceNormalization
nn.SpatialBatchNormalization
nn.ShaveImage
nn.CAddTable
--------------------------------残差块 5
nn.Sequential
nn.ConcatTable
nn.Sequential
nn.SpatialConvolution
nn.InstanceNormalization
nn.SpatialBatchNormalization
nn.ReLU
nn.SpatialConvolution
nn.InstanceNormalization
nn.SpatialBatchNormalization
nn.ShaveImage
nn.CAddTable
nn.SpatialFullConvolution	全卷积		64-->32减维,并2倍上采样
nn.InstanceNormalization
nn.SpatialBatchNormalization
nn.ReLU
nn.SpatialFullConvolution	全卷积		32-->16减维,并2倍上采样
nn.InstanceNormalization
nn.SpatialBatchNormalization
nn.ReLU
nn.SpatialConvolution		卷积		16-->3减维
nn.Tanh
nn.MulConstant
nn.TotalVariation

相差不是很大,中间层维数是哪个tensorflow的一半,这个速度应该会快一点。

看来要编译CV4.0了,4.0对于vs2008已经没办法了,由于空间不足,就用mingw32编译吧

下了一个mingw32-4.92,费了一点波折,成功了

《Python OpenCV 图像风格迁移(模仿名画)》一文是、Python调用OpenCV, 这个暂时还不会,先搞一个C++的吧:

//核心代码: 加载模型 -> 读取图片 -> 前传计算 -> 输出图片
#include <opencv2\opencv.hpp>
#include <opencv2\dnn.hpp>
#include <iostream>

using namespace cv;
using namespace std;
 
//----------------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);
        }
        //cv::merge(vectorOfChannels, images_.getMatRef(n));//这里会出错,是前面的create的原因?
        cv::merge(vectorOfChannels, images_);//通道合并
    }
}
//----------------cv中取出	-----------------结束

int main(int argc, char *argv[])
{
	char jpgname[256];//图像名
	if( argc == 2 )
		strcpy_s(jpgname, argv[1]);
	else		
		strcpy_s(jpgname, "5c6.jpg");

	double time1 = static_cast<double>(getTickCount());  //记录起始时间

	// 加载模型
	dnn::Net net = cv::dnn::readNetFromTorch("mosaic.t7");

	// 读取图片
	Mat image = cv::imread(jpgname);

	size_t h=image.rows;// 行数(高度)
	size_t w=image.cols;// 列数(宽度)
	cout<<	w <<endl;
	cout<<	h <<endl;


	Mat inputBlob;//转换为 (1,3,h,w) 的矩阵 即:(图像数,通道,高,宽)
	//blobFromImage函数解释:

	//第一个参数,InputArray image,表示输入的图像,可以是opencv的mat数据类型。
	//第二个参数,scalefactor,这个参数很重要的,如果训练时,是归一化到0-1之间,那么这个参数就应该为0.00390625f (1/256),否则为1.0
	//第三个参数,size,应该与训练时的输入图像尺寸保持一致。
	//第四个参数,mean,这个主要在caffe中用到,caffe中经常会用到训练数据的均值。tf中貌似没有用到均值文件。
	//第五个参数,swapRB,是否交换图像第1个通道和最后一个通道的顺序。
	//第六个参数,crop,如果为true,就是裁剪图像,如果为false,就是等比例放缩图像。
	//inputBlob= cv::dnn::blobFromImage(image, 1.0, Size(416, 416), Scalar(), false, true);//1/255.F
	//inputBlob= cv::dnn::blobFromImage(image, 1.0, Size(416, 416*h/w), Scalar(103.939, 116.779, 123.680), false, true);//
	inputBlob = cv::dnn::blobFromImage(image, 1.0, Size(w,h), 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);
	cv::imwrite("风格图像.jpg", uStyled);

	time1=((double)getTickCount()-time1)/getTickFrequency();//计算程序运行时间
    cout<<"此方法运行时间为:"<<time1<<"秒"<<endl;//输出运行时间。

	waitKey(0);
}

 

效果图:

  这是mosaic风格的

和《fast-neural-style-master》一文比有点暗,应该是后处理有点不同吧,原文相当于做了一个归一化。

 

  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值