草庐IT

android - 识别手写的圆形、菱形和矩形

coder 2023-11-29 原文

我正在寻找有关识别三种手写形状(圆形、菱形和矩形)的一些建议。我尝试了不同的方法,但都失败了,所以也许你可以给我指出另一个更好的方向。

我尝试过的:

1) 基于手写形状和理想形状的点积的简单算法。它在识别矩形方面效果还不错,但在识别圆形和菱形方面就失败了。问题是即使对于理想形状,圆形和菱形的点积也非常相似。

2) 相同的方法,但使用动态时间扭曲作为相似性的度量。类似问题。

3) 神经网络。我尝试了一些方法 - 将点数据提供给神经网络(前馈和 Kohonen)或提供光栅化图像。对于 Kohonen,它总是将所有数据(用于训练的样本事件)归为同一类别。带点的前馈更好(但与方法 1 和 2 处于同一水平)并且光栅化图像非常慢(我需要至少 size^2 个输入神经元,对于小尺寸的光栅圆即使对我来说也无法区分;))也没有成功。我想是因为所有这些形状都是封闭的图形?我不是 ANN 的大专家(有 1 个学期的类(class))所以也许我用错了?

4) 将形状保存为弗里曼链码并使用一些算法计算相似度。我虽然在 FCC 中形状会非常不同。这里没有成功(但我还没有很深入地探索这条路)。

我正在用它为 Android 构建应用程序,但我认为这里的语言无关紧要。

最佳答案

这是形状分类器的一些工作代码。 http://jsfiddle.net/R3ns3/我从以太中提取了阈值数字(*代码中的阈值变量),因此当然可以对其进行调整以获得更好的结果。

我使用边界框、子部分中的平均点、点之间的角度、与边界框中心的极角和角识别。它可以对手绘矩形、菱形和圆形进行分类。代码在鼠标按钮按下时记录点,并在您停止绘图时尝试分类。

HTML

<canvas id="draw" width="300" height="300" style="position:absolute; top:0px; left:0p; margin:0; padding:0; width:300px; height:300px; border:2px solid blue;"></canvas>

JS

