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

【数字图像处理】C语言实现BMP图片的读取显示存储_第1张图片

(一)背景介绍

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

为什么放弃了opencv

1.opencv的平台限制

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

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

前段时间自己一直在看关于opencv的书,就看那些乱七八糟一堆一堆的函数,感觉啥都没有学到。
前段时间看到这样一句话,我们需要警惕开源软件。没错他们是很香,但是他们会让你失去自己的独立性,真正的程序员最好应该是不给自己任何可以依赖的东西的。

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

(二)框架设计

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

现在再来回顾一下项目需求。
1.只用C库实现。
2.为今后的跨平台特性提供接口
3.函数高内聚低耦合,具有较强的可移植性

下面是系统框图
【数字图像处理】C语言实现BMP图片的读取显示存储_第2张图片
实现这个最大的问题在于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 Mat.c

cv.h C图像类顶层头文件

/*************************************************
Copyright © Yueyang Co. Ltd. 2019-2029. All rights reserved.
File name: cv.h
Author: Yueyang
Version: V1.0
Description: LiteCV顶层头文件,提供基础数据类型
Others: 
Log: 11.3 Yueyang
*************************************************/

#ifndef _CV_H
#define _CV_H


#define bool                 u8
#define false                0
#define true                 1  
#define PI                   3.1415926 


#define ARM_LINUX


//在不同的平台上一些数据的字长不一样
#ifdef WINDOWS

typedef unsigned short       WORD;
typedef unsigned long        DWORD;
typedef long                 LONG;
typedef unsigned char        BYTE;
typedef unsigned             char uint8_t;
typedef unsigned short       int uint16_t;
typedef unsigned             int uint32_t;
typedef uint32_t             u32;
typedef uint16_t             u16;
typedef uint8_t              u8;

#endif



#ifdef X86_LINUX

typedef unsigned             char uint8_t;
typedef unsigned short       int uint16_t;
typedef unsigned             int uint32_t;
typedef uint32_t             u32;
typedef uint16_t             u16;
typedef uint8_t              u8;
typedef unsigned short       WORD;
typedef u32                  DWORD;
typedef u32                  LONG;
typedef unsigned char        BYTE;



#endif

#ifdef ARM_LINUX

typedef unsigned short       WORD;
typedef unsigned long        DWORD;
typedef long                 LONG;
typedef unsigned char        BYTE;
typedef unsigned             char uint8_t;
typedef unsigned short       int uint16_t;
typedef unsigned             int uint32_t;
typedef uint32_t             u32;
typedef uint16_t             u16;
typedef uint8_t              u8;
#endif

#ifdef ARM_NONE

#endif


#endif // !CV_H

Mat.h 图像矩阵函数实现

/*************************************************
Copyright © Yueyang Co. Ltd. 2019-2029. All rights reserved.
File name: Mat.h
Author: Yueyang
Version: V1.0
Description: 提供Mat结构体
Others: 
Log: 11.3 Yueyang
*************************************************/

#ifndef Mat_H
#define MAT_H

#include "cv.h"

#define BMP_8    0X01
#define BMP_565  0x02
#define BMP_888  0x03
#define BMP_32   0x04
#define JPEG     0X05

#define     RGB(r,g,b)     ((u32)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16))) 



typedef struct 
{ // bmfh
    WORD    bfType;
    DWORD   bfSize;
    WORD    bfReserved1;
    WORD    bfReserved2;
    DWORD   bfOffBits;
}BITMAPFILEHEADER;
typedef struct 
{ // bmih
    DWORD biSize;
    LONG   biWidth;
    LONG   biHeight;
    WORD   biPlanes;
    WORD   biBitCount;
    DWORD biCompression;
    DWORD biSizeImage;
    LONG   biXPelsPerMeter;
    LONG   biYPelsPerMeter;
    DWORD biClrUsed;
    DWORD biClrImportant;
}BITMAPINFOHEADER;
typedef struct tagRGBQUAD
{ // rgbq
    BYTE    rgbBlue;
    BYTE    rgbGreen;
    BYTE    rgbRed;
    BYTE    rgbReserved;
}RGBQUAD;

typedef struct tagBITMAPINFO
{
    BITMAPINFOHEADER bmiHeader;
    RGBQUAD bmiColors[1];
}BITMAPINFO;


