OpenCV开发->图像组件->imgproc组件(image process)
高等数学(算法->高斯函数)
图像处理->核心处理->图像滤波(说白了降噪或者去噪)
视频处理->降噪处理,去噪
第一点:图像滤波概念
概念一:图像滤波指在尽量保留图像细节特征的条件下对目标图像的噪声进行抑制。在图像预处理中不可缺少的操作,其处理结果的好坏将直接影响到后续图像处理和分析的有效性和可靠性。
概念二:消除图像中的噪声成分叫做图像的平滑化或者滤波操作。
概念三:图像滤波目的有两个->提高图片质量
第一个:抽出对象的特征作为图像识别的特征模式
第二个:适应图像处理的要求,消除图像数字化时所混入的噪声
概念四:滤波器处理要求
第一个:不能够损坏图像的轮廓以及边缘等重要信息
第二个:使图像清晰视觉效果好
概念五:平滑滤波是低频增强的空间域滤波技术,他的目的有两类
第一类:模糊
第二类:消除噪音
概念六:空间域的平滑滤波一般采用简单平均法(算法)进行
原理:求邻近像元点的平均亮度值。
注意:邻域的大小与平滑的效果直接相关,邻域越大平滑的效果越好,但是邻域过大,也会使边缘信息损失的越大,从而使图像变得模糊,因而需要选择合适的邻域大小。
总结:说白了就是加了一层膜
第二点:图像滤波种类(滤波算法)
第一种:线性滤波
方框滤波->BoxBlur()函数
均值滤波->Blur()函数
高斯滤波->GaussianBlur()函数
第二种:非线性滤波
中值滤波->medianBlur()函数
双边滤波->bilateralFilter()函数
第三点:线性滤波器种类
低通滤波器:允许低频率通过
高通滤波器:允许高频率通过
带通滤波器:允许一定范围频率通过
带阻滤波器:阻止一定范围频率通过并且允许其他频率通过
全通滤波器:允许所有频率通过,仅仅改变相位关系
限波滤波器:阻止一个狭窄频率范围通过,是一种特殊带阻滤波器
第四点:滤波和模糊
滤波概念:将信号中特定波段频率滤除的操作,是抑制和防止干扰的一项重要措施。
以高斯滤波举例:高斯滤波可分为低通滤波和高通滤波两种。
高斯滤波是指:采用高斯函数作为滤波函数的滤波操作,至于是不是模糊,要看是高斯低通还是高斯高通,低通就是模糊,高通就是锐化。
总结如下:
高斯滤波是指用高斯函数作为滤波函数的滤波操作。
高斯模糊就是高斯低通滤波。
第五点:线性滤波公式
g = f * h
f表示:输入像素值
h表示:加权系数->"核"->表示一块区域
g表示:输出像素值
第六点:线性滤波核心函数->案例
1、方框滤波->boxFilter()函数
2、均值滤波->blur()函数
3、高斯滤波->GaussianBlur()函数
案例
#include <opencv2/core/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>
using namespace cv;
using namespace std;
// OpenCV开发->图像组件->imgproc组件(image process)
// 线性滤波核心函数->案例
// 1、方框滤波->boxFilter()函数
void boxFiltering() {
// 第一步:加载一张图片
Mat mat_image_src = imread("/Users/alange/Desktop/OpenCV/Images/strawberry.png");
if( mat_image_src.empty() ){
cout << "打不开或者没有该图片" << std::endl;
return;
}
// 参数一:原始图片
// 参数二:目标图片
// 参数三:输出图片深度(位深度:8位、16位、24位、32位、64位等等...)
// 默认值:-1表示采用图片原始深度,类似于这个mat_image_src.depth()函数
Mat mat_image_dst;
// 参数四:内"核"大小->Size2i(width, height)->一块区域->参照范围
// 参数五:Point2i(-1, -1)表示锚点(锚点:被平滑的那个点)
// 默认值就是Point2i(-1, -1)表示含义->如果这个值是负数,表示取"核"的中心点为锚点
// 例如:Size2i(10, 10),那么参数五为Point2i(-1, -1),结果我们的锚点为Point2i(5, 5)
// 参数六:bool值表示->默认值为true,表示内核是否被其他区域归一化
// 参数七:用于推断图像的外部像素某种边界模式->一般都是默认值
boxFilter(mat_image_src, mat_image_dst, -1, Size2i(10, 10));// Size2i(10, 10):这两个值越大越模糊
namedWindow("图片显示");
imshow("图片显示", mat_image_dst);
waitKey();
}
// 2、均值滤波->blur()函数
void averagefiltering() {
// 第一步:加载一张图片
Mat mat_image_src = imread("/Users/alange/Desktop/OpenCV/Images/strawberry.png");
if( mat_image_src.empty() ){
cout << "打不开或者没有该图片" << std::endl;
return;
}
// 参数一:原始图片
// 参数二:目标图片
Mat mat_image_dst;
// 参数三:内"核"大小->Size2i(width, height)->一块区域->参照范围
// 参数四:Point2i(-1, -1)表示锚点(锚点:被平滑的那个点)
// 默认值就是Point2i(-1, -1)表示含义->如果这个值是负数,表示取"核"的中心点为锚点
// 例如:Size2i(10, 10),那么参数五为Point2i(-1, -1),结果我们的锚点为Point2i(5, 5)
// 参数五:用于推断图像的外部像素某种边界模式->一般都是默认值
blur(mat_image_src, mat_image_dst, Size2i(10, 10));
namedWindow("图片显示");
imshow("图片显示", mat_image_dst);
waitKey();
}
// 3、高斯滤波->GaussianBlur()函数
void gaussianFilter() {
//第一步:加载一张图片
Mat mat_image_src = imread("/Users/alange/Desktop/OpenCV/Images/strawberry.png");
if( mat_image_src.empty() ){
cout << "打不开或者没有该图片" << std::endl;
return;
}
// 参数一:原始图片
// 参数二:目标图片
Mat mat_image_dst;
// 参数三:内"核"大小->Size2i(width, height)->一块区域->参照范围
// 注意:核大小必需是奇数,例如:3、5、7、9、11、13、15...
// 参数四:高斯核函数在X方向上标准偏差
// 参数五:高斯核函数在Y方向上标准偏差
// 参数六:用于推断图像的外部像素某种边界模式->一般都是默认值
GaussianBlur(mat_image_src, mat_image_dst, Size2i(15, 15), 0, 0);// Size2i(15, 15):必须为基数
namedWindow("高斯滤波");
imshow("高斯滤波", mat_image_dst);
waitKey();
}
int main(int argc, const char * argv[]) {
//1、方框滤波->boxFilter()函数
// boxFiltering();
//2、均值滤波->blur()函数
// averagefiltering();
//3、高斯滤波->GaussianBlur()函数
gaussianFilter();
return 0;
}
第七点:非线性滤波
1、场景:例如在噪声是散粒噪声而不是高斯噪声,即图像偶尔会出现很大的值的时候,用高斯滤波器对图像进行模糊的话,那么噪声像素是不会被去除的,它们只是转换为更加柔和但是依然可见的散粒,这个时候采用非线性滤波就可以解决。
2、中值滤波
概念:基本上实现思想是用像素点邻域灰度值的中值来代替改像素点的灰度值,该方法在去除脉冲噪声、椒盐噪声的同时又能够保留图像的边缘细节。
3、双边滤波
概念:是结合图像的空间邻近度和像素值相似度的一种折中处理,同时考虑空域信息和灰度相似性,达到保边去噪的目的,具有简单、非迭代、局部的特点。
第八点:非线性滤波->核心函数->案例
#include <opencv2/core/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>
using namespace cv;
using namespace std;
// 1、中值滤波
void medianFilter() {
// 第一步:加载一张图片
Mat mat_image_src = imread("/Users/alange/Desktop/OpenCV/Images/strawberry.png");
if( mat_image_src.empty() ){
cout << "打不开或者没有该图片" << std::endl;
return;
}
// 参数一:原始图片
// 参数二:目标图片
Mat mat_image_dst;
// 参数三:孔径的线性尺寸(注意:参数必需是大于等于1,并且是奇数,例如:3、5、7、9...)
medianBlur(mat_image_src, mat_image_dst, 9);
namedWindow("中值滤波");
imshow("中值滤波", mat_image_dst);
waitKey();
}
// 2、双边滤波->美颜处理
void bilateralFiltering() {
// 第一步:加载一张图片
Mat mat_image_src = imread("/Users/alange/Desktop/OpenCV/Images/strawberry.png");
if( mat_image_src.empty() ){
cout << "打不开或者没有该图片" << std::endl;
return;
}
Mat mat_image_dst;
// 参数一:原始图片
// 参数二:目标图片
// 参数三(d):表示过滤过程中每个像素邻域的直径,
// 如果这个值被设置为非正数,那么OpenCV框架会从第五个参数(sigmaSpace)计算出这个值
// 参数四(sigmaColor):颜色空间滤波器的sigma值
// 这个参数值越大,就表明该像素邻域内有越宽广的颜色会被混合到一起
// 参数五(sigmaSpace):坐标空间中滤波器的sigma值,坐标空间的标注方差。
// 它的值越大,意味着越远像素会相互影响,从而使更大的区域中足够相似的颜色获取相同的颜色。
// 当d>0时,d指定了领域大小且与sigmaSpace无关,否则,d正比于sigmaSpace
// 参数六:用于推断图像外部像素的某种边界模式,一般采用默认值
// 双边滤波算法->研究算法
// 一般图片->权衡调整->相对比较平均
int value = 100;// 如果这个值被设置为非正数,那么OpenCV框架会从第五个参数(sigmaSpace)计算出这个值
// 折中选择
bilateralFilter(mat_image_src, mat_image_dst, value, value * 2, value / 2);
namedWindow("双边滤波");
imshow("双边滤波", mat_image_dst);
waitKey();
}
int main(int argc, const char * argv[]) {
//1、中值滤波
// medianFilter();
//2、双边滤波->美颜处理
bilateralFiltering();
return 0;
}
第九点:形态学滤波
概念一:膨胀或者腐蚀操作本质就是将图像(或图像一部分区域,这个图像或者区域称之为A)与核(称之为B)进行卷积。
概念二:核可以是任何形状和大小,他拥有一个单独定义出来的参考点,我们称之为锚点。多数情况下,核是一个小的,中间带有参考点和实心正方形或者圆盘。其实,可以把核视为模版或者掩码。
1、膨胀:求局部最大值操作
2、腐蚀:求局部最小值操作
案例:
// 1、膨胀:求局部最大值操作
void dilateFilter() {
// 第一步:加载一张图片
Mat mat_image_src = imread("/Users/alange/Desktop/OpenCV/Images/strawberry.png");
if( mat_image_src.empty() ){
cout << "打不开或者没有该图片" << std::endl;
return;
}
// 参数一:核类型(样式)
// MORPH_RECT:矩形
// MORPH_CROSS:交叉形(十字架,"+")
// MORPH_ELLIPSE:椭圆形
// 参数二:核大小
Mat mat_element = getStructuringElement(MORPH_CROSS, Size2i(10, 10));
Mat mat_image_dst;
// 参数一:原始图片
// 参数二:目标图片
// 参数三:核
// 参数四:锚的位置->默认位置Point2i(-1, -1)
// 参数五:迭代使用
// 例如:1表示调用一次dilate函数,2表示调用两次dilate函数,以此类推...
// 参数六:用于推断图像外部像素的某种边界模式,一般采用默认值
dilate(mat_image_src, mat_image_dst, mat_element);
namedWindow("膨胀");
imshow("膨胀", mat_image_dst);
waitKey();
}
// 2、腐蚀:求局部最小值操作
void erodeFilter() {
// 第一步:加载一张图片
Mat mat_image_src = imread("/Users/alange/Desktop/OpenCV/Images/strawberry.png");
if( mat_image_src.empty() ){
cout << "打不开或者没有该图片" << std::endl;
return;
}
// 参数一:核类型(样式)
// MORPH_RECT:矩形
// MORPH_CROSS:交叉形(十字架,"+")
// MORPH_ELLIPSE:椭圆形
// 参数二:核大小
Mat mat_element = getStructuringElement(MORPH_ELLIPSE, Size2i(10, 10));
Mat mat_image_dst;
// 参数一:原始图片
// 参数二:目标图片
// 参数三:核
// 参数四:锚的位置->默认位置Point2i(-1, -1)
// 参数五:迭代使用
// 例如:1表示调用一次dilate函数,2表示调用两次dilate函数,以此类推...
// 参数六:用于推断图像外部像素的某种边界模式,一般采用默认值
erode(mat_image_src, mat_image_dst, mat_element);
namedWindow("腐蚀");
imshow("腐蚀", mat_image_dst);
waitKey();
}
int main(int argc, const char * argv[]) {
// 1、膨胀:求局部最大值操作
// dilateFilter();
// 2、腐蚀:求局部最小值操作
erodeFilter();
return 0;
}
第十点:形态学滤波->morphologyEx()函数
1、开运算
2、闭运算
3、形态学梯度
4、顶帽
5、黑帽
案例
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main(int argc, const char * argv[]) {
Mat mat_image_src = imread("/Users/alange/Desktop/OpenCV/Images/strawberry.png");
if( mat_image_src.empty() ){
cout << "打不开或者没有该图片" << std::endl;
return 0;
}
/* ************************ 调用的是API Start ************************ */
// Mat mat_element = getStructuringElement(MORPH_RECT, Size2i(10, 10));
// Mat mat_image_dst;
// morphologyEx(mat_image_src, mat_image_dst, MORPH_CLOSE, mat_element);
/* ************************ 调用的是API End ************************ */
//自己实现开运算
/* ************************ 开运算 Start ************************ */
// Mat mat_element = getStructuringElement(MORPH_RECT, Size2i(10, 10));
// Mat mat_image_dst;
// 开运算->先进性腐蚀->膨胀
// erode(mat_image_src, mat_image_dst, mat_element);
// dilate(mat_image_dst, mat_image_dst, mat_element);
/* ************************ 开运算 End ************************ */
/* ************************ 闭运算 Start ************************ */
// Mat mat_element = getStructuringElement(MORPH_RECT, Size2i(10, 10));
// Mat mat_image_dst;
// // 闭运算->先进行膨胀->腐蚀
// dilate(mat_image_src, mat_image_dst, mat_element);
// erode(mat_image_dst, mat_image_dst, mat_element);
/* ************************ 闭运算 End ************************ */
/* ************************ 形态学下梯度 Start ************************ */
Mat mat_element = getStructuringElement(MORPH_RECT, Size2i(10, 10));
Mat mat_image_dst;
// 形态学下梯度->先得到膨胀图->再得到腐蚀图->最后进行差值
Mat mat_image_dst_erode;
erode(mat_image_src, mat_image_dst_erode, mat_element);
Mat mat_image_dst_dilate;
dilate(mat_image_src, mat_image_dst_dilate, mat_element);
mat_image_dst = mat_image_dst_dilate - mat_image_dst_erode;
/* ************************ 形态学下梯度 End ************************ */
//其他一些处理,自己玩玩
namedWindow("形态学滤波图片");
imshow("形态学滤波图片", mat_image_dst);
waitKey();
return 0;
}
第十一点:漫水填充?
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main(int argc, const char * argv[]) {
Mat mat_image_src = imread("/Users/alange/Desktop/OpenCV/Images/strawberry.png");
// Mat mat_image_src = imread("/Users/alange/Desktop/OpenCV/Images/girl.png");
if( mat_image_src.empty() ){
cout << "打不开或者没有该图片" << std::endl;
return 0;
}
Rect rect;
floodFill(mat_image_src,
Point2i(50, 50),
Scalar(155, 100, 255),
&rect,
Scalar(30, 30, 30),
Scalar(30, 30, 30));
namedWindow("漫水填充");
imshow("漫水填充", mat_image_src);
waitKey();
return 0;
}
第十二点:图像金字塔
第十三点:图片尺寸缩放->resize()函数
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
//第四点:图片尺寸缩放->resize()函数->图片压缩方式
int main(int argc, const char * argv[]) {
Mat mat_image_src = imread("/Users/alange/Desktop/OpenCV/Images/strawberry.png");
Mat mat_image_dst;
resize(mat_image_src, mat_image_dst, Size2i(60, 50));
imwrite("/Users/alange/Desktop/image_1.png", mat_image_dst);
namedWindow("图片");
imshow("图片", mat_image_dst);
waitKey();
return 0;
}
图像变换
第一点:基于OpenCV边缘检测
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
// OpenCV开发->图像变换
//第一点:基于OpenCV边缘检测
int main(int argc, const char * argv[]) {
//载入原图
Mat srcImage = imread("/Users/alange/Desktop/OpenCV/Images/strawberry.png");
Mat dstImage, edge, grayImage;
//【1】创建与src同类型和大小的矩阵(dst)
dstImage.create( srcImage.size(), srcImage.type() );
//【2】将原图像转换为灰度图像
cvtColor(srcImage, grayImage, COLOR_BGR2GRAY);
//【3】先用使用 3x3内核来降噪
blur(grayImage, edge, Size(5,5) );
//【4】运行Canny算子
Canny(edge, edge, 3, 9,3 );
//【5】显示效果图
namedWindow("Canny边缘检测");
imshow("Canny边缘检测", edge);
waitKey();
return 0;
}
第二点:霍夫变换
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main( )
{
//【1】载入原始图和Mat变量定义
Mat srcImage = imread("/Users/alange/Desktop/OpenCV/Images/strawberry.png"); //工程目录下应该有一张名为1.jpg的素材图
Mat midImage,dstImage;//临时变量和目标图的定义
//【2】进行边缘检测和转化为灰度图
Canny(srcImage, midImage, 50, 200, 3);//进行一此canny边缘检测
cvtColor(midImage,dstImage, COLOR_GRAY2BGR);//转化边缘检测后的图为灰度图
//【3】进行霍夫线变换
vector<Vec2f> lines;//定义一个矢量结构lines用于存放得到的线段矢量集合
HoughLines(midImage, lines, 1, CV_PI/180, 150, 0, 0 );
//【4】依次在图中绘制出每条线段
for( size_t i = 0; i < lines.size(); i++ )
{
float rho = lines[i][0], theta = lines[i][1];
Point pt1, pt2;
double a = cos(theta), b = sin(theta);
double x0 = a*rho, y0 = b*rho;
pt1.x = cvRound(x0 + 1000*(-b));
pt1.y = cvRound(y0 + 1000*(a));
pt2.x = cvRound(x0 - 1000*(-b));
pt2.y = cvRound(y0 - 1000*(a));
//此句代码的OpenCV2版为:
//line( dstImage, pt1, pt2, Scalar(55,100,195), 1, CV_AA);
//此句代码的OpenCV3版为:
line( dstImage, pt1, pt2, Scalar(55,100,195), 1, LINE_AA);
}
//【5】显示效果图
imshow("【效果图】", dstImage);
waitKey(0);
return 0;
}
网友评论