技术经验谈 技术经验谈
首页
  • 最佳实践

    • 抓包
    • 数据库操作
  • ui

    • 《JavaScript教程》
    • 《JavaScript高级程序设计》
    • 《ES6 教程》
    • 《Vue》
    • 《React》
    • 《TypeScript 从零实现 axios》
    • 《Git》
    • TypeScript
    • JS设计模式总结
  • 总纲
  • 整体开发框架
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

hss01248

一号线程序员
首页
  • 最佳实践

    • 抓包
    • 数据库操作
  • ui

    • 《JavaScript教程》
    • 《JavaScript高级程序设计》
    • 《ES6 教程》
    • 《Vue》
    • 《React》
    • 《TypeScript 从零实现 axios》
    • 《Git》
    • TypeScript
    • JS设计模式总结
  • 总纲
  • 整体开发框架
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 前端

  • 图形图像

    • 像素操作
      • YUV
      • RGB与YUV转换公式
      • 色彩空间
      • RGB
      • HSL/HSV
      • c实现
      • java实现
    • 图床的选择
    • 图片压缩
    • 图片压缩2
    • 最新图像压缩格式AVIF
    • 颜色模型和色彩空间
    • webP压缩
    • google相机拍照携带1s视频的实现和解析
  • 基础

  • 多媒体

  • 大数据风控

  • 大观

  • 技术视野

  • 云服务器价格对比
  • 其他IT相关
  • 图形图像
hss01248
2021-07-16
目录

像素操作

# 像素操作

# 基本概念

  • ARGB88/RGB565: 真正在Android手机上显示的像素点的内存格式. 参见:像素格式RGB (opens new window)
  • yuv 文件压缩前/解压后的采样格式.最常用yuv420.yuv是个中间状态的格式,主要为压缩算法而生
  • jpg/png/webp/gif: 图像文件压缩后的存储格式,其中jpg,webp均有元数据exif. 各压缩格式也对应了相应格式的编解码算法
  • H.264/H.265: 当下最常用视频编解码算法
  • Mp4/avi/mkv: 视频压缩后的封装格式,包括帧数据和元数据

封装格式 vs 编码格式 vs 元数据

从YUV到RGB (opens new window)

总结:

  • Android和iOS项目中,从摄像头来的数据都是YUV格式的;

  • 解码一个视频时,每一帧中buffer里的data也都是YUV格式的

    而:

  • UI界面显示画面需要使用RGB格式的data;

  • OpenCV等库需要RGB格式的输入;

  • 神经网络需要RGB这3个channel的输入.

图像与视频编码基础知识 (opens new window)

# YUV

Y 表示明亮度(Luminance、Luma),而 U 和 V 表示色度(Chrominance、Chroma)。

而色度又定义了颜色的两个方面:色调和饱和度

一个bitmap对象变成图像文件的过程:

RGB->yuv->压缩成jpg/png

视频通信系统之所以要采用YUV,而不是RGB,主要是因为RGB信号不利于压缩

与下面HSL的不同: yuv是包含了色彩表示和采样模式. 而下方色彩空间中的HSL是单个像素点的色彩表示方法

一文读懂 YUV 的采样与格式 (opens new window)

最常用的采样模式是yuv420: 周围4个像素共用色度

image-20210208163631335

yuv不直接用来存储,而是用作压缩算法的输入,最终压缩成jpg/png等格式存储在文件系统中.

比如图片压缩过程中,先将RGB转换为YUV420,然后使用jpg/png压缩算法压缩成jpg/png格式

image-20210208165834050

# RGB与YUV转换公式

为什么有些手机glide图片加载后白色背景会变绿?

安卓的一个skia的代码,为了优化执行速度对yuv转RGB的运算进行了魔改,结果导致精度损失。结果导致 JPG 图片压缩发绿

参见知乎问题: 为什么图片反复压缩后普遍会变绿,而不是其他颜色? (opens new window)

RGB、YUV各颜色分量的范围为:[0, 1]

RGB --> YUV

Y= 0.299⋅R+0.587⋅G+0.114⋅B U=-0.147⋅R-0.289⋅G+0.436⋅B V= 0.615⋅R-0.515⋅G-0.100⋅B

注:将彩色图像转换成灰色图像,就是从RGB求得Y明亮度的过程 即:灰度 = 0.299⋅R+0.587⋅G+0.114⋅B

YUV --> RGB

R= Y+1.14⋅V G= Y-0.39⋅U-0.58⋅V B= Y+2.03⋅U

# 色彩空间

色彩空间图示 (opens new window)

图像的色彩空間cvtColor(HSV、HSL、HSB ) (opens new window)

色彩空间RGB/CMYK/HSL/HSB/HSV/Lab/YUV基础理论及转换方法:RGB与YUV (opens new window)

RGB色空间是电脑/手机/平板采用的RGB三原色加法色形成的色空间,适用于CG。

CMYK色空间,是印刷油墨CMYK四色减法色形成的色空间,适用于印刷系统。

以上两个色空间,是由显色手段决定的,受到显示器或者印刷手段的材料和工艺的物理限制。

HSB/HSV/HSL则是在RGB的基础上,根据颜色三属性的理论推导出来的色空间,最符合人眼的直觉。

最后的Lab色空间是一个内部转换用的色空间,RGB色转换为CMYK色时,需要先转换为Lab色,再转为CMYK

img

# RGB

A:透明度(Alpha)

R:红色(Red)

G:绿(Green)

B:蓝(Blue)

Android上:

Bitmap.Config ARGB_8888:由4个8位组成,即A=8,R=8,G=8,B=8,那么****一个像素点占8+8+8+8=32位****(4字节)与下面RGB32相反

Bitmap.Config ARGB_4444:由4个4位组成,即A=4,R=4,G=4,B=4,那么一个像素点占4+4+4+4=16位 (2字节)

Bitmap.Config RGB_565:没有透明度,R=5,G=6,B=5,,那么一个像素点占5+6+5=16位(2字节)

Bitmap.Config ALPHA_8:每个像素占8位,只有透明度,没有颜色。

image-20210208162413203

BGR: RGB24 opencv常用.

image-20210208162446098

image-20210208162622485

# HSL/HSV

参考: RGB、HSL、Hex 網頁色彩碼,看完這篇全懂了 (opens new window)

image-20210208165959359

image-20210208161250430

image-20210208161306396

image-20210208161328558

#

# 从像素点中提取a,r,g,b色值:

均为遍历Android的bitmap像素

# c实现

