您的位置:首页 > 编程语言 > C语言/C++

基于标准C语言的数字图像处理基本框架

2013-04-16 11:01 543 查看
考虑到现有的数字图像处理都是基于Windows平台,都或多或少使用了Win32 API函数,不能移植到Linux或者嵌入式系统中。为了使程序可移植,采用标准C语言建立了数字图像处理的基本框架,如下图所示:





程序参考了网上一些博客的内容,并进行了改变,建立了符合自己习惯的数据结构。主要实现了bmp格式图像的打开、保存、创建、图像颜色空间转换等功能,暂时还没有添加具体的处理函数。我想,既然有了程序的框架,添加算法只是编写一个个函数的问题。

本程序具体实现的功能如下:

* 打开和保存bmp文件,这里使用自定义数据结构Bitmap,相关函数定义如下:

bmp.h:

int CreateBitmap(Bitmap* bmp, int width, int height, int bitCount);

void ReleaseBitmap(Bitmap* bmp);

int CheckPath(char *path);

int ReadBitmap(char* path, Bitmap* bmp);

int SaveBitmap(char* path, Bitmap* bmp);

* 图像格式转换

basicprocess.h:

int RGB2Gray(Bitmap* src, Bitmap* dst);

int Gray2RGB(Bitmap* src, Bitmap* dst);

int Gray2BW(Bitmap* src, Bitmap* dst, int threshold);

void hsv2rgb(float H, float S, float V, float *R, float *G, float *B);

void rgb2hsv(float R, float G, float B, float *H, float *S, float* V);

程序源码如下,欢迎大家批评指正。

/**//*

****************************************Copyright (c)**************************************************

** Feisky

** http://www.cnblogs.com/feisky/

**

**------------------------------------- File Info ------------------------------------------------------

** File name: bmp.h

** Last modified Date: 2009-9-25

** Last Version: 1.0

** Descriptions: 位图文件结构及基本函数定义 打开和保存bmp文件

**

** Created by: Feisky

** Created date: 2009-07-25

** Version: 1.0

** Descriptions: Preliminary version.

**

**------------------------------------------------------------------------------------------------------

*/

#ifndef BMP_H_INCLUDED

#define BMP_H_INCLUDED

#include <ctype.h>

#include <stdio.h>

#include <stdlib.h>

#include <malloc.h>

#include <string.h>

/**//**

* 位图文件结构及基本函数定义 打开和保存bmp文件

*/

typedef unsigned short WORD;

typedef unsigned long DWORD;

typedef long LONG;

typedef unsigned char BYTE;

/**//* 位图文件头结构 14字节 */

typedef struct tagBITMAPFILEHEADER {

WORD bfType;

DWORD bfSize;

WORD bfReserved1;

WORD bfReserved2;

DWORD bfOffBits;

} BITMAPFILEHEADER;

/**//* 位图信息头结构 40字节 */

typedef struct tagBITMAPINFOHEADER {

DWORD biSize; // 结构长度 40B

LONG biWidth;

LONG biHeight;

WORD biPlanes; // 1

WORD biBitCount; // 表示颜色要用到的位数

DWORD biCompression; // 压缩格式

DWORD biSizeImage; // 位图占用字节数=biWidth'(4的整倍数)*biHeight

LONG biXPelsPerMeter; // 水平分辨率

LONG biYPelsPerMeter; // 垂直分辨率

DWORD biClrUsed; // 本图像用到的颜色数

DWORD biClrImportant; // 本图像的重要颜色数

} BITMAPINFOHEADER;

/**//* 调色板 4字节 */

typedef struct tagRGBQUAD {

BYTE rgbBlue;

BYTE rgbGreen;

BYTE rgbRed;

BYTE rgbReserved;

} RGBQUAD;

/**//* 定义图像信息 */

typedef struct tagBITMAPINFO {

BITMAPINFOHEADER bmiHeader;

RGBQUAD bmiColors[1];

} BITMAPINFO;

/**//* 定义位图图像 */

typedef struct _Bitmap

{

BITMAPFILEHEADER bmfh;

BITMAPINFOHEADER bmih;

int width;

int height;

int bitCount; // 8 或者24

int imageSize; // 图像数据大小(imageSize=height*widthStep)字节

BYTE* imageData;//排列的图像数据

int widthStep; //排列的图像行大小

}Bitmap;

