申请书范文网,分享全网优秀范文,学习好帮手!
申请书范文网 > 【数字图像处理】BMP图片的读取显示存储(C语言实现)

【数字图像处理】BMP图片的读取显示存储(C语言实现)

时间:2019-12-01 07:59:36

相关推荐

【数字图像处理】BMP图片的读取显示存储(C语言实现)

(一)背景介绍

这段时间接到了一个新活,是关于图像处理的一个探地摄像头的项目。所以也差不多是时候开始学习一下数字图像处理的知识了。本来我们的方案是直接移植opencv,编译一下以后其他就基本啥都不用管了,非常方便。但是最后还是决定不适用这个方案。

为什么放弃了opencv

1.opencv的平台限制

opencv的平台依赖性太强,只能运行于X86电脑和嵌入式LINUX平台,这意味这一些底层永远都无法接触到。而且程序不可能跑在裸机平台上了。如果硬要一直到逻辑平台上的话代价比自己写一个程序要大。

2.自己想要搞清数字图像处理的底层实现

前段时间自己一直在看关于opencv的书,就看那些乱七八糟一堆一堆的函数,感觉啥都没有学到。

前段时间看到这样一句话,我们需要警惕开源软件。没错他们是很香,但是他们会让你失去自己的独立性,真正的程序员最好应该是不给自己任何可以依赖的东西的。

所以我决定除了C库什么都不依赖,所有底层全部自己敲一遍,同时尽可能为以后扩展跨平台的特性提供接口。

(二)框架设计

写代码写到了今天,不可能在向之前一样闭着眼睛就开始写代码。写代码之前理清思路可以给自己省去许多麻烦。

现在再来回顾一下项目需求。

1.只用C库实现。

2.为今后的跨平台特性提供接口

3.函数高内聚低耦合,具有较强的可移植性

下面是系统框图

实现这个最大的问题在于C语言并不支持类的使用,在重载,继承等特性上也没有,想要实现这种面对对象的程序设计我们得要另外再想方法。

在实现上面其实主要就是图片的读取,保存,加载,显示,拷贝,析构等功能。现在基本已经实现。

(三)程序设计

(1)BMP详解

BMP图片简介:

BMP图片是windows操作系统中的标准图像文件格式,可以分为两类:设备相关位图(DDB)和设备无关位图(DIB),使用广泛。它采用位映射存储格式,除了图像深度可选以外,不采用其他任何压缩,因此,BMP文件所占用的空间很大。BMP文件的图像深度可选lbit、4bit、8bit及24bit。BMP文件存储数据时,图像的扫描方式是按从左到右、从下到上的顺序。由于BMP文件格式是Windows环境中交换与图有关的数据的一种标准,因此在Windows环境中运行的图形图像软件都支持BMP图像格式。

BMP图片的存储:

1:位图头文件数据结构,它包含BMP图像文件的类型、显示内容等信息;

2:位图信息数据结构,它包含有BMP图像的宽、高、压缩方法,以及定义颜色等信息;

3:调色板,这个部分是可选的,有些位图需要调色板,有些位图,比如真彩色图(24位的BMP)就不需要调色板;

4:位图数据,这部分的内容根据BMP位图使用的位数不同而不同,在24位图中直接使用RGB,而其他的小于24位的使用调色板中颜色索引值。

C 语言程序设计思路:

1、定义一个存储头文件数据结构体

