Home > Back-end >  Detect cropped image is within mask
Detect cropped image is within mask

Time:10-28

Say I have an image as follows and I would like to crop some sub-images of the retina only. enter image description here

So the first step I took is to find a mask

# Find Mask
img = imread(folder   'test.jpg')
blur = cv2.GaussianBlur(img, (3, 3), cv2.BORDER_DEFAULT)
edged = cv2.Canny(blur, 10, 250) 

# threshold
thresh = cv2.threshold(edged, 128, 255, cv2.THRESH_BINARY)[1]

# apply close morphology
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)

# get bounding box coordinates from the one filled external contour
filled = np.zeros_like(thresh)
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
max_cnt = max(cnts, key=cv2.contourArea)
x,y,w,h = cv2.boundingRect(max_cnt)
cv2.drawContours(filled, [max_cnt], 0, 255, -1)

# crop filled contour image
mask = filled.copy()

cv2_imshow(mask)

Here is the mask found: enter image description here

Then I wish to crop subimages of 50 * 50 within the inner area of a mask

Here is some code I found online:

# This gives the retina only
new_image = cv2.cvtColor(img, cv2.COLOR_BGR2BGRA)
new_image[:,:,3] = mask[:,:]
imshow(new_image)

enter image description here

Below is closer to what I want. There are two sub-images that are within the mask. But what I really want is to crop maybe 5 sub-images randomly that are within the mask. Is there a way that I can do that? Or how can I check the cropped images are within the mask?

def img_to_grid(img):
    # ww = [[i.min(), i.max()] for i in np.array_split(range(img.shape[0]),row)]
    # hh = [[i.min(), i.max()] for i in np.array_split(range(img.shape[1]),col)]
    print(img.shape[0], img.shape[1])
    ww = [[i, i 100-1] for i in range(0, img.shape[0],100)]
    print(ww)
    hh = [[i, i 100-1] for i in range(0, img.shape[1],100)]
    print(hh)
    grid = [img[j:jj,i:ii,:] for j,jj in ww for i,ii in hh]
    print((j, jj, i, ii) for j,jj in ww for i,ii in hh)
    return grid, len(ww), len(hh)

def plot_grid(grid,row,col,h=5,w=5):
    fig, ax = plt.subplots(nrows=row, ncols=col)
    [axi.set_axis_off() for axi in ax.ravel()]

    fig.set_figheight(h)
    fig.set_figwidth(w)
    c = 0
    for row in ax:
        for col in row:
            col.imshow(np.flip(grid[c],axis=-1))
            c =1
    plt.show()


grid , r,c = img_to_grid(img)
plot_grid(grid,r,c)

enter image description here

CodePudding user response:

If you want to extract really random sub-images that is not necessary inscribed in a circle, you can just get some coords within the non-zero mask bounding box, check if it contains only ones, and save them, if so.

sub_imgs = []

# Define minimum width and height for the cropped region
min_width = 32
min_height = 32

# Define the number of sub-images
sub_img_count = 5

while len(sub_imgs) < sub_img_count:
    x1 = np.random.randint(x, x   w)
    y1 = np.random.randint(y, y   h)

    maxw = w - (x1 - x)
    maxh = h - (y1 - y)

    # Skip if maximum possible sizes don't meet the requirement
    if not (maxw > min_width and maxh > min_height):
        continue

    width = np.random.randint(min_width, maxw)
    height = np.random.randint(min_height, maxh)

    # Extract the region only if it is within the mask
    if np.all(mask[y1: y1   height, x1: x1   width]):
        sub_img = img[y1: y1   height, x1: x1   width, :]
        sub_imgs.append(sub_img)

# Save the cropped regions
for i, sub_img in enumerate(sub_imgs):
    cv2.imwrite(f'{i   1}.jpg', sub_img)

The cropped sub-image example

  • Related