首先对于任何一个二维图像,加载入内存后都能看作一个二维像素数组。假如是一张8位图像,它的每个像素值可以用一个0~255的unsigned char表示,也就是说图像可以看成一个unsigned char的数组。假设它的长和宽分别为width和height,那么这个图像用byte B[height,width](c#二维数组)或者用unsigned char B[height][width](C++二维数组)来表示就非常的恰当。推而广之,假如是一个长宽高分别是width、height和depth的三维图像,那么就可以采用三维数组来byte B[depth,height,width](C#)或者unsigned char B[depth][height][width](C++)来表示。
由于内存地址实际上是线性的,在计算机里面多维数组都是用一维数组的方式组织的,实际上,若使用二维数组B[a][b]。对于一个长宽分别为b和a的位图B,内存中实际上是一个线性排列的布局,也就是说计算机会把一个二维数组看成是数组的数组,一个三维的数组就是数组的数组的数组。例如二维数组unsigned char B[height][width] ,内存中的就是height个长度为width的数组,那么假如数组的初始地址为B,那么B[i][j]的实际存储位置是在i个width后面再加j个位置。所以我们若把二维数组一维化,我们可以把B声明为一个一维数组 unsigned char B[width*height],当我们取第i行j列的像素的时候,就使用B[i*width+j]这个表达式。
这里有一个问题,为什么要讨论二维和三维图像的一维化,直接使用多维数组行吗?其实图像都统一使用一维数组的表达方式,很大程度是因为IO原因。因为对于一张位图,或者是.raw格式的无压缩图像,在读取图像的时候都是使用一维数组作为缓冲区(比如c语言的fread函数 size_t fread ( void *buffer, size_t size, size_t count, FILE *stream) 中的buffer就是个一维数组)那么将图像文件读为一维数组后,一般为了避免不必要的开销,就不会再把这个数组的值按位置一一复制到一个二维数组去,而是直接使用这个一维数组。实际上,使用二维、三维数组作为二维、三维图像的存储结构也完全没有问题。只是在遇到这两种不同方式的时候,记住二维的B[j][i]对应于一维的B[i*width+j],三维的B[k][j][i]对应于一维的B[i+j*width+k*width*height]即可。
下面的代码是用C++封装了二维或三维图像的相关属性、方法和数据。可以看出,图像最基本要有长宽高这些表示尺寸的属性,然后需要一个表示像素类型的类别PixelType。对于8位图像,一般使用char或 unsigned char表示像素类型。对于16位或者32位图像,既可以用C++语言相应长度的short和int/float变量来表示,也可以声明一个新结构体,由若干个char或unsigned char成员来组成。使用结构体也是比较常用的方法,比如对于ARGB图像而言使用的PixelType是一个有四个unsigned char成员的结构体,这样这四个成员能分别表示对应的颜色的A、R、G、B分量。图像结构体中当然还必须有指向图像数据的指针*B,同时还要提供存取像素的方法。
#define T PixelType
struct Bitmap2D
{
T *B;
int width;
int height;
void SetPixel(int,int,T);
T GetPixel(int,int);
}
struct Bitmap3D
{
T *B;
int width;
int height;
int depth
void SetPixel(int,int,int,T);
T GetPixel(int,int,int);
}
综合以上所述,对于二维图像j行i列的像素的操作的伪代码如下:
GetPixel(i,j)
return B[i+width*j]
SetPixel(i,j,v)
B[i+width*j]=v
三维图像k层j行i列的像素存取方式如下:
GetPixel(i,j,k)
return B[i+width*j+width*height*k]
SetPixel(i,j,k,v)
B[i+width*j+width*height*k]=v
附 三维图像
二维图像在平时使用计算机的时候比较常见,相比之下三维图像一般只出现在专业图像领域。对于三维图像可以有很多表现形式,比如图像序列(N张大小一样的二维图),RAW体数据(三维数组文件)等。如本文用作测试的三维图像Lobster.raw数据,来自www.volvis.org,是用CT扫描产生56张宽301高324的图片然后组合在一起的。内部的值偏大的像素集合组成一个三维的龙虾形状。
不像二维图片能直接完整的在屏幕上显示,想观察三维图像的内容一般得采用特别的办法。一种是观察某一维切片,比如如下的图就是lobster数据分别在Z轴上取5-10-15-....-55的切片制作的动态图。
用体绘制软件ParaView可以用体绘制技术直接在3D场景中观察三维图片的内容:
附2:三维图像的IO
三维图像经常会以.raw文件的形式提供,例如www.volvis.org上的所有sample,解压后都是一个.raw文件。Raw文件其实是存图像最简单的方式,是一种对图像无压缩的存储。实际上,这种格式就是把图像一维化的数组存储成文件,所以可以轻易的写出读取Raw文件的代码。不过由于这个文件不带自描述信息,所以在读的时候一定要清楚所读的文件是多少位的图像,长宽高是多少。例如上图所展示的lobster数据。从数据描述中可知其大小为301×324×56,8位,所以采用C++语言将其读为unsigned char数组的代码如下:
void InitArrayFromVolFile(unsigned char * &data,const char* fileName,int length) { long dataSize = length; std::FILE* file = fopen(fileName,"rb"); if( file == NULL ) { printf("open the file failed "); } fread( data,sizeof(unsigned char),dataSize,file ); fclose(file); }
再将其输出为文件的代码如下,都是比较简单的读写调用,由此同时可以看出,无论是2维还是3维图像,使用一维数组的方式存数据,对于IO来说是十分方便。
void OutPutVolume(const char* fileName,unsigned char* pointer,int width,int height,int depth) { int length=width*height*depth; FILE *const nfile = fopen(fileName,"wb"); fwrite(pointer,sizeof(unsigned char),length,nfile); fclose(nfile); }
前段时间需要找各种三维图像来做实验,发现这个www.volvis.org及其不稳定,时不时就是服务器关闭了,这样会导致需要数据的时候比较麻烦,所以这里干脆把一些常用的数据下来到博客园贴着,以防不时之需。
数据预览 | 数据参数 | 数据描述 |
Aneurism 256x256x256 1:1:1 |
Rotational C-arm x-ray scan of the arteries of the right half of a human head. A contrast agent was injected into the blood and an aneurism is present. |
|
Backpack Scan 16Bits (12bits set) 512 x 512 x 373 0.9766, 0.9766, 1.25 |
CT scan of a backpack filled with items. |
|
Bonsai 256x256x256 1:1:1 |
CT scan of a bonsai tree. |
|
Boston Teapot 256x256x178 1:1:1 |
CT scan of the SIGGRAPH 1989 teapot with a small version of the AVS lobster inside. |
|
Colon Phantom 8Bits 512 x 512 x 442 0.9316, 0.9316, 0.5 |
CT scan of a Colon phantom with several different objects and five pedunculated large polyps in the central object. http://pan.baidu.com/s/1eQgNj6y |
|
Engine 256x256x128 1:1:1 |
CT scan of two cylinders of an engine block. |
|
Foot 256x256x256 1:1:1 |
Rotational C-arm x-ray scan of a human foot. Tissue and bone are present in the dataset. |
|
Lobster 301x324x56 (1:1:1.4) |
CT scan of a lobster contained in a block of resin. |
|
Head MRI CISS 8Bits (8bits set) 256 x 256 x 124 0.9, 0.9, 0.9 |
1.5T MRT 3D CISS dataset of a human head that highlights the CSF (Cerebro-Spinal-Fluid) filled cavities of the head. |
|
Neghip 64x64x64 (1:1:1) |
Simulation of the spatial probability distribution of the electrons in a high potential protein molecule. |
|
Colon Prone 8Bits 512 x 512 x 463 0.625, 0.625, 1.0 |
CT scan of abdomen in prone orientation (back faces ceiling, belly faces table. |
|
Silicium 98x34x34 (1:1:1) |
Simulation of a silicium grid. |
|
Skull 256x256x256 1:1:1 |
Rotational C-arm x-ray scan of phantom of a human skull. |
爬网的太疯狂了,转载本文要注明出处啊:http://www.cnblogs.com/chnhideyoshi/