1. Requisitos experimentales
1. Analice archivos en formato BMP para obtener información de la imagen
2. Convierta imágenes BMP en imágenes en formato YUV
3. Convierta múltiples imágenes BMP en videos YUV.
2. Contenido experimental
1. Obtener fotografías
Obtenga imágenes bmp (540 * 720):
2.conceptos básicos del formato bmp
El experimento utiliza archivos bmp de color verdadero de 24 bits. El documento se divide en tres partes:
- FileHeader
- InfoHeader
- Información RGB de la imagen
El uso #include<windows.h>
puede leer fácilmente la información del encabezado del archivo en la estructura
3. Realización de la programación
El programa se modifica del código de rgb a yuv en [Experimento 1] .
Función principal
La función principal implementa el siguiente proceso:
- Lea el archivo bmp en los parámetros para obtener la información de ancho, alto y color
- rgb a yuv
- Empiece a escribir la transición a partir de la segunda imagen.
- Escribe una imagen estática
- Guarde la imagen actual en temp y guárdela para la próxima transición
el código se muestra a continuación
int main(int argc, char** argv)
{
u_int8_t* y_temp;
u_int8_t* u_temp;
u_int8_t* v_temp;
int transFrames = 30;//转场帧数
int photoFrames = 30;//静止图片帧数
for (int pic = 2; pic < argc; pic++) //从第二个参数到最后一个是图片
{
//1.读bmp文件头,获取宽高
BITMAPFILEHEADER File_header;
BITMAPINFOHEADER Info_header;
FILE* bmpFile;
bmpFile = fopen(argv[pic], "rb");
fread(&File_header, sizeof(BITMAPFILEHEADER), 1, bmpFile);
fread(&Info_header, sizeof(BITMAPINFOHEADER), 1, bmpFile);
u_int frameWidth;
u_int frameHeight;
frameWidth = Info_header.biWidth;
frameHeight = Info_header.biHeight;
//2.色彩信息读入rgb_buffer
u_int8_t* rgbBuf = (u_int8_t*)malloc(frameWidth * frameHeight * 3);
fread(rgbBuf, 1, frameWidth * frameHeight * 3, bmpFile);
fclose(bmpFile);
//3.追加模式打开yuv文件
FILE* yuvFile = fopen(argv[1], "ab+");
//4.rgb转yuv
u_int8_t* yBuf = (u_int8_t*)malloc(frameWidth * frameHeight);
u_int8_t* uBuf = (u_int8_t*)malloc((frameWidth * frameHeight) / 4);
u_int8_t* vBuf = (u_int8_t*)malloc((frameWidth * frameHeight) / 4);
if (RGB2YUV(frameWidth, frameHeight, rgbBuf, yBuf, uBuf, vBuf, FALSE))
{
printf("error");
return 0;
}
for (int i = 0; i < frameWidth * frameHeight; i++)
{
if (yBuf[i] < 16) yBuf[i] = 16;
if (yBuf[i] > 235) yBuf[i] = 235;
}
for (int i = 0; i < frameWidth * frameHeight / 4; i++)
{
if (uBuf[i] < 16) uBuf[i] = 16;
if (uBuf[i] > 240) uBuf[i] = 240;
if (vBuf[i] < 16) vBuf[i] = 16;
if (vBuf[i] > 240) vBuf[i] = 240;
}
//5.从第二张图片开始加入转场
if (pic > 2) {
for (int frame = 0; frame < transFrames; frame++) {
u_int8_t* y_mix = getInsertFrames(y_temp, yBuf, transFrames, frame, frameWidth, frameHeight);
u_int8_t* u_mix = getInsertFrames(u_temp, uBuf, transFrames, frame, frameWidth / 2, frameHeight / 2);
u_int8_t* v_mix = getInsertFrames(v_temp, vBuf, transFrames, frame, frameWidth / 2, frameHeight / 2);
fwrite(y_mix, 1, frameWidth * frameHeight, yuvFile);
fwrite(u_mix, 1, (frameWidth * frameHeight) / 4, yuvFile);
fwrite(v_mix, 1, (frameWidth * frameHeight) / 4, yuvFile);
}
}
//6.写静态图片
for (int frame = 0; frame < photoFrames; frame++) {
fwrite(yBuf, 1, frameWidth * frameHeight, yuvFile);
fwrite(uBuf, 1, (frameWidth * frameHeight) / 4, yuvFile);
fwrite(vBuf, 1, (frameWidth * frameHeight) / 4, yuvFile);
}
printf("\n%u %ux%u video frames written\n",
pic, frameWidth, frameHeight);
fclose(yuvFile);
//7.将当前图片存入temp中,留给下一张转场用
y_temp = (u_int8_t*)malloc(frameWidth * frameHeight);
u_temp = (u_int8_t*)malloc(frameWidth * frameHeight*0.5);
v_temp = (u_int8_t*)malloc(frameWidth * frameHeight*0.5);
for (int i = 0; i < frameWidth * frameHeight; i++)
{
*(y_temp + i) = *(yBuf + i);
}
for (int i = 0; i < frameWidth * frameHeight/4; i++)
{
*(u_temp + i) = *(uBuf + i);
*(v_temp + i) = *(vBuf + i);
}
}
return(0);
}
Entre ellos, la RGB2YUV()
función es el código dado por el profesor en el [Experimento 1], por lo que no se publica.
Parámetros de depuración
Ingrese el nombre del archivo yuv y el nombre del archivo bmp que se generarán como parámetros:
Función de transición getInsertFrames ()
getInsertFrames()
La función se utiliza para obtener un fotograma mixto de dos imágenes, y se escriben dos métodos de transición: superposición y barrido.
Cubrir:
u_int8_t* getInsertFrames_mix(u_int8_t* buf1, u_int8_t* buf2, int frame,int currentFrame, u_int frameWidth,u_int frameHeight) {
//获取两帧混合(插值)
//frame:总转场帧数
//currentFrame:当前帧
u_int8_t * mix = (u_int8_t*)malloc(frameWidth * frameHeight);
for (int j = 0; j < frameHeight * frameWidth; j++) {
*(mix + j) = int((*(buf2 + j)* currentFrame + *(buf1 + j)*(frame- currentFrame)) / frame);
}
return mix;
}
Pasar un trapo
u_int8_t* getInsertFrames_sweap(u_int8_t* buf1, u_int8_t* buf2, int frame, int currentFrame, u_int frameWidth, u_int frameHeight) {
//获取两帧混合(扫下来)
//frame:总转场帧数
//currentFrame:当前帧
u_int8_t * mix = (u_int8_t*)malloc(frameWidth * frameHeight);
for (int h = 0; h < frameHeight; h++) {
for (int w = 0; w < frameWidth; w++) {
if (currentFrame * frameHeight / frame > h) {
*(mix + h * frameWidth + w) = *(buf2 + h * frameWidth + w);
}
else {
*(mix + h * frameWidth + w) = *(buf1 + h * frameWidth + w);
}
}
}
return mix;
}
3. Resultados experimentales
Los resultados experimentales utilizan LICEcap
software para grabar imágenes GIF, csdn solo puede admitir imágenes de no más de 5 M, por lo que solo se graba un cambio de imagen.
(1) Superposición
(2) Limpiar
4. Resumen del experimento:
- La estructura del lenguaje C es muy conveniente para leer rápidamente varias partes de la información del archivo.
- Para el video yuv, no hay compresión y ocupa espacio y la redundancia es muy alta.