纯C++超分辨率重建LapSRN --改编--(一)数据和框架

由于网络上找不到多通道多核的转置卷积,那么只能从matconvnet入手了,先用LapSRN 8倍的,它的层数小一点(放大一个2倍差不多8层 3x8=24,实际上是25层,只要8,9层就可以出现一个2倍放大图,其它2倍的20多层,4倍的40多层 )

先说一下流程

1。从matlab中导出LapSRN数据(网络权重(卷积核)和偏置,按用到的顺序导出,所以在我们的程序中不需要排列核位置)

2。从文本文件中导入结构中

3。外框架和 LapSRN 函数(几乎和matlab中一样)

4。然后就是三个函数vl_nnconv(正向卷积),vl_nnconvt(反向),vl_nnrelu(激励)

vl_nnrelu比较简单,其它的围绕vl_nnconv 和vl_nnconvt 展开(也就是对matconvnet中的代码涂涂改改)。

现在开始:

1。导出LapSRN 8倍网络数据到 LapSRN_x8.txt 文件中

%% 参数
scale  = 8; % SR 采样比例 可以是 2、4 或 8 倍

%% 加载预训练模型
model_filename = fullfile('pretrained_models', sprintf('LapSRN_x%d.mat', scale));

fprintf('载入 %s\n', model_filename);
net = load(model_filename);
net=net.net;

l=length(net.layers);
% 
% 
j=0;
% 
upsample_num=0;% 图像放大计数
residual_num=0;% 残差图计数

%保存模型数据
%偏移
%---------------------------------------
FID=fopen('LapSRN_x8.txt','w');

%所有层
for i=1:l %42 是上采样层
    issave=0;
    disp(['第 ',num2str(i),' 层']);
    if strTong(net.layers(i).type,'dagnn.Conv')
        
            j=j+1
            disp('卷积层');
            
            
            %得到权重(也就是卷积核)和偏移
            disp('参数是:');
            disp(net.layers(i).params);
            fft=net.layers(i).params{1};
            for k=1:length(net.params)
                if strTong(net.params(k).name,fft)
                    weight=net.params(k).value;
                    break;
                end
            end
            if net.layers(i).block.hasBias==false
                bias=[]; % 无偏移
            else
                fft=net.layers(i).params{2};
                for k=1:length(net.params)
                    if strTong(net.params(k).name,fft)
                        bias=net.params(k).value;
                        break;
                    end
                end
            end
	    wname=['卷积层' num2str(j) '\n'];
	    fprintf(FID,wname );
	    issave=1;

    end
    
    
    if strTong(net.layers(i).type,'dagnn.ConvTranspose')
        
            
            disp('上采样层');%反向卷积,转置卷积
            
            
            disp('输入是:');
            disp(net.layers(i).inputs);
            
            %得到权重(也就是卷积核)和偏移
            disp('参数是:');
            disp(net.layers(i).params);
            fft=net.layers(i).params{1};
            for k=1:length(net.params)
                if strTong(net.params(k).name,fft)
                    weight=net.params(k).value;
                    break;
                end
            end
            if net.layers(i).block.hasBias==false
                bias=[]; % 无偏移
            else
                fft=net.layers(i).params{2};
                for k=1:length(net.params)
                    if strTong(net.params(k).name,fft)
                        bias=net.params(k).value;
                        break;
                    end
                end
            end
            disp('输出是:');
            disp(net.layers(i).outputs);
            
            upsample=net.layers(i).block.upsample;
            crop=net.layers(i).block.crop;
            numGroups=net.layers(i).block.numGroups;
            opts=net.layers(i).block.opts{:}
            % 字符串是否包含
            if strBao(net.layers(i).outputs{:}, 'img_up') %残差
	    	    wname=['图像放大层\n'];
		    fprintf(FID,wname );

            else
	    	    wname=['残差放大层\n'];
		    fprintf(FID,wname );
                
            end
	    issave=1;
    end

    if 	    issave==1;

	
	
	
	    [h,w,c,p]=size(weight);
	    l0=h*w*c*p;
	    fprintf(FID,'长度 %d\n',l0 );%有多少个

        for i0=1:c
            for j0=1:p
                for t=1:h
                    for s=1:w
                        fprintf(FID, '%f ',weight(s,t,i0,j0)); 
                    end
                    fprintf(FID, '\n'); 

                end
            end
	    end

	    if ~isempty(bias)
		    bname=['有偏移\n'];
		    fprintf(FID,bname );
		    l0=length(bias);
		    fprintf(FID,'长度 %d\n',l0 );%有多少个

		    for i0=1:l0
                fprintf(FID, '%f ',bias(i0)); 
		    end
		    fprintf(FID, '\n'); 
	    else
		    bname=['无偏移\n'];
		    fprintf(FID,bname );
	    end

	    
       end
