Страницы

Поиск по вопросам

Показаны сообщения с ярлыком фурье. Показать все сообщения
Показаны сообщения с ярлыком фурье. Показать все сообщения

вторник, 31 марта 2020 г.

Преобразование Фурье в Pandas

#python #pandas #dataframe #scipy #фурье


Есть DataFrame примерно такого содержания:

Time     Data
95114    1012.0
96078    1108.0
97033    1132.0
98015    1076.0
...


Состоит из 100 строк, где:


Time - время измерения в микросекундах
Data - измеряемое значение. 


Мне необходимо найти ДПФ этой зависимости. Все бы ничего, только частота измерения
непостоянна. Она немного плывет со временем случайным образом. Т.е. мои потуги в духе:

xf = fftfreq(len(df['Time']),1000) # 1000 взята как примерный период измерений
i = xf > 0
yf = fft(df['Data'])


Дают немного неожиданный результат. Я так понимаю, что дело в частоте. Как правильно
ее искать? Интерполировать свой дискретный ряд и потом уже находить его ДПФ? 

В итоге мне нужно будет найти площадь между определенными частотами спектра. 
    


Ответы

Ответ 1



Можно воспользоваться методом DataFrame.resample(), чтобы преобразовать DataFrame во временной ряд с единым интервалом (в качестве единого интервала возьмем средний интервал между замерами в микросекундах) и после этого интерполировать недостающие значения. Для этого надо конвертировать df.Time в datetime dtype и установить этот столбец в качестве индекса: In [62]: freq = int(df['Time'].diff().mean()) # средняя частота измерения в микросекундах In [63]: freq Out[63]: 967 In [64]: df = (df.set_index(pd.to_datetime(df.pop('Time'), unit='us')) .resample('{}U'.format(freq)) .mean() .interpolate()) In [65]: df Out[65]: Data Time 1970-01-01 00:00:00.094766 1012.0 1970-01-01 00:00:00.095733 1108.0 1970-01-01 00:00:00.096700 1132.0 1970-01-01 00:00:00.097667 1076.0 После этого можно попробовать воспользоваться преобразованиями Фурье.

понедельник, 16 декабря 2019 г.

Получение частоты звука с микрофона

#c_sharp #аудио #фурье #fft #naudio


Есть задача получать частоту звука с микрофона для дальнейших преобразований на C#.
Подобное уже делал на Python с numpy, но тут как то не клеится...

private void write(byte[] angles, int byte_len)
{
    Complex[] _fftBuffer = new Complex[byte_len];
    var _m = (int)Math.Log(byte_len, 2.0);

    for (var n=0; n < byte_len; n++)
    {
        var r = angles[n];
        var i = 0;
        _fftBuffer[n].X = (float)(r * FastFourierTransform.HammingWindow(n, byte_len));
        _fftBuffer[n].Y = i;

    }
    FastFourierTransform.FFT(true, _m, _fftBuffer);
    float[] fft_x = new float[_fftBuffer.Length];
    for (var i=0; i<_fftBuffer.Length; i++)
    {
        fft_x[i] = Math.Abs(_fftBuffer[i].X);
    }
    int i_peak = fft_x.ToList().IndexOf(fft_x.Max());
    for (var i = 0; i < _fftBuffer.Length; i++)
    {
        fft_x[i] = (float)Math.Log(Math.Abs(_fftBuffer[i].X));
    }
    ///var i_peak = fft_x.Max();
    var i_interp = parabolic(fft_x, i_peak);

    float freq = byte_len * i_interp / angles.Length;
    Console.WriteLine("Debug stop");

    ///this.port.Write(this.first_command, 0, 8);
    ///this.port.Write(this.get_comand(0.0f, 0.0f), 0, 32);


}
private float parabolic(float[] f, int peak)
{
    var xv = 0.5f * (f[peak-1] - f[peak+1])/(f[peak-1]-2*f[peak] + f[peak+1]) + peak;

    return xv;
}


Это что на С# сделал. Сделано так, ибо так же было на Python.
В конечном итоге работает, но неправильно - частота получается одна и та же (+- пара
герц), но по идее там должны быть абсолютно другие частоты - передаем данные с помощью
звука.

Помогите разобраться, что в коде может быть не так?

UPD

Вот что получилось в итоге. Спасибо товарищу @MSDN.WhiteKnight - натолкнул на правильные
мысли.
Плюс использовался проект 
вот отсюда

выкладываю только код, который несет смысл по вытаскиванию частот звука с микрофона(МОНО).
Можно переделать на стерео - не особо сложно будет

public partial class MainWindow : Window
{
    static double Fs = 48000; // Частота дискретизации !В данной программе ТОЛЬКО
целые числа
    static double T = 1.0 / Fs; // Шаг дискретизации
    static int N; //Длина сигнала (точек)
    static double Fn = Fs / 2;// Частота Найквиста
    WaveIn waveIn;

    public MainWindow()
    {
        InitializeComponent();
    }

    void waveIn_DataAvailable(object sender, WaveInEventArgs e)
    {

        //данные из буфера распределяем в массив чтобы в нем они были в формате ?PCM?
        byte[] buffer = e.Buffer;
        N = buffer.Length;
        int bytesRecorded = e.BytesRecorded;
        Complex[] sig = new Complex[bytesRecorded / 2];
        for (int i = 0, j = 0; i < e.BytesRecorded; i += 2, j++)
        {
            short sample = (short)((buffer[i + 1] << 8) | buffer[i + 0]);
            sig[j] = sample / 32768f;
        }

        Fourier.Forward(sig, FourierOptions.Matlab);
        // обнуляем спектр на небольших частотах (там постоянная составляющая и вообще
много помех)
        for (int i = 0; i < 35 * sig.Length / Fn; i++)
        {
            sig[i] = 0;
        }

        write(sig);

    }
    //Окончание записи
    private void waveIn_RecordingStopped(object sender, EventArgs e)
    {
        waveIn.Dispose();
        waveIn = null;
    }

    private void start_button_Click(object sender, RoutedEventArgs e)
    {
        this.waveIn = new WaveIn();
        this.waveIn.DeviceNumber = 0;
        this.waveIn.DataAvailable += this.waveIn_DataAvailable;
        this.waveIn.RecordingStopped += this.waveIn_RecordingStopped;
        this.waveIn.WaveFormat = new WaveFormat((int)Fs, 1);
        this.waveIn.StartRecording();
        Start_button.IsEnabled = false;
        Stop_button.IsEnabled = true;
        this.log_box("старт записи");
    }


    private void stop_Button_Click(object sender, RoutedEventArgs e)
    {
        this.stop_recording();
    }

    private void stop_recording()
    {
        this.waveIn.StopRecording();
        Start_button.IsEnabled = true;
        Stop_button.IsEnabled = false;
        this.log_box("конец записи");
    }


    private void log_box(string message)
    {
        Log_Box.AppendText("\n" + message);
        Log_Box.ScrollToEnd();
    }

    private void write(Complex[] signal)
    {
        PointPairList list1 = new PointPairList();
        int max_index = 0;
        double freq = 0;
        double K = signal.Length / 2;
        for (int i = 0; i < K; i++)
        {
            list1.Add(i * Fn / K, Complex.Abs(signal[i]) / N * 2);
        }

        foreach (ZedGraph.PointPair i in list1)
        {
            if (i.Y > list1[max_index].Y)
            {
                max_index = list1.IndexOf(i);
            }
        }
        freq = list1[max_index].X;

        string s = freq.ToString();
        log_box(s);


    }

}


что использовалось...
NAudio - для получения потока звука с микрофона

MathNET - Фурье

ZedGraph - как переходник для работы с сигналом после преобразования Фурье - его
можно убрать, но в моем случае был удобен.
    


Ответы

Ответ 1



Ваш код будет работать нормально, только если на вход подать данные определенного формата: моно, 1 байт на сэмпл, определенная частота дискретизации и т.п. Кроме того, он не учитывает несколько деталей: из результата БПФ нужно отбросить первое значение ("постоянная составляющая") и вторую половину значений (которая не несет полезной информации); количество сэмплов должно быть в степени 2. Лучше написать код, который может корректно обрабатывать разные форматы, для этого возьмем за основу класс SampleAggregator из примера на Github: using System; using System.Collections.Generic; using System.Text; using System.Diagnostics; using NAudio.Dsp; namespace WindowsFormsTest1 { public class SampleAggregator { // volume public event EventHandler MaximumCalculated; private float maxValue; private float minValue; public int NotificationCount { get; set; } public Complex[] FftBuffer { get { return this.fftBuffer; } } int count; // FFT public event EventHandler FftCalculated; public bool PerformFFT { get; set; } private Complex[] fftBuffer; private FftEventArgs fftArgs; private int fftPos; private int fftLength; private int m; public SampleAggregator(int fftLength = 1024) { if (!IsPowerOfTwo(fftLength)) { throw new ArgumentException("FFT Length must be a power of two"); } this.m = (int)Math.Log(fftLength, 2.0); this.fftLength = fftLength; this.fftBuffer = new Complex[fftLength]; this.fftArgs = new FftEventArgs(fftBuffer); } bool IsPowerOfTwo(int x) { return (x & (x - 1)) == 0; } public void Reset() { count = 0; maxValue = minValue = 0; } public void Add(float value) { if (PerformFFT) { fftBuffer[fftPos].X = (float)(value * FastFourierTransform.HammingWindow(fftPos, fftBuffer.Length)); fftBuffer[fftPos].Y = 0; fftPos++; if (fftPos >= fftBuffer.Length) { fftPos = 0; // 1024 = 2^10 FastFourierTransform.FFT(true, m, fftBuffer); if(FftCalculated != null) FftCalculated(this, fftArgs); } } maxValue = Math.Max(maxValue, value); minValue = Math.Min(minValue, value); count++; if (count >= NotificationCount && NotificationCount > 0) { if (MaximumCalculated != null) { MaximumCalculated(this, new MaxSampleEventArgs(minValue, maxValue)); } Reset(); } } } public class MaxSampleEventArgs : EventArgs { [DebuggerStepThrough] public MaxSampleEventArgs(float minValue, float maxValue) { this.MaxSample = maxValue; this.MinSample = minValue; } public float MaxSample { get; private set; } public float MinSample { get; private set; } } public class FftEventArgs : EventArgs { [DebuggerStepThrough] public FftEventArgs(Complex[] result) { this.Result = result; } public Complex[] Result { get; private set; } } } Тогда для определения частоты порции из первых 1024 сэмплов Wav-файла можно использовать вот такой код: using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Windows.Forms; using NAudio; using NAudio.Wave; using NAudio.Wave.SampleProviders; namespace WindowsFormsTest1 { public partial class Form1 : Form { private float parabolic(float[] f, int peak) { if (peak == 0) return f[0]; var xv = 0.5f * (f[peak - 1] - f[peak + 1]) / (f[peak - 1] - 2 * f[peak] + f[peak + 1]) + peak; return xv; } public Form1() { InitializeComponent(); } void PrintFrequency(float[] samples, int n_samples, WaveFormat fmt) { textBox1.Text = ""; for (int i = 0; i < fmt.Channels; i++) { SampleAggregator aggregator = new SampleAggregator(n_samples); aggregator.PerformFFT = true; int j; float f; //выделяем данные одного канала for (j = 0; j < n_samples; j++) { int index = (j * fmt.Channels) + i; f = samples[index]; aggregator.Add(f); } float[] fft_x = new float[aggregator.FftBuffer.Length / 2]; //только первая половина БПФ имеет смысл for (j = 0; j < fft_x.Length; j++) { float real = aggregator.FftBuffer[j].X; float imag = aggregator.FftBuffer[j].Y; fft_x[j] = (float)Math.Sqrt(real * real + imag * imag); //получаем амплитуду } fft_x[0] = 0.0f;//избавляемся от постоянной составляющей int i_peak = fft_x.ToList().IndexOf(fft_x.Max()); for (j = 0; j < fft_x.Length; j++) { fft_x[j] = (float)Math.Log(Math.Abs(aggregator.FftBuffer[j].X)); } var i_interp = parabolic(fft_x, i_peak); float freq = fmt.SampleRate * i_interp / (float)n_samples; textBox1.Text += ("Channel " + i.ToString() + ": " + freq.ToString() + " Hz" + Environment.NewLine); } } private void button1_Click(object sender, EventArgs e) { WaveStream readerStream = new WaveFileReader("c:\\Test\\sound_01.wav"); WaveStream pcmStream; WaveStream stream; //создаем поток в PCM-формате if (readerStream.WaveFormat.Encoding != WaveFormatEncoding.Pcm) { pcmStream = WaveFormatConversionStream.CreatePcmStream(readerStream); stream = new BlockAlignReductionStream(pcmStream); } else { pcmStream = readerStream; stream = readerStream; } float[] samples; const int N_SAMPLES = 1024; //количество сэмплов для спектрального анализа ISampleProvider prov; using(stream) using(readerStream) using (pcmStream) { prov = stream.ToSampleProvider(); samples = new float[N_SAMPLES * prov.WaveFormat.Channels]; int res = prov.Read(samples, 0, N_SAMPLES * prov.WaveFormat.Channels); if (res < N_SAMPLES * prov.WaveFormat.Channels) throw new Exception("Not enough data"); } PrintFrequency(samples,N_SAMPLES,prov.WaveFormat); } } }

среда, 11 декабря 2019 г.

Умножение больших чисел при помощи дискретного преобразования Фурье

#cpp #алгоритм #преобразование #фурье


Немного теории. Дискретное преобразование Фурье - это линейное преобразование, которое
задается матрицей Вандермонда. Матрица состоит из степеней примитивного корня из единицы
степени n, где n - длина векторов и размерность квадратной матрицы. Проще показать,
как она строится, чем описывать словами.



Матрица обратного преобразования порождается степенями элемента, обратного к выбранному
примитивному корню из единицы. 

Преобразование Фурье над конечным числовым полем почему-то непопулярно у кодеров
в Роиссе, но оно есть и используется в криптографии. Разница в том, что корень из единицы
извлекается не в комплексном поле, а в поле классов вычетов. Остальное все то же самое.

На свёртку можно смотреть как на операцию умножения многочленов с коэффициентами
из поля или конечного кольца классов вычетов. Если применить нормализацию (перекидывать
перенос при переполнении разрядов), то получается умножение длинных чисел. Как я понял,
свёртка и преобразование Фурье достаточно умны, чтобы при умножении чисел расширять
конечное поле, если в нем не хватает цифр. Тут надо сделать важное пояснение примером.

Хотим найти преобразование Фурье от вектора (4, 3, 2, 1) над числовым полем Галуа
GF(5) характеристики 5. Матрица Вандермонда порождается примитивным корнем этого поля,
т.е. двойкой. 

Замечание: не всякий элемент, взаимно простой с модулем, по которому строится поле,
является примитивным корнем. Русская педивикия врет. Например, степени двойки не покроют
все элементы поля GF(7). 

В результате действия этой матрицей на вектор (4, 3, 2, 1) получается вектор (0,
1, 2, 3). Но что, если мы захотим найти преобразование Фурье от вектора (7, 1, 7, 1)?
В поле GF(5) нет элемента 7, но есть класс эквивалентности [2], содержащий семерку.
Как в этом случае отработает преобразование?

Аналогичная ситуация возникнет, если будем умножать числа при помощи этих преобразований.
Например, умножить число 7777 (вектор (7, 7, 7, 7)) на себя. Здесь снова используется
поле GF(5), в котором опять нет семерки.

Свёртка работает так: дополняем два данных вектора нулями (их длина при этом увеличивается
в два раза), применяем к ним прямое преобразование Фурье, два полученных вектора умножаем
почленно и к результату применяем обратное преобразование Фурье. Эта операция работает
как умножение двух многочленов с заданными коэффициентами из поля.

Пример. Найдем свертку (2, 1) и (1, 1). Дополним векторы нулями, получим a' = (2,
1, 0, 0) и b' = (1, 1, 0, 0). Применим к ним прямое преобразование: F(a') = (3, 4,
1, 0) и F(b') = (2, 3, 0, 4). Умножим последние векторы почленно: (1, 2, 0, 0). Применим
к полученному вектору обратное преобразование: (2, 3, 1, 0).

Моя реализация преобразований Фурье, свёртки и умножения длинных чисел:

#include 
#include 

// Возведение a в степень b по модулю p
int powmod (int a, int b, int p)
{
    int res = 1;
    while (b)
        if (b & 1)
            res = int ((long long) res * a % p),  --b;
        else
            a = int ((long long) a * a % p),  b >>= 1;
    return res;
}

// Вычисление обратного к a элемента по модулю n
int inverse(int a, int n)
{
    int b0 = n, t, q;
    int x0 = 0, x1 = 1;
    if (n == 1) return 1;
    while (a > 1) {
        q = a / n;
        t = n, n = a % n, a = t;
        t = x0, x0 = x1 - q * x0, x1 = t;
    }
    if (x1 < 0) x1 += b0;
    return x1;
}

// Вычисление примитивного корня числового поля
// (Стандартный DFT использует комплексные числа, поэтому изменим алгоритм для работы
в Zp)
// Ограничение: p - простое
int generator (int p)
{
    std::vector fact;
    int phi = p - 1,  n = phi;
    for (int i = 2; i * i <= n; ++i)
        if (n % i == 0)
        {
            fact.push_back (i);
            while (n % i == 0)
                n /= i;
        }
    if (n > 1)
        fact.push_back (n);

    for (int res = 2; res <= p; ++res) {
        bool ok = true;
        for (size_t i = 0; i < fact.size() && ok; ++i)
            ok &= powmod (res, phi / fact[i], p) != 1;
        if (ok)  return res;
    }
    return -1;
}

