Linux应用编程(二):图像处理

一:图像转换工具环境搭建

1、JPEG文件格式转换工具

(1)下载解压

tar xzf libjpeg-turbo-1.2.1.tar.gz
(2)交叉编译

创建临时安装目录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)将编译文件拷贝到交叉编译工具对应目录下

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)将编译文件拷贝到开发板对应的目录下

2、PNG文件格式转换工具

(1)下载解压

 tar xzf libpng-1.6.36.tar.gz

(2)交叉编译

a.安装zlib环境

http://www.zlib.net/

Linux应用编程(二):图像处理_第1张图片

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需要提前创建,该目录存放编译后的文件)

make 

sudo make install

b.安装libpng环境

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需要提前创建,该目录存放编译后的文件)

修改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(可能需要先sudo -i 再 make install)

libpng安装参考:https://blog.csdn.net/itolddd9720/article/details/87865217

(3)将编译文件拷贝到交叉编译工具对应目录下

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)将编译后的文件拷贝的开发板中

二:图像数据转换算法

1、BMP2RGB

Linux应用编程(二):图像处理_第2张图片

我们一般见到的图像以24位图像为主,即R、G、B三种颜色各用8个bit来表示,这样的图像我们称为真彩色,这种情况下是不需要调色板的,也就是所位图信息头后面紧跟的就是位图数据了。因此,我们常常见到有这样一种说法:位图文件从文件头开始偏移54个字节就是位图数据了,这其实说的是24或32位图的情况。这也就解释了我们按照这种程序写出来的程序为什么对某些位图文件没用了。

bmp文件格式详解参考:https://blog.csdn.net/man9953211/article/details/51890216

(1)根据bmp文件的头部信息判断接收的文件是否为BMP格式。1-2字节  :424dh = 'BM',表示支持的位图格式。

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)将要显示的文件数据映射到内存当中

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)从bmp文件中读取图像信息并转换为lcd坐标数据,24bpp的BMP图像为BGR格式

pucDest:数据转换后存放目标地址;

 pucSrc:数据源文件地址,以左下角为原点地址(笛卡尔坐标),要用于lcd显示需转换为左上角为原点地址(LCD坐标)

Linux应用编程(二):图像处理_第3张图片Linux应用编程(二):图像处理_第4张图片

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)将BGR数据转换为RGB数据

for (y = 0; y < ptData->iHeight; y++){		
    for(x = 0;xiWidth*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

对于JPG格式文件转换为RGB格式时我们可以用到第一节安装的libjpeg工具API接口,使用步骤如下:

(1)分配和初始化一个jpeg_decompress_struct结构体

struct jpeg_decompress_struct tInfo;
struct jpeg_error_mgr tJerr;

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

(2)指定源文件

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

(3)获得jpg信息头并设置解压参数并判断是否为JPEG格式文件 

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);
}

我们就可以通过tInfo中的image_width,image_height等成员来获得图像的信息了。此外我们还可以设置cinfo中的scale_num和scale_denom等成员变量来设置解压参数。

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

(4)启动解压

调用这个函数后,就可以对cinfo所指定的源文件进行解压,并将解压后的数据存到cinfo结构体的成员变量中。

jpeg_start_decompress(&ptData->tInfo);

(5)读取解压后的数据:

jpeg_read_scanlines(&cinfo, buffer, 1),调

用这个函数后,可以读取RGB数据到buffer中,参数3能指定读取多少行

/* 解压完成后可以通过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)完成读取

jpeg_finish_decompress(&ptData->tInfo);

(7)释放jpeg_decompress_struct结构体 

jpeg_destroy_decompress(&ptData->tInfo);

3、PNG2RGB

对于PNG格式文件转换为RGB格式时我们可以用到第一节安装的libpng工具API接口,使用步骤如下:

(1)读取文件前8个字节,使用库函数png_sig_cmp判断是否为PNG格式

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)分配和初始化两个与libpng相关的结构体png_ptr,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)设置错误返回点,当出现错误时,libpng将会自动调用返回到这个点。在这个点我们可以进行一些清理工作。如果在调用png_create_read_struct时没有设置自定义的错误处理函数,这一步是必须要做的。

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

(4)指定源文件

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

(5)获取PNG图像信息

a.解析图片数据信息

该函数会把所有的图片数据解码到ptData->ptPngInfoPoint数据结构中。至于转化为什么格式,由参数png_transforms决定,它是一个整型参数,可以使用libpng库中定义的宏进行传参。这个参数相关的宏有很多,具体的可以参考库中的相关文件的解析。

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

b.查询图像信息

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)将获取的图片信息读出来

a.一次性读取

 row_pointers是存放图片数据的指针

png_read_image(ptData->ptPngStrPoint, row_pointers);

b.逐行读取

pucPngData是每行数据的首地址

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

(7)销毁内存

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

三:图像显示

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;iiRotateHeight;i++){
		for(j = 0;jiRotateWidth*3;j+=3){
			if(j/3pucRotateData[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);
				}	
			}
		}
	}
}

 

你可能感兴趣的:(Linux应用开发)