1

I have a picture of 2600x2600 in gray. Or it can be seen as a matrix of unsigned short. I would like to find the darkest (or the brightest by computing the inverse picture) square are of a fixed size N. N could be parametrized (if there is more than one darkest square I would like all).

I read detection-of-rectangular-bright-area-in-a-image-using-opencv but it needs to a threshold value I don't have and furthermore I search a fixed size.

Do anyone as a way to find it in c++ or python ?

Community
  • 1
  • 1
user1811468
  • 111
  • 1
  • 2

2 Answers2

1
For each row of the image,
    Add up the N consecutive pixels, so you get W - N + 1 pixels.
For each column of the new image,
    For each consecutive sequence of N pixels, (H - N + 1)
        Add them up and compare to the current best.

To add up each consecutive sequence of pixels, you could subtract the last pixel, and add the next pixel.

You could also reuse the image array as storage, if it can be modified. If not, a memory-optimization would be to just store the latest column, and go trough it for each step in the first loop.

Runtime: O(w·h)

Here is some code in C#, to demonstrate this (ignoring the pixel format, and any potential overflows):

List<Point> FindBrightestSquare(int[,] image, int N, out int squareSum)
{
    int width = image.GetLength(0);
    int height = image.GetLength(1);
    if (width < N || height < N)
    {
        return false;
    }

    int currentSum;
    for (int y = 0; y < height; y++)
    {
        currentSum = 0;
        for (int x = 0; x < width; x++)
        {
            currentSum += image[x,y];
            if (x => N)
            {
                currentSum -= image[x-N,y];
                image[x-N,y] = currentSum;
            }
        }
    }

    int? bestSum = null;
    List<Point> bestCandidates = new List<Point>();
    for (int x = 0; x <= width-N; x++)
    {
        currentSum = 0;
        for (int y = 0; y < height; y++)
        {
            currentSum += image[x,y];
            if (y >= N)
            {
                currentSum -= image[x, y-N];
                if (bestSum == null || currentSum > bestSum)
                {
                    bestSum = currentSum;
                    bestCandidates.Clear();
                    bestCandidates.Add(new Point(x, y-N));
                }
                else if (currentSum == bestSum)
                {
                    bestCandidates.Add(new Point(x, y-N));
                }
            }
        }
    }

    squareSum = bestSum.Value;
    return bestCandidates;
}
Markus Jarderot
  • 86,735
  • 21
  • 136
  • 138
0

You could increment the threshold until you find a square, and use a 2D FSM to detect the square.

This will produce a match in O(width * height * bpp) (binary search on the lowest possible threshold, assuming a power-of-two range):

- set threshold to its maximum value 
- for every bit of the threshold
  - clear the bit in the threshold
  - if there is a match
    - record the set of matches as a result
  - else
    - set the bit
- if there is no record, then the threshold is its maximum.

to detect a square:
- for every pixel:
  - if the pixel is too bright, set its line-len to 0
  - else if it's the first column, set its line-len to 1
  - else set its line-len to the line-len of the pixel to the left, plus one

  - if the pixel line-len is less than N, set its rect-len to 0
  - else if it's the first row, set its rect-len to 1
  - else set its rect-len to the rect-len of the pixel above, plus one

  - if the rect-len is at least N, record a match.

line-len represents the number of consecutive pixels that are dark enough.

rect-len represents the number of consecutive rows of dark pixels that are long enough and aligned.

For video-capture, replace the binary search by a linear search from the threshold for the previous frame.

Obviously, you can't get better than theta(width/N * height/N) best case (as you'll have to rule out every possible position for a darker square) and the bit depth can be assumed constant, so this algorithm is asymptotically optimal for a fixed N. It's probably asymptotically optimal for N as a part of the input as well, as (intuitively) you have to consider almost every pixel in the average case.

John Dvorak
  • 26,799
  • 13
  • 69
  • 83