【问题标题】:Splitting images into distinct subimages in python在python中将图像拆分为不同的子图像
【发布时间】:2021-01-27 21:16:55
【问题描述】:

我有一些python代码(使用枕头模块)将图像转换为一系列剪影,如下所示,这段代码完全正常。

我这样做的目的是将原始图像分成一系列子图像。

我完全不知道如何去检测哪些区域是集群并且应该被裁剪成他们自己的子图像,任何建议都将不胜感激

【问题讨论】:

  • Scikit-image 有大量的examples。您基本上是在寻找对象/边缘检测。
  • 你到底想做什么?你想提取黑色的每一片叶子吗?如果是这样,您可以按照此处所述使用 numpy 进行操作:stackoverflow.com/questions/60780831/…
  • @Rivers 我正在尝试提取 rgb 中的每一片叶子,我将它们转换为黑色,因为我认为确定边缘会更容易,不过谢谢!我去看看
  • 您也可以在黑白图像上使用docs.opencv.org/master/d4/d73/tutorial_py_contours_begin.html,将每片叶子作为子图像。

标签: python python-3.x computer-vision python-imaging-library


【解决方案1】:

这是一种方法:

此代码将提取图像的区域(部分)。 我们通常将其称为“感兴趣的区域提取”(ROIs 提取)或有时称为“感兴趣的区域提取”。

首先,我们对源图像进行一些操作,以便找到我们要提取的对象的精确轮廓。然后根据这些轮廓,我们提取出我们想要的图像部分。

对于您的示例 BMerz,它将在单独的文件中输出每个绿叶。

import cv2
import numpy as np

# Source image
source_image_path = "leaves.png"
source_image_name, ext =  source_image_path.split(".")

# Load the image
source_image = cv2.imread(source_image_path)

# Convert image to grayscale
grayscale_image = cv2.cvtColor(source_image, cv2.COLOR_BGR2GRAY)

# Save the image
cv2.imwrite((source_image_name + "_grayscale." + ext), grayscale_image)

# Remove gaussian noise
denoised_image = cv2.GaussianBlur(grayscale_image,(3,3),0)

# Detect edges
#160 and 210 : min and max thresholds. Look at the saved image after tweakings, in order to find the right values.
edges = cv2.Canny(denoised_image, 160, 210)

# Save the image
cv2.imwrite((source_image_name + "_edges." + ext), edges)


# Use erode and dilate to remove unwanted edges and close gaps of some edges
# Again, tweak the kernel values as needed

# Erode will make the edges thinner. If the kernel size is big, some edges will be removed.
# (1,1) will erode a little, (2,2) will erode more, (5,5) will erode even more...
kernel = np.ones((1,1), np.uint8)
eroded_edges = cv2.erode(edges, kernel, iterations = 10)

# dilate will smooth the edges
# (1,1) will dilate a little, (2,2) will dilate more, (5,5) will dilate even more...
kernel = np.ones((3,3), np.uint8)
dilated_edges = cv2.dilate(eroded_edges, kernel, iterations = 1)


# Find contours
# Use a copy of the image: findContours alters the image
dilated_edges_copy = dilated_edges.copy()
ret, thresh = cv2.threshold(dilated_edges_copy, 127, 255, 0)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# We could have used v2.RETR_EXTERNAL and CHAIN_APPROX_NONE too

# Create a list containing only the contours parents from the hierarchy returned by findContours
hierarchy_parents_only = [x[3] for x in hierarchy[0]]

print("Number of contours found: ", len(contours))
print("Number of hierarchies found: ", len(hierarchy_parents_only))


# Now we will filter the contours. We select only the ones we need.
selected_contours = list()
selected_hierarchy = list()
min_area = 100

for index,contour in enumerate(contours):
    # Keep only contours having no parent (remove overlapping contours
    if hierarchy_parents_only[index] == -1:
        # Keep only contours having an area greater than "min_area"
        area = cv2.contourArea(contour)
        if area > min_area:
            selected_contours.append(contour)
            selected_hierarchy.append(hierarchy[0][index])

print("Number of selected contours: ", len(selected_contours))
print("Number of selected hierarchies : ", len(selected_hierarchy))


# Draw all contours on the source image (usefull for debugging, but change color (0, 0, 0) to something else if the background is black too).
# -1 means drawing all contours, "(0, 255, 0)" for contours in green color, "3" is the thickness of the contours
source_image_with_contours = cv2.drawContours(source_image, selected_contours, -1, (0, 0, 0), 3) 

# Save the image
cv2.imwrite((source_image_name + "_with_contours." + ext), source_image_with_contours)


# Now, extract each image
for index,contour in enumerate(selected_contours):

    # Image name for writing to file
    cropped_image_path = source_image_name + "_" + str(index) + "." + ext

    # Create mask where white is what we want, black otherwise
    mask = np.zeros_like(grayscale_image)

    # Draw filled contour in mask
    cv2.drawContours(mask, selected_contours, index, 255, -1)

    # Mask everything but the object we want to extract
    masked_image = cv2.bitwise_and(source_image, source_image, mask=mask)
    cv2.imwrite("out2.jpg", masked_image)
    
    # Determine the bounding box (minimum rectangle in which the object can fit)
    (y, x) = np.where(mask == 255)
    (top_y, top_x) = (np.min(y), np.min(x))
    (bottom_y, bottom_x) = (np.max(y), np.max(x))

    # Crop image (extract)
    extracted_image = masked_image[top_y:bottom_y+1, top_x:bottom_x+1]

    # Write to file
    cv2.imwrite(cropped_image_path, extracted_image)

【讨论】:

  • 抱歉响应缓慢,但这非常有效!谢谢!
猜你喜欢
  • 2019-07-17
  • 2016-11-09
  • 1970-01-01
  • 2020-03-03
  • 2013-01-27
  • 2023-03-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多