JPEG编码原理及文件格式及代码分析

2023-11-09

一 JPEG编码原理
首先我们先来看一下JPEG的编码原理图
在这里插入图片描述
如上图所示,下面进行逐步的分析:
1 RGB->YUV
首先为了降低互相的关联性,将RGB转换为YUV,这样就可以对亮度信号和色度信号进行分别的处理
在这里插入图片描述

2 零电平偏置下移
由于后面需要对图像进行DCT变换,如果不进行偏移,会使分量值过大,所以在这里采用偏置下移的方法,便于DCT变换量化后直流的系数大大降低,也就降低了数据量。
3 分块
JPEG标准在处理图片时会先把图片分割成一个个8x8像素的方块,源图像如果不是8x8的整数倍,需进行补充,后面的DCT、量化、熵编码都是针对单个方块的操作,编码的产物是这些方块的压缩数据。压缩数据经过解码还原成像素数据,然后将一个个方块拼成一整完整图片的像素数据显示。
4 DCT变换
对每一块进行DCT变化,目的是去除图像数据之间的相关性,便于量化过程去除图像数据的空间冗余。由于人眼对图片中的低频信息(色彩变化不明显,如图片的整体色调,物体轮廓)比较敏感,对高频信息不敏感(色彩变化剧烈,如物体的边缘、人脸上的小斑点),因此我们可以利用DCT变换把图片中高频和低频部分区分开来,然后将高频部分的数据进行压缩,这样就达到压缩图片的功能。
二维DCT变换公式如下所示
在这里插入图片描述
需要特别强调的是,DCT是一种无损变换,这样做的目的是在为下一步的量化做准备。
5 量化
所谓量化其实就是将频率/量化步长,将量化步长以内的精度信息丢失,JPEG算法提供了两张标准的量化系数矩阵,如下所示
在这里插入图片描述
可以看出越往左上角,值越小,因此这张量化表的作用就是屏蔽高频信息。
6 压缩
在这里直流分量与交流分量采用了不同的压缩方法。
对于直流分量来说,量化后每一块所得的数值比较大,但相邻块之间的差值比较小,这就很适合采用DPCM的压缩方式,在之前的博客中有较为详细的介绍,但DPCM之后还不够,还要进行霍夫曼编码,进行进一步的压缩
对于交流分量来说,每一块中剩余的交流分量都比较小,JPEG先用RLE(run-length encoding,游程编码)编码将图像数据以“之字形”排列,如下图,这样可以尽可能的将频率为0的数据存储在一起。连续N个0,可以用一个0和一个长度N来表示,压缩效果很好,然后将剩下的位置使用霍夫曼编码。
在这里插入图片描述
在这里说一句,JPEG的解码就是将其编码过程倒过来,进行一步一步的还原,在这里就不细说了。
二 JPEG文件格式
JPEG文件由一系列字段组成,每个字段都有marker(标记),由0xff开头。接下来对每一个字段进行简要的说明
1 SOI
这个字段定义了文件的起始标记,标记为FFD8。
2 APP0
Application,应用程序保留标记0,标志FFE0,包含一定信息
① 数据长度 2字节 ①~⑨9个字段的总长度
即不包括标记代码,但包括本字段
② 标识符 5字节 固定值0x4A46494600,即字符串“JFIF0”
③ 版本号 2字节 一般是0x0102,表示JFIF的版本号1.2
可能会有其他数值代表其他版本
④ X和Y的密度单位 1字节 只有三个值可选
0:无单位;1:点数/英寸;2:点数/厘米
⑤ X方向像素密度 2字节 取值范围未知
⑥ Y方向像素密度 2字节 取值范围未知
⑦ 缩略图水平像素数目 1字节 取值范围未知
⑧ 缩略图垂直像素数目 1字节 取值范围未知
⑨ 缩略图RGB位图 长度可能是3的倍数 缩略图RGB位图数据
3 DQT
也就是量化表,JPEG文件一般有2个DQT段,为Y值(亮度)定义1个, 为UV值(色度)定义1个。每张量化表都由FFDB开始,量化表中的第一个字节被分成了高四位和低四位来用。高四位表示了该量化表的精度,0:8位;1:16位;低四位表示了量化表ID,取值范围为0~3;接下来是所有的表项,数量为(64×(精度+1))字节,里面都是量化的系数。量化表中的数据按照Z字形保存量化表内8x8的数据
4 SOF0
标志位FFC0,包含图像基本信息
段标识 1 FF
段类型 1 C0
段长度 2 其值=8+组件数量×3
  (以下为段内容)
