Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/sn4k3/UVtools.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'UVtools.GUI/FrmMain.cs')
-rw-r--r--UVtools.GUI/FrmMain.cs464
1 files changed, 354 insertions, 110 deletions
diff --git a/UVtools.GUI/FrmMain.cs b/UVtools.GUI/FrmMain.cs
index 0f742ad..7905296 100644
--- a/UVtools.GUI/FrmMain.cs
+++ b/UVtools.GUI/FrmMain.cs
@@ -12,8 +12,6 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
-using System.Linq;
-using System.Numerics;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
@@ -137,6 +135,13 @@ namespace UVtools.GUI
Clear();
+ if (Width >= Screen.FromControl(this).WorkingArea.Width ||
+ Height >= Screen.FromControl(this).WorkingArea.Height)
+ {
+ WindowState = FormWindowState.Maximized;
+ }
+
+
DragEnter += (s, e) => { if (e.Data.GetDataPresent(DataFormats.FileDrop)) e.Effect = DragDropEffects.Copy; };
DragDrop += (s, e) => { ProcessFile((string[])e.Data.GetData(DataFormats.FileDrop)); };
@@ -663,7 +668,6 @@ namespace UVtools.GUI
}
}
-
using (FrmInstallPEProfiles form = new FrmInstallPEProfiles())
{
form.ShowDialog();
@@ -939,6 +943,11 @@ namespace UVtools.GUI
if (ReferenceEquals(sender, tsLayerImageExport))
{
+ tsLayerImageExport.ShowDropDown();
+ return;
+ }
+ if (ReferenceEquals(sender, tsLayerImageExportFile))
+ {
using (SaveFileDialog dialog = new SaveFileDialog())
{
if (ReferenceEquals(pbLayer, null))
@@ -960,10 +969,21 @@ namespace UVtools.GUI
stream.Close();
}
}
+ }
+ return;
+ }
- return;
-
+ if (ReferenceEquals(sender, tsLayerImageExportClipboard))
+ {
+ if (ReferenceEquals(pbLayer, null))
+ {
+ return; // This should never happen!
}
+
+ Image image = (Image)pbLayer.Image.Tag;
+ Clipboard.SetImage(image.ToBitmap());
+
+ return;
}
if (ReferenceEquals(sender, btnFirstLayer))
@@ -1149,18 +1169,29 @@ namespace UVtools.GUI
}
else if (issue.X >= 0 && issue.Y >= 0)
{
- int x = issue.X;
- int y = issue.Y;
+ if (issue.BoundingRectangle.IsEmpty || issue.Size == 1)
+ {
+ int x = issue.X;
+ int y = issue.Y;
+
+ if (tsLayerImageRotate.Checked)
+ {
+ x = ActualLayerImage.Height - 1 - issue.Y;
+ y = issue.X;
+ }
- if (tsLayerImageRotate.Checked)
+ pbLayer.ZoomToRegion(x, y, 5, 5);
+ //pbLayer.ZoomOut(true);
+ }
+ else
{
- x = ActualLayerImage.Height - 1 - issue.Y;
- y = issue.X;
+ pbLayer.ZoomToRegion(
+ tsLayerImageRotate.Checked ? ActualLayerImage.Height - 1 - issue.BoundingRectangle.Bottom : issue.BoundingRectangle.X,
+ tsLayerImageRotate.Checked ? issue.BoundingRectangle.X : issue.BoundingRectangle.Y,
+ tsLayerImageRotate.Checked ? issue.BoundingRectangle.Height : issue.BoundingRectangle.Width,
+ tsLayerImageRotate.Checked ? issue.BoundingRectangle.Width : issue.BoundingRectangle.Height
+ );
}
-
- //pbLayer.Zoom = 1200;
- pbLayer.ZoomToRegion(x, y, 5, 5);
- pbLayer.ZoomOut(true);
}
tsIssueCount.Tag = lvIssues.SelectedIndices[0];
@@ -1595,54 +1626,27 @@ namespace UVtools.GUI
if (tsLayerImageLayerOutline.Checked)
{
- Image<Gray, byte> grayscale = ActualLayerImage.ToEmguImage();
- //ThresholdBinary(new Gray(127), new Gray(255) )
- ListViewItem item = new ListViewItem();
- //grayscale = grayscale.Canny(80, 40, 3, true);
- //var grayscaleInv = grayscale.ThresholdBinaryInv(new Gray(200), new Gray(255));
+ Image<Gray, byte> greyscale = ActualLayerImage.ToEmguImage();
+#if DEBUG
+ grayscale = grayscale.ThresholdBinary(new Gray(254), new Gray(255));
VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
Mat external = new Mat();
-
+
CvInvoke.FindContours(grayscale, contours, external, RetrType.Ccomp, ChainApproxMethod.ChainApproxSimple);
var arr = external.GetData();
-
-
- //
- // hierarchy[i][0]: the index of the next contour of the same level
- // hierarchy[i][1]: the index of the previous contour of the same level
- // hierarchy[i][2]: the index of the first child
- // hierarchy[i][3]: the index of the parent
- //
for (int i = 0; i < contours.Size; i++)
{
if ((int)arr.GetValue(0, i, 2) != -1 || (int)arr.GetValue(0, i, 3) == -1) continue;
var r = CvInvoke.BoundingRectangle(contours[i]);
-
- //CvInvoke.Rectangle(grayscale, r, new MCvScalar(125), 5);
- grayscale.FillConvexPoly(contours[i].ToArray(), new Gray(125), LineType.FourConnected);
- }
-
-
- //var grayscaleinv = grayscale.ThresholdBinaryInv(new Gray(200), new Gray(255));
-
- //grayscale =grayscaleinv;
- /*grayscale = grayscale.Dilate(1).Erode(1);
-
- Gray gray = new Gray(255);
- Mat external = new Mat();
- VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
- CvInvoke.FindContours(grayscale, contours, external, RetrType.Ccomp, ChainApproxMethod.ChainApproxSimple);
-
- for (int i = 0; i < contours.Size; i++)
- {
- grayscale.FillConvexPoly(contours[i].ToArray(), gray, LineType.FourConnected);
+ CvInvoke.Rectangle(grayscale, r, new MCvScalar(125), 10);
}
- */
-
- imageRgba = grayscale.ToImageSharpL8().CloneAs<Rgba32>();
- grayscale.Dispose();
+#else
+ greyscale = greyscale.Canny(80, 40, 3, true);
+#endif
+ imageRgba = greyscale.ToImageSharpL8().CloneAs<Rgba32>();
+ greyscale.Dispose();
}
else if (tsLayerImageLayerDifference.Checked)
{
@@ -1650,7 +1654,7 @@ namespace UVtools.GUI
{
var previousImage = SlicerFile[layerNum-1].Image;
var nextImage = SlicerFile[layerNum+1].Image;
- var newImage = new Image<Rgba32>(previousImage.Width, previousImage.Height);
+ //var newImage = new Image<Rgba32>(previousImage.Width, previousImage.Height);
/*Parallel.For(0, ActualLayerImage.Height, y => {
var newImageSpan = newImage.GetPixelRowSpan(y);
@@ -1722,23 +1726,56 @@ namespace UVtools.GUI
!ReferenceEquals(Issues, null) &&
Issues.TryGetValue(ActualLayer, out var issues))
{
+ imageRgba.TryGetSinglePixelSpan(out var span);
+ byte alpha;
foreach (var issue in issues)
{
if (ReferenceEquals(issue, null)) continue; // Removed issue
if(!issue.HaveValidPoint) continue;
+
+ if (issue.Type == LayerIssue.IssueType.ResinTrap)
+ {
+ using (var dummyImage = new Image<Gray, byte>(ActualLayerImage.Width,
+ ActualLayerImage.Height))
+ {
+ dummyImage.FillConvexPoly(issue.Pixels, new Gray(255));
+ dummyImage.DrawPolyline(issue.Pixels, true, new Gray(125), 2);
+ byte[,,] data = dummyImage.Data;
+ for (int y = issue.BoundingRectangle.Y; y < issue.BoundingRectangle.Bottom; y++)
+ {
+ for (int x = issue.BoundingRectangle.X; x < issue.BoundingRectangle.Right; x++)
+ {
+ if (data[y, x, 0] == 0) continue;
+ if(data[y, x, 0] == 255)
+ span[y * ActualLayerImage.Width + x] = new Rgba32(255, 180, 0);
+ else
+ span[y * ActualLayerImage.Width + x] = new Rgba32(255, 0, 0);
+ }
+ }
+ }
+
+ continue;
+ }
+
foreach (var pixel in issue)
{
- var alpha = ActualLayerImage[pixel.X, pixel.Y].PackedValue;
- if (alpha == 0) continue;
- // alpha, Color.Yellow
- alpha = Math.Max((byte) 80, alpha);
switch (issue.Type)
{
+ /*case LayerIssue.IssueType.ResinTrap:
+ break;*/
case LayerIssue.IssueType.Island:
- imageRgba[pixel.X, pixel.Y] = new Rgba32(alpha, alpha, 0);
+ alpha = ActualLayerImage[pixel.X, pixel.Y].PackedValue;
+ if (alpha == 0) continue;
+ // alpha, Color.Yellow
+ alpha = Math.Max((byte)80, alpha);
+ span[pixel.Y * ActualLayerImage.Width + pixel.X] = new Rgba32(alpha, alpha, 0);
break;
default:
- imageRgba[pixel.X, pixel.Y] = new Rgba32(alpha, 0, 0);
+ alpha = ActualLayerImage[pixel.X, pixel.Y].PackedValue;
+ if (alpha == 0) continue;
+ // alpha, Color.Yellow
+ alpha = Math.Max((byte)80, alpha);
+ span[pixel.Y * ActualLayerImage.Width + pixel.X] = new Rgba32(alpha, 0, 0);
break;
}
@@ -1967,7 +2004,7 @@ namespace UVtools.GUI
return;
}
}
- #endregion
+#endregion
@@ -2264,63 +2301,266 @@ namespace UVtools.GUI
}
}
- /*var layerHollowAreas = new ConcurrentDictionary<uint, List<LayerHollowArea>>();
+ return true;
+ var layerHollowAreas = new ConcurrentDictionary<uint, List<LayerHollowArea>>();
+
+ Stopwatch sw = new Stopwatch();
+ sw.Start();
Parallel.ForEach(SlicerFile,
//new ParallelOptions{MaxDegreeOfParallelism = 1},
layer =>
{
- var image = layer.Image;
- Image<Gray, byte> grayscale = image.ToEmguImage().ThresholdBinary(new Gray(254), new Gray(255));
-
- var listHollowArea = new List<LayerHollowArea>();
-
- VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
- Mat hierarchy = new Mat();
-
- CvInvoke.FindContours(grayscale, contours, hierarchy, RetrType.Ccomp, ChainApproxMethod.ChainApproxSimple);
-
- var arr = hierarchy.GetData();
- //
- //hierarchy[i][0]: the index of the next contour of the same level
- //hierarchy[i][1]: the index of the previous contour of the same level
- //hierarchy[i][2]: the index of the first child
- //hierarchy[i][3]: the index of the parent
- //
- Stopwatch sw = new Stopwatch();
- sw.Start();
- for (int i = 0; i < contours.Size; i++)
+ using (var image = layer.Image)
{
- if ((int) arr.GetValue(0, i, 2) != -1 || (int) arr.GetValue(0, i, 3) == -1) continue;
+ using (Image<Gray, byte> grayscale = image.ToEmguImage().ThresholdBinary(new Gray(254), new Gray(255)))
+ {
+ var listHollowArea = new List<LayerHollowArea>();
- grayscale.Dispose();
- grayscale = new Image<Gray, byte>(image.Width, image.Height);
- //grayscale = grayscale.CopyBlank();
- grayscale.FillConvexPoly(contours[i].ToArray(), new Gray(125));
- List<Point> points = new List<Point>();
+ VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
+ Mat hierarchy = new Mat();
- var rect = CvInvoke.BoundingRectangle(contours[i]);
- byte[,,] data = grayscale.Data;
- for (int y = rect.Y; y < rect.Bottom; y++)
- {
- for (int x = rect.X; x < rect.Right; x++)
+ CvInvoke.FindContours(grayscale, contours, hierarchy, RetrType.Ccomp, ChainApproxMethod.ChainApproxSimple);
+
+ var arr = hierarchy.GetData();
+ //
+ //hierarchy[i][0]: the index of the next contour of the same level
+ //hierarchy[i][1]: the index of the previous contour of the same level
+ //hierarchy[i][2]: the index of the first child
+ //hierarchy[i][3]: the index of the parent
+ //
+
+ for (int i = 0; i < contours.Size; i++)
{
+ if ((int) arr.GetValue(0, i, 2) != -1 || (int) arr.GetValue(0, i, 3) == -1)
+ continue;
- if (data[y, x, 0] != 125) continue;
- points.Add(new Point(x, y)); // Gather pixels
+ listHollowArea.Add(new LayerHollowArea(contours[i].ToArray(), CvInvoke.BoundingRectangle(contours[i]), layer.Index == 0 || layer.Index == SlicerFile.LayerCount-1 ? LayerHollowArea.AreaType.Drain : LayerHollowArea.AreaType.Unknown));
+
+ if (listHollowArea.Count > 0)
+ layerHollowAreas.TryAdd(layer.Index, listHollowArea);
}
}
+ }
+ });
+
+ List<LayerHollowArea> linkedAreas = new List<LayerHollowArea>();
+ LayerHollowArea lastCheckedArea;
+
+ for (uint layerIndex = 1; layerIndex < SlicerFile.LayerCount-1; layerIndex++) // Ignore first and last layers, always drains
+ {
+ if(!layerHollowAreas.TryGetValue(layerIndex, out var areas)) continue; // No hollow areas in this layer, ignore
+
+ byte areaCount = 0;
+ foreach (var area in areas)
+ {
+ if (area.Type != LayerHollowArea.AreaType.Unknown) continue; // processed, ignore
+ area.Type = LayerHollowArea.AreaType.Trap;
+
+ areaCount++;
+
+ linkedAreas.Clear();
+
+ for (sbyte dir = 1; dir >= -1 && area.Type != LayerHollowArea.AreaType.Drain; dir -= 2)
+ {
+ Queue<LayerHollowArea> queue = new Queue<LayerHollowArea>();
+ queue.Enqueue(area);
+ int nextLayerIndex = (int) layerIndex;
+ while (queue.Count > 0 && area.Type != LayerHollowArea.AreaType.Drain)
+ {
+ lastCheckedArea = queue.Dequeue();
+ nextLayerIndex += dir;
+ Debug.WriteLine($"Area Count: {areaCount} | Layer: {layerIndex} | Next Layer: {nextLayerIndex} | Dir: {dir}");
+ if (nextLayerIndex < 0 && nextLayerIndex >= SlicerFile.LayerCount) break; // Exhaust layers
+ bool haveNextAreas = layerHollowAreas.TryGetValue((uint)nextLayerIndex, out var nextAreas);
+
+ using (var image = SlicerFile[nextLayerIndex].Image)
+ {
+ using (var emguImage = new Image<Gray, byte>(ActualLayerImage.Width, ActualLayerImage.Height))
+ {
+ image.TryGetSinglePixelSpan(out var span);
+ emguImage.FillConvexPoly(lastCheckedArea.Contour, new Gray(255));
+
+ bool exitPixelLoop = false;
+
+ byte[,,] data = emguImage.Data;
+ for (int y = lastCheckedArea.BoundingRectangle.Y;
+ y <= lastCheckedArea.BoundingRectangle.Bottom && area.Type != LayerHollowArea.AreaType.Drain && !exitPixelLoop;
+ y++)
+ {
+ for (int x = lastCheckedArea.BoundingRectangle.X;
+ x <= lastCheckedArea.BoundingRectangle.Right && area.Type != LayerHollowArea.AreaType.Drain && !exitPixelLoop;
+ x++)
+ {
+
+ if (data[y, x, 0] != 255) continue;
+
+ if (span[y * image.Width + x] == Helpers.L8Black) // Found a black pixel: Drain or trap
+ {
+ if (haveNextAreas)
+ {
+ foreach (var nextArea in nextAreas)
+ {
+ if (!area.BoundingRectangle.IntersectsWith(nextArea.BoundingRectangle)) // If not intersect futher ispection is useless
+ {
+ continue;
+ }
+ if (CvInvoke.PointPolygonTest(new VectorOfPoint(nextArea.Contour),
+ new PointF(x, y), false) >= 0)
+ {
+ if (nextArea.Type == LayerHollowArea.AreaType.Drain) // Found a drain, stop query
+ {
+ area.Type = LayerHollowArea.AreaType.Drain;
+ }
+ else
+ {
+ queue.Enqueue(nextArea);
+ }
+
+ linkedAreas.Add(nextArea);
+
+ exitPixelLoop = true;
+ break;
+ }
+ }
+ }
+ else // Black pixel without next areas = Drain
+ {
+ area.Type = LayerHollowArea.AreaType.Drain;
+ exitPixelLoop = true;
+ break;
+ }
+ } // black check
+ } // X loop
+ } // Y loop
+ } // Dispose emgu image
+ } // Dispose image
+ } // Areas loop
+ } // Dir layer loop
+
+ foreach (var linkedArea in linkedAreas) // Update linked areas
+ {
+ linkedArea.Type = area.Type;
+ }
+
+ /*for (sbyte dir = 1; dir >= -1; dir-=2)
+ {
+ Debug.WriteLine($"dir: {dir}");
+ for (int nextLayerIndex = (int) (layerIndex + dir); nextLayerIndex >= 0 && nextLayerIndex < SlicerFile.LayerCount; nextLayerIndex+= dir) // Search on next layer
+ {
+ Debug.WriteLine($"Next Layer: {nextLayerIndex}");
+ bool nextHaveAreas = layerHollowAreas.TryGetValue((uint) nextLayerIndex, out var nextList);
+ // if (!layerHollowAreas.TryGetValue((uint) i, out var nextList)) // No areas found on next layer, check for tops
+ // {
+ area.Type = LayerHollowArea.AreaType.Trap;
+ using (var image = SlicerFile[nextLayerIndex].Image)
+ {
+ using (var emguImage = new Image<Gray, byte>(ActualLayerImage.Width, ActualLayerImage.Height))
+ {
+ image.TryGetSinglePixelSpan(out var span);
+ emguImage.FillConvexPoly(lastCheckedArea.Contour, new Gray(255));
+
+ byte[,,] data = emguImage.Data;
+ for (int y = lastCheckedArea.BoundingRectangle.Y;
+ y < lastCheckedArea.BoundingRectangle.Bottom && area.Type != LayerHollowArea.AreaType.Drain;
+ y++)
+ {
+ for (int x = lastCheckedArea.BoundingRectangle.X;
+ x < lastCheckedArea.BoundingRectangle.Right && area.Type != LayerHollowArea.AreaType.Drain;
+ x++)
+ {
+
+ if (data[y, x, 0] != 255) continue;
+
+ var pixelIndex = y * image.Width + x;
+ if (span[pixelIndex] == Helpers.L8Black) // Found a black pixel: Drain
+ {
+ if (nextHaveAreas)
+ {
+ foreach (var nextArea in nextList)
+ {
+ if (CvInvoke.PointPolygonTest(new VectorOfPoint(nextArea.Contour),
+ new PointF(x, y), false) > 0)
+ {
+ linkedAreas.Add(nextArea);
+ if (nextArea.Type == LayerHollowArea.AreaType.Drain) // Found a drain, stop query
+ {
+ area.Type = nextArea.Type;
+ }
+
+ break;
+ }
+ }
+ }
+ else
+ {
+ area.Type = LayerHollowArea.AreaType.Drain;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
- listHollowArea.Add(new LayerHollowArea(points.ToArray()));
+ if (area.Type == LayerHollowArea.AreaType.Drain) // Found a drain, stop query
+ {
+ break;
+ }
+ //}
+
+ /*foreach (var nextArea in nextList)
+ {
+ if (area.BoundingRectangle.IntersectsWith(nextArea.BoundingRectangle))
+ {
+ lastCheckedArea = nextArea;
+ linkedAreas.Add(nextArea);
+ if (nextArea.Type == LayerHollowArea.AreaType.Drain) // Found a drain, stop query
+ {
+ area.Type = nextArea.Type;
+ break;
+ }
+ }
+ }*/
+ /*}
+
+ if(area.Type == LayerHollowArea.AreaType.Drain) // Found a drain, stop query
+ break;
}
- sw.Stop();
- Debug.WriteLine(sw.ElapsedMilliseconds);
+ foreach (var linkedArea in linkedAreas) // Update linked areas
+ {
+ linkedArea.Type = area.Type;
+ }*/
+ }
+ }
- if (listHollowArea.Count > 0)
- layerHollowAreas.TryAdd(layer.Index, listHollowArea);
- });*/
+ Issues = new Dictionary<uint, List<LayerIssue>>();
+ for (uint layerIndex = 0; layerIndex < SlicerFile.LayerCount; layerIndex++)
+ {
+ if (!layerHollowAreas.TryGetValue(layerIndex, out var list)) continue;
+ if (list.Count > 0)
+ {
+ var issuesHollow = new List<LayerIssue>();
+
+ foreach (var area in list)
+ {
+ if (area.Type == LayerHollowArea.AreaType.Trap)
+ {
+ issuesHollow.Add(new LayerIssue(SlicerFile[layerIndex], LayerIssue.IssueType.ResinTrap, area.Contour, area.BoundingRectangle));
+ }
+ }
+
+ if (issues.Count > 0)
+ {
+ Issues.Add(layerIndex, issuesHollow);
+ }
+ }
+ }
+
+ sw.Stop();
+ Debug.WriteLine($"RectSearch: {sw.ElapsedMilliseconds}ms");
result = true;
}
@@ -2347,19 +2587,23 @@ namespace UVtools.GUI
try
{
- foreach (var kv in Issues)
+ if (!ReferenceEquals(Issues, null))
{
- foreach (var issue in kv.Value)
+ foreach (var kv in Issues)
{
- TotalIssues++;
- count++;
- ListViewItem item = new ListViewItem(lvIssues.Groups[(int)issue.Type]) {Text = issue.Type.ToString() };
- item.SubItems.Add(count.ToString());
- item.SubItems.Add(kv.Key.ToString());
- item.SubItems.Add($"{issue.X}, {issue.Y}");
- item.SubItems.Add(issue.Size.ToString());
- item.Tag = issue;
- lvIssues.Items.Add(item);
+ foreach (var issue in kv.Value)
+ {
+ TotalIssues++;
+ count++;
+ ListViewItem item = new ListViewItem(lvIssues.Groups[(int) issue.Type])
+ {Text = issue.Type.ToString()};
+ item.SubItems.Add(count.ToString());
+ item.SubItems.Add(kv.Key.ToString());
+ item.SubItems.Add($"{issue.X}, {issue.Y}");
+ item.SubItems.Add(issue.Size.ToString());
+ item.Tag = issue;
+ lvIssues.Items.Add(item);
+ }
}
}
}