unity c# 触摸屏物体识别桌算法

article/2025/9/11 18:18:31

unity源码地址链接:unityc#触摸屏物体识别桌算法-C#文档类资源-CSDN下载

实操的时候出现算出来的坐标不对,没有时间去找问题,优化了,所以代码仅供参考。

使用的是Lean Touch插件,免费的。

模块由三个点构成,基本构成等腰三角形,但是实际是会有误差的。

我的想法是在识别时,1.先计算出所有的边的长度,并记录下坐标。2.然后对比配置文件中的长度,记录符合配置文件的长度。3.然后再对比配置文件中的角度值。

主要算法在OnFingerUpdate()中,Update()中按下W键,则是记录模块的三条边长度和顶角的角度。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Lean.Touch;
using UnityEngine.UI;
using System;public class touchTest : MonoBehaviour
{public Text text;public Text text2;public static List<LeanFinger> Fingers = new List<LeanFinger>(10);private static List<LeanFinger> allFingers = new List<LeanFinger>();//记录模块最后一次的旋转角度,并进行比较,当前是正转是反转private double[] RecordLastAngel = new double[6] { 0, 0, 0, 0, 0, 0 };public GameObject[] MoveObj;public GameObject RecordPage;void Start(){//MoveObj[0].transform.rotation = Quaternion.Euler(Vector3.forward * (float)-60);}private void OnEnable(){LeanTouch.OnFingerUpdate += OnFingerUpdate;LeanTouch.OnFingerDown += OnFingerDown;LeanTouch.OnFingerUp += OnFingerUp;LeanTouch.OnFingerSwipe += OnFingerSwipe;}private void OnDisable(){LeanTouch.OnFingerUpdate -= OnFingerUpdate;LeanTouch.OnFingerDown -= OnFingerDown;LeanTouch.OnFingerUp -= OnFingerUp;LeanTouch.OnFingerSwipe -= OnFingerSwipe;}public class PtoP_Length{public float distances { get; set; }public Vector2 FirstPosition { get; set; }public Vector2 SecondPosition { get; set; }}void OnFingerUpdate(LeanFinger finger){var fingers = LeanTouch.Fingers;text.text = "";if (fingers.Count >= 4){List<PtoP_Length> PtoP_length = new List<PtoP_Length>();PtoP_length.Clear();//Debug.Log("1" + fingers[0].ScreenPosition);//Debug.Log("2" + fingers[1].ScreenPosition);//Debug.Log("3" + fingers[2].ScreenPosition);//Debug.Log("4" + fingers[3].ScreenPosition);//所有点到点的长度for (int i = 1; i < fingers.Count; i++){//text.text += fingers[i].ScreenPosition.ToString() + "|";for (int j = i + 1; j < fingers.Count; j++){double temp = getPointBetweenLength(fingers[i].ScreenPosition, fingers[j].ScreenPosition);//记录点到点的长度和两点的坐标PtoP_Length ppl = new PtoP_Length();ppl.FirstPosition = fingers[i].ScreenPosition;ppl.SecondPosition = fingers[j].ScreenPosition;ppl.distances = (float)(temp);PtoP_length.Add(ppl);text2.text += temp + "|";}}//对比配置文件中的令牌数据List<int> RecordDis = new List<int>();//RecordDis.Clear();for (int i = 0; i < ReadXml.ID.Count; i++){RecordDis.Clear();//对比配置文件中符合距离的数据for (int j = 0; j < PtoP_length.Count; j++){//记录符合距离的数据if (PtoP_length[j].distances > (Convert.ToInt32(ReadXml.DisA[i]) - 10)&& PtoP_length[j].distances < (Convert.ToInt32(ReadXml.DisA[i]) + 10)){RecordDis.Add(j);}else if (PtoP_length[j].distances > (Convert.ToInt32(ReadXml.DisB[i]) - 10)&& PtoP_length[j].distances < (Convert.ToInt32(ReadXml.DisB[i]) + 10)){RecordDis.Add(j);}else if (PtoP_length[j].distances > (Convert.ToInt32(ReadXml.DisC[i]) - 10)&& PtoP_length[j].distances < (Convert.ToInt32(ReadXml.DisC[i]) + 10)){RecordDis.Add(j);}}bool temprecordbool = false;//获取正确角度的数值for (int k = 0; k < RecordDis.Count; k++){for (int l = 0; l < RecordDis.Count; l++){if (temprecordbool == false){for (int o = 0; o < RecordDis.Count; o++){//获取所有可能double temp1 = PtoP_length[RecordDis[k]].distances;double temp2 = PtoP_length[RecordDis[l]].distances;double temp3 = PtoP_length[RecordDis[o]].distances;//获取所有可能的角度double tempangle = GetAngle(temp1, temp2, temp3);//把记录下的角度增减10度左右,因为可能会有误差double angleplus = Convert.ToDouble(ReadXml.Angle[i]) + 10;double anglejian = Convert.ToDouble(ReadXml.Angle[i]) - 10;//然后和所有的角度进行比对if (tempangle <= angleplus && tempangle >= anglejian){//角度正确,即表示temp1为(1,2),temp2为(2,3),temp3为(1,3)或者(3,1)//坐标只有3个点,那么只需要PtoP_length[RecordDis[k]].distances上的两个点//就是第一个和第二个,第二个vet2为顶点坐标,//PtoP_length[RecordDis[l]].distances的第二个坐标即为最后一个坐标点Vector2 vet1 = PtoP_length[RecordDis[k]].FirstPosition;Vector2 vet2 = PtoP_length[RecordDis[k]].SecondPosition;Vector2 vet3 = PtoP_length[RecordDis[l]].SecondPosition;Vector2 centerPoint = GetCiclePoint(vet1, vet2, vet3);MoveObj[i].transform.position = new Vector2(centerPoint.x, centerPoint.y);//计算角度值,角度值为坐标系的上方为:0~180度,坐标系的下方为:-1~-179度//angel = Math.atan2(y, x)double xposition = vet2.x - centerPoint.x;double yposition = vet2.y - centerPoint.y;double roationAngel = Math.Round(Math.Atan2(yposition, xposition), 2);if (roationAngel < 0)roationAngel = roationAngel + 360;//if (RecordLastAngel[i] == 0)   //第一次为空时,记录坐标,后面都是通过获取到的实时角度来和第一次记录的坐标,来进行计算,是正转还是反转RecordLastAngel[i] = roationAngel;//当前旋转的角度,负数为反转,正数为正转double newAngel = roationAngel - RecordLastAngel[i];//if (newAngel > 5 || newAngel < -5)//{text2.text += "编号:" + i.ToString() + "的坐标为" + centerPoint + "角度为:" + roationAngel + "旋转了:" + newAngel;MoveObj[i].transform.rotation = Quaternion.Euler(Vector3.forward * (float)newAngel);temprecordbool = true;//}//MoveObj[i].transform.Rotate(0f, 0f, 2f);//每一帧绕自身坐标轴Z轴旋转2度}//else//{//    //角度不对,即移出屏幕//    MoveObj[i].transform.position = new Vector2(-2000, -2000);//    MoveObj[i].transform.Rotate(0f, 0f, 0f);//    for (int ab = 0; ab < RecordLastAngel.Length; ab++)//    { RecordLastAngel[ab] = 0; }//}}}}}}}}/// <summary>/// 任意两点之间的长度/// </summary>/// <param name="p"></param>/// <param name="p2"></param>/// <returns></returns>double getPointBetweenLength(Vector2 p, Vector2 p2){double value = Math.Sqrt(Math.Abs(p.x - p2.x) * Math.Abs(p.x - p2.x) + Math.Abs(p.y - p2.y) * Math.Abs(p.y - p2.y));return Math.Round(value, 2);}string SanJiao(double b1, double b2, double b3){string ss = "";//首先判断能否组成三角形if (b1 + b2 > b3 && b1 + b3 > b2 && b2 + b3 > b1){//return "可以组成三角形";//判断是怎样的三角形,并输出if (b1 == b2 && b2 == b3){ss = "是等边三角形";}else if (b1 == b2 || b2 == b3 || b1 == b3)ss = "是等腰三角形";else if (b1 * b1 + b2 * b2 == b3 * b3 || b1 * b1 + b3 * b3 == b2 * b2 || b3 * b3 + b2 * b2 == b1 * b1)ss = "是直角三角形";}elsess = "输入的三边不能组成三角形";return ss;}//返回等腰三角形的顶角//但公式不能算出等腰三角形的顶角//令牌的三条边会有误差,正好不形成等腰三角,可以直接调用/// <summary>/// 计算角度/// </summary>/// <param name="a">长度最小的两条边</param>/// <param name="b">长度最小的两条边</param>/// <param name="c">最长的一条边长度</param>/// <returns></returns>double GetAngle(double a, double b, double c){try{double sss = Math.Acos((a * a + b * b - c * c) / (2 * a * b)) / Math.PI * 180;return sss;}catch { return 0; }}//获取三点的中心点Vector2 GetCiclePoint(Vector2 first, Vector2 second, Vector2 thrid){float tempA1;float tempA2, tempB1, tempB2;float tempC1, tempC2;float temp, x, y;tempA1 = first.x - first.x;tempB1 = first.y - second.y;tempC1 = float.Parse(((Math.Pow(first.x, 2) - Math.Pow(second.x, 2) + Math.Pow(first.y, 2) - Math.Pow(second.y, 2)) / 2).ToString());tempA2 = thrid.x - second.x;tempB2 = thrid.y - second.y;tempC2 = float.Parse(((Math.Pow(thrid.x, 2) - Math.Pow(second.x, 2) + Math.Pow(thrid.y, 2) - Math.Pow(second.y, 2)) / 2).ToString());temp = tempA1 * tempB2 - tempA2 * tempB1;if (temp == 0){x = first.x;y = first.y;}else{x = (tempC1 * tempB2 - tempC2 * tempB1) / temp;y = (tempA1 * tempC2 - tempA2 * tempC1) / temp;}return new Vector2(x, y);}void OnFingerDown(LeanFinger finger){//Debug.Log("Finger:" + finger.Index);//text2.text = text2.text + finger.TapCount + "\r\n";}void OnFingerUp(LeanFinger finger){//for (int i = 0; i < text2.Length; i++)//{//    text2[i].text = "";//}}void OnFingerSwipe(LeanFinger finger){//Debug.Log("FingerSwipe:" + finger.ScreenPosition);}public Text text3;void Update(){text3.text = MoveObj[0].transform.position.x.ToString()+","+ MoveObj[0].transform.position.y.ToString();//MoveObj[0].transform.Rotate(0f, 0f, 2f);//每一帧绕自身坐标轴Z轴旋转2度var fingers = LeanTouch.Fingers;//Debug.Log("update:" + fingers.Count);//text.text = text.text + fingers.ScreenPosition + "\r\n";//Debug.Log("Finger:" + LeanGesture.GetTwistDegrees());//LeanGesture.GetTwistDegrees();if (Input.GetKeyDown(KeyCode.D)){RecordPage.SetActive(!RecordPage.activeInHierarchy);}if (Input.GetKeyDown(KeyCode.W) && RecordPage.activeInHierarchy){if (fingers.Count == 3){//记录模块坐标double firstBian = getPointBetweenLength(fingers[1].ScreenPosition, fingers[2].ScreenPosition);double secondBian = getPointBetweenLength(fingers[2].ScreenPosition, fingers[3].ScreenPosition);double thridBian = getPointBetweenLength(fingers[1].ScreenPosition, fingers[3].ScreenPosition);double temp1 = firstBian - secondBian;double temp2 = firstBian - thridBian;double temp3 = secondBian - thridBian;string id = RecordPage.transform.GetChild(0).transform.GetChild(0).transform.GetComponent<Text>().text;if (temp1 <= 10 && temp1 >= -10){double angle = GetAngle(firstBian, secondBian, thridBian);ReadXml.readxml.UpdateXml(id, firstBian.ToString(), secondBian.ToString(), thridBian.ToString(), angle.ToString());}else if (temp2 <= 10 && temp2 >= -10){double angle = GetAngle(firstBian, thridBian, secondBian);ReadXml.readxml.UpdateXml(id, firstBian.ToString(), thridBian.ToString(), secondBian.ToString(), angle.ToString());}else if (temp3 <= 10 && temp3 >= -10){double angle = GetAngle(secondBian, thridBian, firstBian);ReadXml.readxml.UpdateXml(id, secondBian.ToString(), thridBian.ToString(), firstBian.ToString(), angle.ToString());}}}//allFingers.Clear();//allFingers.AddRange(LeanTouch.Fingers);//allFingers.AddRange(LeanTouch.InactiveFingers);//allFingers.Sort((a, b) => a.Index.CompareTo(b.Index));//for (var i = 0; i < allFingers.Count; i++)//{//    var finger = allFingers[i];//    //var progress = touch.TapThreshold > 0.0f ? finger.Age / touch.TapThreshold : 0.0f;//    //var style = GetFadingLabel(finger.Set, progress);//    //if (style.normal.textColor.a > 0.0f)//    //{//    var screenPosition = finger.ScreenPosition;//    var state = "UPDATE";//    if (finger.Down == true) state = "DOWN";//    if (finger.Up == true) state = "UP";//    if (finger.IsActive == false) state = "INACTIVE";//    if (finger.Expired == true) state = "EXPIRED";//    if (finger.Index != -42)//    {//        string sss = finger.Index + " - " + state + "  + " + Mathf.FloorToInt(screenPosition.x) + ", " + Mathf.FloorToInt(screenPosition.y);//    }//}}
}

