OpenCV Skeletonization - eiichiromomma/CVMLAB GitHub Wiki

(OpenCV) Skeletonization

細線化より単純にスケルトンを抽出

cvFilter2Dによる2次元フィルタ処理の練習も兼用

やり方

  1. cvDistTransformで距離変換(尾根=スケルトン になる)
  2. Kasvandの反復型線検出オペレータを適用した画像S0,S45,S90,S135を求める
  3. Smax=max(S0,S45,S90,S135)を求める
  4. g(x,y)=Smax(Smax>=0のとき), 0(Smax<0のとき)を求める

画像

入力画像

ペイントで適当に作成

S0

S45

S90

S135

算出結果

閾値は適当に決めた。対象物の予見される中心までの距離を基準に考えれば大体の数値は決められるかも? 低めに設定してノイズや枝の除去をするか、高めに設定して膨張収縮させるかするとスケルトンだけ抽出できるかも?

PythonやC++

OpenCV Multi-View参照

ソース(旧)

    //Kasvandの反復型線検出オペレータ 作成:Eiichiro Momma
    //2008.1.21 ざっくり実装 
    #include <cv.h>
    #include <highgui.h>
    void main(void)
    {
      IplImage *src;
      IplImage *distsrc;
      IplImage *out;
      IplImage *S00;
      IplImage *S45;
      IplImage *S90;
      IplImage *S135;
      CvMat kern00, kern45, kern90, kern135;
      float Smax=0;
      //Kasvandの反復型線検出オペレータ
      float L0[]={
        -1,-1,-1,-1,-1,
         0, 0, 0, 0, 0,
         2, 2, 2, 2, 2,
         0, 0, 0, 0, 0,
        -1,-1,-1,-1,-1
      };
      float L45[]={
         0,-1,-1, 0, 2,
        -1,-1, 0, 2, 0,
        -1, 0, 2, 0,-1,
         0, 2, 0,-1,-1,
         2, 0,-1,-1, 0
      };
      float L90[]={
        -1, 0, 2, 0,-1,
        -1, 0, 2, 0,-1,
        -1, 0, 2, 0,-1,
        -1, 0, 2, 0,-1,
        -1, 0, 2, 0,-1
      };
      float L135[]={
         2, 0,-1,-1, 0,
         0, 2, 0,-1,-1,
        -1, 0, 2, 0,-1,
        -1,-1, 0, 2, 0,
         0,-1,-1, 0, 2
      };
      src=cvLoadImage("OpenCVKasvandTest.png)",0);
      distsrc=cvCreateImage(cvGetSize(src),IPL_DEPTH_32F,1);
      S00=cvCreateImage(cvGetSize(src),IPL_DEPTH_32F,1);
      S45=cvCreateImage(cvGetSize(src),IPL_DEPTH_32F,1);
      S90=cvCreateImage(cvGetSize(src),IPL_DEPTH_32F,1);
      S135=cvCreateImage(cvGetSize(src),IPL_DEPTH_32F,1);
      out=cvCreateImage(cvGetSize(src),IPL_DEPTH_32F,1);
      //kernelの作成
      cvInitMatHeader(&kern00,5,5,CV_32FC1,L0);
      cvInitMatHeader(&kern45,5,5,CV_32FC1,L45);
      cvInitMatHeader(&kern90,5,5,CV_32FC1,L90);
      cvInitMatHeader(&kern135,5,5,CV_32FC1,L135);
      //距離変換
      cvDistTransform(src,distsrc,CV_DIST_L2,5);
      //フィルタ処理
      cvFilter2D(distsrc,S00,&kern00);
      cvFilter2D(distsrc,S45,&kern45);
      cvFilter2D(distsrc,S90,&kern90);
      cvFilter2D(distsrc,S135,&kern135);
      //
      //Smax = MAX(S00,S45,S90,S135)
      //     / Smax, Smax >= 0
      // g = |
      //     \ 0 , others
      //
      for (int y=0; y < out->height; y++){
        for (int x=0; x< out->width; x++){
          Smax = MAX(MAX(((float*)(S00->imageData + y* S00->widthStep))[x], ((float*)(S45->imageData + y* S45->widthStep))[x]),
            MAX(((float*)(S90->imageData + y* S90->widthStep))[x], ((float*)(S135->imageData + y* S135->widthStep))[x]));
          ((float*)(out->imageData + y* out->widthStep))[x] = Smax > 0 ? Smax: 0.0;
        }
      }
      cvThreshold(out,out,7,1,CV_THRESH_BINARY);
      cvNamedWindow("S00",1);
      cvNamedWindow("S45",1);
      cvNamedWindow("S90",1);
      cvNamedWindow("S135",1);
      cvNamedWindow("out",1);
      cvShowImage("S00",S00);
      cvShowImage("S45",S45);
      cvShowImage("S90",S90);
      cvShowImage("S135",S135);
      cvShowImage("out",out);
      cvWaitKey(0);
      //画像出力のため8Uのsrcを再利用
      //Sxxは出力の勾配がわかるよう32倍(適当)
      cvCvtScaleAbs(S00,src,32,0);
      cvSaveImage("S00.png)",src);
      cvCvtScaleAbs(S45,src,32,0);
      cvSaveImage("S45.png)",src);
      cvCvtScaleAbs(S90,src,32,0);
      cvSaveImage("S90.png)",src);
      cvCvtScaleAbs(S135,src,32,0);
      cvSaveImage("S135.png)",src);
      cvCvtScaleAbs(out,src,255,0);
      cvSaveImage("out.png)",src);
    }
⚠️ **GitHub.com Fallback** ⚠️