zoukankan      html  css  js  c++  java
  • 浅谈二维和三维图像数据

      首先对于任何一个二维图像,加载入内存后都能看作一个二维像素数组。假如是一张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.

    http://pan.baidu.com/s/1hqeHkXY

    Backpack Scan 16Bits
    (12bits set)
    512 x 512 x 373
    0.9766, 0.9766, 1.25

    CT scan of a backpack filled with items.

    http://pan.baidu.com/s/1pJO4hwJ

    Bonsai

    256x256x256
    1:1:1

    CT scan of a bonsai tree.

    http://pan.baidu.com/s/1sjPfZhr

    Boston Teapot

    256x256x178
    1:1:1

    CT scan of the SIGGRAPH 1989 teapot with a small version of the AVS lobster inside.

    http://pan.baidu.com/s/1qWlS0SO

    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.

    http://pan.baidu.com/s/1dDoWEY1

    Foot

    256x256x256
    1:1:1

    Rotational C-arm x-ray scan of a human foot. Tissue and bone are present in the dataset.

    http://pan.baidu.com/s/1hqHWORi

    Lobster

    301x324x56
    (1:1:1.4)

    CT scan of a lobster contained in a block of resin.

    http://pan.baidu.com/s/1gdKaIo7

    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.
    We also provide a segmentation of the cerebral ventricular system, where the first (negative) number is the number of all voxels of the segmentation, followed by the voxel array indices of the voxels of the segmentations. Please read the new comment above if you have problems with the voxel indices in the segmenation file.

    http://pan.baidu.com/s/1dD67C7R

    Neghip

    64x64x64
    (1:1:1)

    Simulation of the spatial probability distribution of the electrons in a high potential protein molecule.

    http://pan.baidu.com/s/1sjxvEJr

    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.

    http://pan.baidu.com/s/1jGA1kvO

    Silicium

    98x34x34
    (1:1:1)

    Simulation of a silicium grid.

    http://pan.baidu.com/s/1pcKQ6

    Skull

    256x256x256
    1:1:1

    Rotational C-arm x-ray scan of phantom of a human skull.

    http://pan.baidu.com/s/1hqqS0tQ

       爬网的太疯狂了,转载本文要注明出处啊:http://www.cnblogs.com/chnhideyoshi/

     

  • 相关阅读:
    470. 用 Rand7() 实现 Rand10() 采样
    165. 比较版本号 字符串
    Java 通过属性名称读取或者设置实体的属性值
    双非Java的学习之旅以及秋招路程
    【Unity3D】不可读Texture资源的获取
    java 8 Map 之merge用法
    Jmeter-计数器的应用
    Jmeter-集合点【同步定时器】应用
    2. Go并发编程--GMP调度
    Go序列化嵌套结构体
  • 原文地址:https://www.cnblogs.com/chnhideyoshi/p/3DVolume.html
Copyright © 2011-2022 走看看