Application Programming in Linux Environment (7): Image Processing

One: Setting up the image conversion tool environment

1. JPEG file format conversion tool

(1) Download and unzip

tar xzf libjpeg-turbo-1.2.1.tar.gz
(2) Cross compilation

Create a temporary installation directory tmp: mkdir tmp

jun@zero:~/work/file/application/02_picture/lib/libjpeg-turbo-1.2.1$ ./configure --host=arm-linux-gnueabihf --prefix=/home/jun/work/file/application/02_picture/lib/libjpeg-turbo-1.2.1/tmp/

make

make install

(3) Copy the compiled file to the corresponding directory of the cross compilation tool

cp tmp/include/* ~/work/tool/arm-linux-gcc/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/usr/include/

cp tmp/lib/*so* -d ~/work/tool/arm-linux-gcc/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/usr/lib/

(4) Copy the compiled files to the corresponding directory of the development board

2. PNG file format conversion tool

(1) Download and unzip

 tar xzf libpng-1.6.36.tar.gz

(2) Cross compilation

a. Install zlib environment

http://www.zlib.net/

export CC=arm-linux-gnueabihf-gcc 

./configure --prefix=/home/jun/work/tool/arm-linux-gcc/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/zlib (zlib needs to be created in advance , This directory stores the compiled files)

make 

sudo make install

b. Install libpng environment

cd libpng-1.6.36

./configure CC=arm-linux-gnueabihf-gcc --host=arm-linux-gnueabihf CFLAGS=-I/home/jun/work/tool/arm-linux-gcc/gcc-linaro-4.9.4-2017.01- x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/zlib/include LDFLAGS=-L/home/jun/work/tool/arm-linux-gcc/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/ arm-linux-gnueabihf/zlib/lib --prefix=/home/jun/work/tool/arm-linux-gcc/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/ libpng (libpng needs to be created in advance, this directory stores the compiled files)

Modify the Makefile:

在DEFAULT_INCLUDES = -I.下面再加一句DEFAULT_INCLUDES += -I/home/jun/work/tool/arm-linux-gcc/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/zlib/include

make

sudo make install (may need sudo -i first and then make install)

libpng installation reference: https://blog.csdn.net/itolddd9720/article/details/87865217

(3) Copy the compiled file to the corresponding directory of the cross compilation tool

jun@zero:~/work/tool/arm-linux-gcc/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/zlib/lib$ cp * -r -d ../../libc/usr/lib

jun@zero:~/work/tool/arm-linux-gcc/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/zlib/include$ cp * ../../libc/usr/include/

jun@zero:~/work/tool/arm-linux-gcc/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libpng/lib$ cp * -r -d ../../libc/usr/lib

jun@zero:~/work/tool/arm-linux-gcc/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libpng/include$ cp * ../../libc/usr/include/

(4) Copy the compiled files to the development board

Two: Image data conversion algorithm

1、BMP2RGB

The images we generally see are mainly 24-bit images, that is, the three colors of R, G, and B are represented by 8 bits each. Such images are called true colors. In this case, no palette is needed. , That is, the bitmap data is immediately following the bitmap information header. Therefore, we often see such a saying: Bitmap files are offset by 54 bytes from the beginning of the file as bitmap data. This is actually a 24 or 32 bit image. This also explains why the program we write according to this kind of program is useless for some bitmap files.

For detailed explanation of bmp file format, please refer to: https://blog.csdn.net/man9953211/article/details/51890216

(1) Determine whether the received file is in BMP format according to the header information of the bmp file. 1-2 bytes: 424dh ='BM', indicating the supported bitmap format.

IsBmp(&ptData->ptFp, strFileName);
int IsBmp(FILE **ppFp, const char *strFileName) 
{
	char strCheckHeader[2]; 
	*ppFp= fopen(strFileName, "rb+");
	if (*ppFp== NULL) {
		return -1;
	}
	if (fread(strCheckHeader, 1, 2, *ppFp) != 2) 
		return -1;
    
	if (strCheckHeader[0] != 0x42 || strCheckHeader[1] != 0x4d)
		return -1;
	else
		return 0;
}

(2) Map the file data to be displayed to the memory

int MapFile(PT_PictureData ptData)
{
	int iFd;
	struct stat tStat;
	
	/* 打开文件 */
    	iFd = fileno(ptData->ptFp);
	fstat(iFd, &tStat);
	ptData->iFileSize= tStat.st_size;
	ptData->pucFileData= (unsigned char *)mmap(NULL , tStat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, iFd, 0);
	if (ptData->pucFileData == (unsigned char *)-1)
	{
		printf("mmap error!\n");
		return -1;
	}
	return 0;
}

(3) Read the image information from the bmp file and convert it to lcd coordinate data. The 24bpp BMP image is in BGR format

