• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

samsmithnz / PuzzleSolver / 4064748535

pending completion
4064748535

push

github

GitHub
Merge pull request #28 from samsmithnz/AddingMapAndPathFinding

806 of 854 branches covered (94.38%)

Branch coverage included in aggregate %.

342 of 342 new or added lines in 8 files covered. (100.0%)

1165 of 1194 relevant lines covered (97.57%)

1263151.22 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.89
/src/PuzzleSolver/ImageColorGroups.cs
1
using SixLabors.ImageSharp;
2
using SixLabors.ImageSharp.PixelFormats;
3
using System;
4
using System.Collections.Generic;
5
using System.Linq;
6

7
namespace PuzzleSolver
8
{
9
    public class ImageColorGroups
10
    {
11
        public SortedList<int, Rgb24> PriorityColorPalette { get; set; }
26✔
12
        public List<Rgb24> ColorPalette { get; set; }
5,380,600✔
13

14
        public ImageColorGroups(List<Rgb24> colorPalette, SortedList<int, Rgb24> priorityColorPalette = null)
13✔
15
        {
13✔
16
            ColorPalette = colorPalette;
13✔
17
            if (priorityColorPalette == null)
13✔
18
            {
11✔
19
                PriorityColorPalette = new SortedList<int, Rgb24>();
11✔
20
            }
11✔
21
            else
22
            {
2✔
23
                PriorityColorPalette = priorityColorPalette;
2✔
24
            }
2✔
25
        }
13✔
26

27
        /// <summary>
28
        /// Get Images Statistics for target image
29
        /// </summary>
30
        /// <param name="sourceFilename"></param>
31
        /// <param name="image"></param>
32
        /// <param name="onlyShowTop3"></param>
33
        /// <returns></returns>
34
        public ImageStats ProcessStatsForImage(string sourceFilename = null, Image<Rgb24> image = null, bool onlyShowTop3 = true)
35
        {
13✔
36
            ImageStats imageStats = null;
13✔
37
            Image<Rgb24> sourceImage = null;
13✔
38
            if (sourceFilename != null)
13!
39
            {
13✔
40
                sourceImage = Image.Load<Rgb24>(sourceFilename);
13✔
41
            }
13✔
42
            else if (image != null)
×
43
            {
×
44
                sourceImage = image;
×
45
            }
×
46

47
            if (sourceImage != null)
13✔
48
            {
13✔
49
                imageStats = new ImageStats(sourceImage)
13✔
50
                {
13✔
51
                    ColorGroups = ProcessImageIntoColorGroups(sourceImage),
13✔
52
                    PriorityColorPalette = PriorityColorPalette
13✔
53
                };
13✔
54
                imageStats.NamedColorsAndPercentList = BuildNamedColorsAndPercentList(imageStats.ColorGroups, imageStats.PriorityColorPalette, onlyShowTop3);
13✔
55
            }
13✔
56
            return imageStats;
13✔
57
        }
13✔
58

59
        private Dictionary<Rgb24, List<Rgb24>> ProcessImageIntoColorGroups(Image<Rgb24> image)
60
        {
13✔
61
            Dictionary<Rgb24, List<Rgb24>> groupedColors = new Dictionary<Rgb24, List<Rgb24>>();
13✔
62

63
            image.ProcessPixelRows(accessor =>
13✔
64
            {
13✔
65
                //int srcWidth = sourceImg.Size().Width;
13✔
66
                int srcHeight = image.Size().Height;
13✔
67

13✔
68
                for (var row = 0; row < srcHeight; row++)
8,338✔
69
                {
4,156✔
70
                    Span<Rgb24> pixelSpan = accessor.GetRowSpan(row);
4,156✔
71
                    for (var col = 0; col < pixelSpan.Length; col++)
10,769,486✔
72
                    {
5,380,587✔
73
                        Rgb24? colorGroup = FindClosestColorGroup(pixelSpan[col]);
5,380,587✔
74
                        if (colorGroup != null)
5,380,587✔
75
                        {
5,380,587✔
76
                            if (!groupedColors.ContainsKey((Rgb24)colorGroup))
5,380,587✔
77
                            {
258✔
78
                                List<Rgb24> colorList = new List<Rgb24>()
258✔
79
                                {
258✔
80
                                pixelSpan[col]
258✔
81
                                };
258✔
82
                                groupedColors[(Rgb24)colorGroup] = colorList;
258✔
83
                            }
258✔
84
                            else
13✔
85
                            {
5,380,329✔
86
                                List<Rgb24> colorList = groupedColors[(Rgb24)colorGroup];
5,380,329✔
87
                                colorList.Add(pixelSpan[col]);
5,380,329✔
88
                                groupedColors[(Rgb24)colorGroup] = colorList;
5,380,329✔
89
                            }
5,380,329✔
90
                        }
5,380,587✔
91
                    }
5,380,587✔
92
                }
4,156✔
93
            });
26✔
94

95
            //Order with the most number of colors rolling up into the parent color first.
96
            groupedColors = groupedColors.OrderByDescending(x => x.Value.Count).ToDictionary(x => x.Key, x => x.Value);
787✔
97

98
            return groupedColors;
13✔
99
        }
13✔
100

101
        //Group RGB colors into multiple groups
102
        private Rgb24? FindClosestColorGroup(Rgb24 colorToTest)
103
        {
5,380,587✔
104
            Rgb24? closestColorGroup = null;
5,380,587✔
105
            List<KeyValuePair<Rgb24, int>> results = new List<KeyValuePair<Rgb24, int>>();
5,380,587✔
106
            foreach (Rgb24 color in ColorPalette)
287,618,649✔
107
            {
135,738,444✔
108
                int colorDifference = GetColorDifference(color, colorToTest);
135,738,444✔
109
                results.Add(new KeyValuePair<Rgb24, int>(color, colorDifference));
135,738,444✔
110
            }
135,738,444✔
111
            //Order the results and save over itself
112
            results = results.OrderBy(t => t.Value).ToList();
141,119,031✔
113

114
            //Check if the largest positive or negative value is closer
115
            if (results.Count > 0)
5,380,587✔
116
            {
5,380,587✔
117
                closestColorGroup = results[0].Key;
5,380,587✔
118
            }
5,380,587✔
119
            return closestColorGroup;
5,380,587✔
120
        }
5,380,587✔
121

122
        //Since it uses Sqrt, it always returns a positive number
123
        private static int GetColorDifference(Rgb24 color1, Rgb24 color2)
124
        {
135,738,444✔
125
            return (int)Math.Sqrt(Math.Pow(color1.R - color2.R, 2) + Math.Pow(color1.G - color2.G, 2) + Math.Pow(color1.B - color2.B, 2));
135,738,444✔
126
        }
135,738,444✔
127

128
        private static List<ColorStats> BuildNamedColorsAndPercentList(
129
            Dictionary<Rgb24, List<Rgb24>> colorGroups,
130
            SortedList<int, Rgb24> priorityColorPalette,
131
            bool onlyShowTop3)
132
        {
13✔
133
            List<ColorStats> roughNamePercentList = new List<ColorStats>();
13✔
134
            //Calculate the name and percent and add it into a list
135
            foreach (KeyValuePair<Rgb24, List<Rgb24>> colorGroup in colorGroups)
555✔
136
            {
258✔
137
                double percent = (double)colorGroup.Value.Count / (double)colorGroups.Sum(t => t.Value.Count);
35,512✔
138
                roughNamePercentList.Add(new ColorStats(colorGroup.Key, ColorPalettes.ToName(colorGroup.Key), percent));
258✔
139
            }
258✔
140
            //If there are priority items, update the order
141
            if (priorityColorPalette.Count > 0)
13✔
142
            {
1✔
143
                foreach (KeyValuePair<int, Rgb24> priorityItem in priorityColorPalette)
5✔
144
                {
1✔
145
                    ColorStats priorityColorStats = roughNamePercentList.Where(x => x.Rgb == priorityItem.Value).FirstOrDefault();
4!
146
                    if (priorityColorStats != null)
1✔
147
                    {
1✔
148
                        priorityColorStats.Order = priorityItem.Key;
1✔
149
                    }
1✔
150
                }
1✔
151
            }
1✔
152
            //Order the percent list
153
            roughNamePercentList = roughNamePercentList.OrderBy(t => t.Order).ThenByDescending(x => x.Percent).ThenBy(x => x.Name).ToList();
787✔
154

155
            //Add the other percent if needed
156
            List<ColorStats> finalNamePercentList = new List<ColorStats>();
13✔
157
            if (onlyShowTop3 == true)
13✔
158
            {
6✔
159
                int count = 0;
6✔
160
                double totalOtherPercent = 0;
6✔
161
                foreach (ColorStats item in roughNamePercentList)
66✔
162
                {
24✔
163
                    if (onlyShowTop3 == true && count < 2)
24!
164
                    {
12✔
165
                        finalNamePercentList.Add(item);
12✔
166
                        count++;
12✔
167
                    }
12✔
168
                    else
169
                    {
12✔
170
                        totalOtherPercent += item.Percent;
12✔
171
                    }
12✔
172
                }
24✔
173
                //If there is an other percent over 0, add it
174
                if (Math.Round(totalOtherPercent, 2) > 0)
6✔
175
                {
6✔
176
                    finalNamePercentList.Add(new ColorStats(null, "Other", totalOtherPercent));
6✔
177
                }
6✔
178
            }
6✔
179
            else
180
            {
7✔
181
                finalNamePercentList = roughNamePercentList;
7✔
182
            }
7✔
183

184
            return finalNamePercentList;
13✔
185
        }
13✔
186
    }
187
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc