/// <summary> /// Apply envelope filter to provided matrix. /// </summary> /// <param name="data">Matrix to be filtered.</param> public override void Transform(ref List <double[]> data) { List <Signal> Signals = new List <Signal>(); data.ForEach((Item) => { Signals.Add(Accord.Audio.Signal.FromArray(Item, SampleRate)); }); var HPFilter = new Accord.Audio.Filters.HighPassFilter(Alpha); Signals = new List <Signal>(HPFilter.Apply(Signals.ToArray())); List <double[]> Output = new List <double[]>(); Signals.ForEach((Item) => { Output.Add(Item.ToDouble()); }); data = Output; }
// THE MAIN CARDIO COMPUTATION: private double HeartComputation(Bitmap image) { // ComputeAndStorAverageRGB(image); ComputeAndStorAverageRGB(image); if (isDataReady) { //////////////////////////////// // NORMALIZE THE RGB SIGNALS BY SUBTRACTING THE MEAN: //build color matrix double[][] colors = { red, green, blue }; /////////////////////////////////// // ADD A HIGH PASS FILTERING STEP: var testFilter = new Accord.Audio.Filters.HighPassFilter(0.1f); float RC = 1 / (2 * (float)(3.142) * (float)(0.1)); float dt = 1 / (float)(30); float ALPHA = dt / (dt + RC); testFilter.Alpha = ALPHA; var floatMtx = new float[colors.Length][]; for (int i = 0; i < colors.Length; i++) { floatMtx[i] = new float[colors[i].Length]; for (int j = 0; j < colors[i].Length; j++) { floatMtx[i][j] = (float)colors[i][j]; } } Accord.Audio.Signal target = Accord.Audio.Signal.FromArray(floatMtx[0], 1, Accord.Audio.SampleFormat.Format32BitIeeeFloat); Accord.Audio.Signal target_out = testFilter.Apply(target); target_out.CopyTo(floatMtx[0]); target = Accord.Audio.Signal.FromArray(floatMtx[1], 1, Accord.Audio.SampleFormat.Format32BitIeeeFloat); target_out = testFilter.Apply(target); target_out.CopyTo(floatMtx[1]); target = Accord.Audio.Signal.FromArray(floatMtx[2], 1, Accord.Audio.SampleFormat.Format32BitIeeeFloat); target_out = testFilter.Apply(target); target_out.CopyTo(floatMtx[2]); for (int i = 0; i < floatMtx.Length; i++) { for (int j = 0; j < floatMtx[i].Length; j++) { colors[i][j] = (double)floatMtx[i][j]; } } /////////////////////////////////// /////////////////////////////////// // Z-SCORE: double[][] norm_colorsT; double[][] norm_colors; double[][] colorsT = colors.Transpose(); norm_colorsT = Accord.Statistics.Tools.ZScores(colorsT); norm_colors = norm_colorsT.Transpose(); /////////////////////////////////// /////////////////////////////////// // PERFORM ICA: var ica = new IndependentComponentAnalysis() { Algorithm = IndependentComponentAlgorithm.Parallel, Contrast = new Logcosh(), Iterations = 1000, NumberOfInputs = 3, NumberOfOutputs = 3 }; ica.Iterations = 1000000; MultivariateLinearRegression demix = ica.Learn(norm_colorsT); double[][] resultT = demix.Transform(norm_colorsT); double[][] result = resultT.Transpose(); /////////////////////////////////// /////////////////////////////////// // ADD A Low PASS FILTERING STEP: var LPFilter = new Accord.Audio.Filters.LowPassFilter(0.1f); RC = 1 / (2 * (float)(3.142) * (float)(0.1)); dt = 1 / (float)(30); ALPHA = dt / (dt + RC); testFilter.Alpha = ALPHA; var LPMtx = new float[result.Length][]; for (int i = 0; i < result.Length; i++) { LPMtx[i] = new float[result[i].Length]; for (int j = 0; j < result[i].Length; j++) { LPMtx[i][j] = (float)result[i][j]; } } target = Accord.Audio.Signal.FromArray(LPMtx[0], 30, Accord.Audio.SampleFormat.Format32BitIeeeFloat); target_out = testFilter.Apply(target); target_out.CopyTo(LPMtx[0]); target = Accord.Audio.Signal.FromArray(LPMtx[1], 30, Accord.Audio.SampleFormat.Format32BitIeeeFloat); target_out = testFilter.Apply(target); target_out.CopyTo(LPMtx[1]); target = Accord.Audio.Signal.FromArray(LPMtx[2], 30, Accord.Audio.SampleFormat.Format32BitIeeeFloat); target_out = testFilter.Apply(target); target_out.CopyTo(LPMtx[2]); /* * for (int i = 0; i < LPMtx.Length; i++) * { * for (int j = 0; j < LPMtx[i].Length; j++) * result[i][j] = (double)LPMtx[i][j]; * } */ /////////////////////////////////// /////////////////////////////////// // CALCULATE THE FFT OF ECH CHANNEL: int length = red.Length; double[] imagR = new double[length]; double[] imagG = new double[length]; double[] imagB = new double[length]; red_norm = norm_colors[0]; green_norm = norm_colors[1]; blue_norm = norm_colors[2]; ica_source_1 = result[0]; ica_source_2 = result[1]; ica_source_3 = result[2]; Accord.Math.Transforms.FourierTransform2.FFT(result[0], imagR, FourierTransform.Direction.Forward); Accord.Math.Transforms.FourierTransform2.FFT(result[1], imagG, FourierTransform.Direction.Forward); Accord.Math.Transforms.FourierTransform2.FFT(result[2], imagB, FourierTransform.Direction.Forward); double[] magR = GetMag(result[0], imagR); double[] magG = GetMag(result[1], imagG); double[] magB = GetMag(result[2], imagB); for (int i = 0; i < timeWindows / 2; i++) { red_norm_FFT[i] = magR[i]; green_norm_FFT[i] = magG[i]; blue_norm_FFT[i] = magB[i]; } /////////////////////////////////// /////////////////////////////////// // FIND THE MAX FREQUENCY AND POWER FROM THE FFTs: double[] freq = Vector.Interval((double)0, (double)(timeWindows - 1)); for (int i = 0; i < freq.Length; i++) { freq[i] = freq[i] / (double)timeWindows * FrameRate; } int MaxRedIndex; double MaxRedValue; GetMax(out MaxRedIndex, out MaxRedValue, freq, magR, 0.45, 3); int MaxGreenIndex; double MaxGreenValue; GetMax(out MaxGreenIndex, out MaxGreenValue, freq, magG, 0.45, 3); int MaxBlueIndex; double MaxBlueValue; GetMax(out MaxBlueIndex, out MaxBlueValue, freq, magB, 0.45, 3); //Get the max power if ((MaxRedValue > MaxGreenValue) && (MaxRedValue > MaxBlueValue)) { //Red is the Max HeartBeatFrequency = freq[MaxRedIndex]; } if ((MaxGreenValue > MaxRedValue) && (MaxGreenValue > MaxBlueValue)) { //Green is the Max HeartBeatFrequency = freq[MaxGreenIndex]; } if ((MaxBlueValue > MaxRedValue) && (MaxBlueValue > MaxGreenValue)) { //Blue is the Max HeartBeatFrequency = freq[MaxBlueIndex]; } /////////////////////////////////// HeartBeatFrequency = HeartBeatFrequency * 60; isDataReady = false; return(HeartBeatFrequency); } return(HeartBeatFrequency); }