当前位置:网站首页>Experiment 2 YUV
Experiment 2 YUV
2022-07-23 07:58:00 【Myster_ KID】
TGA to YUV File conversion and examples
List of articles
One 、TGA File structure
| name | Offset (Byte) | length (Byte) | explain |
|---|---|---|---|
| ID Length | 0 | 1 | Length of image information field : by 0 When, it means that there is no image information field |
| Colour Map Type | 1 | 1 | Palette Type : 0: No palette 1: There is a palette |
| Image Type Code | 2 | 1 | |
| Colour Map Offset | 3 | 2 | Color table entry index |
| Colour Map Length | 5 | 2 | Color table total entry Count |
| Colour Map Depth | 7 | 1 | Each color table entry Number of digits : 16:Targa 16 24:Targa 24 32:Targa 32 |
| X Origin | 8 | 2 | In the lower left corner of the image x coordinate |
| Y Origin | 10 | 2 | In the lower left corner of the image y coordinate |
| Width | 12 | 2 | Image width |
| Height | 14 | 2 | High image |
| Bits Per Pixel | 16 | 1 | The number of bits per pixel of the image |
| Image Descriptor | 17 | 1 | 0: No image data 1: No compression 、 An image with a palette 2: No compression 、 Palette free RGB Images 3: Uncompressed black and white image 9: Run length encoded image with palette 10: Run length encoded RGB Images 11: Compressed black and white image 32: Use Huffman、Delta、 Run length encoding compression encoded image with palette 33: Use Huffman、Delta、 Run length encoding compression encoded image with palette ,4 Quadtree type processing |
| Image Identification Field | 18 | variable | The length of this field is determined by ID Length Field assignment . Generally ignored . If you need to store more information , It can be placed after the image data |
| Colour Map Data | variable | variable | if Colour Map Type by 0, Then the field does not exist . Each palette entry The length of can be 4(RGBA)、3(RGB) or 2 byte ( The first 1 bytes GGBBBBB, The first 2 bytes ARRRRRGG) |
| Image Data Field | variable | variable | Be careful ,TGA Files are stored in small end ,RGB Component with B、G、R Sequential storage of , Image data is stored from the lower left corner |
Two 、 Experimental thinking
- by TGA The file establishes the structure of the file header , Read the contents of the file header into ;
- According to the header information , Calculate the offset , Find the starting point of image data ;
- Read in image data , Yes RLE Decode the compressed image , And according to Bits Per Pixel Different , Separate R、G、B component ;
- Turn the image upside down , Change to RGB How to store files
- Use rgb2yuv function , That is, to YUV File conversion
3、 ... and 、 Code
declarations.h
#pragma once
#include <iostream>
typedef struct
{
char idLength = 0; // Length of identification field (length = 1B, offset = 0B)
char colourMapType = 0; // Colour map type (length = 1B, offset = 1B): 0 for no colour map included, 1 for colour map included
char imageTypeCode = 0; // Image type code (length = 1B, offset = 2B): 2 for uncompressed & unmapped RGB image, 10 for run length encoded & unmapped RGB image
/* Colour map specification (all set to 0 if colour map type is 0) */
short colourMapOffset = 0; // Colour map origin (length = 2B, offset = 3B): index of first colour map entry
short colourMapLength = 0; // Colour map length (length = 2B, offset = 5B): number of colour map entries
char colourMapDepth = 0; // Colour map depth (length = 1B, offfset = 7B): number of bits in each entry. 16 for the Targa 16, 24 for the Targa 24, 32 for the Targa 32
/* Image specification */
short x_origin = 0; // X coordinate of the lower left corner (length = 2B, offset = 8B)
short y_origin = 0; // Y coordinate of the lower left corner (length = 2B, offset = 10B)
short width = 0; // Width of image (length = 2B, offset = 12B)
short height = 0; // Height of image (length = 2B, offset = 14B)
char bitsPerPixel = 0; // Number of bits in each pixel (length = 1B, offset = 16B)
char imageDescriptor = 0; // Image descripter byte (length = 1B, offset = 17B)
} HEADER;
typedef struct
{
unsigned char r, g, b, a;
} PIXEL;
void ReadTgaHeader(HEADER* tgaHdPtr, FILE* tgaPtr);
void ReadColourData(HEADER* tgaHdPtr, PIXEL* colourData, FILE* tgaPtr);
void Trans2RgbFormat(PIXEL* colourData, unsigned char* rgbBuff, HEADER* tgaHdPtr);
void rgb2yuv(FILE* yuvPtr, int width, int height, unsigned char* rgbBuff);
ReadTgaHeader.cpp
#include <iostream>
#include "declarations.h"
using namespace std;
void ReadTgaHeader(HEADER* tgaHdPtr, FILE* tgaPtr)
{
/* Read data in TGA file header fields */
tgaHdPtr->idLength = fgetc(tgaPtr);
tgaHdPtr->colourMapType = fgetc(tgaPtr);
tgaHdPtr->imageTypeCode = fgetc(tgaPtr);
fread(&tgaHdPtr->colourMapOffset, 2, 1, tgaPtr);
fread(&tgaHdPtr->colourMapLength, 2, 1, tgaPtr);
tgaHdPtr->colourMapDepth = fgetc(tgaPtr);
fread(&tgaHdPtr->x_origin, 2, 1, tgaPtr);
fread(&tgaHdPtr->y_origin, 2, 1, tgaPtr);
fread(&tgaHdPtr->width, 2, 1, tgaPtr);
fread(&tgaHdPtr->height, 2, 1, tgaPtr);
tgaHdPtr->bitsPerPixel = fgetc(tgaPtr);
tgaHdPtr->imageDescriptor = fgetc(tgaPtr);
/* Display header info on screen */
cout << "\nTGA file header information:\n";
printf("ID length: %d\n", tgaHdPtr->idLength);
printf("Colour Map type: %d\n", tgaHdPtr->colourMapType);
printf("Image type code: %d\n", tgaHdPtr->imageTypeCode);
printf("Colour map offset: %d\n", tgaHdPtr->colourMapOffset);
printf("Colour map length: %d\n", tgaHdPtr->colourMapLength);
printf("Colour map depth: %d\n", tgaHdPtr->colourMapDepth);
printf("X origin: %d\n", tgaHdPtr->x_origin);
printf("Y origin: %d\n", tgaHdPtr->y_origin);
printf("Width: %d\n", tgaHdPtr->width);
printf("Height: %d\n", tgaHdPtr->height);
printf("Image pixel size: %d\n", tgaHdPtr->bitsPerPixel);
printf("Descriptor: %d\n\n", tgaHdPtr->imageDescriptor);
}
ReadColourData.cpp
#include "declarations.h"
void SeparateRGBA(PIXEL* pixel, unsigned char* rgba, int bytesPerPixel)
{
switch (bytesPerPixel)
{
case 4:
pixel->r = rgba[2];
pixel->g = rgba[1];
pixel->b = rgba[0];
pixel->a = rgba[3];
break;
case 3:
pixel->r = rgba[2];
pixel->g = rgba[1];
pixel->b = rgba[0];
pixel->a = 255;
break;
case 2:
pixel->r = (rgba[1] & 0b01111100) << 1;
pixel->g = ((rgba[1] & 0b00000011) << 6) | ((rgba[0] & 0b11100000) >> 2);
pixel->b = (rgba[0] & 0b00011111) << 3;
pixel->a = (rgba[1] & 0b10000000);
break;
default:
break;
}
}
void ReadColourData(HEADER* tgaHdPtr, PIXEL* colourData, FILE* tgaPtr)
{
int bytesPerPx = tgaHdPtr->bitsPerPixel / 8; // Bytes per pixel
unsigned char tempRGBA[4]; // Temporary buffer for the RGBA data of 1 pixel
int n = 0; // nth pixel
while (n < tgaHdPtr->width * tgaHdPtr->height)
{
switch (tgaHdPtr->imageTypeCode)
{
/* Uncompressed, unmapped RGB image */
case 2:
{
/* Read the colour data of 1 pixel */
if (fread(tempRGBA, 1, bytesPerPx, tgaPtr) != bytesPerPx)
{
printf("ERROR!!! Unexpected end of file at pixel %d.\n", n);
exit(-1);
}
SeparateRGBA(&(colourData[n]), tempRGBA, bytesPerPx);
//printf("%-4x%-4x%-4x\n", colourData[n].b, colourData[n].g, colourData[n].r); // Check
n++;
break;
}
/* Run length encoded, unmapped RGB image */
case 10:
{
unsigned char tempPktHeader; // Temporary buffer for the packet header
int pktHdID = 0; // Determines if it's an RL packet or a raw packet
int pktRunSize = 0; // Run size (the number of pixels in this packet)
/* Read the packet header */
if (fread(&tempPktHeader, 1, 1, tgaPtr) != 1)
{
printf("ERROR!!! Unexpected end of file at pixel %d.\n", n);
exit(-1);
}
pktHdID = (tempPktHeader & 0x80) >> 7;
pktRunSize = (tempPktHeader & 0x7F) + 1;
/* Raw packet */
if (pktHdID == 0)
{
for (int i = 0; i < pktRunSize; i++)
{
if (fread(tempRGBA, 1, bytesPerPx, tgaPtr) != bytesPerPx)
{
printf("ERROR!!! Unexpected end of file at pixel %d.\n", n);
exit(-1);
}
SeparateRGBA(&(colourData[n]), tempRGBA, bytesPerPx);
n++;
}
}
/* RL packet */
else if (pktHdID == 1)
{
if (fread(tempRGBA, 1, bytesPerPx, tgaPtr) != bytesPerPx)
{
printf("ERROR!!! Unexpected end of file at pixel %d.\n", n);
exit(-1);
}
for (int i = 0; i < pktRunSize; i++)
{
SeparateRGBA(&(colourData[n]), tempRGBA, bytesPerPx);
n++;
}
}
else
{
printf("ERROR!!! Unexpected invalid value of packet header ID.\n");
exit(-1);
}
break;
}
default:
break;
}
}
}
Trans2RgbFormat.cpp
#include "declarations.h"
void Trans2RgbFormat(PIXEL* colourData, unsigned char* rgbBuff, HEADER* tgaHdPtr)
{
/* Write RGB data in .rgb format into rgbBuff */
int w = tgaHdPtr->width;
int h = tgaHdPtr->height;
for (int i = 0; i < h; i++) // i for row of image
{
for (int j = 0; j < w; j++) // j for column of image
{
int rgbPxNum = (h - 1 - i) * w + j; // Pixel number in RGB file
int tgaPxNum = i * w + j; // Pixel number in TGA file
rgbBuff[3 * rgbPxNum + 2] = colourData[tgaPxNum].r;
rgbBuff[3 * rgbPxNum + 1] = colourData[tgaPxNum].g;
rgbBuff[3 * rgbPxNum] = colourData[tgaPxNum].b;
}
}
}
rgb2yuv.cpp
#include <iostream>
#include "declarations.h"
int rgb66[256], rgb129[256], rgb25[256];
int rgb38[256], rgb74[256], rgb112[256];
int rgb94[256], rgb18[256];
void rgbLookupTable()
{
for (int i = 0; i < 256; i++)
{
rgb66[i] = 66 * i;
rgb129[i] = 129 * i;
rgb25[i] = 25 * i;
rgb38[i] = 38 * i;
rgb74[i] = 74 * i;
rgb112[i] = 112 * i;
rgb94[i] = 94 * i;
rgb18[i] = 18 * i;
}
}
void rgb2yuv(FILE* yuvPtr, int width, int height, unsigned char* rgbBuff)
{
int pxCount = width * height;
unsigned char* yBuff = new unsigned char[pxCount]; // Buffer for Y component
unsigned char* uBuff = new unsigned char[pxCount / 4]; // Buffer for U component
unsigned char* vBuff = new unsigned char[pxCount / 4]; // Buffer for V component
unsigned char* uBuff444 = new unsigned char[pxCount]; // Buffer for U component in 4:4:4 format
unsigned char* vBuff444 = new unsigned char[pxCount]; // Buffer for V component in 4:4:4 format
// RGB to YUV (4:4:4)
for (int i = 0; i < pxCount; i++) // i for pixel number
{
unsigned char r = rgbBuff[3 * i + 2]; // R component of the ith pixel
unsigned char g = rgbBuff[3 * i + 1]; // G component of the ith pixel
unsigned char b = rgbBuff[3 * i]; // B component of the ith pixel
rgbLookupTable();
yBuff[i] = ((rgb66[r] + rgb129[g] + rgb25[b]) >> 8) + 16;
uBuff444[i] = ((-rgb38[r] - rgb74[g] + rgb112[b]) >> 8) + 128;
vBuff444[i] = ((rgb112[r] - rgb94[g] - rgb18[b]) >> 8) + 128;
}
// 4:4:4 to 4:2:0
for (int i = 0; i < height; i += 2)
{
for (int j = 0; j < width; j += 2)
{
uBuff[i / 2 * width / 2 + j / 2] = uBuff444[i * width + j];
vBuff[i / 2 * width / 2 + j / 2] = vBuff444[i * width + j];
}
}
delete[]uBuff444;
delete[]vBuff444;
fwrite(yBuff, sizeof(unsigned char), pxCount, yuvPtr);
fwrite(uBuff, sizeof(unsigned char), pxCount / 4, yuvPtr);
fwrite(vBuff, sizeof(unsigned char), pxCount / 4, yuvPtr);
}
main.cpp
#include <iostream>
#include "declarations.h"
using namespace std;
int main(int argc, char* argv[])
{
/* Declarations */
FILE* tgaFilePtr, * yuvFilePtr;
//FILE* rgbFilePtr;
HEADER hd; // Structure variable for TGA file header
int w, h, pxCount;
const char* tgaFileName = "snow32RLE.tga";
const char* yuvFileName = "snow32RLE.yuv";
//const char* rgbFileName = "snow32RLE.rgb";
PIXEL* rgbaData = NULL; // Entire RGBA data of TGA file; used for future funtions
unsigned char* rgbBuffer = NULL; // RGB data of TGA file (in .rgb format); extracted from rgbaData; used for tga2yuv
int offset = 0;
/* Open the files */
if (fopen_s(&tgaFilePtr, tgaFileName, "rb") == 0)
{
cout << "Successfully opened \"" << tgaFileName << "\".\n";
}
else
{
cout << "Failed to open \"" << tgaFileName << "\".\n";
exit(-1);
}
if (fopen_s(&yuvFilePtr, yuvFileName, "wb") == 0)
{
cout << "Successfully opened \"" << yuvFileName << "\".\n";
}
else
{
cout << "Failed to open \"" << yuvFileName << "\".\n";
exit(-1);
}
//if (fopen_s(&rgbFilePtr, rgbFileName, "wb") == 0)
//{
// cout << "Successfully opened \"" << rgbFileName << "\".\n";
//}
//else
//{
// cout << "Failed to open \"" << rgbFileName << "\".\n";
// exit(-1);
//}
/* Read and display the header fields */
ReadTgaHeader(&hd, tgaFilePtr);
w = hd.height;
h = hd.width;
pxCount = w * h;
/* Space allocation */
rgbaData = new PIXEL[hd.width * hd.height];
memset(rgbaData, 0, hd.height * hd.width); // Initialisation
rgbBuffer = new unsigned char[hd.width * hd.height * 3];
memset(rgbBuffer, 0, hd.height * hd.width * 3); // Initialisation
/* Developed function check & invalidation check */
if (hd.imageTypeCode != 2 && hd.imageTypeCode != 10)
{
cout << "Can only handle image type 2 (uncompressed, unmapped RGB) & image type 10 (run length encoded, unmapped RGB).\nOther options being developed.\n";
exit(-1);
}
if (hd.bitsPerPixel != 16 && hd.bitsPerPixel != 24 && hd.bitsPerPixel != 32)
{
cout << "Invalid value of image pixel size!\nCan only handle pixel depths of 16, 24, and 32.\n";
exit(-1);
}
if (hd.colourMapType != 0 && hd.colourMapType != 1)
{
cout << "Invalid value of colour map type!\nCan only handle colour map types of 0 and 1.\n";
exit(-1);
}
/* Skip over unnecessary chunks */
offset += hd.idLength;
offset += hd.colourMapType * hd.colourMapLength * hd.colourMapDepth;
cout << offset << " byte(s) skipped over.\n\n";
fseek(tgaFilePtr, offset, SEEK_CUR); // Skip 'offset' bytes from the end of header
/* Read the image RGB (A, if exists) data */
ReadColourData(&hd, rgbaData, tgaFilePtr);
/* Transform .tga formatted RGB data into .rgb format */
Trans2RgbFormat(rgbaData, rgbBuffer, &hd);
//fwrite(rgbBuffer, 3, pxCount, rgbFilePtr);
/* Transform RGB into YUV */
rgb2yuv(yuvFilePtr, w, h, rgbBuffer);
delete[]rgbaData;
delete[]rgbBuffer;
//fclose(rgbFilePtr);
fclose(tgaFilePtr);
fclose(yuvFilePtr);
}
Four 、 Running results
The test image used in the experiment is “snow.jpeg” adopt Adobe Photoshop Transformed from “snow16.tga”“snow24.tga” and “snow32.tga”.
The original image is as follows :
With RLE Compression of the Targa 32 The image, for example , The output is :

Targa 32 (Image Type Code = 10) Debug console output
Use the converted image YUV Viewer Plus open , give the result as follows :
Converted YUV Images (Image Type Code = 2)

Converted YUV Images (Image Type Code = 10)
边栏推荐
- Ftxui basic notes (Hello World)
- etcdv3·watch操作实现及相关重点说明
- The new idea 2022.2 was officially released, and the new features are really fragrant
- (五)数电——公式化简法
- Fastapi learning (II) -- fastapi+jinjia2 template rendering web page (jump back to the rendering page)
- Detailed analysis of the 110th blog of the fledgling Xiao Li in stm32__ NVIC_ Setprioritygrouping (uint32_t prioritygroup) function
- I use the factory mode in jd.com and explain the factory mode clearly
- 1.11 ArrayList&学生管理系统
- 【第31天】给定一个整数 n ,求出它的每个质因数的底数与指数 | 算术基本定理
- It can't be true? Nailing has been downloaded. Don't you know you can play like this?
猜你喜欢

初出茅庐的小李第109篇博客之如何打开Keil中文件的真是路径

一次 MySQL 误操作导致的事故,「高可用」都顶不住了

VMware virtual machine changes static IP and hostname, and uses xshell to connect

图的存储结构及方法(一)

Fledgling Xiao Li's 108th blog binary print

沃尔沃xc90的安全性如何?一起来看看吧

【干货原创】发现了一个好用到爆的数据分析利器

Information system project managers must recite the core examination points (49) contract law

使用Hystrix实现容错处理

“蔚来杯“2022牛客暑期多校训练营1 (部分题目总结)
随机推荐
golang--module
不会吧?钉钉都下载了,你还不知道可以这样玩?
Interpretation of URL structure
QT document reading notes - qaudioinput & qaudioformat parsing and examples
VMware virtual machine changes static IP and hostname, and uses xshell to connect
关于Redis,是先更新数据库,还是先更新缓存?
Ftxui basic notes (Hello World)
如何在 PHP 应用程序中预防SQL 注入
I use the factory mode in jd.com and explain the factory mode clearly
Understand the domestic open source Magnolia license series agreement in simple terms
信息系统项目管理师必背核心考点(四十九)合同法
局域网SDN技术硬核内幕 - 16 三 从物到人 园区用户漫游的EVPN实现
初出茅庐的小李第111篇博客之中英文点阵字符显示原理
Bottom compulsory of large factory: "communication realization between application program and AMS"
Scala generic generic class details - t
局域网SDN技术硬核内幕 8 从二层交换到三层路由
Information system project managers must recite the core examination points (49) contract law
Codeforces Round #809 (Div. 2)(C和D1两题)
亚马逊旗下Zoox通过安全测试 并在加州申请试驾
ASP. Net core creates MVC projects and uploads multiple files (streaming)