I am trying to find the regional maximum in this image:
to make a cut in its position like this:
I found a method how to filter regional maxima here but I can't make it work for my case.
My code so far:
import numpy as np
import cv2
import skimage as sm
from skimage.morphology import reconstruction
import scipy as sp
img = cv2.imread('img.png', 0)
img = sm.img_as_float(img)
img = sp.ndimage.gaussian_filter(img, 1)
seed = np.copy(img)
seed[1:-1,1:-1] = img.min()
mask = img
dilated = reconstruction(seed, mask, method = 'dilation')
img = img - dilated
cv2.imshow('img', img)
cv2.waitKey()
My Solution:
import numpy as np
import cv2
img = cv2.imread('img.png', 0)
_, thresh = cv2.threshold(img, 250, 255, cv2.THRESH_BINARY)
rows = np.sum(thresh/255, axis = 1)
ol = len(np.nonzero(rows)[0])
L = []
z = 0
for idx, row in enumerate(rows):
if row > 0:
if z > 5 and z < ol - 5:
L.append(idx)
z += 1
split = np.min(rows[L])
thresh[np.where(rows == split)[0][0]] = 0
cv2.imshow('img', thresh)
cv2.waitKey()
HansHirse wrote a more professional approach:
import numpy as np
import cv2
img = cv2.imread('img.png', 0)
_, thresh = cv2.threshold(img, 250, 255, cv2.THRESH_BINARY)
rows = np.sum(thresh/255, axis = 1)
exclude = 5
idx = np.where(rows > 0)[0]
idx = idx[exclude : len(idx) - exclude]
cut = idx[np.argmin(rows[idx])]
thresh[cut] = 0
cv2.imshow('img', thresh)
cv2.waitKey()
Both result in:
It would be interesting to see an approach, that is not limited to horizontal pixels.
If your "chromatids" (I will refer to the shown structure in that way, because it kind of looks like one) are all aligned in that way, you can simply count the white pixels per row, and search for the minimum.
Please have a look at the following code, which is hopefully self-explanatory:
import cv2
import numpy as np
# Load input image
input = cv2.imread('images/Q6YM9.png', cv2.IMREAD_GRAYSCALE)
# Extract "chromatid" (the structure looks like one...)
_, chromatid = cv2.threshold(input, 250, 255, cv2.THRESH_BINARY)
# Sum row-wise pixel values
rowPixelSum = np.sum(chromatid / 255, axis=1)
# Detect all rows with non-zero elements
ind = np.where(rowPixelSum > 0)[0]
# Exclude n rows at the top and bottom of the "chromatid"
# Caveat: Check for plausibility (index out of bounds, etc.)
nEx = 15
ind = ind[15:len(ind)-nEx]
# Detect index of row with minimum pixel count
cutRow = ind[np.argmin(rowPixelSum[ind])]
# Detect start and end of "chromatid" on row with minimum pixel count
row = np.where(chromatid[cutRow, :] > 0)[0]
xStart = row[0]
xEnd = row[-1]
# For visualization: Draw black line through row with minimum pixel count
cv2.line(input, (xStart, cutRow), (xEnd, cutRow), 0, 3)
cv2.line(chromatid, (xStart, cutRow), (xEnd, cutRow), 0, 3)
# Write output image
cv2.imwrite('images\input.png', input)
cv2.imwrite('images\chromatid.png', chromatid)
The outputs look like this:
If your "chromatids" have varying orientations, one could utilize some rotation prior to the above-mentioned code, based on the "principal component" of the chromatid.
Hope that helps!