如何在视网膜图像掩码内随机裁剪50×50子图并验证有效性
视网膜图像掩码内随机裁剪50×50子图方案
问题背景
现有一张视网膜图像,目标是仅裁剪视网膜区域的子图。已完成以下前置步骤:
- 通过代码生成了视网膜区域的掩码
- 得到了仅保留视网膜的图像
- 尝试网格裁剪仅得到2个符合要求的子图,需求是随机裁剪5个完全位于掩码内的50×50子图,同时需要验证裁剪的子图是否在掩码内。
已实现的前置代码
生成掩码的代码
# 生成掩码 img = imread(folder + 'test.jpg') blur = cv2.GaussianBlur(img, (3, 3), cv2.BORDER_DEFAULT) edged = cv2.Canny(blur, 10, 250) # 二值化 thresh = cv2.threshold(edged, 128, 255, cv2.THRESH_BINARY)[1] # 形态学闭运算 kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5)) thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel) # 获取外接轮廓的 bounding box 并填充轮廓 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) # 得到掩码 mask = filled.copy() cv2_imshow(mask)
生成仅保留视网膜图像的代码
# 生成仅保留视网膜的图像 new_image = cv2.cvtColor(img, cv2.COLOR_BGR2BGRA) new_image[:,:,3] = mask[:,:] imshow(new_image)
尝试的网格裁剪代码
def img_to_grid(img): 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)
解决方案:随机裁剪5个掩码内的50×50子图
实现思路
- 筛选所有可放置50×50子图的左上角坐标:坐标需满足子图不超出图像边界,且对应区域的掩码全部为255(完全在视网膜区域内)。
- 从有效坐标中随机挑选5个不同的位置,裁剪对应子图。
- 通过检查子图对应掩码区域是否全为255,验证子图是否符合要求。
完整代码
import cv2 import numpy as np import random import matplotlib.pyplot as plt # 假设已存在img(原始视网膜图像)和mask(生成的掩码)变量 sub_size = 50 # 子图尺寸 num_subimgs = 5 # 需要的子图数量 # 1. 筛选所有有效的左上角坐标 valid_coords = [] img_h, img_w = img.shape[:2] for y in range(img_h - sub_size + 1): for x in range(img_w - sub_size + 1): # 检查该区域内的掩码是否全为255 mask_region = mask[y:y+sub_size, x:x+sub_size] if np.all(mask_region == 255): valid_coords.append((x, y)) # 2. 随机挑选指定数量的坐标(如果有效坐标不足则取全部) selected_coords = random.sample(valid_coords, min(num_subimgs, len(valid_coords))) # 3. 裁剪子图 subimgs = [] for x, y in selected_coords: subimg = img[y:y+sub_size, x:x+sub_size] subimgs.append(subimg) # 4. 验证子图是否完全在掩码内 def validate_subimg(coord, mask, sub_size): x, y = coord mask_region = mask[y:y+sub_size, x:x+sub_size] return np.all(mask_region == 255) # 输出验证结果 for idx, coord in enumerate(selected_coords): is_valid = validate_subimg(coord, mask, sub_size) print(f"第{idx+1}个子图是否有效:{is_valid}") # 显示裁剪得到的子图 fig, axes = plt.subplots(1, len(subimgs), figsize=(15, 5)) for ax, subimg in zip(axes, subimgs): ax.imshow(cv2.cvtColor(subimg, cv2.COLOR_BGR2RGB)) ax.axis('off') plt.show()
代码说明
- 有效坐标筛选:遍历所有可能的左上角位置,确保对应子图区域完全覆盖视网膜(掩码全为255)。
- 随机采样:使用
random.sample避免重复选取同一位置,同时处理有效坐标不足的情况。 - 验证逻辑:通过检查掩码区域的像素值,确保子图没有超出视网膜范围。
- 结果展示:用matplotlib批量展示裁剪后的子图,直观确认效果。
注意事项
- 如果有效坐标数量不足5个,代码会自动取所有有效坐标,避免报错。
- 可通过修改
sub_size和num_subimgs参数,适配不同尺寸的子图和数量需求。
内容的提问来源于stack exchange,提问作者test tes
相关产品推荐
相关产品推荐

