一、算法原理
滤波器从效果分:平滑和锐化。
二、核函数设计
1. sobel 梯度算子
算法实现:
Mat sobel_filter(Mat img, bool horizontal) { int height = img.rows; int width = img.cols; cv::Mat out = cv::Mat::zeros(height, width, CV_8UC1); double kernel[kernel_size][kernel_size] = { 1,2,1,0,0,0,-1,-2,-1 }; if (horizontal) { kernel[0][1] = 0; kernel[2][1] = 0; kernel[1][0] = 2; kernel[1][2] = -2; } int pad = floor(kernel_size / 2); double v = 0; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { v = 0; for (int dy = -pad; dy < pad + 1; dy++) { for (int dx = -pad; dx < pad + 1; dx++) { if ((y + dy) >= 0 && (x + dx) >= 0 && (y + dy) < height && (x + dx) < width) v += img.at<uchar>(y + dy, x + dx) * kernel[dy + pad][dy + pad]; } } v = fmax(v, 0); v = fmin(v, 255); out.at<uchar>(y, x) = (uchar)v; } } return out; }
2.prewitt 算子
算法实现:
Mat prewitt_filter(const Mat& img, bool horizontal) { int height = img.rows; int width = img.cols; // prepare output cv::Mat out = cv::Mat::zeros(height, width, CV_8UC1); double kernel[3][3] = { -1,-1,-1,0,0,0,1,1,1 }; if (horizontal) { kernel[0][1] = 0; kernel[0][2] = 1; kernel[1][0] = -1; kernel[1][2] = 1; kernel[2][0] = -1; kernel[2][1] = 0; } int pad = floor(3 / 2); double v = 0; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { v = 0; for (int dy = -pad; dy < pad + 1; dy++) { for (int dx = -pad; dx < pad + 1; dx++) { if ((y + dy) >= 0 && (x + dx) >= 0 && (y + dy) < height && (x + dx) < width) { v += img.at<uchar>(y + dy, x + dx) * kernel[dy + pad][dx + pad]; } } } v = fmax(v, 0); v = fmin(v, 255); out.at<uchar>(y, x) = (uchar)v; } } return out; }
3.Laplace 算子
算法实现
Mat laplascian_filter(Mat& img) { int height = img.rows; int width = img.cols; // prepare output cv::Mat out = cv::Mat::zeros(height, width, CV_8UC1); double kernel[3][3] = { 0,1,0,1,-4,1,0,1,0 }; int pad = floor(3 / 2); double v = 0; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { v = 0; for (int dy = -pad; dy < pad + 1; dy++) { for (int dx = -pad; dx < pad + 1; dx++) { if ((y + dy) >= 0 && (x + dx) >= 0 && (y + dy) < height && (x + dx) < width) { v += img.at<uchar>(y + dy, x + dx) * kernel[dy + pad][dx + pad]; } } } v = fmax(v, 0); v = fmin(v, 255); out.at<uchar>(y, x) = (uchar)v; } } return out; }
4. robert 算子
5.差分滤波器
算法实现
Mat diff_filter(const Mat& img, bool horizontal) { int height = img.rows; int width = img.cols; cv::Mat out = cv::Mat::zeros(height, width, CV_8UC1); //纵向 double kernel[kernel_size][kernel_size] = { {0, -1, 0}, {0, 1, 0}, {0, 0, 0} }; //横向 if (horizontal) { kernel[0][1] = 0; kernel[1][0] = -1; } int pad = floor(kernel_size / 2); double v = 0; // filtering for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { v = 0; for (int dy = -pad; dy < pad + 1; dy++) { for (int dx = -pad; dx < pad + 1; dx++) { if (((y + dy) >= 0) && ((x + dx) >= 0) && ((y + dy) < height) && ((x + dx) < width)) { v += img.at<uchar>(y + dy, x + dx) * kernel[dy + pad][dx + pad]; } } } v = fmax(v, 0); v = fmin(v, 255); out.at<uchar>(y, x) = (uchar)v; } } return out; }
6.Emboss 滤波
算法实现
Mat emboss_filter(Mat& img) { int height = img.rows; int width = img.cols; // prepare output cv::Mat out = cv::Mat::zeros(height, width, CV_8UC1); double kernel[3][3] = { -2,-1,0,-1,1,1,0,1,2}; int pad = floor(3 / 2); double v = 0; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { v = 0; for (int dy = -pad; dy < pad + 1; dy++) { for (int dx = -pad; dx < pad + 1; dx++) { if ((y + dy) >= 0 && (x + dx) >= 0 && (y + dy) < height && (x + dx) < width) { v += img.at<uchar>(y + dy, x + dx) * kernel[dy + pad][dx + pad]; } } } v = fmax(v, 0); v = fmin(v, 255); out.at<uchar>(y, x) = (uchar)v; } } return out; }
7. loG滤波
算法实现
Mat log_filter(Mat& img,float sigma) { int height = img.rows; int width = img.cols; // prepare output double kernel[kernel_size][kernel_size] = { 0}; cv::Mat out = cv::Mat::zeros(height, width, CV_8UC1); int pad = floor(kernel_size / 2); double kernel_sum = 0; double y = 0; double x = 0; for (int i = 0; i < kernel_size; i++) { for (int j = 0; j < kernel_size; j++) { y = i - pad; x = j - pad; kernel[i][j] = (y*y + x * x - sigma * sigma) / (2 * M_pi*pow(sigma, 6))*exp(-(y*y + x * x) / (2 * sigma*sigma)); kernel_sum += kernel[i][j]; cout << kernel[i][j] << " "; } cout << endl; }
//做了归一化处理,此处如果没有,得到结果不尽人意,甚至出现全黑,或者全白 for (int y = 0; y < kernel_size; y++) { for (int x = 0; x < kernel_size; x++) { kernel[y][x] /= kernel_sum; cout << kernel[y][x] << " "; } cout << endl; } double v = 0; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { v = 0; for (int dy = -pad; dy < pad + 1; dy++) { for (int dx = -pad; dx < pad + 1; dx++) { if ((y + dy) >= 0 && (x + dx) >= 0 && (y + dy) < height && (x + dx) < width) { v += img.at<uchar>(y + dy, x + dx) * kernel[dy + pad][dx + pad]; } } } v = fmax(v, 0); v = fmin(v, 255); out.at<uchar>(y, x) = (uchar)v; } } return out; }