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

samsmithnz / PuzzleSolver / 3941005693

pending completion
3941005693

Pull #20

github

GitHub
Merge fb0a1ed8b into 9fd794745
Pull Request #20: Adding test form

294 of 300 branches covered (98.0%)

Branch coverage included in aggregate %.

23 of 23 new or added lines in 1 file covered. (100.0%)

376 of 395 relevant lines covered (95.19%)

6828984.22 hits per line

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

81.48
/src/PuzzleSolver/ImageProcessing.cs
1
using SixLabors.ImageSharp;
2
using SixLabors.ImageSharp.PixelFormats;
3
using System.Text;
4

5
namespace PuzzleSolver;
6

7
public class ImageProcessing
8
{
9
    public List<Rgb24> ColorPalette { get; set; }
4,997,633✔
10

11
    public ImageProcessing(List<Rgb24> colorPalette)
10✔
12
    {
10✔
13
        //Add the primary and secondary colors, with black and white for initial buckets
14
        ColorPalette = colorPalette;
10✔
15
    }
10✔
16

17
    public Dictionary<Rgb24, List<Rgb24>> ProcessImageIntoColorGroups(string sourceFilename)
18
    {
10✔
19
        Dictionary<Rgb24, List<Rgb24>> groupedColors = new();
10✔
20
        FileInfo srcFile = new(sourceFilename);
10✔
21
        //string destFilename = Path.GetFileNameWithoutExtension(srcFile.Name) + "_sorted.jpg";
22

23
        using Image<Rgb24> sourceImg = Image.Load<Rgb24>(srcFile.FullName);
10✔
24

25
        //int srcWidth = sourceImg.Size().Width;
26
        int srcHeight = sourceImg.Size().Height;
10✔
27

28
        //using var destImg = new Image<Rgb24>(srcWidth, srcHeight);
29
        //Dictionary<Rgb24, int> pixels = new();
30
        sourceImg.ProcessPixelRows(accessor =>
10✔
31
        {
10✔
32
            for (var row = 0; row < srcHeight; row++)
7,196✔
33
            {
3,588✔
34
                Span<Rgb24> pixelSpan = accessor.GetRowSpan(row);
3,588✔
35
                for (var col = 0; col < pixelSpan.Length; col++)
10,002,422✔
36
                {
4,997,623✔
37
                    Rgb24? colorGroup = FindClosestColorGroup(pixelSpan[col]);
4,997,623✔
38
                    if (colorGroup != null)
4,997,623✔
39
                    {
4,997,623✔
40
                        if (!groupedColors.ContainsKey((Rgb24)colorGroup))
4,997,623✔
41
                        {
281✔
42
                            List<Rgb24> colorList = new()
281✔
43
                            {
281✔
44
                                pixelSpan[col]
281✔
45
                            };
281✔
46
                            groupedColors[(Rgb24)colorGroup] = colorList;
281✔
47
                        }
281✔
48
                        else
10✔
49
                        {
4,997,342✔
50
                            List<Rgb24> colorList = groupedColors[(Rgb24)colorGroup];
4,997,342✔
51
                            colorList.Add(pixelSpan[col]);
4,997,342✔
52
                            groupedColors[(Rgb24)colorGroup] = colorList;
4,997,342✔
53
                        }
4,997,342✔
54
                    }
4,997,623✔
55
                }
4,997,623✔
56
            }
3,588✔
57
        });
20✔
58

59
        return groupedColors;
10✔
60
    }
10✔
61

62
    //Group RGB colors into multiple groups
63
    private Rgb24? FindClosestColorGroup(Rgb24 colorToTest)
64
    {
4,997,623✔
65
        Rgb24? closestColorGroup = null;
4,997,623✔
66
        List<KeyValuePair<Rgb24, int>> results = new();
4,997,623✔
67
        foreach (Rgb24 color in ColorPalette)
526,479,687✔
68
        {
255,743,409✔
69
            int colorDifference = GetColorDifference(color, colorToTest);
255,743,409✔
70
            results.Add(new KeyValuePair<Rgb24, int>(color, colorDifference));
255,743,409✔
71
        }
255,743,409✔
72
        //Order the results and save over itself
73
        results = results.OrderBy(t => t.Value).ToList();
260,741,032✔
74

75
        //Check if the largest postive or negative value is closer
76
        if (results.Count > 0)
4,997,623✔
77
        {
4,997,623✔
78
            closestColorGroup = results[0].Key;
4,997,623✔
79
        }
4,997,623✔
80
        return closestColorGroup;
4,997,623✔
81
    }
4,997,623✔
82

83
    //Since it uses Sqrt, it always returns a postive number
84
    private static int GetColorDifference(Rgb24 color1, Rgb24 color2)
85
    {
255,743,409✔
86
        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));
255,743,409✔
87
    }
255,743,409✔
88

89
    public static string BuildNamedColorsAndPercentsString(Dictionary<Rgb24, List<Rgb24>> colorGroups)
90
    {
6✔
91
        //loop through dictionary and calculate percents for each key
92
        StringBuilder sb = new();
6✔
93
        List<KeyValuePair<string, double>> namePercents = new();
6✔
94
        //Calculate the name and percent and add it into a list
95
        foreach (KeyValuePair<Rgb24, List<Rgb24>> colorGroup in colorGroups)
544✔
96
        {
263✔
97
            double percent = (double)colorGroup.Value.Count / (double)colorGroups.Sum(t => t.Value.Count);
30,854✔
98
            namePercents.Add(new KeyValuePair<string, double>(ColorPalettes.ToName(colorGroup.Key), percent));
263✔
99
        }
263✔
100
        //Return the string ordered by percent
101
        foreach (KeyValuePair<string, double> item in namePercents.OrderByDescending(x => x.Value).ThenBy(x => x.Key))
1,070✔
102
        {
263✔
103
            sb.AppendLine($"{item.Key}: {item.Value:0.00%}");
263✔
104
        }
263✔
105
        return sb.ToString();
6✔
106
    }
6✔
107

108
    public static Image<Rgba32> Extract(Image<Rgba32> sourceImage, Rectangle sourceArea)
109
    {
×
110
        Image<Rgba32> targetImage = new(sourceArea.Width, sourceArea.Height);
×
111

112
        int height = sourceArea.Height;
×
113

114
        sourceImage.ProcessPixelRows(accessor =>
×
115
        {
×
116
            for (int row = 0; row < height; row++)
×
117
            {
×
118
                Span<Rgba32> sourceRow = accessor.GetRowSpan(sourceArea.Y + row);
×
119
                Span<Rgba32> targetRow = accessor.GetRowSpan(row);
×
120

×
121
                //Span<Rgba32> sourceRow = sourceImage.GetPixelRowSpan(sourceArea.Y + row);
×
122
                //Span<Rgba32> targetRow = targetImage.GetPixelRowSpan(row);
×
123

×
124
                sourceRow.Slice(sourceArea.X, sourceArea.Width).CopyTo(targetRow);
×
125
            }
×
126
        });
×
127

128
        return targetImage;
×
129
    }
×
130

131
}
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

© 2025 Coveralls, Inc