OpenCV基础九:滤波与卷积(陆续更新)

九. 滤波与卷积

边界外推和边界处理

自定义边框

自定义外推

阈值化操作

cv::threshold函数

double	cv::threshold(
	cv::InputArray	src,
    cv::OutputArray	dst,
    double	thresh,						//阈值值
    double	maxValue,				//最大值
    int		thresholdType			//阈值处理类型
);

每种阈值化操作类型对应于第i个源像素(srci) 和阈值thresh之间的比较运算方式, 根据源像素和阈值之间的关系, 目标像素dsti可以被赋值为0, srci或给定的最大值maxValue.

cv::threshold()中thresholdType的可选项:

阈值类型操作
cv::THRESH_BINARYDSTi = (SRCi > thresh) ? MAXVALUE : 0
cv::THRESH_BINARY)INVDSTi = (SRCi > thresh) ? 0 : MAXVALUE
cv::THRESH_TRUNCDSTi = (SRCi > thresh) ? THRESH : SRCi
cv::THRESH_T0ZERODSTi = (SRCi > thresh) ? SRCi : 0
cv::THRESH_T0ZERO_INVDSTi = (SRCi > thresh) ? 0 : SRCi

Otus算法

函数cv::threshold()也可以自动决定最优的阈值, 只需要对参数thresh传递值cv::THRESH_OTUS即可.

Otus算法遍历所有可能的阈值, 然后对每个阈值结果的两类像素计算方差 σ i 2 {\sigma_i}^2 σi2(即低于阈值和高于阈值的两类像素).Otus算法计算方差使下列表达式最小:
σ i 2 = w 1 ( t ) ⋅ σ 1 2 + w 2 ( t ) ⋅ σ 2 2 {\sigma_i}^2 = w_1(t) \cdot {\sigma_1}^2 + w_2(t) \cdot {\sigma_2}^2 σi2=w1(t)σ12+w2(t)σ22
式中的 w 1 ( t ) w_1(t) w1(t) w 2 ( t ) w_2(t) w2(t)是根据两类像素的数量计算而来的权值, σ 1 2 {\sigma_1}^2 σ12 σ 2 2 {\sigma_2}^2 σ22表示两类像素的方差. 实际上, 这种方法不是一个相对高效的过程.

自适应阈值

阈值可以在整个过程中自动产生变化:

void	cv::adaptiveThreshold(
	cv::InputArray	src,					//输入图像
    cv::OutputArray	ds,					//输出图像
    double	maxValue,					//最大值
    int		adaptiveMethod,				//方法或者高斯分布
    int		thresholdType,				//阈值类型
    int		blockSize,							//块的大小
    double	C										//常数
);

根据adaptiveMethod的设置, 可以使用两种不同的自适应阈值方法. 两种方法都是逐个像素地计算自适应阈值T(x, y), 方法是通过计算每个像素位置周围的b x b区域的加权平均值然后减去常数C, 其中b由blockSize给定.

当图像中出现较大的明暗差异时, 自适应阈值非常有效. 这个函数仅醋栗单通道8位或浮点型图像, 并且要求源图像和目标图像不同.

平滑

平滑也成为"模糊", 平滑图像的目的有很多, 但通常都是为了减少噪声和伪影. 在降低分辨率的时候, 平滑也十分重要.

简单模糊和方框型滤波器

void	cv::blur(
	cv::InputArray	src,
    cv::OutputArray	dst,
    cv::Size	ksize,									//核大小
    cv::Point	anchor = cv::Point(-1, -1),		//Location of anchor point
    int		borderType = cv::BORDER_DEFAULT		//border extrapolation to use(边界插值)
);

图像中的每个值都是源图像中相应位置一个窗口(核)中像素的平均值(窗口尺寸通过ksize声明),

anchor指定计算时核与源图像的对齐方式, 默认情况下anchor位cv::Point(-1, -1), 表示核相对于滤波器剧中.

简单模糊是方框型滤波器(Box Filter)的一种特殊形式. 方框型滤波器中所有值 k i , j k_{i,j} ki,j全部相等(为1或者1/A, 其中A为滤波器的面积).

