exercise-09

This commit is contained in:
Andrew Straw 2024-12-08 18:57:48 +01:00
parent cdf30e717a
commit e2838fcb8c
6 changed files with 1732 additions and 0 deletions

View file

@ -42,6 +42,7 @@ http://pythontutor.com/
| exercise-06 | 2024-11-20 | | exercise-06 | 2024-11-20 |
| exercise-07 | 2024-11-27 | | exercise-07 | 2024-11-27 |
| exercise-08 | 2024-12-04 | | exercise-08 | 2024-12-04 |
| exercise-09 | 2024-12-11 |
## Submitting assignments ## Submitting assignments

View file

@ -0,0 +1,419 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# You must run this cell, but you can ignore its contents.\n",
"\n",
"import hashlib\n",
"\n",
"def ads_hash(ty):\n",
" \"\"\"Return a unique string for input\"\"\"\n",
" ty_str = str(ty).encode()\n",
" m = hashlib.sha256()\n",
" m.update(ty_str)\n",
" return m.hexdigest()[:10]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Numpy array for images"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"deletable": false,
"editable": false,
"nbgrader": {
"cell_type": "code",
"checksum": "638fe83e8c7237afbb3ac1af8f16e079",
"grade": false,
"grade_id": "cell-6a738215de5622a5",
"locked": true,
"schema_version": 3,
"solution": false
}
},
"outputs": [],
"source": [
"import numpy as np\n",
"import matplotlib.pyplot as plt"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Images are saved in computers as arrays of numbers. In Python, the library called `numpy` (often abbreviated `np` for short). is the most common way to manipulate arrays of numbers. Here we will create an 8x8 pixel image and put it in the variable `check`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Create a variable called `check` which will contain an 8x8 array of numbers.\n",
"check = np.zeros((8, 8))\n",
"check[::2, 1::2] = 1\n",
"check[1::2, ::2] = 1\n",
"check"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Now lets view our 8x8 pixel image:\n",
"plt.imshow(check, cmap='gray');"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Questions Part A - Image representation\n",
"\n",
"Use numpy slicing to set the values in an array:\n",
"\n",
"- Use `plt.imshow` to show a new 8x8 pixel image in which the top half is white and the bottom half is black.\n",
"- Use `plt.imshow` to show a new 8x8 pixel image in which the left half is white and the right half is black."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"deletable": false,
"nbgrader": {
"cell_type": "code",
"checksum": "54a6b9c8846af369d5753911d916851b",
"grade": true,
"grade_id": "cell-4ee9d19bc490e8bf",
"locked": false,
"points": 1,
"schema_version": 3,
"solution": true,
"task": false
}
},
"outputs": [],
"source": [
"# YOUR CODE HERE\n",
"raise NotImplementedError()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"deletable": false,
"nbgrader": {
"cell_type": "code",
"checksum": "9b9342fa9b869febd0d2be08cc84a619",
"grade": true,
"grade_id": "cell-9d1baa0ef55db4c6",
"locked": false,
"points": 1,
"schema_version": 3,
"solution": true,
"task": false
}
},
"outputs": [],
"source": [
"# YOUR CODE HERE\n",
"raise NotImplementedError()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Questions Part B - More image representation\n",
"\n",
"Write the numerical value corresponding with each pixel. In other words, what number corresponds with the black color and which number corresponds with the white color?"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"deletable": false,
"nbgrader": {
"cell_type": "code",
"checksum": "05a82888baf180f282cff34c8466f850",
"grade": false,
"grade_id": "cell-2fd29ad721f075e0",
"locked": false,
"schema_version": 3,
"solution": true
}
},
"outputs": [],
"source": [
"# YOUR CODE HERE\n",
"raise NotImplementedError()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"deletable": false,
"editable": false,
"nbgrader": {
"cell_type": "code",
"checksum": "e0766ab97487f394e00e43e62cdc3297",
"grade": true,
"grade_id": "cell-4f11d45d5fbbe454",
"locked": true,
"points": 1,
"schema_version": 3,
"solution": false
}
},
"outputs": [],
"source": [
"# If this runs without error, it means the answer in your previous cell was correct.\n",
"assert ads_hash(float(black))=='8aed642bf5'\n",
"assert ads_hash(float(white))=='d0ff5974b6'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Questions Part C - More image representation and contrast enhancement\n",
"\n",
"Now let's look at a more interesting image. We will use data included with the library `skimage` (also called scikit-image). The homepage for scikit-image is [here](http://scikit-image.org/)."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# If import skimage fails, you can install it like this in Jupyter:\n",
"# !pip install scikit-image\n",
"# or like this at the command line:\n",
"# python -m pip install scikit-image\n",
"from skimage import data\n",
"\n",
"# Load the sample image data into a variable called `camera`.\n",
"camera = data.camera()\n",
"\n",
"plt.figure(figsize=(4, 4))\n",
"plt.imshow(camera, cmap='gray', interpolation='nearest', vmin=0, vmax=255)\n",
"plt.axis('off')\n",
"\n",
"plt.tight_layout()\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"So, let's checkout some things about the image. How many pixels are here? Put your answer in the `num_pixels` variable."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"deletable": false,
"nbgrader": {
"cell_type": "code",
"checksum": "9724b1acb021773cfeba10403ce47eae",
"grade": false,
"grade_id": "cell-35aec8ec167eaa1a",
"locked": false,
"schema_version": 3,
"solution": true,
"task": false
}
},
"outputs": [],
"source": [
"# YOUR CODE HERE\n",
"raise NotImplementedError()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"deletable": false,
"editable": false,
"nbgrader": {
"cell_type": "code",
"checksum": "c45d4e8bc58c1a92790a5307c61594df",
"grade": true,
"grade_id": "cell-9eda0f4283380a85",
"locked": true,
"points": 1,
"schema_version": 3,
"solution": false,
"task": false
}
},
"outputs": [],
"source": [
"# If this runs without error, it means the answer in your previous cell was correct.\n",
"assert ads_hash(num_pixels)=='54faea9b3e'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"What is the distribution of luminance values in the image?"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plt.hist(camera.flat,bins=256);\n",
"plt.xlabel('luminance');\n",
"plt.ylabel('number of occurances');"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can see that there are two main peaks in the intensity histogram. We can also see that the intensities go from 0 to 255. This happens to be the range of values that fit in an 8 bit *byte*. This is the unit of memory size on modern computers. Is it correct to think that each pixel in this image is stored as a byte?\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"camera.dtype"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The `dtype` of a numpy array is the \"data type\" - the type for each individual element of the array. Above we see the answer is `uint8` which means \"unsigned integer, 8 bits\". So, yes, each pixel is stored here as a byte."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If you look at the histogram, you can see that there is some part of the luminance space which has very few occurances, namely above a luminance value of about 220. We can probably make better use of the 0-255 dynamic range available.\n",
"\n",
"In the cell below, enter a scale factor which fills the histogram of possible luminances more completely but does not cause too much clipping of the image values. The tower in the background should still be visible, for example. Look at the figures below to judge the effect of changing the scale factor. Put this in the variable `scale_factor`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"deletable": false,
"nbgrader": {
"cell_type": "code",
"checksum": "d2db0a18898480013b2a7637e06a4225",
"grade": false,
"grade_id": "cell-9ff4a4d60c8485d0",
"locked": false,
"schema_version": 3,
"solution": true
}
},
"outputs": [],
"source": [
"# YOUR CODE HERE\n",
"raise NotImplementedError()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"deletable": false,
"editable": false,
"nbgrader": {
"cell_type": "code",
"checksum": "d258c5be175387e003b6f1dd91dfdfcb",
"grade": true,
"grade_id": "cell-484ef1503b6e25a0",
"locked": true,
"points": 1,
"schema_version": 3,
"solution": false,
"task": false
}
},
"outputs": [],
"source": [
"# assert that scale_factor is a number\n",
"assert scale_factor - 0.0 == scale_factor"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's look at the histogram of rescaled luminances."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"rescaled = np.clip(scale_factor*camera.astype(np.float32),0,255).astype(np.uint8)\n",
"plt.hist(rescaled.flat,bins=256);\n",
"plt.xlabel('luminance');\n",
"plt.ylabel('number of occurances');\n",
"\n",
"plt.figure(figsize=(4, 4))\n",
"plt.imshow(rescaled, cmap='gray', interpolation='nearest', vmin=0, vmax=255)\n",
"plt.axis('off')\n",
"plt.tight_layout()\n",
"plt.show()"
]
}
],
"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.11.10"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,402 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Bean counting using connected components and more to do multiple object detection\n",
"\n",
"Now we have an image of many coffee beans and we want to count the number of coffee beans in the image."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"import scipy.misc\n",
"from scipy import ndimage\n",
"import imageio.v2 as imageio"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"im_rgb = imageio.imread('data/IMG_4272.JPG')\n",
"original_gray = im_rgb[:,:,1] # take green channel to make grayscale image"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plt.imshow(original_gray, cmap='gray')\n",
"plt.colorbar();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's view our image is pseudocolor. This will be helpful for getting absolute intensity values from the images."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plt.imshow(original_gray, cmap='jet')\n",
"plt.colorbar();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"One thing we may notice are some very small details in the image which will not help us perform our bean counting task."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"im = ndimage.gaussian_filter(original_gray, sigma=10.0)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plt.imshow(im, cmap='jet')\n",
"plt.colorbar();"
]
},
{
"cell_type": "markdown",
"metadata": {
"deletable": false,
"editable": false,
"nbgrader": {
"cell_type": "markdown",
"checksum": "9c04a893014b0c518a098943bb0db0f4",
"grade": false,
"grade_id": "cell-349688ed72efb990",
"locked": true,
"schema_version": 3,
"solution": false
}
},
"source": [
"## Question Part A\n",
"\n",
"We now want to pick a single threshold. Ideally, this will perfectly decompose our image into connected components of coffee beans and a background.\n",
"\n",
"Enter a threshold and describe why you chose this value. Use the variable `threshold`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"deletable": false,
"nbgrader": {
"cell_type": "code",
"checksum": "7b8f1f4d5f6da8b2b58cd0f6e3d1bbf4",
"grade": false,
"grade_id": "cell-6e1c2b89bd8a66f5",
"locked": false,
"schema_version": 3,
"solution": true
}
},
"outputs": [],
"source": [
"# YOUR CODE HERE\n",
"raise NotImplementedError()"
]
},
{
"cell_type": "markdown",
"metadata": {
"deletable": false,
"nbgrader": {
"cell_type": "markdown",
"checksum": "040f56c800c3a3a9d8073030823d80e1",
"grade": true,
"grade_id": "cell-4590afe7907cebe0",
"locked": false,
"points": 0,
"schema_version": 3,
"solution": true
}
},
"source": [
"YOUR ANSWER HERE"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"thresholded = (im < threshold).astype(np.uint8)\n",
"plt.imshow(thresholded, cmap='gray')\n",
"plt.colorbar();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now, we are once again going to use [connected components labeling](https://en.wikipedia.org/wiki/Connected-component_labeling) to detect objects in our binary image."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"labels, num_labels = ndimage.label(thresholded)\n",
"plt.imshow(labels, cmap='jet')\n",
"plt.colorbar();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Detour: erosion and dilation (morphological operations)\n",
"\n",
"Here we will take a small detour to demonstrate some morphological operations. You can read about morphological image processing [here](https://en.wikipedia.org/wiki/Mathematical_morphology).\n",
"\n",
"We will first perform `erosion` 30 times in a row on our thresholded image. What does the erosion do?"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"eroded = thresholded\n",
"for i in range(30):\n",
" eroded = ndimage.binary_erosion(eroded)\n",
"plt.imshow(eroded.astype(np.uint8), cmap='gray')\n",
"plt.colorbar();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now we will perform `dilation` 30 times in a row on our thresholded image. What does the dilation do?"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"dilated = thresholded\n",
"for i in range(30):\n",
" dilated = ndimage.binary_dilation(dilated)\n",
"plt.imshow(dilated.astype(np.uint8), cmap='gray')\n",
"plt.colorbar()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now what about the combination of `erosion` with `dilation`?"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"ed = thresholded\n",
"for i in range(30):\n",
" ed = ndimage.binary_erosion(ed)\n",
"for i in range(30):\n",
" ed = ndimage.binary_dilation(ed)\n",
"plt.imshow(ed.astype(np.uint8), cmap='gray')\n",
"plt.colorbar();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# End of detour - no more morphological operations\n",
"\n",
"Let's view our connected components labels a bit larger."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(10, 10))\n",
"labels, num_labels = ndimage.label(thresholded)\n",
"plt.imshow(labels, cmap='jet')\n",
"plt.colorbar();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"So, above are the labels for each connected component. Note that some individual coffee beans may be broken into two or more components and that sometimes multiple coffee beans may have been combined into one connected component."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now we can calculate the \"center of mass\" of each connected component."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"coms = ndimage.center_of_mass(thresholded, labels, index=range(1,num_labels))"
]
},
{
"cell_type": "markdown",
"metadata": {
"deletable": false,
"editable": false,
"nbgrader": {
"cell_type": "markdown",
"checksum": "4f893ff960cb1a4875a63476f8f3a29a",
"grade": false,
"grade_id": "cell-1213340a2a7c110e",
"locked": true,
"schema_version": 3,
"solution": false
}
},
"source": [
"## Question Part B\n",
"\n",
"Change the parameters (and, if you like, change the processing steps) to label each coffee bean individually. Make a plot where each bean is marked with an \"x\".\n",
"\n",
"You may like to change:\n",
"\n",
" - the image channel used (red, green, blue, an average of all channels, ...)\n",
" - gaussian blur size\n",
" - threshold used for binarization\n",
" - optionally, any morphological image operations"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"deletable": false,
"nbgrader": {
"cell_type": "code",
"checksum": "5d08800fec54d4202136e3f732d48e59",
"grade": true,
"grade_id": "cell-9a32e77f790bb4da",
"locked": false,
"points": 2,
"schema_version": 3,
"solution": true
}
},
"outputs": [],
"source": [
"# YOUR CODE HERE\n",
"raise NotImplementedError()"
]
},
{
"cell_type": "markdown",
"metadata": {
"deletable": false,
"editable": false,
"nbgrader": {
"cell_type": "markdown",
"checksum": "72b5665ee0d8d36a5eab437cb746837a",
"grade": false,
"grade_id": "cell-5b9512404535239b",
"locked": true,
"schema_version": 3,
"solution": false
}
},
"source": [
"## Question Part C\n",
"\n",
"Describe what can go wrong when performing this connected components analysis to count and identify individual coffee beans. Name two possible problems and what do you see if each problem happens?"
]
},
{
"cell_type": "markdown",
"metadata": {
"deletable": false,
"nbgrader": {
"cell_type": "markdown",
"checksum": "f3b280e2ac990b166198df66eeadf05c",
"grade": true,
"grade_id": "cell-b109315aba1b058b",
"locked": false,
"points": 2,
"schema_version": 3,
"solution": true
}
},
"source": [
"YOUR ANSWER HERE"
]
}
],
"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.11.10"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 354 KiB