Пример #1
0
        /// <summary>
        /// Converts summary indices to a tracks image, one track for each index.
        /// </summary>
        public static Image <Rgb24> DrawImageOfSummaryIndices(
            Dictionary <string, IndexProperties> listOfIndexProperties,
            Dictionary <string, double[]> dictionaryOfSummaryIndices,
            string titleText,
            TimeSpan indexCalculationDuration,
            DateTimeOffset?recordingStartDate,
            List <GapsAndJoins> errors = null,
            bool verbose = true)
        {
            const int trackHeight      = DefaultTrackHeight;
            int       scaleLength      = 0;
            var       backgroundColour = Color.White;

            // init list of bitmap images to store image tracks
            var bitmapList = new List <Tuple <IndexProperties, Image <Rgb24> > >(dictionaryOfSummaryIndices.Keys.Count);

            // set up strings to store info about which indices are used
            var s1 = new StringBuilder("Indices not found:");
            var s2 = new StringBuilder("Indices not plotted:");

            // accumulate the individual tracks in a List
            foreach (string key in dictionaryOfSummaryIndices.Keys)
            {
                if (!listOfIndexProperties.ContainsKey(key))
                {
                    s1.Append(" {0},".Format2(key));
                    continue;
                }

                IndexProperties ip = listOfIndexProperties[key];
                if (!ip.DoDisplay)
                {
                    s2.Append(" {0},".Format2(key));
                    continue;
                }

                //string name = ip.Name;
                double[] array = dictionaryOfSummaryIndices[key];
                scaleLength = array.Length;

                // alternate rows have different colour to make tracks easier to read
                backgroundColour = backgroundColour == Color.LightGray ? Color.White : Color.LightGray;
                var bitmap = ip.GetPlotImage(array, backgroundColour, errors);
                bitmapList.Add(Tuple.Create(ip, bitmap));
            }

            if (verbose)
            {
                Logger.Warn(s1.ToString());
                Logger.Warn(s2.ToString());
            }

            var listOfBitmaps = bitmapList

                                //    .OrderBy(tuple => tuple.Item1.Order) // don't order because want to preserve alternating gray/white rows.
                                .Select(tuple => tuple.Item2)
                                .Where(b => b != null).ToList();

            //set up the composite image parameters
            int           x_offset   = 2;
            int           graphWidth = x_offset + scaleLength;
            int           imageWidth = x_offset + scaleLength + TrackEndPanelWidth;
            Image <Rgb24> titleBmp   = ImageTrack.DrawTitleTrack(imageWidth, trackHeight, titleText);

            TimeSpan       xAxisPixelDuration = indexCalculationDuration;
            TimeSpan       fullDuration       = TimeSpan.FromTicks(xAxisPixelDuration.Ticks * graphWidth);
            Image <Rgb24>  timeBmp1           = ImageTrack.DrawTimeRelativeTrack(fullDuration, graphWidth, trackHeight);
            Image <Rgb24>  timeBmp2           = timeBmp1;
            DateTimeOffset?dateTimeOffset     = recordingStartDate;

            if (dateTimeOffset.HasValue)
            {
                // draw extra time scale with absolute start time. AND THEN Do SOMETHING WITH IT.
                timeBmp2 = ImageTrack.DrawTimeTrack(fullDuration, dateTimeOffset, graphWidth, trackHeight);
            }

            //draw the composite bitmap
            var imageList = new List <Image <Rgb24> >
            {
                titleBmp,
                timeBmp1,
            };

            foreach (var image in listOfBitmaps)
            {
                imageList.Add(image);
            }

            imageList.Add(timeBmp2);
            var compositeBmp = (Image <Rgb24>)ImageTools.CombineImagesVertically(imageList);

            return(compositeBmp);
        }
        // ##############################################################################################################
        // ######################### ORIGINAL METHOD FOR STITCHING  Gianna Pavan's DATA (10 minutes every 30 minutes)

        /// <summary>
        /// This method stitches together spectrogram images derived from consecutive shorter recordings over a 24 hour period.
        /// Currently set for the recording protocol of Gianna Pavan (10 minutes every 30 minutes).
        ///
        /// Call this method from Sandpit or where ever!
        ///
        /// IMPORTANT NOTE: This method does NOT check to see if the images are in temporal order.
        ///                 A SORT line should be inserted somewhere
        /// </summary>
        public static void StitchPartialSpectrograms()
        {
            //######################################################
            // ********************* set the below parameters
            var    inputDirectory  = new DirectoryInfo(@"Z:\Italy_GianniPavan\output4\Towsey.Acoustic");
            string opFileStem      = "Sassofratino_24hours_v3";
            var    outputDirectory = new DirectoryInfo(@"Z:\Italy_GianniPavan\output4\");

            // a filter to select images to be stitched
            string endString = "_000.2MAPS.png";

            // recording protocol
            int      minutesBetweenRecordingStarts = 30;
            TimeSpan minOffset = TimeSpan.Zero; // assume first recording in sequence started at midnight

            // X-axis timescale
            int pixelColumnsPerHour = 60;
            int trackHeight         = IndexDisplay.DefaultTrackHeight;

            // ********************* set the above parameters
            //######################################################

            string[] fileEntries       = Directory.GetFiles(inputDirectory.FullName);
            var      images            = new List <Image>();
            bool     interpolateSpacer = true;
            var      imagePair         = new Image[2];

            TimeSpan xAxisTicInterval = TimeSpan.FromMinutes(pixelColumnsPerHour); // assume 60 pixels per hour

            // loop through all files in the required directory
            foreach (string path in fileEntries)
            {
                // filter files.
                if (!path.EndsWith(endString))
                {
                    continue;
                }

                var image       = new Bitmap(path);
                int spacerWidth = minutesBetweenRecordingStarts - image.Width;

                if (interpolateSpacer)
                {
                    var spacer = new Bitmap(spacerWidth, image.Height);
                    imagePair[0] = image;
                    imagePair[1] = spacer;
                    image        = (Bitmap)ImageTools.CombineImagesInLine(imagePair);
                }

                images.Add(image);
            }

            var compositeBmp = ImageTools.CombineImagesInLine(images.ToArray());

            var fullDuration = TimeSpan.FromMinutes(compositeBmp.Width);
            var timeBmp      = ImageTrack.DrawTimeTrack(fullDuration, minOffset, xAxisTicInterval, compositeBmp.Width, trackHeight, "hours");

            var gr         = Graphics.FromImage(compositeBmp);
            int halfHeight = compositeBmp.Height / 2;

            //add in the title bars
            string title    = $"24 hour FALSE-COLOUR SPECTROGRAM      (scale: hours x kHz)      (colour: R-G-B = BGN-AVG-CVR)         {Meta.OrganizationTag}  ";
            var    titleBmp = ImageTrack.DrawTitleTrack(compositeBmp.Width, trackHeight, title);
            int    offset   = 0;

            gr.DrawImage(titleBmp, 0, offset); //draw in the top time scale
            title    = $"24 hour FALSE-COLOUR SPECTROGRAM      (scale: hours x kHz)      (colour: R-G-B = ACI-ENT-EVN)         {Meta.OrganizationTag}  ";
            titleBmp = ImageTrack.DrawTitleTrack(compositeBmp.Width, trackHeight, title);
            offset   = halfHeight;
            gr.DrawImage(titleBmp, 0, offset); //draw in the top time scale

            //add in the timescale tracks
            offset = trackHeight;
            gr.DrawImage(timeBmp, 0, offset); //draw in the top time scale
            offset = compositeBmp.Height - trackHeight;
            gr.DrawImage(timeBmp, 0, offset); //draw in the top time scale
            offset = halfHeight - trackHeight;
            gr.DrawImage(timeBmp, 0, offset); //draw in the top time scale
            offset = halfHeight + trackHeight;
            gr.DrawImage(timeBmp, 0, offset); //draw in the top time scale

            compositeBmp.Save(Path.Combine(outputDirectory.FullName, opFileStem + ".png"));
        }
Пример #3
0
        /// <summary>
        /// Converts summary indices to a tracks image
        /// </summary>
        /// <param name="listOfIndexProperties"></param>
        /// <param name="dictionaryOfSummaryIndices"></param>
        /// <param name="titleText"></param>
        /// <param name="indexCalculationDuration"></param>
        /// <param name="recordingStartDate"></param>
        /// <param name="sunriseDataFile"></param>
        /// <param name="errors"></param>
        public static Bitmap DrawImageOfSummaryIndices(
            Dictionary <string, IndexProperties> listOfIndexProperties,
            Dictionary <string, double[]> dictionaryOfSummaryIndices,
            string titleText,
            TimeSpan indexCalculationDuration,
            DateTimeOffset?recordingStartDate,
            FileInfo sunriseDataFile   = null,
            List <GapsAndJoins> errors = null,
            bool verbose = false)
        {
            // to translate past keys into current keys
            Dictionary <string, string> translationDictionary = InitialiseIndexProperties.GetKeyTranslationDictionary();

            const int trackHeight = DefaultTrackHeight;
            int       scaleLength = 0;
            var       bitmapList  = new List <Tuple <IndexProperties, Image> >(dictionaryOfSummaryIndices.Keys.Count);

            // accumulate the individual tracks in a List
            foreach (string key in dictionaryOfSummaryIndices.Keys)
            {
                string correctKey = key;
                if (!listOfIndexProperties.ContainsKey(key))
                {
                    if (translationDictionary.ContainsKey(key))
                    {
                        correctKey = translationDictionary[key];
                        LoggedConsole.WriteWarnLine(
                            "The csv header is an unknown index <{0}>. Translated to <{1}>",
                            key,
                            correctKey);
                    }
                    else
                    {
                        if (verbose)
                        {
                            Logger.Warn(
                                "A index properties configuration could not be found for {0} (not even in the translation directory). Property is ignored and not rendered"
                                .Format2(key));
                        }

                        continue;
                    }
                }

                IndexProperties ip = listOfIndexProperties[correctKey];
                if (!ip.DoDisplay)
                {
                    continue;
                }

                string   name  = ip.Name;
                double[] array = dictionaryOfSummaryIndices[key];
                scaleLength = array.Length;
                Image bitmap = ip.GetPlotImage(array, errors);

                bitmapList.Add(Tuple.Create(ip, bitmap));
            }

            var listOfBitmaps = bitmapList
                                .OrderBy(tuple => tuple.Item1.Order)
                                .Select(tuple => tuple.Item2)
                                .Where(b => b != null).ToList();

            //set up the composite image parameters
            int      X_offset      = 2;
            int      graphWidth    = X_offset + scaleLength;
            int      imageWidth    = X_offset + scaleLength + TrackEndPanelWidth;
            TimeSpan scaleDuration = TimeSpan.FromMinutes(scaleLength);
            int      imageHt       = trackHeight * (listOfBitmaps.Count + 4); //+3 for title and top and bottom time tracks
            Bitmap   titleBmp      = ImageTrack.DrawTitleTrack(imageWidth, trackHeight, titleText);

            //Bitmap time1Bmp = ImageTrack.DrawTimeTrack(scaleDuration, TimeSpan.Zero, DrawSummaryIndices.TimeScale, graphWidth, TrackHeight, "Time (hours)");
            TimeSpan       xAxisPixelDuration = indexCalculationDuration;
            TimeSpan       fullDuration       = TimeSpan.FromTicks(xAxisPixelDuration.Ticks * graphWidth);
            Bitmap         timeBmp1           = ImageTrack.DrawTimeRelativeTrack(fullDuration, graphWidth, trackHeight);
            Bitmap         timeBmp2           = timeBmp1;
            Bitmap         suntrack           = null;
            DateTimeOffset?dateTimeOffset     = recordingStartDate;

            if (dateTimeOffset.HasValue)
            {
                // draw extra time scale with absolute start time. AND THEN Do SOMETHING WITH IT.
                timeBmp2 = ImageTrack.DrawTimeTrack(fullDuration, dateTimeOffset, graphWidth, trackHeight);
                suntrack = SunAndMoon.AddSunTrackToImage(scaleLength, dateTimeOffset, sunriseDataFile);
            }

            //draw the composite bitmap
            var imageList = new List <Image>();

            imageList.Add(titleBmp);
            imageList.Add(timeBmp1);
            for (int i = 0; i < listOfBitmaps.Count; i++)
            {
                imageList.Add(listOfBitmaps[i]);
            }

            imageList.Add(timeBmp2);
            imageList.Add(suntrack);
            Bitmap compositeBmp = (Bitmap)ImageTools.CombineImagesVertically(imageList);

            return(compositeBmp);
        }
Пример #4
0
        public static void Execute(Arguments arguments)
        {
            var inputDirs = arguments.InputDataDirectories.Select(FileInfoExtensions.ToDirectoryInfo);
            var output    = arguments.OutputDirectory.ToDirectoryInfo();

            string date = "# DATE AND TIME: " + DateTime.Now;

            LoggedConsole.WriteLine("\n# DRAW an EASY IMAGE from consecutive days of SUMMARY INDICES in CSV files.");
            LoggedConsole.WriteLine("#    IT IS ASSUMED THAT THE CSV files are already concatenated into 24 hour files.");
            LoggedConsole.WriteLine(date);
            LoggedConsole.WriteLine("# Summary Index.csv files are in directories:");
            foreach (DirectoryInfo dir in inputDirs)
            {
                LoggedConsole.WriteLine("    {0}", dir.FullName);
            }

            LoggedConsole.WriteLine("# Output directory: " + output);
            if (arguments.StartDate == null)
            {
                LoggedConsole.WriteLine("# Start date = NULL (No argument provided). Will revise start date ....");
            }
            else
            {
                LoggedConsole.WriteLine("# Start date = " + arguments.StartDate.ToString());
            }

            if (arguments.EndDate == null)
            {
                LoggedConsole.WriteLine("# End   date = NULL (No argument provided). Will revise end date ....");
            }
            else
            {
                LoggedConsole.WriteLine("# End   date = " + arguments.EndDate.ToString());
            }

            LoggedConsole.WriteLine("# FILE FILTER = " + arguments.FileFilter);
            LoggedConsole.WriteLine();

            // PATTERN SEARCH FOR SUMMARY INDEX FILES.
            //string pattern = "*__Towsey.Acoustic.Indices.csv";
            FileInfo[] csvFiles = IndexMatrices.GetFilesInDirectories(inputDirs.ToArray(), arguments.FileFilter);

            //LoggedConsole.WriteLine("# Subdirectories Count = " + subDirectories.Length);
            LoggedConsole.WriteLine("# SummaryIndexFiles.csv Count = " + csvFiles.Length);

            if (csvFiles.Length == 0)
            {
                LoggedConsole.WriteErrorLine("\n\nWARNING from method DrawEasyImage.Execute():");
                LoggedConsole.WriteErrorLine("        No SUMMARY index files were found.");
                LoggedConsole.WriteErrorLine("        RETURNING EMPTY HANDED!");
                return;
            }

            // Sort the files by date and return as a dictionary: sortedDictionaryOfDatesAndFiles<DateTimeOffset, FileInfo>
            //var sortedDictionaryOfDatesAndFiles = LDSpectrogramStitching.FilterFilesForDates(csvFiles, arguments.TimeSpanOffsetHint);

            // calculate new start date if passed value = null.
            DateTimeOffset?startDate = arguments.StartDate;
            DateTimeOffset?endDate   = arguments.EndDate;

            TimeSpan totalTimespan = (DateTimeOffset)endDate - (DateTimeOffset)startDate;
            int      dayCount      = totalTimespan.Days + 1; // assume last day has full 24 hours of recording available.

            LoggedConsole.WriteLine("\n# Start date = " + startDate.ToString());
            LoggedConsole.WriteLine("# End   date = " + endDate.ToString());
            LoggedConsole.WriteLine(string.Format("# Elapsed time = {0:f1} hours", dayCount * 24));
            LoggedConsole.WriteLine("# Day  count = " + dayCount + " (inclusive of start and end days)");
            LoggedConsole.WriteLine("# Time Zone  = " + arguments.TimeSpanOffsetHint.ToString());

            // create top level output directory if it does not exist.
            DirectoryInfo opDir = output;

            if (!opDir.Exists)
            {
                opDir.Create();
            }

            // SET UP DEFAULT SITE LOCATION INFO    --  DISCUSS IWTH ANTHONY
            // The following location data is used only to draw the sunrise/sunset tracks on images.
            double?latitude        = null;
            double?longitude       = null;
            var    siteDescription = new SiteDescription();

            siteDescription.SiteName  = arguments.FileStemName;
            siteDescription.Latitude  = latitude;
            siteDescription.Longitude = longitude;

            // the following required if drawing the index images
            FileInfo indexPropertiesConfig = null;

            // require IndexGenerationData and indexPropertiesConfig for drawing
            //indexGenerationData = IndexGenerationData.GetIndexGenerationData(csvFiles[0].Directory);
            indexPropertiesConfig = arguments.IndexPropertiesConfig.ToFileInfo();
            Dictionary <string, IndexProperties>    listOfIndexProperties = IndexProperties.GetIndexProperties(indexPropertiesConfig);
            Tuple <List <string>, List <double[]> > tuple = CsvTools.ReadCSVFile(csvFiles[0].FullName);
            var names = tuple.Item1;

            // default EASY indices
            int    redID = 3; // backgroundNoise
            int    grnID = 5; // avSNROfActiveframes
            int    bluID = 7; // events per second
            string rep   = @"bgn-avsnr-evn";

            // ACI Ht Hpeaks EASY indices
            if (false)
            {
                redID = 11;  // ACI
                grnID = 12;  // Ht

                //bluID = 13;  // HavgSp
                //bluID = 14;  // Hvariance
                //bluID = 15;  // Hpeaks
                bluID = 16;  // Hcov

                //bluID = 7;  // SPT
                rep = @"aci-ht-hcov";

                //rep = @"aci-ht-spt";
            }

            // LF, MF, HF
            if (true)
            {
                redID = 10;  // LF
                grnID = 9;   // MF
                bluID = 8;   // HF
                rep   = @"lf-mf-hf";
            }

            IndexProperties redIndexProps = listOfIndexProperties[names[redID]];
            IndexProperties grnIndexProps = listOfIndexProperties[names[grnID]];
            IndexProperties bluIndexProps = listOfIndexProperties[names[bluID]];

            int dayPixelHeight = 4;
            int rowCount       = (dayPixelHeight * dayCount) + 35; // +30 for grid lines
            int colCount       = 1440;
            var bitmap         = new Image <Rgb24>(colCount, rowCount);
            var colour         = Color.Yellow;
            int currentRow     = 0;
            var oneDay         = TimeSpan.FromHours(24);
            int graphWidth     = colCount;
            int trackHeight    = 20;
            var stringFont     = Drawing.Arial8;

            string[] monthNames = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };

            // for drawing the y-axis scale
            int scaleWidth = trackHeight + 7;
            var yAxisScale = new Image <Rgb24>(scaleWidth, rowCount + (2 * trackHeight));

            yAxisScale.Mutate(g =>
            {
                g.Clear(Color.Black);

                // loop over days
                for (int d = 0; d < dayCount; d++)
                {
                    var thisday = ((DateTimeOffset)startDate).AddDays(d);

                    if (thisday.Day == 1)
                    {
                        int nextRow = currentRow + 1;
                        for (int c = 0; c < colCount; c++)
                        {
                            bitmap[c, currentRow] = Color.Gray;
                            bitmap[c, nextRow]    = Color.Gray;
                        }

                        for (int c = 0; c < scaleWidth; c++)
                        {
                            yAxisScale[c, currentRow + trackHeight] = Color.Gray;
                            yAxisScale[c, nextRow + trackHeight]    = Color.Gray;
                        }

                        string month = monthNames[thisday.Month - 1];
                        if (thisday.Month == 1) // January
                        {
                            g.DrawText(thisday.Year.ToString(), stringFont, Color.White,
                                       new PointF(0, nextRow + trackHeight + 1));  //draw time
                            g.DrawText(month, stringFont, Color.White,
                                       new PointF(1, nextRow + trackHeight + 11)); //draw time
                        }
                        else
                        {
                            g.DrawText(month, stringFont, Color.White,
                                       new PointF(1, nextRow + trackHeight + 1)); //draw time
                        }

                        currentRow += 2;
                    }

                    // get the exact date and time
                    LoggedConsole.WriteLine($"READING DAY {d + 1} of {dayCount}:   {thisday.ToString()}");

                    // CREATE DAY LEVEL OUTPUT DIRECTORY for this day
                    string dateString = $"{thisday.Year}{thisday.Month:D2}{thisday.Day:D2}";

                    tuple      = CsvTools.ReadCSVFile(csvFiles[d].FullName);
                    var arrays = tuple.Item2;

                    var redArray = arrays[redID];
                    var grnArray = arrays[grnID];
                    var bluArray = arrays[bluID];

                    // NormaliseMatrixValues the indices
                    redArray = DataTools.NormaliseInZeroOne(redArray, redIndexProps.NormMin, redIndexProps.NormMax);
                    grnArray = DataTools.NormaliseInZeroOne(grnArray, grnIndexProps.NormMin, grnIndexProps.NormMax);
                    bluArray = DataTools.NormaliseInZeroOne(bluArray, bluIndexProps.NormMin, bluIndexProps.NormMax);

                    for (int c = 0; c < colCount; c++)
                    {
                        for (int r = 0; r < dayPixelHeight; r++)
                        {
                            //transformedValue = Math.Sqrt(redArray[c]);
                            var transformedValue = redArray[c] * redArray[c];
                            int redVal           = (int)Math.Round(transformedValue * 255);
                            if (redVal < 0)
                            {
                                redVal = 0;
                            }
                            else if (redVal > 255)
                            {
                                redVal = 255;
                            }

                            //transformedValue = Math.Sqrt(grnArray[c]);
                            transformedValue = grnArray[c] * grnArray[c]; // square the value
                            int grnVal       = (int)Math.Round(transformedValue * 255);
                            if (grnVal < 0)
                            {
                                grnVal = 0;
                            }
                            else if (grnVal > 255)
                            {
                                grnVal = 255;
                            }

                            //transformedValue = Math.Sqrt(bluArray[c]);
                            transformedValue = bluArray[c] * bluArray[c]; // square the value
                            int bluVal       = (int)Math.Round(transformedValue * 255);
                            if (bluVal < 0)
                            {
                                bluVal = 0;
                            }
                            else if (bluVal > 255)
                            {
                                bluVal = 255;
                            }

                            bitmap[c, currentRow + r] = Color.FromRgb((byte)redVal, (byte)grnVal, (byte)bluVal);
                        }
                    } // over all columns

                    currentRow += dayPixelHeight;

                    if (thisday.Day % 7 == 0)
                    {
                        for (int c = 0; c < colCount; c++)
                        {
                            bitmap[c, currentRow] = Color.Gray;
                        }

                        currentRow++;
                    }
                } // over days
            });
            // draw on civil dawn and dusk lines
            int startdayOfYear = ((DateTimeOffset)startDate).DayOfYear;
            int endDayOfYear   = ((DateTimeOffset)endDate).DayOfYear;

            SunAndMoon.AddSunRiseSetLinesToImage(bitmap, arguments.BrisbaneSunriseDatafile.ToFileInfo(), startdayOfYear, endDayOfYear, dayPixelHeight);

            // add the time scales
            Image <Rgb24> timeBmp1      = ImageTrack.DrawTimeRelativeTrack(oneDay, graphWidth, trackHeight);
            var           imageList     = new [] { timeBmp1, bitmap, timeBmp1 };
            Image <Rgb24> compositeBmp1 = (Image <Rgb24>)ImageTools.CombineImagesVertically(imageList);

            imageList = new [] { yAxisScale, compositeBmp1 };
            Image <Rgb24> compositeBmp2 = (Image <Rgb24>)ImageTools.CombineImagesInLine(imageList);

            // indices used for image
            string        indicesDescription = $"{redIndexProps.Name}|{grnIndexProps.Name}|{bluIndexProps.Name}";
            string        startString        = $"{startDate.Value.Year}/{startDate.Value.Month}/{startDate.Value.Day}";
            string        endString          = $"{endDate.Value.Year}/{endDate.Value.Month}/{endDate.Value.Day}";
            string        title    = $"EASY:   {arguments.FileStemName}    From {startString} to {endString}                          Indices: {indicesDescription}";
            Image <Rgb24> titleBar = ImageTrack.DrawTitleTrack(compositeBmp2.Width, trackHeight, title);

            imageList     = new [] { titleBar, compositeBmp2 };
            compositeBmp2 = (Image <Rgb24>)ImageTools.CombineImagesVertically(imageList);
            var outputFileName = Path.Combine(opDir.FullName, arguments.FileStemName + "." + rep + ".EASY.png");

            compositeBmp2.Save(outputFileName);
        } // Execute()