【python/html/js 鼠标点选/框选图片内容】

html代码

注意修改图片地址,坐标会保存为`coordinates.json`

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Image Click and Drag Selection</title>
    <style>
      body {
        font-family: Arial, sans-serif;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        height: 100vh;
        margin: 0;
        background-color: rgba(197, 197, 197, 0.984);
        /* 20%透明度的红色填充 */
      }

      #image-container {
        position: relative;
        display: flex;
        justify-content: center;
        align-items: center;
        max-width: 90%;
        max-height: 90vh;
      }

      #image-container img {
        max-width: 100%;
        max-height: 100%;
        display: block;
      }

      #image-container .marker {
        position: absolute;
        width: 5px;
        height: 5px;
        background-color: rgba(255, 0, 0, 0.2);
        /* 20%透明度的红色填充 */
        border: 1px solid red;
        /* 红色轮廓 */
        border-radius: 50%;
        transform: translate(-50%, -50%);
      }

      #image-container .rectangle {
        position: absolute;
        border: 1.5px solid green;
        /* 绿色轮廓 */
        background-color: rgba(0, 255, 0, 0.2);
        /* 20%透明度的绿色填充 */
      }

      #coordinates {
        margin-top: 20px;
        font-size: 18px;
      }

      .button {
        padding: 10px 20px;
        font-size: 16px;
        cursor: pointer;
        background-color: #4caf50;
        color: white;
        border: none;
        border-radius: 5px;
        margin: 0 10px;
      }
      .button:hover {
        background-color: #45a049;
      }
      #button-container {
        display: flex;
        justify-content: center;
        margin-top: 20px;
      }
    </style>
  </head>

  <body>
    <div id="image-container">
      <img id="image" src="langchain+chatglm.png" alt="Sample Image" />
    </div>
    <div id="coordinates">Click or drag on the image to see coordinates.</div>
    <div id="button-container">
      <button id="save-button" class="button">Save Coordinates</button>
      <button id="clear-button" class="button">Clear All</button>
    </div>

    <script>
      const imageContainer = document.getElementById("image-container");
      const image = document.getElementById("image");
      const coordinatesDiv = document.getElementById("coordinates");
      const saveButton = document.getElementById("save-button");
      const clearButton = document.getElementById("clear-button");

      let isDragging = false;
      let startX, startY;
      let rectangle;
      let clickStartTime;
      let lastCoordinates = null;
      let coordinates = [];

      imageContainer.addEventListener("mousedown", (e) => {
        if (e.button === 0) {
          // Left mouse button
          const rect = image.getBoundingClientRect();
          startX = e.clientX - rect.left;
          startY = e.clientY - rect.top;

          // Record the start time of the click
          clickStartTime = Date.now();

          // Create a rectangle
          rectangle = document.createElement("div");
          rectangle.classList.add("rectangle");
          rectangle.style.left = `${startX}px`;
          rectangle.style.top = `${startY}px`;
          rectangle.style.width = "0";
          rectangle.style.height = "0";
          imageContainer.appendChild(rectangle);

          isDragging = true;
        }
      });

      imageContainer.addEventListener("mousemove", (e) => {
        if (isDragging) {
          const rect = image.getBoundingClientRect();
          const x = e.clientX - rect.left;
          const y = e.clientY - rect.top;

          // Get image dimensions
          const imageWidth = image.width;
          const imageHeight = image.height;

          // Limit coordinates to image boundaries
          const boundedX = Math.max(0, Math.min(x, imageWidth));
          const boundedY = Math.max(0, Math.min(y, imageHeight));

          // Update rectangle dimensions
          const width = Math.abs(boundedX - startX);
          const height = Math.abs(boundedY - startY);
          rectangle.style.left = `${Math.min(boundedX, startX)}px`;
          rectangle.style.top = `${Math.min(boundedY, startY)}px`;
          rectangle.style.width = `${width}px`;
          rectangle.style.height = `${height}px`;
        }
      });

      imageContainer.addEventListener("mouseup", (e) => {
        if (isDragging && e.button === 0) {
          const rect = image.getBoundingClientRect();
          const endX = e.clientX - rect.left;
          const endY = e.clientY - rect.top;

          const clickDuration = Date.now() - clickStartTime;

          // Get image dimensions
          const imageWidth = image.width;
          const imageHeight = image.height;

          // Limit coordinates to image boundaries
          const boundedEndX = Math.max(0, Math.min(endX, imageWidth));
          const boundedEndY = Math.max(0, Math.min(endY, imageHeight));

          if (clickDuration < 200) {
            // Short click (click)
            // Remove the rectangle
            imageContainer.removeChild(rectangle);

            // Place a marker
            const marker = document.createElement("div");
            marker.classList.add("marker");
            marker.style.left = `${startX}px`;
            marker.style.top = `${startY}px`;
            imageContainer.appendChild(marker);

            // Calculate percentage coordinates
            const percentX = ((startX / imageWidth) * 100).toFixed(2);
            const percentY = ((startY / imageHeight) * 100).toFixed(2);

            coordinatesDiv.textContent = `Clicked at: (${percentX}%, ${percentY}%)`;
            lastCoordinates = { type: "click", x: percentX, y: percentY };
            coordinates.push({ type: "click", x: percentX, y: percentY });
          } else {
            // Long click (drag)
            const x1 = Math.min(startX, boundedEndX);
            const y1 = Math.min(startY, boundedEndY);
            const x2 = Math.max(startX, boundedEndX);
            const y2 = Math.max(startY, boundedEndY);

            // Calculate percentage coordinates
            const percentX1 = ((x1 / imageWidth) * 100).toFixed(2);
            const percentY1 = ((y1 / imageHeight) * 100).toFixed(2);
            const percentX2 = ((x2 / imageWidth) * 100).toFixed(2);
            const percentY2 = ((y2 / imageHeight) * 100).toFixed(2);

            coordinatesDiv.textContent = `Rectangle: (${percentX1}%, ${percentY1}%) to (${percentX2}%, ${percentY2}%)`;
            lastCoordinates = {
              type: "rectangle",
              x1: percentX1,
              y1: percentY1,
              x2: percentX2,
              y2: percentY2,
            };
            coordinates.push({
              type: "rectangle",
              x1: percentX1,
              y1: percentY1,
              x2: percentX2,
              y2: percentY2,
            });
          }

          isDragging = false;
        }
      });

      imageContainer.addEventListener("mouseleave", () => {
        if (isDragging) {
          isDragging = false;
          imageContainer.removeChild(rectangle);
        }
      });

      saveButton.addEventListener("click", () => {
        if (lastCoordinates) {
          const json = JSON.stringify(coordinates, null, 2);
          const blob = new Blob([json], { type: "application/json" });
          const url = URL.createObjectURL(blob);
          const a = document.createElement("a");
          a.href = url;
          a.download = "coordinates.json";
          a.click();
          URL.revokeObjectURL(url);
        } else {
          alert("No coordinates to save.");
        }
      });
      clearButton.addEventListener("click", () => {
        coordinates = [];
        const markers = imageContainer.querySelectorAll(".marker, .rectangle");
        markers.forEach((marker) => marker.remove());
      });
    </script>
  </body>