// Реализация прямого DFT над Zp
// Принимает вектор длины n, эта длина используется при вычислении
// примитивного корня поля
// Вычисления приводятся по mod (n + 1), т.к. длина вектора на 1 меньше p,
// где p: Zp
std::vector forward_dft (std::vector& a)
{
    std::vector result;
    int prim_root = generator (a.size());   // Корень степени n из единицы
    for (int i = 0; i < a.size(); i++)
    {
        int sum   = 0;
        int power = 0;
        for (int j = 0; j < a.size(); j++)
        {
            int power_of_root = powmod (prim_root, power, a.size() + 1);
            sum   += power_of_root * a[j];  // Накапливаем сумму произведений элементов
строки матрицы на вектор
            power += i;                     // Увеличиваем степень, в которую возводится
примитивный корень из единицы
        }
        result.push_back(sum % (a.size() + 1)); // Набрали сумму, приводим по mod
p, p = длина вектора + 1
    }
    return result;
}


std::vector inversed_dft (std::vector& a)
{
    std::vector result;
    int prim_root = generator (a.size());   // Корень степени n из единицы
    int inv_prim_root = inverse (prim_root, a.size() + 1);  // Обратный к найденному
примитивному корню
    int inv_n         = inverse (a.size(), a.size() + 1);   // Обратный к n по mod
(n + 1)
    for (int i = 0; i < a.size(); i++)
    {
        int sum   = 0;
        int power = 0;
        for (int j = 0; j < a.size(); j++)
        {
            int power_of_inv_root = powmod (inv_prim_root, power, a.size() + 1);
            sum   += inv_n * power_of_inv_root * a[j];  // Накапливаем сумму произведений
элементов строки матрицы на вектор
            power += i;                         // Увеличиваем степень, в которую
возводится примитивный корень из единицы
        }
        result.push_back(sum % (a.size() + 1)); // Набрали сумму, приводим по mod
p, p = длина вектора + 1
    }
    return result;
}

// Свертка двух векторов при помощи дискретного преобразования Фурье
std::vector convolution (std::vector a, std::vector b)
{
    a.insert(a.end(), a.size(), 0);
    b.insert(b.end(), b.size(), 0);

    a = forward_dft(a);
    b = forward_dft(b);

    std::vector result(a.size(), 0);
    for(int i = 0; i < result.size(); i++)
        result[i] = a[i] * b[i];

    result = inversed_dft(result);

    return result;
}

// Умножение двух больших чисел
std::vector multiply (std::vector a, std::vector b)
{
    std::vector result = convolution(a, b);

    // Нормализация, выполнение переносов
    int carry = 0;
    for (int i = 0; i < result.size(); i++)
    {
        result[i] += carry;
        carry = result[i] / 10;
        result[i] %= 10;
    }

    return result;
}

int main()
{
    int a[] = {1, 2, 1, 2, 1, 2, 1, 2};
    int b[] = {7, 5, 7, 5, 7, 5, 7, 5};

    std::vector u(std::begin(a), std::end(a));
    std::vector v(std::begin(b), std::end(b));

    std::vector result = multiply(u, v);
    for(int i = 0; i < result.size(); i++)
        std::cout << result[i] << " ";

    /*std::vector u(std::begin(a), std::end(a));
    std::vector v(std::begin(b), std::end(b));

    std::vector result = convolution(u, v);
    for(int i = 0; i < result.size(); i++)
        std::cout << result[i] << " ";*/


    /*int a[] = {4, 3, 2, 1};
    std::vector v(std::begin(a), std::end(a));

    std::vector result = forward_dft(v);

    std::cout << "[DEBUG]: Forward DFT" << std::endl;
    for(int i = 0; i < result.size(); i++)
        std::cout << result[i] << " ";
    std::cout << std::endl;

    result = inversed_dft(result);

    std::cout << "[DEBUG]: Inversed DFT" << std::endl;
    for(int i = 0; i < result.size(); i++)
        std::cout << result[i] << " ";*/
}


Умножение длинных чисел в функции main работает неправильно. Сначала я думал, что
это связано с тем, что алгоритм работает над конечным полем, в котором нет некоторых
"цифр" большого числа. Но видно, что при умножении чисел 12121212 на 75757575 используется
поле достаточного размера, чтобы содержать там соответствие для цифры 7. При возведении
числа 12 в квадрат алгоритм работает почти правильно, т.е. получается вектор (1, 4,
4, 0), но возникает лишний ноль из-за размерности векторов и дополнения нулями. Где
я ошибся?
    


Ответы

Ответ 1



У вас в программе вообще отсутствует поиск простого числа, в поле которого дальше идёт дискретное преобразование Фурье - это довольно странно. Я предположил, что вы считаете, что размер массива плюс единица является простым числом (что в вашем примере действительно так - 2*8+1=17 - простое). Далее у вас неконсистентно используется функция generator - объявлена она с параметром-простым числом p, а вызывается от a.size() (что, по моему предположению, является p-1). При этом, что забавно, первообразный корень тоже находится - он существует по в том числе по модулям, являющимися степенями двойки. Последняя и фатальная проблема заключается в том, что модуля 17 недостаточно для умножения чисел длины 8 по основанию 10. При умножении чисел мы переходим к умножению многочленов (например, 4321 переходит в многочлен 4x^3+3*x^2+2*x+1), потом умножаем многочлены в поле, а потом превращаем многочлен обратно в число. Если в процессе умножения хотя бы один коэффициент многочлена "переполнился" (т.е. стал больше или равен модуля), то мы всё получим корректный результат умножения многочленов, но он уже не будет соответствовать корректному числу. Например, умножая 4321 на 321 (т.е. (4x^3+3*x^2+2*x+1)*(3*x^2+2*x+1)) мы получим многочлен 12*x^5+17*x^4+16*x^3+10*x^2+4*x+1, что при подстановке x=10 даёт как раз число 1387041. Однако если известны коэффициенты многочлена лишь по модулю 17, то коэффициент при x^4 зануляется и становится невозможно восстановить, чему он был равен на самом деле. Вам следует выбирать поле достаточно большого размера, чтобы при перемножении двух многочленов коэффициенты результата не превосходили модуль.

воскресенье, 8 декабря 2019 г.

Какие есть алгоритмы шифрования изображений, устойчивые к трансформации?

#фурье #fft #изображения #wavelet #шифрование


Какие есть алгоритмы шифрования изображений, устойчивые к изменению размера изображения,
поворотам на углы, кратные 90 градусам?
Т.е. зашифровал исходное изображение - оно на себя не похоже, набор узоров, загрузил
на фотохостинг, где его в т.ч. уменьшили. Взял уменьшенный вариант, и тем же ключом
расшифровал в уменьшенную копию исходной картинки. Есть такие решения?
В идеале — вообще зашифровали - распечатали - сфотографировали на мобильник распечатку
- дешифровали в исходное, пусть такого же уменьшенного разрешения и плюс искажения
перспективы. Т.е. решение, не привязанное жестко к пикселам, и к точным значениям цветов/яркостей.
Upd. как шаг к анонимности интернетов в эпоху тотального контроля государств и корпораций,
имеет смысл добиваться такого вида зашифрованного изображения, что автоматическими
методами сложно провести его связь с исходником. Т.е. например, гистограмма зашифрованного
никак не должна кореллировать с гистограммой исходника. Например, если порезать картинку
на блоки и переставить их местами, гистограмма никак не изменится. Если канал инвертнуть,
гистограмма его просто отзеркалится. Поэтому, повторю, интересно услышать тех, кто
работал с FFT (быстрое преобразование Фурье) и вейвлетами.    


Ответы

Ответ 1



UPD [2013-02-07] Новый алгоритм «Chan» Не оставляет меня в покое эта тема. Написал новый алгоритм шифрования. Алгоритм работает очень долго, посему просьба не тестировать на больших картинках и набраться терпения: кнопки «Encrypt» и «Decrypt» понимают с первого раза, не стреляйте в них очередью. Примеры: Оригинал Зашифрованное изображение Расшифрованное изображение Расшифрованное с неверным паролем Основан на преобразовании цветов пикселей, но работает весьма неплохо, на мой взгляд. Недостатки: шифрование слишком слабое; перебо́ров за 10–20 можно подобрать такой пароль, который даст представление о содержании изображения (хотя цвета могут быть искажены) JPEG-компрессия сказывается на расшифрованном изображении (появляется рябь), поэтому на тестовой странице я выдаю результат в PNG очень много коллизий ключей очень медленно, необходимо оптимизировать Положительные черты: устойчивость к любым трансформациям (кроме цвета), будь то поворот/разворот или даже посторонние данные, например: Исходное: зашифрованная ранее картинка находится на нормальной (к примеру, фото плаката с изображением зашифрованной фотографии) Расшифрованное: зашифрованная картинка «распаковалась» Есть идея добавить свойство (bool) loseless, в зависимости от которого алгоритм и, соответственно, результат, будет меняться: при loseless = on – будет работать как сейчас; при loseless = off – шифрование будет значительно надежнее, но с потерей двух цветов: 0xFFFFFF станет 0xFFFFFE, а 0x000000 – 0x000001 (то есть, и в зашифрованном и в дешифрованном абс. белый и абс. черный будут отсутствовать). Или можно не заморачиваться и прописать loseless = off как единственный вариант. @sergiks, а у тебя как дела с этой задачей? ----------------------------------------------------------------------------------------- UPD [2013-01-30] Новая версия алгоритма «мозаика» Доделал вот прототип: http://image.lotoflot.com/mosaic_crypt.php Выдерживает повороты кратные 90 град., но с изменением размера беда: очень сильные искажения после дешифровки. Удачный пример Оригинал Зашифрованное изображение Расшифрованное изображение Лавина хорошая благодаря md5. Ключ внутри функции раскладывается на составляющие, каждый из которых хешируется. Для нормальной работы нужен массивный набор данных (а не 2-3 символа), поэтому решил не изобретать и подключить md5. Параметр Pieces определяет, на сколько кусков в обоих направлениях (X, Y) будет порезана картинка. Чем больше значение, тем больше блоков. Обычно лучше устанавливать значение в диапазоне 10—30 для картинок размера 300—2000 px. Я как-то давно на PHP начал писать класс-прослойку для GD. Так вот эти функции шифровки/дешифровки я запихнул в класс расширения этой прослойки, так что код будет слегка запутанным. Но если все же заинтересует, могу поделиться.

Ответ 2



