當前位置:
首頁 > 知識 > SLIC超像素分割演算法研究(代碼可下載)

SLIC超像素分割演算法研究(代碼可下載)

超像素概念是2003年Xiaofeng Ren[1]提出和發展起來的圖像分割技術,是指具有相似紋理、顏色、亮度等特徵的相鄰像素構成的有一定視覺意義的不規則像素塊。它利用像素之間特徵的相似性將像素分組,用少量的超像素代替大量的像素來表達圖片特徵,很大程度上降低了圖像後處理的複雜度,所以通常作為分割演算法的預處理步驟。已經廣泛用於圖像分割、姿勢估計、目標跟蹤、目標識別等計算機視覺應用[2],而目前,OpenCV關於超像素生成,沒有發現網上有相關代碼,但其實在opencv_contrib目錄下面的未穩定功能模塊有SLIC,SEEDS,LSC演算法相關實現,如果想要使用這個目錄的功能,需要自己重新進行OpenCV的編譯[8],有關編譯和配置方法可參考[8 ,9]。一些常用的超像素分割演算法和性能對比如下表[3]:

SLIC超像素分割演算法研究(代碼可下載)

本文介紹SLIC(simple lineariterativeclustering)超像素分割演算法,即簡單的線性迭代聚類,該演算法是目前執行速度最快的超像素分割方法[3],2015年實現並行執行速度達250FPS [4,5]。SLIC演算法是2010年Achanta[6]提出的一種思想簡單、實現方便的演算法,將彩色圖像轉化為CIELAB顏色空間和XY坐標下的5維特徵向量,然後對5維特徵向量構造距離度量標準,對圖像像素進行局部聚類的過程[2],演算法基本思路與Kmeans聚類演算法類似。演算法具體實現過程如下[6,2]:

SLIC超像素分割演算法研究(代碼可下載)

1. 初始化種子點(聚類中心):按照設定的超像素個數,在圖像內均勻的分配種子點。假設圖片總共有 N 個像素點,預分割為 K 個相同尺寸的超像素,那麼每個超像素的大小為N/ K ,則相鄰種子點的距離(步長)近似為S=sqrt(N/K)。

2. 在種子點的n*n鄰域內重新選擇種子點(一般取n=3)。具體方法為:計算該鄰域內所有像素點的梯度值,將種子點移到該鄰域內梯度最小的地方。這樣做的目的是為了避免種子點落在梯度較大的輪廓邊界上,以免影響後續聚類效果。

3. 在每個種子點周圍的鄰域內為每個像素點分配類標籤(即屬於哪個聚類中心)。和標準的k-means在整張圖中搜索不同,SLIC的搜索範圍限制為2S*2S,可以加速演算法收斂,如下圖。在此注意一點:期望的超像素尺寸為S*S,但是搜索的範圍是2S*2S。

4. 距離度量。包括顏色距離和空間距離。對於每個搜索到的像素點,分別計算它和該種子點的距離。距離計算方法如下:

SLIC超像素分割演算法研究(代碼可下載)

其中,dc代表顏色距離,ds代表空間距離,Ns是類內最大空間距離,定義為Ns=S=sqrt(N/K),適用於每個聚類。最大的顏色距離Nc既隨圖片不同而不同,也隨聚類不同而不同,所以我們取一個固定常數m(取值範圍[1,40],一般取10)代替。最終的距離度量D"如下:

SLIC超像素分割演算法研究(代碼可下載)

由於每個像素點都會被多個種子點搜索到,所以每個像素點都會有一個與周圍種子點的距離,取最小值對應的種子點作為該像素點的聚類中心。

5. 迭代優化。理論上上述步驟不斷迭代直到誤差收斂(可以理解為每個像素點聚類中心不再發生變化為止),實踐發現10次迭代對絕大部分圖片都可以得到較理想效果,所以一般迭代次數取10。

