欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-03-09 13:06:31
...

由于网络上找不到多通道多核的转置卷积,那么只能从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的代码。

外框架完成。