</html>
标注界面
页面
​​​​​

coordinates.json 示例

[
  {
    "type": "rectangle",
    "x1": "3.81",
    "y1": "13.35",
    "x2": "92.95",
    "y2": "22.87"
  },
  {
    "type": "click",
    "x": "19.07",
    "y": "51.07"
  },
  {
    "type": "click",
    "x": "38.81",
    "y": "50.31"
  },
  {
    "type": "click",
    "x": "59.04",
    "y": "50.19"
  },
  {
    "type": "rectangle",
    "x1": "23.55",
    "y1": "65.10",
    "x2": "74.38",
    "y2": "74.87"
  }
]

处理代码

import json
import matplotlib.pyplot as plt
import numpy as np
import torch
import matplotlib.pyplot as plt
from PIL import Image

np.random.seed(3)

 显示代码

def show_mask(mask, ax, random_color=False, borders=True):
    if random_color:
        color = np.concatenate([np.random.random(3), np.array([0.6])], axis=0)
    else:
        color = np.array([30 / 255, 144 / 255, 255 / 255, 0.6])
    h, w = mask.shape[-2:]
    mask = mask.astype(np.uint8)
    mask_image = mask.reshape(h, w, 1) * color.reshape(1, 1, -1)
    if borders:
        import cv2

        contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
        # Try to smooth contours
        contours = [
            cv2.approxPolyDP(contour, epsilon=0.01, closed=True) for contour in contours
        ]
        mask_image = cv2.drawContours(
            mask_image, contours, -1, (1, 1, 1, 0.5), thickness=2
        )
    ax.imshow(mask_image)


