我刚刚学习一些 OpenCV,并在 Blender 中玩。
作为测试,我试图重新创建我在另一篇文章中看到的东西,但在搅拌机内。我想重新创建一个我创建的观察飞机的相机。我想从中创建图像的图像是: 在此输入图片描述
这是我迄今为止在 Blender 中的代码:
import bpy
import cv2
import numpy as np
from mathutils import Matrix, Vector
from scipy.spatial.transform import Rotation
def focalMM_to_focalPixel(focalMM, sensorWidth, imageWidth):
pixelPitch = sensorWidth / imageWidth
return focalMM / pixelPitch
# Read Image
im = cv2.imread("assets/cameraView.jpg")
imageWidth = 1920
imageHeight = 1080
imageSize = [imageWidth, imageHeight]
points_2D = np.array([
(949, 49),
(1415, 45),
(962, 913),
(1398, 977)
], dtype="double")
points_3D = np.array([
(-.30208, -1.8218, 8.3037),
(-.30208, -1.8303, 8.3037),
(-.30208, -1.8218, 1.381),
(-.30208, -1.8303, 1.381)
])
focalLengthMM = 50
sensorWidth = 36
fLength = focalMM_to_focalPixel(focalLengthMM, sensorWidth, imageWidth)
print("focalLengthPixel", fLength)
K = np.array([
[fLength, 0, imageWidth/2],
[0, fLength, imageHeight/2],
[0, 0, 1]
])
distCoeffs = np.zeros((5, 1))
success, rvecs, tvecs = cv2.solvePnP(points_3D, points_2D, K, distCoeffs, flags=cv2.SOLVEPNP_ITERATIVE)
np_rodrigues = np.asarray(rvecs[:,:], np.float64)
rmat = cv2.Rodrigues(np_rodrigues)[0]
camera_position = -np.matrix(rmat).T @ np.matrix(tvecs)
# Test the solvePnP by projecting the 3D Points to camera
projPoints = cv2.projectPoints(points_3D, rvecs, tvecs, K, distCoeffs)[0]
for p in points_2D:
cv2.circle(im, (int(p[0]), int(p[1])), 3, (0, 255, 0), -1)
for p in projPoints:
cv2.circle(im, (int(p[0][0]), int(p[0][1])), 3, (255, 0, 0), -1)
# cv2.imshow("image", im)
# cv2.waitKey(0)
r = Rotation.from_rotvec([rvecs[0][0], rvecs[1][0], rvecs[2][0]])
rot = r.as_euler('xyz', degrees=True)
tx = camera_position[0][0]
ty = camera_position[1][0]
tz = camera_position[2][0]
rx = round(180 - rot[0], 5)
ry = round(rot[1], 5)
rz = round(rot[2], 5)
# Creating the camera in Blender
bpy.ops.object.camera_add()
camera = bpy.context.object
camera.location = (tx, ty, tz)
# Convert rotation from degrees to radians for Blender
camera.rotation_euler = (np.radians(rx), np.radians(ry), np.radians(rz))
# Setting the camera parameters
camera.data.lens = focalLengthMM
camera.data.sensor_width = sensorWidth
camera.data.sensor_height = sensorWidth * (imageHeight / imageWidth)
camera.data.shift_x = (imageWidth / 2 - K[0, 2]) / imageWidth
camera.data.shift_y = (imageHeight / 2 - K[1, 2]) / imageHeight
我对如何实现正确的旋转和平移感到困惑,并且我确信我做错了什么。
我得到的值让我的相机进入了一个奇怪的位置。下图突出显示的相机是生成的相机与原始相机。
我感谢任何帮助。
我能够弄清楚如何在 Blender 中做到这一点。我将在下面发布我的代码。要去检查并清理它,但这完成了我打算做的事情。
import bpy
import cv2
import numpy as np
from scipy.spatial.transform import Rotation
from mathutils import Matrix, Vector
import logging
# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def focalMM_to_focalPixel(focalMM, sensorWidth, imageWidth):
pixelPitch = sensorWidth / imageWidth
return focalMM / pixelPitch
def load_image(image_path):
try:
im = cv2.imread(image_path)
if im is None:
raise FileNotFoundError(f"Image not found at path: {image_path}")
return im
except Exception as e:
logger.error(f"Error loading image: {e}")
raise
def calculate_camera_matrix(focalLengthMM, sensorWidthMM, imageWidth, imageHeight):
focalLengthPixels = focalMM_to_focalPixel(focalLengthMM, sensorWidthMM, imageWidth)
K = np.array([
[focalLengthPixels, 0, imageWidth / 2],
[0, focalLengthPixels, imageHeight / 2],
[0, 0, 1]
], dtype='double')
return K
def main():
image_path = r"P:\Projects\CornerDetection\assets\BlenderTestRender_V2.png"
points_2D = np.array([
(683, 59),
(1201, 49),
(1210, 978),
(716, 1012)
], dtype="double")
points_3D = np.array([
(-0.302079, -1.82178, 8.30375),
(-0.302079, 1.83035, 8.30375),
(-0.302079, 1.83035, 1.38104),
(-0.302079, -1.82178, 1.38104)
], dtype="double")
focalLengthMM = 50
sensorWidthMM = 36
sensorHeightMM = 20.25
im = load_image(image_path)
imageHeight, imageWidth = im.shape[:2]
# Calculate intrinsic matrix using the provided function
K = calculate_camera_matrix(focalLengthMM, sensorWidthMM, imageWidth, imageHeight)
distCoeffs = np.zeros((5, 1)) # Assuming no lens distortion
# Solve PnP
ret, rvecs, tvecs = cv2.solvePnP(points_3D, points_2D, K, distCoeffs)
rmat, _ = cv2.Rodrigues(rvecs)
projPoints, _ = cv2.projectPoints(points_3D, rvecs, tvecs, K, distCoeffs)
for p in points_2D:
cv2.circle(im, (int(p[0]), int(p[1])), 3, (0, 255, 0), -1)
for p in projPoints:
cv2.circle(im, (int(p[0][0]), int(p[0][1])), 2, (255, 0, 0), -1)
R_world2cv = Matrix(rmat.tolist())
T_world2cv = Vector(tvecs.flatten())
R_bcam2cv = Matrix(
((1, 0, 0),
(0, -1, 0),
(0, 0, -1)))
R_cv2world = R_world2cv.transposed()
rot = R_cv2world @ R_bcam2cv
loc = R_cv2world @ -T_world2cv
cv2.imshow("image", im)
cv2.waitKey(0)
cv2.destroyAllWindows()
# Ensure the context is properly set
bpy.context.scene.camera = None
bpy.ops.object.camera_add()
# Set camera intrinsics, extrinsics and background
cam = bpy.context.object
camd = cam.data
camd.type = 'PERSP'
camd.lens = focalLengthMM
camd.sensor_width = sensorWidthMM
camd.sensor_height = sensorHeightMM
render_size = [
bpy.context.scene.render.pixel_aspect_x * bpy.context.scene.render.resolution_x,
bpy.context.scene.render.pixel_aspect_y * bpy.context.scene.render.resolution_y
]
camd.sensor_fit = 'HORIZONTAL' if render_size[0] / render_size[1] <= imageWidth / imageHeight else 'VERTICAL'
refsize = imageWidth if render_size[0] / render_size[1] <= imageWidth / imageHeight else imageHeight
camd.shift_x = (imageWidth * 0.5 - K[0, 2]) / refsize
camd.shift_y = (imageHeight * 0.5 - K[1, 2]) / refsize
camd.show_background_images = True
if not camd.background_images:
bg = camd.background_images.new()
else:
bg = camd.background_images[0]
bg.source = 'IMAGE'
bg.image = bpy.data.images.load(image_path)
bg.frame_method = 'FIT'
bg.display_depth = 'FRONT'
cam.matrix_world = Matrix.Translation(loc) @ rot.to_4x4()
bpy.context.scene.camera = cam
if __name__ == "__main__":
main()