TI DSP TMS320C66x学习笔记之TI官方读BMP程序(一)

    一直想认真写一下关于DSP的学习笔记,但是由于时间和惰性,徘徊许久,都没能提笔,趁着系统学习TMS320C6657的机会,在此开博,用于对自己学习的总结,也希望能跟大家分享学习心得,相互交流共同进步。

    博客暂时是以自己学习过程为次序,将觉得有必要拿出来分享的经验贴出来,才疏学浅,有错误,请大家不吝赐教。

    TI可以说是很厚道的一家芯片公司,大量的代码和文档给大家学习深入带来了很大方便,但也正因为资料繁多,新手往往不知从何下手。现在提供几个在线学习的网站,大部分问题都可以在这几个网站得到解决。

    首先推荐TI wiki几乎所有的文档都可以通过这里一一找到,网址:http://processors.wiki.ti.com/

    其次是德州仪器在线支持社区,可以在上面提问和搜索你遇到的问题,一般提问在1-2个工作日会有TI的支持工程师解答,在此提一下,这里有很多TI支持发出来的源代码可以用于学习,网址:http://www.deyisupport.com/

    最后是TI的英文帮助社区--TI E2E Community,英文比较好的朋友,在此提问会得到更专业的回答,网址:http://e2e.ti.com/

    好了,现在进入今天的主题,TI官方提供的源代码---读BMP图像。

    可以从多核开发套件的图像处理demo文件夹C:\ti\mcsdk_2_01_02_06\demos\image_processing中导入工程,读BMP图像主要是两个文件mcip_bmp_utils.c和mcip_bmp_utils.h,我的代码也是“拿来主义”,大部分与TI源代码相同,只修改部分,以适用自己的需求,期间对代码进行了详细注释,大家可以参考下,理清思路。


   分析程序首先从mcip_bmp_utils.h开始,贴出BMP图像文件头定义,可以参考本博客---图像处理与模式识别分类中----BMP文件结构,即可了解。它对文件头结构体做了很好的划分,分别后续操作。觉得做得最科学的是它设计了一个原始图像数据的结构体raw_image_data_t,这个做法开始我还不太理解,后来发现,有了它可以将文件的获取和文件解码松耦合,使得原始数据可以从通过任何形式进行获取,例如,TCP、摄像头、文件系统中的原始数据,提高了读BMP图像程序模块的通用性,不仅仅限于在CCS进行软仿,而且可以脱离PC机通过TCP、摄像头之类的方式获取原始图像数据,然后进行BMP图像解码。

#ifndef BMP_UTILS_H
#define BMP_UTILS_H

#include <stdint.h>
#include <xdc/runtime/Memory.h>
#include <xdc/runtime/Error.h>

/****************************************************************************/
/*               位图文件头结构体                                           */
/****************************************************************************/
#ifdef _HOST_BUILD
#pragma pack(1)
#endif

typedef struct bmpfile_signature {
  uint8_t signature[2];      /* Signature - 'BM' */
} bmpfile_signature_t;

typedef struct bmpfile_header {
  uint32_t file_size;       /* BMP图像文件的大小 */
  uint16_t reserved1;
  uint16_t reserved2;
  uint32_t bitmap_offset;   /* BMP图像数据的偏移地址 */
} bmpfile_header_t;

typedef struct bmpfile_dib_header {
  uint32_t header_size;    /* 本结构的大小 */
  int32_t  image_width;        /* 位图的宽度 */
  int32_t  image_height;       /* 位图的高度 */
  uint16_t number_of_planes;      /* Number of planes */
  uint16_t bits_per_pixel;       /* 每个像素的位数 */
  uint32_t compression_type;/* 压缩类型 */
  uint32_t image_size;   /* 表示位图数据区域的大小以字节为单位 */
  int32_t  horizontal_resolution;         /* 水平分辨率,单位像素/m */
  int32_t  vertical_resolution;         /* 垂直分辨率,单位像素/m */
  uint32_t number_of_colors;      /* BMP图像使用的颜色,0表示使用全部颜色,对于256色位图来说,此值为100h=256 */
  uint32_t important_color_count;   /* Important color count */
} bmpfile_dib_header_t;

typedef struct bmp_header {
	bmpfile_signature_t  signature;
	bmpfile_header_t     file;
	bmpfile_dib_header_t dib;
} bmp_header_t;

/****************************************************************************/
/*             位图RGB调色板入口结构体                                      */
/****************************************************************************/
typedef struct {
  uint8_t red;
  uint8_t green;
  uint8_t blue;
  uint8_t reserved;
} bmp_color_table_t;
typedef enum {
  BMP_RGB = 0,
  BMP_RLE8,
  BMP_RLE4,
  BMP_BITFIELDS,
  BMP_JPEG,
  BMP_PNG
} bmp_compression_method_e;

/* 原始图像数据,需要解码
 */

typedef struct raw_image_data {
	uint8_t * data;
	uint32_t  length;
} raw_image_data_t;
    接下来是函数外部声明

/*****************************************************************************/
/**
 *      Created on: 2015-11-9
 *      Author: HeWu
 *      这个函数用于从文件系统中读取文件的元素数据,
 *      参数说明:const char *_fname文件名
 *                      const char *_mode读写模式
 *      返回类型:raw_image_data_t(整个原始文件的字节数据,以及字节长度)
 * */
/*****************************************************************************/
extern raw_image_data_t get_raw_image_data_from_file(const char *_fname, const char *_mode);

/*****************************************************************************/
/**
 *      Created on: 2015-11-9
 *      Author: HeWu
 *      这个函数用于从raw data转换到bmp结构体,
 *      参数说明:raw_image_data_t * p_input_image图像原始字节数据
 *                      unsigned char * p_output_pixel_array图像的像素信息,用于后续处理
 *            返回:raw_image_data_t结构体
 * */
/*****************************************************************************/
extern int raw_data_cvt_bmp_pixels(raw_image_data_t * p_input_image,unsigned char * p_output_pixel_array);

/*****************************************************************************/
/* *
 * 函数功能:这个函数BMP文件中读取文件头信息。
 * 说明:函数对文件做了一些初步的检查。
 *          如果读取文件成功返回0;
 *          如果读取文件失败或检查失败,返回负数。
 */
/*****************************************************************************/
extern int bmp_read_header (raw_image_data_t * image, bmp_header_t * hdr);

/*****************************************************************************/
/* *
 * 函数说明:读取调色板。这个函数用的比较少,调色板是单色、16色和256色图像文件特有。
 *
 */
/*****************************************************************************/
extern int bmp_read_colormap (raw_image_data_t * image, bmp_header_t * hdr,
				bmp_color_table_t * color_table);

/*****************************************************************************/
/* *
 * 函数功能:读取图像(像素值),需要计算像素占用字节数。
 * 参数说明:raw_image_data_t * image,待解码数据
 *                 bmp_header_t * hdr, 文件头
 *                 uint8_t * pixel_array_rgb,用于返回的像素值指针,后续图像算法就是对它进行了
 */
extern int bmp_read_image (raw_image_data_t * image, bmp_header_t * hdr, uint8_t * pixel_array_rgb);

/*****************************************************************************/
/* *
 * 函数功能:通过BMP图像,创建并将像素值保存为灰度图像。
 * 参数说明:raw_image_data_t * image,保存结果
 *                 uint8_t * pixel_array,像素值指针
 */
/*****************************************************************************/
extern int bmp_write_gray_bmpfile (raw_image_data_t * image, uint8_t * pixel_array,
		                           uint32_t width, uint32_t height);

/*****************************************************************************/
/*
 * 函数功能:获取灰度BMP图的文件大小
 */
/*****************************************************************************/
extern uint32_t bmp_get_gray_bmpfile_size (uint32_t width, uint32_t height);

#endif /*BMP_UTILS_H*/
    对一下两个函数稍作解释,
extern raw_image_data_t get_raw_image_data_from_file(const char *_fname, const char *_mode);
extern int raw_data_cvt_bmp_pixels(raw_image_data_t * p_input_image,unsigned char * p_output_pixel_array);
    这两个函数本身不应该放在这个读bmp模块中,这是直接写来,第一个是从文件系统中获取原始图像数据(也可以从其他途径获取),第二个是将原始图像解码成像素数组(读取BMP图像的完整先bmp_read_header()函数和后bmp_read_image()函数)。

    

    下面是mcip_bmp_utils.c函数的实现文件。