def show_points(coords, labels, ax, marker_size=375):
    pos_points = coords[labels == 1]
    neg_points = coords[labels == 0]
    ax.scatter(
        pos_points[:, 0],
        pos_points[:, 1],
        color="green",
        marker="*",
        s=marker_size,
        edgecolor="white",
        linewidth=1.25,
    )
    ax.scatter(
        neg_points[:, 0],
        neg_points[:, 1],
        color="red",
        marker="*",
        s=marker_size,
        edgecolor="white",
        linewidth=1.25,
    )


def show_box(box, ax, lw=2):
    x0, y0 = box[0], box[1]
    w, h = box[2] - box[0], box[3] - box[1]
    ax.add_patch(
        plt.Rectangle((x0, y0), w, h, edgecolor="green", facecolor=(0, 0, 0, 0), lw=lw)
    )

def show_boxs(boxs, ax, lw=2):
    for box in boxs:
        show_box(box, ax, lw=lw)


def show_masks(
    image,
    masks,
    scores,
    point_coords=None,
    box_coords=None,
    input_labels=None,
    borders=True,
):
    for i, (mask, score) in enumerate(zip(masks, scores)):
        plt.figure(figsize=(10, 10))
        plt.imshow(image)
        show_mask(mask, plt.gca(), borders=borders)
        if point_coords is not None:
            assert input_labels is not None
            show_points(point_coords, input_labels, plt.gca())
        if box_coords is not None:
            # boxes
            show_box(box_coords, plt.gca())
        if len(scores) > 1:
            plt.title(f"Mask {i+1}, Score: {score:.3f}", fontsize=18)
        plt.axis("off")
        plt.show()
image = Image.open("langchain+chatglm.png")
image = np.array(image.convert("RGB"))
H, W, C = image.shape

 处理坐标数据

with open("coordinates.json", "r") as f:
    cors = json.load(f)
print(cors)
mmh = lambda x: max(min(x, H), 0)
mmw = lambda x: max(min(x, W), 0)
cors = [
    (
        {**c, "x": mmw(float(c["x"]) / 100 * W), "y": mmh(float(c["y"]) / 100 * H)}
        if c["type"] == "click"
        else {
            **c,
            "x1": mmw(float(c["x1"]) / 100 * W),
            "y1": mmh(float(c["y1"]) / 100 * H),
            "x2": mmw(float(c["x2"]) / 100 * W),
            "y2": mmh(float(c["y2"]) / 100 * H),
        }
    )
    for c in cors
]
cors

[{'type': 'rectangle', 'x1': 45.9486, 'y1': 106.533, 'x2': 1120.977, 'y2': 182.5026}, {'type': 'click', 'x': 229.98420000000002, 'y': 407.53860000000003}, {'type': 'click', 'x': 468.0486, 'y': 401.4738}, {'type': 'click', 'x': 712.0224000000001, 'y': 400.5162}, {'type': 'rectangle', 'x1': 284.01300000000003, 'y1': 519.4979999999999, 'x2': 897.0227999999998, 'y2': 597.4626000000001}]

input_point = np.array([[c['x'], c['y']] for c in cors if c['type']=='click'])
input_label = np.array([0] * len(input_point))
input_point, input_label

(array([[229.9842, 407.5386], [468.0486, 401.4738], [712.0224, 400.5162]]), array([0, 0, 0]))

 matplotlib显示图片