/**//**

* 位图创建函数 创建一个Bitmap结构,并为图像数据分配空间

*

* 使用方法:

* Bitmap *bmp=(Bitmap*)malloc(sizeof(Bitmap));

* ret=CreateBitmap(bmp,50,50,3);

*/

int CreateBitmap(Bitmap* bmp, int width, int height, int bitCount)

{

bmp->width=width;

bmp->height=height;

bmp->bmih.biWidth=width;

bmp->bmih.biHeight=height;

bmp->widthStep=(int)((width*bitCount+31)/32)*4; //计算排列的宽度

bmp->imageSize=bmp->height*bmp->widthStep*sizeof(BYTE);//计算排列的图像大小

if(bitCount==8)

{

bmp->bitCount=8;

bmp->bmfh.bfType=0x4d42; //注意是4d42 这个地方折磨我一下午啊

bmp->bmfh.bfReserved1=0;

bmp->bmfh.bfReserved2=0;

bmp->bmih.biBitCount=8;

bmp->bmih.biSize=40;

bmp->bmih.biPlanes=1;

bmp->bmfh.bfSize=54+256*4+height*bmp->widthStep;

bmp->bmfh.bfOffBits=1078;

bmp->bmih.biBitCount=8;

bmp->bmih.biCompression=0;

bmp->bmih.biSizeImage=bmp->imageSize;

bmp->bmih.biClrUsed=0;

bmp->bmih.biClrImportant=0;

bmp->bmih.biXPelsPerMeter=0;

bmp->bmih.biYPelsPerMeter=0;

}

else if (bitCount==24)

{

bmp->bitCount=24;

bmp->bmfh.bfType=0x4d42;

bmp->bmih.biBitCount=24;

bmp->bmfh.bfReserved1=0;

bmp->bmfh.bfReserved2=0;

bmp->bmih.biSize=40;

bmp->bmih.biPlanes=1;

bmp->bmfh.bfSize=54+height*bmp->widthStep;

bmp->bmfh.bfOffBits=54;

bmp->bmih.biBitCount=24;

bmp->bmih.biSizeImage=bmp->imageSize;

bmp->bmih.biClrUsed=0;

bmp->bmih.biCompression=0;

bmp->bmih.biClrImportant=0;

bmp->bmih.biXPelsPerMeter=0;

bmp->bmih.biYPelsPerMeter=0;

}

else

{

printf("Error(CreateBitmap): only supported 8 or 24 bits bitmap.\n");

return -1;

}

bmp->imageData=(BYTE*)malloc(bmp->imageSize); //分配数据空间

if(!(bmp->imageData))

{

printf("Error(CreateBitmap): can not allocate bitmap memory.\n");

return -1;

}

return 0;

}

/**//**

* 位图指针释放函数 释放位图数据空间

*

* 使用方法:

* ReleaseBitmap(bmp);

*/

void ReleaseBitmap(Bitmap* bmp)

{

free(bmp->imageData);

bmp->imageData=NULL;

free(bmp);

bmp=NULL;

}

/**//**

* 路径检查函数:是否为BMP文件,是否可读

* 正确返回0,错误返回-1

*

* 使用方法

* ret=CheckPath(path);

*/

int CheckPath(char *path)

{

FILE *fd;

int len = strlen(path) / sizeof(char);

char ext[3];

//check whether the path include the characters "bmp" at end

strncpy(ext, &path[len - 3], 3);

if (!(ext[0] == 'b' && ext[1] == 'm' && ext[2] == 'p')) {

printf("Error(CheckPath): the extension of the file is not bmp.\n");

return -1;

}

//check whether the file can be read or not

fd = fopen(path, "r");

if (!fd)

{

printf("Error(CheckPath): can not open the file.\n");

return -1;

}

fclose(fd);

return 0;

}

/**//**

* 从文件中读取位图函数

* 正确返回0,错误返回-1

*

* 使用方法:

* bmp=(Bitmap*)malloc(sizeof(Bitmap));

* ret=ReadBitmap(path, bmp);

*/

int ReadBitmap(char* path, Bitmap* bmp)

{

int ret;

FILE *fd;

//检查路径是否可读

ret=CheckPath(path);

if(ret==-1)

{

printf("Error(ReadBitmap): the path of the image is invalid.\n");

return -1;

}

//打开文件

fd=fopen(path,"rb");

if(fd==0)

{

printf("Error(ReadBitmap): can not open the image.\n");

return -1;

}

//读取文件信息头 14字节

fread(&(bmp->bmfh.bfType),sizeof(WORD),1,fd);

fread(&(bmp->bmfh.bfSize),sizeof(DWORD),1,fd);

fread(&(bmp->bmfh.bfReserved1),sizeof(WORD),1,fd);

fread(&(bmp->bmfh.bfReserved2),sizeof(WORD),1,fd);

fread(&(bmp->bmfh.bfOffBits),sizeof(DWORD),1,fd);

//读取位图信息头 40字节

fread(&(bmp->bmih.biSize),sizeof(DWORD),1,fd);

fread(&(bmp->bmih.biWidth),sizeof(DWORD),1,fd);

fread(&(bmp->bmih.biHeight),sizeof(DWORD),1,fd);

fread(&(bmp->bmih.biPlanes),sizeof(WORD),1,fd);

fread(&(bmp->bmih.biBitCount),sizeof(WORD),1,fd);

fread(&(bmp->bmih.biCompression),sizeof(DWORD),1,fd);

fread(&(bmp->bmih.biSizeImage),sizeof(DWORD),1,fd);

fread(&(bmp->bmih.biXPelsPerMeter),sizeof(DWORD),1,fd);

fread(&(bmp->bmih.biYPelsPerMeter),sizeof(DWORD),1,fd);

fread(&(bmp->bmih.biClrUsed),sizeof(DWORD),1,fd);

fread(&(bmp->bmih.biClrImportant),sizeof(DWORD),1,fd);

//创建位图结构

ret=CreateBitmap(bmp, bmp->bmih.biWidth, bmp->bmih.biHeight, bmp->bmih.biBitCount);

if(ret==-1)

{

printf("Error(CreateBitmap): can not CreateBitmap.\n");

return -1;

}

//读取图像数据

//由于4字节对齐格式

fseek(fd,bmp->bmfh.bfOffBits,SEEK_SET); //定位到图像数据区

ret=fread(bmp->imageData,bmp->imageSize,1,fd);

if(ret==0)

{

if(feof(fd)) //if the file pointer point to the end of the file

{

}

if(ferror(fd)) //if error happened while read the pixel data

{

printf("Error(ReadBitmap): can not read the pixel data.\n");

fclose(fd);

return -1;

}

}

//关闭文件

fclose(fd);

return 0;

}

/**//**

* 保存位图到文件中去

* 正确返回0,错误返回-1

*

* 使用方法:

* bmp=(Bitmap*)malloc(sizeof(Bitmap));

* ret=SaveBitmap(path, bmp);

*/

int SaveBitmap(char* path, Bitmap* bmp)

