纯C++超分辨率重建SRCNN --改编--(五)卷积边界填充
程序员文章站
2023-12-30 19:24:46
...
前面的重建图边界有个方框,影响效果,这里改进一下,加上边界填充。
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;
}
效果图:
啊,咋会这样呢?放大就有黑块,可能是我哪里翻译错了吧。
先这样吧。