plt.figure(figsize=(10, 10))
plt.imshow(image)
show_points(input_point, input_label, plt.gca(), marker_size=100)
show_boxs([[c['x1'], c['y1'],c['x2'], c['y2']] for c in cors if c['type']=='rectangle'], plt.gca(), lw=1)
plt.axis("on")
plt.show()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/951773.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Zustand selector 发生 infinate loops的原因以及解决

Zustand selector 发生 infinate loops 做zustand tutorial project的时候&#xff0c;使用选择器方法引入store&#xff0c;出现Maximum update depth exceeded,也就是组件一直重新渲染&#xff0c;改成直接使用store就没有不会出现这个问题。如下&#xff1a; // const [xIs…

AngularJs指令中出错:Error: $compile:nonassign Non-Assignable Expression

Expression {resumeId: item.resumeId} used with directive rwdsDelete is non-assignable! 在AngularJS中&#xff0c;$compile服务用于将指令编译成HTML。当你在模板中使用了一个表达式&#xff0c;但这个表达式不是一个左值&#xff08;即不能被赋值的表达式&#xff09;时…

moviepy 将mp4视频文件提取音频mp3 - python 实现

DataBall 助力快速掌握数据集的信息和使用方式&#xff0c;会员享有 百种数据集&#xff0c;持续增加中。 需要更多数据资源和技术解决方案&#xff0c;知识星球&#xff1a; “DataBall - X 数据球(free)” -------------------------------------------------------------…

openssl编译

关于windows下&#xff0c;openssl编译 环境准备 安装 perl:https://djvniu.jb51.net/200906/tools/ActivePerl5_64.rar安装nasm&#xff1a;https://www.nasm.us/pub/nasm/releasebuilds/2.13.01/win64/nasm-2.13.01-installer-x64.exe下载opensll源码&#xff1a;https://o…

QT c++ 样式 设置 标签(QLabel)的渐变色美化

上一篇文章中描述了按钮的纯色&#xff0c;本文描述标签的渐变色美化。 1.头文件 #ifndef WIDGET_H #define WIDGET_H #include <QWidget> //#include "CustomButton.h"#include <QVBoxLayout> #include <QLinearGradient> #include <QLabel…

学习打怪日记

目录 0 关于1 SpringBoot上传大文件抛出异常&#xff1a;MaxUploadSizeExceededException2 SpringBoot警告&#xff1a;HikariPool-1 - Failed to validate connection com.mysql.cj.jdbc.ConnectionImpl6221f160 (No operations allowed after connection closed.). Possibly …

xss-labs关卡记录15-20关

十五关 随便传一个参数&#xff0c;然后右击查看源码发现&#xff0c;这里有一个陌生的东西&#xff0c;就是ng-include。这里就是&#xff1a; ng-include指令就是文件包涵的意思&#xff0c;用来包涵外部的html文件&#xff0c;如果包涵的内容是地址&#xff0c;需要加引号。…

(五)ROS通信编程——参数服务器

前言 参数服务器在ROS中主要用于实现不同节点之间的数据共享&#xff08;P2P&#xff09;。参数服务器相当于是独立于所有节点的一个公共容器&#xff0c;可以将数据存储在该容器中&#xff0c;被不同的节点调用&#xff0c;当然不同的节点也可以往其中存储数据&#xff0c;关…

自动化测试框架搭建-数据库方法连接-初阶

目的 将数据库连接的步骤封装成一个方法&#xff0c;在需要连接数据库时&#xff0c;传入指定的参数&#xff08;SQL&#xff09;即可实现对数据查询和修改 代码实现 1、编写数据库连接方法 2、导入其他方法中使用步骤一 import pymysqldef mysqlConnetion(Sql):# 数据库连…

vivado 时钟指南

时钟指南 每个 FPGA 架构都为时钟提供有专用资源。掌握 FPGA 架构中的时钟资源&#xff0c;使您能够规划好自己的时钟&#xff0c;从而实现时钟 资源的最佳利用。大多数设计无需您了解这些细节。但如果您能够控制布局&#xff0c;同时对每个时钟域上的扇出有良好的思 路&a…

