Determining correct box to place image according to ratio

Hey all I am in need of some help with determines what box I need to place a given image into depending on that images ratio (image width / image height) to the box areas Aspect Ratio (box width / box height).

The code below is what I currently have that I am using to determine this (which does not work):

public static Dictionary<string, List<double>> sizeOfPhotoBoxes = new Dictionary<string, List<double>>()
{/*
                                               [Width]
                                              |     [Height]
                                              |     |      [Aspact Ratio]
                                             ↓    ↓    ↓
        KEY:         VALUE(s):   [1]  [2]  [3]*/
     { "box1", new List<double> {357, 272, 1.31} },
     { "box2", new List<double> {357, 272, 1.31 } },
     { "box3", new List<double> {365, 460, 0.79 } },
     { "box4", new List<double> {365, 265, 1.38 } },
     { "box5", new List<double> {715, 455, 1.57 } },
     { "box6", new List<double> {360, 465, 0.77 } },
     { "box7", new List<double> {360, 465, 0.77 } },
     { "box8", new List<double> {360, 465, 0.77 } },
     { "box9", new List<double> {540, 290, 1.86 } },
    { "box10", new List<double> {540, 290, 1.86 } }
};

double RA = (double)item.images[0].width / item.images[0].height;

foreach (var AR in sizeOfPhotoBoxes)
{
   if (AR.Value[2] >= RA && AR.Value[2] <= RA)
   {
      System.Diagnostics.Debug.WriteLine("found");
   }
}

I'm trying to figure out how to loop through my boxes' Aspect Ratio's to determine which box that image should go into according to that image Ratio. Currently with the code above, I am not getting the "found" output.

A few image samples:

1) 960/720 = 1.33

2) 1440/800 = 1.8

3) 1078/1440 = 0.74

4) 2048/1152 = 1.77

So taking the example above:

Image 1 would be best in Box 1 or 2 since that box has a 1.31 Aspect Ratio.

Image 2 would be best in box 9 or 10 since that box has a 1.86 Aspect Ratio.

Image 3 would be best in box 6, 7 or 8 since that box has a 0.77 Aspect Ratio.

Image 4 would be best in box 9 or 10 since that box has a 1.86 Aspect Ratio.

Any help with the code to determine this above would be great! Thanks!!
StealthrtAsked:
Who is Participating?
 
it_saigeConnect With a Mentor DeveloperCommented:
You are correct, the aspect ratio of .55 is outside the bounds set by the variance limits.  To ensure that we return results when the photo's are outside the range of the variances, we need to include one more check and get the lowest or greatest ratio'd boxes; e.g. -
static IEnumerable<KeyValuePair<string, List<double>>> GetBoxes(double ratio)
{
    var ratios = (from box in photoBoxes orderby box.Value[2] select box.Value[2]);
    if (ratio < ratios.First())
    {
        return (from box in photoBoxes
                where box.Value[2] == ratios.First()
                select box);
    }
    else if (ratio > ratios.Last())
    {
        return (from box in photoBoxes
                where box.Value[2] == ratios.Last()
                select box);
    }
    return (from box in photoBoxes
            where ratio == box.Value[2] ||
            (ratio < box.Value[2] && box.Value[2] - ratio <= .1) ||
            (ratio > box.Value[2] && ratio - box.Value[2] <= .1)
            select box);
}

Open in new window

Proof of concept -
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;

namespace EE_Q29087094
{
    class Program
    {
        static Dictionary<string, List<double>> photoBoxes = new Dictionary<string, List<double>>
        {
            { "box1", new List<double> {357, 272, 1.31} },
            { "box2", new List<double> {357, 272, 1.31 } },
            { "box3", new List<double> {365, 460, 0.79 } },
            { "box4", new List<double> {365, 265, 1.38 } },
            { "box5", new List<double> {715, 455, 1.57 } },
            { "box6", new List<double> {360, 465, 0.77 } },
            { "box7", new List<double> {360, 465, 0.77 } },
            { "box8", new List<double> {360, 465, 0.77 } },
            { "box9", new List<double> {540, 290, 1.86 } },
            { "box10", new List<double> {540, 290, 1.86 } }
        };

        static void Main(string[] args)
        {
            var photos = new[] { new Bitmap(960, 720), new Bitmap(1440, 800), new Bitmap(1078, 1440), new Bitmap(2048, 1152), new Bitmap(528, 960) };
            foreach (var photo in photos)
            {
                var boxes = GetBoxes(photo.Width / (double)photo.Height);
                foreach (var box in boxes)
                {
                    Console.WriteLine($"Found match for photo {string.Join("x", new[] { photo.Width, photo.Height })} with aspect ratio {(photo.Width / (double)photo.Height):N2}; {box.Key} is {string.Join("x", box.Value.Take(2).ToArray())} with an aspect ratio of {box.Value.Last()}");
                }
            }

            Console.ReadLine();
        }

        static IEnumerable<KeyValuePair<string, List<double>>> GetBoxes(double ratio)
        {
            var ratios = (from box in photoBoxes orderby box.Value[2] select box.Value[2]);
            if (ratio < ratios.First())
            {
                return (from box in photoBoxes
                        where box.Value[2] == ratios.First()
                        select box);
            }
            else if (ratio > ratios.Last())
            {
                return (from box in photoBoxes
                        where box.Value[2] == ratios.Last()
                        select box);
            }
            return (from box in photoBoxes
                    where ratio == box.Value[2] ||
                    (ratio < box.Value[2] && box.Value[2] - ratio <= .1) ||
                    (ratio > box.Value[2] && ratio - box.Value[2] <= .1)
                    select box);
        }
    }
}

Open in new window

Now produces the following output -Capture.PNG
-saige-
1
 
it_saigeDeveloperCommented:
You have to set variance limits since you are not dealing with explicit matches:
using System;
using System.Collections.Generic;
using System.Linq;

namespace EE_Q29087094
{
    class Program
    {
        static Dictionary<string, List<double>> photoBoxes = new Dictionary<string, List<double>>
        {
            { "box1", new List<double> {357, 272, 1.31} },
            { "box2", new List<double> {357, 272, 1.31 } },
            { "box3", new List<double> {365, 460, 0.79 } },
            { "box4", new List<double> {365, 265, 1.38 } },
            { "box5", new List<double> {715, 455, 1.57 } },
            { "box6", new List<double> {360, 465, 0.77 } },
            { "box7", new List<double> {360, 465, 0.77 } },
            { "box8", new List<double> {360, 465, 0.77 } },
            { "box9", new List<double> {540, 290, 1.86 } },
            { "box10", new List<double> {540, 290, 1.86 } }
        };

        static void Main(string[] args)
        {
            var photos = new[] { new[] { 960, 720 }, new[] { 1440, 800 }, new[] { 1078, 1440 }, new[] { 2048, 1152 } };
            foreach (var photo in photos)
            {
                var boxes = (from box in photoBoxes
                             let ratio = photo[0] / (double)photo[1]
                             /* box ratio matches photo ratio */
                             where ratio == box.Value[2] ||
                             /* if photo ratio less than box ratio and
                              * box ratio - photo ratio is less than or equal to .1 */
                             (ratio < box.Value[2] && box.Value[2] - ratio <= .1) ||
                             /* if photo ratio greater than box ratio and
                              * photo ratio - box ratio is less than or equal to .1 */
                             (ratio > box.Value[2] && ratio - box.Value[2] <= .1)
                             select box);
                foreach (var box in boxes)
                {
                    Console.WriteLine($"Found match for photo {string.Join("x", photo)} with aspect ratio {(photo[0] / (double)photo[1]):N2}; {box.Key} is {string.Join("x", box.Value.Take(2).ToArray())} with an aspect ratio of {box.Value.Last()}");
                }
            }

            Console.ReadLine();
        }
    }
}

Open in new window

Which produces the following output -Capture.PNG
-saige-
0
 
StealthrtAuthor Commented:
Thats great @saige but I am looking to do 1 image at a time.

I did a little modding of your code:

 
double RA = (double)item.images[0].width / item.images[0].height;
var photo = new[] { new[] { item.images[0].width, item.images[0].height } };

//foreach (var photo in photos)
// {
       var boxes = (from box in sizeOfPhotoBoxes
          let ratio = RA
          where ratio == box.Value[2] ||
                 (ratio < box.Value[2] && box.Value[2] - ratio <= .1) ||
                 (ratio > box.Value[2] && ratio - box.Value[2] <= .1)
          select box);

       foreach (var box in boxes)
       {
            Console.WriteLine($"Found match for photo with aspect ratio {box.Key} is {box.Value.Take(2).ToArray()} with an aspect ratio of {box.Value.Last()}");
       }
}

Open in new window

But it produces no returned values.
0
Upgrade your Question Security!

Your question, your audience. Choose who sees your identity—and your question—with question security.

 
it_saigeDeveloperCommented:
If you simply want to pass in a photo to a method then you would do something like this:
using System;
using System.Collections.Generic;
using System.Linq;

namespace EE_Q29087094
{
    class Program
    {
        static Dictionary<string, List<double>> photoBoxes = new Dictionary<string, List<double>>
        {
            { "box1", new List<double> {357, 272, 1.31} },
            { "box2", new List<double> {357, 272, 1.31 } },
            { "box3", new List<double> {365, 460, 0.79 } },
            { "box4", new List<double> {365, 265, 1.38 } },
            { "box5", new List<double> {715, 455, 1.57 } },
            { "box6", new List<double> {360, 465, 0.77 } },
            { "box7", new List<double> {360, 465, 0.77 } },
            { "box8", new List<double> {360, 465, 0.77 } },
            { "box9", new List<double> {540, 290, 1.86 } },
            { "box10", new List<double> {540, 290, 1.86 } }
        };

        static void Main(string[] args)
        {
            var photos = new[] { new[] { 960, 720 }, new[] { 1440, 800 }, new[] { 1078, 1440 }, new[] { 2048, 1152 } };
            foreach (var photo in photos)
            {
                var boxes = GetBoxes(photo);
                foreach (var box in boxes)
                {
                    Console.WriteLine($"Found match for photo {string.Join("x", photo)} with aspect ratio {(photo[0] / (double)photo[1]):N2}; {box.Key} is {string.Join("x", box.Value.Take(2).ToArray())} with an aspect ratio of {box.Value.Last()}");
                }
            }

            Console.ReadLine();
        }

        static IEnumerable<KeyValuePair<string, List<double>>> GetBoxes(int[] photo)
        {
            return (from box in photoBoxes
                    let ratio = photo[0] / (double)photo[1]
                    where ratio == box.Value[2] ||
                    (ratio < box.Value[2] && box.Value[2] - ratio <= .1) ||
                    (ratio > box.Value[2] && ratio - box.Value[2] <= .1)
                    select box);
        }
    }
}

Open in new window

Which gives the same output as above.  But in reviewing your code you seem to be getting your width and height from an image list of a sorts.  So perhaps you are looking for something more along the lines of:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;

namespace EE_Q29087094
{
    class Program
    {
        static Dictionary<string, List<double>> photoBoxes = new Dictionary<string, List<double>>
        {
            { "box1", new List<double> {357, 272, 1.31} },
            { "box2", new List<double> {357, 272, 1.31 } },
            { "box3", new List<double> {365, 460, 0.79 } },
            { "box4", new List<double> {365, 265, 1.38 } },
            { "box5", new List<double> {715, 455, 1.57 } },
            { "box6", new List<double> {360, 465, 0.77 } },
            { "box7", new List<double> {360, 465, 0.77 } },
            { "box8", new List<double> {360, 465, 0.77 } },
            { "box9", new List<double> {540, 290, 1.86 } },
            { "box10", new List<double> {540, 290, 1.86 } }
        };

        static void Main(string[] args)
        {
            var photos = new[] { new Bitmap(960, 720), new Bitmap(1440, 800), new Bitmap(1078, 1440), new Bitmap(2048, 1152) };
            foreach (var photo in photos)
            {
                var boxes = GetBoxes(new[] { photo.Width, photo.Height });
                foreach (var box in boxes)
                {
                    Console.WriteLine($"Found match for photo {string.Join("x", new[] { photo.Width, photo.Height })} with aspect ratio {(photo.Width / (double)photo.Height):N2}; {box.Key} is {string.Join("x", box.Value.Take(2).ToArray())} with an aspect ratio of {box.Value.Last()}");
                }
            }

            Console.ReadLine();
        }

