两张图片进行分析

两张图片进行分析,可以拖动左边图片进行放大、缩小查看图片差异

 

底图

 

<template>
   
   <div class="box_container">
    <section>
      <div class="" v-for="item in imgData.imgDataVal" :key="item.id">
        <img :style="{
          width: boxStyle.width + '%',
          top: boxStyle.top,
          left: boxStyle.left,
        }" :src="item.src" :alt="item.name" />

        <div v-if="clickState" class="selectRegion"
          :style="{ top: selectRegionStyle.top, left: selectRegionStyle.left }"></div>
        <div class="text">
          <p>{{ item.name }}</p>
        </div>

      </div>
      <div ref=" moveDom" id="moveDom"></div>


    </section>

    <p   class="p-diff">差别【不准确】: {{ differencePercentage }}%</p>
  </div>
</template>

<script lang="ts" setup>
  
import imageYT from '../assets/yt.png';
import imageFX from '../assets/fx.png';
import pixelmatch from 'pixelmatch';

import { reactive, ref, onMounted, onBeforeUnmount } from 'vue';
  
 
 
let differencePercentage = ref(0);
onMounted(() => {
  compareImages();
});
function compareImages() {
  const imgA = document.createElement('img');
  const imgB = document.createElement('img');

  imgA.onload = () => {
    imgB.onload = () => {
      const width = imgA.width;
      const height = imgA.height;
      const canvasA = document.createElement('canvas');
      const canvasB = document.createElement('canvas');
      canvasA.width = width;
      canvasA.height = height;
      canvasB.width = width;
      canvasB.height = height;
      const ctxA = canvasA.getContext('2d') as any;
      const ctxB = canvasB.getContext('2d') as any;
      ctxA.drawImage(imgA, 0, 0);
      ctxB.drawImage(imgB, 0, 0);
      const dataA = ctxA.getImageData(0, 0, width, height);
      const dataB = ctxB.getImageData(0, 0, width, height);
      const diff = pixelmatch(dataA.data, dataB.data, null, width, height);
      differencePercentage.value =
        100 - parseInt(((diff / (width * height)) * 100).toFixed(2));
    };
    imgB.src = imageFX as any;
  };
  imgA.src = imageYT as any;
}

let imgData = reactive({
  imgDataVal: [
    {
      id: 1,
      name: '原始图',
      src: imageYT
    },
    {
      id: 2,
      name: '分析图',
      src: imageFX
    }
  ]
})

/**
 * @description: 添加鼠标事件
 * @return {*}
 */

const init = () => {
  moveDom.value = document.getElementById('moveDom')
  moveDom.value.addEventListener('mousemove', moveEvent)
  moveDom.value.addEventListener('wheel', wheelEvent)
  moveDom.value.addEventListener('mousedown', mousedownEvent)
  moveDom.value.addEventListener('mouseup', mouseupEvent)
  moveDom.value.addEventListener('mouseout', mouseoutEvent)
  moveDom.value.addEventListener('mouseover', mouseoverEvent)
}
onMounted(() => {

  init()
})


 const moveDom: any = ref(null);
const images: any = ref(null);
images.value = document.getElementsByClassName('chatImgs');
/**
 * @description: 卸载鼠标事件
 * @return {*}
 */
onBeforeUnmount(() => {
  moveDom.value.removeEventListener('mousemove', moveEvent);
  moveDom.value.removeEventListener('mouseleave', wheelEvent);
  moveDom.value.removeEventListener('mousedown', mousedownEvent);
});
const boxStyle = ref({
  width: 50,
  top: '50%',
  left: '50%',
});
const selectRegionStyle = ref({
  top: '50%',
  left: '50%',
});
const moveX = ref(null);
const moveY = ref(null);

/**
 * @description: 鼠标移动事件
 * @param {*} e
 * @return {*}
 */
const moveEvent = (e: any) => {
  moveX.value = e.offsetX;
  moveY.value = e.offsetY;
  selectRegionStyle.value.left = `${e.offsetX}px`;
  selectRegionStyle.value.top = `${e.offsetY}px`;
  if (clickState.value) {
    boxStyle.value.top = `${e.offsetY}px`;
    boxStyle.value.left = `${e.offsetX}px`;
  }
};
/**
 * @description: 滚轮事件
 * @param {*} e
 * @return {*}
 */
const wheelEvent = (e: any) => {
  if (e.deltaY < 0) {
    if (boxStyle.value.width > 200) {
      return;
    }
    boxStyle.value.width = boxStyle.value.width + 10;
  } else {
    if (boxStyle.value.width < 50) {
      return;
    }
    boxStyle.value.width = boxStyle.value.width - 10;
  }
};

const clickState = ref(false);
const overState = ref(false);
/**
 * @description: 鼠标左键按下事件
 * @param {*} e
 * @return {*}
 */
const mousedownEvent = (e: any) => {
  clickState.value = true;
  overState.value = true;
};
/**
 * @description: 鼠标移入事件
 * @param {*} e
 * @return {*}
 */
const mouseoverEvent = (e: any) => {
  if (overState.value) {
    clickState.value = true;
  }
};
/**
 * @description: 鼠标左键抬起事件
 * @param {*} e
 * @return {*}
 */
const mouseupEvent = (e: any) => {
  clickState.value = false;
  overState.value = false;
};
/**
 * @description: 鼠标移出事件
 * @param {*} e
 * @return {*}
 */
const mouseoutEvent = (e: any) => {
  clickState.value = false;
};
</script>

<style scoped lang="scss">
.box_container {
  width: 100vw;
  height: 100vh;

  padding: 0;

}


section {
  width: 100%;
  height: 85%;
  display: flex;
  justify-content: center;
  justify-items: center;


  >div {
    flex: 1;
    height: 100%;
    position: relative;
    overflow: hidden;
    background-color: #0decb8da;
    box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.07);

    img {
      width: 100%;
      position: absolute;
      transform: translate(-50%, -50%);
      z-index: 0;

    }

    .selectRegion {
      position: absolute;
      width: 100px;
      height: 100px;
      transform: translate(-50%, -50%);
      border: 1px solid rgba(0, 0, 0, 0.3);

    }
  }

  // 左边区域可以拖动
  #moveDom {
    width: 49.8%;
    height: 85.0%;
    background-color: rgba(0, 0, 0, 0);
    position: absolute;
    top: 0;
    left: 0;
    cursor: move;
  }

  >div:nth-child(1) {
    margin-right: 5px;
  }

  >div:nth-child(2) {
    cursor: no-drop;
    margin-left: 5px;
  }

  .text {
    width: 100%;
    height: 50px;
    position: absolute;
    bottom: 0;
    left: 0;
    background-color: rgba(0, 0, 0, 0.1);

    p {
      width: 100%;
      height: 100%;
      line-height: 100%;
      text-align: center;
      line-height: 50px;
      // color: #333;
      color: #fff;
      font-weight: 600;
      letter-spacing: 10px;
      font-size: 18px;
    }
  }
}
.p-diff{
  display: flex;
  justify-content: center;
  margin-top: 20px;
  font-size: 20px;
  font-weight:600
}
</style>

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

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

相关文章

JavaSE--【类和对象】