【微信小程序】回到顶部图标-页面滚动事件 | 漫画-综合实训

一、回到顶部-页面滚动事件 在微信小程序中&#xff0c;如果你想将“回到顶部”的功能按钮换成图标&#xff0c;你可以通过以下步骤实现&#xff1a; 1. 准备图标 首先&#xff0c;你需要准备一个图标图片。这个图标可以是任何你选择的格式&#xff0c;如 PNG 或 SVG。将图标…

通过一个含多个包且引用外部jar包的项目实例感受Maven的便利性

目录 1 引言2 手工构建3 基于Maven的构建4 总结 1 引言 最近在阅读一本Java Web的书籍1时&#xff0c;手工实现书上的一个含多个Packages的例子&#xff0c;手工进行编译、运行&#xff0c;最终实现了效果。但感觉到整个构建过程非常繁琐&#xff0c;不仅要手写各个源文件的编…

el-tree拖拽光标错位问题

背景&#xff1a;el-tree实现的分类树增加拖拽功能后&#xff0c;当分类树由于数量较多产生滚动条&#xff0c;如果分类树已滚动&#xff0c;进行拖拽时会造成光标错位的问题: 原因&#xff1a;el-tree拖拽光标定位的高度并未加上滚动的高度解决&#xff1a;将滚动的样式属性放…

【YashanDB知识库】解决mybatis的mapper文件sql语句结尾加分号“;“报错

本文内容来自YashanDB官网&#xff0c;原文内容请见 https://www.yashandb.com/newsinfo/7863046.html?templateId1718516 现象 mybatis或mybaits-plus的mapper文件sql结尾加分号";" 执行时报错&#xff1a;”YAS-04209 unexpected word;“ 解决办法 将sql结尾…

day03-前端Web-Vue3.0基础

目录 前言1. Vue概述2. 快速入门2.1 需求2.2 步骤2.3 实现 3. Vue指令3.1 介绍3.2 v-for3.2.1 介绍3.2.2 演示3.2.3 v-for的key3.2.4 案例-列表渲染 3.3 v-bind3.3.1 介绍3.3.2 演示3.3.3 案例-图片展示 3.4 v-if & v-show3.4.1 介绍3.4.2 案例-性别职位展示 3.6 v-model3.…

Spring Web 嵌套对象校验失效

问题复现 当开发一个学籍管理系统时&#xff0c;我们会提供了一个 API 接口去添加学生的相关信息&#xff0c;学生中有个嵌套属性联系电话&#xff0c;其对象定义参考下面的代码&#xff1a; import lombok.Data; import javax.validation.constraints.Size; Data public class…

计算机网络 (27)IP多播

前言 IP多播&#xff08;也称多址广播或组播&#xff09;技术是一种允许一台或多台主机&#xff08;多播源&#xff09;发送单一数据包到多台主机&#xff08;一次性的、同时的&#xff09;的TCP/IP网络技术。 一、基本概念 定义&#xff1a;多播作为一点对多点的通信&#xff…

计算机毕业设计PyHive+Hadoop深圳共享单车预测系统 共享单车数据分析可视化大屏 共享单车爬虫 共享单车数据仓库 机器学习 深度学习

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

口碑很好的国产LDO芯片,有哪些?

在几乎任何一个电路设计中&#xff0c;都可能会使用LDO&#xff08;低压差线性稳压器&#xff09;这个器件。 虽然LDO不是什么高性能的IC&#xff0c;但LDO芯片市场竞争异常激烈。最近几年&#xff0c;诞生了越来越多的精品国产LDO&#xff0c;让人看得眼花缭乱。 业内人士曾经…

Transformer:深度学习的变革力量

深度学习领域的发展日新月异&#xff0c;在自然语言处理&#xff08;NLP&#xff09;、计算机视觉等领域取得了巨大突破。然而&#xff0c;早期的循环神经网络&#xff08;RNN&#xff09;在处理长序列时面临着梯度消失、并行计算能力不足等瓶颈。而 Transformer 的横空出世&am…