{ "cells": [ { "cell_type": "markdown", "id": "d236e728-86ed-4f1c-93fe-544bc07ac8d5", "metadata": {}, "source": [ "# Computing with images\n", "\n", "We have seen in the last chapter that images exist in the form of Numpy arrays. We will here see different types of image processing computations that we can do with such arrays such as arithmetic operations, combining images etc.\n", "\n", "We have seen in the last chapter that we could create images using e.g. the ```np.random.random``` function. Let's create two tiny images:" ] }, { "cell_type": "code", "execution_count": 5, "id": "7bc5c285-a17b-460e-bbf1-bd8050093ad3", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[1., 1., 1., 1., 1.],\n", " [1., 1., 1., 1., 1.],\n", " [1., 1., 1., 1., 1.]])" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import numpy as np\n", "\n", "image1 = np.ones((3,5))\n", "image1" ] }, { "cell_type": "code", "execution_count": 6, "id": "067853b6-f3fa-4c11-a768-30ca5fd8cc6d", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[0.27194417, 0.30500551, 0.88970898, 0.74560188, 0.91738941],\n", " [0.98418878, 0.2635199 , 0.25729652, 0.22427242, 0.39387982],\n", " [0.59095273, 0.90222827, 0.4722848 , 0.05913885, 0.96609068]])" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "image2 = np.random.random((3,5))\n", "image2" ] }, { "cell_type": "markdown", "id": "021b84f4-f74a-4c74-80b7-85b4aa3b8836", "metadata": {}, "source": [ "## Simple calculus\n", "\n", "As a recap from last chapter, we have seen that we can do arithemtics with images just as we would with simple numbers:" ] }, { "cell_type": "code", "execution_count": 8, "id": "d8f0ad23-6616-4056-a34a-cffd04d8cd95", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[4., 4., 4., 4., 4.],\n", " [4., 4., 4., 4., 4.],\n", " [4., 4., 4., 4., 4.]])" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "image1_plus = image1 + 3\n", "image1_plus" ] }, { "cell_type": "markdown", "id": "fe7a7149-698c-4286-86a8-7514743abbaa", "metadata": {}, "source": [ "This is valid for all basis operations like addition, multiplication etc. Even raising to a given power works:" ] }, { "cell_type": "code", "execution_count": 27, "id": "3a2e5a3d-b132-4d53-b82d-c5d9006e1213", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[16., 16., 16., 16., 16.],\n", " [16., 16., 16., 16., 16.],\n", " [16., 16., 16., 16., 16.]])" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "image1_plus ** 2" ] }, { "cell_type": "markdown", "id": "b201825f-d0b0-41a7-b583-40da2bcbd4e0", "metadata": {}, "source": [ "## Combining images\n", "\n", "If images have the same size, we can here again treat them like simple numbers and do maths with them: again addition, multiplication etc. For example:" ] }, { "cell_type": "code", "execution_count": 28, "id": "30865c30-8ea6-4e97-a743-49094ff6bdfb", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[1.27194417, 1.30500551, 1.88970898, 1.74560188, 1.91738941],\n", " [1.98418878, 1.2635199 , 1.25729652, 1.22427242, 1.39387982],\n", " [1.59095273, 1.90222827, 1.4722848 , 1.05913885, 1.96609068]])" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "image1 + image2" ] }, { "cell_type": "markdown", "id": "14abbe03-718d-4b70-bab6-d7131c4a7f16", "metadata": {}, "source": [ "## Functions pixel by pixel\n", "\n", "In addition of allowing us to create various types of arrays, Numpy also provides us functions that can operate on arrays. In many cases, the input is an image and the output is an image of the same size where *a given function has been applied to each individual pixel*. \n", "\n", "For example we might want to apply a log function to an image to reduce the range of values that pixels can take. Here we would use the ```np.log``` function:" ] }, { "cell_type": "code", "execution_count": 12, "id": "1be0f38c-35df-411e-9961-c2c8285c7288", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[-1.3021585 , -1.18742543, -0.11686086, -0.29356349, -0.08622324],\n", " [-0.01593755, -1.3336264 , -1.35752608, -1.49489381, -0.93170945],\n", " [-0.52601924, -0.10288772, -0.75017308, -2.82786728, -0.03449758]])" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.log(image2)" ] }, { "cell_type": "markdown", "id": "1c5ddcc7-10c2-49b8-8da5-72d3837530e6", "metadata": {}, "source": [ "As we can see the input image had 3 rows and 5 columns and the output image has the same dimensions. You can find many functions in Numpy that operate this way e.g. to take an exponential (```np.exp()```), to do trigonometry (```np.cos()```, ```np.sin()```) etc." ] }, { "cell_type": "markdown", "id": "6a65bd49-255b-4e2f-ac4a-c051a169ddf5", "metadata": {}, "source": [ "## Image statistics\n", "\n", "Another type of functions takes an image as input but returns an output of a different size by computing a statistic on the image or parts of it. For example we can compute the average of *all* ```image2``` pixel values:" ] }, { "cell_type": "code", "execution_count": 32, "id": "00cd34ee-08d3-406f-a8b4-4c31216db5cc", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.5495668473697417" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.mean(image2)" ] }, { "cell_type": "markdown", "id": "87ae0a8f-f6a4-4190-b85f-a17e8a5bd2d2", "metadata": {}, "source": [ "Or we can specify that we want to compute the mean along a certain dimension of the image, in 2D along columns or rows. Let's keep in mind what ```image2``` is:" ] }, { "cell_type": "code", "execution_count": 30, "id": "a75034d0-9110-4ee2-b5a5-0d019a5cc352", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[0.27194417, 0.30500551, 0.88970898, 0.74560188, 0.91738941],\n", " [0.98418878, 0.2635199 , 0.25729652, 0.22427242, 0.39387982],\n", " [0.59095273, 0.90222827, 0.4722848 , 0.05913885, 0.96609068]])" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "image2" ] }, { "cell_type": "markdown", "id": "7bea9efb-5aa4-4501-900a-a9cb13208bf0", "metadata": {}, "source": [ "Now we take the average over columns, which means along the first axis or ```axis=0```:" ] }, { "cell_type": "code", "execution_count": 31, "id": "3fd7a790-9383-40dd-b2ef-21a1b7fc998f", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0.61569523, 0.49025123, 0.53976343, 0.34300438, 0.75911997])" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.mean(image2, axis=0)" ] }, { "cell_type": "markdown", "id": "3069cf2c-362f-494c-a750-3574faf11258", "metadata": {}, "source": [ "The same logic applies to all other statistical functions such as taking the minium (```np.min()```), the maxiumum (```np.max()```), standard deviation (```np.std()```), median (```np.median()```) etc." ] }, { "cell_type": "markdown", "id": "7d94b5a6-7606-4a0a-b88f-93012d50d5b6", "metadata": {}, "source": [ "Note that most of this function can also be called directly on the Numpy array variable. For example" ] }, { "cell_type": "code", "execution_count": 33, "id": "8e77e21e-92bc-48bc-a26d-5cbbe22d0287", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.31182981411327126" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.std(image2)" ] }, { "cell_type": "markdown", "id": "f5b00ab4-c6d0-4ab6-815f-41408d0f5999", "metadata": {}, "source": [ "and" ] }, { "cell_type": "code", "execution_count": 34, "id": "09961793-69ec-412b-9bc9-223f4ff07005", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.31182981411327126" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "image2.std()" ] }, { "cell_type": "markdown", "id": "7c9ecae0-5f2b-4030-9b66-4458bf1bb556", "metadata": {}, "source": [ "are completely equivalent. In the latter case using the dot notation, you might hear that ```std()``` is a *method* of ```image2```." ] }, { "cell_type": "code", "execution_count": null, "id": "371c1e76-38f8-40d8-b983-3ce79e594a4a", "metadata": {}, "outputs": [], "source": [ "Finally we might want to have a look at the actual distribution of pixel values. For this " ] }, { "cell_type": "markdown", "id": "cedbe894-561a-4cab-9001-1410328c0aaf", "metadata": {}, "source": [ "## Exercise\n", "\n", "From the ```numpy.random``` module, find a function that generates **Poisson** noise and creata a 4x9 image. Compute its mean and standard deviation." ] }, { "cell_type": "code", "execution_count": null, "id": "a6470339-1972-433d-92ad-a660403fa671", "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.8.13" } }, "nbformat": 4, "nbformat_minor": 5 }