使用常见的边缘检测滤波器(3 × 3 3\times3 3 ×3)大小,对 fate.jpeg
进行图像处理。
边缘检测用于检测图像中的线。通常这样提取图像中的信息的操作被称为 特征提取。
MAX-MIN滤波器是一种常见的 边缘检测滤波器,其使用网格内像素的最大值和最小值的差值对网格内像素重新赋值。
边缘检测通常在 灰度图像上进行。
MAX-MIN滤波器:
cv::Mat max_min_filter(cv::Mat img, int kernel_size)
{
int row = img.rows;
int col = img.cols;
int channel = img.channels();
cv::Mat new_image = cv::Mat::zeros(row, col, CV_8UC1);
int pad = floor(kernel_size / 2);
double max_val = 0, min_val = 10000, val = 0;
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
max_val = 0;
min_val = 10000;
for (int di = -pad; di < pad + 1; di++) {
for (int dj = -pad; dj < pad + 1; dj++) {
if (((di + i) >= 0) && ((di + i) < row) && ((dj + j) >= 0) && ((dj + j) < col)) {
val = img.at<uchar>(i + di, j + dj);
}
if (val > max_val) {
max_val = val;
}
if (val < min_val) {
min_val = val;
}
}
}
new_image.at<uchar>(i, j) = (uchar)(max_val - min_val);
}
}
return new_image;
}
输入图像 (fate.jpeg)MAX-MIN滤波图像 (fate_max_min.jpeg)
差分滤波器对图像亮度急剧变化的边缘有提取效果,可以获得邻接像素的差值。
纵向:
K = [ 0 − 1 0 0 1 0 0 0 0 ] K=\left[ \begin{matrix} 0&-1&0\ 0&1&0\ 0&0&0 \end{matrix} \right]K =0 0 0 −1 1 0 0 0 0
横向:
K = [ 0 0 0 − 1 1 0 0 0 0 ] K=\left[ \begin{matrix} 0&0&0\ -1&1&0\ 0&0&0 \end{matrix} \right]K =0 −1 0 0 1 0 0 0 0
cv::Mat diff_filter(cv::Mat img, int kernel_size, bool horizontal)
{
int row = img.rows;
int col = img.cols;
cv::Mat new_image = cv::Mat::zeros(row, col, CV_8UC1);
int pad = floor(kernel_size / 2);
int kernel[3][3] = {{0, -1, 0}, {0, 1, 0}, {0, 0, 0}};
if (horizontal)
{
kernel[0][1] = 0;
kernel[1][0] = -1;
}
double val = 0;
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
val = 0;
for (int di = -pad; di < pad + 1; di++)
{
for (int dj = -pad; dj < pad + 1; dj++)
{
if (((di + i) >= 0) && ((di + i) < row) && ((dj + j) >= 0) && ((dj + j) < col))
{
val += img.at<uchar>(i + di, j + dj) * kernel[di + pad][dj + pad];
}
}
}
val = fmax(val, 0);
val = fmin(val, 255);
new_image.at<uchar>(i, j) = (uchar)val;
}
}
return new_image;
}
输入图像 (fate.jpeg)纵向滤波图像 (fate_diff_v.jpeg)横向滤波图像 (fate_diff_h.jpeg)
Sobel滤波器可以提取特定方向(纵向或横向)的边缘,滤波器按下式定义:
纵向:
K = [ 1 2 1 0 0 0 − 1 − 2 − 1 ] K=\left[ \begin{matrix} 1&2&1\ 0&0&0\ -1&-2&-1 \end{matrix} \right]K =1 0 −1 2 0 −2 1 0 −1
横向:
K = [ 1 0 − 1 2 0 − 2 1 0 − 1 ] K=\left[ \begin{matrix} 1&0&-1\ 2&0&-2\ 1&0&-1 \end{matrix} \right]K =1 2 1 0 0 0 −1 −2 −1
cv::Mat sobel_filter(cv::Mat img, int kernel_size, bool horizontal)
{
int row = img.rows;
int col = img.cols;
cv::Mat new_image = cv::Mat::zeros(row, col, CV_8UC1);
int pad = floor(kernel_size / 2);
int kernel[3][3] = {{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;
}
double val = 0;
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
val = 0;
for (int di = -pad; di < pad + 1; di++)
{
for (int dj = -pad; dj < pad + 1; dj++)
{
if (((di + i) >= 0) && ((di + i) < row) && ((dj + j) >= 0) && ((dj + j) < col))
{
val += img.at<uchar>(i + di, j + dj) * kernel[di + pad][dj + pad];
}
}
}
val = fmax(val, 0);
val = fmin(val, 255);
new_image.at<uchar>(i, j) = (uchar)val;
}
}
return new_image;
}
输入图像 (fate.jpeg)纵向滤波图像 (fate_sobel_v.jpeg)横向滤波图像 (fate_sobel_h.jpeg)
Prewitt滤波器是用于边缘检测的一种滤波器,使用下式定义:
纵向:
K = [ − 1 − 1 − 1 0 0 0 1 1 1 ] K=\left[ \begin{matrix} -1&-1&-1\ 0&0&0\ 1&1&1 \end{matrix} \right]K =−1 0 1 −1 0 1 −1 0 1
横向:
K = [ − 1 0 − 1 − 1 0 1 − 1 0 1 ] K=\left[ \begin{matrix} -1&0&-1\ -1&0&1\ -1&0&1 \end{matrix} \right]K =−1 −1 −1 0 0 0 −1 1 1
cv::Mat prewitt_filter(cv::Mat img, int kernel_size, bool horizontal)
{
int row = img.rows;
int col = img.cols;
cv::Mat new_image = cv::Mat::zeros(row, col, CV_8UC1);
int pad = floor(kernel_size / 2);
int 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;
}
double val = 0;
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
val = 0;
for (int di = -pad; di < pad + 1; di++)
{
for (int dj = -pad; dj < pad + 1; dj++)
{
if (((di + i) >= 0) && ((di + i) < row) && ((dj + j) >= 0) && ((dj + j) < col))
{
val += img.at<uchar>(i + di, j + dj) * kernel[di + pad][dj + pad];
}
}
}
val = fmax(val, 0);
val = fmin(val, 255);
new_image.at<uchar>(i, j) = (uchar)val;
}
}
return new_image;
}
输入图像 (fate.jpeg)纵向滤波图像 (fate_prewitt_v.jpeg)横向滤波图像 (fate_prewitt_h.jpeg)
Laplacian滤波器是对图像亮度进行二次微分从而检测边缘的滤波器。由于数字图像是离散的,x x x方向和y y y方向的一次微分分别按照以下式子计算:
I x ( x , y ) = I ( x + 1 , y ) − I ( x , y ) ( x + 1 ) − x = I ( x + 1 , y ) − I ( x , y ) I y ( x , y ) = I ( x , y + 1 ) − I ( x , y ) ( y + 1 ) − y = I ( x , y + 1 ) − I ( x , y ) I_x(x,y)=\frac{I(x+1,y)-I(x,y)}{(x+1)-x}=I(x+1,y)-I(x,y)\ I_y(x,y) =\frac{I(x, y+1) – I(x,y)}{(y+1)-y}= I(x, y+1) – I(x,y)I x (x ,y )=(x +1 )−x I (x +1 ,y )−I (x ,y )=I (x +1 ,y )−I (x ,y )I y (x ,y )=(y +1 )−y I (x ,y +1 )−I (x ,y )=I (x ,y +1 )−I (x ,y )
因此二次微分按照以下式子计算:
I x x ( x , y ) = I x ( x , y ) − I x ( x − 1 , y ) x − ( x − 1 ) = I x ( x , y ) − I x ( x − 1 , y ) = [ I ( x + 1 , y ) − I ( x , y ) ] − [ I ( x , y ) − I ( x − 1 , y ) ] = I ( x + 1 , y ) − 2 I ( x , y ) + I ( x − 1 , y ) I_{xx}(x,y) =\frac{I_x(x,y) – I_x(x-1,y)}{x – (x-1)} =I_x(x,y) – I_x(x-1,y)\ =[I(x+1, y) – I(x,y)] – [I(x, y) – I(x-1,y)]= I(x+1,y) – 2\ I(x,y) + I(x-1,y)I xx (x ,y )=x −(x −1 )I x (x ,y )−I x (x −1 ,y )=I x (x ,y )−I x (x −1 ,y )=[I (x +1 ,y )−I (x ,y )]−[I (x ,y )−I (x −1 ,y )]=I (x +1 ,y )−2 I (x ,y )+I (x −1 ,y )
同理:
I y y ( x , y ) = I ( x , y + 1 ) − 2 I ( x , y ) + I ( x , y − 1 ) I_{yy}(x,y)=I(x,y+1)-2\ I(x,y)+I(x,y-1)I yy (x ,y )=I (x ,y +1 )−2 I (x ,y )+I (x ,y −1 )
特此,Laplacian 表达式如下:
∇ 2 I ( x , y ) = I x x ( x , y ) + I y y ( x , y ) = I ( x − 1 , y ) + I ( x , y − 1 ) − 4 ∗ I ( x , y ) + I ( x + 1 , y ) + I ( x , y + 1 ) \nabla^2\ I(x,y)=I_{xx}(x,y)+I_{yy}(x,y)=I(x-1,y) + I(x,y-1) – 4 * I(x,y) + I(x+1,y) + I(x,y+1)∇2 I (x ,y )=I xx (x ,y )+I yy (x ,y )=I (x −1 ,y )+I (x ,y −1 )−4 ∗I (x ,y )+I (x +1 ,y )+I (x ,y +1 )
如果把这个式子表示为卷积核是下面这样的:
K = [ 0 1 0 1 − 4 1 0 1 0 ] K= \left[ \begin{matrix} 0&1&0\ 1&-4&1\ 0&1&0 \end{matrix} \right]K =0 1 0 1 −4 1 0 1 0
#include
#include
#include
cv::Mat BGR2GRAY(cv::Mat img)
{
int row = img.cols;
int col = img.rows;
cv::Mat new_image = cv::Mat::zeros(row, col, CV_8UC1);
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
new_image.at<uchar>(i, j) = 0.2126 * (float)img.at<cv::Vec3b>(i, j)[2] \
+ 0.7152 * (float)img.at<cv::Vec3b>(i, j)[1] \
+ 0.0722 * (float)img.at<cv::Vec3b>(i, j)[0];
}
}
return new_image;
}
cv::Mat laplacian_filter(cv::Mat img, int kernel_size)
{
int row = img.rows;
int col = img.cols;
cv::Mat new_image = cv::Mat::zeros(row, col, CV_8UC1);
int pad = floor(kernel_size / 2);
int kernel[3][3] = {{0, 1, 0}, {1, -4, 1}, {0, 1, 0}};
double val = 0;
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
val = 0;
for (int di = -pad; di < pad + 1; di++)
{
for (int dj = -pad; dj < pad + 1; dj++)
{
if (((di + i) >= 0) && ((di + i) < row) && ((dj + j) >= 0) && ((dj + j) < col))
{
val += img.at<uchar>(i + di, j + dj) * kernel[di + pad][dj + pad];
}
}
}
val = fmax(val, 0);
val = fmin(val, 255);
new_image.at<uchar>(i, j) = (uchar)val;
}
}
return new_image;
}
int main(){
cv::Mat img = cv::imread("../fate.jpeg", cv::IMREAD_COLOR);
cv::Mat gray = BGR2GRAY(img);
cv::Mat new_image = laplacian_filter(gray, 3);
cv::imwrite("../fate_laplacian.jpeg", new_image);
cv::imshow("vv", new_image);
cv::waitKey(0);
cv::destroyAllWindows();
return 0;
}
输入图像 (fate.jpeg)laplacian滤波图像 (fate_laplacianjpeg)
Emboss滤波器可以使物体轮廓更加清晰,定义如下:
K = [ − 2 − 1 0 − 1 1 1 0 1 2 ] K= \left[ \begin{matrix} -2&-1&0\ -1&1&1\ 0&1&2 \end{matrix} \right]K =−2 −1 0 −1 1 1 0 1 2
#include
#include
#include
cv::Mat BGR2GRAY(cv::Mat img)
{
int row = img.cols;
int col = img.rows;
cv::Mat new_image = cv::Mat::zeros(row, col, CV_8UC1);
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
new_image.at<uchar>(i, j) = 0.2126 * (float)img.at<cv::Vec3b>(i, j)[2] \
+ 0.7152 * (float)img.at<cv::Vec3b>(i, j)[1] \
+ 0.0722 * (float)img.at<cv::Vec3b>(i, j)[0];
}
}
return new_image;
}
cv::Mat emboss_filter(cv::Mat img, int kernel_size)
{
int row = img.rows;
int col = img.cols;
cv::Mat new_image = cv::Mat::zeros(row, col, CV_8UC1);
int pad = floor(kernel_size / 2);
int kernel[3][3] = {{-2, -1, 0}, {-1, 1, 1}, {0, 1, 2}};
double val = 0;
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
val = 0;
for (int di = -pad; di < pad + 1; di++)
{
for (int dj = -pad; dj < pad + 1; dj++)
{
if (((di + i) >= 0) && ((di + i) < row) && ((dj + j) >= 0) && ((dj + j) < col))
{
val += img.at<uchar>(i + di, j + dj) * kernel[di + pad][dj + pad];
}
}
}
val = fmax(val, 0);
val = fmin(val, 255);
new_image.at<uchar>(i, j) = (uchar)val;
}
}
return new_image;
}
int main(){
cv::Mat img = cv::imread("../fate.jpeg", cv::IMREAD_COLOR);
cv::Mat gray = BGR2GRAY(img);
cv::Mat new_image = emboss_filter(gray, 3);
cv::imwrite("../1-10/fate_emboss.jpeg", new_image);
cv::imshow("vv", new_image);
cv::waitKey(0);
cv::destroyAllWindows();
return 0;
}
输入图像 (fate.jpeg)emboss滤波图像 (fate_emboss.jpeg)
Original: https://blog.csdn.net/hahahanba/article/details/123449674
Author: hahahanba
Title: 常用的边缘检测滤波器
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/640718/
转载文章受原作者版权保护。转载请注明原作者出处!