金字塔图像分割原理解析与示例[opencv]

图像分割指的是将数字图像细分为多个图像子区域的过程,在OpenCv中实现了三种跟图像分割相关的算法,它们分别是:金字塔分割算法,分水岭分割算法以及均值漂移分割算法。它们的使用过程都很简单,刚开始学习opencv,先记录一下我对金字塔分割原理的理解吧。

金字塔分割算法

金字塔分割算法由cvPrySegmentation所实现,该函数的使用还是比较简单;需要注意的是图像的尺寸以及金字塔的层数,图像的宽度和高度必须能被2整除,能够被2整除的次数决定了金字塔的最大层数。下面的代码演示了如何校验金字塔层数:

/// <summary>/// 当改变金字塔分割的参数“金字塔层数”时,对参数进行校验/// </summary>private void txtPSLevel_TextChanged(object sender, EventArgs e){int level = int.Parse(txtPSLevel.Text);if (level < 1 || imageSource.Width % (int)(Math.Pow(2, level – 1)) != 0 || imageSource.Height % (int)(Math.Pow(2, level – 1)) != 0){MessageBox.Show(this, "输入的金字塔层数不符合要求,计算结果可能会无效。", "金字塔层数错误!")}

opencv中有分装好的函数库,

void pyrMeanShiftFiltering( 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(c1,c2)=|c1-c2|. 如果输入图像有单个通道(红、绿、兰),那幺 p(c1,c2)=0,3·(c1r-c2r)+0,59·(c1g-c2g)+0,11·(c1b-c2b) . 每一个簇可以有多个连接部件。

图像 src 和 dst 应该是 8-比特、单通道 或 3-通道图像,且大小一样 Threshold1,Threshold2的解读:金字塔分割先通过p(c(a),c(b))<threshold1在像素a,b…中找连通域,也就是所谓的连接部件A,B… 第二步通过p(c(A),c(B))<threshold2判断两个联通与是否属于同一个簇,簇即使我们最后得到的分割结果。

这是一个测试例子:

#include <opencv2/core/core.hpp>#include <opencv2/highgui/highgui.hpp>#include <opencv2/imgproc/imgproc.hpp>#include <iostream>using namespace cv;using namespace std;Mat src, dst;int spatialRad , colorRad , maxPryLevel; //空间,颜色,金字塔层数void meanshift_seg(){////调用meanshift图像金字塔进行分割pyrMeanShiftFiltering(src, dst, spatialRad, colorRad, maxPryLevel); RNG rng = theRNG();Mat mask(dst.rows + 2, dst.cols + 2, CV_8UC1, Scalar::all(0));for (int i = 0; i<dst.rows; i++) //opencv图像等矩阵也是基于0索引for (int j = 0; j<dst.cols; j++)if (mask.at<uchar>(i + 1, j + 1) == 0){Scalar newcolor(rng(256), rng(256), rng(256));floodFill(dst, mask, Point(j, i), newcolor, 0, Scalar::all(1), Scalar::all(1));}imshow("结果图像", dst);}void meanshift_seg_s(int i, void *) //控制滑动块{spatialRad = i;meanshift_seg();}void meanshift_seg_c(int i, void *){colorRad = i;meanshift_seg();}void meanshift_seg_m(int i, void *){maxPryLevel = i;meanshift_seg();}int main(int argc, uchar* argv[]){namedWindow("载入原图像", WINDOW_AUTOSIZE);namedWindow("结果图像", WINDOW_AUTOSIZE);src = imread("../pict1.jpg");CV_Assert(!src.empty());spatialRad = 10;colorRad = 10;maxPryLevel = 1;createTrackbar("空间度", "结果图像", &spatialRad, 80, meanshift_seg_s);createTrackbar("色度", "结果图像", &colorRad, 255, meanshift_seg_c);createTrackbar("金字塔层级", "结果图像", &maxPryLevel, 5, meanshift_seg_m);imshow("载入原图像", src);imshow("结果图像", src);waitKey();return 0;}结果图:

可以调节,当金字塔层级越高时候,切割效果越明显。好了,今天就不写了,我去上课了,后面继续。。。

如此锐气,二十后生有之,六旬男子则更多见。

金字塔图像分割原理解析与示例[opencv]

相关文章:

你感兴趣的文章:

标签云: