您的位置:澳门新葡萄京最大平台 > 最大平台 > NET平台下对C3D文件的读写

NET平台下对C3D文件的读写

发布时间:2019-09-12 13:38编辑:最大平台浏览(82)

    【题外话】

    如今实验室要自个儿修改C3D(The 3D Biomechanics Data Standard)文件,尽管从互连网找到了一个叫c3d4sharp的类库,这一个类库单纯读取C3D文件的话还是能够,然则假使要兑现修改大概创立C3D文件就比较费心了。同期c3d4sharp完毕得比较轻巧,相当多C3D文件里一些数据都不协助。万幸C3D文件总体不是很复杂,于是我就从头重新写了叁个C3D文件读写的库,未来在codeplex上创办了个品类叫C3D.NET。

     

    【小说索引】

    1. C3D文件格式的结构
    2. C3D文件头的结构
    3. C3D文件参数会集的结构
    4. C3D文件数量区域的结构
    5. 采纳C3D.NET读写文件示例

     

    【一、C3D文件格式的结构】

    率先说C3D文件全体不是很复杂,也绝非过多纵横交错的定义,C3D的文书档案格式可以从其官方网站下载或在线阅读。首先C3D文件是以Section为单位存款和储蓄的,每多个Section固定为512字节。Section一定是按顺序存储的,不过风趣的是,Section的序号是从1开首的,实际不是0。C3D文件分为三部分,分别是Section ID = 1的C3D文件头(固定为二个Section,512字节),Section ID一般等于2(在文书头内会提交)的C3D参数集合以及Section ID不知道等于几(在文件头和参数集合中都会付给)的C3D数据部分。

    而是C3D也可能有很复杂的位置,二个是有关整型的行使,能够动用应用有暗号的(Int16),也得以应用无符号的(UInt16),只可是前面一个能积存的数据量要多一些而已,既然这样,不知何故当初还要选拔有暗记的整型。并且最关键的是,文书档案内并未有其余标志能提议文书档案使用的是何种整型。官方给出的缓慢解决措施是,能够依附举个例子帧总量、帧索引等推断,如若读出负数,则接纳无符号的,不然采纳有暗号的。

    另二个是C3D文件能在分歧门类的CPU上扭转,那表现于不一致CPU可能行使的字节序(Endian)和浮点数字不一致,举个例子大家用的CPU都以利用Little-Endian以及IEEE754的浮点数标准。从互连网查还发掘有DEC (VAX)以及IBM等CPU采取分裂的浮点数规范,详见小编事先一篇小说:。而C3D则是永葆3类CPU,IntelCPU选用Little-Endian以及IEEE754标准的浮点数,DEC (VAX)选择的Little-Endian以及故意的浮点数,MIPS (SGI)选拔的Big-Endian以及IEEE754标准的浮点数,所以在读取文书档案的时候或然必要优良开展拍卖,在第一节会详细表达。

     

    【二、C3D文件头的结构】

    第一来讲第1局地,也正是C3D的文件头,C3D的文书头一定只占1个Section,即一定的512字节,所以只要读取前512字节就能够把全体头数据获得到了。即便种种Section有512字节之多,可是对于C3D的文件头只占了相当少的一片段,在文件头中有恢宏空白的区域。在这之中第一有个别是文本头参数部分,内容如下:

    图片 1

    字节 类型 说明
    00H Byte 参数集合开始的Section ID(通常为0x02,但也不一定)
    01H Byte 文件标识(固定为0x50)
    02H-03H Int16 每帧里3D坐标点的个数
    04H-05H Int16 每帧里模拟测量的个数
    06H-07H Int16 第1帧的序号(最小为1)
    08H-09H Int16 最后1帧的序号
    0AH-0BH Int16 最大插值差距
    0CH-0FH Single 比例因子(正数表示存储的帧为整数帧,负数为浮点帧)
    10H-11H Int16  数据区域开始的Section ID
    12H-13H Int16 每帧模拟采样个数
    14H-17H Single 帧率

    在此之后的第1局地,也正是积存的平地风波,听上去应该占非常多字节,但是由于限制了平地风波数量最多不可能抢先18个,同时事件名称最长为4字节,所以事件部分也只占相当少的空间。由于C3D主若是为着记录运动的数量,可能在中间有为数相当多非常主要的地点,事件正是用来标志出那些地点的。二个平地风波富含八个内容,分别是最长四字节的事件名称、一字节的风云是还是不是相应显得的景况以及四个四字节的单精度浮点数表示事件出现的时光。

    字节 类型 说明
    12AH-12BH Int16 事件名是否支持4字节(支持为0x3039,不支持为0)
    12CH-12DH Int16 事件数量(最大为18)
    130H-176H Single[] 按事件顺序存储的每个事件发生的时间(第1个帧为0.0s)
    178H-188H Byte[] 按事件顺序存储的每个事件是否应该显示(1为显示,0为不显示)
    18CH-1D2H Char[] 按事件顺序存储的每个事件的名称(每个事件占4字节)

     

    【三、C3D文件参数会集的布局】 

    C3D文件存款和储蓄了一大波的参数,其行使了看似目录的艺术存款和储蓄了参数,可是幸好独有一流。即参数部分唯有参数组和参数,並且各样参数组里只可以有参数无法再包括参数组,每种参数必需在多少个参数组内。参数集结起初于文件头中的首先个字节表示的Section ID,平常为2,但是也不肯定,有的文件会在文件头后留出空白,然后参数集结发轫的Section ID就滞缓了。所以判别是还是不是为C3D文件千万不要一开头读进去个Int16然后决断是或不是0x5002,而早晚要判定第叁个字节是或不是0x50,明确参数集合的岗位也没有什么可争辨的要基于文件的首先字节来。

    而对此参数集结,初步的4字节定义如下:

    字节 类型 说明
    00H Byte 第一个参数所在的Section在整个参数集合中的位置(通常为0x01,说明开头4字节之后就是第一个参数)
    01H Byte 参数集合部分标识(固定为0x50)
    02H Byte 参数集合所占Section数量
    03H Byte 生成文件的CPU类型(0x54为Intel,0x55为DEC (VAX, PDP-11),0x56为MIPS (SGI/MIPS))

    中间前2个字节官方说一向忽略就行,不过为了合营在写入的时候还是要写进去的。第3字节其实我们按梯次读到头也无需那些数额。这中间首要的是CPU类型,由于分歧CPU类型选用的字节序以及存储的浮点数字有所区别,所以我们还亟需基于CPU类型实行对应的拍卖。

    对于速龙和DEC生成的文书档案,都是选取Little-Endian字节序存款和储蓄的文书档案,所以断定要选拔Little-Endian来读取Int16、Single等类型;而MIPS则运用的Big-Endian字节序存款和储蓄文书档案,所以在读取的时候势要求咬定当前Computer暗中同意的字节序以及文书档案选用的字节序。

    而对于AMD和MIPS生成的文书档案,对于浮点数字的积累都以使用标准的IEEE754浮点数字,对于.NET来讲没有必要举行别的管理;而DEC生成的文书档案则应用特有浮点数,需求将4个字节全体读取现在再打开极度的转移,转换方法见自个儿此前的篇章:。

    在此之下就存款和储蓄着富有的参数了,参数分为两类,分别是参数组和参数。

    对此参数组,要存款和储蓄以下6个内容:

    字节 类型 说明
    00H SByte 参数组名称长度(如果为负数则表示该参数组锁定请不要修改,而长度为绝对值)
    01H SByte 参数组ID的负数
    02H - ... Char[] 参数组名称(仅包含大写字母、0-9以及下划线_)
    ... + 1 - ... + 2 Int16 下一参数组/参数的偏移(包含本内容的2字节)
    ... + 3
    Byte 参数组描述长度
    ... + 4 -  Char[] 参数组描述内容(ASCII码)

    C3D文件未有鲜明二个参数组前面跟另一个参数组依然跟该参数组里的保有参数,所以读取的时候要注意下。而参数的剧情则与参数组基本均等,只是在下一参数组/参数的舞狮与参数组描述长度之间寄存着该参数的实际数目罢了,由于地点描述起来太费事了,这里就不写了。

    字节

    类型

    说明

    此前的内容

     

    Int16

    下一参数组/参数的舞狮(包涵本内容的2字节)

     

    Byte

    参数存放内容的项目(-1 Char,1 Byte,2 Int16,4 Single),相对值即为长度

     

    Byte

    参数内容维数(0-3)

     

    Byte[]

    参数每一维大小(倘使维数为0,就一向不此部分)

     

    Byte[] 

    参数实际内容

     

    Byte

    参数组描述长度

    此后的剧情

    此间须求验证的正是,由于参数能够存放数组,所以扩展了维数的标记,即当维数为0时,贮存的内容为Char、Byte、Int16、Single等转移出的字节数组;而当维数为1时,贮存的为Char[]、Byte[]、Int16[]、Single[]等转移出的字节数组,就那样类推。而对数组的积累,其实正是数组各样成分依次展打开仓库储,而对此多维数组,则是按行优先开展仓储的,比方三个维度数组,先存款和储蓄Data[0,0,1]再存储Data[0,0,2],依次类推。

    而是须要证实的是,对于Char[]以及Char[,]那三种,假若表示的话实际应当相应的是String以及String[]。

     

    【四、C3D文件数量区域的构造】

    C3D数据区域以帧为单位寄放的,其实一定于那几个区域就是三个帧的聚合。而C3D帧其实分为三种,一种是整数帧,而另一种是浮点帧。这两个的界别在于,前边二个存款和储蓄的富有剧情都是Int16,而后人则为Single,除却,前面一个的3D坐标点(X、Y、Z)还要求倍Gaby例因子才足以,而后人存款和储蓄的从头到尾的经过也正是已经乘以了百分比因子了。

    数据区域起首于参数集结中的"POINT"参数组中的"DATA_START"参数,其象征数据区域初叶的Section ID,除外,在文件头中也是有一份别本。不过依照官方的传教,假使文件头和参数群集中皆有个别内容,优先读取参数集结中的数据。

    对于每种帧,又富含多少个部分,第一有的为3D坐标点部分,第四盘部为仿照采集样品部分。

    • 对于每帧的3D坐标点部分,存款和储蓄着该帧全体3D坐标点的数码,每一个3D坐标点包含4个Int16或Single数据,分别是X坐标、Y坐标、Z坐标以及Residual和Camera Mask,当中Residual和Camera Mask共占八个Int16。相比风趣的是,对于浮点帧,Residual和Camera Mask仍旧也依旧二个Int16,只可是存款和储蓄的时候要将相应的数值转变为Single再开展仓库储存。
      • 对此浮点帧,存款和储蓄的X、Y、Z坐标正是其实的坐标;而对此整数帧,存款和储蓄的X、Y、Z的坐标还亟需倍Gaby例因子才得以,比例因子存款和储蓄于参数群集中的"POINT"参数组中的"SCALE"参数。
      • Residual和Camera Mask共占一个Int16,将其转移为字节数组之后,高位字节(第3个字节)的最高位代表Residual的标记,即表示该坐标点是不是有效,假若为0则象征有效,假设为1则代表无效,而剩余的7个字节则为Camera Mask,每一人代表二个摄影机,从未有到高位分别代表7个录制机是不是利用(为1为利用,为0为未选择)。而Residual的真实数据则为字节数组的第0字节乘以比例因子(浮点帧则为比例因子的相对值)。
    • 而仿照采集样品部分,则存款和储蓄着该帧全体的模仿采集样品的数额,但是每一个帧恐怕包涵多少个模拟采集样品,同一时间各样模仿采集样品大概又含有八个channel,存款和储蓄的数量即为该channel下记录的数码。可是存款和储蓄的数额与实际的数额还索要依靠下述公式进行折算,当中data value为存储的数据,real world value为实际的数量。

      • zero offset可以从"ANALOG"参数组中的"OFFSET"中得到,该多少为Int16的数组,第i位指的就是第i个channel的zero offset。
      • channel scale能够从"ANALOG"参数组中的"SCALE"中拿走,该数量为Single的数组,第i位指的就是dii个channel的scale。
      • general scale是独具模拟采集样品都亟需倍加的比重,该多少能够从"ANALOG"参数组中的"GEN_SCALE"中获取,为Single。

      real world value = (data value - zero offset) channel scale general scale

     

    【五、使用C3D.NET读写文件示例】

    前方说了如此多,其实假设用C3D.NET来分析的话实际是非常轻松的。我们能够从下载C3D.NET的二进制文件恐怕源码,引用后根本的类都在C3D这些命名空间下。

    对于遍历全体的3D坐标能够应用以下的点子,首先能够从文件也许从流中创造C3D文件,然后从文件头中读取存款和储蓄的第1帧的序号,然后读取采集样品点的数额就足以了,当然也足以不从参数组中读取,间接利用file.AllFrames[i].Point3Ds.Length也可以:

     1 C3DFile file = C3DFile.LoadFromFile("文件路径");
     2 Int16 firstFrameIndex = file.Header.FirstFrameIndex;
     3 Int16 pointCount = file.Parameters["POINT:USED"].GetData<Int16>();
     4 
     5 for (Int16 i = 0; i < file.AllFrames.Count; i++)
     6 {
     7     for (Int16 j = 0; j < pointCount; j++)
     8     {
     9         Console.WriteLine("Frame {0} : X = {1}, Y = {2}, Z = {3}",
    10             firstFrameIndex + i,
    11             file.AllFrames[i].Point3Ds[j].X,
    12             file.AllFrames[i].Point3Ds[j].Y ,
    13             file.AllFrames[i].Point3Ds[j].Z);
    14     }
    15 }
    

    而读取模拟采集样品的话,接纳的章程也近乎:

     1 Single frameRate = file.Parameters["POINT", "RATE"].GetData<Single>();
     2 Int16 analogChannelCount = file.Parameters["ANALOG", "USED"].GetData<Int16>();
     3 Int16 analogSamplesPerFrame = (Int16)(file.Parameters["ANALOG", "RATE"].GetData<Int16>() / frameRate);
     4 
     5 for (Int16 i = 0; i < file.AllFrames.Count; i++)
     6 {
     7     for (Int16 j = 0; j < analogChannelCount; j++)
     8     {
     9         for (Int16 k = 0; k < analogSamplesPerFrame; k++)
    10         {
    11             Console.WriteLine("Frame {0}, Sample {1} : {2}",
    12                 firstFrameIndex + i, j + 1,
    13                 file.AllFrames[i].AnalogSamples[j][k]);
    14         }
    15     }
    16 }
    

    除了那么些之外叁次性将C3D文件内容总体读收取来的这种艺术以外,仍可以使用C3DReader来一帧一帧的读取。

     1 using (FileStream fs = new FileStream("文件路径", FileMode.Open, FileAccess.Read))
     2 {
     3     C3DReader reader = new C3DReader(fs);
     4     C3DHeader header = reader.ReadHeader();
     5     C3DParameterDictionary dictionary = reader.ReadParameters();
     6     Int32 index = header.FirstFrameIndex;
     7 
     8     while (true)
     9     {
    10         C3DFrame frame = reader.ReadNextFrame(dictionary);
    11 
    12         if (frame == null)
    13         {
    14             break;
    15         }
    16 
    17         for (Int16 j = 0; j < frame.Point3Ds.Length; j++)
    18         {
    19             Console.WriteLine("Frame {0} : X = {1}, Y = {2}, Z = {3}",
    20                 index++,
    21                 frame.Point3Ds[j].X,
    22                 frame.Point3Ds[j].Y,
    23                 frame.Point3Ds[j].Z);
    24         }
    25     }
    26 }
    

    对于开创一个C3D文件,只须要采纳C3DFile.Create()就足以创制二个空的C3D文件的,不包蕴其余的参数集合。而保存C3D文件则直接利用file.SaveTo("文件路线")就可以了。

    对于拉长参数会集能够采纳以下的代码:

    1 //首先需要添加参数集合,ID为正数
    2 file.Parameters.AddGroup(1, "POINT", "");
    3 //然后往指定ID的参数集合中添加参数即可
    4 file.Parameters[1].Add("USED", "").SetData<Int16>(5);
    

    加多帧能够运用如下的代码:

    1 file.AllFrames.Add(new C3DFrame(new C3DPoint3DData[] {
    2     new C3DPoint3DData() { X = x, Y = y, Z = z, Residual = residual, CameraMask = cameraMask},
    3     new C3DPoint3DData() { X = x, Y = y, Z = z, Residual = residual, CameraMask = cameraMask},
    4     new C3DPoint3DData() { X = x, Y = y, Z = z, Residual = residual, CameraMask = cameraMask},
    5     new C3DPoint3DData() { X = x, Y = y, Z = z, Residual = residual, CameraMask = cameraMask},
    6     new C3DPoint3DData() { X = x, Y = y, Z = z, Residual = residual, CameraMask = cameraMask} }));
    

    自然,也得以将C3DPoint3DData数组换到C3DAnalogSamples数组,恐怕两者同有的时候候足够也得以。

     

    【相关链接】

    1. C3D.ORG:
    2. c3d4sharp - C3D File reading/writing tools written in C#:
    3. C3D.NET:

    本文由澳门新葡萄京最大平台发布于最大平台,转载请注明出处:NET平台下对C3D文件的读写

    关键词:

上一篇:没有了

下一篇:没有了