Skip to content

博客

相机坐标

图像处理、立体视觉等等方向常常涉及到四个坐标系:世界坐标系、相机(摄像机)坐标系、图像坐标系、像素坐标系:

通过如下图的转换,可以将世界坐标中点的坐标(Xw, Yw, Zw),同二维图像中的像素坐标(u,v)对应起来。

  • 像素坐标系

摄像机采集的数字图像在计算机内可以存储为数组,数组中的每一个元素(象素,pixel)的值即是图像点的亮度(灰度)。在图像上定义直角坐标系u-v,每一象素的坐标(u,v)分别是该象素在数组中的列数和行数。故(u,v)是以象素为单位的图像坐标系坐标。

  • 图像坐标系

由于(u,v)只代表像素的列数与行数,而像素在图像中的位置并没有用物理单位表示出来,所以,我们还要建立以物理单位(如毫米)表示的图像坐标系x-y。用(x,y)表示以物理单位度量的成像平面坐标系的坐标。在x-y坐标系中,原点定义在摄像机光轴和图像平面的交点处,称为图像的主点(principal point),该点一般位于图像中心处。

假设(u0,v0)代表O1在u-v坐标系下的坐标,dx与dy分别表示每个像素在横轴x和纵轴y上的物理尺寸,则图像中的每个像素在u-v坐标系中的坐标和在x-y坐标系中的坐标之间都存在如下的关系:

$$ \begin{cases} u = \dfrac{x}{d_x} + u_0 \ v = \dfrac{y}{d{y}} + v_0 \end{cases}\tag{1} $$

用齐次坐标与矩阵形式表示为:

$$ \begin{bmatrix} u \ v \ 1 \end{bmatrix} = \begin{bmatrix} \dfrac{1}{d_x} & 0 & {u_0} \ 0 & \dfrac{1}{d_y} & {v_0} \ 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} x \ y \ 1 \end{bmatrix}\tag{2} $$

这样,就建立了图像中,像素坐标和物理尺寸坐标之间的对应关系。

  • 相机坐标系

相机坐标系 (Xc,Yc,Zc)中,原点 为相机透镜的中心,坐标轴 Xc 轴与 x 轴平行,Yc 轴与 y 轴平行,Zc 轴与相机光轴重合。从相机坐标系到图像坐标系,属于透视投影关系,从3D转换到2D。

设相机的焦距为 f,则根据小孔成像模型,可知相机坐标系下空间点 (Xc,Yc,Zc),与物理尺寸坐标 (x,y) 的关系如下:

$$ \begin{cases} \dfrac{x}{f} = \dfrac{X_c}{Z_c} \ \dfrac{y}{f} = \dfrac{Y_c}{Z_c} \end{cases}\tag{3} $$

$$ \begin{cases} Z_c \cdot x = f \cdot {X_c} \ Z_c \cdot y = f \cdot {Y_c} \end{cases}\tag{4} $$

$$ Z_c \begin{bmatrix} x \ y \ 1 \end{bmatrix} = \begin{bmatrix} f & 0 & 0 & 0 \ 0 & f & 0 & 0 \ 0 & 0 & 1 & 0 \end{bmatrix} \begin{bmatrix} X_c \ Y_c \ Z_c \ 1 \end{bmatrix}\tag{5} $$

由(2)和(5),可以得到像素坐标 (u,v) 与相机坐标点 (Xc,Yc,Zc) 的关系为:

$$ Z_c \begin{bmatrix} u \ v \ 1 \end{bmatrix} = \begin{bmatrix} \dfrac{1}{d_x} & 0 & u_0 \ 0 & \dfrac{1}{d_y} & v_0 \ 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} f & 0 & 0 & 0 \ 0 & f & 0 & 0 \ 0 & 0 & 1 & 0 \end{bmatrix} \begin{bmatrix} X_c \ Y_c \ Z_c \ 1 \end{bmatrix} = \begin{bmatrix} \dfrac{f}{d_x} & 0 & u_0 & 0 \ 0 & \dfrac{f}{d_y} & v_0 & 0 \ 0 & 0 & 1 & 0 \end{bmatrix} \begin{bmatrix} X_c \ Y_c \ Z_c \ 1 \end{bmatrix}\tag{6} $$

  • 世界坐标系

在环境中还选择一个参考坐标系来描述摄像机和物体的位置,该坐标系称为世界坐标系。摄像机坐标系和世界坐标系之间的关系可用旋转矩阵R与平移向量t来描述。由此,空间中一点P在世界坐标系和摄像机坐标系下的齐次坐标分别为和且存在如下关系:

$$ \begin{bmatrix} X_c \ Y_c \ Z_c \ 1\end{bmatrix} = \begin{bmatrix} R & T \ 0^{T} & 1 \end{bmatrix} \begin{bmatrix} X_w \ Y_w \ Z_w \ 1 \end{bmatrix}\tag{7} $$

