2015년 4월 10일 금요일

opencv 3.0 에 blob or labeling algorithm 추가 되었다...

 이전 글에서 opencv 에 labeling algorithm이 없어서, 구현해서 사용한다고 했었는데..
요즘 open source 에 기여를 해보고 싶어서, 만들어서 pull request 해봐야 겠다고 생각했었다.
github에서 clone해서 시작해보려고 code들을 둘러 보는데 labeling 기능이 추가 되어있었다.
이름은 익숙한 labeling이나 blob은 아니고 connected_compnents 이다.

함수 사용은 아래와 같다.
int cv::connectedComponents(InputArray image,
OutputArray labels,
int connectivity = 8,
int ltype = CV_32S 
)
computes the connected components labeled image of boolean image
image with 4 or 8 way connectivity - returns N, the total number of labels [0, N-1] where 0 represents the background label. ltype specifies the output label image type, an important consideration based on the total number of labels or alternatively the total number of pixels in the source image.
Parameters
imagethe image to be labeled
labelsdestination labeled image
connectivity8 or 4 for 8-way or 4-way connectivity respectively
ltypeoutput image label type. Currently CV_32S and CV_16U are supported.

blob 하고 나서 object 들의 feature들을 추출해야 할 경우가 대부분인데. 그때는 아래 함수를 사용하면 된다.

int cv::connectedComponentsWithStats(InputArray image,
OutputArray labels,
OutputArray stats,
OutputArray centroids,
int connectivity = 8,
int ltype = CV_32S 
)
This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.
Parameters
imagethe image to be labeled
labelsdestination labeled image
statsstatistics output for each label, including the background label, see below for available statistics. Statistics are accessed via stats(label, COLUMN) where COLUMN is one of cv::ConnectedComponentsTypes
centroidsfloating point centroid (x,y) output for each label, including the background label
connectivity8 or 4 for 8-way or 4-way connectivity respectively
ltypeoutput image label type. Currently CV_32S and CV_16U are supported.
실제 algorithm이 어떻게 구현되어있는지 궁금해서 source code 분석중인데.. 어렵다.
현재 3.0 에 추가된 connectedComponents algorithm은 아래의 paper 이다.

https://sdm.lbl.gov/~kewu/ps/LBNL-59102.pdf




connectedComponentsWithStats 에는 blob에 대한 아래의 정보들을 추출해 준다.


  1. //! connected components algorithm output formats
  2. enum ConnectedComponentsTypes {
  3. CC_STAT_LEFT = 0, //!< The leftmost (x) coordinate which is the inclusive start of the bounding
  4. //!< box in the horizontal direction.
  5. CC_STAT_TOP = 1, //!< The topmost (y) coordinate which is the inclusive start of the bounding
  6. //!< box in the vertical direction.
  7. CC_STAT_WIDTH = 2, //!< The horizontal size of the bounding box
  8. CC_STAT_HEIGHT = 3, //!< The vertical size of the bounding box
  9. CC_STAT_AREA = 4, //!< The total area (in pixels) of the connected component
  10. CC_STAT_MAX = 5
  11. };

blob에 대한 Gray 값 추출이 필요할 때가 많은데.. 그게 없어서 아쉽다.
아래는 blobImage 로 각 blob의 Gray Sum을 뽑는 함수다.
각 blob의 gray sum을 area 값으로 나누어서 평균 gray값으로 쓸수 있다.

  1.     Mat Stats;
  2.     Mat Center;
  3.     int nNum = connectedComponentsWithStats(m_BinImg,m_LabelImg,Stats,Center);
  4.     double *pContArray = new double [nNum];
  5.     ExtractObjMeanGray(pContArray,nNum);
  6.     delete [] pContArray;

  1. BOOL CBlobObjectFeature::ExtractObjMeanGray(double *pContArray, int nTotalBlobs)
  2. {
  3.     BOOL bRet = TRUE;

  4.     int nOriginType = m_OrginContImg.type();
  5.     int nLabelType = m_LabelImg.type();

  6.     ///////////////////////////////이부분 필요 없는데. 그냥 놔둔 이유..//////////////////////
  7.     ///////////////opencv3.1에서는 connectedComponents 함수는 0부터 1++ 된 blob 들만 나온다..////////
  8.     ///////////////하지만 다른 library의 blob알고리즘들은 1++가 아닌것이 더 많았다..///////////////////
  9.     /////////////// 혹 바뀔지도 모르거나 다른 lib들과 호환성을 위해 빼지 않았음////////////////
  10.     map<int, int> mapBlobIdx;
  11.     for(int y=0;y<m_LabelImg.rows;y++)
  12.     {
  13.         for(int x=0;x<m_LabelImg.cols;x++)
  14.         {
  15.             if(m_LabelImg.at<int>(Point(x,y))!=0)
  16.             {
  17.                 mapBlobIdx[m_LabelImg.at<int>(Point(x,y))]=0;
  18.             }
  19.         }
  20.     }

  21.     map<int,int>::iterator iter;
  22.     int n=1;
  23.     for(iter = mapBlobIdx.begin();iter!=mapBlobIdx.end();iter++)
  24.     {
  25.         iter->second = n;
  26.         n++;
  27.     }
  28.     ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  29.     ZeroMemory(pContArray,sizeof(double)*nTotalBlobs);
  30.     for(int y=0;y<m_LabelImg.rows;y++)
  31.     {
  32.         for(int x=0;x<m_LabelImg.cols;x++)
  33.         {
  34.             int nLabel;
  35.             double dGray;
  36.             nLabel = m_LabelImg.at<int>(Point(x,y));
  37.             dGray = m_OrginContImg.at<uchar>(Point(x,y));
  38.             pContArray[mapBlobIdx[nLabel]] += dGray;
  39.         }
  40.     }
  41.     
  42.     return bRet;
  43. }

댓글 없음:

댓글 쓰기