我有一组图像培养皿,不幸的是它们的质量不是最高的(下面的示例,轴不是图像的一部分)。 我正在尝试选择背景,并使用以下内容计算其面积(以像素为单位):
image = Image.open(path)
black_image = 1 * (np.asarray(image.convert('L')) < 12)
black_region = black_image.sum()
这将产生以下内容:
如果我对黑色像素的选择更加严格,则会错过其他图像中的像素,如果我比较松散,则最终会选择太多的培养皿本身。有一种方法我只能选择亮度值小于12并且与边缘连续的像素吗?我也愿意接受openCV解决方案。
答案 0 :(得分:3)
如果您将图像的最上面的一行/行和最下面的一行/行进行阈值处理,您将得到此图,其中我将第一行放在顶部,将底部行放在底部,原始图像的限制-无需您这样做,我只是在说明这种技术。
现在查看线条从黑色变为白色,然后由白色变为黑色(顶部以红色圈出)的位置。不幸的是,您的图像带有注释和轴,我必须对其进行修剪,以便您的编号不会完全相同。在最上面一行/行上,我的图像在第319列从黑色变为白色,然后在第648列变为黑色。如果将它们相加,则得到966并除以2,则x轴上的图像中心在483列
看底线/行的过渡(用红色圆圈表示)在第234和736列,它们加起来等于970,这在平均时为485,所以我们知道圆心在垂直图像列483-485上或说484。
然后,您现在应该可以算出图像的中心和半径并遮盖图像以准确计算背景。
答案 1 :(得分:3)
希望我并没有过分简化这个问题,但是从我的角度来看,使用具有简单阈值,形态学运算和findContours
的OpenCV应该可以解决问题。
请参见以下代码:
import cv2
import numpy as np
# Input
input = cv2.imread('images/x0ziO.png', cv2.IMREAD_COLOR)
# Input to grayscale
gray = cv2.cvtColor(input, cv2.COLOR_BGR2GRAY)
# Binary threshold
_, gray = cv2.threshold(gray, 20, 255, cv2.THRESH_BINARY)
# Morphological improvements of the mask
gray = cv2.morphologyEx(gray, cv2.MORPH_OPEN, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5)))
gray = cv2.morphologyEx(gray, cv2.MORPH_CLOSE, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (11, 11)))
# Find contours
cnts, _ = cv2.findContours(gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
# Filter large size contours; at the end, there should only be one left
largeCnts = []
for cnt in cnts:
if (cv2.contourArea(cnt) > 10000):
largeCnts.append(cnt)
# Draw (filled) contour(s)
gray = np.uint8(np.zeros(gray.shape))
gray = cv2.drawContours(gray, largeCnts, -1, 255, cv2.FILLED)
# Calculate background pixel area
bgArea = input.shape[0] * input.shape[1] - cv2.countNonZero(gray)
# Put result on input image
input = cv2.putText(input, 'Background area: ' + str(bgArea), (20, 30), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1.0, (255, 255, 255))
cv2.imwrite('images/output.png', input)
中间的“蒙版”图像如下所示:
然后,最终输出看起来像这样:
答案 2 :(得分:2)
尝试实验性floodfill()
方法。 https://pillow.readthedocs.io/en/5.1.x/reference/ImageDraw.html?highlight=floodfill#PIL.ImageDraw.PIL.ImageDraw.floodfill
如果您的所有图像都与示例相同,则只需选择图像的两个或四个角来填充粉红色,然后算上即可。
另请参见Image Segmentation with Watershed Algorithm,它非常类似于泛洪填充,但不依赖于单一的唯一颜色。
答案 3 :(得分:2)
由于您愿意接受OpenCV方法,因此可以使用
SimpleBlobDetector
显然,我得到的结果也不完美,因为要设置的超参数很多。超参数使它非常灵活,因此它是一个不错的起点。
这就是检测器的功能(请参见详细here):
thresholdStep
直到maxThreshold
。因此,第一个阈值为minThreshold
,第二个阈值为minThreshold + thresholdStep
,第三个阈值为minThreshold + 2 x thresholdStep
,依此类推。 合并:计算二进制图像中二进制blob的中心,并合并比minDistBetweenBlobs
更近的blob。
中心和半径计算:计算并返回新合并的Blob的中心和半径。
找到下面的代码。
# Standard imports
import cv2
import numpy as np
# Read image
im = cv2.imread("petri.png", cv2.IMREAD_COLOR)
# Setup SimpleBlobDetector parameters.
params = cv2.SimpleBlobDetector_Params()
# Change thresholds
params.minThreshold = 0
params.maxThreshold = 255
# Set edge gradient
params.thresholdStep = 5
# Filter by Area.
params.filterByArea = True
params.minArea = 10
# Set up the detector with default parameters.
detector = cv2.SimpleBlobDetector_create(params)
# Detect blobs.
keypoints = detector.detect(im)
# Draw detected blobs as red circles.
# cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS ensures the size of the circle corresponds to the size of blob
im_with_keypoints = cv2.drawKeypoints(im, keypoints, np.array([]), (0, 0, 255),
cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
# Show keypoints
cv2.imshow("Keypoints", im_with_keypoints)
cv2.waitKey(0)