世界坐标系,相机坐标系和图像坐标系的转换(Python)
标签: Open3D
世界坐标系,相机坐标系和图像坐标系的转换(Python)
相机内参外参说明:https://panjinquan.blog.csdn.net/article/details/102502213
计算机视觉:相机成像原理:世界坐标系、相机坐标系、图像坐标系、像素坐标系之间的转换:https://blog.csdn.net/chentravelling/article/details/53558096
1.世界坐标->相机坐标

2.相机坐标系->图像坐标系
此时投影点p的单位还是mm,并不是pixel,需要进一步转换到像素坐标系。
3.图像坐标系与像素坐标系
像素坐标系和图像坐标系都在成像平面上,只是各自的原点和度量单位不一样。图像坐标系的原点为相机光轴与成像平面的交点,通常情况下是成像平面的中点或者叫principal point。图像坐标系的单位是mm,属于物理单位,而像素坐标系的单位是pixel,我们平常描述一个像素点都是几行几列。所以这二者之间的转换如下:其中dx和dy表示每一列和每一行分别代表多少mm,即1pixel=dx mm
那么通过上面四个坐标系的转换就可以得到一个点从世界坐标系如何转换到像素坐标系的。
python代码shi实现:
# -*- coding: utf-8 -*-
"""
# --------------------------------------------------------
# @Project: prpject
# @Author : panjq
# @E-mail : [email protected]
# @Date : 2020-02-04 16:03:01
# @url : https://www.jianshu.com/p/c5627ad019df
# --------------------------------------------------------
"""
import sys
import os
from tools import image_processing
sys.path.append(os.getcwd())
import numpy as np
from modules.utils_3d import vis
camera_intrinsic = {
# R,旋转矩阵
"R": [[-0.91536173, 0.40180837, 0.02574754],
[0.05154812, 0.18037357, -0.98224649],
[-0.39931903, -0.89778361, -0.18581953]],
# t,平移向量
"T": [1841.10702775, 4955.28462345, 1563.4453959],
# 焦距,f/dx, f/dy
"f": [1145.04940459, 1143.78109572],
# principal point,主点,主轴与像平面的交点
"c": [512.54150496, 515.45148698]
}
class Human36M(object):
@staticmethod
def convert_wc_to_cc(joint_world):
"""
世界坐标系 -> 相机坐标系: R * (pt - T)
:return:
"""
joint_world = np.asarray(joint_world)
R = np.asarray(camera_intrinsic["R"])
T = np.asarray(camera_intrinsic["T"])
joint_num = len(joint_world)
# 世界坐标系 -> 相机坐标系
# [R|t] world coords -> camera coords
joint_cam = np.zeros((joint_num, 3)) # joint camera
for i in range(joint_num): # joint i
joint_cam[i] = np.dot(R, joint_world[i] - T) # R * (pt - T)
return joint_cam
@staticmethod
def __cam2pixel(cam_coord, f, c):
"""
相机坐标系 -> 像素坐标系: (f / dx) * (X / Z) = f * (X / Z) / dx
cx,ppx=260.166; cy,ppy=205.197; fx=367.535; fy=367.535
将从3D(X,Y,Z)映射到2D像素坐标P(u,v)计算公式为:
u = X * fx / Z + cx
v = Y * fy / Z + cy
D(v,u) = Z / Alpha
=====================================================
camera_matrix = [[428.30114, 0., 316.41648],
[ 0., 427.00564, 218.34591],
[ 0., 0., 1.]])
fx = camera_intrinsic[0, 0]
fy = camera_intrinsic[1, 1]
cx = camera_intrinsic[0, 2]
cy = camera_intrinsic[1, 2]
=====================================================
:param cam_coord:
:param f: [fx,fy]
:param c: [cx,cy]
:return:
"""
# 等价于:(f / dx) * (X / Z) = f * (X / Z) / dx
# 三角变换, / dx, + center_x
u = cam_coord[..., 0] / cam_coord[..., 2] * f[0] + c[0]
v = cam_coord[..., 1] / cam_coord[..., 2] * f[1] + c[1]
d = cam_coord[..., 2]
return u, v, d
@staticmethod
def convert_cc_to_ic(joint_cam):
"""
相机坐标系 -> 像素坐标系
:param joint_cam:
:return:
"""
# 相机坐标系 -> 像素坐标系,并 get relative depth
# Subtract center depth
# 选择 Pelvis骨盆 所在位置作为相机中心,后面用之求relative depth
root_idx = 0
center_cam = joint_cam[root_idx] # (x,y,z) mm
joint_num = len(joint_cam)
f = camera_intrinsic["f"]
c = camera_intrinsic["c"]
# joint image,像素坐标系,Depth 为相对深度 mm
joint_img = np.zeros((joint_num, 3))
joint_img[:, 0], joint_img[:, 1], joint_img[:, 2] = Human36M.__cam2pixel(joint_cam, f, c) # x,y
joint_img[:, 2] = joint_img[:, 2] - center_cam[2] # z
return joint_img
if __name__ == "__main__":
joint_world = [[-91.679, 154.404, 907.261],
[-223.23566, 163.80551, 890.5342],
[-188.4703, 14.077106, 475.1688],
[-261.84055, 186.55286, 61.438915],
[39.877888, 145.00247, 923.98785],
[-11.675994, 160.89919, 484.39148],
[-51.550297, 220.14624, 35.834396],
[-132.34781, 215.73018, 1128.8396],
[-97.1674, 202.34435, 1383.1466],
[-112.97073, 127.96946, 1477.4457],
[-120.03289, 190.96477, 1573.4],
[25.895456, 192.35947, 1296.1571],
[107.10581, 116.050285, 1040.5062],
[129.8381, -48.024918, 850.94806],
[-230.36955, 203.17923, 1311.9639],
[-315.40536, 164.55284, 1049.1747],
[-350.77136, 43.442127, 831.3473],
[-102.237045, 197.76935, 1304.0605]]
joint_world = np.asarray(joint_world)
kps_lines = ((0, 7), (7, 8), (8, 9), (9, 10), (8, 11), (11, 12), (12, 13), (8, 14), (14, 15),
(15, 16), (0, 1), (1, 2), (2, 3), (0, 4), (4, 5), (5, 6))
# show in 世界坐标系
vis.vis_3d(joint_world, kps_lines, coordinate="WC", title="WC")
human36m = Human36M()
# show in 相机坐标系
joint_cam = human36m.convert_wc_to_cc(joint_world)
vis.vis_3d(joint_cam, kps_lines, coordinate="CC", title="CC")
joint_img = human36m.convert_cc_to_ic(joint_cam)
# show in 像素坐标系
kpt_2d = joint_img[:, 0:2]
image_path = "/media/dm/dm1/git/python-learning-notes/modules/utils_3d/s_01_act_02_subact_01_ca_02_000001.jpg"
image = image_processing.read_image(image_path)
image = image_processing.draw_key_point_in_image(image, key_points=[kpt_2d], pointline=kps_lines)
image_processing.cv_show_image("image", image)
智能推荐
Python由放弃到入门,基础篇七(类)下
类的实例化 有感于现在python教程多如牛毛,且大多高不可攀,多次拜读而不得其门道,遂由入门到放弃。偶有机缘,得一不错教程,得以入门,现博客分享,想要获取完整教程,ff17328081445。 通过对比可以看到,实例化后再使用的格式,①是空着的,意思是这里不再需要@classmethod的声明,并且在第②处,把cls替换成了self。同时,实例化后再使用的格式,需要先赋值然后再调用(第③处): ...
pytorch CNN手写字体识别
数据整体训练一次,对于accuracy都是0的问题,由于刚开始学,有些代码的细节我也没看懂,不过整体结果是对的,可能是由于pytorch版本的更新,导致accuracy的计算方式有所改变 内容转载自:https://www.bilibili.com/video/av15997678/?p=19...
linux后台运行命令总结
linux后台运行命令总结 问题: 我们有时候需要登录远程服务器跑运行时间非常长的脚本,这个时候你要让脚本后台运行,不然占着终端窗口看着不舒服。但万一网络不好,(比如我这儿的破校园网,高峰时几秒钟断一次),终端突然和服务器之间的连接断了,那脚本就会自动停了(因为运行test.sh进程的父进程就是当前的shell终端进程,关闭当前shell终端时,父进程退出,会发送hangup信号给所有子进程,子进...
类对象模型和this指针
关于类/对象大小的计算 类只是一种类型定义,它本身是没有大小可言的。 我们这里指的类的大小,其实指的是类的对象所占的大小。因此,如果用sizeof运算符对一个类型名操作,得到的是具有该类型实体的大小。 首先,类大小的计算遵循结构体的对齐原则 类的大小与普通数据成员有关,与成员函数和静态成员无关。即普通成员函数,静态成员函数,静态数据成员,静态常量数据成员均对类的大小无影响 虚函数对类的大小有影响,...
猜你喜欢
3D人脸重建——PRNet网络输出的理解
前言 之前有款换脸软件不是叫ZAO么,分析了一下,它的实现原理绝对是3D人脸重建,而非deepfake方法,找了一篇3D重建的论文和源码看看。这里对源码中的部分函数做了自己的理解和改写。 国际惯例,参考博客: 什么是uv贴图? PRNet论文 PRNet代码 本博客主要是对PRNet的输出进行理解。 理论简介 这篇博客比较系统的介绍了3D人脸重建的方法,就我个人浅显的理解,分为两个流派:1.通过算...
javascript简单的正则表达式入门
内容来自百度前端学院javascript入门课程 基本的HTML: 样式: javascript: document.write和innerHTML有什么区别 前者是直接将内容写入文档流,如果写入之前没有调用document.open,那么回自动调用document.open(每打开一次文档流都会清除之前的所有内容包括变量)。每次写完关闭后重新调用该函数的话,会导致页面重写。 innerHTML是...
微信小程序一个你可能需要的功能
根据工作需要。需要做一个图片选中部分区域的效果。百度了很久,都没有见有。于是就自己写了个,需要的可以借鉴下,还有很多需要改善的地方 现在先看看效果 效果图 那这个有什么用呢。。需求是选中图片的某个区域然后给它添加注释。还可以有其他用处。那这个是怎么做到的呢 。。首先我说下基本的思路 ——-> 图片作为一个背景。然后上面是一层canvas 以及最上面生成的view 因为...
Linux Zabbix分布式监控 通过API接口远程 管理Zabbix所监控主机
一、API 1、什么是API API(Application Programming Interface,应用程序编程接口)是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。 Zabbix API允许你以编程方式检索和修改Zabbix的配置,并提供对历史数据的访问。 它广泛用于: 创建新的应用程序以使用Zabbix...
java 调用博思得条码打印机
效果: 打印文字、二维码、图片 准备工作: 1)、JNative(JNative.jar、JNativeCpp.dll) 2)、博思得dll文件(CDFPSK.dll)和API文档 ...
