按空白分割图像

问题描述 投票:0回答:2

我有一个图像,我试图将其分割成单独的组件,我已经使用 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)

原图

k-means结果

python opencv
2个回答
3
投票

我的解决方案涉及创建一个二进制对象蒙版,其中所有对象都为白色,背景为黑色。然后,我根据面积从最大到最小提取每个对象。我使用这个“孤立的对象”蒙版来分割原始图像中的每个对象。然后我将结果写入磁盘。这些是步骤:

  1. 调整图像大小(您的原始输入是巨大的)
  2. 转换为灰度
  3. 根据面积从最大到最小提取每个对象
  4. 创建隔离对象的
  5. 二进制掩码 涂抹一点点
  6. morphology
  7. 来增强面膜效果
  8. 使用二值掩码对原始 BGR 图像进行掩码
  9. 应用洪水填充
  10. 将背景着色为白色
  11. 图像保存到磁盘
  12. 对图像中的所有对象重复
  13. 该过程
  14. 让我们看看代码。通过该脚本,我使用了两个辅助函数:
  15. 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 文件保存到磁盘:

    

检测外部轮廓。

对于每个轮廓:

0
投票
2.1 创建黑色蒙版图像
  1. 2.2 在掩模图像上绘制第i个填充轮廓

    2.3 为第 i 部分创建黑色结果图像
  2. 2.4 使用刚刚创建的蒙版从源图像复制到结果图像

    3.5 保存第i部分的结果图像

© www.soinside.com 2019 - 2024. All rights reserved.