algorithm which will find a best fitting picture - algorithm

I have a list of images, each one of them has width and height.
and I have one div - with width and height
now I have to find out which image would look the best in my div - would be the least distorted.
What i'm trying now is checking the aspect ratios and width - but then i need some kind of weight - how important should be each one.
Is there a better way to do it? Any ready to use algorithms?
edit: about the weight - lets say I have a div of size 100 x 50, and 2 images: 2000 x 1000, 101 x 51. The ratio for first one is perfect - but i would have to scale it down 20 times, so it would be easier for the browser and proabably for the viewer experience use the second image. So I use
a = abs((img.aspect_ratio - div.aspect_ratio) / (img.aspect_ratio + div.aspect_ratio))
b = abs((img.width - div.width) / (img.width + div.width))
// division to scale the value between (0, 1)
and then look for image with smallest a + b. To get better effect tried to use a+2b instead - these are the weights.

Related

Best fitting rectangle with a variable number of small rectangles keeping aspect ratio

I need to find the optimal placement of a given N child rectangles keeping the aspect ratio of the father rectangle.
Use case is the following:
- the father rectangle is a big picture, let's say 4000x3000 pixels (this one can be rescaled).
- child rectangles are 296x128 pixels (e-ink displays of users)
The objective is to show the big picture across all the current number of displays (this number can change from 1 to 100)
This is an example:
Can happen that number of small rectangles will not fit the big rectangle aspect ratio, like if number of small rectangles is odd, in this case I can think to have like a small number (max 5) of spare rectangles to add in order to complete the big rectangle.
this seems to be a valid approach (python + opencv)
import cv2
import imutils
def split_image(image, boards_no=25, boards_shape=(128, 296), additional=5):
# find image aspect ratio
aspect_ratio = image.shape[1]/image.shape[0]
print("\nIMAGE INFO:", image.shape, aspect_ratio)
# find all valid combination of a,b that maximize your available badges
valid_props = [(a, b) for a in range(boards_no+additional+1) for b in range(boards_no+additional+1) if a*b in [q for q in range(boards_no, boards_no+additional)]]
print("\nVALID COMBINATIONS", valid_props)
# find all aspect ratio from previous combination
aspect_ratio_all = [
{
'board_x': a,
'board_y': b,
'aspect_ratio': (a*boards_shape[1])/(b*boards_shape[0]),
'shape': (b*boards_shape[0], a*boards_shape[1]),
'type': 'h'
} for (a, b) in valid_props]
aspect_ratio_all += [
{
'board_x': a,
'board_y': b,
'aspect_ratio': (a*boards_shape[0])/(b*boards_shape[1]),
'shape': (b*boards_shape[1], a*boards_shape[0]),
'type': 'v'
} for (a, b) in valid_props]
min_ratio_diff = min([abs(aspect_ratio-x['aspect_ratio']) for x in aspect_ratio_all])
best_ratio = [x for x in aspect_ratio_all if abs(aspect_ratio-x['aspect_ratio']) == min_ratio_diff][0]
print("\MOST SIMILAR ASPECT RATIO:", best_ratio)
# resize image maximining height or width
resized_img = imutils.resize(image, height=best_ratio['shape'][0])
border_width = int((best_ratio['shape'][1] - resized_img.shape[1]) / 2)
border_height = 0
if resized_img.shape[1] > best_ratio['shape'][1]:
resized_img = imutils.resize(image, width=best_ratio['shape'][1])
border_height = int((best_ratio['shape'][0] - resized_img.shape[0]) / 2)
border_width = 0
print("RESIZED SHAPE:", resized_img.shape, "BORDERS (H, W):", (border_height, border_width))
# fill the border with black
resized_img = cv2.copyMakeBorder(
resized_img,
top=border_height,
bottom=border_height,
left=border_width,
right=border_width,
borderType=cv2.BORDER_CONSTANT,
value=[0, 0, 0]
)
# split in tiles
M = resized_img.shape[0] // best_ratio['board_y']
N = resized_img.shape[1] // best_ratio['board_x']
return [resized_img[x:x+M,y:y+N] for x in range(0,resized_img.shape[0],M) for y in range(0,resized_img.shape[1],N)]
image = cv2.imread('image.jpeg')
tiles = split_image(image)
Our solutions will always be rectangles into which we have fit the biggest picture that we can keeping the aspect ratio correct. The question is how we grow them.
In your example a single display is 296 x 128. (Which I assume is length and height.) Our scaled image to 1 display is 170.6 x 128. (You can take out fractional pixels in your scaling.)
The rule is that at all points, whatever direction is filled gets filled in with more displays so we can expand the picture. In the single display solution we therefore go from a 1x1 rectangle to a 1x2 one and we now have 296 x 256. Our scaled image is now 296 x 222.
Our next solution will be a 2x2 display. This gives us 594 x 256 and our scaled image is 321.3 x 256.
Next we get a 2x3 display. This gives us 594 x 384 and our scaled display is now 512 x 384.
Since we are still maxing on the second dimension we next go to 2x4. This gives us 594 x 512 and our scaled display is 594 x 445.5. And so on.
For your problem it will not take long to run through all of the sizes up to however many displays you have, and you just take the biggest rectangle that you can make from the list.
Important special case. If the display rectangle and image have the same aspect ratio, you have to add to both dimensions. Which in the case that the image and the displays have the same aspect ratio gives you 1 x 1, 2 x 2, 3 x 3 and so on through the squares.

resizing image with rmagick/imagemagick to be less than a specified product of its width and height

I'm running a script that resizes images that are too large. I've used "resize_to_fit" to reduce images to a specific pixel size depending on the longer side, but I'm wondering if it's possible to do it with this logic instead: for any image whose width x height product is greater than a set value, resize the image so that the new width and height values are as large as possible while still being under that value. In other words, I don't want to arbitrarily resize the dimensions more than necessary, and I'd want to retain aspect ratio in this conversion. This may be more of a math question than a ruby one, but in any case, this is what I've tried:
image = Magick::Image.read(image_file)[0];
dimensions = image.columns, image.rows
resolution = dimensions[0] * dimensions[1]
if resolution > 4000000
resolution_ratio = 4000000 / resolution.to_f
dimension_ratio = dimensions[0].to_f * resolution_ratio
img = img.resize_to_fit(dimension_ratio,dimension_ratio)
img.write("#{image}")
end
So let's say an image has a width of 2793px and a height of 1970px. The resolution would be 5,502,210. It thus goes through the conditional statement, and as of right now, outputs a new width of 2030 and height of 1432. The product of these two is 2,906,960—which is obviously well under 4,000,000. But there are other possible width x height combinations whose product could be much closer to 4,000,000 pixels than 2,906,960 is. Is there a way of determining that information, and then resizing it accordingly?
You need to properly calculate the ratio, which is a square root from your desired dimension divided by (row multiplied by col):
row, col = [2793, 1970]
ratio = Math.sqrt(4_000_000.0 / (row * col))
[row, col].map &ratio.method(:*)
#⇒ [
# [0] 2381.400006266842,
# [1] 1679.6842149465374
#]
[row, col].map(&ratio.method(:*)).reduce(:*)
#∞ 3999999.9999999995

Algorithm for cropping image to specific ratio

I need an algorithm that given an image's width, height and a target ratio will calculate the number of pixels to be shaved from the image's sides to get to that ratio, that has the smallest change in the image's area.
How might one implement such an algorithm?
Edit
Sorry for the inconsistency in my original question; I have revised my it.
Bring the ratio into reduced form, so that gcd(ratio_width, ratio_height) = 1.
Calculate floor(width / ratio_width) and floor(height / ratio_height). Your factor is the minimum of these two.
Multiply ratio_width and ratio_height by that factor to obtain the new image dimensions.
Shave the difference.
To minimize the change in area, you want to find the largest rectangle of the desired aspect ratio that will fit inside the original image bounds.
So, if the original image is too wide, then make the final image's height = original height, and shave off the extra width.
If the original image is too tall, make the final image's width = original width, and shave off the extra height.
Note: This assumes that you are not allowed to increase the width or height beyond the original dimensions. If that is not the case, the algorithm would be:
Constraint 1: x_final * y_final = x_initial * y_initial
Contraint 2: x_final / y_final = r
The solution is:
x_final = sqrt(r*x_initial*y_initial)
y_final = sqrt(x_initial*y_initial/r)

