protected override float PerPixelOperation(Matrix input, int row, int column)
        {
            float signalMean1;
            float signalVariance1;
            float signalMean2;
            float signalVariance2;
            float noiseVariance;

            //calculate signal mean 1 and signal variance 1

            SignalMeanInfo signalMeanInfo = new SignalMeanInfo();

            DoWindowPass(input, row, column, InternalCalcSignalMean, signalMeanInfo);
            signalMean1 = signalMeanInfo.sum / signalMeanInfo.count;


            SignalVarianceInfo signalVarianceInfo = new SignalVarianceInfo();

            signalVarianceInfo.signalMean = signalMean1;
            DoWindowPass(input, row, column, InternalCalcSignalVariance, signalVarianceInfo);

            signalVariance1 = signalVarianceInfo.sum / (signalVarianceInfo.count - 1);

            //calculate z and eta and signal mean 2

            ZtmmseInfo info1 = new ZtmmseInfo(WindowSize);

            info1.mean  = signalMean1;
            info1.stdev = (float)Math.Sqrt(signalVariance1);
            DoWindowPass(input, row, column, CalcEta, info1);

            signalMean2 = info1.sum / info1.eta;

            //calculate signal variance 2
            info1.sum  = 0;
            info1.mean = signalMean2;
            DoWindowPass(input, row, column, CalcSignalVariance2, info1);

            signalVariance2 = info1.sum / (info1.eta - 1);

            //calculate noise variance

            noiseVariance = CalculateNoiseVariance();


            return(CalculateFinalValue(input, row, column, signalMean2, signalVariance2, noiseVariance));
        }
        protected virtual void CalcSignalVariance2(float value, int row, int column, int rowWithinWindow, int columnWithinWindow, ZtmmseInfo info)
        {
            float z = info.z[rowWithinWindow, columnWithinWindow];

            if (z <= Zeta)
            {
                value    -= info.mean;
                value    *= value;
                info.sum += value;
            }
        }
        protected virtual void CalcEta(float value, int row, int column, int rowWithinWindow, int columnWithinWindow, ZtmmseInfo info)
        {
            float z = Math.Abs((value - info.mean) / info.stdev);

            info.z[rowWithinWindow, columnWithinWindow] = z;

            if (z <= Zeta)
            {
                info.eta++;
                info.sum += value;
            }
        }