vb.net - 从单应性中提取变换和旋转矩阵?

标签 vb.net opencv matrix emgucv homography

我有来自相机的 2 个连续图像,我想估计相机姿势的变化:
two pictures with camera movement

我计算光流:

Const MAXFEATURES As Integer = 100
imgA = New Image(Of [Structure].Bgr, Byte)("pic1.bmp")
imgB = New Image(Of [Structure].Bgr, Byte)("pic2.bmp")
grayA = imgA.Convert(Of Gray, Byte)()
grayB = imgB.Convert(Of Gray, Byte)()
imagesize = cvGetSize(grayA)
pyrBufferA = New Emgu.CV.Image(Of Emgu.CV.Structure.Gray, Byte) _
    (imagesize.Width + 8, imagesize.Height / 3)
pyrBufferB = New Emgu.CV.Image(Of Emgu.CV.Structure.Gray, Byte) _
    (imagesize.Width + 8, imagesize.Height / 3)
features = MAXFEATURES
featuresA = grayA.GoodFeaturesToTrack(features, 0.01, 25, 3)
grayA.FindCornerSubPix(featuresA, New System.Drawing.Size(10, 10),
                       New System.Drawing.Size(-1, -1),
                       New Emgu.CV.Structure.MCvTermCriteria(20, 0.03))
features = featuresA(0).Length
Emgu.CV.OpticalFlow.PyrLK(grayA, grayB, pyrBufferA, pyrBufferB, _
                          featuresA(0), New Size(25, 25), 3, _
                          New Emgu.CV.Structure.MCvTermCriteria(20, 0.03D),
                          flags, featuresB(0), status, errors)
pointsA = New Matrix(Of Single)(features, 2)
pointsB = New Matrix(Of Single)(features, 2)
For i As Integer = 0 To features - 1
    pointsA(i, 0) = featuresA(0)(i).X
    pointsA(i, 1) = featuresA(0)(i).Y
    pointsB(i, 0) = featuresB(0)(i).X
    pointsB(i, 1) = featuresB(0)(i).Y
Next
Dim Homography As New Matrix(Of Double)(3, 3)
cvFindHomography(pointsA.Ptr, pointsB.Ptr, Homography, HOMOGRAPHY_METHOD.RANSAC, 1, 0)

看起来是正确的,相机向左和向上移动:
optical flow
现在我想知道相机移动和旋转了多少。如果我声明我的相机位置以及它在看什么:
' Create camera location at origin and lookat (straight ahead, 1 in the Z axis)
Location = New Matrix(Of Double)(2, 3)
location(0, 0) = 0 ' X location
location(0, 1) = 0 ' Y location
location(0, 2) = 0 ' Z location
location(1, 0) = 0 ' X lookat
location(1, 1) = 0 ' Y lookat
location(1, 2) = 1 ' Z lookat

如何计算新位置和外观?

如果我做错了这一切或者如果有更好的方法,任何建议将非常受欢迎,谢谢!

最佳答案

那么你所看到的简单来说就是Pythagorean theorem problem a^2 + b^2 = c^2。然而,当涉及到基于相机的应用程序时,要准确确定事情并不容易。您已经找到了“a”所需的一半细节,但是找到“b”或“c”要困难得多。

简答

基本上它不能用单个相机完成。但它可以用两个摄像头完成。

冗长的答案 (我想我会更深入地解释,没有双关语意)

我会试着解释一下,假设我们在图像中选择两个点并向左移动相机。我们知道每个点 B1 与相机的距离为 20mm,点 B2 为 40mm。现在让我们假设我们处理图像并且我们的测量结果是 A1 是 (0,2) 和 A2 是 (0,4) 这些分别与 B1 和 B2 相关。现在 A1 和 A2 不是测量值;它们是运动的像素。

我们现在要做的是将 A1 和 A2 的变化乘以计算得出的常数,该常数将是 B1 和 B2 处的真实世界距离。注意:根据测量 B*,每一个都不同。这一切都与Angle of view有关或更普遍地称为不同距离摄影中的视野。如果您知道相机 CCD 上每个像素的大小以及相机内部镜头的 f 数,您就可以准确地计算出常数。

我希望情况并非如此,因此在不同的距离处,您必须放置一个您知道长度的对象并查看它占用多少像素。关闭时,您可以使用标尺使事情变得更容易。通过这些测量。您获取这些数据并形成一 strip 有最佳拟合线的曲线。其中 X 轴将是对象的距离,Y 轴将是像素与距离比率的常数,您必须乘以您的运动。

