最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C語言實(shí)現(xiàn)YUV文件轉(zhuǎn)JPEG格式

 更新時(shí)間:2023年12月13日 09:35:58   作者:樂山勁松  
這篇文章主要為大家詳細(xì)介紹了如何利用C語言實(shí)現(xiàn)將YUV文件轉(zhuǎn)為JPEG格式,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

先取yuv 文件中一個(gè)16×8的塊,跑通全流程

理解與思路:

1.塊分割

YUV 文件分為:YUV444   YUV 422   YUV420。444:就是:12個(gè)char 有4個(gè)Y,4個(gè)U,4個(gè)    U,422:8個(gè)char  中有4個(gè)Y ,U,V各兩個(gè),420:意思就是8char里有6個(gè)Y,1個(gè)U,1個(gè)V。444與422  中的三分量多是交錯(cuò)存儲(chǔ)的,420則是先存儲(chǔ)Y,再存儲(chǔ)U,V。

YUV存儲(chǔ)也是線型存儲(chǔ)的,不是平面塊存儲(chǔ)的。

對(duì)應(yīng)到j(luò)peg,也要按YUV的三種格式分別分塊。jpeg協(xié)議中有一概念MCU:最小編碼塊。jpeg就是按MCU 為單位循環(huán)存儲(chǔ)的。MCU中又有若干8×8 的block。這些block  就是Y  ,U ,V  分量的8×8  塊。

我理解:對(duì)應(yīng)YUV444,  一行內(nèi)取24字節(jié)(這是指水平行,程序處理同時(shí)要取8個(gè)水平行,意思MCU=8×24字節(jié))。含有Y,U,V各8個(gè)字節(jié)。也就是說:程序一次讀取8行24個(gè)char ,處理成3張8×8的表,直到讀完整個(gè)yuv文件

YUV422:一行 8個(gè)char中有4個(gè)Y,UV各2個(gè)。必須把Y湊成8那就要乘2。那就是一行為16個(gè)字節(jié),MCU=16×8,取8行生成一張8×8的Y,UV 各半張,UV要補(bǔ)0成為8×8。

YUV420:一行8個(gè)字節(jié)中有6個(gè)Y,UV各一個(gè),Y×8成為8的倍數(shù)水平要取64字節(jié),所以,MCU=8×8×8,意思就是有6張Y表,UV 各一張。

2.量化

Jpeg幾乎對(duì)Y分量不壓縮處理,只壓縮UV彩色分量。把幾個(gè)Y拼在一起余弦處理因?yàn)橛嘞肄D(zhuǎn)化是沒有損失的,也不會(huì)讓數(shù)據(jù)失真。真正讓數(shù)據(jù)失真是量化這個(gè)環(huán)節(jié),如果量化表全為1,則是無損量化。

下面的程序?yàn)榻栌贸善穲D片的量化表。

3. Z形排序

采用查表法,先按Z順序生成一個(gè)表,讀數(shù)時(shí)按表的數(shù)值作為讀取位置。

#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>  //v4l2 頭文件
#include <string.h>
#include <sys/mman.h>
#include <linux/fb.h>
#include <math.h>
#define PI 3.1415926
 
 
#define  pic_width   1280     //1280*720  640*360  960*540   320*240   424*240  848*480 640*480
#define  pic_heigth  720
 
 
#define filename  "/home/wzpc/Pictures/my.yuv"
#define file1  "/home/wzpc/Pictures/my.jpg"        //借用成品圖片的量化表
//int fdct(char (*i)[8], char (*o)[8] );
 