其中,R是3×3的正交单位矩阵(也成为旋转矩阵),T是三维的平移向量

所以,由(6)和(7)可以得到像素点(u,v)到世界坐标点的转换关系:

$$ Z_c \begin{bmatrix} u \ v \ 1 \end{bmatrix} = \begin{bmatrix} \dfrac{f}{d_x} & 0 & u_0 & 0 \ 0 & \dfrac{f}{d_y} & v_0 & 0 \ 0 & 0 & 1 & 0 \end{bmatrix} \begin{bmatrix} R & T \ 0^{T} & 1 \end{bmatrix} \begin{bmatrix} X_w \ Y_w \ Z_w \ 1 \end{bmatrix}\tag{8} $$

其中:

$$ \begin{bmatrix} \dfrac{f}{d_x} & 0 & u_0 & 0 \ 0 & \dfrac{f}{d_y} & v_0 & 0 \ 0 & 0 & 1 & 0 \end{bmatrix} 是相机的内参 $$

$$ \begin{bmatrix} R & T \ 0^{T} & 1 \end{bmatrix} 是相机的外参 $$

相机的内参和外参数可以通过张正友标定获得,OpenCV摄像相投标定教程。如果已知一个点的世界坐标,可以在图像中找到与其对应的像素点,但反之,则不能通过图像中的一个点找到它在世界坐标中对应的点,因为(8)中Zc未知。

相机内参数,由相机本身决定,只和相机本身有关。摄像头由于光学透镜的特性使得成像存在着径向畸变,可由三个参数k1,k2,k3确定。由于装配方面的误差,传感器与光学镜头之间并非完全平行,因此成像存在切向畸变,可由两个参数p1,p2确定。

单个摄像头的定标主要是计算出摄像头的内参(焦距f和成像原点cx,cy、五个畸变参数(一般只需要计算出k1,k2,p1,p2,对于鱼眼镜头等径向畸变特别大的才需要计算k3))以及外参(标定物的世界坐标)。

相机外参数,相机在世界坐标系中的位姿,由相机与世界坐标系的相对位姿关系决定。其参数有:旋转向量R(大小为1x3的矢量或旋转矩阵3x3)和平移向量T(Tx,Ty,Tz)。

conda管理Python环境

近期做一个项目的调研,需要使用到OpenCV、Python,这里记录anaconda进行Python环境配置管理过程。

  • virtualenv,用于在一台机器上创建多个独立的Python虚拟运行环境,多个Python环境相互独立,互不影响
  • pyenv, Python版本管理工具,可以方便的在多个Python版本之间进行切换
  • Anaconda,Anaconda是一个用于科学计算的Python发行版,支持 Linux, Mac, Windows系统,提供了包管理与环境管理的功能,可以很方便地解决多版本python并存、切换以及各种第三方包安装问题。Anaconda利用工具/命令conda来进行package和environment的管理,并且已经包含了Python和相关的配套工具。

conda可以理解为一个工具,也是一个可执行命令,其核心功能是包管理与环境管理。包管理与pip的使用类似,环境管理则允许用户方便地安装不同版本的python并可以快速切换。Anaconda则是一个打包的集合,里面预装好了conda、某个版本的python、众多packages、科学计算工具等等,所以也称为Python的一种发行版

Anaconda下载安装参见官网下载,支持Windows,macOS,Linux平台。

Conda环境管理功能允许同时安装多个不同版本的Python,并可以自由切换。

# 查看已经安装的环境
conda info -e
# 创建一个名为python34的环境,指定Python版本是3.4(不用管是3.4.x,conda会为我们自动寻找3.4.x中的最新版本)
conda create --name python34 python=3.4
# 安装好后,使用activate激活某个环境
activate python34 # for Windows source activate python34 # for Linux & Mac
# 激活后,会发现terminal输入的地方多了python34的字样,实际上,此时系统做的事情就是把默认2.7环境从PATH中去除,再把3.4对应的命令加入PATH
python --version
# 可以得到`Python 3.4.5 :: Anaconda 4.1.1 (64-bit)`,即系统已经切换到了3.4的环境
# 如果想返回默认的python 2.7环境,运行
deactivate python34 # for Windows source deactivate python34 # for Linux & Mac
# 删除一个已有的环境
conda remove --name python34 --all
# 查看当前环境下已安装的包
conda list
# 查看某个指定环境的已安装包
conda list -n python34
# 查找package信息
conda search numpy
# 安装package
conda install -n python34 numpy
# 如果不用-n指定环境名称,则被安装在当前活跃环境
# 也可以通过-c指定通过某个channel安装
# 更新package
conda update -n python34 numpy
# 删除package
conda remove -n python34 numpy

由于默认的安装源在国外,conda下载速度十分缓慢。可以使用清华大学TUNA镜像。 TUNA 还提供了 Anaconda 仓库的镜像,运行以下命令:

conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
conda config --set show_channel_urls yes

即可添加 Anaconda Python 免费仓库。

