// write minimal and maximal values of coordinates used for normalization and denormalization of data public static void writeMinMax <T, U>(char mode, CoordinatesContainer <T> minMax, CoordinatesContainer <U> faceModeMinMax = null) { bool boolMode = (mode == Constants.faceMode ? true : false); TextWriter writer = new StreamWriter(CaptureLabel.exportMinMaxDirectory, false, Encoding.UTF8); CsvSerializer serializer = new CsvSerializer(writer, System.Globalization.CultureInfo.CurrentCulture); CsvWriter csv = new CsvWriter(serializer); List <List <T> > minMaxT = new List <List <T> >(minMax.getCoordinates()); minMaxT = Enumerable.Range(0, minMaxT[0].Count) .Select(i => minMaxT.Select(lst => lst[i]).ToList()).ToList(); csv.WriteField(""); // check which mode is selected to construct appropriate header string[] rectNames = (boolMode) ? Constants.rectangleNameF : (mode == Constants.faceElementsMode ? Constants.rectangleNameE : Constants.rectangleNameG); // construct header foreach (string s in rectNames) { csv.WriteField(s); csv.WriteField(""); } if (boolMode) { csv.WriteField("Face width:"); } csv.NextRecord(); csv.WriteField(""); for (int i = 0; i < rectNames.Length; i++) { csv.WriteField("(x,"); csv.WriteField("y)"); } csv.NextRecord(); csv.WriteField("Min:"); // write minimal and maximal values to .csv file for (int i = 0; i < minMaxT.Count; i++) { for (int j = 0; j < minMaxT[i].Count; j++) { csv.WriteField(minMaxT[i][j]); } if (mode == Constants.faceMode && faceModeMinMax != null) { csv.WriteField(faceModeMinMax.getRow(0)[i]); } csv.NextRecord(); csv.WriteField("Max:"); } writer.Close(); }
// correct face rectangle coordinates because stored coordinates are coordinates // of top left corner of the rectangle and we need central point for neural network input public static void correctFaceCoordinates(CoordinatesContainer <int> realCoordinatesList, CoordinatesContainer <int> faceModeSize, List <double> imageResizeFactor, double scale, bool reverse = false) { int i = 0; // scale faceModeSize (face width) to get real coordinates of face right if (!reverse) { foreach (List <int> l in faceModeSize.getCoordinates()) { l[0] = (int)(Math.Round(l[0] / imageResizeFactor[i], MidpointRounding.AwayFromZero)); i++; } } i = 0; // correction factor for the first if face mode foreach (List <int> l in realCoordinatesList.getCoordinates()) { int halfWidth = (reverse == false ? faceModeSize.getRow(i)[0] / 2 : -faceModeSize.getRow(i)[0] / 2); l[0] = l[0] + halfWidth; l[1] = l[1] + (int)(Math.Round(halfWidth * scale, MidpointRounding.AwayFromZero)); i++; } i = 0; // scale faceModeSize (face width) to get relative coordinates (rectangleCoordinates) of face right if (reverse) { foreach (List <int> l in faceModeSize.getCoordinates()) { l[0] = (int)(Math.Round(l[0] * imageResizeFactor[i], MidpointRounding.AwayFromZero)); i++; } } }
// exports values to normalized .csv file based on current work mode private void exportNormalized() { Tuple <List <List <double> >, List <List <int> > > normalized; Tuple <List <List <double> >, List <List <int> > > normalizedFS; CoordinatesContainer <double> normalizedCoordinates; CoordinatesContainer <double> normalizedFaceSize; CoordinatesContainer <int> minMaxCoord; CoordinatesContainer <int> minMaxFS; // save current image index values saveCoordinates(); // export logic for face mode if (mode == Constants.faceMode) { // correct face coordinates Utilities.correctFaceCoordinates(realCoordinatesList, faceModeSize, imageResizeFactor, Constants.modeFRectScale); // normalize coordinates and face size values normalized = Utilities.normalizeOutput <double, int>(realCoordinatesList); normalizedFS = Utilities.normalizeOutput <double, int>(faceModeSize); // asing values to appropriate value containers normalizedCoordinates = new CoordinatesContainer <double>(normalized.Item1); minMaxCoord = new CoordinatesContainer <int>(normalized.Item2); normalizedFaceSize = new CoordinatesContainer <double>(normalizedFS.Item1); minMaxFS = new CoordinatesContainer <int>(normalizedFS.Item2); // write normalized coordinates .csv file Utilities.writeToCSV(mode, normalizedCoordinates, imageNames, lookAngleContainer, normalizedFaceSize, isFacePresent, normalized: true); // create .csv file with minimal and maximal values needed for denormalization Utilities.writeMinMax(mode, minMaxCoord, minMaxFS); // correct face coordinates Utilities.correctFaceCoordinates(realCoordinatesList, faceModeSize, imageResizeFactor, Constants.modeFRectScale, true); } // export logic for face elements mode and eye countour mode else { // normalize coordinates and face size values normalized = Utilities.normalizeOutput <double, int>(realCoordinatesList, faceModeSize, Constants.faceElementsMode); normalizedFS = Utilities.normalizeOutput <double, int>(faceModeSize); // asing values to appropriate value containers normalizedCoordinates = new CoordinatesContainer <double>(normalized.Item1); minMaxCoord = new CoordinatesContainer <int>(normalized.Item2); normalizedFaceSize = new CoordinatesContainer <double>(normalizedFS.Item1); minMaxFS = new CoordinatesContainer <int>(normalizedFS.Item2); // write normalized coordinates .csv file Utilities.writeToCSV(mode, normalizedCoordinates, imageNames, lookAngleContainer, faceModeSize, eyesNotVisibleContainer: eyesNotVisibleContainer, elementState: eyeClosed, normalized: true); // create .csv file with minimal and maximal values needed for denormalization Utilities.writeMinMax(mode, minMaxCoord, minMaxFS); } }
// parsing face elements mode values from .csv file public static Tuple <List <int>, List <CoordinatesContainer <int> > > parseFaceElements(List <List <int> > lines) { List <int> item1 = new List <int>(); List <CoordinatesContainer <int> > item2 = new List <CoordinatesContainer <int> >(); CoordinatesContainer <int> eyesNotVisibleContainer = new CoordinatesContainer <int>(); CoordinatesContainer <int> realCoordinates = new CoordinatesContainer <int>(); CoordinatesContainer <int> lookAngleContainer = new CoordinatesContainer <int>(); CoordinatesContainer <int> faceModeSize = new CoordinatesContainer <int>(); List <int> singleRow = new List <int>(); // interate rough rows of values and parse them appropriately foreach (List <int> line in lines) { singleRow.Add(line[0]); singleRow.Add(line[1]); List <int> temp = new List <int>(singleRow); eyesNotVisibleContainer.addRow(temp); singleRow.Clear(); for (int i = 2; i < 12; i++) { singleRow.Add(line[i]); } temp = new List <int>(singleRow); realCoordinates.addRow(temp); singleRow.Clear(); for (int i = 12; i < 16; i++) { singleRow.Add(line[i]); } temp = new List <int>(singleRow); lookAngleContainer.addRow(temp); singleRow.Clear(); singleRow.Add(line[16]); temp = new List <int>(singleRow); faceModeSize.addRow(temp); singleRow.Clear(); } item2.Add(realCoordinates); item2.Add(lookAngleContainer); item2.Add(faceModeSize); item2.Add(eyesNotVisibleContainer); return(Tuple.Create(item1, item2)); }
// clean up function // called when importing or re-importing data and when New is selected from the File menu private void cleanUp() { imagePathTB.ReadOnly = false; csvPathTB.ReadOnly = false; csvFileName = "newCsv.csv"; imageLocation = null; imageNames = null; imageResizeFactor = null; imagePadX = null; imagePadY = null; rectangles = null; coordinatesList = null; realCoordinatesList = null; faceModeSize = null; lookAngleContainer = null; eyesNotVisibleContainer = null; isFacePresent = null; eyeClosed = null; currentImageIndex = 0; isLoaded = false; someoneIsInFocus = false; savedAs = false; imageLocation = new List <string>(); imageNames = new List <string>(); imageResizeFactor = new List <double>(); imagePadX = new List <double>(); imagePadY = new List <double>(); coordinatesList = new CoordinatesContainer <int>(); realCoordinatesList = new CoordinatesContainer <int>(); faceModeSize = new CoordinatesContainer <int>(); lookAngleContainer = new CoordinatesContainer <int>(); eyesNotVisibleContainer = new CoordinatesContainer <int>(); isFacePresent = new List <int>(); eyeClosed = new List <int>(); }
// write relevant information to .csv file that is not normalized public static void writeToCSV <T, U, X>(char mode, CoordinatesContainer <T> realCoordinatesList, List <string> imageNames, CoordinatesContainer <U> lookAngleContainer, CoordinatesContainer <X> faceModeSize, List <int> elementState = null, CoordinatesContainer <U> eyesNotVisibleContainer = null, bool normalized = false) { // should be embedded in try-catch string csvPath = (normalized == true ? CaptureLabel.exportDirectory : CaptureLabel.saveDirectory); TextWriter writer = new StreamWriter(@csvPath, false, Encoding.UTF8); CsvSerializer serializer = new CsvSerializer(writer, System.Globalization.CultureInfo.CurrentCulture); CsvWriter csv = new CsvWriter(serializer); csv.WriteField(""); string[] rectNames = ((mode == Constants.faceMode) ? Constants.rectangleNameF : (mode == Constants.faceElementsMode ? Constants.rectangleNameE : Constants.rectangleNameG)); // construct header if (mode == Constants.faceMode) { csv.WriteField("noFace"); } if (mode == Constants.faceElementsMode) { csv.WriteField("noLeftEye"); csv.WriteField("noRightEye"); } if (mode == Constants.eyeContourMode) { csv.WriteField("eyeClosed"); } foreach (string s in rectNames) { csv.WriteField(s); csv.WriteField(""); } foreach (string s in Constants.lookingAngleString) { csv.WriteField(s); } if (mode == Constants.eyeContourMode) { csv.WriteField("Eye width:"); } else { csv.WriteField("Face width:"); } csv.NextRecord(); csv.WriteField("Picture:"); csv.WriteField(""); if (mode == Constants.faceElementsMode) { csv.WriteField(""); } for (int i = 0; i < rectNames.Length; i++) { csv.WriteField("(x,"); csv.WriteField("y)"); } csv.NextRecord(); // write rectangle coordinates to .csv file based on mode for (int i = 0; i < realCoordinatesList.getSize(); i++) { csv.WriteField(imageNames[i]); if (mode != Constants.faceElementsMode) { csv.WriteField(elementState[i]); } if (mode == Constants.faceElementsMode) { foreach (U value in eyesNotVisibleContainer.getRow(i)) { csv.WriteField(value); } } foreach (T value in realCoordinatesList.getRow(i)) { csv.WriteField(value); } foreach (U value in lookAngleContainer.getRow(i)) { csv.WriteField(value); } csv.WriteField(faceModeSize.getRow(i)[0]); csv.NextRecord(); } writer.Close(); }
// normalize output values for face elements and eye countour mode public static Tuple <List <List <T> >, List <List <int> > > normalizeOutputFaceElements <T, U>(CoordinatesContainer <U> realCoordinatesList, CoordinatesContainer <int> faceModeSize) { List <List <U> > coordinates = new List <List <U> >(realCoordinatesList.getCoordinates()); List <List <int> > minMaxValues = new List <List <int> >(); List <List <T> > result = new List <List <T> >(); // normalize elements int i = 0; foreach (List <U> l in coordinates) { int faceWidth = faceModeSize.getRow(i)[0]; List <T> temp = new List <T>(); // normalize output with formula: // Xnorm = (X - Xmin) / (Xmax - Xmin) for (int j = 0; j < l.Count; j += 2) { double valX = (double)(Convert.ToDouble(l[j]) / faceWidth); double valY = (double)(Convert.ToDouble(l[j + 1]) / (faceWidth * Constants.modeFRectScale)); // if value is not a number set it to zero if (Double.IsNaN(valX) || Double.IsNaN(valY)) { valX = 0; valY = 0; } temp.Add((T)(object)valX); temp.Add((T)(object)valY); } result.Add(temp); i++; } return(Tuple.Create(result, minMaxValues)); }
// normalize output values for face mode public static Tuple <List <List <T> >, List <List <int> > > normalizeOutputFaceMode <T, U>(CoordinatesContainer <U> realCoordinatesList) { List <List <U> > coordinates = new List <List <U> >(realCoordinatesList.getCoordinates()); List <List <int> > minMaxValues = new List <List <int> >(); List <List <T> > result = new List <List <T> >(); // transpose elements coordinates = Enumerable.Range(0, coordinates[0].Count) .Select(i => coordinates.Select(lst => lst[i]).ToList()).ToList(); // normalize elements foreach (List <U> l in coordinates) { int min = Convert.ToInt32(l.Min()); int max = Convert.ToInt32(l.Max()); minMaxValues.Add(new List <int>() { min, max }); List <T> temp = new List <T>(); // normalize output with formula: // Xnorm = (X - Xmin) / (Xmax - Xmin) for (int i = 0; i < l.Count; i++) { double val = (double)(Convert.ToInt32(l[i]) - min) / (max - min); // if value is not a number set it to zero if (Double.IsNaN(val)) { val = 0; } temp.Add((T)(object)val); } result.Add(temp); } // transpose elements result = Enumerable.Range(0, result[0].Count) .Select(i => result.Select(lst => lst[i]).ToList()).ToList(); return(Tuple.Create(result, minMaxValues)); }
// called as part of the private void exportNormalized() function // normalize output values to be saved to new .csv file public static Tuple <List <List <T> >, List <List <int> > > normalizeOutput <T, U>(CoordinatesContainer <U> realCoordinatesList, CoordinatesContainer <int> faceModeSize = null, char mode = 'f') { Tuple <List <List <T> >, List <List <int> > > normalized; if (mode == Constants.faceMode) { normalized = normalizeOutputFaceMode <T, U>(realCoordinatesList); } else { normalized = normalizeOutputFaceMode <T, U>(realCoordinatesList); } return(normalized); }
// used for parsing face elements mode and eye contour mode .csv files public static Tuple <List <int>, List <CoordinatesContainer <int> > > parseTypeOneCSV(char mode, List <List <int> > lines) { List <int> item1 = new List <int>(); List <CoordinatesContainer <int> > item2 = new List <CoordinatesContainer <int> >(); CoordinatesContainer <int> realCoordinates = new CoordinatesContainer <int>(); CoordinatesContainer <int> lookAngleContainer = new CoordinatesContainer <int>(); CoordinatesContainer <int> faceModeSize = new CoordinatesContainer <int>(); List <int> singleRow = new List <int>(); int iCoordLow = 0; int iCoordHigh = 0; // sets starting reading positions base on the working mode if (mode == Constants.faceMode) { iCoordLow = 7; iCoordHigh = 11; } else if (mode == Constants.eyeContourMode) { iCoordLow = 11; iCoordHigh = 15; } // interate rough rows of values and parse them appropriately foreach (List <int> line in lines) { item1.Add(line[0]); for (int i = 1; i < iCoordLow; i++) { singleRow.Add(line[i]); } List <int> temp = new List <int>(singleRow); realCoordinates.addRow(temp); singleRow.Clear(); for (int i = iCoordLow; i < iCoordHigh; i++) { singleRow.Add(line[i]); } temp = new List <int>(singleRow); lookAngleContainer.addRow(temp); singleRow.Clear(); singleRow.Add(line[iCoordHigh]); temp = new List <int>(singleRow); faceModeSize.addRow(temp); singleRow.Clear(); } item2.Add(realCoordinates); item2.Add(lookAngleContainer); item2.Add(faceModeSize); return(Tuple.Create(item1, item2)); }
// import button logic private void importButton_Click(object sender, EventArgs e) { Cursor.Current = Cursors.WaitCursor; // release everything from memory before new import (or new import) cleanUp(); // initialize selected mode initMode(mode); try { // get list of everything in folder passed to imageFolder imageLocation = new List <string>(Directory.GetFiles(imageFolder)); csvFileName = new DirectoryInfo(imageFolder).Name; var sortedFiles = Directory.GetFiles(@"C:\", "*").OrderByDescending(d => new FileInfo(d).CreationTime); // Parse list of image locations to contain only image locations imageLocation = Utilities.parseImagesToList(imageLocation); // import only if there are images found in folder if (imageLocation.Count > 0) { // set imagePanel to first image imagePanel.BackgroundImage = Image.FromFile(imageLocation[0]); currentImageIndex = 0; // extract image names foreach (string name in imageLocation) { imageNames.Add(Path.GetFileNameWithoutExtension(name)); } // check for existing .csv file if (!String.IsNullOrEmpty(csvPath) && csvPath.Contains(".csv")) { // parse .csv file based on mode selected Tuple <List <int>, List <CoordinatesContainer <int> > > tempCSV = Utilities.parseCSV(csvPath, mode); // set mode relevant fields if (mode == Constants.faceMode) { isFacePresent = tempCSV.Item1; } if (mode == Constants.faceElementsMode) { eyesNotVisibleContainer = new CoordinatesContainer <int>(tempCSV.Item2[3]); } if (mode == Constants.eyeContourMode) { eyeClosed = tempCSV.Item1; } // set relevant fields to ones that are parsed from .csv file realCoordinatesList = new CoordinatesContainer <int>(tempCSV.Item2[0]); lookAngleContainer = new CoordinatesContainer <int>(tempCSV.Item2[1]); faceModeSize = new CoordinatesContainer <int>(tempCSV.Item2[2]); // calculate resize factor between original image and image on the imagePanel for (int i = 0; i < imageNames.Count; i++) { imagePanel.BackgroundImage = Image.FromFile(imageLocation[i]); calculateResizeFactor(i); imagePanel.BackgroundImage.Dispose(); } // correct face coordinates if (mode == Constants.faceMode) { Utilities.correctFaceCoordinates(realCoordinatesList, faceModeSize, imageResizeFactor, Constants.modeFRectScale, true); } List <int> singleRow; // set rectangle coordinates based on real one read from .csv file for (int i = 0; i < realCoordinatesList.getSize(); i++) { singleRow = realCoordinatesList.getRow(i); coordinatesList.addRow(new List <int>(calculateRectangleCoordinates(singleRow, i))); } // load currentImageIndex image from file and load associated coordinates imagePanel.BackgroundImage = Image.FromFile(imageLocation[currentImageIndex]); loadCoordinates(currentImageIndex); } imagePathTB.ReadOnly = true; loaded = true; } } // catch if something went wrong in the section above catch (Exception msg) { imagePathTB.ReadOnly = false; MessageBox.Show(msg.Message, Constants.errorCaption, MessageBoxButtons.OK, MessageBoxIcon.Error); return; } imagePanel.Refresh(); Cursor.Current = Cursors.Default; }
// copy constructor public CoordinatesContainer(CoordinatesContainer <T> container) { rowCoordinates = new List <List <T> >(container.getCoordinates()); }