protected override double Calculation(LockBitmap originalBmp, LockBitmap steganoBmp) { Color orig; Color steg; var originalDiffernce = 0.0; var totalDifference = 0.0; for (var y = 0; y < originalBmp.Height; y++) { for (var x = 0; x < originalBmp.Width; x++) { orig = originalBmp.GetPixel(x, y); steg = steganoBmp.GetPixel(x, y); originalDiffernce += Math.Pow(Math.Abs(orig.R) + Math.Abs(orig.G) + Math.Abs(orig.B), 2); totalDifference += Math.Pow(Math.Abs(orig.R - steg.R) + Math.Abs(orig.G - steg.G) + Math.Abs(orig.B - steg.B), 2); } } return originalDiffernce/totalDifference; }
protected override double Calculation(LockBitmap originalBmp, LockBitmap steganoBmp) { Color orig; Color steg; var size = originalBmp.Height*originalBmp.Width; var totalDifference = 0.0; var maxDifference = 0.0; double currentDifference; for (var y = 0; y < originalBmp.Height; y++) { for (var x = 0; x < originalBmp.Width; x++) { orig = originalBmp.GetPixel(x, y); steg = steganoBmp.GetPixel(x, y); currentDifference = Math.Pow(Math.Abs(orig.R) + Math.Abs(orig.G) + Math.Abs(orig.B), 2); if (currentDifference >= maxDifference) maxDifference = currentDifference; totalDifference += Math.Pow(Math.Abs(orig.R - steg.R) + Math.Abs(orig.G - steg.G) + Math.Abs(orig.B - steg.B), 2); } } return size*maxDifference/totalDifference; }
public static void ChangeColor(Bitmap src, Color color, IEnumerable<Pixel> changedPixels) { var lockBitmap = new LockBitmap(src); lockBitmap.LockBits(); foreach (var changedPixel in changedPixels) { lockBitmap.SetPixel(changedPixel.X, changedPixel.Y, color); } lockBitmap.UnlockBits(); }
/** * Outputs a laplace graph in csv format. * * The CSV file will be comma separated, and is * written to the specified place on disk. * * @param image The image to create the laplace graph of. * @return A string representation of the laplace graph in * the format of CSV. */ public static string GetCSVGraph(LockBitmap image) { var sb = new StringBuilder(); sb.Append("\"Frequency\",\"Laplace Value\"\n"); var graph = GetGraph(image); for (var i = 0; i < graph.Length; i++) { sb.Append(graph[i][1] + "," + graph[i][0] + "\n"); } sb.Append("\n\n"); return sb.ToString(); }
protected Filter(LockBitmap image, int startbits, int endbits) { if (image == null) { throw new ArgumentNullException(nameof(image)); } Image = image; StartRange = startbits; EndRange = endbits; ByteMask = GetByteMask(); if (!image.IsLocked) { image.LockBits(); } }
protected override double Calculation(LockBitmap originalBmp, LockBitmap steganoBmp) { var size = originalBmp.Height*originalBmp.Width; Color orig; Color steg; var difference = 0.0; for (var y = 0; y < originalBmp.Height; y++) { for (var x = 0; x < originalBmp.Width; x++) { orig = originalBmp.GetPixel(x, y); steg = steganoBmp.GetPixel(x, y); difference += Math.Abs(orig.R - steg.R) + Math.Abs(orig.G - steg.G) + Math.Abs(orig.B - steg.B); } } return difference/size; }
protected override double Calculation(LockBitmap originalBmp, LockBitmap steganoBmp) { var origFiltered = new Laplace(originalBmp, 0, 8); var stegoFiltered = new Laplace(steganoBmp, 0, 8); var originalDiff = 0.0; var totalDiff = 0.0; for (var y = 0; y < originalBmp.Height; y++) { for (var x = 0; x < originalBmp.Width; x++) { //TODO Shouldnt that be the other direction? First TOTAL and second ORIGINAL? originalDiff += Math.Pow(origFiltered.GetValue(x, y) - stegoFiltered.GetValue(x, y), 2); totalDiff += Math.Pow(origFiltered.GetValue(x, y), 2); } } return originalDiff/totalDiff; }
public static Bitmap ChangeColor(Bitmap src, Color color) { var result = new Bitmap(src); var lockBitmap = new LockBitmap(result); lockBitmap.LockBits(); var compareClr = Color.FromArgb(255, 255, 255, 255); for (var y = 0; y < lockBitmap.Height; y++) { for (var x = 0; x < lockBitmap.Width; x++) { if (lockBitmap.GetPixel(x, y) == compareClr) { lockBitmap.SetPixel(x, y, color); } } } lockBitmap.UnlockBits(); return result; }
/* * A small main method that will print out the message length * in percent of pixels. */ public static void Main(string[] args) { if (args.Length != 1) { Console.WriteLine("Usage: invisibleinktoolkit.benchmark.SamplePairs <imagefilename>"); Environment.Exit(1); } try { Console.WriteLine("\nSample Pairs Results"); Console.WriteLine("--------------------"); var sp = new SamplePairs(); using (var bitmap = new Bitmap(args[0])) { var image = new LockBitmap(bitmap); image.LockBits(); double average = 0; var results = sp.DoAnalysis(image, ANALYSIS_COLOUR_RED); Console.WriteLine("Result from red: " + results); average += results; results = sp.DoAnalysis(image, ANALYSIS_COLOUR_GREEN); Console.WriteLine("Result from green: " + results); average += results; results = sp.DoAnalysis(image, ANALYSIS_COLOUR_BLUE); Console.WriteLine("Result from blue: " + results); average += results; average = average/3; Console.WriteLine("Average result: " + average); Console.WriteLine(); image.UnlockBits(); } } catch (Exception e) { Console.WriteLine("ERROR: Cannot process that image type, please try another image."); Console.WriteLine(e.StackTrace); } }
public double Calculate(Bitmap originalBmp, Bitmap steganoBmp) { if (originalBmp == null) { throw new ArgumentNullException(nameof(originalBmp)); } if (originalBmp == null) { throw new ArgumentNullException(nameof(steganoBmp)); } var original = new LockBitmap(originalBmp); original.LockBits(); var stegano = new LockBitmap(steganoBmp); stegano.LockBits(); var result = Calculation(original, stegano); original.UnlockBits(); stegano.UnlockBits(); return result; }
public Prewitt(LockBitmap image, int startbits, int endbits) : base(image, startbits, endbits) { }
protected abstract double Calculation(LockBitmap originalBmp, LockBitmap steganoBmp);
/* * Does an RS analysis of a given image. * <P> * The analysis data returned is specified by name in * the getResultNames() method. * * @param image The image to analyse. * @param colour The colour to analyse. * @param overlap Whether the blocks should overlap or not. * @return The analysis information. */ public double[] DoAnalysis(LockBitmap image, int color, bool overlap) { int startx = 0, starty = 0; var block = new Color[mM*mN]; double numregular = 0, numsingular = 0; double numnegreg = 0, numnegsing = 0; double numunusable = 0, numnegunusable = 0; double variationB = 0, variationP = 0, variationN = 0; while (startx < image.Width && starty < image.Height) { //this is done once for each mask... for (var m = 0; m < 2; m++) { //get the block of data var k = 0; for (var i = 0; i < mN; i++) { for (var j = 0; j < mM; j++) { block[k] = image.GetPixel(startx + j, starty + i); k++; } } // get the variation the block variationB = GetVariation(block, color); //now flip according to the mask block = FlipBlock(block, mMask[m]); variationP = GetVariation(block, color); //flip it back block = FlipBlock(block, mMask[m]); //negative mask mMask[m] = InvertMask(mMask[m]); variationN = GetNegativeVariation(block, color, mMask[m]); mMask[m] = InvertMask(mMask[m]); //now we need to work out which group each belongs to //positive groupings if (variationP > variationB) { numregular++; } if (variationP < variationB) { numsingular++; } if (variationP == variationB) { numunusable++; } //negative mask groupings if (variationN > variationB) { numnegreg++; } if (variationN < variationB) { numnegsing++; } if (variationN == variationB) { numnegunusable++; } //now we keep going... } //get the next position if (overlap) startx += 1; else startx += mM; if (startx >= image.Width - 1) { startx = 0; if (overlap) { starty += 1; } else { starty += mN; } } if (starty >= image.Height - 1) { break; } } //get all the details needed to derive x... var totalgroups = numregular + numsingular + numunusable; var allpixels = GetAllPixelFlips(image, color, overlap); var x = GetX(numregular, numnegreg, allpixels[0], allpixels[2], numsingular, numnegsing, allpixels[1], allpixels[3]); //calculate the estimated percent of flipped pixels and message length double epf, ml; if (2*(x - 1) == 0) epf = 0; else epf = Math.Abs(x/(2*(x - 1))); if (x - 0.5 == 0) ml = 0; else ml = Math.Abs(x/(x - 0.5)); //now we have the number of regular and singular groups... var results = new double[28]; //save them all... //these results results[0] = numregular; results[1] = numsingular; results[2] = numnegreg; results[3] = numnegsing; results[4] = Math.Abs(numregular - numnegreg); results[5] = Math.Abs(numsingular - numnegsing); results[6] = numregular/totalgroups*100; results[7] = numsingular/totalgroups*100; results[8] = numnegreg/totalgroups*100; results[9] = numnegsing/totalgroups*100; results[10] = results[4]/totalgroups*100; results[11] = results[5]/totalgroups*100; //all pixel results results[12] = allpixels[0]; results[13] = allpixels[1]; results[14] = allpixels[2]; results[15] = allpixels[3]; results[16] = Math.Abs(allpixels[0] - allpixels[1]); results[17] = Math.Abs(allpixels[2] - allpixels[3]); results[18] = allpixels[0]/totalgroups*100; results[19] = allpixels[1]/totalgroups*100; results[20] = allpixels[2]/totalgroups*100; results[21] = allpixels[3]/totalgroups*100; results[22] = results[16]/totalgroups*100; results[23] = results[17]/totalgroups*100; //overall results results[24] = totalgroups; results[25] = epf; results[26] = ml; results[27] = image.Width*image.Height*3*ml/8; return results; }
protected LockBitmap LockBitmap(string src) { var lockBitmap = new LockBitmap(new Bitmap(src)); lockBitmap.LockBits(); return lockBitmap; }
/** * Gets the RS analysis results for flipping performed on all * pixels. * * @param image The image to analyse. * @param colour The colour to analyse. * @param overlap Whether the blocks should overlap. * @return The analysis information for all flipped pixels. */ private double[] GetAllPixelFlips(LockBitmap image, int colour, bool overlap) { //setup the mask for everything... var allmask = new int[mM*mN]; for (var i = 0; i < allmask.Length; i++) { allmask[i] = 1; } //now do the same as the doAnalysis() method int startx = 0, starty = 0; var block = new Color[mM*mN]; double numregular = 0, numsingular = 0; double numnegreg = 0, numnegsing = 0; double numunusable = 0, numnegunusable = 0; double variationB, variationP, variationN; while (startx < image.Width && starty < image.Height) { //done once for each mask for (var m = 0; m < 2; m++) { //get the block of data var k = 0; for (var i = 0; i < mN; i++) { for (var j = 0; j < mM; j++) { block[k] = image.GetPixel(startx + j, starty + i); k++; } } //flip all the pixels in the block (NOTE: THIS IS WHAT'S DIFFERENT //TO THE OTHER doAnalysis() METHOD) block = FlipBlock(block, allmask); //get the variation the block variationB = GetVariation(block, colour); //now flip according to the mask block = FlipBlock(block, mMask[m]); variationP = GetVariation(block, colour); //flip it back block = FlipBlock(block, mMask[m]); //negative mask mMask[m] = InvertMask(mMask[m]); variationN = GetNegativeVariation(block, colour, mMask[m]); mMask[m] = InvertMask(mMask[m]); //now we need to work out which group each belongs to //positive groupings if (variationP > variationB) numregular++; if (variationP < variationB) numsingular++; if (variationP == variationB) numunusable++; //negative mask groupings if (variationN > variationB) numnegreg++; if (variationN < variationB) numnegsing++; if (variationN == variationB) numnegunusable++; //now we keep going... } //get the next position if (overlap) startx += 1; else startx += mM; if (startx >= image.Width - 1) { startx = 0; if (overlap) starty += 1; else starty += mN; } if (starty >= image.Height - 1) break; } //save all the results (same order as before) var results = new double[4]; results[0] = numregular; results[1] = numsingular; results[2] = numnegreg; results[3] = numnegsing; return results; }
public Sobel(LockBitmap image, int startbits, int endbits) : base(image, startbits, endbits) { }
//FUNCTIONS /** * Runs all the steganalysis. * * @param stego The stego image to test. * @return All the results as text. * @throws IllegalArgumentException If the stego image is null. * @throws Exception If it has problems reading the images. */ public string Run(Bitmap stego) { using (stego) { var image = new LockBitmap(stego); image.LockBits(); var results = new StringBuilder("Results of steganalysis\n" + "==========================\n\n"); string colour; double averageresults = 0, averagelength = 0; //RS Analysis if (mRunRsAnalysis) { results.Append("RS ANALYSIS\n" + "============\n\n"); results.Append("RS Analysis (Non-overlapping groups)\n"); for (var j = 0; j < 3; j++) { var rsa = new RsAnalysis(2, 2); var testresults = rsa.DoAnalysis(image, j, false); //get the right colour if (j == 0) { colour = "red"; } else if (j == 1) { colour = "green"; } else { colour = "blue"; } //Append the results results.Append("Percentage in " + colour + ": "); //Round and Append results results.Append(Round(testresults[26]*100, 5) + "\n"); //and the approximate length (in bytes) results.Append("Approximate length (in bytes) from " + colour + ": " + Round(testresults[27], 5) + "\n"); averageresults += testresults[26]; averagelength += testresults[27]; } //now do again for overlapping groups results.Append("\nRS Analysis (Overlapping groups)\n"); for (var j = 0; j < 3; j++) { var rsa = new RsAnalysis(2, 2); var testresults = rsa.DoAnalysis(image, j, true); //get the right colour if (j == 0) { colour = "red"; } else if (j == 1) { colour = "green"; } else { colour = "blue"; } //Append the results results.Append("Percentage in " + colour + ": "); //Round and Append results results.Append(Round(testresults[26]*100, 5) + "\n"); //and the approximate length (in bytes) results.Append("Approximate length (in bytes) from " + colour + ": " + Round(testresults[27], 5) + "\n"); averageresults += testresults[26]; averagelength += testresults[27]; } results.Append("\nAverage across all groups/colours: " + Round(averageresults/6*100, 5)); results.Append("\nAverage approximate length across all groups/colours: " + Round(averagelength/6, 5)); results.Append("\n\n\n"); } //Sample Pairs averageresults = 0; averagelength = 0; if (mRunSamplePairs) { results.Append("SAMPLE PAIRS\n" + "=============\n"); for (var j = 0; j < 3; j++) { var sp = new SamplePairs(); var estimatedlength = sp.DoAnalysis(image, j); var numbytes = image.Height*image.Width*3/8 *estimatedlength; //get the right colour if (j == 0) { colour = "red"; } else if (j == 1) { colour = "green"; } else { colour = "blue"; } //Append the results results.Append("Percentage in " + colour + ": "); //Round and Append results results.Append(Round(estimatedlength*100, 5) + "\n"); //and the approximate length (in bytes) results.Append("Approximate length (in bytes) from " + colour + ": " + Round(numbytes, 5) + "\n"); averageresults += estimatedlength; averagelength += numbytes; } //average results results.Append("\nAverage across all groups/colours: " + Round(averageresults/3*100, 5)); results.Append("\nAverage approximate length across all groups/colours: " + Round(averagelength/3, 5)); results.Append("\n\n\n"); } //Laplace graph if (mRunLaplaceGraph) { results.Append("LAPLACE GRAPH (CSV formatted)\n" + "==============================\n\n"); results.Append(LaplaceGraph.GetCSVGraph(image)); } //Append some new lines to make it look nice results.Append("\n\n\n\n"); mResultsString = results.ToString(); image.UnlockBits(); } return mResultsString; }
/** * Generates a CSV formatted string of steganalysis information. * <P> * The directory passed has all it's image files steganalysed and * the results are returned in a comma separated file format. No spaces * are used in column headings, and all bar the steganography type are * numerical values. * * @param directory The directory to steganalyse. * @param laplacelimit The number of laplace values to write out in total. * @return A string containing a csv file of results. */ public string GetCSV(string directory, int laplacelimit) { //output progress to console Console.WriteLine("\n\nCSV Progress: {"); var files = Directory.GetFiles(directory); var fivepercent = (int) Math.Floor((double) files.Length/20); var csv = new StringBuilder(); //add all the headings if (mRunRsAnalysis) { var rsa = new RsAnalysis(2, 2); var rflag = "(rs overlapping)"; string colour; //overlapping for (var i = 0; i < 3; i++) { IEnumerable<string> rnames = rsa.GetResultNames(); //get the right colour if (i == 0) { colour = " red "; } else if (i == 1) { colour = " green "; } else { colour = " blue "; } foreach (var rname in rnames) { var aname = rname; var towrite = aname + colour + rflag + ","; towrite = towrite.Replace(' ', '-'); csv.Append(towrite); } } //non overlapping rflag = "(rs non-overlapping)"; for (var i = 0; i < 3; i++) { IEnumerable<string> rnames = rsa.GetResultNames(); //get the right colour if (i == 0) { colour = " red "; } else if (i == 1) { colour = " green "; } else { colour = " blue "; } foreach (var rname in rnames) { var aname = rname; var towrite = aname + colour + rflag + ","; towrite = towrite.Replace(' ', '-'); csv.Append(towrite); } } } if (mRunSamplePairs) { string colour; //overlapping for (var i = 0; i < 3; i++) { //get the right colour if (i == 0) { colour = "-red-"; } else if (i == 1) { colour = "-green-"; } else { colour = "-blue-"; } csv.Append("SP-Percentage" + colour + ","); csv.Append("SP-Approximate-Bytes" + colour + ","); } } if (mRunLaplaceGraph) { for (var i = 0; i < laplacelimit; i++) { csv.Append("Laplace-value-" + i + ","); } } csv.Append("Steganography-Type,Image-Name\n"); //check all the files for (var i = 0; i < files.Length; i++) { //print progress if (i > 0 && fivepercent > 0) { if (i%fivepercent == 0) { Console.WriteLine("#"); } } if (files[i].EndsWith(".bmp") || files[i].EndsWith(".png") || files[i].EndsWith(".jpg")) { //file can be worked on. string flag; try { using (var bitmap = new Bitmap(files[i])) { var image = new LockBitmap(bitmap); image.LockBits(); //run RS analysis if (mRunRsAnalysis) { //overlapping for (var j = 0; j < 3; j++) { var rsa = new RsAnalysis(2, 2); var testresults = rsa.DoAnalysis(image, j, true); for (var k = 0; k < testresults.Length; k++) { csv.Append(testresults[k] + ","); } } //non-overlapping for (var j = 0; j < 3; j++) { var rsa = new RsAnalysis(2, 2); var testresults = rsa.DoAnalysis(image, j, false); for (var k = 0; k < testresults.Length; k++) { csv.Append(testresults[k] + ","); } } } //run Sample Pairs if (mRunSamplePairs) { //overlapping for (var j = 0; j < 3; j++) { var sp = new SamplePairs(); var estimatedlength = sp.DoAnalysis(image, j); var numbytes = image.Height*image.Width*3/8 *estimatedlength; csv.Append(estimatedlength + "," + numbytes + ","); } } //run LaplaceGraph if (mRunLaplaceGraph) { var lgres = LaplaceGraph.GetGraph(image); for (var j = 0; j < laplacelimit; j++) { if (lgres.Length <= laplacelimit && j >= lgres.Length) { csv.Append("0,"); } else { if (lgres[j][0] != j) { csv.Append("0,"); } else { csv.Append(lgres[j][1] + ","); } } } } if (files[i].IndexOf("_") >= 0 || files[i].IndexOf("-") >= 0) { if (files[i].IndexOf("_") >= 0) { flag = files[i].Substring(files[i].IndexOf("_") + 1, files[i].LastIndexOf(".")); } else { flag = files[i].Substring(files[i].IndexOf("-") + 1, files[i].LastIndexOf(".")); } } else { flag = "none"; } csv.Append(flag); //Append in the file name csv.Append("," + files[i]); if (csv[csv.Length - 1] == ',') { csv.Remove(csv.Length - 1, 1); } csv.Append("\n"); image.UnlockBits(); } } catch (Exception) { //skip the file... } //cleanup to speed up memory GC.Collect(); } } //all done Console.WriteLine("} Complete!"); csv.Append("\n"); return csv.ToString(); }
/** * Creates an ARFF file of steganography information. * <P> * An ARFF file is the natural internal format for WEKA - Waikato * Environment for Knowledge Analysis. WEKA can also handle CSV * files but it is much nicer to be able to produce the natural format. * The same information as per the CSV generator is produced here, just * in a different format. * * @param directory The directory to steganalyse. * @param laplacelimit The maximum number of laplace values to output. * @param relationname The internal name of the relation as it will be * seen in WEKA. * @return An ARFF formatted file full of the steganalysis information. * @see www.cs.waikato.ac.nz/ml/weka * */ public string GetARFF(string directory, int laplacelimit, string relationname) { var arff = new StringBuilder(); //output progress to console Console.WriteLine("\n\nARFF Progress: {"); var files = Directory.GetFiles(directory); var fivepercent = (int) Math.Floor((double) files.Length/20); arff.Append("% Steganography Benchmarking Data\n%\n"); arff.Append("% Sourced from automatic generation in Digital Invisible Ink Toolkit\n"); arff.Append("% Generator created by Kathryn Hempstalk.\n"); arff.Append("% Generator copyright under the Gnu General Public License, 2005\n"); arff.Append("\n"); arff.Append("\n@relation '" + relationname + "'\n\n"); //add all the headings if (mRunRsAnalysis) { var rsa = new RsAnalysis(2, 2); var rflag = "(rs overlapping)"; string colour; //overlapping for (var i = 0; i < 3; i++) { IEnumerable<string> rnames = rsa.GetResultNames(); //get the right colour if (i == 0) { colour = " red "; } else if (i == 1) { colour = " green "; } else { colour = " blue "; } foreach (var rname in rnames) { var aname = rname; var towrite = aname + colour + rflag; arff.Append("@attribute '" + towrite + "' numeric\n"); } } //non overlapping rflag = "(rs non-overlapping)"; for (var i = 0; i < 3; i++) { IEnumerable<string> rnames = rsa.GetResultNames(); //get the right colour if (i == 0) { colour = " red "; } else if (i == 1) { colour = " green "; } else { colour = " blue "; } foreach (var rname in rnames) { var aname = rname; var towrite = aname + colour + rflag; arff.Append("@attribute '" + towrite + "' numeric\n"); } } } if (mRunSamplePairs) { string colour; //overlapping for (var i = 0; i < 3; i++) { //get the right colour if (i == 0) { colour = " red "; } else if (i == 1) { colour = " green "; } else { colour = " blue "; } arff.Append("@attribute 'SP Percentage" + colour + "' numeric\n"); arff.Append("@attribute 'SP Approximate Bytes" + colour + "' numeric\n"); } } if (mRunLaplaceGraph) { for (var i = 0; i < laplacelimit; i++) { arff.Append("@attribute 'Laplace value " + i + "' numeric\n"); } } arff.Append("@attribute 'Steganography Type' {"); //iterate through all the hashmap values... var stegotypes = GetStegTypes(Directory.GetFiles(directory)); var valuesarray = stegotypes.Values.ToArray(); arff.Append(valuesarray[0]); for (var i = 1; i < valuesarray.Length; i++) { arff.Append("," + valuesarray[i]); } arff.Append("}\n"); arff.Append("@attribute 'Image Name' string\n"); arff.Append("\n@data\n"); //check all the files for (var i = 0; i < files.Length; i++) { //print progress if (i > 0 && fivepercent > 0) { if (i%fivepercent == 0 && i != 0) { Console.WriteLine("#"); } } if (files[i].EndsWith(".bmp") || files[i].EndsWith(".png") || files[i].EndsWith(".jpg")) { //file can be worked on. try { using (var bitmap = new Bitmap(files[i])) { var image = new LockBitmap(bitmap); image.LockBits(); //run RS analysis if (mRunRsAnalysis) { //overlapping for (var j = 0; j < 3; j++) { var rsa = new RsAnalysis(2, 2); var testresults = rsa.DoAnalysis(image, j, true); for (var k = 0; k < testresults.Length; k++) { arff.Append(testresults[k] + ","); } } //non-overlapping for (var j = 0; j < 3; j++) { var rsa = new RsAnalysis(2, 2); var testresults = rsa.DoAnalysis(image, j, false); for (var k = 0; k < testresults.Length; k++) { arff.Append(testresults[k] + ","); } } } //run Sample Pairs if (mRunSamplePairs) { //overlapping for (var j = 0; j < 3; j++) { var sp = new SamplePairs(); var estimatedlength = sp.DoAnalysis(image, j); var numbytes = image.Height*image.Width*3/8 *(estimatedlength/100); arff.Append(estimatedlength + "," + numbytes + ","); } } //run LaplaceGraph if (mRunLaplaceGraph) { var lgres = LaplaceGraph.GetGraph(image); for (var j = 0; j < laplacelimit; j++) { if (lgres.Length <= laplacelimit && j >= lgres.Length) { arff.Append("0,"); } else { if (lgres[j][0] != j) { arff.Append("0,"); } else { arff.Append(lgres[j][1] + ","); } } } } string flag; if (files[i].IndexOf("_") >= 0 || files[i].IndexOf("-") >= 0) { if (files[i].IndexOf("_") >= 0) { flag = files[i].Substring(files[i].IndexOf("_") + 1, files[i].LastIndexOf(".")); } else { flag = files[i].Substring(files[i].IndexOf("-") + 1, files[i].LastIndexOf(".")); } } else { flag = "none"; } arff.Append(flag); arff.Append("," + files[i]); if (arff[arff.Length - 1] == ',') { arff.Remove(arff.Length - 1, 1); } arff.Append("\n"); image.UnlockBits(); } } catch (Exception) { //skip the file... } //cleanup to speed up memory GC.Collect(); } } //all done Console.WriteLine("} Complete!"); return arff.ToString(); }
/** * Does sample pairs analysis on an image. * * @param image The image to analyse. */ public double DoAnalysis(LockBitmap image, int colour) { //get the images sizes int imgx = image.Width, imgy = image.Height; int startx = 0, starty = 0; var apair = new Color[2]; int u, v; long P, X, Y, Z; long W; P = X = Y = Z = W = 0; //pairs across the image for (starty = 0; starty < imgy; starty++) { for (startx = 0; startx < imgx; startx = startx + 2) { //get the block of data (2 pixels) apair[0] = image.GetPixel(startx, starty); apair[1] = image.GetPixel(startx + 1, starty); u = GetPixelColour(apair[0], colour); v = GetPixelColour(apair[1], colour); //if the 7 msb are the same, but the 1 lsb are different if ((u >> 1 == v >> 1) && ((v & 0x1) != (u & 0x1))) W++; //if the pixels are the same if (u == v) Z++; //if lsb(v) = 0 & u < v OR lsb(v) = 1 & u > v if ((v == (v >> 1) << 1) && (u < v) || (v != (v >> 1) << 1) && (u > v)) X++; //vice versa if ((v == (v >> 1) << 1) && (u > v) || (v != (v >> 1) << 1) && (u < v)) Y++; P++; } } //pairs down the image for (starty = 0; starty < imgy; starty = starty + 2) { for (startx = 0; startx < imgx; startx++) { //get the block of data (2 pixels) apair[0] = image.GetPixel(startx, starty); apair[1] = image.GetPixel(startx, starty + 1); u = GetPixelColour(apair[0], colour); v = GetPixelColour(apair[1], colour); //if the 7 msb are the same, but the 1 lsb are different if ((u >> 1 == v >> 1) && ((v & 0x1) != (u & 0x1))) W++; //the pixels are the same if (u == v) Z++; //if lsb(v) = 0 & u < v OR lsb(v) = 1 & u > v if ((v == (v >> 1) << 1) && (u < v) || (v != (v >> 1) << 1) && (u > v)) X++; //vice versa if ((v == (v >> 1) << 1) && (u > v) || (v != (v >> 1) << 1) && (u < v)) Y++; P++; } } //solve the quadratic equation //in the form ax^2 + bx + c = 0 var a = 0.5*(W + Z); double b = 2*X - P; double c = Y - X; //the result double x; //straight line if (a == 0) x = c/b; //curve //take it as a curve var discriminant = Math.Pow(b, 2) - 4*a*c; if (discriminant >= 0) { var rootpos = (-1*b + Math.Sqrt(discriminant))/(2*a); var rootneg = (-1*b - Math.Sqrt(discriminant))/(2*a); //return the root with the smallest absolute value (as per paper) if (Math.Abs(rootpos) <= Math.Abs(rootneg)) x = rootpos; else x = rootneg; } else { x = c/b; } if (x == 0) { //let's assume straight lines again, something is probably wrong x = c/b; } return x; }
public Laplace(LockBitmap image, int startbits, int endbits) : base(image, startbits, endbits) { }
/** * Gets the laplace graph of an image. The image * is assumed to be colour, no negative values will * result. * * @param image The image to get the graph of. * @return The graph of the image. */ public static double[][] GetGraph(LockBitmap image) { var filter = new Laplace(image, 0, 8); //filter the image var fparray = new FilteredPixel[image.Width*image.Height]; for (var i = 0; i < image.Width; i++) { for (var j = 0; j < image.Height; j++) { fparray[i*image.Height + j] = new FilteredPixel(i, j, Math.Abs(filter.GetValue(i, j))); } } //sort the filter results //is in ascending order - low at start, high at end Array.Sort(fparray, new FpComparator()); //now for each individual filter result, we count how many we have //first find out how many different values we have var numdistinct = 1; for (var i = 1; i < fparray.Length; i++) { if (fparray[i].FilterValue != fparray[i - 1].FilterValue) { numdistinct++; } } //now we create an array to hold the filter values and their counts //var results = new double[numdistinct][2]; var results = new double[numdistinct][]; for (var i = 0; i < results.Length; i++) { results[i] = new double[2]; } results[0][0] = fparray[0].FilterValue; results[0][1] = 1; var k = 0; //now we fill up the array foreach (var t in fparray) { if (results[k][0] != t.FilterValue) { k++; results[k][0] = t.FilterValue; results[k][1] = 1; } else { results[k][1]++; } } //now normalise the graph foreach (var t in results) { t[1] = t[1]/fparray.Length; } //graph produced, return results return results; }