该配置保存在.condarc文件,也可以直接进行配置,Windows为C://Users/username/.condarc,Linux/Mac为~/.condarc。

channels:
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
- defaults
ssl_verify: true
show_channel_urls: true
Terminal window
$ conda config --remove channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
Terminal window
$ conda config --show
add_anaconda_token: True
add_pip_as_python_dependency: True
aggressive_update_packages:
- ca-certificates
- certifi
- openssl
allow_conda_downgrades: False
allow_cycles: True
allow_non_channel_urls: False
allow_softlinks: False
always_copy: False
always_softlink: False
always_yes: None
anaconda_upload: None
....

[Go]Deferred函数案例

package main
func main() {
println(DeferFunc1(1))
println(DeferFunc2(1))
println(DeferFunc3(1))
}
func DeferFunc1(i int) (t int) {
t = i
defer func() {
t += 3
}()
return t
}
func DeferFunc2(i int) int {
t := i
defer func() {
t += 3
}()
return t
}
func DeferFunc3(i int) (t int) {
defer func() {
t += i
}()
return 2
}

运行结果:

4
1
3

解析:

首先,只有在函数执行完毕后,这些被延迟的函数才会执行;其次,defer语句中的函数会在return语句更新返回值变量后再执行,而且函数中定义的匿名函数可以访问该函数包括返回值变量在内的所有变量。所以,DeferFunc1, DeferFunc3,分别返回4,3。DeferFunc2中因为defer中的匿名函数更新的是函数中变量t,不会影响返回值所以返回1。

Linux统计文件数量

统计当前文件夹下文件的个数,包括子文件夹里的

Section titled “统计当前文件夹下文件的个数,包括子文件夹里的”
Terminal window
ls -lR | grep '^-' | wc -l

统计当前文件夹下文件夹的个数,包括子文件夹下的

Section titled “统计当前文件夹下文件夹的个数,包括子文件夹下的”
Terminal window
ls -lR | grep '^d' | wc -l

统计当前文件夹下的文件夹个数

Section titled “统计当前文件夹下的文件夹个数”
Terminal window
ls -l | grep '^d' | wc -l
  • 方式一
Terminal window
ls -l | grep '^-' | wc -l
  • 方式二
Terminal window
find DIR_NAME -type f | wc -l

注:DIR_NAME指定的目录

Mac配置Selenium + Python3

Selenium也是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。支持的浏览器包括IE、Mozilla Firefox、Mozilla Suite等。这个工具的主要功能包括:测试与浏览器的兼容性——测试你的应用程序看是否能够很好得工作在不同浏览器和操作系统之上。测试系统功能——创建衰退测试检验软件功能和用户需求。支持自动录制动作和自动生成。Net、Java、Perl等不同语言的测试脚本。Selenium 是ThoughtWorks专门为Web应用程序编写的一个验收测试工具。

Mac OS 10.13.2中自带的Python版本是2.7,可以使用Anaconda使用管理环境,并可以方便的切换到Python3。

pip install selenium

Selenium3.0后,Firefox浏览器同其他浏览器一样都已经独立出来,必须要使用下载和配置浏览器驱动,而且浏览器和驱动的版本必须匹配,否则会出现各种诡异的错误。

归功于某些不可抗拒因素,下载谷歌相关联的包不是那么方便,需要的驱动可以在淘宝镜像上下载。

下载到ChromeDriver后,并将驱动的所在路径加入环境变量中。

编写一个简单的测试脚本,进入www.taobao.com

from selenium import webdriver
driver = webdriver.Chrome()
driver.get("https://cart.taobao.com")

执行脚本后会打开一个新增chrome浏览器,并进入淘宝首页。

1. ChromeDriver和Chrome的版本对应关系:

Section titled “1. ChromeDriver和Chrome的版本对应关系:”
ChromeDriver版本Chrome版本
v2.35v62-64
v2.34v61-63
v2.33v60-62
v2.32v59-61
v2.31v58-60
v2.30v58-60
v2.29v56-58
v2.28v55-57
v2.27v54-56
v2.26v53-55
v2.25v53-55
v2.24v52-54
v2.23v51-53
v2.22v49-52
v2.21v46-50
v2.20v43-48

附:ChromeDriver可以在下面的链接下载到:

http://chromedriver.storage.googleapis.com/index.html
// OR
https://npm.taobao.org/mirrors/chromedriver/

2. 在mac上使用webdriver调用chrome浏览器发生错误:

Section titled “2. 在mac上使用webdriver调用chrome浏览器发生错误:”
raise WebDriverException("Can not connect to the Service %s" % self.path)
selenium.common.exceptions.WebDriverException: Message: Can not connect to the Service chromedriver

修改办法,将 127.0.0.1 localhost添加到/etc/hosts配置文件中, 在终端中输入

Terminal window
sudo killall -HUP mDNSResponder

使hosts文件的更改生效。

注:解决办法来自github.com/SeleniumHQ