strgeon

32位BMP格式转YUV格式-并行计算
前言首先介绍32位BMP格式的图片转YUV420P格式。然后介绍如何使用openmpi进行并行。下载地址---&g...
扫描右侧二维码阅读全文
23
2018/07

32位BMP格式转YUV格式-并行计算

前言

首先介绍32位BMP格式的图片转YUV420P格式。然后介绍如何使用openmpi进行并行。
下载地址--->戳我


使用file命令查看文件格式

首先还是来看看如何查看文件的格式。原本想做jpg和png这种类型的转换,但是发现这种类型较为复杂,最后还是选择的BMP和YUV的格式。
使用方法:file 文件名
file命令


BMP文件格式介绍

BMP格式里面可以看看-->BMP百度经验其中的对应数据结构部分

BMP文件的组成:

  • BMP文件头(14Byte):提供文件的格式、大小等信息
  • 位图信息头(40Byte):提供图像数据的尺寸、位平面数、压缩方式、颜色索引等信息
  • 颜色信息:对应图像数据的顺序,32位中为BGRA
  • 图形数据(数据大小):图像数据,上下镜像储存

我是用的是32位的BMP格式(BGRA),没有用24位BMP格式(BGR)。图象数据BGRA:默认的BMP是不支持ALPHA通道的,但对32位BMP而言,每个象素用32位(4个字节)表示,前三个字节表示RGB分量,最后一个字节可以做为ALPHA通道的值,因此32位位图可以存储带ALPHA通道的图像,在文件中,各分量的存储顺序为BGRA,BGRA,BGRA,BGRA…
要注意的是,BMP图像的象素存储顺序是从下到上,如果按照正常的顺序,是上下镜像,需要自己翻转,如果不反转,情况如下图。
bmp储存顺序


YUV文件格式介绍

想要转换成YUV的格式,那么当然需要知道YUV的储存方式,YUV下面的格式有很多种,这里我使用的是YUV420P格式,可以看一下这个介绍-->- 图文详解YUV420数据格式

对于YUV文件,“Y”表示明亮度(Luminance或 Luma),也就是灰度值;而“U”和“V” 表示的则是色度(Chrominance或Chroma),作用是描述影像色彩及饱和度,用于指定像素的颜色。在文件中的储存直接保存的是数据文件。由RGB通过公式转化成YUV格式,每个点的RGB值和YUV值一一对应,对于储存的方式有点特别,有一定的压缩。
储存顺序是Y(width*height)-U(width*height/4)-V(width*height/4),转化出来之后的大小是原来数据的1/2,其在内存中占用的空间是width*height*1.5(BYTE),注意是每四个点使用一个UV值,注意下图的颜色对应。其数据储存的顺序如下:
YUV420P储存
其转换标准公式如下,本次使用到了RGB转YUV的公式:

RGB to YUV Conversion
Y  =      (0.257 * R) + (0.504 * G) + (0.098 * B) + 16
Cr = V =  (0.439 * R) - (0.368 * G) - (0.071 * B) + 128
Cb = U = -(0.148 * R) - (0.291 * G) + (0.439 * B) + 128

YUV to RGB Conversion
B = 1.164(Y - 16) + 2.018(U - 128)
G = 1.164(Y - 16) - 0.813(V - 128) - 0.391(U - 128)
R = 1.164(Y - 16) + 1.596(V - 128)


使用mplayer查看YUV文件

因为YUV格式的数据不方便打开,在Linux上不好查看,这里使用一个叫做mplayer的工具来进行图片的查看

$ sudo apt-get install mplayer
//如果显示有依赖不全的情况,执行这一句
$ sudo apt-get install -f
//图片查看的命令,注意替换文件名和长宽还有格式
$ mplayer -demuxer rawvideo -rawvideo w=1920:h=1080:format=i420 test.yuv -loop 0

mplayer用法介绍

这里简单介绍一下mplayer的使用