以下是参考图片和链接

Object Interaction With Touchscreens : 6 Steps (with Pictures) - Instructables

感兴趣的,可以试试在OnFingerDown()中先识别哪个几个点是按下了,然后在OnFingerUpdate()中再处理,会更精准点。因为OnFingerUpdate()中获取到的坐标并不精确。


http://chatgpt.dhexx.cn/article/FspDbIkg.shtml

相关文章

如何用AR引擎技术, 5步优雅实现物体识别和跟踪

AR技术让应用实现虚拟世界和现实世界的融合&#xff0c;让开发者的创意和脑洞能够拥有更多炫酷有趣的呈现方式。AR拍照、AR购物、AR教育、AR搜索等丰富应用场景&#xff0c;凭借着AR技术的加持&#xff0c;为用户带来更优质的沉浸式体验&#xff0c;为用户创造更多价值。 例如…

物体识别全流程(Ubuntu16.04)结合ROS

物体识别全流程&#xff08;Ubuntu16.04&#xff09;结合ROS 1.使用labellmg&#xff0c;标记图片&#xff0c;生成xml标签 在此下载labellmg包 下载之后解压到要放置的目录 推荐使用Python3Qt5 打开labellmg包 在当前目录终端下运行如下命令行 sudo apt-get install pyqt5-…

