Statistical Analisys of Accuracy Improvement

用统计学方法检验算法对正确率的提升

前两天投出的一篇Paper有了回音,Reviewer给的意见里有一条是建议对正确率的提升效果进行统计分析。以前从没解决过类似问题,特此记录一下。

其实Reviewer有相关的疑问非常可以理解,我自己也经常对论文中的结果有质疑,单纯凭正确率是感觉有些武断,这次有这个机会学习一下怎么用统计学习的方法进行检验,感觉挺有意思,记录一下。

用Excel进行T检验

T检验是通过T分布检验两组样本的差异是否显著的方法,得出的结果主要看P值,当P值较小(常取0.05或0.01)时,认为差异是显著的,反之则认为不存在显著性差异。
我们的实验检验的目标是改进方法对准确率的提升,因此两组数据为相同输入情况下不同算法(原始算法和改进算法)的正确率。

用Excel进行T检验其实比较简单,P值的计算有以下两种方法:

  1. 利用函数工具
    这个方法和我们平时计算平均值、加和等操作是一样的步骤,点取表格选择TTest函数,输入Array1,Array2,单尾还是双尾,再选择一个Type参数即可(1代表成对检验,2代表双样本等方差假设,3代表双样本异方差假设),计算得到的结果就是P值;
  2. 利用统计工具
    这个方法相比直接使用函数的方法更复杂一些,但会给出一个包含均值、方差、自由度等多个数据的更详细的分析结果。
    首先,加载数据分析工具,点击“文件”->“Excel选项”->“加载项”选项卡,将“分析工具库”添加到活动应用程序加载项中。
    然后返回表单,选择“数据”->最右侧的“数据分析”按钮->T检验即可。

xrdp problem connecting

Linux远程桌面连接Problem Connecting问题解决

起因是上周五,我美滋滋的用着远程桌面结果突然被强制退出,然后就再也登不上了,尝试了重启服务和系统、卸载再安装xrdp和vnc、新建用户、新建文件内容为allowroot=1等等许多操作之后仍然报错。
主要的错误类型有两种:一种是提示problem connecting,一种是在problem connecting之前还有一句password failed.两种错误我都不能接受,首先我检查了3350和5910两个端口,都处于LISTEN状态,其次我的password肯定是没有错。查看了log也没有出现任何相关错误提示。
错误提示如下:

connecting to sesman ip 127.0.0.1 port 3350
sending login info to sesman
xrdp_mm_process_login_response: login successful for display
started connecting
connecting to 127.0.0.5910
tcp connected
security level is 2 (1 = none, 2 = standard)
password failed
error - problem connecting

于是今天决定一切推翻重来,主要是用了以下几个步骤,也不知道是哪个起了作用,就都先记录如下:

sudo apt-get update
sudo apt-get remove xrdp vnc4server
sudo apt-get install xinit
sudo apt-get install gdm
sudo apt-get install kubuntu-desktop
sudo apt-get install xrdp
sudo apt-get install vnc4server
echo xfce4-session >~/.xsession
vi /etc/xrdp/startwm.sh
//在. /etc/X11/Xsession 前一行插入xfce4-session
vi /etc/xrdp/sesman.ini
//在末尾增加两行
//param8=-SecurityTypes
//param9=None
sudo service xrdp restart

有用的语句:

ps -ef | grep vnc
sudo kill 进程
netstat -nltp
sudo adduser kkk
sudo userdel kkk

在问题解决过程中找到的相关建议:
https://blog.csdn.net/Blateyang/article/details/86297472
https://blog.csdn.net/u011816696/article/details/73350931
https://unix.stackexchange.com/questions/106974/windows-remote-desktop-login-failed-with-ubuntu-server-12-4
https://www.linuxquestions.org/questions/showthread.php?s=96fe980f2ffb4f61357fc3a6dd4dc9ce&p=5569746
http://www.dellts.cn/article/22.html

OpenCV Cross Compile

OpenCV交叉编译

最近接触了一下板子上的图像处理,完全是从0开始,所以很长一段时间都处于迷茫的自学阶段,不断重复掉坑爬坑掉坑爬坑的过程,心好累然而也没做出什么满意的东西。
这里总结一下里面比较重要的一个环节,OpenCV的交叉编译。

准备工作

从准备工作开始就踩了超多的坑,板子的开发真的好难(流下了宽宽的泪水)。
一开始是在网络上的虚拟机搞,这个虚拟机虽说是linux但是是64位,linux里64位和32位有好多包是不同的,所以在版本匹配上走了好多好多弯路,而且因为公司的网络比较复杂,所以虚拟机和板子是没办法ping通的,最后还是放弃了这个在自己电脑上搭了一个新的。本地虚拟机的优点就是很好ping通,缺点就是我的小电脑亚历山大,根本不敢装图形界面。
装好虚拟机以后就作以下两件事:

  1. 安装交叉编译器
    由于用的是华为海思的开发板,因此使用海思SDK中提供的交叉编译器,编译器的安装步骤如下:
    1)进入Hi3516A_SDK_Vx.x.x.x/osdrv/opensource/toolchain/arm-hisiv300-linux目录,arm-hisiv300-linux.tar.bz2如果没有抽取则抽取到此处,运行chmod +x cross.v300.install,然后运行./cross.v300.install即可。
    2) 执行source /etc/profile, 安装交叉编译器的脚本配置的环境变量就可以生效了,或者请重新登陆也可。
    3) 安装好的交叉编译器一般在/opt目录下。

  2. 安装CMake
    1) 网站下载代码https://cmake.org/download/
    2) 解压到~/目录 tar -xvf cmake-3.11.0-Linux-x86_64.tar.gz
    3) 为cmake创建连接 sudo ln -s ~/cmake-3.11.0-Linux-x86_64/bin/* /usr/bin/
    4) 测试 cmake –version

编译

这个过程用六个字来概括就是“尽人事,听天命”,过程中会出现超多的莫名其妙的报错,有的居然通过重启虚拟机就可以解决,百思不得其解啊。
以下为复制别人的内容,因为这个过程漫长又不可控,所以我自己的记录比较少,我在编译过程中遇见的问题会在最后一部分总结以下,这部分就写一下如果不出错流程会是怎样:
1、修改cmake文件
在源码的platforms下已经有对各平台的交叉编译支持,我们只需要做一些简单的修改。
[zzz@localhost platforms]$ pwd
/home/zzz/software/opencv-3.1.0/platforms
[zzz@localhost platforms]$ ll
total 28
drwxr-xr-x. 4 zzz zzz 4096 Dec 18 23:02 android
drwxr-xr-x. 3 zzz zzz 4096 Dec 18 23:02 ios
drwxr-xr-x. 4 zzz zzz 4096 Jan 22 17:24 linux
drwxr-xr-x. 2 zzz zzz 4096 Dec 18 23:02 osx
-rw-r–r–. 1 zzz zzz 323 Dec 18 23:02 readme.txt
drwxr-xr-x. 2 zzz zzz 4096 Dec 18 23:02 scripts
drwxr-xr-x. 2 zzz zzz 4096 Dec 18 23:02 winrt

我们的目标是交叉编译到arm上,那么就进入到linux下:
[zzz@localhost linux]$ pwd
/home/zzz/software/opencv-3.1.0/platforms/linux
[zzz@localhost linux]$ ll
total 20
-rw-r–r–. 1 zzz zzz 4196 Jan 22 16:35 arm-gnueabi.toolchain.cmake

arm-gnueabi.toolchain.cmake指明了交叉编译的一些路径等设置,我们根据实际情况对其进行适当修改:
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_VERSION 1)
set(CMAKE_SYSTEM_PROCESSOR arm-hisiv300-linux-gnueabi)
set(GCC_COMPILER_VERSION “4.6” CACHE STRING “GCC Compiler version”)
set(FLOAT_ABI_SUFFIX “”)
if (NOT SOFTFP)
set(FLOAT_ABI_SUFFIX “hf”)
endif()
#CROSS COMPILE SETTING
set(TOOLCHAIN_DIR “/opt/hisi-linux/x86-arm/arm-hisiv300-linux/“)
set(CMAKE_C_COMPILER “/opt/hisi-linux/x86-arm/arm-hisiv300-linux/bin/arm-hisiv300-linux-uclibcgnueabi-gcc”)
set(CMAKE_CXX_COMPILER “/opt/hisi-linux/x86-arm/arm-hisiv300-linux/bin/arm-hisiv300-linux-uclibcgnueabi-g++”)
set(CMAKE_FIND_ROOT_PATH /opt/hisi-linux/ /opt/hisi-linux/x86-arm/arm-hisiv300-linux/)
set(ARM_LINUX_SYSROOT /opt/hisi-linux/x86-arm/arm-hisiv300-linux/ CACHE PATH “ARM cross compile system root”)
MESSAGE(STATUS “This is cross compile dir —>”$(CMAKE_C_COMPILER))

#find_program(CMAKE_C_COMPILER NAMES arm-linux-gnueabi${FLOAT_ABI_SUFFIX}-gcc-${GCC_COMPILER_VERSION})

#find_program(CMAKE_CXX_COMPILER NAMES arm-linux-gnueabi${FLOAT_ABI_SUFFIX}-g++-${GCC_COMPILER_VERSION})
#set(ARM_LINUX_SYSROOT /usr/arm-linux-gnueabi${FLOAT_ABI_SUFFIX} CACHE PATH “ARM cross compilation system root”)

#set(CMAKE_CXX_FLAGS           ""                    CACHE STRING "c++ flags")

#set(CMAKE_C_FLAGS “” CACHE STRING “c flags”)
#set(CMAKE_SHARED_LINKER_FLAGS “” CACHE STRING “shared linker flags”)
#set(CMAKE_MODULE_LINKER_FLAGS “” CACHE STRING “module linker flags”)
#set(CMAKE_EXE_LINKER_FLAGS “-Wl,-z,nocopyreloc” CACHE STRING “executable linker flags”)
set(CMAKE_CXX_FLAGS “${CMAKE_CXX_FLAGS} -mthumb -fdata-sections -Wa,–noexecstack -fsigned-char -Wno-psabi”)
set(CMAKE_C_FLAGS “${CMAKE_C_FLAGS} -mthumb -fdata-sections -Wa,–noexecstack -fsigned-char -Wno-psabi”)
set(CMAKE_SHARED_LINKER_FLAGS “-Wl,–fix-cortex-a8 -Wl,–no-undefined -Wl,–gc-sections -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now ${CMAKE_SHARED_LINKER_FLAGS}”)
set(CMAKE_MODULE_LINKER_FLAGS “-Wl,–fix-cortex-a8 -Wl,–no-undefined -Wl,–gc-sections -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now ${CMAKE_MODULE_LINKER_FLAGS}”)
set(CMAKE_EXE_LINKER_FLAGS “-Wl,–fix-cortex-a8 -Wl,–no-undefined -Wl,–gc-sections -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now ${CMAKE_EXE_LINKER_FLAGS}”)
if(USE_NEON)
message(WARNING “You use obsolete variable USE_NEON to enable NEON instruction set. Use -DENABLE_NEON=ON instead.” )
set(ENABLE_NEON TRUE)
elseif(USE_VFPV3)
message(WARNING “You use obsolete variable USE_VFPV3 to enable VFPV3 instruction set. Use -DENABLE_VFPV3=ON instead.” )
set(ENABLE_VFPV3 TRUE)
endif()

        #set(CMAKE_FIND_ROOT_PATH ${CMAKE_FIND_ROOT_PATH} ${ARM_LINUX_SYSROOT})
        if(EXISTS ${CUDA_TOOLKIT_ROOT_DIR})
set(CMAKE_FIND_ROOT_PATH ${CMAKE_FIND_ROOT_PATH} ${CUDA_TOOLKIT_ROOT_DIR})

endif()
set( CMAKE_SKIP_RPATH TRUE CACHE BOOL “If set, runtime paths are not added when using shared libraries.” )
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)

# macro to find programs on the host OS

macro( find_host_program )
set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER )
set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER )
set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER )
if( CMAKE_HOST_WIN32 )
SET( WIN32 1 )
SET( UNIX )
elseif( CMAKE_HOST_APPLE )
SET( APPLE 1 )
SET( UNIX )
endif()
find_program( ${ARGN} )
SET( WIN32 )
SET( APPLE )
SET( UNIX 1 )
set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY )
set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY )
set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY )
endmacro()

# macro to find packages on the host OS

macro( find_host_package )
set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER )
set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER )
set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER )
if( CMAKE_HOST_WIN32 )
SET( WIN32 1 )
SET( UNIX )
elseif( CMAKE_HOST_APPLE )
SET( APPLE 1 )
SET( UNIX )
endif()
find_package( ${ARGN} )
SET( WIN32 )
SET( APPLE )
SET( UNIX 1 )
set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY )
set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY )
set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY )
endmacro()
2、交叉编译
设置好了以后,开始进行交叉编译:
建立好执行cmake的路径:build_softfp,建立好编译后的安装路径:install_dir
[zzz@localhost linux]$ ll
total 20
-rw-r–r–. 1 zzz zzz 4196 Jan 22 16:35 arm-gnueabi.toolchain.cmake
drwxrwxr-x. 15 zzz zzz 4096 Jan 22 16:38 build_softfp
drwxrwxr-x. 6 zzz zzz 4096 Jan 22 15:51 install_dir
执行:
[zzz@localhost build_softfp]$ pwd
/home/zzz/software/opencv-3.1.0/platforms/linux/build_softfp
[zzz@localhost build_softfp]$ cmake -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=../install_dir/ -D SOFTFP=ON -D ENABLE_NEON=ON -D CMAKE_TOOLCHAIN_FILE=../arm-gnueabi.toolchain.cmake ../../../
等待10几分钟。

问题总结

  1. make报错提示“No suitable threading library available”: 定位到common.cc文件,头文件首行加上#define HAVE_PTHREAD
  2. 提示找不到bits/auxv.h: 搜索发现在/usr/include/x86_64-linux-gun/bits/auxv.h,更改对应文件的include
  3. 查看arm-linux-gcc编译器的版本arm-linux-gcc -v时报错bin/.arm-none-linux-gnueabi-gcc: not found:
    a. 解决方法一:sudo apt-get install lsb-core但出现安装失败
    b. 解决方法二:原因可能是64位ubuntu系统缺少某些32位包,只要装一下ia32-libs就ok了.但是,貌似从ubuntu 13.10之后就没有ia32-libs了,因此sudo apt-get install lib32stdc++6 lib32z1 lib32ncurses5 lib32bz2-1.0,但还是出现安装失败。
    但是!此时可以输出版本信息了!于是pass
  4. ubuntu16.04安装32位交叉编译工具链的兼容包:
    apt-get install lib32ncurses5 ​
    apt-get install lib32z1​
  5. 配置linux内核时报错curses.h: No such file or directory:
    Sudo apt-get install libncurses5-dev libncursesw5-dev
  6. 错误:error while loading shared libraries: libstdc++.so.6: cannot open shared object file: No such file or direcory。
    $sudo apt-get install libstdc++6
    $sudo apt-get install lib32stdc++6
  7. 输入命令语句为:make ARCH=arm CROSS_COMPILE=arm-hisiv500-linux- uImage
    报错信息为:
    kernel/power/swap.c:1168:10: error: ‘RESTARTSYS’ undeclared (first use in this function)
    return -RESTARTSYS;
    cp arch/arn/configs/hi3518ev200_full_defconfig .config —> 这句要执行好, 是3518的配置文件。
    如果没有拷贝成功, 则在进行menuconfig时, 没有3518ev200的一些选择项。 比如没有拷贝就执行menuconfig, 则在菜单选项,I2C 目录中没有3518 的选项。 如果 执行成功, 就有3518 I2C 的选项。
  8. 编译linux kernel uImage时提示:“mkimage” command not found – U-Boot images will not be built:
    sudo apt-get install u-boot-tools
  9. 错误提示:ECHO : not found等一系列found问题
    首先用whereis echo查看echo所在路径
    然后用export查看PATH中包含的路径
    发现包含无误,则修改文件第一句#!/bin/sh为#!/bin/bash即可

Monocular Depth Estimation 9

  1. 入门篇:图像深度估计相关总结
  2. 应用篇:Learning to be a Depth Camera
  3. 尺度篇:Make3D
  4. 迁移篇:Depth Extraction from Video Using Non-parametric Sampling
  5. 深度篇:David Eigen
  6. 无监督篇:Left-Right Consistency & Ego Motion
  7. 相对深度篇:Depth in the Wild & Size to Depth
  8. SLAM辅助篇:MegaDepth
  9. 方法比较篇:Evaluation of CNN-based Methods

单目图像深度估计 - 方法比较篇:Evaluation of CNN-based Methods

今天的论文阅读笔记是关于以下这篇论文:
[1] Evaluation of CNN-based Single-Image Depth Estimation Methods, CVPR, 2018
这篇文章提出了一个新的数据集,分析了已有CNN单目图像深度估计算法存在的问题,并且实验对比了已有的经典算法,可以算是一篇小综述。

写完这篇阅读笔记,深度估计这一系列就告一段落,接下来希望抛开理论多做一些实验。
单目图像深度估计的研究热度是逐渐升高的,越是近期相关的Paper越多,就在我写这篇Blog的同时发现了一篇自监督的论文号称达到了目前最好的正确率…但因为这个问题本身就是个ill-posed的问题,所以目前的方法各有优劣,不存在十全十美的方法,还是有改进空间的。

2018 CVPR的这篇文章给单目深度估计一个简称叫SIDE(Single-Image Depth Estimation),作者指出SIDE相关的研究本身具有重要意义,体现在自动驾驶、机器人导航、增强现实等大火方向的应用。但是目前的方法仍然存在很多问题,比如在进行正确率计算的时候只关注全局的表现忽略了对边界等细节的要求,因此从视觉上看预测结果与输入图片相比会更模糊,缺失很多物体边界、平滑表面、对透明或纹理比较难预测的物体的预测等等。针对这些问题,作者提出了几个新的error形式,并且提出一个新的数据集,这个数据集给出了计算这些细节error需要的全部信息,最后对比了不同的方法和数据集。

单目图像深度估计的发展脉络大约是:在计算能力和数据集都不足的时候,大部分方法是基于人为的特征计算。比如基于三角测量的双目方法MVS(multi-view stereo),SfM(structure from motion),基于通道梯度的单目方法SfS(Shape of Shading)。以上三种属于passive方法,也有一些active的方法利用根据对焦和失焦或偏振(polarization cues)等线索。其他的方法有利用光场相机(light field camera)的方法等。随着RGBD数据集的出现,数据驱动的基于学习的方法超过了传统方法,尤其是利用CNN的方法。
第一次听说光场相机,发现这是个很有意思的技术,网络上的解释如下:
光场相机不同于一般的单一镜头、感光元件接收单一光束的原理相机,它是透过庞大的显微镜头阵列(Microlens array)记录整个光场的数值,再透过软件运算还原影像,并可随意调整对焦点再次运算出新的影像。
总之,基于大规模数据集的深度方法是目前研究的主流。

目前比较成熟且常用的RGBD数据集有Make3D,Kitti,NYU depth, CityScape等。
作者总结了目前常用的RGBD数据集的缺点:

  • Make3D和Kitti的场景受限(室外),且深度图的分辨率很低;
  • NYU depth v2只包含室内场景,但Kinect的有效距离范围很小,遮挡、边界等不够清晰。

Error Metrics

现有的Error主要有以下几个:
Error Metrics
然而这些都只关注了全局的一致性,在loss中并不能体现平面(如桌面和墙壁)的平整性和三维方向,以及边界和遮挡判断是否正确。因此作者提出了几个新的error:

  1. 对不同深度区间的预测正确率进行统计
  2. 平整性
    Error Metrics
    planarity error计算了(mask得到的)某一特定平面预测得到的三维points与实际的偏差;
    orientation error计算了预测平面与实际平面的角度偏差,角度通过反余弦函数得到,arccos函数可以根据函数值求出弧度值。
  3. 物体边界
    在深度图中,具有前后关系的两个物体相互遮挡形成的边界可表示为梯度的迅速下降,边缘的预测是否准确决定了预测结果的细节在视觉上的细节优化。因此作者提出一种边界相关的error,首先调用structured edges提取预测图中的边界。
    Error Metrics
    depth boundary error计算了预测的边界与实际边界之间的偏差;
    completeness error计算了边界的完整性,即是否预测除了完整的边界。
  4. 偏差纠正(偏大还是偏小)
    传统的loss关注整幅图像的深度连续性和预测误差,但没有全局计算到底预测值是偏大还是偏小。
    Error Metrics
    directed depth errors(DDEs)取一个标值(3m),根据深度关系进行mask后得到计算结果。

下图是平面和边界loss的示意图。
Error Metrics

Dataset

文章提出了一个新的数据集IBims-1,每幅图片包含RGBD和平面mask以及边界信息。但场景也比较单一,目前数据量还不大。

Evaluation

这部分是各种CNN方法的对比,作者选取了几个CNN模型,有经典的也有近期的,这些模型都用NYU v2进行的训练。

  • 不同深度区间的预测正确率
    Evaluations
    上图为[3]的方法在NYU和IBims-1两个数据集的预测误差,可以看出在深度大的地方预测误差会更大。

  • 平面结构的预测
    作者选择桌面、墙面和地面作为代表平面进行不同方法的比较,在IBims-1数据集上各方法的表现如下。
    Evaluations
    可以看出已有方法对水平的平面预测结果较好,但对竖直平面预测结果较差。
    Evaluations
    从表格可以看出[3]的方法得到了目前为止最小的error,但在边界和平面的预测结果不十分理想。

  • 距离判断
    实验表明,就算是达到了80%以上正确率的算法,都倾向于给出更小的预测depth,也就是说把物体预测的更近。

  • 数据增强(Data Augmentation)
    对比了水平翻转、竖直翻转、通道交换(swapping of image channels),色彩平移(shifting the hue by some offser)等的实验结果如下:
    Evaluations
    从表格上可以看出:

  1. 水平翻转对结果影响不大,竖直翻转error增大了60%;
  2. 小范围加大曝光对结果产生很大影响,但降低曝光并未产生相同程度影响;
  3. 直方图拉伸和颜色改变对预测结果影响不大。
    同时作者提出竖直翻转对结果影响很大的原因可能是因为NYU数据集中的图片里,很大一部分pixels都是地板并且在图片的下半部分。
  • 有纹理的平面
    这个实验很有趣,作者将纹理和图像打印出来贴在墙上,让CNN对其进行深度预测,结果如下图:
    Evaluations
    可以看出,梯度对深度的预测起到了很重要的影响,所有网络都没能预测出正确的深度。其实这也反映了深度估计的ill,就算是人类站在一张照片前,如果没有充分理解这是一张照片的话,也有可能错误估计其中物体的距离吧。

总结与思考

写完这篇文章,深度估计相关的阅读笔记就告一段落,小小的松了一口气。
从一点也不了解,到现在稍稍摸到了一点门道,越学习越发现自己知道的少。
今天看到新闻说Face book的技术路线是机器学习优先的,在不是必要的情况下不会选择更复杂的深度学习算法,这好像解决了我心里一直以来的一个疑问:在真正应用的时候是选取快速但结果比较粗糙的经典机器学习方法还是选正确率更高但复杂的多的深度方法。
据我现在的了解,深度学习还远远没到大众都可以使用的程度,经费充足的项目和大学可以发更多的Paper,因为他们有巨大的计算等资源。在不考虑硬件发展的情况下,这些基于庞大运算量的正确率高达98%的算法真的是商业应用的出路吗?可能能够拉来投资,但是用起来有多闹心只有自己知道吧。
扯多了,总之我还是觉得简单才是真正的优雅,希望以后自己不会跑偏。

[2]Dollar et al, Fast edge detection using structured forests, IEEE trans, 2015
[3]Li et al, A two-streamed network for estimation fine-scaled depth maps from single rgb images, CVPR,2017

Monocular Depth Estimation 8

  1. 入门篇:图像深度估计相关总结
  2. 应用篇:Learning to be a Depth Camera
  3. 尺度篇:Make3D
  4. 迁移篇:Depth Extraction from Video Using Non-parametric Sampling
  5. 深度篇:David Eigen
  6. 无监督篇:Left-Right Consistency & Ego Motion
  7. 相对深度篇:Depth in the Wild & Size to Depth
  8. SLAM辅助篇:MegaDepth
  9. 方法比较篇:Evaluation of CNN-based Methods

单目图像深度估计 - SLAM辅助篇:MegaDepth

今天的论文笔记是关于以下这篇Paper:
[1] MegaDepth-Learning Single-View Depth Prediction from Internet Photos, CVPR, 2018 [Project Page]
CVPR的单目深度估计论文有很多,粗略的看了一圈,决定写这篇。之前的博客里写到过说目前所有的计算机视觉相关的深度学习方法都有一个共同的问题——对数据集的依赖。在单目图像深度估计来看呢,就是基于室内数据集NYUDepth训练出来的模型在室外数据集KITTI、CitiScape里表现不好,反之亦然。与此同时,目前的数据集还存在很多其他不足比如场景单一(NYU),训练集规模小(Make3D),采样稀疏(KITTI)。
为了解决这些问题,作者提出一个全新的思路:

用来源于网络的多张景点图像通过建模算法进行三维建模,从而得到对应的深度预测值,通过对预测值进行一系列优化(如划分临时物体(如游客),根据语义分割将前景、背景和天空单列处理等),用优化后的数据训练深度预测网络,通过结合梯度、尺度不变和相对深度的loss进行网络训练。

总结的还不够精炼,我认为loss方面就是将现在比较流行的方法大杂烩了一下,更有创新的是作者利用网络图片的思路。
因为某一热门景点的照片,通过tag可以轻松的在网络上找到,而且照片来源的多样性保证了照片角度的丰富性,更适用于放在三维建模算法里进行建模,文章中用到的建模软件为COLMAP。面临的问题就是网络照片中的随机内容,比如景点照中的行人,甚至以景点为tag的自拍。

数据集建立

首先在Flickr上收集Landmarks10K数据集中的地标对应的图片,然后用SfM(structure from motion)和MVS(multi-view stereo)方法进行3D建模,建模后获取到的是景点的模型和建模时使用的每张图片对应的深度图。
但得到的原始深度图有很多噪声点和异常值,因此要对深度图进行优化,优化分为以下两个步骤:

  1. 改进MVS算法,在每一步迭代时对比像素深度更改,限制只能进行小范围的更改,并且附加中值滤波去除不稳定的深度值。提出这个优化的原因是在COLMAP的MVS过程中,算法设计为了保证geometric consistency,因此对于一些存在前景比如游客的照片,在迭代的过程中会把前景深度同化成背景的深度,造成数据出错。
  2. 利用语义分割生成序列深度(相对深度)信息。

Refine MVS

具体解释一下第二个步骤。
由于multi-view stereo方法不擅长处理临时物体(行人、汽车)和难以建模的物体(杆、信号灯、天空区域),但这些难以识别的物体可以在语义上进行分割和提取。作者使用语义信息做了以下三个处理:

  1. Semantic filtering:去除MVS得到的不准确前景(foreground)深度信息。用PSPNet对图像进行语义分割,将像素分为前景(喷泉、雕塑、游客)、背景(建筑、塔、山)和天空三类。
  2. Euclidean vs. ordinal depth:以语义为标准对图片进行分类,划分为euclidean depth data和ordinal depth data。通过阈值判断在建模过程中重建的(reconstructed)像素的比例,大于30%的图片认为是有效的图片,可以用于进行Euclidean估计,这样可以排除自拍的照片,因为自拍中建筑物占比较小;
  3. Automatic ordinal depth labeling:利用语义标签自动标记前后深度序列信息。

Auto Ordinal

Loss组成

文章的loss分为三个部分,分别是尺度不变loss,多尺度梯度loss和相对序数关系loss,公式如下:
Loss

总结和思考

这片文章找到了网络图片利用的一个突破口,网络图片的数量巨大,但是缺少对应的深度标签,由于深度网络对数据的依赖,有效的利用大量的网络数据可以提高预测模型的表现能力。但问题同样存在,因为深度估计建立在MVS等算法基础上,有了中间商赚差价导致最终的结果不能超过MVS生成的图像。

Monocular Depth Estimation 7

  1. 入门篇:图像深度估计相关总结
  2. 应用篇:Learning to be a Depth Camera
  3. 尺度篇:Make3D
  4. 迁移篇:Depth Extraction from Video Using Non-parametric Sampling
  5. 深度篇:David Eigen
  6. 无监督篇:Left-Right Consistency & Ego Motion
  7. 相对深度篇:Depth in the Wild & Size to Depth
  8. SLAM辅助篇:MegaDepth
  9. 方法比较篇:Evaluation of CNN-based Methods

单目图像深度估计 - 相对深度篇:Depth in the Wild & Size to Depth

目前单目图像深度估计需要面临的主要问题之一就是我们用来获得ground truth depth的硬件设备本身具有一定误差和环境限制,比如说基于红外的相机(Kinect)无法在室外使用,而所有设备都只在一定距离范围内具有精确度,超出这个范围的获取结果是不可信的,因此我们所获得的深度图本身就具有一定误差。在误差的基础上进行建模,使得后续模型拟合的难度加大了。
因此就有科学家提出,其实人类对深度的实际数值并不敏感,反而是对相对深度即物体的前后关系更加敏感。这篇笔记打算写的两篇论文都是基于这个思考而来:
[1] Single-Image Depth Perception in the Wild, NIPS, 2016 [Project Page]
[2] Size to Depth: A New Perspective for Single Image Estimation, CVPR, 2018


Single-Image Depth Perception in the Wild, NIPS, 2016

这篇文章很有趣,作者指出就算是具有完备又复杂视觉系统的人类也很难推断出物体的实际深度(距离)值,而且人也会被迷惑(比如“鸽子为什么这么大”),但人可以根据经验(物体大小)、遮挡关系、光线和阴影等知识来准确的判断相对深度,即物体的前后关系。之前已经有由相对深度估计绝对深度的研究,但缺少适用于现状的数据集。因此这篇文章的贡献主要有:

  • Depth in the Wild数据集
  • 通过相对深度预测绝对深度的方法

DIW数据集
目前已有的数据集的缺陷有:基于Kinect的数据集局限于室内场景;基于LIDAR的数据集局限于人造的场景(街道)。因此DIW的数据集的目的是采集更多的非人造场景。
文章作者详细写了数据集的整理和标注方法。首先,从英文词典中随机抽取关键词到图片网站Flickr上搜索,然后手动去除剪贴画等人造的图片,最后用众包的方式获取打标结果。
数据集中相对深度的表达方式为问询(query),一个query可以表达为(i,j,r),其中i,j为两个数据点,r为两点像素的相对深度,0表示难以判断的接近,+1表示i比j更近,-1表示i比j更远。
为了更有效的利用人为的打标信息,数据集中每幅图片选取一对像素点进行一次问询。作者解释说,在一幅图片上选取多个点获取其相对深度是可行的,但存在问题是往往相似的点具有相似的深度,因此在一幅图上标记多点难免产生数据冗余。
文章还对如何选取这唯一的一对像素点进行了探讨。有趣的实验结果如下:

  • 直接判定更靠近图片底部的点为较近点可以获得85.8%的预测正确率。
  • 同一水平线上的两个点,直接判定更靠近中心点的点为较近的点可以获得71.4%的预测正确率。
    因此本文作者选取的方式为:选取同一水平线上距离中心点距离相同(左右对称)的两个点。用这样的选取方式选取的两个点,左边的点为较近点的概率为50.3%。

通过相对深度预测绝对深度
这部分也比较有意思,以我的理解,作者的意思是说假如数据集足够大只需要一个能够拟合相对深度的网络就可以预测绝对深度。是不是说一幅图片如果相对深度能够确定,自然可以确定绝对深度呢?
作者提出的Loss缺失没有依赖绝对深度,而是只根据相对深度。
Loss
上图为文章提出的Loss,若两个点的相对深度关系为“接近”时Loss让两个点的绝对深度更加接近,反之则让两个点的绝对深度之间具有较大差距。
通过实验发现先在NYU Depth数据集上训练然后在DIW数据集上进行Refine得到的网络具有最优的预测表现。


Size to Depth: A New Perspective for Single Image Estimation, CVPR, 2018

上一篇文章有一个主要的问题就是同样的图片可能会对应完全不同的距离值,假设同一部相机在不同距离拍摄相同场景的情况。这篇文章针对这种问题,提出size to depth的方法。
文章中提到了两个很有趣的实验:

  • 从2D图片判断绝对深度:被试验者犹豫的时间较长,且结果有21%的相对误差。
  • 从2D图片中判断物体尺寸: 被试验者犹豫的时间较短,且结果只有8%的相对误差。
    我个人理解,犹豫时间可以表达人类在这方面能力的强弱,因此人类由于先验知识的影响,判断物体尺寸的能力远远好于判断距离的能力。

Size to Depth,根据画面内物体的size信息推测深度。具体过程首先是把图片分割成小块(pitch)为每个pitch设定一个size,这个size由人工标注,size的值为pitch中的主要物体(dominant component)的实际大小,最后用CRF进行平滑。
CRF的研究不算多,可能是因为CRF的复杂度比较高而且会影响到输出size的原因。
Loss
上面公式为文章使用的energy function,其中第一部分的目标是缩小预测值与标记值的差异,第二部分是consistency约束。

Monocular Depth Estimation 6

  1. 入门篇:图像深度估计相关总结
  2. 应用篇:Learning to be a Depth Camera
  3. 尺度篇:Make3D
  4. 迁移篇:Depth Extraction from Video Using Non-parametric Sampling
  5. 深度篇:David Eigen
  6. 无监督篇:Left-Right Consistency & Ego Motion
  7. 相对深度篇:Depth in the Wild & Size to Depth
  8. SLAM辅助篇:MegaDepth
  9. 方法比较篇:Evaluation of CNN-based Methods

单目图像深度估计 - 6. 无监督篇:Left-Right Consistency & Ego Motion

近几年有关单目图像深度识别的算法以CNN为主流,更细的说是以无监督的同时对深度、计算机角度、光流等同时计算的端到端深度网络为主流。
所谓无监督其实是指在训练过程中不需要输入真实的深度值,这样做有一个好处就是目前能够测量到深度信息的传感器还不够精确,因此由不够精确的label训练出的model得到的预测结果必然不会特别令人满意;
所谓同时计算呢,在我理解是指在训练过程中,用一个能够表征时间序列上有前后关系的帧之间的差别的loss同时训练多个网络,而在得到model后每个网络可以单独使用。
很聪明,不同作用的网络相当于人为的特征提取过程,最后的预测基于这个人为的特征提取结果,但这种方法也有其缺点,我能想到的就是参数的增加,网络结构的复杂化和人为特征对最终预测结果有没有起引导作用只能用实验去证明。

详细说呢,首先,所谓的“无监督”虽然不需要输入真实深度信息,但需要输入双目摄像头获取到的同一时刻不同角度的图像或者前后帧图像,只是这样就叫做无监督在我看来略显牵强。
其次,关于多网络共同训练,本来深度网络就很难解释,复杂化网络的结构得到多个看似可以解释的子网络,是否和深度网络的端到端黑盒特性有所冲突?较重的人为干涉是不是反而影响深度网络对数据隐含知识的理解和抽取?
以上只是我个人的一些思考,希望在未来的学习过程中能得到一些答案。


UnSupervised Learning of Depth and Ego-Motion from Video,CVPR,2017

接下来写一下Google发表于CVPR2017的这篇文章,从题目可以看出这篇文章提出了一种非监督的多功能网络,主要思想就像之前提到过的用一个loss同时训练两个网络。网络的结果如Fig.2,其中第一个网络可接受一幅图片作为输入,输出其对应的深度图片;第二个网络为姿态网络,接受t,t+1和t-1三个时刻三幅图片作为输入,输出从t到t+1和从t到t-1的相机姿态变化矩阵。
关于Pose的部分我不很了解,所以主要说明一下Depth CNN网络和Loss的结构。

Depth CNN
Model Architecture
基本结构见上图,输入为前中后三帧连续的图片,同时训练两个网络,一个得到深度预测结果,一个得到视差矩阵结果。
Model Architecture
其中视差网络用到了深度预测网络的预测结果。应用结构与DisNet相同的网络作为深度估计的网络,DispNet拥有主流的encoder-decoder结构,下一步打算看一下DispNet的相关Paper,因此在这不多介绍。作者提到使用多视角的图片训练深度预测网络结果和单张图片效果没有很大差异,说明光流约束需要在对多视角图片进行有效利用的前提下使用。

Loss
Loss
由Eq.4可见,Loss分为三个部分。其中第一部分为sample和target的差别,第二部分为多尺度平滑参数,第三部的目的是为了避免Es趋于0。


UnSupervised Monocular Depth Estimation with Left-Right Consistency, CVPR, 2017

这篇Paper主要思想为使用双目摄像头得到的同一时刻的两幅图片(left,right)进行训练,得到由left生成right(或right生成left)的网络,然后根据生成的双目图片得到depth。那所谓的无监督是指不需要ground truth depth,只需要双目图片。这种方法的好处是避免了深度测量硬件本身的误差,作者提出现有的深度测量硬件比如雷达、红外相机、TOF相机等本身就有误差,而且具有有效范围的限制,对比看来摄像头或双目摄像头硬件技术更为成熟,误差也会更小,因此在此基础上训练出来的网络应该有更好的精度。

目前也有类似的由左图生成右图的方法,但本位方法的改进就在于提出了一种left-right consistency,在训练过程中不仅限制由左图到右图的连续性,同时也限制右图到左图的连续性。
Method Compare
上图为几种方法的比较,可以看出Naive方法的输出只受target影响,而NoLR方法的输出受左右图同时的影响,本文方法则在NoLR的基础上增加了左右连续性限制。

Loss
上图为文章的主要创新点:左右一致性Loss。这个Loss可以同时考虑到左右视差一致性、平滑性、重建效果。
Loss Architecture
Loss公式表示如上图,可见Loss分为三部分:

  • 第一部分为与input的相似性
  • 第二部分为平滑性约束
  • 第三部分为左右一致性约束

CNN网络的结构夜视基于DispNet在此不再说明。

总结

这两篇文章都是基于无监督的方法,但说是无监督又有点牵强,但我认为无论在那个研究领域,无监督都是最终的目标,毕竟label总有不可靠的概率,自我学习和纠正能力才是人工智能具有智能的真正标志。
两种方法都用到了DispNet,是不是可以说明现有的CNN模型结构完全可以胜任大部分计算机视觉任务呢?
很多CV相关的Paper中的网络结构总结起来有以下几种情况:

  • 使用已有网络训练好的参数初始化
  • 使用已有网络的结构
  • 使用已有网络中的一部分
    其中已有网络指VGG,ResNet,DispNet,LeNet等等。

Monocular Depth Estimation 5

  1. 入门篇:图像深度估计相关总结
  2. 应用篇:Learning to be a Depth Camera
  3. 尺度篇:Make3D
  4. 迁移篇:Depth Extraction from Video Using Non-parametric Sampling
  5. 深度篇:David Eigen
  6. 无监督篇:Left-Right Consistency & Ego Motion
  7. 相对深度篇:Depth in the Wild & Size to Depth
  8. SLAM辅助篇:MegaDepth
  9. 方法比较篇:Evaluation of CNN-based Methods

单目图像深度估计 - 5. 深度篇:David Eigen的两篇研究

终于写到了目前比较主流的深度学习方法。随着大规模的数据集的出现以及硬件运算能力的提高,数据驱动的方法开始在计算机视觉、自然语言理解等领域发光发热。David Eigen可以说是第一个把深度学习方法用于单目图像深度估计的人,他提出的多尺度CNN网络到现在仍然在被引用和对比。这篇笔记就写一下Eigen的两篇经典论文:
[1] Depth Map Prediction from a Single Image using a Multi-Scale Deep Network,NIPS 2014. Project Page
[2] Predicting Depth, Surface, Normals and Semantic Labels with a Common Multi-Scale Convolutional Architecture,ICCV 2015 Project Page
从题目可以看出,第一篇Paper侧重于单目图像深度估计的任务中多尺度深度网络的应用,第二篇Paper主要内容为提出一个通用的网络可以解决单目深度估计、语义分割和法向量预测三个Task。从网络结构来看,第二篇提出的网络是在第一篇Paper中提出的网络的基础上进行的微调,同时也对loss进行了小小的调整,但整体改动不大。因此这篇阅读笔记也重点记一下第一篇Paper。

Depth Map Prediction from a Single Image using a Multi-Scale Deep Network


从2维推导出3维其实是一个ill-posed的Task,因为在拍摄照片即从三维(现实世界)到二维(照片)的过程中,信息的丢失是不可逆的。然而在计算机视觉相关的任务中,深度信息的增加可以提高相应算法的识别率,比如图像分割、识别等,而这些计算机视觉方法所代表的能力(比如环境感知)往往是机器人等热门AI技术所需要的。因此能否利用大规模的已有数据去训练深度网络使其可以对缺失的三维信息进行估计的研究具有很重要的现实意义。

网络结构

文章中提出了一个多尺度的混合网络,网络具有两个部分,分别为:

  1. 一个全局粗网络(coarse-scale network):在全局的level对整幅图像的深度进行初步预测,全局信息通过全连接层实现,粗网络得到的结果分辨率较小,因此需要进一步优化。
  2. 一个局部精网络(fine-scale network):在粗网络的预测结果基础上,结合原始输入图片的局部信息对预测结果进行进一步优化。
    网络结构如下图所示:
    Model Architecture

第一部分为全局粗网络,深度估计与其他Task的一个区别就是全局性,人类在确定深度的时候就用到了很多全局特征,比如消失点、物体位置、遮挡关系等等(这些在入门篇中有相关介绍),而其他Task比如人脸识别,可能更重要的是找到某一局部的特征。因此在全局的层面上对深度进行预测是比较重要的一个环节。
全局粗网络包括7层,其中前5层为卷积和最大池化层,后两层为全连接层。输入图像的尺寸为304X228(NYU_Depth_v2图像的原始尺寸为640X480,此处先对图像进行了参数为2的下采样,然后裁剪掉了部分边界),输出图像的尺寸为74X55,即原图的四分之一。
除了粗精度网络的最后一层使用线性函数,所有隐藏层都使用Relu(rectified linear units)激活。其中有一些tricks,比如引用了一种自学习upsampling,可自主学习图像边界;粗网络和细网络的训练不同步进行,训练好了粗网络后将参数固定再训练细网络;在Layer6有dropout操作,1到5层使用在ImageNet数据集上预训练得到的参数进行初始化等。

第二部分为细网络,其中fine layer1进行了池化操作形成74X55大小的特征图stack,这个大小正好和粗网络的输出一致,因此在fin layer2可以将粗网络的输出作为一个feature map输入。为保持图像大小不变,后续的两层卷积层都进行的是0填充(zero-padded,用0填充边界使卷积后的结果大小不会改变)卷积。

在网络训练的过程中,用到了数据增加和异常点排除的Tricks。

  • Data Augmentation:这是数据驱动的深度学习方法都需要的一步,由于深度网络的训练过程需要大量的数据,越大越好,因此对已有的数据进行缩放、旋转、随机裁剪、色彩改变、翻转等操作,可有效增加训练数据量,提高网络识别正确率。
  • 在NYU_Depth数据集中,由于硬件的原因,部分数据点的深度数据是缺失的,作者使用mask来标记这些缺失的点,并且采用直接下采样的方法使缩小尺寸后的图像和mask仍然具有对应关系,因此可以在训练过程总过滤掉数据缺失的点。
Scale-Invariant Error & Training Loss

文章的另一创新点为尺度不变损失函数,公式如下:
eq1
其中:
eq2
对任意尺度的深度预测结果y及对应的真实深度图y*来说,得到的error是一样大的,因此体现其尺度不变性。如果用d表示log空间中预测值和实际值的差异,上述公式可写作:
eq3
由此可得到Training Loss如下,其中参数λ为0到1之间的值,当λ等于0时l2error不对loss进行影响:
eq4

以上就是NIPS 2014这篇Paper的主要内容,在实验部分,作者在NYU和KITTI两个数据集都进行了实验,取得了比较好的结果。但这种方法存在以下缺点:

  1. 输出的预测结果很小,只为原始输入图像的四分之一
  2. 边界仍然不够清晰,且四个角点有明显的错误点
  3. 在室内数据集上训练得到的网络只适用于室内图片的预测
    以上三点也是大部分深度方普遍存在的缺点。

Predicting Depth, Surface Normals and Semantic Labels with a Common Multi-Scale Convolutional Architecture


这篇文章的主要创新点在于用一个结构通用(不同任务只需要改动参数)的网络可进行三种不同的Task并且得到令人满意的结果。但我们的关注点在单目图像深度估计这一部分,因此关于法向量估计和图像语义分割的部分就不写在这篇笔记中了。
这篇文章的网络结构在上一篇基础上进行了一些改进,但先粗后细的思想仍然没变,改进后的网络结构如下图:
Model Architecture
由图可见,网络结构由两部分变为了三部分,并且网络的层数有所增加。与文献[1]不同的是:

  1. 增加了Scale3使输出图片的大小扩大至输入图像的二分之一。
  2. 新提出的网络(DNL)中,coarse网络不再将预测结果传输给fine网络,而是将多通道的feature maps传输给fine网络,使得coarse网络和fine网络可以同时训练。
  3. 粗网络提出了两种不同的网络结构(AlexNet和VGG),
    Training Loss也有相应的小改动,改动后的loss如下:
    Training Loss
    在尺度不变Loss的基础上增加了图像梯度的部分,这部分可使得在预测值和实际值接近的基础上其趋势也要接近。
    在训练的过程中,对coarse和fine网络同时进行训练,然后固定其参数训练scale3的网络。

从实验结果来看,改进后的网络在预测正确率和输出图片质量(大小)上均有所提高,同时VGG的效果好于AlexNet,因此作者提出在深度学习方法中,网络size对预测结果有很重要的影响。

Monocular Depth Estimation 4

  1. 入门篇:图像深度估计相关总结
  2. 应用篇:Learning to be a Depth Camera
  3. 尺度篇:Make3D
  4. 迁移篇:Depth Extraction from Video Using Non-parametric Sampling
  5. 深度篇:David Eigen
  6. 无监督篇:Left-Right Consistency & Ego Motion
  7. 相对深度篇:Depth in the Wild & Size to Depth
  8. SLAM辅助篇:MegaDepth
  9. 方法比较篇:Evaluation of CNN-based Methods

单目图像深度估计 - 4. 迁移篇:Depth Extraction from Video Using Non-parametric Sampling

Depth Extraction from Video
第四篇写一下Depth Extraction from Video Using Non-parametric Sampling这篇文章中的Depth Transfer方法。

不同于其他主流方法,Depth Transfer并没有训练出特定的识别模型,而是通过把有标签数据与待预测样本进行点到点的对应,然后将深度信息进行迁移,形成深度估计结果。虽然诸如处理时间长、受训练集影响大等缺点十分显而易见,但这种思路仍然让人眼前一亮。其实如何能更好的利用有标签数据也是值得研究的方向,尤其是现在,深度网络的可解释性不高,我们不能确定拿到黑盒子里去训练一定能对宝贵的有标签数据进行有效利用,那不如换个方法。

言归正传,文章中提到Depth Transfer方法既能应用于单幅图像的深度估计,也能应用于视频的深度估计。显然,视频比图像多了时间前后文关系,因此文章的亮点就是如何利用有标签数据集和视频的前后文关系对图像的深度进行估计。

Depth Transfer
Fig.1

如Fig.1所示,算法主要分为三个步骤:

  1. 在RGBD数据集中寻找与input相似的多幅图片
  2. 通过将选出的相似图片(candidates)形变使其与input对应,得到input的初步深度估计结果
  3. 对step2的结果进行全局优化,得到最终pixel level的深度估计

图像深度估计

相似的场景会对应相似的深度,Depth Transfer方法建立在这个基础之上。

candidate的选取

  1. 首先,计算input及有标签数据集中每幅图像(或视频中的每帧图像)的GIST特征和光流特征信息;
  2. 然后,将input与数据集中的图像进行比较,选取K(=7)个最接近的匹配作为candidate。在这个过程中,限制数据集中同一video内的帧只能选取一个,以保证选出来的candidate有一定的变化;
  3. 最后,调用SIFT flow算法将input与candidate进行像素级的对应。SIFT flow算法为每个candidata产生一个对应方法(wraping function),wraping function将candidate的像素位置与input的像素位置相对应。

优化深度估计
通过选取和wraping,为input产生了K(candidate个数)个像素级的深度估计结果,接下来讲解如何利用所有预测结果对深度估计进行优化。

Eq1
Eq.1

Eq.1为Depth Transfer方法的Loss,通过最小化Loss可以得到最优估计。其中L为input图像,D为深度估计结果,Z为概率归一化常数,alpha=10,beta=0.5。
E(D)包含三部分,其中Et表示数据特性,Es表示平滑特性,Ep表示数据集特性。

Eq2
Eq.2

Et可用来衡量深度估计D与每个wrap后的candidate深度的相似性,其中Phi为L1范式。公式第二部分是为了最小化x,y两个方向的梯度差异。

Eq3
Eq.3
Eq4
Eq.4

Eq.3和Eq.4分别为Es和Ep的计算方法,其中Prior P为数据集中全部图像的均值。

视频深度估计

视频比单幅图像多了时间前后文关系,因此在对视频的深度估计进行优化时,在Eq.1的基础上增加了Ec和Em两部分,以保证:

  1. 物体深度在时间上是连续的;
  2. 运动物体的深度与其接地点一致。

Eq5
Eq.5
Eq6
Eq.6
Eq7
Eq.7

其中,Ec为时序关系,Em为运动线索。通过计算同一时间序列上有前后关系的每两张图片的光流变化控制其时序连续性。
同时,对视频中的运动物体进行检测提取并对其进行接地约束(运动物体与地面接触),在此过程中通过判断pixel和背景的差别来检测运动的物体。

总结和思考

Depth Transfer的缺点是处理时间较长(每帧图片需要1分钟)并且受有标签数据集影响大(当数据集包含较多图像时搜索时间成倍增长),优点是对运动物体的深度估计有很好的效果,因此比较适用于电影2D转3D等主要物体比较明确的场景。
这篇文章非常长,因为包括了方法的介绍、数据集的介绍以及非常丰富的实验对比,还有很长的附加文档。之所以挑出这篇来写,是因为我在那么多深度网络的图像处理论文里总觉得自己要迷失了,总是思考一直对一个黑盒子进行微调到底是不是正确的方法,而这片文章正好给了一个全新的思路。有时候规律是潜藏的,我们没有发现之前总觉得它不存在,假若我们的生活场景能够分解成特定的几种模式的话,只要用比较简单的寻找-对应就可以进行一切估计了。

[1] Karsch K, Liu C, Kang S B. Depth Extraction from Video Using Non-parametric Sampling[C]// European Conference on Computer Vision. Springer, Berlin, Heidelberg, 2012:775-788.

Monocular Depth Estimation 3

  1. 入门篇:图像深度估计相关总结
  2. 应用篇:Learning to be a Depth Camera
  3. 尺度篇:Make3D
  4. 迁移篇:Depth Extraction from Video Using Non-parametric Sampling
  5. 深度篇:David Eigen
  6. 无监督篇:Left-Right Consistency & Ego Motion
  7. 相对深度篇:Depth in the Wild & Size to Depth
  8. SLAM辅助篇:MegaDepth
  9. 方法比较篇:Evaluation of CNN-based Methods

单目图像深度估计 - 3. 尺度篇:Make3D

Make3D

终于进行到第三篇,这次膜拜一下单目图像深度识别的经典方法:Make3D(Website)。 Make3D方法经典的原因有二,其一是相关论文Learning Depth from Single Monocular Images发表于2005年,是我找到的最早的一篇单目图像深度识别的论文;其二是近期的许多研究在论文中都将自己的方法与Make3D进行了对比。这篇博客主要整理一下2005年发表于NIPS的这篇文章内容和我的相关理解。

上一篇文章中提到过,想要对深度进行估计,不能仅仅依靠局部特征(local features)还需要全局信息(global context)。举个例子,一个蓝色的像素点或一小块蓝色的图像区域,仅仅依靠其本身的信息无法判断它是属于一个蓝色的物体还是属于蓝色的天空。文中提到,人类对深度进行预测时也用到了全局特征如纹理变化,结构变化,轮廓遮挡,已知物体大小,模糊和失焦等。因此,想进行更加准确的深度预测,重要的是如何提取并利用全局信息

多尺度图像

为什么多尺度信息可以作为全局信息应用呢?这就需要说一下什么是尺度以及图像的多尺度性质了。以下引用于互联网:

在一幅图像中,只有在一定的尺度范围内,一个物体才有意义。举一个例子,树枝这个概念,只有在几厘米到几米的距离去观察它,才能感知到它的确是树枝;如果在微米级或者千米级去观察,就不能感知到树枝这个概念了,这样的话可以感知到的是细胞或者是森林的概念。因而,如果想要描述现实世界的结构,或者将三维物体映射到二维的图像上去,多尺度表示将会至关重要。多尺度表示的概念很容易理解,举例说明,绘制地图时会有比例尺的概念。世界地图中就只能够显示大洲大洋,以及较大的地域和国家;而一个城市地图,甚至可以详细的显示出每条街道。

图像的多尺度性质,类似于人的眼睛观察物体,在离物体的距离不同时,所感知的特征是不一样的。也就是同一物体在视场中,成像的大小不同时,也就是尺度不同时,表现出的特征不相同。

读研时候接触过遥感图像的多尺度分割,在我理解,大的尺度分割即将图像分为数量较少的大面积区域,小的尺度分割即为将图像划分成数量较多的小面积区域。因此,若是一副图像包含大海、沙滩和一把放置在沙滩上的躺椅,在某一较大尺度将图像分为两部分,分别为沙滩和海面,那么在这一尺度上无法找到躺椅;同理,在某一较小尺度下,将图像分为躺椅、多块海浪、平静海面、背光沙滩、受光沙滩等好几部分,则无法获得完整的大海区域。扯一句题外话,多尺度分割的一个优势是存在一种分级结构,即总是在分割结果的基础上进行合并或进一步分割,因此分割区域间不存在重叠,使得后续处理和计算可以更快速。

在图像的高斯金字塔或降采样形成的金字塔中,由顶到底尺度减小,因此在高斯金字塔的顶端图线上提取到的信息可视作全局信息。举个例子,我们取一个图像区域相邻的上、下、左、右四个区域作为其邻居,这四个邻居的像素均值作为此区域的一个特征,那么在原始图像上这五个图像区域可能都为某一物体的一部分,而在高尺度的图像上,相邻的区域可能为不同的物体。

Make3D方法

Make3D方法中,将局部信息和多尺度全局信息组合成特征向量,然后应用MRF方法进行深度估计。选取MRF方法是因为MRF适用于局部特征不够需要用到全局特征的情况,MRF的常见应用有物体识别、文本分割、图像打标等。

其中局部信息和全局信息用不同空间尺度(scales)即图像分辨率(image resolution)上的特征表示。Make3D方法还创新的提出了一种列特征(Column Feature),由于室外图像中大部分物体如树、楼房等都具有竖直的结构,即物体应“站立”在地面上而不是悬浮在空中,因此文章选取了每个小区域(patch)竖直方向上下多个相邻区域计算其列特征。

文章将图像划分成多块(patch),并将每一块的特征分为绝对深度特征(Absolute Depth Feature)和相对深度特征(Relative Depth Feature)。其中,绝对深度特征是指单个patch的深度,相对深度特征是指两个patch之间的差异。绝对深度特征的获取方法如下图:

Feature Vector
Fig.2 Absolute depth feature

Fig.2的上部分为Make3D方法使用的卷积mask,从左到右,前9个为Law’s mask(Law’s texture energy in TEXTURE)其中第一个用于提取模糊特征;后六个用于边界检测。Fig.2的下半部分说明了特征向量的组成以及多尺度特征和列特征的图示说明。由图可见,单个patch的特征由三个不同尺度的特征和一个列特征组成,而patch间的相对特征由直方图的差异表示。因此,某个patch的特征向量为:((1+4)*3+4)*34=646维(自身加上四个邻居在三个尺度上的特征,加上4个列特征;17个Law’s mask结果的1次和2次能量计算)。另外,相对深度特征的计算方法为:每个patch计算17维的mask结果,并且由每一个结果图生成10列的直方图得到170个特征后做差计算。

得到特征向量后,构建概率模型并且通过求取最大后验概率得到模型参数。文章构建了两种模型分别为高斯模型(Fig.3)和拉普拉斯模型(Fig.4)。

Gaussian
Fig.3 Gaussian
Laplacian
Fig.4 Laplacian

公式的前半部分可最小化预测值与实际深度值之间的差异,后半部分为平滑性约束即最小化不同尺度上相邻patch的差异。由于高斯模型无法生成边界清晰的深度预测结果,因此引入拉普拉斯模型。通过求解凸优化问题得到最优解,实现深度预测,Make3D方法的实验结果见下图。

Experiment1
Fig.5
Experiment2
Fig.6

Fig.5和Fig.6为实验结果,Fig.5中从左到右分别为实际图像、实际深度、高斯结果和拉普拉斯结果,Fig.6为应用不同特征进行计算的结果对比,可以看出拉普拉斯方法较优。

总结和思考

Make3D方法的经典不用多说,值得思考的是算法中应用全局特征的方法,近期的研究如多尺度CNN等也用多尺度来表示一种全局方法,但是要想接近人类的深度识别,我们不光要考虑到局部特征和全局特征,还要考虑到过往经验和知识。因此,如何将知识应用到深度识别中去是另一个值得研究的方向。