OPENCV二值化图像内孔洞填充/小区域去除

首先给大家推荐一下我老师大神的人工智能教学网站。教学不仅零基础,通俗易懂,而且非常风趣幽默,还时不时有内涵黄段子!点这里可以跳转到网站

对于二值化图像,去除孔洞时采用的方法实际上与去除小区域相同,因此完全可以用同一个函数进行。

这两个功能可以采取区域生长法来实现。须注意,去除小区域时为保存有用信息,可采用8邻域探测,去除孔洞时则4邻域即可,否则容易泄露,出现靠边缘的孔洞未去除的情况。

效果(区域面积阈值为700): 

原图像:

小面积区域去除:

孔洞填充结果:

[cpp]view plaincopy

  1. #include <cv.h>  
  2. #include <highgui.h>  
  3. #include <opencv2/imgproc/imgproc.hpp>    
  4. #include <opencv2/highgui/highgui.hpp>    
  5. #include <iostream>    
  6. #include <vector>    
  7.   
  8.   
  9. using namespace cv;  
  10. using namespace std;  
  11.   
  12. void RemoveSmallRegion(Mat& Src, Mat& Dst, int AreaLimit=50, int CheckMode=1, int NeihborMode=0);  
  13.   
  14. int main()    
  15. {    
  16.     double t = (double)getTickCount();  
  17.   
  18.     char* imagePath = “E:\\SVM\\局部.jpg”;  
  19.     char* OutPath = “E:\\SVM\\局部_去除孔洞.jpg”;  
  20.       
  21.     Mat Src = imread(imagePath, CV_LOAD_IMAGE_GRAYSCALE);  
  22.     Mat Dst = Mat::zeros(Src.size(), CV_8UC1);  
  23.       
  24.   
  25.     //二值化处理  
  26.     for(int i = 0; i < Src.rows; ++i)    
  27.     {    
  28.         uchar* iData = Src.ptr<uchar>(i);  
  29.         for(int j = 0; j < Src.cols; ++j)    
  30.         {    
  31.             if(iData[j] == 0 || iData[j]==255) continue;  
  32.             else if (iData[j] < 10)    
  33.             {    
  34.                 iData[j] = 0;    
  35.                 //cout<<‘#’;  
  36.             }    
  37.             else if (iData[j] > 10)    
  38.             {    
  39.                 iData[j] = 255;   
  40.                 //cout<<‘!’;  
  41.             }    
  42.         }    
  43.     }    
  44.     cout<<“Image Binary processed.”<<endl;  
  45.   
  46.     RemoveSmallRegion(Src, Dst, 20, 1, 1);  
  47.     RemoveSmallRegion(Dst, Dst, 20, 0, 0);  
  48.     cout<<“Done!”<<endl;  
  49.     imwrite(OutPath, Dst);  
  50.           
  51.     t = ((double)getTickCount() – t)/getTickFrequency();  
  52.     cout<<“Time cost: “<<t<<” sec.”<<endl;  
  53.   
  54.     return 0;    
  55. }    
  56.   
  57. //CheckMode: 0代表去除黑区域,1代表去除白区域; NeihborMode:0代表4邻域,1代表8邻域;  
  58. void RemoveSmallRegion(Mat& Src, Mat& Dst, int AreaLimit, int CheckMode, int NeihborMode)  
  59. {     
  60.     int RemoveCount=0;       //记录除去的个数  
  61.     //记录每个像素点检验状态的标签,0代表未检查,1代表正在检查,2代表检查不合格(需要反转颜色),3代表检查合格或不需检查  
  62.     Mat Pointlabel = Mat::zeros( Src.size(), CV_8UC1 );  
  63.       
  64.     if(CheckMode==1)  
  65.     {  
  66.         cout<<“Mode: 去除小区域. “;  
  67.         for(int i = 0; i < Src.rows; ++i)    
  68.         {    
  69.             uchar* iData = Src.ptr<uchar>(i);  
  70.             uchar* iLabel = Pointlabel.ptr<uchar>(i);  
  71.             for(int j = 0; j < Src.cols; ++j)    
  72.             {    
  73.                 if (iData[j] < 10)    
  74.                 {    
  75.                     iLabel[j] = 3;   
  76.                 }    
  77.             }    
  78.         }    
  79.     }  
  80.     else  
  81.     {  
  82.         cout<<“Mode: 去除孔洞. “;  
  83.         for(int i = 0; i < Src.rows; ++i)    
  84.         {    
  85.             uchar* iData = Src.ptr<uchar>(i);  
  86.             uchar* iLabel = Pointlabel.ptr<uchar>(i);  
  87.             for(int j = 0; j < Src.cols; ++j)    
  88.             {    
  89.                 if (iData[j] > 10)    
  90.                 {    
  91.                     iLabel[j] = 3;   
  92.                 }    
  93.             }    
  94.         }    
  95.     }  
  96.   
  97.     vector<Point2i> NeihborPos;  //记录邻域点位置  
  98.     NeihborPos.push_back(Point2i(-1, 0));  
  99.     NeihborPos.push_back(Point2i(1, 0));  
  100.     NeihborPos.push_back(Point2i(0, -1));  
  101.     NeihborPos.push_back(Point2i(0, 1));  
  102.     if (NeihborMode==1)  
  103.     {  
  104.         cout<<“Neighbor mode: 8邻域.”<<endl;  
  105.         NeihborPos.push_back(Point2i(-1, -1));  
  106.         NeihborPos.push_back(Point2i(-1, 1));  
  107.         NeihborPos.push_back(Point2i(1, -1));  
  108.         NeihborPos.push_back(Point2i(1, 1));  
  109.     }  
  110.     else cout<<“Neighbor mode: 4邻域.”<<endl;  
  111.     int NeihborCount=4+4*NeihborMode;  
  112.     int CurrX=0, CurrY=0;  
  113.     //开始检测  
  114.     for(int i = 0; i < Src.rows; ++i)    
  115.     {    
  116.         uchar* iLabel = Pointlabel.ptr<uchar>(i);  
  117.         for(int j = 0; j < Src.cols; ++j)    
  118.         {    
  119.             if (iLabel[j] == 0)    
  120.             {    
  121.                 //********开始该点处的检查**********  
  122.                 vector<Point2i> GrowBuffer;                                      //堆栈,用于存储生长点  
  123.                 GrowBuffer.push_back( Point2i(j, i) );  
  124.                 Pointlabel.at<uchar>(i, j)=1;  
  125.                 int CheckResult=0;                                               //用于判断结果(是否超出大小),0为未超出,1为超出  
  126.   
  127.                 for ( int z=0; z<GrowBuffer.size(); z++ )  
  128.                 {  
  129.   
  130.                     for (int q=0; q<NeihborCount; q++)                                      //检查四个邻域点  
  131.                     {  
  132.                         CurrX=GrowBuffer.at(z).x+NeihborPos.at(q).x;  
  133.                         CurrY=GrowBuffer.at(z).y+NeihborPos.at(q).y;  
  134.                         if (CurrX>=0&&CurrX<Src.cols&&CurrY>=0&&CurrY<Src.rows)  //防止越界  
  135.                         {  
  136.                             if ( Pointlabel.at<uchar>(CurrY, CurrX)==0 )  
  137.                             {  
  138.                                 GrowBuffer.push_back( Point2i(CurrX, CurrY) );  //邻域点加入buffer  
  139.                                 Pointlabel.at<uchar>(CurrY, CurrX)=1;           //更新邻域点的检查标签,避免重复检查  
  140.                             }  
  141.                         }  
  142.                     }  
  143.   
  144.                 }  
  145.                 if (GrowBuffer.size()>AreaLimit) CheckResult=2;                 //判断结果(是否超出限定的大小),1为未超出,2为超出  
  146.                 else {CheckResult=1;   RemoveCount++;}  
  147.                 for (int z=0; z<GrowBuffer.size(); z++)                         //更新Label记录  
  148.                 {  
  149.                     CurrX=GrowBuffer.at(z).x;   
  150.                     CurrY=GrowBuffer.at(z).y;  
  151.                     Pointlabel.at<uchar>(CurrY, CurrX) += CheckResult;  
  152.                 }  
  153.                 //********结束该点处的检查**********  
  154.   
  155.   
  156.             }    
  157.         }    
  158.     }    
  159.   
  160.     CheckMode=255*(1-CheckMode);  
  161.     //开始反转面积过小的区域  
  162.     for(int i = 0; i < Src.rows; ++i)    
  163.     {    
  164.         uchar* iData = Src.ptr<uchar>(i);  
  165.         uchar* iDstData = Dst.ptr<uchar>(i);  
  166.         uchar* iLabel = Pointlabel.ptr<uchar>(i);  
  167.         for(int j = 0; j < Src.cols; ++j)    
  168.         {    
  169.             if (iLabel[j] == 2)    
  170.             {    
  171.                 iDstData[j] = CheckMode;   
  172.             }    
  173.             else if(iLabel[j] == 3)  
  174.             {  
  175.                 iDstData[j] = iData[j];  
  176.             }  
  177.         }    
  178.     }   
  179.       
  180.     cout<<RemoveCount<<” objects removed.”<<endl;  
  181. }  

网址:http://blog.csdn.net/robberjohn/article/details/44081571

点这里可以跳转到人工智能网站

0 0 投票数
文章评分
订阅评论
提醒
0 评论
内联反馈
查看所有评论
0
希望看到您的想法,请发表评论。x
()
x