コード例 #1
0
        static Frequency_4x4 DCT2D_4x4(Bitmap b)
        {
            Frequency_4x4 f = new Frequency_4x4();
            int x = 0;
            int y = 0;
            int i = 0;
            int j = 0;

            double summand = 0;

            for (y = 0; y < 4; y++)
            {
                for (x = 0; x < 4; x++)
                {
                    for (i = 0; i < 4; i++)
                    {
                        for (j = 0; j < 4; j++)
                        {
                            summand += (b.GetPixel(j, i).ToArgb() * Math.Cos(Math.PI * y * ((2 * i) + 1) / 8) * Math.Cos(Math.PI * x * ((2 * j) + 1) / 8));
                        }
                    }
                    //summand = 0.5 * summand;
                    if (x == 0) summand *= (0.5);
                    if (y == 0) summand *= (0.5);
                    if (x > 0) summand *= (1.0 / Math.Sqrt(2));
                    if (y > 0) summand *= (1.0 / Math.Sqrt(2));
                    f.frequencies[x, y] = summand;
                    summand = 0;
                }
            }
            return f;
        }
コード例 #2
0
        static Bitmap iDCT2D_4x4(Frequency_4x4 f)
        {
            Bitmap b = new Bitmap(4, 4);
            int x = 0;
            int y = 0;
            int i = 0;
            int j = 0;

            double summand = 0;
            double temp = 0;
            for (y = 0; y < 4; y++)
            {
                for (x = 0; x < 4; x++)
                {
                    for (i = 0; i < 4; i++)
                    {
                        for (j = 0; j < 4; j++)
                        {
                            temp = f.frequencies[j, i] * Math.Cos(Math.PI * i * ((2 * y) + 1) / 8) * Math.Cos(Math.PI * j * ((2 * x) + 1) / 8);
                            if (i == 0) temp *= (0.5);
                            if (j == 0) temp *= (0.5);
                            if (i > 0) temp *= (1.0 / Math.Sqrt(2));
                            if (j > 0) temp *= (1.0 / Math.Sqrt(2));
                            //summand *= 0.5;
                            summand += temp;
                        }
                    }
                    //summand = 0.5 * summand;

                    b.SetPixel(x, y, Color.FromArgb((int)Math.Round(summand)));
                    summand = 0;
                }
            }
            return b;
        }
コード例 #3
0
        /// <summary>
        /// Retrieves the bit from within the 8 dimensional vector
        /// </summary>
        /// <param name="f"></param>
        /// <returns></returns>
        static byte vector_Retrieve8D(Frequency_4x4 f, int T)
        {
            byte bit = 0;
            double distance = Math.Pow(f.frequencies[0, 0], 2) + Math.Pow(f.frequencies[1, 0], 2) + Math.Pow(f.frequencies[0, 1], 2) + Math.Pow(f.frequencies[0, 2], 2) + Math.Pow(f.frequencies[1, 1], 2) + Math.Pow(f.frequencies[2, 0], 2) + Math.Pow(f.frequencies[3, 0], 2) + Math.Pow(f.frequencies[2, 1], 2);
            distance = Math.Sqrt(distance);
            double distance_prime = distance / (double)T;
            distance_prime = distance_prime - Math.Round(distance_prime);
            if (distance_prime >= 0)
                bit = 1;
            else
                bit = 0;

            return bit;
        }
コード例 #4
0
        /// <summary>
        /// Embed the bit within the 8 dimensional vector
        /// </summary>
        /// <param name="f"></param>
        /// <returns></returns>
        static Frequency_4x4 vector_Embed8D(Frequency_4x4 f, int T, byte bit)
        {
            double distance = Math.Pow(f.frequencies[0, 0], 2) + Math.Pow(f.frequencies[1, 0], 2) + Math.Pow(f.frequencies[0, 1], 2) + Math.Pow(f.frequencies[0, 2], 2) + Math.Pow(f.frequencies[1, 1], 2) + Math.Pow(f.frequencies[2, 0], 2) + Math.Pow(f.frequencies[3, 0], 2) + Math.Pow(f.frequencies[2, 1], 2);
            distance = Math.Sqrt(distance);
            double distance_prime = Math.Round(distance / (double)T);
            if (bit > 0)
                distance_prime += 0.25;
            else
                distance_prime -= 0.25;
            distance_prime = distance_prime * (double)T;
            double coeff = distance_prime / distance;
            f.frequencies[0, 0] *= coeff;
            f.frequencies[1, 0] *= coeff;
            f.frequencies[0, 1] *= coeff;
            f.frequencies[0, 2] *= coeff;
            f.frequencies[1, 1] *= coeff;
            f.frequencies[2, 0] *= coeff;
            f.frequencies[3, 0] *= coeff;
            f.frequencies[2, 1] *= coeff;

            return f;
        }
コード例 #5
0
        /// <summary>
        /// Retrieves a byte[] within the transform domain of the video and returns the byte[].
        /// </summary>
        /// <param name="b"></param>
        /// <returns></returns>
        static byte[] transform_Retrieve(Bitmap b, byte[] bytes, int T, int rep)
        {
            double[,] block = new double[4, 4];

            if (loop) pos = 0;

            if (loop) pos_bit = 0;

            if (loop) pos_rep = 0;

            Bitmap src = new Bitmap(4, 4);
            int x = 0;
            int y = 0;
            byte bit = 0;
            byte avg = 0;
            Frequency_4x4 f = new Frequency_4x4();
            byte[] newbytes = new byte[bytes.Length];

            for (; ; pos++)
            {
                if (pos == bytes.Length && loop == true) return newbytes;
                if (pos == bytes.Length) pos = 0;

                for (pos_bit = 0; pos_bit < 8; pos_bit++)
                {
                    for (pos_rep = 0; pos_rep < rep; pos_rep++)
                    {
                        src = b.Clone(new Rectangle(x, y, 4, 4), b.PixelFormat);
                        f = DCT2D_4x4(src);
                        //block = Array2DFromBitmap(src);

                        //int alpha = arithmetic_Difference(block, matrix_SGN(block));
                        //if (alpha <= ((2*T) + G) && alpha >= -((2*T)+ G)) //see my frustration above at Alavianmehr et. als' "original" work
                        //{
                        avg += vector_Retrieve8D(f, T);

                        //}
                        //if (alpha > ((2 * T) + G) || alpha < -((2 * T) + G)) k--;

                        x += 4;
                        if (x >= b.Width) { y += 4; x = 0; }
                        if (y >= b.Height)
                            return newbytes;
                    }
                    bit = (byte)Math.Round((double)avg / (double)rep);
                    newbytes[pos] = (byte)(newbytes[pos] >> 1);
                    newbytes[pos] += (byte)(128 * bit);
                    avg = 0;
                }
            }
            //return newbytes;
        }
コード例 #6
0
        /// <summary>
        /// Embeds a byte[] within the transform domain of the video and returns the bitmap.
        /// </summary>
        /// <param name="b"></param>
        /// <returns></returns>
        static Bitmap transform_Embed(Bitmap b, int T, byte[] bytes, int rep)
        {
            int block_size = 4;
            double[,] block = new double[block_size, block_size];

            Bitmap src = new Bitmap(block_size, block_size);
            Frequency_4x4 f = new Frequency_4x4();
            int x = 0;
            int y = 0;

            if (loop) pos = 0;

            if (loop) pos_bit = 0;

            if (loop) pos_rep = 0;

            for (; ; pos++)
            {
                if (pos == bytes.Length && loop == true) return b;
                if (pos == bytes.Length) pos = 0;

                for (pos_bit = 0; pos_bit < 8; pos_bit++)
                {
                    for (pos_rep = 0; pos_rep < rep; pos_rep++)
                    {
                        src = b.Clone(new Rectangle(x, y, block_size, block_size), b.PixelFormat);
                        f = DCT2D_4x4(src);
                        byte bit = (byte)((bytes[pos] >> (byte)(pos_bit)) % 2);
                        f = vector_Embed8D(f, T, bit);

                        src = iDCT2D_4x4(f);
                        for (int m = 0; m < block_size; m++)
                            for (int n = 0; n < block_size; n++)
                                b.SetPixel(x + n, y + m, src.GetPixel(n, m));

                        //int foo = src.GetPixel(0, 0).ToArgb();
                        //foo = 0;

                        x += block_size;
                        if (x >= b.Width) { y += block_size; x = 0; }
                        if (y >= b.Height) return b;

                    }
                }
            }
            //return b;
        }
