CCF-CSP真题《202212-3 JPEG 解码》思路+python,c++满分题解

Posted Hulake_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CCF-CSP真题《202212-3 JPEG 解码》思路+python,c++满分题解相关的知识,希望对你有一定的参考价值。

想查看其他题的真题及题解的同学可以前往查看:CCF-CSP真题附题解大全

试题编号:202212-3
试题名称:JPEG 解码
时间限制:1.0s
内存限制:512.0MB
问题描述:

问题背景

        四年一度的世界杯即将画上尾声。在本次的世界杯比赛中,视频助理裁判(Video Assistant Referee, VAR)的应用可谓是大放异彩。VAR 使用视频回放技术帮助主裁判作出正确判罚决定。西西艾弗岛足球联赛的赛场上也引入了一套 VAR 设备。作为技术供应商的技术主管小C,需要存储和编码 VAR 产生的图像数据。小 C 分析比较发现,JPEG 编码算法可以达到较好的压缩效果,并且质量损失是可以接受的。因此,小 C 决定使用 JPEG 编码算法来存储和传输图像数据。JPEG 是一种常用的图片有损压缩算法,它的压缩率高,但是压缩后的图片质量下降较多。JPEG 图片的压缩率一般在 10:1 到 20:1 之间,一般用于存储照片等图片质量要求不高的场景。

        为了简化问题,我们以灰度图片为例,介绍 JPEG 编码算法的过程。一张灰度图片,可以被视为由多个像素点组成。每个像素点对应一个 0 到 255 之间的数值,用于表示像素点的亮度。JPEG 编码算法将图片分割为 8×8 的小块,每个小块被称作一个最小编码单元。对每个小块进行如下的计算:

  1. 将每个像素点的数值减去 128,使得每个像素点的数值都在 -128 到 127 之间。
  2. 将每个小块的像素点排成一个 8×8 的矩阵,并对矩阵进行离散余弦变换(DCT)。进行离散余弦变换后,仍然得到一个 8×8 的矩阵,矩阵中的每个元素都是实数,并且所得矩阵的左上方的数字的绝对值较大,右下方的数字的绝对值较小,甚至接近 0。
  3. 对矩阵进行量化操作。量化操作是指将矩阵中的每个元素都除以一个数字,并取整数。量化操作的目的是为了减少矩阵中的数据,从而减少编码后的文件大小。量化操作的数字越大,矩阵中的数据就越少,但是压缩后的图片质量也会越差。
  4. 对矩阵进行 Z 字形扫描。Z 字形扫描是指从左上角开始,沿着 Z 字形的路径扫描矩阵中的元素,将扫描到的元素依次排成一个数组,由于 Z 字形扫描的路径是从左上角到右下角,数组结尾处可能存在着连续的 0,为了节省空间,可以不存储这些连续的 0。得到的数据被称为扫描数据。

        最后,将得到的各个小块的扫描数据采用哈夫曼编码进行压缩,并置于必要的数据结构中,就能得到一张 JPEG 图片了。

问题描述

        在本题中,你需要实现一个能够解码 JPEG 图片的一个最小编码单元的程序。解码的步骤与上述编码的步骤相反,具体的步骤是:

  1. 读入量化矩阵 Qi,j,其中 i,j 的取值范围为 0∼7。

  2. 初始化一个 8×8 的矩阵 M,令 Mi,j=0。

  3. 读入扫描数据,将扫描数据按照这样的顺序写入矩阵 M:从左上角 M0,0 开始,接下来填充它的右侧相邻的元素 M0,1,然后依次向左下方填充直至 M1,0,接下来从它下侧相邻的元素 M2,0 开始,依次向右上方填充直至 M0,2,依次类推,循环往复,直至填充满整个矩阵或用尽所有扫描数据,如图所示。

    填充顺序
  4. 将矩阵 M 中的每个元素都乘以量化矩阵 Q 中的对应元素。

  5. 对矩阵 M 进行离散余弦逆变换,得到一个 8×8 的矩阵 M′。其中,逆变换的公式如下:

  6. 将矩阵 M′ 中的每个元素都加上 128,并取最接近的整数(四舍五入)。如果得到的整数大于 255,则取 255;如果得到的整数小于 0,则取 0。得到的矩阵即为解码后的图片。例如,假设给定的量化矩阵是:

    给出的扫描数据是:-26, -3, 0, -3, -2, -6, 2, -4, 1, -3, 1, 1, 5, 1, 2, -1, 1, -1, 2, 0, 0, 0, 0, 0, -1 -1,那么填充后的矩阵 M 是:

     与量化矩阵逐项相乘后的矩阵是:

     经过离散余弦逆变换后的矩阵 M′ 是:

    经过加 128 后并取整的矩阵是:

