Подвыбор массива чисел

У меня есть серия из 100 целочисленных значений, которые мне нужно уменьшить / подвыбрать до 77 значений для того, чтобы вписаться в предопределенное пространство на экране. Это дает долю 77/100 значений на пиксель — не очень аккуратно.

Предполагая, что 77 является фиксированным и не может быть изменено, каковы некоторые типичные методы для подвыборки 100 чисел до 77. Я чувствую, что это будет зубчатое отображение, под которым я подразумеваю, что первое новое значение — это среднее значение [0, 1], затем следующее значение [3], затем среднее [4, 5] и т. Д. Но как мне подойти к получению шаблона для этого отображения?

Я работаю в C ++, хотя меня больше интересует техника, чем реализация.

Заранее спасибо.

2

Решение

Существуют разные способы интерполяции (см. википедия)

Линейный будет что-то вроде:

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

Другие решения

Либо, если вы уменьшаете или повышаете частоту, вы пытаетесь восстановить сигнал по несэмплированным моментам времени … поэтому вы должны сделать некоторые предположения.

Теорема о сэмплировании говорит вам, что если вы сэмплируете сигнал, зная, что он не имеет частотных составляющих более половины частоты сэмплирования, вы можете непрерывно и полностью восстанавливать сигнал в течение всего периода времени. Есть способ восстановить сигнал, используя sinc() функции (это sin(x)/x)

sinc() (в самом деле sin(M_PI/Sampling_period*x)/M_PI/x) — это функция, которая имеет следующие свойства:

  1. Его значение равно 1 для x == 0.0 и 0 для x == k*Sampling_period с k == 0, +-1, +-2, ...
  2. Он не имеет частотной составляющей более половины частоты выборки, полученной из Sampling_period,

Итак, если вы считаете сумму функций F_x(x) = Y[k]*sinc(x/Sampling_period - k) быть функцией sinc, которая равна значению выборки в позиции k и 0 при другом значении выборки и сумме по всем k в вашей выборке, вы получите наилучшую непрерывную функцию, которая имеет свойства отсутствия компонентов на частотах, превышающих половину частоты выборки, и имеет те же значения, что и набор выборок.

Сказав это, вы можете пересчитать эту функцию в любое удобное для вас положение, получая лучший способ пересчитать ваши данные.

Это, безусловно, сложный способ повторной выборки данных (у него также есть проблема отсутствия причинно-следственной связи, поэтому его нельзя реализовать в реальном времени), и в прошлом у вас было несколько методов, используемых для упрощения интерполяции. Вы должны построить все функции sinc для каждой точки выборки и сложить их вместе. Затем вы должны повторно сэмплировать результирующую функцию к новым точкам выборки и дать это в результате.

Далее приведен пример только что описанного метода интерполяции. Он принимает некоторые входные данные (in_sz выборки) и вывод интерполированных данных с помощью метода, описанного ранее (я предположил, что экстремумы совпадают, что делает N+1 образцы равны N+1 образцы, и это делает несколько запутанные вычисления (in_sz - 1)/(out_sz - 1) в коде (изменить на in_sz/out_sz если вы хотите разъяснить N samples -> M samples преобразование:

#include <math.h>
#include <stdio.h>
#include <stdlib.h>

/* normalized sinc function */
double sinc(double x)
{
x *= M_PI;
if (x == 0.0) return 1.0;
return sin(x)/x;
} /* sinc */

/* interpolate a function made of in samples at point x */
double sinc_approx(double in[], size_t in_sz, double x)
{
int i;
double res = 0.0;
for (i = 0; i < in_sz; i++)
res += in[i] * sinc(x - i);
return res;
} /* sinc_approx */

/* do the actual resampling.  Change (in_sz - 1)/(out_sz - 1) if you
* don't want the initial and final samples coincide, as is done here.
*/
void resample_sinc(
double in[],
size_t in_sz,
double out[],
size_t out_sz)
{
int i;
double dx = (double) (in_sz-1) / (out_sz-1);
for (i = 0; i < out_sz; i++)
out[i] = sinc_approx(in, in_sz, i*dx);
}

/* test case */
int main()
{
double in[] = {
0.0, 1.0, 0.5, 0.2, 0.1, 0.0,
};

const size_t in_sz = sizeof in / sizeof in[0];
const size_t out_sz = 5;
double out[out_sz];
int i;

for (i = 0; i < in_sz; i++)
printf("in[%d] = %.6f\n", i, in[i]);
resample_sinc(in, in_sz, out, out_sz);
for (i = 0; i < out_sz; i++)
printf("out[%.6f] = %.6f\n", (double) i * (in_sz-1)/(out_sz-1), out[i]);

return EXIT_SUCCESS;
} /* main */
3

Создайте 77 новых пикселей на основе средневзвешенного значения их позиций.

В качестве игрушечного примера подумайте о 3-пиксельном регистре, который вы хотите добавить к 2.

Оригинал (обозначим как многомерный массив original с RGB как [0, 1, 2]):

|----|----|----|

Подвыборка (обозначим как многомерный массив subsample с RGB как [0, 1, 2]):

|------|------|

Здесь интуитивно понятно, что первый подвыбор выглядит как 2/3 первого исходного пикселя и 1/3 следующего.

Для первого пикселя подобразца subsample[0]Вы делаете это RGB среднее значение m оригинальные пиксели, которые перекрываются, в этом случае 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] зеленый компонент второго исходного пикселя.

Имейте в виду, что для различных подвыборок вам нужно будет определить набор исходных ячеек, которые вносят вклад в подвыборку, а затем провести нормализацию, чтобы найти относительные веса каждой из них.

Существуют гораздо более сложные графические приемы, но этот прост и работает.

1

Все зависит от того, что вы хотите сделать с данными — как вы хотите их визуализировать.

Очень простой подход заключается в рендеринге в изображение шириной 100, а затем плавное масштабирование изображения до более узкого размера. Какую бы графику / среду разработки вы не использовали, она наверняка будет поддерживать такую ​​операцию.

Скажем, однако, что ваша цель может заключаться в сохранении определенных качеств данных, таких как минимумы и максимумы. В таком случае для каждой ячейки вы рисуете линию более темного цвета до минимального значения, а затем продолжаете более светлым до максимального значения. Или вы можете вместо того, чтобы просто поместить пиксель в среднее значение, нарисовать линию от минимума до максимума.

Наконец, вы можете захотеть сделать так, как если бы у вас было только 77 значений — тогда цель состоит в том, чтобы каким-то образом преобразовать 100 значений в 77. Это будет означать некоторую интерполяцию. Линейная или квадратичная интерполяция проста, но добавляет искажения к сигналу. В идеале, вы, вероятно, захотите добавить в эту задачу интерполятор sinc. Хороший список их можно найти Вот. Для теоретического фона, посмотрите Вот.

1
По вопросам рекламы [email protected]