c 试水解码jpeg图片比特流

2023-12-23 08:30

本文主要是介绍c 试水解码jpeg图片比特流,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1c07421828194f0abd0b837d28bd185c.jpeg找到一张采用霍夫曼通用DC,AC编码表的图片,提取出此图片的比特流准备对它解码,再反推怎样编码。

下图是此图片比特流前100个字节。解码是每次读一字节,对这8比特解码,如8比特不能解码,再读入一字节。因为霍夫曼表最多是16比特位编码,意思是说超过16位比特还没有被解码就是错误的。当然不一定都是8比特,有时候是2比特等,这就涉及到比特的移位等操作。但操作单位是1字节8比特。

75a09a2e3d96400a96bb9e896184c227.jpeg

图1

上传此图片文件

下面是霍夫曼4张通用表;

cd389c8f03844d67a41b950187f2301c.jpeg

此图片帧全局(0xffc0)

ff ,c0 ,0 ,11 ,8 ,1 ,67 ,1 ,da ,3 ,1 ,22 ,0 ,2 ,11 ,1 ,3 ,11 ,1 ,

对全局头分析:

总长0x11=17位,8 代表采样精度是8位,1,67  是图片行数=1×256+0 x67=359行,1,da 代表图片列数:1x256+0xda=474,    3 代表图片的分量数:亮度Y,色度U,V 三个。

后9字节分为3组,每组3字节,第一组id为1(Y),第二为2(U),第三3(V),id号为第一字节,第3字节为每个分量采样的量化表id,第二个字节高4位代表水平采样个数,低4位垂直采样个数。

1,22,0    表示Y  在MCU中水平垂直隔有2个

2, 11 ,1   U 各一次

3, 11,  1         V 各一次 

意思就是说:此图片采样的是YUV 422 格式,有2个Y,1个U,1个V。

------------------------------------------------

此图片扫描头 SOS (0xffda)

ff ,da ,0 ,c ,3 ,1 ,0 ,2 ,11 ,3 ,11 ,0 ,3f ,0 ,

0,c:   扫描头长度 0×256+0xc=12 字节

 3: 3分量 ,Y,U,V

1,0,2,11,3,11  分位三组,每组2字节,第一个是id号

第二字节高4位是DC 号,低4位为AC 号

0 :代表Z排序是从0开始编号

3f: 0x3f=63   表示Z排序是63结束,最后一字节默认是0

有这些信息就可以解码了。

因为采用的是yuv422格式,那比特流开始就是2个Y,.紧跟1个U  ,1个V,组成一个MCU。比特流以此MCU格式为单位循环直到结束。

首先是亮度DC解码,马上是亮度AC解码,再是第二个亮度DC解码,再是第二个亮度AC解码。

现在在验证转换的方法是否正确:对,正确!现在解码出亮度DC=94,马上就是对亮度AC解码。

其实最简单粗暴的方法是把每一个比特位用一个char数组元素存储,这样就可连续读取。

特别要注意存入char数组时,读入的比特位是存储在数组的最高位。换一句话说,比特流是反序排列的,比如编码后是2字节,是先写入高字节,再写入低字节。8位二进制数是先读入高位,最后读入低位。
  下一步把另外3张表加入,完整解码看还遇到什么问题

已加入Y_AC  表,遇到0xff 0  报错

