C++实现超分辨率 IDN

IDN (由信息蒸馏网络实现的快速准确的超分辨率)

在《IDN-Caffe-master》和《IDN-tensorflow-master》都有训练好的模型。

里面的一张和其它几个运行时间和效果比较图表:

效果比MemNet,DRRN好一点,差不多在同一个数量级,但速度很快。

这里用C++实现其中的4倍重建:

流程图:

信息蒸馏块:

上面的4组是说核数量只有通道数的4分之1

 

按caffe,tensorflow模型的不同,有部分差别:

1。1(亮度)或 3(RGB)输入输出

2。反卷积 或 像素混组(放大部分)

------------------------------------------------------------------------

先实现caffe模型:

定义蒸馏块:

struct 蒸馏块
{
	//增强单元-----------
	//上组
	层数据 *conv1_上; //64->48
	层数据 *conv2_上; //48->32 (4组:12x4=48)
	层数据 *conv3_上; //32->64 
	//64分割成(16+48) (其中16和输入64连接成80,48传入下组)

	//下组
	层数据 *conv1_下; //48->64
	层数据 *conv2_下; //64->48 (4组:16x4=64)
	层数据 *conv3_下; //48->80

	//和连接相加

	//压缩单元
	层数据 *down;//80->64

};

模型定义和初始化:

struct IDN模型
{
    //特征提取
	层数据 * conv1;//1->64
	层数据 * conv2;//64->64

	//信息蒸馏块
	int 蒸馏块数量;//4块
	蒸馏块 * 块;

	//重建(upsample)
	层数据 * 放大4倍;//64->1 反卷积(步长:4,核:17)
	
	
	//输入 和 输入双三次放大的 相加 即重建

	
	//构造函数
	IDN模型();

};

IDN模型::IDN模型()
{

	int size;
	层数据 * 层;

	//用于一层(宏)
	/*输入维度,输出维度,核宽*/
	/*输入维度,输出维度,核宽*/
	#define 初始化ONE层(IN,OUT,KW) \
	\
	层->输入维度=IN;\
	层->输出维度=OUT;\
	层->核宽=KW;\
	层->权重长度=层->输出维度*层->输入维度*层->核宽*层->核宽;\
	层->权重_数据=(float*)malloc(sizeof(float) * 层->权重长度);\
	层->偏移长度=层->输出维度;\
	层->偏移_数据=(float*)malloc(sizeof(float) * 层->偏移长度);\



	#define 初始化层(ConvX,IN,OUT,KW) \
	size = sizeof(层数据);\
\
	层=ConvX =(层数据 *)malloc(size);\
	初始化ONE层(IN,OUT,KW)\

	//组中核数量只有普通卷积的4分之1-------------------!!
	#define 初始化组卷积层(ConvX,IN,OUT,KW) \
\
	初始化层(ConvX,IN,OUT,KW) \
	层->输入维度*=4;\

	//用于一组(宏)
	/*组名称,输入维度,输出维度,核宽,组中层数*/

	//特征提取: 2层
	/*名称,输入维度,输出维度,核宽,组中层数*/
		初始化层(conv1,1,64,3);
		初始化层(conv2,64,64,3);

		蒸馏块数量=4;
		size = sizeof(蒸馏块)*蒸馏块数量;
		块=(蒸馏块*)malloc(size);
		蒸馏块 * 蒸馏块0=块;
		for (int k = 0;k<蒸馏块数量;k++)
		{

			初始化层(蒸馏块0->conv1_上,64,48,3);
			初始化组卷积层(蒸馏块0->conv2_上,12,32,3);
			初始化层(蒸馏块0->conv3_上,32,64,3);

			初始化层(蒸馏块0->conv1_下,48,64,3);
			初始化组卷积层(蒸馏块0->conv2_下,16,48,3);
			初始化层(蒸馏块0->conv3_下,48,80,3);

			初始化层(蒸馏块0->down,80,64,1);

			蒸馏块0++;
		}

		初始化层(放大4倍,64,1,17);

}

主函数:

void IDN(char * savefilename,IDN模型 & sr)
{

//		
	int wid=bmp.width;
	int hei=bmp.height;
		cout<<"输入图像宽度:"<<wid<<endl;
		cout<<"        高度:"<<hei<<endl;
//
	卷积层 Y(wid,hei,1);//亮度
	Y.data=new float[wid * hei ]; 
	卷积层 U(wid,hei,1);//
	U.data=new float[wid * hei ]; 
	卷积层 V(wid,hei,1);
	V.data=new float[wid * hei ]; 

	//jpg转换为Y,U,V卷积层
	bmp2YUV(&Y,&U,&V);

	卷积层 Y备份(wid,hei,1);//亮度
	Y备份.data=new float[wid * hei ]; 

	//备份
	卷积层复制(&Y,&Y备份);


	del卷积层(U);
	del卷积层(V);

	//---------------------------------------------->
	层数据 * 层;

	//两个卷积层 交替前传(源,目标)
			
	//用这个传回
	卷积层 * di=(卷积层 *)malloc(sizeof(卷积层));
		di->width=1;
		di->height=1;
		di->depth=1;
		di->data=new float[1 ]; 

	卷积层 *源,*目标;
	源 = &Y;
	
	目标 = di;

	int pad;

		

	//定义一个宏
	//用于各个层
	#define 卷积前传(ConvX,步长)/* 上采样、下采样 */ \
	\
	层=ConvX;/* Conv2 层 */ \
	if(层->输出维度 != 目标->depth || 目标->width != wid || 目标->height != hei)\
		Resize卷积层(*目标,wid,hei,层->输出维度);\
	pad=层->核宽/2;\
	vl_nnconv(源,目标,层 ,步长,步长,pad,pad,pad,pad);\
	vl_nnrelu(目标,0.05f);\
\
	std::swap (源,目标);\


	cout<<"输入层..."<<endl;
	卷积前传(sr.conv1,1);
	卷积前传(sr.conv2,1);


	//----------------------------------------------<

	    
	    

	//第二部分  4个蒸馏块
	卷积层 convfea5(wid,hei,源->depth);
	convfea5.data=new float[wid * hei * 源->depth ]; 

	卷积层 *源备份=&convfea5;


	if(源->depth != 目标->depth || 目标->width != wid || 目标->height != hei)
		Resize卷积层(*目标,wid,hei,源->depth);

	蒸馏块 * 蒸馏块0=sr.块;
	cout<<sr.蒸馏块数量<<"个蒸馏块... 包括 2 组卷积"<<endl;

		
	卷积层 割1(wid,hei,16);
	割1.data=new float[wid * hei * 16 ]; 
	卷积层 割2(wid,hei,48);
	割2.data=new float[wid * hei * 48 ]; 

	卷积层 加(wid,hei,80);
	加.data=new float[wid * hei * 80 ]; 

	for (int k = 0;k<sr.蒸馏块数量;k++)
	{
		cout<<"\r"<<k;


		//备份 (split)
		卷积层复制(源,源备份);


		卷积前传(蒸馏块0->conv1_上,1);
		//卷积前传(蒸馏块0->conv2_上,1);//4组 组卷积?
		组卷积4分(*源,*目标,蒸馏块0->conv2_上);
		std::swap (源,目标);

		卷积前传(蒸馏块0->conv3_上,1);

		//通道分割 (slice) 64->16,48
		通道分割(*源,割1,割2);
		

		Resize卷积层(*源,wid,hei,割2.depth);
		卷积层复制(&割2,源);


		卷积前传(蒸馏块0->conv1_下,1);
		//卷积前传(蒸馏块0->conv2_下,1);
		组卷积4分(*源,*目标,蒸馏块0->conv2_下);
		std::swap (源,目标);
		卷积前传(蒸馏块0->conv3_下,1);
						
		//concat
		通道连接(*源备份,割1,加);//16+64=80

		//数据增强 (Eltwise sum)
		卷积层相加(&加,源);

		//数据压缩
		卷积前传(蒸馏块0->down,1);

		蒸馏块0++;//到下蒸馏块
	}
	cout<<endl;
	del卷积层(*源备份);

	        
	//放大4倍
		
	cout<<"放大4倍... "<<endl;

	wid *= 4;hei *= 4;

	层=sr.放大4倍;/* Conv2 层 */ 
	if(层->输出维度 != 目标->depth || 目标->width != wid || 目标->height != hei)
		Resize卷积层(*目标,wid,hei,层->输出维度);
	pad=层->核宽/2;

	//调整图像位置和双三次重合
	int e=-4;//上下
	int f=-4;//左右
	vl_nnconvt(源,目标,层 ,4,4,pad+e,pad-e,pad+f,pad-f);
	//vl_nnrelu(目标);


	//cout<<层->偏移_数据[0]<<endl;
	std::swap (源,目标);


		//save_卷积层2jpg(源,"up");


	//原图放大4倍
	ResizeGrayscaleImage(4.0);
	wid=bmp.width;
	hei=bmp.height;


	卷积层 uY(wid,hei,1);//亮度
	uY.data=new float[wid * hei ]; 
	卷积层 uU(wid,hei,1);//
	uU.data=new float[wid * hei ]; 
	卷积层 uV(wid,hei,1);
	uV.data=new float[wid * hei ]; 

	//jpg转换为RGB卷积层
	bmp2YUV(&uY,&uU,&uV);
	//bmp2YUV(&uU,&uV);
					

	//卷积层双三次插值(Y备份,uY);


	//输入加上残差
	卷积层相加(源,&uY);
		//save_卷积层2jpg(&uY,"uY");

	YUV2bmp(&uY,&uU,&uV);
						
	
	del卷积层(*源);
	del卷积层(*目标);
	


	cout<<"图像转换成jpg格式... "<<endl;


	savejpg(savefilename);

	cout<<"转换文件已经保存为:    "<<savefilename<<endl;

}

效果图:

小图

IDN 4倍

EDSR 4倍

效果和EDSR可以说在一个数量级,运行时间只有EDSR的一半左右,并且占用内存小。

下载:

win32超分辩重建IDN实用程序

快速超分辨率重建IDN(4倍)的win32程序,由IDN-Caffe-master的模型改编而来.

https://download.csdn.net/download/juebai123/11123292

 

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值