var state = {
    width: 300,
    height: 300,
    pointRadius: 2,
    cornerThreshold: 125,
    circleThreshold: 145,
    rectangleThreshold: 45,
    diamondThreshold: 135,
    canvas: document.getElementById("draw"),
    ctx: document.getElementById("draw").getContext("2d"),
    drawing: false,
    points: [],
    getCorners: function(angles, pts) {
        var list = pts || this.points;
        var corners = [];
        for(var i=0; i<angles.length; i++) {
            if(angles[i] <= this.cornerThreshold) {
                corners.push(list[(i + 1) % list.length]);
            }
        }
        return corners;
    },
    draw: function(color, pts) {
        var list = pts||this.points;
        this.ctx.fillStyle = color;
        for(var i=0; i<list.length; i++) {
            this.ctx.beginPath();
            this.ctx.arc(list[i].x, list[i].y, this.pointRadius, 0, Math.PI * 2, false);
            this.ctx.fill();
        }
    },
    classify: function() {
        // get bounding box
        var left = this.width, right = 0, 
            top = this.height, bottom = 0;
        for(var i=0; i<this.points.length; i++) {
            var pt = this.points[i];
            if(left > pt.x) left = pt.x;
            if(right < pt.x) right = pt.x;
            if(top > pt.y) top = pt.y;
            if(bottom < pt.y) bottom = pt.y;
        }
        var center = {x: (left+right)/2, y: (top+bottom)/2};
        this.draw("#00f", [
            {x: left, y: top},
            {x: right, y: top},
            {x: left, y: bottom},
            {x: right, y: bottom},
            ]);
        // find average point in each sector (9 sectors)
        var sects = [
            {x:0,y:0,c:0},{x:0,y:0,c:0},{x:0,y:0,c:0},
            {x:0,y:0,c:0},{x:0,y:0,c:0},{x:0,y:0,c:0},
            {x:0,y:0,c:0},{x:0,y:0,c:0},{x:0,y:0,c:0}
            ];
        var x3 = (right + (1/(right-left)) - left) / 3;
        var y3 = (bottom + (1/(bottom-top)) - top) / 3;
        for(var i=0; i<this.points.length; i++) {
            var pt = this.points[i];
            var sx = Math.floor((pt.x - left) / x3);
            var sy = Math.floor((pt.y - top) / y3);
            var idx = sy * 3 + sx;
            sects[idx].x += pt.x;
            sects[idx].y += pt.y;
            sects[idx].c ++;
            if(sx == 1 && sy == 1) {
                return "UNKNOWN";
            }
        }
        // get the significant points (clockwise)
        var sigPts = [];
        var clk = [0, 1, 2, 5, 8, 7, 6, 3]
        for(var i=0; i<clk.length; i++) {
            var pt = sects[clk[i]];
            if(pt.c > 0) {
                sigPts.push({x: pt.x / pt.c, y: pt.y / pt.c});
            } else {
                return "UNKNOWN";
            }
        }
        this.draw("#0f0", sigPts);
        // find angle between consecutive 3 points
        var angles = [];
        for(var i=0; i<sigPts.length; i++) {
            var a = sigPts[i],
                b = sigPts[(i + 1) % sigPts.length],
                c = sigPts[(i + 2) % sigPts.length],
                ab = Math.sqrt(Math.pow(b.x-a.x,2)+Math.pow(b.y-a.y,2)),
                bc = Math.sqrt(Math.pow(b.x-c.x,2)+ Math.pow(b.y-c.y,2)),
                ac = Math.sqrt(Math.pow(c.x-a.x,2)+ Math.pow(c.y-a.y,2)),
                deg = Math.floor(Math.acos((bc*bc+ab*ab-ac*ac)/(2*bc*ab)) * 180 / Math.PI);
            angles.push(deg);                
        }
        console.log(angles);
        var corners = this.getCorners(angles, sigPts);
        // get polar angle of corners
        for(var i=0; i<corners.length; i++) {
            corners[i].t = Math.floor(Math.atan2(corners[i].y - center.y, corners[i].x - center.x) * 180 / Math.PI);
        }
        console.log(corners);
        // whats the shape ?
        if(corners.length <= 1) { // circle
            return "CIRCLE";
        } else if(corners.length == 2) { // circle || diamond
            // difference of polar angles
            var diff = Math.abs((corners[0].t - corners[1].t + 180) % 360 - 180);
            console.log(diff);
            if(diff <= this.circleThreshold) {
                return "CIRCLE";
            } else {
                return "DIAMOND";
            }
        } else if(corners.length == 4) { // rectangle || diamond
            // sum of polar angles of corners
            var sum = Math.abs(corners[0].t + corners[1].t + corners[2].t + corners[3].t); 
            console.log(sum);
            if(sum <= this.rectangleThreshold) {
                return "RECTANGLE";
            } else if(sum >= this.diamondThreshold) {
                return "DIAMOND";
            } else {
                return "UNKNOWN";
            }
        } else {
            alert("draw neater please");
            return "UNKNOWN";
        }
    }
};
state.canvas.addEventListener("mousedown", (function(e) {
    if(!this.drawing) {
        this.ctx.clearRect(0, 0, 300, 300);
        this.points = [];
        this.drawing = true;
        console.log("drawing start");
    }
}).bind(state), false);
state.canvas.addEventListener("mouseup", (function(e) {
    this.drawing = false;
    console.log("drawing stop");
    this.draw("#f00");
    alert(this.classify());
}).bind(state), false);
state.canvas.addEventListener("mousemove", (function(e) {
    if(this.drawing) {
        var x = e.pageX, y = e.pageY;
        this.points.push({"x": x, "y": y});
        this.ctx.fillStyle = "#000";
        this.ctx.fillRect(x-2, y-2, 4, 4);
    }
}).bind(state), false);

关于android - 识别手写的圆形、菱形和矩形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20254440/

有关android - 识别手写的圆形、菱形和矩形的更多相关文章

  1. 报告回顾丨模型进化狂飙,DetectGPT能否识别最新模型生成结果? - 2

    导读语言模型给我们的生产生活带来了极大便利,但同时不少人也利用他们从事作弊工作。如何规避这些难辨真伪的文字所产生的负面影响也成为一大难题。在3月9日智源Live第33期活动「DetectGPT:判断文本是否为机器生成的工具」中,主讲人Eric为我们讲解了DetectGPT工作背后的思路——一种基于概率曲率检测的用于检测模型生成文本的工具,它可以帮助我们更好地分辨文章的来源和可信度,对保护信息真实、防止欺诈等方面具有重要意义。本次报告主要围绕其功能,实现和效果等展开。(文末点击“阅读原文”,查看活动回放。)Ericmitchell斯坦福大学计算机系四年级博士生,由ChelseaFinn和Chri

  2. [Vuforia]二.3D物体识别 - 2

    之前说过10之后的版本没有3dScan了,所以还是9.8的版本或者之前更早的版本。 3d物体扫描需要先下载扫描的APK进行扫面。首先要在手机上装一个扫描程序,扫描现实中的三维物体,然后上传高通官网,在下载成UnityPackage类型让Unity能够使用这个扫描程序可以从高通官网上进行下载,是一个安卓程序。点到Tools往下滑,找到VuforiaObjectScanner下载后解压数据线连接手机,将apk文件拷入手机安装然后刚才解压文件中的Media文件夹打开,两个PDF图打印第一张A4-ObjectScanningTarget.pdf,主要是用来辅助扫描的。好了,接下来就是扫描三维物体。将瓶

  3. ruby-on-rails - 在 heroku 的 .fonts 文件夹中包含自定义字体,似乎无法识别它们 - 2

    Heroku支持人员告诉我,为了在我的Web应用程序中使用自定义字体(未安装在系统中,您可以在bash控制台中使用fc-list查看已安装的字体)我必须部署一个包含所有字体的.fonts文件夹里面的字体。问题是我不知道该怎么做。我的意思是,我不知道文件名是否必须遵循heroku的任何特殊模式,或者我必须在我的代码中做一些事情来考虑这种字体,或者如果我将它包含在文件夹中它是自动的......事实是,我尝试以不同的方式更改字体的文件名,但根本没有使用该字体。为了提供更多详细信息,我们使用字体的过程是将PDF转换为图像,更具体地说,使用rghostgem。并且最终图像根本不使用自定义字体。在

  4. 安卓apk修改(Android反编译apk) - 2

    最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路

  5. ruby-on-rails - 没有这样的文件或目录 - 用 Mini Magick 识别 - 2

    在我让另一个人重做我的前端UI之前,我的Rails应用程序运行平稳。我已经尝试解决此错误3天了。这是错误:Nosuchfileordirectory-identifyExtractedsource(aroundline#59):575859606162@post=Post.find(params[:id])authorize@postif@post.update_attributes(post_params)flash[:notice]="Postwasupdated."redirect_to[@topic,@post]else{"utf8"=>"✓","_method"=>"patc

  6. ruby - 使用 ruby​​ 识别阵列上的运行 - 2

    如果我们有一个数组array=[1,1,0,0,2,3,0,0,0,3,3,3]我们如何识别给定数字的运行(具有相同值的连续数字的数量)?例如:run_pattern_for(array,0)->2run_pattern_for(array,3)->1run_pattern_for(array,1)->1run_pattern_for(array,2)->0没有2的运行,因为没有连续出现2。3有一个运行,因为只有一个幻影以树为连续数字。 最佳答案 尝试:classArraydefcount_runs(element)chunk{|n

  7. 最新版人脸识别小程序 图片识别 生成二维码签到 地图上选点进行位置签到 计算签到距离 课程会议活动打卡日常考勤 上课签到打卡考勤口令签到 - 2

    技术选型1,前端小程序原生MINA框架cssJavaScriptWxml2,管理后台云开发Cms内容管理系统web网页3,数据后台小程序云开发云函数云开发数据库(基于MongoDB)云存储4,人脸识别算法基于百度智能云实现人脸识别一,用户端效果图预览老规矩我们先来看效果图,如果效果图符合你的需求,就继续往下看,如果不符合你的需求,可以跳过。1-1,登录注册页可以看到登录页有注册入口,注册页如下我们的注册,需要管理员审核,审核通过后才可以正常登录使用小程序1-2,个人中心页登录成功以后,我们会进入个人中心页我们在个人中心页可以注册人脸,因为我们做人脸识别签到,需要先注册人脸才可以进行人脸比对,进

  8. ruby-on-rails - 尝试登录和使用 heroku 时无法识别 ruby​​.exe - 2

    当尝试创建一个heroku应用程序并通过git推送到它时,我收到以下错误:$herokucreate'"C:\ProgramFiles\ruby-1.9.2\bin\ruby.exe"isnotrecognizedasaninternalorexternalcommand,operableprogramorbatchfile.但是,$ruby-vruby1.9.3p125[i386-mingw32]我已经检查了PATH环境,它肯定包含“C:\ProgramFiles(x86)\ruby-1.9.2\bin”。同样有趣的是,当导航到该目录时,它实际上并不包含名为ruby​​.exe的文件

  9. 基于Python的人脸识别课堂系统(毕设)——附录上 - 2

    本文章承接《基于Python的人脸识别课堂考勤系统(毕设)》,填坑上篇文章遗留的代码部分。因为项目分的模块比较多,再加上本人能力有限,所以代码过于臃肿还存在许多优化的地方。同样本篇文章也仅适用于小白,零基础人群。PS:每个文件之中代码都已经区分开来,可以对照左侧目录部分实现快速预览!    由于代码过于多我这里分成上,下两个部分来发布吧!一、主文件importosimportsysimportrandomimportpymysqlimportcv2importnumpyasnpfrommathimportpifrommatplotlibimportpyplotaspltfromPILimpor

  10. 焕新古文化传承之路,AI为古彝文识别赋能 - 2

    目录1古彝文与古典保护2古文识别的挑战2.1西文与汉文OCR2.2古彝文识别难点3合合信息:古彝文保护新思路3.1图像矫正3.2图像增强3.3语义理解3.4工程技巧4总结1古彝文与古典保护彝文指的是云南、贵州、四川等地的彝族人使用的文字,区别于现代意义上的彝文,古彝文指的是在民间流通使用的原生态彝文,多达87046字。古彝文的起源距今至少数千年,是世界上最古老的文字之一。对古彝文字集研究有助于理解尚未被翻译成汉文、用字尚未规范化的古籍,更深层、透彻地作用于传统文化保护。古彝文字义对照图(网络资料+邵文苑供图)古籍是不可再生的宝贵资源,应当得到妥善保护。中国的古籍在历史上迭经水火兵燹等自然灾害、

随机推荐