typedef struct
{
    //! the number of rows and columns or (-1, -1) when the matrix has more than 2 dimensions

     BITMAPFILEHEADER bmf;
     BITMAPINFOHEADER bmi;

    LONG highth, width;
    u8 pictype;
    char* PATH;
    BYTE *imgData;

}Mat;

void Mat_INIT();
Mat MatCreate(u8* filepath,u16 width,u16 height,u8 type);


#endif // !Mat_H

bmp.h bmp位图处理函数接口

/*************************************************
Copyright © Yueyang Co. Ltd. 2019-2029. All rights reserved.
File name: bmp.h
Author: Yueyang
Version: V1.0
Description: 提供对于bmp文件的操作函数
Others: 
Log: 11.3 Yueyang
*************************************************/

#ifndef BMP_H_INCLUDED
#define BMP_H_INCLUDED
#include "stdio.h"
#include "Mat.h"

//通配指针提供,跨平台主要的实现方式
 void   (*Li_free)   (void *_Memory);
 void * (*Li_malloc) (size_t _Size);
 void * (*Li_memcpy) (void * _Dst,const void * _Src,size_t _Size);
 void   (*show)      (Mat* mat);
 u8*    (*at)        (Mat* mat,int width,int highth);
 int    (*process)   (Mat* mat,int x,int y,u32 color);
 Mat    (*load)      (char *filepath);
 int    (*save)      (char *filepath,Mat* mat);
 Mat    (*copy)      (Mat mat);
 void   (*destory)   (Mat* mat);
 Mat    (*create) (u8* filepath,u16 width,u16 height,u8 type);


//检查路径是否合法
int CheckbmpFilePath(char *filepath);
//读BMP文件头
int ReadbmpFileHeader(char *filepath,BITMAPFILEHEADER *bmfh);
//打印BMP文件头
void PrintbmpFileHeader(BITMAPFILEHEADER *bmfh);
//读BMP信息头
int ReadbmpInfoHeader(char *filepath,BITMAPINFOHEADER *bmih);
//打印BMP信息头
void PrintbmpInfoHeader(BITMAPINFOHEADER *bmih);
//读取BMP的图像数据
int ReadbmpPixelData(char *filepath,BYTE *imgData);
//获取图像每一行所占用的字节数
LONG GetLineBytes(int imgWidth,int bitCount);
//打印位图数据信息
void PrintbmpPixelData(BYTE *imgData,int width,int height,int bitCount);
//提供一个MAT的结构体将其存储为BMP文件
int SaveAsbmpImage(char *filepath,Mat* mat);
//图片显示 注意在不同的硬件平台上需要重写这个函数

//加载BMP图片,并返回一个MAT结构体
Mat bmpload(char *filepath);
//对于图片的每一个像素分别操作
int bmpprocess(Mat* mat,int width,int highth,u32 color);
//获取BMP某个像素所在的地址
u8* bmpat(Mat* mat,int width,int highth);
//BMP拷贝函数
Mat bmpcopy(Mat mat);
//析构函数
void bmpdestory(Mat* mat);

void ARM_ShowbmpImage(Mat* mat,struct fb_var_screeninfo vinfo,struct fb_fix_screeninfo finfo,char *fbp);

#endif 

bmp.c

/*************************************************
Copyright © Yueyang Co. Ltd. 2019-2029. All rights reserved.
File name: bmp.c
Author: Yueyang
Version: V1.0
Description: 提供对于bmp文件的操作函数
Others: 
Log: 11.3 Yueyang
*************************************************/

#include 
#include 
#include 
#include 
#include "string.h"
#include "bmp.h"