typedef struct tagBITMAPFILEHEADER{unsigned short bfType;//保存图片类型。 'BM'unsigned long bfSize;//位图文件的大小,以字节为单位(3-6字节,低位在前)unsigned short bfReserved1;//位图文件保留字,必须为0(7-8字节)unsigned short bfReserved2;//位图文件保留字,必须为0(9-10字节)unsigned long bfOffBits; //RGB数据偏移地址,位图数据的起始位置,以相对于位图(11-14字节,低位在前)}BITMAPFILEHEADER;

2定义一个存储位图信息的结构体

typedef struct tagBITMAPINFOHEADER{unsigned long biSize;//本结构所占用字节数(15-18字节)unsigned long biWidth;//位图的宽度,以像素为单位(19-22字节)unsigned long biHeight; //位图的高度,以像素为单位(23-26字节)unsigned short biPlanes; //目标设备的级别,必须为1(27-28字节)unsigned short biBitCount; //每个像素所需的位数,必须是1(双色)(29-30字节),4(16色),8(256色)16(高彩色)或24(真彩色)之一unsigned long biCompression;//位图压缩类型,必须是0(不压缩),(31-34字节)//1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一unsigned long biSizeImage; //位图的大小(其中包含了为了补齐行数是4的倍数而添加的空字节),以字节为单位(35-38字节)unsigned long biXPelsPerMeter;//位图水平分辨率,每米像素数(39-42字节)unsigned long biYPelsPerMeter;//位图垂直分辨率,每米像素数(43-46字节)unsigned long biClrUsed;//位图实际使用的颜色表中的颜色数(47-50字节)unsigned long biClrImportant; //位图显示过程中重要的颜色数(51-54字节)}BITMAPINFOHEADER;

然后就是对于文件的一些读取写入的事情

在写程序是特别注意要将BMP的部分和图片有关处理的部分进行解耦。方便日后扩展其他的图片格式。

核心的文件主要是两个:bmp.c bmp.h

bmp.h

C图像类顶层头文件

/** @Descripttion: 提供对于BMP文件的底层处理函数* @version: V2.0* @Author: Yueyang* @email: 1700695611@* @Date: -10-26 19:35:49* @LastEditors: Yueyang* @LastEditTime: -10-31 12:06:11*/#ifndef BMP_H_INCLUDED#define BMP_H_INCLUDED#include "stdio.h"#include "cv.h"/*** 黑白:文件头(14字节)+信息头(40字节)+2个调色板(共8字节)+Height(图像高度)*(Width+8-Width%8)/8 16色:文件头(14字节)+信息头(40字节)+16个调色板(共64字节)+Height(图像高度)*(Width+4-Width%4)/2 256色:文件头(14字节)+信息头(40字节)+256个调色板(共1024字节)+Height(图像高度)*(Width+4-Width%4)16位色:文件头(14字节)+信息头(40字节)+Height(图像高度)*(Width+4-Width%4)*2 (由于每个像素由两个字节表示)24位色:文件头(14字节)+信息头(40字节)+Height(图像高度)*(Width+4-Width%4)*3 (由于每个像素由三个字节表示)* *//*** 字 段 名描 述biSize(填40进去)4本结构的大小,根据不同的操作系统而不同,在Windows中,此字段的值总为28h字节=40字biWidth4BMP图像的宽度,单位像素biHeight4BMP图像的高度,单位像素biPlanes(1)2总为1biBitCount(DRP+1)*82BMP图像的色深,即一个像素用多少位表示,常见有1、4、8、16、24和32,分别对应单色、16色、256色、16位高彩色、24位真彩色和32位增强型真彩色biCompression(0)4压缩方式,0表示不压缩,1表示RLE8压缩,2表示RLE4压缩,3表示每个像素值由指定的掩码决定biSizeImage4BMP图像数据大小,必须是4的倍数,图像数据大小不是4的倍数时用0填充补足//可以决定在物理上图片的大小biXPelsPerMeter(3780)4水平分辨率,单位像素/mbiYPelsPerMeter(3780)4垂直分辨率,单位像素/mbiClrUsed(0)4BMP图像使用的颜色,0表示使用全部颜色,对于256色位图来说,此值为100h=256biClrImportant(0)4重要的颜色数,此值为0时所有颜色都重要,对于使用调色板的BMP图像来说,当显卡不能够显示所有颜色时,此值将辅助驱动程序显示颜色*//** 与BMP文件有关的变量*/typedef struct {// bmihDWORD biSize;LONG biWidth;LONG biHeight;WORD biPlanes;WORD biBitCount;DWORD biCompression;DWORD biSizeImage;LONG biXPelsPerMeter;LONG biYPelsPerMeter;DWORD biClrUsed;DWORD biClrImportant;}BITMAPINFOHEADER;/**bfType:位图文件类型,必须是0x424D,即字符串“BM”,也就是说,所有的“*.bmp”文件的头两个字节都是“BM”。*bfSize:位图文件大小,包括这14个字节。*bfReserved1, bfReserved2:Windows保留字,暂不用。*bfOffBits:(bfsize+bisize)从文件头到实际的位图数据的偏移字节数*/typedef struct {// bmfhWORD bfType;DWORD bfSize;WORD bfReserved1;WORD bfReserved2;DWORD bfOffBits;}BITMAPFILEHEADER;//调色板typedef struct{unsigned char rgbBlue; //该颜色的蓝色分量 unsigned char rgbGreen; //该颜色的绿色分量 unsigned char rgbRed; //该颜色的红色分量 unsigned char rgbReserved; //保留值 } RGBQuad;/*** @name: Read_bmp* @msg: 读取一个BMP图片* @param char *filepath 读取文件的路径* BITMAPFILEHEADER *bmf 与文件有关的信息* BITMAPINFOHEADER *bmi 与图片有关的信息* @return 数据指针*/BYTE* Read_bmp(BYTE *filepath,BITMAPFILEHEADER *bmf,BITMAPINFOHEADER *bmi);/*** @name: * @msg: 写BMP图片,只负责写数据,没有图片的转换功能* @param char *filepath 读取文件的路径* BYTE *imgData 读到的数据* BITMAPFILEHEADER *bmf 与文件有关的信息* BITMAPINFOHEADER *bmi 与图片有关的信息* PICTYPE pt 图片类型* @return 0 (right) or -1(something wrong)*/BYTE Write_bmp(BYTE *filepath,BYTE *imgData,BITMAPFILEHEADER *bmf,BITMAPINFOHEADER *bmi,PICTYPE pt);void Print_bmp_FileHeader(BITMAPFILEHEADER *bmfh);void Print_bmp_InfoHeader(BITMAPINFOHEADER *bmih);#endif

bmp.c

/** @Descripttion: BMP的底层函数* @version: V 2.0* @Author: Yueyang* @email: 1700695611@* @Date: -11-04 01:22:01* @LastEditors: Yueyang* @LastEditTime: -11-10 22:40:10*/#ifndef BMP_H#define BMP_H#include <stdio.h>#include <stdlib.h>#include <string.h>#include <malloc.h>#include "string.h"#include "bmp.h"int Read_bmp_FileHeader(char *filepath,BITMAPFILEHEADER *bmfh){FILE *fp;fp=fopen(filepath,"rb");if(!fp){return -1;}if(fread(&bmfh->bfType,sizeof(WORD),1,fp)!=1){fclose(fp);return -1;}if(fread(&bmfh->bfSize,sizeof(DWORD),1,fp)!=1){fclose(fp);return -1;}if(fread(&bmfh->bfReserved1,sizeof(WORD),1,fp)!=1){fclose(fp);return -1;}if(fread(&bmfh->bfReserved2,sizeof(WORD),1,fp)!=1){fclose(fp);return -1;}if(fread(&bmfh->bfOffBits,sizeof(DWORD),1,fp)!=1){fclose(fp);return -1;}fclose(fp);return 0;}int Read_bmp_InfoHeader(char *filepath,BITMAPINFOHEADER *bmih){FILE *fp;fp=fopen(filepath,"rb");if(!fp){return -1;}fseek(fp,14,SEEK_SET);if(fread(&bmih->biSize,sizeof(DWORD),1,fp)!=1){fclose(fp);return -1;}if(fread(&bmih->biWidth,sizeof(LONG),1,fp)!=1){fclose(fp);return -1;}if(fread(&bmih->biHeight,sizeof(LONG),1,fp)!=1){fclose(fp);return -1;}if(fread(&bmih->biPlanes,sizeof(WORD),1,fp)!=1){fclose(fp);return -1;}if(fread(&bmih->biBitCount,sizeof(WORD),1,fp)!=1){fclose(fp);return -1;}if(fread(&bmih->biCompression,sizeof(DWORD),1,fp)!=1){fclose(fp);return -1;}if(fread(&bmih->biSizeImage,sizeof(DWORD),1,fp)!=1){fclose(fp);return -1;}if(fread(&bmih->biXPelsPerMeter,sizeof(LONG),1,fp)!=1){fclose(fp);return -1;}if(fread(&bmih->biYPelsPerMeter,sizeof(LONG),1,fp)!=1){fclose(fp);return -1;}if(fread(&bmih->biClrUsed,sizeof(DWORD),1,fp)!=1){fclose(fp);return -1;}if(fread(&bmih->biClrImportant,sizeof(DWORD),1,fp)!=1){fclose(fp);return -1;}fclose(fp);return 0;}void Print_bmp_FileHeader(BITMAPFILEHEADER *bmfh){printf("The contents in the file header of the BMP file:\n");printf("bfOffBits: %ld\n",(long int)bmfh->bfOffBits);printf("bfReserved1: %ld\n",(long int)bmfh->bfReserved1);printf("bfReserved2: %ld\n",(long int)bmfh->bfReserved2);printf("bfSize: %ld\n",(long int)bmfh->bfSize);printf("bfType: %ld\n",(long int)bmfh->bfType);}void Print_bmp_InfoHeader(BITMAPINFOHEADER *bmih){printf("The content in the info header of the BMP file:\n");printf("biBitCount: %ld\n",(long int)bmih->biBitCount);printf("biClrImportant: %ld\n",(long int)bmih->biClrImportant);printf("biClrUsed: %ld\n",(long int)bmih->biClrUsed);printf("biCompression: %ld\n",(long int)bmih->biCompression);printf("biHeight: %ld\n",(long int)bmih->biHeight);printf("biPlanes: %ld\n",(long int)bmih->biPlanes);printf("biSize: %ld\n",(long int)bmih->biSize);printf("biSizeImage: %ld\n",(long int)bmih->biSizeImage);printf("biWidth: %ld\n",(long int)bmih->biWidth);printf("biXPelsPerMeter: %ld\n",(long int)bmih->biXPelsPerMeter);printf("biYPelsPerMeter: %ld\n",(long int)bmih->biYPelsPerMeter);}/*** @name: Read_bmp* @msg: 读取一个BMP图片* @param char *filepath 读取文件的路径* BITMAPFILEHEADER *bmf 与文件有关的信息* BITMAPINFOHEADER *bmi 与图片有关的信息* @return 数据指针*/BYTE* Read_bmp(BYTE *filepath,BITMAPFILEHEADER *bmf,BITMAPINFOHEADER *bmi){BYTE *imgData;BITMAPINFOHEADER bmih;BITMAPFILEHEADER bmfh;FILE *fp;u8 R, G, B;u16 pixel;int n,i;int width;int height;int bitCount;DWORD dwLineBytes;n=Read_bmp_FileHeader(filepath,&bmfh);if(n==-1){printf("Can not read the file header of the BMP file.\n");return NULL;}n=Read_bmp_InfoHeader(filepath,&bmih);if(n==-1){printf("Can not read the info header of the BMP file.\n");return NULL;}memcpy(bmi,&bmih,sizeof(BITMAPINFOHEADER));memcpy(bmf,&bmfh,sizeof(BITMAPFILEHEADER));#ifdef DEBUGPrint_bmp_FileHeader(bmf);Print_bmp_InfoHeader(bmi);#endif // DEBUGwidth=bmih.biWidth;height=bmih.biHeight;bitCount=bmih.biBitCount;imgData=(BYTE*)malloc((bitCount/(8*sizeof(BYTE)))*width*height*sizeof(BYTE));fp=fopen(filepath,"rb");if(!fp){printf("Can not open the file: %s\n",filepath);return NULL;}fseek(fp,bmfh.bfOffBits,SEEK_SET);//移动到数据开始的地方if(fread(imgData,(bitCount/(8*sizeof(BYTE)))*width*height*sizeof(BYTE),1,fp)!=1){free(imgData);fclose(fp);return NULL;}fclose(fp);return imgData;}/*** @name: * @msg: 写BMP图片,只负责写数据,没有图片的转换功能* @param char *filepath 读取文件的路径* BYTE *imgData 读到的数据* BITMAPFILEHEADER *bmf 与文件有关的信息* BITMAPINFOHEADER *bmi 与图片有关的信息* PICTYPE pt 图片类型* @return 0 (right) or -1(something wrong)*/BYTE Write_bmp(BYTE *filepath,BYTE *imgData,BITMAPFILEHEADER *bmf,BITMAPINFOHEADER *bmi,PICTYPE pt){FILE *fp;int i;RGBQuad *IpRGBQuad;LONG height=bmi->biHeight;DWORD dwLineBytes=(bmi->biBitCount/(8*sizeof(BYTE)))*bmi->biWidth;fp=fopen(filepath,"wb");if(!fp){printf("Error: Can not open the file:%s\n",filepath);}switch (pt){case LI_BMP_1://BWdwLineBytes=(bmi->biWidth +8-bmi->biWidth%8)/8;if(fwrite(&(bmf->bfType),sizeof(WORD),1,fp)!=1){fclose(fp);return -1;}if(fwrite(&(bmf->bfSize),sizeof(DWORD),1,fp)!=1){fclose(fp);return -1;}if(fwrite(&(bmf->bfReserved1),sizeof(WORD),1,fp)!=1){fclose(fp);return -1;}if(fwrite(&(bmf->bfReserved2),sizeof(WORD),1,fp)!=1){fclose(fp);return -1;}if(fwrite(&(bmf->bfOffBits),sizeof(DWORD),1,fp)!=1){fclose(fp);return -1;}if(fwrite(bmi,40,1,fp)!=1){fclose(fp);return -1;}/*图像的读取顺序是从下到上,从左到右*/IpRGBQuad = (RGBQuad *)malloc(2*sizeof(RGBQuad));IpRGBQuad[0].rgbRed = 0;IpRGBQuad[0].rgbGreen = 0;IpRGBQuad[0].rgbBlue = 0;IpRGBQuad[0].rgbReserved = 0;IpRGBQuad[1].rgbRed = 255;IpRGBQuad[1].rgbGreen = 255;IpRGBQuad[1].rgbBlue = 255;IpRGBQuad[0].rgbReserved = 0; fwrite(IpRGBQuad,8,1,fp);if(fwrite(imgData,dwLineBytes*height,1,fp)!=1){fclose(fp);return -1;}break;case LI_BMP_8://GRAYLILOG("WRITE GRAY");if(fwrite(&(bmf->bfType),sizeof(WORD),1,fp)!=1){fclose(fp);return -1;}if(fwrite(&(bmf->bfSize),sizeof(DWORD),1,fp)!=1){fclose(fp);return -1;}if(fwrite(&(bmf->bfReserved1),sizeof(WORD),1,fp)!=1){fclose(fp);return -1;}if(fwrite(&(bmf->bfReserved2),sizeof(WORD),1,fp)!=1){fclose(fp);return -1;}if(fwrite(&(bmf->bfOffBits),sizeof(DWORD),1,fp)!=1){fclose(fp);return -1;}if(fwrite(bmi,40,1,fp)!=1){fclose(fp);return -1;}/*图像的读取顺序是从下到上,从左到右*/IpRGBQuad = (RGBQuad *)malloc(256*sizeof(RGBQuad));//灰度图为8位的调色板数据为256个结构,1024个字节for(int i = 0;i < 256;i++){IpRGBQuad[i].rgbRed = i;IpRGBQuad[i].rgbGreen = i;IpRGBQuad[i].rgbBlue = i;IpRGBQuad[i].rgbReserved = 0;}fwrite(IpRGBQuad,1024,1,fp);if(fwrite(imgData,height*dwLineBytes,1,fp)!=1){fclose(fp);return -1;}break;case LI_BMP_565://BMP565printf("暂不支持,实在不行自己写\n");/* code */break;case LI_BMP_888://BMP888//因为存在字节对齐问题不能一次写入if(fwrite(&(bmf->bfType),sizeof(WORD),1,fp)!=1){fclose(fp);return -1;}if(fwrite(&(bmf->bfSize),sizeof(DWORD),1,fp)!=1){fclose(fp);return -1;}if(fwrite(&(bmf->bfReserved1),sizeof(WORD),1,fp)!=1){fclose(fp);return -1;}if(fwrite(&(bmf->bfReserved2),sizeof(WORD),1,fp)!=1){fclose(fp);return -1;}if(fwrite(&(bmf->bfOffBits),sizeof(DWORD),1,fp)!=1){fclose(fp);return -1;}if(fwrite(bmi,40,1,fp)!=1){fclose(fp);return -1;}if(fwrite(imgData,height*dwLineBytes,1,fp)!=1){fclose(fp);return -1;}break; case LI_BMP_32://BMP32if(fwrite(&(bmf->bfType),sizeof(WORD),1,fp)!=1){fclose(fp);return -1;}if(fwrite(&(bmf->bfSize),sizeof(DWORD),1,fp)!=1){fclose(fp);return -1;}if(fwrite(&(bmf->bfReserved1),sizeof(WORD),1,fp)!=1){fclose(fp);return -1;}if(fwrite(&(bmf->bfReserved2),sizeof(WORD),1,fp)!=1){fclose(fp);return -1;}if(fwrite(&(bmf->bfOffBits),sizeof(DWORD),1,fp)!=1){fclose(fp);return -1;}if(fwrite(bmi,40,1,fp)!=1){fclose(fp);return -1;}if(fwrite(imgData,height*dwLineBytes,1,fp)!=1){fclose(fp);return -1;}break; default:break;}}#endif // !BMP_H

li_Image.h

图像类实现Li_Image

/** @Descripttion: 实现图像类的初始化接口* @version: * @Author: Yueyang* @email: 1700695611@* @Date: -10-27 22:43:25* @LastEditors: Yueyang* @LastEditTime: -11-13 18:06:26*/#ifndef LI_IMAGE_H#define LI_IMAGE_H#include "cv.h"#include "bmp.h"/*** @name: li_free_arr* @msg: 为LiArr释放内存* @param {void}* @return {void}*/LI_APIvoid li_free_arr(LiArr* arr);/*** @name: li_malloc_arr* @msg: 为LiArr申请内存* @param {size}申请内存的大小* @return {LiArr}数组类型*/LI_APILiArr* li_malloc_arr(LONG size);/*** @name: Li_Create_Mat* @msg: * @param LONG width,LONG height, 高和宽BYTE depth, 图像深度* @return {Li_Mat}*/Li_Mat* Li_Create_Mat(LiArr* data,LONG width,LONG height,BYTE depth);/*** @name: Li_Destroy_Mat* @msg: 为LiMat释放内存* @param {void}* @return {void}*/void Li_Destroy_Mat(Li_Mat* mat);/*** @name: Li_Load_Image* @msg: 用户接口函数,用来读取一张图片* 对于是否支持jpeg 与 png 可以通过cv.h中的宏定义调整* @param* BYTE *filepath 图片路径* PICTYPE pt 图片类型* @return 0 (right) or -1(something wrong)*/LI_APILi_Image* Li_Load_Image(BYTE* filepath,PICTYPE pt);/*** @name: Li_Save_Image* @msg: 用户接口函数,用来保存一张图片* 对于是否支持jpeg 与 png 可以通过cv.h中的宏定义调整* @param* BYTE *filepath 图片路径* Li_Image* img Litecv图片类型* @return 0 (right) or -1(something wrong)*/LI_APIBYTE Li_Save_Image(BYTE* filepath,Li_Image* img);/*** @name: Li_Destroy_Image* @msg: 用户接口函数,用来删除一张图片* @paramLi_Image * img* @return 0 (right) or -1(something wrong)*/LI_APIvoid Li_Destroy_Image(Li_Image * img);/*** @name: Li_Create_Imgae* @msg: 用户接口函数,用来创建一张图片* @paramLONG width 图片宽度LONG height 图片高度BYTE depth 颜色深度PICTYPE pth 图片类型* @return Li_Image* 一张图片*/LI_APILi_Image* Li_Create_Image(LONG width,LONG height,BYTE depth,PICTYPE pth);/*** @name: Li_Copy_Imgae* @msg: 用户接口函数,用来创建一张图片* @paramLONG width 图片宽度LONG height 图片高度BYTE depth 颜色深度PICTYPE pth 图片类型* @return Li_Image* 一张图片*/LI_APILi_Image* Li_Copy_Image(Li_Image *img);/*** @name: Li_CvtColor* @msg: 提供数组的类型转换不提供类型检查,目标指针在函数内不分配内存* @paramconst LiArr* src 原数据LiArr *dst 目标数据BYTE cvtype 转换方式* @return Li_Image* 一张图片*/LI_APIvoid Li_CvtColor(const LiArr* src,LiArr *dst,LONG width,LONG height,BYTE cvtype);/*** @name: Li_Convert_Image* @msg: 提供图片类型转化,图片类型指针在* @paramconst LiArr* src 原数据LiArr *dst 目标数据BYTE cvtype 转换方式* @return Li_Image* 一张图片*/LI_APILi_Image* Li_Convert_Image(const Li_Image* src,BYTE convertype);/*** @name: Li_Get_Roi* @msg: 获取感兴趣区域* @param {Li_Image* img 原图像* LONG x1 左下角所在列号* LONG y1 左下角所在行号* LONG x2 右上角所在列号* LONG y2}右上角所在行号* @return {Li_Image*}*/LI_APILi_Image* Li_Get_Roi(Li_Image* img,LONG x1,LONG y1,LONG x2,LONG y2);/*** @name: Li_ReShape* @msg: 调整图像大小* @param Li_Image* img 原图像* LONG tag_width 图像宽度* LONG tag_height图像高度* @return {*}*/LI_APILi_Image* Li_ReShape(Li_Image* img,LONG tag_width,LONG tag_height);#endif // !LI_IMAGE_H

li_image.c

/** @Descripttion: 图像类基本的初始化函数* @version: V 2.0* @Author: Yueyang* @email: 1700695611@* @Date: -10-27 22:41:59* @LastEditors: Yueyang* @LastEditTime: -11-10 22:33:27*/#include "cv.h"#include "stdlib.h"#include "string.h"#undef LOG#define LOG "LI_CV_CORE"#include "bmp.c"#include "png.c"#include "jpeg.c"/*** @name: li_malloc_arr* @msg: 为LiArr申请内存* @param {size}申请内存的大小* @return {LiArr}数组类型*/LI_APILiArr* li_malloc_arr(LONG size){return (LiArr*)malloc((size_t)size);}/*** @name: li_free_arr* @msg: 为LiArr释放内存* @param {void}* @return {void}*/void li_free_arr(LiArr* arr){return free((void *)arr);}/*** @name: Li_Destroy_Mat* @msg: 为LiMat释放内存* @param {void}* @return {void}*/void Li_Destroy_Mat(Li_Mat* mat){li_free_arr(mat->arr);free((void*)mat);}/*** @name: li_bgr_at* @msg: * @param {Li_Image* mat* LONG x 指针所在列号* LONG y 所在行号}* @return {*}*/LiArr* li_bgr_at(Li_Image* mat,LONG x,LONG y){if(x<mat->width&&y<mat->height&&x>=0&&y>=0)return mat->data+mat->width*(1+mat->imgdepth)*y+(1+mat->imgdepth)*x;else {LILOG("BEYOND THE MAT");return NULL;}}LiArr* li_gray_at(Li_Image* mat,LONG x,LONG y){if(x<mat->width&&y<mat->height&&x>=0&&y>=0)return mat->data+mat->width*1*y+1*x;else {//LILOG("BEYOND THE MAT");return NULL;}}LiArr* li_rgba_at(Li_Image* mat,LONG x,LONG y){if(x<mat->width&&y<mat->height&&x>=0&&y>=0)return mat->data+mat->width*4*y+4*x;else {LILOG("BEYOND THE MAT");return NULL;}}/*** @name: Li_Create_Mat* @msg: * @param LONG width,LONG height, 高和宽BYTE depth, 图像深度* @return {Li_Mat}*/Li_Mat* Li_Create_Mat(LiArr* data,LONG width,LONG height,BYTE depth){Li_Mat* li_mat=(Li_Mat*)malloc(sizeof(Li_Mat));li_mat->datadepth= depth;li_mat->height = height;li_mat->width = width;li_mat->matsize=width*height;if(depth!=LI_DEP_1U) {li_mat->Bitcount =(depth+1)*8;li_mat->arrsize=li_mat->matsize*(depth+1);}else {li_mat->Bitcount=1;li_mat->arrsize=li_mat->matsize*1/8;//对于二值化图像一个BYTE代表8个像素点} li_mat->arr=li_malloc_arr(li_mat->arrsize);memcpy(li_mat->arr,data,li_mat->arrsize);return li_mat;}/*** @name: ptr_li_image_create* @msg: 创建Li_image 类型指针* @param *LiArr* data,(已经初始化过的数据指针)*LONG width,LONG height,*BYTE depth,PICTYPE pth(图片类型)* @return {Li_Image}一个图片*/Li_Image* ptr_li_image_create(LiArr* dt,LONG width,LONG height,BYTE depth,PICTYPE pth){Li_Image* img =(Li_Image*)malloc(sizeof(Li_Image));Li_Mat* limt=NULL;img->pt=pth;img->data=dt;img->width=width;img->height=height;img->imgdepth=depth;switch (pth){case LI_BMP_888:limt= Li_Create_Mat(dt,width,height,depth);memcpy(&img->limat,limt,sizeof(Li_Mat));//数据指针一并过来了,所以li_mat->arr不能释放img->at=li_bgr_at;break;case LI_JPEG:limt= Li_Create_Mat(dt,width,height,depth);memcpy(&img->limat,limt,sizeof(Li_Mat));//数据指针一并过来了,所以li_mat->arr不能释放img->at=li_bgr_at;break;case LI_BMP_8:limt= Li_Create_Mat(dt,width,height,depth);memcpy(&img->limat,limt,sizeof(Li_Mat));//数据指针一并过来了,所以li_mat->arr不能释放img->at=li_gray_at;break; case LI_BMP_32:limt= Li_Create_Mat(dt,width,height,depth);memcpy(&img->limat,limt,sizeof(Li_Mat));//数据指针一并过来了,所以li_mat->arr不能释放img->at=li_rgba_at;break; case LI_PNG:limt= Li_Create_Mat(dt,width,height,depth);memcpy(&img->limat,limt,sizeof(Li_Mat));//数据指针一并过来了,所以li_mat->arr不能释放img->at=li_rgba_at;break; default:break;} return img;}/*** @name: ptr_li_image_destroy* @msg: 销毁Li_image 类型指针* @param {Li_Image* }一个图片指针** @return void*/void ptr_li_image_destroy(Li_Image* img){li_free_arr(img->limat.arr);free(img);}//获取默认的BMP文件头BITMAPFILEHEADER get_default_file_head(Li_Mat m){LONG DataSizePerLine = (m.width * m.Bitcount /8+ 3) / 4*4;BITMAPFILEHEADER bf;if(m.datadepth!=LI_DEP_8U&&m.datadepth!=LI_DEP_1U)bf.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)-2;else if(m.datadepth==LI_DEP_8U) bf.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+1024-2;else if(m.datadepth==LI_DEP_1U) bf.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+8-2;bf.bfSize =DataSizePerLine*m.height+bf.bfOffBits;bf.bfType =19778;//"BM"bf.bfReserved1=0;bf.bfReserved2=0;return bf;}//获取默认的BMP信息BITMAPINFOHEADER get_default_info_head(Li_Mat m){LONG DataSizePerLine = (m.width * m.Bitcount /8+ 3) / 4*4;BITMAPINFOHEADER bi;bi.biBitCount=m.Bitcount;bi.biSize =40;bi.biWidth =m.width;bi.biHeight =m.height;bi.biPlanes =1;bi.biClrImportant=0;bi.biClrUsed =0;//默认全都用if(m.Bitcount!=32){bi.biXPelsPerMeter=3780;//默认大小bi.biYPelsPerMeter=3780;}else{bi.biXPelsPerMeter=0;//默认大小bi.biYPelsPerMeter=0; }bi.biSizeImage=DataSizePerLine*bi.biHeight;bi.biCompression=0;//默认不压缩return bi;}/*** @name: Li_Save_Image* @msg: 用户接口函数,用来保存一张图片* 对于是否支持jpeg 与 png 可以通过cv.h中的宏定义调整* @param* BYTE *filepath 图片路径* Li_Image* img Litecv图片类型* @return 0 (right) or -1(something wrong)*/LI_APIBYTE Li_Save_Image(BYTE* filepath,Li_Image* img){if(img==NULL){LILOG("A NULL IMG");return -1;}BYTE sta;BITMAPFILEHEADER bf;BITMAPINFOHEADER bi;switch (img->pt){case LI_BMP_888:bf= get_default_file_head(img->limat);bi= get_default_info_head(img->limat);sta=Write_bmp(filepath,img->data,&bf,&bi,img->pt);break;case LI_BMP_32:bf= get_default_file_head(img->limat);bi= get_default_info_head(img->limat);sta=Write_bmp(filepath,img->data,&bf,&bi,img->pt);break;case LI_BMP_8:bf= get_default_file_head(img->limat);bi= get_default_info_head(img->limat);sta=Write_bmp(filepath,img->data,&bf,&bi,img->pt); break; #ifdef USE_JPEGcase LI_JPEG:LILOG("WRITE JPEG");sta=Write_Jpeg(filepath,img->data,100,img->limat.width,img->limat.height);break;#endif#ifdef USE_PNGcase LI_PNG:sta=Write_Png(filepath,img->data,img->limat.width,img->limat.height);break;#endifdefault:break;}return sta;}/*** @name: Li_Load_Image* @msg: 用户接口函数,用来读取一张图片* 对于是否支持jpeg 与 png 可以通过cv.h中的宏定义调整* @param* BYTE *filepath 图片路径* PICTYPE pt 图片类型* @return 0 (right) or -1(something wrong)*/LI_APILi_Image* Li_Load_Image(BYTE* filepath,PICTYPE pt){BYTE* data;LONG width,height;int depth;BITMAPFILEHEADER bf;BITMAPINFOHEADER bi;Li_Image* img=NULL;switch (pt){case LI_BMP_888:LILOG("BMP888");data=Read_bmp(filepath,&bf,&bi);width=bi.biWidth;height=bi.biHeight;depth=LI_DEP_24U;img=ptr_li_image_create(data,width,height,depth,pt);break;case LI_BMP_32:LILOG("BMP32");data=Read_bmp(filepath,&bf,&bi);width=bi.biWidth;height=bi.biHeight;depth=LI_DEP_32U;img=ptr_li_image_create(data,width,height,depth,pt);break;case LI_BMP_8:LILOG("BMP8");data=Read_bmp(filepath,&bf,&bi);width=bi.biWidth;height=bi.biHeight;depth=LI_DEP_8U;img=ptr_li_image_create(data,width,height,depth,pt);break;case LI_BMP_565:LILOG("BMP16");data=Read_bmp(filepath,&bf,&bi);width=bi.biWidth;height=bi.biHeight;depth=LI_DEP_16U;img=ptr_li_image_create(data,width,height,depth,pt);break;#ifdef USE_JPEGcase LI_JPEG:LILOG("JPEG");data=Read_Jpeg(filepath,&width,&height);depth=LI_DEP_24U;img=ptr_li_image_create(data,width,height,depth,pt);break;#endif #ifdef USE_PNGcase LI_PNG:LILOG("PNG");data=Read_Png(filepath,&width,&height);depth=LI_DEP_32U;img=ptr_li_image_create(data,width,height,depth,pt);break;#endif default:break;}return img;}/*** @name: Li_Destroy_Image* @msg: 用户接口函数,用来删除一张图片* @paramLi_Image * img* @return 0 (right) or -1(something wrong)*/LI_APIvoid Li_Destroy_Image(Li_Image * img){ptr_li_image_destroy(img);}/*** @name: Li_Create_Imgae* @msg: 用户接口函数,用来创建一张图片* @paramLONG width 图片宽度LONG height 图片高度BYTE depth 颜色深度PICTYPE pth 图片类型* @return Li_Image* 一张图片*/LI_APILi_Image* Li_Create_Image(LONG width,LONG height,BYTE depth,PICTYPE pth){LiArr * data=li_malloc_arr(width*height*(depth+1));memset(data,0xFF,width*height*(depth+1));return ptr_li_image_create(data,width,height,depth,pth);}/*** @name: Li_Copy_Imgae* @msg: 用户接口函数,用来创建一张图片* @paramLONG width 图片宽度LONG height 图片高度BYTE depth 颜色深度PICTYPE pth 图片类型* @return Li_Image* 一张图片*/LI_APILi_Image* Li_Copy_Image(Li_Image *img){Li_Image * out=NULL;out=Li_Create_Image(img->width,img->height,img->imgdepth,img->pt);memcpy((void*)out->data,(void*)img->data,img->width*img->height*(img->imgdepth+1));return out;}#include "li_convert.c"#include "li_painter.c"

怎样使用这个图片类读取各种类型的图片

main.c

/** @Descripttion: 底层图片IO测试* @version: V 2.0* @Author: Yueyang* @email: 1700695611@* @Date: -10-26 19:35:49* @LastEditors: Yueyang* @LastEditTime: -11-04 15:50:21*/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <malloc.h>#include "bmp.h"#include "cv.h"#include "li_image.h"int main(){//加载保存销毁图片Li_Image* out=Li_Load_Image("./picture/whu_rgb888.bmp",LI_BMP_888);Li_Save_Image("./picture/1.bmp",out);Li_Destroy_Image(out);Li_Image* out3=Li_Load_Image("./picture/whu_gray.bmp",LI_BMP_8); Li_Save_Image("./picture/2.bmp",out3); Li_Destroy_Image(out3);Li_Image* out4=Li_Load_Image("./picture/whu_rgba.bmp",LI_BMP_32); Li_Save_Image("./picture/3.bmp",out4); Li_Destroy_Image(out4);Li_Image* out1=Li_Load_Image("./picture/whu_png.png",LI_PNG);Li_Save_Image("./picture/1.png",out1);Li_Destroy_Image(out1);Li_Image* out2=Li_Load_Image("./picture/whu_jpg.jpg",LI_JPEG);Li_Save_Image("./picture/1.jpg",out2);Li_Destroy_Image(out2);//创建图片并操作像素BYTE* ptr=NULL;Li_Image* out7 =Li_Create_Image(300,300,LI_DEP_24U,LI_BMP_888);ptr=out7->at(out7,10,10);if(ptr!=NULL){memset(ptr,0xFF,1);memset(ptr+1,0,1); memset(ptr+2,0,1); }Li_Save_Image("./picture/1.bmp",out3);Li_Destroy_Image(out7);Li_Image* out8 =Li_Load_Image("./picture/whu_jpg.jpg",LI_JPEG);ptr=out8->at(out8,10,10);if(ptr!=NULL){memset(ptr,0xFF,1);memset(ptr+1,0,1); memset(ptr+2,0,1);}Li_Save_Image("./picture/2.jpg",out8);Li_Destroy_Image(out8);Li_Image* out5 =Li_Load_Image("./picture/whu_png.png",LI_PNG);ptr=out5->at(out5,10,10);if(ptr!=NULL){memset(ptr,0xFF,1);memset(ptr+1,0,1); memset(ptr+2,0,1);}Li_Save_Image("./picture/2.png",out5);Li_Image* out6=Li_Copy_Image(out5);Li_Save_Image("./picture/3.png",out6);LILOG("over");return 0; }

(四)写在最后

其实重新造轮子这种事情看似没有意义,可是在这个过程中所能学到的东西绝不是会用opencv的几个函数所能相比的。

到目前为止笔者已经分别在WINDOWS,X86_LINUX,ARM_LINUX这三个平台上适配了这个图形系统。我会持续的在github中完善这个系统。

github地址:

Litecv github源码地址

开发手册:

(一)Core API

/*** @name: li_free_arr* @msg: 为LiArr释放内存* @param {void}* @return {void}*/LI_APIvoid li_free_arr(LiArr* arr);/*** @name: li_malloc_arr* @msg: 为LiArr申请内存* @param {size}申请内存的大小* @return {LiArr}数组类型*/LI_APILiArr* li_malloc_arr(LONG size);/*** @name: Li_Create_Mat* @msg: * @param LONG width,LONG height, 高和宽BYTE depth, 图像深度* @return {Li_Mat}*/Li_Mat* Li_Create_Mat(LiArr* data,LONG width,LONG height,BYTE depth);/*** @name: Li_Destroy_Mat* @msg: 为LiMat释放内存* @param {void}* @return {void}*/void Li_Destroy_Mat(Li_Mat* mat);/*** @name: Li_Load_Image* @msg: 用户接口函数,用来读取一张图片* 对于是否支持jpeg 与 png 可以通过cv.h中的宏定义调整* @param* BYTE *filepath 图片路径* PICTYPE pt 图片类型* @return 0 (right) or -1(something wrong)*/LI_APILi_Image* Li_Load_Image(BYTE* filepath,PICTYPE pt);/*** @name: Li_Save_Image* @msg: 用户接口函数,用来保存一张图片* 对于是否支持jpeg 与 png 可以通过cv.h中的宏定义调整* @param* BYTE *filepath 图片路径* Li_Image* img Litecv图片类型* @return 0 (right) or -1(something wrong)*/LI_APIBYTE Li_Save_Image(BYTE* filepath,Li_Image* img);/*** @name: Li_Destroy_Image* @msg: 用户接口函数,用来删除一张图片* @paramLi_Image * img* @return 0 (right) or -1(something wrong)*/LI_APIvoid Li_Destroy_Image(Li_Image * img);/*** @name: Li_Create_Imgae* @msg: 用户接口函数,用来创建一张图片* @paramLONG width 图片宽度LONG height 图片高度BYTE depth 颜色深度PICTYPE pth 图片类型* @return Li_Image* 一张图片*/LI_APILi_Image* Li_Create_Image(LONG width,LONG height,BYTE depth,PICTYPE pth);/*** @name: Li_Copy_Imgae* @msg: 用户接口函数,用来创建一张图片* @paramLONG width 图片宽度LONG height 图片高度BYTE depth 颜色深度PICTYPE pth 图片类型* @return Li_Image* 一张图片*/LI_APILi_Image* Li_Copy_Image(Li_Image *img);/*** @name: Li_CvtColor* @msg: 提供数组的类型转换不提供类型检查,目标指针在函数内不分配内存* @paramconst LiArr* src 原数据LiArr *dst 目标数据BYTE cvtype 转换方式* @return Li_Image* 一张图片*/LI_APIvoid Li_CvtColor(const LiArr* src,LiArr *dst,LONG width,LONG height,BYTE cvtype);/*** @name: Li_Convert_Image* @msg: 提供图片类型转化,图片类型指针在* @paramconst LiArr* src 原数据LiArr *dst 目标数据BYTE cvtype 转换方式* @return Li_Image* 一张图片*/LI_APILi_Image* Li_Convert_Image(const Li_Image* src,BYTE convertype);/*** @name: Li_Get_Roi* @msg: 获取感兴趣区域* @param {Li_Image* img 原图像* LONG x1 左下角所在列号* LONG y1 左下角所在行号* LONG x2 右上角所在列号* LONG y2}右上角所在行号* @return {Li_Image*}*/LI_APILi_Image* Li_Get_Roi(Li_Image* img,LONG x1,LONG y1,LONG x2,LONG y2);/*** @name: Li_ReShape* @msg: 调整图像大小* @param Li_Image* img 原图像* LONG tag_width 图像宽度* LONG tag_height图像高度* @return {*}*/LI_APILi_Image* Li_ReShape(Li_Image* img,LONG tag_width,LONG tag_height);

(二)IMGPROC 模块

/*** @name: Li_Split* @msg: 图像色道分离* @param {Li_Image* img}* @return {Li_Image** 图像指针的指针}*/LI_APIvoid Li_Split(Li_Image* img,Li_Image** out);/*** @name: Li_Split* @msg: 图像色道分离* @param {Li_Image* img 原图像* Li_Image**色道分离以后的图像}* @return {}*/LI_APILi_Image* Li_Combine(Li_Image** out,BYTE depth);/*** @name: Li_Threshold* @msg: 图像阈值化* @param {Li_Image* img 原图像* double threshold 图像阈值0-255* }* @return {Li_Image* 二值化后的灰白图像}*/LI_API Li_Image* Li_Threshold(Li_Image* img,double threshold);/*** @name: Li_Convolute* @msg: 计算图像卷积* @param {Li_Image* img 卷积图像* Li_Kernel* kernal 卷积核 }* @return {Li_Image*}*/LI_APILi_Image* Li_Convolute(Li_Image* img,Li_Kernel* kernal);/*** @name: Li_GetKernel* @msg: 得到卷积核矩阵* @param {*}* @return {*}*/LI_API Li_Kernel* Li_GetKernel(double* data,BYTE KernalKind);/*** @name: Li_Smooth* @msg: 计算图像滤波* @param {Li_Image* img 原图像* BYTE smoothtype( Li_GAUSS, //高斯滤波Li_AVERAGE, //均值滤波Li_MEDIUM, //中值滤波)}* @return {Li_Image*}*/LI_APILi_Image* Li_Smooth(Li_Image* img,BYTE smoothtype);/*** @name: Li_Sharp* @msg: 图像锐化* @param {Li_Image* img}* @return {Li_Image*}*/LI_APILi_Image* Li_Sharp(Li_Image* img);/*** @name: Li_Emboss* @msg: 图像雕版* @param {Li_Image* img}* @return {Li_Image*}*/LI_APILi_Image* Li_Emboss(Li_Image* img);/*** @name: Li_Salt_Noise* @msg: 图像椒盐噪声* @param {Li_Image* img* LONG num 噪点数量}* @return {Li_Image*}*/LI_APILi_Image* Li_Salt_Noise(Li_Image* img,LONG num);enum CannyType{LI_CANNY_ROBERTS,LI_CANNY_SOBEL,LI_CANNY_PREWITT,LI_CANNY_MYDEFINE};/*** @name: Li_Double_Threshold* @msg: 图像双阈值化* @param {Li_Image* img 原图像* double min 小阈值* double max 大阈值* }* @return {Li_Image* 二值化后的灰白图像}*/LI_API Li_Image* Li_Double_Threshold(Li_Image* img,double min,double max);/*** @name: Li_Canny* @msg: 参考文章 /HUSTER_Gy/article/details/102942452?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522160498444419724838560446%2522%252C%2522scm%2522%253A%25220713.130102334.pc%255Fall.%2522%257D&request_id=160498444419724838560446&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_v2~rank_v28-11-102942452.first_rank_ecpm_v3_pc_rank_v2&utm_term=canny%E8%BE%B9%E7%BC%98%E6%A3%80%E6%B5%8B%E7%AE%97%E6%B3%95c%E5%AE%9E%E7%8E%B0&spm=1018.2118.3001.4449* 图像砍尼检测* @param {Li_Image* img 原图像* BYTE CannyType选择算子* BYTE min最大阈值* BYTE max}最小阈值* @return {*}*/LI_APILi_Image* Li_Canny(Li_Image* img,BYTE CannyType,BYTE min,BYTE max);/*** @name: Li_Hough_Line* @msg: 霍夫直线变换* @param {Li_Image* img 原图像* LiLine* lines 返回的直线类型指针* LONG maxthrea 允许的最大角度* LONG maxr语序的最大半径}* @return {*}*/LI_API void Li_Hough_Line(Li_Image* img,LiLine* lines, LONG maxthrea,LONG maxr);/*** @name: Li_Hough_Circle_R* @msg: 固定半径的Hough变换* @param {Li_Image* img 原图像* LiCircle* circles 返回的圆指针(不会再内部分配内存)* LONG R变换半径* LONG* range}圆心得范围* @return {*}*/LI_API LONG Li_Hough_Circle_R(Li_Image* img,LiCircle* circles, LONG R,LONG* range);/*** @name: Li_Hough_Circle* @msg: 给定范围的Hough变换* @param {Li_Image* img 原图像* LiCircle* circles 返回的圆指针(不会再内部分配内存)* LONG Rmin,LONG Rmax 最小最大半径* LONG* range}圆心得范围* @return {*}*/LI_API void Li_Hough_Circle(Li_Image* img,LiCircle* circles, LONG Rmin,LONG Rmax,LONG* range);/*** @name: Li_Dilate* @msg: 图像膨胀(局部最小)* @param {Li_Image* img}* @return {Li_Image*}*/LI_APILi_Image* Li_Dilate(Li_Image* img);/*** @name: Li_Erode* @msg: 图像腐蚀(局部最小)* @param {Li_Image* img}* @return {Li_Image*}*/LI_APILi_Image* Li_Erode(Li_Image* img);/*** @name: Li_Add* @msg: 图像像素相加* @param {Li_Image* img1,Li_Image* img2}* @return {Li_Image*}*/LI_APILi_Image* Li_Add(Li_Image* img1,Li_Image* img2);/*** @name: Li_Minus* @msg: 图像像素相加* @param {Li_Image* img1,Li_Image* img2}* @return {Li_Image*}*/LI_APILi_Image* Li_Minus(Li_Image* img1,Li_Image* img2);/*** @name: Li_Grandient* @msg: 形态学梯度* @param {Li_Image* img}* @return {Li_Image*}*/LI_APILi_Image* Li_Grandient(Li_Image* img);/*** @name: Li_Mod_Open* @msg: 形态学开运算* @param {Li_Image* img}* @return {Li_Image* }*/LI_APILi_Image* Li_Mod_Open(Li_Image* img);/*** @name: Li_Mod_Close* @msg: 形态学闭运算* @param {Li_Image* img}* @return {Li_Image* }*/LI_APILi_Image* Li_Mod_Close(Li_Image* img);/*** @name: Li_TopHat* @msg: 图像顶帽运算* @param {Li_Image* img}* @return {Li_Image*}*/LI_APILi_Image* Li_TopHat(Li_Image* img);/*** @name: Li_BlackHat* @msg: 图像黑帽运算* @param {Li_Image* img}* @return {Li_Image*}*/LI_APILi_Image* Li_BlackHat(Li_Image* img);/*** @name: Li_Visual_Hist* @msg: 直方图转化为图像* @param {Li_Hist* hist}* @return {Li_Image*}*/LI_APILi_Image* Li_Visual_Hist(Li_Hist* hist);/*** @name: Li_Get_Hist* @msg: 绘制直方图* @param {Li_Image* img 图像}* @return {Li_Hist* 直方图数据}*/LI_API Li_Hist* Li_Get_Hist(Li_Image* img);/*** @name: Li_Print_Hist* @msg: 打印直方图* @param {Li_Hist* hist}* @return {*}*/LI_APIvoid Li_Print_Hist(Li_Hist* hist);/*** @name: Li_Normalize_Hist* @msg: 直方图均衡化* @param {Li_Image* img}* @return {*}*/LI_APILi_Image* Li_Normalize_Hist(Li_Image* img);

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。