緒:
本文本家兒要針對方針區域和布景區域灰度值近似,即圖像對比度差;
采用基于Otsu閾值朋分法不易朋分;
這里介紹給出了一個不算堅苦的方式:
起首,以三個模板對圖像進行卷積,提取特征,構建特征標的目的量調集;
然后,采用k-means聚類方式,對特征標的目的量調集聚類,提取方針類別;
最后,基于形態學操作,朋分出方針區域。
 方針區域和布景區域灰度值近似的圖像,如下圖所示:
在圖中,
比力光滑的處所為路面--方針,
紋理較豐碩的處所為樹林--布景;這是遙感圖像;
那么問題來了:
若何在這幅圖像中,朋分出路臉孔標區域?
 在上圖中,常見的閾值朋分法必定是不可的。
這里給出了一種紋理朋分方式,
利用了三種特征來表征某一像素在其范疇規模內的紋理性質;
按照路臉孔標區域和樹林布景區域的紋理性質分歧,來進行闡發。
起首,給出了三個特征模板,如圖所示:
①單元面積灰度轉變總量:
針對這個公式,我機關了一個5*5的模板
即只需要用這個模板對原圖進行濾波就可以求出單元面積灰度轉變總量;
②Laws紋理測量模板中的高頻點檢測模板R5R5
③Laws紋理測量模板中的V外形檢測模板E5S5
 別離將上述三個模板與圖像做卷積,
并將獲得的成果構成一個矢量;在三維空間里面進行Kmean聚類;
法式如下:
Mat pLawsEnergy(raw_img.size(),CV_32FC3);//特征標的目的量調集
int i,j,m,n;
float sumRR,sumES,sumVAR;
for (i=2;i<m_width-2;i++)//lie
{
for (j=2;j<m_height-2;j++)//hang
{
sumRR = 0;
sumES = 0;
sumVAR= 0;
for (m=-2;m<=2;m++)//核巨細,卷積操作
{
for (n=-2;n<=2;n++)
{
unsigned char *raw_data=(unsigned char*)(raw_img.data+(j+n)*raw_img.step);
float p_data = raw_data[i+m];
sumES += E5S5[m+2][n+2]*p_data;
sumRR += R5R5[m+2][n+2]*p_data;
sumVAR+= VAR[m+2][n+2]*p_data;
}
}
float *pLawsEnergy_data = (float*)(pLawsEnergy.data+j*pLawsEnergy.step);
pLawsEnergy_data[3*i+0]=abs(sumVAR)/25;
pLawsEnergy_data[3*i+1]=abs(sumRR)/25;
pLawsEnergy_data[3*i+2]=abs(sumES)/25;
}
}
 
 k-means聚類:
k-means算法是一個聚類算法,
聚類算法用于按照數據的特征發現數據項的相似性,并將相似的數據項放在統一個組中,相似性采用距離進行描述。
k-means聚類的流程:
起首,隨機拔取k個點,將每個點分派給它們,獲得最初的k個分類;
然后,在每個分類入彀算均值,將點從頭分派,劃歸到比來的中間點;
反復上述步調直到點的劃歸不再改變。
 k-means聚類的流程:
針對本圖像,分為路臉孔標和樹林布景兩類;
①設置初始聚類中間{100,100,100},{0,0,0};
②按照差的絕對值之和計較相似度,將圖像像素劃分為方針和布景兩類;
③從頭計較聚類中間;一般用求重心的方式;
④判定,聚類中間是否改變,若是沒改變則收斂;不然,繼續迭代。
⑤采用形態學操作進一步優化朋分圖像;
如圖所示:
//進來的伴侶,點贊,存眷,投票,感謝!
 本文法式總結如下:
因為字數較多,故經由過程圖像顯示如下:
#include "stdafx.h"
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
const int R5R5[5][5]=
{
1, -4, 6, -4, 1,
-4, 16,-24, 16, -4,
6, -24, 36, -24, 6,
-4, 16,-24, 16, -4,
1, -4, 6, -4, 1
};
const int E5S5[5][5]=
{
-1, 0, 2, 0, -1,
-2, 0, 4, 0, -2,
0, 0, 0, 0, 0,
2, 0, -4, 0, 2,
1, 0, -2, 0, 1
};
const int VAR[5][5]=
{
-1, -1, -1, -1, -1,
-1, -1, -1, -1, -1,
-1, -1, 24, -1, -1,
-1, -1, -1, -1, -1,
-1, -1, -1, -1, -1,
};
Mat raw_img = imread("3A.bmp",0);
int m_height = raw_img.rows;
int m_width = raw_img.cols;
Mat pLawsEnergy(raw_img.size(),CV_32FC3);
int i,j,m,n;
float sumRR,sumES,sumVAR;
for (i=2;i<m_width-2;i++)
{
for (j=2;j<m_height-2;j++)
{
sumRR = 0;
sumES = 0;
sumVAR= 0;
for (m=-2;m<=2;m++)
{
for (n=-2;n<=2;n++)
{
unsigned char *raw_data=(unsigned char*)(raw_img.data+(j+n)*raw_img.step);
float p_data = raw_data[i+m];
sumES += E5S5[m+2][n+2]*p_data;
sumRR += R5R5[m+2][n+2]*p_data;
sumVAR+= VAR[m+2][n+2]*p_data;
}
}
float *pLawsEnergy_data = (float*)(pLawsEnergy.data+j*pLawsEnergy.step);
pLawsEnergy_data[3*i+0]=abs(sumVAR)/25;
pLawsEnergy_data[3*i+1]=abs(sumRR)/25;
pLawsEnergy_data[3*i+2]=abs(sumES)/25;
}
}
//namedWindow("dst",CV_WINDOW_NORMAL);
//imshow("dst",pLawsEnergy);
//聚類朋分成果
Mat clusters_img(raw_img.size(),CV_8UC1);
float center1[3]={100,100,100};
float center2[3]={0,0,0};//初始聚類中間
float center1_pre[3]={0,0,0};//判別是否收斂
float center2_pre[3]={0,0,0};
unsigned int loop_times=0;//輪回次數
unsigned int flag = 0;
int classnum[2]={0,0};//每種類此外個數
do
{
loop_times++;
classnum[0]=0;
classnum[1]=0;
float dist1,dist2;
for (i=2;i<m_width-2;i++)
{
for (j=2;j<m_height-2;j++)
{
dist1=0;
dist2=0;
for (m=0;m<3;m++)
{
float *pLawsEnergy_data_1=(float*)(pLawsEnergy.data+j*pLawsEnergy.step);
dist1 += abs(pLawsEnergy_data_1[3*i+m]-center1[m]);
dist2 += abs(pLawsEnergy_data_1[3*i+m]-center2[m]);
}
if (dist1 < dist2)
{
unsigned char *clusters_data_1=(unsigned char*)(clusters_img.data+j*clusters_img.step);
clusters_data_1[i]=0;
classnum[0]++;
}
else
{
unsigned char *clusters_data_2=(unsigned char*)(clusters_img.data+j*clusters_img.step);
clusters_data_2[i]=255;
classnum[1]++;
}
}
}
//從頭計較聚類中間
for (i=0;i<3;i++)
{
center1[i]=0;
center2[i]=0;
}
for (i=2;i<m_width-2;i++)
{
for (j=2;j<m_height-2;j++)
{
unsigned char *clusters_data_3=(unsigned char*)(clusters_img.data+j*clusters_img.step);
if (clusters_data_3[i]==0)
{
for (m=0;m<3;m++)
{
float *pLawsEnergy_data_2=(float*)(pLawsEnergy.data+j*pLawsEnergy.step);
center1[m] +=pLawsEnergy_data_2[3*i+m]/classnum[0];
}
}
else
{
for (m=0;m<3;m++)
{
float *pLawsEnergy_data_3=(float*)(pLawsEnergy.data+j*pLawsEnergy.step);
center2[m] +=pLawsEnergy_data_3[3*i+m]/classnum[1];
}
}
}
}
flag=0;//判定是否收斂
for (m=0;m<3;m++)
{
if (center1[m]!=center1_pre[m])
{
flag=1;
center1_pre[m]=center1[m];
}
if (center2[m]!=center2_pre[m])
{
flag=1;
center2_pre[m]=center2[m];
}
}
} while (flag && loop_times<150);
imwrite("temp_binary.jpg",clusters_img);
Mat element = getStructuringElement(MORPH_RECT, Size(5, 5));
dilate(clusters_img, clusters_img, element);
erode(clusters_img, clusters_img, element);
dilate(clusters_img, clusters_img, element);
imwrite("binary_img.jpg",clusters_img);
Mat dst_img;
raw_img.copyTo(dst_img,~clusters_img);
imwrite("segment.jpg",dst_img);
waitKey(0);
return 0;
}
 0 篇文章
如果覺得我的文章對您有用,請隨意打賞。你的支持將鼓勵我繼續創作!