int ReadbmpFileHeader(char *filepath,BITMAPFILEHEADER *bmfh)
{
   FILE *fp;
   fp=fopen(filepath,"rb");
   if(!fp)
   {
      printf("Can not open the file:%s\n",filepath);
      return -1;
   }
   if(fread(&bmfh->bfType,sizeof(WORD),1,fp)!=1)
   {
      printf("Can not read bfType in the file header.\n");
      fclose(fp);
      return -1;
   }
   if(fread(&bmfh->bfSize,sizeof(DWORD),1,fp)!=1)
   {
      printf("Can not read bfSize in the file header.\n");
      fclose(fp);
      return -1;
   }
   if(fread(&bmfh->bfReserved1,sizeof(WORD),1,fp)!=1)
   {
      printf("Can not read bfReserved1 in the file header.\n");
      fclose(fp);
      return -1;
   }
   if(fread(&bmfh->bfReserved2,sizeof(WORD),1,fp)!=1)
   {
      printf("Can not read bfReserved2 in the file header.\n");
      fclose(fp);
      return -1;
   }
   if(fread(&bmfh->bfOffBits,sizeof(DWORD),1,fp)!=1)
   {
      printf("Can not read bfOffBits in the file header.\n");
      fclose(fp);
      return -1;
   }
   fclose(fp);
   return 0;
}


int ReadbmpInfoHeader(char *filepath,BITMAPINFOHEADER *bmih)
{
   FILE *fp;
   fp=fopen(filepath,"rb");
   if(!fp)
   {
      printf("Can not open the file:%s\n",filepath);
      return -1;
   }
   fseek(fp,14,SEEK_SET);
   if(fread(&bmih->biSize,sizeof(DWORD),1,fp)!=1)
   {
      printf("Can not read biSize in the info header.\n");
      fclose(fp);
      return -1;
   }
   if(fread(&bmih->biWidth,sizeof(LONG),1,fp)!=1)
   {
      printf("Can not read biWidth in the info header.\n");
      fclose(fp);
      return -1;
   }
   if(fread(&bmih->biHeight,sizeof(LONG),1,fp)!=1)
   {
      printf("Can not read biHeight in the info header.\n");
      fclose(fp);
      return -1;
   }
   if(fread(&bmih->biPlanes,sizeof(WORD),1,fp)!=1)
   {
      printf("Can not read biPlanes in the info header.\n");
      fclose(fp);
      return -1;
   }
   if(fread(&bmih->biBitCount,sizeof(WORD),1,fp)!=1)
   {
      printf("Can not read biBitCount in the info header.\n");
      fclose(fp);
      return -1;
   }
   if(fread(&bmih->biCompression,sizeof(DWORD),1,fp)!=1)
   {
      printf("Can not read biCompression in the info header.\n");
      fclose(fp);
      return -1;
   }
   if(fread(&bmih->biSizeImage,sizeof(DWORD),1,fp)!=1)
   {
      printf("Can not read biSizeImage in the info header.\n");
      fclose(fp);
      return -1;
   }
   if(fread(&bmih->biXPelsPerMeter,sizeof(LONG),1,fp)!=1)
   {
      printf("Can not read biXPelsPerMeter in the info header.\n");
      fclose(fp);
      return -1;
   }
   if(fread(&bmih->biYPelsPerMeter,sizeof(LONG),1,fp)!=1)
   {
      printf("Can not read biYPelsPerMeter in the info header.\n");
      fclose(fp);
      return -1;
   }
   if(fread(&bmih->biClrUsed,sizeof(DWORD),1,fp)!=1)
   {
      printf("Can not read biClrUsed in the info header.\n");
      fclose(fp);
      return -1;
   }
   if(fread(&bmih->biClrImportant,sizeof(DWORD),1,fp)!=1)
   {
      printf("Can not read biClrImportant in the info header.\n");
      fclose(fp);
      return -1;
   }
   fclose(fp);
   return 0;
}


int ReadbmpPixelData(char *filepath,BYTE *imgData)
{
   BITMAPINFOHEADER bmih;
   BITMAPFILEHEADER bmfh;
   BYTE *data;
   FILE *fp;
   int n;
   int width;
   int height;
   int bitCount;
   DWORD dwLineBytes;
   n=ReadbmpFileHeader(filepath,&bmfh);
   if(n==-1)
   {
      printf("Can not read the file header of the BMP file.\n");
      return -1;
   }
   n=ReadbmpInfoHeader(filepath,&bmih);
   if(n==-1)
   {
      printf("Can not read the info header of the BMP file.\n");
      return -1;
   }
   width=bmih.biWidth;
   height=bmih.biHeight;
   bitCount=bmih.biBitCount;
   dwLineBytes=GetLineBytes(width,bitCount);

   data=(BYTE*)Li_malloc(dwLineBytes*height*sizeof(BYTE));
   if(!data)
   {
      printf("Can not allocate memory for the pixel data.\n");
      return -1;
   }
   fp=fopen(filepath,"rb");
   if(!fp)
   {
      printf("Can not open the file: %s\n",filepath);
      Li_free(data);
      return -1;
   }
   if(bitCount==8)
   {
      fseek(fp,bmfh.bfOffBits,SEEK_SET);
   }
   else if(bitCount==24)
   {
      fseek(fp,bmfh.bfOffBits,SEEK_SET);
   }
   else if(bitCount==16)
   {
      fseek(fp,bmfh.bfOffBits,SEEK_SET);
   }
   else
   {
      printf("DO NOT SUPPORT THIS KIND OF FILE\n");
      return -1;
   }
   
   if(fread(data,dwLineBytes*height*sizeof(BYTE),1,fp)!=1)
   {
      printf("Can not read the pixel data.\n");
      Li_free(data);
      fclose(fp);
      return -1;
   }
   Li_memcpy(imgData,data,dwLineBytes*height*sizeof(BYTE));
   Li_free(data);
   fclose(fp);
   return 0;
}

void PrintbmpFileHeader(BITMAPFILEHEADER *bmfh)
{
   printf("The contents in the file header of the BMP file:\n");
   printf("bfOffBits: %ld\n",bmfh->bfOffBits);
   printf("bfReserved1: %ld\n",bmfh->bfReserved1);
   printf("bfReserved2: %ld\n",bmfh->bfReserved2);
   printf("bfSize: %ld\n",bmfh->bfSize);
   printf("bfType: %ld\n",bmfh->bfType);
}

void PrintbmpInfoHeader(BITMAPINFOHEADER *bmih)
{
   printf("The content in the info header of the BMP file:\n");
   printf("biBitCount: %ld\n",bmih->biBitCount);
   printf("biClrImportant: %ld\n",bmih->biClrImportant);
   printf("biClrUsed: %ld\n",bmih->biClrUsed);
   printf("biCompression: %ld\n",bmih->biCompression);
   printf("biHeight: %ld\n",bmih->biHeight);
   printf("biPlanes: %ld\n",bmih->biPlanes);
   printf("biSize: %ld\n",bmih->biSize);
   printf("biSizeImage: %ld\n",bmih->biSizeImage);
   printf("biWidth: %ld\n",bmih->biWidth);
   printf("biXPelsPerMeter: %ld\n",bmih->biXPelsPerMeter);
   printf("biYPelsPerMeter: %ld\n",bmih->biYPelsPerMeter);
}

LONG GetLineBytes(int imgWidth,int bitCount)
{
   return (imgWidth*bitCount+31)/32*4;
}

void PrintbmpPixelData(BYTE *imgData,int width,int height,int bitCount)
{
   int i;
   int j;
   int p;
   DWORD dwLineBytes=GetLineBytes(width,bitCount);
      if(bitCount==8)
      {
         for(i=0;i<height;i++)
         {
         for(j=0;j<width;j++)
         {
         p=*(imgData+dwLineBytes*(height-1-i)+j);
         printf("%d,",p);
         }
         printf("\n");
         }
      }
      else if(bitCount==24)
      {
         for(i=0;i<height;i++)
         {
         for(j=0;j<width*3;j++)
         {
         printf("(");
         p=*(imgData+dwLineBytes*(height-1-i)+j);
         printf("%d,",p);
         j++;
         p=*(imgData+dwLineBytes*(height-1-i)+j);
         printf("%d,",p);
         j++;
         p=*(imgData+dwLineBytes*(height-1-i)+j);
         printf("%d) ",p);
         }
         printf("\n");
         }
      }
      else
      {
         printf("Only supported: 8 or 24 bits.\n");
      }
   }


 int CheckbmpFilePath(char *filepath)
 {
   FILE *fp;
   int len=strlen(filepath)/sizeof(char);
   char ext[3];
   if(filepath[0]!='\"')
   {
      strncpy(ext,&filepath[len-3],3);
      if(!(ext[0]=='b' && ext[1]=='m' && ext[2]=='p'))
      {
      printf("Error: The file is not a BMP file.\n");
      printf("Error: The extention of the filename must be 'bmp',not 'BMP'\n");
      return -1;
      }
      fp=fopen(filepath,"r");
      if(!fp)
      {
      printf("Error: The path is not correct.\n");
      return -1;
      }
      fclose(fp);
   }
   else
   {
      printf("Error: The path must not include blank space.\n");
      return -1;
   }
   return 0;
}


Mat bmpload(char *filepath)
{
    int i,q;
    int bitCount;
    DWORD dwLineBytes;
    Mat mat;
    i=CheckbmpFilePath(filepath);
    i=0;
    mat.PATH=Li_malloc(100);
    strcpy(mat.PATH,filepath);

   
     i=ReadbmpFileHeader(filepath,&mat.bmf);
     if(i!=-1)
     {
      printf("Read the file header successfully.\n");
     }
     else
     {
      printf("Read the file header failed.\n");
      q=1;
     }
     i=ReadbmpInfoHeader(filepath,&mat.bmi);
     if(i!=-1)
     {
      printf("Read the info header successfully.\n");
     }
     else
     {
      printf("Read the info header failed.\n");
      q=1;
     }
     PrintbmpFileHeader(&mat.bmf);
     PrintbmpInfoHeader(&mat.bmi);
     mat.highth=mat.bmi.biHeight;
     mat.width=mat.bmi.biWidth;
     bitCount=mat.bmi.biBitCount;
     mat.pictype=mat.bmi.biBitCount/8;
     dwLineBytes=GetLineBytes(mat.width,bitCount);
     mat.imgData=(BYTE*)Li_malloc(dwLineBytes*(mat.highth)*sizeof(BYTE));
     if(!mat.imgData)
     {
      printf("Can not allocate memory for the image.\n");
      q=1;
     }
     i=ReadbmpPixelData(filepath,mat.imgData);
     if(i==-1)
     {
      printf("Read the pixel data failed.\n");
      q=1;
     }
     else
     {
      printf("Read the pixel data successfully.\n");
     }
     return mat;
}


int bmpprocess(Mat* mat,int width,int highth,u32 color)
{
   u32 offset;
   u8 R=(u8)(color);
   u8 G=(u8)(((WORD)(color)) >> 8);
   u8 B=(u8)((color)>>16);
   DWORD dwLineBytes=GetLineBytes(mat->width,24);
   offset=dwLineBytes*(mat->highth-1-highth)+width*3;
   *(mat->imgData+offset)=R;
   *(mat->imgData+offset+1)=G;
   *(mat->imgData+offset+2)=B;
   return 0;
}

u8* bmpat(Mat* mat,int width,int highth)
{
   u32 offset;  
	   DWORD dwLineBytes=GetLineBytes(mat->width,24);
	   offset=dwLineBytes*(mat->highth-1-highth)+width*3;

	   return mat->imgData+offset;
	

}