样本精度 1 8 每个样本位数(大多数软件不支持12和16)
图片高度 2
图片宽度 2
组件数量 1 3 1=灰度图,3=YCbCr/YIQ 彩色图,4=CMYK 彩色图
  (以下每个组件占用3字节)
组件 ID 1 1=Y, 2=Cb, 3=Cr, 4=I, 5=Q
采样系数 1 0-3位:垂直采样系数
4-7位:水平采样系数
量化表号 1
5 DHT
标志位FFC4,存放哈夫曼表,JPEG文件里有2类Haffman 表:一类用于DC(直流量),一类用于AC(交流量)。一般有4个表:亮度的DC和AC,色度的DC和AC。最多可有6个。该Marker以FFC4作为开始标记。然后是字段长度,类型(AC/DC),索引(Index),位表(bit table),值表(value table)。
6 SOS
扫描行开始,标志位FFDA,表明了字段的长度,然后说明了颜色分量数,该与SOF字段中的数据应该是保持一致的。然后针对于每一个颜色分量信息,给出了每个分量的DC/AC使用的哈夫曼表编号。
三 代码解读
本次实验主要做到了JPG文件转换为YUV文件,并且输出了量化系数以及霍夫曼码表。
首先先来看一下如何写入YUV文件,原先的代码为分别生成.Y .U .V文件,其实只需要将这三个写入的数据按照YUV的顺序写入YUV文件即可,具体代码如下所示

static void write_yuv(const char *filename, int width, int height, unsigned char **components)
{
  FILE *F;
  char temp[1024];

  snprintf(temp, 1024, "%s.Y", filename);
  F = fopen(temp, "wb");
  fwrite(components[0], width, height, F);
  fclose(F);
  snprintf(temp, 1024, "%s.U", filename);
  F = fopen(temp, "wb");
  fwrite(components[1], width*height/4, 1, F);
  fclose(F);
  snprintf(temp, 1024, "%s.V", filename);
  F = fopen(temp, "wb");
  fwrite(components[2], width*height/4, 1, F);
  fclose(F);
  snprintf(temp, 1024, "%s.YUV", filename);
  F = fopen(temp, "wb");
  fwrite(components[0], width, height, F);
  fwrite(components[1], width * height / 4, 1, F);
  fwrite(components[2], width * height / 4, 1, F);
  fclose(F);
}

结果如下所示
原图像为
在这里插入图片描述
生成的YUV图像为
在这里插入图片描述

最主要的是观看量化系数的步骤,首先先来看一下主函数中调用的convert_one_image函数

