Basics

Create StreamableImage

From file

code
            StreamableImage streamableImage = new StreamableImage(new File("path/to/file"));

From BufferedImage

code
            BufferedImage bufferedImage = ImageIO.read(new File("path/to/file"));
            StreamableImage streamableImage = new StreamableImage(bufferedImage);

Create ImageStream

code
        streamableImage.stream();

Create ParallelImageStream

code
        streamableImage.parallelStream();

Collect ImageStream

code
        streamableImage.stream().collect(new Collector<BufferedImage>() {
            @Override
            public BufferedImage collect(BufferedImage bufferedImage) {
                return bufferedImage;
            }
        });

Predicates


Usage

We use Predicates to select which pixels of the image we want to work on further (f.e. apply a filter). They are applied with method ImageStream bounds(Predicate<Pixel> predicate)

Filters

Arithmetic filters

Invert filter

code
        BufferedImage bufferedImage = streamableImage.stream()
                .apply(Filters.invertFilter())
                .collect(Collectors.toBufferedImage());

before_InvertFilter after_InvertFilter

Binarization filters

Otsu filter

code
        BufferedImage bufferedImage = streamableImage.parallelStream()
                .apply(Filters.otsuBinarizationFilter())
                .collect(Collectors.toBufferedImage());

before_OtsuFilter after_OtsuFilter

Color filters

Grayscale filter

code
        BufferedImage bufferedImage = streamableImage.stream()
                .apply(Filters.grayScaleFilter())
                .collect(Collectors.toBufferedImage());

before_GrayScaleFilter after_GrayScaleFilter

Sepia filter

code
        BufferedImage bufferedImage = streamableImage.stream()
                .apply(Filters.sepiaFilter())
                .collect(Collectors.toBufferedImage());

before_SepiaFilter after_SepiaFilter

Convolve filters

Box blur filter

code
        BufferedImage bufferedImageBlur5 = streamableImage.stream()
                .apply(Filters.boxBlurFilter(5))
                .collect(Collectors.toBufferedImage());

before_BoxBlurFilter5 after_BoxBlurFilter5

Emboss filter

code
        BufferedImage bufferedImage = streamableImage.stream()
                .apply(Filters.embossFilter())
                .collect(Collectors.toBufferedImage());

before_EmbossFilter after_EmbossFilter

Sharpen filter

code
        BufferedImage bufferedImage = streamableImage.stream()
                .apply(Filters.sharpenFilter())
                .collect(Collectors.toBufferedImage());

before_SharpenFilter after_SharpenFilter

Edge detection filters

Roberts filter

code
        BufferedImage bufferedImageX = streamableImage.parallelStream()
                .apply(Filters.grayScaleFilter())
                .apply(Filters.robertsCrossXFilter())
                .collect(Collectors.toBufferedImage());

before_RobertsX after_RobertsX

code
        BufferedImage bufferedImageY = streamableImage.parallelStream()
                .apply(Filters.grayScaleFilter())
                .apply(Filters.robertsCrossYFilter())
                .collect(Collectors.toBufferedImage());

before_RobertsY after_RobertsY

code
        BufferedImage bufferedImage = streamableImage.parallelStream()
                .apply(Filters.edgeDetection(bufferedImageX, bufferedImageY))
                .collect(Collectors.toBufferedImage());

after_Roberts

Sobel filter

code
        BufferedImage bufferedImageX = streamableImage.parallelStream()
                .apply(Filters.grayScaleFilter())
                .apply(Filters.sobelXFilter())
                .collect(Collectors.toBufferedImage());

before_SobelX after_SobelX

code
        BufferedImage bufferedImageY = streamableImage.parallelStream()
                .apply(Filters.grayScaleFilter())
                .apply(Filters.sobelYFilter())
                .collect(Collectors.toBufferedImage());

before_SobelY after_SobelY

code
        BufferedImage bufferedImage = streamableImage.parallelStream()
                .apply(Filters.edgeDetection(bufferedImageX, bufferedImageY))
                .collect(Collectors.toBufferedImage());

after_Sobel

Equalization filters

Histogram equalization filter

code
        BufferedImage bufferedImage = streamableImage.parallelStream()
                .apply(Filters.histogramEqualizationFilter())
                .collect(Collectors.toBufferedImage());

before_HistogramEqualizationFilter after_HistogramEqualizationFilter

Morphology filters

Dilatation filter

code
        BufferedImage bufferedImage = streamableImage.stream()
                .apply(Filters.dilatationFilter())
                .collect(Collectors.toBufferedImage());

before_dilatationFilter after_dilatationFilter

Erosion filter

code
        BufferedImage bufferedImage = streamableImage.stream()
                .apply(Filters.erosionFilter())
                .collect(Collectors.toBufferedImage());

before_erosionFilter after_erosionFilter

Noise generators

Salt and pepper generator

code
        BufferedImage bufferedImage = streamableImage.stream()
                .apply(Filters.saltAndPepperFilter())
                .collect(Collectors.toBufferedImage());

before_saltAndPepperFilter after_saltAndPepperFilter

Statistical filters

Max filter

code
        BufferedImage bufferedImage = streamableImage.parallelStream()
                .setThreads(50)
                .apply(Filters.maxFilter(9))
                .collect(Collectors.toBufferedImage());

before_maxFilter after_maxFilter

Min filter

code
        BufferedImage bufferedImage = streamableImage.parallelStream()
                .setThreads(50)
                .apply(Filters.minFilter(9))
                .collect(Collectors.toBufferedImage());

before_minFilter after_minFilter

Mean filter

code
        BufferedImage bufferedImage = streamableImage.parallelStream()
                .setThreads(50)
                .apply(Filters.meanFilter(9))
                .collect(Collectors.toBufferedImage());

before_meanFilter after_meanFilter

Median filter

code
        BufferedImage bufferedImage = streamableImage.parallelStream()
                .setThreads(50)
                .apply(Filters.medianFilter(9))
                .collect(Collectors.toBufferedImage());

before_medianFilter after_medianFilter

Logging mechanism

Where is the logger

There is a protected field in Filter class called logger which lets us collect information about what is happening in Filter subclasses.

How to use it

Simply put the information you want to investigate like logger.info("Your message").
To make the logs visible, a configuration file log4j2.xml needs to be set up. Example configuration:

Print out logs to the standard output.
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{1} - %msg%n" />
        </Console>
    </Appenders>
    <Loggers>
        <Root level="debug">
            <AppenderRef ref="Console" />
        </Root>
    </Loggers>
</Configuration>

Using the presented configuration, the result of this line looks as follows (if it is put in SaltAndPepperFilter class):
20:00:22.423 [main] INFO SaltAndPepperFilter - Your message

Levels of logs

In the previous example, the log level used is called INFO. Currently the logger is set to display levels:
DEBUG, INFO, WARN, ERROR and FATAL.
You can still use logs of level TRACE yet those will not be shown in the output at the moment.

More about logging levels and architecure: log4j2 manual