金字塔及其应用
PyrDown
图像的下采样
void cvPyrDown( const CvArr* src, CvArr* dst, int filter=CV_GAUSSIAN_5x5 );
-
src
- 输入图像. dst
- 输出图像, 宽度和高度应是输入图像的一半 filter
-
卷积滤波器的类型,目前仅支持
CV_GAUSSIAN_5x5
函数 cvPyrDown 使用 Gaussian 金字塔分解对输入图像向下采样。首先它对输入图像用指定滤波器进行卷积,然后通过拒绝偶数的行与列来下采样图像。
PyrUp
图像的上采样
void cvPyrUp( const CvArr* src, CvArr* dst, int filter=CV_GAUSSIAN_5x5 );
-
src
- 输入图像. dst
- 输出图像, 宽度和高度应是输入图像的2倍 filter
-
卷积滤波器的类型,目前仅支持
CV_GAUSSIAN_5x5
函数 cvPyrUp 使用Gaussian 金字塔分解对输入图像向上采样。首先通过在图像中插入 0 偶数行和偶数列,然后对得到的图像用指定的滤波器进行高斯卷积,其中滤波器乘以4做差值。所以输出图像是输入图像的 4 倍大小。(hunnish: 原理不清楚,尚待探讨)
PyrSegmentation
用金字塔实现图像分割
void cvPyrSegmentation( IplImage* src, IplImage* dst, CvMemStorage* storage, CvSeq** comp, int level, double threshold1, double threshold2 );
-
src
- 输入图像. dst
- 输出图像. storage
- Storage: 存储连通部件的序列结果 comp
- 分割部件的输出序列指针 components. level
- 建立金字塔的最大层数 threshold1
- 建立连接的错误阈值 threshold2
- 分割簇的错误阈值
函数 cvPyrSegmentation 实现了金字塔方法的图像分割。金字塔建立到 level
指定的最大层数。如果 p(c(a),c(b))<threshold1
,则在层 i 的象素点 a 和它的相邻层的父亲象素 b 之间的连接被建立起来,
定义好连接部件后,它们被加入到某些簇中。如果p(c(A),c(B))<threshold2
,
则任何两个分割 A 和 B 属于同一簇。
如果输入图像只有一个通道,那么
p(c¹,c²)=|c¹-c²|
.
如果输入图像有单个通道(红、绿、兰),那么
p(c¹,c²)=0,3·(c¹r-c²r)+0,59·(c¹g-c²g)+0,11·(c¹b-c²b)
.
每一个簇可以有多个连接部件。
src
和
dst
应该是 8-比特、单通道 或 3-通道图像,且大小一样
连接部件
CvConnectedComp
连接部件
typedef struct CvConnectedComp { double area; /* 连通域的面积 */ float value; /* 分割域的灰度缩放值 */ CvRect rect; /* 分割域的 ROI */ } CvConnectedComp;
FloodFill
用指定颜色填充一个连接域
void cvFloodFill( CvArr* image, CvPoint seed_point, CvScalar new_val, CvScalar lo_diff=cvScalarAll(0), CvScalar up_diff=cvScalarAll(0), CvConnectedComp* comp=NULL, int flags=4, CvArr* mask=NULL ); #define CV_FLOODFILL_FIXED_RANGE (1 << 16) #define CV_FLOODFILL_MASK_ONLY (1 << 17)
-
image
- 输入的 1- 或 3-通道, 8-比特或浮点数图像。输入的图像将被函数的操作所改变,除非你选则 CV_FLOODFILL_MASK_ONLY 选项 (见下面). seed_point
- 开始的种子点. new_val
- 新的重新绘制的象素值 lo_diff
-
当前观察象素值与其部件领域象素或者待加入该部件的种子象素之负差(Lower difference)的最大值。对 8-比特 彩色图像,它是一个 packed value.
up_diff
- 当前观察象素值与其部件领域象素或者待加入该部件的种子象素之正差(upper difference)的最大值。 对 8-比特 彩色图像,它是一个 packed value. comp
- 指向部件结构体的指针,该结构体的内容由函数用重绘区域的信息填充。 flags
-
操作选项. 低位比特包含连通值, 4 (缺省) 或 8, 在函数执行连通过程中确定使用哪种邻域方式。高位比特可以是 0 或下面的开关选项的组合:
- CV_FLOODFILL_FIXED_RANGE - 如果设置,则考虑当前象素与种子象素之间的差,否则考虑当前象素与其相邻象素的差。(范围是浮点数).
- CV_FLOODFILL_MASK_ONLY - 如果设置,函数不填充原始图像 (忽略
new_val
), 但填充面具图像 (这种情况下 MASK 必须是非空的).
mask
-
运算面具, 应该是单通道、8-比特图像, 长和宽上都比输入图像
image
大两个象素点。若非空,则函数使用且更新面具, 所以使用者需对mask
内容的初始化负责。填充不会经过 MASK 的非零象素, 例如,一个边缘检测子的输出可以用来作为 MASK 来阻止填充边缘。或者有可能在多次的函数调用中使用同一个 MASK,以保证填充的区域不会重叠。注意: 因为 MASK 比欲填充图像大,所以mask
中与输入图像(x,y)像素点相对应的点具有(x+1,y+1)坐标。
函数 cvFloodFill 用指定颜色,从种子点开始填充一个连通域。连通性有象素值的接近程度来衡量。在点 (x, y)
的象素被认为是属于重新绘制的区域,如果:
src(x',y')-lo_diff<=src(x,y)<=src(x',y')+up_diff, 灰度图像,浮动范围 src(seed.x,seed.y)-lo<=src(x,y)<=src(seed.x,seed.y)+up_diff, 灰度图像,固定范围 src(x',y')r-lo_diffr<=src(x,y)r<=src(x',y')r+up_diffr 和 src(x',y')g-lo_diffg<=src(x,y)g<=src(x',y')g+up_diffg 和 src(x',y')b-lo_diffb<=src(x,y)b<=src(x',y')b+up_diffb, 彩色图像,浮动范围 src(seed.x,seed.y)r-lo_diffr<=src(x,y)r<=src(seed.x,seed.y)r+up_diffr 和 src(seed.x,seed.y)g-lo_diffg<=src(x,y)g<=src(seed.x,seed.y)g+up_diffg 和 src(seed.x,seed.y)b-lo_diffb<=src(x,y)b<=src(seed.x,seed.y)b+up_diffb, 彩色图像,固定范围其中
src(x',y')
是象素邻域点的值。也就是说,为了被加入到连通域中,一个象素的彩色/亮度应该足够接近于:
- 它的邻域象素的彩色/亮度值,当该邻域点已经被认为属于浮动范围情况下的连通域。
- 固定范围情况下的种子点的彩色/亮度值
FindContours
在二值图像中寻找轮廓
int cvFindContours( CvArr* image, CvMemStorage* storage, CvSeq** first_contour, int header_size=sizeof(CvContour), int mode=CV_RETR_LIST, int method=CV_CHAIN_APPROX_SIMPLE, CvPoint offset=cvPoint(0,0) );
-
image
- 输入的 8-比特、单通道图像. 非零元素被当成 1, 0 象素值保留为 0 - 从而图像被看成二值的。为了从灰度图像中得到这样的二值图像,可以使用 cvThreshold, cvAdaptiveThreshold 或 cvCanny. 本函数改变输入图像内容。 storage
- 得到的轮廓的存储容器 first_contour
- 输出参数:包含第一个输出轮廓的指针 header_size
-
如果
method
=CV_CHAIN_CODE,则序列头的大小 >=sizeof( CvChain),否则 >=sizeof(CvContour) .
mode
-
提取模式.
CV_RETR_EXTERNAL
- 只提取最外层的轮廓CV_RETR_LIST
- 提取所有轮廓,并且放置在 list 中CV_RETR_CCOMP
- 提取所有轮廓,并且将其组织为两层的 hierarchy: 顶层为连通域的外围边界,次层为洞的内层边界。CV_RETR_TREE
- 提取所有轮廓,并且重构嵌套轮廓的全部 hierarchy
method
-
逼近方法 (对所有节点, 不包括使用内部逼近的
CV_RETR_RUNS
).CV_CHAIN_CODE
- Freeman 链码的输出轮廓. 其它方法输出多边形(定点序列).CV_CHAIN_APPROX_NONE
- 将所有点由链码形式翻译为点序列形式CV_CHAIN_APPROX_SIMPLE
- 压缩水平、垂直和对角分割,即函数只保留末端的象素点;CV_CHAIN_APPROX_TC89_L1,
- 应用 Teh-Chin 链逼近算法.CV_CHAIN_APPROX_TC89_KCOSCV_LINK_RUNS
- 通过连接为 1 的水平碎片使用完全不同的轮廓提取算法。仅有CV_RETR_LIST
提取模式可以在本方法中应用.
函数 cvFindContours 从二值图像中提取轮廓,并且返回提取轮廓的数目。指针 first_contour
的内容由函数填写。它包含第一个最外层轮廓的指针,如果指针为 NULL,则没有检测到轮廓(比如图像是全黑的)。其它轮廓可以从 first_contour 利用
h_next
和 v_next
链接访问到。 在 cvDrawContours 的样例显示如何使用轮廓来进行连通域的检测。轮廓也可以用来做形状分析和对象识别 - 见CVPR2001 教程中的 squares
样例。该教程可以在 SourceForge 网站上找到。
StartFindContours
初始化轮廓的扫描过程
CvContourScanner cvStartFindContours( CvArr* image, CvMemStorage* storage, int header_size=sizeof(CvContour), int mode=CV_RETR_LIST, int method=CV_CHAIN_APPROX_SIMPLE, CvPoint offset=cvPoint(0,0) );
-
image
- 输入的 8-比特、单通道二值图像 storage
- 提取到的轮廓容器 header_size
-
序列头的尺寸 >=sizeof(
CvChain) 若
method
=CV_CHAIN_CODE,否则尺寸 >=sizeof(CvContour) .
mode
- 提取模式,见 cvFindContours. method
- 逼近方法。它与 cvFindContours 里的定义一样,但是 CV_LINK_RUNS 不能使用。 offset
- ROI 偏移量,见 cvFindContours.
函数 cvStartFindContours 初始化并且返回轮廓扫描器的指针。扫描器在 cvFindNextContour 使用以提取其余的轮廓。
FindNextContour
Finds next contour in the image
CvSeq* cvFindNextContour( CvContourScanner scanner );
-
scanner
- 被函数 cvStartFindContours 初始化的轮廓扫描器.
函数 cvFindNextContour 确定和提取图像的下一个轮廓,并且返回它的指针。若没有更多的轮廓,则函数返回 NULL.
SubstituteContour
替换提取的轮廓
void cvSubstituteContour( CvContourScanner scanner, CvSeq* new_contour );
-
scanner
- 被函数 cvStartFindContours 初始化的轮廓扫描器 .. new_contour
- 替换的轮廓
函数 cvSubstituteContour 把用户自定义的轮廓替换前一次的函数 cvFindNextContour 调用所提取的轮廓,该轮廓以用户定义的模式存储在边缘扫描状态之中。轮廓,根据提取状态,被插入到生成的结构,List,二层 hierarchy, 或 tree 中。如果参数 new_contour
=NULL, 则提取的轮廓不被包含入生成结构中,它的所有后代以后也不会被加入到接口中。
EndFindContours
结束扫描过程
CvSeq* cvEndFindContours( CvContourScanner* scanner );
-
scanner
- 轮廓扫描的指针.
函数 cvEndFindContours 结束扫描过程,并且返回最高层的第一个轮廓的指针。