DSP

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

2019-07-13 10:26发布

    一直想认真写一下关于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: imcsdk_2_01_02_06demosimage_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 #include #include /****************************************************************************/ /* 位图文件头结构体 */ /****************************************************************************/ #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图像使用的颜 {MOD},0表示使用全部颜 {MOD},对于256 {MOD}位图来说,此值为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调 {MOD}板入口结构体 */ /****************************************************************************/ 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); /*****************************************************************************/ /* * * 函数说明:读取调 {MOD}板。这个函数用的比较少,调 {MOD}板是单 {MOD}、16 {MOD}和256 {MOD}图像文件特有。 * */ /*****************************************************************************/ 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 #include #include #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 ", _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) ", _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 ", _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 "); ret_val = -1; return ret_val; } if (bmp_read_header(p_input_image, &bmp_header) < 0) { printf("Error in reading header "); ret_val = -1; return ret_val; } pixel_size = bmp_header.dib.bits_per_pixel / 8;//一个像素的字节数 row_width = bmp_header.dib.image_width * pixel_size;//一行的字节数 /*读调 {MOD}板,现在很多bmp图像都没有调 {MOD}板,可以忽略这一部分*/ 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 "); 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 "); 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 "); 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 ", 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 ", 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 ", 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 ", hdr->dib.compression_type); return -1; } return 0; } /****************************************************************************/ /* 读BMP调 {MOD}板 */ /****************************************************************************/ 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 ", 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: index: blue green red "); for (i = 0; i < hdr->dib.number_of_colors; i++){ printf("%d: 0x%02x 0x%02x 0x%02x ", i, color_table[i].blue, color_table[i].green, color_table[i].red); } } #endif return 0; } /****************************************************************************/ /* 读取图像(像素值) */ /****************************************************************************/ 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)); }    这里就不解释了直接看注释。    需要源代码的朋友,可以留言。谢谢支持。