Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
Release history
===============

`v0.15.1` - 2023-03-16
----------------------

Added
~~~~~

- OpenCV-like intrinsic matrix in camera setup
- configurable denoiser start frame

Changed
~~~~~~~

- ovrlaping refractive volumes handling


`v0.15.0` - 2022-12-30
----------------------

Expand Down Expand Up @@ -553,6 +568,7 @@ Added
- this changelog, markdown description content type tag for PyPI
- use [Semantic Versioning](https://semver.org/spec/v2.0.0.html)

.. _`v0.15.1`: https://github.com/rnd-team-dev/plotoptix/releases/tag/v0.15.1
.. _`v0.15.0`: https://github.com/rnd-team-dev/plotoptix/releases/tag/v0.15.0
.. _`v0.14.4`: https://github.com/rnd-team-dev/plotoptix/releases/tag/v0.14.4
.. _`v0.14.3`: https://github.com/rnd-team-dev/plotoptix/releases/tag/v0.14.3
Expand Down
4 changes: 2 additions & 2 deletions examples/1_basics/12_camera_shaders.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -1027,7 +1027,7 @@
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
Expand All @@ -1041,7 +1041,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.4"
"version": "3.10.6"
}
},
"nbformat": 4,
Expand Down
309 changes: 309 additions & 0 deletions examples/1_basics/13_camera_calibration.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,309 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Camera calibration\n",
"\n",
"Pinhole and thin-lens cameras accept OpenCV-like intrinsics matrix in setup/update functions. This notebook illustrates how intrinsic parameters should be provided and how you can recover them with OpenCV camera calibration."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import cv2 as cv\n",
"from plotoptix import TkOptiX"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Setup the raytracer:"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"rt = TkOptiX(start_now=False)\n",
"\n",
"rt.set_param(min_accumulation_step=4,\n",
" max_accumulation_frames=512)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Add chess board pattern used for calibration."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"rx = 10\n",
"ry = 10\n",
"n = 11\n",
"\n",
"x = np.linspace(0, rx, n)\n",
"y = np.linspace(0, ry, n)\n",
"X, Y = np.meshgrid(x, y)\n",
"\n",
"# positions of cubes\n",
"xyz = np.stack((X.flatten(), Y.flatten(), np.zeros(n**2))).T - np.array([0, 0, 0.15])\n",
"\n",
"widx = [i for i in range(0,xyz.shape[0]) if i % 2 == 0]\n",
"bidx = [i for i in range(0,xyz.shape[0]) if i % 2 == 1]\n",
"\n",
"xp = np.linspace(1, rx, n-1)\n",
"yp = np.linspace(1, ry, n-1)\n",
"Xp, Yp = np.meshgrid(xp, yp)\n",
"xyzp = np.stack((Xp.flatten(), Yp.flatten(), np.zeros((n-1)**2))).T.astype(np.float32)\n",
"#rt.set_data(\"points\", xyzp, r=0.1, c=0.9) # points to confirm true positions of objpoints\n",
"\n",
"rt.set_data(\"wcubes\", xyz[widx,:], u=[0.998, 0, 0], v=[0, 0.998, 0], w=[0, 0, 0.15], c=0.93, geom=\"Parallelepipeds\")\n",
"rt.set_data(\"bcubes\", xyz[bidx,:], u=[0.998, 0, 0], v=[0, 0.998, 0], w=[0, 0, 0.15], c=0.15, geom=\"Parallelepipeds\")\n",
"rt.set_data(\"base\", [-0.5, -0.5, -0.3], u=[12, 0, 0], v=[0, 12, 0], w=[0, 0, 0.2], c=0.9, geom=\"Parallelepipeds\")\n",
"\n",
"rt.set_data(\"plane\", [-20, -20, -1], u=[50, 0, 0], v=[0, 50, 0], c=0.9, geom=\"Parallelograms\") # a wall behind cubes\n",
"\n",
"rt.setup_area_light(\"light1\", center=[15, 4, 15], target=[5, 4, 0], u=7, v=7, color=[8.5, 8, 7.5])\n",
"\n",
"rt.set_ambient([0.1, 0.2, 0.4])\n",
"rt.set_background(0)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Camera setup. Absolute scale in [mm] is used, though it requires to specify sensor height (Y dimension)."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"sensor_height = 24 # [mm]\n",
"fx = 17 # [mm]\n",
"fy = 17 # [mm]\n",
"cx = 3 # [mm]\n",
"cy = 0 # [mm]\n",
"\n",
"# OpenCV-like camera intrinsic matrix\n",
"cam_mat = np.array([[fx, 0, cx], [0, fy, cy], [0, 0, 1]], dtype=np.float32)\n",
"\n",
"eye = [7, 7, 10]\n",
"tgt = [6, 6, 0]\n",
"up = [0, -1, 0]\n",
"\n",
"rt.setup_camera(\n",
" \"cam1\", cam_type=\"ThinLens\",\n",
" eye=eye, target=tgt, up=up,\n",
" camera_matrix=cam_mat,\n",
" sensor_height=sensor_height,\n",
" glock=True\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Start the ray tracing:"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"rt.start()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Collect calibration images.**\n",
"\n",
"Calibration with OpenCV is performed for a fixed image size, this it is set below to 1300x950 to avoid changes caused by the GUI.\n",
"\n",
"Change the anlgle of view and/or camera target and wait until callback notifies image was captured. Collect a few images. These will be used to reconstruct camera parameters."
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"1 images captured\n",
"2 images captured\n",
"3 images captured\n",
"4 images captured\n",
"5 images captured\n",
"6 images captured\n",
"7 images captured\n"
]
}
],
"source": [
"width = 1500\n",
"height = 950\n",
"\n",
"rt.set_rt_size((width, height))\n",
"\n",
"imgpoints = []\n",
"objpoints = []\n",
"\n",
"def image_ready(rt: TkOptiX) -> None:\n",
" gray = cv.cvtColor(rt._img_rgba, cv.COLOR_BGR2GRAY)\n",
" retval, corners = cv.findChessboardCorners(gray, (n-1, n-1))\n",
" if retval:\n",
" corners2 = cv.cornerSubPix(\n",
" gray, corners, (5,5), (-1,-1),\n",
" (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 10, 0.001)\n",
" )\n",
" imgpoints.append(corners2)\n",
" objpoints.append(100*xyzp.astype(np.float32))\n",
"\n",
" print(len(imgpoints), \"images captured\")\n",
" else:\n",
" print(\"skip image\")\n",
" \n",
"rt.set_accum_done_cb(image_ready)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Run camera calibration. OpenCV returns calues in [pixels] so they need to appropriate scaling to get values back in [mm]."
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"fx: 672.6737619162795\n",
"fy: 672.6596888212799\n",
"fx: 16.99386345893759 [mm]\n",
"fy: 16.993507928116546 [mm]\n",
"cx: 0.12460680641213917\n",
"cy: -0.000521407446712252\n",
"cx: 2.99056335389134 [mm]\n",
"cy: -0.012513778721094049 [mm]\n",
"dist: [[-2.07361708e-04 4.49837393e-04 9.99845034e-06 -4.78913174e-06\n",
" -2.68033315e-04]]\n"
]
}
],
"source": [
"img_size = rt.get_size()\n",
"pixel_pitch = sensor_height / img_size[1]\n",
"\n",
"ret, mtx, dist, rvecs, tvecs = cv.calibrateCamera(objpoints, imgpoints, img_size, None, None)\n",
"\n",
"print(\"fx:\", mtx[0,0])\n",
"print(\"fy:\", mtx[1,1])\n",
"print(\"fx:\", pixel_pitch * mtx[0,0], \"[mm]\")\n",
"print(\"fy:\", pixel_pitch * mtx[1,1], \"[mm]\")\n",
"print(\"cx:\", mtx[0,2] / img_size[0] - 0.5)\n",
"print(\"cy:\", mtx[1,2] / img_size[1] - 0.5)\n",
"print(\"cx:\", sensor_height * (mtx[0,2] / img_size[0] - 0.5), \"[mm]\")\n",
"print(\"cy:\", sensor_height * (mtx[1,2] / img_size[1] - 0.5), \"[mm]\")\n",
"print(\"dist:\", dist)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Try another set of parameters and re-run image capturing and calibration."
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"sensor_height = 24 # [mm]\n",
"fx = 21 # [mm]\n",
"fy = 18 # [mm]\n",
"cx = 0 # [mm]\n",
"cy = -2 # [mm]\n",
"\n",
"# OpenCV-like camera intrinsic matrix\n",
"cam_mat = np.array([[fx, 0, cx], [0, fy, cy], [0, 0, 1]], dtype=np.float32)\n",
"\n",
"rt.update_camera(\"cam1\",\n",
" camera_matrix=cam_mat,\n",
" sensor_height=sensor_height,\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Close the ray-tracer."
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {},
"outputs": [],
"source": [
"rt.close()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.6"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
4 changes: 2 additions & 2 deletions examples/1_basics/4_materials_and_glass_colors.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
Expand All @@ -360,7 +360,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.4"
"version": "3.10.6"
}
},
"nbformat": 4,
Expand Down
4 changes: 2 additions & 2 deletions examples/1_basics/4_materials_configuration.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
Expand All @@ -251,7 +251,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.4"
"version": "3.10.6"
}
},
"nbformat": 4,
Expand Down
Loading