对给定灰度图像(以矩阵形式输入,整型数),按照给定的卷积核(以矩阵形式输入,浮点数)进行卷积,卷积核不需要翻转,输出图像卷积结果(以矩阵形式输出)。
要求:
-
对图像边界处的卷积运算,在卷积核超出图像边界的地方,图像内容按零处理;
-
卷积运算完需要四舍五入,按整型数输出结果,不用对数据范围进行处理,即输出数据可以大于255。
输入:
m n
u v (u、v一定是奇数)
m行n列的图像矩阵数据
u行v列的卷积核
输出:
m行n列的图像矩阵数据 (空格相隔)
#include <iostream>
#include <vector>
#include <iomanip>
#include <limits>
#include <math.h>
using namespace std;
void showImage(vector<vector<float>> &image_2d)
{
for (int i = 0; i < image_2d.size(); i++)
{
for (int j = 0; j < image_2d[0].size(); j++)
// 访问并且输出(左对齐)二维矩阵的各个元素
cout << setiosflags(ios::left) << setw(8) << +image_2d[i][j];
cout << " ";
cout << endl;
}
}
void showImagev2(vector<vector<int>> &image_2d)
{
for (int i = 0; i < image_2d.size(); i++)
{
for (int j = 0; j < image_2d[0].size(); j++)
{
cout << image_2d[i][j] << " ";
}
cout << endl;
}
}
vector<vector<int>> Conv_2d(
vector<vector<float>> &image, vector<vector<float>> &kernel,
int m, int n, int u_pad, int v_pad)
{
int image_row = image.size(); //获取图片矩阵的行数
int image_col = image[0].size(); //获取图片矩阵的列数
int kernel_row = kernel.size(); //获取卷积核矩阵的行数
int kernel_col = kernel[0].size(); // 获取卷积核矩阵的列数
// cout << "Image Size: " << image_row << "," << image_col << endl;
// cout << "Kernel Size: " << kernel_row << "," << kernel_col << endl;
vector<vector<int>> result; //定义二维vector用于接收卷积结果
int result_row = m; //计算结果矩阵的行数
int result_col = n; //计算结果矩阵的列数
// cout << "Result Size: " << result_row << "," << result_col << endl;
for (int i = 0; i < result_row; i++)
{
vector<int> row_result; //定义一维行矩阵以便于填入二维的result矩阵
for (int j = 0; j < result_col; j++)
{
float res = 0; //用于记录每一次卷积过程,图片与卷积核矩阵中数字乘积的结果
for (int k = 0; k < kernel_row; k++)
{
for (int m = 0; m < kernel_col; m++)
{
long int row = i + k; //防止溢出
long int col = j + m; //防止溢出
if (row >= image_row || col >= image_col)
{
cout << "-[INFO] Preparing i=" << i << " j=" << j << endl;
cout << "-[CONFIG] k=" << k << " m=" << m << endl;
cout << "-[ERROR] ERROR!" << endl;
cout << endl;
}
// cout << "-[COMPUTE] " << image[row][col] << "*" << kernel[k][m] << endl;
float mul = image[row][col] * kernel[k][m]; //调用私有函数进行一次乘法运算
res = res + mul; //调用私有函数计算每次卷积与卷积核计算的总和
// cout << "-[RESULT] res=" << res << endl;
}
}
row_result.push_back(round(res)); //将一次的卷积结果填入行矩阵中
}
result.push_back(row_result); //将某一行的卷积结果填入二维卷积结果矩阵中
}
return result;
}
int main()
{
int m, n, u, v;
float value;
cin >> m >> n >> u >> v;
// 填充大小
int u_pad, v_pad;
u_pad = (v - 1) / 2;
v_pad = (u - 1) / 2;
// 图像矩阵
vector<vector<float>> ConvolutionImage;
for (int p = 0; p < v_pad; p++)
{
vector<float> pad_vector;
pad_vector.assign(n + u + 1, 0);
ConvolutionImage.push_back(pad_vector);
}
for (int i = 0; i < m; i++)
{
vector<float> line_vector; //定义一维行矩阵以便于填入二维的result矩阵
for (int p1 = 0; p1 < u_pad; p1++)
{
line_vector.push_back(0.0);
}
for (int j = 0; j < n; j++)
{
cin >> value;
line_vector.push_back(value);
}
for (int p2 = 0; p2 < u_pad; p2++)
{
line_vector.push_back(0.0);
}
ConvolutionImage.push_back(line_vector);
}
for (int p = 0; p < v_pad; p++)
{
vector<float> pad_vector;
pad_vector.assign(n + u - 1, 0);
ConvolutionImage.push_back(pad_vector);
}
//卷积核矩阵
vector<vector<float>> ConvolutionKernel;
for (int i = 0; i < u; i++)
{
vector<float> line_vector; //定义一维行矩阵以便于填入二维的result矩阵
for (int j = 0; j < v; j++)
{
cin >> value;
line_vector.push_back(value);
}
ConvolutionKernel.push_back(line_vector);
}
// cout << "Image:" << endl;
// showImage(ConvolutionImage); //输出结果
// cout << "Conv:" << endl;
// showImage(ConvolutionKernel); //输出结果
//用于接收卷积结果
vector<vector<int>> ConvolutionResult;
ConvolutionResult = Conv_2d(
ConvolutionImage, ConvolutionKernel,
m, n, u_pad, v_pad);
// cout << "Result:" << endl;
showImagev2(ConvolutionResult); //输出结果
// system("pause");
return 0;
}
/*
5 5
3 3
9 0 6 2 2
9 7 6 2 10
3 5 9 9 7
7 5 8 0 5
2 9 6 5 5
0.0625 0.1250 0.0625
0.1250 0.2500 0.1250
0.0625 0.1250 0.0625
*/
/*
3 3
1 3
1 1 1
1 1 1
1 1 1
1 1 1
*/
/*
5 5
3 1
9 0 6 2 2
9 7 6 2 10
3 5 9 9 7
7 5 8 0 5
2 9 6 5 5
0.0625 0.1250 0.0625
*/
/*
5 5
3 5
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
*/