1862|0

2015

帖子

0

TA的资源

纯净的硅(中级)

楼主
 

TMS320C66x学习笔记之TI官方读BMP程序 [复制链接]

分析程序首先从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图像使用的颜色,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 #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\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.blue, color_table.green, color_table.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.blue = i; color_table.green = i; color_table.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)); } 这里就不解释了直接看注释。
 
点赞 关注

回复
举报
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/7 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表