Need help altering an algorithm
Asked Answered
A

1

-2

I need to make a that scans every pixel on the screen.

I am currently using this:

public static void Spiral()
{

    // starting point
    x = ((int)Math.Floor(Screen.PrimaryScreen.Bounds.Height / 2.0)) - 1;
    y = ((int)Math.Floor(Screen.PrimaryScreen.Bounds.Width / 2.0)) - 1;

    for (int j = Screen.PrimaryScreen.Bounds.Height; j <= 2; k--)
    {
        for (int k = 0; k < (k < (Screen.PrimaryScreen.Bounds.Height - 1) ? 2 : 3); j++)
        {
            for (int i = 0; i < s; i++)
            {
                c++;
            }
            d = (d + 1) % 2;
        }
        s = s + 1;
    }
}

While this works, it only works with even dimensions (eg: 400x400) but for my use case i need to have it support uneven dimensions as well (eg: 1920x1080). I don't know how to alter this algorithm to make that happen.

I hope someone can help me with this since this kinda stuff is hard for me

EDIT: apparently i wasn't clear enough about what the issue is since it got closed? i'll eloborate (i hope it gets reopened soon):

lets say we got this image:

now currently only this part gets detected since the lowest dimension is the only one it can detect:

enter image description here

but i need the algorithm changed to support the whole image regardless if it's squared or not. Hope someone can help me solve this

Ashes answered 13/9, 2020 at 1:55 Comment(9)
What about it doesn't work with uneven dimensions?Trexler
For those who are curious, the image came from this question.Forsyth
This seemed like a perfectly good question that I was about to post an answer to. I don't understand why it was closed?Cardwell
I've got an answer waiting to post. I just need some more users to vote to reopen.Cardwell
Seems you only need to put some Math.min(your_x_coord, max_x_screencoord) (and the same for Y) into your code. Do that until both coords are out of the screenbounds and you are done. - then loop for both coords till the max value of both. Maybe that gets you onto a path to solve it yourself.Lunkhead
@CodeCaster - I'd love to give the answer that I've got ready to go, but I can't do it until the question is reopened.Cardwell
@Cardwell I can tell you why I would consider this question incomplete - what's the algorithm? This has a name, it's not a new algorithm. It's a space filling curve, but not the kind used for GIS, and I haven't worked with graphics math for decades. It's almost certain the question of irregular dimensions in graphics processing was answered 40 years ago already, with multiple optimizations for the actual processing.Snowshoe
@Cardwell it's also quite possible there's no need for a spiral - a spiral can speed up finding features expected to be near the center of the image, but what if we can just parallelize the operation, eg with PLINQ? Graphics algorithms can be accelerated with SIMD operations tooSnowshoe
Do you need to build a spiral, or find first pixel that is closest to the center?Horbal
C
0

Let's turn this into a simple sequence of points.

We know that we are going in one of four directions.

var steps = new (int dx, int dy)[] { (1, 0), (0, 1), (-1, 0), (0, -1) };

To create a spiral we move the first direction once, then the second once; then the next two twice, then the next two three times, then the next two four times, etc. If we hit the end of the list we then cycle back to the start. So if we start with n = 0 then we repeat each direction n / 2 + 1 times (knowing that this is integer maths).

Here's my Spiral generator method:

public IEnumerable<Point> Spiral(int x, int y)
{
    yield return new Point(x, y);
    var steps = new(int dx, int dy)[] { (1, 0), (0, 1), (-1, 0), (0, -1) };
    var i = 0;
    var n = 0;
    while (true)
    {
        for (var j = 0; j < n / 2 + 1; j++)
        {
            var (sx, sy) = steps[i];
            x += sx;
            y += sy;
            yield return new Point(x, y);
        }
        if (++i >= steps.Length)
            i = 0;
        n++;
    }
}

The first 50 points (i.e. Spiral(0, 0).Take(50)) are then this:

(0, 0), (1, 0), (1, 1), (0, 1), (-1, 1), (-1, 0), (-1, -1), (0, -1), (1, -1), (2, -1), (2, 0), (2, 1), (2, 2), (1, 2), (0, 2), (-1, 2), (-2, 2), (-2, 1), (-2, 0), (-2, -1), (-2, -2), (-1, -2), (0, -2), (1, -2), (2, -2), (3, -2), (3, -1), (3, 0), (3, 1), (3, 2), (3, 3), (2, 3), (1, 3), (0, 3), (-1, 3), (-2, 3), (-3, 3), (-3, 2), (-3, 1), (-3, 0), (-3, -1), (-3, -2), (-3, -3), (-2, -3), (-1, -3), (0, -3), (1, -3), (2, -3), (3, -3), (4, -3)

Now, it's super easy to generate the spiral you want.

If I assume that you're starting at the middle of the screen, then this is it:

