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
Branches
No related tags found
1 merge request!24First version of save function + unit tests
from .downloader import Downloader from .downloader import Downloader
from .load import DataLoader, load, ImgExamples from .load import DataLoader, load, ImgExamples
from .save import save from .save import DataSaver, save
from .sync import Sync from .sync import Sync
from . import logger 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: class DataSaver:
def __init__(self): """Utility class for saving data to different file formats.
self.verbose = False
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): 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): DataSaver(replace=replace, compression=compression, **kwargs).save(path, data)
return DataSaver().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