for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
            color = *((int *) pixelColor);
            if(isRGB565){
              //图像为RGB565时
                r = (BYTE) ((color & 0xF800) >> 11 << 3);
                g = (BYTE) ((color & 0x07E0) >> 5 << 2);
                b = (BYTE) (color & 0x001F << 3);
                pixelColor += 2;
            } else{
              //图像为ARGB888时
                r = (BYTE) ((color & 0x00FF0000) >> 16) ;
                g = (BYTE) ((color & 0x0000FF00) >> 8) ;
                b = (BYTE) (color & 0X000000FF);
                pixelColor += 4;
            }

            *data = b;
            *(data + 1) = g;
            *(data + 2) = r;
            data += 3;

        }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# java实现

 out: for (int i = 0; i < w; i++) {
                    for (int j = 0; j < h; j++) {
                        // The argb {@link Color} at the specified coordinate
                        int pix = tagBitmap.getPixel(i,j);
                        long alpha = ((pix >> 24) & 0xff)
                        int r = ((pix >> 16) & 0xff);
                        int g = ((pix >>  8) & 0xff);
                        int b = ((pix      ) & 0xff);
1
2
3
4
5
6
7
8

# alpha通道合成前景色和背景色

常用于png转jpg中

前景色* alpha/255 + 背景色 * (255 - alpha)/255

要使用rgb三个通道分别计算,而不能作为一个int值整体计算:

image-20210208170203824

 out: for (int i = 0; i < w; i++) {
                    for (int j = 0; j < h; j++) {
                        // The argb {@link Color} at the specified coordinate
                        int pix = tagBitmap.getPixel(i,j);
                        long alpha = ((pix >> 24) & 0xff)
                        if(alpha == 0){
                                //将alpha改成255.完全不透明
                                pix = luban.tintBgColorIfHasTransInAlpha | 0xff000000;
                            }else {
                               /* 要使用rgb三个通道分别计算,而不能作为一个int值整体计算:
                               long pix2 = (long) (pix * alpha/255f +  luban.tintBgColorIfHasTransInAlpha * (255f-alpha) / 255f);
                                pix2 = pix2 | 0xff000000; */

                                int r = ((pix >> 16) & 0xff);
                                int g = ((pix >>  8) & 0xff);
                                int b = ((pix      ) & 0xff);

                                int br = ((luban.tintBgColorIfHasTransInAlpha >> 16) & 0xff);
                                int bg = ((luban.tintBgColorIfHasTransInAlpha >>  8) & 0xff);
                                int bb = ((luban.tintBgColorIfHasTransInAlpha      ) & 0xff);

                                int fr = Math.round((r * alpha +  br * (255-alpha)) / 255f);
                                int fg = Math.round((g * alpha +  bg * (255-alpha)) / 255f);
                                int fb = Math.round((b * alpha +  bb * (255-alpha)) / 255f);

                                // 注意是用或,不是用加: pix = 0xff << 24 + fr << 16 + fg << 8 + fb;
                                pix =  (0xff << 24) | (fr << 16) | (fg << 8) | fb;
                                //等效: Color.argb(0xff,fr,fg,fb);
                            }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# 计算一个颜色的反色

主要用于在图片上显示文字,计算出文字用哪种颜色可以看起来反差最大,看起来最明显

首先计算整张图或者文字待显示区域的图像的RGB均值,可以直接用像素点算,也可以使用Android的 Palette API:

使用 Palette API 选择颜色 (opens new window)

得到这个背景RGB后,如何计算其反差色:

使用255-单通道值 肯定不行,如果一个颜色刚好是128 128 128. 计算出来的色值也是基本一样. 并无反差.

HSV/HSL(色相 (opens new window)、饱和度 (opens new window)、明度 (opens new window))是基于人眼感觉的色彩空间表示法,那么使用HSV色彩空间的值来计算?

其实只要针对背景的明度,选择前景色是用白字还是黑字即可:

参考: 计算能在任何背景色上清晰显示的前景色 (opens new window)

/// 获取一个颜色的人眼感知亮度,并以 0~1 之间的小数表示。
/// </summary>
private static double GetGrayLevel(Color color)
{
    return (0.299 * color.R + 0.587 * color.G + 0.114 * color.B) / 255;
}


private static Color GetReverseForegroundColor(double grayLevel) => grayLevel > 0.5 ? Colors.Black : Colors.White;
1
2
3
4
5
6
7
8
9

image-20210208160218058

如果不止要白色黑色,而要绝对的反色呢?

色相取对角线的色相,明度根据背景取0%或100%.饱和度取100%.

# 本质和相关api

像素操作在Android上可以用java/c自己取色计算,实现各种通道混合,以及多图颜色混合.

也可以使用Android自带的一些api,比如Android关于Color你所知道的和不知道的一切 (opens new window)里提到的

colorFilter颜色过滤器,Xfermode:图片叠合时的处理方式 -> 也就是ps里的那个图层间的混合选项:

Image result for ps 混合模式

也可以使用opencv的相关api实现图片混合计算. 本质上都是两幅图像素间的加减乘除运算.

对比Android 绘画和图像相关api,其实和ps有很多相互印证之处. 另有两篇好文可以参考:

可以结合ps一起学

Android关于Color你所知道的和不知道的一切 (opens new window)

Android关于Paint你所知道的和不知道的一切 (opens new window)

Android关于Canvas你所知道的和不知道的一切 (opens new window)

编辑 (opens new window)
上次更新: 2022/08/25, 20:20:31
图形绘制
图床的选择

← 图形绘制 图床的选择→

最近更新
01
截图后的自动压缩工具
12-27
02
图片视频文件根据exif批量重命名
12-27
03
chatgpt图片识别描述功能
02-20
更多文章>
Theme by Vdoing | Copyright © 2020-2025 | 粤ICP备20041795号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式