分享一个从图片中提取色卡的实现

news2024/10/17 15:23:39

概述

最近在做“在线地图样式配置”的功能的时候,发现百度地图有个功能时上传一张图片,从图片中提取颜色并进行配图。本文就简单实现一下如何从图片中提取色卡。

效果

image.png

image.png

实现

实现思路

通过canvasdrawImage绘制图片,并通过getImageData获取颜色,根据颜色的距离对颜色进行分组,分组后的结果进行求平均。

实现代码

<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <canvas id="canvas"></canvas>

    <script>
      const canvas = document.querySelector("#canvas");
      const { offsetWidth, offsetHeight } = document.body;
      canvas.width = offsetWidth * 0.8;
      canvas.height = offsetHeight * 0.8;
      const ctx = canvas.getContext("2d");
      
      /**
       * 计算颜色距离,判断是否为相近颜色
       * @param {Array} color1
       * @param {Array} color2
       */
      function colorDistance([r1, g1, b1], [r2, g2, b2]) {
        const rmean = (r1 + r2) / 2;
        const r = r1 - r2;
        const g = g1 - g2;
        const b = b1 - b2;
        return Math.sqrt(
          (2 + rmean / 256) * (r * r) +
            4 * (g * g) +
            (2 + (255 - rmean) / 256) * (b * b)
        );
      }

      const img = new Image();
      img.src = "./earth.jpg";
      let maxSize = 400
      img.onload = () => {
        let { width, height } = img;
        // 进行等比缩放
        if(width > height && width > maxSize) {
          const ratio = maxSize / width
          width = maxSize
          height = ratio * height
        }
        if(height > width && height > maxSize) {
          const ratio = maxSize / height
          height = maxSize
          width = ratio * width
        }
        // 绘制图片
        ctx.drawImage(img, 0, 0, width, height);
        
        const data = ctx.getImageData(0, 0, width, height).data;
        
        const dict = {};
        
        // 获取分组颜色
        const getKey = (color2) => {
          const colors = Object.keys(dict).map((c) => c.split(",").map(Number));
          if (colors.length === 0) return color2.join(",");
          const delt = 88; // 分组范围
          let res = color2.join(",");
          for (let i = 0; i < colors.length; i++) {
            const color = colors[i];
            const dis = colorDistance(color, color2);
            if (dis < delt) {
              res = color.join(",");
              break;
            }
          }
          return res;
        };
        
        // 将颜色进行分组
        for (let i = 0; i < data.length; i += 4) {
          const r = data[i];
          const g = data[i + 1];
          const b = data[i + 2];
          const ckey = getKey([r, g, b]);
          if (!dict[ckey]) dict[ckey] = [];
          dict[ckey].push([r, g, b]);
        }
        
        // 将颜色按照数量进行排序
        const result = Object.keys(dict)
          .map((c) => {
            return {
              key: c,
              colors: dict[c],
            };
          })
          .sort((a, b) => b.colors.length - a.colors.length);
        
        // 取相近色的颜色平均值   
        for (let i = 0; i < result.length; i++) {
          const { colors } = result[i];
          let r = 0,
            g = 0,
            b = 0;
          for (let j = 0; j < colors.length; j++) {
            const [r1, g1, b1] = colors[j];
            r += r1;
            g += g1;
            b += b1;
          }
          r = Math.round(r / colors.length);
          g = Math.round(g / colors.length);
          b = Math.round(b / colors.length);
          result[i]["key"] = [r, g, b].join(",");
        }
        // 根据颜色亮度进行排序
        const colorss = result.map(({ key }) => key).sort((a, b) => {
          const [ra, ga, ba] = a.split(",").map(Number)
          const [rb, gb, bb] = b.split(",").map(Number)
          const la = ra * 0.299 + ga * 0.587 + ba *0.114
          const lb = rb * 0.299 + gb * 0.587 + bb *0.114
          return lb - la
        });
        // 渲染颜色
        const h = 20;
        for (let i = 0; i < colorss.length; i++) {
          ctx.fillStyle = `rgb(${colorss[i]})`;
          ctx.strokeStyle = `#fff`;
          const y = i * h + (height + 20);
          ctx.fillRect(0, y, 30, h);
          ctx.strokeRect(0, y, 30, h);
        }
      };
    </script>
  </body>
