一边界拓展
有时滤波处理需要考虑边界,为图像增加一定的边缘,以适应卷积核在原图上的边界操作。
拓展边界的方法:
1>重复:
aaaaaa|abcdefgh|hhhhhhh
2>反射:
fedcba|abcdefgh|hgfedcb
3>反射101:
gfedcb|abcdefgh|gfedcba
4>外包装:
cdefgh|abcdefgh|abcdefg
5>常量:
iiiiii|abcdefgh|iiiiiii
void copyMakeBorder(InputArray src, OutputArray dst,
int top, int bottom, int left, int right,
int borderType,
const Scalar&value=Scalar())
/*top,bottom,left,right,上下左右边界拓展的长度
*dst的size为Size(src.rows+top+down,src.cols+left+right);
*borderType:
*BORDER_REPLICATE 重复
*BORDER_REFLECT 反射
*BORDER_REFLECT_101 反射101
*BORDER_WRAP 外包装
*BORDER_CONSTANT 常量
*value 当borderType=BORDER_CONSTANT时,边界的拓展像素值
*/
二常见滤波
1,线性滤波
每个像素的输出值,是输入像素的加权和
1>方框滤波
所用核:
where
void boxFilter(InputArray src, OutputArray dst,
int ddepth, Size ksize,
Point anchor=Point(-1,-1), bool normalize=true,
int borderType=BORDER_DEFAULT )
/*ddepth输出图像的深度(-1,就用src.depth())
*ksize滤波的核大小
*anchor锚点,Point(-1,-1)代表在核的中心
*normalize是否归一化
*(归一化把要处理的量缩放到一个范围内,以便统一的处理和直观量化)
*borderType边界拓展类型
*/
2>均值滤波
调用boxFilter的归一化
缺点:
不能很好的保护图像的细节,在图像去噪的同时也破坏了图像的细节部分,从而使图像变得模糊,不能很好的去除噪声点
void blur(InputArray src, OutputArray dst,
Size ksize, Point anchor=Point(-1,-1),
int borderType=BORDER_DEFAULT )
//src的depth应该为CV_8U,CV_16U,CV_16S,CV_32F,CV_64F之一
3>高斯滤波
高斯滤波是一种线性平滑滤波,可以消除高斯噪声。高斯模糊对于图像来说就是一个低通滤波操作。高斯平滑滤波器对于抑制服从正态分布的噪声非常有效。
void GaussianBlur(InputArray src, OutputArray dst,
Size ksize, double sigmaX, double sigmaY=0,
int borderType=BORDER_DEFAULT )
/*src图像深度为CV_8U,CV_16U,CV_16S,CV_32F,CV_64F之一
*ksize核大小,ksize.width和ksize.height可以不同,但都得为正奇数
*ksize可以为0,可以通过sigmaX,sigmaY计算出来
*sigmaX,sigmaY表示在X,Y方向的标准偏差
*使用时可以只指定ksize或者只指定sigmaX和sigmaY,或者两者都指定
*/
4>filter2D
用自定义核与图像卷积
void filter2D(InputArray src, OutputArray dst,
int ddepth, InputArray kernel,
Point anchor=Point(-1,-1), double delta=0,
int borderType=BORDER_DEFAULT )
/*ddepth dst的深度:(以下为src相应深度,dst可以选择深度,-1为不变)
*src.depth() = CV_8U, ddepth = -1/CV_16S/CV_32F/CV_64F
*src.depth() = CV_16U/CV_16S, ddepth = -1/CV_32F/CV_64F
*src.depth() = CV_32F, ddepth = -1/CV_32F/CV_64F
*src.depth() = CV_64F, ddepth = -1/CV_64F
*delta为像素点在存储之前,额外增加的值
*/
用法见Core的图像Sharp
5>滤波引擎
FilterEngine类
几乎可以把所有的滤波操作施加到图像上
//很多跟滤波相关的create函数,就是返回Ptr<FilterEngine>
cv::createSeparableLinearFilter()
cv::createLinearFilter(),cv::createGaussianFilter()
cv::createGaussianFilter(), cv::createDerivFilter()
cv::createBoxFilter(),cv::createMorphologhyFilter()
2,非线性滤波
1>中值滤波
基本思想用像素点邻域的灰度值的中值来代替该像素点的灰度值,该方法在去除脉冲噪声,椒盐噪声的同时又能保留图像的边缘细节
优点:
同样的3×3的区域进行处理,中值滤波的消除的能力更强,无论在去除噪声,还是保留边缘都不错
缺点:
时间是均值滤波的五倍以上
中值滤波的步骤:
1)将n×n范围内的像素点按强度排列
2) 选择中间值作为新值
void medianBlur(InputArray src, OutputArray dst, int ksize)
//src,channels应该为1,3,4
//当ksize为3,5的时候depth为CV_8U,CV_16U,CV_32F,当ksize更大时,就CV_8U
2>双边滤波
结合图像的空间邻近度和像素值近似度的一种折中处理,同时考虑空域信息和灰度相似度,达到保边去噪的目的,具有简单,非迭代,局部的特点
优点:
边缘保存
void bilateralFilter(InputArray src, OutputArray dst,
int d, double sigmaColor,
double sigmaSpace,
int borderType=BORDER_DEFAULT )
//src为8-bit或浮点型,1或3通道
//d每个像素的邻域直径,如果为负,则通过sigmaSpace,成正比关系
//sigmaColor颜色空间的sigma值,值越大,表明该像素邻域内有越宽广的颜色混合到一起
//sigmaSpace坐标空间的sigma值,值越大,表明越远的像素会相互影响,
//使更大区域中足够相似的颜色获取相同的颜色
3,滤波综合
操作图像:
//方框滤波 time:0.000488141s
cv::boxFilter(image,result1,-1,cv::Size(3,3));
//均值滤波 time:0.000788124s
cv::blur(image,result2,cv::Size(3,3));
//高斯滤波 time:0.000333969s
cv::GaussianBlur(image,result3,cv::Size(3,3),0);
//中值滤波 time:0.000296508s
cv::medianBlur(image,result4,3);
//双边滤波 time:0.00323766s
cv::bilateralFilter(image,result5,3,3,3);
二形态学滤波
1,腐蚀和膨胀
腐蚀和膨胀的功能:
1)消除噪声
2)分割出独立的图像元素,在图像连接相邻的元素
3)寻找图像中的明显的极大值或极小值区域
4)求出图像的梯度
1>膨胀
核与图像卷积,以核区域的最大值代替当前像素值。
void dilate(InputArray src, OutputArray dst,
InputArray kernel, Point anchor=Point(-1,-1),
int iterations=1, int borderType=BORDER_CONSTANT,
const Scalar&borderValue=morphologyDefaultBorderValue() )
//src的depth应该为CV_8U,CV_16U,CV_16S,CV_32F,CV_64F.
//kernel,膨胀操作的核,当为NULL时,表示使用3*3的核
//iterations,使用dilate的迭代次数
//borderValue,BORDER_CONSTANT情况下的边界拓展填充
//morphologyDefaultBorderValue会默认,dilate填充-Inf
//kernel可以使用getStructuringElement得到
Mat getStructuringElement(int shape, Size ksize,
Point anchor=Point(-1,-1))
//shape:
//MORPH_RECT 举行
//MORPH_ELLIPSE 交叉性
//MORPH_CROSS 椭圆形
2>腐蚀
核与图像卷积,以核区域的最小值代替当前像素值
void erode(InputArray src, OutputArray dst,
InputArray kernel, Point anchor=Point(-1,-1),
int iterations=1, int borderType=BORDER_CONSTANT,
const Scalar& borderValue=morphologyDefaultBorderValue() )
//用法见膨胀
//morphologyDefaultBorderValue,会默认填充+Inf
2,开运算,闭运算,形态学梯度,顶帽,黑帽
//提前定义核
//核的半径自己调整
int kel_size=3;
cv::Mat kel=cv::getStructuringElement(cv::MORPH_RECT,
cv::Size(2*kel_size+1,2*kel_size+1),
//锚点,为中心点
cv::Point(kel_size,kel_size));
1>开运算
先腐蚀,后膨胀的过程
dst=dilate(erode(src,element));
用来消除小物体,在纤细出分离物体,并且在平滑较大物体的边界同事不明显改变其面积
void Opening(const cv::Mat &image,cv::Mat &result)
{
cv::Mat Image=image.clone();
cv::Mat Image2;
//腐蚀
cv::erode(Image,Image2,kel);
//膨胀
cv::dilate(Image2,result,kel);
}
效果图:
2>闭运算
先膨胀,后腐蚀的过程
dst=erode(dilate(src,element));
闭运算能够排除小型黑色区域
void Closing(const cv::Mat &image,cv::Mat &result)
{
cv::Mat Image=image.clone();
cv::Mat Image2;
//膨胀
cv::dilate(Image,Image2,kel);
//腐蚀
cv::erode(Image2,result,kel);
}
效果图:
3>形态学梯度
膨胀图与腐蚀图之差
dst=dilate(src,element)-erode(src,element);
对于二值图像进行这一操作可以将团块的边缘突出,可以用形态学梯度保留物体的边缘轮廓
void Morphological(const cv::Mat &image,cv::Mat &result)
{
cv::Mat Image=image.clone();
cv::Mat Image2,Image3;
cv::dilate(Image,Image2,kel);
cv::erode (Image,Image3,kel);
result=Image2-Image3;
}
效果图:
4>顶帽
是原图像与与开运算的结果图之差
dst=src-open(src,element);
突出了比原图轮廓周围的区域更加明亮的区域,且这一操作与选择的核的大小相关,在一幅图像具有大幅背景,而微笑物体比较有规律的情况下,可以使用顶帽操作进行背景提取。
void TopHat(const cv::Mat &image,cv::Mat &result)
{
cv::Mat Image=image.clone();
cv::Mat Image2;
Opening(Image,Image2);
result=Image-Image2;
}
5>黑帽
闭运算的结果图与原图像之差
dst=close(src,element)-src;
突出比原图轮廓周围更暗的区域,用来分离比邻近暗的斑块
void BlackHat(const cv::Mat &image,cv::Mat &result)
{
cv::Mat Image=image.clone();
cv::Mat Image2;
Closing(Image,Image2);
result=Image2-Image;
}
5>多功能API
morphologyEx
进行形态学滤波
void morphologyEx(InputArray src, OutputArray dst,
int op, InputArray kernel,
Point anchor=Point(-1,-1), int iterations=1,
int borderType=BORDER_CONSTANT,
const Scalar& borderValue=morphologyDefaultBorderValue() )
//src的depth应该为CV_8U,CV_16U,CV_16S,CV_32F,CV_64F.
//op:
//MORPH_OPEN 开运算
//MORPH_CLOSE 闭运算
//MORPH_GRADIENT 形态学梯度
//MORPH_TOPHAT 顶帽
//MORPH_BLACKHAT 黑帽
//kernel,通过getStructuringElement()得到
三图像金字塔与图像尺寸缩放
1>尺寸调整
void resize(InputArray src, OutputArray dst, Size dsize,
double fx=0, double fy=0,
int interpolation=INTER_LINEAR )
/*dst,有着dsize的尺寸,或者由src.size()计算出来
*dsize,输出图像的大小,如果为0,通过
*dsize=Size(round(fx*src.cols),round(fy*src.rows))计算
*fx延x轴的缩放系数,如果为0,则为size.width/src.cols
*fy延y轴的缩放系数,如果为0,则为size.height/src.cols
*interpolation:
*INTER_NEAREST 最邻近插值
*INTER_LINEAR 线性插值
*INTER_AREA 区域差值_利用像素区域关系的重采样插值
*INTER_CUBIC 三次样条插值_超过4*4像素邻域内的双三次插值
*INTER_LANCZOS4 Lanczos插值_超过8*8像素邻域内的Lancaos插值
*
*缩小图像用:INTER_AREA
*放大图像用:INTER_CUBIC 效率不高 或者 INTER_LINEAR 效率高_速度快
*/
//两种使用方法
//[1]:显示指定dsize
resize(src,dst,dst.size());
//[2]:显示指定fx和fy
resize(src,dst,Size(),0.5,0.5);
2>高斯金字塔
第K层高斯金字塔通过平滑,亚采样就可以获得K+1层高斯图像。包含一系列低通滤波器。
为了获得第i+1层金字塔图像:
1)对图像i进行高斯内核卷积
2)将所有偶数行和列去除
结果图只有原图四分之一
void pyrDown(InputArray src,OutputArray dst,
const Size& dstsize=Size(),
int borderType=BORDER_DEFAULT)
//dstsize输出图像的大小,在默认值Size()情况下为
//Size((src.cols+1)/2,(src.rows+1)/2)
任何情况都要满足
首先进行卷积运算
对偶数行和列做插值
3>拉普拉斯金字塔
Li=Gi-UP(Gi+1)×g5×5
UP()操作将源图像中位置为(x,y)的像素映射到目标图像的(2x+1,2y+1)位置
void pyrUp(InputArray src, OutputArray dst,
const Size& dstsize=Size(),
int borderType=BORDER_DEFAULT )
//dstsize输出图像大小,如果默认值Size(),则
//Size(src.cols*2,src.rows*2)
都要满足: