diff --git a/CITATION.cff b/CITATION.cff index 65e69ee039..a043a3437f 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -29,7 +29,7 @@ authors: family-names: Genc email: utku.genc@intel.com affiliation: Intel -version: 0.2.4 +version: 0.2.5 doi: https://doi.org/10.48550/arXiv.2202.08341 date-released: 2022-02-18 references: diff --git a/anomalib/__init__.py b/anomalib/__init__.py index 063c872150..5fe1bae826 100644 --- a/anomalib/__init__.py +++ b/anomalib/__init__.py @@ -14,4 +14,4 @@ # See the License for the specific language governing permissions # and limitations under the License. -__version__ = "0.2.4" +__version__ = "0.2.5" diff --git a/anomalib/data/btech.py b/anomalib/data/btech.py index 2bdc942f80..78cb9879cc 100644 --- a/anomalib/data/btech.py +++ b/anomalib/data/btech.py @@ -38,6 +38,7 @@ from torch.utils.data import DataLoader from torch.utils.data.dataset import Dataset from torchvision.datasets.folder import VisionDataset +from tqdm import tqdm from anomalib.data.inference import InferenceDataset from anomalib.data.utils import DownloadProgressBar, read_image @@ -94,7 +95,9 @@ def make_btech_dataset( Returns: DataFrame: an output dataframe containing samples for the requested split (ie., train or test) """ - samples_list = [(str(path),) + filename.parts[-3:] for filename in path.glob("**/*.bmp")] + samples_list = [ + (str(path),) + filename.parts[-3:] for filename in path.glob("**/*") if filename.suffix in (".bmp", ".png") + ] if len(samples_list) == 0: raise RuntimeError(f"Found 0 images in {path}") @@ -107,7 +110,7 @@ def make_btech_dataset( + "/ground_truth/" + samples.label + "/" - + samples.image_path.str.rstrip("bmp").str.rstrip(".") + + samples.image_path.str.rstrip("png").str.rstrip(".") + ".png" ) @@ -337,10 +340,9 @@ def prepare_data(self) -> None: if (self.root / self.category).is_dir(): logging.info("Found the dataset.") else: - self.root.mkdir(parents=True, exist_ok=True) - zip_filename = self.root / "btad.zip" + zip_filename = self.root.parent / "btad.zip" - logging.info("Downloading the dataset.") + logging.info("Downloading the BTech dataset.") with DownloadProgressBar(unit="B", unit_scale=True, miniters=1, desc="BTech") as progress_bar: urlretrieve( url="https://avires.dimi.uniud.it/papers/btad/btad.zip", @@ -350,10 +352,25 @@ def prepare_data(self) -> None: logging.info("Extracting the dataset.") with zipfile.ZipFile(zip_filename, "r") as zip_file: - zip_file.extractall(self.root) + zip_file.extractall(self.root.parent) logging.info("Renaming the dataset directory") - shutil.move(src=str(self.root / "BTech_Dataset_transformed"), dst=str(self.root / "BTech")) + shutil.move(src=str(self.root.parent / "BTech_Dataset_transformed"), dst=str(self.root)) + + # NOTE: Each BTech category has different image extension as follows + # | Category | Image | Mask | + # |----------|-------|------| + # | 01 | bmp | png | + # | 02 | png | png | + # | 03 | bmp | bmp | + # To avoid any conflict, the following script converts all the extensions to png. + # This solution works fine, but it's also possible to properly ready the bmp and + # png filenames from categories in `make_btech_dataset` function. + logging.info("Convert the bmp formats to png to have consistent image extensions") + for filename in tqdm(self.root.glob("**/*.bmp"), desc="Converting bmp to png"): + image = cv2.imread(str(filename)) + cv2.imwrite(str(filename.with_suffix(".png")), image) + filename.unlink() logging.info("Cleaning the tar file") zip_filename.unlink() diff --git a/anomalib/models/dfkde/model.py b/anomalib/models/dfkde/model.py index 10cce16df4..a0cd0c6ad8 100644 --- a/anomalib/models/dfkde/model.py +++ b/anomalib/models/dfkde/model.py @@ -104,7 +104,7 @@ def __init__(self, hparams: Union[DictConfig, ListConfig]): self.embeddings: List[Tensor] = [] @staticmethod - def configure_optimizers(): + def configure_optimizers(): # pylint: disable=arguments-differ """DFKDE doesn't require optimization, therefore returns no optimizers.""" return None diff --git a/anomalib/models/dfm/model.py b/anomalib/models/dfm/model.py index c3d12242a5..944c885677 100644 --- a/anomalib/models/dfm/model.py +++ b/anomalib/models/dfm/model.py @@ -38,7 +38,7 @@ def __init__(self, hparams: Union[DictConfig, ListConfig]): self.embeddings: List[Tensor] = [] @staticmethod - def configure_optimizers() -> None: + def configure_optimizers() -> None: # pylint: disable=arguments-differ """DFM doesn't require optimization, therefore returns no optimizers.""" return None diff --git a/anomalib/models/padim/model.py b/anomalib/models/padim/model.py index 8999545278..ca44b09478 100644 --- a/anomalib/models/padim/model.py +++ b/anomalib/models/padim/model.py @@ -298,7 +298,7 @@ def __init__(self, hparams: Union[DictConfig, ListConfig]): self.embeddings: List[Tensor] = [] @staticmethod - def configure_optimizers(): + def configure_optimizers(): # pylint: disable=arguments-differ """PADIM doesn't require optimization, therefore returns no optimizers.""" return None diff --git a/anomalib/utils/callbacks/__init__.py b/anomalib/utils/callbacks/__init__.py index f31b08148c..ad4e120585 100644 --- a/anomalib/utils/callbacks/__init__.py +++ b/anomalib/utils/callbacks/__init__.py @@ -25,13 +25,11 @@ from .cdf_normalization import CdfNormalizationCallback from .min_max_normalization import MinMaxNormalizationCallback from .model_loader import LoadModelCallback -from .openvino import OpenVINOCallback from .save_to_csv import SaveToCSVCallback from .timer import TimerCallback from .visualizer_callback import VisualizerCallback __all__ = [ - "OpenVINOCallback", "LoadModelCallback", "TimerCallback", "VisualizerCallback", @@ -97,6 +95,10 @@ def get_callbacks(config: Union[ListConfig, DictConfig]) -> List[Callback]: ) ) if "openvino" in config.optimization and config.optimization.openvino.apply: + from .openvino import ( # pylint: disable=import-outside-toplevel + OpenVINOCallback, + ) + callbacks.append( OpenVINOCallback( input_size=config.model.input_size, diff --git a/requirements/base.txt b/requirements/base.txt index e13202d2a4..1680f7e249 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -7,9 +7,11 @@ kornia==0.5.6 lxml==4.6.5 matplotlib==3.4.3 networkx~=2.5 -nncf@ git+https://github.com/openvinotoolkit/nncf@37a830a412e60ec2fd2d84d7f00e2524e5f62777#egg=nncf numpy~=1.19.5 omegaconf==2.1.1 +opencv-python>=4.5.3.56 +opencv-contrib-python==4.5.5.62 +pandas~=1.1.5 pillow==9.0.0 pytorch-lightning==1.5.9 torch==1.8.1 diff --git a/requirements/openvino.txt b/requirements/openvino.txt index 04aa49dd97..4c48b3428b 100644 --- a/requirements/openvino.txt +++ b/requirements/openvino.txt @@ -1,6 +1,6 @@ defusedxml==0.7.1 requests==2.26.0 networkx~=2.5 +nncf@ git+https://github.com/openvinotoolkit/nncf@37a830a412e60ec2fd2d84d7f00e2524e5f62777#egg=nncf onnx==1.10.1 -opencv-python==4.5.3.56 openvino-dev==2021.4.2 diff --git a/setup.py b/setup.py index 29848d5647..eab937425e 100644 --- a/setup.py +++ b/setup.py @@ -86,7 +86,7 @@ def get_required_packages(requirement_files: List[str]) -> List[str]: setup( name="anomalib", # TODO: https://github.com/openvinotoolkit/anomalib/issues/36 - version="0.2.4", + version="0.2.5", author="Intel OpenVINO", author_email="help@openvino.intel.com", description="anomalib - Anomaly Detection Library", @@ -94,7 +94,7 @@ def get_required_packages(requirement_files: List[str]) -> List[str]: license="Copyright (c) Intel - All Rights Reserved. " 'Licensed under the Apache License, Version 2.0 (the "License")' "See LICENSE file for more details.", - python_requires=">=3.8", + python_requires=">=3.7", packages=find_packages("."), install_requires=INSTALL_REQUIRES, extras_require=EXTRAS_REQUIRE, diff --git a/tests/pre_merge/utils/callbacks/openvino_callback/test_openvino.py b/tests/pre_merge/utils/callbacks/openvino_callback/test_openvino.py index aca4bff357..9b2f377e91 100644 --- a/tests/pre_merge/utils/callbacks/openvino_callback/test_openvino.py +++ b/tests/pre_merge/utils/callbacks/openvino_callback/test_openvino.py @@ -5,7 +5,7 @@ from pytorch_lightning.callbacks.early_stopping import EarlyStopping from anomalib.config import get_configurable_parameters -from anomalib.utils.callbacks import OpenVINOCallback +from anomalib.utils.callbacks.openvino import OpenVINOCallback from tests.pre_merge.utils.callbacks.openvino_callback.dummy_lightning_model import ( DummyLightningModule, FakeDataModule, diff --git a/tox.ini b/tox.ini index 74aee167b3..86a27eb500 100644 --- a/tox.ini +++ b/tox.ini @@ -106,6 +106,7 @@ ignore = E203,W503 extension-pkg-whitelist = cv2 ignored-modules = cv2 disable = duplicate-code, + arguments-differ, fixme, import-error, no-self-use,