int  main(void) {
//-----------FDCT()函數(shù)------------------------------------
	int fdct(char (*i)[8], char (*o)[8] ) {  //i 為輸入   o 為參數(shù)傳入的輸出轉(zhuǎn)換后的數(shù)據(jù)
		
		
		double s;
		double au;
		double av;
		
		for (int u = 0; u < 8; u++) {
			for (int v = 0; v < 8; v++) {
				for (int y = 0; y < 8; y++) {
					for (int x = 0; x < 8; x++) {
						s = s + (1.0 / 4) * i[y][x] * cos((2 * y + 1) * u * PI / 16) * cos((2 * x + 1) * v * PI / 16);
					}
				}
				
				if (u == 0) {
					au = 1.0 / sqrt(2);
				} else {
					au = 1.0;
				}
				if (v == 0) {
					av = 1.0 / sqrt(2);
				} else {
					av = 1.0;
				}
				
				s = s * au * av;   //-30.1856
				int s1 = round(s * 100); //-3019
				s = s1 / 100.0;    //-30.19
				o[u][v] = s;       //double 轉(zhuǎn)為char 類型
				s = 0;
			}
		}
		
		return 0;
	}	
//--------Z 排序--------------------------------
	
int zz(char (*i1)[8],char o1[64]){
    int zb[64]={0,8,1,2,9,16,24,17,10,3,4,11,18,25,32,40,33,26,19,12,5,6,13,20,27,34,41,48,56,
            49,42,35,28,21,14,7,15,22,29,36,43,50,57,58,51,44,37,30,23,31,38,45,52,59,60,
	        53,46,39,47,54,61,62,55,63
             };
	char *p1=(char *)i1;
	for(int a=0;a<64;a++){
		int c=zb[a];
		o1[a]=p1[c];
 
}	
	
	return 0;
}
// -----量化函數(shù)---------------
int lh(char (*i)[8],char (*lhb)[8], char (*o)[8]){
	for(int a=0;a<8;a++){
		for(int b=0;b<8;b++){
			o[a][b]=round((i[a][b])/(lhb[a][b]));
		}
	}
	
	return 0;
}
 
 
	FILE *f1 = fopen(file1, "rb");  //如用mmap 必須以讀寫方式打開文件
	if (f1 == NULL) {
		puts("filename error");
		exit(-1);
	}
	fseek(f1, 0, SEEK_END);
	int len1 = ftell(f1);
	fseek(f1, 0, SEEK_SET);
	
	int fd1 = fileno(f1);
	unsigned char *mp1 = mmap(NULL, len1, PROT_READ, MAP_SHARED, fd1, 0); //必須要讀,寫
//---------讀量化表-------------------------------
	char lh00[64]={};                   //提取量化表
	char lh10[64]={};
	for(int a=0;a<len1;a++){
		if((mp1[a]==0xff)&&(mp1[a+1]==0xdb)&&(mp1[a+2]==0)){
			for(int b=0;b<65;b++){
				
				if(mp1[a+b+4]==0){
					memcpy(lh00,&(mp1[a+b+5]),64);
				}
				if(mp1[a+b+4]==1){
					memcpy(lh10,&(mp1[a+b+5]),64);
				}
			}
			printf("\n");
			
		}
	}
	for(int a=0;a<64;a++){
//		printf("%d  ,",lh00[a]);
	}
	printf("\n");
//---------------------------------------------------------------------------
	FILE *f = fopen(filename, "rb");  //如用mmap 必須以讀寫方式打開文件
	if (f == NULL) {
		puts("filename error");
		exit(-1);
	}
	fseek(f, 0, SEEK_END);
	int len_file = ftell(f);
	fseek(f, 0, SEEK_SET);
	
	int fd = fileno(f);
	unsigned char *mp = mmap(NULL, len_file, PROT_READ, MAP_SHARED, fd, 0); //必須要讀,寫
	
	int width_pic = 1280;
	int heigth_pic = 720;
	
	//out:1.文件總長度 len_file
	// 2.圖片寬度 1280  width_pic
	// 3.圖片高度 720   heigth_pic
	// 4.圖片數(shù)據(jù) *mp
	//--------------------------------------------------------
	//因?yàn)閥uv422數(shù)據(jù)是4個(gè)字節(jié)生成2個(gè)像素點(diǎn),所以圖片的width*heigth*2=len_file
	//攝像頭輸出的分辨率圖片寬度×2都是8的倍數(shù),高度X2也是8的倍數(shù)。所以yuv數(shù)據(jù)都不用補(bǔ)列。最多補(bǔ)文件末尾的空字節(jié)
	//攝像頭的分辨率末尾數(shù)X2=0,8,6,4,2,就是8的倍數(shù)
	
	// 1.----------檢查yuv文件長度末尾是否有空字節(jié),有,補(bǔ)0-------------------
	if ((width_pic * heigth_pic * 2) != len_file) {
		memset(&mp[len_file], 0, (width_pic * heigth_pic * 2 - len_file));
	}
	
	
	// 2.----------取16*8--------------------------------------
	//YUV422 字節(jié)排列:[0]=Y0 [1]=U0 [2]=Y1 [3]=V0 [4]=Y2 [5]=U1 [6]=Y3 [7]=V1    4個(gè)Y  2個(gè)U  2個(gè)V
	//所以取16個(gè)字節(jié)的yuv 數(shù)據(jù),含8個(gè)y ,4個(gè)u,4個(gè)v
	
	unsigned char (*i_mp)[width_pic] = (unsigned char (*)[width_pic])mp;
	
	
	
	int m = 0;     //  行  取1個(gè)(0,0)開始的16×8 塊
	int n = 0;     //列
	int heigth = heigth_pic;   //行
	int width = width_pic;     //列
	int fheigth = 8;
	int fwidth = 16;
	
	unsigned char o[8][16] = {};    //取出16×8的塊
	
	if ((m + fheigth) > heigth) {
		puts("fheigth error");
		exit(-1);
	}
	if ((n + fwidth) > width) {
		puts("fwidth error");
		exit(-1);
	}
	for (int a = 0; a < fheigth; a++) {
		for (int b = 0; b < fwidth; b++) {
			o[a][b] = i_mp[a + m][b + n];
		}
	}
	
	munmap(mp, len_file);
//----------分離Y---------------------
	char y[8][8] = {};
	for (int a = 0; a < 8; a++) {
		for (int b = 0; b < 8; b++) {
			y[a][b] = o[a][2 * b] - 128;
		}
	}
	
	
	//----------分離U-----------------
	char u[8][8] = {};
	memset(&u, 0, 64);               //補(bǔ)0
	for (int a = 0; a < 8; a++) {
		for (int b = 0; b < 8; b++) {
			if ((4 * b + 1) <= 16) {
				u[a][b] = o[a][4 * b + 1] - 128;
			}
		}
	}
	//-----------分離v-----------------
	char v[8][8] = {};
	memset(&v, 0, 64);                 //補(bǔ)0
	for (int a = 0; a < 8; a++) {
		for (int b = 0; b < 8; b++) {
			if ((4 * b + 3) <= 16) {
				v[a][b] = o[a][4 * b + 3] - 128;
			}
		}
	}
	
	
	
//--------------FDCY Y- U  V----------------------------
	char y_fdct[8][8] = {};
	fdct(y, y_fdct);
	char u_fdct[8][8] = {};
	fdct(u, u_fdct);
	char v_fdct[8][8] = {};
	fdct(v, v_fdct);
	
	
//----------------量化 Y U  V  -----------------------------------
	//借用成品jpg圖片量化表,lh0,lh1
	char (*lh0)[8]=(char (*)[8])lh00;
	char (*lh1)[8]=(char (*)[8])lh10;
	
	char y_lh[8][8]={};
	char u_lh[8][8]={};
	char v_lh[8][8]={};
	
	lh(y_fdct,lh0,y_lh);
	lh(u_fdct,lh1,u_lh);
	lh(v_fdct,lh1,v_lh);
	
//---------Z排序--------------------------
    char y_z[64]={};
	char u_z[64]={};
	char v_z[64]={};
	zz(y_lh,y_z);
	zz(u_lh,u_z);
	zz(v_lh,v_z);
	
	
 
		for (int b = 0; b < 64; b++) {
			printf("%d  ,", v_z[b]);
		}
	
	
	
	
	return 0;
}

到此這篇關(guān)于C語言實(shí)現(xiàn)YUV文件轉(zhuǎn)JPEG格式的文章就介紹到這了,更多相關(guān)C語言YUV轉(zhuǎn)JPEG內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++中inline函數(shù)詳解

    C++中inline函數(shù)詳解

    inline函數(shù)的定義:在函數(shù)聲明或定義中函數(shù)返回類型前加上關(guān)鍵字inline,即可以把函數(shù)指定為內(nèi)聯(lián)函數(shù)。inline函數(shù)對(duì)編譯器而言必須是可見的,以便它能夠在調(diào)用點(diǎn)展開該函數(shù)。
    2015-07-07
  • OpenGL實(shí)現(xiàn)中點(diǎn)劃線法

    OpenGL實(shí)現(xiàn)中點(diǎn)劃線法

    這篇文章主要為大家詳細(xì)介紹了OpenGL實(shí)現(xiàn)中點(diǎn)劃線法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-02-02
  • C++編程實(shí)現(xiàn)獲取當(dāng)前可執(zhí)行文件名稱

    C++編程實(shí)現(xiàn)獲取當(dāng)前可執(zhí)行文件名稱

    在C++開發(fā)中,有時(shí)需要獲取當(dāng)前可執(zhí)行文件的名稱用來處理一些事務(wù),本文總結(jié)了在Windows和Linux平臺(tái)上獲取當(dāng)前可執(zhí)行文件名稱的多種方法,大家可以根據(jù)需要進(jìn)行選擇
    2026-03-03
  • C++找出字符串中出現(xiàn)最多的字符和次數(shù),時(shí)間復(fù)雜度小于O(n^2)

    C++找出字符串中出現(xiàn)最多的字符和次數(shù),時(shí)間復(fù)雜度小于O(n^2)

    今天小編就為大家分享一篇關(guān)于C++找出字符串中出現(xiàn)最多的字符和次數(shù),時(shí)間復(fù)雜度小于O(n^2),小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • C++詳細(xì)分析講解引用的概念與使用

    C++詳細(xì)分析講解引用的概念與使用

    引用(reference)就是C++對(duì)C語言的重要擴(kuò)充。引用就是某一變量(目標(biāo))的一個(gè)別名,對(duì)引用的操作與對(duì)變量直接操作完全一樣
    2022-05-05
  • C++11 算法std::copy_if 與 std::copy_n詳解

    C++11 算法std::copy_if 與 std::copy_n詳解

    C++11新增std::copy_if與std::copy_n,前者條件篩選復(fù)制,后者固定數(shù)量復(fù)制,提升代碼可讀性與性能,適用于數(shù)據(jù)過濾及批量處理,需注意范圍重疊與目標(biāo)空間不足等陷阱,本文給大家介紹C++11算法std::copy_if 與 std::copy_n詳解,感興趣的朋友一起看看吧
    2025-07-07
  • 二叉搜索樹的插入與刪除(詳細(xì)解析)

    二叉搜索樹的插入與刪除(詳細(xì)解析)

    添加結(jié)點(diǎn)其實(shí)很容易,我們只需要找到結(jié)點(diǎn)所行對(duì)應(yīng)的位置就可以了,而且沒有要求是平衡的二叉搜索樹,因此每次添加結(jié)點(diǎn)都是在葉子結(jié)點(diǎn)上操作,不需要修改二叉搜索樹整體的結(jié)構(gòu)
    2013-09-09
  • C++指向類成員函數(shù)的指針詳細(xì)解析

    C++指向類成員函數(shù)的指針詳細(xì)解析

    由于這幾天在開發(fā)中要用到函數(shù)指針,所以就整理了一下關(guān)于函數(shù)指針的概念
    2013-08-08
  • C++中typedef 及其與struct的結(jié)合使用

    C++中typedef 及其與struct的結(jié)合使用

    這篇文章主要介紹了C++中typedef 及其與struct的結(jié)合使用,需要的朋友可以參考下
    2014-02-02
  • C++全面精通類與對(duì)象

    C++全面精通類與對(duì)象

    類和對(duì)象是兩種以計(jì)算機(jī)為載體的計(jì)算機(jī)語言的合稱。對(duì)象是對(duì)客觀事物的抽象,類是對(duì)對(duì)象的抽象。類是一種抽象的數(shù)據(jù)類型;變量就是可以變化的量,存儲(chǔ)在內(nèi)存中—個(gè)可以擁有在某個(gè)范圍內(nèi)的可變存儲(chǔ)區(qū)域
    2022-05-05

最新評(píng)論

宣威市| 侯马市| 页游| 安丘市| 开阳县| 宁乡县| 长葛市| 汉阴县| 增城市| 外汇| 甘洛县| 东至县| 巴东县| 泗洪县| 通山县| 澄城县| 南陵县| 大渡口区| 武义县| 双流县| 岳阳县| 项城市| 祁门县| 扬中市| 海兴县| 卢龙县| 白朗县| 高要市| 安福县| 句容市| 新营市| 娱乐| 大竹县| 青浦区| 吐鲁番市| 广昌县| 余姚市| 成都市| 涿州市| 临桂县| 唐海县|