lsd_slam 源碼分析 數據結構 內存管理 Frame 圖像金字塔 梯度金字塔 最大梯度值金字塔 逆深度值金字塔 逆深度方差值金字塔

數據結構

lsd_slam代碼 算法分析

Frame 幀類 詳情

* 每張圖像創建 5層的圖像金字塔  每一層的尺度 變爲上一層的1/2
* 圖像的 內參數 也上上一層的 1/2
* 內參數求逆得到 內參數逆矩陣
* 一幀包含 Ki  = [Ii,Gi,Mi,Di,Vi]
* [像素 梯度 最大梯度值 逆深度  逆深度方差]
* 最大梯度 閾值濾波得到 關鍵點 需要跟蹤 並需要計算三維點映射到地圖中

一、圖像金字塔構建方法爲 :

* 上一層 的 四個像素的值的平均值合併成一個像素爲下一層的像素
* 
* 	int wh = width*height;// 當前層 像素總數
*	const float* s;
*	for(int y=0; y<wh; y += width*2)// 隔行
*	{
*		for(int x=0; x<width; x+= 2)// 隔列下采樣
*		{
*			s = source + x + y;// 上一層 像素對應位置
*			*dest = (s[0] +
*					s[1] +
*					s[width] +
*					s[1+width]) * 0.25f;// 四個像素的值的平均值合併成一個
*			dest++;
*		}
*	}
* 

二、梯度金字塔構建方法(四個值 dx , dy, i, null)

* 使用同一層的 圖像  左右像素求得x方向梯度  上下求得 方向梯度 
*           *(img_pt-width)
*  val_m1  *(img_pt)   val_p1
*           *(img_pt+width)
* 1.  (val_p1 - val_m1)/2    = x 方向梯度
* 2.  0.5f*(*(img_pt+width) - *(img_pt-width)) = y方向梯度
* 3.  val_00 = *(img_pt)   當前 點像素值
* 4. 第四維度 沒有存儲數據    gradxyii_pt  Eigen::Vector4f
*
* 

三、臨近最大合成梯度 值 地圖構建 一個合成梯度值

*  創建 梯度圖內 臨近四點中梯度最大值 的 最大值梯度 圖 , 並記錄梯度值較大的可以映射 成 地圖點的數量
* 在梯度圖中 求去合成梯度 g=sqrt(gx^2+gy^2)  ,求的 上中下 三個梯度值中的最大值,形成臨時梯度最大值圖
* 在臨時梯度最大值圖 中求 的  左中右 三個梯度值中的最大值,形成最後的 最大梯度值地圖
*  並記錄 最大梯度大小超過閾值的點 可以映射成地圖點  
* 

四、構建 第0層 逆深度均值圖 和方差圖

* 1. 使用 真實 深度值  取反得到逆深度值,方差初始爲一個設定值
* 2. 沒有真實值是,也可以使用高斯分佈均值初始化 逆深度均值圖 和方差圖
* 

五、高層逆深度均值金字塔圖 和逆深度方差金字塔圖的構建

* 
*  根據逆深度 構建  逆深度均值圖 方差圖(高斯分佈)  金字塔
*       current   -----> 右邊一個
*       下邊              下右邊       上一層四個位置 
*  上一層 逆方差和  /  上一層 逆深度均值 (四個位置處) 和  得到深度信息 再 取逆得到 逆深度均值
*  上一層 逆深度 方差和 取逆得到 本層 逆深度方差 

 

Frame.cpp


#include "DataStructures/Frame.h"
#include "DataStructures/FrameMemory.h"
#include "DepthEstimation/DepthMapPixelHypothesis.h"
#include "Tracking/TrackingReference.h"

namespace lsd_slam
{

