Skip to content
Permalink
Browse files

estimate minimum cell side as 1/4 of largest cell

  • Loading branch information...
Verkhovskaya committed May 12, 2019
1 parent e48df85 commit 6d788dc782f6d7bb05c2680931ca33dcf5d13364
Showing with 104 additions and 124 deletions.
  1. +76 −71 count_cells.py
  2. +4 −3 file_utils.py
  3. +21 −17 k_means.py
  4. +2 −26 server.py
  5. BIN test_in.jpg
  6. +1 −7 website/landing_page.html
@@ -3,90 +3,97 @@
import numpy as np
import sys
from scipy.signal import convolve2d
import os
path = os.path.dirname(os.path.abspath(__file__)) + '/'
sys.setrecursionlimit(100000)

class Cell:
def __init__(self, array, x, y):
self.array = array
self.x = x
self.y = y
self.array = array
self.x = x
self.y = y

cells_global = []
def split_into_two_major_colors(image_array):
colors = k_means_2(simplify_image(image_array, 10, 10))
distances = []
for i in range(len(colors)):
distances.append(get_distance_to(image_array, colors[i]))
overlays = []
for i in range(len(colors)):
is_closest = np.zeros(image_array.shape[:2]) + 1
for j in range(len(colors)):
is_closest = is_closest * (distances[i] <= distances[j])
overlays.append(is_closest)
return overlays
colors = k_means_2(simplify_image(image_array, 10, 10))
distances = []
for i in range(len(colors)):
distances.append(get_distance_to(image_array, colors[i]))
overlays = []
for i in range(len(colors)):
is_closest = np.zeros(image_array.shape[:2]) + 1
for j in range(len(colors)):
is_closest = is_closest * (distances[i] <= distances[j])
overlays.append(is_closest)
return overlays

def split_into_individual_cells(cell_overlay, image_array, min_cell_side):
image_copy = np.copy(cell_overlay)
cells = []
for x in range(cell_overlay.shape[0]):
for y in range(cell_overlay.shape[1]):
found_locations = []
map_cell(found_locations, image_copy, x, y)
if len(found_locations) > min_cell_side**2/2:
x_start = min([location[0] for location in found_locations])
y_start = min([location[1] for location in found_locations])
new_overlay = array_overlay_from_found_locations(found_locations, image_array)
if np.sum(np.sum(new_overlay))/(new_overlay.shape[0]*new_overlay.shape[1]) > 0.5:
cells.append(Cell(new_overlay, x_start, y_start))
return cells
def split_into_individual_cells(cell_overlay, image_array):
image_copy = np.copy(cell_overlay)
cells = []
for x in range(cell_overlay.shape[0]):
for y in range(cell_overlay.shape[1]):
found_locations = []
map_cell(found_locations, image_copy, x, y)
if len(found_locations) > 0:
x_start = min([location[0] for location in found_locations])
y_start = min([location[1] for location in found_locations])
new_overlay = array_overlay_from_found_locations(found_locations, image_array)
if np.sum(np.sum(new_overlay))/(new_overlay.shape[0]*new_overlay.shape[1]) > 0.5:
cells.append(Cell(new_overlay, x_start, y_start))
return cells

def array_overlay_from_found_locations(found_locations, image_array):
min_x = min([point[0] for point in found_locations])
max_x = max([point[0] for point in found_locations]) + 1
min_y = min([point[1] for point in found_locations])
max_y = max([point[1] for point in found_locations]) + 1
new_array = np.zeros(list(np.concatenate(((max_x-min_x, max_y-min_y), image_array.shape[2:]))))
for point in found_locations:
new_array[point[0]-min_x, point[1]-min_y] = image_array[point[0], point[1]]
return new_array
min_x = min([point[0] for point in found_locations])
max_x = max([point[0] for point in found_locations]) + 1
min_y = min([point[1] for point in found_locations])
max_y = max([point[1] for point in found_locations]) + 1
new_array = np.zeros(list(np.concatenate(((max_x-min_x, max_y-min_y), image_array.shape[2:]))))
for point in found_locations:
new_array[point[0]-min_x, point[1]-min_y] = image_array[point[0], point[1]]
return new_array

def map_cell(found_locations, image_array, x, y):
if x < image_array.shape[0] and y < image_array.shape[1] and x >= 0 and y >= 0:
if image_array[x,y]:
found_locations.append((x,y))
image_array[x,y] = False
map_cell(found_locations, image_array, x+1, y)
map_cell(found_locations, image_array, x, y+1)
map_cell(found_locations, image_array, x-1, y)
map_cell(found_locations, image_array, x, y-1)
if x < image_array.shape[0] and y < image_array.shape[1] and x >= 0 and y >= 0:
if image_array[x,y]:
found_locations.append((x,y))
image_array[x,y] = False
map_cell(found_locations, image_array, x+1, y)
map_cell(found_locations, image_array, x, y+1)
map_cell(found_locations, image_array, x-1, y)
map_cell(found_locations, image_array, x, y-1)

def get_cell_overlay(overlays):
overlay = overlays[0]
if (np.sum(overlay[0,:]) + np.sum(overlay[:,0]) + np.sum(overlay[-1,:]) + np.sum(overlay[:,-1]))/(overlay.shape[0] + overlay.shape[1])/2 < 0.5:
return overlay
else:
return overlays[1]
overlay = overlays[0]
if (np.sum(overlay[0,:]) + np.sum(overlay[:,0]) + np.sum(overlay[-1,:]) + np.sum(overlay[:,-1]))/(overlay.shape[0] + overlay.shape[1])/2 < 0.5:
return overlay
else:
return overlays[1]


def get_cells(image, min_cell_side):
overlays = split_into_two_major_colors(image)
cell_overlay = get_cell_overlay(overlays)
cells = split_into_individual_cells(cell_overlay, image, min_cell_side)
def get_cells(image, min_cell_side=None):
overlays = split_into_two_major_colors(image)
cell_overlay = get_cell_overlay(overlays)
cells = split_into_individual_cells(cell_overlay, image)
if min_cell_side == None:
min_cell_side = max(max([cell.array.shape[0] for cell in cells]), max([cell.array.shape[1] for cell in cells])) / 4
print(min_cell_side)
print(len(cells))
cells = list(filter(lambda cell: cell.array.shape[0] > min_cell_side and cell.array.shape[1] > min_cell_side, cells))

if len(cells) <= 1:
return cells
else:
all_cells = []
for cell in cells:
split_cells = get_cells(cell.array, min_cell_side)
if len(split_cells) > 1:
for new_cell in split_cells:
if len(cells) <= 1:
return cells
else:
all_cells = []
for cell in cells:
split_cells = get_cells(cell.array, min_cell_side)
if len(split_cells) > 1:
for new_cell in split_cells:
new_cell.x += cell.x
new_cell.y += cell.y
all_cells.append(new_cell)
else:
all_cells.append(cell)
return all_cells
else:
all_cells.append(cell)
return all_cells

def draw_outline(image_array, cells):
new_image = np.copy(image_array)
@@ -99,15 +106,13 @@ def draw_outline(image_array, cells):
return new_image


def convert_image(in_name, out_name, min_cell_side):
image = load_image('/home/annav8/cell_counter/' + in_name)
cells = get_cells(image, min_cell_side)
def convert_image(in_name, out_name):
image = load_image(path + in_name)
cells = get_cells(image)
save_image(draw_outline(image, cells), name=out_name)
return len(cells)

def test():
print(convert_image('cells.jpg', 'out.jpg', 10))
print(convert_image('JPEG image.jpeg', 'out2.jpg', 20))
# est()
print(convert_image('test_in.jpg', 'test_out.jpg'))
test()

print('hello')
@@ -1,6 +1,8 @@
import numpy as np
import matplotlib.pyplot as plt
import math
import os
path = os.path.dirname(os.path.abspath(__file__))

def load_image(image_path):
print('Loading image')
@@ -44,7 +46,6 @@ def image_add_location_data(image_array, keep_location=False, cluster_factor=40)
return np.array(new_array)

def get_distance_to(image_array, color_array):
print('Calculating distance to ' + str(color_array))
if len(color_array) != image_array.shape[2]:
raise Exception("Dimensions don't match")
new_array = np.zeros((image_array.shape[0], image_array.shape[1]))
@@ -58,7 +59,7 @@ def show_image(image_array):
plt.show()

def save_image(image_array, name='out.jpg'):
plt.imsave('/home/annav8/cell_counter/'+name, image_array)
plt.imsave(path+name, image_array)

def merge_images(image_arrays):
num_across = int(len(image_arrays)**0.5)
@@ -80,4 +81,4 @@ def merge_images(image_arrays):
def kmeans(points_array, num_colors):
print('Running kmeans, looking for ' + str(num_colors) + ' clusters')
kmeans = 0 # KMeans(n_clusters=num_colors, random_state=0).fit(points_array)
return kmeans.cluster_centers_
return kmeans.cluster_centers_
@@ -1,26 +1,30 @@
import numpy as np