那么我们如何应用这条曲线。嗯,这是猜测工作。理论上,运动 A* 的测量值越大,物体离相机越近。在我们的示例中,A1 > A2 的比率分别为 5 毫米和 3 毫米,我们现在知道点 B1 移动了 10 毫米(2x5 毫米),而 B2 移动了 6 毫米(2x6 毫米)。但是让我们面对现实吧——我们永远不会知道 B,我们永远无法判断移动的距离是一个物体关闭的 20 个像素没有移动很远,还是远处的物体移动了很远的距离。这就是为什么像 Xbox Kinect 这样的东西使用额外的传感器来获取可以与图像中的对象相关联的深度信息的原因。

您可以尝试使用两个摄像头进行尝试,因为已知这些摄像头之间的距离可以更准确地计算运动(无需使用深度传感器即可有效)。这背后的数学非常复杂,我建议您查阅一些有关该主题的期刊论文。如果你想让我解释这个理论,我可以尝试。

我所有的经验都来自于为我的 PHD 设计高速视频采集和图像处理,所以相信我,这不能用一台相机完成,抱歉。我希望这会有所帮助。

干杯

克里斯

[编辑]

我打算添加评论,但由于大量信息,这更容易:

由于它是 Kinect,我将假设您有一些与每个点相关联的相关深度信息,否则您将需要弄清楚如何获得它。

您需要开始的方程式是针对视野 ( FOV ):

o/d = i/f

在哪里:

f 等于通常以 mm 为单位给出的镜头焦距(即 18 28 30 50 是标准示例)

d 是从 kinect 数据收集到的镜头的物距

Ø 是物体尺寸(或垂直于光轴并被光轴平分的“视场”)。

是图像尺寸(或垂直于光轴并被光轴平分的“视场光阑”)。

我们需要计算 , 其中 Ø 是我们的未知所以 (这是对角线测量),

我们将需要 ccd 上像素的大小,这将以微米或微米为单位,您需要找出这些信息,众所周知,我们将其视为 14 微米,这是中档区域扫描相机的标准。

所以首先我们需要计算出 i 水平尺寸( ih ),它是相机宽度的像素数乘以 ccd 像素的大小(我们将使用 640 x 320)

所以: ih = 640*14um = 8960um

   = 8960/1000 = 8.96mm

现在我们需要 垂直尺寸( iv )相同的过程但高度

所以: iv = (320 * 14um)/1000 = 4.48mm

现在 由勾股定理找到 勾股定理 a^2 + b^2 = c^2

所以: = sqrt(ih^2_iv^2)
  = 10.02 mm

现在我们假设我们有一个 28 毫米的镜头。同样,必须找出这个确切的值。所以我们的方程被重新排列为我们 Ø 是:

o = (i * d)/f

记住 Ø 将是对角线(我们假设物体或点距离 50 毫米):

Ø = (10.02mm * 50mm)/28mm
17.89mm

现在我们需要计算 o 水平维度( oh )和 o 垂直维度( ov ),因为这将为我们提供对象移动的每个像素的距离。现在为 FOV α CCD 成正比我们将计算出一个比率 k

k = 输入/输出
= 10.02 / 17.89 

= 0.56

所以:

Ø 水平尺寸( ):

= ih/k

= 8.96 毫米/0.56 = 每像素 16 毫米

Ø 垂直尺寸( ov ):

ov = iv/k

= 4.48 毫米/0.56 = 每像素 8 毫米

现在我们有了我们需要的常量,让我们在一个例子中使用它。如果我们在 50mm 处的物体从位置 (0,0) 移动到 (2,4),那么现实生活中的测量值是:

(2*16mm , 4*8mm) = (32mm,32mm)

同样,一个勾股定理:a^2 + b^2 = c^2

总距离 = sqrt(32^2 + 32^2)
           = 45.25mm

复杂我知道,但一旦你在程序中拥有它,它就更容易了。因此,对于每一点,您都必须重复至少一半的过程,如 d 因此将更改 Ø 对于您检查的每一点。

希望这能让你上路,

干杯
克里斯

关于vb.net - 从单应性中提取变换和旋转矩阵?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7388893/

相关文章:

c++ - adjustROI 会改变 cv::Mat 的 wholeSize 吗?

.net - 使用 VB.NET 从字符串中检测 IFormatProvider 或 CultureInfo

opencv - 计算图像中每行的字节数

python - 如何将 12 位 DICOM 图像转换为 8 位 jpeg?

Android ZXing图像处理

matlab - 基于矩阵 A,通过矩阵 A 的列的所有可能的乘法生成矩阵 B

matrix - 矩阵与其他矩阵的矢量化索引(以 Octave 为单位)

用户控件中的 Asp.NET 下拉列表未触发 SelectedIndexChanged 事件

.net - 在 VB.NET 中解析 JSON

c# - 如果源字符串不以相同的子字符串开头,则添加一个子字符串