输入格式

从标准输入读入数据。

输入的前 8 行,每行有空格分隔 8 个正整数,是量化矩阵。

接下来的 1 行是 1 个正整数 n,表示扫描数据的个数。

接下来的 1 行是 1 个数字 T,取值为 0、1 或 2,表示要进行的任务。

接下来的 1 行,有空格分隔的 n 个整数,是扫描数据。

输出格式

输出到标准输出中。

输出共 8 行,每行有 8 个空格分隔的整数,表示一个图像矩阵。

当 T 取 0 时,输出填充(步骤 3)后的图像矩阵;当 T 取 1 时,输出量化(步骤 4)后的图像矩阵;当 T 取 2 时,输出最终的解码结果。

样例输入

16 11 10 16 24 40 51 61
12 12 14 19 26 58 60 55
14 13 16 24 40 57 69 56
14 17 22 29 51 87 80 62
18 22 37 56 68 109 103 77
24 35 55 64 81 104 113 92
49 64 78 87 103 121 120 101
72 92 95 98 112 100 103 99
26
2
-26 -3 0 -3 -2 -6 2 -4 1 -3 1 1 5 1 2 -1 1 -1 2 0 0 0 0 0 -1 -1

样例输出

62 65 57 60 72 63 60 82
57 55 56 82 108 87 62 71
58 50 60 111 148 114 67 65
65 55 66 120 155 114 68 70
70 63 67 101 122 88 60 78
71 71 64 70 80 62 56 81
75 82 67 54 63 65 66 83
81 94 75 54 68 81 81 87

样例说明

本组样例即为题目描述中的样例。

子任务

对于 20% 的数据,有 T=0;

对于 40% 的数据,有 T=0 或 1;

对于 100% 的数据,有 T∈0,1,2,且 n∈[0,64],并且量化矩阵中的各个元素 qi,j 满足 0<qi,j<256,扫描序列中的各个元素 mi 满足 −256<mi<256。

提示

在 C/C++ 语言中,可以通过包含 math.h(C 语言)或 cmath(C++ 语言)来使用数学函数。 π 的值可以通过表达式 acos(-1) 获得。

在 Python 语言中,可以通过 from math import pi 引入 π。

在 Java 语言中,可以使用 Math.PI 来获取 π 的值.

真题来源:JPEG 解码

感兴趣的同学可以如此编码进去进行练习提交

python题解:


c++满分题解:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>

using namespace std;

const int N = 8;

int n, T;

int a[N][N], M[N][N], M1[N][N];
double M2[N][N];
int q[64];

double trans(double i, double j)

    double res = 0;
    for (int u = 0; u <= 7; u ++ )
        for (int v = 0; v <= 7; v ++ )
            if (u == 0 && v == 0)
                res += (double)M1[u][v] * cos(0) * cos(0) / 2.0;
            else if (u == 0)
                res += (double)M1[u][v] * sqrt(0.5) * cos(acos(-1) * (i + 0.5) * double(u) / 8.0) * cos(acos(-1) * (j + 0.5) * v / 8.0);
            else if (v == 0)
                res += (double)M1[u][v] * sqrt(0.5) * cos(acos(-1) * (i + 0.5) * double(u) / 8.0) * cos(acos(-1) * (j + 0.5) * v / 8.0);
            else
                res += (double)M1[u][v] * cos(acos(-1) * (i + 0.5) * double(u) / 8) * cos(acos(-1) * (j + 0.5) * double(v) / 8.0);

    return (double)res / 4.0;    


int main()

    for (int i = 0; i < 8; i ++ )
        for (int j = 0; j < 8; j ++ )
            cin >> a[i][j];
    
    cin >> n >> T;
    
    for (int i = 0; i < n; i ++ )
        cin >> q[i];
    
    // T1.
    int k = 0; 
    for (int i = 0; i < 8; i ++ )
        if (i % 2 == 0)
        
            for (int j = 0; j <= i; j ++ )
                M[i - j][j] = q[k ++ ];
        
        else
            for (int j = 0; j <= i; j ++ )
                M[j][i - j] = q[k ++ ];
        
    for (int i = 8; i < 15; i ++ )
        if (i % 2 == 0)
            for (int j = i - 7; j <= 7; j ++ )
                M[i - j][j] = q[k ++ ];
        else
            for (int j = i - 7; j <= 7; j ++ )
                M[j][i - j] = q[k ++ ];
    
    
    // T2.
    for (int i = 0; i < 8; i ++ )
        for (int j = 0; j < 8; j ++ )
            M1[i][j] = M[i][j] * a[i][j];
        
    // T3.    
    for (int i = 0; i < 8; i ++ )
        for (int j = 0; j < 8; j ++ )
        
            M2[i][j] = round(trans(i, j) + 128);
            if (M2[i][j] > 255) M2[i][j] = 255;
            if (M2[i][j] < 0) M2[i][j] = 0;
        
            
    // 输出    
    if (T == 0)
        for (int i = 0; i < 8; i ++ )
        
            for (int j = 0; j < 8; j ++ )
                cout << M[i][j] << " ";
            cout << endl;
        
    
    if (T == 1)
        for (int i = 0; i < 8; i ++ )
        
            for (int j = 0; j < 8; j ++ )
                cout << M1[i][j] << " ";
            cout << endl;
        
    
    if (T == 2)
        for (int i = 0; i < 8; i ++ )
        
            for (int j = 0; j < 8; j ++ )
                cout <<  M2[i][j] << " ";
            cout << endl;
        
    return 0;

运行结果: 


借鉴: ShowerSong

新CCF-CSP认证历年真题解

CSP认证考什么怎么考?
  
  CCF计算机职业资格认证的每一道试题都十分经典,覆盖现实世界中方方面面的问题。这个历年试题解主要使用C/C++语言编写,将逐步增加Python和Java的解题程序。程序中附有注释,力求解题思路清晰简洁,值得珍藏与模仿。
  逐题改写过程中,富文本编辑器写的博客将全部用Markdown编辑器改写。改写的第一题,都增加了Python和Java的解题程序。
  本文本来只是一个索引链接,为了更加易于使用,格式做了调整,界面更加简洁。原来博文《CCF-CSP认证历年真题解》阅读量已经超过23万,大受广大网友喜爱,博文需要提供更好的服务。本文完成后,原来的博文不再更新。
  部分解题原始代码来自仙客传奇团队。

考试时间第1题第2题第3题第4题第5题
2021.092300000
2021.0422灰度直方图邻域均值DHCP服务器校门外的树疫苗运输 80分链接
2020.1221期末预测之安全指数期末预测之最佳阈值0食材运输 100分链接星际旅行 100分链接
2020.0920称检测点查询风险人群筛查0星际旅行 100分链接密信与计数 100分链接
2020.0619线性分类器稀疏向量Markdown渲染器1246 100分链接乔乔和牛牛逛超市 100分链接
2019.1218报数回收站选址化学方程式区块链魔数 100分链接
2019.0917小明种苹果小明种苹果(续)字符画推荐系统城市规划 100分链接
2019.0316小中大二十四点损坏的RAID5消息传递接口317号子任务 100分链接
2018.1215小明上学小明放学CIDR合并数据中心管道清洁 100分链接
2018.0914卖菜买菜元素选择器再卖菜线性递推式 募集题解
2018.0313000棋局评估二次求和 100分链接
2017.12120000商路 60分链接
2017.0911打酱油00通信网络除法
2017.0310分蛋糕00地铁修建引水入城 100分链接
2016.129中间数000卡牌游戏 募集题解
2016.098最大波动000祭坛 100分链接
2016.047折点计数000网络连接 募集题解
2015.126数位之和000矩阵 募集题解
2015.095数列分段000最佳文章 100分链接
2015.034图像旋转000最小花费 100分链接
2014.123门禁系统000货物调度 100分链接
2014.092相邻数对0字符串匹配0拼图
2014.031相反数000任务调度 100分链接
2013.120出现次数最多的数ISBN号码最大的矩形有趣的数I’m stuck!

相关链接:
  官方网站:CCF计算机职业资格认证
  CCF认证历年真题 满分代码
  CCF201312–模拟练习试题参考答案(C++)
  CCF201312–模拟练习试题参考答案(Java)
      
  程序员需要有精益求精的工匠精神,追求逻辑的极简、时间的最少和存储的最省,并且懂得其中的平衡。
  数据表示需要优先考虑,对于许多问题,找到表示该问题的数据结构,问题自然就解决了。
  希望获得100分,仅仅使用原题的样例来测试是不够的,需要自己设计一些样例,并且需要考虑特殊的边界条件。
  采用C/C++语言编程时,使用STL的包装类和算法是十分必要,这会简化程序逻辑。

以上是关于CCF-CSP真题《202212-3 JPEG 解码》思路+python,c++满分题解的主要内容,如果未能解决你的问题,请参考以下文章

CCF-CSP真题202206-归一化处理/寻宝大冒险

CCF-CSP真题《202209-3—防疫大数据》思路+python题解

201912-4 区块链CCF-CSP真题

CCF-CSP真题《202212-1 现值计算》思路+python,c++,c满分题解

解2022年408考研真题第1题

华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典