      int privateFrameAllocCount = 0;
      // 構造函數有兩個,主要是最後一個參數給的有所不同,實際上它代表的是兩種不同格式的圖片數據
      // 構造函數  0~255 的圖像  
      Frame::Frame(int id, int width, int height, const Eigen::Matrix3f& K, double timestamp, const unsigned char* image)
      {
	// 類參數變量初始化 主要初始化 圖像金字塔的 內參數  內參數逆
	      initialize(id, width, height, K, timestamp);
      // 獲取圖像內存空間	
	      data.image[0] = FrameMemory::getInstance().getFloatBuffer(data.width[0]*data.height[0]);//float類型存儲 指針
	      float* maxPt = data.image[0] + data.width[0]*data.height[0];// 存儲區域 float 的個數 對應像素個數
      // 使用指針複製圖像的內一個像素
	      for(float* pt = data.image[0]; pt < maxPt; pt++)// 拷貝每一個像素
	      {
		      *pt = *image;// 拷貝每一個像素
		      image++;// 指針指向下一個
	      }
	      data.imageValid[0] = true;// 第0層圖像金字塔 已經有圖像數據了

	      privateFrameAllocCount++;// 私有幀數量++

	      if(enablePrintDebugInfo && printMemoryDebugInfo)// 調試信息
		      printf("ALLOCATED frame %d, now there are %d\n", this->id(), privateFrameAllocCount);
      }
      // 構造函數  0~1 的圖像  
      Frame::Frame(int id, int width, int height, const Eigen::Matrix3f& K, double timestamp, const float* image)
      {
	// 類參數變量初始化 主要初始化 圖像金字塔的 內參數  內參數逆
	      initialize(id, width, height, K, timestamp);
      // 獲取圖像內存空間	
	      data.image[0] = FrameMemory::getInstance().getFloatBuffer(data.width[0]*data.height[0]);
      // 使用memcpy 複製圖像內容 兩個指針指向的類型一直
	      memcpy(data.image[0], image, data.width[0]*data.height[0] * sizeof(float));//  指針類型相同 使用 memcpy拷貝內容 
	      data.imageValid[0] = true;// 第0層圖像金字塔 已經有圖像數據了

	      privateFrameAllocCount++;// 私有幀數量++

	      if(enablePrintDebugInfo && printMemoryDebugInfo)// 調試信息
		      printf("ALLOCATED frame %d, now there are %d\n", this->id(), privateFrameAllocCount);
      }
      // 析構函數
      Frame::~Frame()
      {
      // 調試信息
	      if(enablePrintDebugInfo && printMemoryDebugInfo)
		      printf("DELETING frame %d\n", this->id());// 打印信息 刪除 幀
      // 回收內存
	      FrameMemory::getInstance().deactivateFrame(this);// 這裏只是回收內存

	      if(!pose->isRegisteredToGraph)
		      delete pose;// 還沒有  註冊放入到地圖 就刪除位姿
	      else
		      pose->frame = 0;
      // 刪除圖像金字塔的每一層 圖像
	      for (int level = 0; level < PYRAMID_LEVELS; ++ level)// 每一層圖像金字塔
	      {
		      FrameMemory::getInstance().returnBuffer(data.image[level]);// 圖像
		      FrameMemory::getInstance().returnBuffer(reinterpret_cast<float*>(data.gradients[level]));// 梯度
		      FrameMemory::getInstance().returnBuffer(data.maxGradients[level]);//
		      FrameMemory::getInstance().returnBuffer(data.idepth[level]);// 逆深度 均值
		      FrameMemory::getInstance().returnBuffer(data.idepthVar[level]);// 逆深度方差
	      }
      // 刪除 深度 逆深度均值   逆深度方差
	      FrameMemory::getInstance().returnBuffer((float*)data.validity_reAct);
	      FrameMemory::getInstance().returnBuffer(data.idepth_reAct);
	      FrameMemory::getInstance().returnBuffer(data.idepthVar_reAct);
      // 最後再釋放permaRef_colorAndVarData和permaRef_posData,這兩個參數是位置,顏色和方差的引用,用於重定位,
      // 注意:這個參數只是在initialize中初始化爲空指針
	      if(permaRef_colorAndVarData != 0)
		      delete permaRef_colorAndVarData;// 刪除 顏色和方差的引用
	      if(permaRef_posData != 0)
		      delete permaRef_posData;// 位置 的 引用 

	      privateFrameAllocCount--;/// 私有幀數量--
	      if(enablePrintDebugInfo && printMemoryDebugInfo)// 調試信息
		      printf("DELETED frame %d, now there are %d\n", this->id(), privateFrameAllocCount);
      }


