Reputation: 105
Please, I'd like to compute the percentage of hexagonal cells (e.g., the number of cells having 6 neighbors cells/ total number of cells) in a binary image and produce a colored coded image as shown below.
I've tried the python code below but I didn't get the correct output. For example, as you can see that the red cells in the binary image have either, 4,5,6, or 7 neighbors cells, but it wrongly calculated as they have 3,4 and 6 neighbors.
An example of a binary image and its output is attached.
import sys
import json
import cv2
import os
import scipy.io
import numpy as np
from scipy.ndimage import measurements, morphology
from skimage import measure
import time
def cells_measurements(path, orig_image, color="yellow", size=3,
pixel_sz=0.00104167):
size = int(size)
im = cv2.imread(path, cv2.IMREAD_GRAYSCALE)
_, im = cv2.threshold(im, 127, 255, cv2.THRESH_BINARY)
labeled_image, num_of_cells = measurements.label(255 - im)
props = measure.regionprops(labeled_image)
number_of_cells = len(props)
colored_image = np.pad(cv2.cvtColor(~im, cv2.COLOR_GRAY2BGR), ((1, 1),(1, 1), (0, 0,)), mode='constant',constant_values=0)
colors = [[0, 0, 128], [0, 0, 255], [0, 128, 255], [0, 255, 255],[128,255, 128], [255, 255, 0], [255, 128, 0],[255, 0, 0]]
count_hex = 0
labels = np.unique(labeled_image)
for l in labels[1:]:
i_temp = (labeled_image == l).astype(float) * 255
i_temp = cv2.dilate(i_temp, np.ones((3, 3)), iterations=2) - i_temp
i_temp2 = np.copy(labeled_image)
i_temp2[i_temp == 0.] = 0
adjacent = len(np.unique(i_temp2)) - 1
if adjacent == 6:
count_hex += 1
cv2.floodFill(colored_image, None, (int(cell_center_all[l - 1][1]),
int(cell_center_all[l - 1][0])), colors[min(adjacent, 7)])
hexagonal_cells = (count_hex / num_of_cells) * 100
colored_image = np.pad(colored_image, ((0, 0), (0, 75), (0, 0)),
'constant', constant_values=255)
for i in range(8):
step = colored_image.shape[0] // 8
colored_image[i * step:+(i + 1) * step, -60:-35] = colors[7 - i]
colored_image[i * step, -60:-35] = 0
colored_image[(i + 1) * step, -60:-35] = 0
colored_image[i * step:(i + 1) * step, -60] = 0
colored_image[i * step:(i + 1) * step, -35] = 0
cv2.putText(colored_image, str(7 - i), (colored_image.shape[1] -
30, 5 + i * step + step // 2), cv2.FONT_HERSHEY_DUPLEX, 0.5, 0)
color_path = 'Labeled Images/' + fn + "_color.png"
cv2.imwrite(color_path, colored_image)
Auto_Cells_Pleomorphism = []
Mask_Path = 'generated_samples_masks/'
Original_img_path = 'TestingSet/enhanced_imgs/'
# please note that the "mask" image is the result of the segmentation
algorithm which I will provide today
# Loop over images
for i in range(1, 640):
filename = str(i) + '.png'
print(filename)
Masks_Path = os.path.join(Mask_Path, filename)
Original_image = os.path.join(Original_img_path, filename)
[hexagonal_cells] = cells_measurements(Masks_Path, Original_image,
color="yellow", size=3)
Auto_Cells_Pleomorphism.append(round(hexagonal_cells))
As you can see that the binary image has some blurred edges. How can I improve their visibility?
Upvotes: 0
Views: 499
Reputation: 7131
One approach could be to use the Watershed algorithm for segmentation.
Read about it here:
https://scikit-image.org/docs/dev/auto_examples/segmentation/plot_watershed.html
https://www.pyimagesearch.com/2015/11/02/watershed-opencv/
There are many other segmentation algorithms that you could look at to see if anything works better (e.g. Felsenszwalb's algorithm). Here is a simple comparison of three algorithms, you could easily extend this example to see how they compare on your dataset.
Once you have the contours of all elements (polygons) you can use them to create a "complete map" (identify all cells and their neighbours, no holes, no unknown elements) to make sure you are not missing any cells. You could call this the topology of your cells.
One thing that might help is to create "clearer" polygons from the once returned by the watershed algorithm.
You might have to
This is called "fixing, repairing, simplifying a mesh". It is a topic on its own, and there are of course tools for that. You can read about Python-related projects here, here or here.
Once this is finished you just count the edges, create a list of all neighbouring cells and cross-check that all neighbours are detected.
This algorithm is not something that will work out of the box, you will have to improve and tweak it until it works.
Upvotes: 1