移动网站开发书籍,建站是什么专业,泉州seo按天付费,商务网站建设教学视频教程文章目录 一、概述图像滤波1.1、均值滤波1.2中值滤波1.3、高斯滤波1.4、双边滤波1.5、方框滤波 二、自定义掩码三、边缘处理四、Sobel算子五、Scharr算子六、拉普拉斯算子十、Canny算法 一、概述图像滤波
头文件 quick_opencv.h#xff1a;声明类与公共函数
#pragma once
#i… 文章目录 一、概述图像滤波1.1、均值滤波1.2中值滤波1.3、高斯滤波1.4、双边滤波1.5、方框滤波 二、自定义掩码三、边缘处理四、Sobel算子五、Scharr算子六、拉普拉斯算子十、Canny算法 一、概述图像滤波
头文件 quick_opencv.h声明类与公共函数
#pragma once
#include opencv2\opencv.hpp
using namespace cv;class QuickDemo {
public:...void blur_Demo(Mat image);void medianblur_Demo(Mat image);void gaussian_Demo(Mat image);void bilateralFilter_Demo(Mat image);void custom_mask_Demo(Mat image); //自定义掩膜运算void edge_process_Demo(Mat image1);};主函数调用
#include opencv2\opencv.hpp
#include quick_opencv.h
#include iostream
using namespace cv;int main(int argc, char** argv) {Mat src imread(D:\\Desktop\\pandas.jpg);if (src.empty()) {printf(Could not load images...\n);return -1;}namedWindow(input, WINDOW_NORMAL);imshow(input, src);QuickDemo qk;...qk.blur_Demo(src);qk.medianblur_Demo(src);qk.gaussian_Demo(src);qk.bilateralFilter_Demo(src);qk.custom_mask_Demo(src);qk.edge_process_Demo(src1);waitKey(0);destroyAllWindows();return 0;
}1.1、均值滤波
blur( InputArray src,OutputArray dst, Size ksize, Point anchor Point(-1,-1)int borderType BORDER_DEFAULT)src输入图像 。 dst输出图像 。 ksize内核大小 一般用 Size(w,h)w 为宽度h 为深度。 anchor被平滑的点表示取 内核中心 默认值 Point(-1,-1)。 boderType推断图像外部像素的某种边界模式。默认值 BORDER_DEFAULT 目的去除图像上的尖锐噪声平滑图像。 原理均值滤波属于线性滤波它的实现原理是邻域平均法 源文件 quick_demo.cpp实现类与公共函数 void QuickDemo::blur_Demo(Mat image) {Mat dst, dst1, dst2;blur(image, dst, Size(5, 5), Point(-1, -1));blur(image, dst1, Size(15, 1), Point(-1, -1));blur(image, dst2, Size(1, 15), Point(-1, -1));imshow(均值滤波, dst);imshow(横向滤波, dst1);imshow(竖直滤波, dst2);
}1.2中值滤波
medianBlur(InputArray src,OutputArray dst,int ksize)src输入图像 。 dst输出图像 。 ksize孔径的线性尺寸这个参数必须是大于1 的奇数 统计排序滤波器 中值对椒盐噪声有很好的抑制作用 void QuickDemo::medianblur_Demo(Mat image) {Mat dst, dst1, dst2;medianBlur(image.clone(), dst, (3, 3));medianBlur(image.clone(), dst1, (5, 5));medianBlur(image.clone(), dst2, (7, 7));imshow(中值滤波, dst);imshow(中值滤波1, dst1);imshow(中值滤波2, dst2);
}1.3、高斯滤波
GaussianBlur( InputArray src, OutputArray dst, Size ksize,double sigmaX, double sigmaY 0,int borderType BORDER_DEFAULT )src输入图像 。 dst输出图像 。 ksizeksize.width 和 ksize.height 可以不同但他们都必须为正数和奇数或者为0可由 sigma 计算而来 sigmaX高斯核函数在 X 方向的的标准差 sigmaY高斯核函数在 Y 方向的的标准差 若 sigmaY 为零就将它设为 sigmaX若 sigmaX 和 sigmaY 都是0那么就由 ksize.width 和 ksize.height 计算出来 高斯滤波是一种线性平滑滤波适用于消除高斯噪声广泛应用于图像处理的减噪过程。 高斯滤波就是对整幅图像进行加权平均的过程每一个像素点的值都由其本身和邻域内的其他像素值经过加权平均后得到。 高斯滤波的具体操作是用一个模板或称卷积、掩模扫描图像中的每一个像素用模板确定的邻域内像素的加权平均灰度值去替代模板中心像素点的值。 void QuickDemo::gaussian_Demo(Mat image) {Mat dst;GaussianBlur(image, dst, Size(5, 5), 15);imshow(高斯滤波, dst);
}1.4、双边滤波
边缘保留滤波算法
高斯双边滤波Meanshift均值迁移模糊局部均方差模糊导向滤波
双边滤波的原理示意图
void bilateralFilter(
InputArray src, 输入图像
OutputArray dst, 目标图像需要和源图片有一样的尺寸和类型
int d, 在过滤期间使用的每个像素邻域的直径。如果输入d非0没输入则sigmaSpace由d计算得出。
double sigmaColor, 颜色空间滤波器的sigma值这个参数的值越大就表明该像素邻域内有更宽广的颜色会被混合到一起产生较大的半相等颜色区域。
double sigmaSpace, 坐标空间滤波器的sigma值坐标空间的标注方差。他的数值越大意味着越远的像素会相互影响从而使更大的区域足够相似的颜色获取相同的颜色。当d0d指定了邻域大小且与sigmaSpace无关。否则d正比于sigmaSpace。
int borderType BORDER_DEFAULT 图像边界模式
)src: 输入图像可以是Mat类型图像必须是8位或浮点型单通道、三通道的图像。 dst: 输出图像和原图像有相同的尺寸和类型。 d: 表示在过滤过程中每个像素邻域的直径范围。如果这个值是非正数则函数会从第五个参数sigmaSpace计算该值。 sigmaColor:颜色空间过滤器的sigma值这个参数的值月大表明该像素邻域内有月宽广的颜色会被混合到一起产生较大的半相等颜色区域。 sigmaSpace: 坐标空间中滤波器的sigma值如果该值较大则意味着颜色相近的较远的像素将相互影响从而使更大的区域中足够相似的颜色获取相同的颜色。当d0时d指定了邻域大小且与sigmaSpace五官否则d正比于sigmaSpace. borderTypeBORDER_DEFAULT: 用于推断图像外部像素的某种边界模式有默认值BORDER_DEFAULT. void QuickDemo::bilateralFilter_Demo(Mat image) {Mat dst;bilateralFilter(image, dst, 0, 100.0, 10.0);imshow(双边滤波, dst);
}1.5、方框滤波
boxFilter( InputArray src, OutputArray dst, int ddepth,Size ksize, Point anchor Point(-1,-1),bool normalize true,int borderType BORDER_DEFAULT )src输入图像 dst输出图像 ddepth输出图像的深度-1 代表使用原图深度 ksize 滤波内核的大小。一般这样写Size(w, h)来表示内核的大小Size(10, 10)就表示 10x10 的核大小 anchor Point(-1,-1) 表示锚点即被平滑的那个点注意他有默认值Point(-1,-1) 如果这个点坐标是负值的话就表示取核的中心为锚点所以默认值Point(-1,-1)表示这个锚点在核的中心。 normalize true默认值为true一个标识符表示内核是否被其区域归一化normalized了 borderType BORDER_DEFAULT用于推断图像外部像素的某种边界模式。有默认值BORDER_DEFAULT我们一般不去管它。 二、自定义掩码 Mat kernel_ (Mat_char(3, 3) 0, -1, 0, -1, 5, -1, 0, -1, 0);void filter2D(
InputArray src, 输入图像
OutputArray dst, 输出图像和输入图像具有相同的尺寸和通道数量
int ddepth, 目标图像深度为-1时保持输入图像通道深度
InputArray kernel, 卷积核
Point anchorPoint(-1,-1),表示过滤点在内核中的相对位置的内核锚锚应位于内核内默认值-1-1表示锚点位于内核中心。
double delta0, 在储存目标图像前可选的添加到像素的值默认值为0
int borderTypeBORDER_DEFAULT 默认值是BORDER_DEFAULT,即对全部边界进行计算。
);void QuickDemo::custom_mask_Demo(Mat image) {// 自定义filter函数实现int offset image.channels();int cols (image.cols - 1) * offset;int rows image.rows;Mat dst Mat::zeros(image.size(), image.type());for (int row 1; row (rows - 1); row) {const uchar* previous image.ptruchar(row-1);const uchar* current image.ptruchar(row);const uchar* next image.ptruchar(row1);uchar* output dst.ptruchar(row);for (int col offset; col cols; col) {output[col] saturate_castuchar(5 * current[col] - (current[col - offset] current[col offset] previous[col] next[col]));}}imshow(dst, dst);// opencv自带filter2D函数实现Mat dst2;Mat kernel_ (Mat_char(3, 3) 0, -1, 0, -1, 5, -1, 0, -1, 0);filter2D(image.clone(), dst2, image.depth(), kernel_);imshow(dst2, dst2);
}可以看出dst2没有黑边了边缘被处理了。
三、边缘处理 在卷积开始之前增加边缘像素填充的像素值为0或者RGB黑色比如3x3在 四周各填充1个像素的边缘在卷积处理之后再去掉这些边缘这样就确保图像的边缘被处理 void copyMakeBorder(
InputArray src, // 输入图像
OutputArray dst, // 输出图像
int top, // 填充边缘长度一般上下左右都取相同值
int bottom,
int left,
int right,
int borderType, // 填充类型
const Scalar value Scalar() // 边框颜色值边框类型BUALE_CONTER时才有用
)openCV中的处理方法是 BORDER_DEFAULT - 默认的处理镜像边界像素1234|4321 BORDER_CONSTANT – 填充边缘用指定像素值 BORDER_REPLICATE – 填充边缘像素用已知的边缘像素值。复制边界像素1234|4444 BORDER_WRAP – 用另外一边的像素来补偿填充 使用参数 BORDER_CONSTANT 0 BORDER_REPLICATE 1 BORDER_REFLECT 2 BORDER_REFLECT_101 4, BORDER_REFLECT101 BORDER_REFLECT_101, BORDER_DEFAULT BORDER_REFLECT_101, BORDER_WRAP 3, BORDER_TRANSPARENT 5, 源文件 quick_demo.cpp实现类与公共函数
void QuickDemo::edge_process_Demo(Mat image) {Mat dst0, dst1;copyMakeBorder(image, dst0, 5, 5, 5, 5, BORDER_REFLECT);copyMakeBorder(image, dst1, 5, 5, 5, 5, BORDER_CONSTANT,Scalar(0,255,255));imshow(REFLECT, dst0);imshow(CONSTANT, dst1);
}四、Sobel算子
实现步骤
x轴方向求导 —— y轴方向求导 —— 最终结果为二者相加
函数原型
Sobelsrcddepthdxdyksize3…
离散微分算子discrete differentiation operator用来计算图像灰度的近似梯度 Soble算子功能集合高斯平滑和微分求导 一阶微分算子求导算子在水平和垂直两个方向上求导得到图像X方法与Y方向梯度图像
代码案例
chess cv2.imread(chess.png)
# 求y方向边缘
dy cv2.Sobel(chess, cv2.CV_64F, 1, 0, ksize5)
# 求x方向边缘
dx cv2.Sobel(chess, cv2.CV_64F, 0, 1, ksize5)
# 二者相加
result dy dxcv2.imshow(chess, chess)
cv2.imshow(dy, dy)
cv2.imshow(dx, dx)
cv2.imshow(result, result)
cv2.waitKey(0)从上图可以明显看出当dx设置为1时求得y方向上的边缘信息反之也是最终二者相加的结果也就是Sobel算子的结果。不能一开始就设定dxdy为1这样子不能达到该效果 五、Scharr算子
定义与Sobel类似但使用的kernel值不同并且只能为3x3只能求x方向或y方向一个方向的边缘信息 由于Sobel算子求取导数的近似值kernel3时不是很准确图像中较弱的边缘提取效果较差OpenCV使用改进版本Scharr函数算子如上右图
例如一个 3 * 3 的 Sobel 算子在梯度角度水平或垂直方向时其不精确性就非常明显。Scharr 算子是对 Sobel 算子差异性的增强两者之间的在检测图像边缘的原理和使用方式上相同。
而 Scharr 算子的主要思路是通过将模版中的权重系数放大来增大像素值间的差异也是计算 x 或 y 方向上的图像差分 sobel,Scharr算子等此类算子都是输出图像深度 输入图像深度 。
void Sobel(
InputArray src, 输入图像单通道
OutputArray dst, 输出图像
int ddepth, 输出图像深度 输入图像深度
int dx, x梯度几阶导数一般为0、1、2其中0表示这个方向上没有求导
int dy, y梯度几阶导数
int ksize 3, 滤波窗口大小357…
double scale 1, 是否缩放默认1.0
double delta 0, 偏移常数
int borderType BORDER_DEFAULT ) 图像边缘处理方式。默认值cv2.BORDER_DEFAULT在经过处理后需要用 convertScaleAbs() 函数将其转回原来的uint8形式否则将无法显示图像而只是一副灰色的窗口。
void convertScaleAbs(
InputArray src, 输入图像
OutputArray dst, 输出uint8类型图片
double alpha 1, 伸缩系数
double beta 0 偏移值加到结果上的一个值
)由于Sobel算子是在两个方向计算的最后还需要用cv::addWeighted(src1, alpha, src2, beta, gamma, dst)函数将其组合起来。
//头文件 quick_opencv.h声明类与公共函数
#pragma once
#include opencv2\opencv.hpp
using namespace cv;class QuickDemo {
public:...void edge_extract_Demo(Mat image1);void laplance_Demo(Mat image1);void canny_Demo(Mat image1);
};//主函数调用该类的公共成员函数
#include opencv2\opencv.hpp
#include quick_opencv.h
#include iostream
using namespace cv;int main(int argc, char** argv) {Mat src imread(D:\\Desktop\\jianbian.png);if (src.empty()) {printf(Could not load images...\n);return -1;}QuickDemo qk;qk.edge_extract_Demo(src1);qk.laplance_Demo(src1);qk.canny_Demo(src1);waitKey(0);destroyAllWindows();return 0;
}//源文件 quick_demo.cpp实现类与公共函数
void QuickDemo::edge_extract_Demo(Mat image) {Mat gau_dst, gray_dst, xgrad, ygrad;GaussianBlur(image, gau_dst, Size(3, 3), 10);cvtColor(gau_dst, gray_dst, COLOR_BGR2GRAY);//Sobel(gray_dst, xgrad, -1, 1, 0, 3);//Sobel(gray_dst, ygrad, -1, 0, 1, 3);//Sobel(gray_dst, xgrad, CV_16S, 1, 0, 3);//Sobel(gray_dst, ygrad, CV_16S, 0, 1, 3);Scharr(gray_dst, xgrad, CV_16S, 1, 0, 3);Scharr(gray_dst, ygrad, CV_16S, 0, 1, 3);convertScaleAbs(xgrad, xgrad);convertScaleAbs(ygrad, ygrad);Mat xygrad;addWeighted(xgrad, 0.5, ygrad, 0.5, 0, xygrad);imshow(xgrad, xgrad);imshow(ygrad, ygrad);imshow(xygrad, xygrad);Mat xy_grad Mat::zeros(xgrad.size(),xgrad.type());int width xgrad.cols;int height xgrad.rows;for (int h 0; h height; h) {uchar* current_x xgrad.ptruchar(h);uchar* current_y ygrad.ptruchar(h);uchar* current_d xy_grad.ptruchar(h);for (int w 0; w width; w) {*current_d saturate_castuchar(*current_x *current_y);}}imshow(xy_grad, xy_grad);
}输出图像深度-1(与原图保持一致) 输出图像深度CV_16S 方向梯度细节更多了。 使用自定义函数直接相加结果右 (使用addWeighted函数各方向梯度0.5的权重组合发虚左) 测试scharr()效果细节更加丰富
六、拉普拉斯算子
优点可同时求得两个方向的边缘
缺点对噪音比较敏感一般需要先进行去噪在调用拉普拉斯算子
函数原型
Laplacianimgddepthksize1 在二阶导数的时候最大变化处的值为零即边缘是零值。通过二阶导数计算依据此理论我们可以计算图像二阶导数提取边缘。
void Laplacian(
InputArray src, 输入图像单通道
OutputArray dst, 输出图像
int ddepth, 输出图像深度 输入图像深度
int ksize 1, 滤波窗口大小357…
double scale 1, 是否缩放默认1.0
double delta 0, 偏移常数
int borderType BORDER_DEFAULT 图像边缘处理方式
)一般处理流程
高斯模糊 – 去噪声GaussianBlur() 转换为灰度图像cvtColor() 拉普拉斯 – 二阶导数计算Laplacian() 取绝对值convertScaleAbs() 显示结果
void QuickDemo::laplance_Demo(Mat image) {Mat gau_dst, gray_dst, laplance_dst, ygrad;GaussianBlur(image, gau_dst, Size(3, 3), 10);cvtColor(gau_dst, gray_dst, COLOR_BGR2GRAY);Laplacian(gray_dst, laplance_dst, CV_16S, 3, 1.0, 0);convertScaleAbs(laplance_dst, laplance_dst);threshold(laplance_dst, laplance_dst, 0, 255, THRESH_OTSU | THRESH_BINARY);imshow(laplance_dst, laplance_dst);
}chess cv2.imread(chess.png)
result cv2.Laplacian(chess, cv2.CV_64F, ksize5)cv2.imshow(chess, chess)
cv2.imshow(result, result)
cv2.waitKey(0)从效果上看比起Sobel步骤更加简单并且效果也比较好缺点就是如果噪声过多的话效果会比较差
十、Canny算法
实现步骤
1、使用5x5高斯滤波消除噪音
2、使用Sobel计算图像梯度的方向0°、45°、90°、135°
3、取局部极大值
4、阈值计算
函数原型
CannyimgminValmaxVal…
其中的minVal和maxVal代表边缘的阈值两者差值过大的话会损失一定的边缘信息
代码案例
img cv2.imread(1.jpg)
result cv2.Canny(img, 100, 200)cv2.imshow(org, img)
cv2.imshow(result, result)
cv2.waitKey(0)Canny算法介绍 - 非最大信号抑制 T1 T2为阈值凡是高于T2的都保留凡是小于T1都丢弃从高于T2的像素出发凡是大于T1而且相互连接的都保留。最终得到一个输出二值图像。 推荐的高低阈值比值为 T2: T1 3:1/2:1其中T2为高阈值T1为低阈值
void Canny(
InputArray image, 输入图像单通道
OutputArray edges, 输出图像
double threshold1, 阈值T1
double threshold2, 阈值T2 一般为 2*T1
int apertureSize 3, Soble算子的size窗口大小
bool L2gradient false 默认false L1归一化Ture则为L2归一化
);一般处理流程 高斯模糊 - GaussianBlur 灰度转换 - cvtColor 计算梯度 – Sobel/Scharr 非最大信号抑制 高低阈值输出二值图像 void QuickDemo::canny_Demo(Mat image) {Mat gau_dst, gray_dst, grad_dst;GaussianBlur(image, gau_dst, Size(3, 3), 10);cvtColor(gau_dst, gray_dst, COLOR_BGR2GRAY);Canny(gray_dst, grad_dst, 50.0, 100.0, 3, false);imshow(grad_dst, grad_dst);
}