//input0对应/dev/video0,查看摄像头内容
mplayer tv:// -tv driver=v4l2:input=0:width=640:height=480:fps=25 -vo x11
//在mplayer中查看YUV格式的图片或视频,可使用如下命令:
$ mplayer -demuxer rawvideo -rawvideo w=1920:h=1080:format=i420 test.yuv -loop 0
//查看mplayer支持的格式
$ mplayer -rawvideo format=help

注意:因为本次课设使用的YUV的420格式.-loop 0为循环播放
format的可选项:420(yv12,i420),422(yuy2,uyvy)
更多格式可以使用上面的命令查看。


得到32位BMP图片

首先还是需要拿到素材,我们使用的是32位BMP图片。Ubuntu自带的截图得到的png是不带A通道的png图片。我这里使用的是crosscover安装的QQ8.5,使用QQ的截图,得到png图片,然后使用opencv进行转换,会自动转换成32位BMP图片,得到方法不重要,使用file xx.bmp,是32位BMP即可。我是用的opencv的方式进行转化。

#include "cv.h"
#include "highgui.h"
#include <cstdio>
#include <iostream>
using namespace std;

int main(int argc,char ** argv)
{
    char filename[100] = "test.png";
    IplImage *img = cvLoadImage(filename,-1);
    cvShowImage("example", img);
    cvWaitKey(0);
    cvSaveImage("test.bmp",img);
    cvReleaseImage(&img);
}

然后命令行编译运行

//编译转换程序
$ g++ png2bmp.cpp -o png2bmp `pkg-config --cflags --libs opencv`
//运行转换程序
$ ./png2bmp test.png test.bmp
//这样就可以得到我们需要用到的bmp格式的文件了


BMP转换YUV

首先还是先写普通的转换程序,写好之后再改成openmpi的并行。
bmp2yuyv.cpp文件内容如下:

#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace  std;

#define TMAPFILEHEADERLENGTH 14 // The bmp FileHeader length is 14
#define BM 19778 // The ASCII code for BM

static float RGBYUV02990[256], RGBYUV05870[256], RGBYUV01140[256];
static float RGBYUV01684[256], RGBYUV03316[256];
static float RGBYUV04187[256], RGBYUV00813[256];


void InitLookupTable();

int RGBtoYUV (int x_dim,int y_dim,void *bmp, void *y_out, void *u_out, void *v_out)
{
    long i, j,size;
    unsigned char *r, *g, *b;
    unsigned char *y, *u, *v;
    unsigned char *pu1, *pv1, *psu, *psv;
    unsigned char *y_buffer, *u_buffer, *v_buffer;
    unsigned char *sub_u_buf, *sub_v_buf;
    InitLookupTable();
    size=x_dim*y_dim;
    y_buffer = (unsigned char *)y_out;
    sub_u_buf = (unsigned char *)u_out;
    sub_v_buf = (unsigned char *)v_out;
    u_buffer = (unsigned char *)malloc(size * sizeof(unsigned char));
    v_buffer = (unsigned char *)malloc(size * sizeof(unsigned char));
    if (!(u_buffer && v_buffer))
    {
        if (u_buffer) free(u_buffer);
        if (v_buffer) free(v_buffer);
        return 2;
    }


    b = (unsigned char *)bmp;
    y = y_buffer;
    u = u_buffer;
    v = v_buffer;
    pu1 =u_buffer;
    pv1= v_buffer;
    psu = sub_u_buf;
    psv = sub_v_buf;

    for (j = 0; j < y_dim; j++){
        for (i = 0; i < x_dim; i++)
        {
            g = b + 1;
            r = b + 2;
            *y = (unsigned char)( RGBYUV02990[*r] + RGBYUV05870[*g] + RGBYUV01140[*b]);
            *u = (unsigned char)(- RGBYUV01684[*r] - RGBYUV03316[*g] + (*b)/2 + 128);
            *v = (unsigned char)( (*r)/2 - RGBYUV04187[*g] - RGBYUV00813[*b] + 128);
            b += 4;
            y ++;
            u ++;
            v ++;
        }
    }


    for (j=0; j< y_dim/2; j++)
    {
        for (i=0; i< x_dim/2; i++)
        {
            *psu=*pu1;
            *psv=*pv1;
            psu++;
            psv++;
            pv1+=2;
            pu1+=2;
        }
        pu1+=x_dim;
        pv1+=x_dim;
    }
    free(u_buffer);
    free(v_buffer);
    return 0;
}


void InitLookupTable()
{
    int i;
    for (i = 0; i < 256; i++) RGBYUV02990[i] = (float)0.2990 * i;
    for (i = 0; i < 256; i++) RGBYUV05870[i] = (float)0.5870 * i;
    for (i = 0; i < 256; i++) RGBYUV01140[i] = (float)0.1140 * i;
    for (i = 0; i < 256; i++) RGBYUV01684[i] = (float)0.1684 * i;
    for (i = 0; i < 256; i++) RGBYUV03316[i] = (float)0.3316 * i;
    for (i = 0; i < 256; i++) RGBYUV04187[i] = (float)0.4187 * i;
    for (i = 0; i < 256; i++) RGBYUV00813[i] = (float)0.0813 * i;
}


void bmp_file_test(FILE* fpbmp)
{
    unsigned short bfType = 0;
    fseek(fpbmp, 0L, SEEK_SET);
    fread(&bfType, sizeof(char), 2, fpbmp);
    if (BM != bfType)
    {
        printf("This file is not bmp file.!!!\n");
        exit(1);
    }
}

//翻转数组,因为bmp图片是反着存的
void swapU(unsigned char *a,unsigned char *b)
{
    unsigned char temp;
    for(int i=0;i<4;i++){
        temp=*a;
        *a=*b;
        *b=temp;
        a++,b++;
    }
}
void reversePic(void *bmp,int width,int height)
{
    unsigned char *b=(unsigned char *)bmp;
    for(int i=0;i<height/2;i++){
        int posUp=i*width;
        int posDown=(height-i-1)*width;
        for(int j=0;j<width;j++){
            int up=posUp+j;
            int down=posDown+j;
            //swap
            swapU(b+up*4,b+down*4);
        }
    }
}

int main(int argc,char **argv)
{
    if(argc != 3){
        perror("./a.out rgb_name yuv_name");
        exit(0);
    }
    unsigned int width, height, pixelBit,temp;

    FILE* bmpfile =NULL;
    FILE* rgbtmp  =NULL;
    FILE* yuvfile =NULL;
    unsigned char* rgbbuf =NULL;
    unsigned char* ybuf =NULL;
    unsigned char* ubuf =NULL;
    unsigned char* vbuf =NULL;


    if((bmpfile = fopen(argv[1], "rb+"))==NULL)
    {
        printf("cannot find rgb file\n");
        exit(1);
    }
    if((rgbtmp = fopen("temp.rgb", "wb+"))==NULL)
    {
        printf("cannot find rgb file\n");
        exit(1);
    }
    if((yuvfile = fopen(argv[2],"wb")) == NULL)
    {
        printf("cannot find yuv file\n");
        exit(1);
    }

    //判断是否是bmp图片
    bmp_file_test(bmpfile);
    //获得图片的长宽还有像素占用的位数
    fseek(bmpfile, 18L, SEEK_SET);
    fread(&temp, sizeof(unsigned int), 1, bmpfile);
    width = temp;
    fseek(bmpfile, 22L, SEEK_SET);
    fread(&temp, sizeof(unsigned int), 1, bmpfile);
    height = temp;
    fseek(bmpfile, 28L, SEEK_SET);
    fread(&temp, 2*sizeof(char), 1, bmpfile);
    pixelBit = temp; //这里的大小是一个字(2个字节)
    printf("width = %d , height = %d , pixelBit = %d\n", width, height,pixelBit);

    rgbbuf = (unsigned char*)malloc(width *height*4 );
    ybuf = (unsigned char*)malloc(width * height);
    ubuf = (unsigned char*)malloc((width * height) / 4);
    vbuf = (unsigned char*)malloc((width * height) / 4);
    if (rgbbuf == NULL || ybuf == NULL || ubuf == NULL || vbuf == NULL)
    {
        printf("no enought memory\n");
        exit(1);
    }
    fseek(bmpfile, 54L, SEEK_SET); //定位到像素点信息位置
    fread (rgbbuf, 1, width * height * 4, bmpfile);
    //bmp是倒着存的,翻转图像
    reversePic(rgbbuf,width,height);
    fwrite(rgbbuf, 1, width * height * 4, rgbtmp);
    fclose(bmpfile);
    fread(rgbbuf, 1, width * height * 4, rgbtmp  );
    if(RGBtoYUV(width, height, rgbbuf, ybuf, ubuf, vbuf)==0){
        printf("图片转换成功\n");
    }

    fwrite(ybuf, 1, width*height, yuvfile);
    fwrite(ubuf, 1, (width*height) / 4, yuvfile);
    fwrite(vbuf, 1, (width*height) / 4, yuvfile);

    fclose(rgbtmp);
    fclose(yuvfile);
    free(rgbbuf);
    free(ybuf);
    free(ubuf);
    free(vbuf);
    return(0);
}

然后将这个文件进行编译运行就能转换得到YUV文件了

//编译程序
$ cd bmp2yuvyv/
$ g++ bmp2yuyv.cpp -o bmp2yuyv
//进行转换,会有打印信息
$ ./bmp2yuyv test.bmp test.yuv
width = 1920 , height = 1080 , pixelBit = 32
图片转换成功
//显示转换出来的YUV图片
$ mplayer -demuxer rawvideo -rawvideo w=1920:h=1080:format=i420 test.yuv -loop 0


使用openmpi并行

有了普通的转化程序,接下来的任务就是将我们原本的程序并行化,思想就是通过输入来进行动态的调整,将图片的转换按行进行并行。单文件写比较麻烦,这里使用了makefile来进行管理。
文件结构就是makefile,read.cpp,write.cpp,mpi.cpp,将一些并行化的处理等写在了mpi.cpp中(write中啥都没写,本来准备一下分离一下代码,因为懒)直接放代码吧,以上代码会在文末给出下载链接。

#makefile
    all: program

    program: mpi.o read.o write.o
        mpic++ mpi.o read.o write.o -o program

    mpi.o: mpi.cpp
        mpic++ -c mpi.cpp -o mpi.o
        #mpicc -o mpi.o mpi.c

    read.o: read.cpp
        g++ -c read.cpp -o read.o

    write.o: write.cpp
        g++ -c write.cpp -o write.o

    clean:
        rm -f write.o read.o mpi.o program core *~
//read.h
#include<cstdio>
#include<cstdlib>

void bmp_file_check(FILE* fpbmp);  //判断是否是BMP图片文件
void swapU(unsigned char *a,unsigned char *b);
void reversePic(void *bmp,int width,int height);
void read_pic_more_data(FILE *bmpfile,int *width,int *height,int *pixelBit,int *temp);
//write.h
void save();
//read.cpp
#include"read.h"
#define BM 19778 // The ASCII code for BM

void bmp_file_check(FILE* fpbmp)
{
    unsigned short bfType = 0;
    fseek(fpbmp, 0L, SEEK_SET);
    fread(&bfType, sizeof(char), 2, fpbmp);
    if (BM != bfType)
    {
        printf("This file is not bmp file.!!!\n");
        exit(1);
    }
}

//翻转数组,因为bmp图片是反着存的
void swapU(unsigned char *a,unsigned char *b)
{
    unsigned char temp;
    for(int i=0;i<4;i++){
        temp=*a;
        *a=*b;
        *b=temp;
        a++,b++;
    }
}
void reversePic(void *bmp,int width,int height)
{
    unsigned char *b=(unsigned char *)bmp;
    for(int i=0;i<height/2;i++){
        int posUp=i*width;
        int posDown=(height-i-1)*width;
        for(int j=0;j<width;j++){
            int up=posUp+j;
            int down=posDown+j;
            //swap
            swapU(b+up*4,b+down*4);
        }
    }
}
//读取宽高大小数据
void read_pic_more_data(FILE *bmpfile,int *width,int *height,int *pixelBit,int *temp)
{
    //判断是否是bmp图片
    bmp_file_check(bmpfile);
    //获得图片的长宽还有像素占用的位数
    fseek(bmpfile, 18L, SEEK_SET);
    fread(temp, sizeof(unsigned int), 1, bmpfile);
    *width = *temp;
    fseek(bmpfile, 22L, SEEK_SET);
    fread(temp, sizeof(unsigned int), 1, bmpfile);
    *height = *temp;
    fseek(bmpfile, 28L, SEEK_SET);
    fread(temp, 2*sizeof(char), 1, bmpfile);
    *pixelBit = *temp; //这里的大小是一个字(2个字节)
    // printf("width = %d , height = %d , pixelBit = %d\n", *width, *height, *pixelBit);
}
//write.cpp
#include"write.h"

void save()
{}
//mpi.cpp
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<mpi.h>
#include<cstring>
#include"read.h"
#include"write.h"
using namespace  std;
// #define uint unsigned int


static float RGBYUV02990[256], RGBYUV05870[256], RGBYUV01140[256];
static float RGBYUV01684[256], RGBYUV03316[256];
static float RGBYUV04187[256], RGBYUV00813[256];


void InitLookupTable();

int RGBtoYUV (int width,int height,void *bmp,void *y_out, void *u_out, void *v_out)
{
    long i,j,size;
    unsigned char *r, *g, *b;
    unsigned char *y, *u, *v;
    unsigned char *pu1, *pv1, *psu, *psv;
    unsigned char *y_buffer, *u_buffer, *v_buffer;
    unsigned char *sub_u_buf, *sub_v_buf;
    InitLookupTable();
    size=width*height;
    y_buffer = (unsigned char *)y_out;
    sub_u_buf = (unsigned char *)u_out;
    sub_v_buf = (unsigned char *)v_out;
    u_buffer = (unsigned char *)malloc(size * sizeof(unsigned char));
    v_buffer = (unsigned char *)malloc(size * sizeof(unsigned char));
    if (!(u_buffer && v_buffer))
    {
        if (u_buffer) free(u_buffer);
        if (v_buffer) free(v_buffer);
        return 2;
    }


    b = (unsigned char *)bmp;
    y = y_buffer;
    u = u_buffer;
    v = v_buffer;
    pu1 =u_buffer;
    pv1= v_buffer;
    psu = sub_u_buf;
    psv = sub_v_buf;

    for (j = 0; j < height; j++){
        for (i = 0; i < width; i++)
        {
            g = b + 1;
            r = b + 2;
            *y = (unsigned char)( RGBYUV02990[*r] + RGBYUV05870[*g] + RGBYUV01140[*b]);
            *u = (unsigned char)(- RGBYUV01684[*r] - RGBYUV03316[*g] + (*b)/2 + 128);
            *v = (unsigned char)( (*r)/2 - RGBYUV04187[*g] - RGBYUV00813[*b] + 128);
            b += 4;
            y ++;
            u ++;
            v ++;
        }
    }


    for (j=0; j< height/2; j++)
    {
        for (i=0; i< width/2; i++)
        {
            *psu=*pu1;
            *psv=*pv1;
            psu++;
            psv++;
            pv1+=2;
            pu1+=2;
        }
        pu1+=width;
        pv1+=width;
    }
    free(u_buffer);
    free(v_buffer);
    return 0;
}


void InitLookupTable()
{
    int i;
    for (i = 0; i < 256; i++) RGBYUV02990[i] = (float)0.2990 * i;
    for (i = 0; i < 256; i++) RGBYUV05870[i] = (float)0.5870 * i;
    for (i = 0; i < 256; i++) RGBYUV01140[i] = (float)0.1140 * i;
    for (i = 0; i < 256; i++) RGBYUV01684[i] = (float)0.1684 * i;
    for (i = 0; i < 256; i++) RGBYUV03316[i] = (float)0.3316 * i;
    for (i = 0; i < 256; i++) RGBYUV04187[i] = (float)0.4187 * i;
    for (i = 0; i < 256; i++) RGBYUV00813[i] = (float)0.0813 * i;
}


int main(int argc,char **argv)
{
    //mpi-data
    double startTime,endTime;
    int id;/*进程序号*/
    int p; /*进程总数*/
    int from,to;/*发送接收序号*/
    int tag=0;/*消息标签*/
    int tran_height;/*消息储存*/
    MPI_Status status;/*return status for*/
    /*启动MPI*/
    MPI_Init(&argc,&argv);
    startTime=MPI_Wtime();
    /*查找进程号*/
    MPI_Comm_rank(MPI_COMM_WORLD,&id);
    /*查找进程总数*/
    MPI_Comm_size(MPI_COMM_WORLD,&p);

    //my-program-data
    char srcfile[]="test.bmp";
    char dstfile[]="test.yuv";
    int width, height, pixelBit,temp;

    FILE* bmpfile =NULL;
    FILE* rgbtmp  =NULL;
    FILE* yuvfile =NULL;
    unsigned char* rgbbuf =NULL;
    unsigned char* ybuf =NULL;
    unsigned char* ubuf =NULL;
    unsigned char* vbuf =NULL;
    if((bmpfile = fopen(srcfile, "rb+"))==NULL)
    {
        printf("cannot find rgb file\n");
        exit(1);
    }
    if((rgbtmp = fopen("temp.rgb", "wb+"))==NULL)
    {
        printf("cannot find rgb file\n");
        exit(1);
    }
    if((yuvfile = fopen(dstfile,"wb")) == NULL)
    {
        printf("cannot find yuv file\n");
        exit(1);
    }
    read_pic_more_data(bmpfile,&width,&height,&pixelBit,&temp);
    if(width%2==1||height%2==1){
        printf("输入图片宽或高为奇数,请修改图片\n");
    }
    MPI_Barrier(MPI_COMM_WORLD);

    if(id==0){
        //主进程进行运行
        rgbbuf = (unsigned char*)malloc(width *height*4 );
        ybuf = (unsigned char*)malloc(width * height);
        ubuf = (unsigned char*)malloc((width * height) / 4);
        vbuf = (unsigned char*)malloc((width * height) / 4);
        if (rgbbuf == NULL || ybuf == NULL || ubuf == NULL || vbuf == NULL)
        {
            printf("no enought memory\n");
            exit(1);
        }
        fseek(bmpfile, 54L, SEEK_SET); //定位到像素点信息位置
        fread (rgbbuf, 1, width * height * 4, bmpfile);
        //bmp是倒着存的,翻转图像
        reversePic(rgbbuf,width,height);
        fwrite(rgbbuf, 1, width * height * 4, rgbtmp);
        fclose(bmpfile);

        int aver_height=height/(p-1);
        int rem_height=height%(p-1);
        unsigned char *tran_pos=rgbbuf;
        int *tran=(int *)malloc(p*sizeof(int));
        tran[0]=0;
        for(int i=1;i<p;i++){
            if(i<=rem_height)
                tran[i]=aver_height+1;
            else
                tran[i]=aver_height;
        }
        for(int i=1;i<p;i++){
            if(tran[i]%2!=0){
                //因为总和是4的倍数,所以不用管最后一项可能为奇数
                tran[i]--;
                tran[i+1]++;
            }
        }
        //分发数据,将需要转换的指针头部位置发给子进程
        for(to=1;to<p;to++){
            MPI_Send(&tran[to],1,MPI_INT,to,tag,MPI_COMM_WORLD);
            MPI_Send(tran_pos,tran[to]*width*4,MPI_UNSIGNED_CHAR,to,tag,MPI_COMM_WORLD);
            tran_pos+=tran[to]*width*4;
        }
        //从子进程接收数据
        int posy=0,posu=0,posv=0;
        for(to=1;to<p;to++){
            MPI_Recv(ybuf+posy,width*tran[to],MPI_UNSIGNED_CHAR,to,tag,MPI_COMM_WORLD,&status);
            MPI_Recv(ubuf+posu,width*tran[to]/4,MPI_UNSIGNED_CHAR,to,tag,MPI_COMM_WORLD,&status);
            MPI_Recv(vbuf+posv,width*tran[to]/4,MPI_UNSIGNED_CHAR,to,tag,MPI_COMM_WORLD,&status);
            posy+=tran[to]*width;
            posu+=tran[to]*width/4;
            posv+=tran[to]*width/4;
        }
        fwrite(ybuf, 1, width*height, yuvfile);
        fwrite(ubuf, 1, (width*height) / 4, yuvfile);
        fwrite(vbuf, 1, (width*height) / 4, yuvfile);
        //关闭文件流指针
        fclose(rgbtmp);
        fclose(yuvfile);
        free(tran);
        free(rgbbuf);
        free(ybuf);
        free(ubuf);
        free(vbuf);
    }else{
        //接收主进程分发过来的数据,tran_height表示需要修改的
        MPI_Recv(&tran_height,1,MPI_INT,0,tag,MPI_COMM_WORLD,&status);
        cout<<id<<":"<<tran_height<<endl;
        unsigned char * tran_buf =  (unsigned char*)malloc(width *tran_height*4 );
        MPI_Recv(tran_buf,width*tran_height*4,MPI_UNSIGNED_CHAR,0,tag,MPI_COMM_WORLD,&status);
        //根据传来的tran_buf进行转换
        ybuf = (unsigned char*)malloc(width * tran_height);
        ubuf = (unsigned char*)malloc((width * tran_height) / 4);
        vbuf = (unsigned char*)malloc((width * tran_height) / 4);
        if(RGBtoYUV(width, tran_height, tran_buf, ybuf, ubuf, vbuf)==0){
            // cout<<id<<":转换成功"<<endl;
        }
        //将YUV三个通道的内容回传给0号进程
        MPI_Send(ybuf,width*tran_height,MPI_UNSIGNED_CHAR,0,tag,MPI_COMM_WORLD);
        MPI_Send(ubuf,width*tran_height/ 4,MPI_UNSIGNED_CHAR,0,tag,MPI_COMM_WORLD);
        MPI_Send(vbuf,width*tran_height/ 4,MPI_UNSIGNED_CHAR,0,tag,MPI_COMM_WORLD);
    }
    endTime=MPI_Wtime();
    // cout<<(int)startTime/3600<<"h:"<<((int)startTime%3600)/60<<"m:"<<(int)startTime%600<<"s:"<<endl;
    MPI_Barrier(MPI_COMM_WORLD);
    if(id==0)
        cout<<"time:"<<(endTime-startTime)<<endl;
    //拦截所有进程
    /*关闭MPI*/
    MPI_Finalize();
    return 0;
}

编译和运行方法

//使用make方法
$ cd hpc-cal/
$ make program
//使用openmpi运行,这里指定4个进程,输出其他进程的处理行数
//不得少于2个,0号进程做分发
$ mpiexec -np 4 program
1:360
2:360
3:360
time:0.0517164
//查看转化结果
$ mplayer -demuxer rawvideo -rawvideo w=1920:h=1080:format=i420 1.yuv -loop 0


坑点

这个程序是做完了,但是有个坑点,就是传入图片的长宽像素值不能为奇数,必须都是偶数。
因为在转化成YUV格式的时候其中的u和v的值是(width*height)/4;,也就是每四个点共用一个UV的值,其实可以在程序中进行处理,但是对于列的处理比较麻烦,这里也就没有继续做优化了。


参考资料

最后修改:2018 年 08 月 10 日 03 : 53 PM
如果觉得我的文章对你有用,请随意赞赏

发表评论