int convert_one_image(const char *infilename, const char *outfilename, int output_format)
{
  FILE *fp;
  unsigned int length_of_file;
  unsigned int width, height;
  unsigned char *buf;
  struct jdec_private *jdec;
  unsigned char *components[3];

  /* Load the Jpeg into memory */
  fp = fopen(infilename, "rb");
  if (fp == NULL)
    exitmessage("Cannot open filename\n");
  length_of_file = filesize(fp);
  buf = (unsigned char *)malloc(length_of_file + 4);
  if (buf == NULL)
    exitmessage("Not enough memory for loading file\n");
  fread(buf, length_of_file, 1, fp);
  fclose(fp);

  /* Decompress it */
  jdec = tinyjpeg_init();
  if (jdec == NULL)
    exitmessage("Not enough memory to alloc the structure need for decompressing\n");

  if (tinyjpeg_parse_header(jdec, buf, length_of_file)<0)
    exitmessage(tinyjpeg_get_errorstring(jdec));

  /* Get the size of the image */
  tinyjpeg_get_size(jdec, &width, &height);

  snprintf(error_string, sizeof(error_string),"Decoding JPEG image...\n");
  if (tinyjpeg_decode(jdec, output_format) < 0)
    exitmessage(tinyjpeg_get_errorstring(jdec));

  /* 
   * Get address for each plane (not only max 3 planes is supported), and
   * depending of the output mode, only some components will be filled 
   * RGB: 1 plane, YUV420P: 3 planes, GREY: 1 plane
   */
  tinyjpeg_get_components(jdec, components);

  /* Save it */
  switch (output_format)
   {
    case TINYJPEG_FMT_RGB24:
    case TINYJPEG_FMT_BGR24:
      write_tga(outfilename, output_format, width, height, components);
      break;
    case TINYJPEG_FMT_YUV420P:
      write_yuv(outfilename, width, height, components);
      break;
    case TINYJPEG_FMT_GREY:
      write_pgm(outfilename, width, height, components);
      break;
   }

  /* Only called this if the buffers were allocated by tinyjpeg_decode() */
  tinyjpeg_free(jdec);
  /* else called just free(jdec); */

  free(buf);
  return 0;
}

首先先读取了文件的全部信息,并用指针完成了存储,而后进行文件内容的详细读取,tinyjpeg_parse_header函数完成了对文件头部分的读取,量化表就在其中,现在让我们看看这个函数

int tinyjpeg_parse_header(struct jdec_private *priv, const unsigned char *buf, unsigned int size)
{
  int ret;

  /* Identify the file */
  if ((buf[0] != 0xFF) || (buf[1] != SOI))
    snprintf(error_string, sizeof(error_string),"Not a JPG file ?\n");

  priv->stream_begin = buf+2;
  priv->stream_length = size-2;
  priv->stream_end = priv->stream_begin + priv->stream_length;

  ret = parse_JFIF(priv, priv->stream_begin);

  return ret;
}

在这里先进行了文件格式的判断,而后开始读取里面的内容,进入parse_JFIF函数

static int parse_JFIF(struct jdec_private *priv, const unsigned char *stream)
{
  int chuck_len;
  int marker;
  int sos_marker_found = 0;
  int dht_marker_found = 0;
  const unsigned char *next_chunck;

  /* Parse marker */
  while (!sos_marker_found)
   {
     if (*stream++ != 0xff)
       goto bogus_jpeg_format;
     /* Skip any padding ff byte (this is normal) */
     while (*stream == 0xff)
       stream++;

     marker = *stream++;
     chuck_len = be16_to_cpu(stream);
     next_chunck = stream + chuck_len;
     switch (marker)
      {
       case SOF:
	 if (parse_SOF(priv, stream) < 0)
	   return -1;
	 break;
       case DQT:
	 if (parse_DQT(priv, stream) < 0)
	   return -1;
	 break;
       case SOS:
	 if (parse_SOS(priv, stream) < 0)
	   return -1;
	 sos_marker_found = 1;
	 break;
       case DHT:
	 if (parse_DHT(priv, stream) < 0)
	   return -1;
	 dht_marker_found = 1;
	 break;
       case DRI:
	 if (parse_DRI(priv, stream) < 0)
	   return -1;
	 break;
       default:
#if TRACE
	fprintf(p_trace,"> Unknown marker %2.2x\n", marker);
	fflush(p_trace);
#endif
	 break;
      }

     stream = next_chunck;
   }

  if (!dht_marker_found) {
#if TRACE
	  fprintf(p_trace,"No Huffman table loaded, using the default one\n");
	  fflush(p_trace);
#endif
    build_default_huffman_tables(priv);
  }

#ifdef SANITY_CHECK
  if (   (priv->component_infos[cY].Hfactor < priv->component_infos[cCb].Hfactor)
      || (priv->component_infos[cY].Hfactor < priv->component_infos[cCr].Hfactor))
    snprintf(error_string, sizeof(error_string),"Horizontal sampling factor for Y should be greater than horitontal sampling factor for Cb or Cr\n");
  if (   (priv->component_infos[cY].Vfactor < priv->component_infos[cCb].Vfactor)
      || (priv->component_infos[cY].Vfactor < priv->component_infos[cCr].Vfactor))
    snprintf(error_string, sizeof(error_string),"Vertical sampling factor for Y should be greater than vertical sampling factor for Cb or Cr\n");
  if (   (priv->component_infos[cCb].Hfactor!=1) 
      || (priv->component_infos[cCr].Hfactor!=1)
      || (priv->component_infos[cCb].Vfactor!=1)
      || (priv->component_infos[cCr].Vfactor!=1))
    snprintf(error_string, sizeof(error_string),"Sampling other than 1x1 for Cr and Cb is not supported");
#endif

  return 0;
bogus_jpeg_format:
#if TRACE
  fprintf(p_trace,"Bogus jpeg format\n");
  fflush(p_trace);
#endif
  return -1;
}

