【手撕算法】C++实现超像素分割算法
寫完這篇,圖像分割的傳統(tǒng)方法就快全了,傳統(tǒng)圖像分割大體有基于閾值的,這類就沒啥算法可以寫,所以直接略過了;然后就是K-means這種聚類/分裂的,從幾個(gè)點(diǎn)開始進(jìn)行聚類分割,或者一張圖不斷分裂達(dá)到分割目的;
【手撕算法】K-means算法實(shí)現(xiàn)主題色提取
再有就是區(qū)域生長這類的;
【手撕算法】基于隊(duì)列實(shí)現(xiàn)的區(qū)域增長分割算法
以及分水嶺算法,分水嶺算法代碼寫好有一段時(shí)間了,但實(shí)在不知道文章咋寫…就再放放吧;最后就是超像素分割了,超像素分割有k-means算法的影子,所以可以先看看k-means算法的代碼實(shí)現(xiàn)過程。
1,算法原理
初始化種子點(diǎn)(聚類中心):按照設(shè)定的超像素個(gè)數(shù),在圖像內(nèi)均勻的分配種子點(diǎn)。假設(shè)圖片總共有 N 個(gè)像素點(diǎn),預(yù)分割為 K 個(gè)相同尺寸的超像素,那么每個(gè)超像素的大小為N/ K ,則相鄰種子點(diǎn)的距離(步長)近似為S=sqrt(N/K)。
在種子點(diǎn)的n*n鄰域內(nèi)重新選擇種子點(diǎn)(一般取n=3)。具體方法為:計(jì)算該鄰域內(nèi)所有像素點(diǎn)的梯度值,將種子點(diǎn)移到該鄰域內(nèi)梯度最小的地方。這樣做的目的是為了避免種子點(diǎn)落在梯度較大的輪廓邊界上,以免影響后續(xù)聚類效果。
在每個(gè)種子點(diǎn)周圍的鄰域內(nèi)為每個(gè)像素點(diǎn)分配類標(biāo)簽(即屬于哪個(gè)聚類中心)。和標(biāo)準(zhǔn)的k-means在整張圖中搜索不同,SLIC的搜索范圍限制為2S2S,可以加速算法收斂,如下圖。在此注意一點(diǎn):期望的超像素尺寸為SS,但是搜索的范圍是2S*2S。
距離度量。包括顏色距離和空間距離。對(duì)于每個(gè)搜索到的像素點(diǎn),分別計(jì)算它和該種子點(diǎn)的距離。距離計(jì)算方法如下:
其中,dc代表顏色距離,ds代表空間距離,Ns是類內(nèi)最大空間距離,定義為Ns=S=sqrt(N/K),適用于每個(gè)聚類。最大的顏色距離Nc既隨圖片不同而不同,也隨聚類不同而不同,所以我們?nèi)∫粋€(gè)固定常數(shù)m(取值范圍[1,40],一般取10)代替。最終的距離度量D’如下:
由于每個(gè)像素點(diǎn)都會(huì)被多個(gè)種子點(diǎn)搜索到,所以每個(gè)像素點(diǎn)都會(huì)有一個(gè)與周圍種子點(diǎn)的距離,取最小值對(duì)應(yīng)的種子點(diǎn)作為該像素點(diǎn)的聚類中心。
迭代優(yōu)化。理論上上述步驟不斷迭代直到誤差收斂(可以理解為每個(gè)像素點(diǎn)聚類中心不再發(fā)生變化為止),實(shí)踐發(fā)現(xiàn)10次迭代對(duì)絕大部分圖片都可以得到較理想效果,所以一般迭代次數(shù)取10。
增強(qiáng)連通性。經(jīng)過上述迭代優(yōu)化可能出現(xiàn)以下瑕疵:出現(xiàn)多連通情況、超像素尺寸過小,單個(gè)超像素被切割成多個(gè)不連續(xù)超像素等,這些情況可以通過增強(qiáng)連通性解決。主要思路是:新建一張標(biāo)記表,表內(nèi)元素均為-1,按照“Z”型走向(從左到右,從上到下順序)將不連續(xù)的超像素、尺寸過小超像素重新分配給鄰近的超像素,遍歷過的像素點(diǎn)分配給相應(yīng)的標(biāo)簽,直到所有點(diǎn)遍歷完畢為止。
2,偽算法描述
3,程序介紹
程序聲明了一個(gè)SLIC算法類,類的具體程序太長了,就不貼了,大家可以去qq群【222954293】下載程序自己看,都注釋好了。
就看一下主程序吧:
int main() {【1】讀取原圖并顯示Mat image = imread("千矢.png",33);if (image.empty()){printf_s("圖片讀取失敗");return -1;}imshow("原圖", image);【2】轉(zhuǎn)換為LAB顏色空間 方便計(jì)算距離Mat lab_image = image.clone();cvtColor(image, lab_image, COLOR_BGR2Lab);//定義超像素?cái)?shù)以及權(quán)重int w = image.cols, h = image.rows;int nr_superpixels = 300;//超像素?cái)?shù)int nc = 40;//權(quán)重mdouble step = sqrt((w * h) / (double)nr_superpixels);【3】執(zhí)行SLIC超像素算法SLIC slic;slic.generate_superpixels(&lab_image, step, nc);slic.create_connectivity(&lab_image);【4】顯示分割輪廓和分割結(jié)果圖//該三個(gè)函數(shù)可以分別注釋單獨(dú)顯示查看slic.colour_with_cluster_means(&image);//顏色均值填充slic.display_contours(&image, Scalar(0, 0, 255));//顯示輪廓//slic.display_center_grid(&image, Scalar(255, 0, 0));//顯示中心點(diǎn)imshow("result", image);waitKey(0); }一共是四個(gè)步驟。其中步驟【2】中需要自己定義兩個(gè)變量nr_superpixels和nc。
- nr_superpixels為超像素個(gè)數(shù),你可以根據(jù)圖像大小自己定義,如果圖像x方向10個(gè)超像素塊,y方向30個(gè)超像素塊,那就是300。
- 權(quán)重變量nc,即上文【算法原理】第4步中的固定常數(shù)m,一般取1-40范圍內(nèi)的整數(shù)。
3,效果展示
4,THE END
本文原創(chuàng)內(nèi)容有限,就是整合了一下自己看的超像素分割的博客,兩篇不錯(cuò)的鏈接放這兒了:
https://blog.csdn.net/zhj_matlab/article/details/52986700 https://blog.csdn.net/qq_26129959/article/details/90760028代碼放qq群【222954293】了,今天就到這里啦。
總結(jié)
以上是生活随笔為你收集整理的【手撕算法】C++实现超像素分割算法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 计算机黑屏什么原因,教您电脑黑屏的原因是
- 下一篇: s3c2440移植MQTT