动态设置图片的主题色(保留明暗关系)
github地址
PrimaryColorDemo
效果
原始图片
就是一张普通的png图片

根据选择的主题色动态渲染。

思考
最近在思考怎么实现动态的设置图片的主题色。不是那种渲染透明iocn。而是把图片的明暗关系保留。而改变其中的主题色。终于花了半天的时间研究出来了。和大家共享。
实现
思路很简单
- 将图片从RGB色彩空间转化为YUV色彩空间
- 使用ColorMatirx的setRotate(0, hue0);方法。将图片沿着Y轴旋转hue0的角度(角度从0到360度)
- 在家图片从YUV色彩空间转化RGB色彩空间
原理
YUV 空间
通俗的讲。YUV只是颜色的一种表达形式。Y中保存了图片的明暗度。UV保存了图片的色度信息。
下图所示,第一张是原图,依次是YUV分量。

setRotate方法
ColorMatirx的setRotate方法可以将颜色沿着一个轴旋转,沿着的这个轴的信息就不会变化。
/**
-
用于色调的旋转运算
-
axis=0 表示色调围绕红色进行旋转
-
axis=1 表示色调围绕绿色进行旋转
-
axis=2 表示色调围绕蓝色进行旋转
*/
public void setRotate(int axis, float degrees)

1)围绕红色轴旋转
我们可以根据三原色来建立一个三维向量坐标系,当围绕红色旋转时,我们将红色虚化为一个点,绿色为横坐标,蓝色为纵坐标,旋转θ°。

偷梁换柱
如果我们将颜色从RGB转换为YUV 那么这个时候调用setRotate(0,degrees)那么颜色就会以Y信息为轴,进行旋转degrees的角度。
由于没有改变Y信息,所以图片的明暗度不会发生变化。
代码如下
ColorMatrix cm = new ColorMatrix();ColorMatrix tmp = new ColorMatrix();cm.setRGB2YUV();tmp.setRotate(0, hue0);cm.postConcat(tmp);tmp.setYUV2RGB();cm.postConcat(tmp);paint.setColorFilter(new ColorMatrixColorFilter(cm));canvas.drawBitmap(bitmap,0,0,paint);
难点计算这个转动角度
其实也很简单。我们只需获取原来图片中的主题色

使用拾色器就可以搞定
然后根据目标色计算角度。
因为只转动UV信息
所以将原图中的UV信息组成一个二维向量,目标色的UV信息组成一个二维向量。
计算公式如下。

还需要注意一点
就是上面计算出来的角度是最小角度。
还要根据两个向量之间的叉积,来判断向量之间的位置关系。
叉乘公式
两个向量的叉乘,又叫向量积、外积、叉积,叉乘的运算结果是一个向量而不是一个标量。并且两个向量的叉积与这两个向量组成的坐标平面垂直。
一、二维向量叉乘公式:a(x1,y1),b(x2,y2),则a×b=(x1y2-x2y1)
根据叉乘结果的正负,可以判断两个向量的位置关系
判断点P在向量AB的左侧还是右侧,则可根据向量ABxAP 的叉乘结果r 来判断,根据右手定则:
- 若r > 0,则点P在向量AB的左侧;
- 若r = 0,则点P在向量AB上;
- 若r < 0,则点P在向量AB的右侧。
代码实现
注意,主题色写死在代码里面。要扩展需要自行改动。
最后的代码如下:
package com.example.orderlayoutdemo;import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.util.Log;/*** <pre>* Created by zhuguohui* Date: 2023/4/21* Time: 17:24* Desc:* </pre>*/
public class ImageUtils {public static Bitmap handleImageEffect(Bitmap bitmap,int targetColor){//由于不能直接在原图上修改,所以创建一个图片,设定宽度高度与原图相同。为32位ARGB图片Bitmap currentBitmap = Bitmap.createBitmap(bitmap.getWidth(),bitmap.getHeight(), Bitmap.Config.ARGB_8888);//创建一个和原图相同大小的画布Canvas canvas = new Canvas(currentBitmap);//创建笔刷并设置抗锯齿Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);float hue0=getHub(Color.parseColor("#61BCF8"),targetColor);ColorMatrix cm = new ColorMatrix();ColorMatrix tmp = new ColorMatrix();cm.setRGB2YUV();tmp.setRotate(0, hue0);cm.postConcat(tmp);tmp.setYUV2RGB();cm.postConcat(tmp);paint.setColorFilter(new ColorMatrixColorFilter(cm));canvas.drawBitmap(bitmap,0,0,paint);return currentBitmap;}public static float getHub(int fromColor,int targetColor){int[] yuv1 = convertRGB2YUV(fromColor);int[] yuv2 = convertRGB2YUV(targetColor);//计算两个颜色的uv分量组成的向量之间的夹角return getDegreeBetweenVectors(new int[]{yuv1[1], yuv1[2]}, new int[]{yuv2[1], yuv2[2]});}/*** 计算向量1,顺时针旋转多少度可以得到向量2* 返回的度数为0到360度* @param vs1* @param vs2* @return*/private static float getDegreeBetweenVectors(int[] vs1,int[] vs2 ){double cosDegree=0;//向量的内积int nj = vs1[0] * vs2[0] + vs1[1] * vs2[1];//叉积int cj=vs1[0]*vs2[1]-vs1[1]*vs2[0];double bl = Math.sqrt(vs1[0] * vs1[0] + vs1[1] * vs1[1]) *Math.sqrt(vs2[0] * vs2[0] + vs2[1] * vs2[1]);cosDegree= (nj/bl);double degree = Math.acos(cosDegree) / Math.PI * 180;//叉积大于0,表示向量2 在向量1的左边degree = (float) (cj > 0 ? 360- degree : degree);return (float) degree;}private static int[] convertRGB2YUV(int color) {ColorMatrix cm = new ColorMatrix();cm.setRGB2YUV();final float[] yuvArray = cm.getArray();int r = Color.red(color);int g = Color.green(color);int b = Color.blue(color);int[] result = new int[3];result[0] = floatToByte(yuvArray[0] * r + yuvArray[1] * g + yuvArray[2] * b);result[1] = floatToByte(yuvArray[5] * r + yuvArray[6] * g + yuvArray[7] * b) ;result[2] = floatToByte(yuvArray[10] * r + yuvArray[11] * g + yuvArray[12] * b) ;return result;}private static int floatToByte(float x) {int n = java.lang.Math.round(x);return n;}}
相关文章:
动态设置图片的主题色(保留明暗关系)
github地址 PrimaryColorDemo 效果 原始图片 就是一张普通的png图片 根据选择的主题色动态渲染。 思考 最近在思考怎么实现动态的设置图片的主题色。不是那种渲染透明iocn。而是把图片的明暗关系保留。而改变其中的主题色。终于花了半天的时间研究出来了。和大家共享。 …...
mybatis中#与$的区别
文章目录 区别详细讲解${}sql注入案例 区别 #会进行预编译,安全,通过#{}传入的参数 mybatis会认为是一个字符串,自动加上引号“” $ 不会进行预编译,通过$ 传入的参数会直接取出来使用,可能会产生sql注入风险ÿ…...
CVPR2023论文整理
文章目录 CVPR2023一. Vision and Language / Multimodal CVPR2023 根据官方信息统计,今年共收到 9155 份提交,比去年增加了 12%,创下新纪录,今年接收了 2360 篇论文,接收率为 25.78%。作为对比,去年有 81…...
RK3399平台开发系列讲解(中断篇)掌握信号处理
🚀返回专栏总目录 文章目录 一、信号的基本概念二、信号处理流程三、如何通过 API 注册一个信号处理函数四、可重入与异步信号安全3.1、可重入函数3.2、异步信号安全沉淀、分享、成长,让自己和他人都能有所收获!😄 📢信号在操作系统中有悠久的历史,信号的概念和使用方…...
业余爱好者想入门编程,一定远离那些只会说No的家伙,尤其程序员
视频:https://haokan.baidu.com/v?pdwisenatural&vid3050207991292418741 自媒体上的程序员群体有一个非常有意思的特点,就是特别愿意否定别人,特别喜欢说no,还有一个特点,特别不爱分享一些有用的技术和知识&…...
DHCP及中继(UOS)
DHCP服务器 中继器 客户端 服务器 安装DHCP apt install isc-dhcp-server -y 编辑配置文件 vim /etc/dhcp/dhcpd.conf 重启服务 systemctl restart isc-dhcp-server 配置监听网卡 vim /etc/default/isc-dhcp-server 中继器 安装dhcp yum install dhcp -y nmtui 修改…...
【Linux】进程的概念
文章目录 📖 前言1. 冯诺依曼体系结构1.1 内存存在的意义:1.2 程序加载到内存的意义:1.3 程序的预加载: 2. 认识进程2.1 如何理解管理:2.2 什么叫是进程:(初步理解) 3. 简单认识操作…...
奇舞周刊第490期:WebAssembly 多语言/宿主环境中的使用
记得点击文章末尾的“ 阅读原文 ”查看哟~ 下面先一起看下本期周刊 摘要 吧~ 奇舞精选 ■ ■ ■ WebAssembly 多语言/宿主环境中的使用 WebAssembly (WASM) 的一个优势就是能够支持将不同语言编译成 WASM 代码,然后在不同的宿主环境中运行。这样就可以在不同的宿主环…...
【css】使用css实现提示框各种弹出效果。
简言 最近工作编写页面时,需要有一个提示框从下到上弹出的效果。 冥想了一下,实现了出来。 记录下实现思路。 实现思路 实现步骤如下: 编写样式。 首页要有承载内容的容器(box)。外层在套一个包装盒子(用来进行定位…...
1685_Excel的几种脚本处理方式
全部学习汇总: GreyZhang/python_basic: My learning notes about python. (github.com) 做个小结,实际上是写的我自己学习的过程。 关于Excel的处理方式很多,我也不会那么多,在这里我只想写一下我自己接触过的。大致是三种方式&a…...
Unity中使用struct和class来存储数据的注意事项
在 Unity 中,struct 和 class 都是用来定义自定义类型的关键字。它们的主要区别在于如何存储和传递它们的实例。 特点structclass存储方式值类型引用类型默认构造函数自动有性能快慢可空性不可空可空继承单继承单继承或多重继承 一、相似之处 1、都是用来定义自定…...
共阳(共阴)LED数码管编码交互演示
LED数码管原理 LED数码管有两大类,一类是共阴极接法,另一类是共阳极接法,共阴极就是各段的显示字码共用一个电源的负极,是高电平点亮,共阳极就是各段的显示字码共用一个电源的正极,是低电平点亮。只要控制…...
如何在 TensorFlow 中使用 GPU 加速深度学习计算?
一、前言 TensorFlow 是由 Google 开源的深度学习框架,它具有易用、高效、灵活等特点,被广泛应用于学术界和工业界中。而 GPU 是一种高性能的计算设备,可以加速深度学习的计算过程。本文将介绍如何在 TensorFlow 中使用 GPU 加速深度学习计算。 二、安装 TensorFlow 安装…...
RK3568平台开发系列讲解(Linux系统篇)线程 pthread 详解
🚀返回专栏总目录 文章目录 一、POSIX 线程模型二、pthread_create()创建线程三、线程属性3.1、初始化线程对象属性3.2、销毁一个线程属性对象3.3、线程的分离状态3.4、线程的调度策略3.5、线程的优先级3.6、线程栈四、线程退出五、回收已终止线程的资源沉淀、分享、成长,让…...
hspJAVA
循序渐进学Java 零基础 -韩顺平 第 1 章 内容介绍 1 1.1 本套 JAVA 课程内容 1 1.1.1 课程的三个阶段 1 1.1.2 关于课程的说明 1 1.1.3 课程特色 2 1.2 JAVA 就业方向 2 1.3 JAVA 开发场景举例 1-SSM 3 1.4 JAVA 开发场景举例 2:ANDROID 核心代码 3 1.5 JAVA 开发场…...
OpenAI-ChatGPT最新官方接口《嵌入向量式文本转换》全网最详细中英文实用指南和教程,助你零基础快速轻松掌握全新技术(五)(附源码)
Embeddings 嵌入向量式文本转换 前言Overview 概述What are embeddings? 什么是嵌入?How to get embeddings 如何获取嵌入python代码示例cURL代码示例 Embedding models 嵌入模型Second-generation models 第二代模型First-generation models (not recommended) 第…...
1042. 不邻接植花
有 n 个花园,按从 1 到 n 标记。另有数组 paths ,其中 paths[i] [xi, yi] 描述了花园 xi 到花园 yi 的双向路径。在每个花园中,你打算种下四种花之一。 另外,所有花园 最多 有 3 条路径可以进入或离开. 你需要为每个花园选择一…...
Linux FTP服务
FTP服务 作用 传输文件 端口 FTP服务器默认使用TCP协议的20、21端口与客户端进行通信 20端口用于建立数据连接,并传输文件数据 21端口用于建立控制连接,并传输FTP控制命令 模式 FTP数据连接分为主动模式和被动模式 主动模式:客户端告诉服务端…...
JavaScript基础入门全解析(下)
数据类型(重点) ●是指我们存储在内存中的数据的分类,为了方便数据的管理,将数据分成了不同的类型 ●我们通常分为两大类 基本数据类型 和 复杂数据类型(引用数据类型) 基本数据类型 ●在js中基本数据类…...
【C++初阶】(入门)输入输出
#include< iostream> std是C标准库的命名空间名,C将标准库的定义实现都放到这个命名空间中 文章目录 ✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨👻一、iostream库介绍👻二、使用总结 ✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨ Ǵ…...
大型活动交通拥堵治理的视觉算法应用
大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动(如演唱会、马拉松赛事、高考中考等)期间,城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例,暖城商圈曾因观众集中离场导致周边…...
FastAPI 教程:从入门到实践
FastAPI 是一个现代、快速(高性能)的 Web 框架,用于构建 API,支持 Python 3.6。它基于标准 Python 类型提示,易于学习且功能强大。以下是一个完整的 FastAPI 入门教程,涵盖从环境搭建到创建并运行一个简单的…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...
如何在网页里填写 PDF 表格?
有时候,你可能希望用户能在你的网站上填写 PDF 表单。然而,这件事并不简单,因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件,但原生并不支持编辑或填写它们。更糟的是,如果你想收集表单数据ÿ…...
CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)
漏洞概览 漏洞名称:Apache Flink REST API 任意文件读取漏洞CVE编号:CVE-2020-17519CVSS评分:7.5影响版本:Apache Flink 1.11.0、1.11.1、1.11.2修复版本:≥ 1.11.3 或 ≥ 1.12.0漏洞类型:路径遍历&#x…...
免费PDF转图片工具
免费PDF转图片工具 一款简单易用的PDF转图片工具,可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件,也不需要在线上传文件,保护您的隐私。 工具截图 主要特点 🚀 快速转换:本地转换,无需等待上…...
RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill
视觉语言模型(Vision-Language Models, VLMs),为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展,机器人仍难以胜任复杂的长时程任务(如家具装配),主要受限于人…...
Web中间件--tomcat学习
Web中间件–tomcat Java虚拟机详解 什么是JAVA虚拟机 Java虚拟机是一个抽象的计算机,它可以执行Java字节码。Java虚拟机是Java平台的一部分,Java平台由Java语言、Java API和Java虚拟机组成。Java虚拟机的主要作用是将Java字节码转换为机器代码&#x…...
【Veristand】Veristand环境安装教程-Linux RT / Windows
首先声明,此教程是针对Simulink编译模型并导入Veristand中编写的,同时需要注意的是老用户编译可能用的是Veristand Model Framework,那个是历史版本,且NI不会再维护,新版本编译支持为VeriStand Model Generation Suppo…...
如何在Windows本机安装Python并确保与Python.NET兼容
✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏…...
