Уменьшите размер (установите максимальную ширину и высоту) - PullRequest
0 голосов
/ 29 мая 2018

Я пишу сценарий для обработки нескольких изображений в высоком разрешении.Размеры этих изображений варьируются от 1000 до 5000 пикселей.Чтобы подготовить их к веб-загрузке (загрузить), мне нужно уменьшить их.

Меня не интересует реализация уменьшения (открыть изображение, масштабировать, сохранить и т. Д.).Меня интересует расчет новых уменьшенных размеров.

Допустим, у меня есть изображение с размерами 800x2000 пикселей, и я установил 2400x1200 в качестве максимальных размеров.Уменьшенные размеры изображения должны быть 480x1200 пикселей.Размеры изображения не могут превышать максимальные размеры.

Как рассчитать это?


При формировании вопроса в голове я тоже экспериментировал и придумал следующий алгоритм:

def scale(dim, max_dim):
    new_dim = {"w" : 0, "h" : 0}

    # no change if dim is lower than given max_dim
    if dim["w"] <= max_dim["w"] and dim["h"] <= max_dim["h"]:
        return dim

    ratio = 0

    # detect which side overflows
    if dim["w"] > max_dim["w"]:
        ratio = max_dim["w"] / dim["w"]
    else:
        ratio = max_dim["h"] / dim["h"]

    # scale according to overflowing side
    new_dim["w"] = dim["w"] * ratio
    new_dim["h"] = dim["h"] * ratio

    # now the other side might overflow after scaling
    # check if that's true and scale again
    if new_dim["h"] > max_dim["h"]:
        ratio = max_dim["h"] / dim["h"]
    if new_dim["w"] > max_dim["w"]:
        ratio = max_dim["w"] / dim["w"]

    new_dim["w"] = math.floor(dim["w"] * ratio)
    new_dim["h"] = math.floor(dim["h"] * ratio)

    return new_dim

Кажется, это дает правильные результаты, хотя я не уверен, что это предпочтительный подход.Например, я делаю две проверки;во-первых, чтобы обнаружить переполнение, а во-вторых, чтобы исправить (возможное) второе переполнение, которое возникает в результате первой шкалы.Возможно, я выполняю избыточные вычисления, поэтому мне также нужен совет по этому поводу.

Контрольные примеры:

max_dim = {"w" : 2400, "h" : 1200}

dim1 = {"w" : 800,  "h" : 1000}
dim2 = {"w" : 800,  "h" : 2000}
dim3 = {"w" : 800,  "h" : 2500}
dim4 = {"w" : 2500, "h" : 800}
dim5 = {"w" : 2500, "h" : 3000}
dim6 = {"w" : 1800, "h" : 1500}
dim7 = {"w" : 2500, "h" : 1000}
dim8 = {"w" : 2500, "h" : 1400}
dim9 = {"w" : 2500, "h" : 2000}

print(scale(dim1, max_dim))
print(scale(dim2, max_dim))
print(scale(dim3, max_dim))
print(scale(dim4, max_dim))
print(scale(dim5, max_dim))
print(scale(dim6, max_dim))
print(scale(dim7, max_dim))
print(scale(dim8, max_dim))
print(scale(dim9, max_dim))

Выходы:

{'w': 800, 'h': 1000}
{'w': 480, 'h': 1200}
{'w': 384, 'h': 1200}
{'w': 2400, 'h': 768}
{'w': 1000, 'h': 1200}
{'w': 1440, 'h': 1200}
{'w': 2400, 'h': 960}
{'w': 2142, 'h': 1200}
{'w': 1500, 'h': 1200}

Эти выводы верны.Ни ширина, ни высота введенных размеров не превышают максимальные размеры.

Кроме того, я знаю, что в Python есть встроенные методы масштабирования изображения (resize и thumbnail), но я сделаю дальшеизменения (изменение соотношения сторон, установка прозрачных пикселей и пустых областей на белый и т. д.), поэтому мне нужно выполнить расчет вручную.

Ответы [ 2 ]

0 голосов
/ 29 мая 2018

Сначала получите соотношение ширины и высоты, исходя из того, что вы можете написать простое предложение if.

def resize(width, height):
    pref_width  = 2400
    pref_height = 1200
    pref_ratio = pref_width/pref_height
    ratio = width/height

Если изображение слишком широкое, соотношение изображений будет больше, чем предпочтительноекоэффициент, и мы можем рассчитать все на основе ширины, чтобы избежать переполнения:

    if ratio > pref_ratio:
        return pref_width, height * (pref_width / width)

Если изображение слишком велико по высоте, мы устанавливаем предпочтительную высоту в качестве новой высоты и рассчитываем ширину соответственно.Нам не нужно учитывать, что изменяемый размер изображения имеет одинаковые размеры, потому что формула не имеет значения и в любом случае дает нам правильный ответ.

    else:
        return width * (pref_height / height), pref_height
0 голосов
/ 29 мая 2018

Да, достаточно сделать одно сравнение (также можно сохранить Max_W * Hgt и Max_H * Wdt в переменных для сохранения умножения на одну единицу:))

if (Max_W * Hgt < Max_H * Wdt):
    W_Result = Max_W
    H_Result = Hgt * Max_W / Wdt
else:
   W_Result = Wdt * Max_H / Hgt
   H_Result = Max_H
...