我正在为我的 ML 模型构建一个 Web 应用程序,在其中我需要用鼠标指针标记图像中存在遮挡的区域。然后,ML 模型获取标记的图像并重建缺失的区域。
为了在图像上绘制,首先我制作了一个画布,然后我们需要将所选图像上传到该画布上。然后我制作了画布以获取调整后的图像的大小。
这里的问题是:鼠标指向一个位置,但在另一个位置上绘图。
我进一步发现,当我改变网页窗口大小时,在某些窗口形状下,鼠标指针精确地绘制在我想要的位置。
我不明白发生了什么?是因为窗口大小调整错误还是什么原因?
调整画布大小
function overlayImage() {
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var rect = canvas.getBoundingClientRect();
var img = this;
var scaleX = canvas.width / img.width;
var scaleY = canvas.height / img.height;
var scale = Math.min(scaleX, scaleY);
var newWidth = img.width * scale;
var newHeight = img.height * scale;
ctx.clearRect(0, 0, canvas.width, canvas.height);
canvas.width = newWidth;
canvas.height = newHeight;
ctx.drawImage(img, 0,0, newWidth, newHeight);
}
现在是鼠标事件
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
var rect = canvas.getBoundingClientRect();
let coord = {
x: 0,
y: 0
};
document.addEventListener("mousedown", start);
document.addEventListener("mouseup", stop);
window.addEventListener("resize", resize);
function resize() {
ctx.canvas.width = window.innerWidth;
ctx.canvas.height = window.innerHeight;
}
resize();
function reposition(event) {
coord.x = (event.clientX - rect.left) / (rect.right - rect.left) * canvas.width;
coord.y = (event.clientY - rect.top) / (rect.bottom - rect.top) * canvas.height;
}
function start(event) {
document.addEventListener("mousemove", draw);
console.log("To check if mouse event is occurring")
reposition(event);
}
function stop() {
document.removeEventListener("mousemove", draw);
}
function draw(event) {
ctx.beginPath();
ctx.lineWidth = 5;
ctx.lineCap = "round";
ctx.strokeStyle = "black";
ctx.moveTo(coord.x, coord.y);
reposition(event);
ctx.lineTo(coord.x, coord.y);
ctx.stroke();
}
我尝试纠正 x,y 的偏移值,但仍然不起作用。
然后我检查了如果我不调整画布大小,那么可能会有所帮助,但仍然不起作用。
堆栈溢出中存在静态画布大小的解决方案,但我的画布大小根据图像尺寸而变化,并且纵横比平衡。这就是为什么我可以在一些图像上正确绘制,而绘图的起点远离我所指的位置。
在使用
x
和 y
之前,您需要更新 moveTo()
和 lineTo()
坐标(通过获取画布本身的比例因子来获取正确的位置)。查看下面示例中的 DrawingBoard
类的 startDrawing
、addPoint
和 scale
函数。
drawing.js
class DrawingBoard {
constructor(canvas) {
this.canvas = canvas;
this.ctx = canvas.getContext('2d');
this.isDrawing = false;
}
scale(x, y) {
const pageWidth = document.body.clientWidth;
const scale = Math.min(pageWidth / this.canvas.width, 1);
return [x/scale, y/scale];
}
startDrawing(x, y, color) {
this.isDrawing = true;
this.ctx.strokeStyle = color;
this.ctx.beginPath();
this.ctx.moveTo(... this.scale(x, y));
}
addPoint(x, y) {
if (this.isDrawing) {
this.ctx.lineTo(... this.scale(x, y));
this.ctx.stroke();
}
}
stopDrawing() {
this.isDrawing = false;
this.ctx.closePath();
}
}
const imageCanvas = document.getElementById('imageCanvas');
const overlayCanvas = document.getElementById('overlayCanvas');
const board = new DrawingBoard(overlayCanvas);
overlayCanvas.addEventListener('mousedown', event => {
board.startDrawing(event.offsetX, event.offsetY, '#ff7b06');
});
overlayCanvas.addEventListener('mousemove', event => {
board.addPoint(event.offsetX, event.offsetY);
});
overlayCanvas.addEventListener('mouseup', () => board.stopDrawing());
overlayCanvas.addEventListener('mouseout', () => board.stopDrawing());
以下代码与回答问题并不真正相关,但是,它提供了一个完整的工作示例。
drawing.js
继续
document
.getElementById('imageInput')
.addEventListener('change', ({target: {files}}) => {
const [file] = files;
imageCanvas.hidden = false;
overlayCanvas.hidden = false;
if (file && file.type.match('image/jpeg')) {
const reader = new FileReader();
reader.onload = ({target: {result}}) => {
const image = new Image();
image.onload = () => {
const ctx = imageCanvas.getContext('2d');
const maxWidth = document.body.clientWidth;
let { width, height } = image;
imageCanvas.width = width;
imageCanvas.height = height;
copyProperties(overlayCanvas, imageCanvas, 'width', 'height');
ctx.clearRect(0, 0, width, height);
ctx.drawImage(image, 0, 0, width, height);
}
image.src = result;
}
reader.readAsDataURL(file);
}
});
function copyProperties(target, source, ...properties) {
for (const property of properties) {
target[property] = source[property];
}
}
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Draw on Image</title>
<link rel="stylesheet" href="drawing.css">
</head>
<body>
<header>
<label for="imageInput">Select an JPEG Image</label>
<input type="file" id="imageInput" accept=".jpg,.jpeg">
</header>
<main>
<div class="canvas-container">
<canvas id="imageCanvas" hidden></canvas>
<canvas id="overlayCanvas" hidden></canvas>
</div>
</main>
<script src="drawing.js"></script>
</body>
</html>
drawing.css
body {
margin: 0;
padding: 0;
}
header {
padding: 1rem;
border-bottom: 1px solid black;
}
.canvas-container {
position: relative;
}
canvas {
max-width: 100%;
height: auto;
}
#overlayCanvas {
position: absolute;
top: 0;
left: 0;
pointer-events: auto;
cursor: crosshair;
}