Skip to content

Instantly share code, notes, and snippets.

@raacampbell
Created June 18, 2024 07:01
Show Gist options
  • Save raacampbell/526aeb0a7f2d3a6b4ecb1b1d27808d8e to your computer and use it in GitHub Desktop.
Save raacampbell/526aeb0a7f2d3a6b4ecb1b1d27808d8e to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"id": "d5c44ccf",
"metadata": {},
"source": [
"## Projector mask registered to in vivo camera feed\n",
"\n",
"A projector generates a pattern and projects it into the field of view of a camera. The two fields of view are unlikley to be perfectly co-aligned. They likely will be offset, rotated, and scaled with respect to each other. So we want an affine transform that takes us from one to the other. This would allow us to define regions in the camera's coordinate space and convert these to the projector space so we know where to stimulate. \n",
"\n",
"The idea will be to present a series of bright spots one after the other with the projector. Determine the coordinates of each in the camera field of view. Then do an affine transform to take us from one space to the other. \n",
"\n",
"The idea here comes from this project: [Zapit](https://github.com/zapit-optostim/zapit/), which does a similar thing but with a scanned laser spot instead of a projector.\n",
"In particular see the step for the [scanner calibration to camera](https://zapit.gitbook.io/user-guide/using-the-gui/scanner-calibration). \n",
"The most relevant methods in Zapit are [calibrateScanners.m](https://github.com/Zapit-Optostim/zapit/blob/main/zapit/%2Bzapit/%40pointer/calibrateScanners.m) and [runAffineTransform.m](https://github.com/Zapit-Optostim/zapit/blob/main/zapit/%2Bzapit/%40pointer/runAffineTransform.m)\n"
]
},
{
"cell_type": "code",
"execution_count": 52,
"id": "6344b741",
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"import cv2\n",
"\n",
"from skimage import measure\n",
"from skimage.transform import estimate_transform"
]
},
{
"cell_type": "code",
"execution_count": 53,
"id": "8bad6286",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAaAAAAGgCAYAAADsNrNZAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy88F64QAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAYx0lEQVR4nO3df0yV993/8Rc/D1ThoDjOgQnKGhOs2mhFETVbM8lIZzadrJsJ3eiPzLXFVjSpla24bK0edVnrdK1Os7k107qaTK3mnsZgS2KKqHS6ulZ00UxSe45tNs6xWo+U87n/6Pc+3zG18yD2DfJ8JFdSrvM5hzefRp+54HCZ5JxzAgDgc5ZsPQAAYGAiQAAAEwQIAGCCAAEATBAgAIAJAgQAMEGAAAAmCBAAwAQBAgCYIEAAABO3LEAvvviiRo4cqYyMDJWVlenQoUO36lMBAPqhpFtxL7g//vGP+v73v6/169errKxMq1ev1rZt29TW1qa8vLzPfG4sFtO5c+eUlZWlpKSk3h4NAHCLOed04cIFFRQUKDn5M65z3C0wefJkV1tbG/+4q6vLFRQUuEAg8F+f297e7iRxcHBwcPTzo729/TP/vk9VL7ty5YpaW1tVX18fP5ecnKyKigo1NzdftT4ajSoajcY/dv/vgmy6vq5UpfX2eACAW+wTdeqA/kdZWVmfua7XA/Thhx+qq6tLPp+v23mfz6cTJ05ctT4QCOinP/3pNQZLU2oSAQKAfufT64j/+mMU83fB1dfXKxwOx4/29nbrkQAAn4NevwIaNmyYUlJSFAqFup0PhULy+/1Xrfd4PPJ4PL09BgCgj+v1K6D09HRNnDhRjY2N8XOxWEyNjY0qLy/v7U8HAOinev0KSJIWLVqkmpoalZaWavLkyVq9erUuXryohx566FZ8OgBAP3RLAvTd735XH3zwgZYuXapgMKjx48drz549V70xAQAwcN2SX0S9GZFIRF6vV/dqFu+CA4B+6BPXqTe0U+FwWNnZ2dddZ/4uOADAwESAAAAmCBAAwAQBAgCYIEAAABMECABgggABAEwQIACACQIEADBBgAAAJggQAMAEAQIAmCBAAAATBAgAYIIAAQBMECAAgAkCBAAwQYAAACYIEADABAECAJggQAAAEwQIAGCCAAEATKRaDwAAt8Lec0dveG1lwfhbNgeujysgAIAJAgQAMEGAAAAmCBAAwAQBAgCYIEAAABMECABgggABAEwQIACACQIEADDBrXgA3Ja4vU7fxxUQAMAEAQIAmCBAAAATBAgAYIIAAQBMECAAgAkCBAAwQYAAACYIEADABAECAJggQAAAEwQIAGCCAAEATBAgAIAJAgQAMEGAAAAmCBAAwAQBAgCYIEAAABMECABgggABAEwQIACACQIEADBBgAAAJggQAMAEAQIAmCBAAAATBAgAYCKhAAUCAU2aNElZWVnKy8vT7Nmz1dbW1m3N5cuXVVtbq9zcXA0ePFhVVVUKhUK9OjQAoP9LKEBNTU2qra3VwYMHtW/fPnV2duprX/uaLl68GF+zcOFC7dq1S9u2bVNTU5POnTunOXPm9PrgAID+Lck553r65A8++EB5eXlqamrSl7/8ZYXDYX3hC1/Qli1b9O1vf1uSdOLECY0ePVrNzc2aMmXKVa8RjUYVjUbjH0ciERUWFupezVJqUlpPRwMAGPnEdeoN7VQ4HFZ2dvZ1193Uz4DC4bAkaejQoZKk1tZWdXZ2qqKiIr6mpKRERUVFam5uvuZrBAIBeb3e+FFYWHgzIwEA+okeBygWi6murk7Tpk3T2LFjJUnBYFDp6enKycnpttbn8ykYDF7zderr6xUOh+NHe3t7T0cCAPQjqT19Ym1trY4fP64DBw7c1AAej0cej+emXgMA0P/06Apo/vz52r17t15//XUNHz48ft7v9+vKlSvq6Ojotj4UCsnv99/UoACA20tCAXLOaf78+dq+fbv279+v4uLibo9PnDhRaWlpamxsjJ9ra2vT2bNnVV5e3jsTAwBuCwl9C662tlZbtmzRzp07lZWVFf+5jtfrVWZmprxerx555BEtWrRIQ4cOVXZ2tp544gmVl5df8x1wAICBK6EArVu3TpJ07733dju/adMmPfjgg5KkF154QcnJyaqqqlI0GlVlZaVeeumlXhkWAHD7uKnfA7oVIpGIvF4vvwcEAP3U5/J7QAAA9BQBAgCYIEAAABMECABgggABAEz0+FY86N/2njt6w2srC8bfsjkADFxcAQEATBAgAIAJAgQAMEGAAAAmCBAAwAQBAgCYIEAAABMECABgggABAEwQIACACW7FM0Bxex0A1rgCAgCYIEAAABMECABgggABAEwQIACACQIEADBBgAAAJggQAMAEAQIAmCBAAAATBAgAYIIA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",
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Make an image with four squares that we can mess about with layer\n",
"# You can consider this to be the image you present via the projector.\n",
"\n",
"im_size = 100;\n",
"im = np.zeros((im_size,im_size))\n",
"\n",
"# Some single hot pixels\n",
"im[25,25]=1\n",
"im[10,75]=1\n",
"im[75,25]=1\n",
"im[60,60]=1\n",
"im = im*100;\n",
"# Dilate to generate the squares\n",
"kernel = np.ones((3, 3)) # 3x3 kernel; you can adjust size\n",
"im = cv2.dilate(im, kernel, iterations=1)\n",
"\n",
"plt.imshow(im);"
]
},
{
"cell_type": "code",
"execution_count": 69,
"id": "268d6f0b",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAaAAAAGgCAYAAADsNrNZAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy88F64QAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAaV0lEQVR4nO3dfXCU9b338U+STTaxkA0EsyGaQOrhPkHAEXkMMK3WnDJKWyjU1hlsIzqlahACc6ukNXRahaCdUcRRLEyleApSmSkiTqvDBMkMx8hDLFZKCXTklIy4i06bXQQJMfu7/+A+1/ESUDYPfDfk/ZrZmb0edvnm5+jbK9cmpDnnnAAAuMTSrQcAAPRNBAgAYIIAAQBMECAAgAkCBAAwQYAAACYIEADABAECAJggQAAAEwQIAGCixwL0zDPPaOjQocrOztaECRO0e/funvqjAAC9UFpP/C643//+9/rRj36k5557ThMmTNCKFSu0adMmNTc3q6Cg4Atfm0gkdOzYMfXv319paWndPRoAoIc553TixAkVFRUpPf0LrnNcDxg/fryrqqrytjs6OlxRUZGrq6v70te2tLQ4STx48ODBo5c/WlpavvC/9wF1szNnzqipqUk1NTXevvT0dFVUVKixsfGc89va2tTW1uZtu/9/QTZFtyqgzO4eDwDQwz5Vu3bqj+rfv/8XntftAfroo4/U0dGhcDjs2x8Oh3Xw4MFzzq+rq9MvfvGL8wyWqUAaAQKAXufsdcSX3kYx/xRcTU2NYrGY92hpabEeCQBwCXT7FdCgQYOUkZGhaDTq2x+NRlVYWHjO+cFgUMFgsLvHAACkuG6/AsrKytKYMWNUX1/v7UskEqqvr1d5eXl3/3EAgF6q26+AJGnRokWqrKzU2LFjNX78eK1YsUInT57UnDlzeuKPAwD0Qj0SoB/84Af68MMPtWTJEkUiEV1//fV67bXXzvlgAgCg7+qRH0Tting8rlAopBs1nU/BAUAv9Klr1w5tUSwWU25u7gXPM/8UHACgbyJAAAATBAgAYIIAAQBMECAAgAkCBAAwQYAAACYIEADABAECAJggQAAAEwQIAGCCAAEATBAgAIAJAgQAMEGAAAAmCBAAwESP/I2oAC5zaWm+zQ/vmeg9/9e4dt+xQQVx3/bAbx3qubnQq3AFBAAwQYAAACYIEADABPeAACTPOd/mPfO3eM/nho594UtvuWKSbztx6lT3zYVehSsgAIAJAgQAMMG34AB02VMHbvKezy1f/4XnfnLjCN928I97emQmpD6ugAAAJggQAMAEAQIAmOAeEIAuK1id4z0fv/Ve37Erd7zv2w7+N/d8cBZXQAAAEwQIAGCCAAEATHAPCECXZb2+93+ff+7Yp5d2FPQiXAEBAEwQIACACQIEADBBgAAAJggQAMAEAQIAmCBAAAATBAgAYIIAAQBMECAAgAkCBAAwQYAAACYIEADABAECAJggQAAAEwQIAGCCAAEATBAgAIAJAgQAMEGAAAAmCBAAwAQBAgCYIEAAABMECABgggABAEwQIACACQIEADBBgAAAJggQAMAEAQIAmCBAAAATSQWorq5O48aNU//+/VVQUKAZM2aoubnZd87p06dVVVWl/Px89evXT7NmzVI0Gu3WoQEAvV9SAWpoaFBVVZXeeustbdu2Te3t7frmN7+pkydPeucsXLhQW7du1aZNm9TQ0KBjx45p5syZ3T44AKB3S3POuc6++MMPP1RBQYEaGhr0ta99TbFYTFdeeaU2bNig733ve5KkgwcPavjw4WpsbNTEiRPPeY+2tja1tbV52/F4XMXFxbpR0xVIy+zsaAAAI5+6du3QFsViMeXm5l7wvC7dA4rFYpKkgQMHSpKamprU3t6uiooK75yysjKVlJSosbHxvO9RV1enUCjkPYqLi7syEgCgl+h0gBKJhKqrqzV58mSNHDlSkhSJRJSVlaW8vDzfueFwWJFI5LzvU1NTo1gs5j1aWlo6OxIAoBcJdPaFVVVV2r9/v3bu3NmlAYLBoILBYJfeAwDQ+3TqCmjevHl69dVX9cYbb+jqq6/29hcWFurMmTNqbW31nR+NRlVYWNilQQEAl5ekAuSc07x587R582Zt375dpaWlvuNjxoxRZmam6uvrvX3Nzc06evSoysvLu2diAMBlIalvwVVVVWnDhg3asmWL+vfv793XCYVCysnJUSgU0t13361FixZp4MCBys3N1f3336/y8vLzfgIOANB3JRWgVatWSZJuvPFG3/61a9fqzjvvlCQ9+eSTSk9P16xZs9TW1qapU6fq2Wef7ZZhAQCXjy79HFBPiMfjCoVC/BwQAPRSl+TngAAA6CwCBAAwQYAAACYIEADABAECAJggQAAAEwQIAGCCAAEATBAgAIAJAgQAMEGAAAAmCBAAwAQBAgCYIEAAABMECABgggABAEwQIACACQIEADBBgAAAJggQAMAEAQIAmCBAAAATBAgAYIIAAQBMECAAgAkCBAAwQYAAACYC1gPg0ki//lrfdmLfAaNJAOAsroAAACYIEADABAECAJjgHtBl5Ot/+cR7/tNBzb5j/3X6bd/2L796wyWZCQAuhCsgAIAJAgQAMMG34PqIydn+/9fICBd4zzuixy/1OADAFRAAwAYBAgCYIEAAABPcA7qMPL+/3Ht+7bj3fceWNt/q274y/zMb3AMCYIArIACACQIEADBBgAAAJrgHdBkZdtdB7/mq0//mOzZQh3zbHZdkIgC4MK6AAAAmCBAAwATfgruMJE6fth4BAC4aV0AAABMECABgggABAEwQIACACQIEADBBgAAAJggQAMAEAQIAmCBAAAATBAgAYIIAAQBMECAAgAkCBAAwQYAAACYIEADABAECAJggQAAAE10K0PLly5WWlqbq6mpv3+nTp1VVVaX8/Hz169dPs2bNUjQa7eqcAIDLTKcDtGfPHv3617/Wdddd59u/cOFCbd26VZs2bVJDQ4OOHTummTNndnlQAMDlpVMB+vjjjzV79mytWbNGAwYM8PbHYjH95je/0RNPPKFvfOMbGjNmjNauXas333xTb7311nnfq62tTfF43PcAAFz+OhWgqqoqTZs2TRUVFb79TU1Nam9v9+0vKytTSUmJGhsbz/tedXV1CoVC3qO4uLgzIwEAepmkA7Rx40a9/fbbqqurO+dYJBJRVlaW8vLyfPvD4bAikch536+mpkaxWMx7tLS0JDsSAKAXCiRzcktLixYsWKBt27YpOzu7WwYIBoMKBoPd8l4AgN4jqSugpqYmHT9+XDfccIMCgYACgYAaGhq0cuVKBQIBhcNhnTlzRq2trb7XRaNRFRYWdufcAIBeLqkroJtvvlnvvvuub9+cOXNUVlamhx56SMXFxcrMzFR9fb1mzZolSWpubtbRo0dVXl7efVMDAHq9pALUv39/jRw50rfvK1/5ivLz8739d999txYtWqSBAwcqNzdX999/v8rLyzVx4sTumxoA0OslFaCL8eSTTyo9PV2zZs1SW1ubpk6dqmeffba7/xgAQC+X5pxz1kN8VjweVygU0o2arkBapvU4AIAkferatUNbFIvFlJube8Hz+F1wAAATBAgAYIIAAQBMECAAgAkCBAAwQYAAACYIEADABAECAJggQAAAEwQIAGCCAAEATBAgAIAJAgQAMEGAAAAmCBAAwAQBAgCYIEAAABMECABgggABAEwQIACACQIEADBBgAAAJggQAMAEAQIAmCBAAAATBAgAYIIAAQBMECAAgAkCBAAwQYAAACYIEADABAECAJggQAAAEwQIAGCCAAEATBAgAIAJAgQAMEGAAAAmCBAAwAQBAgCYIEAAABMECABgggABAEwQIACACQIEADBBgAAAJggQAMAEAQIAmCBAAAATAesBABhJz/BtHlk23rd91Zhj3vP/EzruO/bf4z/pubnQZ3AFBAAwQYAAACYIEADABPeAgL4q0eHb/L/Tt/i254aO6UJuuWKS/61Oneq+udBncAUEADBBgAAAJggQAMAE94AASJKeOnCTb3tu+foLnnumfLhvO1Df1CMz4fLGFRAAwAQBAgCY4FtwACRJVz2R6dv+j8Ac73l6w599xwLiW27oOq6AAAAmCBAAwETSAXr//fd1xx13KD8/Xzk5ORo1apT27t3rHXfOacmSJRo8eLBycnJUUVGhw4cPd+vQAIDeL6l7QP/61780efJk3XTTTfrTn/6kK6+8UocPH9aAAQO8cx5//HGtXLlS69atU2lpqWprazV16lQdOHBA2dnZ3f4FAOgeaf+1z79tMwb6kKQC9Nhjj6m4uFhr16719pWWlnrPnXNasWKFHn74YU2fPl2S9MILLygcDuvll1/W7bfffs57trW1qa2tzduOx+NJfxEAgN4nqW/BvfLKKxo7dqxuu+02FRQUaPTo0VqzZo13/MiRI4pEIqqoqPD2hUIhTZgwQY2Njed9z7q6OoVCIe9RXFzcyS8FANCbJBWg9957T6tWrdKwYcP0+uuv695779X8+fO1bt06SVIkEpEkhcNh3+vC4bB37PNqamoUi8W8R0tLS2e+DgBAL5PUt+ASiYTGjh2rZcuWSZJGjx6t/fv367nnnlNlZWWnBggGgwoGg516LQCg90rqCmjw4MG69tprffuGDx+uo0ePSpIKCwslSdFo1HdONBr1jgEAICUZoMmTJ6u5udm379ChQxoyZIiksx9IKCwsVH19vXc8Ho9r165dKi8v74ZxAQCXi6S+Bbdw4UJNmjRJy5Yt0/e//33t3r1bq1ev1urVqyVJaWlpqq6u1qOP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0ahRo7R3717vuHNOS5Ys0eDBg5WTk6OKigodPnzYcOJLr6OjQ7W1tSotLVVOTo6uueYaPfLII75fsMk6dZFLQRs3bnRZWVnu+eefd3/961/dj3/8Y5eXl+ei0aj1aCamTp3q1q5d6/bv3+/27dvnbr31VldSUuI+/vhj75x77rnHFRcXu/r6erd37143ceJEN2nSJMOpbe3evdsNHTrUXXfddW7BggXeftbJuX/+859uyJAh7s4773S7du1y7733nnv99dfd3//+d++c5cuXu1Ao5F5++WX3zjvvuO985zuutLTUffLJJ4aTX1pLly51+fn57tVXX3VHjhxxmzZtcv369XNPPfWUdw7r1DUpGaDx48e7qqoqb7ujo8MVFRW5uro6w6lSx/Hjx50k19DQ4JxzrrW11WVmZrpNmzZ55/ztb39zklxjY6PVmGZOnDjhhg0b5rZt2+a+/vWvewFinc566KGH3JQpUy54PJFIuMLCQverX/3K29fa2uqCwaB78cUXL8WIKWHatGnurrvu8u2bOXOmmz17tnOOdeoOKfctuDNnzqipqUkVFRXevvT0dFVUVKixsdFwstQRi8UkSQMHDpQkNTU1qb293bdmZWVlKikp6ZNrVlVVpWnTpvnWQ2Kd/scrr7yisWPH6rbbblNBQYFGjx6tNWvWeMePHDmiSCTiW6dQKKQJEyb0qXWaNGmS6uvrdejQIUnSO++8o507d+qWW26RxDp1h5T7bdgfffSROjo6FA6HffvD4bAOHjxoNFXqSCQSqq6u1uTJkzVy5EhJUiQSUVZWlvLy8nznhsNhRSIRgyntbNy4UW+//bb27NlzzjHW6az33ntPq1at0qJFi/TTn/5Ue/bs0fz585WVlaXKykpvLc7372BfWqfFixcrHo+rrKxMGRkZ6ujo0NKlSzV79mxJYp26QcoFCF+sqqpK+/fv186dO61HSTktLS1asGCBtm3bpuzsbOtxUlYikdDYsWO1bNkySdLo0aO1f/9+Pffcc6qsrDSeLnW89NJLWr9+vTZs2KARI0Zo3759qq6uVlFREevUTVLuW3CDBg1SRkbGOZ9MikajKiwsNJoqNcybN0+vvvqq3njjDV199dXe/sLCQp05c0atra2+8/vamjU1Nen48eO64YYbFAgEFAgE1NDQoJUrVyoQCCgcDrNOkgYPHqxrr73Wt2/48OE6evSoJHlr0df/HXzggQe0ePFi3X777Ro1apR++MMfauHChaqrq5PEOnWHlAtQVlaWxowZo/r6em9fIpFQfX29ysvLDSez45zTvHnztHnzZm3fvl2lpaW+42PGjFFmZqZvzZqbm3X06NE+tWY333yz3n33Xe3bt897jB07VrNnz/aes07S5MmTz/kY/6FDhzRkyBBJUmlpqQoLC33rFI/HtWvXrj61TqdOnTrnb/PMyMhQIpGQxDp1C+tPQZzPxo0bXTAYdL/97W/dgQMH3Ny5c11eXp6LRCLWo5m49957XSgUcjt27HAffPCB9zh16pR3zj333ONKSkrc9u3b3d69e115ebkrLy83nDo1fPZTcM6xTs6d/Yh6IBBwS5cudYcPH3br1693V1xxhfvd737nnbN8+XKXl5fntmzZ4v7yl7+46dOn97mPF1dWVrqrrrrK+xj2H/7wBzdo0CD34IMPeuewTl2TkgFyzrmnn37alZSUuKysLDd+/Hj31ltvWY9kRtJ5H2vXrvXO+eSTT9x9993nBgwY4K644gr33e9+133wwQd2Q6eIzweIdTpr69atbuTIkS4YDLqysjK3evVq3/FEIuFqa2tdOBx2wWDQ3Xzzza65udloWhvxeNwtWLDAlZSUuOzsbPfVr37V/exnP3NtbW3eOaxT1/D3AQEATKTcPSAAQN9AgAAAJggQAMAEAQIAmCBAAAATBAgAYIIAAQBMECAAgAkCBAAwQYAAACYIEADAxP8DydCH9wWf3nAAAAAASUVORK5CYII=",
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Let's use an affine transformation to rotate and scale this image\n",
"# The resulting image you can consider to be the image you record with your camera\n",
"# The goal will be to de-rotate and de-scale this.\n",
"\n",
"# Define the rotation angle and scale\n",
"angle = 12 # Rotation in degrees\n",
"scale = 0.94 # Scaling factor\n",
"\n",
"# Calculate the center of the image\n",
"center = (im_size // 2, im_size // 2)\n",
"\n",
"# Compute the transformation matrix for rotation and scaling\n",
"M = cv2.getRotationMatrix2D(center, angle, scale)\n",
"\n",
"# Apply the affine transformation\n",
"transformed_im = cv2.warpAffine(im, M, (im_size, im_size))\n",
"\n",
"plt.imshow(transformed_im);"
]
},
{
"cell_type": "code",
"execution_count": 70,
"id": "251fd355",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Orig centroids found using regionprops\n",
"x: 75.0 y: 10.0\n",
"x: 25.0 y: 25.0\n",
"x: 60.0 y: 60.0\n",
"x: 25.0 y: 75.0\n"
]
}
],
"source": [
"# Find the original centroid locations by looking for the bright spots\n",
"\n",
"ret,thresh_orig = cv2.threshold(im,80,100,cv2.THRESH_BINARY) #Threshold\n",
"labels = measure.label(thresh_orig, background=0) #Make a label image\n",
"regions_orig = measure.regionprops(labels) #Find the bright things\n",
"\n",
"# Report to screen what was found\n",
"print(\"Orig centroids found using regionprops\")\n",
"for props in regions_orig:\n",
" y0, x0 = props.centroid\n",
" print(\"x: %0.1f y: %0.1f\" % (x0, y0))\n",
"\n",
"# generate an array (we will use this later to do the affine registration)\n",
"orig_centroids = np.array([p.centroid for p in regions_orig])"
]
},
{
"cell_type": "code",
"execution_count": 71,
"id": "fd22dd81",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Transformed centroids\n",
"x: 65.2 y: 8.4\n",
"x: 22.0 y: 31.7\n",
"x: 61.2 y: 57.4\n",
"x: 31.7 y: 78.0\n"
]
}
],
"source": [
"# Same again but for the transformed centroids\n",
"print(\"Transformed centroids\")\n",
"ret,thresh_transformed = cv2.threshold(transformed_im,80,100,cv2.THRESH_BINARY) \n",
"labels = measure.label(thresh_transformed, background=0)\n",
"regions_transformed = measure.regionprops(labels)\n",
"\n",
"for props in regions_transformed:\n",
" y0, x0 = props.centroid\n",
" print(\"x: %0.1f y: %0.1f\" % (x0, y0))\n",
" \n",
"# generate an array (we will use this later to do the affine registration)\n",
"transformed_centroids = np.array([p.centroid for p in regions_transformed])"
]
},
{
"cell_type": "markdown",
"id": "8891801f",
"metadata": {},
"source": [
"## Register with an affine transform\n",
"We must register with an affine transform. This will attempt to re-rotate and re-scale the transformed image. The `estimate_transform` command does an affine transform using pairs of points (not images). So the points in the matrices above need to be in the same order. The above matrices may need sorting if they are not in the same order. You can sort based on Y position. If doing this in reality, the ideal way is to present each stimulus patch one at a time. \n"
]
},
{
"cell_type": "code",
"execution_count": 72,
"id": "ce053a21",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[ 0.92442426 -0.19007152 13.38134811]\n",
" [ 0.19564294 0.92386368 -6.01494861]\n",
" [ 0. 0. 1. ]]\n"
]
}
],
"source": [
"tform = estimate_transform('affine', orig_centroids, transformed_centroids)\n",
"par = tform.params\n",
"print(par) # the estimated affine transformation matrix (in homogeneous coordinates)\n"
]
},
{
"cell_type": "code",
"execution_count": 73,
"id": "08485e5d",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Actual rotation angle: 12.00 ; calculated de-rotation angle: 11.95\n",
"Actual scale factor: 0.94 ; calculated re-scale factor: 0.94\n"
]
}
],
"source": [
"# To confirm we are getting sensible stuff, let's display to screen the calculated re-scale and de-rotation values. \n",
"\n",
"# Extract the components of the matrix\n",
"a, b, c = par[0, 0], par[0, 1], par[0, 2]\n",
"d, e, f = par[1, 0], par[1, 1], par[1, 2]\n",
"\n",
"# Calculate the scale factors\n",
"scale_x = np.sqrt(a**2 + d**2)\n",
"scale_y = np.sqrt(b**2 + e**2)\n",
"\n",
"# Calculate the rotation angle (in radians)\n",
"theta = np.arctan2(d, a)\n",
"\n",
"# Convert the rotation angle to degrees\n",
"derotation_angle = np.degrees(theta)\n",
"\n",
"\n",
"# Let's demonstrate that this works\n",
"print(\"Actual rotation angle: %0.2f ; calculated de-rotation angle: %0.2f\" % (angle,derotation_angle))\n",
"print(\"Actual scale factor: %0.2f ; calculated re-scale factor: %0.2f\" % (scale, np.mean([scale_x,scale_y])))"
]
},
{
"cell_type": "code",
"execution_count": 74,
"id": "36d8d7c9",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Text(0.5, 1.0, 'Original')"
]
},
"execution_count": 74,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAA9EAAAHoCAYAAABO2mw/AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy88F64QAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAwRElEQVR4nO3deXRV5b0//k8gEMIU5oQgQ7AsccAfFgQBx8ottbTFilpbtGi9VVsc0FYFr2DVKg5dlaut47I41KHaOlTb6vWi0ustomLROiFWVKomVJQEQRDJ/v3R6/l6DOITODEBX6+19lrs5zx755NH5JN39tn7FGVZlgUAAADwqVo1dwEAAACwtRCiAQAAIJEQDQAAAImEaAAAAEgkRAMAAEAiIRoAAAASCdEAAACQSIgGAACAREI0AAAAJBKiYRvx+OOPx+jRo6NDhw5RVFQUixYtau6SCuK6666LoqKieOWVV5q7FAD4TPzkJz+JoqKizTr2s+ibr7zyShQVFcV1113XZF8DWjIhGj6mqKgoaXv44Yebu9Sc9evXxyGHHBJvv/12XHLJJXHjjTdG//79m7ssAPjcefbZZ+Pwww+PPn36RElJSVRWVsakSZPi2Wefbe7SgAIpbu4CoKW58cYb8/ZvuOGGeOCBBxqM77jjjp9lWZv097//PV599dW45ppr4t///d+buxwA+Fy644474tvf/nZ069Ytjj766KiqqopXXnklrr322vjtb38bt956a3zzm9/81POceeaZMW3atM2q4YgjjojDDjssSkpKNut44NMJ0fAxhx9+eN7+o48+Gg888ECD8Y9bs2ZNtG/fvilL+0TLly+PiIguXboU7JyrV6+ODh06FOx8ALAt+/vf/x5HHHFEDBw4MP785z9Hz549c6+ddNJJsddee8URRxwRTz/9dAwcOHCj5/iw9xYXF0dx8eb9mN66deto3br1Zh0LpPF2btgM++67b+yyyy6xcOHC2HvvvaN9+/ZxxhlnRETE3XffHePHj4/KysooKSmJ7bffPs4999zYsGHDRs/x3HPPxX777Rft27ePPn36xEUXXdTg61122WWx8847R/v27aNr164xfPjwuPnmmyMi4sgjj4x99tknIiIOOeSQKCoqin333Td37IMPPhh77bVXdOjQIbp06RITJkyI559/Pu/8H9579dxzz8V3vvOd6Nq1a+y5554RETFgwID42te+Fg8//HAMHz48SktLY8iQIbm3s99xxx0xZMiQaNeuXQwbNiz++te/Nqj/hRdeiIMPPji6desW7dq1i+HDh8fvf//7BvOeffbZ+NKXvhSlpaWx3XbbxU9/+tOor69P/K8CAM3n4osvjjVr1sTVV1+dF6AjInr06BFXXXVVrF69OtfnN9V7N3ZP9HvvvRcnnnhi9OjRIzp16hTf+MY34vXXX4+ioqL4yU9+kpu3sXuiP+zljzzySIwYMSLatWsXAwcOjBtuuCHva7z99tvx4x//OIYMGRIdO3aMzp07xwEHHBBPPfVUAVcKtn6uRMNmWrFiRRxwwAFx2GGHxeGHHx7l5eUR8a/m1bFjxzjllFOiY8eO8eCDD8bMmTOjrq4uLr744rxzvPPOO/GVr3wlDjrooDj00EPjt7/9bZx++ukxZMiQOOCAAyIi4pprrokTTzwxDj744DjppJNi7dq18fTTT8eCBQviO9/5Thx77LHRp0+fOP/88+PEE0+M3XffPVfLf//3f8cBBxwQAwcOjJ/85Cfx3nvvxWWXXRZjxoyJJ598MgYMGJBXzyGHHBKDBg2K888/P7Isy42/9NJLua91+OGHx89+9rP4+te/HldeeWWcccYZ8cMf/jAiImbNmhWHHnpoLF68OFq1+tfv6J599tkYM2ZM9OnTJ6ZNmxYdOnSI2267LQ488MD43e9+l3tbW3V1dey3337xwQcf5OZdffXVUVpaWvj/eABQYPfcc08MGDAg9tprr42+vvfee8eAAQPiD3/4Q974J/XejzvyyCPjtttuiyOOOCL22GOPmDdvXowfPz65vpdeeikOPvjgOProo2Py5Mnxq1/9Ko488sgYNmxY7LzzzhER8fLLL8ddd90VhxxySFRVVUVNTU1cddVVsc8++8Rzzz0XlZWVyV8PtmkZsElTpkzJPv6/yj777JNFRHbllVc2mL9mzZoGY8cee2zWvn37bO3atQ3OccMNN+TG1q1bl1VUVGQTJ07MjU2YMCHbeeedN1njQw89lEVEdvvtt+eNDx06NOvVq1e2YsWK3NhTTz2VtWrVKvvud7+bGzvrrLOyiMi+/e1vNzh3//79s4jI/vKXv+TG7r///iwistLS0uzVV1/NjV911VVZRGQPPfRQbmz//ffPhgwZkve919fXZ6NHj84GDRqUG5s6dWoWEdmCBQtyY8uXL8/KysqyiMiWLl26yTUAgOaycuXKLCKyCRMmbHLeN77xjSwisrq6uk323g9f+9DChQuziMimTp2aN+/II4/MIiI766yzcmNz5sxp0Dc/7OV//vOfc2PLly/PSkpKsh/96Ee5sbVr12YbNmzI+xpLly7NSkpKsnPOOSdvLCKyOXPmbPL7hW2Vt3PDZiopKYmjjjqqwfhHr5yuWrUq3nrrrdhrr71izZo18cILL+TN7dixY9691m3bto0RI0bEyy+/nBvr0qVL/OMf/4jHH3+8UfW9+eabsWjRojjyyCOjW7duufFdd901/u3f/i3++Mc/NjjmuOOO2+i5dtpppxg1alRuf+TIkRER8aUvfSn69evXYPzD+t9+++148MEH49BDD82txVtvvRUrVqyIcePGxZIlS+L111+PiIg//vGPsccee8SIESNy5+vZs2dMmjSpUd83AHzWVq1aFRERnTp12uS8D1+vq6vLjX1S7/2o++67LyIi986vD51wwgnJNe600055V8l79uwZO+ywQ97PHCUlJbl3km3YsCFWrFgRHTt2jB122CGefPLJ5K8F2zohGjZTnz59om3btg3Gn3322fjmN78ZZWVl0blz5+jZs2cuKNfW1ubN3W677Rrc89S1a9d45513cvunn356dOzYMUaMGBGDBg2KKVOmxP/+7/9+an2vvvpqRETssMMODV7bcccd46233orVq1fnjVdVVW30XB8NyhERZWVlERHRt2/fjY5/WP9LL70UWZbFjBkzomfPnnnbWWedFRH/76For776agwaNKjB195Y/QDQknwYjj8M059kY2H7k3rvR7366qvRqlWrBnO/8IUvJNf48V4e0fBnjvr6+rjkkkti0KBBUVJSEj169IiePXvG008/3eBnGPg8c080bKaN3au7cuXK2GeffaJz585xzjnnxPbbbx/t2rWLJ598Mk4//fQGD8n6pKdnZh+5J2rHHXeMxYsXx7333hv33Xdf/O53v4vLL788Zs6cGWeffXaTf0+bqvPT6v/w+/3xj38c48aN2+jcxvwAAAAtUVlZWfTu3TuefvrpTc57+umno0+fPtG5c+fc2Gf17I+UnznOP//8mDFjRnzve9+Lc889N7p16xatWrWKqVOnetAnfIQQDQX08MMPx4oVK+KOO+6IvffeOze+dOnSLTpvhw4d4lvf+lZ861vfivfffz8OOuigOO+882L69OnRrl27jR7Tv3//iIhYvHhxg9deeOGF6NGjR5N/hNWHH+HRpk2bGDt27Cbn9u/fP5YsWdJgfGP1A0BL87WvfS2uueaaeOSRR3JP2f6o//mf/4lXXnkljj322Eafu3///lFfXx9Lly7Ne9fWSy+9tEU1f9xvf/vb2G+//eLaa6/NG1+5cmX06NGjoF8Ltmbezg0F9OFveT/6W933338/Lr/88s0+54oVK/L227ZtGzvttFNkWRbr16//xON69+4dQ4cOjeuvvz5WrlyZG3/mmWfiv/7rv+KrX/3qZteUqlevXrHvvvvGVVddFW+++WaD1//5z3/m/vzVr341Hn300XjsscfyXr/pppuavE4A2FKnnnpqlJaWxrHHHtugd7/99ttx3HHHRfv27ePUU09t9Lk/fDfXx3+euOyyyza/4I1o3bp1gyeE33777bnnlwD/4ko0FNDo0aOja9euMXny5DjxxBOjqKgobrzxxk1+ZMWn+fKXvxwVFRUxZsyYKC8vj+effz5+8YtfxPjx4z/1ASYXX3xxHHDAATFq1Kg4+uijcx9xVVZWlveZkk3pl7/8Zey5554xZMiQ+P73vx8DBw6MmpqamD9/fvzjH//IffbkaaedFjfeeGN85StfiZNOOin3EVf9+/f/1LfHAUBzGzRoUFx//fUxadKkGDJkSBx99NFRVVUVr7zySlx77bXx1ltvxS233BLbb799o889bNiwmDhxYsyePTtWrFiR+4irF198MSKiwfNVNtfXvva1OOecc+Koo46K0aNHx9/+9re46aabcu8sA/5FiIYC6t69e9x7773xox/9KM4888zo2rVrHH744bH//vt/4j3Bn+bYY4+Nm266KX7+85/Hu+++G9ttt12ceOKJceaZZ37qsWPHjo377rsvzjrrrJg5c2a0adMm9tlnn7jwwguTHmRSCDvttFM88cQTcfbZZ8d1110XK1asiF69esVuu+0WM2fOzM3r3bt3PPTQQ3HCCSfEBRdcEN27d4/jjjsuKisr4+ijj/5MagWALXHIIYfE4MGDY9asWbng3L1799hvv/3ijDPOiF122WWzz33DDTdERUVF3HLLLXHnnXfG2LFj4ze/+U3ssMMOn3hrV2OdccYZsXr16rj55pvjN7/5TXzxi1+MP/zhDzFt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v//9rEuXLllNTU1zl9bijRs3LpszZ072zDPPZIsWLcq++tWvZv369cvefffd3Jzjjjsu69u3bzZ37tzsiSeeyPbYY49s9OjRzVj11uGxxx7LBgwYkO26667ZSSedlBu3no3z9ttvZ/3798+OPPLIbMGCBdnLL7+c3X///dlLL72Um3PBBRdkZWVl2V133ZU99dRT2Te+8Y2sqqoqe++995qx8pbrvPPOy7p3757de++92dKlS7Pbb78969ixY/af//mfuTnWlJZGr98y+n3T0e8LQ78vLL2+ZWmRIXrEiBHZlClTcvsbNmzIKisrs1mzZjVjVVun5cuXZxGRzZs3L8uyLFu5cmXWpk2b7Pbbb8/Nef7557OIyObPn99cZbZ4q1atygYNGpQ98MAD2T777JNrqtaz8U4//fRszz33/MTX6+vrs4qKiuziiy/Oja1cuTIrKSnJbrnlls+ixK3O+PHjs+9973t5YwcddFA2adKkLMusKS2TXl9Y+n1h6PeFo98Xll7fsrS4t3O///77sXDhwhg7dmxurFWrVjF27NiYP39+M1a2daqtrY2IiG7dukVExMKFC2P9+vV56zt48ODo16+f9d2EKVOmxPjx4/PWLcJ6bo7f//73MXz48DjkkEOiV69esdtuu8U111yTe33p0qVRXV2dt6ZlZWUxcuRIa/oJRo8eHXPnzo0XX3wxIiKeeuqpeOSRR+KAAw6ICGtKy6PXF55+Xxj6feHo94Wl17csxc1dwMe99dZbsWHDhigvL88bLy8vjxdeeKGZqto61dfXx9SpU2PMmDGxyy67REREdXV1tG3bNrp06ZI3t7y8PKqrq5uhypbv1ltvjSeffDIef/zxBq9Zz8Z7+eWX44orrohTTjklzjjjjHj88cfjxBNPjLZt28bkyZNz67axfwOs6cZNmzYt6urqYvDgwdG6devYsGFDnHfeeTFp0qSICGtKi6PXF5Z+Xxj6fWHp94Wl17csLS5EUzhTpkyJZ555Jh555JHmLmWrtWzZsjjppJPigQceiHbt2jV3OduE+vr6GD58eJx//vkREbHbbrvFM888E1deeWVMnjy5mavbOt12221x0003xc033xw777xzLFq0KKZOnRqVlZXWFD4H9Pstp98Xnn5fWHp9y9Li3s7do0ePaN26dYOnHdbU1ERFRUUzVbX1Of744+Pee++Nhx56KLbbbrvceEVFRbz//vuxcuXKvPnWd+MWLlwYy5cvjy9+8YtRXFwcxcXFMW/evLj00kujuLg4ysvLrWcj9e7dO3baaae8sR133DFee+21iIjcuvk3IN2pp54a06ZNi8MOOyyGDBkSRxxxRJx88skxa9asiLCmtDx6feHo94Wh3xeefl9Yen3L0uJCdNu2bWPYsGExd+7c3Fh9fX3MnTs3Ro0a1YyVbR2yLIvjjz8+7rzzznjwwQejqqoq7/Vhw4ZFmzZt8tZ38eLF8dprr1nfjdh///3jb3/7WyxatCi3DR8+PCZNmpT7s/VsnDFjxjT4GJYXX3wx+vfvHxERVVVVUVFRkbemdXV1sWDBAmv6CdasWROtWuX/c966deuor6+PCGtKy6PXbzn9vrD0+8LT7wtLr29hmvvJZhtz6623ZiUlJdl1112XPffcc9kxxxyTdenSJauurm7u0lq8H/zgB1lZWVn28MMPZ2+++WZuW7NmTW7Occcdl/Xr1y978MEHsyeeeCIbNWpUNmrUqGaseuvy0ad1Zpn1bKzHHnssKy4uzs4777xsyZIl2U033ZS1b98++/Wvf52bc8EFF2RdunTJ7r777uzpp5/OJkyY4CMaNmHy5MlZnz59ch97cccdd2Q9evTITjvttNwca0pLo9dvGf2+6en3W0a/Lyy9vmVpkSE6y7Lssssuy/r165e1bds2GzFiRPboo482d0lbhYjY6DZnzpzcnPfeey/74Q9/mHXt2jVr37599s1vfjN78803m6/orczHm6r1bLx77rkn22WXXbKSkpJs8ODB2dVXX533en19fTZjxoysvLw8Kykpyfbff/9s8eLFzVRty1dXV5eddNJJWb9+/bJ27dplAwcOzP7jP/4jW7duXW6ONaUl0us3n37f9PT7LaffF45e37IUZVmWNc81cAAAANi6tLh7ogEAAKClEqIBAAAgkRANAAAAiYRoAAAASCREAwAAQCIhGgAAABIJ0QAAAJBIiAYAAIBEQjQAAAAkEqIBAAAgkRANAAAAif5/2O5Xzf8A20sAAAAASUVORK5CYII=",
"text/plain": [
"<Figure size 1200x600 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Now we apply the affine transformation to the transformed image and compare it to the original\n",
"UNWARPED = cv2.warpAffine(transformed_im, par[:2, :], (im_size, im_size))\n",
"\n",
"fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 6))\n",
"\n",
"ax1.imshow(UNWARPED);\n",
"ax1.set_title('Transformed')\n",
"ax2.imshow(im);\n",
"ax2.set_title('Original')\n"
]
},
{
"cell_type": "code",
"execution_count": 76,
"id": "a5204ef9",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<matplotlib.image.AxesImage at 0x13d57fd30>"
]
},
"execution_count": 76,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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LtXW1qbzrQAAV7uBX/+Y1dfX2zXXXJO4DfvNN9+0cePG2RNPPJE4p6mpycrKymzLli124MABW7BgAbdhMxgMxggcGb0NOxaL2dKlS62ystKKiors2muvtaefftp6e3sT58TjcVu5cqWFQiELBAI2d+5c6+joGPD3IEAMBoNxdYzLBSjHrN/HGGSBWCymYDDoPQ0AwCBFo1GVlpZe9DifBQcAcEGAAAAuCBAAwAUBAgC4IEAAABcECADgggABAFwQIACACwIEAHBBgAAALggQAMAFAQIAuCBAAAAXBAgA4IIAAQBcECAAgAsCBABwQYAAAC4IEADABQECALggQAAAFwQIAOCCAAEAXBAgAIALAgQAcEGAAAAuCBAAwAUBAgC4IEAAABcECADgggABAFwQIACACwIEAHBBgAAALggQAMAFAQIAuCBAAAAXBAgA4IIAAQBcECAAgAsCBABwQYAAAC4IEADABQECALggQAAAFwQIAOCCAAEAXBAgAIALAgQAcEGAAAAuCBAAwAUBAgC4IEAAABcECADgggABAFwQIACACwIEAHBBgAAALggQAMAFAQIAuCBAAAAXBAgA4IIAAQBcZF2AzMx7CgCADLjcz/OsC9CpU6e8pwAAyIDL/TzPsSy75IjH4zp+/LjMTJWVlers7FRpaan3tLJWLBZTRUUF63QZrNPAsE4Dwzpdmpnp1KlTmjhxonJzL36dk/8lzmlAcnNzNWnSJMViMUlSaWkp/4EHgHUaGNZpYFingWGdLi4YDF72nKx7CQ4AMDIQIACAi6wNUCAQ0M9//nMFAgHvqWQ11mlgWKeBYZ0GhnXKjKy7CQEAMDJk7RUQAODqRoAAAC4IEADABQECALggQAAAF1kboBdeeEFTpkxRUVGRZs2apd27d3tPyU1jY6NuvfVWlZSUaPz48brrrrvU0dGRdE5PT48aGhpUXl6u0aNHa9GiRerq6nKacXZoampSTk6Oli1bltjHOn3h448/1n333afy8nIVFxfrpptu0t69exPHzUyrVq3ShAkTVFxcrLq6Oh0+fNhxxl++vr4+rVy5UlVVVSouLtZ1112n1atXJ33AJus0SJaFNm3aZIWFhfb73//e/v73v9uPfvQjKysrs66uLu+puZg3b56tX7/eDh48aPv27bPvfOc7VllZaZ999lninIceesgqKiqspaXF9u7da7fddpvNnj3bcda+du/ebVOmTLGbb77Zli5dmtjPOpl9+umnNnnyZPvBD35gu3btsiNHjtg777xj//znPxPnNDU1WTAYtM2bN9v+/fvtzjvvtKqqKjtz5ozjzL9ca9assfLyctu2bZsdPXrUmpubbfTo0fbcc88lzmGdBicrAzRz5kxraGhIbPf19dnEiROtsbHRcVbZ4+TJkybJWltbzcysu7vbCgoKrLm5OXHORx99ZJKsra3Na5puTp06ZVOnTrXt27fb7bffnggQ6/SFJ5980r7xjW9c9Hg8HrdwOGzPPvtsYl93d7cFAgF7/fXXv4wpZoX58+fbAw88kLRv4cKFtnjxYjNjnTIh616CO3v2rNrb21VXV5fYl5ubq7q6OrW1tTnOLHtEo1FJ0tixYyVJ7e3tOnfuXNKaVVdXq7KyckSuWUNDg+bPn5+0HhLr9P+9/fbbqqmp0T333KPx48dr+vTpevnllxPHjx49qkgkkrROwWBQs2bNGlHrNHv2bLW0tOjQoUOSpP3792vnzp264447JLFOmZB1n4b9ySefqK+vT6FQKGl/KBTSP/7xD6dZZY94PK5ly5Zpzpw5mjZtmiQpEomosLBQZWVlSeeGQiFFIhGHWfrZtGmT3n//fe3Zs+e8Y6zTF44cOaIXX3xRy5cv109/+lPt2bNHjz32mAoLC1VfX59Yiwv9PziS1umpp55SLBZTdXW18vLy1NfXpzVr1mjx4sWSxDplQNYFCJfW0NCggwcPaufOnd5TyTqdnZ1aunSptm/frqKiIu/pZK14PK6amho988wzkqTp06fr4MGDWrdunerr651nlz3eeOMNbdiwQRs3btSNN96offv2admyZZo4cSLrlCFZ9xLcuHHjlJeXd96dSV1dXQqHw06zyg5LlizRtm3b9O6772rSpEmJ/eFwWGfPnlV3d3fS+SNtzdrb23Xy5Endcsstys/PV35+vlpbW/X8888rPz9foVCIdZI0YcIE3XDDDUn7rr/+eh07dkySEmsx0v8f/MlPfqKnnnpK9957r2666SZ973vf0+OPP67GxkZJrFMmZF2ACgsLNWPGDLW0tCT2xeNxtbS0qLa21nFmfsxMS5Ys0VtvvaUdO3aoqqoq6fiMGTNUUFCQtGYdHR06duzYiFqzuXPn6oMPPtC+ffsSo6amRosXL048Zp2kOXPmnHcb/6FDhzR58mRJUlVVlcLhcNI6xWIx7dq1a0St0+nTp8/7bZ55eXmKx+OSWKeM8L4L4kI2bdpkgUDA/vCHP9iHH35oP/7xj62srMwikYj31Fw8/PDDFgwG7a9//audOHEiMU6fPp0456GHHrLKykrbsWOH7d2712pra622ttZx1tmh/11wZqyT2Re3qOfn59uaNWvs8OHDtmHDBhs1apS99tpriXOampqsrKzMtmzZYgcOHLAFCxaMuNuL6+vr7Zprrknchv3mm2/auHHj7IknnkicwzoNTlYGyMzs17/+tVVWVlphYaHNnDnT3nvvPe8puZF0wbF+/frEOWfOnLFHHnnExowZY6NGjbK7777bTpw44TfpLJEaINbpC1u3brVp06ZZIBCw6upqe+mll5KOx+NxW7lypYVCIQsEAjZ37lzr6Ohwmq2PWCxmS5cutcrKSisqKrJrr73Wnn76aevt7U2cwzoNDr8PCADgIuveAwIAjAwECADgggABAFwQIACACwIEAHBBgAAALggQAMAFAQIAuCBAAAAXBAgA4IIAAQBc/D+0+gLZore1pgAAAABJRU5ErkJggg==",
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"rgb_image = np.zeros((im_size, im_size, 3), dtype=np.uint8)\n",
"rgb_image[:, :, 0] = im\n",
"rgb_image[:, :, 1] = UNWARPED\n",
"\n",
"# Not amazing, but close. I wonder why it's not perfect??\n",
"plt.imshow(rgb_image)\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "10352fac",
"metadata": {},
"outputs": [],
"source": []
}
],
"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": 5
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment