草庐IT

python - 如何使用 sympy 从 View 矩阵中提取眼睛/目标/向上?

coder 2023-08-18 原文

我们在 #python channel 中尝试了很长一段时间如何使用 sympy 从 View 矩阵中计算眼睛/目标/向上向量。一种可能的方法是:

from sympy import *
from pprint import pprint

v1, v2, v3, v4 = symbols('v1 v2 v3 v4')
v5, v6, v7, v8 = symbols('v5 v6 v7 v8')
v9, v10, v11, v12 = symbols('v9 v10 v11 v12')
v13, v14, v15, v16 = symbols('v13 v14 v15 v16')

V = Matrix([
    [v1, v2, v3, v4],
    [v5, v6, v7, v8],
    [v9, v10, v11, v12],
    [v13, v14, v15, v16],
    ])
u1, u2, u3 = symbols('u1 u2 u3', real=True)
t1, t2, t3 = symbols('t1 t2 t3', real=True)
e1, e2, e3 = symbols('e1 e2 e3', real=True)

U = Matrix([u1, u2, u3])
T = Matrix([t1, t2, t2])
E = Matrix([e1, e2, e3])

def calculate_view_matrix(up, eye, target):
    zaxis = (eye - target).normalized()
    xaxis = up.cross(zaxis).normalized()
    yaxis = zaxis.cross(xaxis)

    orientation = Matrix([
        [xaxis[0], yaxis[0], zaxis[0], 0],
        [xaxis[1], yaxis[1], zaxis[1], 0],
        [xaxis[2], yaxis[2], zaxis[2], 0],
        [0, 0, 0, 1],
            ])

    translation = Matrix([
            [1, 0, 0, 0],
            [0, 1, 0, 0],
            [0, 0, 1, 0],
            [-eye[0], -eye[1], -eye[2], 1],
            ])

    return orientation * translation

print(V - calculate_view_matrix(U, E, T))

s = solve([
    V - calculate_view_matrix(U, E, T),
    U.norm() - 1,
    T.norm() - 1],
    [u1, u2, u3, t1, t2, t3, e1, e2, e3])

print(s)

但由于某种原因,该脚本已经运行了约 20 分钟,而 sympy 到目前为止还无法给出任何解决方案。

另一种尝试也试图将上述一般问题简化为更简单的问题,例如如何计算向上向量?

在更简单的上下文中,问题定义应该是这样的:

  1. u,z,x 是构成 orthonormal basis 的 3d 向量.
  2. z, x 是常数向量
  3. u 是未知向量

求解这个的方程式:

u.cross(z).normalized() - x

如果您尝试像这样解决上述通用方程的一个简单特例...

from sympy import *
u1,u2,u3=symbols('u1 u2 u3', real = True)
x=Matrix([1,0,0])
z=Matrix([0,0,1])
u=Matrix([u1,u2,u3])

print(solve(u.cross(z).normalized() - x, u))

你会得到 NotImplementedError: could not solve u2 - Abs(u2)

NS:事实是,为了从 View 矩阵中提取输入,计算矩阵的函数必须是单射或双射的,否则初始信息将丢失。如果您不添加任何约束,上述函数绝对不是单射的,因为在使用归一化操作的那一刻,该函数自动不再是单射的,例如:

a) normalize(x) = x/|x|
b) To prove normalize is injective then normalize(a)=normalize(b) should give a=b
c) normalize(a)=normalize(b) => a/|a|=b/|b| , which is not true then normalize is not injective

当然,这可以简单地证明只是说无限向量可以提供相同的归一化向量。

这就是为什么向 calculate_view_matrix 添加了一些约束的原因。即:U.norm() - 1T.norm() - 1。从理论上讲,这应该使 calculate_view_matrix 成为单射的...(或不是 :))

所以主要问题是,如何正确约束/修改 calculate_view_matrix 以便它可以计算出 View 矩阵的眼睛/目标/向上向量?

最佳答案

除了打字错误(T = Matrix([t1, t2, t2]))之外,从 View 矩阵返回的 Ansatz、眼睛和目标向量还有几个缺陷:

  • View 矩阵描述了 3D 中的刚性变换,它只有 6 个自由度(3 个轴旋转,3 个轴平移)。这大致意味着 16 个值 v1, v2, ..., v16 中只能选择 6 个(或多或少是任意的),其他值是相关的或以任何方式确定(例如 v4 = v8 = v12 = 0, v16 = 1, v3**2 = 1 - v1**2 - v2**2, ... ).所以一般来说,矩阵差分的方程是矛盾的。
  • 即使在要求 U.norm() - 1 = 0 时,向上矢量 U 也可以取无限多个值(一个角度未确定)。要将 U 的可能解减少到有限多种情况,可以添加条件 U*(E-T) = 0
  • 条件 T.norm() - 1 = 0 是错误的。可以/应该要求长度为 1 的是 T - E(视角方向)。

总而言之,我没有找到修复 Ansatz s.t. 的方法。 U, E, T 可以使用方程式和 sympy 从 View 矩阵计算。但是 U, E, T 可以很容易地从 View 矩阵中提取出来:

  • 可以从第二列读取规范化的U(满足上述要求)
  • -E可以从最后一行开始读取
  • 可以从第三列读取归一化 View 向量E - T

在 sympy/Python 代码中:

def calculate_up_eye_target(viewMat):
  eye = -viewMat[3,0:3].T
  target = eye - viewMat[0:3,2]
  up = viewMat[0:3,1]
  return up, eye, target

关于python - 如何使用 sympy 从 View 矩阵中提取眼睛/目标/向上?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43706865/

有关python - 如何使用 sympy 从 View 矩阵中提取眼睛/目标/向上?的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  4. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  5. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  6. ruby - 在 Ruby 中使用匿名模块 - 2

    假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

  7. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  8. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  9. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  10. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

随机推荐