一、手写Auto_Padding
1.代码
// 判断x是否在区间[a,b]内。
bool IsInRange(int x, int a, int b)
{
return a <= x && x <= b;
}
// 判断输入字符串是否为纯数字
bool IsAllDigits(const string& str)
{
return all_of(str.begin(), str.end(), isdigit);
}
/*
* 自动填充函数
* \param img 输入图片指针
* \param rows 输入图片高
* \param cols 输入图片宽
* \param kernel_size 卷积核大小
* \param mode 填充方式:0-255的正整数、replicate复制填充、reflect镜像填充
* \return unsigned char*型填充后图像的指针
*/
void* AutoPadding(unsigned char* img, int rows, int cols, int channels, int kernel_size, string mode, unsigned char* padded)
{
if (kernel_size % 2 == 0)
throw "Error: Kernel size must be an odd number.";
else
{
int pad_size = (kernel_size - 1) / 2;
int padded_rows = rows + pad_size * 2;
int padded_cols = cols + pad_size * 2;
if (IsAllDigits(mode)) // 常数填充
{
int padding_value = stoi(mode);
if (IsInRange(padding_value, 0, 255))
{
for (int y = 0; y < padded_rows; ++y)
{
for (int x = 0; x < padded_cols; ++x)
{
for (int z = 0; z < channels; ++z)
{
if (IsInRange(y - pad_size, 0, rows - 1) && IsInRange(x - pad_size, 0, cols - 1))
padded[y * padded_cols * channels + x * channels + z] = img[(y - pad_size) * cols * channels + (x - pad_size) * channels + z]; // 内部填充
else
padded[y * padded_cols * channels + x * channels + z] = padding_value; // 边缘填充
}
}
}
}
else
throw "Error: Padding value is not in range.";
}
else if (mode == "replicate") // 复制填充
{
for (int y = 0; y < rows; ++y)
{
for (int x = 0; x < cols; ++x)
{
for (int z = 0; z < channels; ++z)
{
padded[(y + pad_size) * padded_cols * channels + (x + pad_size) * channels + z] = img[y * cols * channels + x * channels + z]; // 内部填充
}
}
}
for (int y = 0; y < pad_size; ++y)
{
for (int x = 0; x < padded_cols; ++x)
{
for (int z = 0; z < channels; ++z)
{
if (not IsInRange(x, pad_size, padded_cols - pad_size - 1)) // 四顶点矩阵填充
{
if (pad_size - x >= 0)
{
padded[y * padded_cols * channels + x * channels + z] = img[0];
padded[(y + padded_rows - pad_size) * padded_cols * channels + x * channels + z] = img[(rows - 1) * cols * channels + z];
}
else
{
padded[y * padded_cols * channels + x * channels + z] = img[(cols - 1) * channels + z];
padded[(y + padded_rows - pad_size) * padded_cols * channels + x * channels + z] = img[(rows - 1) * cols * channels + (cols - 1) * channels + z];
}
}
else // 上下边界填充
{
padded[y * padded_cols * channels + x * channels + z] = img[(x - pad_size) * channels + z];
padded[(y + padded_rows - pad_size) * padded_cols * channels + x * channels + z] = img[(rows - 1) * cols * channels + (x - pad_size) * channels + z];
}
}
}
for (int x = pad_size; x < padded_rows - pad_size; ++x) // 左右边界填充
{
for (int z = 0; z < channels; ++z)
{
padded[x * padded_cols * channels + y * channels + z] = img[(x - pad_size) * cols * channels + z];
padded[x * padded_cols * channels + (y + padded_cols - pad_size) * channels + z] = img[(x - pad_size) * cols * channels + (cols - 1) * channels + z];
}
}
}
}
else if (mode == "reflect")
{
if (pad_size <= rows - 1 && pad_size <= cols - 1)
{
int padded_rows = rows + pad_size * 2;
int padded_cols = cols + pad_size * 2;
for (int y = 0; y < rows; ++y)
{
for (int x = 0; x < cols; ++x)
{
for (int z = 0; z < channels; ++z)
padded[(y + pad_size) * padded_cols * channels + (x + pad_size) * channels + z] = img[y * cols * channels + x * channels + z]; // 内部填充
}
}
for (int i = 0; i < cols; ++i)
{
for (int k = 1; k <= pad_size; ++k) // 上下边缘镜像
{
for (int z = 0; z < channels; ++z)
{
padded[(pad_size - k) * padded_cols * channels + (i + pad_size) * channels + z] = img[k * cols * channels + i * channels + z];
padded[(pad_size + rows - 1 + k) * padded_cols * channels + (i + pad_size) * channels + z] = img[(rows - 1 - k) * cols * channels + i * channels + z];
}
}
}
for (int i = 0; i < padded_rows; ++i)
{
for (int k = 1; k <= pad_size; ++k) // 左右边缘镜像
{
for (int z = 0; z < channels; ++z)
{
padded[i * padded_cols * channels + (pad_size - k) * channels + z] = padded[i * padded_cols * channels + (pad_size + k) * channels + z];
padded[i * padded_cols * channels + (pad_size + cols - 1 + k) * channels + z] = padded[i * padded_cols * channels + (pad_size + cols - 1 - k) * channels + z];
}
}
}
}
else
throw "Error: Kernel size is too big.";
}
else
throw "Error: This mode is not defined.";
}
}
2.测试
void PaddingMatrixTest(int rows , int cols, int kernel_size, string mode)
{
Mat matrix = Mat::zeros(rows, cols, CV_8UC1);
randu(matrix, Scalar(10), Scalar(99));
cout << matrix << endl;
Mat test(matrix.rows + (kernel_size - 1), matrix.cols + (kernel_size - 1), CV_8UC1);
try
{
AutoPadding(matrix.data, matrix.rows, matrix.cols, matrix.channels(), kernel_size, mode, test.data);
}
catch (const char* error_msg)
{
cout << error_msg << endl;
}
cout << test << endl;
}
void PaddingImageTest(string path, string mode)
{
Mat img = imread(path);
imshow("原图", img);
int kernel_size = min(int(img.rows / 2), int(img.cols / 2));
Mat test(img.rows + (kernel_size - 1), img.cols + (kernel_size - 1), CV_8UC3);
try
{
AutoPadding(img.data, img.rows, img.cols, img.channels(), kernel_size, mode, test.data);
}
catch (const char* error_msg)
{
cout << error_msg << endl;
}
imshow("填充", test);
waitKey(0);
}
int main()
{
PaddingMatrixTest(5, 5, 5, "replicate");
PaddingImageTest("test.png", "replicate");
return 0;
}
二、滤波函数
1.代码
/*
* 滤波
* \param img 输入图片指针
* \param rows 输入图片高
* \param cols 输入图片宽
* \param channels 输入图像通道数
* \param kernel_size 卷积核大小
* \param padding_mode 填充方式:0-255的正整数、replicate复制填充、reflect镜像填充
* \param blur_mode 滤波方式:Median、Mean
* \param blured 输出图片指针
*/
void Blur(unsigned char* img, int rows, int cols, int channels, int kernel_size, string padding_mode, string blur_mode, unsigned char* blured)
{
int pad_size = (kernel_size - 1) / 2;
int padded_rows = rows + pad_size * 2;
int padded_cols = cols + pad_size * 2;
unsigned char* padded = new unsigned char[padded_rows * padded_cols * channels];
AutoPadding(img, rows, cols, channels, kernel_size, padding_mode, padded);
vector<unsigned char> temp(kernel_size * kernel_size);
for (int y = pad_size; y < padded_rows - pad_size; ++y)
{
for (int x = pad_size; x < padded_cols - pad_size; ++x)
{
for (int z = 0; z < channels; ++z)
{
int index = 0;
for (int j = y - pad_size; j <= y + pad_size; ++j)
{
for (int i = x - pad_size; i <= x + pad_size; ++i)
temp[index++] = padded[j * padded_cols * channels + i * channels + z];
}
if (blur_mode == "Median")
{
sort(temp.begin(), temp.end());
blured[(y - pad_size) * cols * channels + (x - pad_size) * channels + z] = temp[(index - 1) / 2];
}
else if (blur_mode == "Mean")
{
int sum = accumulate(temp.begin(), temp.end(), 0);
blured[(y - pad_size) * cols * channels + (x - pad_size) * channels + z] = sum / index;
}
else
throw "Error: This mode is not defined.";
//cout << z << "\n";
}
}
}
delete[] padded;
}
2.测试
void BlurTest(string path, int kernel_size, string padding_mode, string mode)
{
Mat img = imread(path);
imshow("原图", img);
Mat test(img.rows, img.cols, CV_8UC3);
try
{
Blur(img.data, img.rows, img.cols, img.channels(), kernel_size, padding_mode, mode, test.data);
}
catch (const char* error_msg)
{
cout << error_msg << endl;
}
imshow("滤波", test);
waitKey(0);
}
int main()
{
Mat img = imread("test.png");
BlurTest("test.png", 5, "reflect", "Mean");
return 0;
}