我有一系列100个整数值,我需要将其减少/子采样到77个值,以便适应屏幕上的预定义空间。这给出了每像素77/100值的一小部分 - 不是很整洁。
假设77是固定的并且无法更改,那么将100个数字二次采样到77的典型技术是什么。我感觉它将是一个锯齿状的映射,我的意思是第一个新值是平均值[0,1]然后下一个值是[3],然后是平均[4,5]等。但是我该如何获得这个映射的模式呢?
我在C ++工作,虽然我对这项技术比对实现更感兴趣。
提前致谢。
答案 0 :(得分:3)
如果您进行降采样或过采样,您将尝试在非采样时间点重建信号......所以您必须做出一些假设。
采样定理告诉您,如果您采样信号,知道其频率分量超过采样频率的一半,则可以在整个定时周期内连续完全恢复信号。有一种方法可以使用sinc()
函数重建信号(这是sin(x)/x
)
sinc()
(确实是sin(M_PI/Sampling_period*x)/M_PI/x
)是一个具有以下属性的函数:
x == 0.0
的值为1,x == k*Sampling_period
的{{1}}的值为0 k == 0, +-1, +-2, ...
派生的sampling_frequency的一半以上没有频率成分。因此,如果您认为函数Sampling_period
的总和是sinc函数,它等于位置F_x(x) = Y[k]*sinc(x/Sampling_period - k)
处的采样值,而0处于其他采样值,并且是样本中所有k的总和,则& #39;将获得最佳连续功能,该功能具有在采样频率的一半以上的频率上没有分量的特性,并且具有与样本集相同的值。
这样说,您可以在任何您喜欢的位置重新采样此功能,从而获得重新采样数据的最佳方式。
到目前为止,这是一种重新采样数据的复杂方法(它也存在不是因果关系的问题,因此无法实时实现),并且您过去使用了几种方法来简化插值。你必须构造每个样本点的所有sinc函数并将它们加在一起。然后,您必须将结果函数重新采样到新的采样点,并将其作为结果。
接下来是刚刚描述的插值方法的示例。它接受一些输入数据(k
样本)并使用前面描述的方法输出内插数据(我认为极值重合,这使得in_sz
样本等于N+1
样本,这使得在代码中强调N+1
的计算(如果您想进行简单(in_sz - 1)/(out_sz - 1)
转换,请更改为in_sz/out_sz
:
N samples -> M samples
答案 1 :(得分:2)
有不同的插值方法(参见wikipedia)
线性的将是:
std::array<int, 77> sampling(const std::array<int, 100>& a)
{
std::array<int, 77> res;
for (int i = 0; i != 76; ++i) {
int index = i * 99 / 76;
int p = i * 99 % 76;
res[i] = ((p * a[index + 1]) + ((76 - p) * a[index])) / 76;
}
res[76] = a[99]; // done outside of loop to avoid out of bound access (0 * a[100])
return res;
}
答案 2 :(得分:1)
根据位置的加权平均值创建77个新像素。
作为一个玩具示例,请考虑要将子采样为2的3像素大小写。
原始(表示为多维数组original
,RGB为[0,1,2]):
|----|----|----|
子样本(表示为多维数组subsample
,RGB为[0,1,2]):
|------|------|
在这里,直观地看到第一个子样本看起来像第一个原始像素的2/3和下一个的1/3。
对于第一个子样本像素subsample[0]
,您可以将其设为重叠的m
原始像素的RGB平均值,在本例中为original[0] and original[1]
。但我们以加权方式这样做。
subsample[0][0] = original[0][0] * 2/3 + original[1][0] * 1/3 # for red
subsample[0][1] = original[0][1] * 2/3 + original[1][1] * 1/3 # for green
subsample[0][2] = original[0][2] * 2/3 + original[1][2] * 1/3 # for blue
在此示例中,original[1][2]
是第二个原始像素的绿色成分。
请记住,对于不同的子采样,您必须确定有助于子样本的原始单元格集,然后进行标准化以找到每个子样本的相对权重。
有更复杂的图形技术,但这一点很简单并且有效。
答案 3 :(得分:1)
一切都取决于您希望如何处理数据 - 您希望如何将其可视化。
一种非常简单的方法是渲染到100幅图像,然后将图像平滑缩放到更窄的尺寸。无论您使用什么图形/开发框架,都一定会支持这样的操作。
但是,假设您的目标可能是保留某些数据质量,例如最小值和最大值。在这种情况下,对于每个纸盒,您要绘制一条深色的线条,直至最小值,然后继续使用较浅的颜色,直到最大值。或者,您可以,而不是仅仅将像素设置为平均值,而是从最小值到最大值绘制一条线。
最后,您可能希望渲染,就好像您只有77个值 - 然后目标是以某种方式将100个值转换为77.这将暗示某种插值。线性或二次插值很容易,但会增加信号的失真。理想情况下,您可能想要在问题上抛出一个sinc插值器。可以找到一个很好的列表here。对于理论背景,请查看here。