int SaveAsbmpImage(char *filepath,Mat* mat)
{
   FILE *fp;
   RGBQUAD pal[256];
   int i;
   int height;
   DWORD dwLineBytes;
   Mat* dst;
   height=mat->bmi.biHeight;
   dwLineBytes=GetLineBytes(mat->bmi.biWidth,mat->bmi.biBitCount);
   strcpy(mat->PATH,filepath);
   fp=fopen(filepath,"wb");
   if(!fp)
   {
      printf("Error: Can not open the file:%s\n",filepath);
   }

   for(i=0;i<256;i++)
   {
      pal[i].rgbReserved=0;
      pal[i].rgbBlue=i;
      pal[i].rgbGreen=i;
      pal[i].rgbRed=i;
   }

   if(fwrite(&mat->bmf.bfType,sizeof(WORD),1,fp)!=1)
   {
      printf("Can not write bfType in the file header.\n");
      fclose(fp);
   }

   if(fwrite(&mat->bmf.bfSize,sizeof(DWORD),1,fp)!=1)
   {
      printf("Can not write bfSize in the file header.\n");
      fclose(fp);
   }

   if(fwrite(&mat->bmf.bfReserved1,sizeof(WORD),1,fp)!=1)
   {
      printf("Can not write bfReserved1 in the file header.\n");
      fclose(fp);
   }

   if(fwrite(&mat->bmf.bfReserved2,sizeof(WORD),1,fp)!=1)
   {
      printf("Can not write bfReserved2 in the file header.\n");
      fclose(fp);
   }

   if(fwrite(&mat->bmf.bfOffBits,sizeof(DWORD),1,fp)!=1)
   {
      printf("Can not write bfOffBits in the file header.\n");
      fclose(fp);
   }
   if(fwrite(&mat->bmi.biSize,sizeof(DWORD),1,fp)!=1)
   {
      printf("Can not write biSize in the info header.\n");
      fclose(fp);
   }

   if(fwrite(&mat->bmi.biWidth,sizeof(LONG),1,fp)!=1)
   {
      printf("Can not write biWidth in the info header.\n");
      fclose(fp);
   }

   if(fwrite(&mat->bmi.biHeight,sizeof(LONG),1,fp)!=1)
   {
      printf("Can not write biHeight in the info header.\n");
      fclose(fp);
   }

   if(fwrite(&mat->bmi.biPlanes,sizeof(WORD),1,fp)!=1)
   {
      printf("Can not write biPlanes in the info header.\n");
      fclose(fp);
   }

   if(fwrite(&mat->bmi.biBitCount,sizeof(WORD),1,fp)!=1)
   {
      printf("Can not write biBitCount in the info header.\n");
      fclose(fp);
   }

   if(fwrite(&mat->bmi.biCompression,sizeof(DWORD),1,fp)!=1)
   {
      printf("Can not write biCompression in the info header.\n");
      fclose(fp);
   }

   if(fwrite(&mat->bmi.biSizeImage,sizeof(DWORD),1,fp)!=1)
   {
      printf("Can not write biSizeImage in the info header.\n");
      fclose(fp);
   }

   if(fwrite(&mat->bmi.biXPelsPerMeter,sizeof(LONG),1,fp)!=1)
   {
      printf("Can not write biXPelsPerMeter in the info header.\n");
      fclose(fp);
   }

   if(fwrite(&mat->bmi.biYPelsPerMeter,sizeof(LONG),1,fp)!=1)
   {
      printf("Can not write biYPelsPerMeter in the info header.\n");
      fclose(fp);
   }

   if(fwrite(&mat->bmi.biClrUsed,sizeof(DWORD),1,fp)!=1)
   {
      printf("Can not write biClrUsed in the info header.\n");
      fclose(fp);
   }

   if(fwrite(&mat->bmi.biClrImportant,sizeof(DWORD),1,fp)!=1)
   {
      printf("Can not write biClrImportant in the info header.\n");
      fclose(fp);
   }

   if(mat->bmi.biBitCount==8)
   {
      if(fwrite(pal,sizeof(RGBQUAD),256,fp)!=256)
      {
      printf("Error: can not write the color palette.\n");
      fclose(fp);
      }
   }

   if(fwrite(mat->imgData,height*dwLineBytes,1,fp)!=1)
   {
      printf("Error: can not write the pixel data.\n");
      fclose(fp);
   }

   fclose(fp);
   printf("Save As the image successfully.\n");

   return 0;

}

Mat bmpcopy(Mat mat)
{
   Mat out;
   out.bmf=mat.bmf;
   out.bmi=mat.bmi;
   out.highth=mat.highth;
   out.width=mat.width;
   out.pictype=mat.pictype;
   out.PATH=Li_malloc(100);
   strcpy(out.PATH,mat.PATH);
   out.imgData=(BYTE*)Li_malloc(mat.highth*mat.width*3);
   Li_memcpy(out.imgData,mat.imgData,mat.highth*mat.width*3);
   return out;

}

void bmpdestory(Mat* mat)
{
   free(mat->PATH);
   free(mat->imgData);
}


#ifdef WINDOWS

void ShowbmpImage(Mat* mat)
{
   char cmd[266];
   strcpy(cmd,"start ");
   strcat(cmd,mat->PATH);
   printf("%s\n",cmd);
   system(cmd);
}

#endif 


#ifdef X86_LINUX

void ShowbmpImage(Mat* mat)
{
   char cmd[266];
   strcpy(cmd,"display ");
   strcat(cmd,mat->PATH);
   printf("%s\n",cmd);
   system(cmd);
}
#endif 

