• 【opencv】图像细化


    【opencv】图像细化

    【opencv】图像细化

     分类:
     

         在我们进行图像处理的时候,有可能需要对图像进行细化,提取出图像的骨架信息,进行更加有效的分析。

         图像细化(Image Thinning),一般指二值图像的骨架化(Image Skeletonization) 的一种操作运算。

         所谓的细化就是经过一层层的剥离,从原来的图中去掉一些点,但仍要保持原来的形状,直到得到图像的骨架。骨架,可以理解为图象的中轴。

         好的细化算法一定要满足:
    • 收敛性;
    • 保证细化后细线的连通性;
    • 保持原图的基本形状;
    • 减少笔画相交处的畸变;
    • 细化结果是原图像的中心线;
    • 细化的快速性和迭代次数少;

        这里,我们对“Zhang并行快速细化算法”进行了实现(注意,该算法为并行算法,而我们在实现过程中并没有并行化处理,所以,效率并没有达到最好)。

        参考资料

    • 细化算法
    • 论文 A fast parallel algorithm for thinning digital patterns
      [cpp] view plain copy
       
       在CODE上查看代码片派生到我的代码片
      1. #include <opencv2/opencv.hpp>  
      2. #include <iostream>  
      3. #include <vector>  
      4. #include <limits>  
      5.   
      6. using namespace cv;  
      7. using namespace std;  
      8.   
      9. /** 
      10.  * @brief 对输入图像进行细化 
      11.  * @param[in] src为输入图像,用cvThreshold函数处理过的8位灰度图像格式,元素中只有0与1,1代表有元素,0代表为空白 
      12.  * @param[out] dst为对src细化后的输出图像,格式与src格式相同,调用前需要分配空间,元素中只有0与1,1代表有元素,0代表为空白 
      13.  * @param[in] maxIterations限制迭代次数,如果不进行限制,默认为-1,代表不限制迭代次数,直到获得最终结果 
      14.  */  
      15. void thinImage(IplImage* src,IplImage* dst,int maxIterations = -1 )  
      16. {  
      17.     CvSize size = cvGetSize(src);  
      18.     cvCopy(src,dst);//将src中的内容拷贝到dst中  
      19.     int count = 0;  //记录迭代次数  
      20.     while (true)  
      21.     {  
      22.         count++;  
      23.         if(maxIterations!=-1 && count > maxIterations) //限制次数并且迭代次数到达  
      24.             break;  
      25.         //std::cout << count << ' ';输出迭代次数  
      26.         vector<pair<int,int> > mFlag; //用于标记需要删除的点  
      27.         //对点标记  
      28.         for (int i=0; i<size.height; ++i)  
      29.         {  
      30.             for (int j=0; j<size.width; ++j)  
      31.             {  
      32.                 //如果满足四个条件,进行标记  
      33.                 //  p9 p2 p3  
      34.                 //  p8 p1 p4  
      35.                 //  p7 p6 p5  
      36.                 int p1 = CV_IMAGE_ELEM(dst,uchar,i,j);  
      37.                 int p2 = (i==0)?0:CV_IMAGE_ELEM(dst,uchar,i-1,j);  
      38.                 int p3 = (i==0 || j==size.width-1)?0:CV_IMAGE_ELEM(dst,uchar,i-1,j+1);  
      39.                 int p4 = (j==size.width-1)?0:CV_IMAGE_ELEM(dst,uchar,i,j+1);  
      40.                 int p5 = (i==size.height-1 || j==size.width-1)?0:CV_IMAGE_ELEM(dst,uchar,i+1,j+1);  
      41.                 int p6 = (i==size.height-1)?0:CV_IMAGE_ELEM(dst,uchar,i+1,j);  
      42.                 int p7 = (i==size.height-1 || j==0)?0:CV_IMAGE_ELEM(dst,uchar,i+1,j-1);  
      43.                 int p8 = (j==0)?0:CV_IMAGE_ELEM(dst,uchar,i,j-1);  
      44.                 int p9 = (i==0 || j==0)?0:CV_IMAGE_ELEM(dst,uchar,i-1,j-1);  
      45.   
      46.                 if ((p2+p3+p4+p5+p6+p7+p8+p9)>=2 && (p2+p3+p4+p5+p6+p7+p8+p9)<=6)  
      47.                 {  
      48.                     int ap=0;  
      49.                     if (p2==0 && p3==1) ++ap;  
      50.                     if (p3==0 && p4==1) ++ap;  
      51.                     if (p4==0 && p5==1) ++ap;  
      52.                     if (p5==0 && p6==1) ++ap;  
      53.                     if (p6==0 && p7==1) ++ap;  
      54.                     if (p7==0 && p8==1) ++ap;  
      55.                     if (p8==0 && p9==1) ++ap;  
      56.                     if (p9==0 && p2==1) ++ap;  
      57.                       
      58.                     if (ap==1)  
      59.                     {  
      60.                         if (p2*p4*p6==0)  
      61.                         {  
      62.                             if (p4*p6*p8==0)  
      63.                             {  
      64.                                 //标记  
      65.                                 mFlag.push_back(make_pair(i,j));  
      66.                             }  
      67.                         }  
      68.                     }  
      69.                 }  
      70.             }  
      71.         }  
      72.   
      73.         //将标记的点删除  
      74.         for (vector<pair<int,int> >::iterator i=mFlag.begin(); i!=mFlag.end(); ++i)  
      75.         {  
      76.             CV_IMAGE_ELEM(dst,uchar,i->first,i->second) = 0;  
      77.         }  
      78.   
      79.         //直到没有点满足,算法结束  
      80.         if (mFlag.size()==0)  
      81.         {  
      82.             break;  
      83.         }  
      84.         else  
      85.         {  
      86.             mFlag.clear();//将mFlag清空  
      87.         }  
      88.   
      89.         //对点标记  
      90.         for (int i=0; i<size.height; ++i)  
      91.         {  
      92.             for (int j=0; j<size.width; ++j)  
      93.             {  
      94.                 //如果满足四个条件,进行标记  
      95.                 //  p9 p2 p3  
      96.                 //  p8 p1 p4  
      97.                 //  p7 p6 p5  
      98.                 int p1 = CV_IMAGE_ELEM(dst,uchar,i,j);  
      99.                 if(p1!=1) continue;  
      100.                 int p2 = (i==0)?0:CV_IMAGE_ELEM(dst,uchar,i-1,j);  
      101.                 int p3 = (i==0 || j==size.width-1)?0:CV_IMAGE_ELEM(dst,uchar,i-1,j+1);  
      102.                 int p4 = (j==size.width-1)?0:CV_IMAGE_ELEM(dst,uchar,i,j+1);  
      103.                 int p5 = (i==size.height-1 || j==size.width-1)?0:CV_IMAGE_ELEM(dst,uchar,i+1,j+1);  
      104.                 int p6 = (i==size.height-1)?0:CV_IMAGE_ELEM(dst,uchar,i+1,j);  
      105.                 int p7 = (i==size.height-1 || j==0)?0:CV_IMAGE_ELEM(dst,uchar,i+1,j-1);  
      106.                 int p8 = (j==0)?0:CV_IMAGE_ELEM(dst,uchar,i,j-1);  
      107.                 int p9 = (i==0 || j==0)?0:CV_IMAGE_ELEM(dst,uchar,i-1,j-1);  
      108.   
      109.                 if ((p2+p3+p4+p5+p6+p7+p8+p9)>=2 && (p2+p3+p4+p5+p6+p7+p8+p9)<=6)  
      110.                 {  
      111.                     int ap=0;  
      112.                     if (p2==0 && p3==1) ++ap;  
      113.                     if (p3==0 && p4==1) ++ap;  
      114.                     if (p4==0 && p5==1) ++ap;  
      115.                     if (p5==0 && p6==1) ++ap;  
      116.                     if (p6==0 && p7==1) ++ap;  
      117.                     if (p7==0 && p8==1) ++ap;  
      118.                     if (p8==0 && p9==1) ++ap;  
      119.                     if (p9==0 && p2==1) ++ap;  
      120.   
      121.                     if (ap==1)  
      122.                     {  
      123.                         if (p2*p4*p8==0)  
      124.                         {  
      125.                             if (p2*p6*p8==0)  
      126.                             {  
      127.                                 //标记  
      128.                                 mFlag.push_back(make_pair(i,j));  
      129.                             }  
      130.                         }  
      131.                     }  
      132.                 }  
      133.             }  
      134.         }  
      135.         //删除  
      136.         for (vector<pair<int,int> >::iterator i=mFlag.begin(); i!=mFlag.end(); ++i)  
      137.         {  
      138.             CV_IMAGE_ELEM(dst,uchar,i->first,i->second) = 0;  
      139.         }  
      140.   
      141.         //直到没有点满足,算法结束  
      142.         if (mFlag.size()==0)  
      143.         {  
      144.             break;  
      145.         }  
      146.         else  
      147.         {  
      148.             mFlag.clear();//将mFlag清空  
      149.         }  
      150.     }  
      151. }  
      152.   
      153. int main(int argc, char*argv[])  
      154. {  
      155.     //获取图像  
      156.     if (argc!=2)  
      157.     {  
      158.         cout << "参数个数错误!"<<endl;  
      159.         return -1;  
      160.     }  
      161.     IplImage *pSrc = cvLoadImage(argv[1],CV_LOAD_IMAGE_GRAYSCALE);  
      162.     if (!pSrc)  
      163.     {  
      164.         cout << "读取文件失败!" << endl;  
      165.         return -1;  
      166.     }  
      167.     IplImage *pTemp = cvCreateImage(cvGetSize(pSrc),pSrc->depth,pSrc->nChannels);  
      168.     IplImage *pDst = cvCreateImage(cvGetSize(pSrc),pSrc->depth,pSrc->nChannels);  
      169.       
      170.     //将原图像转换为二值图像  
      171.     cvThreshold(pSrc,pTemp,128,1,CV_THRESH_BINARY);   
      172.     //图像细化  
      173.     thinImage(pTemp,pDst);  
      174.   
      175.     for (int i=0; i<pDst->height; ++i)  
      176.     {  
      177.         for (int j=0; j<pDst->width; ++j)  
      178.         {  
      179.             if(CV_IMAGE_ELEM(pDst,uchar,i,j)==1)  
      180.                 CV_IMAGE_ELEM(pDst,uchar,i,j)= 255;  
      181.         }  
      182.     }  
      183.   
      184.     namedWindow("src",CV_WINDOW_AUTOSIZE);  
      185.     namedWindow("dst",CV_WINDOW_AUTOSIZE);  
      186.     cvShowImage("src",pSrc);  
      187.     cvShowImage("dst",pDst);  
      188.   
      189.     waitKey(0);  
      190. }  

          运行效果

      1原图像

      2.运行效果

     
     
  • 相关阅读:
    用C#一步步创建Window Service (转) 沧海一粟
    IOS 开发,调用打电话,发短信,打开网址 沧海一粟
    IOS UIScrollView (转) 沧海一粟
    苹果IOS开发者账号总结 沧海一粟
    ios公司开发者账号申请分享攻略(转自yiwind0101) 沧海一粟
    iOS开发:自定义UITableViewCell(转) 沧海一粟
    可任意自定义的UITableViewCell(转) 沧海一粟
    iphone开发获取当前app的名称和版本号 沧海一粟
    SMTP协议在cmd下利用命令行发送邮件(转) 沧海一粟
    iPhone提供的4种基本的表格视图单元格 沧海一粟
  • 原文地址:https://www.cnblogs.com/donaldlee2008/p/5232035.html
Copyright © 2020-2023  润新知