使用GPU(OpenGL)来运行网络应该会快一点吧。
下面以《glsl着色器实现多重纹理与帧缓冲对象(fbo)》一文为模板生成一个卷积函数。用于超分SRCNN 中的卷积。
接口:
//初始化
// main的参数 和 层高,宽
void conv_init(int argc, char* argv[],int h,int w);
//卷积
//核数据,核宽,输入数据,输出数据
void conv_GLSL(float* kernel,int kw,float *inData, float * &outData);
拿这个去替换《纯C++超分辨率重建SRCNN》的卷积函数
下面说一下与《glsl着色器实现多重纹理与帧缓冲对象(fbo)》一文不同之处
片元着色器 卷积:
//片元着色器
const char *fShader = {
"#version 400 compatibility \n"
//层数据
"uniform sampler2DRect LenaTexture; \n"
//核宽
"uniform int kw; \n"
//9x9的核大小 , 5x5则只使用前面部分
"uniform float kernel[81]; \n"
"void main()"
"{"
" vec2 pos = gl_TexCoord[0].st;\n"//坐标
" vec4 fSum = vec4(0.0,0.0,0.0,0.0);\n"//卷积值
" ivec2 vecSize = textureSize(LenaTexture);\n"//层数据宽高
" int index = 0;"
" int coreSize2=kw/2;"//半核宽
" for (float i = pos.x - coreSize2; i < pos.x + coreSize2 + 1.0; i += 1.0)" //对准核心
" for (float j = pos.y - coreSize2; j < pos.y + coreSize2 + 1.0; j += 1.0)"
" {"
" if (i >=0 && j >= 0 && i < vecSize.x && j < vecSize.y)"//相当于边界以 0 填充
" {"
" vec4 currentColor = texture2DRect(LenaTexture,vec2(i,j));\n"
" fSum += currentColor*kernel[index];\n" //积和
" }"
" index++;\n"//遍历核
" }"
" gl_FragColor = fSum;\n"
"}"
};
纹理格式 把GL_RGBA 替换为 GL_R32F 和 GL_RED,这里只要单色就可以了。比如:
//glTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, imgWidth, imgHeight, 0,GL_RGBA,GL_FLOAT,0 );
glTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, GL_R32F, imgWidth, imgHeight, 0,GL_RED,GL_FLOAT,0 );
初始化
// main的参数 和 层高,宽
void conv_init(int argc, char* argv[],int h,int w)
{
imgWidth=w;imgHeight=h;
//printf("输入宽,高: %d,%d\n",w,h);
glutInit( &argc, argv );
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize ( imgWidth, imgHeight);
glutInitWindowPosition( 100, 100 );
glutCreateWindow(" GLSL卷积 ");
glewInit();
initFBO2(imgWidth, imgHeight );
int dataSize = imgHeight * imgWidth ;
outPutFb = new GLfloat[dataSize]; //输出纹理缓冲 [imgHeight * imgWidth]
memset(outPutFb,0,dataSize*sizeof(float));
progHandle = initShaders(vShader, fShader);
}
这 里是一个固定的宽高,所以要放在双三次放大的后面。
卷积
//核数据,核宽,输入数据,输出数据
void conv_GLSL(float* kernel,int kw,float *inData, float * &outData)
{
//9x9,5x5核都放到kernel81
init(inData);//数据生成纹理
float kernel81[81]={0.0f};
memcpy(kernel81, kernel, kw*kw*sizeof(float));
if ( progHandle <= 0 )
printf("Failed to run shader.\n");
else{
//设置初始一致变量
glUniform1i( glGetUniformLocation( progHandle, "LenaTexture" ), 0 ); //0 是纹理的句柄//这个就是层数据(卷积对象)
glUniform1i( glGetUniformLocation( progHandle, "kw" ), kw ); //核宽
glUniform1fv( glGetUniformLocation( progHandle, "kernel"),81,kernel81);//核数据
}
display();//启用卷积计算
readFromTexture( outPutFb );//读回卷积结果
outData=outPutFb;
}
成2 个cpp文件,原来的 SRCNN.cpp 和 这个 GLSL.cpp。
SRCNN.cpp中只修改SRCNN函数
IMAGE SRCNN(int argc, char* argv[],IMAGE *jpg,int up_scale)
{
// 双三次插值
// 先将低分辨率图像使用双三次插值放大至目标尺寸(如放大至2倍、3倍、4倍)
//im_b = imresize(im_gnd, up_scale, 'bicubic');
IMAGE im_h=*jpg;
//双三次放大
ResizeGrayscaleImage(&im_h,up_scale ) ;
//saveimage("放大.jpg", &im_h);
//显示
putimage(im_h.getwidth(), 0, &im_h);
SRCNN模型 sr;
// 加载 CNN 模型参数
loadModel(&sr);
int wid=im_h.getwidth();
int hei=im_h.getheight();
//
conv_init(argc, argv,hei, wid);
//图像转化为卷积矩阵
//彩色
卷积矩阵 im_b(wid,hei);//即Y通道
卷积矩阵 U(wid,hei),V(wid,hei);
//RGB转换为YUV
RGB2YUV(&im_h,&im_b,&U,&V);
//用于保存调试图像的变量
IMAGE im_tt;
//char txt[256];
// 第一层卷积:卷积核尺寸9×9(f1×f1),卷积核数目64(n1),输出64张特征图;
cout<<"第一层卷积..."<<endl;
//conv1_data = zeros(hei, wid, conv1_filters);
vector <卷积矩阵> conv1_data;//[64]结果
clock_t start_t, end_t;//计算时间
double total_t;