图像孔洞填充与小连通域的删除

2024-02-02 11:38

本文主要是介绍图像孔洞填充与小连通域的删除,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

图像孔洞填充与小连通域的删除

 

cvFindContours

 从二值图像中检索轮廓,并返回检测到的轮廓的个数。first_contour的值由函数填充返回,它的值将为第一个外轮廓的指针,当没有轮廓被检测到时为NULL。其它轮廓可以使用h_next和v_next连接,从first_contour到达。

int cvFindContours( CvArr* image, CvMemStorage* storage, CvSeq** first_contour,                                                                                               

                  int header_size=sizeof(CvContour), int mode=CV_RETR_LIST,                                        

                  int method=CV_CHAIN_APPROX_SIMPLE, CvPoint offset=cvPoint(0,0) );         

image

8比特单通道的源二值图像。非零像素作为1处理,0像素保存不变。从一个灰度图像得到二值图像的函数有:cvThreshold,cvAdaptiveThreshold和cvCanny。

storage

返回轮廓的容器。

first_contour

输出参数,用于存储指向第一个外接轮廓。

header_size

header序列的尺寸.如果选择method = CV_CHAIN_CODE, 则header_size >= sizeof(CvChain);其他,则

header_size >= sizeof(CvContour)。

mode

CV_RETR_EXTERNAL:只检索最外面的轮廓;

CV_RETR_LIST:检索所有的轮廓,并将其放入list中;

CV_RETR_CCOMP:检索所有的轮廓,并将他们组织为两层:顶层是各部分的外部边界,第二层是空洞的边界;

CV_RETR_TREE:检索所有的轮廓,并重构嵌套轮廓的整个层次。

 

蓝色表示v_next,绿色表示h_next

method

边缘近似方法(除了CV_RETR_RUNS使用内置的近似,其他模式均使用此设定的近似算法)。可取值如下:

CV_CHAIN_CODE:以Freeman链码的方式输出轮廓,所有其他方法输出多边形(顶点的序列)。

CV_CHAIN_APPROX_NONE:将所有的连码点,转换成点。

CV_CHAIN_APPROX_SIMPLE:压缩水平的、垂直的和斜的部分,也就是,函数只保留他们的终点部分。

CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS:使用the flavors of Teh-Chin chain近似算法

的一种。

CV_LINK_RUNS:通过连接水平段的1,使用完全不同的边缘提取算法。使用CV_RETR_LIST检索模式能使用此方法。

offset

偏移量,用于移动所有轮廓点。当轮廓是从图像的ROI提取的,并且需要在整个图像中分析时,这个参数将很有用。

讨论部分cvDrawContours中的案例显示了任何使用轮廓检测连通区域。轮廓可以用于形状分析和目标识别——可以参考文件夹OpenCV sample中的squares.c

 

 

cvDrawContours

cvDrawContours:在图像上绘制外部和内部轮廓

函数cvDrawContours用于在图像上绘制外部和内部轮廓。当thickness >= 0 时,绘制轮廓线;否则填充由轮廓包围的部分。

void cvDrawContours( CvArr *img, CvSeq* contour,CvScalar external_color, CvScalar hole_color,                                                      

                      int max_level, int thickness=1, int line_type=8, CvPoint offset=cvPoint(0,0) );                                                                                                   

Img 要在其上绘制轮廓的图像。和在其他绘图函数里一样,轮廓是ROI的修剪结果。

Contour  指向第一个轮廓的指针。

external_color  外轮廓的颜色。

hole_color    内轮廓的颜色。      

max_level   画轮廓的最大层数。如果是0,只绘制contour;如果是1,将绘制contour后和contour同层的所有  

            轮廓;如果是2,绘制contour后所有同层和低一层的轮廓,以此类推;如果值是负值,则函数并不

            绘制contour后的轮廓,但是将画出其子轮廓,一直到abs(max_level) - 1层。

thickness

绘制轮廓线的宽度。如果为负值(例如,等于CV_FILLED),则contour内部将被绘制。

line_type

轮廓线段的类型,具体查看cvLine的描述。

offset

按给定值移动所有点的坐标。

 

 

cvContourArea

double cvContourArea( const CvArr* contour, CvSliceslice=CV_WHOLE_SEQ );
contour:轮廓(顶点的序列或数组)。
slice:感兴趣区轮廓部分的起点和终点,默认计算整个轮廓的面积。
函数cvContourArea计算整个或部分轮廓的面积。在计算部分轮廓的情况时,由轮廓弧线和连接两端点的弦
围成的区域总面积被计算

 

 

 

 
  1.  
  2.  
  3.  
  4. #include <stdio.h>

  5. #include <cv.h>

  6. #include <cxcore.h>

  7. #include <highgui.h>

  8.  
  9.  
  10. // 内轮廓填充

  11. // 参数:

  12. // 1. pBinary: 输入二值图像,单通道,位深IPL_DEPTH_8U。

  13. // 2. dAreaThre: 面积阈值,当内轮廓面积小于等于dAreaThre时,进行填充。

  14. void FillInternalContours(IplImage *pBinary, double dAreaThre)

  15. {

  16. double dConArea;

  17. CvSeq *pContour = NULL; //创建一序列

  18. CvSeq *pConInner = NULL;

  19. CvMemStorage *pStorage = NULL; //用来创建一个内存存储器,来统一管理各种动态对象的内存,比如说序列,这个函数返回一个新创建的内存存储器指针。

  20.  
  21.  
  22. // 执行条件

  23. if (pBinary)

  24. {

  25. // 查找所有轮廓

  26. pStorage = cvCreateMemStorage(0); //创建一个内存存储器,为0时内存块默认大小为64k,申请一块内存来存储找到的轮廓序列

  27. cvFindContours(pBinary, pStorage, &pContour, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE); //从二值图像中检索轮廓,并返回检测到的轮廓的个数

  28. // 源二值图、容器、第一个外轮廓指针、head序列大小、轮廓分两层、边缘只保留终点

  29. cvDrawContours(pBinary, pContour, CV_RGB(255, 255, 255), CV_RGB(255, 255, 255), 2, CV_FILLED, 8, cvPoint(0, 0)); //在图像上绘制外部和内部轮廓

  30. // 源二值图、第一个轮廓的指针、外轮廓的颜色、内轮廓的颜色、画两层轮廓、绘制轮廓线的宽度、轮廓线段的类型、按给定值移动所有点的坐标。

  31. // 外轮廓循环

  32. int wai = 0;

  33. int nei = 0;

  34. for (; pContour != NULL; pContour = pContour->h_next) //对检测到的轮廓进行逐一处理,h_next为下一个轮廓

  35. {

  36. wai++;

  37. // 内轮廓循环

  38. for (pConInner = pContour->v_next; pConInner != NULL; pConInner = pConInner->h_next)

  39. {

  40. nei++;

  41. dConArea = fabs(cvContourArea(pConInner, CV_WHOLE_SEQ));// 内轮廓面积

  42. printf("%f\n", dConArea);

  43. if (dConArea <= dAreaThre) //只处理满足条件的轮廓,不满足条件的轮廓扔掉

  44. {

  45. cvDrawContours(pBinary, pConInner, CV_RGB(255, 255, 255), CV_RGB(255, 255, 255), 0, CV_FILLED, 8, cvPoint(0, 0));

  46. } // 源二值图、第一个轮廓的指针、外轮廓的颜色、内轮廓的颜色、画第一个外轮廓、绘制轮廓线的宽度、轮廓线段的类型、按给定值移动所有点的坐标。

  47. }

  48. }

  49. printf("wai = %d, nei = %d", wai, nei);

  50. cvReleaseMemStorage(&pStorage);

  51. pStorage = NULL;

  52. }

  53. }

  54.  
  55. int Otsu(IplImage* src)

  56. {

  57. int height=src->height;

  58. int width=src->width;

  59.  
  60. //histogram

  61. float histogram[256] = {0};

  62. for(int i=0; i < height; i++)

  63. {

  64. unsigned char* p=(unsigned char*)src->imageData + src->widthStep * i;

  65. for(int j = 0; j < width; j++)

  66. {

  67. histogram[*p++]++;

  68. }

  69. }

  70. //normalize histogram

  71. int size = height * width;

  72. for(int i = 0; i < 256; i++)

  73. {

  74. histogram[i] = histogram[i] / size;

  75. }

  76.  
  77. //average pixel value

  78. float avgValue=0;

  79. for(int i=0; i < 256; i++)

  80. {

  81. avgValue += i * histogram[i]; //整幅图像的平均灰度

  82. }

  83.  
  84. int threshold;

  85. float maxVariance=0;

  86. float w = 0, u = 0;

  87. for(int i = 0; i < 256; i++)

  88. {

  89. w += histogram[i]; //假设当前灰度i为阈值, 0~i 灰度的像素(假设像素值在此范围的像素叫做前景像素) 所占整幅图像的比例

  90. u += i * histogram[i]; // 灰度i 之前的像素(0~i)的平均灰度值: 前景像素的平均灰度值

  91.  
  92. float t = avgValue * w - u;

  93. float variance = t * t / (w * (1 - w) );

  94. if(variance > maxVariance)

  95. {

  96. maxVariance = variance;

  97. threshold = i;

  98. }

  99. }

  100.  
  101. return threshold;

  102. }

  103.  
  104.  
  105.  
  106. void DeleteIslet(IplImage* pic1,IplImage** pic0)

  107. {

  108. /************删除二值化图像中面积较小的连通域****************************/

  109. CvSeq* contour = NULL;

  110. double minarea =300.0;

  111. double tmparea = 0.0;

  112.  
  113. CvMemStorage* storage = cvCreateMemStorage(0);

  114.  
  115. IplImage* img_Clone=cvCloneImage(pic1);

  116. //访问二值图像每个点的值

  117. uchar *pp;

  118. IplImage* img_dst = cvCreateImage(cvGetSize(pic1),IPL_DEPTH_8U,1);

  119.  
  120. //------------搜索二值图中的轮廓,并从轮廓树中删除面积小于某个阈值minarea的轮廓-------------//

  121. CvScalar color = cvScalar(255,0,0);//CV_RGB(128,0,0);

  122. CvContourScanner scanner = NULL;

  123. scanner = cvStartFindContours(pic1,storage,sizeof(CvContour),CV_RETR_CCOMP,CV_CHAIN_APPROX_NONE,cvPoint(0,0));

  124. //开始遍历轮廓树

  125. CvRect rect;

  126. while (contour==cvFindNextContour(scanner))

  127. {

  128. tmparea = fabs(cvContourArea(contour));

  129. rect = cvBoundingRect(contour,0);

  130. if (tmparea < minarea/*||tmparea>4900*/)

  131. {

  132.  
  133. //当连通域的中心点为黑色时,而且面积较小则用白色进行填充

  134. pp=(uchar*)(img_Clone->imageData + img_Clone->widthStep*(rect.y+rect.height/2)+rect.x+rect.width/2);

  135. if (pp[0]==0)

  136. {

  137. for(int y = rect.y;y<rect.y+rect.height;y++)

  138. {

  139. for(int x =rect.x;x<rect.x+rect.width;x++)

  140. {

  141. pp=(uchar*)(img_Clone->imageData + img_Clone->widthStep*y+x);

  142.  
  143. if (pp[0]==0)

  144. {

  145. pp[0]=255;

  146. }

  147. }

  148. }

  149. }

  150.  
  151. }

  152. }

  153.  
  154. *pic0=img_Clone;

  155. }

  156.  
  157.  
  158.  
  159.  
  160.  
  161.  
  162.  
  163.  
  164. int main( )

  165. {

  166. IplImage* oringin=cvLoadImage("test.bmp",1);

  167. IplImage* pic1=cvLoadImage("test.bmp",0);

  168. IplImage* pic2=NULL;

  169. DeleteIslet(pic1,&pic2); //删除小联通域

  170.  
  171. IplImage* pic3=cvCloneImage(pic2); //取反再删除

  172. cvNot(pic2,pic3);

  173. IplImage* pic4=NULL;

  174. DeleteIslet(pic3,&pic4);

  175.  
  176. /**************孔洞填充*********************/

  177. IplImage* pic5 = cvCreateImage(cvGetSize(pic4), 8, 1);

  178. int thresh = Otsu(pic4);

  179. cvThreshold(pic4,pic5, thresh, 255, CV_THRESH_BINARY);

  180.  
  181. FillInternalContours(pic5, 200);

  182.  
  183. IplImage* pic6 = cvCreateImage(cvGetSize(pic5), 8, 1);

  184. cvNot(pic5,pic6);

  185.  
  186. //cvSaveImage("out2.bmp",pic6);

  187.  
  188. cvNamedWindow("oringin");

  189. cvShowImage("oringin", oringin);

  190.  
  191. cvNamedWindow("删除小联通域");

  192. cvShowImage("删除小联通域", pic2);

  193.  
  194. cvNamedWindow("孔洞填充");

  195. cvShowImage("孔洞填充", pic6);

  196.  
  197. cvWaitKey(0);

  198.  
  199. cvDestroyWindow( "oringin" );

  200. cvDestroyWindow( "删除小联通域" );

  201. cvDestroyWindow( "孔洞填充" );

  202. cvReleaseImage(&oringin);

  203. cvReleaseImage(&pic2);

  204. cvReleaseImage(&pic6);

  205.  
  206. return 0;

  207.  
  208. }

 