/* ======================================================================== */
/*  TEXAS INSTRUMENTS, INC.                                                 */
/*                                                                          */
/* ======================================================================== */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mcip_bmp_utils.h"


/*#define BMP_UTILS_DEBUG*/


/* BMP灰度图像默认文件头*/
static bmp_header_t default_grayscale_bmp_header = {
		{
			{'B', 'M'} /*signature*/
		},
		{
			263222,  /*file_size*/
			0, 0,    /*reserved1, reserved2*/
			1078     /*bitmap_offset*/
		},
		{
			40,      /*header_size*/
			512,     /*width*/
			512,     /*height*/
			1,       /*nplanes*/
			8,       /*bitspp*/
			0,       /*compress_type*/
			262144,  /*bmp_bytesz*/
			0,       /*hres*/
			0,       /*vres*/
			256,     /*ncolors*/
			0        /*nimpcolors*/
		}
};


/*****************************************************************************/
/**
 *      Created on: 2015-11-9
 *      Author: HeWu
 *      这个函数用于从文件系统中读取文件的元素数据,
 *      返回类型包括整个文件的字节数据,以及字节长度
 * */
/*****************************************************************************/
raw_image_data_t get_raw_image_data_from_file(const char *_fname, const char *_mode)
{
	Error_Block eb;
	Error_init(&eb);
	FILE * fpr = 0;
	raw_image_data_t  raw_image = {0, 0};
	uint32_t read_length = 0;
    int ret_val = 0;


	fpr = fopen(_fname, _mode);
	if(!fpr) {
		printf("Unable to open image file %s\n", _fname);
	}


	fseek(fpr, 0, SEEK_END);
	raw_image.length = ftell(fpr);
	fseek(fpr, 0, SEEK_SET);


	/**
	 * 之所以用这个Memory_alloc(),而不用malloc(),
	 * 是为了放置内存碎片化,还是用TI提供的函数咯
	 * */
	raw_image.data = (uint8_t*)Memory_alloc(NULL,raw_image.length,0,&eb);
	if(!raw_image.data) {
		printf("Unable allocate buffer for raw image file read (%s)\n", _fname);
	}


     //fread()返回的是已读取的字节数,ret_val用于指针移动和检查
	do {
		ret_val = fread(raw_image.data + read_length, 1, raw_image.length - read_length, fpr);
		if (!ret_val) {
			printf("Unable read the raw image file %s\n", _fname);
		}
		read_length += ret_val;
	} while (read_length < raw_image.length);
	return raw_image;//返回原始图像数据
}
/*****************************************************************************/
/**
 *      Created on: 2015-11-9
 *      Author: HeWu
 *      这个函数用于从raw data转换到bmp结构体,
 *      返回类型包括像素数据指针
 * */
/*****************************************************************************/
extern int raw_data_cvt_bmp_pixels(raw_image_data_t * p_input_image,unsigned char * p_output_pixel_array)
{
	    Error_Block eb;
	    Error_init(&eb);
	    bmp_color_table_t * p_color_table = 0;
	    bmp_header_t bmp_header;
	    uint8_t * pixel_array_rgb = 0;
	    int  color_table_size,pixel_array_rgb_size;
	    int pixel_size, row_width;
	    int i, j, ret_val = 0;
    
	    if ((p_input_image == 0) || (p_input_image->length == 0) || (p_input_image->data == 0)) {
	        printf("Invalid BMP image data\n");
	        ret_val = -1;
	        return ret_val;
	    }


	    if (bmp_read_header(p_input_image, &bmp_header) < 0) {
	        printf("Error in reading header\n");
	        ret_val = -1;
	        return ret_val;
	    }


	    pixel_size = bmp_header.dib.bits_per_pixel / 8;//一个像素的字节数
	    row_width  = bmp_header.dib.image_width * pixel_size;//一行的字节数


        /*读调色板,现在很多bmp图像都没有调色板,可以忽略这一部分*/
	    if (bmp_header.dib.number_of_colors) {
	        /* Color table present */
	        color_table_size = sizeof(bmp_color_table_t) * bmp_header.dib.number_of_colors;
	        p_color_table = (bmp_color_table_t *)Memory_alloc(NULL,color_table_size,0,&eb);
	        if(!p_color_table) {
	            printf("Can't allocate memory for color table\n");
	            ret_val = -1;
	            return ret_val;
	        }
	        if (bmp_read_colormap(p_input_image, &bmp_header, p_color_table) < 0) {
	            printf("Error in reading color map\n");
	            ret_val = -1;
	            return ret_val;
	        }
	    }


	    /* 读像素数据 ,直接由第二个参数传入指针,不用在此分配内存*/
	     if (bmp_read_image (p_input_image, &bmp_header, p_output_pixel_array) < 0) {
	         printf("Error in reading pixel image\n");
	         ret_val = -1;
	         return ret_val;
	     }


}


