http://blog.csdn.net/ixshells/article/details/41278955
这是以前发的一篇文章,虽然自己已经在csdn上发布了第二篇类似文章,现在还是都发上来。
原文地址:http://nbcoders.com/tu-xiang-zhi-mo-bang-gong-ju.html
魔棒工具对于做过ps的同学应该都不陌生,本文就介绍下魔棒工具在图像中的实现原理以及实现。
1.魔棒工具
还是用一组图来介绍下魔棒工具的使用
如上图所示,魔棒工具就是能够快速选中并抠去选中区域的小工具。
2.解决思路
因为才不久做了一个程序效果很类似,使用的阀值分割和边缘检测来做。所以,当看到要实现这个效果的时候我的第一反应便是朝着这个
方向去了。通过阀值分割将图片的颜色区域进行分类,再在这个类别中选中其中的特定类别。或者是通过边缘检测方式检测出边缘后,再得出边缘中所围住选中的那个像素点的区域。刚开始想的思路大致是这样。
当看到PS的魔棒工具中的参数后,思路基本就确定了。思路并不是通过阀值分割和边缘检测,而是通过计算周围与该像素点的相似像素的一个区域。即点中一个像素点,该像素点向周围扩张,找取与该像素点相似的像素点的一个区域。ps中参数如下图:
ps中对自动选中某个区域效果最主要的是前面两个参数:取样大小和容差。其中取样大小是进行计算时,不是只是单个计算,是计算这个像素周围领域的平均值来比较像素值的相似度。
3.实现步骤
1.如何找出相似点
方式是通过将图转化成灰图,灰度图是像素从由浅到深进行分类。如果灰度像素差值在一定范围类,那么将两像素视为相似。
2.如何找出选中区域
通过鼠标点中图的点向周期扩张成一个相似区域。将与该像素值相似的点放入相似队列 中,再找出相邻8领域中的点。直到找出所有的点。大致方式如下图所所示
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 <width && cy >=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. 效果展示
这里直接将素相似区域(魔棒相似区域设置为黄色)