pucDest: save the destination address after data conversion;

 pucSrc: Data source file address, the lower left corner is the origin address (Cartesian coordinates), to be used for LCD display, it needs to be converted to the upper left corner as the origin address (LCD coordinates)

unsigned char *pucSrc;
unsigned char *pucDest;

ptData->pucBmpData = malloc(ptData->iBmpDataSize);
ptData->pucRgbData = malloc(ptData->iBmpDataSize);

pucDest = ptData->pucBmpData;
iLineWidthAlign = (iLineBytes + 3) & ~0x3;   /* 向4取整 */
pucSrc = aFileHead + ptBITMAPFILEHEADER->bfOffBits;

pucSrc = pucSrc + (ptData->iHeight - 1) * iLineWidthAlign;

for (y = 0; y < ptData->iHeight; y++)
{		
    memcpy(pucDest, pucSrc, ptData->iWidth*3);
    pucSrc  -= iLineWidthAlign;
    pucDest += iLineBytes;
}

(4) Convert BGR data to RGB data

for (y = 0; y < ptData->iHeight; y++){		
    for(x = 0;x<ptData->iWidth*3;x+=3){
        ptData->pucRgbData[iPos++] = ptData->pucBmpData[y*ptData->iWidth*3+x+2];
        ptData->pucRgbData[iPos++] = ptData->pucBmpData[y*ptData->iWidth*3+x+1];
        ptData->pucRgbData[iPos++] = ptData->pucBmpData[y*ptData->iWidth*3+x+0];
    }
}

2、JPG2RGB

When converting JPG format files to RGB format, we can use the libjpeg tool API interface installed in the first section. The steps are as follows:

(1) Allocate and initialize a jpeg_decompress_struct structure

struct jpeg_decompress_struct tInfo;
struct jpeg_error_mgr tJerr;

ptData->tInfo.err = jpeg_std_error(&ptData->tJerr);
jpeg_create_decompress(&ptData->tInfo);

(2) Specify the source file

if ((ptData->ptFp= fopen(strFileName, "rb")) == NULL) {
    fprintf(stderr, "can't open %s\n", strFileName);
    return -1;
}

(3) Obtain the jpg information header and set the decompression parameters and judge whether it is a JPEG format file 

if (!IsJpg(ptData, strFileName)) {
    printf("file is not jpg ...\n");
    return -1;
} 

static int IsJpg(PT_PictureData ptData, const char *strFileName) 
{
	int iRet;

	jpeg_stdio_src(&ptData->tInfo, ptData->ptFp);

	/* 用jpeg_read_header获得jpeg信息*/
	iRet = jpeg_read_header(&ptData->tInfo, TRUE);
	
    	return (iRet == JPEG_HEADER_OK);
}

We can get the image information through the image_width, image_height and other members in tInfo. In addition, we can also set member variables such as scale_num and scale_denom in cinfo to set decompression parameters.

/* 默认尺寸为原尺寸 */
ptData->tInfo.scale_num = 1;
ptData->tInfo.scale_denom = 1;

(4) Start decompression

After calling this function, you can decompress the source file specified by cinfo, and store the decompressed data in the member variables of the cinfo structure.

jpeg_start_decompress(&ptData->tInfo);

(5) Read the decompressed data:

jpeg_read_scanlines(&cinfo, buffer, 1),调

After using this function, you can read RGB data into the buffer, and parameter 3 can specify how many rows to read

/* 解压完成后可以通过tInfo中的成员获得图像的某些信息 */
ptData->iWidth= ptData->tInfo.output_width;
ptData->iHeight = ptData->tInfo.output_height;
ptData->iBpp = ptData->tInfo.output_components*8;
/* 计算一行的数据长度 */ 
iRowSize = ptData->iWidth * ptData->tInfo.output_components;
pucbuffer = malloc(iRowSize);
ptData->iRgbSize= iRowSize * ptData->iHeight;
ptData->pucRgbData = malloc(ptData->iRgbSize);

/* pucHelp指向ptData->pucRgbData首地址 */
pucHelp = ptData->pucRgbData;
/* 循环调用jpeg_read_scanlines来一行一行地获得解压的数据 */
while (ptData->tInfo.output_scanline < ptData->tInfo.output_height) 
{
	/* 调用jpeg_read_scanlines得到的时候会存到pucbuffer中 */
	jpeg_read_scanlines(&ptData->tInfo, &pucbuffer, 1);
	/* 将数据一行行读到缓冲区中 */
	memcpy(pucHelp,pucbuffer,iRowSize);
	pucHelp  += iRowSize;
}
free(pucbuffer);

(6) Complete reading

jpeg_finish_decompress(&ptData->tInfo);

(7) Release the jpeg_decompress_struct structure 

jpeg_destroy_decompress(&ptData->tInfo);

3、PNG2RGB

When converting PNG format files to RGB format, we can use the libpng tool API interface installed in the first section. The steps are as follows:

(1) Read the first 8 bytes of the file and use the library function png_sig_cmp to determine whether it is in PNG format

