Image_preprocessing
긴 aixs를 기준으로 나머지는 0(Black)으로 채우되 중심은 유지
os.chdir('/home/mskang/hyeokjong/cancer/2018/task1/ISIC2018_Task1-2_Training_Input')
train_inputs_list = os.listdir('/home/mskang/hyeokjong/cancer/2018/task1/ISIC2018_Task1-2_Training_Input')
train_inputs_list.remove('ATTRIBUTION.txt')
train_inputs_list.remove('LICENSE.txt')
# len(train_inputs_list)
for i in tqdm(range(len(train_inputs_list))):
os.chdir('/home/mskang/hyeokjong/cancer/2018/task1/ISIC2018_Task1-2_Training_Input')
img = Image.open(train_inputs_list[i])
imgArray = np.array(img)
a,b,_ = imgArray.shape
if a >= b:
z = np.zeros(( a, (a-b)//2 , 3))
con = np.concatenate( [z,imgArray,z], axis=1)
else:
z = np.zeros(((b-a)//2 , b , 3))
con = np.concatenate( [z,imgArray,z], axis=0)
con = con.astype('uint8')
padded_image = Image.fromarray(con)
os.chdir('/home/mskang/hyeokjong/cancer/2018/task1/train_input_pad')
padded_image.save('padded_' + train_inputs_list[i] + '.jpg')
Segmentation에서 다음과 같이 resize를 하면 ground truth(target)에서 각 pixel이 int가 아닌 float으로 변화한다.
이유는 그냥 대충 Resize하면 되겠지 하고 했던게 잘못이다.
class custom_dataset(Dataset):
def __init__(self, inputs_dir , targets_dir, transform = None):
self.inputs_dir = inputs_dir
self.inputs_list = os.listdir(inputs_dir)
self.targets_dir = targets_dir
self.targets_list = os.listdir(targets_dir)
self.transform = transform
def __len__(self):
return len(self.inputs_list)
def __getitem__(self,idx):
os.chdir(self.inputs_dir)
input_image = Image.open(self.inputs_list[idx])
os.chdir(self.targets_dir)
target_image = Image.open(self.targets_list[idx])
if self.transform:
input_image_tensor = self.transform(input_image)
target_image_tensor = self.transform(target_image)
return ( input_image_tensor ,target_image_tensor)
path_train_inputs = '/home/mskang/hyeokjong/cancer/2018/task1/train_input_pad'
path_train_targets = '/home/mskang/hyeokjong/cancer/2018/task1/train_targets_pad'
train_dataset = custom_dataset(path_train_inputs, path_train_targets )
train_transformation = transforms.Compose([transforms.Resize(4),
transforms.RandomHorizontalFlip(),
transforms.ToTensor()])
train_dataset.transform = train_transformation
batch_size = 2
train_dl = DataLoader(train_dataset, batch_size, shuffle=True,
num_workers=4, pin_memory=True)
for i,j in train_dl:
inputs,targets = i,j
break
inputs.shape
---------------------------
torch.Size([2, 3, 4, 4])
targets.shape
---------------------------
torch.Size([2, 1, 4, 4])
targets
---------------------------
tensor([[[[0.0000, 0.0157, 0.0196, 0.0000],
[0.0314, 0.4510, 0.4784, 0.0157],
[0.0471, 0.4314, 0.4000, 0.0196],
[0.0000, 0.0000, 0.0000, 0.0000]]],
[[[0.0000, 0.0000, 0.0000, 0.0000],
[0.0000, 0.0314, 0.0588, 0.0000],
[0.0000, 0.0471, 0.0824, 0.0000],
[0.0000, 0.0000, 0.0000, 0.0000]]]])
Resize의 방법에도 엄청 많은 종류가 있고 위와같이 Resize를 수행하면 매끄럽게 계산되어 float이 생겨버린다.
위 code를 보면
Custom_dataset
에서 transform을 대응 가능하게 해 놨는데 직접 해보니 dataset에서 transform을 하나 .transform
으로 변환을 찍어주나 속도차이가 없다.(생각해보면 둘이 완전 같은거 같다)
실험진행
즉, target은 transforms.Resize()
를 사용하면 안된다는 것이다.
그럼 어느정도의 해결책이 보이는데 위의 code처럼 .transform
으로 해버리면 input과 target이 같은 transform을 적용하니 애초에 dataset class
에서 각기 다른 transform을 적용하면 될거 같다는 생각이 들었다.
torch.nn.functional.interpolate(input, size=None, scale_factor=None, mode='nearest', align_corners=None, recompute_scale_factor=None)
에서 mode
조정
- 다르게 적용해도 되나?
- 생각해 보니 FCN model을 사용하는데 왜 resize를 하려고 하지?
- 물론 FCN classification model이면 resize를 해야한다. 대신 target은 resize를 안한다 label이니까.
- 그럼 segmentation에서 resize를 하는경우가 있나?
- variable size image가 FCN model에 가능한건 맞지먄 pytorch로 구현하는데 문제가 있는데 이유가 torch의 dataloader는 same size만 받을 수 있다.
따라서 크게 두가지의 해결법이 있을거 같은데
첫번째는 본 포스트에서 말하는 resize이고,
두번째는 trainer를 직접 coding하던가 (어차피 iterator이니까) 아니면 dataloader도 만드는 것이다. ( custom collate_fn )
https://discuss.pytorch.org/t/how-to-create-a-dataloader-with-variable-size-input/8278/2
근데 어째 custom collate_fn의 역할이 그냥 0을 넣어서 size 맞춰주는거 같다.
물론 첫번째가 계산이 빠르다.
추가적으로 custom collate_fn를 생각해 봐야하는게 극단적으로 다른 size의 image이면 같은 model을 사용하는것이 안좋고 따라서 reize해주는것이 맞다고 본다.
다만 비율 유지의 문제가 있다.
대부분의 code들이 class 부분에서 transform을 진행 하던데 이 이유인거 같다.
해결법은 다음과 같다.
1. pytorch 내장 torch.nn.functional.interpolate
, torch.nn.Upsample
두개가 있다.
2. https://pytorch.org/vision/stable/transforms.html 를 보면
torchvision.transforms.Resize(size, interpolation=<InterpolationMode.BILINEAR: 'bilinear'>, max_size=None, antialias=None)
에서 mode를 지정할 수 있다.
3. custom transformation class를 만들면 된다.
즉, transforms.Compose( [ ] ) 안에 원소로 들어가야 하는것들이 class임을 알 수 있다.
2번이 제일 편하다.
Loss와 마찬가지로 function과 class두개가 있는데 class가 상속받아 custom하기 편하다.
torch가 이런부분은 잘만든거 같다.
https://stackoverflow.com/questions/23853632/which-kind-of-interpolation-best-for-resizing-image
어떠한 interpolation이 좋은가?
ㅅㄱㅁㄴ래그 dksdp sjgdmaus ekfmrp ehlsmsep?\
Author And Source
이 문제에 관하여(Image_preprocessing), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@jj770206/Image-pretreatment저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)