pm21-dragon/exercises/release/exercise-09/3__Bean_counting.ipynb
2024-12-08 18:58:07 +01:00

403 lines
9.7 KiB
Plaintext

{
"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
}