【opencv】圖像細化


【原文:http://blog.csdn.net/qianchenglenger/article/details/19332011

在我們進行圖像處理的時候,有可能需要對圖像進行細化,提取出圖像的骨架信息,進行更加有效的分析。

     圖像細化(Image Thinning),一般指二值圖像的骨架化(Image Skeletonization 的一種操作運算。

     所謂的細化就是經過一層層的剝離,從原來的圖中去掉一些點,但仍要保持原來的形狀,直到得到圖像的骨架。骨架,可以理解為圖象的中軸。

     好的細化算法一定要滿足:

  • 收斂性;
  • 保證細化后細線的連通性;
  • 保持原圖的基本形狀;
  • 減少筆畫相交處的畸變;
  • 細化結果是原圖像的中心線;
  • 細化的快速性和迭代次數少;

    這里,我們對"Zhang並行快速細化算法"進行了實現(注意,該算法為並行算法,而我們在實現過程中並沒有並行化處理,所以,效率並沒有達到最好)。

    參考資料

細化算法

論文 A fast parallel algorithm for thinning digital patterns

[cpp] view plaincopy

  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位灰度圖像格式,元素中只有01,1代表有元素,0代表為空白 
  12.  * @param[out] dst為對src細化后的輸出圖像,格式與src格式相同,調用前需要分配空間,元素中只有01,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.運行效果


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM