一种尽可能减小内存占用的数据结构设计方法

  

      背景:以三维点为例,随着采集设备的日新月异,三维点的属性信息也越来越多(例如颜色、强度、回波信息、gps时间等);导致点云数据在处理时加载到计算机中所需要的内存空间也越来越大,但是有些数据往往只有x、y、z三个坐标值,则不需要为其开辟多余的内存空间,那一套统一的数据结构怎样才做到灵活兼容呢(加载数据时尽可能少的占用内存空间),vcg的底层数据结构则提供了一种方案,其可以根据需要进行内存的申请。下面的代码是来自于vcg数据结构里的一段代码。

      

 

template <class VALUE_TYPE>
class vector_ocf: public std::vector<VALUE_TYPE> {
    typedef std::vector<VALUE_TYPE> BaseType;
    typedef typename vector_ocf<VALUE_TYPE>::iterator ThisTypeIterator;

public:
  vector_ocf():std::vector<VALUE_TYPE>()
  {
    ColorEnabled = false;
    CurvatureEnabled = false;
    CurvatureDirEnabled = false;
    MarkEnabled = false;
    NormalEnabled = false;
    QualityEnabled = false;
    RadiusEnabled = false;
    TexCoordEnabled = false;
    VFAdjacencyEnabled = false;
  }

////////////////////////////////////////
// All the standard methods of std::vector that can change the reallocation are
// redefined in order to manage the additional data.
  void push_back(const VALUE_TYPE & v)
    {
        BaseType::push_back(v);
        BaseType::back()._ovp = this;
        if (ColorEnabled)         CV.push_back(vcg::Color4b(vcg::Color4b::White));
        if (QualityEnabled)       QV.push_back(0);
        if (MarkEnabled)          MV.push_back(0);
        if (NormalEnabled)        NV.push_back(typename VALUE_TYPE::NormalType());
        if (TexCoordEnabled)      TV.push_back(typename VALUE_TYPE::TexCoordType());
        if (VFAdjacencyEnabled)   AV.push_back(VFAdjType());
        if (CurvatureEnabled)     CuV.push_back(typename VALUE_TYPE::CurvatureType());
        if (CurvatureDirEnabled)  CuDV.push_back(typename VALUE_TYPE::CurvatureDirType());
        if (RadiusEnabled)        RadiusV.push_back(typename VALUE_TYPE::RadiusType());
    }

    void pop_back();

    void resize(size_t _size)
    {
        const size_t oldsize = BaseType::size();
            BaseType::resize(_size);
        if(oldsize<_size){
            ThisTypeIterator firstnew = BaseType::begin();
            advance(firstnew,oldsize);
            _updateOVP(firstnew,(*this).end());
        }
        if (ColorEnabled)         CV.resize(_size);
        if (QualityEnabled)       QV.resize(_size,0);
        if (MarkEnabled)          MV.resize(_size);
        if (NormalEnabled)        NV.resize(_size);
        if (TexCoordEnabled)      TV.resize(_size);
        if (VFAdjacencyEnabled)   AV.resize(_size,VFAdjType::Zero());
        if (CurvatureEnabled)     CuV.resize(_size);
        if (CurvatureDirEnabled)  CuDV.resize(_size);
        if (RadiusEnabled)        RadiusV.resize(_size);
    }

    void reserve(size_t _size)
    {
        BaseType::reserve(_size);
        if (ColorEnabled)        CV.reserve(_size);
        if (QualityEnabled)      QV.reserve(_size);
        if (MarkEnabled)         MV.reserve(_size);
        if (NormalEnabled)       NV.reserve(_size);
        if (TexCoordEnabled)     TV.reserve(_size);
        if (VFAdjacencyEnabled)  AV.reserve(_size);
        if (CurvatureEnabled)    CuV.reserve(_size);
        if (CurvatureDirEnabled) CuDV.reserve(_size);
        if (RadiusEnabled)       RadiusV.reserve(_size);
    }

    void _updateOVP(ThisTypeIterator lbegin, ThisTypeIterator lend)
    {
        ThisTypeIterator vi;
        for(vi=lbegin;vi!=lend;++vi)
                (*vi)._ovp=this;
    }

////////////////////////////////////////
// Enabling Eunctions

bool IsQualityEnabled() const {return QualityEnabled;}
void EnableQuality() {
    assert(VALUE_TYPE::HasQualityOcf());
    QualityEnabled=true;
    QV.resize((*this).size(),0);
}
void DisableQuality() {
    assert(VALUE_TYPE::HasQualityOcf());
    QualityEnabled=false;
    QV.clear();
}

bool IsColorEnabled() const {return ColorEnabled;}
void EnableColor() {
    assert(VALUE_TYPE::HasColorOcf());
    ColorEnabled=true;
    CV.resize((*this).size());
}
void DisableColor() {
    assert(VALUE_TYPE::HasColorOcf());
    ColorEnabled=false;
    CV.clear();
}

bool IsMarkEnabled() const {return MarkEnabled;}
void EnableMark() {
    assert(VALUE_TYPE::HasMarkOcf());
    MarkEnabled=true;
    MV.resize((*this).size(),0);
}
void DisableMark() {
    assert(VALUE_TYPE::HasMarkOcf());
    MarkEnabled=false;
    MV.clear();
}

bool IsNormalEnabled() const {return NormalEnabled;}
void EnableNormal() {
    assert(VALUE_TYPE::HasNormalOcf());
    NormalEnabled=true;
    NV.resize((*this).size());
}
void DisableNormal() {
    assert(VALUE_TYPE::HasNormalOcf());
    NormalEnabled=false;
    NV.clear();
}

bool IsVFAdjacencyEnabled() const {return VFAdjacencyEnabled;}
void EnableVFAdjacency() {
    assert(VALUE_TYPE::HasVFAdjacencyOcf());
    VFAdjacencyEnabled=true;
    AV.resize((*this).size(),VFAdjType::Zero());
}
void DisableVFAdjacency() {
    assert(VALUE_TYPE::HasVFAdjacencyOcf());
    VFAdjacencyEnabled=false;
    AV.clear();
}

bool IsCurvatureEnabled() const {return CurvatureEnabled;}
void EnableCurvature() {
    assert(VALUE_TYPE::HasCurvatureOcf());
    CurvatureEnabled=true;
    CuV.resize((*this).size());
}
void DisableCurvature() {
    assert(VALUE_TYPE::HasCurvatureOcf());
    CurvatureEnabled=false;
    CuV.clear();
}

bool IsCurvatureDirEnabled() const {return CurvatureDirEnabled;}
void EnableCurvatureDir() {
    assert(VALUE_TYPE::HasCurvatureDirOcf());
    CurvatureDirEnabled=true;
    CuDV.resize((*this).size());
}
void DisableCurvatureDir() {
    assert(VALUE_TYPE::HasCurvatureDirOcf());
    CurvatureDirEnabled=false;
    CuDV.clear();
}

bool IsRadiusEnabled() const {return RadiusEnabled;}
void EnableRadius() {
    assert(VALUE_TYPE::HasRadiusOcf());
    RadiusEnabled=true;
    RadiusV.resize((*this).size());
}
void DisableRadius() {
    assert(VALUE_TYPE::HasRadiusOcf());
    RadiusEnabled=false;
    RadiusV.clear();
}


bool IsTexCoordEnabled() const {return TexCoordEnabled;}
void EnableTexCoord() {
    assert(VALUE_TYPE::HasTexCoordOcf());
    TexCoordEnabled=true;
    TV.resize((*this).size());
}
void DisableTexCoord() {
    assert(VALUE_TYPE::HasTexCoordOcf());
    TexCoordEnabled=false;
    TV.clear();
}

struct VFAdjType {
    VFAdjType():_fp(0),_zp(-1) {}
  VFAdjType(typename VALUE_TYPE::FacePointer fp, int zp):_fp(fp),_zp(zp){}
    typename VALUE_TYPE::FacePointer _fp ;
    int _zp ;
    static VFAdjType Zero() { return VFAdjType(0,-1); }
    bool IsNull() const { return (_zp ==-1); }
    };

public:
  std::vector<typename VALUE_TYPE::ColorType> CV;
  std::vector<typename VALUE_TYPE::CurvatureType> CuV;
  std::vector<typename VALUE_TYPE::CurvatureDirType> CuDV;
  std::vector<int> MV;
  std::vector<typename VALUE_TYPE::NormalType> NV;
  std::vector<typename VALUE_TYPE::QualityType> QV;
  std::vector<typename VALUE_TYPE::RadiusType> RadiusV;
  std::vector<typename VALUE_TYPE::TexCoordType> TV;
  std::vector<struct VFAdjType> AV;

  bool ColorEnabled;
  bool CurvatureEnabled;
  bool CurvatureDirEnabled;
  bool MarkEnabled;
  bool NormalEnabled;
  bool QualityEnabled;
  bool RadiusEnabled;
  bool TexCoordEnabled;
  bool VFAdjacencyEnabled;
};

 

      下面这个函数很好的诠释了内存申请的过程。如果对该属性不进行内存空间的申请,后期该属性相关的数据则无法访问或者越界导致程序崩溃。

void EnableNormal() 
{ assert(VALUE_TYPE::HasNormalOcf()); NormalEnabled
=true; NV.resize((*this).size()); }

 所以在初始化点云对象之前会根据点云数据里已有的属性进行相应字段的内存空间的开辟;

例如:

PointCloud pc;//只是个示例

pc.EnableNormal();

pc.CurvatureEnabled();

...

     所以在访问该字段的数据时,也应该要加以判断,不然就会出现数组越界导致程序崩溃的问题出现。

譬如访问Curvature属性时,则需要根据CurvatureEnabled变量进行判断该属性是否存在数据。

      此外,由于大地坐标的有效数字超过了7位,所以也只有double类型才能适配,众所周知double占8个字节,float占4个字节,一倍的差距对于大数据量的点云加载到内存中所引起的内存占用过高的问题是很明显的,所以建议设置一个中心坐标,然后将数据转成局部坐标(小坐标),这样可以较大程度减少点云数据加载到程序中所占用的内存。

    通过以上两个手段来设计内存数据结构,能较大程度减少数据量过大内存空间不够的问题(多则能降低一半以上,少则也能降低1/3)。

    当然一些字段也可以共有一个int类型,例如回波次数、回波序号二者则可以采用二进制的手段共有一个int似乎也是可行的。

    

posted @ 2024-07-06 11:52  点小二  阅读(66)  评论(0编辑  收藏  举报