Search code examples
pythonnumpynumpy-ndarrayedge-detectionnumpy-slicing

how to detect and slice boxes out of a numpy array


I've got a wide image with 2 images inside it, these 2 images could be seen as 'boxes' in the big image and the numpy array would look like this:

[
[200,200,200,157,200,200,200,238,256,167,234,266,154,200,200,200,157,200,200,200,238,256,167,234,266,154,200,200,200,157,200,200,200],
[200,200,200,200,200,200,200,238,256,167,234,266,154,200,200,200,200,200,200,200,238,256,167,234,266,154,200,200,200,200,200,200,200],
[200,144,200,200,132,200,200,238,256,167,234,266,154,200,144,200,200,132,200,200,238,256,167,234,266,154,200,144,200,200,132,200,200],
[200,200,200,200,200,200,200,238,256,167,234,266,154,200,200,200,200,200,200,200,238,256,167,234,266,154,200,200,200,200,200,200,200],
[200,200,166,200,200,200,200,238,256,167,234,266,154,200,200,166,200,200,200,200,238,256,167,234,266,154,200,200,166,200,200,200,200],
[182,200,200,200,200,200,200,238,256,167,234,266,154,182,200,200,200,200,200,200,238,256,167,234,266,154,182,200,200,200,200,200,200]
]

These are the boxes

Because i applied a median filter, the surrounding pixels are all 200 with a little bit of noise here and there. My question is: How can i extract those 2 sub-images from this big image and put them as their own array so i have the pictures seperately. My guess would be to slice them out or maybe use edge detection but i haven't succeeded to do so yet. The array in the question is mockup but represents how it looks like because the real array it too big for the output in visual studio. Underneath is what a picture really looks like, there are different pictures with each different 'white spaces' and amount of sub pictures in it. The size is fixed and always 28 x 200.


Solution

  • I am not sure whether my assumptions of your image data is correct. The following algorithm only works, if the image itself does not contain "flat regions" of 200.

    import numpy as np
    from matplotlib import pyplot as plt
    
    data = np.array([
    [200,200,200,157,200,200,200,238,256,167,234,266,154,200,200,200,157,200,200,200,238,256,167,234,266,154,200,200,200,157,200,200,200],
    [200,200,200,200,200,200,200,238,256,167,234,266,154,200,200,200,200,200,200,200,238,256,167,234,266,154,200,200,200,200,200,200,200],
    [200,144,200,200,132,200,200,238,256,167,234,266,154,200,144,200,200,132,200,200,238,256,167,234,266,154,200,144,200,200,132,200,200],
    [200,200,200,200,200,200,200,238,256,167,234,266,154,200,200,200,200,200,200,200,238,256,167,234,266,154,200,200,200,200,200,200,200],
    [200,200,166,200,200,200,200,238,256,167,234,266,154,200,200,166,200,200,200,200,238,256,167,234,266,154,200,200,166,200,200,200,200],
    [182,200,200,200,200,200,200,238,256,167,234,266,154,182,200,200,200,200,200,200,238,256,167,234,266,154,182,200,200,200,200,200,200]
    ])
    
    
    # filter all regions of (more or less) constant 200
    median_data = np.median(data, axis=0)
    diff_data = np.append([0], np.diff(median_data))
    img_region = (diff_data != 0) & (median_data != 200)
    
    # get image regions, identify longest image as "true" image length
    idx_pairs = np.where(np.diff(np.hstack(([False],img_region,[False]))))[0]
    region_lengths = np.diff(idx_pairs)[::2]
    longest_region = np.max(np.diff(idx_pairs)[::2])
    
    # fix broken images
    for i_region, region_length in enumerate(region_lengths):
        if region_length != longest_region:
            try:
                img_region[slice(idx_pairs[i_region*2], idx_pairs[i_region*2]+longest_region)] = True
            except IndexError:
                pass  # removed mini-regions
        idx_pairs = np.where(np.diff(np.hstack(([False], img_region, [False]))))[0]
    
    # get number of images
    n_img = np.sum(np.diff(img_region.astype(int)) == 1)
    image_data = data[:, img_region]
    
    # slice images
    images = np.split(image_data, n_img, axis=1)
    for img in images:
        plt.figure()
        plt.imshow(img)
    
    plt.show()