{

int ret;

FILE *fd;

//检查路径是否正确

int len = strlen(path) / sizeof(char);

char ext[3];

//check whether the path include the characters "bmp" at end

strncpy(ext, &path[len - 3], 3);

if (!(ext[0] == 'b' && ext[1] == 'm' && ext[2] == 'p'))

{

printf("Error(SaveBitmap): the extension of the file is not bmp.\n");

return -1;

}

//打开文件

fd=fopen(path,"wb");

if(fd==0)

{

printf("Error(SaveBitmap): can not open the image.\n");

return -1;

}

//保存文件信息头 14字节

fwrite(&(bmp->bmfh.bfType),sizeof(WORD),1,fd);

fwrite(&(bmp->bmfh.bfSize),sizeof(DWORD),1,fd);

fwrite(&(bmp->bmfh.bfReserved1),sizeof(WORD),1,fd);

fwrite(&(bmp->bmfh.bfReserved2),sizeof(WORD),1,fd);

fwrite(&(bmp->bmfh.bfOffBits),sizeof(DWORD),1,fd);

//保存位图信息头 40字节

fwrite(&(bmp->bmih.biSize),sizeof(DWORD),1,fd);

fwrite(&(bmp->bmih.biWidth),sizeof(DWORD),1,fd);

fwrite(&(bmp->bmih.biHeight),sizeof(DWORD),1,fd);

fwrite(&(bmp->bmih.biPlanes),sizeof(WORD),1,fd);

fwrite(&(bmp->bmih.biBitCount),sizeof(WORD),1,fd);

fwrite(&(bmp->bmih.biCompression),sizeof(DWORD),1,fd);

fwrite(&(bmp->bmih.biSizeImage),sizeof(DWORD),1,fd);

fwrite(&(bmp->bmih.biXPelsPerMeter),sizeof(DWORD),1,fd);

fwrite(&(bmp->bmih.biYPelsPerMeter),sizeof(DWORD),1,fd);

fwrite(&(bmp->bmih.biClrUsed),sizeof(DWORD),1,fd);

fwrite(&(bmp->bmih.biClrImportant),sizeof(DWORD),1,fd);

//如果为8位,则 保存调色板

RGBQUAD pal[256];

int i;

if(bmp->bitCount==8)

{

for(i=0;i<256;i++)

{

pal[i].rgbBlue=i;

pal[i].rgbGreen=i;

pal[i].rgbRed=i;

pal[i].rgbReserved=0;

}

if(fwrite(pal,sizeof(RGBQUAD)*256,1,fd)!=1)

{

printf("Error(SaveBitmap): can not write Color Palette.\n");

return -1;

}

}

//保存图像数据

ret=fwrite(bmp->imageData,bmp->imageSize,1,fd);

if(ret!=1)

{

printf("Error(SaveBitmap): can not save the pixel data.\n");

return -1;

}

//关闭文件

fclose(fd);

return 0;

}

#endif // BMP_H_INCLUDED

/**//*

****************************************Copyright (c)**************************************************

** Feisky

** http://www.cnblogs.com/feisky/

**

**------------------------------------- File Info ------------------------------------------------------

** File name: basicprocess.h

** Last modified Date: 2009-9-28

** Last Version: 1.0

** Descriptions: 位图图像基本处理函数 图像格式转换

**

** Created by: Feisky

** Created date: 2009-9-28

** Version: 1.0

** Descriptions: Preliminary version.

**

**------------------------------------------------------------------------------------------------------

*/

#ifndef BASICPROCESS_H_

#define BASICPROCESS_H_

#include "bmp.h"

#include <math.h>

/**//**

* <font color="#3f7f5f">位图图像基本处理函数 图像格式转换</font>

*/

int RGB2Gray(Bitmap* src, Bitmap* dst)

{

int ret;

int n=0,i,j;

BYTE r,g,b,gray;

//检查图像格式是否合法

if(src->bitCount!=24)

{

printf("Error(RGB2Gray): the source image must be in RGB format.\n");

return -1;

}

//为dst图像分配数据空间

ret=CreateBitmap(dst,src->width,src->height,8);

if(ret==-1)

{

printf("Error(RGB2Gray): can't create target image.\n");

return -1;

}

//计算灰度数据

for(i=0;i<src->height;i++)

{

n=0;

for(j=0;j<src->width*3;j++,n++)

{

b=*(src->imageData+src->widthStep*(src->height-1-i)+j);

j++;

g=*(src->imageData+src->widthStep*(src->height-1-i)+j);

j++;

r=*(src->imageData+src->widthStep*(src->height-1-i)+j);

gray=(r*19595 + g*38469 + b*7472) >> 16;

*(dst->imageData+dst->widthStep*(dst->height-1-i)+n)=gray;

}

}

return 0;

}

/**//**

* Gray2RGB

*

* 使用方法:

* bmp=(Bitmap*)malloc(sizeof(Bitmap));

* ret=ReadBitmap(path, bmp);

* dstbmp=(Bitmap*)malloc(sizeof(Bitmap));

* ret=Gray2RGB(bmp,dstbmp);

*/

int Gray2RGB(Bitmap* src, Bitmap* dst)

{

int ret;

int n=0,i,j;

BYTE r;

//检查图像格式是否合法

if(src->bitCount!=8)

{

printf("Error(Gray2RGB): the source image must be in gray scale.\n");

return -1;

}

//为dst图像分配数据空间

ret=CreateBitmap(dst,src->width,src->height,24);

if(ret==-1)

{

printf("Error(Gray2RGB): can't create target image.\n");

return -1;

}

//计算灰度数据

for(i=0;i<src->height;i++)

{

n=0;

for(j=0;j<src->width;j++,n++)

{

r=*(src->imageData+src->widthStep*(src->height-1-i)+j);

*(dst->imageData+dst->widthStep*(dst->height-1-i)+n)=r;

n++;

*(dst->imageData+dst->widthStep*(dst->height-1-i)+n)=r;

n++;

*(dst->imageData+dst->widthStep*(dst->height-1-i)+n)=r;

}

}

return 0;

}

