图像处理中的滤波
- 定义: 即在尽量保留图像细节特征的条件下对目标图像的噪声进行抑制.
- 是图像预处理中不可缺少的操作
- 其处理效果的好坏将直接响到后续图像处理和分析的有效性和可靠性
- 去除没有用的信息. 保留有用的信息. 可能是低频 也可能是高频.
- 平滑
两个目的
- 抽出对象的特征作为图像识别的特征模式
- 为适应图像处理的要求,消除图像数字化时所混入的噪声
两个原则
- 不能损坏图像的轮廓以及边缘等重要信息
- 使图像清晰. 视觉效果更好
滤波器的分类
低通
作用: 边缘平滑
常用的低通滤波器: 高斯滤波、中值滤波、均值(方框)滤波、双边滤波
高通
作用: 边缘提取和增强(因为边缘区域的灰度变换加大,也就是频率较高)
常用的算子: Canny算子、Sobel算子、Laplace算子
线性滤波
输出的像素是输入领域像素的算术关系
非线性滤波
输出像素是输入领域像素的逻辑关系,例如中值滤波
test_blurry.cpp
/*
*
* 功能:使用常用的几种低通滤波器(包括均值(方框)滤波、高斯滤波、中值滤波、和双边滤波),实现边缘平滑
*
*/
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
int main(int argc, char* argv[]){
//读入图片
cv::Mat image = cv::imread(argv[1]);
/******************** 均值滤波 *********************/
//这种滤波方法就是取一个像素的邻域内各像素的平均值作为滤波结果
cv::Mat filter_box;
//函数形式:blur(InputArray src, OutputArray dst, Size ksize, Point anchor=Point(-1,-1), int borderType=BORDER_DEFAULT )
//邻域大小为 5 * 5
//cv::Point(-1, -1) 表明邻域的零位就是邻域的中心,这个是默认值,如果不改变的话可以不填。
//cv::BORDER_DEFAULT 是对边界的处理办法,这个一般也不需要改变的。
cv::blur(image, filter_box, cv::Size(5, 5), cv::Point(-1, -1), cv::BORDER_DEFAULT);
/******************** 高斯滤波 *********************/
//高斯滤波采取邻域内越靠近的值提供越大的权重的方式计算平均值。权重的选取采用高斯函数的形式。高斯函数有个非常好的特点,就是无论在时域还是频域都是钟形的。通过控制 σ 可以控制低通滤波的截止频率。
cv::Mat filter_gaussian;
//函数形式:GaussianBlur(InputArray src, OutputArray dst, Size ksize, double sigmaX, double sigmaY=0, int borderType=BORDER_DEFAULT )
//Size(3,3)定义了核的大小
//最后一个参数是高斯滤波的 σ 。从函数原型上可以看到有 sigmaX 和 sigmaY 两个参数。通常情况下 sigmaY 取与 sigmaX 相同的值,这时可以不写出来。也就是用它的默认值 0.
cv::GaussianBlur(image, filter_gaussian, cv::Size(3, 3), 1.5);
/******************** 中值滤波 *********************/
//中值滤波是一种非线性滤波器。它是取邻域内各点的统计中值作为输出。这种滤波器可以有效的去除椒盐噪声。还能保持图像中各物体的边界不被模糊掉。是一种最常用的非线性滤波器。这种滤波器只能使用正方形的邻域。
cv::Mat filter_median;
//函数形式:medianBlur(InputArray src, OutputArray dst, int ksize)
//ksize一般取奇数,例如3,5,7,滤波尺寸
cv::medianBlur(image, filter_median, 7);
/******************** 双边滤波 *********************/
//双边滤波的思想是抑制与中心像素值差别太大的像素,输出像素值依赖于邻域像素值的加权合
cv::Mat filter_bila;
//函数形式:bilateralFilter(InputArray src, OutputArray dst, int d, double sigmaColor, double sigmaSpace,int borderType=BORDER_DEFAULT );
//d 表示滤波时像素邻域直径,d为负时由 sigaColor计算得到;d>5时不能实时处理。
//sigmaColor、sigmaSpace非别表示颜色空间和坐标空间的滤波系数sigma。可以简单的赋值为相同的值。<10时几乎没有效果;>150时为油画的效果。
//borderType可以不指定。
cv::bilateralFilter(image, filter_bila, 1, 10, 10);
//显示结果
cv::putText(filter_box, "blur", cv::Point(10, 10), cv::FONT_HERSHEY_SIMPLEX, 1.0, cv::Scalar(255));
cv::putText(filter_gaussian, "GaussianBlur", cv::Point(10, 10), cv::FONT_HERSHEY_SIMPLEX, 1.0, cv::Scalar(255));
cv::putText(filter_median, "medianBlur", cv::Point(10, 10), cv::FONT_HERSHEY_SIMPLEX, 1.0, cv::Scalar(255));
cv::putText(filter_bila, "bilateralFilter", cv::Point(10, 10), cv::FONT_HERSHEY_SIMPLEX, 1.0, cv::Scalar(255));
const int width = image.cols;
const int height = image.rows;
cv::Mat show_image(cv::Size(5 * width, height), CV_8UC3);
image.copyTo(show_image(cv::Rect(0, 0, width, height)));
filter_box.copyTo(show_image(cv::Rect(width, 0, width, height)));
filter_gaussian.copyTo(show_image(cv::Rect(2 * width, 0, width, height)));
filter_median.copyTo(show_image(cv::Rect(3 * width, 0, width, height)));
filter_bila.copyTo(show_image(cv::Rect(4 * width, 0, width, height)));
cv::imshow("show", show_image);
cv::waitKey(0);
return 0;
}
锐化
- 图像锐化(image sharpening)是补偿图像的轮廓,增强图像的边缘及灰度跳变的部分,使图像变得清晰,分为空域处理和频域处理两类。图像锐化是为了突出图像上地物的边缘、轮廓,或某些线性目标要素的特征。这种滤波方法提高了地物边缘与周围像元之间的反差,因此也被称为边缘增强。
//功能:使用算子对图片进行锐化
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
int main(int argc, char* argv[]){
cv::Mat image = cv::imread(argv[1]);
//基于拉普拉斯算子的图像锐化
//拉普拉斯滤波核3*3
// 0 -1 0
// -1 5 -1
// 0 -1 0
cv::Mat kernel = (cv::Mat_<float>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
cv::Mat sharpen_laplace;
cv::filter2D(image, sharpen_laplace, image.depth(), kernel);
cv::imshow("show", sharpen_laplace);
cv::waitKey(0);
return 0;
}
边缘检测
- 使用不同的算子(Sobel,Canny,Laplace)实现边缘检测
/*
*
* 功能:使用不同的算子(Sobel,Canny,Laplace)实现边缘检测
*
*/
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
int main(int argc,char* argv[]){
//读入图片
cv::Mat src = cv::imread(argv[1]);
//Sobel算子
//Sobel 算子是一个离散微分算子 (discrete differentiation operator)。 它用来计算图像灰度函数的近似梯度。
cv::Mat dst_sobel;
//输入图像
//输出图像
//输入图像颜色通道数
//x方向阶数
//y方向阶数
cv::Sobel(src,dst_sobel,src.depth(),1,1);
//Laplace算子
cv::Mat dst_laplace;
//输入图像
//输出图像
//输入图像颜色通道数
cv::Laplacian(src,dst_laplace,src.depth());
//Canny算子
cv::Mat dst_canny;
//Canny只处理灰度图
cv::cvtColor(src,dst_canny,CV_RGB2GRAY);
//输入图像
//输出图像
//低阈值
//高阈值,opencv建议是低阈值的3倍
//内部sobel滤波器大小
cv::Canny(dst_canny,dst_canny,50,150,3);
//显示图片
cv::imshow("Sobel",dst_sobel);
cv::imshow("Laplace",dst_laplace);
cv::imshow("Canny",dst_canny);
cv::waitKey(0);
return 0;
}
角点检测
findContours
drawContours
- 注意: findContours函数使用后,输入图片会改变,所以,使用该函数前最好把图像存到另外一个Mat
颜色直方图
calcHist
重聚焦demo
/*
*
* 功能:非目标区域进行模糊处理,实现对焦效果
*
*/
#include <vector>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
int main(int argc, char* argv[]){
//--1.读入图片
cv::Mat image = cv::imread("E:\\test\\horse_hw.jpg");
//--2.转换灰度图
cv::Mat gray;
cv::cvtColor(image, gray, CV_RGB2GRAY);
//--3.二值化灰度图
cv::Mat binary;
cv::threshold(gray, binary, 85, 255, cv::THRESH_BINARY_INV);
//--4.寻找轮廓
std::vector<std::vector<cv::Point> > contours;
cv::Mat binary_copy; //因为findcontours函数会改变输入的图像,所以复制一个图像作为函数的输入
binary.copyTo(binary_copy);
cv::findContours(binary_copy, contours, CV_RETR_EXTERNAL/*获取外轮廓*/, CV_CHAIN_APPROX_NONE/*获取每个轮廓的每个像素*/);
//遍历每一个轮廓,把多余的轮廓去掉
std::vector<std::vector<cv::Point> >::const_iterator it = contours.begin();
while (it != contours.end()){
if (it->size()<500 || cv::boundingRect(*it).width>0.5*image.cols)
it = contours.erase(it);
else
++it;
}
//通过绘制轮廓,制作掩码
cv::Mat mask(image.size(), CV_8U, cv::Scalar(0));
cv::drawContours(mask, contours, -1/*绘制所有轮廓*/, cv::Scalar(255)/*绘制为白色*/, CV_FILLED/*轮廓全部填充*/);
cv::Mat dst;
//对图像进行模糊处理
cv::blur(image, dst, cv::Size(9, 9));
//对目标部分做锐化处理
cv::Mat horse;
image.copyTo(horse);
cv::Mat kernel = (cv::Mat_<float>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
cv::filter2D(horse, horse, image.depth(), kernel);
//合成画面,把锐化后的目标部分复制到dst对应的位置
horse.copyTo(dst, mask);
//--4.显示结果(原图和结果图显示在一起)
const int width = image.cols;
const int height = image.rows;
cv::Mat show_image(cv::Size(2 * width, height), CV_8UC3);
//将image拷贝到显示图片指定位置
image.copyTo(show_image(cv::Rect(0, 0, width, height)));
//dst拷贝image指定位置
dst.copyTo(show_image(cv::Rect(width, 0, width, height)));
//显示
cv::imshow("show", show_image);
cv::waitKey(0);
}