我在图像分割/OpenCV场景中还是个新手,希望你能帮我。目前,我正在尝试计算这张照片中2种液体的百分比
应该是这样的(作为例子)
我认为opencv分水岭可以帮助我,但我无法做到这一点。我试图手动设置标记,但我得到以下错误:(-215:断言失败)src. type()==CV_8UC3
如果有人能帮我(也许有更好的方法),我将不胜感激
这是我使用的代码:
import cv2
import numpy as np
img = cv2.imread('image001.jpg')
# convert the image to grayscale and blur it slightly
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imshow("gray", gray)
# read image
#img = cv2.imread('jeep.jpg')
hh, ww = img.shape[:2]
hh2 = hh // 2
ww2 = ww // 2
# define circles
radius = hh2
yc = hh2
xc = ww2
# draw filled circle in white on black background as mask
mask = np.zeros_like(gray)
mask = cv2.circle(mask, (xc,yc), radius, (255,255,255), -1)
# apply mask to image
result = cv2.bitwise_and(gray, mask)
cv2.imshow("Output", result)
ret, thresh = cv2.threshold(result,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
cv2.imshow("ret 1", thresh)
markers = cv2.circle(thresh, (xc,50), 5, 1, -1)
markers = cv2.circle(thresh, (xc,yc+50), 5, 2, -1)
markers = cv2.circle(thresh, (15,15), 5, 3, -1)
cv2.imshow("marker 1", markers)
markers = cv2.watershed(img, markers)
img[markers == -1] = [0,0,255]
cv2.imshow("watershed", markers)
cv2.waitKey(0)
首先,您会获得一个异常,因为OpenCV的流域()
函数期望标记
数组由32位整数组成。来回转换将消除错误:
markers = markers.astype(np.int32)
markers = cv2.watershed(img, markers)
markers = markers.astype(np.uint8)
但是,如果您现在执行代码,您会发现结果不是很好,分水岭算法会将液体区域与不需要的区域合并。为了使您的代码像这样工作,您应该为图像中的每个特征提供一个标记。这将是非常不切实际的。
让我们首先提取我们感兴趣的图像区域,即两个液体圆圈。您已经尝试过进行掩蔽操作,我在下面的代码中通过使用OpenCV的HoughCircle()函数自动检测圆圈来改进它。然后分水岭算法将需要一个图像,每个区域有一个标记。我们将用零填充标记图像,在每个液体区域放置一个标记,一个标记作为背景。将所有这些放在一起,我们获得了下面的代码和结果。
考虑到你的图像质量(反射,压缩伪影等),我个人认为结果相当好,我不确定另一种方法会给你更好的。另一方面,如果你能得到质量更好的图像,基于颜色空间的分割方法可能更合适(正如Christoph Rackwitz所指出的)。
import cv2
import numpy as np
img = cv2.imread('image001.jpg')
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Detect circle
circles = cv2.HoughCircles(img_gray, cv2.HOUGH_GRADIENT, 1.3, 100)
# only one circle is detected
circle = circles[0,0,:]
center_x, center_y, radius = circles[0,0,0], circles[0,0,1], circles[0,0,2]
img_circle = img.copy()
cv2.circle(img_circle, (center_x, center_y), int(radius), (0, 255, 0), 3)
cv2.imshow("circle", img_circle)
# build mask for this circle
mask = np.zeros(img_gray.shape, np.uint8)
cv2.circle(mask, (center_x, center_y), int(radius), 255, -1)
img_masked = img.copy()
img_masked[mask == 0] = 0
cv2.imshow("image-masked", img_masked)
# create markers
markers = np.zeros(img_gray.shape, np.int32)
markers[10, 10] = 1 # background marker
markers[int(center_y - radius*0.9), int(center_x)] = 100 # top liquid
markers[int(center_y + radius*0.9), int(center_x)] = 200 # bottom liquid
# do watershed
markers = cv2.watershed(img_masked, markers)
cv2.imshow("watershed", markers.astype(np.uint8))
cv2.waitKey(0)