1. 前処理後
CV データは、前処理後に次の仕様を満たす必要があります。
- img、mask — 元の画像と切り取った画像のパスをそれぞれ保存する 2 つの配列 (str)
- imgs、mask — 元のイメージと切り取ったイメージ (テンソル) をそれぞれ保存する 2 つの配列
- マスクには 0 と 1 のみがあり、imgs 変数の型は torch.long です。
2. データの拡張
データ拡張は、データ ジェネレーターがデータをキャプチャするときに調整され、キャプチャされたデータはそれに応じて処理されてモデルに投入されます。現在、次の機能強化が計画されています: ランダム クロッピング (近接補間)、水平反転、
torchvision.transforms は、pytorchの画像前処理パッケージです。一般に、Compose は複数のステップを統合するために使用されます。これを使用して標準化操作を実行し、3 つのレイヤーの標準化と差異を入力できます。画像とセグメントの同期が失われる可能性があるため、トリミングなどの拡張機能は実行しないことをお勧めします。
tf = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.25, 0.25, 0.25])]
)
トリミングは次のコードで実現できます。
def rand_crop(imgs, masks, h, w):
"""随机裁剪img与seg"""
rect = torchvision.transforms.RandomCrop.get_params(imgs, (h, w))
imgs = torchvision.transforms.functional.crop(imgs, *rect)
masks = torchvision.transforms.functional.crop(masks, *rect)
return imgs, masks
ただし、上記のコードの欠点は、このプロジェクトのファイルが npy ファイルであることです。numpy ファイルは、np.load で読み込んだ後、Image.formarray(np) または torch.tensor(np) で変換できますが、データは変換されています (-1 から 1)。直接変換プロセスの PIL テンソルは認識できないため、処理する必要があります。
したがって、最良の解決策は、np 独自の方法を使用してデータ拡張を実現することだと思われます。
- np.flip はランダムな反転を実装します (Fate は疑似サイコロです)。
def horiz_flip(imgs, segs, dice):
Fate = randint(1, 100)
if dice>=Fate:
imgs = np.flip(imgs, 1) # 水平翻转
segs = np.flip(segs, 1)
# res2 = np.flip(img, 0) # 垂直翻转
# res3 = np.flip(img, -1) # 水平垂直翻转
return imgs, segs
else: return imgs, segs
- skimage.util に基づいてランダム ノイズを追加します。
import skimage
def add_noise(img):
Fate = randint(1,100)
if Fate <= 40:
return img
elif Fate<=70:
"高斯噪声"
img = skimage.util.random_noise(img, mode='gaussian', var=0.01)
return img
else:
"椒盐噪声"
img = skimage.util.random_noise(img, mode='s&p')
return img
- np.lib.pad に基づくランダムなトリミング:
def random_crop(image, seg, crop_shape, padding=None): oshape = np.shape(image) if padding: oshape = (oshape[0] + 2 * padding, oshape[1] + 2 * padding) npad = ((padding, padding), (padding, padding),(0, 0)) npad_seg = ((padding, padding), (padding, padding)) print(oshape) print(npad) image_pad = np.lib.pad(image, pad_width=npad, mode='constant', constant_values=0) seg_pad = np.lib.pad(seg, pad_width=npad_seg, mode='constant', constant_values=0) nh = random.randint(0, oshape[0] - crop_shape[0]) nw = random.randint(0, oshape[1] - crop_shape[1]) image_crop = image_pad[nh:nh + crop_shape[0], nw:nw + crop_shape[1]] seg_crop = seg_pad[nh:nh + crop_shape[0], nw:nw + crop_shape[1]] return image_crop, seg_crop else: print("WARNING!!! nothing to do!!!") return image plt.figure(figsize=(5,5)) img1 = np.load(img[1145])[:,:,:] seg1 = np.load(mask[1145])[:,:] plt.subplot(2,2,1) plt.imshow(img1, cmap='gray') plt.subplot(2,2,2) plt.imshow(seg1, cmap='gray') img1, seg1 = random_crop(img1, seg1, [224, 224], 16) plt.subplot(2,2,3) plt.imshow(img1, cmap='gray') plt.subplot(2,2,4) plt.imshow(seg1, cmap='gray') plt.tight_layout() plt.show()
- ヒント: トレーニング モデルでは 3 チャネルを使用する必要があるため、上記の操作では 3 チャネル (RGB) 画像をトリミングできるはずです。imshow を使用すると問題が発生する可能性があります。別の記事を参照してください。
noisy = np.clip(noisy, 0.0, 1.0)
モデルの特定の効果によっては、ノイズの使用の効果が MRI 画像に良くない場合があります。
この時点で、画像の前処理と画像拡張が完了します。
補充する
- 変換操作では、この操作により画像の空間情報が破壊されることがわかります。衛星画像、航空画像、医療画像などの画像の元の空間構造を破壊したくないため、画像を回転するときは、 90 度の倍数で回転させるのが最適です。
- 非剛体変換は、医療画像の問題におけるデータを増強するのに役立ちます。次の非剛体変換クラスは主にアルバムで提供されます:
ElasticTransform(弹性变换)
、GridDistortion(网格畸变)
およびOpticalDistortion(光学畸变)
。 - albumentations ライブラリのメソッドを使用すると、非常に簡単にデータ拡張を実現できます。コードは下図に示すように、ランダムなトリミング (100% の確率)、ランダムな非破壊変換 (50% のランダムな垂直反転、50% のランダムな回転) を統合しています。 90度ごと)、80%確率的ランダム非剛体変換(弾性変換、グリッド歪み、光学歪みの確率比は1:1:2)、ランダム非空間変換(コントラストバランスの確率50%、50%)明るさとコントラストがランダムに変化する確率 (%))。上記skimageパッケージでノイズ追加も追加されました。
- メソッドは img を返します。img["image"] は画像、img["mask"] はマーカーです。
-
from albumentations import * def augmentation(img, seg): img = Compose([ # 随机裁剪 RandomSizedCrop(min_max_height=(224, 224), height=224, width=224, interpolation=cv2.INTER_NEAREST, p=1), # 非破坏性转换 VerticalFlip(p=0.5), # 随机垂直翻转 RandomRotate90(p=0.5), # 随机旋转90度 # 非刚体转换 OneOf([ ElasticTransform(p=0.5, interpolation=cv2.INTER_NEAREST), # 弹性变换 GridDistortion(p=0.5, interpolation=cv2.INTER_NEAREST), # 网格畸变 OpticalDistortion(p=1, distort_limit=2, shift_limit=0.5, interpolation=cv2.INTER_NEAREST) # 光学畸变 ], p=0.8), # 非空间性转换 RandomBrightnessContrast(p=0.5), # 随机改变亮度对比度 ])(image=img, mask=seg) return img plt.figure(figsize=(5,5)) img1 = np.load(img[1145])[:,:,:] seg1 = np.load(mask[1145])[:,:] plt.subplot(2,2,1) plt.imshow(img1) plt.subplot(2,2,2) plt.imshow(seg1, cmap='gray') img1 = augmentation(img1, seg1) plt.subplot(2,2,3) plt.imshow(img1["image"]) plt.subplot(2,2,4) plt.imshow(img1["mask"], cmap='gray') plt.tight_layout() plt.show()