opencv人脸识别以及自定义物体识别系统

目录 一、简介&#xff1a; 二、软硬件应用&#xff1a; 三、模块介绍&#xff1a; &#xff08;一&#xff09;人脸识别&#xff1a; &#xff08;二&#xff09;、自定义物体识别&#xff1a; &#xff08;三&#xff09;、图片展示&#xff1a; &#xff08;四&#x…

opencv物体识别-识别水果

前言 玩一玩用opencv做一些简单的物体识别 1.思路讲解 我们基于简单的opencv的阈值分割&#xff0c;通过这个阈值分割&#xff0c;我们能把我们需要识别的物体在二值图里面变成白色&#xff0c;其余的变成黑色。然后对我们分割出来的物体部分提取轮廓&#xff0c;算出覆盖轮…

物体识别

一、物体识别 图像识别&#xff1a;很重要&#xff0c;是很多算法的基础 图像识别定位&#xff1a;识别出来是猫&#xff0c;且定位出猫的位置 物体检测&#xff1a;每个图像中含有多物体&#xff0c;检测出有几个个体&#xff0c;并框出来位置 图像分割&#xff1a;不仅仅框…

【AI技术】物体识别概述1

【AI技术】物体识别概述1 1、背景2、物体识别3、应用 1、背景 主要针对客户以及初学者概述物体识别。 2、物体识别 物体识别又叫目标识别&#xff0c;物体分类&#xff0c;图像分类&#xff0c;习惯性称为图像分类&#xff0c;即对整张图片进行分类。 物体识别针对的是物体分…