</html>

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

主数据系统管理、运维的实践经验与建议

公司在预研一个新的主数据系统&#xff0c;领导问笔者给些建议。结合近两年的主数据系统管理、维护经验&#xff0c;给大致写了一些。 里面少数问题属于目前在运行的主数据系统的系统痛点所致&#xff0c;不过大多数笔者认为是通病&#xff0c;一口气写来已两千字&#xff0c;…

【验证码识别】Python+卷积神经网络算法+人工智能+深度学习+Django网页界面+计算机课设项目+TensorFlow+算法模型

一、介绍 验证码识别&#xff0c;使用Python作为开发语言&#xff0c;通过TensorFlow搭建CNN卷积神经网络算法模型&#xff0c;并通过对收集的几千张验证码图片作为数据集&#xff0c;然后进行迭代训练&#xff0c;最终得到一个识别精度较高的模型文件&#xff0c;然后使用Dja…

Cesium 区域高程图

Cesium 区域高程图 const terrainAnalyse new HeightMapMaterial({viewer,style: {stops: [0, 0.05, 0.5, 1],//颜色梯度设置colors: [green, yellow, blue , red],}});

JS 分支语句

目录 1. 表达式与语句 1.1 表达式 1.2 语句 1.3 区别 2. 程序三大流控制语句 3. 分支语句 3.1 if 分支语句 3.2 双分支 if 语句 3.3 双分支语句案例 3.3.1 案例一 3.3.2 案例二 3.4 多分支语句 1. 表达式与语句 1.1 表达式 1.2 语句 1.3 区别 2. 程序三大流控制语…

66 消息队列

66 消息队列 基础概念 参考资料&#xff1a;消息队列MQ快速入门&#xff08;概念、RPC、MQ实质思路、队列介绍、队列对比、应用场景&#xff09; 消息队列就是一个使用队列来通信的组件&#xff1b;为什么需要消息队列&#xff1f; 在实际的商业项目中&#xff0c;它这么做肯…

shell原理

shell 是个进程 &#xff0c; exe在user/bin/bash [用户名主机名 pwd] snprintf fflush&#xff08;stdout&#xff09;&#xff0c;在没有\n情况下立马输出 strtok 第一个参数null表示传入上个有效参数 命令行中&#xff0c;有些命令必须由子进程执行&#xff0c; 如ls 有些…

【进阶OpenCV】 (11)--DNN板块--实现风格迁移

文章目录 DNN板块一、DNN特点二、DNN函数流程三、实现风格迁移1. 图像预处理2. 加载星空模型3. 输出处理 总结 DNN板块 DNN模块是 OpenCV 中专门用来实现 DNN(Deep Neural Networks,深度神经网络) 模块的相关功能&#xff0c;其作用是载入别的深度学习框架(如 TensorFlow、Caf…

考虑促销因素的医药电商平台需求预测研究

一、考虑促销因素的医药电商平台需求预测研究 一、引言 1. 互联网医疗健康的发展 内容&#xff1a;介绍了在互联网的大背景下&#xff0c;医疗健康行业如何迅速发展&#xff0c;举例了&#xff11;药网和叮当快药等平台提供的服务。重点&#xff1a;互联网医疗用户规模和市场…

《人工智能(AI)和深度学习简史》

人工智能&#xff08;AI&#xff09;和深度学习在过去几十年里有了飞跃式的进步&#xff0c;彻底改变了像计算机视觉、自然语言处理、机器人这些领域。本文会带你快速浏览AI和深度学习发展的关键历史时刻&#xff0c;从最早的神经网络模型&#xff0c;一直到现在的大型语言模型…

【技术支持】家里智能电视不能联网重置小米路由器之路

问题现象 最近家里的路由器出现一点问题&#xff0c;现象是手机和电脑连接wifi后&#xff0c;都可以正常打开网页看视频。 但是小爱同学和小米盒子&#xff0c;都出现网络问题&#xff0c;不能正常播放音乐或者视频。 这是小米盒子的网络问题截图 这是和小米盒子连接的智能电…

骨架提取(持续更新)

一 什么是骨架提取 1.1 简介 骨架提取是图像处理或计算机视觉中的一种技术&#xff0c;用于从二值化图像中提取物体的中心线或轮廓&#xff0c;通常称为“骨架”或“细化图像”。这一技术主要用于简化形状表示&#xff0c;同时保留物体的拓扑结构。 这里我们强调了&#xff…

openpyxl -- Cell

文章目录 CellCell的属性MergedCell 版本&#xff1a;openpyxl - 3.0.10 Cell 创建一个单元格&#xff0c;并存入数据、样式、注释等&#xff1b;openpyxl.cell.cell.Cell;获取cell worksheet_obj[“B3”]&#xff0c;根据coordinate获取cell; 也可直接赋值写入&#xff1b;wo…

查找学位论文的数据库有哪些

学位论文分类&#xff1a;一般分为学士论文、硕士论文、博士论文。下面介绍一下能够轻松获取学位论文全文的数据库及获取数据库资源的途径。 1.知网 中国优秀硕士学位论文全文数据库 &#xff08;中国知网CNKI&#xff09; 中国博士学位论文全文数据库 &#xff08;中国知网…

获取时隔半个钟的三天与el-time-select

摘要&#xff1a; 今天遇到需求是配送时间&#xff0c;时隔半个钟的排线&#xff01;所以需要拼接时间&#xff01;例如2024-10-08 14&#xff1a;30&#xff0c;2024-10-08 15&#xff1a;00&#xff0c;2024-10-08 15&#xff1a;30 <el-form-item label"配送时间&a…

Cyber Weekly #28

赛博新闻 1、特斯拉发布无人驾驶汽车Cybercab和Robovan 本周五&#xff08;10月11日&#xff09;&#xff0c;特斯拉公布两款车型Cybercab和Robovan&#xff0c;以及他们的Robotaxi无人驾驶出租车计划。Cybercab没有方向盘&#xff0c;没有充电孔&#xff0c;也没有脚踏板和后…

动态规划的优化与高级应用

姊妹篇&#xff1a; 动态规划基础与经典问题-CSDN博客 贪心算法&#xff1a;原理、应用与优化_最优解-CSDN博客​​​​​​贪心算法&#xff1a;原理、应用与优化_最优解-CSDN博客 一、动态规划的优化策 动态规划在提高时间效率的同时&#xff0c;往往会占用较多的空间。因…

【电商搜索】现代工业级电商搜索技术-中科大-利用半监督学习改进非点击样本的转化率预测

【电商搜索】现代工业级电商搜索技术-中科大-利用半监督学习改进非点击样本的转化率预测 0. 论文信息 RecSys24: Utilizing Non-click Samples via Semi-supervised Learning for Conversion Rate Prediction inproceedings{huang2024utilizing, title{Utilizing Non-click S…

微生物测序报告中的多样性数据详细解读

随着技术的发展&#xff0c;高通量测序技术已成为研究微生物群落的重要工具。这种技术使得科学家们能够解析巨量微生物DNA序列&#xff0c;从而获得丰富的微生物组数据&#xff0c;包括16S rRNA基因、ITS序列和宏基因组。然而&#xff0c;这些数据只是迈向揭示微生物群落复杂性…

docker启动MySQL容器失败原因排查记录

背景 最近在尝试容器搭建MySQL集群时碰到一个错误&#xff0c;启动MySQL时碰到一个&#xff0c;经过排查解决&#xff0c;在此做一个记录 问题过程 1、启动MySQL容器 $ sudo docker run -d -p 3306:3306 \ > --name mysql \ > -v /opt/mysql/log:/var/log/mysql \ &g…

java项目之大型商场应急预案管理系统(源码+文档)

项目简介 大型商场应急预案管理系统实现了以下功能&#xff1a; 大型商场应急预案管理系统的主要使用者管理员功能有个人中心&#xff0c;员工管理&#xff0c;预案信息管理&#xff0c;预案类型管理&#xff0c;事件类型管理&#xff0c;预案类型统计管理&#xff0c;事件类…