char strCheckHeader[8]; 
*ppFp= fopen(strFileName, "rb");
if (*ppFp== NULL) {
	return -1;
}
if (fread(strCheckHeader, 1, 8, *ppFp) != 8) 
	return -1;
return png_sig_cmp(strCheckHeader, 0, 8); 

(2) Allocate and initialize two libpng-related structures png_ptr and info_ptr

png_structp ptPngStrPoint;//png结构体指针
png_infop ptPngInfoPoint;//png信息结构体指针

ptData->ptPngStrPoint  = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); 
ptData->ptPngInfoPoint= png_create_info_struct(ptData->ptPngStrPoint);

(3) Set the error return point, when an error occurs, libpng will automatically call to return to this point. At this point we can carry out some clean-up work. If no custom error handling function is set when calling png_create_read_struct, this step must be done.

setjmp(png_jmpbuf(ptData->ptPngStrPoint));
rewind(ptData->ptFp); //等价fseek(fp, 0, SEEK_SET);

(4) Specify the source file

png_init_io(ptData->ptPngStrPoint, ptData->ptFp);

(5) Get PNG image information

a. Analyze image data information

This function will decode all picture data into ptData->ptPngInfoPoint data structure. As for the format of the transformation, it is determined by the parameter png_transforms, which is an integer parameter, which can be passed using the macro defined in the libpng library. There are many macros related to this parameter. For details, please refer to the analysis of related files in the library.

png_read_png(ptData->ptPngStrPoint, ptData->ptPngInfoPoint, PNG_TRANSFORM_EXPAND, 0);

b. Query image information

ptData->iChannels 	= png_get_channels(ptData->ptPngStrPoint, ptData->ptPngInfoPoint); 
ptData->iWidth 	 = png_get_image_width(ptData->ptPngStrPoint, ptData->ptPngInfoPoint);
ptData->iHeight  = png_get_image_height(ptData->ptPngStrPoint, ptData->ptPngInfoPoint);

(6) Read out the obtained picture information

a. One-time read

 row_pointers is a pointer to store image data

png_read_image(ptData->ptPngStrPoint, row_pointers);

b. Read line by line

pucPngData is the first address of each row of data

png_bytepp pucPngData;
pucPngData = png_get_rows(ptData->ptPngStrPoint, ptData->ptPngInfoPoint);

(7) Destroy the memory

png_destroy_read_struct(&ptData->ptPngStrPoint, &ptData->ptPngInfoPoint, 0);

Three: image display

static int FBShowPixel(int iX, int iY, unsigned int dwColor)
{
	unsigned char *pucFB;
	unsigned short *pwFB16bpp;
	unsigned int *pdwFB32bpp;
	unsigned short wColor16bpp; /* 565 */
	int iRed;
	int iGreen;
	int iBlue;

	if ((iX >= g_tFBVar.xres) || (iY >= g_tFBVar.yres))
	{
		printf("out of region\n");
		return -1;
	}

	pucFB      = g_pucFBMem + g_dwLineWidth * iY + g_dwPixelWidth * iX;
	pwFB16bpp  = (unsigned short *)pucFB;
	pdwFB32bpp = (unsigned int *)pucFB;
	
	switch (g_tFBVar.bits_per_pixel)
	{
		case 8:
		{
			*pucFB = (unsigned char)dwColor;
			break;
		}
		case 16:
		{
			iRed   = (dwColor >> (16+3)) & 0x1f;
			iGreen = (dwColor >> (8+2)) & 0x3f;
			iBlue  = (dwColor >> 3) & 0x1f;
			wColor16bpp = (iRed << 11) | (iGreen << 5) | iBlue;
			*pwFB16bpp	= wColor16bpp;
			break;
		}
		case 32:
		{
			*pdwFB32bpp = dwColor;
			break;
		}
		default :
		{
			printf("can't support %d bpp\n", g_tFBVar.bits_per_pixel);
			return -1;
		}
	}

	return 0;
}

static void FbShowPicture(PT_PictureData ptData){
	int i ,j;
	int iColor;
	for(i = 0;i<ptData->iRotateHeight;i++){
		for(j = 0;j<ptData->iRotateWidth*3;j+=3){
			if(j/3<g_tFBVar.xres&&i<g_tFBVar.yres){
				iColor = (ptData->pucRotateData[i*ptData->iRotateWidth*3+j+0]<<16) 
        				+ (ptData->pucRotateData[i*ptData->iRotateWidth*3+j+1]<<8) 
        				+ (ptData->pucRotateData[i*ptData->iRotateWidth*3+j+2]<<0);
				if(FBShowPixel(j/3, i, iColor)!=0){
					printf("FBShowPixel error,postion:x = %d,y = %d\n",i,j/3);
				}	
			}
		}
	}
}

 

Guess you like

Origin blog.csdn.net/qq_34968572/article/details/107233517