ubuntu 22.04系统Docker和Nvidia-docker的安装、测试,及运行GUI应用

快速搭建所需开发环境

Docker文档:https://docs.docker.com/,Docker安装指南: Install Docker Engine on Ubuntu

Dokcer安装

Docker测试

其他Docker命令:

Tips:Docker中一般Crtl+C退出,传送门:停止、删除所有的 docker 容器和镜像

Nvidia-docker安装

查看nvidia版本

参考链接:官网 installation guide
Github:NVIDIA/nvidia-docker

测试

Docker 容器 GUI

若遇到X Error时,添加参数:--ipc=host 或 --env="QT_X11_NO_MITSHM=1",参考链接:
How to fix X Error: BadAccess, BadDrawable, BadShmSeg while running graphical application using Docker?
Docker: gazebo: cannot connect to X server
若遇到 libGL error: No matching fbConfigs or visuals found libGL error... ,参考链接:
使用docker时出现libGL error: No matching fbConfigs or visuals found libGL error: failed to load driver...
已成功测试上述链接中的 pull image 方式
使用nvidia-smi查看nvidia driver和cuda版本,根据 nvidia/cudagl ,选择合适的TAG

创建新的长期镜像:

如果遇到如下报错:

上述报错目前没有找到很好的解决方法,应该是某个安装包意外修改了系统配置,导致出现问题,重装系统可以顺利解决此问题。

参考链接


像素坐标转世界坐标的计算

原理

下图表示了小孔成像模型(图片及公式参考 OpenCV官方资料

这个图里涉及4个坐标系:

  1. 世界坐标系:其坐标原点可视情况而定,可以表示空间的物体,单位为长度单位,比如MM(毫米),用矩阵$\begin{bmatrix} X_W \\ Y_W \\Z_W \end{bmatrix}$表示;
  2. 相机坐标系:以摄像机光心为原点(在针孔模型中也就是针孔为中心),z轴与光轴重合,也就是z轴指向相机的前方(与成像平面垂直),x轴与y轴的正方向与世界坐标系平行,单位为长度单位,比如MM(毫米),用矩阵$\begin{bmatrix}X_c \\ Y_c \\ Z_c\end{bmatrix}$表示;
  3. 图像物理坐标系(也叫成像平面坐标系):用物理长度单位表示像素的位置,坐标原点为摄像机光轴与图像物理坐标系的交点位置,单位为长度单位,比如MM(毫米),用矩阵$\begin{bmatrix}x \\ y \end{bmatrix}$表示。
  4. 像素坐标系:坐标原点在左上角,以像素为单位,有明显的范围限制,即用于表示全画面的像素长和像素长宽,矩阵$\begin{bmatrix}u \\ v \end{bmatrix}$表示。

以下公式描述了$\begin{bmatrix}u & v \end{bmatrix}^T$、$\begin{bmatrix}x & y \end{bmatrix}^T$、$\begin{bmatrix}X_c & Y_c & Z_c\end{bmatrix}^T$和$\begin{bmatrix}X_W & Y_W & Z_W \end{bmatrix}^T$之间的转换关系。

$z\begin{bmatrix}u \\ v\\ 1 \end{bmatrix}= \begin{bmatrix}1/d_x&0&c_x\\0&1/d_y&c_y\\0&0&1 \end{bmatrix} \begin{bmatrix}f&0&0\\ 0&f&0\\ 0&0&1 \end{bmatrix} \begin{bmatrix}r11&r12&r13&t1\\ r21&r22&r23&t2\\ r31&r32&r33&t3 \end{bmatrix} \begin{bmatrix}X_W \\ Y_W \\Z_W \\ 1\end{bmatrix}$

以上公式中,$d_x$和$d_y$表示1个像素有多少长度,即用传感器的尺寸除以像素数量,比如2928.384um * 2205.216um的传感的分辨率为2592 * 1944,每个像素的大小即约1.12um。

由于相机与物体的视角来看,都是三维坐标,因此两者之间的变换只需要进行矩阵的旋转、平移即可达到坐标系转换的目的(不同坐标系中,物体的绝对大小并不会随着坐标系的变化而变化,因此不涉及缩放处理)。对于变换矩阵  $\begin{bmatrix}r11&r12&r13&t1\\ r21&r22&r23&t2\\ r31&r32&r33&t3 \end{bmatrix}$ 需要理解,矩阵是由 3*3 的旋转矩阵 r (rotation) 和 3*1的平移向量 t (translation)组成。

$f$表示焦距,在上图中,根据相似三角形,P点和p点具有以下关系:

$\frac{X_c}{x} = \frac{Y_c}{y} = \frac{Z_c}{f}$ 即$x=X_c/(\frac{Z_c}{f})$ $y=Y_c/(\frac{Z_c}{f})$,可见:$f$越大,$x$和$y$越大,$Z_c$越大,$x$和$y$越小。

$c_x$和$c_y$表示中心点在像素坐标系中的位置。

要求像素坐标系中某像素点对应在世界坐标系中的位置,需要知道相机的内参、外参,相机的内参可以通过标定获得,外参可以人为设定。

第一步,将像素坐标变换到相机坐标系:

$z\begin{bmatrix}u \\ v\\ 1 \end{bmatrix} = \begin{bmatrix}f_x&0&c_x\\0&f_y&c_y\\0&0&1 \end{bmatrix} \begin{bmatrix}x \\ y\\ 1 \end{bmatrix} = K\begin{bmatrix}x \\ y\\ 1 \end{bmatrix}$

两边乘以K的逆后推导出:

$\begin{bmatrix}x \\ y\\ z \end{bmatrix}=K^{-1} \begin{bmatrix}u \\ v\\ 1 \end{bmatrix}$

第二步,从相机坐标系变换到世界坐标系:

$\begin{bmatrix}X_c \\ Y_c\\ Z_c \end{bmatrix} = R \begin{bmatrix}X \\ Y\\ Z \end{bmatrix} + t$

将方程乘以$R^{-1}$,可以推导出:

$\begin{bmatrix}X \\ Y\\ Z \end{bmatrix} = \begin{bmatrix}X_c \\ Y_c \\ Z_c \end{bmatrix}R^{-1} - t R^{-1}= z\begin{bmatrix}x\\ y\\ 1 \end{bmatrix}R^{-1} - t R^{-1}$

代码

通过输入相机的内参,旋转向量,平移向量和像素坐标,可以通过以下函数求出对应的世界坐标点。
以下代码中需求注意要对平移向量取转置,将1x3矩阵变为3x1矩阵后,才能实现3x3矩阵和3x1矩阵的乘法运算。

验证

先使用projectPoints生成像素点:

使用以下欧拉角:

对应的平移向量,表示空间坐标原点相对在相平面原点偏移x=134mm,y=132mm,z=200mm。

生成空间坐标点:

经projectPoints计算后对应的像素空间点是:

经函数求出的空间坐标点是:

可以对比按11*8格和30mm/格所生成空间坐标点结果,基本一致。

参考链接


摄像头和机械臂的手眼标定

一、背景

Calibration是机器人开发者永远的痛。虽然说方法说起来几十年前就有,但每一个要用摄像头的人都还是要经过一番痛苦的踩坑,没有轻轻松松拿来就效果好的包。其实人类不就是个手眼协调的先进“机器人”吗,O(∩_∩)O哈哈~

机器人视觉应用中,手眼标定是一个非常基础且关键的问题。简单来说手眼标定的目的就是获取机器人坐标系和相机坐标系的关系,最后将视觉识别的结果转移到机器人坐标系下。

手眼标定行业内分为两种形式,根据相机固定的地方不同,如果相机和机器人末端固定在一起,就称之为“眼在手”(eye in hand),如果相机固定在机器人外面的底座上,则称之为“眼在外”(eye to hand)。

eye to hand 眼在外
eye to hand 眼在外
eye to hand 眼在手
eye to hand 眼在手

二、手眼关系的数学描述

1. eye in hand,这种关系下,两次运动,机器人底座和标定板的关系始终不变。求解的量为相机和机器人末端坐标系的位姿关系。

2. eye to hand,这种关系下,两次运动,机器人末端和标定板的位姿关系始终不变。求解的量为相机和机器人底座坐标系之间的位姿关系。

手眼标定eye in hand 和eye to hand 的区别主要是机器人那边,一个是end相对于base,另一个是base相对于end。千万注意。

三、AX = XB问题的求解

旋转和平移分步法求解:

  • Y. Shiu, S. Ahmad Calibration of Wrist-Mounted Robotic Sensors by Solving Homogeneous Transform Equations of the Form AX = XB. In IEEE Transactions on Robotics and Automation, 5(1):16-29, 1989.
  • R. Tsai, R. Lenz A New Technique for Fully Autonomous and Efficient 3D Robotics Hand/Eye Calibration. In IEEE Transactions on Robotics and Automation, 5(3):345-358, 1989.

迭代求解及相关资料可以看看相关网上的英文教程 Calibration and Registration Techniques for Robotics 其中也有一些AX= XB的matlab代码可以使用。

ROS 下也有相关的一些package可以利用

四、其他参考资料

3D 视觉之手眼标定 邱强Flyqq 微信文章

手眼标定的两种方式_wzj5530的专栏-CSDN博客_手眼标定 图不错

深入浅出地理解机器人手眼标定_二毛的博客-CSDN博客_机器人手眼标定 部分halcon代码

eye-in-hand手眼标定系统_二毛的博客-CSDN博客 halcon代码

手眼标定之9点法_GoRunningSnail的博客-CSDN博客 部分原理

UR5、Kinect2手眼标定总结_zhang970187013的博客-CSDN博客 UR5 与easy hand eye

一般用“两步法”求解基本方程,即先从基本方程上式求解出旋转部分,再代入求解出平移部分。

经典手眼标定算法之Tsai-Lenz的OpenCV实现_YunlinWang的博客-CSDN博客

============== Halcon 官方示例-手眼标定 ==================

五、Matlab下手眼标定解算

相机与机器人是eye-to-hand模式,机器人为加拿大Kinova 6轴机械臂,机器人pose为基座相对于末端的x,y,z,rx,ry,rz,rw, 单位为米。姿态使用单位四元数表示。

2017.08.29Kinova_pose_all_8_1.txt

pattern pose为标定板相对于相机的x,y,z,rx,ry,rz,rw, 单位为米。姿态使用单位四元数表示。

2017.08.29Pattern_pose_all_8_1.txt

此Matlab文件调用数据进行离线解算。Calibration and Registration Techniques for Robotics 的这部分 Registering Two Sets of 6DoF Data with 1 Unknown,有code下载,下载好命名为shiu.m和tsai.m供下面程序调用就行。我这里贴出

Jaco_handeye_test_10.m 测试程序中用到了Peter Corke老师的机器人工具箱。我的Matlab版本R2013a,利用机器人工具箱的一些转换函数(四元数的构建,欧拉角转换等),它安装和基本使用参考这里:Matlab机器人工具箱_Learning by doing-CSDN博客_matlab机器人工具箱


稍微解释一下,程序做的就是读入机器人和相机的两两姿态信息,转换为4x4 的齐次变换矩阵,送入tsai.m程序求解。

手眼标定eye in hand 和eye to hand 的区别主要是机器人那边,一个是end相对于base,另一个是base相对于end。千万注意。

====================平面九点标定法====================

当利用RGB相机或者是机器人只进行平面抓取(也即固定姿态抓取,机器人六自由度位置和姿态简化为只考虑平移,姿态人为给定并且固定,这时机器人可以移动到目标点上方),问题可以简化为平面RGB图像的目标像素点集A(x1,y1)与机器人在平面(X1,Y1)的点对关系。具体做法是相机识别像素点给到A,然后利用示教器查看机器人在基座标系下的坐标,当做B。

相机坐标和机器人坐标写成齐次的形式,投影矩阵X是一个3x3的矩阵我们需要6组对应点来求解最小配置解。利用奇异值分解SVD来求取。

D:\opencv_work\cubeSolver\cv_solver\ConsoleApplication1\CV_SVD.cpp

D:\Matlab_work\handeye\NinePoints_Calibration.m

OpenCV: Operations on arrays

结果对比:左halcon C#(第三列为0,0,1,没做显示),右opencv c++,底下为Matlab结果,三者一致,算法检测通过。

=============

四轴平面机器人的手眼标定_Stones1025的博客-CSDN博客

这种方法利用点对,求仿摄变换矩阵

================= Eye in hand 数据及Ground truth =========================

Marker in Camera 八组数据,单位:米及弧度,姿态用的是RotVector表示

Robot end-effector in Base 八组数据,单位:米及弧度,姿态用的是RotVector表示

Ground truth:Camera in end-effector

参考链接


nvidia-smi GPU性能状态(Performance State)含义

我正在使用Nvidia GTX Titan X进行深度学习实验。
我正在使用nvidia-smi来监视GPU的运行状态,但是提供的工具的性能(性能)状态没有意义。

我已经查看了nvidia-smi手册,它表示以下内容:

Performance State
The current performance state for the GPU. States range from P0 (maximum performance) to P12 (minimum performance).

如果不在GPU上运行任何进程(空闲状态),则GPU性能状态为p0。
但是,当运行一些计算繁重的过程时,状态变为p2。

我的问题是,为什么我的GPU闲置时处于P0状态,但是在执行繁重的计算任务时切换到P2? 不应该相反吗?

另外,有没有办法使我的GPU始终在P0状态下运行(最高性能)?


令人困惑。

但是,nvidia-smi手册是正确的。

当一个或一组GPU处于空闲状态时,在计算机上运行nvidia-smi的过程通常会使其中一个GPU退出空闲状态。这是由于该工具正在收集的信息-需要唤醒其中一个GPU。

此唤醒过程最初会将GPU置于P0状态(最高性能状态),但如果GPU空闲或不是特别忙碌,GPU驱动程序将监控该GPU,并最终开始降低性能状态以节省功耗。

另一方面,当GPU在工作负载下处于活动状态时,GPU驱动程序将根据其自身的启发式方法不断调整性能状态以提供最佳性能,同时使性能状态与实际工作负载相匹配。如果没有达到热或功率限制,则对于最活跃和最重的连续工作负载,性能状态应达到最高水平(P0)。

周期性很重但不连续的工作负载可能会导致GPU功耗状态在P0-P2级别附近波动。由于热(温度)或电源问题而"受限制"的GPU也可能会看到P状态降低。这种限制是显而易见的,并在nvidia-smi中单独报告,但是可能并非所有GPU类型都启用这种报告。

如果要在GPU上查看P0状态,我可以提供的最佳建议是运行短暂,繁重且连续的工作负载(例如,执行大型sgemm操作的工作),然后在该工作负载期间监视GPU。在这种情况下应该可以看到P0状态。

如果您使用的是正在使用cuDNN库的机器学习应用程序(例如Caffe),并且正在训练大型网络,则应该可以不时看到P0,因为cuDNN会执行类似于sgemm的操作通常情况下。

但是对于零星的工作负载,最常见的状态很有可能是P2。

要始终"强制" P0电源状态,可以尝试通过nvidia-smi工具尝试持久性模式和应用程序时钟。使用nvidia-smi --help或nvidia-smi的手册页了解选项。

尽管我认为这通常不适用于Tesla GPU,但除非特别设置更高的应用时钟,否则某些NVIDIA GPU可能会在计算负载下将自身限制为P2功耗状态。使用nvidia-smi -a命令查看可用于GPU的当前应用程序时钟,默认应用程序时钟和最大时钟。 (某些GPU(包括较旧的GPU)可能会在其中某些字段中显示N / A。这通常表明应用程序时钟无法通过nvidia-smi进行修改。)如果在计算负载期间卡似乎以P2状态运行,则可能通过将应用程序时钟增加到最大可用时钟(即最大时钟),可以将其增加到P0状态。使用nvidia-smi --help了解如何格式化命令以更改GPU上的应用程序时钟。修改应用程序时钟或启用可修改的应用程序时钟可能需要root / admin特权。设置GPU持久模式也可能是理想的或必要的。这将防止驱动程序在GPU活动期间"卸载",这可能导致驱动程序重新加载时重置应用程序时钟。

对于这种情况下受影响的卡,此默认行为是在计算负载下限制为P2,这是由GPU驱动程序设计的。

参考链接


ubuntu 21.10(GeForce GTX 3060 12GB)编译StyleGAN3

安装驱动:

Anaconda 上建立独立的编译环境,然后执行编译:

参考 Anaconda conda切换为国内源  加速下载。

编译配置StyleGAN3

如果报错:

上述报错产生的原因是在 Anaconda 下载的包,在进行编译的时候,使用了高版本的 libstdc++.so。而运行时却使用了Anaconda 环境里低版本的 libstdc++.so 导致报错。

了解了原因,解决方法就比较简单了,可以手工升级 Anaconda 环境下的 libstdc++.so 动态库。

如下:

目前测试发现,当batch=4的时候会在第11天的时候报告OOM,如下:

参考链接


ImageNet(2010-2017)图像识别数据集

ImageNet 数据集是目前世界上图像识别最大的数据库,根据 WordNet 层次 结构 (目前仅限物体)组织,主要用于机器视觉领域的图像分类和目标检测。其中层次结构的每个节点由数百和数千个图像描绘,每个节点平均有超过 500 个图像,有大约 1500 万张图片,2.2 万类。 ImageNet 数据集于 2009 年由斯坦福大学的李飞飞等人在视觉科学学会(VSS)首次发布,而后自 2010 年起一年一度的 ImageNet 大规模视觉识别挑战(ILSVRC)挑战赛不断完善 ImageNet 数据集。

ImageNet.torrent  需要占用磁盘空间 860.55 GB

参考链接


在ubuntu 18.04(GeForce GTX 760 4GB显存)使用Pytorch Pix2PixGAN(CUDA-10.1)

1. 参照 pytorch 1.0.1在ubuntu 18.04(GeForce GTX 760)编译(CUDA-10.1) 建立 pytorch 1.0.1 的编译环境,并解决编译时遇到的问题。

2. 依旧是推荐在 Anaconda 上建立独立的编译环境,然后执行编译:

编译出错信息,参考 pytorch 1.0.1在ubuntu 18.04(GeForce GTX 760)编译(CUDA-10.1) 里面的介绍解决。

3. 编译安装 TorchVision

4. 检出 CycleGAN and pix2pix in PyTorch 的代码,并安装依赖

执行训练的时候,如果出现如下错误:

这个原因是由于 PyTorch 版本差异造成的,(作者在 Pytorch 0.4.1 版本上测试,我们在 Pytorch 1.0.1 版本上测试),执行如下命令修复:

5. 测试训练结果

参考链接


在ubuntu 18.04(GeForce GTX 760 4GB显存)使用MaskTextSpotter(CUDA-10.1)进行训练

参考 在ubuntu 18.04(GeForce GTX 760 4GB显存)编译/测试MaskTextSpotter(CUDA-10.1) 建立能运行的测试环境。

由于测试集使用的是 icdar2013 ,因此,务必保证已经可以在 icdar2013 数据集中进行测试。

接下来就是进行数据训练:

1. 修改训练脚本,默认情况下,训练脚本中使用了 8 张卡进行训练,我们只有一张卡,因此要调整训练参数

2. 下载训练集 MaskTextSpotter 默认使用的是 SynthText 数据集进行训练,需要先下载这个数据集,大约 40GB

3. 解压缩 SynthText 数据集到指定目录

4. 下载转换后的 SynthText 数据集索引文件,上面解压缩出来的索引是 .mat 扩展名的文件,我们需要转换成 MaskTextSpotter 需要的数据索引文件,作者提供了一份已经转换好的文件,我们直接下载并使用这个文件即可,这个文件大概要 1.6GB 的样子。

5. 生成训练文件 train_list.txt

执行脚本,生成文件

执行测试

注意,我们在 configs/pretrain.yaml 加载的权重文件是 "WEIGHT: "./outputs/finetune/model_finetune.pth" ,这个权重文件是从 SynthText 训练得来的,那么这个"model_finetune.pth"是怎么生成的呢?

作者没有详细介绍,我们从 masktextspotter.caffe2 项目的配置文件中可以知道,这个文件其实是从 " WEIGHTS: https://dl.fbaipublicfiles.com/detectron/ImageNetPretrained/MSRA/R-50.pkl" 开始生成的。这个文件也可以从本站下载 R-50.pkl

R-50.pkl: converted copy of MSRA’s original ResNet-50 model

具体配置文件内容参考如下:

其实我们直接删除或者注释掉权重文件加载部分也是可以的。只是,如果想要复现原作者的测试成果的话,我们最好使用相同的配置信息。

对于 4GB 显存的机器来说,由于显存非常有限,导致非常可能在运行的途中出现 "RuntimeError: CUDA out of memory." ,目前测试来看,继续执行命令即可。

训练结果存储在 outputs/pretrain 目录下,训练结果会在训练到一定阶段之后,存储到这个目录下。

如果出现类似如下错误,请适当减少学习速率 BASE_LR

参考链接


PyTorch运行时提示'ImportError: torch.utils.ffi is deprecated. Please use cpp extensions instead.'

在测试编译FOTS 的时候,出现如下错误:

最省事的情况是降级pytorch版本到0.4,强烈建议使用Anaconda创建独立的Python开发环境,然后在干净的环境中运行。

参考链接