Skip to content

Commit ad68f55

Browse files
committed
Adding micro exercises
1 parent 7dba451 commit ad68f55

File tree

5 files changed

+187
-0
lines changed

5 files changed

+187
-0
lines changed

exercises/micro/README.md

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
Adapted from an idea by Ashwin Srinath, hosted at
2+
https://github.com/shwina/micro .
3+
4+
5+
The file `counting.py` contains a simple implementation of a function `count_objects`.
6+
7+
`count_objects` is used to count objects in
8+
microscopic images. An example image is given below:
9+
10+
![Example microscopic image](img/specimen_example.png)
11+
12+
The images are assumed to be in **binary** format,
13+
i.e., they can be represented by arrays of 0s (dark pixels)
14+
and 1s (bright pixels). For example, the image above may be represented
15+
by the following 32-by-32 array:
16+
17+
```
18+
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
19+
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
20+
0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
21+
0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
22+
0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0
23+
0 0 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0
24+
0 0 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0
25+
0 0 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 1 1 0 0
26+
0 0 0 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 1 1 0 0 1 1 1 1 0 0
27+
0 0 0 1 1 1 1 0 0 0 0 0 0 1 1 1 1 1 0 0 0 1 1 1 1 0 1 1 1 1 0 0
28+
0 0 0 1 1 1 1 0 0 0 0 0 1 1 1 1 1 1 0 0 1 1 1 1 1 0 1 1 1 1 0 0
29+
0 0 0 1 1 1 1 0 0 0 0 0 1 1 1 1 1 1 0 0 0 1 1 1 1 1 0 0 0 0 0 0
30+
0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0
31+
0 0 1 1 1 1 1 1 0 0 0 0 1 1 1 1 1 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0
32+
0 0 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0
33+
0 0 1 1 1 1 1 1 1 0 0 0 0 1 1 1 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0
34+
0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0
35+
0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0
36+
0 0 0 0 0 0 0 0 0 1 1 1 0 0 1 1 1 1 0 0 0 1 1 1 1 1 0 0 0 0 0 0
37+
0 0 1 1 1 1 0 0 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0
38+
0 0 1 1 1 1 1 0 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0
39+
0 0 1 1 1 1 1 0 1 1 1 1 1 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
40+
0 0 1 1 1 1 0 0 0 1 1 1 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
41+
0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 1 1 1 1 0 0 0 0
42+
0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 1 1 1 1 1 1 0 0 0
43+
0 0 0 0 0 0 0 0 1 1 0 0 0 0 1 1 1 1 0 0 0 0 0 1 1 1 1 1 1 1 0 0
44+
0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 1 1 1 0 0 0 0 1 1 1 1 1 1 0 0
45+
0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 1 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0
46+
0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0
47+
0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0
48+
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0
49+
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
50+
```
51+
52+
The function `count_objects` accepts a (binary) NumPy array
53+
as input and returns the number of objects found in this "image".
54+
For example, if `img` is an array representing the above image,
55+
`count_objects` can be used as follows:
56+
57+
```python
58+
>>> count_objects(img)
59+
16
60+
```
61+
62+
**Assumptions**:
63+
64+
1. The bright pixels (1) representing each object are completely surrounded by dark pixels (0).
65+
2. There are no "holes" in each object, i.e., each object is a continuous blob of bright pixels (1),
66+
with no dark pixels (0) inside this blob.
67+
68+
69+
The file `test_counting.py` contains tests that will allow you to optimize the
70+
function without breaking its functionality.

