How to find same-value rectangular areas of a given size in a matrix most efficiently?

Posted by neo on Stack Overflow See other posts from Stack Overflow or by neo
Published on 2011-01-11T10:39:54Z Indexed on 2011/01/11 11:53 UTC
Read the original article Hit count: 150

Filed under:
|
|
|
|

My problem is very simple but I haven't found an efficient implementation yet.

Suppose there is a matrix A like this:

0 0 0 0 0 0 0
4 4 2 2 2 0 0
4 4 2 2 2 0 0
0 0 2 2 2 1 1
0 0 0 0 0 1 1

Now I want to find all starting positions of rectangular areas in this matrix which have a given size. An area is a subset of A where all numbers are the same.

Let's say width=2 and height=3. There are 3 areas which have this size:

2 2   2 2   0 0
2 2   2 2   0 0
2 2   2 2   0 0

The result of the function call would be a list of starting positions (x,y starting with 0) of those areas.

List((2,1),(3,1),(5,0))

The following is my current implementation. "Areas" are called "surfaces" here.

case class Dimension2D(width: Int, height: Int)
case class Position2D(x: Int, y: Int)

def findFlatSurfaces(matrix: Array[Array[Int]], surfaceSize: Dimension2D): List[Position2D] = {

    val matrixWidth = matrix.length
    val matrixHeight = matrix(0).length
    var resultPositions: List[Position2D] = Nil

    for (y <- 0 to matrixHeight - surfaceSize.height) {
        var x = 0
        while (x <= matrixWidth - surfaceSize.width) {
            val topLeft = matrix(x)(y)
            val topRight = matrix(x + surfaceSize.width - 1)(y)
            val bottomLeft = matrix(x)(y + surfaceSize.height - 1)
            val bottomRight = matrix(x + surfaceSize.width - 1)(y + surfaceSize.height - 1)
            // investigate further if corners are equal
            if (topLeft == bottomLeft && topLeft == topRight && topLeft == bottomRight) {
                breakable {
                    for (sx <- x until x + surfaceSize.width;
                         sy <- y until y + surfaceSize.height) {
                        if (matrix(sx)(sy) != topLeft) {
                            x = if (x == sx) sx + 1 else sx 
                            break
                        }
                    }
                    // found one!       
                    resultPositions ::= Position2D(x, y)
                    x += 1
                }
            } else if (topRight != bottomRight) {
                // can skip x a bit as there won't be a valid match in current row in this area
                x += surfaceSize.width 
            } else {
                x += 1
            }
        }   
    }
    return resultPositions
}

I already tried to include some optimizations in it but I am sure that there are far better solutions. Is there a matlab function existing for it which I could port? I'm also wondering whether this problem has its own name as I didn't exactly know what to google for.

Thanks for thinking about it! I'm excited to see your proposals or solutions :)

© Stack Overflow or respective owner

Related posts about algorithm

Related posts about scala