#topics h2 { background: rgba(43, 102, 149, 1); border-radius: 6px; box-shadow: 0 0 1px rgba(95, 90, 75, 1), 1px 1px 6px 1px rgba(10, 10, 0, 0.5); color: rgba(255, 255, 255, 1); font-family: "微软雅黑", "宋体", "黑体", Arial; font-size: 15px; font-weight: bold; height: 24px; line-height: 23px; margin: 12px 0 !important; padding: 5px 0 5px 10px; text-shadow: 2px 2px 3px rgba(34, 34, 34, 1) }
#topics h1 span { font-weight: bold; line-height: 1.5; font-family: "Helvetica Neue", Helvetica, Verdana, Arial, sans-serif; text-decoration: underline; color: rgba(201, 27, 67, 1); text-shadow: 2px 2px 3px rgba(34, 34, 34, 1) }

  采样后,需要对8*8block进行DCT(离散余弦变换)。为什么要进行DCT?第一点是余弦变化后的图片能量主要集中在低频,我们只需要保存低频数据,默认高频0。第二点是,DCT后的图片很适合哈夫曼压缩,对于原图而言,区域相连的pixle数值差不多,哈夫曼压缩效果差。全部代码在 https://github.com/Cheemion/JPEG_COMPRESS

图片引用自"Compressed Image File Formats JPEG, PNG, GIF, XBM, BMP - John Miano"[1]

          

1.离散余弦变换直觉上的认识

假设我们有一个2*2的图片如下,最亮代表1, 最暗代表-1。

我们普通的认识是,这是一个由4个4维向量组成的一个图片(如下)。可以看成是一个2*2的平面向量,也可以看成4维向量(1,0,0,0)(0,1,0,0)(0,0,1,0)(0,0,0,1)。每个向量两两相交,并且都是单位向量。这4个基向量可以得到任何的一张2*2的图片。

(1,0,0,-1) = 1 *(1, 0, 0, 0) +  0 *(0,1, 0, 0) + 0 *(0, 0, 1, 0) + (-1) * (0, 0, 0, 1);

离散余弦变化,其实只是把上面的4个基向量进行了变化。如下

基向量变成了(0.5,0.5,0.5, 0.5)(0.5, -0.5, 0.5, -0.5) (0.5, 0.5, -0.5, -0.5) (0.5, -0,5, -0.5, 0.5),每个向量两两相交,并且都是单位向量。这4个基向量可以得到任何的一张2*2的图片。

所以DCT其实只是换了一个基向量而已。

左边第一个图为低频,因为整个图的颜色没有变化,可以认为变化频率为0

最右边的图为高频,上下和左右的颜色都变化了一次。

(1,0,0,-1) =  0 *(0.5, 0.5, 0.5, 0.5) +  1 *(0.5,-0.5, 0.5, -0.5) + 1 *(0.5, 0.5, -0.5, -0.5) + 0  * (0.5, -0.5, -0.5, 0.5);

蓝色的系数只要通过原图和新的基向量点成就可以得到,比如向量(0.5, 0.5, 0.5, 0.5)前面的系数为 1 * 0.5 + 0 * 0.5 + 0 * 0.5 + (-1) * 0.5 = 0;

2.离散余弦变换公式上的认识

DCT离散余弦正变换

令G(i, j) = cos((i + 0.5) * pi * u /N) * cos((j + 0.5) * pi * u / N), u 和 v是constant

随着u和v从0到7(因为我们的block是8*8) 不断的变化我们可以画出如下图

画图代码matlab如下

function [ out ] = g( u,v )
p = zeros(8,8);
for i = 0:7
for j = 0:7
p(i + 1,j + 1) = cos((i + 0.5) * u * pi / 8) * cos((j + 0.5) * v * pi / 8);
end
end
out = p;
end

matlab画图代码

clc; clear; close all;
figure;
maximum = 0;
minimum = 100;
for u = 0:7
for v = 0:7
pp = g(u,v)
subplot(8, 8, u * 8 + v + 1);
imshow((pp + 1) ./ 2);
end
end

matlab画图代码主函数

乘以系数c(u)c(v)是使我们的G(i, j)变成单位向量。公式剩余部分就是点乘的过程。

IDCT逆变换

3.代码

void DCT(Block& block) {
Block temp;
std::memcpy(&temp, &block, sizeof(Block)); //copy from original
//8 rows
//DCT行变化
for(uint i = 0; i < 8; i++) {
double* f = &temp[i * 8]; //one dimension Array , and will perform DCT on it
for(uint k = 0; k < 8; k++) {
double sum = 0.0;
for(uint n = 0; n < 8; n++){
sum = sum + f[n] * std::cos(((n + 0.5) * M_PI * k / 8));
}
sum = (k == 0) ? (sum * std::sqrt(1.0 / 8)) : (sum * std::sqrt(2.0 / 8));
block[i * 8 + k] = sum;
}
} std::memcpy(&temp, &block, sizeof(Block)); //copy from
//DCT列变化
for(uint i = 0; i < 8; i++) {
double* f = &temp[i]; //one dimension Array with 8 steps increment , and will perform DCT on it
for(uint k = 0; k < 8; k++) {
double sum = 0.0;
for(uint n = 0; n < 8; n++){
sum = sum + f[n * 8] * std::cos(((n + 0.5) * M_PI * k / 8));
}
sum = (k == 0) ? (sum * std::sqrt(1.0 / 8)) : (sum * std::sqrt(2.0 / 8));
block[i + k * 8] = sum;
}
}
}

以上全部的代码在https://github.com/Cheemion/JPEG_COMPRESS/tree/main/Day3

完结

Thanks for reading.

wish you have a good day.

>>>> JPG学习笔记4(附完整代码)


参考资料

[1]https://github.com/Cheemion/JPEG_COMPRESS/blob/main/resource/Compressed%20Image%20File%20Formats%20JPEG%2C%20PNG%2C%20GIF%2C%20XBM%2C%20BMP%20-%20John%20Miano.pdf

JPG学习笔记3(附完整代码)的更多相关文章

  1. Android 监听双卡信号强度(附完整代码)

    Android 监听双卡信号强度 监听单卡信号强度 监听单卡的信号强度非常简单直接用TelephonyManager.listen()去监听sim卡的信号强度. TelephonyManager = ...

  2. JPG学习笔记4(附完整代码)

    #topics h2 { background: rgba(43, 102, 149, 1); border-radius: 6px; box-shadow: 0 0 1px rgba(95, 90, ...

  3. JPG学习笔记2(附完整代码)

    #topics h2 { background: rgba(43, 102, 149, 1); border-radius: 6px; box-shadow: 0 0 1px rgba(95, 90, ...

  4. WebGL three.js学习笔记 创建three.js代码的基本框架

    WebGL学习----Three.js学习笔记(1) webgl介绍 WebGL是一种3D绘图协议,它把JavaScript和OpenGL ES 2.0结合在一起,通过增加OpenGL ES 2.0的 ...

  5. 学习笔记:python3,代码。小例子习作(2017)

    http://www.cnblogs.com/qq21270/p/7634025.html 学习笔记:python3,一些基本语句(一些基础语法的代码,被挪到这里了) 日期和时间操作 http://b ...

  6. 学习笔记:python3,代码。小例子习作

    http://www.cnblogs.com/qq21270/p/7634025.html 学习笔记:python3,一些基本语句(一些基础语法的代码,被挪到这里了) 日期和时间操作 http://b ...

  7. 雨痕 的《Python学习笔记》--附脑图(转)

    原文:http://www.pythoner.com/148.html 近日,在某微博上看到有人推荐了 雨痕 的<Python学习笔记>,从github上下载下来看了下,确实很不错. 注意 ...

  8. Linux Shell输出颜色字符学习笔记(附Python脚本实现自动化定制生成)

    齿轮发出咔嚓一声,向前进了一格.而一旦向前迈进,齿轮就不能倒退了.这就是世界的规则. 0x01背景 造了个轮子:御剑师傅的ipintervalmerge的Python版本.觉得打印的提示信息如果是普通 ...

  9. 基于C#的内网穿透学习笔记(附源码)

    如何让两台处在不同内网的主机直接互连?你需要内网穿透!          上图是一个非完整版内外网通讯图由内网端先发起,内网设备192.168.1.2:6677发送数据到外网时候必须经过nat会转换成 ...

随机推荐

  1. feign使用okHttpClient,调用原理

    最近项目中 spring cloud 用到http请求,使用feign,配置okhttp,打算配置一下就直接使用,不过在压测与调优过程中遇到一些没有预测到的问题,附上排查与解析结 yml.pom配置 ...

  2. nodejs的调试debug

    目录 简介 开启nodejs的调试 调试的安全性 使用WebStorm进行nodejs调试 使用Chrome devTools进行调试 使用node-inspect来进行调试 其他的debug客户端 ...

  3. mysql的安装使用及其用户管理

    mysql的安装使用及其用户管理   一.mariadb安装 搭建yum源 [mariadb] name = MariaDB baseurl = http://mirrors.ustc.edu.cn/ ...

  4. Android N selectQualifiedNetwork分析

    前言: 参考:Android N wifi auto connect流程分析 后续 Android 8.0/9.0 wifi 自动连接评分机制 分析 前面说了,handleScanResults会去调 ...

  5. 反向传播(Back Propagation)

    反向传播(Back Propagation) 通常在设计好一个神经网络后,参数的数量可能会达到百万级别.而我们利用梯度下降去跟新参数的过程如(1).但是在计算百万级别的参数时,需要一种有效计算梯度的方 ...

  6. apache https 双向证书生成

    Https分单向认证和双向认证 单向认证表现形式:网站URL链接为https://xxx.com格式 双向认证表现心事:网站URL链接为https://xxx.com格式,并且需要客户端浏览器安装一个 ...

  7. windows下hash抓取的几种方式

    前提:在渗透测试过程中,对于windows系统的机器渗透需要注意hash的获取,其中hash分为LM-HASH与NTLM-HASH,在windows系统中,hash的默认存储位置为: C:\Windo ...

  8. 小米和MAC触摸板手势汇总

    小米的触摸手势: 左键:单指单击 右键:双指单击 选取并打开:单指双击 滚动页面:双指 移动 拖拽项目:双击并拖拽 放大/缩小:双指张开,双指捏合 MAC触摸板手势: http://www.cr173 ...

  9. jenkins 简介和简单操作

    持续集成:Continuous Intergration (CI) 持续交付:Continuous Delivery(CD) 持续部署:Continuous Deployment(CD) jenkin ...

  10. DEDECMS的20位MD5加密密文解密

    解密20位md5,20位md5加密算法.   dedecms的20位md5加密算噶是从32位md5中截取的20位,所以去掉前3位喝最后1位,即可获得16位md5值,即可破解15位md5.   例如:  ...