/****************************************************************************/
 /* 读BMP信息头                                            */
/****************************************************************************/
int bmp_read_header (raw_image_data_t * image, bmp_header_t * hdr)
{
	/*如果文件头结构体大于原始图像数据大小,则是无效图像*/
    if (image->length < 
        sizeof(bmpfile_signature_t) + sizeof(bmpfile_header_t) + sizeof(bmpfile_dib_header_t)) {
        printf ("Insufficient Image Buffer Length %d\n", image->length);
        return -1;
    }


    /*将原始图像数据解码到三个BMP文件头结构体*/
	memcpy(&(hdr->signature), image->data, sizeof(bmpfile_signature_t));
	memcpy(&(hdr->file), image->data + sizeof(bmpfile_signature_t),
			sizeof(bmpfile_header_t));
	memcpy(&(hdr->dib), image->data + sizeof(bmpfile_signature_t) + sizeof(bmpfile_header_t),
			sizeof(bmpfile_dib_header_t));

	/*做一些检查,自己看英文咯*/
	if((hdr->signature.signature[0] != 'B') || (hdr->signature.signature[1] != 'M')) {
		printf("Incorrect MAGIC number 0x%x 0x%x\n", hdr->signature.signature[0], hdr->signature.signature[1]);
		return -1;
	}


	if((hdr->dib.bits_per_pixel != 8) &&  (hdr->dib.bits_per_pixel != 24)) {
		printf("Only 8 or 24 bits per pixel supported, the image bpp is %d\n", hdr->dib.bits_per_pixel);
		return -1;
	}


	if(hdr->dib.compression_type != BMP_RGB) {
		printf("Need a RGB type image, the image type is %d\n", hdr->dib.compression_type);
		return -1;
	}
	
	return 0;
}


/****************************************************************************/
/*  读BMP调色板                                                                                         */
/****************************************************************************/
int bmp_read_colormap (raw_image_data_t * image, bmp_header_t * hdr,
						bmp_color_table_t * color_table)
{
	int index;


	if(hdr->dib.number_of_colors == 0) {
		printf("Color table can't be read, ncolors = %d\n", hdr->dib.number_of_colors);
		return -1;
	}


	index = sizeof(bmpfile_signature_t) + sizeof(bmpfile_header_t) + hdr->dib.header_size;


	memcpy(color_table, image->data + index, sizeof(bmp_color_table_t) * hdr->dib.number_of_colors);


#if BMP_UTILS_DEBUG
	{
		int i;
		printf("Color Table:\nindex:\tblue\tgreen\tred\n");
		for (i = 0; i < hdr->dib.number_of_colors; i++){
			printf("%d:\t0x%02x\t0x%02x\t0x%02x\n",
				i,  color_table[i].blue, color_table[i].green, color_table[i].red);
		}
	}
#endif
	return 0;
}


/****************************************************************************/
/*  <span style="font-family: Arial, Helvetica, sans-serif;">读取图像(像素值)</span><span style="font-family: Arial, Helvetica, sans-serif;">                                     */</span>
/****************************************************************************/
int bmp_read_image (raw_image_data_t * image, bmp_header_t * hdr, uint8_t * pixel_array_rgb)
{ 
	int i;
	int index;
	int pixel_size = hdr->dib.bits_per_pixel / 8;//一个像素字节数
	int row_width  = hdr->dib.image_width * pixel_size;//一行字节数
	int row_width_with_pad = ((row_width) + 3) & (~3);//这里不懂?一下跳四个字节?应该是对齐?


	for(i = 0; i < hdr->dib.image_height; i++) {
		/*index从原始图像数据最后一行开始,与bmp结构有关,自己查*/
		index = hdr->file.bitmap_offset + (row_width_with_pad * (hdr->dib.image_height - i - 1));
		/*读取row_width个字节,将原始图像数据最后一行当做真实图像pixel_array_rgb像素值的第一行*/
		memcpy(pixel_array_rgb + (i * row_width), image->data + index, row_width);

	}
	return 0;
}


