我有一个图像,我试图将其分割成单独的组件,我已经使用 k 均值聚类成功创建了图像中对象的掩码。 (我已在下面包含结果和掩模)
然后我尝试裁剪原始图像的每个单独部分并将其保存到新图像中,这可能吗?
import numpy as np
import cv2
path = 'software (1).jpg'
img = cv2.imread(path)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
twoDimage = img.reshape((-1,3))
twoDimage = np.float32(twoDimage)
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
K = 2
attempts=10
ret,label,center = cv2.kmeans(twoDimage,K,None,criteria,attempts,cv2.KMEANS_PP_CENTERS)
center = np.uint8(center)
res = center[label.flatten()]
result_image = res.reshape((img.shape))
cv2.imwrite('result.jpg',result_image)
我的解决方案涉及创建一个二进制对象蒙版,其中所有对象都为白色,背景为黑色。然后,我根据面积从最大到最小提取每个对象。我使用这个“孤立的对象”蒙版来分割原始图像中的每个对象。然后我将结果写入磁盘。这些是步骤:
writeImage
findBiggestBlob
。第一个功能非常不言自明。第二个函数创建二进制输入图像中最大斑点的二进制掩码。这两个功能都在这里介绍:
# Writes a PNG image:
def writeImage(imagePath, inputImage):
imagePath = imagePath + ".png"
cv2.imwrite(imagePath, inputImage, [cv2.IMWRITE_PNG_COMPRESSION, 0])
print("Wrote Image: " + imagePath)
def findBiggestBlob(inputImage):
# Store a copy of the input image:
biggestBlob = inputImage.copy()
# Set initial values for the largest contour:
largestArea = 0
largestContourIndex = 0
# Find the contours on the binary image:
contours, hierarchy = cv2.findContours(inputImage, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)
# Get the largest contour in the contours list:
for i, cc in enumerate(contours):
# Find the area of the contour:
area = cv2.contourArea(cc)
# Store the index of the largest contour:
if area > largestArea:
largestArea = area
largestContourIndex = i
# Once we get the biggest blob, paint it black:
tempMat = inputImage.copy()
cv2.drawContours(tempMat, contours, largestContourIndex, (0, 0, 0), -1, 8, hierarchy)
# Erase smaller blobs:
biggestBlob = biggestBlob - tempMat
return biggestBlob
现在,让我们看看主要脚本。让我们读取图像并获取初始的二进制掩码:# Imports
import cv2
import numpy as np
# Read image
imagePath = "D://opencvImages//"
inputImage = cv2.imread(imagePath + "L85Bu.jpg")
# Get image dimensions
originalImageHeight, originalImageWidth = inputImage.shape[:2]
# Resize at a fixed scale:
resizePercent = 30
resizedWidth = int(originalImageWidth * resizePercent / 100)
resizedHeight = int(originalImageHeight * resizePercent / 100)
# Resize image
inputImage = cv2.resize(inputImage, (resizedWidth, resizedHeight), interpolation=cv2.INTER_LINEAR)
writeImage(imagePath+"objectInput", inputImage)
# Deep BGR copy:
colorCopy = inputImage.copy()
# Convert BGR to grayscale:
grayscaleImage = cv2.cvtColor(inputImage, cv2.COLOR_BGR2GRAY)
# Threshold via Otsu:
_, binaryImage = cv2.threshold(grayscaleImage, 250, 255, cv2.THRESH_BINARY_INV)
这是根据
30%
按 resizePercent
调整大小的输入:这是使用固定
threshold
为 250
创建的二进制掩码:现在,我要通过
while
循环运行这个掩码。每次迭代时,我都会提取“最大”斑点,直到没有斑点为止。每一步都会创建一个新的二进制掩码,其中一次只存在一个对象。这将是隔离原始(调整大小)
BGR
图像中的对象的关键:
# Image counter to write pngs to disk:
imageCounter = 0
# Segmentation flag to stop the processing loop:
segmentObjects = True
while (segmentObjects):
# Get biggest object on the mask:
currentBiggest = findBiggestBlob(binaryImage)
# Use a little bit of morphology to "widen" the mask:
kernelSize = 3
opIterations = 2
morphKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (kernelSize, kernelSize))
# Perform Dilate:
binaryMask = cv2.morphologyEx(currentBiggest, cv2.MORPH_DILATE, morphKernel, None, None, opIterations,cv2.BORDER_REFLECT101)
# Mask the original BGR (resized) image:
blobMask = cv2.bitwise_and(colorCopy, colorCopy, mask=binaryMask)
# Flood-fill at the top left corner:
fillPosition = (0, 0)
# Use white color:
fillColor = (255, 255, 255)
colorTolerance = (0,0,0)
cv2.floodFill(blobMask, None, fillPosition, fillColor, colorTolerance, colorTolerance)
# Write file to disk:
writeImage(imagePath+"object-"+str(imageCounter), blobMask)
imageCounter+=1
# Subtract current biggest blob to
# original binary mask:
binaryImage = binaryImage - currentBiggest
# Check for stop condition - all pixels
# in the binary mask should be black:
whitePixels = cv2.countNonZero(binaryImage)
# Compare agaisnt a threshold - 10% of
# resized dimensions:
whitePixelThreshold = 0.01 * (resizedWidth * resizedHeight)
if (whitePixels < whitePixelThreshold):
segmentObjects = False
这里有一些值得注意的事情。这是为第一个对象创建的第一个隔离蒙版:
很好。一个带有
BGR
图像的简单蒙版就可以了。但是,如果我应用
dilate
形态学操作,我可以提高掩模的质量。这将“加宽”斑点,覆盖原始轮廓几个像素。 (该操作实际上是在“Neighborhood”像素内搜索“最大”强度像素)。接下来,遮罩将生成一个 BGR
图像,其中只有对象斑点和黑色背景。我不想要黑色背景,我想要白色。我
flood-fill
在左上角得到第一个
BGR
面具:
我将每个掩码保存到磁盘上的新文件中。非常酷。现在,退出循环的条件非常简单 - 当所有 blob 处理完毕后停止。为了实现这一点,我将当前最大的斑点减去原始二进制白色,并计算白色像素的数量。当计数低于某个阈值(在本例中为调整大小的图像的 10%
)时,停止循环。检查每个隔离对象的gif
。每个帧都作为 png
文件保存到磁盘:
检测外部轮廓。 对于每个轮廓:
2.3 为第 i 部分创建黑色结果图像
3.5 保存第i部分的结果图像