SLIC 超像素分割(C++)
摘要:
SLIC:simple linear iterative clustering,简单的线性迭代聚类,它使用k-means聚类来生成超像素,实现起来简单,运行效率还比较高,超像素对边界的保持效果也比较好,具体的与其他方法的对比结果在下方论文中有详细记录。
文章目录
- 摘要:
- 1.原理
- 2. 实现
- 2.1 初始化聚类中心
- 2.2 聚类
- 2.3 更新聚类中心
- 2.4 显示超像素分割结果
- 3. 实测效果
- 4. 完整源码
论文地址:https://infoscience.epfl.ch/record/177415/files/Superpixel_PAMI2011-2.pdf
代码地址:https://www.epfl.ch/labs/ivrl/research/slic-superpixels/#SLICO
1.原理
SLIC本质上说只需要一个聚类数k,这个聚类数k也就是超像素的个数,希望把图片分割成多少个超像素就设多少个聚类中心,在初始化时把聚类中心等间隔的放到图像上,设图像像素数为N,则在每个边长为N/k\sqrt{N/k}N/k的方格内放置一个初始聚类中心, 为了避免把噪声像素和边缘当作聚类中心,会把该中心移动到周围3*3邻域内梯度最小的地方。
在用k-means做聚类时,采用的特征是Lab颜色空间的三个值加上坐标x,y,一共5个维度,xi.feature=[L,a,b,x,y]Tx_{i.feature} = [L,a,b,x,y]^Txi.feature=[L,a,b,x,y]T,另外与常规的k均值不同的地方是,这里计算距离时只考虑聚类中心周围2N/k∗2N/k2\sqrt{N/k} * 2\sqrt{N/k}2N/k∗2N/k的邻域,因此计算量和一般的k均值聚类相比要小很多。搜索空间对比如下图,S=N/kS = \sqrt{N/k}S=N/k
聚类后计算每一类的平均特征,并把聚类中心的特征更新为平均特征。如果迭代超过10次或者前后两次聚类的差小于阈值则结束,否则继续聚类,更新聚类中心…。算法流程如下:
2. 实现
2.1 初始化聚类中心
原文中按聚类数k来等间隔地初始化聚类中心,假设样本总数为N,聚类数为k,则每隔N/kN/kN/k个样本放置一个聚类中心。在图片上等间隔地放置k个初始聚类中心,也就是把图片等分成边长为N/k\sqrt{N/k}N/k的格子,在格子的固定位置放置初始聚类中心。另外为了避免初始的聚类中心落在物体边缘上,还要对每一个聚类中心都进行一下微调,具体就是计算初始聚类中心点周围邻域的梯度,把中心点移到梯度最小的点上。
这里实现的时候以初始超像素的边长len作为参数会比较直观,可以很简单的控制生成的超像素的大小,k和len的关系是len=N/klen=\sqrt{N/k}len=N/k。
注:图片坐标系以左上角为原点,水平向右为x轴正方向,水平向下为y轴正方向(与opencv一致),在访问图片数据矩阵时,一般用行和列的方式来描述,也就是row对应y,colum对应x。
- 等间隔放置聚类中心,
int initilizeCenters(cv::Mat &imageLAB, std::vector<center> ¢ers, int len)
{if (imageLAB.empty()){std::cout << "In itilizeCenters: image is empty!\n";return -1;}uchar *ptr = NULL;center cent;int num = 0;for (int i = 0; i < imageLAB.rows; i += len){cent.y = i + len / 2;if (cent.y >= imageLAB.rows) continue;ptr = imageLAB.ptr<uchar>(cent.y);for (int j = 0; j < imageLAB.cols; j += len){cent.x = j + len / 2;if ((cent.x >= imageLAB.cols)) continue;cent.L = *(ptr + cent.x * 3);cent.A = *(ptr + cent.x * 3 + 1);cent.B = *(ptr + cent.x * 3 + 2);cent.label = ++num;centers.push_back(cent);}}return 0;
}
- 把聚类中心移到到周围8邻域里梯度最小的地方,梯度用Sobel计算(不希望聚类中心落在边缘上所以才调整的)
int fituneCenter(cv::Mat &imageLAB, cv::Mat &sobelGradient, std::vector<center> ¢ers)
{if (sobelGradient.empty()) return -1;center cent;double *sobPtr = sobelGradient.ptr<double>(0);uchar *imgPtr = imageLAB.ptr<uchar>(0);int w = sobelGradient.cols;for (int ck = 0; ck < centers.size(); ck++){cent = centers[ck];if (cent.x - 1 < 0 || cent.x + 1 >= sobelGradient.cols || cent.y - 1 < 0 || cent.y + 1 >= sobelGradient.rows){continue;}//end ifdouble minGradient = 9999999;int tempx = 0, tempy = 0;for (int m = -1; m < 2; m++){sobPtr = sobelGradient.ptr<double>(cent.y + m);for (int n = -1; n < 2; n++){double gradient = pow(*(sobPtr + (cent.x + n) * 3), 2)+ pow(*(sobPtr + (cent.x + n) * 3 + 1), 2)+ pow(*(sobPtr + (cent.x + n) * 3 + 2), 2);if (gradient < minGradient){minGradient = gradient;tempy = m;//rowtempx = n;//column}//end if}}cent.x += tempx;cent.y += tempy;imgPtr = imageLAB.ptr<uchar>(cent.y);centers[ck].x = cent.x;centers[ck].y = cent.y;centers[ck].L = *(imgPtr + cent.x * 3);centers[ck].A = *(imgPtr + cent.x * 3 + 1);centers[ck].B = *(imgPtr + cent.x * 3 + 2);}//end forreturn 0;
}
2.2 聚类
对每一个聚类中心center_k,计算它到周围2len*2len区域的所有点的距离,如果新计算的距离比原来的距离更小,则把该点归入center_k这一类。
注意聚类的本质就是“物以类聚”,判断样本点和聚类中心的“近似”程度,可以从两个方面来考察,一种是距离测度:距离越近越相似,另一种是相似性测度,例如角度相似系数,相关系数,指数相似系数等。
距离的计算方式有很多种,比如:
- 欧拉距离d(x⃗,y⃗)=∣∣x⃗−y⃗∣∣22d(\vec{x},\vec{y}) = ||\vec{x}-\vec{y}||_2^2d(x,y)=∣∣x−y∣∣22
- 城区距离d(x⃗,y⃗)=∣x⃗−y⃗∣d(\vec{x},\vec{y}) = |\vec{x}-\vec{y}|d(x,y)=∣x−y∣
- 切比雪夫距离d(x⃗,y⃗)=max∣xi−yi∣,i表示维度d(\vec{x},\vec{y}) = max|x_i-y_i|,i表示维度d(x,y)=max∣xi−yi∣,i表示维度
- 马氏距离(Mahalanobis):d(x⃗,y⃗)=(x⃗−y⃗)TV−1(x⃗−y⃗),V表示样本总体的协方差矩阵,V=1n−1Σi=1n(xi−x⃗ˉ⃗)(xi−x⃗ˉ⃗)T,n为样本数,xi⃗为第i个样本(列向量),x⃗ˉ为样本均值d(\vec{x},\vec{y}) = (\vec{x}-\vec{y})^TV^{-1}(\vec{x}-\vec{y}),V表示样本总体的协方差矩阵,V= \frac{1}{n-1}\Sigma_{i=1}^{n}(\vec{x_i - \bar{\vec{x}}})(\vec{x_i - \bar{\vec{x}}})^T,n为样本数, \vec{x_i}为第i个样本(列向量), \bar{\vec{x}}为样本均值d(x,y)=(x−y)TV−1(x−y),V表示样本总体的协方差矩阵,V=n−11Σi=1n(xi−xˉ)(xi−xˉ)T,n为样本数,xi为第i个样本(列向量),xˉ为样本均值,它有一点比较好的性质就是与量纲无关(另外它还对坐标尺度、旋转、平移保持不变,从统计意义上去除了分量间的相关性),在这里分割超像素时,Lab颜色空间的距离往往会比空间距离大很多,用欧式距离时需要加一个权重参数来调节颜色距离和空间距离的比例。
要是以后有时间的话可以考虑一下都试一下这些距离聚类的效果。这里采用的是欧式距离,而且因为Lab颜色空间和图像xy坐标空间量纲不同,需要调整颜色空间距离和xy坐标距离的权重,论文中用下面的方式来计算距离
dc=(lj−li)2+(aj−ai)2+(bj−bi)2ds=(xj−xi)2+(yj−yi)2D=dc2+(dsS)2m2\begin{aligned} d_{c}&=\sqrt{\left(l_{j}-l_{i}\right)^{2}+\left(a_{j}-a_{i}\right)^{2}+\left(b_{j}-b_{i}\right)^{2}} \\ d_{s} &=\sqrt{\left(x_{j}-x_{i}\right)^{2}+\left(y_{j}-y_{i}\right)^{2}}\\D&=\sqrt{d_{c}^{2}+\left(\frac{d_{s}}{S}\right)^{2} m^{2}} \end{aligned}dcdsD=(lj−li)2+(aj−ai)2+(bj−bi)2=(xj−xi)2+(yj−yi)2=dc2+(Sds)2m2
但是实际上在做超像素分割时我们更关心超像素的大小,而不是有多少个,虽然尺寸S和聚类数k有明确的对应关系,但是把k当输入参数不如直接用尺寸S来得直接,另外ds的权重用m2S2ds的权重用\frac{m^2}{S^2}ds的权重用S2m2实际用起来有点麻烦,因为单独修改m或者s都会被另外一个参数调制,所以D的计算我改成了下面这样D=dc2+mds2\begin{aligned}D=\sqrt{d_{c}^{2}+md_{s}^{2} }\end{aligned}D=dc2+mds2
int clustering(const cv::Mat &imageLAB, cv::Mat &DisMask, cv::Mat &labelMask,std::vector<center> ¢ers, int len, int m)
{if (imageLAB.empty()){std::cout << "clustering :the input image is empty!\n";return -1;}double *disPtr = NULL;//disMask type: 64FC1double *labelPtr = NULL;//labelMask type: 64FC1const uchar *imgPtr = NULL;//imageLAB type: 8UC3//disc = std::sqrt(pow(L - cL, 2)+pow(A - cA, 2)+pow(B - cB,2))//diss = std::sqrt(pow(x-cx,2) + pow(y-cy,2));//dis = sqrt(disc^2 + (diss/len)^2 * m^2)double dis = 0, disc = 0, diss = 0;//cluster center's cx, cy,cL,cA,cB;int cx, cy, cL, cA, cB, clabel;//imageLAB's x, y, L,A,Bint x, y, L, A, B;//注:这里的图像坐标以左上角为原点,水平向右为x正方向,水平向下为y正方向,与opencv保持一致// 从矩阵行列角度看,i表示行,j表示列,即(i,j) = (y,x)for (int ck = 0; ck < centers.size(); ++ck){cx = centers[ck].x;cy = centers[ck].y;cL = centers[ck].L;cA = centers[ck].A;cB = centers[ck].B;clabel = centers[ck].label;for (int i = cy - len; i < cy + len; i++){if (i < 0 | i >= imageLAB.rows) continue;//pointer point to the ith rowimgPtr = imageLAB.ptr<uchar>(i);disPtr = DisMask.ptr<double>(i);labelPtr = labelMask.ptr<double>(i);for (int j = cx - len; j < cx + len; j++){if (j < 0 | j >= imageLAB.cols) continue;L = *(imgPtr + j * 3);A = *(imgPtr + j * 3 + 1);B = *(imgPtr + j * 3 + 2);disc = std::sqrt(pow(L - cL, 2) + pow(A - cA, 2) + pow(B - cB, 2));diss = std::sqrt(pow(j - cx, 2) + pow(i - cy, 2));dis = sqrt(pow(disc, 2) + m * pow(diss, 2));if (dis < *(disPtr + j)){*(disPtr + j) = dis;*(labelPtr + j) = clabel;}//end if}//end for}}//end for (int ck = 0; ck < centers.size(); ++ck)return 0;
}
2.3 更新聚类中心
对每一个聚类中心center_k,把所有属于这一类的点的特征加起来求平均,把这个平均特征赋给center_k。
int updateCenter(cv::Mat &imageLAB, cv::Mat &labelMask, std::vector<center> ¢ers, int len)
{double *labelPtr = NULL;//labelMask type: 64FC1const uchar *imgPtr = NULL;//imageLAB type: 8UC3int cx, cy;for (int ck = 0; ck < centers.size(); ++ck){double sumx = 0, sumy = 0, sumL = 0, sumA = 0, sumB = 0, sumNum = 0;cx = centers[ck].x;cy = centers[ck].y;for (int i = cy - len; i < cy + len; i++){if (i < 0 | i >= imageLAB.rows) continue;//pointer point to the ith rowimgPtr = imageLAB.ptr<uchar>(i);labelPtr = labelMask.ptr<double>(i);for (int j = cx - len; j < cx + len; j++){if (j < 0 | j >= imageLAB.cols) continue;if (*(labelPtr + j) == centers[ck].label){sumL += *(imgPtr + j * 3);sumA += *(imgPtr + j * 3 + 1);sumB += *(imgPtr + j * 3 + 2);sumx += j;sumy += i;sumNum += 1;}//end if}}//update centerif (sumNum == 0) sumNum = 0.000000001;centers[ck].x = sumx / sumNum;centers[ck].y = sumy / sumNum;centers[ck].L = sumL / sumNum;centers[ck].A = sumA / sumNum;centers[ck].B = sumB / sumNum;}//end forreturn 0;
}
2.4 显示超像素分割结果
方式一:把属于同一类的点的特征都替换成平均特征;
方式二:画出聚类边界;
3. 实测效果
- 左侧为原图,中间为在原图上画出超像素边界效果图,右侧为超像素图像效果
4. 完整源码
//
//created by Mr. Peng. 2021\08\31
//#include "opencv.hpp"struct center
{int x;//columnint y;//rowint L;int A;int B;int label;
};/
//input parameters:
//imageLAB: the source image in Lab color space
//DisMask: it save the shortest distance to the nearest center
//labelMask: it save every pixel's label
//centers: clustering center
//len: the super pixls will be initialize to len*len
//m: a parameter witch adjust the weights of the spacial and color space distance
//
//output:
int clustering(const cv::Mat &imageLAB, cv::Mat &DisMask, cv::Mat &labelMask,std::vector<center> ¢ers, int len, int m)
{if (imageLAB.empty()){std::cout << "clustering :the input image is empty!\n";return -1;}double *disPtr = NULL;//disMask type: 64FC1double *labelPtr = NULL;//labelMask type: 64FC1const uchar *imgPtr = NULL;//imageLAB type: 8UC3//disc = std::sqrt(pow(L - cL, 2)+pow(A - cA, 2)+pow(B - cB,2))//diss = std::sqrt(pow(x-cx,2) + pow(y-cy,2));//dis = sqrt(disc^2 + (diss/len)^2 * m^2)double dis = 0, disc = 0, diss = 0;//cluster center's cx, cy,cL,cA,cB;int cx, cy, cL, cA, cB, clabel;//imageLAB's x, y, L,A,Bint x, y, L, A, B;//注:这里的图像坐标以左上角为原点,水平向右为x正方向,水平向下为y正方向,与opencv保持一致// 从矩阵行列角度看,i表示行,j表示列,即(i,j) = (y,x)for (int ck = 0; ck < centers.size(); ++ck){cx = centers[ck].x;cy = centers[ck].y;cL = centers[ck].L;cA = centers[ck].A;cB = centers[ck].B;clabel = centers[ck].label;for (int i = cy - len; i < cy + len; i++){if (i < 0 | i >= imageLAB.rows) continue;//pointer point to the ith rowimgPtr = imageLAB.ptr<uchar>(i);disPtr = DisMask.ptr<double>(i);labelPtr = labelMask.ptr<double>(i);for (int j = cx - len; j < cx + len; j++){if (j < 0 | j >= imageLAB.cols) continue;L = *(imgPtr + j * 3);A = *(imgPtr + j * 3 + 1);B = *(imgPtr + j * 3 + 2);disc = std::sqrt(pow(L - cL, 2) + pow(A - cA, 2) + pow(B - cB, 2));diss = std::sqrt(pow(j - cx, 2) + pow(i - cy, 2));dis = sqrt(pow(disc, 2) + m * pow(diss, 2));if (dis < *(disPtr + j)){*(disPtr + j) = dis;*(labelPtr + j) = clabel;}//end if}//end for}}//end for (int ck = 0; ck < centers.size(); ++ck)return 0;
}/
//input parameters:
//imageLAB: the source image in Lab color space
//labelMask: it save every pixel's label
//centers: clustering center
//len: the super pixls will be initialize to len*len
//
//output:
int updateCenter(cv::Mat &imageLAB, cv::Mat &labelMask, std::vector<center> ¢ers, int len)
{double *labelPtr = NULL;//labelMask type: 64FC1const uchar *imgPtr = NULL;//imageLAB type: 8UC3int cx, cy;for (int ck = 0; ck < centers.size(); ++ck){double sumx = 0, sumy = 0, sumL = 0, sumA = 0, sumB = 0, sumNum = 0;cx = centers[ck].x;cy = centers[ck].y;for (int i = cy - len; i < cy + len; i++){if (i < 0 | i >= imageLAB.rows) continue;//pointer point to the ith rowimgPtr = imageLAB.ptr<uchar>(i);labelPtr = labelMask.ptr<double>(i);for (int j = cx - len; j < cx + len; j++){if (j < 0 | j >= imageLAB.cols) continue;if (*(labelPtr + j) == centers[ck].label){sumL += *(imgPtr + j * 3);sumA += *(imgPtr + j * 3 + 1);sumB += *(imgPtr + j * 3 + 2);sumx += j;sumy += i;sumNum += 1;}//end if}}//update centerif (sumNum == 0) sumNum = 0.000000001;centers[ck].x = sumx / sumNum;centers[ck].y = sumy / sumNum;centers[ck].L = sumL / sumNum;centers[ck].A = sumA / sumNum;centers[ck].B = sumB / sumNum;}//end forreturn 0;
}int showSLICResult(const cv::Mat &image, cv::Mat &labelMask, std::vector<center> ¢ers, int len)
{cv::Mat dst = image.clone();cv::cvtColor(dst, dst, cv::COLOR_BGR2Lab);double *labelPtr = NULL;//labelMask type: 32FC1uchar *imgPtr = NULL;//image type: 8UC3int cx, cy;double sumx = 0, sumy = 0, sumL = 0, sumA = 0, sumB = 0, sumNum = 0.00000001;for (int ck = 0; ck < centers.size(); ++ck){cx = centers[ck].x;cy = centers[ck].y;for (int i = cy - len; i < cy + len; i++){if (i < 0 | i >= image.rows) continue;//pointer point to the ith rowimgPtr = dst.ptr<uchar>(i);labelPtr = labelMask.ptr<double>(i);for (int j = cx - len; j < cx + len; j++){if (j < 0 | j >= image.cols) continue;if (*(labelPtr + j) == centers[ck].label){*(imgPtr + j * 3) = centers[ck].L;*(imgPtr + j * 3 + 1) = centers[ck].A;*(imgPtr + j * 3 + 2) = centers[ck].B;}//end if}}}//end forcv::cvtColor(dst, dst, cv::COLOR_Lab2BGR);cv::namedWindow("showSLIC", 0);cv::imshow("showSLIC", dst);cv::waitKey(1);return 0;
}int showSLICResult2(const cv::Mat &image, cv::Mat &labelMask, std::vector<center> ¢ers, int len)
{cv::Mat dst = image.clone();//cv::cvtColor(dst, dst, cv::COLOR_Lab2BGR);double *labelPtr = NULL;//labelMask type: 32FC1double *labelPtr_nextRow = NULL;//labelMask type: 32FC1uchar *imgPtr = NULL;//image type: 8UC3for (int i = 0; i < labelMask.rows - 1; i++){labelPtr = labelMask.ptr<double>(i);imgPtr = dst.ptr<uchar>(i);for (int j = 0; j < labelMask.cols - 1; j++){//if left pixel's label is different from the right's if (*(labelPtr + j) != *(labelPtr + j + 1)){*(imgPtr + 3 * j) = 0;*(imgPtr + 3 * j + 1) = 0;*(imgPtr + 3 * j + 2) = 0;}//if the upper pixel's label is different from the bottom's labelPtr_nextRow = labelMask.ptr<double>(i + 1);if (*(labelPtr_nextRow + j) != *(labelPtr + j)){*(imgPtr + 3 * j) = 0;*(imgPtr + 3 * j + 1) = 0;*(imgPtr + 3 * j + 2) = 0;}}}//show centerfor (int ck = 0; ck < centers.size(); ck++){imgPtr = dst.ptr<uchar>(centers[ck].y);*(imgPtr + centers[ck].x * 3) = 100;*(imgPtr + centers[ck].x * 3 + 1) = 100;*(imgPtr + centers[ck].x * 3 + 1) = 10;}cv::namedWindow("showSLIC2", 0);cv::imshow("showSLIC2", dst);cv::waitKey(1);return 0;
}int initilizeCenters(cv::Mat &imageLAB, std::vector<center> ¢ers, int len)
{if (imageLAB.empty()){std::cout << "In itilizeCenters: image is empty!\n";return -1;}uchar *ptr = NULL;center cent;int num = 0;for (int i = 0; i < imageLAB.rows; i += len){cent.y = i + len / 2;if (cent.y >= imageLAB.rows) continue;ptr = imageLAB.ptr<uchar>(cent.y);for (int j = 0; j < imageLAB.cols; j += len){cent.x = j + len / 2;if ((cent.x >= imageLAB.cols)) continue;cent.L = *(ptr + cent.x * 3);cent.A = *(ptr + cent.x * 3 + 1);cent.B = *(ptr + cent.x * 3 + 2);cent.label = ++num;centers.push_back(cent);}}return 0;
}//if the center locates in the edges, fitune it's location.
int fituneCenter(cv::Mat &imageLAB, cv::Mat &sobelGradient, std::vector<center> ¢ers)
{if (sobelGradient.empty()) return -1;center cent;double *sobPtr = sobelGradient.ptr<double>(0);uchar *imgPtr = imageLAB.ptr<uchar>(0);int w = sobelGradient.cols;for (int ck = 0; ck < centers.size(); ck++){cent = centers[ck];if (cent.x - 1 < 0 || cent.x + 1 >= sobelGradient.cols || cent.y - 1 < 0 || cent.y + 1 >= sobelGradient.rows){continue;}//end ifdouble minGradient = 9999999;int tempx = 0, tempy = 0;for (int m = -1; m < 2; m++){sobPtr = sobelGradient.ptr<double>(cent.y + m);for (int n = -1; n < 2; n++){double gradient = pow(*(sobPtr + (cent.x + n) * 3), 2)+ pow(*(sobPtr + (cent.x + n) * 3 + 1), 2)+ pow(*(sobPtr + (cent.x + n) * 3 + 2), 2);if (gradient < minGradient){minGradient = gradient;tempy = m;//rowtempx = n;//column}//end if}}cent.x += tempx;cent.y += tempy;imgPtr = imageLAB.ptr<uchar>(cent.y);centers[ck].x = cent.x;centers[ck].y = cent.y;centers[ck].L = *(imgPtr + cent.x * 3);centers[ck].A = *(imgPtr + cent.x * 3 + 1);centers[ck].B = *(imgPtr + cent.x * 3 + 2);}//end forreturn 0;
}/
//input parameters:
//image: the source image in RGB color space
//resultLabel: it save every pixel's label
//len: the super pixls will be initialize to len*len
//m: a parameter witch adjust the weights of diss
//output:
int SLIC(cv::Mat &image, cv::Mat &resultLabel, std::vector<center> ¢ers, int len, int m)
{if (image.empty()){std::cout << "in SLIC the input image is empty!\n";return -1;}int MAXDIS = 999999;int height, width;height = image.rows;width = image.cols;//convert colorcv::Mat imageLAB;cv::cvtColor(image, imageLAB, cv::COLOR_BGR2Lab);//get sobel gradient mapcv::Mat sobelImagex, sobelImagey, sobelGradient;cv::Sobel(imageLAB, sobelImagex, CV_64F, 0, 1, 3);cv::Sobel(imageLAB, sobelImagey, CV_64F, 1, 0, 3);cv::addWeighted(sobelImagex, 0.5, sobelImagey, 0.5, 0, sobelGradient);//sobel output image type is CV_64F//initiate//std::vector<center> centers;//disMask save the distance of the pixels to center;cv::Mat disMask ;//labelMask save the label of the pixelscv::Mat labelMask = cv::Mat::zeros(cv::Size(width, height), CV_64FC1);//initialize centers, get centersinitilizeCenters(imageLAB, centers, len);//if the center locates in the edges, fitune it's locationfituneCenter(imageLAB, sobelGradient, centers);//update cluster 10 times for (int time = 0; time < 10; time++){//clusteringdisMask = cv::Mat(height, width, CV_64FC1, cv::Scalar(MAXDIS));clustering(imageLAB, disMask, labelMask, centers, len, m);//updateupdateCenter(imageLAB, labelMask, centers, len);//fituneCenter(imageLAB, sobelGradient, centers);}resultLabel = labelMask;return 0;
}int SLIC_Demo()
{std::string imagePath = "K:\\deepImage\\plane.jpg";cv::Mat image = cv::imread(imagePath);cv::Mat labelMask;//save every pixel's labelcv::Mat dst;//save the shortest distance to the nearest centersstd::vector<center> centers;//clustering centersint len = 25;//the scale of the superpixel ,len*lenint m = 10;//a parameter witch adjust the weights of spacial distance and the color space distanceSLIC(image, labelMask, centers, len, m);cv::namedWindow("image", 1);cv::imshow("image", image);showSLICResult(image, labelMask, centers, len);showSLICResult2(image, labelMask, centers, len);cv::waitKey(0);return 0;
}int main()
{SLIC_Demo();return 0;
}
SLIC 超像素分割(C++)相关推荐
- 图像分割:Python的SLIC超像素分割
图像分割:Python的SLIC超像素分割 1. 什么是超像素? 2. 为什么超像素在计算机视觉方面有重要的作用? 3. 简单线性迭代聚类(SLIC) 4. 效果图 5. 源码 参考 1. 什么是超像 ...
- VLFeat SLIC超像素分割(Cpp版)
这段时间对VLFeat的C接口非常的感兴趣,以前用的都是其Matlab接口,虽然很方便,而且提供的Matlab接口要比C接口功能更强大,但Matlab终归只能用来做一下快速的方法验证,所以想比较完整的 ...
- SLIC超像素分割方法
为了方便查找,记录SLIC超像素分割方法的介绍 简介 关键代码分析 应用
- SLIC超像素分割详解
SLIC超像素分割详解(一) 超像素概念是2003年Xiaofeng Ren提出和发展起来的图像分割技术,是指具有相似纹理.颜色.亮度等特征的相邻像素构成的有一定视觉意义的不规则像素块.它利用像素之间 ...
- SLIC 超像素分割详解(三):应用
看过上面的介绍后,我们应该思考一下:分割好的超像素有什么用?怎么用?用到哪里? 首先,超像素可以用来做跟踪,可以参考卢湖川课题组发表在IEEE TIP上的<Robust superpixeltr ...
- SLIC超像素分割的算法介绍和源码分析
前述 最近在看显著性检测,发现很多算法的基础是超像素分割,而正在看的Saliency Optimization from Robust Background Detection算法的预处理是SLIC算 ...
- 【转】 SLIC超像素分割详解(一):简介
http://blog.csdn.net/electech6/article/details/45509779 转载于:https://www.cnblogs.com/nfydream/p/57749 ...
- julia 调用python库_Julia调用Python实现超像素分割SLIC算法
最近想要在julia中实现 Simple Linear Iterative Clustering (SLIC) 算法对图像进行超像素分割,关于SLIC超像素分割算法,请参考SLIC Superpixe ...
- 超像素分割算法————综述
参考:超像素-学习笔记 什么是超像素?评价标准?SLIC.SEED.ETPS算法 比较的指标:图像边界的粘附性.算法速度.存储效率.分割性能 超像素算法:将像素组合成感知有意义的原子区域( atomi ...
- MATLAB显示slic,quickshift超像素分割结果图
首先介绍vlfeat库函数:vl_slic,vl_quickshift,vl_quckseg vl_slic SLIC superpixels segments = vl_slic(im,regio ...
最新文章
- 洛谷 P1843 奶牛晒衣服
- Android Sutiod报错:Dx unsupported class file version 52.0(解决)
- (转)汉字转拼音码缩写
- ts文件怎么合并转换成mp4?
- 基于人脸识别录入 人脸图片识别 及测试的效果
- 和老外聊天、发邮件常用英语缩写(超实用)
- android room详解
- 大疆创新2019校招
- matlab ts模糊工具箱,通过算例熟悉MATLAB模糊控制工具箱
- 【python】python爬虫requests库详解
- C盘不够了怎么办!将其他盘空间怎么分给C盘!
- SAP中服务类采购订单的收货审批确认
- 从野蛮生长到元年爆发,细数RPA的百年风雨
- 计算机c盘属性不显示安全选项,Win10系统下磁盘属性没有安全选项卡怎么解决?...
- 新年签通用php,《转帖》个人制作 猎人TMW字符串 三系整合通用 新年快乐帖
- RTU-518G 研究
- win10输入法变成繁体中文还原成简体中文的方法
- 波特率dlm_波特率与分频系数
- 现代控制理论-工程数学基础(1)-特征值特征向量
- 前端根据后端信息动态拼接html
热门文章
- WinCC V7.4 过程值归档概述及流程演示
- Win7如何简单的关闭445端口及445端口入侵详解
- ZYNQ图像处理(2)——ov5640_hdmi显示环境搭建
- testbench——信号的产生
- python爬虫万能代码-python网络爬虫源代码(可直接抓取图片)
- 平衡车 两轮平衡车扭扭车程序漂移车主板方案原理图pcb图程 两轮平衡车扭扭车程序体感车
- 基于SSM的毕业论文管理系统
- 《JavaScript 设计模式核心原理与应用实践》
- 联想笔记本腾讯会议摄像头灰屏或黑屏问题解决
- python画建筑物_通过Python将故宫的建筑物图片,转化为手绘图