图像之魔棒工具实现

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基本的数据结构和函数

 

[cpp] view plain copy
 
  1. //相似像素队列结构  
  2. struct Queue   
  3. {  
  4.     int x;  
  5.     int y;  
  6.     Queue* next;  
  7. };  
  8.   
  9. void getMagicWandRegion(const IplImage* src, IplImage* dst, int seedx, int seedy, int threshold)  
  10. {  
  11.     //如果传入图不是灰度图则返回  
  12.     if(!src || src->nChannels != 1)return ;  
  13.   
  14.     int width = src->width;  
  15.     int height = src->height;  
  16.     int srcWidthStep = src->widthStep;  
  17.     uchar* img = (uchar*)src->imageData;  
  18.   
  19.     //标记每个像素点是否被计算过,这里用一单通道图来标记  
  20.     IplImage* M = cvCreateImage(cvSize(width, height), 8, 1);  
  21.     int Mwidthstep = M->widthStep;  
  22.     cvZero(M);  
  23.     M->imageData[seedy * Mwidthstep + seedx] = 1;    //种子点位置为1,其它位置为0  
  24.   
  25.     //队列的两端  
  26.     int start = 0;  
  27.     int end = 1;  
  28.       
  29.     //将第一个像素点入队列  
  30.     Queue *queue = new Queue;  
  31.     queue->x = seedx;  
  32.     queue->y = seedy;  
  33.     queue->next = NULL;  
  34.     Queue *first = queue;  
  35.     Queue *last = queue;  
  36.   
  37.     //第一个像素点的值  
  38.     uchar pixel = (uchar)img[seedy * srcWidthStep + seedx];  
  39.   
  40.     while (end - start > 0)  
  41.     {  
  42.         int x = first->x;  
  43.         int y = first->y;  
  44.   
  45.         //向周围扩展搜索  
  46.         for (int yy = -1; yy<=1; yy++)  
  47.         {  
  48.             for (int xx = -1; xx<=1; xx++)  
  49.             {  
  50.                 int cx = x + xx;  
  51.                 int cy = y + yy;  
  52.                 if (cx >= 0 && cx <width && cy >=0 && cy < height)  
  53.                 {  
  54.                     //如果为相似点,那么将其入队,并标记  
  55.                     if (abs(img[cy * srcWidthStep + cx] - pixel) <= threshold && M->imageData[cy * Mwidthstep + cx] != 1)  
  56.                     {  
  57.                         Queue *node = new Queue;  
  58.                         node->x = cx;  
  59.                         node->y = cy;  
  60.                         node->next = NULL;  
  61.   
  62.                         end++;  
  63.                         last->next = node;  
  64.                         last = node;  
  65.   
  66.                         M->imageData[cy * Mwidthstep + cx] = 1;  
  67.                     }  
  68.                 }  
  69.             }  
  70.         }  
  71.         Queue* temp = first;  
  72.         first = first->next;  
  73.         delete temp;  
  74.         start++;  
  75.     }  
  76.   
  77.     //此处将图扩展区域内变为黄色,不是关键代码,代码省去  
  78.   
  79.   
  80.     cvReleaseImage(&M);  
  81. }  

 

5. 效果展示

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

 

posted @ 2017-11-13 10:23  mydddfly  阅读(904)  评论(0编辑  收藏  举报