分簇+觸控式螢幕精確定位Algo
分簇+觸控式螢幕精確定位Algo
問題分析
現代生活,觸控式螢幕手機已是非常普及,可以說人手一隻。我們只要用手指輕輕在螢幕上觸碰,手機就能感應到我們的操作,並且執行相應的功能。那麼,手機是怎樣定位到觸控點的呢?這個就是我們今天要討論演算法所重點要模擬解決的問題。
解決的思路是:把我們手機螢幕看成一個二維座標系,橫豎分別分為X軸和Y軸,這樣我們就可以通過座標值來定位某個點。知道如何表示觸控點還不足夠,我們怎樣確定定位點呢?這就涉及到硬體了,每個螢幕TP上面都會有電容感應器,當你用手觸控某個地方時,那裡對應的電容值便會升高。多點觸控,就會有多個地方電容值升高。
但問題又來了,我們觸控的地方往往是一個區域,因為我們手指有一定的寬度。所以,我們需要按電容值的高低對螢幕座標先進行分簇,即區域性最大值聚類。對np_values搜尋區域性極大值。如果只找到一個區域性最大值,則有一個單點觸控。如果找到多個區域性極大值,則有多個接觸。
分簇完成,接下來就好辦了,可以通過計算電容加權平均值得出每個分簇的精確定位。
分簇實現
下面是一個螢幕電容值的模擬資料表:

電容值模擬表.png
可以看到,表中所給電容值橫軸方向、縱軸方向都有所變化,當觸控式螢幕某個位置有觸控動作發生時,該處電容值會升高,由此可判斷出,上圖中有兩處按壓。
可得到兩個序列:
x軸序列是{0,6,137,84,9,4},Y軸序列是{1,4,45,25,2,2,13,52,58,15,4}。
分簇要找的就是所給序列的突峰區間,如果用索引(座標索引從0開始計)來表示的話,上述x軸序列有一個分簇區間[0,5],y軸序列有兩個分簇區間[0,4]和[5,10]。圖示如下:

X軸序列.png

Y軸序列.png
最後,我們需要輸出分簇結果:x軸分簇[0,5],y軸分簇[0,4]、[5,10]。
分簇演算法實現的難點在哪兒呢?我覺得應該是如何判斷一個分簇的開始與結束。為了實現判斷,我在遍歷索引的時候,加上了標誌變數(如果當前電容值比它的前者大的話,標誌變數置1,否則置2)。然後在輸出分簇的時候,我們就可以通過判斷標誌變數,準確輸出區間。主要實現程式碼如下:
printf("x方向上的增減標誌位如下:\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方向上的增減標誌位如下:\n"); for (j = 0; j < y-1; j++) { if(yy[j] <= yy[j+1]) { yTag[j] = 1; } //根據區間來看,前後相等的情況應該賦值為2,所以上面小於情況的=號可下可不下 if(yy[j] >= yy[j+1]) { yTag[j] = 2; bianjieY++; } printf("%d", yTag[j]); } //定義二維陣列用於儲存區間的索引 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]); }
精確定位實現
有了分簇結果,我們就可以借用分簇結果來計算每個分簇對應的精確座標值了。計算的過程:首先需要找到分簇區間中每個索引對應的電容值,把電容值累加到變數CapacitanceALL,然後將每個索引值*對應電容值累加到變數AddAll,最後就可通過AddAll / CapacitanceALL來計算出每個分簇的精確值location。
主要實現程式碼如下:
while(i < x-1) { printf("\nX方向上的分簇[%d, %d]", xsection[i][0], xsection[i][1]); AddAll = 0.0,CapacitanceALL = 0.0; location = 0.0; //輸出此段分簇區間的精確定位 for(m = xsection[i][0];m <= xsection[i][1];m++) { AddAll = AddAll + xx[m] * m; CapacitanceALL = CapacitanceALL + xx[m]; } location = AddAll / CapacitanceALL; printf(" 此段分簇區間的加權精確x值是:%.3f",location); i++; if(xsection[i][0] == 0) { break; } }
演算法測試
測試資料用的是上面提供電容模擬表中的數值,分別輸入X、Y方向上的電容值,測試結果如下:

AlgoTest.png
後言
關於這個演算法就介紹這麼多了,有什麼不對的地方還望多多指教,也歡迎大家關注我(簡書/ ofollow,noindex">GitHub )
謝謝觀看此文。
原始碼地址