コード例 #7
0
        /*
        /// <summary>
        /// Helper
        /// </summary>
        /// <param name="f"></param>
        /// <param name="num"></param>
        /// <returns></returns>
        static double[] _f(Frequency_4x4x4 f, int i)
        {
            double[] d = { f.frequencies[0, 0, i], f.frequencies[0, 1, i], f.frequencies[0, 2, i], f.frequencies[0, 3, i], f.frequencies[1, 0, i], f.frequencies[1, 1, i], f.frequencies[1, 2, i], f.frequencies[1, 3, i], f.frequencies[2, 0, i], f.frequencies[2, 1, i], f.frequencies[2, 2, i], f.frequencies[2, 3, i], f.frequencies[3, 0, i], f.frequencies[3, 1, i], f.frequencies[3, 2, i], f.frequencies[3, 3, i] };
            return d;
        }

        /// <summary>
        /// Helper
        /// </summary>
        /// <param name="f"></param>
        /// <param name="num"></param>
        /// <returns></returns>
        static Frequency_4x4x4 f_(Frequency_4x4x4 f,  double[] f0, int i)
        {
            Frequency_4x4x4 f1 = new Frequency_4x4x4();
            Array.Copy( f.frequencies, f1.frequencies, f1.frequencies.Length);

            f1.frequencies[0, 0, i] = f.frequencies[0, 0, i];
            f1.frequencies[0, 1, i] = f.frequencies[0, 1, i];
            f1.frequencies[0, 2, i] = f.frequencies[0, 2, i];
            f1.frequencies[0, 3, i] = f.frequencies[0, 3, i];
            f1.frequencies[1, 0, i] = f.frequencies[1, 0, i];
            f1.frequencies[1, 1, i] = f.frequencies[1, 1, i];
            f1.frequencies[1, 2, i] = f.frequencies[1, 2, i];
            f1.frequencies[1, 3, i] = f.frequencies[1, 3, i];
            f1.frequencies[2, 0, i] = f.frequencies[2, 0, i];
            f1.frequencies[2, 1, i] = f.frequencies[2, 1, i];
            f1.frequencies[2, 2, i] = f.frequencies[2, 2, i];
            f1.frequencies[2, 3, i] = f.frequencies[2, 3, i];
            f1.frequencies[3, 0, i] = f.frequencies[3, 0, i];
            f1.frequencies[3, 1, i] = f.frequencies[3, 1, i];
            f1.frequencies[3, 2, i] = f.frequencies[3, 2, i];
            f1.frequencies[3, 3, i] = f.frequencies[3, 3, i];

            return f1;
        }
         *
         *
        */
        static void Main(string[] args)
        {
            byte[] videoData = new byte[0];
            byte[] bytes = new byte[0];
            Bitmap b = new Bitmap(1, 1);
            Bitmap b1 = new Bitmap(1, 1);
            Bitmap b2 = new Bitmap(1, 1);
            Bitmap b3 = new Bitmap(1, 1);

            string savefilename = "file";
            byte[] saveFile = new byte[1];
            Frequency_4x4x4 steg = new Frequency_4x4x4();

            Console.WriteLine("XMAS PACKAGER -- (0x00)");
            Console.WriteLine("------------");
            Console.WriteLine("Digital Data Hiding and Forensic Steganalysis for Online Videos");
            Console.WriteLine("What is the video width?");
            int videoWidth = Int32.Parse(Console.ReadLine());
            Console.WriteLine("What is the video height?");
            int videoHeight = Int32.Parse(Console.ReadLine());
            Console.WriteLine("What is the number of frames of the video?");
            int frameLength = Int32.Parse(Console.ReadLine());
            Console.WriteLine("What is the video's filename?");
            string filename = Console.ReadLine();
            Console.WriteLine("What is the stegano file's filename?");
            string sfilename = Console.ReadLine();
            Console.WriteLine("Are you hiding data, reconstructing it, or performing steganalysis? <H/R/S>");
            string hiding = Console.ReadLine();

            if (hiding == "S")
            {

                Console.WriteLine("\n > == Blind Steganalysis using the 3D DCT's high frequencies and K-means Clustering ==");
                Console.WriteLine("\n 1. Specify Cluster Centroids (Recommended) \n 2. CPU-Generated Random Cluster Centroids \n ");
                string cent = Console.ReadLine();
                if (cent == "2")
                {
                    Console.WriteLine("The CPU will generate k random cluster centroids. This may or may not give the best output. \nWhat is k?");
                    int k = Int32.Parse(Console.ReadLine());

                }
                if (cent == "1")
                {
                    Console.WriteLine("To initialize the k means algorithm, you need to select two representative videos so that the program has an understanding of the difference between the two classes. "
                    + "\n\n The first video should have data hidden inside of all frames (Stegano), while the second should have no data hidden inside of any frame. (Clean) \nWhat is k?");
                    int k = Int32.Parse(Console.ReadLine());
                    Console.WriteLine("Specify the filename of the stegano video");
                    string steganovid = Console.ReadLine();
                    Console.WriteLine("Specify the filename of the clean video");
                    string cleanvid = Console.ReadLine();
                    Console.WriteLine("Choose a parameter T for (Typically 0-4)");
                    int T = Int32.Parse(Console.ReadLine());

                    Bitmap[] sData = new Bitmap[4];
                    Bitmap[] cData = new Bitmap[4];

                    //
                    // An explanation of how this all works with apologies for false rates
                    //
                    // With k = 2, we harvest the first four frames of the videos
                    // and group them together into two separate classes (or clusters)
                    // To create two ideal classes:
                    //
                    //
                    //
                    // Ideal Dirty Video
                    // Ideal Clean Video
                    //
                    //
                    //
                    // We then check the similarity/distance between incoming group and existing classes in k-means.
                    // We group by high similarity / low distance
                    // Cosine Distance = (1 - Cosine similarity)
                    //
                    //
                    //
                    // A group contains 4 frames.
                    // Each class is initially represented by a group of first 4 frames from a separate video.
                    //
                    // Really and truly, the "Dirty" and "Clean" are meaningless
                    // Watch, for example, we use k = 2
                    // and set each cluster representative to be a "Ideally Clean" (strong correlations) and "Ideally Dirty" (weak correlations) video
                    // We imagine a Clean video has strong spatial and temporal correlations
                    // and a Dirty video has weak correlations of both.
                    //
                    //
                    // But our attacker's crafty data hiding algorithm might be different from our own
                    // and it might preserve either temporal and spatial correlations or both.
                    //
                    // This would mean that not all dirty videos may exhibit weak correlations.
                    //
                    // We could use larger values of k
                    // To create classes where unique steganography only modifies certain correlations
                    //
                    // All this algorithm is doing is measuring if an input video group has strong and weak correlations
                    // which it captures using intra-frame (spatial) markov features, and inter-frame (temporal) markov features
                    // Which only capture the unique probabilities of transitioning from DCT coefficient to DCT coefficient.
                    //
                    //
                    // The algorithm classifies due to weak spatial and temporal correlations in DCT domain.
                    // It checks to see how similar DCT frequencies are to each other.
                    //
                    // BUT
                    //
                    // One could set k to anything
                    // And have
                    //
                    // Strong Temporal Correlations with Weak Spatial Correlations,
                    // Strong Spatial Correlations with Weak Temporal Correlations,
                    // ...
                    // etc
                    //
                    // (any number of classes)
                    //
                    // and other features are exhibited from YouTube videos, such as the Absolute Central Moment, Kurtosis, Skewness, etc
                    // which introduce the possibility for even more classes
                    //
                    //
                    //
                    // Because Steganography algorithms are very different, some create weak spatial correlations, some, weak temporal correlations.
                    // There are a seemingly limitless number of ways to hide data in videos which all have unique footprints.
                    //
                    // The steganalysis scheme then
                    // but with contiguous spacing (scaled by T) to compensate
                    // for temporal error correcting codes.
                    //
                    // Why?
                    //
                    // Data hiding in online video is unreliable without "temporal error correction",
                    // This means we repeat the message in multiple neighboring frames to improve the reliability of data hiding.
                    //
                    // YouTube compression can be seen as a form of steganographic attack called a Collusion Attack
                    // A Collusion Attack on a video weakens a hidden message by altering the frames around it and creating weak temporal correlation.
                    //
                    // This only means that many of our frames in time series become too different from each other,
                    // which would convince us that there is hidden data in the video using this detection scheme.
                    //
                    // In reality YouTube messes up our hidden data by introducing errors in it and around it by dropping frames and encoding them
                    // with motion vector data, which is why it is necessary to use temporal error correction.
                    //
                    // But with temporal error correction, if we try to perform steganalysis on neighboring frames,
                    // we may get false negatives thanks to error correcting codes.
                    //
                    // With the strong temporal correlation, or, the very close similarity between frames,
                    // temporal error correcting codes fool us into thinking that nothing is there.
                    // Alternatively, we may get true positives thanks to noisy collusion attack
                    // but this is too difficult to determine in advance what we will get with YouTube.
                    // All it will likely do is interfere with our detection scheme
                    //
                    //
                    // Temporal error correction lowers the bitrate in the temporal direction if it repeats the message in time
                    // This creates strong temporal correlations between DCT blocks.
                    // With the model in [1] this would give us a false negative.
                    // This algorithm classifies using WEAK temporal correlations between DCT blocks
                    // But the temporal corrected message has STRONG temporal correction.
                    //
                    //
                    // We just want to get an honest detection reading that isn't affected by error correction or collusion.
                    //
                    //
                    // Likewise, fast moving, choppy, and noisy videos
                    // give many false positives for this reason because they have weak temporal correlations.
                    // and the authors mention this.
                    //
                    // YouTube does not collude videos which have no information as long as they are smooth and slow-moving,
                    // and they usually remain this way after compression
                    //
                    // Slow moving videos with hidden data that isn't temporally corrected are colluded,
                    // but it should not negatively affect the detection performance.
                    //
                    // It is the error correction which is annoying
                    // because it reduces bitrate
                    // a very widely held fact of Forensic Steganalysis is that bitrate reduction can harm Steganalysis
                    // because hiding less information lowers detection rates :(
                    //
                    //
                    Console.WriteLine("A. Initializing Steganalytic Tool (8 Steps)");

                    Console.WriteLine("1. Loading Data");
                    for (int i = 0; i < 4; i++)
                        sData[i] = BitmapFromArray1DSafe(GetBytesFromFile(steganovid, (((videoWidth * videoHeight) * i * T) + (((videoWidth * videoHeight) * i * T) / 2)), videoWidth * videoHeight), videoWidth, videoHeight);;

                    for (int i = 0; i < 4; i++)
                        cData[i] = BitmapFromArray1DSafe(GetBytesFromFile(steganovid, (((videoWidth * videoHeight) * i * T) + (((videoWidth * videoHeight) * i * T) / 2)), videoWidth * videoHeight), videoWidth, videoHeight); ;

                    Console.WriteLine("2. Performing 3D DCT Transform, Acquiring Groups Y(k1,k2,k3,k) for Initial Centroids, calculating Low-Order Statistics");
                    double[,,] sDataGroup = M_Group(sData[0], sData[1], sData[2], sData[3]);
                    double[,,] cDataGroup = M_Group(cData[0], cData[1], cData[2], cData[3]);

                    Console.WriteLine("2. Assembling transform histograms"); ;
                    double smean = m(sDataGroup); Console.WriteLine("Mean of stegano video is" + smean);
                    double cmean = m(cDataGroup); Console.WriteLine("Mean of clean video is " + cmean);

                    double sstd = std(sDataGroup, smean); Console.WriteLine("Sigma of stegano video is " + sstd);
                    double cstd = std(cDataGroup, cmean); Console.WriteLine("Sigma of clean video is " + cstd);

                    Console.WriteLine("\n3. Calculating Kurtosis for Initial Centroids");
                    double sKurtosis = Kurtosis(smean, sstd, flatten(sDataGroup));
                    double cKurtosis = Kurtosis(cmean, cstd, flatten(cDataGroup));
                    Console.WriteLine("Kurtosis for Clean Videos: " + cKurtosis);
                    Console.WriteLine("Kurtosis for Dirty Videos: " + sKurtosis);

                    Console.WriteLine("\n4. Calculating Skewness for Initial Centroids");
                    double sSkewness = Skewness(smean, sstd, flatten(sDataGroup));
                    double cSkewness = Skewness(cmean, cstd, flatten(cDataGroup));
                    Console.WriteLine("Skewness for Clean Videos: " + cSkewness);
                    Console.WriteLine("Skewness for Dirty Videos: " + sSkewness);

                    Console.WriteLine("\n5. Calculating 1st order Absolute Central Moment for Initial Centroids");
                    double s1stabs = AbsCentralMoment(1, videoHeight, videoWidth, flatten(sDataGroup), smean);
                    double c1stabs = AbsCentralMoment(1, videoHeight, videoWidth, flatten(cDataGroup), cmean);
                    Console.WriteLine("1st order Absolute Moment for Clean Videos: " + c1stabs);
                    Console.WriteLine("1st order Absolute Moment for Dirty Videos: " + s1stabs);

                    Console.WriteLine("\n6. Calculating 2nd order Absolute Central Moment for Initial Centroids");
                    double s2ndabs = AbsCentralMoment(2, videoHeight, videoWidth, flatten(sDataGroup), smean);
                    double c2ndabs = AbsCentralMoment(2, videoHeight, videoWidth, flatten(cDataGroup), cmean);
                    Console.WriteLine("2nd order Absolute Moment for Clean Videos: " + c2ndabs);
                    Console.WriteLine("2nd order Absolute Moment for Dirty Videos: " + s2ndabs);

                    Console.WriteLine("\n7. Calculating 3rd order Absolute Central Moment for Initial Centroids");
                    double s3rdabs = AbsCentralMoment(3, videoHeight, videoWidth, flatten(sDataGroup), smean);
                    double c3rdabs = AbsCentralMoment(3, videoHeight, videoWidth, flatten(cDataGroup), cmean);
                    Console.WriteLine("3rd order Absolute Moment for Clean Videos: " + c3rdabs);
                    Console.WriteLine("3rd order Absolute Moment for Dirty Videos: " + s3rdabs);

                    Console.WriteLine("\n8. Calculating Markov Features for Initial Centroids");
                    Markov smv = new Markov();
                    Markov cmv = new Markov();

                    //Reduce feature dimension by T, which is 10
                    sDataGroup = Truncate(sDataGroup);
                    cDataGroup = Truncate(cDataGroup);

                    smv.markov = transition_Tensor(sDataGroup);
                    cmv.markov = transition_Tensor(cDataGroup);

                    Console.WriteLine("\n8. Assembling essential feature Vectors for initializing 2-means");
                    FeatureVector fv1 = featureVector1(smv, s1stabs, s2ndabs, s3rdabs, sSkewness, sKurtosis, -1);
                    FeatureVector fv2 = featureVector1(cmv, c1stabs, c2ndabs, c3rdabs, cSkewness, cKurtosis, -1);

                    Console.WriteLine("Done Initializing! \n\n");

                    Console.WriteLine("B. Gathering Low-order and High-order statistics from target video frames.");

                    Console.ReadLine();
                }

                for (int i = 0; i < frameLength - 3; i++)
                {

                    Console.Write("\n Scanning the video with " + (100 * (((double)i / (double)frameLength))) + "% Completed \n");

                    videoData = GetBytesFromFile(filename, (((videoWidth * videoHeight) * i) + (((videoWidth * videoHeight) * i) / 2)), videoWidth * videoHeight);
                    b = BitmapFromArray1D(videoData, videoWidth, videoHeight);

                    videoData = GetBytesFromFile(filename, (((videoWidth * videoHeight) * (i+1)) + (((videoWidth * videoHeight) * (i+1)) / 2)), videoWidth * videoHeight);
                    b1 = BitmapFromArray1D(videoData, videoWidth, videoHeight);

                    videoData = GetBytesFromFile(filename, (((videoWidth * videoHeight) * (i+2)) + (((videoWidth * videoHeight) * (i+2)) / 2)), videoWidth * videoHeight);
                    b2 = BitmapFromArray1D(videoData, videoWidth, videoHeight);

                    videoData = GetBytesFromFile(filename, (((videoWidth * videoHeight) * (i+3)) + (((videoWidth * videoHeight) * (i+3)) / 2)), videoWidth * videoHeight);
                    b3 = BitmapFromArray1D(videoData, videoWidth, videoHeight);

                    steg = DCT3D_4x4x4(b, b1, b2, b3);

                    videoData = Array1DFromBitmap(b, videoWidth * videoHeight);
                    SaveBytesToFile(filename, (((videoWidth * videoHeight) * i) + (((videoWidth * videoHeight) * i) / 2)), videoWidth * videoHeight, videoData);

                }

            }

            if (hiding == "R")
            {
                Console.WriteLine("Enter the filename to save the reconstructed file to");
                savefilename = Console.ReadLine();
                Console.WriteLine("What is the filesize of the file in bytes? If unknown, type 42");
                filesizespecified = long.Parse(Console.ReadLine());
            }

            Console.WriteLine("What algorithm will you use? <Choose Number> \n \n \n 1. (checkers): Spatial Domain PVD - Very Robust, uses computationally efficient Pixel Value Differencing and Histogram Shifting algorithms. Easily detectable visually however. Payload capacity is large. Reccomended if video is being uploaded to YouTube or highly compressed on disk. Not recommended for covert operation and is weak to known steganalysis attacks.");
            Console.WriteLine("\n \n \n 2. (smiling face): Transform Domain DCT2D 8-D Vector Quantization - Fragile, with borderline robustness, uses computationally intensive Discrete Cosine Transform and eight dimensional vector quantization. Invisible with distortion < 3db (6% visual distortion calculated with PSNR). Payload capacity is large but small once error correction used. Highly recommended if video is stored on hard disk and will not be re-encoded. Recommended for covert operation as embedded data is invisible.");
            string response = Console.ReadLine();

            while (true)
            {
                if (response == "2")
                {
                    Console.WriteLine("What is your thresholding parameter T?");
                    int T = Int32.Parse(Console.ReadLine());
                    Console.WriteLine("What is the error correcting codeword length you'll use? (Set this to 900 or greater for YouTube.)");
                    int rep = Int32.Parse(Console.ReadLine());
                    bytes = GetBytesFromFile(sfilename, 0);
                    acc = new double[8 * bytes.Length];

                    finalFile = new byte[bytes.Length];

                    if (bytes.Length * 8 * rep > videoWidth * videoHeight / 4 / 4)
                    {
                        Console.WriteLine(" * File is much larger than embedding capacity of frame with chosen error code, would you like to embed it across all frames? <Y/n>");
                        string allframes = Console.ReadLine();

                        if (allframes != "Y")

                        {
                            Console.WriteLine("File too large, aborting...");
                        }
                        else
                        {
                            loop = false;
                        }
                    }
                    Frequency_4x4 f = new Frequency_4x4();

                    for (int i = 0; i < frameLength; i++)
                    {
                        if (hiding == "H")
                        {

                            Console.Write("\n Processing.." + (100 * (((double)i / (double)frameLength))) + "% Completed \n");

                            videoData = GetBytesFromFile(filename, (((videoWidth * videoHeight) * i) + (((videoWidth * videoHeight) * i) / 2)), videoWidth * videoHeight);
                            b = BitmapFromArray1DSafe(videoData, videoWidth, videoHeight);
                            b = transform_Embed(b, T, bytes, rep);

                            videoData = Array1DFromBitmapSafe(b, videoWidth * videoHeight);
                            SaveBytesToFile(filename, (((videoWidth * videoHeight) * i) + (((videoWidth * videoHeight) * i) / 2)), videoWidth * videoHeight, videoData);

                        }
                        if (hiding == "R")
                        {

                                if (bytes.Length * rep >= (videoWidth * videoHeight / 8 / 16))
                                    loop = false;

                                filesizespecified = bytes.Length;

                            Console.Write("\n Processing.." + (100 * (((double)i / (double)frameLength))) + "% Completed \n");

                            videoData = GetBytesFromFile(filename, (((videoWidth * videoHeight) * i) + (((videoWidth * videoHeight) * i) / 2)), videoWidth * videoHeight);
                            b = BitmapFromArray1DSafe(videoData, videoWidth, videoHeight);
                            saveFile = transform_Retrieve(b, bytes, T, rep);

                            if (!loop)
                                Console.WriteLine("BER for chunk " + i + " (Bit Error Rate) is " + BER(bytes, saveFile, (int)(pos), (int)(videoWidth * videoHeight / 16 / rep)));
                            if (loop)
                                Console.WriteLine("BER (Bit Error Rate) is " + BER(bytes, saveFile));

                            SaveBytesToFile(savefilename, 0, bytes.Length, saveFile);
                            if (loop)
                                acc = AccArray(saveFile, acc);

                        }

                    }
                    acc = AvgArray(acc, frameLength);
                    Console.WriteLine("P value is " + P(acc));
                    Console.WriteLine("Done!");
                    Console.ReadLine();
                }
                if (response == "1")
                {
                    Console.WriteLine("What is your thresholding parameter T?");
                    int T = Int32.Parse(Console.ReadLine());
                    Console.WriteLine("What is your thresholding parameter G?");
                    int G = Int32.Parse(Console.ReadLine());
                    Console.WriteLine("What is the block size");
                    int block_size = Int32.Parse(Console.ReadLine());
                    Console.WriteLine("What is the spatial error correcting codeword length you'll use? (Set this to 50 or greater for YouTube.)");
                    int rep = Int32.Parse(Console.ReadLine());
                    Console.WriteLine("What is the temporal error correcting codeword length you'll use? (Set this to 50 or greater for YouTube.)");
                    int trep = Int32.Parse(Console.ReadLine());
                    bytes = GetBytesFromFile(sfilename, 0);
                    finalFile = new byte[bytes.Length];
                    acc = new double[8 * bytes.Length];

                    long loc = 0;
                    if (bytes.Length * 8 * rep > videoWidth * videoHeight / block_size / block_size)
                    {
                        Console.WriteLine(" * File is much larger than embedding capacity of frame with chosen error code, would you like to embed it across all frames? <Y/n>");
                        string allframes = Console.ReadLine();

                        if (allframes != "Y")
                        {
                            Console.WriteLine("File too large, aborting...");

                        }

                        else
                        {
                            loop = false;
                        }

                    }

                    for (int i = 0; i < frameLength; i++)
                    {

                        if (hiding == "H")
                        {

                            Console.Write("\n Processing.." + (100 * (((double)i / (double)frameLength))) + "% Completed \n");

                            videoData = GetBytesFromFile(filename, (((videoWidth * videoHeight) * i) + (((videoWidth * videoHeight) * i) / 2)), videoWidth * videoHeight);
                            b = BitmapFromArray1D(videoData, videoWidth, videoHeight);
                            b = spatial_Embed(b, block_size, T, G, bytes, rep, trep);

                            videoData = Array1DFromBitmap(b, videoWidth * videoHeight);
                            SaveBytesToFile(filename, (((videoWidth * videoHeight) * i) + (((videoWidth * videoHeight) * i) / 2)), videoWidth * videoHeight, videoData);

                        }
                        if (hiding == "R")
                        {

                                if (bytes.Length * rep >= (videoWidth * videoHeight / 8 / block_size / block_size))
                                    loop = false;

                                filesizespecified = bytes.Length;

                            Console.Write("\n Processing.." + (100 * (((double)i / (double)frameLength))) + "% Completed.");
                            loc = pos;
                            videoData = GetBytesFromFile(filename, (((videoWidth * videoHeight) * i) + (((videoWidth * videoHeight) * i) / 2)), videoWidth * videoHeight);
                            b = BitmapFromArray1D(videoData, videoWidth, videoHeight);
                            saveFile = spatial_Retrieve(b, block_size, T, G, bytes, rep, trep);

                            if (!loop)
                                if ((i+1) % (trep) == 0)
                                {
                                    Console.WriteLine("BER for chunk " + i + " (Bit Error Rate) is " + BER(bytes, saveFile, (int)(loc), (int)(pos - loc)));
                                    Array.Copy(saveFile, pos, finalFile, pos, pos - loc); //this is the cumulative file
                                    Console.WriteLine((100 * (((double)i / (double)frameLength))) + " % of the file ( " + pos + " ) bytes : total filesize of ( " + bytes.Length + " ) bytes has been saved to " + savefilename);
                                    SaveBytesToFile(savefilename, 0, bytes.Length, finalFile); //save the whole file
                                }

                            if (loop)
                                Console.WriteLine("BER (Bit Error Rate) is " + BER(bytes, saveFile));
                            if (loop)
                                SaveBytesToFile(savefilename, 0, bytes.Length, saveFile); //save this
                            if (loop)
                                acc = AccArray(saveFile, acc);

                        }

                    }
                    acc = AvgArray(acc, frameLength);
                    Console.WriteLine("P value is " + P(acc));
                    Console.WriteLine("SUCCESS! Completed 100%. Please be careful with this video.");
                    Console.ReadLine();
                }
                Console.WriteLine("Try a different response.");
                Console.ReadLine();
            }
        }