      void Frame::takeReActivationData(DepthMapPixelHypothesis* depthMap)
      {
// 上鎖
	      boost::shared_lock<boost::shared_mutex> lock = getActiveLock();
// 申請內存
	      if(data.validity_reAct == 0)
		      data.validity_reAct = (unsigned char*) FrameMemory::getInstance().getBuffer(data.width[0]*data.height[0]);

	      if(data.idepth_reAct == 0)
		      data.idepth_reAct = FrameMemory::getInstance().getFloatBuffer((data.width[0]*data.height[0]));

	      if(data.idepthVar_reAct == 0)
		      data.idepthVar_reAct = FrameMemory::getInstance().getFloatBuffer((data.width[0]*data.height[0]));

// 賦值
	      float* id_pt = data.idepth_reAct;// 起始位置
	      float* id_pt_max = data.idepth_reAct + (data.width[0]*data.height[0]);// 最大位置
	      float* idv_pt = data.idepthVar_reAct;
	      unsigned char* val_pt = data.validity_reAct;

	      for (; id_pt < id_pt_max; ++ id_pt, ++ idv_pt, ++ val_pt, ++depthMap)
	      {
		      if(depthMap->isValid)// 深度圖 有效
		      {
			      *id_pt = depthMap->idepth;// 深度值
			      *idv_pt = depthMap->idepth_var;// 深度值方差
			      *val_pt = depthMap->validity_counter;
		      }
		      else if(depthMap->blacklisted < MIN_BLACKLIST)
		      {
			      *idv_pt = -2;
		      }
		      else
		      {
			      *idv_pt = -1;
		      }
	      }

	      data.reActivationDataValid = true;
      }


// 參考幀
      void Frame::setPermaRef(TrackingReference* reference)
      {
	      assert(reference->frameID == id());
	      reference->makePointCloud(QUICK_KF_CHECK_LVL);

	      permaRef_mutex.lock();// 上鎖

	      if(permaRef_colorAndVarData != 0)
		      delete permaRef_colorAndVarData;
	      if(permaRef_posData != 0)
		      delete permaRef_posData;

	      permaRefNumPts = reference->numData[QUICK_KF_CHECK_LVL];
	      permaRef_colorAndVarData = new Eigen::Vector2f[permaRefNumPts];
	      permaRef_posData = new Eigen::Vector3f[permaRefNumPts];

	      memcpy(permaRef_colorAndVarData,
			      reference->colorAndVarData[QUICK_KF_CHECK_LVL],
			      sizeof(Eigen::Vector2f) * permaRefNumPts);

	      memcpy(permaRef_posData,
			      reference->posData[QUICK_KF_CHECK_LVL],
			      sizeof(Eigen::Vector3f) * permaRefNumPts);

	      permaRef_mutex.unlock();
      }
      
// 求解 深度值標準差逆( 深度值方差逆  開根號 )  均值(求和 取平均)
      void Frame::calculateMeanInformation()
      {
	      return;

	      if(numMappablePixels < 0)
		      maxGradients(0);

	      const float* idv = idepthVar(0);// 深度方差 起始位置
	      const float* idv_max = idv + width(0)*height(0);// 最大位置
	      float sum = 0; int goodpx = 0;
	      for(const float* pt=idv; pt < idv_max; pt++)
	      {
		      if(*pt > 0)
		      {
			      sum += sqrtf(1.0f / *pt);// 深度值方差逆  開根號 得到 深度值標準差逆  和 
			      goodpx++;
		      }
	      }

	      meanInformation = sum / goodpx;// 深度值標準差逆  均值
      }
      
////////////////////////////////////////////////////////////////////////////////////////////
// 使用 逆深度圖深度值假設值(高斯分佈平滑後的數據) 設置 第0層的 逆深度均值和方差  對深度估計值進行設定
      void Frame::setDepth(const DepthMapPixelHypothesis* newDepth)
      {
     // 首先調用了鎖,把數據都鎖了起來
	      boost::shared_lock<boost::shared_mutex> lock = getActiveLock();
	      boost::unique_lock<boost::mutex> lock2(buildMutex);
   // 申請第0層的 深度均值和方差 的存儲空間
	      if(data.idepth[0] == 0)
		      data.idepth[0] = FrameMemory::getInstance().getFloatBuffer(data.width[0]*data.height[0]);
	      if(data.idepthVar[0] == 0)
		      data.idepthVar[0] = FrameMemory::getInstance().getFloatBuffer(data.width[0]*data.height[0]);

	      float* pyrIDepth = data.idepth[0];//  第一個內存地址的指針
	      float* pyrIDepthVar = data.idepthVar[0];
	      float* pyrIDepthMax = pyrIDepth + (data.width[0]*data.height[0]);// 最大的內存地址
	      
	      float sumIdepth=0;// 逆深度均值和
	      int numIdepth=0;// 有 有效逆深度值 的 像素點數量

	      for (; pyrIDepth < pyrIDepthMax; ++ pyrIDepth, ++ pyrIDepthVar, ++ newDepth) //, ++ pyrRefID)
	      {
		      if (newDepth->isValid && newDepth->idepth_smoothed >= -0.05)// 預設值的值符合 一些前提條件
		      {
			      *pyrIDepth = newDepth->idepth_smoothed;// 逆深度均值
			      *pyrIDepthVar = newDepth->idepth_var_smoothed;// 逆深度方差

			      numIdepth++;// 有 有效逆深度值 的 像素點數量
			      sumIdepth += newDepth->idepth_smoothed;// 逆深度均值和
		      }
		      // 預設值不符合規定,設置異常值 -1
		      else
		      {
			      *pyrIDepth = -1;
			      *pyrIDepthVar = -1;
		      }
	      }
	      
	      meanIdepth = sumIdepth / numIdepth;// 逆深度均值
	      numPoints = numIdepth;// 有 有效逆深度值 的 像素點數量


	      data.idepthValid[0] = true;// 第0層逆深度值 已經得到
	      data.idepthVarValid[0] = true;// 第0層逆深度均值 已經得到
	      release(IDEPTH | IDEPTH_VAR, true, true);// 最後調用release,釋放第0層以上層的深度估計值
	      data.hasIDepthBeenSet = true;
	      depthHasBeenUpdatedFlag = true;// 更新標誌
      }

// 從 深度真實值 設置 第0層的逆深度值和方差
      void Frame::setDepthFromGroundTruth(const float* depth, float cov_scale)
      {
      // 首先調用了鎖,把數據都鎖了起來	
	      boost::shared_lock<boost::shared_mutex> lock = getActiveLock();
	      const float* pyrMaxGradient = maxGradients(0);
	      boost::unique_lock<boost::mutex> lock2(buildMutex);
     // 申請第0層的 深度均值和方差 的存儲空間	      
	      if(data.idepth[0] == 0)
		      data.idepth[0] = FrameMemory::getInstance().getFloatBuffer(data.width[0]*data.height[0]);
	      if(data.idepthVar[0] == 0)
		      data.idepthVar[0] = FrameMemory::getInstance().getFloatBuffer(data.width[0]*data.height[0]);

	      float* pyrIDepth = data.idepth[0];//  第一個內存地址的指針
	      float* pyrIDepthVar = data.idepthVar[0];

	      int width0 = data.width[0];// 深度值圖 寬度
	      int height0 = data.height[0];// 高度

	      for(int y=0;y<height0;y++)// 每一行
	      {
		      for(int x=0;x<width0;x++)// 每一列
		      {
			     // 有效位置
			      if (x > 0 && x < width0-1 && y > 0 && y < height0-1 && // pyramidMaxGradient is not valid for the border
					      pyrMaxGradient[x+y*width0] >= MIN_ABS_GRAD_CREATE &&
					      !isnanf(*depth) && *depth > 0)
			      {
				      *pyrIDepth = 1.0f / *depth;// 逆深度值
				      *pyrIDepthVar = VAR_GT_INIT_INITIAL * cov_scale;// 逆深度方差
			      }
			      // 無效位置
			      else
			      {
				      *pyrIDepth = -1;
				      *pyrIDepthVar = -1;
			      }

			      ++ depth;
			      ++ pyrIDepth;
			      ++ pyrIDepthVar;
		      }
	      }
   // 設置標誌	      
	      data.idepthValid[0] = true;// 第0層 逆深度值 已經得到
	      data.idepthVarValid[0] = true;
      // 	data.refIDValid[0] = true;
	      // Invalidate higher levels, they need to be updated with the new data
	      release(IDEPTH | IDEPTH_VAR, true, true);// 最後調用release,釋放第0層以上層的深度估計值
	      data.hasIDepthBeenSet = true;
      }

////////////////////////////////////////////////
// 這個函數是用來設置變換的,準備 兩幀之前的 旋轉 平移  變換矩陣 爲雙目三角測量得到深度做準備
// 第一個參數傳入是哪一幀,
// 第二個參數是這一幀的相似變換矩陣   ----> sR, t
// 第三個參數是相機參數  K ,
// 第四個參數是金字塔等級 level
      void Frame::prepareForStereoWith(Frame* other, Sim3 thisToOther, const Eigen::Matrix3f& K, const int level)
      {
	      Sim3 otherToThis = thisToOther.inverse();
// 1.  other 變換到 當前幀    K*T = K*(R +t) = K*R + K*t
	      //otherToThis = data.worldToCam * other->data.camToWorld;
	      K_otherToThis_R = K * otherToThis.rotationMatrix().cast<float>() * otherToThis.scale();// K*R
	      otherToThis_t = otherToThis.translation().cast<float>();
	      K_otherToThis_t = K * otherToThis_t;// K*t
// 2. 當前幀  變換到 other  K*T = K*(R +t) = K*R + K*t
	      thisToOther_t = thisToOther.translation().cast<float>();
	      K_thisToOther_t = K * thisToOther_t;
	      thisToOther_R = thisToOther.rotationMatrix().cast<float>() * thisToOther.scale();
// 3.  other 變換到 當前幀 旋轉矩陣的每一行    R逆 = R轉置
	      otherToThis_R_row0 = thisToOther_R.col(0);// 第0列 轉置 第0行
	      otherToThis_R_row1 = thisToOther_R.col(1);// 第1列 轉置 第1行
	      otherToThis_R_row2 = thisToOther_R.col(2);// 第2列 轉置 第2行
// 4. 兩幀之間的 距離 平方 t * t'
	      distSquared = otherToThis.translation().dot(otherToThis.translation());
//參考幀
	      referenceID = other->id();
	      referenceLevel = level;
      }
      
      

//  是某種請求函數
// 判斷需要怎樣的數據,如果這個數據沒有,就調用相應的構建函數build*
      void Frame::require(int dataFlags, int level)
      {
	      if ((dataFlags & IMAGE) && ! data.imageValid[level])
	      {
		      buildImage(level);// 第幾層的圖像沒有 則創建  遞歸創建 從最大的圖開始 依次 下采樣 獲取 金字塔圖像
	      }
	      if ((dataFlags & GRADIENTS) && ! data.gradientsValid[level])
	      {
		      buildGradients(level);// 第幾層的 梯度沒有 則創建 
	      }
	      if ((dataFlags & MAX_GRADIENTS) && ! data.maxGradientsValid[level])
	      {
		      buildMaxGradients(level);// 第幾層的  最大梯度 沒有 則創建 
	      }
	      if (((dataFlags & IDEPTH) && ! data.idepthValid[level])
		      || ((dataFlags & IDEPTH_VAR) && ! data.idepthVarValid[level]))
	      {
		      buildIDepthAndIDepthVar(level);//  第幾層的  逆深度   沒有 則創建 
	      }
      }
      
// 是某種釋放函數
      void Frame::release(int dataFlags, bool pyramidsOnly, bool invalidateOnly)
      {
	      for (int level = (pyramidsOnly ? 1 : 0); level < PYRAMID_LEVELS; ++ level)
	      {
		      if ((dataFlags & IMAGE) && data.imageValid[level])
		      {
			      data.imageValid[level] = false;
			      if(!invalidateOnly)
				      releaseImage(level);// 釋放 圖像 
		      }
		      if ((dataFlags & GRADIENTS) && data.gradientsValid[level])
		      {
			      data.gradientsValid[level] = false;
			      if(!invalidateOnly)
				      releaseGradients(level);// 釋放 梯度圖
		      }
		      if ((dataFlags & MAX_GRADIENTS) && data.maxGradientsValid[level])
		      {
			      data.maxGradientsValid[level] = false;
			      if(!invalidateOnly)
				      releaseMaxGradients(level);// 釋放最大梯度圖
		      }
		      if ((dataFlags & IDEPTH) && data.idepthValid[level])
		      {
			      data.idepthValid[level] = false;
			      if(!invalidateOnly)
				      releaseIDepth(level);// 釋放逆深度圖
		      }
		      if ((dataFlags & IDEPTH_VAR) && data.idepthVarValid[level])
		      {
			      data.idepthVarValid[level] = false;
			      if(!invalidateOnly)
				      releaseIDepthVar(level);// 釋放逆深度圖 值
		      }
	      }
      }
      
      
 // 是最小化儲存函數
 // 就是釋放一些內存
      bool Frame::minimizeInMemory()
      {
	      if(activeMutex.timed_lock(boost::posix_time::milliseconds(10)))
	      {
		      buildMutex.lock();
		      // 打印信息
		      if(enablePrintDebugInfo && printMemoryDebugInfo)
			      printf("minimizing frame %d\n",id());

		      release(IMAGE | IDEPTH | IDEPTH_VAR, true, false);
		      release(GRADIENTS | MAX_GRADIENTS, false, false);

		      clear_refPixelWasGood();

		      buildMutex.unlock();
		      activeMutex.unlock();
		      return true;
	      }
	      return false;
      }

// 類參數變量初始化 主要初始化 圖像金字塔的 內參數  內參數逆
      void Frame::initialize(int id, int width, int height, const Eigen::Matrix3f& K, double timestamp)
      {
	      data.id = id;// id
	      
	      pose = new FramePoseStruct(this);// 幀位姿
	    // 相機內參
	      data.K[0] = K;
	      data.fx[0] = K(0,0);
	      data.fy[0] = K(1,1);
	      data.cx[0] = K(0,2);
	      data.cy[0] = K(1,2);
	    // 相機內參數逆
	      data.KInv[0] = K.inverse();// 逆矩陣
	      data.fxInv[0] = data.KInv[0](0,0);
	      data.fyInv[0] = data.KInv[0](1,1);
	      data.cxInv[0] = data.KInv[0](0,2);
	      data.cyInv[0] = data.KInv[0](1,2);
	      
	      data.timestamp = timestamp;// 時間戳

	      data.hasIDepthBeenSet = false;
	      depthHasBeenUpdatedFlag = false;
	      
	      referenceID = -1;
	      referenceLevel = -1;
	      
	      numMappablePixels = -1;
	    /// 初始化金字塔
	      for (int level = 0; level < PYRAMID_LEVELS; ++ level)
	      {
		      data.width[level] = width >> level;// 右移位 相等於 除以2
		      data.height[level] = height >> level;

		      data.imageValid[level] = false;
		      data.gradientsValid[level] = false;
		      data.maxGradientsValid[level] = false;
		      data.idepthValid[level] = false;
		      data.idepthVarValid[level] = false;

		      data.image[level] = 0;
		      data.gradients[level] = 0;
		      data.maxGradients[level] = 0;
		      data.idepth[level] = 0;
		      data.idepthVar[level] = 0;
		      data.reActivationDataValid = false;

      // 		data.refIDValid[level] = false;
		      // 初始化相機金字塔
		      if (level > 0)
		      {
			      data.fx[level] = data.fx[level-1] * 0.5;// 相應的 內參數  是 上一層的一般  大小變小了 變爲原來的1/2
			      data.fy[level] = data.fy[level-1] * 0.5;
			      data.cx[level] = (data.cx[0] + 0.5) / ((int)1<<level) - 0.5;// 也是 變爲 1/2
			      data.cy[level] = (data.cy[0] + 0.5) / ((int)1<<level) - 0.5;

			      data.K[level]  << data.fx[level], 0.0, data.cx[level], 0.0, data.fy[level], data.cy[level], 0.0, 0.0, 1.0;	// synthetic
			      data.KInv[level] = (data.K[level]).inverse();

			      data.fxInv[level] = data.KInv[level](0,0);
			      data.fyInv[level] = data.KInv[level](1,1);
			      data.cxInv[level] = data.KInv[level](0,2);
			      data.cyInv[level] = data.KInv[level](1,2);
		      }
	      }

	      data.validity_reAct = 0;
	      data.idepthVar_reAct = 0;
	      data.idepth_reAct = 0;

	      data.refPixelWasGood = 0;

	      permaRefNumPts = 0;
	      permaRef_colorAndVarData = 0;
	      permaRef_posData = 0;

	      meanIdepth = 1;
	      numPoints = 0;

	      numFramesTrackedOnThis = numMappedOnThis = numMappedOnThisTotal = 0;

	      idxInKeyframes = -1;

	      edgeErrorSum = edgesNum = 1;

	      lastConstraintTrackedCamToWorld = Sim3();

	      isActive = false;
      }

      void Frame::setDepth_Allocate()
      {
	      return;
      }

      // 創建對應層圖像金字塔的  圖像
      // 遞歸構建底層金字塔,因爲上層金字塔是以底層爲基礎的 
      // 分配內存 從上一層  隔行隔列下采樣  方案是下層金字塔的四個像素的值的平均值合併成一個 
      // 建立每一層 圖像金字塔
      void Frame::buildImage(int level)
      {
	      if (level == 0)
	      {
		      printf("Frame::buildImage(0): Loading image from disk is not implemented yet! No-op.\n");
		      return;
	      }
	      
	      require(IMAGE, level - 1);// 首先是遞歸構建底層金字塔,因爲上層金字塔是以底層爲基礎的
	      // 遞歸到底層後,調用buildMutex互斥鎖,
	      boost::unique_lock<boost::mutex> lock2(buildMutex);// 創建線程鎖 上鎖

	      if(data.imageValid[level])
		      return;
	    // 打印調試信息
	      if(enablePrintDebugInfo && printFrameBuildDebugInfo)
		      printf("CREATE Image lvl %d for frame %d\n", level, id());
	      // 當前層的 圖像寬 高
	      int width = data.width[level - 1];// 0,1,2,3,4
	      int height = data.height[level - 1];
	      const float* source = data.image[level - 1];// 上一層的圖像
	      
      // 之後纔是判斷這個等級的金字塔是否已經構建,然後向內存管理的對象申請內存,之後構建整個金字塔
	      if (data.image[level] == 0)// 指針爲空 當前層 未分配存儲空間
		    // 分配 存儲空間
		      data.image[level] = FrameMemory::getInstance().getFloatBuffer(data.width[level] * data.height[level]);
	      float* dest = data.image[level];// 目標地址

      #if defined(ENABLE_SSE)
	      // I assume all all subsampled width's are a multiple of 8.
	      // if this is not the case, this still works except for the last * pixel, which will produce a segfault.
	      // in that case, reduce this loop and calculate the last 0-3 dest pixels by hand....
	      if (width % 8 == 0)
	      {
		      __m128 p025 = _mm_setr_ps(0.25f,0.25f,0.25f,0.25f);

		      const float* maxY = source+width*height;
		      for(const float* y = source; y < maxY; y+=width*2)
		      {
			      const float* maxX = y+width;
			      for(const float* x=y; x < maxX; x += 8)
			      {
				      // i am calculating four dest pixels at a time.

				      __m128 top_left = _mm_load_ps((float*)x);
				      __m128 bot_left = _mm_load_ps((float*)x+width);
				      __m128 left = _mm_add_ps(top_left,bot_left);

				      __m128 top_right = _mm_load_ps((float*)x+4);
				      __m128 bot_right = _mm_load_ps((float*)x+width+4);
				      __m128 right = _mm_add_ps(top_right,bot_right);

				      __m128 sumA = _mm_shuffle_ps(left,right, _MM_SHUFFLE(2,0,2,0));
				      __m128 sumB = _mm_shuffle_ps(left,right, _MM_SHUFFLE(3,1,3,1));

				      __m128 sum = _mm_add_ps(sumA,sumB);
				      sum = _mm_mul_ps(sum,p025);

				      _mm_store_ps(dest, sum);
				      dest += 4;
			      }
		      }

		      data.imageValid[level] = true;
		      return;
	      }
      #elif defined(ENABLE_NEON)
	      // I assume all all subsampled width's are a multiple of 8.
	      // if this is not the case, this still works except for the last * pixel, which will produce a segfault.
	      // in that case, reduce this loop and calculate the last 0-3 dest pixels by hand....
	      if (width % 8 == 0)
	      {
		      static const float p025[] = {0.25, 0.25, 0.25, 0.25};
		      int width_iteration_count = width / 8;
		      int height_iteration_count = height / 2;
		      const float* cur_px = source;
		      const float* next_row_px = source + width;
		      
		      __asm__ __volatile__
		      (
			      "vldmia %[p025], {q10}                        \n\t" // p025(q10)
			      
			      ".height_loop:                                \n\t"
			      
				      "mov r5, %[width_iteration_count]             \n\t" // store width_iteration_count
				      ".width_loop:                                 \n\t"
				      
					      "vldmia   %[cur_px]!, {q0-q1}             \n\t" // top_left(q0), top_right(q1)
					      "vldmia   %[next_row_px]!, {q2-q3}        \n\t" // bottom_left(q2), bottom_right(q3)
		      
					      "vadd.f32 q0, q0, q2                      \n\t" // left(q0)
					      "vadd.f32 q1, q1, q3                      \n\t" // right(q1)
		      
					      "vpadd.f32 d0, d0, d1                     \n\t" // pairwise add into sum(q0)
					      "vpadd.f32 d1, d2, d3                     \n\t"
					      "vmul.f32 q0, q0, q10                     \n\t" // multiply with 0.25 to get average
					      
					      "vstmia %[dest]!, {q0}                    \n\t"
				      
				      "subs     %[width_iteration_count], %[width_iteration_count], #1 \n\t"
				      "bne      .width_loop                     \n\t"
				      "mov      %[width_iteration_count], r5    \n\t" // restore width_iteration_count
				      
				      // Advance one more line
				      "add      %[cur_px], %[cur_px], %[rowSize]    \n\t"
				      "add      %[next_row_px], %[next_row_px], %[rowSize] \n\t"
			      
			      "subs     %[height_iteration_count], %[height_iteration_count], #1 \n\t"
			      "bne      .height_loop                       \n\t"

			      : /* outputs */ [cur_px]"+&r"(cur_px),
							      [next_row_px]"+&r"(next_row_px),
							      [width_iteration_count]"+&r"(width_iteration_count),
							      [height_iteration_count]"+&r"(height_iteration_count),
							      [dest]"+&r"(dest)
			      : /* inputs  */ [p025]"r"(p025),
							      [rowSize]"r"(width * sizeof(float))
			      : /* clobber */ "memory", "cc", "r5",
							      "q0", "q1", "q2", "q3", "q10"
		      );

		      data.imageValid[level] = true;
		      return;
	      }
      #endif

	      int wh = width*height;// 當前層 像素總數
	      const float* s;
	      for(int y=0; y<wh; y += width*2)
	      {
		      for(int x=0; x<width; x+= 2)// 從上一層 隔行隔列下采樣
		      {
			      s = source + x + y;// 上一層 像素對應位置
			      *dest = (s[0] +
					      s[1] +
					      s[width] +
					      s[1+width]) * 0.25f;// 四個像素的值的平均值合併成一個
			      dest++;
		      }
	      }

	      data.imageValid[level] = true;// 該層 圖像已經構建
      }