由上述代码可知,过程中不断读取标志位进行判断,判断结束后进行不同函数的操作,我们在这里要找量化系数,所以重点看DQT部分,也就是parse_DQT(priv, stream)这个函数

static int parse_DQT(struct jdec_private *priv, const unsigned char *stream)
{
  int qi;
  float *table;
  const unsigned char *dqt_block_end;
#if TRACE
  fprintf(p_trace,"> DQT marker\n");
  fflush(p_trace);
#endif
  dqt_block_end = stream + be16_to_cpu(stream);
  stream += 2;	/* Skip length */

  while (stream < dqt_block_end)
   {
     qi = *stream++;
#if SANITY_CHECK
     if (qi>>4)
       snprintf(error_string, sizeof(error_string),"16 bits quantization table is not supported\n");
     if (qi>4)
       snprintf(error_string, sizeof(error_string),"No more 4 quantization table is supported (got %d)\n", qi);
#endif
     table = priv->Q_tables[qi];
     build_quantization_table(table, stream);
     stream += 64;
   }
#if TRACE
  fprintf(p_trace,"< DQT marker\n");
  fflush(p_trace);
#endif
  return 0;
}

进入函数内部的build_quantization_table(table, stream),这里存放着文件信息中的量化系数

static void build_quantization_table(float *qtable, const unsigned char *ref_table)
{
  /* Taken from libjpeg. Copyright Independent JPEG Group's LLM idct.
   * For float AA&N IDCT method, divisors are equal to quantization
   * coefficients scaled by scalefactor[row]*scalefactor[col], where
   *   scalefactor[0] = 1
   *   scalefactor[k] = cos(k*PI/16) * sqrt(2)    for k=1..7
   * We apply a further scale factor of 8.
   * What's actually stored is 1/divisor so that the inner loop can
   * use a multiplication rather than a division.
   */
  int i, j;
  static const double aanscalefactor[8] = {
     1.0, 1.387039845, 1.306562965, 1.175875602,
     1.0, 0.785694958, 0.541196100, 0.275899379
  };
  const unsigned char *zz = zigzag;

  for (i=0; i<8; i++) {
     for (j=0; j<8; j++) {
         fprintf(p_trace, "%-6d", ref_table[*zz]);
         *qtable++ = ref_table[*zz++] * aanscalefactor[i] * aanscalefactor[j];
       
       if (j == 7) {
           fprintf(p_trace, "\n");
       }

     }
   }


}

不难看出这在进行量化的逆操作,也就是用量化系数乘以量化矩阵,得出原始值,所以ref_table[*zz]即为量化矩阵,将其输出到TXT文件中,输出结果如图所示
在这里插入图片描述
而后输出霍夫曼码表,程序中对应代码为
快捷键目录标题文本样式列表链接代码片表格注脚注释自定义列表LaTeX 数学公式插入甘特图插入UML图插入Mermaid流程图插入Flowchart流程图插入类图
代码片复制

下面展示一些 内联代码片

