refactor for readability and implement new get_image function

This commit is contained in:
Brian Bjarke Jensen
2024-07-14 00:10:22 +02:00
parent 2cf55efcb3
commit 9cd4f70194
+67 -75
View File
@@ -1,20 +1,21 @@
from __future__ import annotations """Definition of Visual Critial Discourse Analysis dataloader."""
import random import random
from io import BytesIO
from PIL import Image
from torch import Tensor from torch import Tensor
from torch.utils.data import Dataset from torch.utils.data import Dataset
from torchvision.io import read_image from torchvision.transforms import ColorJitter, InterpolationMode, Normalize
from torchvision.transforms import ColorJitter from torchvision.transforms.functional import (
from torchvision.transforms import InterpolationMode hflip,
from torchvision.transforms import Normalize pad,
from torchvision.transforms.functional import hflip resize,
from torchvision.transforms.functional import pad rotate,
from torchvision.transforms.functional import resize to_pil_image,
from torchvision.transforms.functional import rotate to_tensor,
)
from shared.database import connect from shared.data_store import connect, get_image
# resnet18 original normalization values # resnet18 original normalization values
RESNET_NORMALIZE_MEAN = [0.485, 0.456, 0.406] RESNET_NORMALIZE_MEAN = [0.485, 0.456, 0.406]
@@ -22,125 +23,116 @@ RESNET_NORMALIZE_STD = [0.229, 0.224, 0.225]
class VCDADataset(Dataset): class VCDADataset(Dataset):
"""VCDA dataset class."""
def __init__( def __init__(
self, self,
data_name_list: list[str], data_name_list: list[str],
do_augment: bool = False, do_augment: bool = False,
random_annotations: bool = False, random_annotations: bool = False,
normalize_mean: list[float] = RESNET_NORMALIZE_MEAN,
normalize_std: list[float] = RESNET_NORMALIZE_STD,
): ):
super().__init__() super().__init__()
self.data_name_list = data_name_list self.data_name_list = data_name_list
self.do_augment = do_augment self.do_augment = do_augment
self.random_annotations = random_annotations self.random_annotations = random_annotations
self.normalize_mean = normalize_mean self.normalize_mean = RESNET_NORMALIZE_MEAN
self.normalize_std = normalize_std self.normalize_std = RESNET_NORMALIZE_STD
# prepare augmentation functions # prepare augmentation functions
self.normalize = Normalize( self.normalize = Normalize(
mean=normalize_mean, mean=self.normalize_mean,
std=normalize_std, std=self.normalize_std,
) )
self.color_jitter = ColorJitter( self.color_jitter = ColorJitter(
brightness=1e-1, brightness=1e-1,
contrast=8e-2, contrast=8e-2,
saturation=8e-2, saturation=8e-2,
) )
# connect to database # connect to minio
collection, _, _ = connect() minio_client = connect()
self.collection = collection self.minio_client = minio_client
def __len__(self): def __len__(self):
return len(self.data_name_list) return len(self.data_name_list)
def __getitem__(self, idx): def __getitem__(self, idx):
# get image from database # get image from database
name = self.data_name_list[idx] object_name = self.data_name_list[idx]
query = { image = get_image(
'name': name, client=self.minio_client,
} object_name=object_name,
projection = {
'_id': False,
'image': True,
}
img_bytes = self.collection.find_one(
filter=query,
projection=projection,
) )
img = self.load_image(img_bytes) tensor = self.image_to_tensor(image)
if self.do_augment: if self.do_augment:
img = self.augment(img) tensor = self.augment(tensor)
return img return tensor
def load_image( def image_to_tensor(
self, self,
data: bytes, image: Image.Image,
) -> Tensor: ) -> Tensor:
"""Load images tensor from bytes.""" """Load images tensor from bytes."""
assert isinstance(data, bytes) tensor = to_tensor(image)
img = read_image(BytesIO(data)) tensor /= 255 # normalize 8-bit image
img /= 255 # normalize 8-bit image tensor = self.square_pad(tensor=tensor)
img = self.square_pad(img) tensor = resize(
img = resize( img=tensor,
img=img,
size=(512, 512), size=(512, 512),
interpolation=InterpolationMode.BICUBIC, interpolation=InterpolationMode.BICUBIC,
) )
return img return tensor
@staticmethod @staticmethod
def square_pad( def square_pad(
img: Tensor, tensor: Tensor,
) -> Tensor: ) -> Tensor:
""" """Pads image to a square with side length equal to the largest side of
Pads image to a square with side length the input image."""
equal to the largest side of the input image. assert isinstance(tensor, Tensor)
"""
assert isinstance(img, Tensor)
# B, nc, w, h = img.shape # B, nc, w, h = img.shape
h = img.shape[-2] h = tensor.shape[-2]
w = img.shape[-1] w = tensor.shape[-1]
if h == w: if h == w:
return img return tensor
max_wh = max([h, w]) max_wh = max([h, w])
hp = int((max_wh - w) / 2) hp = int((max_wh - w) / 2)
vp = int((max_wh - h) / 2) vp = int((max_wh - h) / 2)
padding = (hp, vp, hp, vp) padding = (hp, vp, hp, vp)
return pad(img, padding, 0, 'constant') tensor = pad(tensor, padding, 0, 'constant')
return tensor
def augment( def augment(
self, self,
img: Tensor, tensor: Tensor,
) -> Tensor: ) -> Tensor:
""" """Augment image with random horizontal flips, rotations and color
Augment image with random horizontal flips, jitter."""
rotations and color jitter. assert isinstance(tensor, Tensor)
"""
assert isinstance(img, Tensor)
# left-right flip # left-right flip
if random.random() >= 0.5: if random.random() >= 0.5:
img = hflip(img) tensor = hflip(tensor)
# rotation # rotation
rnd = random.random() rnd = random.random()
if rnd < 0.25: if rnd < 0.25:
img = rotate(img, angle=90) tensor = rotate(tensor, angle=90)
if rnd < 0.5: if rnd < 0.5:
img = rotate(img, angle=180) tensor = rotate(tensor, angle=180)
if rnd < 0.75: if rnd < 0.75:
img = rotate(img, angle=270) tensor = rotate(tensor, angle=270)
# color jitter # color jitter
img = self.color_jitter(img) tensor = self.color_jitter(tensor)
return img return tensor
def reverse_normalise( def reverse_normalise(
self, self,
img: Tensor, tensor: Tensor,
) -> Tensor: ) -> Image.Image:
""" """Reverse normalization to get an image that can be interpreted by
Reverse normalization to get an image humans."""
that can be interpreted by humans. assert isinstance(tensor, Tensor)
""" tensor *= Tensor(self.normalize_std).reshape((3, 1, 1))
assert isinstance(img, Tensor) tensor += Tensor(self.normalize_mean).reshape((3, 1, 1))
img *= Tensor(self.normalize_std).reshape((3, 1, 1)) image = to_pil_image(
img += Tensor(self.normalize_mean).reshape((3, 1, 1)) pic=tensor,
return img mode='RGB',
)
return image