目标检测和物体识别的方法有哪些?如何进行物体定位和分类?

目标检测和物体识别是计算机视觉领域中重要的任务&#xff0c;旨在从图像或视频中自动定位和识别出不同类别的物体。这些任务在许多应用领域中具有广泛的应用&#xff0c;如自动驾驶、视频监控、人机交互等。本文将介绍目标检测和物体识别的方法以及如何进行物体定位和分类。 一…

小程序 跳转 公众号 文章

1.通过组件 web-view https://developers.weixin.qq.com/miniprogram/dev/component/web-view.html <web-view src"https://mp.weixin.qq.com/s/Cz4x4QpvF_Pozn7xjYOVyw"></web-view>2.如果是关联好小程序的公众号 1.如果是 左图文章 都是 https://m…

微信小程序跳转公众号h5页面

小程序提供了web- view组件进行用来内嵌网页 根据限制说明准备域名即可&#xff0c;开发阶断可以使用http的域名&#xff0c;在开发者工具中勾选不验证https证书即可&#xff0c;发布上线时必须使用https的域名。 同时需要小程序后台配置业务域名。

微信小程序跳转微信公众号

1 webview 嵌套 微信公众号的页面 然后 文章里 添加 公众号二维码 然后引导用户长按识别公众号 2 公众号有关注的页面 路径 需要自己找 我记得是替换什么officeid啥的 百度即可 3 利用<official-account bindload"lookSuccess" binderror"lookFai…

微信小程序跳转公众号

长按识别跳转 步骤&#xff1a; 新建一个页面使用web-view组件的src链接到公众号编辑好的一篇带有公众号的二维码的文章 微信规则只有小程序关联的公众号里的文章可以长按识别二维码 <template><view><!--微信规则只有小程序关联的公众号里的文章可以长按识别…

小程序直接跳转公众号的必要条件记录

1、小程序必须关联公众号主体&#xff0c;可以从图1查看是否已被关联&#xff0c;如果没有被关联&#xff0c;则可以去图2进行关联 图1&#xff1a; 图2&#xff1a;登录微信公众平台&#xff0c;进入图片广告-小程序管理&#xff0c;进行关联 2.小程序不能直接打开公众号首…

小程序跳转公众号文章

这是首页的代码 <image class"seedingBannar" data-id"{{item.id}}" bindtap"goTweet" src"{{resourceUrlitem.iconPath}}"></image>// 跳转到推文页面goTweet: function (e) {console.log(e.currentTarget.dataset.id)wx…

uni-app微信小程序跳转公众号;微信小程序打开公众号;微信小程序识别二维码添加好友;微信小程序通过公众号添加好友;小程序里识别企业微信二维码点击联系人名片无反应?

需求&#xff1a; 在微信小程序页面中&#xff0c;长按识别图片二维码&#xff0c;识别出联系人后&#xff0c;点击添加好友&#xff1b; 问题&#xff1a;微信官方社区说是小程序添加不了好友&#xff1b; 解决方案&#xff1a; 目前只能通过微信小程序跳转至公众号&#xf…

uniapp写小程序跳转公众号H5链接

需求&#xff1a; 需求是小程序的首页banner图来自pc端配置生产。 在小程序点击轮播的banner图后&#xff0c;跳到对应的linkurl&#xff0c;但是我们和客户约定好&#xff0c;只能跳转公众号。 一开始看了小程序的文档&#xff0c;需要配置什么业务域名&#xff0c;下载校验…

微信小程序如何跳转微信公众号

目录 一、微信公众号配置二、微信小程序配置三、添加代码 一、微信公众号配置 登录微信公众号&#xff0c;点击【小程序管理】&#xff1a; 点击【添加】&#xff1a; 点击【关联小程序】&#xff1a; 输入小程序进行关联&#xff1a; 二、微信小程序配置 登录微信小程序…

小程序跳转公众号关注页面的两种方法

一、web-view方法 这个种方法有一个必须要达到的条件就是&#xff1a;小程序的公众号必须是认证的企业号&#xff0c;而且要在小程序公众号的后台添加“veb-view业务域名”&#xff01;不然会出现如下情况 <!--pages/webview666/webview.wxml--> <view class"ty…

小程序 小程序跳转公众号页面

web-view 基础库 1.6.4 开始支持&#xff0c;低版本需做兼容处理。 承载网页的容器。会自动铺满整个小程序页面&#xff0c;个人类型的小程序暂不支持使用。 客户端 6.7.2 版本开始&#xff0c;navigationStyle: custom 对 web-view 组件无效 小程序插件中不能使用。 属性类…

微信小程序跳转公众号推文

注&#xff1a;笔者是自学小程序&#xff0c;自身开发经验不足&#xff0c;代码肯定存在不规范和不足&#xff0c;该博客参考一下就好 完整项目代码&#xff1a;https://github.com/zim-keavin/wxapp-cloud-demo 实现在小程序中&#xff0c;点击某个组件后跳转到公众号的推文…

微信小程序跳转公众号链接

小程序跳转微信公众号文章&#xff0c;是通过web-view实现的。 1.web-view会默认自动打开所跳转的页面&#xff0c;但我们一般项目需求是点击某一按钮或下一步进行跳转&#xff0c;所以在小程序中我们需要新建一个页面来承载web-view 在页面点击按钮后跳转至承载页面&#xff0…