小言_互联网的博客

【码上实战】【立体匹配系列】经典AD-Census: (2)主类

399人阅读  评论(0)

抱歉停更两周有余,工作时而忙碌,抽出了一些时间陪家人,还建了StereoV3D交流群(博客主页有群二维码哦~),朋友们都非常活跃,简直太棒了!

废话少说,我们继续更新AD-Census的实战教学篇。

上篇框架中,我们梳理了算法框架和代码框架,工程师拿到了设计图纸,得找水泥工砖瓦工砌墙打砖了。

本篇开始就带领大家一起砌墙打砖。

先贴一下AD-Census的效果图:

完整代码已开源在我的Github仓库,供大家下载。

仓库地址:https://github.com/ethan-li-coding/AD-Census

我们来看本篇的内容:

主类

我们将ADCensusStereo作为主类名:

class ADCensusStereo {
   	
public:
	ADCensusStereo();
	~ADCensusStereo();
}

如果是个空类,那只有构造和析构,当然不能是空类。它必须有成员函数和成员变量。

公有函数

在共有函数列表中,最重要的是设计 Match 成员函数为执行匹配的接口,给调用者调用,传入图像,传出视差图。注意接口的输入是三通道彩色图像哦!

/**
* \brief 执行匹配
* \param img_left	输入,左影像数据指针,3通道彩色数据
* \param img_right	输入,右影像数据指针,3通道彩色数据
* \param disp_left	输出,左影像视差图指针,预先分配和影像等尺寸的内存空间
*/
bool Match(const uint8* img_left, const uint8* img_right, float32* disp_left);

在公有函数列表中,我们还需要指定一个初始化接口和释放内存接口,初始化的目的是做一些准备工作,比如内存的初始化、状态的初始化等等。预分配往往是提高效率的常规操作,别总是需要的时候才分配,开辟内存的开销不可忽视。

重设接口是重新初始化操作,当你想改变分辨率或者改变算法参数时,可以调用此接口。

/**
* \brief 类的初始化,完成一些内存的预分配、参数的预设置等
* \param width		输入,核线像对影像宽
* \param height		输入,核线像对影像高
* \param option		输入,算法参数
*/
bool Initialize(const sint32& width, const sint32& height, const ADCensusOption& option);
/**
* \brief 重设
* \param width		输入,核线像对影像宽
* \param height		输入,核线像对影像高
* \param option		输入,算法参数
*/
bool Reset(const uint32& width, const uint32& height, const ADCensusOption& option);

私有函数

在私有函数列表中,我将AD-Census算法的子步骤分别写成单独的接口,便于清晰地调用,每一个接口代表着一个独立的功能。它们分别是

  1. 代价计算
  2. 代价聚合
  3. 扫描线优化
  4. 多步骤视差优化
  5. 视差计算
/** \brief 代价计算 */
void ComputeCost();

/** \brief 代价聚合 */
void CostAggregation();

/** \brief 扫描线优化	 */
void ScanlineOptimize();

/** \brief 多步骤视差优化	*/
void MultiStepRefine();

/** \brief 视差计算(左视图)*/
void ComputeDisparity();

/** \brief 视差计算(右视图)*/
void ComputeDisparityRight();

此外,释放接口则把初始化时开辟的内存释放掉,内存泄漏可是严重的问题,不可掉以轻心。鉴于历史原因,我是一个中度指针用户,内存的开辟释放很小心,现在也渐渐意识到容器的便利性,所以后面的编码中我开始注重容器的使用。

/** \brief 内存释放 */
void Release();

成员变量

为了安全,将成员变量全部设置为私有类型,调用者没有必要直接接触。

首先看成员函数的一览:

/** \brief 算法参数 */
ADCensusOption option_;

/** \brief 影像宽 */
sint32 width_;
/** \brief 影像高 */
sint32 height_;

/** \brief 左影像数据,3通道彩色数据 */
const uint8* img_left_;
/** \brief 右影像数据	,3通道彩色数据 */
const uint8* img_right_;

/** \brief 代价计算器 */
CostComputor cost_computer_;
/** \brief 代价聚合器 */
CrossAggregator aggregator_;
/** \brief 扫描线优化器 */
ScanlineOptimizer scan_line;
/** \brief 多步优化器 */
MultiStepRefiner refiner_;

/** \brief 左影像视差图 */
float32* disp_left_;
/** \brief 右影像视差图 */
float32* disp_right_;

/** \brief 是否初始化标志	*/
bool is_initialized_;
  1. ADCensusOption option_

    算法参数变量,参数结构体ADCensusOption的定义放在文件adcensus_types.h里。里面是根据ADCensus的原文设置的各类阈值。

/** \brief ADCensus参数结构体 */
struct ADCensusOption {
   
	sint32  min_disparity;		// 最小视差
	sint32	max_disparity;		// 最大视差

	sint32	lambda_ad;			// 控制AD代价值的参数
	sint32	lambda_census;		// 控制Census代价值的参数
	sint32	cross_L1;			// 十字交叉窗口的空间域参数:L1
	sint32  cross_L2;			// 十字交叉窗口的空间域参数:L2
	sint32	cross_t1;			// 十字交叉窗口的颜色域参数:t1
	sint32  cross_t2;			// 十字交叉窗口的颜色域参数:t2
	float32	so_p1;				// 扫描线优化参数p1
	float32	so_p2;				// 扫描线优化参数p2
	sint32	so_tso;				// 扫描线优化参数tso
	sint32	irv_ts;				// Iterative Region Voting法参数ts
	float32 irv_th;				// Iterative Region Voting法参数th
	
	float32	lrcheck_thres;		// 左右一致性约束阈值

	bool	do_lr_check;					// 是否检查左右一致性
	bool	do_filling;						// 是否做视差填充
	bool	do_discontinuity_adjustment;	// 是否做非连续区调整
};
  1. sint32 width_/height_

    图像宽高,无需多言。

  2. const uint8* img_left_/img_right_

    图像数据,注释说明是3通道的彩色数据,表明算法目前是只支持3通道彩色数据的。const标示表示算法执行过程中不会对输入的图像数据做任何的写入修改。

  3. CostComputor cost_computer_

    代价计算器,我将代价计算部分的所有功能代码都集成到一个代价计算器类CostComputor中,这样组织会比较清晰,理解上也更加容易。CostComputor类的实现放在cost_computor.h/cost_computor.cpp中,后面篇章我们会细说。

  4. CrossAggregator aggregator_

    代价聚合器,道理同上,我将代价聚合部分的所有功能代码都集成到一个代价聚合器类CrossAggregator中。CrossAggregator类的实现放在cost_aggregator.h/cost_aggregator.cpp中。

  5. ScanlineOptimizer scan_line_

    扫描线优化器,道理同上。ScanlineOptimizer类的实现放在scanline_optimizer.h/scanline_optimizer.cpp中。

  6. MultiStepRefiner refiner_

    多步视差优化器,道理同上。MultiStepRefiner类的实现放multistep_refiner.h/multistep_refiner.cpp中。

  7. float32* disp_left_/disp_right_

    左右图像的视差图,保存算法最终生成的视差图结果。类型是float32,是真实视差值,可直接用于计算深度。

  8. bool is_initialized_

    是否初始化标志。若成功执行Initialize接口,则此标志为true,反之为false,为false时不会执行匹配。

以上就是本篇主类的所有内容,下篇将给大家带来基于十字交叉域代价计算的代码介绍。

下载AD-Census完整源码,点击进入: https://github.com/ethan-li-coding/AD-Census
欢迎同学们在Github项目里讨论,如果觉得博主代码质量不错,右上角点颗星!感谢!

博主简介:
Ethan Li 李迎松(知乎:李迎松)
武汉大学 摄影测量与遥感专业博士
主方向立体匹配、三维重建
2019年获测绘科技进步一等奖(省部级)

爱三维,爱分享,爱开源
GitHub: https://github.com/ethan-li-coding (欢迎follow和star)

个人微信:

欢迎交流!

关注博主不迷路,感谢!
博客主页:https://ethanli.blog.csdn.net


转载:https://blog.csdn.net/rs_lys/article/details/108542837
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场