为了账号安全,请及时绑定邮箱和手机立即绑定

如何在 PIL 中选择与图像边缘相邻的所有黑色像素?

如何在 PIL 中选择与图像边缘相邻的所有黑色像素?

蓝山帝景 2022-01-05 11:05:36
我有一组图像培养皿,不幸的是不是最高质量(下面的示例,轴不是图像的一部分)。我正在尝试选择背景并使用以下像素计算其面积:image = Image.open(path)black_image = 1 * (np.asarray(image.convert('L')) < 12)black_region = black_image.sum()这产生以下内容:如果我对黑色像素的选择更严格,我会错过其他图像中的像素,如果我更宽松,我最终会选择过多的培养皿本身。有没有办法我只能选择亮度值小于 12 并且与边缘相邻的像素?我也对 openCV 解决方案持开放态度。
查看完整描述

2 回答

?
犯罪嫌疑人X

TA贡献2080条经验 获得超4个赞

希望我没有把问题简单化,但从我的角度来看,使用 OpenCV 和简单的阈值、形态学操作,findContours应该可以完成这项工作。


请看下面的代码:


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)

中间的“面具”图像如下所示:

//img1.sycdn.imooc.com//61d50b370001932a09190542.jpg

并且,最终输出如下所示:


//img1.sycdn.imooc.com//61d50b42000127ff09670544.jpg

查看完整回答
反对 回复 2022-01-05
?
隔江千里

TA贡献1906条经验 获得超10个赞

由于您对 OpenCV 方法持开放态度,因此您可以使用 SimpleBlobDetector

显然我得到的结果也不完美,因为有很多超参数需要设置。超参数使它非常灵活,因此是一个不错的起点。

这就是 Detector 的作用(请参阅此处的详细信息):

  1. 阈值:通过使用从 minThreshold 开始的阈值对源图像进行阈值处理,将源图像转换为多个二值图像。这些阈值递增thresholdStep直到maxThreshold。所以第一个阈值是minThreshold,第二个是minThreshold + thresholdStep,第三个是minThreshold + 2 x thresholdStep,依此类推。

  2. 分组:在每个二值图像中,连接的白色像素被分组在一起。让我们称这些为二进制 blob。

  3. 合并:计算二进制图像中二进制 blob 的中心,并且比minDistBetweenBlobs合并位置更近的 blob 。

  4. 中心和半径计算:计算并返回新合并的 blob 的中心和半径。

找到图片下方的代码。

//img1.sycdn.imooc.com//61d50b560001958508040540.jpg

# 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)


查看完整回答
反对 回复 2022-01-05
  • 2 回答
  • 0 关注
  • 323 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号