请先理解好上一章的傅里叶变换,图像的高低频再来研究本章
本章先讲方框滤波,均值滤波,高斯滤波,再讲中值滤波,双边滤波
方框与均值
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
using namespace cv;
int main( ){
Mat image=imread("1.jpg");// 载入原图
namedWindow( "方框滤波【原图】" );//创建窗口
namedWindow( "方框滤波【效果图】");//创建窗口
imshow( "方框滤波【原图】", image );//显示原图
Mat out;//定义效果图
boxFilter( image, out, -1,Size(5, 5));//进行方框滤波操作
//或者blur( srcImage, dstImage, Size(5, 5)); //这句就是均值滤波操作
//上面的函数:-1指用原深度,设置了内核大小5X5,内核的各位置值在函数调用内部自行设定
imshow( "方框滤波【效果图】" ,out );//显示效果图
waitKey( 0 );//等待点击
}
平滑处理也称模糊处理,用于减少图像上的噪点或失真,降低图像分辩率
均值滤波就是归一化设为TRUE(默认就是TRUE)时的方框滤波:用核对原图像进行卷积!!
上面这式子得到的是每个核中的各位置的值,其实都是用来进行卷积操作
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
using namespace cv;
int main( ){
Mat image=imread("1.jpg"); // 载入原图
namedWindow( "中值滤波【原图】" ); //创建窗口
namedWindow( "中值滤波【效果图】"); //创建窗口
imshow( "中值滤波【原图】", image );//输出图像
Mat out;//进行中值滤波操作
medianBlur ( image, out, 7);//中值滤波,7是孔的直径,必须为奇数
imshow( "中值滤波【效果图】" ,out );//输出图像
waitKey( 0 );//等待鼠标点击
}
中值滤波是非线性的,基本思你说呢是用像素点邻域灰度值的中值来代替该像素点的灰度值,可以去除脉冲噪声,去噪的同时又能保留图像的边缘细节
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
using namespace cv;
int main( ){
Mat image=imread("1.jpg"); // 载入原图
namedWindow( "双边滤波【原图】" ); //创建窗口
namedWindow( "双边滤波【效果图】"); //创建窗口
imshow( "双边滤波【原图】", image ); //显示原图
Mat out; //进行双边滤波操作
bilateralFilter(image,out,25,25*2,25/2);//入图,出图,每个像素邻域直径,颜色空间滤波器sigma,坐标空间滤波器sigma
imshow("双边滤波【效果图】",out);//显示效果图
waitKey( 0 );
}
然后是形态学部分
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main(){
Mat image = imread("1.jpg");//载入原图
namedWindow("【原图】膨胀操作");//创建窗口
namedWindow("【效果图】膨胀操作");//创建窗口
imshow("【原图】膨胀操作", image);//显示原图
Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));//定义核
//cout<<element<<endl;可知全是1,我还以为是方框滤波呢!关键还是看调用的函数
Mat out;//定义出图
dilate(image, out, element);//进行膨胀操作
//erode(image, out, element);//进行腐蚀操作
imshow("【效果图】膨胀操作", out);//显示效果图
waitKey(0);
return 0;
}
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;
Mat g_srcImage, g_dstImage;//原始图和效果图
int g_nElementShape = MORPH_RECT;//元素结构的形状
int g_nMaxIterationNum = 10;
int g_nOpenCloseNum = 0;
int g_nErodeDilateNum = 0;
int g_nTopBlackHatNum = 0;
static void on_OpenClose(int, void*);//回调函数
static void on_ErodeDilate(int, void*);//回调函数
static void on_TopBlackHat(int, void*);//回调函数
static void ShowHelpText();
int main( ){
ShowHelpText();
g_srcImage = imread("1.jpg");//载入原图
if( !g_srcImage.data ) { printf("Oh,no,读取srcImage错误~! \n"); return false; }
namedWindow("【原始图】");//显示原始图
imshow("【原始图】", g_srcImage);
namedWindow("【开运算/闭运算】",1);//创建三个窗口
namedWindow("【腐蚀/膨胀】",1);
namedWindow("【顶帽/黑帽】",1);
g_nOpenCloseNum=9;//参数赋值
g_nErodeDilateNum=9;
g_nTopBlackHatNum=2;
createTrackbar("迭代值", "【开运算/闭运算】",&g_nOpenCloseNum,g_nMaxIterationNum*2+1,on_OpenClose);//分别为三个窗口创建滚动条
createTrackbar("迭代值", "【腐蚀/膨胀】",&g_nErodeDilateNum,g_nMaxIterationNum*2+1,on_ErodeDilate);
createTrackbar("迭代值", "【顶帽/黑帽】",&g_nTopBlackHatNum,g_nMaxIterationNum*2+1,on_TopBlackHat);
while(1){//轮询获取按键信息
int c;
on_OpenClose(g_nOpenCloseNum, 0);//执行回调函数
on_ErodeDilate(g_nErodeDilateNum, 0);
on_TopBlackHat(g_nTopBlackHatNum,0);
c = waitKey(0);//获取按键
if( (char)c == 'q'||(char)c == 27 ) break;//按下键盘按键Q或者ESC,程序退出
//按下键盘按键1,使用椭圆(Elliptic)结构元素结构元素MORPH_ELLIPSE
if( (char)c == 49 )//键盘按键1的ASII码为49
g_nElementShape = MORPH_ELLIPSE;
//按下键盘按键2,使用矩形(Rectangle)结构元素MORPH_RECT
else if( (char)c == 50 )//键盘按键2的ASII码为50
g_nElementShape = MORPH_RECT;
//按下键盘按键3,使用十字形(Cross-shaped)结构元素MORPH_CROSS
else if( (char)c == 51 )//键盘按键3的ASII码为51
g_nElementShape = MORPH_CROSS;
//按下键盘按键space,在矩形、椭圆、十字形结构元素中循环
else if( (char)c == ' ' )
g_nElementShape = (g_nElementShape + 1) % 3;
}
return 0;
}
//-----------------------------------【on_OpenClose( )函数】----------------------------------
// 描述:【开运算/闭运算】窗口的回调函数
//-----------------------------------------------------------------------------------------------
static void on_OpenClose(int, void*){
int offset = g_nOpenCloseNum - g_nMaxIterationNum;//偏移量
int Absolute_offset = offset > 0 ? offset : -offset;//偏移量绝对值
//用偏移量绝对值来自定义核
Mat element = getStructuringElement(g_nElementShape, Size(Absolute_offset*2+1, Absolute_offset*2+1), Point(Absolute_offset, Absolute_offset) );
if( offset < 0 )morphologyEx(g_srcImage, g_dstImage, MORPH_OPEN, element);//进行操作
else morphologyEx(g_srcImage, g_dstImage, MORPH_CLOSE, element);
imshow("【开运算/闭运算】",g_dstImage);//显示图像
}
//-----------------------------------【on_ErodeDilate( )函数】----------------------------------
// 描述:【腐蚀/膨胀】窗口的回调函数
//-----------------------------------------------------------------------------------------------
static void on_ErodeDilate(int, void*){
int offset = g_nErodeDilateNum - g_nMaxIterationNum;//偏移量
int Absolute_offset = offset > 0 ? offset : -offset;//偏移量绝对值
//偏移量绝对值自定义核
Mat element = getStructuringElement(g_nElementShape, Size(Absolute_offset*2+1, Absolute_offset*2+1), Point(Absolute_offset, Absolute_offset) );
if( offset < 0 )erode(g_srcImage, g_dstImage, element);//进行操作
else dilate(g_srcImage, g_dstImage, element);
imshow("【腐蚀/膨胀】",g_dstImage);//显示图像
}
//-----------------------------------【on_TopBlackHat( )函数】--------------------------------
// 描述:【顶帽运算/黑帽运算】窗口的回调函数
//----------------------------------------------------------------------------------------------
static void on_TopBlackHat(int, void*){
int offset = g_nTopBlackHatNum - g_nMaxIterationNum;//偏移量
int Absolute_offset = offset > 0 ? offset : -offset;//偏移量绝对值
//自定义核
Mat element = getStructuringElement(g_nElementShape, Size(Absolute_offset*2+1, Absolute_offset*2+1), Point(Absolute_offset, Absolute_offset) );
if( offset < 0 )morphologyEx(g_srcImage, g_dstImage, MORPH_TOPHAT , element);//进行操作
else morphologyEx(g_srcImage, g_dstImage, MORPH_BLACKHAT, element);
imshow("【顶帽/黑帽】",g_dstImage);//显示图像
}
//-----------------------------------【ShowHelpText( )函数】----------------------------------
// 描述:输出一些帮助信息
//----------------------------------------------------------------------------------------------
static void ShowHelpText(){
printf( "\n\t按键操作说明: \n\n"
"\t\t键盘按键【ESC】或者【Q】- 退出程序\n"
"\t\t键盘按键【1】- 使用椭圆(Elliptic)结构元素\n"
"\t\t键盘按键【2】- 使用矩形(Rectangle )结构元素\n"
"\t\t键盘按键【3】- 使用十字型(Cross-shaped)结构元素\n"
"\t\t键盘按键【空格SPACE】- 在矩形、椭圆、十字形结构元素中循环\n" );
}
/*PS:腐蚀与膨胀都是针对白色区域而言的
开运算:先腐蚀后膨胀,作用是平滑边界,放大局部低亮度区域如裂纹
闭运算:先膨胀后腐蚀,作用是消除黑点
形态学梯度:膨胀图与腐蚀图之差,作用是突出边缘
顶帽:原图与开运算结果之差,突出了比原图轮廓周围区域更亮的区域
黑帽:闭运算结果与原图之差,突出了比原图轮廓周围区域更暗的区域*/
漫水填充
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
int main( ){
Mat src = imread("1.jpg");
imshow("【原始图】",src);
Rect ccomp;
floodFill(src, Point(50,300), Scalar(155, 255,55), &ccomp, Scalar(20, 20, 20),Scalar(20, 20, 20));
//输入图像,种子点,填充颜色,重绘区域最小边界矩形区域,负差最大值,正差最大值
imshow("【效果图】",src);
waitKey(0);
return 0;
}
resize
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
int main( ){
Mat srcImage = imread("1.jpg"); //工程目录下应该有一张名为1.jpg的素材图
Mat tmpImage,dstImage1,dstImage2;//临时变量和目标图的定义
tmpImage=srcImage;//将原始图赋给临时变量
imshow("【原始图】", srcImage);//显示原始图
//进行尺寸调整操作,入图,出图,出图尺寸,X缩放,Y缩放,插值方法
resize(tmpImage,dstImage1,Size( tmpImage.cols/2, tmpImage.rows/2 ),0,0,3);
resize(tmpImage,dstImage2,Size( tmpImage.cols*2, tmpImage.rows*2 ),0,0,3);
imshow("【效果图】之一", dstImage1);//显示效果图
imshow("【效果图】之二", dstImage2);//显示效果图
waitKey(0);
return 0;
}
高斯金字塔
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
int main( ){
Mat srcImage = imread("1.jpg"); //工程目录下应该有一张名为1.jpg的素材图
Mat tmpImage,dstImage;//临时变量和目标图的定义
tmpImage=srcImage;//将原始图赋给临时变量
imshow("【原始图】", srcImage); //显示原始图
pyrUp( tmpImage, dstImage, Size( tmpImage.cols*2, tmpImage.rows*2 ) );//进行向上取样操作
//pyrDown( tmpImage, dstImage, Size( tmpImage.cols/2, tmpImage.rows/2 ) );//向下取样
imshow("【效果图】", dstImage); //显示效果图
waitKey(0);
return 0;
}
最后一个处理关键点:阀值化
阀值
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
using namespace cv;
using namespace std;
#define WINDOW_NAME "【程序窗口】"//为窗口标题定义的宏
int g_nThresholdValue = 100;
int g_nThresholdType = 3;
Mat g_srcImage, g_grayImage, g_dstImage;
static void ShowHelpText( ); //输出帮助文字
void on_Threshold( int, void* );//回调函数
int main( ){
ShowHelpText( ); //【0】显示欢迎和帮助文字
g_srcImage = imread("1.jpg"); //【1】读入源图片
if(!g_srcImage.data ) { printf("读取图片错误,请确定目录下是否有imread函数指定的图片存在~! \n"); return false; }
imshow("原始图",g_srcImage); //显示原图
cvtColor( g_srcImage, g_grayImage, COLOR_RGB2GRAY ); //【2】存留一份原图的灰度图
namedWindow( WINDOW_NAME, WINDOW_AUTOSIZE ); //【3】创建窗口并显示原始图
createTrackbar( "模式", WINDOW_NAME, &g_nThresholdType, 4, on_Threshold );//【4】创建滑动条来控制阈值
createTrackbar( "参数值",WINDOW_NAME, &g_nThresholdValue,255, on_Threshold );
on_Threshold( 0, 0 ); //【5】初始化自定义的阈值回调函数
while(1){ //【6】轮询等待用户按键,如果ESC键按下则退出程序
int key;
key = waitKey( 20 );
if( (char)key == 27 ){ break; }
}
}
void on_Threshold( int, void* ){
threshold(g_grayImage,g_dstImage,g_nThresholdValue,255,g_nThresholdType);//调用阈值函数,255是后面部分模式下要取的MAX灰度值
imshow( WINDOW_NAME, g_dstImage ); //更新效果图
}
static void ShowHelpText(){
printf( "\n\t欢迎来到【基本阈值操作】示例程序~\n\n");
printf( "\n\t按键操作说明: \n\n"
"\t\t键盘按键【ESC】- 退出程序\n"
"\t\t滚动条模式0- 二进制阈值\n"
"\t\t滚动条模式1- 反二进制阈值\n"
"\t\t滚动条模式2- 截断阈值\n"
"\t\t滚动条模式3- 反阈值化为0\n"
"\t\t滚动条模式4- 阈值化为0\n" );
}