分簇+觸摸屏精確定位Algo
問題分析
現(xiàn)代生活万搔,觸摸屏手機已是非常普及,可以說人手一只扣孟。我們只要用手指輕輕在屏幕上觸碰烫堤,手機就能感應(yīng)到我們的操作,并且執(zhí)行相應(yīng)的功能哈打。那么塔逃,手機是怎樣定位到觸摸點的呢?這個就是我們今天要討論算法所重點要模擬解決的問題料仗。
解決的思路是:把我們手機屏幕看成一個二維坐標(biāo)系湾盗,橫豎分別分為X軸和Y軸,這樣我們就可以通過坐標(biāo)值來定位某個點立轧。知道如何表示觸摸點還不足夠格粪,我們怎樣確定定位點呢?這就涉及到硬件了氛改,每個屏幕TP上面都會有電容感應(yīng)器帐萎,當(dāng)你用手觸摸某個地方時,那里對應(yīng)的電容值便會升高胜卤。多點觸摸疆导,就會有多個地方電容值升高。
但問題又來了葛躏,我們觸摸的地方往往是一個區(qū)域澈段,因為我們手指有一定的寬度。所以舰攒,我們需要按電容值的高低對屏幕坐標(biāo)先進(jìn)行分簇败富,即局部最大值聚類。對np_values搜索局部極大值摩窃。如果只找到一個局部最大值兽叮,則有一個單點觸摸。如果找到多個局部極大值猾愿,則有多個接觸鹦聪。
分簇完成,接下來就好辦了蒂秘,可以通過計算電容加權(quán)平均值得出每個分簇的精確定位椎麦。
分簇實現(xiàn)
下面是一個屏幕電容值的模擬數(shù)據(jù)表:
可以看到,表中所給電容值橫軸方向材彪、縱軸方向都有所變化观挎,當(dāng)觸摸屏某個位置有觸摸動作發(fā)生時,該處電容值會升高段化,由此可判斷出嘁捷,上圖中有兩處按壓。
可得到兩個序列:
x軸序列是{0显熏,6雄嚣,137,84喘蟆,9缓升,4},Y軸序列是{1蕴轨,4港谊,45,25橙弱,2歧寺,2,13棘脐,52斜筐,58,15蛀缝,4}顷链。
分簇要找的就是所給序列的突峰區(qū)間,如果用索引(坐標(biāo)索引從0開始計)來表示的話屈梁,上述x軸序列有一個分簇區(qū)間[0嗤练,5],y軸序列有兩個分簇區(qū)間[0俘闯,4]和[5潭苞,10]。圖示如下:
最后真朗,我們需要輸出分簇結(jié)果:x軸分簇[0此疹,5],y軸分簇[0遮婶,4]蝗碎、[5,10]旗扑。
分簇算法實現(xiàn)的難點在哪兒呢蹦骑?我覺得應(yīng)該是如何判斷一個分簇的開始與結(jié)束。為了實現(xiàn)判斷臀防,我在遍歷索引的時候眠菇,加上了標(biāo)志變量(如果當(dāng)前電容值比它的前者大的話边败,標(biāo)志變量置1,否則置2)捎废。然后在輸出分簇的時候笑窜,我們就可以通過判斷標(biāo)志變量,準(zhǔn)確輸出區(qū)間登疗。主要實現(xiàn)代碼如下:
printf("x方向上的增減標(biāo)志位如下:\n");
for (i = 0; i < x-1; i++)
{
if(xx[i] <= xx[i+1])
{
xTag[i] = 1;
}
if(xx[i] >= xx[i+1])
{
xTag[i] = 2;
bianjieX++;
}
printf("%d", xTag[i]);
}
printf("y方向上的增減標(biāo)志位如下:\n");
for (j = 0; j < y-1; j++)
{
if(yy[j] <= yy[j+1])
{
yTag[j] = 1;
}
//根據(jù)區(qū)間來看排截,前后相等的情況應(yīng)該賦值為2,所以上面小于情況的=號可下可不下
if(yy[j] >= yy[j+1])
{
yTag[j] = 2;
bianjieY++;
}
printf("%d", yTag[j]);
}
//定義二維數(shù)組用于存儲區(qū)間的索引
for (i = 0; i < x-1; i++) {
if(xTag[i] == 2 && xTag[i+1] == 1) {
xsection[count++][1] = i;
xsection[count][0] = i+1;
}
}
if(xsection[count][1] == 0) {
xsection[count][1] = x-1;
}
while(i < x-1) {
printf("\nX方向上的分簇[%d, %d]", xsection[i][0], xsection[i][1]);
}
精確定位實現(xiàn)
有了分簇結(jié)果辐益,我們就可以借用分簇結(jié)果來計算每個分簇對應(yīng)的精確坐標(biāo)值了断傲。計算的過程:首先需要找到分簇區(qū)間中每個索引對應(yīng)的電容值,把電容值累加到變量CapacitanceALL智政,然后將每個索引值*對應(yīng)電容值累加到變量AddAll认罩,最后就可通過AddAll / CapacitanceALL來計算出每個分簇的精確值location。
主要實現(xiàn)代碼如下:
while(i < x-1) {
printf("\nX方向上的分簇[%d, %d]", xsection[i][0], xsection[i][1]);
AddAll = 0.0,CapacitanceALL = 0.0;
location = 0.0;
//輸出此段分簇區(qū)間的精確定位
for(m = xsection[i][0];m <= xsection[i][1];m++)
{
AddAll = AddAll + xx[m] * m;
CapacitanceALL = CapacitanceALL + xx[m];
}
location = AddAll / CapacitanceALL;
printf(" 此段分簇區(qū)間的加權(quán)精確x值是:%.3f",location);
i++;
if(xsection[i][0] == 0) {
break;
}
}
算法測試
測試數(shù)據(jù)用的是上面提供電容模擬表中的數(shù)值女仰,分別輸入X猜年、Y方向上的電容值,測試結(jié)果如下:
后言
關(guān)于這個算法就介紹這么多了疾忍,有什么不對的地方還望多多指教乔外,也歡迎大家關(guān)注我(簡書/GitHub)
謝謝觀看此文。
源代碼地址?http://pan.baidu.com/s/1slAOoTf