        static IEnumerable<KeyValuePair<string, List<double>>> GetBoxes(int[] photo)
        {
            return (from box in photoBoxes
                    let ratio = photo[0] / (double)photo[1]
                    where ratio == box.Value[2] ||
                    (ratio < box.Value[2] && box.Value[2] - ratio <= .1) ||
                    (ratio > box.Value[2] && ratio - box.Value[2] <= .1)
                    select box);
        }
    }
}

Open in new window

Or better yet
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;

namespace EE_Q29087094
{
    class Program
    {
        static Dictionary<string, List<double>> photoBoxes = new Dictionary<string, List<double>>
        {
            { "box1", new List<double> {357, 272, 1.31} },
            { "box2", new List<double> {357, 272, 1.31 } },
            { "box3", new List<double> {365, 460, 0.79 } },
            { "box4", new List<double> {365, 265, 1.38 } },
            { "box5", new List<double> {715, 455, 1.57 } },
            { "box6", new List<double> {360, 465, 0.77 } },
            { "box7", new List<double> {360, 465, 0.77 } },
            { "box8", new List<double> {360, 465, 0.77 } },
            { "box9", new List<double> {540, 290, 1.86 } },
            { "box10", new List<double> {540, 290, 1.86 } }
        };

        static void Main(string[] args)
        {
            var photos = new[] { new Bitmap(960, 720), new Bitmap(1440, 800), new Bitmap(1078, 1440), new Bitmap(2048, 1152) };
            foreach (var photo in photos)
            {
                var boxes = GetBoxes(photo);
                foreach (var box in boxes)
                {
                    Console.WriteLine($"Found match for photo {string.Join("x", new[] { photo.Width, photo.Height })} with aspect ratio {(photo.Width / (double)photo.Height):N2}; {box.Key} is {string.Join("x", box.Value.Take(2).ToArray())} with an aspect ratio of {box.Value.Last()}");
                }
            }

            Console.ReadLine();
        }

        static IEnumerable<KeyValuePair<string, List<double>>> GetBoxes(Image photo)
        {
            return (from box in photoBoxes
                    let ratio = photo.Width / (double)photo.Height
                    where ratio == box.Value[2] ||
                    (ratio < box.Value[2] && box.Value[2] - ratio <= .1) ||
                    (ratio > box.Value[2] && ratio - box.Value[2] <= .1)
                    select box);
        }
    }
}

Open in new window

Which all produce the same output as above.

-saige-
0
 
StealthrtAuthor Commented:
I would only be using 1 image at a time. The images I get are already in a for loop so I just deal with 1 image at a time.

Your examples seem to still have "photos" where all I would need is just 1 photo.
0
 
it_saigeDeveloperCommented:
Main is looping through the photos in the array/list of photos, for each one of those photos it feeds the photo to the GetBoxes method, you simply have to choose which signature you want to use; e.g. -
double ratio = (double)item.images[0].width / item.images[0].height;

var boxes = GetBoxes(ratio);

Open in new window

The GetBoxes method would then look like this:
static IEnumerable<KeyValuePair<string, List<double>>> GetBoxes(double ratio)
{
    return (from box in photoBoxes
            where ratio == box.Value[2] ||
            (ratio < box.Value[2] && box.Value[2] - ratio <= .1) ||
            (ratio > box.Value[2] && ratio - box.Value[2] <= .1)
            select box);
}

Open in new window

Boxes is an enumerable of boxes where the ratio meets the requirements, to access each one you have to loop:
foreach (var box in boxes)
{
    // You got one of your matches, now do something with it
    Console.WriteLine($"Box: {box.Key}; Values: {{ {string.Join(", ", box.Value.ToArray())} }}");
}

Open in new window


-saige-
0
 
StealthrtAuthor Commented:
Not sure what i am doing wrong but i seem to keep getting nothing..
loopErr1.png
0
 
StealthrtAuthor Commented:
Hum.. i think i found out what is wrong. I am using 528, 960 and that seems to come back with nothing...
0
 
StealthrtAuthor Commented:
Awesome! Thanks saige!
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.