手画图形自动修正HTML
仅在于其形式转载商用利用AI模型识别您绘制的形状并将其修正为标准的几何图形。html!DOCTYPE htmlhtml langzh-CNheadmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0, user-scalablenotitle手画图形自动修正 | AI 识别/titlestyle* {box-sizing: border-box;user-select: none;}body {margin: 0;min-height: 100vh;background: linear-gradient(145deg, #f5f7fa 0%, #e9edf5 100%);display: flex;justify-content: center;align-items: center;font-family: Segoe UI, Roboto, system-ui, -apple-system, sans-serif;padding: 16px;}.card {max-width: 700px;width: 100%;background: rgba(255, 255, 255, 0.7);backdrop-filter: blur(8px);-webkit-backdrop-filter: blur(8px);border-radius: 48px 48px 32px 32px;box-shadow: 0 20px 40px rgba(0, 20, 40, 0.2), 0 8px 16px rgba(0, 0, 0, 0.08);padding: 24px 24px 32px;transition: all 0.2s;border: 1px solid rgba(255, 255, 255, 0.5);}h1 {font-weight: 500;font-size: 1.8rem;letter-spacing: -0.5px;color: #1a2639;margin: 0 0 6px 0;display: flex;align-items: center;gap: 8px;}h1 small {font-size: 1rem;font-weight: 400;color: #4a5b6e;margin-left: 8px;opacity: 0.8;}.sub {color: #3a4a5e;margin-top: -4px;margin-bottom: 20px;font-weight: 300;font-size: 0.95rem;display: flex;justify-content: space-between;align-items: center;flex-wrap: wrap;}.canvas-wrapper {position: relative;background: #ffffff;border-radius: 28px;box-shadow: inset 0 4px 12px rgba(0, 0, 0, 0.06), 0 2px 4px rgba(0, 0, 0, 0.02);padding: 8px;margin-bottom: 20px;border: 1px solid rgba(255, 255, 255, 0.8);}#drawCanvas {display: block;width: 100%;height: auto;aspect-ratio: 1 / 1;background: #ffffff;border-radius: 24px;cursor: crosshair;touch-action: none; /* 避免触摸滚动 */box-shadow: 0 2px 8px rgba(0,0,0,0.03);}.toolbar {display: flex;flex-wrap: wrap;align-items: center;justify-content: center;gap: 12px 16px;margin: 16px 0 10px;}.btn-group {display: flex;gap: 8px;flex-wrap: wrap;justify-content: center;}.btn {background: #ffffffdd;border: none;padding: 10px 22px;border-radius: 60px;font-size: 0.95rem;font-weight: 500;color: #1e2b3a;box-shadow: 0 4px 8px rgba(0, 0, 0, 0.02), 0 2px 4px rgba(0, 0, 0, 0.02);backdrop-filter: blur(4px);background: rgba(255, 255, 255, 0.8);border: 1px solid rgba(255,255,255,0.6);transition: all 0.15s;display: inline-flex;align-items: center;gap: 6px;cursor: pointer;letter-spacing: 0.3px;}.btn-primary {background: #2c3e50;color: white;border: 1px solid #1f2e3d;box-shadow: 0 8px 16px -6px rgba(28, 52, 84, 0.2);}.btn-primary:hover {background: #1f3347;transform: scale(0.97);box-shadow: 0 4px 10px rgba(0,0,0,0.1);}.btn-primary:active {transform: scale(0.95);}.btn-outline {background: transparent;border: 1px solid #b0c0d0;color: #2c3e50;}.btn-outline:hover {background: #eef3fa;border-color: #8a9db0;}.btn:disabled {opacity: 0.5;pointer-events: none;filter: grayscale(0.3);}.badge {background: #d0dae8;padding: 4px 14px;border-radius: 40px;font-size: 0.8rem;color: #1a2a3a;font-weight: 500;}.status-area {background: #f0f4fc;border-radius: 40px;padding: 8px 20px;display: inline-block;font-size: 0.9rem;color: #1f3349;border: 1px solid #dce3ef;backdrop-filter: blur(2px);margin-top: 4px;}.footer {display: flex;justify-content: space-between;align-items: center;flex-wrap: wrap;margin-top: 12px;padding: 0 4px;}.hint {color: #4a5f78;font-size: 0.85rem;background: #eef3fa;padding: 6px 16px;border-radius: 30px;border: 1px solid #d3deec;}media (max-width: 480px) {.card { padding: 16px; }.btn { padding: 8px 16px; font-size: 0.85rem; }.toolbar { gap: 8px; }}/style/headbodydiv classcardh1✦ 图形修正small手画 → 标准/small/h1div classsubspan️ 绘制任意形状 · 点击修正/spanspan classbadge idshapeLabel⚡ 等待识别/span/divdiv classcanvas-wrappercanvas iddrawCanvas width600 height600/canvas/divdiv classtoolbardiv classbtn-groupbutton classbtn btn-primary idcorrectBtn✨ 修正图形/buttonbutton classbtn btn-outline idclearBtn️ 清空/button/divbutton classbtn btn-outline idundoBtn stylepadding:10px 18px;↩ 撤销/button/divdiv classfooterspan classstatus-area idstatusMessage✏️ 画一个圆、矩形或三角形/spanspan classhint⚡ 自动识别并修正/span/div/divscript(function(){// ----- 画布设置 -----const canvas document.getElementById(drawCanvas);const ctx canvas.getContext(2d);const rect canvas.getBoundingClientRect();const statusMsg document.getElementById(statusMessage);const shapeLabel document.getElementById(shapeLabel);// 尺寸 (画布逻辑 600x600)const W 600, H 600;canvas.width W;canvas.height H;// ----- 状态 -----let isDrawing false;let points []; // 当前笔画点集 {x, y}let strokes []; // 历史笔画 (用于撤销)let correctedShape null; // 修正后的图形数据 {type, points, ...}// 绘图样式const STROKE_COLOR #1f2e4a;const STROKE_WIDTH 3.5;const CORRECT_COLOR #d43f34;const CORRECT_WIDTH 3.2;// ----- 辅助函数 -----function getCanvasCoords(e) {const rect canvas.getBoundingClientRect();const scaleX canvas.width / rect.width; // 通常 canvas 逻辑尺寸与 CSS 尺寸比例const scaleY canvas.height / rect.height;let clientX, clientY;if (e.touches) {clientX e.touches[0].clientX;clientY e.touches[0].clientY;e.preventDefault();} else {clientX e.clientX;clientY e.clientY;}const x (clientX - rect.left) * scaleX;const y (clientY - rect.top) * scaleY;return { x: Math.min(W, Math.max(0, x)), y: Math.min(H, Math.max(0, y)) };}// 重绘全部 (包含修正图形)function redraw() {ctx.clearRect(0, 0, W, H);// 绘制所有保存的笔画 (strokes)ctx.lineCap round;ctx.lineJoin round;ctx.strokeStyle STROKE_COLOR;ctx.lineWidth STROKE_WIDTH;for (let stroke of strokes) {if (stroke.length 1) continue;ctx.beginPath();ctx.moveTo(stroke[0].x, stroke[0].y);for (let i 1; i stroke.length; i) {ctx.lineTo(stroke[i].x, stroke[i].y);}ctx.stroke();}// 绘制当前正在画的点 (如果 isDrawing 但 points 可能为空)if (points.length 1 !isDrawing) {// 如果不在绘制状态但有点用于显示最后一段(但通常不会)}// 如果有修正图形绘制修正结果 (覆盖)if (correctedShape) {ctx.save();ctx.strokeStyle CORRECT_COLOR;ctx.lineWidth CORRECT_WIDTH;ctx.setLineDash([6, 5]);ctx.shadowColor rgba(200, 60, 40, 0.2);ctx.shadowBlur 10;const pts correctedShape.points;if (pts pts.length 0) {ctx.beginPath();ctx.moveTo(pts[0].x, pts[0].y);for (let i 1; i pts.length; i) {ctx.lineTo(pts[i].x, pts[i].y);}// 如果是封闭图形 (矩形/三角形/圆用 closePath)if (correctedShape.type rectangle || correctedShape.type triangle || correctedShape.type circle) {ctx.closePath();}ctx.stroke();}ctx.restore();// 更新标签let label correctedShape.type.charAt(0).toUpperCase() correctedShape.type.slice(1);if (correctedShape.type circle) label ⭕ 圆;else if (correctedShape.type rectangle) label ▭ 矩形;else if (correctedShape.type triangle) label △ 三角形;else if (correctedShape.type line) label ━ 线段;shapeLabel.innerText label;statusMsg.innerText ✅ 已修正为 correctedShape.type;} else {// 没有修正图形显示提示if (strokes.length 0 points.length 0) {shapeLabel.innerText ⚡ 等待识别;statusMsg.innerText ✏️ 画一个圆、矩形或三角形;} else {// 有笔画但无修正shapeLabel.innerText 未修正;statusMsg.innerText ✏️ 点击 修正图形 识别;}}}// ----- 核心: 识别并修正图形 (基于简化点集) -----function recognizeAndCorrect() {// 合并所有笔画为一个点集 (用于识别)let allPoints [];for (let stroke of strokes) {allPoints allPoints.concat(stroke);}// 加上当前未保存的 points (如果正在画但没保存, 一般不会)if (points.length 0) {allPoints allPoints.concat(points);}// 如果点太少无法识别if (allPoints.length 6) {statusMsg.innerText ⚠️ 点太少请画一个完整形状;correctedShape null;redraw();return;}// 采样降噪均匀采样最多 80 个点 (提高性能)let sampled [];const step Math.max(1, Math.floor(allPoints.length / 80));for (let i 0; i allPoints.length; i step) {sampled.push(allPoints[i]);}if (sampled.length 4) sampled allPoints.slice(0, 20);// 1. 判断形状: 基于凸包 角度/距离特征 (简易)// 使用凸包算法 (Andrew monotone chain) 获取轮廓function convexHull(points) {if (points.length 3) return points.slice();const sorted points.slice().sort((a, b) a.x - b.x || a.y - b.y);const lower [];for (let p of sorted) {while (lower.length 2 cross(lower[lower.length-2], lower[lower.length-1], p) 0) lower.pop();lower.push(p);}const upper [];for (let p of sorted.reverse()) {while (upper.length 2 cross(upper[upper.length-2], upper[upper.length-1], p) 0) upper.pop();upper.push(p);}lower.pop();upper.pop();return lower.concat(upper);}function cross(o, a, b) {return (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x);}const hull convexHull(sampled);if (hull.length 3) {// 如果点太少或退化成线当作线段const first sampled[0], last sampled[sampled.length-1];correctedShape {type: line,points: [first, last]};redraw();statusMsg.innerText 识别为线段;return;}// 计算多边形面积 (用于判断)function polyArea(pts) {let area 0;const n pts.length;for (let i 0; i n; i) {const j (i1) % n;area pts[i].x * pts[j].y;area - pts[j].x * pts[i].y;}return Math.abs(area) / 2;}const area polyArea(hull);// 计算周长function perimeter(pts) {let p 0;for (let i 0; i pts.length; i) {const j (i1) % pts.length;p Math.hypot(pts[i].x - pts[j].x, pts[i].y - pts[j].y);}return p;}const perim perimeter(hull);// 圆形度: 4pi*area / perim^2const circularity (4 * Math.PI * area) / (perim * perim 0.001);// 判断形状类型let type line;let pts [];// 如果近似圆 (circularity 0.75 且 点数5)if (circularity 0.70 hull.length 5) {type circle;// 计算圆心和半径 (最小二乘)let cx 0, cy 0;for (let p of hull) { cx p.x; cy p.y; }cx / hull.length; cy / hull.length;let r 0;for (let p of hull) {r Math.hypot(p.x - cx, p.y - cy);}r / hull.length;// 生成圆 (32个点)const segs 32;pts [];for (let i 0; i segs; i) {const theta (i / segs) * 2 * Math.PI;pts.push({ x: cx r * Math.cos(theta), y: cy r * Math.sin(theta) });}statusMsg.innerText ⭕ 识别为圆形;}else {// 判断矩形 / 三角形 : 基于凸包顶点数量 角度const hullLen hull.length;// 计算角度 (近似)function angleAt(p, prev, next) {const v1 { x: prev.x - p.x, y: prev.y - p.y };const v2 { x: next.x - p.x, y: next.y - p.y };const dot v1.x * v2.x v1.y * v2.y;const cross v1.x * v2.y - v1.y * v2.x;let ang Math.atan2(cross, dot);if (ang 0) ang Math.PI;return ang;}// 如果 hull 顶点数为 3~5 且 近似直角或锐角if (hullLen 3 hullLen 5) {// 针对三角形 (3个顶点) 或 矩形 (4个顶点)// 计算角度let angles [];for (let i 0; i hullLen; i) {const prev hull[(i-1hullLen) % hullLen];const curr hull[i];const next hull[(i1) % hullLen];angles.push(angleAt(curr, prev, next));}const avgAngle angles.reduce((a,b) ab, 0) / angles.length;const minAngle Math.min(...angles);const maxAngle Math.max(...angles);// 判断三角形角度范围大且接近60度const angleRange maxAngle - minAngle;if (hullLen 3 || (hullLen 4 angleRange 0.8 avgAngle 0.9 avgAngle 1.8)) {type triangle;// 生成三角形: 取凸包 3 个顶点 (或近似)if (hullLen 3) {pts hull.slice();pts.push(hull[0]); // 闭合} else {// 如果多于3个点取三个角度最大的顶点 (最简单)let sorted hull.map((p, idx) ({ p, angle: angles[idx], idx }));sorted.sort((a,b) b.angle - a.angle);const top3 sorted.slice(0, 3).map(item item.p);pts top3.concat(top3[0]);}statusMsg.innerText △ 识别为三角形;}else if (hullLen 4 hullLen 6) {// 尝试矩形: 角度接近 90° (1.57 rad)const rightAngleCount angles.filter(a a 1.2 a 1.9).length;if (rightAngleCount 2) {type rectangle;// 取凸包 4 个顶点排序 (按角度)let sorted hull.map((p, idx) ({ p, angle: angles[idx], idx }));sorted.sort((a,b) a.angle - b.angle);// 取4个极值点 (实际上取最远点)const rectPts [];// 使用极值: 左右上下let minX Infinity, maxX -Infinity, minY Infinity, maxY -Infinity;for (let p of hull) {if (p.x minX) minX p.x;if (p.x maxX) maxX p.x;if (p.y minY) minY p.y;if (p.y maxY) maxY p.y;}const corners [{ x: minX, y: minY },{ x: maxX, y: minY },{ x: maxX, y: maxY },{ x: minX, y: maxY }];pts corners.concat(corners[0]);type rectangle;statusMsg.innerText ▭ 识别为矩形;} else {// 默认当作线段const first sampled[0], last sampled[sampled.length-1];pts [first, last];type line;statusMsg.innerText 识别为线段;}} else {// 线段const first sampled[0], last sampled[sampled.length-1];pts [first, last];type line;statusMsg.innerText 识别为线段;}} else {// 默认线const first sampled[0], last sampled[sampled.length-1];pts [first, last];type line;statusMsg.innerText 识别为线段;}

相关新闻

结点电压法保姆级教程

结点电压法保姆级教程

一句话: 结点电压法用更少的方程、更统一的套路直接求各点电位。不堆公式推导——核心模板就一句话,加上四步操作,复杂电路变成填空题。适合谁读:被支路电流法列方程列到头晕的电路初学者。万能公式 结点电压法的本质是基尔霍夫电流定律&…

2026/7/22 14:01:08 阅读更多 →
MOSFET和BJT在电路里是什么模型

MOSFET和BJT在电路里是什么模型

一句话: 受控源是放大器的电路模型——输出电压/电流不是自己定的,是被电路里另一个电压/电流遥控的。MOSFET 就是压控电流源,BJT 就是流控电流源。模电里的小信号模型就是这东西。适合谁读:学完电路分析正要进入模电、搞不清受控源和晶体管关…

2026/7/22 14:01:08 阅读更多 →
ESP32-C61-WROOM-1-N8R8:大PSRAM加持下的Wi-Fi 6实用派

ESP32-C61-WROOM-1-N8R8:大PSRAM加持下的Wi-Fi 6实用派

去年帮一个做商业显示屏的客户选型,对方的要求很明确:要跑LVGL界面,要Wi-Fi 6联网稳定,成本还不能太高。当时C6价格偏高,C3内存又跑不动UI,最后只能在外挂SRAM和换方案之间来回折腾。现在C61系列里这个N8R8…

2026/7/22 14:00:08 阅读更多 →

最新新闻

【剪映AI配音实战指南】:20年音视频专家亲授,3步搞定专业级AI配音(附避坑清单)

【剪映AI配音实战指南】:20年音视频专家亲授,3步搞定专业级AI配音(附避坑清单)

更多请点击: https://intelliparadigm.com 第一章:剪映AI配音的核心原理与技术演进 剪映AI配音并非简单的语音合成(TTS)工具,而是融合了端到端深度学习、音色克隆、韵律建模与上下文感知语音生成的多模态语音系统。其…

2026/7/23 21:37:00 阅读更多 →
AI论文写作工具评测与学术诚信实践指南

AI论文写作工具评测与学术诚信实践指南

1. AI论文写作工具现状与选择逻辑学术写作正经历着从传统人工创作向智能辅助的转型期。当前市面上的AI论文工具主要分为三大技术流派:基于Transformer架构的通用大语言模型(如GPT系列)、针对学术领域优化的专业模型(如SciBERT&…

2026/7/23 21:37:00 阅读更多 →
文献综述自动化工具:AI如何提升学术研究效率

文献综述自动化工具:AI如何提升学术研究效率

1. 项目概述:文献综述自动化的痛点与突破写文献综述大概是每个研究生都经历过的噩梦。去年帮导师整理某个细分领域的研究进展时,我花了整整三周时间:先要检索上百篇论文,然后逐篇阅读摘要、筛选关键文献,再手动归类不同…

2026/7/23 21:37:00 阅读更多 →
非标准分带CAD数据如何与卫星影像叠加套合

非标准分带CAD数据如何与卫星影像叠加套合

自2008年7月1日起,国内测绘行业统一采用 2000 国家大地坐标系(CGCS2000),逐渐淘汰西安80和北京54坐标系。通常情况下,国家2000坐标系下的文件都基于标准的3度分带或6度分带进行投影。但为了提高坐标的精度,…

2026/7/23 21:37:00 阅读更多 →
Django毕设项目:基于 Django 的电子商务交易系统构建与安全防护方案研究 基于 Django 的商城系统设计与漏洞防范策略研究 (源码+文档,讲解、调试运行,定制等)

Django毕设项目:基于 Django 的电子商务交易系统构建与安全防护方案研究 基于 Django 的商城系统设计与漏洞防范策略研究 (源码+文档,讲解、调试运行,定制等)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/7/23 21:37:00 阅读更多 →
一次全站HTTPS证书过期故障的复盘:从应急响应到自动化证书管理体系的建立全过程

一次全站HTTPS证书过期故障的复盘:从应急响应到自动化证书管理体系的建立全过程

一次全站HTTPS证书过期故障的复盘:从应急响应到自动化证书管理体系的建立全过程 一、故障概述与影响评估 2025年8月12日凌晨02:47,某互联网企业的核心业务平台突然发生大规模服务不可用故障。用户访问官网、API网关、管理后台等所有HTTPS服务时&#xff…

2026/7/23 21:36:00 阅读更多 →

日新闻

从单点好评到指数级传播:AI副业主理人必须掌握的4层口碑渗透模型(含ROI测算表)

从单点好评到指数级传播:AI副业主理人必须掌握的4层口碑渗透模型(含ROI测算表)

更多请点击: https://intelliparadigm.com 第一章:从单点好评到指数级传播:AI副业主理人必须掌握的4层口碑渗透模型(含ROI测算表) 当AI副业主理人不再仅满足于单次服务交付,而是主动构建可复用、可裂变、可…

2026/7/23 0:00:25 阅读更多 →
AI写作开头钩子设计:为什么你的AI文案完读率不足18%?——基于2,346篇A/B测试报告的归因分析

AI写作开头钩子设计:为什么你的AI文案完读率不足18%?——基于2,346篇A/B测试报告的归因分析

更多请点击: https://codechina.net 第一章:AI写作开头钩子设计:为什么你的AI文案完读率不足18%?——基于2,346篇A/B测试报告的归因分析 在对2,346篇跨行业AI生成文案的A/B测试数据进行聚类分析后,我们发现&#xff1…

2026/7/23 0:01:26 阅读更多 →
Chitchatter完整指南:免费开源的终极点对点安全聊天工具

Chitchatter完整指南:免费开源的终极点对点安全聊天工具

Chitchatter完整指南:免费开源的终极点对点安全聊天工具 【免费下载链接】chitchatter Secure peer-to-peer chat that is serverless, decentralized, and ephemeral 项目地址: https://gitcode.com/gh_mirrors/ch/chitchatter Chitchatter是一款革命性的安…

2026/7/23 0:01:26 阅读更多 →

周新闻

Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/22 8:58:19 阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/22 19:43:43 阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/23 17:49:47 阅读更多 →

月新闻