def square_distance(array_1, array_2):
return sum([(array_1[i] - array_2[i])**2 for i in range(len(array_1))])
return sum([abs(array_1[i] - array_2[i])**2 for i in range(len(array_1))])

def k_means_2(image_array):
print('calculating k_means_2')
print(image_array.shape)
num_colors = image_array.shape[2]
color_range = np.max(image_array)
centers = [[0]*num_colors, [color_range]*num_colors]
colors = []
for x in range(image_array.shape[0]):
for y in range(image_array.shape[1]):
color = image_array[x, y]
if sum(color) != 0:
colors.append(color)

centers = [colors[0], colors[-1]]

for i in range(10):
# assign
sums = [[0]*num_colors, [0]*num_colors]
num_points = [0, 0]
for x in range(image_array.shape[0]):
for y in range(image_array.shape[1]):
point = image_array[x, y]
if sum(point) != 0:
assigned_center = 0 if square_distance(point, centers[0]) < square_distance(point, centers[1]) else 1
for k in range(num_colors):
sums[assigned_center][k] += point[k]
num_points[assigned_center] += 1
for color in colors:
assigned_center = 0 if square_distance(color, centers[0]) < square_distance(color, centers[1]) else 1
for k in range(num_colors):
sums[assigned_center][k] += color[k]
num_points[assigned_center] += 1

# update
new_centers = [0, 0]
@@ -30,8 +34,8 @@ def k_means_2(image_array):
for k in range(num_colors)
]
else:
new_centers[j] = [color_range/2] * num_colors
# print(new_centers, i)
print('LOST')
new_centers[j] = colors[0]

if sum([square_distance(new_centers[j], centers[j]) for j in [0, 1]]) < color_range/256.0:
return new_centers
@@ -41,11 +45,11 @@ def k_means_2(image_array):
return centers

def k_means_2_test():
points = np.array([[[0, 0], [1, 2], [3, 5], [5, 5]]])
k_means_2(points)
points = np.array([[[0, 0], [1, 2], [3, 5], [5, 5], [4,5]]])
print(k_means_2(points))

# k_means_2_test()
k_means_2_test()


def none(centers):
return centers
return centers
@@ -5,42 +5,18 @@
@route('/')
def hello_world():
return static_file("landing_page.html", root="/home/annav8/cell_counter/website")
return '''
<h1> Count the number of cells in an image </h1>
<br>
<form action="/count_cells" method="post" enctype="multipart/form-data">
Image: <input type="file" name="image" value="Choose file">
<br>
Minimum cell side length (pixels): <input type="number" name="size" value="10">
<br>
<input type="submit" value="submit">
</form>
<br>
<h2> Example: </h2>
<h3> In </h3>
<img src="/img/in/1778.jpg">
<br>
<h3> Out </h3>
<img src="/img/out/1778.jpg">
<br>
104 cells counted
<br>
<h2> Source code: </h2> <a href="https://github.com/Verkhovskaya/cell_count"> https://github.com/Verkhovskaya/cell_count </a>
'''

@post('/count_cells')
def count_cells():
side = int(request.forms.get('size'))
image = request.files.get('image')
name = str(int(random.random()*10000)) + '.jpg'
image.save('/home/annav8/cell_counter/in/' + name)
num = convert_image('in/'+name, 'out/'+name, side)
num = convert_image('in/'+name, 'out/'+name)
return '<img src="/img/out/' + name + '"> <br>' + str(num) + ' cells counted'

@route('/img/<dir>/<name>')
def img(dir, name):
return static_file(name, root='/home/annav8/cell_counter/'+dir)


application = default_app()
application = default_app()
BIN +25.1 KB test_in.jpg
Binary file not shown.
@@ -16,12 +16,6 @@ <h1> Count the number of cells in an image </h1>
</div>
</div>

<div class="form-group">
<label class="control-label col-sm-2" for="size">Minimum cell size (pixels):</label>
<div class="col-sm-10">
<input type="number" class="form-control" id="size" value="10" name="size">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-default">Count cells</button>
@@ -46,4 +40,4 @@ <h3> Out </h3>
</div>
</div>
</body>
</html>
</html>

0 comments on commit 6d788dc

Please sign in to comment.
You can’t perform that action at this time.