Конкретных алгоритмов не скажу, но наверняка они есть. Наверное надо копать в сторону именно графической шифровки, к примеру поставить точки которые организуют квадрат чтобы уйти от зависимости от ориентации картинки, и внутри этого генерировать данные которые представляют исходную картинку. самое тупое - например точка 2x2 или 3x3 - 1, нет такой точки - 0. Можно наверное более сложно придумать - яркая точка начала, от неё рисовать примитивы - линия под углом - определённый набор битов (например угол задаётся исходным куском битов, цвет каждой следующей линии - следующая пачка данных) ну и т.д. Ваша задача - графически представить нужные вам данные - как - простор для фантазии. Так же можно использовать тупо набор известных вам однозначно обратимых фильтрах (сдвиги, повороты и т.д.) которые Вы применяете в определённом порядке, а для расшифровки - в обратном (например картинку сдвигает на 10 пикселов, поворачиваете на 15 градусов, сдвигаете на 3 пиксела вниз, инвертируете цвета, сдвигаете цвета на 20, меняете каналы местами и т.д.).

Ответ 3



Я бы посоветовал копать в сторону стеганографических трюков с изображениями, когда модифицируется наименее значимый бит (LSB) пикселя или что-то подобное. Обзор некоторых из таких методов здесь Наиболее перспективный для вас метод на мой взгляд это redundant pattern encoding, то есть когда шифровка размещается не по всему изображению, а дублируется в нескольких частях (pattern), так что при обрезке изображения останутся кодированные куски из которых можно будет восстановить сообщение. Теперь рассмотрим способ восстановления исходного шифросообщения после изменения размера изображения (паттерна). Здесь может помочь один из алгоритмов избыточного кодирования, например метод Хамминга или что-то подобное. Благо таких способов довольно много, надо просто задаться процентом сколько бит надо уметь восстанавливать из потерянных - это чуть ли не целая отрасль математики.

Ответ 4



Почему вы так быстро отказались от шифрование данных каждого пикселя независимо друг от друга? Изменения размеров и артефакты сжатия такому методу не страшны. Я, обдумывая ту же идею, склонен предполагать, что можно найти достаточно устойчивый (к взлому) шифр. Но так как в области криптографии моих знаний ноль, с этим вопросом я и пришёл сюда.

суббота, 8 июня 2019 г.

Преобразование Фурье в Pandas

Есть DataFrame примерно такого содержания:
Time Data 95114 1012.0 96078 1108.0 97033 1132.0 98015 1076.0 ...
Состоит из 100 строк, где:
Time - время измерения в микросекундах Data - измеряемое значение.
Мне необходимо найти ДПФ этой зависимости. Все бы ничего, только частота измерения непостоянна. Она немного плывет со временем случайным образом. Т.е. мои потуги в духе:
xf = fftfreq(len(df['Time']),1000) # 1000 взята как примерный период измерений i = xf > 0 yf = fft(df['Data'])
Дают немного неожиданный результат. Я так понимаю, что дело в частоте. Как правильно ее искать? Интерполировать свой дискретный ряд и потом уже находить его ДПФ?
В итоге мне нужно будет найти площадь между определенными частотами спектра.


Ответ

Можно воспользоваться методом DataFrame.resample(), чтобы преобразовать DataFrame во временной ряд с единым интервалом (в качестве единого интервала возьмем средний интервал между замерами в микросекундах) и после этого интерполировать недостающие значения.
Для этого надо конвертировать df.Time в datetime dtype и установить этот столбец в качестве индекса:
In [62]: freq = int(df['Time'].diff().mean()) # средняя частота измерения в микросекундах
In [63]: freq Out[63]: 967
In [64]: df = (df.set_index(pd.to_datetime(df.pop('Time'), unit='us')) .resample('{}U'.format(freq)) .mean() .interpolate())
In [65]: df Out[65]: Data Time 1970-01-01 00:00:00.094766 1012.0 1970-01-01 00:00:00.095733 1108.0 1970-01-01 00:00:00.096700 1132.0 1970-01-01 00:00:00.097667 1076.0
После этого можно попробовать воспользоваться преобразованиями Фурье.