图像之魔棒工具实现

   这是以前发的一篇文章,虽然自己已经在csdn上发布了第二篇类似文章,现在还是都发上来。

   原文地址:http://nbcoders.com/tu-xiang-zhi-mo-bang-gong-ju.html

魔棒工具对于做过ps的同学应该都不陌生,本文就介绍下魔棒工具在图像中的实现原理以及实现。

1.魔棒工具

还是用一组图来介绍下魔棒工具的使用

图像之魔棒工具实现_第1张图片

如上图所示,魔棒工具就是能够快速选中并抠去选中区域的小工具。

2.解决思路

因为才不久做了一个程序效果很类似,使用的阀值分割边缘检测来做。所以,当看到要实现这个效果的时候我的第一反应便是朝着这个

方向去了。通过阀值分割将图片的颜色区域进行分类,再在这个类别中选中其中的特定类别。或者是通过边缘检测方式检测出边缘后,再得出边缘中所围住选中的那个像素点的区域。刚开始想的思路大致是这样。

当看到PS的魔棒工具中的参数后,思路基本就确定了。思路并不是通过阀值分割和边缘检测,而是通过计算周围与该像素点的相似像素的一个区域。即点中一个像素点,该像素点向周围扩张,找取与该像素点相似的像素点的一个区域。ps中参数如下图:

               

ps中对自动选中某个区域效果最主要的是前面两个参数:取样大小和容差。其中取样大小是进行计算时,不是只是单个计算,是计算这个像素周围领域的平均值来比较像素值的相似度。

3.实现步骤

1.如何找出相似点

方式是通过将图转化成灰图,灰度图是像素从由浅到深进行分类。如果灰度像素差值在一定范围类,那么将两像素视为相似。

2.如何找出选中区域

通过鼠标点中图的点向周期扩张成一个相似区域。将与该像素值相似的点放入相似队列 中,再找出相邻8领域中的点。直到找出所有的点。大致方式如下图所所示

    图像之魔棒工具实现_第2张图片

4. 关键函数实现

这里的实现方式是通过OpenCV实现,但也只是用了OpenCV基本的数据结构和函数

//相似像素队列结构
struct Queue 
{
	int x;
	int y;
	Queue* next;
};

void getMagicWandRegion(const IplImage* src, IplImage* dst, int seedx, int seedy, int threshold)
{
	//如果传入图不是灰度图则返回
	if(!src || src->nChannels != 1)return ;

	int width = src->width;
	int height = src->height;
	int srcWidthStep = src->widthStep;
	uchar* img = (uchar*)src->imageData;

	//标记每个像素点是否被计算过,这里用一单通道图来标记
	IplImage* M = cvCreateImage(cvSize(width, height), 8, 1);
	int Mwidthstep = M->widthStep;
	cvZero(M);
	M->imageData[seedy * Mwidthstep + seedx] = 1;    //种子点位置为1,其它位置为0

	//队列的两端
	int start = 0;
	int end = 1;
	
	//将第一个像素点入队列
	Queue *queue = new Queue;
	queue->x = seedx;
	queue->y = seedy;
	queue->next = NULL;
	Queue *first = queue;
	Queue *last = queue;

	//第一个像素点的值
	uchar pixel = (uchar)img[seedy * srcWidthStep + seedx];

	while (end - start > 0)
	{
		int x = first->x;
		int y = first->y;

		//向周围扩展搜索
		for (int yy = -1; yy<=1; yy++)
		{
			for (int xx = -1; xx<=1; xx++)
			{
				int cx = x + xx;
				int cy = y + yy;
				if (cx >= 0 && cx =0 && cy < height)
				{
					//如果为相似点,那么将其入队,并标记
					if (abs(img[cy * srcWidthStep + cx] - pixel) <= threshold && M->imageData[cy * Mwidthstep + cx] != 1)
					{
						Queue *node = new Queue;
						node->x = cx;
						node->y = cy;
						node->next = NULL;

						end++;
						last->next = node;
						last = node;

						M->imageData[cy * Mwidthstep + cx] = 1;
					}
				}
			}
		}
		Queue* temp = first;
		first = first->next;
		delete temp;
		start++;
	}

	//此处将图扩展区域内变为黄色,不是关键代码,代码省去


	cvReleaseImage(&M);
}

5. 效果展示

    这里直接将素相似区域(魔棒相似区域设置为黄色)

图像之魔棒工具实现_第3张图片 

你可能感兴趣的:(数字图像处理,Opencv,C++)