Skip to content
Snippets Groups Projects
Commit 493453ea authored by fima's avatar fima :beers:
Browse files

Merge branch 'save_tiff' into 'main'

First version of save function + unit tests

See merge request !24
parents a522289b fa52d4cd
No related branches found
No related tags found
1 merge request!24First version of save function + unit tests
from .downloader import Downloader
from .load import DataLoader, load, ImgExamples
from .save import save
from .save import DataSaver, save
from .sync import Sync
from . import logger
\ No newline at end of file
"""Provides functionality for saving data to various file formats."""
import os
import tifffile
import numpy as np
from qim3d.io.logger import log
class DataSaver:
def __init__(self):
self.verbose = False
"""Utility class for saving data to different file formats.
Attributes:
replace (bool): Specifies if an existing file with identical path is replaced.
compression (bool): Specifies if the file is with Deflate compression.
Methods:
save_tiff(path,data): Save data to a TIFF file to the given path.
load(path,data): Save data to the given path.
Example:
image = qim3d.examples.blobs_256x256
saver = qim3d.io.DataSaver(compression=True)
saver.save_tiff("image.tif",image)
"""
def __init__(self, **kwargs):
"""Initializes a new instance of the DataSaver class.
Args:
replace (bool, optional): Specifies if an existing file with identical path should be replaced.
Default is False.
compression (bool, optional): Specifies if the file should be saved with Deflate compression.
Default is False.
"""
self.replace = kwargs.get("replace",False)
self.compression = kwargs.get("compression",False)
def save_tiff(self,path,data):
"""Save data to a TIFF file to the given path.
Args:
path (str): The path to save file to
data (numpy.ndarray): The data to be saved
"""
tifffile.imwrite(path,data,compression=self.compression)
def save(self, path, data):
raise NotImplementedError("Save is not implemented yet")
"""Save data to the given path.
Args:
path (str): The path to save file to
data (numpy.ndarray): The data to be saved
Raises:
ValueError: If the file format is not supported.
ValueError: If the specified folder does not exist.
ValueError: If a file extension is not provided.
ValueError: if a file with the specified path already exists and replace=False.
Example:
image = qim3d.examples.blobs_256x256
saver = qim3d.io.DataSaver(compression=True)
saver.save("image.tif",image)
"""
folder = os.path.dirname(path) or '.'
# Check if directory exists
if os.path.isdir(folder):
_, ext = os.path.splitext(path)
# Check if provided path contains file extension
if ext:
# Check if a file with the given path already exists
if os.path.isfile(path) and not self.replace:
raise ValueError("A file with the provided path already exists. To replace it set 'replace=True'")
if path.endswith((".tif",".tiff")):
return self.save_tiff(path,data)
else:
raise ValueError("Unsupported file format")
else:
raise ValueError('Please provide a file extension')
else:
raise ValueError(f'The directory {folder} does not exist. Please provide a valid directory')
def save(path,
data,
replace=False,
compression=False,
**kwargs
):
"""Save data to a specified file path.
Args:
path (str): The path to save file to
data (numpy.ndarray): The data to be saved
replace (bool, optional): Specifies if an existing file with identical path should be replaced.
Default is False.
compression (bool, optional): Specifies if the file should be saved with Deflate compression (lossless).
Default is False.
**kwargs: Additional keyword arguments to be passed to the DataSaver constructor
Example:
image = qim3d.examples.blobs_256x256
qim3d.io.save("image.tif",image,compression=True)
"""
def save(path, data):
return DataSaver().save(path, data)
DataSaver(replace=replace, compression=compression, **kwargs).save(path, data)
\ No newline at end of file
import qim3d
import tempfile
import numpy as np
import os
import hashlib
import pytest
def test_image_exist():
# Create random test image
test_image = np.random.randint(0,256,(100,100,100),'uint8')
# Create temporary directory
with tempfile.TemporaryDirectory() as temp_dir:
image_path = os.path.join(temp_dir,"test_image.tif")
# Save to temporary directory
qim3d.io.save(image_path,test_image)
# Assert that test image has been saved
assert os.path.exists(image_path)
def test_compression():
# Get test image (should not be random in order for compression to function)
test_image = qim3d.examples.blobs_256x256
# Create temporary directory
with tempfile.TemporaryDirectory() as temp_dir:
image_path = os.path.join(temp_dir,"test_image.tif")
compressed_image_path = os.path.join(temp_dir,"compressed_test_image.tif")
# Save to temporary directory with and without compression
qim3d.io.save(image_path,test_image)
qim3d.io.save(compressed_image_path,test_image,compression=True)
# Compute file sizes
file_size = os.path.getsize(image_path)
compressed_file_size = os.path.getsize(compressed_image_path)
# Assert that compressed file size is smaller than non-compressed file size
assert compressed_file_size < file_size
def test_image_matching():
# Create random test image
original_image = np.random.randint(0,256,(100,100,100),'uint8')
# Create temporary directory
with tempfile.TemporaryDirectory() as temp_dir:
image_path = os.path.join(temp_dir,"original_image.tif")
# Save to temporary directory
qim3d.io.save(image_path,original_image)
# Load from temporary directory
saved_image = qim3d.io.load(image_path)
# Get hashes
original_hash = calculate_image_hash(original_image)
saved_hash = calculate_image_hash(saved_image)
# Assert that original image is identical to saved_image
assert original_hash == saved_hash
def test_compressed_image_matching():
# Get test image (should not be random in order for compression to function)
original_image = qim3d.examples.blobs_256x256
# Create temporary directory
with tempfile.TemporaryDirectory() as temp_dir:
image_path = os.path.join(temp_dir,"original_image.tif")
# Save to temporary directory
qim3d.io.save(image_path,original_image,compression=True)
# Load from temporary directory
saved_image_compressed = qim3d.io.load(image_path)
# Get hashes
original_hash = calculate_image_hash(original_image)
compressed_hash = calculate_image_hash(saved_image_compressed)
# Assert that original image is identical to saved_image
assert original_hash == compressed_hash
def test_file_replace():
# Create random test image
test_image1 = np.random.randint(0,256,(100,100,100),'uint8')
test_image2 = np.random.randint(0,256,(100,100,100),'uint8')
# Create temporary directory
with tempfile.TemporaryDirectory() as temp_dir:
image_path = os.path.join(temp_dir,"test_image.tif")
# Save first test image to temporary directory
qim3d.io.save(image_path,test_image1)
# Get hash
hash1 = calculate_image_hash(qim3d.io.load(image_path))
# Replace existing file
qim3d.io.save(image_path,test_image2,replace=True)
# Get hash again
hash2 = calculate_image_hash(qim3d.io.load(image_path))
# Assert that the file was modified by checking if the second modification time is newer than the first
assert hash1 != hash2
def test_file_already_exists():
# Create random test image
test_image1 = np.random.randint(0,256,(100,100,100),'uint8')
test_image2 = np.random.randint(0,256,(100,100,100),'uint8')
# Create temporary directory
with tempfile.TemporaryDirectory() as temp_dir:
image_path = os.path.join(temp_dir,"test_image.tif")
# Save first test image to temporary directory
qim3d.io.save(image_path,test_image1)
with pytest.raises(ValueError,match="A file with the provided path already exists. To replace it set 'replace=True'"):
# Try to save another image to the existing path
qim3d.io.save(image_path,test_image2)
def test_no_file_ext():
# Create random test image
test_image = np.random.randint(0,256,(100,100,100),'uint8')
# Create filename without extension
filename = 'test_image'
# Create temporary directory
with tempfile.TemporaryDirectory() as temp_dir:
image_path = os.path.join(temp_dir,filename)
with pytest.raises(ValueError,match='Please provide a file extension'):
# Try to save the test image to a path witout file extension
qim3d.io.save(image_path,test_image)
def test_folder_doesnt_exist():
# Create random test image
test_image = np.random.randint(0,256,(100,100,100),'uint8')
# Create invalid path
invalid_path = os.path.join('this','path','doesnt','exist.tif')
with pytest.raises(ValueError,match=f'The directory {os.path.dirname(invalid_path)} does not exist. Please provide a valid directory'):
# Try to save test image to an invalid path
qim3d.io.save(invalid_path,test_image)
def test_unsupported_file_format():
# Create random test image
test_image = np.random.randint(0,256,(100,100,100),'uint8')
# Create filename with unsupported format
filename = 'test_image.unsupported'
# Create temporary directory
with tempfile.TemporaryDirectory() as temp_dir:
image_path = os.path.join(temp_dir,filename)
with pytest.raises(ValueError,match='Unsupported file format'):
# Try to save test image with an unsupported file extension
qim3d.io.save(image_path,test_image)
def calculate_image_hash(image):
image_bytes = image.tobytes()
hash_object = hashlib.md5(image_bytes)
return hash_object.hexdigest()
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment