我正在尝试在这张图片中找到区域最大值:
以这样的位置进行切割:
我找到了一种方法来过滤区域最大值here,但我无法使其适用于我的情况。
到目前为止,我的代码:
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()
我的解决方案:
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写了一种更专业的方法:
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()
两者均导致:
有趣的是,该方法不仅限于水平像素。
答案 0 :(得分:3)
如果您的“染色单体”(我将以这种方式引用显示的结构,因为它看起来像一个)都以这种方式对齐,则您只需计算每行的白色像素,然后搜索最小像素
请看下面的代码,希望这些代码不言自明:
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)
输出看起来像这样:
如果您的“染色单体”具有不同的方向,则可以根据染色单体的“主要成分”在上述代码之前进行一些旋转。
希望有帮助!
答案 1 :(得分:1)
在过滤区域最大值之后,您可以尝试使用morphological opening操作将这两部分分开。根据您的区域最小厚度,使用更大的内核或多次打开调用。
要使用打开查找确切的切割位置,您可以随后进行多次打开操作调用,直到单个斑点分裂为两个。您可以检测到通过cv::detectContours()
获得的轮廓分析位置。
另外,您可能会发现distanceTransform()有用。其结果是从每个点到最近边界的距离。这个想法是对图像进行骨架化,并沿着骨架线取distanceTransform()
结果的最小值来找到切割位置。
此外,您还可以尝试基于白色像素位置以k = 2的k均值聚类。切割线将在群集之间。
编辑:
您可能会发现此page有用,因为那里的人们讨论了类似的问题。答案之一是使用cv::convexityDefects()
查找分离点。