end

fclose(FID);
%---------------------------------------

模型数据结构:

#define 总层数 25


struct 层数据
{
	char 类型[255];
	int 权重长度;
	float *	权重_数据;
	int 偏移长度; 
	float *	偏移_数据;
};

struct LapSRN_x8模型
{
	int 层数; //25

	层数据 * 所有层;

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

};

LapSRN_x8模型::LapSRN_x8模型()
{
	层数=总层数; //

	int size;
	size = sizeof(层数据)*层数;//
	所有层=(层数据 *)malloc(size);


}

载入模型数据:

bool loadModel(LapSRN_x8模型 *sr)
{
	char name[]="LapSRN_x8.txt";
	std::ifstream fin(name);

	//检查文件是否存在
	if (!fin)
	{
		return false;
	}

		cout<<"正在载入‘LapSRN_x8.txt’的数据"<<endl;


	//从档案载入
	char str[40];
	int len;

	层数据 * 层=sr->所有层;
	for (int k = 0;k<总层数;k++)
	{
		//cout<<k<<"层"<<endl<<endl;

		fin >> 层->类型;
		//cout<<层->类型<<endl;

		fin >> str;
		//cout<<str<<endl;

		fin >> len;//需要载入的个数
		//cout<<len<<endl;
		层->权重长度=len;

		层->权重_数据=(float*)malloc(sizeof(float) * 层->权重长度);
		float *	w=层->权重_数据;
			
		//float tmp;
		for(int i=0;i<len;i++)
		{
			fin >> *w++;
		}

		fin >> str; //有无偏移
		//cout<<str<<endl;

		if(strcmp(str, "有偏移")==0)
		{
			fin >> str;//长度
			//cout<<str<<endl;
			fin >> len;//需要载入的个数
			//cout<<len<<endl;
			层->偏移长度=len;

			层->偏移_数据=(float*)malloc(sizeof(float) * 层->偏移长度);
			float *	b=层->偏移_数据;

			for(int i=0;i<len;i++)
			{
				fin >> *b++;
			}
		}else
		{
			层->偏移长度=0;

			层->偏移_数据=NULL;
		}
		层++;//到下一层
	}//end


		
	fin.close ();  
	return true;
}

卷积层:

class 卷积层
{
	public:
	int		width;    //宽
	int     height;   //高
	int     depth;		  //通道 深度
	float * data;

	//构造函数
	卷积层(int iwidth,int iheight);
	卷积层(int iwidth,int iheight,int idepth);
	卷积层(int iwidth,int iheight,int c,float * data);
	~卷积层();
};

卷积层::卷积层(int iwidth,int iheight): width(iwidth),
                                            height(iheight)
{
	depth=1;
	data=NULL;

}

卷积层::卷积层(int iwidth,int iheight,int idepth): width(iwidth),
                                            height(iheight),depth(idepth)
{
	data=NULL;

}
卷积层::卷积层(int iwidth,int iheight,int idepth,float * fdata): width(iwidth),
                                            height(iheight),depth(idepth),	data(fdata)

{

}

卷积层::~卷积层()
{

}

内存分配在外部

主函数main ,这里不用图形界面:

int main(int argc, char *argv[])
{
	char jpgname[256];
	if( argc == 2 )
		strcpy(jpgname, argv[1]);
	else		
		strcpy(jpgname, "测试1.jpg");//lena.jpg //6c7a


	//载入图片
	loadjpg(jpgname);

	// 放大倍率 2,4 或 8 倍
	int up_scale = 8;


	clock_t start_t, end_t;//计算时间
	double total_t;
 
	start_t = clock();


	// LapSRN 高分辨率重建
	LapSRN(up_scale);

   end_t = clock();
   
   total_t = (double)(end_t - start_t) / CLOCKS_PER_SEC;

   cout<<"已经完成"<<endl;
   cout<<"用时:"<<total_t<<" 秒"<<endl;

    system("pause");

	return 0;
}

核心流程函数LapSRN:

