纯C++超分辨率重建SRCNN --改编--(五)卷积边界填充

前面的重建图边界有个方框,影响效果,这里改进一下,加上边界填充。

1。‘replicate’ 图像大小通过复制外边界的值来扩展

 2。'same'切去一部分,让输出与输入图像的大小相同

卷积实现上面的两个参数:

void 卷积(卷积矩阵*filter,卷积矩阵*arr, 卷积矩阵*res)
{
	int filterW=filter->width;
	int filterH=filter->height;
	int arrW=arr->width;
	int arrH=arr->height;

    float temp;  
	int tmpW=filterW*2+arrW;//扩展输入宽   + 2 个核宽
	int tmpH=filterH*2+arrH;//扩展输入高

	卷积矩阵  tmp(tmpW,tmpH);
	
	//边宽高(单)
	int w2=filterW;
	int h2=filterH;

	int i,j,m,n;

	//复制输入
	for (i=0; i<arrH; i++)  //输入
    {  
        for (j=0; j<arrW; j++)  
        {  
			tmp.data[(i+h2)*tmpW+(j+w2)] = arr->data[i*arrW+j];
		}
	}

	//对输入扩展边界  ‘replicate’	图像大小通过复制外边界的值来扩展
    for(i=0;i<h2;i++)//拓展上面h2 行
        for(j=0;j<tmpW;j++)  
             tmp.data[(i)*tmpW+(j)]   
                =tmp.data[(h2)*tmpW+(j)]   ;  
   
       
        for(i=0;i<h2;i++)//拓展下面h2行  
            for(j=0;j<tmpW;j++)  
                 tmp.data[(i+h2+arrH)*tmpW+(j)]   
                  =tmp.data[(h2+arrH)*tmpW+(j)]   ;  
   
        for(i=0;i<tmpH;i++)//拓展左边w2列  
            for(j=0;j<w2;j++)  
                 tmp.data[(i)*tmpW+(j)]   
                  =tmp.data[(i)*tmpW+(w2)]   ;  
   
        for(i=0;i<tmpH;i++)//拓展右边w2列  
            for(j=0;j<w2;j++)  
                 tmp.data[(i)*tmpW+(j+w2+arrW)]   
                  =tmp.data[(i)*tmpW+(w2+arrW)]   ;  

	//直接'same'切去一部分,让输出与输入图像的大小相同
	for (i=h2; i<h2+arrH; i++)  //输入
    {  
        for (j=w2; j<w2+arrW; j++)  
        {  
            temp = 0;  
            for ( m=0; m<filterH; m++)  //核
            {  
                for (n=0; n<filterW; n++)  
                {  
     //               if ((i-m)>=0 && (i-m)<tmpH && (j-n)>=0 && (j-n)<tmpW)  
     //               {  
                        temp += filter->data[m*filterW+n]*tmp.data[(i-m)*tmpW+(j-n)];  //积 和
					//}else
					//{
					//	
 				//		cout<<"出错了"<<endl;
     //              }  
                }  
            }  
            res->data[(i-h2)*arrW+(j-w2)] = temp; 
        }  
    }  

	
}

效果图:


基本上和Matlab结果持平了

另外 在 --qq_29058565的博客《图像缩放之双三次插值法》--是2倍放大的,改一下放在这里。

2 倍双三次放大放用到 3 倍模型不知会有怎样效果?

//双三次插值缩放图片

/*
我们要做的就是求出BiCubic函数中的参数x,从而获得上面所说的16个像素所对应的系数。在学习双线性插 
值法的时候,我们是把图像的行和列分开来理解的,那么在这里,我们也用这种方法描述如何求出a(i,j)对应 
的系数k_ij。假设行系数为k_i,列系数为k_j。我们以a00位置为例: 
首先,我们要求出当前像素与P点的位置,比如a00距离P(x+u,y+v)的距离为(1+u,1+v)。 
那么我们可以得到:k_i_0=W(1+u),k_j_0=W(1+v). 
同理我们可以得到所有行和列对应的系数:

k_i_0=W(1+u), k_i_1=W(u), k__i_2=W(1-u), k_i_3=W(2-u); 
k_j_0=W(1+v), k_j_1=W(v), k_j_2=W(1-v), k_j_3=W(2-v);

这样我们就分别得到了行和列方向上的系数。 
由k_i_j=k_i*k_j我们就可以得到每个像素a(i,j)对应的权值了。

最后通过求和公式可以得到目标图片B(X,Y)对应的像素值: 
pixelB(X,Y)=pixelA(0,0)*k_0_0+pixelA(0,1)*k_0_1+…+pixelA(3,3)*k_3_3; 
这里其实就是个求和公式,由于不知道怎么编辑公式,就这样表达了。
*/

/**********************10-9*******************************
功能:双三次插值缩放图片
数学原理:假设原图像A的大小为m*n,新图像B的大小为M*N
如果我们要求B(X,Y)处的像素值:
我们首先可以得到B(X,Y)在图像A中对应的位置(x,y)=(X*(m/M),Y*(N/n))
这个时候求得的x,y是小数值,我们可以通过这个小数值坐标找到距离最近的16个像素点,
利用所选择的基函数,求出对应的每个像素的权值,最终获得pixelB(X,Y)
**********************************************************/

//#include <opencv2\opencv.hpp>
//#include <iostream>
//#include <math.h>
//using namespace std;
//using namespace cv;

//BiCubic基函数
void getW_x(float w_x[4], float x);
void getW_y(float w_y[4], float y);

int 双三次2倍(IMAGE *imgs)
//int main(){
{
    //Mat image = imread("lena.jpg");//源图像
	float image_rows = imgs->getwidth();
	float image_cols = imgs->getheight();

    float Row_B = image_rows*2;
    float Col_B = image_cols*2;

	卷积矩阵 image= im2卷积矩阵(imgs);
	卷积矩阵 biggerImage(Row_B, Col_B);

	Row_B=biggerImage.width;
	Col_B=biggerImage.height ;

   // Mat biggerImage(Row_B, Col_B, CV_8UC3);

    for (int i = 2; i < Row_B-4; i++){
        for (int j = 2; j < Col_B-4; j++){
            float x = i*(image_rows / Row_B);//放大后的图像的像素位置相对于源图像的位置
            float y = j*(image_cols / Col_B);

            /*if (int(x) > 0 && int(x) < image_rows - 2 && int(y)>0 && int(y) < image_cols - 2){*/
                float w_x[4], w_y[4];//行列方向的加权系数
                getW_x(w_x, x);
                getW_y(w_y, y);

                //Vec3f temp = { 0, 0, 0 };
				float temp = 0;
                for (int s = 0; s <= 3; s++){
                    for (int t = 0; t <= 3; t++){
                        //temp = temp + (Vec3f)(image.at<Vec3b>(int(x) + s - 1, int(y) + t - 1))*w_x[s] * w_y[t];
                        temp = temp + image.data[(int(x) + s - 1)*image_rows+( int(y) + t - 1)]*w_x[s] * w_y[t];
                    }
                }

                //biggerImage.at<Vec3b>(i, j) = (Vec3b)temp;
                biggerImage.data[i*Row_B+ j] = temp;
            }
        }

    //imshow("image", image);
    //imshow("biggerImage", biggerImage);
    //waitKey(0);
	IMAGE tt= 卷积矩阵2im(&biggerImage);
	*imgs=tt;
	return 0;
}
/*计算系数*/
void getW_x(float w_x[4],float x){
	float a = -0.5;
    int X = (int)x;//取整数部分
    float stemp_x[4];
    stemp_x[0] = 1 + (x - X);
    stemp_x[1] = x - X;
    stemp_x[2] = 1 - (x - X);
    stemp_x[3] = 2 - (x - X);

    w_x[0] = a*abs(stemp_x[0] * stemp_x[0] * stemp_x[0]) - 5 * a*stemp_x[0] * stemp_x[0] + 8 * a*abs(stemp_x[0]) - 4 * a;
    w_x[1] = (a + 2)*abs(stemp_x[1] * stemp_x[1] * stemp_x[1]) - (a + 3)*stemp_x[1] * stemp_x[1] + 1;
    w_x[2] = (a + 2)*abs(stemp_x[2] * stemp_x[2] * stemp_x[2]) - (a + 3)*stemp_x[2] * stemp_x[2] + 1;
    w_x[3] = a*abs(stemp_x[3] * stemp_x[3] * stemp_x[3]) - 5 * a*stemp_x[3] * stemp_x[3] + 8 * a*abs(stemp_x[3]) - 4 * a;
}
void getW_y(float w_y[4], float y){
	float a = -0.5;
    int Y = (int)y;
    float stemp_y[4];
    stemp_y[0] = 1.0 + (y - Y);
    stemp_y[1] = y - Y;
    stemp_y[2] = 1 - (y - Y);
    stemp_y[3] = 2 - (y - Y);

    w_y[0] = a*abs(stemp_y[0] * stemp_y[0] * stemp_y[0]) - 5 * a*stemp_y[0] * stemp_y[0] + 8 * a*abs(stemp_y[0]) - 4 * a;
    w_y[1] = (a + 2)*abs(stemp_y[1] * stemp_y[1] * stemp_y[1]) - (a + 3)*stemp_y[1] * stemp_y[1] + 1;
    w_y[2] = (a + 2)*abs(stemp_y[2] * stemp_y[2] * stemp_y[2]) - (a + 3)*stemp_y[2] * stemp_y[2] + 1;
    w_y[3] = a*abs(stemp_y[3] * stemp_y[3] * stemp_y[3]) - 5 * a*stemp_y[3] * stemp_y[3] + 8 * a*abs(stemp_y[3]) - 4 * a;
}

效果图:

    

啊,咋会这样呢?放大就有黑块,可能是我哪里翻译错了吧。

先这样吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值