金字塔图像分割原理解析与示例[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;
}
结果图:



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

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值