mcan
mcan

Reputation: 2082

Set the resolution without changing the aspect ratio

I want to scale some images and i want to set the pixels count to some spesific number. For example, if there is an image with width=400px height=100 I can scale it by 0.5 to set the resolution 10000px But the code below may produce some new_width*new_height values like 9999 or 10001 some other width and height values. Total number of pixels must be 10000.

import os
import cv2

TOTAL_PIXEL_NUMBER = 10000

path = 'path/to/images/folder'
for img in os.listdir(path):
    try:
        img_array = cv2.imread(os.path.join(path,img), cv2.IMREAD_GRAYSCALE)
        height, width = img_array.shape
        aspect_ratio = width/height
        new_height = np.sqrt(TOTAL_PIXEL_NUMBER/aspect_ratio)
        new_width = new_height * aspect_ratio
        new_array = cv2.resize(img_array, (new_width,new_height))
        data.append(new_array)
    except Exceptinon as e:
        print(e)

I want to keep the ratio same to not distort the images. But it is not mandatory to stay 'exactly' the same. For example if the original ratio is 0.35 it can be 0.36 or 0.34 in resized image to make the number of total pixels 10000. But how can i pick the optimal ratio to make the resolution constant? Or if there is some opencv function to do that it would be great.

Upvotes: 0

Views: 200

Answers (2)

MBo
MBo

Reputation: 80325

Make a list of ratios including values (10000/1, 5000/2, etc)

[10000, 2500, 625, 400, 156.25, 100, 39.065, 25, 16, 6.25, 4, 1.5625, 1...0.0001]

or ready-to use tuples with ratio, width and height:

[(10000, 10000, 1), (2500, 5000, 2), (625, 2500, 4) ...]

and inverses of the first part of this list.

For given ratio w/h find the closest value from the list and use corresponding width and height to make resulting rectangle.

For example, you have 300x200 image with ratio 1.5. The best value is 1.5625, so result rectangle is 125x80 and scale coefficients are 125/300 and 80/200

l = []
for i in range(1, 10001):
    if (10000 % i == 0):
        w = i
        h = 10000 // i
        r = w / h
        l.append((r, w, h))

ww, hh = 1920, 1080
rr = ww / hh
mn = 100000
for i in range(len(l)):
    cmn = max(rr / l[i][0], l[i][0] / rr)
    if (cmn < mn):
        bestidx = i
        mn = cmn

new_width = l[bestidx][1]
new_height = l[bestidx][2]

Upvotes: 2

Sreekiran A R
Sreekiran A R

Reputation: 3421

you can use the fx and fy parameters to set this.

#creating ratio
rate=1/np.sqrt(height*width/10000)
new_array = cv2.resize(img_array, (0,0), fx=rate, fy=rate)
#this will resize the image to 10000 pixels in 3 channels.

Upvotes: 1

Related Questions