#if TRACE
     fprintf(p_trace,"val=%2.2x code=%8.8x codesize=%2.2d\n", val, code, code_size);
	 fflush(p_trace);
    #endif

存放在build_huffman_table函数中,结果如下图所示
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JPEG编码原理及文件格式及代码分析 的相关文章

  • 浅谈斜率优化

    DP模型 形如 f i max f j w i j quad 1 le j
  • PHP的弱类型比较

    php弱类型比较 php中其中两种比较符号 先将字符串类型转化成相同 再比较 先判断两种字符串的类型是否相等 再比较 前者为弱比较 后者为弱比较 若在某种情况下不注意利用会导致漏洞的出现 例子 攻防世界lottery 进入页面 浏览后查看
  • android studio常用快捷键设置

    android开发工具androidstudio的熟练使用是提高我们开发效率的必备条件 现对android studio使用过程中的一些小技巧进行总结 1 命名规范 android开发过程中使用java语言 对变量的命名遵循驼峰命名法 一般
  • Tracy JS 小笔记 - 数据类型, typeof,类型转换

    数据类型 原始值 引用值 原始值 不可改变的原始值 是存储在栈里面 stack 是个有底儿的箱子结构先进后出 原始值 分为五大类 Number Boolean String undefined null var a 1 我们数据的类型天生就
  • Apache Pig的一些基础概念及用法总结4(转)

    26 错误 ERROR org apache pig tools grunt Grunt ERROR 2042 Error in new logical plan Try Dpig usenewlogicalplan false 的可能原因
  • decltype和declval的用法

    1 decltype是c 11以后出现的一个新的关键字 是用来萃取表达式或者变量或者函数返回值的类型的 具体用法可以参考官网 https en cppreference com w cpp language decltype 2 declv
  • 华为-人民币转换

    java实现 题目描述 考试题目和要点 1 中文大写金额数字前应标明 人民币 字样 中文大写金额数字应用壹 贰 叁 肆 伍 陆 柒 捌 玖 拾 佰 仟 万 亿 元 角 分 零 整等字样填写 2 中文大写金额数字到 元 为止的 在 元 之后
  • xss基础知识点

    xss 1 概念 跨站脚本攻击 英文全称Cross Site Script xss攻击 通常指黑客通过 HTML注入 篡改了网页 插入了恶意的脚本 从而在用户浏览网页时 控制用户浏览器的一种攻击 常见场景 标签内的xss Xss 属性里面的
  • 安装Flutter + Android sdk + vs code运行Flutter项目(史上最详解)

    前言 Flutter开发app是基于Dart语言开发的 就好比html网页开发基于JavaScript一样 而浏览器内核都可以编译JavaScript代码 所有开发html网页不需要下载啥SDK 直接在浏览器就能运行 首先我们安装Dart语
  • python 用for i in range(10)生成列表

    这种方法叫列表解析 1 列出1 10的平方和 结果用列表存储 要求 列出1 10所有数字的平方 1 普通方法 L for i in range 1 11 L append i 2 print L 1 4 9 16 25 36 49 64 8
  • 如何实现通用分页(来看我这一篇就够了超级详细内含源码!!!)

    目录 一 页面显示分页效果 1 1分析页面展示所要展示的属性有哪些 1 2分析页面有哪些每次发送请求有哪些公共的参数 二 具体实现前端通用分页 2 1分析思路 2 2具体实现的过程 2 2 1标签助手类 2 2 2创建标签库描述文件 tld
  • QTableView获取选中行指定列的内容(新手上路)

    1 第一次用QT写东西 在tableview对象后面的函数列表里翻来翻去 找了个看起来顺眼的selectedRows来试图获取选中行的内容 然后插入到list里面 QList
  • TQ2440移植u-boot2016.11全过程记录-【5】设置从NOR FLASH启动U-BOOT

    TQ2440移植u boot2016 11 设置从NOR FLASH启动u boot gedit include configs tq2440 h 屏蔽掉宏CONFIG SKIP LOWLEVEL INIT 修改宏CONFIG SYS TE
  • ModelArts平台部署模型

    相关步骤 构建镜像 上传镜像至swr服务 模型管理建立模型 部署模型上线 调用接口 1 构建自定义镜像 基于Dockfile文件构建 文件准备及文件结构 关于深度学习中的概念 训练 train 以图像识别为例 基于一个标注好的数据集训练好了
  • React-基础语法

    React 基础语法 React 搭建脚手架 安装node JS 安装React脚手架 创建项目 运行项目 其他命令 使用VSCode 安装插件 基础插件 文档目录结构 根组件App js 解析 组件解析 类组件 有状态组件 函数组件 JS
  • 软件测试项目案例哪里找?【银行/教育/商城/金融/等等....】

    项目一 ShopNC商城 项目概况 ShopNC商城是一个电子商务B2C电商平台系统 功能强大 安全便捷 适合企业及个人快速构建个性化网上商城 包含PC IOS客户端 Adroid客户端 微商城 系统PC 后台是基于ThinkPHP MVC
  • ### Paper about Event Detection

    Paper about Event Detection author gr date 2014 03 15 email forgerui gmail com 看一些相关的论文 1 Efficient Visual Event Detecti
  • 【动态规划】最少按多少下开关使灯全亮

    文章目录 无环条件下 题目描述 解题思路 递归版本 迭代版本 有环状态下 题目描述 解题思路 递归版本 迭代版本 无环条件下 题目描述 给定一个数组arr 长度为N arr中的值不是0就是1 arr i 表示第i栈灯的状态 0代表灭灯 1代
  • 介绍:教育研究:定量,定性和混合方法——伯克约翰逊,拉里克里斯滕森著

    www sagepub com bjohnson4e 章节资源的网站
  • 【图形学】GAMES101 Assignment3 作业框架分析

    GAMES101 Assignment3 作业框架分析 文章目录 GAMES101 Assignment3 作业框架分析 rasterizer draw rasterizer rasterize triangle 参考 写作业之前看了一眼代

