0

I am making a image filter, I already have this done, but I've read that for large collections it would be better to use a sequence for iteration, and since is a 8k image I suppose that I would gain some performance because of its lazy initialization with a Sequence<IntArray> instead of Array<IntArray>, or even Sequence<Sequence<Int>>. I don't know if this is possible yet, I'm quite confused and trying to learn this new paradigm for me, and I'm having difficult to find more easier material to understand the usage syntax of this concept.

This is what a tried, but is a mess, I don't have much idea of how to proceed this, or even if I should use the "newImage" as Sequence also.

val myPredicate = { array : IntArray -> !array.first() /*???*/ && !array.last() }
image.asSequence().forEach { array ->
    array.filter(myPredicate ) // ???
}

This is the functional code to be transformed:

fun chunker(image : Array<IntArray>) : Array<IntArray> {
    val arrayRowSize = image.size
    val arrayColSize = image[0].size
    val newImage : Array<IntArray> by lazy {
        Array(arrayRowSize) { IntArray(arrayColSize) }
    }

    var kernel = IntArray(9)
    // to translate to a Sequence those two for loops
    for (row in 1 .. arrayRowSize - 2) {
        for (col in 1 .. arrayColSize - 2) {
            kernel = changer(row, col, kernel, image)
            newImage[row][col] = kernel[4]
        }
    }
    return newImage
}
Robert
  • 7,394
  • 40
  • 45
  • 64
  • 1
    Is it possible that one source of confusion is the different meanings of the word ‘filter’?  In lists and data structures, it means to remove some elements and keep others, according to a selection function called a ‘predicate’.  But in image processing it means to transform an image to create a different image.  Your working code does the latter, but I think your partial attempt is trying to create one of the former… – gidds May 04 '19 at 21:31
  • Uhmm... but I also have forgotten to mention that I'm using the image in grey scale. And I'm not suposed to create new image from the old, but filtered. The filter will pass pixel by pixel, not considering the boards. – Bernardo Becker May 05 '19 at 09:17

1 Answers1

1

I've read that for large collections it would be better to use a sequence for iteration

What you have probably read is that, given a functional pipeline like myCollection.filter(...).map(...).first(...), performance can be improved by using a Sequence for mainly 2 reasons:

  1. the sequence won't process all elements if it doesn't have to (the first() and the end could make it terminate before seeing all elements)
  2. the sequence won't create intermediate collections for each pipeline step (like filter or map), unlike regular collections

In your case, you don't even have a pipeline of functional operations, and you don't create intermediate collections since you create and populate your result directly. Moreover, you can't terminate early because you want to process all pixels anyway, so Sequence might be appropriate but would not be necessarily a performance improvement here.

If you're compiling this Kotlin code targeting the JVM, then there is at least one thing you can do to improve performance:

Instead of using a 2D-array, use a 1D-array with a special indexing. More specifically, instead of newImage[row][col], you would write newImage[row * width + col]. This will avoid double memory references and benefit from cache locality, because you're iterating row by row.

Joffrey
  • 32,348
  • 6
  • 68
  • 100