将人像 (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)