6. 增強連通性。經過上述迭代優化可能出現以下瑕疵:出現多連通情況、超像素尺寸過小,單個超像素被切割成多個不連續超像素等,這些情況可以通過增強連通性解決。主要思路是:新建一張標記表,表內元素均為-1,按照「Z」型走向(從左到右,從上到下順序)將不連續的超像素、尺寸過小超像素重新分配給鄰近的超像素,遍歷過的像素點分配給相應的標籤,直到所有點遍歷完畢為止。

SLIC演算法的代碼(C++和matlab版)可到該演算法發明人Achanta的頁面[7]下載,我們下載該代碼的C++windows版本,並編寫一個簡單圖像格式轉換函數,將SLIC超像素演算法與openCV一起實現了一個簡單的應用實例,因為SLIC演算法輸入必須是RGB彩色圖像,因此我們考慮了灰度圖像和彩色圖像兩種不同情況下的數據轉換,當輸入為灰度圖時,將該灰度圖像複製三次到其他色彩通道,主程序如下(代碼運行還需要從Achanta網站[7]下載的SLIC.cpp和SLIC.h文件,有關我們測試程序的所有代碼(包括了SLIC.cpp和SLIC.h文件)下載網站:http://download.csdn.net/detail/zhouxianen1987/9778247):

[html] view plain copy

  1. #if 1
  2. #include

    <iostream>

  3. #include

    <time.h>

  4. #include "opencv2/opencv.hpp"
  5. #include "SLIC.h"
  6. using namespace std;
  7. using namespace cv;
  8. int imgOpenCV2SLIC(Mat img, int &height, int &width, int &dim, unsigned int * &image);
  9. int imgSLIC2openCV(unsigned int *image, int height, int width, int dim, Mat &imgSLIC);
  10. int main()
  11. {
  12. Mat imgRGB;
  13. time_t tStart,tEnd,exeT;
  14. imgRGB= imread("0_0_77rgb.jpg");
  15. if (imgRGB.empty() == true){
  16. cout

    <<

    "can not open rgb image!"

    <<endl

    ;
  17. }
  18. unsigned int *image;
  19. int height;
  20. int width;
  21. int dim;
  22. long imgSize;
  23. int numlabels(0);
  24. SLIC slic;
  25. int m_spcount= 100 ;
  26. int m_compactness=10;
  27. imgOpenCV2SLIC(imgRGB, height, width, dim, image);//OpenCV 圖像數據轉換成SLIC圖像數據
  28. imgSize = height* width;
  29. int* labels = new int[imgSize];
  30. tStart=clock();
  31. //SLIC超像素分割,代碼下載網站://ivrl.epfl.ch/research/superpixels#SLICO
  32. slic.DoSuperpixelSegmentation_ForGivenNumberOfSuperpixels(image, width, height, labels, numlabels, m_spcount, m_compactness);
  33. slic.DrawContoursAroundSegments(image, labels, width, height, 0);
  34. tEnd=clock();
  35. exeT=tEnd-tStart;
  36. Mat imgSLIC;
  37. imgSLIC2openCV(image, height,width,dim,imgSLIC);//SLIC結果:SLIC圖像數據轉換成OpenCV 圖像數據
  38. //結果顯示
  39. cout

    <<

    "SLIC執行時間exeT:"

    <<exeT<<

    "毫秒"

    <<endl

    ;
  40. imshow("imgRGB",imgRGB);
  41. imshow("imgSLIC1",imgSLIC);
  42. waitKey();
  43. return 0;
  44. }
  45. //OpenCV Mat圖像數據轉換為SLIC圖像數據
  46. //輸入:Mat img, int &height, int &width, int &dim,
  47. //輸出:unsigned int * &image,同時返迴轉換是否成功的標誌:成功為0,識別為1
  48. int imgOpenCV2SLIC(Mat img, int &height, int &width, int &dim, unsigned int * &image)
  49. {
  50. int error=0;
  51. if( img.empty() ) //請一定檢查是否成功讀圖
  52. {
  53. error =1;
  54. }
  55. dim=img.channels();//圖像通道數目
  56. height=img.rows;
  57. width=img.cols;
  58. int imgSize=width*height;
  59. unsigned char *pImage = new unsigned char [imgSize*4];
  60. if(dim==1){
  61. for(int j = 0; j

    <

    height

    ; j++){

  62. uchar * ptr = img.ptr

    <uchar>

    (j);
  63. for(int i = 0; i

    <

    width

    ; i++) {
  64. pImage[j * width*4 + 4*i+3] = 0;
  65. pImage[j * width*4 + 4*i+2] = ptr[0];
  66. pImage[j * width*4 + 4*i+1] = ptr[0];
  67. pImage[j * width*4 + 4*i] = ptr[0];
  68. ptr ++;
  69. }
  70. }
  71. }
  72. else{
  73. if(dim==3){
  74. for(int j = 0; j

    <

    height

    ; j++){
  75. Vec3b * ptr = img.ptr

    <Vec3b>

    (j);
  76. for(int i = 0; i

    <

    width

    ; i++) {
  77. pImage[j * width*4 + 4*i+3] = 0;
  78. pImage[j * width*4 + 4*i+2] = ptr[0][2];//R
  79. pImage[j * width*4 + 4*i+1] = ptr[0][1];//G
  80. pImage[j * width*4 + 4*i] = ptr[0][0];//B
  81. ptr ++;
  82. }
  83. }
  84. }
  85. else error=1;
  86. }
  87. image = new unsigned int[imgSize];
  88. memcpy( image, (unsigned int*)pImage, imgSize*sizeof(unsigned int) );
  89. delete pImage;
  90. return error;
  91. }
  92. //SLIC圖像數據轉換為OpenCV Mat圖像數據
  93. //輸入:unsigned int *image, int height, int width, int dim
  94. //輸出:Mat &imgSLIC ,同時返迴轉換是否成功的標誌:成功為0,識別為1
  95. int imgSLIC2openCV(unsigned int *image, int height, int width, int dim, Mat &imgSLIC)
  96. {
  97. int error=0;//轉換是否成功的標誌:成功為0,識別為1
  98. if(dim==1){
  99. imgSLIC.create(height, width, CV_8UC1);
  100. //遍歷所有像素,並設置像素值
  101. for( int j = 0; j

    <

    height

    ; ++j)

  102. {
  103. //獲取第 i行首像素指針
  104. uchar * p = imgSLIC.ptr

    <uchar>

    (j);
  105. //對第 i行的每個像素(byte)操作
  106. for( int i = 0; i

    <

    width

    ; ++i )
  107. p[i] =(unsigned char)(image[j*width+i]& 0xFF) ;
  108. }
  109. }
  110. else{
  111. if(dim==3){
  112. imgSLIC.create(height, width, CV_8UC3);
  113. //遍歷所有像素,並設置像素值
  114. for( int j = 0; j

    <

    height

    ; ++j)
  115. {
  116. //獲取第 i行首像素指針
  117. Vec3b * p = imgSLIC.ptr

    <Vec3b>

    (j);
  118. for( int i = 0; i

    <

    width

    ; ++i )
  119. {
  120. p[i][0] = (unsigned char)(image[j*width+i] & 0xFF ); //Blue
  121. p[i][1] = (unsigned char)((image[j*width+i]

    >>

    8 ) & 0xFF ); //Green
  122. p[i][2] = (unsigned char)((image[j*width+i]

    >>

    16) & 0xFF ) ; //Red

  123. }
  124. }
  125. }
  126. else error= 1 ;
  127. }
  128. return error;
  129. }
  130. #endif

執行效果如下:

SLIC超像素分割演算法研究(代碼可下載)

SLIC超像素分割演算法研究(代碼可下載)

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 程序員小新人學習 的精彩文章:

SOAP Fault 元素
Web Services總結

TAG:程序員小新人學習 |