/****************************************************************************/
/*   存储灰度图像到文件中                                        */
/****************************************************************************/
int bmp_write_gray_bmpfile (raw_image_data_t * image, uint8_t * pixel_array,
		                    uint32_t width, uint32_t height)
{
	int i;
	int index = 0;
	int row_width_with_pad = (width + 3) & (~3);
	int pad_size = row_width_with_pad - width;
	bmp_color_table_t * color_table = 0;
	uint8_t * pad_array = 0;
	bmp_header_t hdr = default_grayscale_bmp_header;
    int ret_val = 0;


	if(pad_size) {
		pad_array = calloc(pad_size, 1);
	}


	hdr.dib.image_height     = height;
	hdr.dib.image_width      = width;
	hdr.dib.image_size = (row_width_with_pad * hdr.dib.image_height);


	color_table = calloc(sizeof(bmp_color_table_t), hdr.dib.number_of_colors);


	for(i = 0; i < hdr.dib.number_of_colors; i++) {
		color_table[i].blue  = i;
		color_table[i].green = i;
		color_table[i].red   = i;
	}


	hdr.file.file_size =
			sizeof(bmpfile_signature_t) + sizeof(bmpfile_header_t)
			+ hdr.dib.header_size
			+ (sizeof(bmp_color_table_t) * hdr.dib.number_of_colors)
			+ (row_width_with_pad * hdr.dib.image_height);
	hdr.file.bitmap_offset =
			sizeof(bmpfile_signature_t)
			+ sizeof(bmpfile_header_t) + hdr.dib.header_size
			+ (sizeof(bmp_color_table_t) * hdr.dib.number_of_colors);


    if (image->length < hdr.file.file_size) {
		printf("Insufficient image array size %d (expected %d)", 
            image->length, hdr.file.file_size);
		ret_val = -1;
        goto close_n_exit;
    }


	memcpy(image->data, &hdr.signature, sizeof(bmpfile_signature_t));
	index = sizeof(bmpfile_signature_t);
	memcpy(image->data + index, &hdr.file, sizeof(bmpfile_header_t));
	index += sizeof(bmpfile_header_t);
	memcpy(image->data + index, &hdr.dib, sizeof(bmpfile_dib_header_t));
	index += sizeof(bmpfile_dib_header_t);
	memcpy(image->data + index, color_table, sizeof(bmp_color_table_t) * hdr.dib.number_of_colors);
	index += sizeof(bmp_color_table_t) * hdr.dib.number_of_colors;


	for(i = hdr.dib.image_height - 1; i >= 0; i--) {
		memcpy(image->data + index, pixel_array + (hdr.dib.image_width * i), hdr.dib.image_width);
		index += hdr.dib.image_width;
		if (pad_size) {
			memcpy(image->data + index, pad_array, pad_size);
			index += pad_size;
		}
	}


    ret_val = 0;


close_n_exit:
	if(color_table) free(color_table);
    if(pad_array)   free(pad_array);


	return ret_val;
}


/****************************************************************************/
/*  获取灰度图像文件的文件大小                                     */
/****************************************************************************/
uint32_t bmp_get_gray_bmpfile_size (uint32_t width, uint32_t height)
{
	int row_width_with_pad = (width + 3) & (~3);
	/*默认bmp文件头,修改一些信息,返回真实图像文件大小*/
	bmp_header_t hdr = default_grayscale_bmp_header;


	return(sizeof(bmpfile_signature_t) + sizeof(bmpfile_header_t)
			+ hdr.dib.header_size
			+ (sizeof(bmp_color_table_t) * hdr.dib.number_of_colors)
			+ (row_width_with_pad * height));
}

   这里就不解释了直接看注释。

   需要源代码的朋友,可以留言。谢谢支持。

猜你喜欢

转载自blog.csdn.net/hw5226349/article/details/49761167
TI
今日推荐