这篇关于图像孔洞填充与小连通域的删除的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/670587

相关文章

基于人工智能的图像分类系统

目录 引言项目背景环境准备 硬件要求软件安装与配置系统设计 系统架构关键技术代码示例 数据预处理模型训练模型预测应用场景结论 1. 引言 图像分类是计算机视觉中的一个重要任务,目标是自动识别图像中的对象类别。通过卷积神经网络(CNN)等深度学习技术,我们可以构建高效的图像分类系统,广泛应用于自动驾驶、医疗影像诊断、监控分析等领域。本文将介绍如何构建一个基于人工智能的图像分类系统,包括环境

电脑桌面文件删除了怎么找回来?别急,快速恢复攻略在此

在日常使用电脑的过程中,我们经常会遇到这样的情况:一不小心,桌面上的某个重要文件被删除了。这时,大多数人可能会感到惊慌失措,不知所措。 其实,不必过于担心,因为有很多方法可以帮助我们找回被删除的桌面文件。下面,就让我们一起来了解一下这些恢复桌面文件的方法吧。 一、使用撤销操作 如果我们刚刚删除了桌面上的文件,并且还没有进行其他操作,那么可以尝试使用撤销操作来恢复文件。在键盘上同时按下“C

学习记录:js算法(二十八):删除排序链表中的重复元素、删除排序链表中的重复元素II

