Python,有没有办法在更大的图像区域内找到子区域的属性?

Python, Is there a way to find the properties of a subregion within a larger image region?

目标:我有带粒子的图像,我需要找到它们的面积。 ((array([], dtype=int32), array([], dtype=int64)), <class 'numpy.ndarray'> (512, 512, 3) <class 'tuple'>)每个粒子还有四到五个子区域,我需要知道它们的面积。想一想图片中的一堆脱衣衬衫。我需要找到每件衬衫的面积,对于某件衬衫,我需要知道每条条纹的面积。问题是我需要知道条纹对应哪件衬衫。我需要知道较小区域对应的粒子。这样我就可以获得一个区域中每个子区域的百分比面积。 我有一个灰度大颗粒的图像,一个所有覆盖子区域的图像和每个子区域的图像。我创建了一个简化的图像模型。 [SubRegion1][1] [SubRegion2][2] [TotalAreaRegion][3]

我尝试过的: 使用 openCV 进行分割,然后使用 scikit-image.org 中的 regionprops 我可以获得主要粒子大小、纵横比等。 我不能做的是获得这些子区域区域并知道它们去哪个父粒子。当我需要一个时,我会生成两个单独的标签列表。

代码:


#markers are the marked regions in the total image. red_markers are the marked sub-regions in the second image.
       markers = cv2.watershed(crop_img, markers)
       red_markers = cv2.watershed(red_crop_img, red_markers)


    #if marker = 1, bg, then color 
    crop_img[markers == 1] = [0, 255, 255]
     red_crop_img[red_markers == 1] = [0, 255, 255]
     img2 = color.label2rgb(markers, bg_label=0)
     red_img2 = color.label2rgb(red_markers, bg_label=0)
    mask = red_markers == 255
    masked_img = markers[mask] = 255
    img3 = np.unique(masked_img, return_counts=True)
     print(img3)
output: array[0]array[255]

'''


 


  [1]: https://i.stack.imgur.com/wVef6.png
  [2]: https://i.stack.imgur.com/AhqDZ.png
  [3]: https://i.stack.imgur.com/cZWJC.png

我不是很清楚这个问题,但如果我理解正确,下面的方法应该可行:

  1. 在大粒子灰度图中标注粒子(skimage.morphology.label)
  2. 使用 sub-region 遮罩之一遮罩图像(您可以为此使用 numpy 索引,例如 label_image[mask]
  3. 查看保留了哪些标签,这些标签标识了与遮罩重叠的粒子 (np.unique(label_image[mask]))
  4. 对剩余的 sub-regions
  5. 重复

您可以测量 np.unique(label_image, return_counts=True) 等区域。这将 return 一个标签数组和一个包含该标签的像素数的数组。同样,对于掩码定义的给定 sub-region 中的像素,您可以测量像 np.unique(label_image[mask], return_counts=True).

这样的区域

这是一个演示这种方法的 MWE

import numpy as np
import skimage.morphology

### Create example images

full_image = np.array(
    [[ 255, 255, 255,   0,   0],
     [ 255, 255, 255,   0,   0],
     [   0,   0,   0,   0,   0],
     [   0,   0,   0, 255, 255],
     [ 255, 255,   0, 255, 255]],
    dtype='uint8')

subregion_image = np.array(
    [[255,   0, 255,   0,   0],
     [255,   0, 255,   0,   0],
     [  0,   0,   0,   0,   0],
     [  0,   0,   0, 255, 255],
     [  0,   0,   0,   0,   0]],
    dtype='uint8')

# Make format match that format (i.e. RGB) and datatype of OP
full_image = np.repeat(full_image[:, :, np.newaxis], 3, axis=2).astype(dtype='int32')
subregion_image = np.repeat(subregion_image[:, :, np.newaxis], 3, axis=2).astype(dtype='int64')

### Simplify images

# If we know all three channels are the same it's easier (and equivalent) to have a single channel
full_image = full_image[:, :, 0]  
subregion_image = subregion_image[:, :, 0]

# If we know values are all in the range 0 to 255 we may as well use uint8, miage not matter but it's
# generally helps avoid confusion when dealing with images to have intensity range and datatype match
full_image = full_image.astype('uint8')
subregion_image = subregion_image.astype('uint8')

### Solve the problem

# Label the particles in the large particle image
label_image = skimage.morphology.label(full_image)

# Create a mask for the sub-region
mask = subregion_image == 255

# See which labels remain, these labels identify the particles that overlap with the mask
print(np.unique(label_image[mask]))

# To measure the area we'll set pixels outside the subregion to 0 for background
label_image[~mask] = 0

# Count pixels belonging to each particle
particle_label, pixel_count = np.unique(label_image, return_counts=True)
print(particle_label)
print(pixel_count)

如果您有 PIL 图像或类似图像,您可能需要转换为 numpy 数组,例如 your_image = np.array(your_image)

由于您将遍历 sub-regions,如果您有数百万个 sub-regions,这种方法可能不会特别快。