#ifndef __COLORTRANSFORM_H__ #define __COLORTRANSFORM_H__ #ifdef __cplusplus extern "C" { #endif #define PERROR 1 #define IMAGE_MAX_WIDTH (4*1024) #define IMAGE_MAX_HEIGHT (4*1024) #define MAX_FILE_NAME_LENGTH 256 #define LOGP printf("FUNCTION:%s,LINE:%d\n",__FUNCTION__,__LINE__); #define LINE_BYTES(Width) (((long)(Width) * 8 + 31) / 32 * 4) typedef unsigned char COLOR_BYTE; typedef unsigned short COLOR_WORD; typedef unsigned int COLOR_DWORD; typedef long COLOR_LONG; //Definition of bitmap header, in which file type info is not included as //it is determined by the memory layout of bitmap header. //If added,file info may be wrongly readed. typedef struct __tag_BIT_MAP_FILE_HEADER{ // COLOR_WORD wType;//file type,must be0x424D(BM) COLOR_DWORD dwSize;//file size COLOR_WORD wReserved1;//reserved word COLOR_WORD wReserved2;//reserved word COLOR_DWORD dwOffBits;//offsets from header of file }BITMAPFILEHEADER, *LPBITMAPFILEHEADER; typedef struct __tag_BIT_MAP_INFO_HEADER{ COLOR_DWORD dwSize;//size of info header COLOR_LONG lWidth;//width of image COLOR_LONG lHeight;//height of image COLOR_WORD wPlanes;//count of bit plane,must be 1 COLOR_WORD wBitCount;//bits for every pix COLOR_DWORD dwCompression; //compression type COLOR_DWORD dwSizeImage; //size in byte of compressed file COLOR_LONG lXPelsPerMeter; //horizontal resolution COLOR_LONG lYPelsPerMeter; //vertical resolution COLOR_DWORD dwClrUsed; //count of color actually used by bitmap COLOR_DWORD dwClrImportant; //count of important color in bitmap }BITMAPINFOHEADER, *LPBITMAPINFOHEADER; //definition of bitmap info header typedef struct __tag_RGB_QUAD{ COLOR_BYTE byRGBBlue; //blue component of the color COLOR_BYTE byRGBGreen; //green component of the color COLOR_BYTE byRGBRed; //red component of the color COLOR_BYTE byRGBReserved; //reserverd value }RGBQUAD, *LPRGBQUAD;//definition of palette typedef struct __tag_IMAGE_DATA { COLOR_BYTE byBlue; COLOR_BYTE byGreen; COLOR_BYTE byRed; }IMAGEDATA, *LPIMAGEDATA;//pixel information MRESULT SaveBMPFromYUV(const char* pFilePath, const char *pFileName, const MUInt8 * pSource, int iWidth, int iHeight); MRESULT ReadYUVFromBMP(const char* pFilePath, const char *pFileName, MUInt8 **ppDest, long *pWidth, long *pHeight); MRESULT ConvertYuv420pToNV21(MUInt8 * pDest, const MUInt8 * pSource, int iWidth, int iHeight); MRESULT ConvertYuv420pToNV12(MUInt8 * pDest, const MUInt8 * pSource, int iWidth, int iHeight); MRESULT ConvertYuv420pToYUYV(MUInt8 * pDest, const MUInt8 * pSource, int iWidth, int iHeight); MRESULT ConvertYuv420pToI422H(MUInt8 * pDest, const MUInt8 * pSource, int iWidth, int iHeight); MRESULT ConvertYuv420pToLPI422H(MUInt8 * pDest, const MUInt8 * pSource, int iWidth, int iHeight); #ifdef __cplusplus } #endif #endif //__COLORTRANSFORM_H__ #include <stdio.h> #include <malloc.h> #include <memory.h> #include <fcntl.h> #include <sys/types.h> #include <sys/mman.h> #include <unistd.h> #include "turbojpeg.h" #include "ColorTransform.h" MRESULT SaveBMPFromYUV(const char* pFilePath, const char *pFileName, const MUInt8 * pSource, int iWidth, int iHeight) { if (NULL == pFilePath || NULL == pFileName || NULL == pSource) { return PERROR; } if (iWidth <= 0 || iHeight <= 0) { return PERROR; } MRESULT res = MOK; const COLOR_WORD wType = 0x4d42; BITMAPFILEHEADER strHead; //head of bitmap BITMAPINFOHEADER strInfo; //info head of bitmap IMAGEDATA *pBMPImageData = NULL; //store pixel info of bitmap FILE *pFileOut = NULL; memset(&strHead, 0, sizeof(BITMAPFILEHEADER)); memset(&strInfo, 0, sizeof(BITMAPINFOHEADER)); pBMPImageData = (IMAGEDATA*)malloc(iWidth * iHeight * sizeof(IMAGEDATA)); if (NULL == pBMPImageData) { printf("failed to allocate %d size of memory for pBMPImageData\n", iWidth * iHeight * sizeof(IMAGEDATA)); res = PERROR; goto __EXIT; } memset(pBMPImageData, 0, iWidth * iHeight * sizeof(IMAGEDATA)); int y; int r, g, b; int i, j; for(i = 0; i < iHeight; i++) { for(j = 0; j < iWidth; j++) { y = pSource[j + i * iWidth]; /* yuv<-->rgb Y'= 0.299*R' + 0.587*G' + 0.114*B' U'= -0.147*R' - 0.289*G' + 0.436*B' = 0.492*(B'- Y') V'= 0.615*R' - 0.515*G' - 0.100*B' = 0.877*(R'- Y') R' = Y' + 1.140*V' G' = Y' - 0.394*U' - 0.581*V' B' = Y' + 2.032*U' yCbCr<-->rgb Y’ = 0.257*R' + 0.504*G' + 0.098*B' + 16 Cb' = -0.148*R' - 0.291*G' + 0.439*B' + 128 Cr' = 0.439*R' - 0.368*G' - 0.071*B' + 128 R' = 1.164*(Y’-16) + 1.596*(Cr'-128) G' = 1.164*(Y’-16) - 0.813*(Cr'-128) - 0.392*(Cb'-128) B' = 1.164*(Y’-16) + 2.017*(Cb'-128)*/ r = y; g = y; b = y; r = r > 255 ? 255 : r; g = g > 255 ? 255 : g; b = b > 255 ? 255 : b; r = r < 0 ? 0 : r; g = g < 0 ? 0 : g; b = b < 0 ? 0 : b; (*(pBMPImageData + i * iWidth + j)).byBlue = (COLOR_BYTE)b; (*(pBMPImageData + i * iWidth + j)).byGreen = (COLOR_BYTE)g; (*(pBMPImageData + i * iWidth + j)).byRed = (COLOR_BYTE)r; } } ///save BMP image char arrFilePathName[MAX_FILE_NAME_LENGTH]; strcpy(arrFilePathName, pFilePath); strcat(arrFilePathName, pFileName); sprintf(arrFilePathName, "%s_%dX%d%s" , arrFilePathName, iWidth, iHeight, ".bmp"); if(NULL == (pFileOut = fopen(arrFilePathName, "wb"))) { printf("create the bmp file:%s failed!\n", arrFilePathName); res = PERROR; goto __EXIT; } printf("Save bmp file:%s\n", arrFilePathName); fwrite(&wType, 1, sizeof(COLOR_WORD), pFileOut); strHead.dwSize = iWidth * iHeight * 3 + 54; //size of bitmap in byte strHead.wReserved2 = 0; strHead.dwOffBits = 54; //actual offsets from the header in byte(14 + 40),no palette fwrite(&strHead, 1, sizeof(BITMAPFILEHEADER), pFileOut); strInfo.lWidth = iWidth; strInfo.lHeight = iHeight; strInfo.wBitCount = 24; //specify the count of bits used in rendering colors,common value are:1(Black and white two-color image), 4(16-color image), 8(256-color image), 24(true-color image) strInfo.dwClrImportant = 0; //specify the count of important colors,all colors are identified to be important if it is zero. strInfo.dwClrUsed = 0; //specify the count of colors actually used in image.If it is 0,count of colors used is identified as 2*2*....*2(total count of wBitCount) strInfo.dwCompression = 0; //specify if the image is compressed strInfo.wPlanes = 1; ///count of planes and must be 1 strInfo.dwSize = 40; ///length of struct and must be 40 strInfo.dwSizeImage = 3 * iWidth * iHeight; fwrite(&strInfo, 1, sizeof(BITMAPINFOHEADER), pFileOut); //save pixel data for(i = iHeight - 1; i >= 0; --i) //from top the bottom { for(j = 0; j < iWidth; ++j) //for(int j = iWidth;j > 0;--j) { fwrite( &((*(pBMPImageData + i * iWidth + j)).byBlue), 1, sizeof(COLOR_BYTE), pFileOut); fwrite( &((*(pBMPImageData + i * iWidth + j)).byGreen), 1, sizeof(COLOR_BYTE), pFileOut); fwrite( &((*(pBMPImageData + i * iWidth + j)).byRed), 1, sizeof(COLOR_BYTE), pFileOut); } } __EXIT: if (pFileOut != NULL) { fclose(pFileOut); pFileOut = NULL; } if (pBMPImageData != NULL) { free(pBMPImageData); pBMPImageData = NULL; } return res; } MRESULT ReadYUVFromBMP(const char* pFilePath, const char *pFileName, MUInt8 **ppDest, long *pWidth, long *pHeight) { if (NULL == pFilePath || NULL == pFileName || NULL == ppDest || NULL == pWidth || NULL == pHeight) { printf("parameters invalid\n"); return PERROR; } MRESULT res = MOK; MUInt8 *pData = NULL; FILE *pFile = NULL; char arrFileNameFull[MAX_FILE_NAME_LENGTH]; //file name size_t lReadSize = 0; //return value of fread size_t lWantReadSize = 0; //acutal value want to read size_t lActualFileSize = 0; //actula file size in byte COLOR_DWORD dwFileSize = 0; //file size got from file head COLOR_DWORD dwOffset = 0; // offset of rgb data from header of file int iHeight = 0; // height of bmp file int iWidth = 0; // width of bmp file MUInt8 * pRGBDataLine = NULL; sprintf(arrFileNameFull, "%s%s", pFilePath, pFileName); printf("mask bmp file is:%s\n", arrFileNameFull); pFile = fopen(arrFileNameFull, "rb"); if (NULL == pFile) { printf("can not open file %s\n", arrFileNameFull); res = PERROR; goto __EXIT; } pData = malloc(sizeof(MUInt8) * (sizeof(BITMAPFILEHEADER) > sizeof(BITMAPINFOHEADER) ? sizeof(BITMAPFILEHEADER) : sizeof(BITMAPINFOHEADER))); if (NULL == pData) { res = PERROR; goto __EXIT; } // get file size in byte fseek(pFile, 0L, SEEK_END); lActualFileSize = ftell(pFile); fseek(pFile, 0L, SEEK_SET); //check file type lWantReadSize = 2; lReadSize = fread(pData, 1, lWantReadSize, pFile); if (lReadSize != lWantReadSize) { printf("fread from %s failed and return %u\n", arrFileNameFull, lReadSize); res = PERROR; goto __EXIT; } if (pData[0] != 0x42 || pData[1] != 0x4d) { printf("file type is:%0x%0x,not a bmp file\n", pData[1], pData[0]); res = PERROR; goto __EXIT; } // get file size from file head lWantReadSize = sizeof(BITMAPFILEHEADER); lReadSize = fread(pData, 1, lWantReadSize, pFile); if (lReadSize != lWantReadSize) { printf("read head from %s failed and return %u\n", arrFileNameFull, lReadSize); res = PERROR; goto __EXIT; } dwFileSize = (((COLOR_DWORD)pData[3]) << 24) | (((COLOR_DWORD)pData[2]) << 16) | (((COLOR_DWORD)pData[1]) << 8) | (((COLOR_DWORD)pData[0]) << 0); if ( dwFileSize != lActualFileSize) { printf("file is broken,size in head:%u,actual size:%u\n", dwFileSize, lActualFileSize); res = PERROR; goto __EXIT; } // get rgb offset from file head dwOffset = (((COLOR_DWORD)pData[11]) << 24) | (((COLOR_DWORD)pData[10]) << 16) | (((COLOR_DWORD)pData[9]) << 8) | (((COLOR_DWORD)pData[8]) << 0); // get info head lWantReadSize = sizeof(BITMAPINFOHEADER); lReadSize = fread(pData, 1, lWantReadSize, pFile); if (lReadSize != lWantReadSize) { printf("read info head from %s failed and return %u\n", arrFileNameFull, lReadSize); res = PERROR; goto __EXIT; } iWidth = (((COLOR_LONG)pData[7]) << 24) | (((COLOR_LONG)pData[6]) << 16) | (((COLOR_LONG)pData[5]) << 8) | (((COLOR_LONG)pData[4]) << 0) ; iHeight = (((COLOR_LONG)pData[11]) << 24) | (((COLOR_LONG)pData[10]) << 16) | (((COLOR_LONG)pData[9]) << 8) | (((COLOR_LONG)pData[8]) << 0) ; *pWidth = iWidth; *pHeight = iHeight; // read RGB data and trasform it into YUV Grey format *ppDest = (MUInt8 *)malloc(sizeof(MUInt8) * iWidth * iHeight * 2); if (NULL == *ppDest) { printf("failed to malloc size of %ld memory for *ppDest\n", (long)(sizeof(MUInt8) * (*pWidth) * (*pHeight))); res = PERROR; goto __EXIT; } fseek(pFile, dwOffset, SEEK_SET); int iChannel = 3; int iStep = iChannel * iWidth; int iOffSet = iStep % 4; int i, j; if (iOffSet != 0) { iOffSet = 4 - iOffSet; } pRGBDataLine = (MUInt8 *) malloc(sizeof(MUInt8) * (iStep + iOffSet)); if (NULL == pRGBDataLine) { printf("failed to allocate size of %d memory for pRGBDataLine\n", sizeof(MUInt8) * (iStep + iOffSet)); res = PERROR; goto __EXIT; } for (i = 0; i < iHeight; i++) { fread(pRGBDataLine, 1, iStep + iOffSet, pFile); for (j = 0; j < iWidth; j++) { //if (pRGBDataLine[j * iChannel] != 0 && pRGBDataLine[j * iChannel] != 255) if (255 == pRGBDataLine[j * iChannel]) { (*ppDest)[(iHeight - 1 - i) * iWidth + j] = 0; } else if (0 == pRGBDataLine[j * iChannel]) { (*ppDest)[(iHeight - 1 - i) * iWidth + j] = 255; } else { //printf("pRGBDataLine[%d]:%d invalid\n", j * iChannel, pRGBDataLine[j * iChannel]); (*ppDest)[(iHeight - 1 - i) * iWidth + j] = 255; } } } __EXIT: if (pRGBDataLine != NULL) { free(pRGBDataLine); pRGBDataLine = NULL; } if (pFile != NULL) { fclose(pFile); pFile = NULL; } if (pData != NULL) { free(pData); pData = NULL; } return res; } MRESULT ConvertYuv420pToNV21(MUInt8 * pDest, const MUInt8 * pSource, int iWidth, int iHeight) { if (NULL == pDest || NULL == pSource) { return PERROR; } if (iWidth <= 0 || iHeight <= 0) { return PERROR; } int iArea = iHeight * iWidth; int iSqarea = iArea >> 3; int iQarea = iArea >> 2; int iCount = iSqarea; const unsigned short * pU = (const unsigned short *) (pSource + iArea); const unsigned short * pV = (const unsigned short *) (pSource + iArea + iQarea); unsigned int * pUV = (unsigned int *)(pDest + iArea); memcpy(pDest, pSource, iArea); do { unsigned int uiU = *pU++; unsigned int uiV = *pV++; *pUV++ = ( ( (uiU & 0x00FF) << 8 ) | ( (uiU & 0xFF00) << 16) | ( (uiV & 0x00FF) ) | ( (uiV & 0xFF00) << 8) ); } while (--iCount); return MOK; } MRESULT ConvertYuv420pToNV12(MUInt8 * pDest, const MUInt8 * pSource, int iWidth, int iHeight) { if (NULL == pDest || NULL == pSource) { return PERROR; } if (iWidth <= 0 || iHeight <= 0) { return PERROR; } int iArea = iHeight * iWidth; int iSqarea = iArea >> 3; int iQarea = iArea >> 2; int iCount = iSqarea; const unsigned short * pU = (const unsigned short *) (pSource + iArea); const unsigned short * pV = (const unsigned short *) (pSource + iArea + iQarea); unsigned int * pUV = (unsigned int *)(pDest + iArea); memcpy(pDest, pSource, iArea); do { unsigned int uiU = *pU++; unsigned int uiV = *pV++; *pUV++ = ( ( (uiV & 0x00FF) << 8 ) | ( (uiV & 0xFF00) << 16) | ( (uiU & 0x00FF) ) | ( (uiU & 0xFF00) << 8) ); } while (--iCount); return MOK; } MRESULT ConvertYuv420pToYUYV(MUInt8 * pDest, const MUInt8 * pSource, int iWidth, int iHeight) { if (NULL == pDest || NULL == pSource) { return PERROR; } if (iWidth <= 0 || iHeight <= 0) { return PERROR; } int iStride = iWidth * iHeight; unsigned int x, y; for (y = 0; y < iHeight; ++y) { const MUInt8 *pY = pSource + y * iWidth; const MUInt8 *pU = pSource + iStride + (y / 2) * (iWidth / 2); const MUInt8 *pV = pSource + (iStride * 5) / 4 + (y / 2) * (iWidth / 2); for (x = 0; x < iWidth; x += 2) { *(pDest + 0) = pY[0]; *(pDest + 1) = pU[0]; *(pDest + 2) = pY[1]; *(pDest + 3) = pV[0]; pDest += 4; pY += 2; ++pU; ++pV; } } return MOK; } MRESULT ConvertYuv420pToI422H(MUInt8 * pDest, const MUInt8 * pSource, int iWidth, int iHeight) { if (NULL == pDest || NULL == pSource) { return PERROR; } if (iWidth <= 0 || iHeight <= 0) { return PERROR; } int iStride = iWidth * iHeight; unsigned int x, y; MUInt8 * pDestU = pDest + iStride; MUInt8 * pDestV = pDestU + iStride / 2; memcpy(pDest, pSource, iStride); for (y = 0; y < iHeight; ++y) { const MUInt8 *pU = pSource + iStride + (y / 2) * (iWidth / 2); const MUInt8 *pV = pSource + (iStride * 5) / 4 + (y / 2) * (iWidth / 2); for (x = 0; x < iWidth; x += 2) { *pDestU++ = *pU++; *pDestV++ = *pV++; } } return MOK; } MRESULT ConvertYuv420pToLPI422H(MUInt8 * pDest, const MUInt8 * pSource, int iWidth, int iHeight) { if (NULL == pDest || NULL == pSource) { return PERROR; } if (iWidth <= 0 || iHeight <= 0) { return PERROR; } int iStride = iWidth * iHeight; unsigned int x, y; MUInt8 * pDestUV = pDest + iStride; memcpy(pDest, pSource, iStride); for (y = 0; y < iHeight; ++y) { const MUInt8 *pU = pSource + iStride + (y / 2) * (iWidth / 2); const MUInt8 *pV = pSource + (iStride * 5) / 4 + (y / 2) * (iWidth / 2); for (x = 0; x < iWidth; x += 2) { *pDestUV++ = *pU++; *pDestUV++ = *pV++; } } return MOK; } //conver yuv422 to yuv420 int i; for(i = 0; i < iHeight / 2; i++) { memcpy(*ppImgData + iStride + i * iWidth / 2, pYuvRaw + iStride + i * iWidth, iWidth / 2); memcpy(*ppImgData + iStride * 5 / 4 + i * iWidth / 2, pYuvRaw + iStride * 3 / 2 + i * iWidth, iWidth / 2); }