随机推荐

  • java 多线程学习笔记之 线程互斥

    许多线程共享同一数据 这种情况在现实的生活中也是经常发生的 比如火车站的火车票售票系统 火车票售票系统是一个常年运行的系统 为了满足乘客的需求 我们不能只设一个窗口 必须设很多的售票窗口 每个售票窗口就像一个线程 它们各自运行 共同访问相同
  • GateWay 服务网关

    介绍 Cloud全家桶中有个很重要的组件就是网关 在1 x版本中都是采用的Zuul网关 但在2 x版本中 zuul的升级一直跳票 SpringCloud最后自己研发了一个网关替代Zuul 那就是SpringCloud Gateway Gat
  • 2023年kali linux安装中文输入法

    apt get install fcitx 安装输入法框架 apt get install fcitx googlepinyin 安装谷歌输入法 reboot 重启系统 重启之后右上有个小键盘点击里面的配置 添加google输入法 把Goo
  • vue2.6 Ag-grid 使用

    中文文档 ag grid中文教程 itxst com 一 HTML 结构
  • E3-1230和E3-1230 V2有多神?

    最近追E3 1230 枪E3 1230的人那叫一个多啊 都被捧成神了 我也来说说对E3 1230的看法 同档次的装机方案 我更倾向i5 2320 2500K 3570K 首 先比较两个U的规格吧 E3 1230的主频是3 2G 比i7 26
  • NVIDIA APEX安装完全指南及Megatron-LM/Pytorch运行问题解决(fused_layer_norm_cuda/packaging/amp_C/libc10.so)

    1 问题列表 在Megatron LM Pytorch运行中报错如下 No module named fused layer norm cuda apex没有装或者装的不对 注意直接用pip install apex装的不是真正的nvdia
  • 常用JS验证

    常用JS验证 共通JS Ver Date Author Comment 1 00 2016 04 25 马 新規作成 function replaceAll strvalue strRepBy strRepWith while strval
  • 从 Java 到 Go:实现一个投票和民意调查系统

    在本篇博客中 我们将探讨如何使用 Go 语言实现一个投票和民意调查系统 并从 Java 开发者的角度分析 Go 语言的特点和优势 在阅读本文之前 我们假设您已经具备一定的 Java 编程基础 文章将通过具体的代码示例 帮助您更轻松地从 Ja
  • windows下的命令行工具babun

    什么是babun babun是windows上的一个第三方shell 在这个shell上面你可以使用几乎所有linux unix上面的命令 他几乎可以取代windows的shell 用官方的题目说就是A Windows shell you
  • Linux中部署Spring Cloud项目

    Linux中部署Spring Cloud项目 文章为本人在学习的过程中 记录部署过程 仅供参考学习 因本人经验不足 教程或有不妥之处 还望指正 保姆级教程 敬请食用 简介 在学习过程中 部署时使用的项目是一个个人学习项目 若您喜欢 也可点击
  • Linux-压缩命令

    目录 1 tar 1 1 压缩 tar gz tar bz2 tgz 1 2 解压缩 tar gz tar bz2 tgz 2 zip 2 1 压缩 zip 2 2 解压缩 zip 3 rar 3 1 压缩 rar 3 2 解压缩 rar
  • 强大性能分析工具JVisualVM

    JVisualVM是由Sun提供的性能分析工具 如此强大的后盾怎能不强大 在Jdk6 0以后的版本中是自带的 配置好环境变量然后在运行中输入 JVisualVm 或直接到Jdk的安装目录的Bin目录下找到运行程序即可运行 如果是用Jdk1
  • 静态测试 动态测试 白盒测试的优缺点

    静态分析是一种不通过执行程序而进行测试的技术 静态分析的关键功能是检查软件的表示和描述是否一致 没有冲突或者没有歧义 动态分析的主要特点是当软件系统在模拟的或真实的环境中执行之前 之中和之后 对软件系统行为的分析 动态分析包含了程序在受控的
  • C语言 字母大小互相转换 三种思路

    1 利用ASCII值方法 大小写相差32 方法 1 include
  • maven在Win10的安装和配置

    1 下载和安装maven 一 下载Maven并解压 1 Maven官网下载地址 http maven apache org download cgi 2 下载后解压 将Maven的压缩包解压到 E Java apache maven 3 6
  • 【Unity2D入门教程】简单制作一个弹珠游戏之制作场景①(开场,结束,板子,球)

    学习目标 看过我前面的文章应该知道怎么制作开头和结尾 这里我简单把效果给大伙看一下 我用的游戏分辨率是4 3 因此我们要改变Canvas的的Cavans Scale为X1440 Y1080 结束的场景也一样 接着我们编写一个脚本来管理场景的
  • 基于人工势场算法机器人避障路径规划

    基于人工势场算法机器人避障路径规划 人工势场算法是一种热门的机器人路径规划算法 其通过建立虚拟的 势场 使得机器人在避障时能够像物理学中的粒子一样受到 势 的作用 最终实现自主导航 本文将介绍如何使用 MATLAB 实现基于人工势场算法的机
  • mac中的IDEA的使用快捷键

    1 command F 在当前文件进行文本查找 2 command shift F 进行工程和模块中的文件搜索 3 command u 找到这个方法的接口 4 command option commad 找到这个接口的实现类 5 comma
  • javascript中做减法时,出现小数位增加bug

    这个bug是js固有的 浮点数精度不准 你可以用下面方法来解决 思路是先放大 求和 差 积等运算后再缩小 如 加法函数 用来得到精确的加法结果 说明 javascript的加法结果会有误差 在两个浮点数相加的时候会比较明显 这个函数返回较为
  • JPEG编码原理及文件格式及代码分析

    一 JPEG编码原理 首先我们先来看一下JPEG的编码原理图 如上图所示 下面进行逐步的分析 1 RGB gt YUV 首先为了降低互相的关联性 将RGB转换为YUV 这样就可以对亮度信号和色度信号进行分别的处理 2 零电平偏置下移 由于后