子采样数组

时间:2015-08-05 15:23:28

标签: c++ downsampling

我有一系列100个整数值,我需要将其减少/子采样到77个值,以便适应屏幕上的预定义空间。这给出了每像素77/100值的一小部分 - 不是很整洁。

假设77是固定的并且无法更改,那么将100个数字二次采样到77的典型技术是什么。我感觉它将是一个锯齿状的映射,我的意思是第一个新值是平均值[0,1]然后下一个值是[3],然后是平均[4,5]等。但是我该如何获得这个映射的模式呢?

我在C ++工作,虽然我对这项技术比对实现更感兴趣。

提前致谢。

4 个答案:

答案 0 :(得分:3)

如果您进行降采样或过采样,您将尝试在非采样时间点重建信号......所以您必须做出一些假设。

采样定理告诉您,如果您采样信号,知道其频率分量超过采样频率的一半,则可以在整个定时周期内连续完全恢复信号。有一种方法可以使用sinc()函数重建信号(这是sin(x)/x

sinc()(确实是sin(M_PI/Sampling_period*x)/M_PI/x)是一个具有以下属性的函数:

  1. x == 0.0的值为1,x == k*Sampling_period的{​​{1}}的值为0
  2. k == 0, +-1, +-2, ...派生的sampling_frequency的一半以上没有频率成分。
  3. 因此,如果您认为函数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;
}

Live example

答案 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