#ifdef ARM_LINUX

#include
#include
#include
#include 
#include 
#include 
#include 
#include 
#include 
#include 


void ARM_ShowbmpImage(Mat* mat,struct fb_var_screeninfo vinfo,struct fb_fix_screeninfo finfo,char *fbp)
{

   int x,y;
   u8* addr;
   long int location = 0;
  for(x=0;x<=mat->width;x++)
  for(y=0;y<=mat->highth;y++)
  {
         addr=at(mat,x,y);
  
         location = (x+vinfo.xoffset) * (vinfo.bits_per_pixel/8) +
                 (y+vinfo.yoffset) * finfo.line_length;
         *(fbp + location) =    *(addr); /*  blue */
         *(fbp + location + 1) =*(addr+1);
         *(fbp + location + 2) =*(addr+2); /* red */
         *(fbp + location + 3) = 0x00;
         
  }
}
#endif 

Mat.c

/*************************************************
Copyright © Yueyang Co. Ltd. 2019-2029. All rights reserved.
File name: Mat.c
Author: Yueyang
Version: V1.0
Description: 提供Mat结构体
Others: 
Log: 11.3 Yueyang
*************************************************/

#include "bmp.h"
#include "cv.h"
#include 
#include 

//创建一个空白的图片类
Mat MatCreate(u8* filepath,u16 width,u16 height,u8 type)
{
    Mat mat;
    mat.bmi.biBitCount=type*8;
    mat.bmi.biSize=sizeof(BITMAPINFOHEADER);
    mat.width=width;
    mat.bmi.biWidth=width;
    mat.highth=height;
    mat.bmi.biHeight=height;
    mat.bmi.biPlanes=1;
    mat.bmi.biCompression=0;
    mat.bmi.biSizeImage=height*width*type;
    mat.bmi.biClrUsed=0;
    mat.bmi.biClrImportant=0;
    mat.bmi.biXPelsPerMeter=2874;
    mat.bmi.biYPelsPerMeter=2874;

    mat.bmf.bfType=((u16)'M'<<8)+'B';
    mat.bmf.bfSize=786486;
    mat.bmf.bfOffBits=54;
    mat.imgData=Li_malloc(height*width*type);
    mat.PATH=Li_malloc(100);
    strcpy(mat.PATH,filepath);
    return mat;
}



#ifdef WINDOWS

void Mat_Init()
{
    show=ShowbmpImage;
    at=bmpat;
    process=bmpprocess;
    load=bmpload;
    save=SaveAsbmpImage;
    destory=bmpdestory;
    copy=bmpcopy;
    create=MatCreate;
    filewrite=fwrite;
    fileread=fread;
    fileopen=fopen;
    fileseek=fseek;
    fileclose=fclose;
    Li_malloc=malloc;
    Li_memcpy=memcpy;
    Li_free=free;
}


#endif



#ifdef X86_LINUX

void Mat_Init()
{
    show=ShowbmpImage;
    at=bmpat;
    process=bmpprocess;
    load=bmpload;
    save=SaveAsbmpImage;
    copy=bmpcopy;
    fileread=fread;
    fileopen=fopen;
    fileseek=fseek;
    fileclose=fclose;
    Li_malloc=malloc;
    Li_memcpy=memcpy;
    Li_free=free;
}


#endif

#ifdef ARM_LINUX

void Mat_Init()
{
    show=ShowbmpImage;
    at=bmpat;
    process=bmpprocess;
    load=bmpload;
    save=SaveAsbmpImage;
    copy=bmpcopy;
    Li_malloc=malloc;
    Li_memcpy=memcpy;
    Li_free=free;
}


#endif

#ifdef ARM_NONE

#endif


【数字图像处理】C语言实现BMP图片的读取显示存储_第3张图片

(四)写在最后

其实重新造轮子这种事情看似没有意义,可是在这个过程中所能学到的东西绝不是会用opencv的几个函数所能相比的。
到目前为止笔者已经分别在WINDOWS,X86_LINUX,ARM_LINUX这三个平台上适配了这个图形系统。我会持续的在github中完善这个系统。
github地址:

LITECV github源码地址

你可能感兴趣的:(数字图像处理)