//********************************************************************************************************************************************************************************************** public async Task Solve() { await Task.Run(() => { try { PuzzleSolutionImages.Clear(); compareAllEdges(); CurrentSolverState = PuzzleSolverState.SOLVE_PUZZLE; CurrentSolverStepPercentageFinished = 0; PuzzleDisjointSet p = new PuzzleDisjointSet(Pieces.Count); p.JoinValidation = JoinValidationFunction; _logHandle.Report(new LogEventInfo("Join Pieces")); for (int i = 0; i < matches.Count; i++) { if (_cancelToken.IsCancellationRequested) { _cancelToken.ThrowIfCancellationRequested(); } CurrentSolverStepPercentageFinished = (i / (double)matches.Count) * 100; if (p.InOneSet()) { break; } int p1 = matches[i].PieceIndex1; int e1 = matches[i].EdgeIndex1; int p2 = matches[i].PieceIndex2; int e2 = matches[i].EdgeIndex2; p.JoinSets(p1, p2, e1, e2); } _logHandle.Report(new LogEventInfo("Possible solution found (" + p.SetCount.ToString() + " solutions)")); CurrentSolverStepPercentageFinished = 100; CurrentSolverState = PuzzleSolverState.SOLVED; CurrentSolutionNumber = 0; CurrentSolutionPieceIndex = 0; int setNo = 0; foreach (Forest jointSet in p.GetJointSets()) { Matrix <int> solution = jointSet.locations; Matrix <int> solution_rotations = jointSet.rotations; for (int i = 0; i < solution.Size.Width; i++) { for (int j = 0; j < solution.Size.Height; j++) { int piece_number = solution[j, i]; if (piece_number == -1) { continue; } Pieces[piece_number].Rotate(4 - solution_rotations[j, i]); Pieces[piece_number].SolutionRotation = solution_rotations[j, i] * 90; Pieces[piece_number].SolutionLocation = new Point(i, j); Pieces[piece_number].SolutionID = setNo; } } Solutions.Add(solution); SolutionsRotations.Add(solution_rotations); // Get the enabled Plugins for solution image generation List <PluginGroupGenerateSolutionImage> pluginsGenerateSolutionImage = PluginFactory.GetEnabledPluginsOfGroupType <PluginGroupGenerateSolutionImage>(); foreach (PluginGroupGenerateSolutionImage plugin in pluginsGenerateSolutionImage) { PluginNameAttribute nameAttribute = plugin.GetType().GetCustomAttributes(false).Where(a => a.GetType() == typeof(PluginNameAttribute)).FirstOrDefault() as PluginNameAttribute; Bitmap solutionImg = plugin.GenerateSolutionImage(solution, setNo, Pieces.ToList()); PuzzleSolutionImages.Add(new ImageDescribedLight("Solution #" + setNo.ToString() + " (" + nameAttribute.Name + ")", PuzzlePiecesFolderPath + @"\Results\Solutions\Solution#" + setNo.ToString() + ".png", solutionImg)); if (PluginFactory.GetGeneralSettingsPlugin().SolverShowDebugResults) { _logHandle.Report(new LogEventImage("Solution #" + setNo.ToString() + " (" + nameAttribute.Name + ")", solutionImg)); } solutionImg.Dispose(); } setNo++; } } catch (OperationCanceledException) { _logHandle.Report(new LogEventWarning("The operation was canceled. Step: " + CurrentSolverState.ToString())); CurrentSolverState = PuzzleSolverState.UNSOLVED; } catch (Exception ex) { _logHandle.Report(new LogEventError("The following error occured in step " + CurrentSolverState.ToString() + ":\n" + ex.Message)); CurrentSolverState = PuzzleSolverState.ERROR; CurrentSolverStepPercentageFinished = 100; } }, _cancelToken); }
//############################################################################################################################################################################################## /// <summary> /// Extract all pieces from the source image. /// </summary> private void extract_pieces() { try { CurrentSolverState = PuzzleSolverState.INIT_PIECES; Piece.NextPieceID = 0; CurrentSolverStepPercentageFinished = 0; _logHandle.Report(new LogEventInfo("Extracting Pieces")); NumberPuzzlePieces = 0; Pieces.Clear(); InputImages.Clear(); List <string> imageExtensions = new List <string>() { ".jpg", ".png", ".bmp", ".tiff" }; FileAttributes attr = File.GetAttributes(PuzzlePiecesFolderPath); List <FileInfo> imageFilesInfo = new List <FileInfo>(); if (attr.HasFlag(FileAttributes.Directory)) //detect whether its a directory or file { DirectoryInfo folderInfo = new DirectoryInfo(PuzzlePiecesFolderPath); imageFilesInfo = folderInfo.GetFiles().ToList(); } else { FileInfo fileInfo = new FileInfo(PuzzlePiecesFolderPath); imageFilesInfo.Add(fileInfo); } imageFilesInfo = imageFilesInfo.Where(f => imageExtensions.Contains(f.Extension)).ToList(); int loopCount = 0; ParallelOptions parallelOptions = new ParallelOptions { CancellationToken = _cancelToken, MaxDegreeOfParallelism = (PluginFactory.GetGeneralSettingsPlugin().UseParallelLoops ? Environment.ProcessorCount : 1) }; //For each input image Parallel.For(0, imageFilesInfo.Count, parallelOptions, (i) => { using (Image <Rgba, byte> sourceImg = new Image <Rgba, byte>(imageFilesInfo[i].FullName)) //.LimitImageSize(1000, 1000)) { CvInvoke.MedianBlur(sourceImg, sourceImg, 5); // Get the (first) enabled Plugin for input image mask generation PluginGroupInputImageMask pluginInputImageMask = PluginFactory.GetEnabledPluginsOfGroupType <PluginGroupInputImageMask>().FirstOrDefault(); using (Image <Gray, byte> mask = pluginInputImageMask.GetMask(sourceImg)) { _logHandle.Report(new LogEventInfo("Extracting Pieces from source image " + i.ToString())); if (PluginFactory.GetGeneralSettingsPlugin().SolverShowDebugResults) { _logHandle.Report(new LogEventImage("Source image " + i.ToString(), sourceImg.Bitmap)); _logHandle.Report(new LogEventImage("Mask " + i.ToString(), mask.Bitmap)); } CvBlobDetector blobDetector = new CvBlobDetector(); // Find all blobs in the mask image, extract them and add them to the list of pieces CvBlobs blobs = new CvBlobs(); blobDetector.Detect(mask, blobs); foreach (CvBlob blob in blobs.Values.Where(b => b.BoundingBox.Width >= PluginFactory.GetGeneralSettingsPlugin().PuzzleMinPieceSize&& b.BoundingBox.Height >= PluginFactory.GetGeneralSettingsPlugin().PuzzleMinPieceSize)) { if (_cancelToken.IsCancellationRequested) { _cancelToken.ThrowIfCancellationRequested(); } Rectangle roi = blob.BoundingBox; Image <Rgba, byte> pieceSourceImg; Image <Gray, byte> pieceMask; try { if (sourceImg.Height > roi.Height + 4 && sourceImg.Width > roi.Width + 4) { roi.Inflate(2, 2); } pieceSourceImg = sourceImg.Copy(roi); pieceMask = mask.Copy(roi); } catch (Exception) { roi = blob.BoundingBox; pieceSourceImg = sourceImg.Copy(roi); pieceMask = mask.Copy(roi); } // Mask out background of piece Image <Rgba, byte> pieceSourceImageForeground = new Image <Rgba, byte>(pieceSourceImg.Size); CvInvoke.BitwiseOr(pieceSourceImg, pieceSourceImg, pieceSourceImageForeground, pieceMask); Image <Gray, byte> pieceMaskInverted = pieceMask.Copy(pieceMask); pieceMaskInverted._Not(); Image <Rgba, byte> background = new Image <Rgba, byte>(pieceSourceImg.Size); background.SetValue(new Rgba(255, 255, 255, 0)); Image <Rgba, byte> pieceSourceImageBackground = new Image <Rgba, byte>(pieceSourceImg.Size); CvInvoke.BitwiseOr(background, background, pieceSourceImageBackground, pieceMaskInverted); Image <Rgba, byte> pieceSourceImgMasked = new Image <Rgba, byte>(pieceSourceImg.Size); CvInvoke.BitwiseOr(pieceSourceImageForeground, pieceSourceImageBackground, pieceSourceImgMasked); Piece p = new Piece(pieceSourceImgMasked, pieceMask, imageFilesInfo[i].FullName, roi.Location, _logHandle, _cancelToken); lock (_piecesLock) { Pieces.Add(p); } sourceImg.Draw(roi, new Rgba(255, 0, 0, 1), 2); int baseLine = 0; Size textSize = CvInvoke.GetTextSize(p.PieceID.Replace("Piece", ""), FontFace.HersheyDuplex, 3, 2, ref baseLine); CvInvoke.PutText(sourceImg, p.PieceID.Replace("Piece", ""), Point.Add(roi.Location, new Size(0, textSize.Height + 10)), FontFace.HersheyDuplex, 3, new MCvScalar(255, 0, 0), 2); NumberPuzzlePieces++; pieceSourceImg.Dispose(); pieceMask.Dispose(); pieceSourceImageForeground.Dispose(); pieceMaskInverted.Dispose(); background.Dispose(); pieceSourceImageBackground.Dispose(); pieceSourceImgMasked.Dispose(); GC.Collect(); } Interlocked.Add(ref loopCount, 1); CurrentSolverStepPercentageFinished = (loopCount / (double)imageFilesInfo.Count) * 100; if (PluginFactory.GetGeneralSettingsPlugin().SolverShowDebugResults) { _logHandle.Report(new LogEventImage("Source Img " + i.ToString() + " Pieces", sourceImg.Bitmap)); } InputImages.Add(new ImageDescribedLight(Path.GetFileName(imageFilesInfo[i].FullName), PuzzlePiecesFolderPath + @"\Results\InputImagesMarked\" + Path.GetFileName(imageFilesInfo[i].FullName), sourceImg.Bitmap)); //sourceImg.LimitImageSize(1000, 1000).Bitmap)); blobs.Dispose(); blobDetector.Dispose(); GC.Collect(); } } GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); }); Pieces.Sort(p => ((Piece)p).PieceIndex, null); } catch (OperationCanceledException) { _logHandle.Report(new LogEventWarning("The operation was canceled. Step: " + CurrentSolverState.ToString())); CurrentSolverState = PuzzleSolverState.UNSOLVED; } catch (Exception ex) { _logHandle.Report(new LogEventError("The following error occured in step " + CurrentSolverState.ToString() + ":\n" + ex.Message)); CurrentSolverState = PuzzleSolverState.ERROR; CurrentSolverStepPercentageFinished = 100; } }