IEnumerable<Point> query =
    Spiral(1920 / 2, 1080 / 2)
        .Where(z => z.X >= 0 && z.X < 1920)
        .Where(z => z.Y >= 0 && z.Y < 1080)
        .Take(1920 * 1080);

If we want to verify with the smaller screen as given in your question, the that looks like this:

IEnumerable<Point> query =
    Spiral(0, 0)
        .Where(z => z.Y >= -1 && z.Y <= 1)
        .Where(z => z.X >= -2 && z.X <= 2)
        .Take(5 * 3);

That gives:

(0, 0), (1, 0), (1, 1), (0, 1), (-1, 1), (-1, 0), (-1, -1), (0, -1), (1, -1), (2, -1), (2, 0), (2, 1), (-2, 1), (-2, 0), (-2, -1)


Here it is wrapped up in a single method:

public static void Spiral()
{
    IEnumerable<Point> SpiralPoints(int x, int y)
    {
        yield return new Point(x, y);
        var steps = new(int dx, int dy)[] { (1, 0), (0, 1), (-1, 0), (0, -1) };
        var i = 0;
        var n = 0;
        while (true)
        {
            for (var j = 0; j < n / 2 + 1; j++)
            {
                var (sx, sy) = steps[i];
                x += sx;
                y += sy;
                yield return new Point(x, y);
            }
            if (++i >= steps.Length)
                i = 0;
            n++;
        }
    }

    var w = Screen.PrimaryScreen.Bounds.Width;
    var h = Screen.PrimaryScreen.Bounds.Height;
    var l = Screen.PrimaryScreen.Bounds.Left;
    var r = Screen.PrimaryScreen.Bounds.Right;
    var t = Screen.PrimaryScreen.Bounds.Top;
    var b = Screen.PrimaryScreen.Bounds.Bottom;

    foreach (Point point in SpiralPoints(w / 2, h / 2)
        .Where(z => z.X >= l && z.X < r)
        .Where(z => z.Y >= t && z.Y < b)
        .Take(w * h))
    {
        /* Do Stuff With Each Point Here */
    }

}
Cardwell answered 13/9, 2020 at 12:14 Comment(14)
You can just use the LINQ stuff inside a method and that would do what you want. You can replace the tuple with Point very easily - just refactor like normal.Cardwell
Sorry, what did you mean by "point" - did you mean the struct Point?Cardwell
@Ashes - it would have been a good idea to include that in the question. :-)Cardwell
@Ashes - I just updated the answer to use Point. I hope you can see how I refactored it?Cardwell
@Ashes - Can you explain why you can't use LINQ because of "unsafe code"?Cardwell
@Ashes - No, there's no constraint on that I know of. I just did a test and and unsafe block was fine in the foreach.Cardwell
@Ashes - Just a side note: You don't need to do x = ((int)Math.Floor(Screen.PrimaryScreen.Bounds.Width / 2.0)) - 1; as x = Screen.PrimaryScreen.Bounds.Width / 2 - 1; works just the same and is going to prevent any possible rounding error.Cardwell
@Ashes - The algorithm should be quite fast. Can you explain more about detecting things on the outer edge of the screen?Cardwell
@Ashes - I made a change to my ode which halved the execution time for me. It went down from about 184 ms to 79 ms. What are you doing inside the loop?Cardwell
@Cardwell that's why this question is incomplete. It's certain the actual graphics math problem has multiple solutions and optimizations since the 80s (if not earlier). Simply looking for a color doesn't require a spiral either, a simple search of all pixels would be enough, and easy to parallelize. Perhaps the OP is using convolution to find the approximate color? Again, no need for spirals, and as Photoshop has done since the 90s, edges can be handled easily, eg by using different weight on the edges, or assuming a neutral value outside the edges. Haven't worked on that for decadesSnowshoe
@Ashes what are you actually trying to do? This looks like image processing - what specific task, algorithm, are you trying to implement? Why use a spiral in the first place if you intend to scan the entire image? Matrix operations are easy to parallelize and accelerate even if you don't use an explicitly parallel algorithm. You could use PLINQ to parallelize processing or SIMD operations through the Vector and Matrix classes to accelerate matrix operations like convolution.Snowshoe
@PanagiotisKanavos - I agree. On the face of it this was a straight forward question. The problem is when the OP starts introducing new constraints that should have been in the original question.Cardwell
@Ashes - Your question wasn't very clear to start with because you didn't put in enough detail. I managed to get it reopened because I thought I had a good answer to your question. Since answering you've raised a bunch of issues that were not in your question. I suggest that you evaluate my answer based on the question as presented and then post a new question with all of the detail you've now raised. How does that sound?Cardwell
@Cardwell I appreciate the time and help you you put into this and your answer was very helpful. i'll definitely mark it as the best answer since it did answer the main problem i had.Ashes

© 2022 - 2024 — McMap. All rights reserved.