void LapSRN(int up_scale)
{
	LapSRN_x8模型 sr;
	// 加载 CNN 模型参数
	loadModel(&sr);
	//cout<<"loadModel成功"<<endl;
		
	int wid=jpg.getwidth();
	int hei=jpg.getheight();
		cout<<"输入图像宽度:"<<wid<<endl;
		cout<<"        高度:"<<hei<<endl;

	卷积层 im_b(wid,hei);//即Y通道
	im_b.data=new float[wid * hei * sizeof(float)]; 

	卷积层 U(wid,hei),V(wid,hei);
	U.data=new float[wid * hei * sizeof(float)]; 
	V.data=new float[wid * hei * sizeof(float)]; 



	//RGB转换为YUV
	RGB2YUV(&jpg,&im_b,&U,&V);

	//U,V暂时无用,先删除占用内存
			delete []U.data;  U.data=NULL;  
			delete []V.data;  V.data=NULL;  

	//loadImlow(&im_b);//载入matlab导出的数据用于比较
    //save_mat ("im_bis.txt",im_b.data,im_b.width,im_b.height,im_b.depth);  //保存


	//总层数
	int l=总层数;//
	cout<<"共有:"<<l<<"层"<<endl;


	//中间过程
	卷积层 convfea1(wid,hei,64);
	convfea1.data=new float[wid * hei * 64 * sizeof(float)]; 
	卷积层 convfea2(wid,hei,64);
	convfea2.data=new float[wid * hei * 64 * sizeof(float)]; 
	卷积层 *源=&im_b, *目标=&convfea1;

	// 残差图--------------------------------------------------------
	// 2倍残差图
	卷积层 residual1(wid*2,hei*2);
	residual1.data=new float[wid * hei * 4 * sizeof(float)]; 
	卷积层 hR1(wid*2,hei*2);
	hR1.data=new float[wid * hei * 4 * sizeof(float)]; 

	// 4倍残差图
	卷积层 residual2(wid*4,hei*4);
	residual2.data=new float[wid * hei * 16 * sizeof(float)]; 
	卷积层 hR2(wid*4,hei*4);
	hR2.data=new float[wid * hei * 16 * sizeof(float)]; 

	// 8倍残差图
	卷积层 residual3(wid*8,hei*8);
	residual3.data=new float[wid * hei * 64 * sizeof(float)]; 
	卷积层 hR3(wid*8,hei*8);
	hR3.data=new float[wid * hei * 64 * sizeof(float)]; 

	if(residual3.data==NULL)
	{
		printf("图片太大!只能运行4倍放大\n");
		up_scale=4;
	}
	if(residual2.data==NULL)
	{
		printf("图片太大!只能运行2倍放大\n");
		up_scale=2;
	}



	int upsample_num=0;// 图像放大计数
	int residual_num=0;// 残差图计数
	float *weight, *bias;



	//save_矩阵 ("im_b.txt",im_b.data,im_b.width,im_b.height,im_b.depth);  //保存

	层数据 * 层=sr.所有层;

	//循环各层直至结束
	for (int i=0;i<l;i++ )//8 25层
	{
	    
		cout<<"第 "<<i<<" 层"<<endl;



	if (strstr(层->类型, "卷积层"))//strTong(net.layers(i).type,'dagnn.Conv')
	{
		//返回一个指针,指向字符串 s1 中字符串 s2 的第一次出现的位置。
	        
				//j=j+1
				cout<<"卷积..."<<endl;
	            
	            
				//得到权重(也就是卷积核)和偏移
			weight=层->权重_数据;
			bias=层->偏移_数据;
				if (i==0) //strTong(net.layers(i).inputs{1},'LR') //第一层
				{
					//convfea = vl_nnconv(im_b,weight,bias,'Pad',1);//一图得出64特征图

					vl_nnconv(&im_b,目标,层,1 ,1 ,	1 ,1 ,1 ,1 );
					vl_nnrelu(目标, 0.2);//'leak',

					//save_卷积层2jpg(目标,"con0");
					源=目标;
					目标=&convfea2;
				}
				else //一以后
				{
					if (层->权重长度==576) //strBao(net.layers(i).outputs{:}, 'residual')
					{
						cout<<"合成残差..."<<endl;
						//residual_num=residual_num+1;
	                    卷积层 *tmp=目标;//暂存

						if (residual_num==1)
							//residual1= vl_nnconv(convfea,weight,bias,'Pad',1);// 2倍残差图
							目标= & residual1;

						//end
						if (residual_num==2)
							//residual2= vl_nnconv(convfea,weight,bias,'Pad',1);// 4倍残差图
							目标=  &residual2;
						if (residual_num==3)
							//residual3= vl_nnconv(convfea,weight,bias,'Pad',1);// 8倍残差图
							目标= &residual3;
							
						vl_nnconv(源,目标,层,1 ,1 ,1 ,1 ,1 ,1 );
						vl_nnrelu(目标, 0.2);//'leak',
							//char txt[255];
							//sprintf(txt, "第%d残差", residual_num);  
							//save_卷积层2jpg(目标,txt);

							//sprintf(txt, "第%d残差前", residual_num);  
							//save_卷积层2jpg(源,txt);

						目标=tmp;//还原
					}
					else 
					{
							//中间层 64特征图合成1图 再重新生成深一层64特征图
							//convfea = vl_nnconv(convfea,weight,bias,'Pad',1);
							vl_nnconv(源,目标,层,1 ,1 ,	1 ,1 ,1 ,1 );
					
							vl_nnrelu(目标, 0.2);//'leak',

							//char txt[255];
							//sprintf(txt, "con%d", i);  
							//save_卷积层2jpg(目标,txt);

							std::swap(源,目标);
					}
						
					//end
				}//end
	}//end

	if (strstr(层->类型, "残差放大层"))//strTong(net.layers(i).type,'dagnn.Conv')
	{
				cout<<"残差放大..."<<endl;
						residual_num++;
			weight=层->权重_数据;
			bias=层->偏移_数据;
					// 残差放大参数是 'upsample', 2 ,'crop', [0 1 0 1],'numGroups', 1
					//convfea = vl_nnconvt(convfea, weight, bias,'upsample', upsample ,'crop', crop,'numGroups', 1) ;//
			      
			//扩大第一卷积层内存
			delete []目标->data;  目标->data=NULL;  
			if (residual_num==1)
			{

				目标->width=wid*2;目标->height=hei * 2;目标->depth=64;
				目标->data=new float[wid * hei * 4 * 64 * sizeof(float)]; 
			}
			if (residual_num==2)
			{

				目标->width=wid*4;目标->height=hei * 4;目标->depth=64;
				目标->data=new float[wid * hei * 16 * 64 * sizeof(float)]; 
			}
			if (residual_num==3)
			{

				目标->width=wid*8;目标->height=hei * 8;目标->depth=64;
				目标->data=new float[wid * hei * 64 * 64 * sizeof(float)]; 
			}

			vl_nnconvt(源,目标,层,2,2, 0 ,1,0,1) ;//残差放大
							vl_nnrelu(目标, 0.2);//'leak',

							//char txt[255];
							//sprintf(txt, "残差放大%d", i);  
							//save_卷积层2jpg(目标,txt);
			std::swap(源,目标);

						
			//扩大第二卷积层内存
			delete []目标->data;  目标->data=NULL;  
			if (residual_num==1)
			{

				目标->width=wid*2;目标->height=hei * 2;目标->depth=64;
				目标->data=new float[wid * hei * 4 * 64 * sizeof(float)]; 
			}
			if (residual_num==2)
			{

				目标->width=wid*4;目标->height=hei * 4;目标->depth=64;
				目标->data=new float[wid * hei * 16 * 64 * sizeof(float)]; 
			}
			if (residual_num==3)
			{

				目标->width=wid*8;目标->height=hei * 8;目标->depth=64;
				目标->data=new float[wid * hei * 64 * 64 * sizeof(float)]; 
			}
	}

	if (strstr(层->类型, "图像放大层"))//strTong(net.layers(i).type,'dagnn.Conv')
	{
				cout<<"图像放大..."<<endl;

				//到这里可以删除
				delete []目标->data;  目标->data=NULL;  
				delete []源  ->data;  源  ->data=NULL;  

			weight=层->权重_数据;
			bias=层->偏移_数据;//无偏移
					upsample_num=upsample_num+1;
					// 图像放大参数是        'upsample', 2 ,'crop', [1 1 1 1],'numGroups', 1
					if (upsample_num==1) // 2倍放大图
					{
						//img_up1 = vl_nnconvt(imlow, weight, bias,'upsample', upsample ,'crop', crop,'numGroups', 1) ;
						vl_nnconvt(&im_b,&hR1,层,2,2, 1 ,1,1,1) ;//残差放大
		//save_卷积层2jpg(&im_b,"2倍放大前");
		//save_卷积层2jpg(&hR1,"2倍放大");
						卷积层相加(&residual1,&hR1);

						//hR1=img_up1+residual1; // 合成2倍重建图
							//save_卷积层2jpg(&hR1,"2倍重建图");

						delete []im_b.data;  im_b.data=NULL;  
						delete []residual1.data;  residual1.data=NULL;  

						//色彩放大(2倍)

						ResizeGrayscaleImage(&jpg,2)  ;

								//卷积层 U(wid,hei),V(wid,hei);
						U.height=V.height=hei*2;
						U.width =V.width =wid*2;
								U.data=new float[wid * hei *2*2* sizeof(float)]; 
								V.data=new float[wid * hei *2*2* sizeof(float)]; 



								//RGB转换为YUV
								RGB2YUV(&jpg,&U,&V);
								
						//合成色彩重建图
						IMAGE im_h(U.width,U.height);

							YUV2RGB(&hR1,&U,&V, &im_h);
						//保存图像
						saveimage(L"LapSRN 2倍 重建.jpg",	&im_h);
						//U,V暂时无用,先删除占用内存
									delete []U.data;  U.data=NULL;  
					}

					else
						if (upsample_num==2) // 4倍放大图
						{
							//img_up2 = vl_nnconvt(hR1, weight, bias,'upsample', upsample ,'crop', crop,'numGroups', 1) ;//
							vl_nnconvt(&hR1,&hR2,层,2,2, 1 ,1,1,1) ;//残差放大
					//save_卷积层2jpg(&hR2,"4倍放大");
							卷积层相加(&residual2,&hR2);
							//hR2=img_up2+residual2; // 4倍
					//save_卷积层2jpg(&hR2,"4倍重建图");

						delete []hR1.data;  hR1.data=NULL;  
						delete []residual2.data;  residual2.data=NULL;  

						//色彩放大(2倍)

						ResizeGrayscaleImage(&jpg,2)  ;//再2倍就是4倍

								//卷积层 U(wid,hei),V(wid,hei);
						U.height=V.height=hei*4;
						U.width =V.width =wid*4;
								U.data=new float[wid * hei *16* sizeof(float)]; 
								V.data=new float[wid * hei *16* sizeof(float)]; 



								//RGB转换为YUV
								RGB2YUV(&jpg,&U,&V);
								
						//合成色彩重建图
						IMAGE im_h(U.width,U.height);
							YUV2RGB(&hR2,&U,&V, &im_h);
						//保存图像
						saveimage(L"LapSRN 4倍 重建.jpg",	&im_h);
						//U,V暂时无用,先删除占用内存
									delete []U.data;  U.data=NULL;  
						}

						else
						if (upsample_num==3 )// 8倍放大图
						{
							//img_up3 = vl_nnconvt(hR2, weight, bias,'upsample', upsample ,'crop', crop,'numGroups', 1) ;//
							vl_nnconvt(&hR2,&hR3,层,2,2, 1 ,1,1,1) ;//残差放大
		//save_卷积层2jpg(&hR3,"8倍放大");
							卷积层相加(&residual3,&hR3);
							//hR3=img_up3+residual3; // 8倍
							//save_卷积层2jpg(&hR3,"8倍重建图");


						delete []hR2.data;  hR2.data=NULL;  
						delete []residual3.data;  residual3.data=NULL;  

						//色彩放大(2倍)

						ResizeGrayscaleImage(&jpg,2)  ;//再2倍就是8倍

								//卷积层 U(wid,hei),V(wid,hei);
						U.height=V.height=hei*8;
						U.width =V.width =wid*8;
								U.data=new float[wid * hei *64* sizeof(float)]; 
								V.data=new float[wid * hei *64* sizeof(float)]; 



								//RGB转换为YUV
								RGB2YUV(&jpg,&U,&V);
								
						//合成色彩重建图
						IMAGE im_h(U.width,U.height);
							YUV2RGB(&hR3,&U,&V, &im_h);
						//保存图像
						saveimage(L"LapSRN 8倍 重建.jpg",	&im_h);
						//U,V暂时无用,先删除占用内存
									delete []U.data;  U.data=NULL;  
						}//end
					//end
	                
	}
		//		disp('激励层');
		//		convfea = vl_nnrelu(convfea, 0.2);//'leak',

	    
	    
	    

	层++;

	}//end
}

这个可以参看前面的matlab的代码。

外框架完成。

猜你喜欢

转载自blog.csdn.net/juebai123/article/details/81501546