太绕了,还有各种判断要加,如0xff 0.     0.0

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>  
#include <string.h>
#include <sys/mman.h>
#include <linux/fb.h>
#include <math.h>int main(void) {
//	unsigned char dc0[28]={0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,0xa,0xb};char y_dc(unsigned char len,int bit ){   //亮度DCif((len==2)&&(bit==0b00)){return 0;	}	if((len==3)&&(bit==0b010)){return 1;}if((len==3)&&(bit==0b011)){return 2;}if((len==3)&&(bit==0b100)){return 3;}if((len==3)&&(bit==0b101)){return 4;}if((len==3)&&(bit==0b110)){return 5;}if((len==4)&&(bit==0b1110)){return 6;}if((len==5)&&(bit==0b11110)){return 7;}if((len==6)&&(bit==0b111110)){return 8;}if((len==7)&&(bit==0b1111110)){return 9;}if((len==8)&&(bit==0b11111110)){return 10;}if((len==9)&&(bit==0b111111110)){return 11;}else return -1;}//----------------------------------char ali(char len,char i){            //ALI   char o;if (len == 0) {o = 0;}if ((len == 1) && (i == 0)) {o = -1;}if ((len == 1) && (i == 1)) {o = 1;}//--------------------------if ((i >= pow(2, len - 1)) && (i <= pow(2, len))) {o = i;}if ((i >= 0) && (i < pow(2, len - 1))) {o = i - pow(2, len) + 1;}return o;}	//-------Y——AC-----------------​int  y_ac(unsigned char cd,unsigned int i,unsigned char out[2]){int bb=1;unsigned int i_bit=i;unsigned char i_len=cd;unsigned char len;unsigned char o;unsigned char  ws[16]={0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d};unsigned char zh[162]={0x1, 0x2, 0x3, 0x0, 0x4, 0x11, 0x5,0x12,0x21,0x31,0x41,0x6, 0x13,0x51,0x61,0x7,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08,0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28,0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf9,0xfa};unsigned char  cx_ws,cx_b;unsigned char hfm[17][0x7d]={};int t=0;for(int a=0;a<16;a++){             if(ws[a]==0){continue;}for(int b=0;b<ws[a];b++){hfm[a+1][b]=zh[t];t++;}}
//---------------------------------------cx_ws=i_len;int o_js=0;      if(cx_ws==2){o_js=0;cx_b=i_bit-o_js;}if(cx_ws==3){o_js=0b010;cx_b=i_bit-o_js;}if(cx_ws==4){o_js=0b0110;cx_b=i_bit-o_js;}if(cx_ws==5){o_js=0b10010;cx_b=i_bit-o_js;}if(cx_ws==6){o_js=0b101010;cx_b=i_bit-o_js;	}if(cx_ws==7){o_js=0b1011000;cx_b=i_bit-o_js;}if(cx_ws==8){o_js=0b10111000;cx_b=i_bit-o_js;}if(cx_ws==9){o_js=0b101110110;cx_b=i_bit-o_js;}if(cx_ws==10){o_js=0b1011110110;cx_b=i_bit-o_js;}if(cx_ws==11){o_js=0b10111110110;cx_b=i_bit-o_js;}if(cx_ws==12){o_js=0b101111110100;cx_b=i_bit-o_js;}if(cx_ws==15){o_js=0b101111111000000;cx_b=i_bit-o_js;}if(cx_ws==16){o_js=0b1011111110000010;cx_b=i_bit-o_js;}//-----------------------------------------unsigned char o_zj=hfm[cx_ws][cx_b];len=o_zj/16;o=o_zj%16;out[0]=len;out[1]=o;if(o_zj==0){    //没有bb=-1;}return bb;	}​//------------------------------------------------------------------unsigned char data[100]={0xf5,0xe6,0x24,0x4e,0xff,0,0x41,0xfd,0x68,0xde,0xde,0xb4,0xd6,0xff,0,0x8f,0x97,0xfa,0xf,0xeb};//    0xf5           ,  0xe6       ,    0x24//  1 1 1 1 0 1 0 1 ,1 1 1 0 0 1 1 0,0 0 1 0 0 1 0 0//11110   得到7,马上取7位 1011110=x   现在就可把7位加x,利用ALI 反退出真实的DC系数=94。    //思路:用一个25char 数组存储至多3字节的比特流,避免不能读完一个字节的比特流	
//--------一个字节的段位字------------------------------------typedef struct{unsigned char b1:1;unsigned char b2:1;unsigned char b3:1;unsigned char b4:1;unsigned char b5:1;unsigned char b6:1;unsigned char b7:1;unsigned char b8:1;}BIT;BIT bit;unsigned char z[25];     //一个程序单位int bz=24;               //bz是z的游标,bz=24,表示z为空,bz随写入data数据减少int jb=24;               //查询游标,jb随读入二进制位减少int dn=0;               //data[] 下标int o=0;                //输出位数int y=0;unsigned char yac_o[2]={};unsigned char n0=0;
while(1){while(1){//如果z 剩余位大于8,就写入1字节待转换datamemset(&bit,0,1);           memcpy(&bit,&data[dn],1);dn++;	if(bz>8){	           //z[25]写入的剩余空间必大于一字节,防止只写一字节的比特读不完整z[bz]=bit.b8;	       //把每个二进制位用一个char存储z[bz=bz-1]=bit.b7;	z[bz=bz-1]=bit.b6;		z[bz=bz-1]=bit.b5;	z[bz=bz-1]=bit.b4;	z[bz=bz-1]=bit.b3;		z[bz=bz-1]=bit.b2;z[bz=bz-1]=bit.b1;	bz=bz-1;}else{break;}}//----------------int a=0;for( a=2;a<17;a++){          //霍夫曼转换都是从2位开始,最多16位int ls=0;int b=0;for(b=0;b<a;b++){       //位数读取char ls=ls+z[jb-b]*(pow(2,(a-b-1)));   //把n个char 转换为2进制的a位二进制整数		}if(y==0){           //处理 Y_DCo=y_dc(a,ls);	if(o>=0){         //得到位数len,此位数是马上要从data[]读取的二进制位,此o位二进制的值假如是c,不用解码jb=jb-a;      // ali 利用len 和 c  推算出DC值//	y=1;          break;}}else{             //处理 Y_ACo=y_ac(a,ls,yac_o);if(o>=0){         //得到位数len,此位数是马上要从data[]读取的二进制位,此o位二进制的值假如是c,不用解码jb=jb-a;      // ali 利用len 和 c  推算出DC值break;}}}//--------------------
//	if(o>(jb-bz))  continue;
//-----读len 二进制 c-------------if(y==1){n0=yac_o[0];o=yac_o[1];}int ls=0;for(int b=0;b<o;b++){ls=ls+z[jb-b]*(pow(2,(o-b-1)));		}printf("n0:%d  o:%d\n",n0,ali(o,ls));   //94           比特流的第一个亮度DC=94y=1;
//-----bz ,jb 移位重置-:把z中未读的位重新移到最左边z[24]处int t=0;for(int a=24;a>jb-bz;a--){z[a]=z[jb-t];       //把z中未读的位重新移到最左边z[24]处t++;}bz=bz+(24-jb);   //第一轮未被解码剩下比特数jb=24;       //下一次又从最左开始处读// break;
}return 0;
}

虽然报错,也解出4对:

94,(9, 1),(0 ,-17),(0,3)

现在有点麻烦,不能验证这些数据是否正确。感觉不理想,咋DC过后是9个0。只有一个办法验证了,手算,把前几位data数据全部用二进制位表示后手算验证程序是否正确。如正确再往下进行。

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

这篇关于c 试水解码jpeg图片比特流的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/527371

相关文章

Python实现精准提取 PDF中的文本,表格与图片

《Python实现精准提取PDF中的文本,表格与图片》在实际的系统开发中,处理PDF文件不仅限于读取整页文本,还有提取文档中的表格数据,图片或特定区域的内容,下面我们来看看如何使用Python实... 目录安装 python 库提取 PDF 文本内容:获取整页文本与指定区域内容获取页面上的所有文本内容获取

Python基于微信OCR引擎实现高效图片文字识别

《Python基于微信OCR引擎实现高效图片文字识别》这篇文章主要为大家详细介绍了一款基于微信OCR引擎的图片文字识别桌面应用开发全过程,可以实现从图片拖拽识别到文字提取,感兴趣的小伙伴可以跟随小编一... 目录一、项目概述1.1 开发背景1.2 技术选型1.3 核心优势二、功能详解2.1 核心功能模块2.

Go语言如何判断两张图片的相似度

《Go语言如何判断两张图片的相似度》这篇文章主要为大家详细介绍了Go语言如何中实现判断两张图片的相似度的两种方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 在介绍技术细节前,我们先来看看图片对比在哪些场景下可以用得到:图片去重:自动删除重复图片,为存储空间"瘦身"。想象你是一个

使用Python实现base64字符串与图片互转的详细步骤

《使用Python实现base64字符串与图片互转的详细步骤》要将一个Base64编码的字符串转换为图片文件并保存下来,可以使用Python的base64模块来实现,这一过程包括解码Base64字符串... 目录1. 图片编码为 Base64 字符串2. Base64 字符串解码为图片文件3. 示例使用注意

c/c++的opencv实现图片膨胀

《c/c++的opencv实现图片膨胀》图像膨胀是形态学操作,通过结构元素扩张亮区填充孔洞、连接断开部分、加粗物体,OpenCV的cv::dilate函数实现该操作,本文就来介绍一下opencv图片... 目录什么是图像膨胀?结构元素 (KerChina编程nel)OpenCV 中的 cv::dilate() 函

使用Python实现调用API获取图片存储到本地的方法

《使用Python实现调用API获取图片存储到本地的方法》开发一个自动化工具,用于从JSON数据源中提取图像ID,通过调用指定API获取未经压缩的原始图像文件,并确保下载结果与Postman等工具直接... 目录使用python实现调用API获取图片存储到本地1、项目概述2、核心功能3、环境准备4、代码实现

Java实现图片淡入淡出效果

《Java实现图片淡入淡出效果》在现代图形用户界面和游戏开发中,**图片淡入淡出(FadeIn/Out)**是一种常见且实用的视觉过渡效果,它可以用于启动画面、场景切换、轮播图、提示框弹出等场景,通过... 目录1. 项目背景详细介绍2. 项目需求详细介绍2.1 功能需求2.2 非功能需求3. 相关技术详细

Java如何根据文件名前缀自动分组图片文件

《Java如何根据文件名前缀自动分组图片文件》一大堆文件(比如图片)堆在一个目录下,它们的命名规则遵循一定的格式,混在一起很难管理,所以本文小编就和大家介绍一下如何使用Java根据文件名前缀自动分组图... 目录需求背景分析思路实现代码输出结果知识扩展需求一大堆文件(比如图片)堆在一个目录下,它们的命名规

将图片导入Python的turtle库的详细过程

《将图片导入Python的turtle库的详细过程》在Python编程的世界里,turtle库以其简单易用、图形化交互的特点,深受初学者喜爱,随着项目的复杂度增加,仅仅依靠线条和颜色来绘制图形可能已经... 目录开篇引言正文剖析1. 理解基础:Turtle库的工作原理2. 图片格式与支持3. 实现步骤详解第

在React聊天应用中实现图片上传功能

《在React聊天应用中实现图片上传功能》在现代聊天应用中,除了文字和表情,图片分享也是一个重要的功能,本文将详细介绍如何在基于React的聊天应用中实现图片上传和预览功能,感兴趣的小伙伴跟着小编一起... 目录技术栈实现步骤1. 消息组件改造2. 图片预览组件3. 聊天输入组件改造功能特点使用说明注意事项