本篇目标 1. 掌握类的定义方式以及对象的实例化 2. 掌握类中的成员变量和成员方法的使用 3. 掌握对象的整个初始化过程 一、面向对象的初步认知 1.1 面向对象的初步认知 Java是一门纯面向对象的语言(Object Oriented Program&#xff0c;简称OOP)&#xff0c;在面向对象的世界里…

Execl数据导入 EasyExcel实现

官网 1. 需求简介 读取下面表格数据 第一行和第二行是计划信息 第三行是计划详情的抬头信息,以下行是计划详情信息 总段包含多个分段,总段使用了单元格合并功能 2. 实现读取功能 2.1 引入easyexcel依赖 <dependency><groupId>com.alibaba</groupId><…

移动端 UI 风格,视觉盛宴

移动端 UI 风格&#xff0c;视觉盛宴

10.dockerfile自动构建镜像

dockerfile自动构建镜像 类似ansible剧本&#xff0c;大小几kb 手动做镜像&#xff1a;大小几百M 首先创建一个dockerfile的路径&#xff0c;便于在路径下存在多个路径每个路径下都是dockerfile命名的脚本 注释&#xff1a;文件必须为&#xff1a;dockerfile或者Dockerfile …

QT中为程序加入超级管理员权限

QT中为程序加入超级管理员权限 Chapter1 QT中为程序加入超级管理员权限1. mingw编译器2. MSVC编译器3. CMAKE Chapter2 如何给QT程序添加管理员权限(UAC)的几种方法1、Qt Creator中方案一&#xff1a;&#xff08;仅适用于使用msvc编译器&#xff09;方案二&#xff1a;&#x…

单链表复习 (C语言版)

目录 一.顺序表与链表的区别 二.链表概念 三.单链表 1.单链表的开始与初始化 2.单链表的打印 3.单链表的尾插 重难点&#xff1a;单链表实现时的指针详解 4.单链表的头插 5.单链表的尾删 6.单链表的头删 小结&#xff1a; 7.单链表的查找 8.在指定位置前插入数据 …

制作AI问答机器人:从0到1的完整指南

在数字化转型的浪潮中&#xff0c;企业正追求更高效、智能的客户服务解决方案。AI问答机器人以其快速响应、全天候服务和持续学习的能力&#xff0c;成为了提升客户满意度和加速业务发展的关键工具。本文将深入探讨如何制作一个企业级的AI问答机器人&#xff0c;并强调其功能体…

【Linux】(五)—— SSH远程登录和XShell使用

SSH Linux中的SSH&#xff08;Secure Shell&#xff09;是一个强大的网络协议&#xff0c;用于在不安全的网络环境中提供安全的远程登录和资料拷贝等其他网络服务。以下是有关Linux中SSH的关键点和操作指南&#xff1a; SSH的基础概念 安全性&#xff1a;SSH通过对所有传输的…

编程规范-代码检测-格式化-规范化提交

适用于vue项目的编程规范 – 在多人开发时统一编程规范至关重要 1、代码检测 --Eslint Eslint&#xff1a;一个插件化的 javascript 代码检测工具 在 .eslintrc.js 文件中进行配置 // ESLint 配置文件遵循 commonJS 的导出规则&#xff0c;所导出的对象就是 ESLint 的配置对…

【Pytorch】一文向您详细介绍 torch.Tensor() 的常见用法

【Pytorch】一文向您详细介绍 torch.Tensor() 的常见用法 下滑即可查看博客内容 &#x1f308; 欢迎莅临我的个人主页 &#x1f448;这里是我静心耕耘深度学习领域、真诚分享知识与智慧的小天地&#xff01;&#x1f387; &#x1f393; 博主简介&#xff1a;985高校的普通…

WebAPI AOP方式 异常方式 FilterAttribute、ActionFilterAttribute

》》 自定义异常处理特性 using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Web; using System.Web.Http.Filters;namespace WebApplication11 {/// <summary>/// 异常处理特性/// </sum…

Transformer动画讲解:注意力计算Q、K、V

暑期实习基本结束了&#xff0c;校招即将开启。 不同以往的是&#xff0c;当前职场环境已不再是那个双向奔赴时代了。求职者在变多&#xff0c;HC 在变少&#xff0c;岗位要求还更高了。提前准备才是完全之策。 最近&#xff0c;我们又陆续整理了很多大厂的面试题&#xff0c…

九种mfc140u.dll丢失的解决方法,全面解决mfc140u.dll文件丢失

mfc140u.dll是 Microsoft Visual C 2015 Redistributable 的一部分&#xff0c;它与 Microsoft 基础类库&#xff08;MFC&#xff09;的 Unicode 版本有关。当您在运行使用 Visual C 2015 开发的应用程序时&#xff0c;可能会碰到关于mfc140u.dll丢失的错误。下面列出了一些解决…

WPF前端:一个纯Xaml的水平导航栏

效果图&#xff1a; 代码&#xff1a; 1、样式代码&#xff0c;可以写在窗体资源处或者样式资源文件中 <Style x:Key"MenuRadioButtonStyle" TargetType"{x:Type RadioButton}"><Setter Property"FontSize" Value"16" />…

Zabbix实现邮件和钉钉实时告警(使用python脚本)

告警和通知 告警是监控的主要职能,是指将到达某一阈值事件的消息发送给用户,让用户在事件发生的时候即刻知道监控项处于不正常状态,从而让用户来决定是否采取相关措施。 zabbix中,告警是由一系列的流程组成的,⾸首先是触发器到达阈值,接下是Active对事件信息进行处理,其…

谁能赢?阿里的通义 VS 百度的文心

关注卢松松&#xff0c;会经常给你分享一些我的经验和观点。 国产AI大模型领域&#xff0c;当前有两大阵营&#xff1a; (1)以百度文心一言为代表的闭源大模型。李彦宏曾说过&#xff1a;AI大模型开源意义不大&#xff0c;百度绝不抢开发者饭碗。 (2)以阿里通义AI为代表的开…

个股场外期权个人如何参与买卖?

个股场外期权作为一种金融衍生品&#xff0c;为个人投资者提供了多样化的投资选择和风险管理工具。想要参与个股场外期权的买卖&#xff0c;以下是一些关键步骤和考虑因素。 文章来源/&#xff1a;财智财经 第一步&#xff1a;选择合适的金融机构 首先&#xff0c;个人投资者需…

Android 常用开源库 MMKV 源码分析与理解

文章目录 前言一、MMKV简介1.mmap2.protobuf 二、MMKV 源码详解1.MMKV初始化2.MMKV对象获取3.文件摘要的映射4.loadFromFile 从文件加载数据5.数据写入6.内存重整7.数据读取8.数据删除9.文件回写10.Protobuf 实现1.序列化2.反序列化 12.文件锁1.加锁2.解锁 13.状态同步 总结参考…

17- Redis 中的 quicklist 数据结构

在 Redis 3.0 之前&#xff0c;List 对象的底层数据结构是双向链表或者压缩列表&#xff0c;然后在 Redis 3.2 的时候&#xff0c;List 对象的底层改由 quicklist 数据结构实现。 其实 quicklist 就是【双向链表 压缩列表】组合&#xff0c;因为一个 quicklist 就是一个链表&…

视频修复工具,模糊视频变清晰!

老旧视频画面效果差&#xff0c;视频效果模糊。我们经常找不到一个好的工具来让视频更清晰&#xff0c;并把它变成高清画质。相信很多网友都会有这个需求&#xff0c;尤其是视频剪辑行业的网友&#xff0c;经常会遇到这个问题。今天给大家分享一个可以把模糊视频修复清晰的工具…