      // 釋放圖像
      void Frame::releaseImage(int level)
      {
	      if (level == 0)
	      {
		      printf("Frame::releaseImage(0): Storing image on disk is not supported yet! No-op.\n");
		      return;
	      }
	      FrameMemory::getInstance().returnBuffer(data.image[level]);
	      data.image[level] = 0;// 指針爲0
      }

      //  根據 圖像金字塔 構建梯度金字塔  xy方向梯度  是 中心差分
      void Frame::buildGradients(int level)
      {
      // 梯度圖像需要 同一層的 圖像
	      require(IMAGE, level);
	      boost::unique_lock<boost::mutex> lock2(buildMutex);

	      if(data.gradientsValid[level])// 空指針 爲分配內存 返回
		      return;
      // 打印調試信息
	      if(enablePrintDebugInfo && printFrameBuildDebugInfo)
		      printf("CREATE Gradients lvl %d for frame %d\n", level, id());
      // 當前層圖像的寬度和高度 
	      int width = data.width[level];
	      int height = data.height[level];
      // 存儲指針爲空,則 申請內存空間
	      if(data.gradients[level] == 0)
		    //  x 方向梯度  y方向梯度  當前點像素值 第四維度沒有存儲數據  gradxyii_pt
		      data.gradients[level] = (Eigen::Vector4f*)FrameMemory::getInstance().getBuffer(sizeof(Eigen::Vector4f) * width * height);
	      
	      const float* img_pt = data.image[level] + width;// 第二行開始 的 圖像值   應爲要計算y方向梯度
	      const float* img_pt_max = data.image[level] + width*(height-1);// 圖像 最大的指針地址
	      Eigen::Vector4f* gradxyii_pt = data.gradients[level] + width;// 梯度值對應的 空間指針
	      
	      // in each iteration i need -1,0,p1,mw,pw
	      float val_m1 = *(img_pt-1);// 是左右兩個像素點的梯度
	      float val_00 = *img_pt;//  當前中心點
	      float val_p1;// 是中心差分
      //            *(img_pt-width)
      //  val_m1  *(img_pt)   val_p1
      //           *(img_pt+width)
      //   (val_p1 - val_m1)/2  = x 方向梯度
      // 0.5f*(*(img_pt+width) - *(img_pt-width)) = y方向梯度
      // val_00 = *(img_pt)   當前 點像素值
      // 第四維度 沒有存儲數據    gradxyii_pt  Eigen::Vector4f
	      for(; img_pt < img_pt_max; img_pt++, gradxyii_pt++)
	      {
		      val_p1 = *(img_pt+1);

		      *((float*)gradxyii_pt) = 0.5f*(val_p1 - val_m1);// 是左右兩個像素點的梯度 x方向梯度
		      *(((float*)gradxyii_pt)+1) = 0.5f*(*(img_pt+width) - *(img_pt-width));// +/- 一行的長度就得到 上下的座標 y方向梯度
		      *(((float*)gradxyii_pt)+2) = val_00;// 像素值
		      val_m1 = val_00;// 迭代
		      val_00 = val_p1;
	      }

	      data.gradientsValid[level] = true;
      }
      // 釋放 梯度 金字塔
      void Frame::releaseGradients(int level)
      {
	      FrameMemory::getInstance().returnBuffer(reinterpret_cast<float*>(data.gradients[level]));
	      data.gradients[level] = 0;
      }
      
      
// 創建 梯度圖內 臨近四點中梯度最大值 的 最大值梯度 圖 , 並記錄梯度值較大的可以映射 成 地圖點的數量
// 在梯度圖中  求的  上中下 三個梯度值中的最大值,形成臨時梯度最大值圖
// 在臨時梯度最大值圖 中求 的  左中右 三個梯度值中的最大值,形成最後的 最大梯度值地圖
// 並記錄 最大梯度大小超過閾值的點 可以映射成地圖點  
      void Frame::buildMaxGradients(int level)
      {
	// 需要同一層級的 梯度圖
	      require(GRADIENTS, level);
	      boost::unique_lock<boost::mutex> lock2(buildMutex);
       // 已經 得到過了,就不要計算了
	      if(data.maxGradientsValid[level]) return;
       // 打印調試信息
	      if(enablePrintDebugInfo && printFrameBuildDebugInfo)
		      printf("CREATE AbsGrad lvl %d for frame %d\n", level, id());
      // 當前層級的 寬度和高度
	      int width = data.width[level];
	      int height = data.height[level];
      // 未申請內存則申請內存
	      if (data.maxGradients[level] == 0)
		      data.maxGradients[level] = FrameMemory::getInstance().getFloatBuffer(width * height);
	      // 臨時內存地址
	      float* maxGradTemp = FrameMemory::getInstance().getFloatBuffer(width * height);


    // 1. 秋去合成梯度大小 sqrt(dx^2 + dy^2)   write abs gradients in real data.
	      Eigen::Vector4f* gradxyii_pt = data.gradients[level] + width;// 梯度 第二行開始的 地址  , x梯度 y梯度 像素值 空
	      float* maxgrad_pt = data.maxGradients[level] + width;// 對應最大梯度值  存儲起始地址
	      float* maxgrad_pt_max = data.maxGradients[level] + width*(height-1);// 對應最大梯度值  最大存儲地址

	      for(; maxgrad_pt < maxgrad_pt_max; maxgrad_pt++, gradxyii_pt++)
	      {
		      float dx = *((float*)gradxyii_pt);// x 方向梯度
		      float dy = *(1+(float*)gradxyii_pt);// y方向梯度
		      *maxgrad_pt = sqrtf(dx*dx + dy*dy);// 和成梯度
	      }

// 2. 求每個梯度值上中下三個位置中的最大值形成的 臨時最大梯度圖
        // smear up/down direction into temp buffer
	      maxgrad_pt = data.maxGradients[level] + width+1;//第二行 第二個 開始  位置
	      maxgrad_pt_max = data.maxGradients[level] + width*(height-1)-1;// 最大位置
	      float* maxgrad_t_pt = maxGradTemp + width+1;// 對應位置的 臨時變量地址
	      for(;maxgrad_pt<maxgrad_pt_max; maxgrad_pt++, maxgrad_t_pt++)
	      {
		      float g1 = maxgrad_pt[-width];// 上方位置的 合成梯度
		      float g2 = maxgrad_pt[0];// 當前點 合成梯度 
		      if(g1 < g2) g1 = g2;// 保留g1 和 g2 中的最大值
		      float g3 = maxgrad_pt[width];// 下方位置的 合成梯度
		      if(g1 < g3)
			      *maxgrad_t_pt = g3; // 臨時最大值
		      else
			      *maxgrad_t_pt = g1;// 臨時最大值
	      }

	      float numMappablePixels = 0;
// 3. smear left/right direction into real data
	      maxgrad_pt = data.maxGradients[level] + width+1;//第二行 第二個 開始  位置
	      maxgrad_pt_max = data.maxGradients[level] + width*(height-1)-1;// 最大位置
	      maxgrad_t_pt = maxGradTemp + width+1;// 對應位置的 臨時變量地址
	      for(;maxgrad_pt<maxgrad_pt_max; maxgrad_pt++, maxgrad_t_pt++)
	      {
		      float g1 = maxgrad_t_pt[-1];// 左邊
		      float g2 = maxgrad_t_pt[0];// 中間
		      if(g1 < g2) g1 = g2;// 保留g1 和 g2 中的最大值
		      float g3 = maxgrad_t_pt[1];// 右邊
		      if(g1 < g3)
		      {
			      *maxgrad_pt = g3;// 最大值
			      if(g3 >= MIN_ABS_GRAD_CREATE)
				      numMappablePixels++;// 梯度大小超過閾值的 計數
		      }
		      else
		      {
			      *maxgrad_pt = g1;
			      if(g1 >= MIN_ABS_GRAD_CREATE)
				      numMappablePixels++;// 梯度大小超過閾值的 計數
		      }
	      }

	      if(level==0)
		      this->numMappablePixels = numMappablePixels;// 梯度值較大的點可以 求的 地圖點

	      FrameMemory::getInstance().returnBuffer(maxGradTemp);// 刪除臨時內存

	      data.maxGradientsValid[level] = true;// 得到周圍四點 最大梯度值 地圖
      }
// 深度 最大梯度值地圖
      void Frame::releaseMaxGradients(int level)
      {
	      FrameMemory::getInstance().returnBuffer(data.maxGradients[level]);
	      data.maxGradients[level] = 0;
      }

// 根據最初逆深度均值圖 構建  逆深度均值圖 方差圖(高斯分佈)  金字塔
//    current   -----> 右邊一個
//      下邊         下右邊      上一層四個位置處的和 
//  上一層 逆方差和 / 上一層 逆深度均值 (四個位置處) 和 得到深度信息 再 取逆得到 逆深度均值
//  上一層 逆深度 方差和 取逆得到 本層 逆深度方差 
      void Frame::buildIDepthAndIDepthVar(int level)
      {
	      if (! data.hasIDepthBeenSet)
	      {
		      printfAssert("Frame::buildIDepthAndIDepthVar(): idepth has not been set yet!\n");
		      return;
	      }
	      if (level == 0)
	      {
		      printf("Frame::buildIDepthAndIDepthVar(0): Loading depth from disk is not implemented yet! No-op.\n");
		      return;
	      }
      // 遞歸構建 從最開始的 逆深度圖開始構建
	      require(IDEPTH, level - 1);// 需要上一層的逆深度圖
	      boost::unique_lock<boost::mutex> lock2(buildMutex);
	      
	      if(data.idepthValid[level] && data.idepthVarValid[level])// 該層 逆深度均值 和方差 已經創建 就返回
		      return;
      // 打印調試信息
	      if(enablePrintDebugInfo && printFrameBuildDebugInfo)
		      printf("CREATE IDepth lvl %d for frame %d\n", level, id());
      // 當前層的 寬度和高度 
	      int width = data.width[level];
	      int height = data.height[level];
      // 逆深度均值和 逆深度方差圖 內存是否分配
      //  若未分配內存,則分配內存
	      if (data.idepth[level] == 0)
		      data.idepth[level] = FrameMemory::getInstance().getFloatBuffer(width * height);
	      if (data.idepthVar[level] == 0)
		      data.idepthVar[level] = FrameMemory::getInstance().getFloatBuffer(width * height);
      // 上一層 圖像寬度
	      int sw = data.width[level - 1];

	      const float* idepthSource = data.idepth[level - 1];// 上一層 逆深度均值  指針
	      const float* idepthVarSource = data.idepthVar[level - 1];// 上一層 逆深度方差 指針
	      float* idepthDest = data.idepth[level];// 當前層 逆深度均值 指針
	      float* idepthVarDest = data.idepthVar[level];// 當前層 逆深度方差 指針
      //
      //    current   -----> 右邊一個
      //      下邊         下右邊      上一層四個位置處的和 
      //
	      for(int y=0;y<height;y++)// 每一行
	      {
		      for(int x=0;x<width;x++)// 每一列
		      {
			      int idx = 2*(x+y*sw);// 在上一層中的偏移量×2  因爲上一層的尺寸是當前層的 2倍
			      int idxDest = (x+y*width);// 當前層的 偏移量

			      float idepthSumsSum = 0;// 逆深度均值 之和
			      float ivarSumsSum = 0;// 逆深度方差 的逆之 和
			      int num=0;

			      // build sums
			      float ivar;// 逆方差
			      float var = idepthVarSource[idx];//  上一層 逆深度方差
			      if(var > 0)
			      {
				      ivar = 1.0f / var;//  逆方差
				      ivarSumsSum += ivar;// 逆方差 之和
				      idepthSumsSum += ivar * idepthSource[idx];// 加權 逆深度之和 以逆方差爲權重
				      num++;
			      }

			      var = idepthVarSource[idx+1];// 右邊一個
			      if(var > 0)
			      {
				      ivar = 1.0f / var;
				      ivarSumsSum += ivar;
				      idepthSumsSum += ivar * idepthSource[idx+1];
				      num++;
			      }

			      var = idepthVarSource[idx+sw];// 下邊的一個
			      if(var > 0)
			      {
				      ivar = 1.0f / var;
				      ivarSumsSum += ivar;
				      idepthSumsSum += ivar * idepthSource[idx+sw];
				      num++;
			      }

			      var = idepthVarSource[idx+sw+1];// 下右邊的一個
			      if(var > 0)
			      {
				      ivar = 1.0f / var;
				      ivarSumsSum += ivar;
				      idepthSumsSum += ivar * idepthSource[idx+sw+1];
				      num++;
			      }
			      
			      if(num > 0)
			      {
				      float depth = ivarSumsSum / idepthSumsSum;// 上一層 逆方差和 / 上一層 逆深度和 得到深度信息
				      idepthDest[idxDest] = 1.0f / depth;// 深度取逆 得到 逆深度
				      idepthVarDest[idxDest] = num / ivarSumsSum;// 上一層 逆深度 方差和 取逆得到 本層 逆深度方法 
			      }
			      else
			      {
				      idepthDest[idxDest] = -1;
				      idepthVarDest[idxDest] = -1;
			      }
		      }
	      }

	      data.idepthValid[level] = true;
	      data.idepthVarValid[level] = true;
      }
// 釋放 逆深度均值圖 層
      void Frame::releaseIDepth(int level)
      {
	      if (level == 0)
	      {
		      printf("Frame::releaseIDepth(0): Storing depth on disk is not supported yet! No-op.\n");
		      return;
	      }
	      
	      FrameMemory::getInstance().returnBuffer(data.idepth[level]);
	      data.idepth[level] = 0;
      }

// 釋放逆深度 方差 圖 層
      void Frame::releaseIDepthVar(int level)
      {
	      if (level == 0)
	      {
		      printf("Frame::releaseIDepthVar(0): Storing depth variance on disk is not supported yet! No-op.\n");
		      return;
	      }
	      FrameMemory::getInstance().returnBuffer(data.idepthVar[level]);
	      data.idepthVar[level] = 0;
      }

      void Frame::printfAssert(const char* message) const
      {
	      assert(!message);
	      printf("%s\n", message);
      }
 }


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章