将人像 (w<h) 图像水平平铺成 16:9 比例风景蒙太奇的算法

Posted

技术标签:

【中文标题】将人像 (w<h) 图像水平平铺成 16:9 比例风景蒙太奇的算法【英文标题】:Algorithm for horizontally tiling portrait (w<h) images into 16:9 ratio landscape montages 【发布时间】:2021-04-12 16:10:59 【问题描述】:

我想写一个程序,将一组具有相同高度但不同宽度的纵向(即宽度https://en.wikipedia.org/wiki/Knapsack_problem。

【问题讨论】:

给我们一份有代表性的图片尺寸列表如何? 几年前我做了一些相关的事情,从那以后事情可能会继续发展,但可能值得一读...***.com/a/30625536/2836621 【参考方案1】:

我没有足够的代表发表评论,所以我会发布这个作为答案。

您有一组高度相同的图像,因此您知道每个合成图像的目标宽度(假设每个图像的高度为 900,因此您将选择 1600 宽度)。

如果我们将成本函数设置为每个(合成图像的宽度 - 1600)之差的总和,那么这将变成一个最小化类型的问题,您试图找到成本最低的合成图像集.根据您拥有的图像数量,可以简单地尝试所有可能的组合(对单个合成的图像数量有一定限制)并选择最佳结果分数。

对于一些简单的事情,我们可以采取一种贪心算法来解决这个问题:将图像添加到合成中,直到它溢出 (>1600)。一旦溢出,取出最后一张图像并换入下一张。对每个剩余的图像执行此操作并记录分数(composite_width - 1600)。选择最佳合成并从池中删除这些图像。重复此过程,直到图像用完为止。

这是一个有趣的问题。如果我以后有空闲时间,我会更认真地探索它,但是有很多关于最小切割问题的文献,所以可能有一些类似的官方算法或可以适用于此。

编辑:

这是我描述的贪心算法的快速而肮脏的实现。我还有第二个贪心算法,它假设按宽度预先排序(从低到高)列表。对于 100 张宽度在 [200, 1200] 之间的图像,第一个的平均误差为 143.15。第二个在相同参数下的平均误差为 64.19。

import random

# returns average error of a list of compositions
def getError(target, comps):
    total = 0;
    for comp in comps:
        total += abs(target - sum(comp));
    total /= len(comps);
    return round(total, 2);

# randomly generate 'n' images within bounds
def getImgs(num, low, high):
    imgs = [];
    for a in range(num):
        imgs.append(random.randint(low, high));
    return imgs;

# greedy approach
def greedy1(target, imgs):
    # end containers
    comps = [];
    copy = imgs[:];
    while copy:
        # go until overflow or empty
        comp = [];
        total = 0;
        while total < target and copy:
            comp.append(copy[0]);
            total += copy[0];
            copy = copy[1:];

        # remove the last element
        copy.append(comp[-1]);
        total -= comp[-1];
        comp = comp[:-1];

        # start evaluating
        scores = [];
        best_score = 1000000000000; # A REALLY BIG NUMBER
        best_index = -1;
        for a in range(len(copy)):
            curr_score = abs(target - (total + copy[a]));
            if curr_score < best_score:
                best_score = curr_score;
                best_index = a;

        # choose best
        comp.append(copy[best_index]);
        del copy[best_index];
        comps.append(comp);
    return comps;

# another greedy approach (assumes sorted images low->high)
def greedy2(target, imgs):
    # end containers
    comps = [];
    copy = imgs[:];
    while copy:
        # go until overflow or empty
        comp = [];
        total = 0;
        while total < target and copy:
            comp.append(copy[-1]);
            total += copy[-1];
            copy = copy[:-1];

        # remove the last element
        copy.append(comp[-1]);
        total -= comp[-1];
        comp = comp[:-1];

        # go until overflow or past index
        index = 0;
        while index < len(copy) and total + copy[index] < target:
            index += 1;
        if index >= len(copy):
            index = len(copy) - 1;
        if copy:
            comp.append(copy[index]);
            del copy[index];
        comps.append(comp);
    return comps;


# target
target = 1600;

# randomly generate "images"
num = 100;
low = 200;
high = 1200;

# run iterations
iters = 10000;
avg_error1 = 0;
avg_error2 = 0;
for a in range(iters):
    # new set of images
    imgs = getImgs(num, low, high);

    # attempt to fill
    comps = greedy1(target, imgs);
    error1 = getError(target, comps);
    avg_error1 += error1;

    # attemp to fill 2
    imgs.sort();
    comps = greedy2(target, imgs);
    error2 = getError(target, comps);
    avg_error2 += error2;

    # sanity progress check
    if a%200 == 0:
        print(a);

# average
avg_error1 /= iters;
avg_error1 = round(avg_error1, 2);
avg_error2 /= iters;
avg_error2 = round(avg_error2, 2);
print("Average 1: " + str(avg_error1));
print("Average 2: " + str(avg_error2));

# Results for 100 imgs over 10000 iters
# Average 1: 143.15 
# Average 2: 64.19

【讨论】:

以上是关于将人像 (w<h) 图像水平平铺成 16:9 比例风景蒙太奇的算法的主要内容,如果未能解决你的问题,请参考以下文章

R语言ggplot2可视化:ggplot2可视化分组箱图,将可视化图像的图例(legend)放置在图像底部居中其中图例信息水平平铺​ (position legend bottom center)

R语言ggplot2可视化:ggplot2可视化分组箱图,将可视化图像的图例(legend)放置在图像底部左边左对齐其中图例信息水平平铺​ (position legend bottom left)

R语言ggplot2可视化:ggplot2可视化分组箱图,将可视化图像的图例(legend)放置在图像底部左边左对齐其中图例信息水平平铺​ (position legend bottom left)

R语言ggplot2可视化:ggplot2可视化分组箱图,将可视化图像的图例(legend)和标题(title)放置在图像左上方并左对齐其中图例信息水平平铺(top left)

R语言ggplot2可视化:ggplot2可视化分组箱图,将可视化图像的图例(legend)放置在图像右上方并右对齐其中图例信息水平平铺​ (position legend top right)

为啥人像视图照片水平显示?