ColonyCounter/fileutils.py

119 lines
5.0 KiB
Python

import re
from collections import OrderedDict
from os import path, makedirs, listdir
from typing import Callable, Dict, Optional, Tuple, List, Generator, Any, Union
import numpy as np
import pandas as pd
from cv2 import imread, imwrite
DIRIN = path.abspath("in")
DIROUT = path.abspath("out")
DIRCACHE = path.abspath("cache")
[makedirs(d, exist_ok=True) for d in [DIRIN, DIROUT, DIRCACHE]]
def dslice(odict: Dict[Any, Any], start: Optional[int] = None, end: Optional[int] = None) -> Dict[Any, Any]:
return OrderedDict([
(k, odict[k]) for k in list(odict.keys())[start:end]
])
def lval(odict: Dict[Any, Any]) -> Any:
return odict[list(odict.keys())[-1]]
def summarize(dlist):
summary = pd.concat(dlist)
summary.sort_values(["Hour", "Culture", "Label", "Grain"], ignore_index=True, inplace=True)
return summary
class FILE:
def __init__(self, fpath: str, esum: Optional[str] = None):
self.path, self.fname = path.split(path.relpath(fpath, start=DIRIN))
self.fname, self.fext = path.splitext(self.fname)
self.opqueue: Dict[str, Tuple[str, Callable, List[int]]] = OrderedDict()
self.meta: Optional[pd.DataFrame] = None
self.outlines: Optional[np.ndarray] = None
self.load({})
def __repr__(self) -> str:
return path.join(self.path, "".join([self.fname, self.fext]))
def __gt__(self, other) -> bool:
return [int(c) if c.isdigit() else c for c in re.split('([0-9]+)', repr(self))] > \
[int(c) if c.isdigit() else c for c in re.split('([0-9]+)', repr(other))]
def apply(self, opts: Dict[str, Tuple[str, Callable, List[int]]]):
if self.load(opts):
pass
else:
self.apply(dslice(opts, None, -1))
try:
self.data = lval(opts)[0](self.data, *lval(opts)[1], **lval(opts)[2])
if type(self.data) is tuple:
self.meta = pd.DataFrame(None if self.data[1]["data"][1:] == [] else self.data[1]["data"][1:], columns=self.data[1]["data"][0])
self.meta.insert(loc=0, column="Label", value="".join([self.fname, self.fext]))
spath = self.path.split(path.sep)
if len(spath) > 2 and spath[-2][:-1].isdigit():
hour, culture = self.path.split(path.sep)[-2:]
hour = int(hour[:-1])
else:
hour, culture = None, None
self.meta.insert(loc=0, column="Hour", value=hour)
self.meta.insert(loc=1, column="Culture", value=culture)
self.outlines = self.data[1]["outlines"]
self.data = self.data[0]
if lval(opts)[3]:
self.save(False, opts)
except SyntaxError as error:
print(f"Error: {error}")
def getOpStr(self, opts: Dict[str, Tuple[str, Callable, List[int]]]) -> str:
return ';'.join([f"{x}_{','.join([str(y) for y in opts[x][1]])}" for x in opts.keys()])
def getName(self, cache: bool, opts: Dict[str, Tuple[str, Callable, List[int]]]) -> str:
return f"{self.fname}{(cache and self.getOpStr(opts) + '.png') or self.fext}"
def save(self, toDirOut: bool, opts: Dict[str, Tuple[str, Callable, List[int]]]):
if toDirOut:
if not path.exists(path.join(DIROUT, self.path)):
makedirs(path.join(DIROUT, self.path))
imwrite(path.join(DIROUT, self.path, f"{self.fname}.jpg"), self.data)
if self.outlines is not None:
imwrite(path.join(DIROUT, self.path, f"{self.fname}.outlines.jpg"), self.outlines)
if self.meta is not None:
self.meta.to_csv(path.join(DIROUT, self.path, f"{self.fname}.csv"), index=False)
else:
if not path.exists(path.join(DIRCACHE, self.path)):
makedirs(path.join(DIRCACHE, self.path))
imwrite(path.join(DIRCACHE, self.path, self.getName(True, opts)), self.data)
def load(self, opts: Dict[str, Tuple[str, Callable, List[int]]]) -> bool:
if opts == {} and path.exists(path.join(DIRIN, self.path, self.getName(False, []))):
self.data = imread(path.join(DIRIN, self.path, self.getName(False, [])), -1)
return True
if path.exists(path.join(DIRCACHE, self.path, self.getName(True, opts))):
self.data = imread(path.join(DIRCACHE, self.path, self.getName(True, opts)), -1)
return True
return False
def search(pathlist: List[str]) -> Generator[str, None, None]:
"""
Generate file objects from given list of Paths.
+------------+
| Parameters |
+------------+
| pathlist: List[str]
| List of files and directories.
"""
for fpath in pathlist:
if path.isfile(fpath):
yield path.abspath(fpath)
continue
if path.isdir(fpath):
yield from search([path.join(fpath, x) for x in listdir(fpath)])
continue
print(f"[WARN]: No such file or directory: {fpath}")