This document explains how to implement custom traditional low-light enhancement algorithms based on LibLLIE's LLIEnhancer base class.
The traditional algorithm base class is:
from libllie.traditional.algorithms import LLIEnhancerAll algorithm classes that inherit LLIEnhancer are automatically registered when their modules are imported. After registration, they can be used through the unified prediction interface:
import libllie as llie
llie.predict("my_algorithm", "input.jpg")
llie.enhance("my_algorithm", "images/", output="results/my_algorithm")Note: after adding a new algorithm file, you need to import the algorithm class in libllie/traditional/algorithms/__init__.py, or manually import the module before use.
LLIEnhancer is responsible for:
- Reading inputs with
ImageReader. - Converting inputs to NumPy images.
- Validating image shape and dtype.
- Calling the subclass
_enhance(). - Postprocessing output according to
keep_dtypeandclip_output. - Returning NumPy, PIL, bytes, base64, or file according to
output_type.
Subclasses only need to implement:
def _enhance(self, image: np.ndarray, **kwargs) -> np.ndarray:
...Note: three-channel NumPy images are processed in OpenCV-style BGR order by default.
It is recommended to create libllie/traditional/algorithms/MyAlgorithm.py:
from typing import Any, Dict
import numpy as np
from libllie.traditional.algorithms import LLIEnhancer
class MyAlgorithm(LLIEnhancer):
"""Example traditional enhancement algorithm."""
name = "my_algorithm"
aliases = ["myalg", "my"]
def __init__(
self,
gain: float = 1.2,
**kwargs: Any,
) -> None:
"""Initialize the enhancer.
Args:
gain: Brightness gain.
**kwargs: Base enhancer parameters.
"""
super().__init__(**kwargs)
self.gain = gain
def _enhance(self, image: np.ndarray, **kwargs: Any) -> np.ndarray:
"""Enhance one image.
Args:
image: Input image array in BGR order for_teach color images.
**kwargs: Optional runtime parameters.
Returns:
Enhanced image array.
"""
gain = kwargs.get("gain", self.gain)
enhanced = image.astype(np.float32) * gain
return enhanced
def get_params(self) -> Dict[str, Any]:
"""Get enhancer parameters.
Returns:
Dictionary containing base parameters and algorithm parameters.
"""
params = super().get_params()
params.update({"gain": self.gain})
return paramsThen add the following to libllie/traditional/algorithms/__init__.py:
from .MyAlgorithm import MyAlgorithmAlgorithm parameters can be passed during construction:
from libllie.traditional.algorithms import LLIEnhancer
enhancer = LLIEnhancer.create_enhancer("my_algorithm", gain=1.5)They can also be passed through the unified prediction interface:
import libllie as llie
llie.predict(
"my_algorithm",
"input.jpg",
output="results/my_algorithm",
gain=1.5,
)If a parameter is dynamically overridden during prediction, read it from kwargs in _enhance():
gain = kwargs.get("gain", self.gain)LLIEnhancer supports the following output types:
output_type="numpy"
output_type="pil"
output_type="bytes"
output_type="base64"
output_type="file"The traditional algorithm predictor internally forces output_type="numpy" and then saves images uniformly. When using an enhancer directly, other formats can be specified:
enhancer = MyAlgorithm(output_type="pil")
result = enhancer("input.jpg")Single image:
import libllie as llie
enhanced, saved_path = llie.predict(
"my_algorithm",
"input.jpg",
output="results/my_algorithm/output.png",
)Folder:
saved_paths = llie.predict(
"my_algorithm",
"images/",
output="results/my_algorithm",
)from libllie.traditional.algorithms import LLIEnhancer
print(LLIEnhancer.list_registered_enhancers())Or:
import libllie as llie
print(llie.list_algorithms())_enhance()must returnnp.ndarray.- Do not read file paths inside
_enhance(); input reading is already handled byLLIEnhancer. - Do not save images inside
_enhance(); saving is handled by Predictor or ImageWriter. - Algorithms sensitive to color spaces should explicitly handle BGR/RGB conversion.
- Parameter validation is recommended in
__init__()or a separate_validate_*()method.