C++ RAW10 to YUV420 Conversion Code: Efficient Image Format Transformation
This code converts RAW10 image data to YUV420 format using C++. RAW10 format uses 5 bytes for every 4 pixels, while YUV420 uses 1.5 bytes per pixel, requiring a conversion for efficient storage and processing. This implementation provides a detailed explanation of the conversion process and offers a practical example for image processing.
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
struct Pixel {
unsigned short R;
unsigned short G;
unsigned short B;
};
void raw10_to_pixel(const unsigned char* data, vector<Pixel>& pixels, int width, int height) {
pixels.resize(width * height);
int i = 0, j = 0;
for (int pos = 0; pos < width * height * 5 / 4; pos += 5) {
unsigned char b0 = data[pos];
unsigned char b1 = data[pos + 1];
unsigned char b2 = data[pos + 2];
unsigned char b3 = data[pos + 3];
unsigned char b4 = data[pos + 4];
pixels[i * width + j].R = (b0 << 2) | (b1 >> 6);
pixels[i * width + j].G = ((b1 & 0x3F) << 4) | (b2 >> 4);
pixels[i * width + j].B = ((b2 & 0x0F) << 6) | (b3 >> 2);
i += (j + 1) / width;
j = (j + 1) % width;
pixels[i * width + j].R = ((b3 & 0x03) << 8) | b4;
i += (j + 1) / width;
j = (j + 1) % width;
}
}
void pixel_to_yuv420(const vector<Pixel>& pixels, unsigned char* yuv, int width, int height) {
int y_size = width * height;
int uv_size = y_size / 4;
int i, j;
// Y component
for (i = 0; i < height; ++i) {
for (j = 0; j < width; ++j) {
int pos = i * width + j;
yuv[pos] = (unsigned char)(0.299 * pixels[pos].R + 0.587 * pixels[pos].G + 0.114 * pixels[pos].B);
}
}
// U and V components
for (i = 0; i < height; i += 2) {
for (j = 0; j < width; j += 2) {
int pos = y_size + (i / 2) * (width / 2) + (j / 2);
int pos1 = i * width + j;
int pos2 = pos1 + 1;
int pos3 = pos1 + width;
int pos4 = pos3 + 1;
yuv[pos] = (unsigned char)(-0.169 * pixels[pos1].R - 0.331 * pixels[pos1].G + 0.5 * pixels[pos1].B
- 0.169 * pixels[pos2].R - 0.331 * pixels[pos2].G + 0.5 * pixels[pos2].B
- 0.169 * pixels[pos3].R - 0.331 * pixels[pos3].G + 0.5 * pixels[pos3].B
- 0.169 * pixels[pos4].R - 0.331 * pixels[pos4].G + 0.5 * pixels[pos4].B + 128);
pos++;
yuv[pos] = (unsigned char)(0.5 * pixels[pos1].R - 0.419 * pixels[pos1].G - 0.081 * pixels[pos1].B
+ 0.5 * pixels[pos2].R - 0.419 * pixels[pos2].G - 0.081 * pixels[pos2].B
+ 0.5 * pixels[pos3].R - 0.419 * pixels[pos3].G - 0.081 * pixels[pos3].B
+ 0.5 * pixels[pos4].R - 0.419 * pixels[pos4].G - 0.081 * pixels[pos4].B + 128);
}
}
}
int main(int argc, char** argv) {
if (argc < 3) {
cout << 'Usage: raw10_to_yuv420 input.raw output.yuv' << endl;
return -1;
}
char* input_file = argv[1];
char* output_file = argv[2];
ifstream fin(input_file, ios::binary);
if (!fin) {
cout << 'Failed to open input file ' << input_file << endl;
return -1;
}
fin.seekg(0, ios::end);
int file_size = fin.tellg();
fin.seekg(0, ios::beg);
vector<unsigned char> data(file_size);
fin.read((char*)data.data(), file_size);
fin.close();
int width = 640;
int height = 480;
vector<Pixel> pixels;
raw10_to_pixel(data.data(), pixels, width, height);
vector<unsigned char> yuv(width * height * 3 / 2);
pixel_to_yuv420(pixels, yuv.data(), width, height);
ofstream fout(output_file, ios::binary);
if (!fout) {
cout << 'Failed to open output file ' << output_file << endl;
return -1;
}
fout.write((char*)yuv.data(), yuv.size());
fout.close();
return 0;
}
This code can be compiled and run with input and output file paths, for example:
$ ./raw10_to_yuv420 input.raw output.yuv
The 'input.raw' is the RAW10 format input file, and 'output.yuv' is the converted YUV420 format output file. This code utilizes C++11 standard 'vector' and 'fstream' libraries for efficient memory management and file operations.
原文地址: https://www.cveoy.top/t/topic/lC8W 著作权归作者所有。请勿转载和采集!