{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Turntable calibration" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this article is presented a method to determine the homogeneus transformation between the camera coordinate system and the rotation center of the turntable. ![](https://raw.githubusercontent.com/Jesus89/3DScanScience/master/notebooks/images/4.4.%20Laser%20calibration/pattern-position.png)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Capture pattern origin" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "Pattern is automatically moved on the turntable from -90º to 90º respect to the initial position. Each step (5º) it is captured the [pattern's pose](http://nbviewer.ipython.org/github/Jesus89/3DScanScience/blob/master/notebooks/4.1.%20Pattern%20detection.ipynb). The pattern origin point, defined as the bottom-left corner, is computed using the intersection with the projection of the corner in the image and the pattern plane." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": true }, "outputs": [], "source": [ "import numpy as np\n", "\n", "#Load example points\n", "points = np.array([(-71.889508465627387, 50.013567717607749, 344.49352456998758), (-73.938146681112755, 50.246193674080907, 338.01301804172272), (-75.497351387650639, 50.492948734714403, 330.87542127925065), (-76.376380847308425, 50.734117933168591, 324.17522165185346), (-76.714488167787607, 50.993900582296561, 317.3344047282414), (-76.403768361627812, 51.272234507372353, 309.71864906038684), (-75.485306621272557, 51.549433425353058, 302.68961151070874), (-74.000231775386524, 51.809640767591226, 295.94087917913839), (-71.835845971537935, 52.082778636253131, 289.01220924464218), (-69.311034379453886, 52.328053219713709, 282.87092458439184), (-65.822041224968615, 52.625688337478778, 276.18480478407253), (-62.336253545911951, 52.877250167738936, 270.66679623202765), (-58.041963526078746, 53.137164118260294, 264.97985913318598), (-53.181565932121643, 53.376856358245568, 259.6388616558591), (-48.270518476370661, 53.582888438128002, 255.0205618040097), (-42.173702942476567, 53.798821993651814, 250.33223366723669), (-36.54320409745096, 53.975402416771956, 246.74779748678947), (-30.470855853767048, 54.130827402058607, 243.45798455002659), (-23.565546697472435, 54.289427296325343, 240.58263365325183), (-17.031816562984559, 54.410496232507043, 238.44783394220926), (-10.000560702649052, 54.524867785168766, 236.84255161321303), (-3.024878053643687, 54.612931136574318, 235.84493023779947), (4.1151465080711507, 54.678828047877047, 235.49675611700954), (11.189306930064157, 54.717826806420923, 235.76911469780327)])" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false }, "outputs": [ { "data": { "image/png": "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\nHXccgDrZyuOPPw4AmDx5Mq666qocrFoayWQSe/bswdq1a7F27Vp88803iEQi6N69O3r27Am/349I\nJIKrr76aT03QNt7ItllhoUxNFJcpnyr3fLRYixagaDgSiSAajfLNKLn4fggUaZMu2ufz4c4770Q0\nGsXTTz+Npk2bZn0M0t4++OCDGD16NDZv3ozi4mJUV1ejd+/e+OWXXwpOe6sEBaXTnTlzJh599FFe\nX0igfNGbb76JZcuWYcKECfjggw/w22+/4bHHHsO3336LRCKBPn36YPjw4WjRokWOzqA+OI5DmzZt\n0KZNG4waNQpAnVzm7bffxt13341YLIbu3btj1apV6NWrF/r164devXrB4XDUc40SG7ujBVhNZzaa\nW0otiNlEUu4xk6OXMIrLZeREahUaWWOz2WS5eunRlMLmkclA6D//+Q/uueceTJ48GSNHjtTkeELt\nbWVlJYqLiwEAjRo1wqFDhwAcXdpbJcg70p04cSImTpzIf8mEL774As888wwA8GM+AODLL7/E8OHD\n+crsueeei2XLlmHMmDHGLlwhHA4Htm/fjilTpmDcuHHgOA6VlZVYt24d1qxZg2effRY1NTW8r0S/\nfv3QsWNHAEgpbCkt0gmhdoqDEkjpbVnJGp0PkS7NS8ulTwGbL2UbLoRaaPr7dE0p2T4o2TxyUVER\ngsEgpk2bhn379uHjjz/GMccck/1J/w9C7W06fe3Ror1VgrwjXSns27ePH78MACUlJaisrMT+/ftT\notp8etref//9Kf+/efPmGD58OIYPHw4AKb4SL730kqSvRCKRUOVMJsfgXC9wHAe73S57XI2R23g2\n0pYb9YsRsRYDT4Xjc2w2G9avX4/bb78dN9xwAy6//HJdvjer9cjo80aNGsHv98Pr9aK6uppPXxxN\n2lslaJCke8455+DgwYP1fv7pp5+m/dKknqqF+rS1Wq048cQTceKJJ+Kaa66p5yuxcOFClJeXo02b\nNjwJd+/endfUSrUAk/SqIbiSZRpXk24br4UWWrgWqehWDdS2NdODRTg+JxKJ4MEHH8SPP/6It99+\nG23bttXkvAnpRp+/9dZbGDduHBYtWoQhQ4YAQIMbfd5Q0CBJ9/PPP1f8mrKyMvz555+8TVxVVRVK\nS0tRVlaGbdu28X/3559/4uSTT9ZsrQ0JmXwlFi9ejKlTp/K+Er169UL//v1RVlbGR2/kTGaxWHg7\n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\nxhhjjC0t/wO0Ll8Qw5mwtwAAAABJRU5ErkJggg==\n", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "%matplotlib inline\n", "import matplotlib.pyplot as plt\n", "from mpl_toolkits.mplot3d import Axes3D\n", "\n", "# Plot points\n", "fig = plt.figure()\n", "ax = fig.gca(projection = '3d')\n", "X, Y, Z = points.T[0], points.T[1], points.T[2]\n", "ax.scatter(X, Z, Y)\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Fit plane\n", "In this section it is computed the best plane defined by the points using Least squares method." ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "Plane normal\n", "\n", "[ 0.0072119 -0.99925488 -0.03791666]\n", "\n" ] } ], "source": [ "from scipy import optimize\n", "\n", "def distance2plane(p0, n0, p):\n", " return np.dot(np.array(n0), np.array(p) - np.array(p0))\n", "\n", "def residuals_plane(parameters, data_point):\n", " px, py, pz, theta, phi = parameters\n", " nx, ny, nz = np.sin(theta) * np.cos(phi), np.sin(theta) * np.sin(phi), np.cos(theta)\n", " distances = [distance2plane([px, py, pz], [nx, ny, nz], [x, y, z]) for x, y, z in data_point]\n", " return distances\n", "\n", "def fit_plane(data):\n", " estimate = [0, 0, 0, 0, 0] # px, py, pz and zeta, phi\n", " best_fit_values, ier = optimize.leastsq(residuals_plane, estimate, args=(data))\n", " xF, yF, zF, tF, pF = best_fit_values\n", " #point = [xF, yF, zF]\n", " point = data[0]\n", " normal = -np.array([np.sin(tF) * np.cos(pF), np.sin(tF) * np.sin(pF), np.cos(tF)])\n", " return point, normal\n", "\n", "point, normal = fit_plane(points)\n", "\n", "if normal[1] > 0:\n", " normal *= -1\n", "\n", "print(\"\\nPlane normal\\n\\n{0}\\n\".format(normal))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Fit circle\n", "In this section it is computed the best circle contained in the plane, defined by the points using Least squares method." ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def residuals_circle(parameters, points, s, r, point):\n", " r_, s_, Ri = parameters\n", " plane_point = s_ * s + r_ * r + np.array(point)\n", " distance = [np.linalg.norm(plane_point - np.array([x, y, z])) for x, y, z in points]\n", " res = [(Ri - dist) for dist in distance]\n", " return res\n", "\n", "def fit_circle(point, normal, points):\n", " s = np.cross(np.array([1, 0, 0]), np.array(normal))\n", " s = s / np.linalg.norm(s)\n", " r = np.cross(np.array(normal), s)\n", " r = r / np.linalg.norm(r)\n", "\n", " # Define rotation\n", " R = np.array([s, r, normal]).T\n", "\n", " estimate_circle = [0, 0, 0] # px,py,pz and zeta, phi\n", " best_circle_fit_values, ier = optimize.leastsq(residuals_circle, estimate_circle, args=(points, s, r, point))\n", " rF, sF, RiF = best_circle_fit_values\n", "\n", " # Synthetic Data\n", " center_point = sF * s + rF * r + np.array(point)\n", " synthetic = [list(center_point + RiF * np.cos(phi) * r + RiF * np.sin(phi) * s)\n", " for phi in np.linspace(0, 2 * np.pi, 50)]\n", "\n", " return center_point, R\n", "\n", "center, R = fit_circle(point, normal, points)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Homogeneous transformation" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The homogeneous transformation matrix of the turntable is defined by $R$, rotation matrix obtained from the plane's normal, and $\\textbf{t}$, computed by using the center of the circle, the plane's normal and the pattern origin distance. This last value has to be measured in real world, in order to determine the coordinate system on the platform.\n", "![](https://raw.githubusercontent.com/Jesus89/3DScanScience/master/notebooks/images/4.5.%20Turntable%20calibration/pattern-origin-distance.jpg)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "Rotation matrix\n", "\n", "[[ 0.00000000e+00 9.99973994e-01 7.21190061e-03]\n", " [ 3.79176484e-02 7.20671429e-03 -9.99254880e-01]\n", " [ -9.99280867e-01 2.73458311e-04 -3.79166623e-02]]\n", "\n", "\n", "Translation vector\n", "\n", "[ 4.42701066 88.78675021 318.28065121] mm\n", "\n" ] } ], "source": [ "X = 37.2\n", "\n", "t = center - X * np.array(normal)\n", "\n", "print(\"\\nRotation matrix\\n\\n{0}\\n\".format(R))\n", "print(\"\\nTranslation vector\\n\\n{0} mm\\n\".format(t))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# References\n", "* http://stackoverflow.com/questions/15481242/python-optimize-leastsq-fitting-a-circle-to-3d-set-of-points" ] } ], "metadata": { "kernelspec": { "display_name": "Python 2", "language": "python", "name": "python2" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 2 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", "version": "2.7.6" } }, "nbformat": 4, "nbformat_minor": 0 }