Algorithm to set proper "audio" volume based on distance (x,y)

i'm developing a game.
How can i "fade in" the audio volume for a sound, based on the "distance" of a sprite from the current render scene ?
Suppose i've a world:
WIDTH_WORLD = 10000
HEIGHT_WORLD = 10000
Current Scene
xCurrent = 800 ( + Width Res. = 800 + 1024 = 1824)
yCurrent = 400 ( + Height Res. = 400 + 768 =... )
Far Sprite
xSprite = 7000
ySprite = 3000
What is a good algorithm to "calculate" audio volume (and maybe left/right pan channel ratio) ?
Thanks in advance!
Total Volumn
There are several approaches for the attenuation of the volume. E.g. you could use a linear damping function, like volume = max( 0, max_volume - max_volume/max_distance * distance ), or a function with inverse distance fall off, like volume = min( max_volume, max_volume / distance ).
Balance Ratio
Again, there are several approaches to realize an adequate functionality. In your case, you could say, if the object is at or beyond the left screen border, pan to the left, if the object is at or beyond the right screen border, pan to the right, otherwise use an interpolation function, e.g. balance = (object_x-camera_x) / screen_half_width with values between -1: left, +1: right, and 0: center.
When combining these approaches you have to think about what is suitable for your case: For example only damp the volume if the object is out of screen bounds, what ever...
Use the distance (Dsquared = xdist^2 + ydist ^2) as a scaling factor to downscale your volume. Invert this distance squared value to apply directly to your volume (volume falls off as a square of distance, and distance is easily calculated as a squared value anyway).
Left / right channel ratio is done simply by defining two different points for the left and right channels (to the left and right, respectively, of your render location), perform the above calculation, and find the ratios of your channels that way. Because the above calculation is just a sum of two squares, it's very computationally simple.
Well, the volume of a sound degrades as the square of the distance from the sound source, so that would give you a good place to start.
Knowing what library you are using for your game would be helpful though - many game libraries will have this sort of functionality built in already.

Convert pixels into relative cm from a clickable image?

Having a bit of a brain freeze on how to do this. I have an image of an area of a soccer field which the user clicks on to indicate where something occured.
I want to store the coordinates in real world units in my database so that I could change the image at a later time. However, I can't figure out the formula to do this (ignoring the fact that a soccer field has a variable length).
So say my image is 400 px by 300px representing a real-world field 12000cm x 9000cm, what would the point 300px,100px be in centimeters? How would I then convert this cm value back into px on an image that was 800x600 px? Doing it in yards/inches would also be acceptable.
Please show me the working rather than just the single values. Thanks!
just like any other unit conversion: 300 * 12000/400, 100 * 9000/300 is the point where the user click in the soccer field.
More generally, assuming the two scales have the same zeros (i.e. 0 source == 0 target) and you know a point where the scales equal x source == y target, then valueInTarget = valueInSource * (y / x).
Even more generally, assuming you know two points where two scales are equal, i.e. x1 source == y1 target and x2 source == y2 target, then valueInTarget == (valueInSource - x1) * (y2 - y1)/(x2 - x1) + y1 == (valueInSource - x2) * (y1 - y2)/(x1 - x2) + y2.
Use ratios. 400px represent 12000cm, so your width ratio is 30 centimeters per pixel. Applying that ratio to 300px gives us 9000cm.
In your second example, your width ratio is 15 centimeters per pixel (12000/800). So 9000cm gives 600px on the second image.
Same goes for the height.

Resources