/**//**

* Gray2BW 图像二值化

*

* 使用方法:

* bmp=(Bitmap*)malloc(sizeof(Bitmap));

* ret=ReadBitmap(path, bmp);

* dstbmp=(Bitmap*)malloc(sizeof(Bitmap));

* ret=Gray2BW(bmp,dstbmp);

*/

int Gray2BW(Bitmap* src, Bitmap* dst, int threshold)

{

int ret;

int n=0,i,j;

BYTE r;

//检查图像格式是否合法

if(src->bitCount!=8)

{

printf("Error(Gray2BW): the source image must be in gray scale.\n");

return -1;

}

//为dst图像分配数据空间

ret=CreateBitmap(dst,src->width,src->height,8);

if(ret==-1)

{

printf("Error(Gray2BW): can't create target image.\n");

return -1;

}

//计算灰度数据

for(i=0;i<src->height;i++)

{

for(j=0;j<src->width;j++,n++)

{

r=*(src->imageData+src->widthStep*(src->height-1-i)+j);

if(r>=threshold)

{

n=255;

}

else

{

n=0;

}

*(dst->imageData+dst->widthStep*(dst->height-1-i)+j)=n;

}

}

return 0;

}

/**//**

* rgb2hsv

* r,g,b values are from 0 to 1

* h = [0,360], s = [0,1], v = [0,1]

* if s == 0, then h = -1 (undefined)

* 使用方法:

* rgb2hsv(0.2,0.3,0.3,&x,&y,&z);

*/

void rgb2hsv(float R, float G, float B, float *H, float *S, float* V)

{

float min, max, delta,tmp;

tmp = R<G?R:G;

min = tmp<B?tmp:B;

tmp = R>G?R:G;

max = tmp>B?tmp:B;

*V = max; // v

delta = max - min;

if( max != 0 )

*S = delta / max; // s

else

{

// r = g = b = 0 // s = 0, v is undefined

*S = 0;

*H = -1;

return;

}

if( R == max )

*H = ( G - B ) / delta; // between yellow & magenta

else if( G == max )

*H = 2 + ( B - R ) / delta; // between cyan & yellow

else

*H = 4 + ( R - G ) / delta; // between magenta & cyan

(*H) *= 60; // degrees

if( *H < 0 )

(*H) += 360;

}

/**//**

* hsv2rgb

* r,g,b values are from 0 to 1

* h = [0,360], s = [0,1], v = [0,1]

* if s == 0, then h = -1 (undefined)

* 使用方法:

* hsv2rgb(60,0.3,0.5,&x,&y,&z);

*/

void hsv2rgb(float H, float S, float V, float *R, float *G, float *B)

{

int i;

float f, p, q, t;

if( S == 0 )

{

*R =*G = *B = V;

return;

}

H /= 60; // sector 0 to 5

i = floor( H );

f = H - i; // factorial part of h

p = V * ( 1 - S );

q = V * ( 1 - S * f );

t = V * ( 1 - S * ( 1 - f ) );

switch( i )

{

case 0:

*R = V;

*G = t;

*B = p;

break;

case 1:

*R = q;

*G = V;

*B = p;

break;

case 2:

*R = p;

*G = V;

*B = t;

break;

case 3:

*R = p;

*G = q;

*B = V;

break;

case 4:

*R = t;

*G = p;

*B = V;

break;

default: // case 5:

*R = V;

*G = p;

*B = q;

break;

}

}

/**//**

* 直方图均衡化

* 返回 0正确 -1错误

*/

int HistEqualization(Bitmap* dstBmp, Bitmap* srcBmp)

{

return 0;

}

/**//*

* 中值滤波

*/

int MedFilt(Bitmap* dstBmp, Bitmap* srcBmp)

{

return 0;

}

#endif /* BASICPROCESS_H_ */
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: