当边界框重叠时如何检测和裁剪单个精灵?

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

请先参考此链接:

如何自动检测并裁剪精灵表中的各个精灵边界?

在上面链接的示例中,各个精灵的边界框不重叠,因此接受的答案中的代码运行良好,并且所有精灵都提取在单独的文件中。

但是假设精灵的包装方式不同,即使单个图像没有重叠,它们的边界框也会重叠:

那么上面的代码根本无法正常工作,并且只输出一个文件,因为边界框会相交。

有人如何使用 OpenCV 解决这个问题?

如果不使用 OpenCV,我的方法是:

  • 遍历每个精灵,直到找到一个不透明的精灵。将其以及所有连接的非透明精灵存储为单独的集合。
  • 一旦前一组不再有连接的像素,请检查图像其余部分中的剩余像素,忽略我已经看到的像素并将其放入上面的组中。当我遇到一个我以前没有见过的新的非透明像素时,然后重复与第一步相同的操作,但将这些连接的像素放入一个新的集合中。
  • 像这样重复这个过程,直到没有任何像素可供检查。
  • 对于每组连接的像素,创建一个新图像,其尺寸来自由该组最远像素构建的边界框。但仅包括输出图像中该连接集中的像素。对每个集合重复此操作,为每个连接的集合创建一个新图像。

除了我上面描述的方法之外,有没有一种方法可以使用 OpenCV 来做到这一点?我可以用我的方法做到这一点,但我想了解更多有关 OpenCV 及其功能的信息,但我只是一个初学者,仍在学习中。

algorithm opencv image-processing computer-vision sprite
1个回答
1
投票

您可以用白色填充每个轮廓,然后生成仅包含该轮廓的图像。之后,通过获取边界矩形的属性来应用常规裁剪。这是代码:

im = cv2.imread("trees.png") # read image
imGray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY) # convert to gray
contours, _ = cv2.findContours(imGray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # contouring
sortedContours = sorted(contours, key=cv2.contourArea, reverse=True) # sorting, not necessary...
for contourIdx in range(0,len(sortedContours)-1): # loop with index for easier saving
    contouredImage = im.copy() # copy image
    contouredImage = cv2.drawContours(contouredImage, sortedContours, contourIdx, (255,255,255), -1) # fill contour with white
    extractedImage = cv2.inRange(contouredImage, (254,254,254), (255,255,255)) # extract white from image
    resultImage = cv2.bitwise_and(im, im, mask=extractedImage) # AND operator to get only one filled contour at a time
    x, y, w, h = cv2.boundingRect(sortedContours[contourIdx]) # get bounding box
    croppedImage = resultImage[y:y + h, x:x + w] # crop
    cv2.imwrite("contour_"+str(contourIdx)+".png", croppedImage) # save

结果看起来也不错,我只发布最大的和最小的作为示例:

V2.0:使其适用于两个图像

由于某种原因,第一张图像的所有背景的绿色通道上都有 255。这就是为什么只检测到一个大轮廓的原因。我添加了几行代码来预处理图像并考虑 Alpha 通道。这是代码:

im = cv2.imread("trees.png", cv2.IMREAD_UNCHANGED) # read image
b, g, r, alpha = cv2.split(im.copy()) # split image
g[g==255] = 0 # for the first image where the green channel has 255 on all background pixels
imBGR = cv2.merge([b,g,r]) # recombine image in BGR format
imGray = cv2.cvtColor(imBGR, cv2.COLOR_BGR2GRAY) # convert to gray
contours, _ = cv2.findContours(imGray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # contouring
sortedContours = sorted(contours, key=cv2.contourArea, reverse=True) # sorting, not necessary...
for contourIdx in range(0,len(sortedContours)-1): # loop with index for easier saving
    contouredImage = imBGR.copy() # copy BGR image
    contouredImage = cv2.drawContours(contouredImage, sortedContours, contourIdx, (255,255,255), -1) # fill contour with white
    extractedImage = cv2.inRange(contouredImage, (254,254,254), (255,255,255)) # extract white from image
    resultImage = cv2.bitwise_and(imBGR, imBGR, mask=extractedImage) # AND operator to get only one filled contour at a time
    x, y, w, h = cv2.boundingRect(sortedContours[contourIdx]) # get bounding box
    croppedImage = resultImage[y:y + h, x:x + w] # crop
    cv2.imwrite("trees_2_contour_"+str(contourIdx)+".png", croppedImage) # save

我不会再费心添加结果图像,因为它们和以前一样。然而,这是我正在谈论的带有绿色背景的第一个示例的图像:

代码:

im = cv2.imread("trees2.png", cv2.IMREAD_UNCHANGED) # read image
b, g, r, alpha = cv2.split(im.copy()) # split image
imBGR = cv2.merge([b,g,r]) # recombine image in BGR format
plt.imshow(imBGR)

图片:

我用

g[g==255] = 0

解决了这个问题
© www.soinside.com 2019 - 2024. All rights reserved.