作者:OpenSLee,来源:FPGA开源工作室
1背景知识
平滑也称模糊, 是一项简单且使用频率很高的图像处理方法。平滑处理时需要用到一个 滤波器 。 最常用的滤波器是线性滤波器,线性滤波处理的输出像素值 ( g(i,j)) 是输入像素值 (f(i+k,j+l))的加权和 :
称为 核, 它仅仅是一个加权系数。不妨把 滤波器 想象成一个包含加权系数的窗口,当使用这个滤波器平滑处理图像时,就把这个窗口滑过图像。
1.1 均值滤波器
最简单的滤波器, 输出像素值是核窗口内像素值的 均值 ( 所有像素加权系数相等),核如下:
1.2 高斯滤波器
高斯滤波是将输入数组的每一个像素点与 高斯内核 卷积将卷积和当作输出像素值。
假设图像是1维的,那么观察上图,不难发现中间像素的加权系数是最大的, 周边像素的加权系数随着它们远离中间像素的距离增大而逐渐减小。
1.3 中值滤波器
中值滤波将图像的每个像素用邻域 (以当前像素为中心的正方形区域)像素的 中值 代替 。
1.4 双边滤波器
目前我们了解的滤波器都是为了 平滑 图像, 问题是有些时候这些滤波器不仅仅削弱了噪声, 连带着把边缘也给磨掉了。 为避免这样的情形 (至少在一定程度上 ), 我们可以使用双边滤波。类似于高斯滤波器,双边滤波器也给每一个邻域像素分配一个加权系数。 这些加权系数包含两个部分, 第一部分加权方式与高斯滤波一样,第二部分的权重则取决于该邻域像素与当前像素的灰度差值。
2 Opencv 实现
第一步:编写C++源程序.
#include "opencv2/imgproc/imgproc.hpp"#include "opencv2/highgui/highgui.hpp"
using namespace std;using namespace cv;
/// 全局变量int DELAY_CAPTION = 1500;int DELAY_BLUR = 100;int MAX_KERNEL_LENGTH = 31;
Mat src; Mat dst;char window_name[] = "Filter Demo 1";
/// 函数申明int display_caption( char* caption );int display_dst( int delay );
/** * main 函数 */
int main( int argc, char** argv )
{
namedWindow( window_name, CV_WINDOW_AUTOSIZE );
/// 载入原图像
src = imread( "../images/lena.jpg", 1 );
if( display_caption( "Original Image" ) != 0 ) { return 0; }
dst = src.clone();
if( display_dst( DELAY_CAPTION ) != 0 ) { return 0; }
/// 使用 均值平滑
if( display_caption( "Homogeneous Blur" ) != 0 ) { return 0; }
for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
{ blur( src, dst, Size( i, i ), Point(-1,-1) );
if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }
/// 使用高斯平滑
if( display_caption( "Gaussian Blur" ) != 0 ) { return 0; }
for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
{ GaussianBlur( src, dst, Size( i, i ), 0, 0 );
if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }
/// 使用中值平滑
if( display_caption( "Median Blur" ) != 0 ) { return 0; }
for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
{ medianBlur ( src, dst, i );
if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }
/// 使用双边平滑
if( display_caption( "Bilateral Blur" ) != 0 ) { return 0; }
for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
{ bilateralFilter ( src, dst, i, i*2, i/2 );
if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }
/// 等待用户输入
display_caption( "End: Press a key!" );
waitKey(0);
return 0;
}
int display_caption( char* caption )
{
dst = Mat::zeros( src.size(), src.type() );
putText( dst, caption,
Point( src.cols/4, src.rows/2),
CV_FONT_HERSHEY_COMPLEX, 1, Scalar(255, 255, 255) );
imshow( window_name, dst );
int c = waitKey( DELAY_CAPTION );
if( c >= 0 ) { return -1; }
return 0;
}
int display_dst( int delay )
{
imshow( window_name, dst );
int c = waitKey ( delay );
if( c >= 0 ) { return -1; }
return 0;
}
第二步编写CMmakeLists.txt
接下来我们编译程序。
第三步:编译程序
1>运行cmake .
cmake .
2>运行make
Make
3> 运行./display
4> 结果(视频展示)
文章转载自:FPGA开源工作室