文章目录 删除排序链表中的重复元素我的思路解法一:循环解法二:递归 网上思路 删除排序链表中的重复元素 II我的思路网上思路 总结 删除排序链表中的重复元素 给定一个已排序的链表的头 head , 删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。 图一 图二 示例 1:(图一)输入:head = [1,1,2]输出:[1,2]示例 2:(图

如何恢复回收站中已删除/清空的文件

回收站清空后如何恢复已删除的文件?是否可以恢复永久删除的文件?或者最糟糕的是,如果文件直接被删除怎么办?本文将向您展示清空回收站后恢复已删除数据的最佳方法。 回收站清空后如何恢复已删除的文件? “回收站清空后我还能恢复已删除的文件吗?” 答案是肯定的,但是在这种情况下您将需要一个  回收站恢复工具 来从回收站中检索文件: 错误/永久删除回收站或任何数字存储设备中的文件 直接删除的文件/

Verybot之OpenCV应用一:安装与图像采集测试

在Verybot上安装OpenCV是很简单的,只需要执行:         sudo apt-get update         sudo apt-get install libopencv-dev         sudo apt-get install python-opencv         下面就对安装好的OpenCV进行一下测试,编写一个通过USB摄像头采

Linux 删除 当前下的 mysql-8.0.31 空文件夹

在Linux中,如果你想要删除当前目录下的名为mysql-8.0.31的空文件夹(即该文件夹内没有任何文件或子文件夹),你可以使用rmdir命令。但是,如果mysql-8.0.31文件夹并非完全为空(即它包含文件或子文件夹),rmdir命令会失败。 如果你的目标是删除mysql-8.0.31文件夹及其内部的所有内容(无论是否为空),你应该使用rm命令结合-r(或-R,它们是等价的)选项来递归地删

【python计算机视觉编程——7.图像搜索】

python计算机视觉编程——7.图像搜索 7.图像搜索7.1 基于内容的图像检索(CBIR)从文本挖掘中获取灵感——矢量空间模型(BOW表示模型)7.2 视觉单词**思想****特征提取**: 创建词汇7.3 图像索引7.3.1 建立数据库7.3.2 添加图像 7.4 在数据库中搜索图像7.4.1 利用索引获取获选图像7.4.2 用一幅图像进行查询7.4.3 确定对比基准并绘制结果 7.

【python计算机视觉编程——8.图像内容分类】

python计算机视觉编程——8.图像内容分类 8.图像内容分类8.1 K邻近分类法(KNN)8.1.1 一个简单的二维示例8.1.2 用稠密SIFT作为图像特征8.1.3 图像分类:手势识别 8.2贝叶斯分类器用PCA降维 8.3 支持向量机8.3.2 再论手势识别 8.4 光学字符识别8.4.2 选取特征8.4.3 多类支持向量机8.4.4 提取单元格并识别字符8.4.5 图像校正

如何删除不小心上传到git远程仓库中的.idea .iml文件

如果在开始的时候不配置,gitignore文件或者文件配置不正确,初始化上传的时候就会有一些不必要的信息上传上去 如果已经存在了一些文件在git远程仓库中,如。idea,.iml文件等。 首先在项目中定义一个  .gitignore文件,简单的实例如下也可以用idea中的gitignore插件 .DS_Storeclasses/*.settings/target/.classpath

Win8下如何快速查找和删除电脑中的病毒

Win8系统如何查找和删除病毒?检查你的电脑是否存在病毒的一种快速方法是使用 Windows Defender. 此恶意软件防护随 Windows 提供,可帮助识别和删除病毒、间谍软件和其他恶意软件。   注意:如果你使用的是 Windows RT,则 Windows Defender 会始终启用,并且不能关闭。   如果你使用的是 Windows 8,则可以根据自己的喜好运行由其他