exercises/micro/counting.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import numpy as np
2+
3+
4+
def external_match(a):
5+
masks = [np.array([[0, 0], [0, 1]]),
6+
np.array([[0, 0], [1, 0]]),
7+
np.array([[1, 0], [0, 0]]),
8+
np.array([[0, 1], [0, 0]])]
9+
10+
for mask in masks:
11+
if np.all(a == mask):
12+
return True
13+
return False
14+
15+
16+
def internal_match(a):
17+
masks = [np.array([[1, 1], [1, 0]]),
18+
np.array([[1, 1], [0, 1]]),
19+
np.array([[0, 1], [1, 1]]),
20+
np.array([[1, 0], [1, 1]])]
21+
22+
for mask in masks:
23+
if np.all(a == mask):
24+
return True
25+
return False
26+
27+
28+
def count_objects(img):
29+
ny, nx = img.shape
30+
31+
img[[0, -1], :] = 0
32+
img[:, [0, -1]] = 0
33+
34+
E = 0
35+
I = 0
36+
for i in range(ny-1):
37+
for j in range(nx-1):
38+
if external_match(img[i:i+2, j:j+2]):
39+
E = E + 1
40+
if internal_match(img[i:i+2, j:j+2]):
41+
I = I + 1
42+
return (E - I)/4
7.69 KB
Loading

exercises/micro/script.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from scipy.ndimage import imread
2+
3+
from counting import count_objects
4+
5+
6+
if __name__ == '__main__':
7+
img = imread('img/specimen_example.png', flatten=True) // 255
8+
count = count_objects(img)
9+
print('Number of objects:', count)

exercises/micro/test_counting.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import numpy as np
2+
from numpy.testing import assert_equal
3+
4+
from counting import count_objects
5+
6+
7+
def test_count_no_object():
8+
a = np.zeros([6, 6], dtype=np.float64)
9+
assert_equal(count_objects(a), 0)
10+
11+
12+
def test_count_1_object():
13+
a = np.zeros([6, 6], dtype=np.float64)
14+
a[1:-1, 1:-1] = 1
15+
assert_equal(count_objects(a), 1)
16+
17+
18+
def test_count_objects_2_objects():
19+
a = np.array(
20+
[[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
21+
[ 0., 1., 1., 1., 0., 0., 0., 0., 0., 0.],
22+
[ 0., 1., 1., 1., 0., 0., 0., 0., 0., 0.],
23+
[ 0., 1., 1., 1., 0., 0., 0., 0., 0., 0.],
24+
[ 0., 0., 0., 0., 0., 1., 1., 0., 0., 0.],
25+
[ 0., 0., 0., 0., 0., 1., 1., 0., 0., 0.],
26+
[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
27+
[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
28+
[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
29+
[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]])
30+
assert_equal(count_objects(a), 2)
31+
32+
33+
def test_count_1_object_rectangle():
34+
a = np.array(
35+
[[ 0., 0., 0., 0., 0.],
36+
[ 0., 1., 1., 1., 0.],
37+
[ 0., 1., 1., 1., 1.],
38+
[ 0., 1., 1., 1., 0.],
39+
[ 0., 0., 1., 0., 0.],
40+
[ 0., 0., 0., 0., 0.],
41+
[ 0., 0., 0., 0., 0.],
42+
[ 0., 0., 0., 0., 0.],
43+
[ 0., 0., 0., 0., 0.],
44+
[ 0., 0., 0., 0., 0.]])
45+
assert_equal(count_objects(a), 1)
46+
47+
48+
49+
def test_count_1_object_irregular():
50+
a = np.array(
51+
[[ 0., 0., 0., 0., 0.],
52+
[ 0., 1., 1., 1., 0.],
53+
[ 0., 1., 1., 1., 1.],
54+
[ 0., 1., 1., 1., 0.],
55+
[ 0., 0., 1., 0., 0.],
56+
[ 0., 0., 0., 0., 0.],
57+
[ 0., 0., 0., 0., 0.],
58+
[ 0., 0., 0., 0., 0.],
59+
[ 0., 0., 0., 0., 0.],
60+
[ 0., 0., 0., 0., 0.]])
61+
assert_equal(count_objects(a), 1)
62+
63+
64+
def test_count_all_ones():
65+
a = np.ones([6, 6], dtype=np.int32)
66+
assert_equal(count_objects(a), 1)

0 commit comments

Comments
 (0)