因为我很好奇如何获得权重比例,所以我自己进行了一些数学计算(例如线性上采样到公共倍数,然后从大数组中提取目标值的权重,但不创建大数组,只使用权重知道左+右元素对特定值的贡献量)。示例代码总是通过简单的加权平均值创建新值(即40%的123.4与60%的567.8将给出“上采样”值390.04),没有随机用于修改上采样值(此部分留给OP)。
权重比例如下:
如果大小为M的向量被上采样到大小为N(M <= N)(此“上采样”将始终保留输入向量的第一个和最后一个元素,这些在此提案中是“固定”的)
那么每个上采样元素都可以视为在某些原始元素[i,i + 1]之间的某个位置。
如果我们将源元素[i,i + 1]之间的“距离”声明为d = N-1,则上采样元素之间的距离始终可以表示为某个j / d,其中j:[0,d](当j为实际d时,它正好在“ i + 1”元素处,可以认为与[j]=0相同,但具有[i + 1,i + 2]源元素)
然后,两个上采样元素之间的距离为M-1。
因此,当源向量大小为4,上采样向量大小应为5时,上采样元素的比例为[[4/4,0/4],[1/4,3/4],[2/4 ,2/4],[3/4,1/4],[0/4,4/4]],其中indices into vector是[[0,1],[0,1],[1,2],[2,3],[2,3]]。 (源元素之间的“距离”为5-1 = 4,这是将权重规范化为“/ 4”的原因,“上采样”元素之间的“距离”为4-1 = 3,这就是为什么比例在每个步骤中移位[-3,+3]的原因)。
很抱歉我的描述远非“显而易见”(在我头脑中找出来后的感觉),但如果您将其放入电子表格中并进行玩耍,希望它会有些意义。或者也可以调试代码以更好地理解上述咕哝声如何转换为实际代码。
代码示例1,如果权重恰好全部在源元素上,则仅“复制”源元素(即,在示例数据中,仅第一个和最后一个元素被“复制”,其余的上采样元素是原始值的加权平均值)。
#include <iostream>
#include <vector>
#include <cassert>
static double get_upscale_value(const size_t total_weight, const size_t right_weight, const double left, const double right) {
const size_t left_weight = total_weight - right_weight;
return (left * left_weight + right * right_weight) / total_weight;
}
std::vector<double> upsample_weighted(std::vector<double>& in, size_t n)
{
assert( 2 <= in.size() && in.size() <= n );
std::vector<double> upscaled;
upscaled.reserve(n);
size_t index_left = 0;
size_t weight_right = 0;
const size_t in_weight = n - 1;
const size_t weight_add = in.size() - 1;
while (upscaled.size() < n) {
if (0 == weight_right) {
upscaled.push_back(in[index_left]);
} else {
double upscaled_val = get_upscale_value(in_weight, weight_right, in[index_left], in[index_left+1]);
upscaled.push_back(upscaled_val);
}
weight_right += weight_add;
if (in_weight <= weight_right) {
++index_left;
weight_right -= in_weight;
}
}
return upscaled;
}
int main(int argc, const char *argv[])
{
std::vector<double> in { 10, 20, 30 };
std::vector<double> upscaled = upsample_weighted(in, 14);
std::cout << "upsample_weighted from " << in.size() << " to " << upscaled.size() << ": ";
for (const auto i : upscaled) {
std::cout << i << " ";
}
std::cout << std::endl;
return 0;
}
输出:
从3到14进行加权上采样: 10 11.5385 13.0769 14.6154 16.1538 17.6923 19.2308 20.7692 22.3077 23.8462 25.3846 26.9231 28.4615 30
代码示例2,这个示例将“复制”每个源元素,并仅在填充间隙时使用加权平均值,以尽可能保留原始数据(代价是结果不是线性地放大原始数据集,而是“别名”为目标大小定义的“网格”):
(代码与第一个示例几乎相同,除了上采样器中的一行if
语句)
#include <iostream>
#include <vector>
#include <cassert>
static double get_upscale_value(const size_t total_weight, const size_t right_weight, const double left, const double right) {
const size_t left_weight = total_weight - right_weight;
return (left * left_weight + right * right_weight) / total_weight;
}
std::vector<double> upsample_copy_preferred(std::vector<double>& in, size_t n)
{
assert( 2 <= in.size() && in.size() <= n );
std::vector<double> upscaled;
upscaled.reserve(n);
size_t index_left = 0;
size_t weight_right = 0;
const size_t in_weight = n - 1;
const size_t weight_add = in.size() - 1;
while (upscaled.size() < n) {
if (weight_right < weight_add) {
upscaled.push_back(in[index_left]);
} else {
double upscaled_val = get_upscale_value(in_weight, weight_right, in[index_left], in[index_left+1]);
upscaled.push_back(upscaled_val);
}
weight_right += weight_add;
if (in_weight <= weight_right) {
++index_left;
weight_right -= in_weight;
}
}
return upscaled;
}
int main(int argc, const char *argv[])
{
std::vector<double> in { 10, 20, 30 };
std::vector<double> upscaled = upsample_copy_preferred(in, 14);
std::cout << "upsample_copy_preferred from " << in.size() << " to " << upscaled.size() << ": ";
for (const auto i : upscaled) {
std::cout << i << " ";
}
std::cout << std::endl;
return 0;
}
输出:
将3进行上采样复制到14:10、11.5385、13.0769、14.6154、16.1538、17.6923、19.2308、20、22.3077、23.8462、25.3846、26.9231、28.4615、30
(请注意,示例1中的“20.7692”在这里只是原始样本的副本“20”,即使在那个点上如果考虑线性插值,“30”也有一些小权重。)