void	cv::boxFilter(
	cv::InputArray	src,
    cv::OutputArray	dst,
    int		ddepth,										//输出深度(e.g. CV_8U)
    cv::Size	ksize,
    cv::Point	anchor = cv::Point(-1, -1),
    bool	normalize = true,				//ture: divide by box area
    int		borderType = cv::BORDER_DEFAULt
);

变量ddepth的值设为-1则目标图像的深度与源图像保持一致, 否则可以设置为其他任何一种常用别名.

中值滤波器

将每个像素围绕这个像素的矩形邻域内的中值或者"中值"像素(相对于平均像素).

少量具有较大偏差的点也会严重影响到均值滤波, 中值滤波可以采用取中间点的方式来消除异常值.

void	cv::medianBlut(
	cv::InputArray	src,
    cv::OutputArray	dst,
    cv::Size	ksize
);

高斯滤波器

void	cv::GaussianBlur(
	cv::InputArray	src,
    cv::OutputArray	dst,
    cv::Size	ksize,
    double	sigmaX,								//Gaussian half-width in x-direction
    double	sigmaY = 0.0,
    int	borderType = cv::BORDER_DEFAULT		//border extrapllation to use
);

参数sigmaX表示高斯核在x方向上的sigma值(最大值的半宽); 第四个参数表示y方向上的sigam值.

若两者都设为0, 则高斯参数根据以下公式确定:
σ x = ( n x − 1 2 ) ⋅ 0.30 + 0.80 , n x = k s i z e . w i d t h − 1 \sigma_x = (\frac{n_x-1}{2})\cdot0.30 + 0.80, n_x = ksize.width-1 σx=(2nx1)0.30+0.80,nx=ksize.width1

σ y = ( n y − 1 2 ) ⋅ 0.30 + 0.80 , n y = k s i z e . h e i g h t = 1 \sigma_y = (\frac{n_y-1}{2})\cdot0.30+0.80, n_y=ksize.height=1 σy=(2ny1)0.30+0.80,ny=ksize.height=1

双边滤波器

void	cv::bilateraFilter(
	cv::InputArray	src,
    cv::OutputArray	dst,
    int	d,														//像素领域大小(最大距离)
    double	sigmaColor,						//Width param for color weight function
    double	sigmaSpace,						//width param for spatial weight function
    int	borderType = cv::BORDER_DEFAULT
);

第三个参数是像素邻域的直径d, 第四个参数是颜色空间滤波器的sigma值sigmaColor, 第五个参数是坐标空间中滤波器的sigma值sigmaSpace. 第三个参数越大, 平滑时所包括的强度(色彩)越大(因此图像的不连续性将会更显著).

双边滤波器是一种比较大的图像分析算子, 也就是边缘保持平滑.

tips:

  1. 滤波器的大小d对算法的效率有很大影响, 通常在视频处理时不大于5, 但在非实时应用是这个值可以放大到9, 你也可以在调用这个函数时将其设为-1, 函数将自动为图像计算sigmaSpcae变量的值.
  2. 实际情况中, 小的sigmaSpace值比如10会带来一个轻微的但也明显的效果; 而大的sigmaSpace值比如150会对图像产生非常显著的影响, 使图像有一种卡通的效果.
  3. 高斯模糊的过程是减缓像素在空间上的变化, 因此与邻域的关系紧密, 高斯平滑很好地减弱了噪声并且保留了小信号, 但破坏了边缘信息, 最终是高斯模糊把边缘也模糊了.
  4. 可以把双边滤波当作是高斯平滑, 只是相似程度更高的像素权值更高, 边缘更明显, 对比度更高. 双边滤波的效果就是将源图像变成一幅水彩画, 这种效果在多次迭代后效果显著, 因此这种方法在图像分割领域十分有用.

导数和梯度

索贝尔导数

void	cv::Sobel(
	cv::InputArray	src,
    cv::OutputArray	dst,
    int		ddepth,									//输出的图像深度(e.g. CV_8U)
    int		xorder,									 //x中相应导数的阶
    int		yorder,									//y中相应导数的阶
    cv::Size	ksize = 3
);

xorder和yorder是求导顺序, 其取值范围为0, 1和2. 0表示在这个方向上不进行求导(xorder和yorder不能同时取0).

Scharr滤波器

拉普拉斯变换

图像形态学

膨胀和腐蚀

最基础的形态学变换是膨胀和腐蚀, 常应用于: 消除噪声, 元素分割和连接等. 基于这两种操作, 可以实现更复杂的形态学操作, 用来定位强度峰值或孔洞, 另一种形式的图像梯度等.

膨胀是一种卷积操作, 它将目标像素的值替换为卷积核覆盖区域的局部最大值. 膨胀的作用是使填充区域生长.

与膨胀相反, 腐蚀操作计算的是核覆盖范围内的局部最小值.

tips:

图像的形态学操作通常在阈值化操作后的布尔图像上进行.

总的来说, 膨胀扩张了明亮区域, 腐蚀缩减了明亮区域. 另外, 膨胀填充凹面, 腐蚀消除突起.

//腐蚀
void	cv::erode(
	cv::InputArray	src,
    cv::OutputArray	dst,
    cv::InputArray	element,											//Structuring, a cv::Mat()
    cv::Point	anchor = cv::Point(-1, -1),
    int	iterations = 1,															//迭代次数
    int	borderType = cv::BORDER_CONSTANT,
    const cv::Scalar& borderValue = cv::morphologyDefaultBorderValue()
);
//膨胀
void	cv::dilate(
	cv::InputArray	src,
    cv::OutputArray	dst,
    cv::InputArray	element,
    cv::Point	anchor = cv::Point(-1, -1),
    int	iterations = 1,
    int	borderType = cv::BORDER_CONSTAN,
    const	cv::Scalar&	borderValue = cv::morphologyDefaultBorderValue()
);

腐蚀和膨胀支持原地调用(源图像和目标图像是同一副图像).

第三个元素是核, 可以向它传递一个未被初始化的cv::Mat().
膨胀
腐蚀

通用形态学操作

void	cv::morphologEx(
	cv::InputArray	src,
    cv::OutputArray	dst,
    int	op,
    cv::InputArray	element,
    cv::Point	anchor = cv::Point(-1, -1),
    int	iterations = 1,
    int	borderType = cv::BORDER_DEFUALT,
    const	cv::Scalar&	borderValue = cv::morphologyDefaultBorderValue()
);

参数op:

操作值形态学操作是否需要临时图像
cv::MOP_OPEN开操作
cv::MOP_CLOSE闭操作
cv::MOP_GRADIENT形态学梯度总是需要
cv::MOP_TOPHAT顶帽操作就地调用需要(src = dst)
cv::MOP_BLACKHAT底帽操作就地调用需要(src = dst)

开操作和闭操作

  1. 开操作先将图像腐蚀,然后对腐蚀的结果膨胀(常用于对二值图像中的区域进行计数)(放大裂缝和局部小洞)
  2. 闭操作先将图像进行膨胀, 然后对膨胀的结果进行腐蚀(常用于减少无用或噪声驱动的片段)

形态学梯度

顶帽和黑帽

分别用于显示与其邻域相比更亮或更暗的部分.
T o p H a t ( s r c ) = s r c − o p e n ( s r c ) TopHat(src) = src - open(src) TopHat(src)=srcopen(src)

B l a c k H a t ( s r c ) = c l o s e ( s r c ) − s r c BlackHat(src) = close(src) - src BlackHat(src)=close(src)src

顶帽操作用源图像减去对其开操作后的图像

黑帽操作用闭操作后的图像减去源图像

自定义核

自定义形态学核的函数:

cv::Mat	cv::getStructuringElement(
	int	shapce,													//Element shape
    cv::Size	ksize,											//size fo structuring element(odd num!)
    cv::Point	anchor = cv::Point(-1, -1)	//默认锚点在元素中心
);

第一个参数控制构造元素的基本形状, 第二第三个参数确定元素的大小和锚点位置.

cv::getStructuringElement()的元素形状:

形状值元素描述
cv::MORPH_RECT矩形 E i , j = 1 , ∀ i , j E_{i,j}=1,\forall{i,j} Ei,j=1,i,j
cv::MORPH_ELLIPSE椭圆形以ksize, width和ksize,height为
两个半径做椭圆
cv::MORPH_CROSS交叉 E i , j = 1 E_{i,j}=1 Ei,j=1 i = = a n c h o r . y i==anchor.y i==anchor.y j = = a n c h o r . x j==anchor.x j==anchor.x

用线性滤波器做卷积

用cv::filter2D()做卷积

通过cv::sepFilter2D使用可分核

生成卷积核

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值