HSV Operator Example¶
This example demonstrates the use of HSV operator which manipulates the hue, saturation and value (brighness) aspects of the image.
HSV Color space¶
HSV represents colors by separating hue, saturation and brightness. In this color space, the hue is represented as an angle on the color circle. Saturation goes from 0 (greyscale) to 100% (fully saturated colors) and value goes from 0 (black) to 1 (full brightness). For details see: Wikipedia.
A note on implementation¶
For performance reasons, DALI doesn’t use the exact definition of HSV and approximates the operations in HSV space by linear (matrix) operations on RGB colors. This greatly improves performance at the cost of modest loss of fidelity.
Let’s start from importing handful of utils and DALI itself.
from nvidia.dali.pipeline import Pipeline import nvidia.dali.ops as ops import nvidia.dali.types as types import matplotlib.pyplot as plt batch_size = 10 image_filename = "../data/images"
Batch size is greater than one to facilitate switching between images at the end of the notebook.
Next, let’s implement the pipelines. We’ve presented 2 versions of a pipeline. The CPU one does all the processing (i.e. reading file, decoding it and HSV manipulation) on the CPU, while the other pipeline conducts decoding and HSV manipulation on the GPU.
class HsvCpuPipeline(Pipeline): def __init__(self, batch_size, num_threads, device_id): super(HsvCpuPipeline, self).__init__(batch_size, num_threads, device_id, seed=42) self.input = ops.FileReader(device="cpu", file_root=image_filename) self.decode = ops.ImageDecoder(device="cpu", output_type=types.RGB) self.hsv = ops.Hsv(device="cpu", hue=120, saturation=1, value=.4, dtype=types.UINT8) def define_graph(self): read, _ = self.input() image = self.decode(read) converted = self.hsv(image) return image, converted class HsvGpuPipeline(Pipeline): def __init__(self, batch_size, num_threads, device_id): super(HsvGpuPipeline, self).__init__(batch_size, num_threads, device_id, seed=42) self.input = ops.FileReader(device="cpu", file_root=image_filename) self.decode = ops.ImageDecoder(device="mixed", output_type=types.RGB) self.hsv = ops.Hsv(device="gpu", hue=+120, saturation=2, value=1, dtype=types.UINT8) def define_graph(self): read, _ = self.input() image = self.decode(read) converted = self.hsv(image.gpu()) return image, converted
The function below is used to actually display result of HSV manipulation in DALI. Since the pipelines we set up return 2 outputs: modified image and original image, the function aquires both of them from the output and displays them. Additional flag (
cpu) is specified, to determine, whether the pipeline output comes from CPU or GPU. In the latter case, we have to tell the output, to return a CPU-accessible copy of the data.
def display(output, cpu = True): i = 0 # Tweak that to have various images from batch img1 = output.at(i) if cpu else output.as_cpu().at(i) img2 = output.at(i) if cpu else output.as_cpu().at(i) fig, ax = plt.subplots(1,2) ax.imshow(img1); ax.imshow(img2);
Now let’s just build the pipelines, run them and display the results. First the GPU one:
pipegpu = HsvGpuPipeline(batch_size=batch_size, num_threads=1, device_id=0) pipegpu.build() gpu_output = pipegpu.run()
And the CPU:
pipecpu = HsvCpuPipeline(batch_size=batch_size, num_threads=1, device_id=0) pipecpu.build() cpu_output = pipecpu.run()