public List<Bitmap> PickSlices(IReadOnlyList<Bitmap> inputImages, Size sliceSize) { var edgeImages = inputImages.Select(grayscaleFilter.Apply).ToList(); edgeImages.ForEach(edgeDetectionFilter.ApplyInPlace); var edgeDensityHistograms = edgeImages.Select(x => new HorizontalIntensityStatistics(x).Gray).ToList(); var imagesAndHistograms = Enumerable.Range(0, inputImages.Count).Select(index => { return new ImagesAndHistogram { OriginalImage = inputImages[index], EdgeImage = edgeImages[index], EdgeDensityHistogram = edgeDensityHistograms[index], Rating = ratingCalculator.ComputeRating(inputImages[index], edgeDensityHistograms[index], sliceSize.Width, sliceSize.Height) }; }).OrderBy(x => x.Rating).ToList(); var sliceAspect = sliceSize.Width / (double)sliceSize.Height; foreach (var imagesAndHistogram in imagesAndHistograms) { var desiredWidth = (int)(imagesAndHistogram.OriginalImage.Height * sliceAspect); if (desiredWidth > imagesAndHistogram.OriginalImage.Width) { continue; } var range = thumbnailGeneratorUtilities.GetRangeOfWidth(imagesAndHistogram.EdgeDensityHistogram, desiredWidth); var horizontalCrop = new Crop(new Rectangle(range.Min, 0, range.Max - range.Min, imagesAndHistogram.OriginalImage.Height)).Apply(imagesAndHistogram.OriginalImage); var horizontalCrop24bpp = horizontalCrop.Clone(new Rectangle(Point.Empty, horizontalCrop.Size), PixelFormat.Format24bppRgb); imagesAndHistogram.SliceImage = horizontalCrop24bpp; var resizer = new ResizeBicubic(sliceSize.Width, sliceSize.Height); imagesAndHistogram.SliceImageResized = resizer.Apply(horizontalCrop24bpp); } return imagesAndHistograms.Where(x => x.SliceImageResized != null).Select(x => x.SliceImageResized).ToList(); }
public static Bitmap ResizeImage(this Bitmap originalImage, int newWidth, int newHeight) { double aspectRatio; int calculatedWidth, calculatedHeight; if (originalImage.Width > originalImage.Height) { calculatedWidth = newWidth; aspectRatio = (float) newWidth/originalImage.Width; calculatedHeight = Convert.ToInt32(originalImage.Height*aspectRatio); } else { calculatedHeight = newHeight; aspectRatio = (float) newHeight/originalImage.Height; calculatedWidth = Convert.ToInt32(originalImage.Width*aspectRatio); } if (originalImage.Width <= calculatedWidth || originalImage.Height <= calculatedHeight) { calculatedHeight = originalImage.Height; calculatedWidth = originalImage.Width; } var resizeFilter = new ResizeBicubic(calculatedWidth, calculatedHeight); Bitmap result = resizeFilter.Apply(originalImage); return result; }
private static double scoreBitmap(WordsearchRotation rotation, Classifier classifier) { //Extract each charcater in this wordsearch, then run them through the classifier and sum the liklihoods of // the most probable class to determine an overall score for the image Bitmap[,] chars = null; //If using number of rows & cols for a fixed row/col width/height if(rotation.Segmentation == null) { //Use standardised width & height for characters (do this by first resizing the image) int wordsearchWidth = Constants.CHAR_WITH_WHITESPACE_WIDTH * rotation.Cols; int wordsearchHeight = Constants.CHAR_WITH_WHITESPACE_HEIGHT * rotation.Rows; ResizeBicubic resize = new ResizeBicubic(wordsearchWidth, wordsearchHeight); Bitmap resizedImg = resize.Apply(rotation.Bitmap); //Split the bitmap up into a 2D array of bitmaps chars = SplitImage.Grid(resizedImg, rotation.Rows, rotation.Cols); //If the image got resized, dispose of the resized copy if(resizedImg != rotation.Bitmap) { resizedImg.Dispose(); } } else //Otherwise we have a Segmentation object to use { chars = SplitImage.Segment(rotation.Bitmap, rotation.Segmentation); } double score = 0; foreach(Bitmap charImg in chars) { //Remove all of the whitespace etc... returning an image that can be used for classification Bitmap extractedCharImg = CharImgExtractor.Extract(charImg); //Classify this bitmap double[] charResult = classifier.Classify(extractedCharImg); //Get the largest probability from the classifier output and add it to the overall score double largest = charResult[0]; for(int i = 1; i < charResult.Length; i++) { if(charResult[i] > largest) { largest = charResult[i]; } } score += largest; //Clean up extractedCharImg.Dispose(); charImg.Dispose(); } return score; }
static void Main(string[] args) { string sourceDirectory = Path.GetDirectoryName(args[0]); string[] bmpPaths = Directory.GetFiles(args[0]); foreach (string bmpPath in bmpPaths) { string fileName = Path.GetFileNameWithoutExtension(bmpPath); Bitmap bmp = (Bitmap)Image.FromFile(bmpPath); float scaler = 816 / (bmp.Width * 1.0f); ResizeBicubic resizer = new ResizeBicubic( (int)Math.Floor(scaler * bmp.Width), (int)Math.Floor(scaler * bmp.Height)); resizer.Apply(bmp).Save(Path.Combine(sourceDirectory, fileName + "_resized.bmp")); } }
/// <summary> /// Detects and recognizes cards from source image /// </summary> /// <param name="source">Source image to be scanned</param> /// <returns>Recognized Cards</returns> public CardCollection Recognize(Bitmap source) { CardCollection collection = new CardCollection(); //Collection that will hold cards Bitmap temp = source.Clone() as Bitmap; //Clone image to keep original image FiltersSequence seq = new FiltersSequence(); seq.Add(Grayscale.CommonAlgorithms.BT709); //First add grayScaling filter seq.Add(new OtsuThreshold()); //Then add binarization(thresholding) filter temp = seq.Apply(source); // Apply filters on source image //Extract blobs from image whose size width and height larger than 150 BlobCounter extractor = new BlobCounter(); extractor.FilterBlobs = true; extractor.MinWidth = extractor.MinHeight = 150; extractor.MaxWidth = extractor.MaxHeight = 350; extractor.ProcessImage(temp); //Will be used transform(extract) cards on source image QuadrilateralTransformation quadTransformer = new QuadrilateralTransformation(); //Will be used resize(scaling) cards ResizeBilinear resizer = new ResizeBilinear(CardWidth, CardHeight); foreach (Blob blob in extractor.GetObjectsInformation()) { //Get Edge points of card List<IntPoint> edgePoints = extractor.GetBlobsEdgePoints(blob); //Calculate/Find corners of card on source image from edge points List<IntPoint> corners = PointsCloud.FindQuadrilateralCorners(edgePoints); quadTransformer.SourceQuadrilateral = corners; //Set corners for transforming card quadTransformer.AutomaticSizeCalculaton = true; Bitmap cardImg = quadTransformer.Apply(source); //Extract(transform) card image if (cardImg.Width > cardImg.Height) //If card is positioned horizontally cardImg.RotateFlip(RotateFlipType.Rotate90FlipNone); //Rotate cardImg = resizer.Apply(cardImg); //Normalize card size Card card = new Card(cardImg, corners.ToArray()); //Create Card Object bool faceCard = IsFaceCard(cardImg); //Determine type of card(face or not) ResizeBicubic res; seq.Clear(); seq.Add(Grayscale.CommonAlgorithms.BT709); seq.Add(new OtsuThreshold()); Bitmap topLeftSuit = card.GetTopLeftSuitPart(); Bitmap bmp = seq.Apply(topLeftSuit); bmp = CutWhiteSpaces(bmp); res = new ResizeBicubic(32, 40); bmp = res.Apply(bmp); Bitmap topLeftRank = card.GetTopLeftRankPart(); Bitmap bmp2 = seq.Apply(topLeftRank); bmp2 = CutWhiteSpaces(bmp2); seq.Clear(); seq.Add(new OtsuThreshold()); bmp = seq.Apply(bmp); card.Suit = ScanSuit(bmp); if (!faceCard) { res = new ResizeBicubic(26, 40); bmp2 = res.Apply(bmp2); seq.Clear(); seq.Add(new OtsuThreshold()); bmp2 = seq.Apply(bmp2); card.Rank = ScanRank(bmp2); } else { res = new ResizeBicubic(32, 40); bmp2 = res.Apply(bmp2); seq.Clear(); seq.Add(new OtsuThreshold()); bmp2 = seq.Apply(bmp2); card.Rank = ScanFaceRank(bmp2); } collection.Add(card); //Add card to collection } return collection; }
internal static WordsearchSolutionEvaluator EvaluateWordsearchBitmap(Bitmap wordsearchBitmap, string[] wordsToFind, Dictionary<string, List<WordPosition>> correctSolutions, SegmentationAlgorithm segmentationAlgorithm, bool segmentationRemoveSmallRowsAndCols, SegmentationMethod segmentationMethod, Classifier probabilisticRotationCorrectionClassifier, Classifier classifier, Solver wordsearchSolver) { /* * Wordsearch Segmentation */ Segmentation segmentation = segmentationAlgorithm.Segment(wordsearchBitmap); //Remove erroneously small rows and columns from the segmentation if that option is specified if(segmentationRemoveSmallRowsAndCols) { segmentation = segmentation.RemoveSmallRowsAndCols(); } /* * Wordsearch Rotation Correction */ WordsearchRotation originalRotation; //If we're using fixed row & col width if (segmentationMethod == SegmentationMethod.FixedWidth) { originalRotation = new WordsearchRotation(wordsearchBitmap, segmentation.NumRows, segmentation.NumCols); } else //Otherwise we're using varied row/col width segmentation, use the Segmentation object { originalRotation = new WordsearchRotation(wordsearchBitmap, segmentation); } WordsearchRotation rotatedWordsearch = WordsearchRotationCorrection.CorrectOrientation(originalRotation, probabilisticRotationCorrectionClassifier); Bitmap rotatedImage = rotatedWordsearch.Bitmap; //If the wordsearch has been rotated if (rotatedImage != wordsearchBitmap) { //Update the segmentation //If the wordsearch rotation won't have been passed a segmentation if (segmentationMethod == SegmentationMethod.FixedWidth) { //Make a new fixed width segmentation from the WordsearchRotation segmentation = new Segmentation(rotatedWordsearch.Rows, rotatedWordsearch.Cols, rotatedImage.Width, rotatedImage.Height); } else { //Use the rotated segmentation segmentation = rotatedWordsearch.Segmentation; } } /* * Classification */ //Split image up into individual characters Bitmap[,] rawCharImgs = null; //If we're using fixed row & col width if (segmentationMethod == SegmentationMethod.FixedWidth) { ResizeBicubic resize = new ResizeBicubic(Constants.CHAR_WITH_WHITESPACE_WIDTH * segmentation.NumCols, Constants.CHAR_WITH_WHITESPACE_HEIGHT * segmentation.NumRows); Bitmap resizedImage = resize.Apply(rotatedImage); rawCharImgs = SplitImage.Grid(resizedImage, segmentation.NumRows, segmentation.NumCols); //Resized image no longer required resizedImage.Dispose(); } else //Otherwise we're using varied row/col width segmentation { rawCharImgs = SplitImage.Segment(rotatedImage, segmentation); //If the Segmentation Method is to resize the raw char imgs, resize them if (segmentationMethod == SegmentationMethod.VariedWidthWithResize) { ResizeBicubic resize = new ResizeBicubic(Constants.CHAR_WITH_WHITESPACE_WIDTH, Constants.CHAR_WITH_WHITESPACE_HEIGHT); for (int i = 0; i < rawCharImgs.GetLength(0); i++) { for (int j = 0; j < rawCharImgs.GetLength(1); j++) { //Only do the resize if it isn't already that size if (rawCharImgs[i, j].Width != Constants.CHAR_WITH_WHITESPACE_WIDTH || rawCharImgs[i, j].Height != Constants.CHAR_WITH_WHITESPACE_HEIGHT) { Bitmap orig = rawCharImgs[i, j]; rawCharImgs[i, j] = resize.Apply(orig); //Remove the now unnecessary original/not resized image orig.Dispose(); } } } } } //Full sized rotated image no longer required rotatedImage.Dispose(); //Get the part of the image that actually contains the character (without any whitespace) Bitmap[,] charImgs = CharImgExtractor.ExtractAll(rawCharImgs); //Raw char img's are no longer required rawCharImgs.ToSingleDimension().DisposeAll(); //Perform the classification on all of the images (returns probabilities for each possible class) double[][][] classifierOutput = classifier.Classify(charImgs); //Actual images of the characters are no longer required charImgs.ToSingleDimension().DisposeAll(); /* * Solve Wordsearch */ Solution solution = wordsearchSolver.Solve(classifierOutput, wordsToFind); /* * Evaluate the Proposed Solution */ WordsearchSolutionEvaluator evaluator = new WordsearchSolutionEvaluator(solution, correctSolutions); return evaluator; }
/// <summary> /// Process the filter on the specified image. /// </summary> /// /// <param name="image">Source image data.</param> /// protected override unsafe void ProcessFilter(UnmanagedImage image) { UnmanagedImage bgImage = null; BitmapData bgLockedData = null; // get image size var width = image.Width; var height = image.Height; var offset = image.Stride - ((image.PixelFormat == PixelFormat.Format8bppIndexed) ? width : width * 3); // check if we have provided background if ((this.backgroundImage == null) && (this.unmanagedBackgroundImage == null)) { // resize image to 1/3 of its original size to make bluring faster var resizeFilter = new ResizeBicubic((int)width / 3, (int)height / 3); var tempImage = resizeFilter.Apply(image); // create background image from the input image blurring it with Gaussian 5 times var blur = new GaussianBlur(5, 21); blur.ApplyInPlace(tempImage); blur.ApplyInPlace(tempImage); blur.ApplyInPlace(tempImage); blur.ApplyInPlace(tempImage); blur.ApplyInPlace(tempImage); // resize the blurred image back to original size resizeFilter.NewWidth = width; resizeFilter.NewHeight = height; bgImage = resizeFilter.Apply(tempImage); tempImage.Dispose( ); } else { if (this.backgroundImage != null) { // check background image if ((width != this.backgroundImage.Width) || (height != this.backgroundImage.Height) || (image.PixelFormat != this.backgroundImage.PixelFormat)) { throw new InvalidImagePropertiesException("Source image and background images must have the same size and pixel format"); } // lock background image bgLockedData = this.backgroundImage.LockBits( new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, this.backgroundImage.PixelFormat); bgImage = new UnmanagedImage(bgLockedData); } else { bgImage = this.unmanagedBackgroundImage; } } // get background image's statistics (mean value is used as correction factor) var bgStatistics = new ImageStatistics(bgImage); var src = (byte *)image.ImageData.ToPointer( ); var bg = (byte *)bgImage.ImageData.ToPointer( ); // do the job if (image.PixelFormat == PixelFormat.Format8bppIndexed) { // grayscale image var mean = bgStatistics.Gray.Mean; for (var y = 0; y < height; y++) { for (var x = 0; x < width; x++, src++, bg++) { if (*bg != 0) { *src = (byte)Math.Min(mean * *src / *bg, 255); } } src += offset; bg += offset; } } else { // color image var meanR = bgStatistics.Red.Mean; var meanG = bgStatistics.Green.Mean; var meanB = bgStatistics.Blue.Mean; for (var y = 0; y < height; y++) { for (var x = 0; x < width; x++, src += 3, bg += 3) { // red if (bg[RGB.R] != 0) { src[RGB.R] = (byte)Math.Min(meanR * src[RGB.R] / bg[RGB.R], 255); } // green if (bg[RGB.G] != 0) { src[RGB.G] = (byte)Math.Min(meanG * src[RGB.G] / bg[RGB.G], 255); } // blue if (bg[RGB.B] != 0) { src[RGB.B] = (byte)Math.Min(meanB * src[RGB.B] / bg[RGB.B], 255); } } src += offset; bg += offset; } } if (this.backgroundImage != null) { this.backgroundImage.UnlockBits(bgLockedData); } // dispose background image if it was not set manually if ((this.backgroundImage == null) && (this.unmanagedBackgroundImage == null)) { bgImage.Dispose( ); } }
/// <summary> /// Process the filter on the specified image. /// </summary> /// /// <param name="image">Source image data.</param> /// protected override unsafe void ProcessFilter( UnmanagedImage image ) { UnmanagedImage bgImage = null; BitmapData bgLockedData = null; // get image size int width = image.Width; int height = image.Height; int offset = image.Stride - ( ( image.PixelFormat == PixelFormat.Format8bppIndexed ) ? width : width * 3 ); // check if we have provided background if ( ( backgroundImage == null ) && ( unmanagedBackgroundImage == null ) ) { // resize image to 1/3 of its original size to make bluring faster ResizeBicubic resizeFilter = new ResizeBicubic( (int) width / 3, (int) height / 3 ); UnmanagedImage tempImage = resizeFilter.Apply( image ); // create background image from the input image blurring it with Gaussian 5 times GaussianBlur blur = new GaussianBlur( 5, 21 ); blur.ApplyInPlace( tempImage ); blur.ApplyInPlace( tempImage ); blur.ApplyInPlace( tempImage ); blur.ApplyInPlace( tempImage ); blur.ApplyInPlace( tempImage ); // resize the blurred image back to original size resizeFilter.NewWidth = width; resizeFilter.NewHeight = height; bgImage = resizeFilter.Apply( tempImage ); tempImage.Dispose( ); } else { if ( backgroundImage != null ) { // check background image if ( ( width != backgroundImage.Width ) || ( height != backgroundImage.Height ) || ( image.PixelFormat != backgroundImage.PixelFormat ) ) { throw new InvalidImagePropertiesException( "Source image and background images must have the same size and pixel format" ); } // lock background image bgLockedData = backgroundImage.LockBits( new Rectangle( 0, 0, width, height ), ImageLockMode.ReadOnly, backgroundImage.PixelFormat ); bgImage = new UnmanagedImage( bgLockedData ); } else { bgImage = unmanagedBackgroundImage; } } // get background image's statistics (mean value is used as correction factor) ImageStatistics bgStatistics = new ImageStatistics( bgImage ); byte* src = (byte*) image.ImageData.ToPointer( ); byte* bg = (byte*) bgImage.ImageData.ToPointer( ); // do the job if ( image.PixelFormat == PixelFormat.Format8bppIndexed ) { // grayscale image double mean = bgStatistics.Gray.Mean; for ( int y = 0; y < height; y++ ) { for ( int x = 0; x < width; x++, src++, bg++ ) { if ( *bg != 0 ) { *src = (byte) Math.Min( mean * *src / *bg, 255 ); } } src += offset; bg += offset; } } else { // color image double meanR = bgStatistics.Red.Mean; double meanG = bgStatistics.Green.Mean; double meanB = bgStatistics.Blue.Mean; for ( int y = 0; y < height; y++ ) { for ( int x = 0; x < width; x++, src += 3, bg += 3 ) { // red if ( bg[RGB.R] != 0 ) { src[RGB.R] = (byte) Math.Min( meanR * src[RGB.R] / bg[RGB.R], 255 ); } // green if ( bg[RGB.G] != 0 ) { src[RGB.G] = (byte) Math.Min( meanG * src[RGB.G] / bg[RGB.G], 255 ); } // blue if ( bg[RGB.B] != 0 ) { src[RGB.B] = (byte) Math.Min( meanB * src[RGB.B] / bg[RGB.B], 255 ); } } src += offset; bg += offset; } } if ( backgroundImage != null ) { backgroundImage.UnlockBits( bgLockedData ); } // dispose background image if it was not set manually if ( ( backgroundImage == null ) && ( unmanagedBackgroundImage == null ) ) { bgImage.Dispose( ); } }
public static FoundBlobType Find(Bitmap bmp, FoundColorSpaces foundColorSpaces) { FoundBlobType foundBlobType = new FoundBlobType(); ResizeBicubic resize = new ResizeBicubic(30, 50); Bitmap resizedBitmap = resize.Apply(bmp); double blackPixelCount = 0; for (int y = 0; y < resizedBitmap.Height; y++) { for (int x = 0; x < resizedBitmap.Width; x++) { Color color = resizedBitmap.GetPixel(x, y); if (color.R == 0 && color.G == 0 && color.B == 0) { blackPixelCount++; } } } double total = (resizedBitmap.Width * resizedBitmap.Height * 1.0); double percentageBlack = blackPixelCount / total; int p0 = EdgeFoundAtX(resizedBitmap, 6); int p1 = EdgeFoundAtX(resizedBitmap, 16); int p2 = EdgeFoundAtX(resizedBitmap, 36); int p3 = EdgeFoundAtX(resizedBitmap, 43); if (percentageBlack < .6) { if (Math.Abs(p0 - p1) < 4 && Math.Abs(p2 - p0) < 4 && p0 > 0) { foundBlobType.ShapeType = ShapeTypeEnum.Pill; } else if (p0 < p1 && p2 <= p0) { foundBlobType.ShapeType = ShapeTypeEnum.Squiggle; } else if (p0 > p1 && p3 > p1) { foundBlobType.ShapeType = ShapeTypeEnum.Diamond; } } else { foundBlobType.ShapeType = ShapeTypeEnum.NotAType; } float darkestPixelBrightnessValue = float.MaxValue; float lightestPixelBrightnessValue = 0; float lightestHue = float.MaxValue; Bitmap corrected = foundColorSpaces.CorrectedRGBColorSpace; for (int y = 0; y < corrected.Height; y++) { for (int x = 0; x < corrected.Width; x++) { Color color = corrected.GetPixel(x, y); float brightness = color.GetBrightness(); float hue = color.GetHue(); if (brightness < darkestPixelBrightnessValue) { darkestPixelBrightnessValue = brightness; } if (brightness > lightestPixelBrightnessValue) { lightestPixelBrightnessValue = brightness; } if (hue < lightestHue) { lightestHue = hue; } } } float delta = (lightestPixelBrightnessValue - darkestPixelBrightnessValue); float darknessRange = lightestPixelBrightnessValue - (delta * .4f); foundBlobType.StrippedBitmap = new Bitmap(corrected.Width, corrected.Height, PixelFormat.Format24bppRgb); int redPixel = 0, greenPixel = 0, purplePixel = 0; foundBlobType.Histogram = new int[360]; for (int y = 0; y < corrected.Height; y++) { for (int x = 0; x < corrected.Width; x++) { Color color = corrected.GetPixel(x, y); if (color.GetBrightness() < darknessRange) { foundBlobType.StrippedBitmap.SetPixel(x, y, color); float hue = color.GetHue(); float sat = color.GetSaturation(); foundBlobType.Histogram[(int)hue]++; if (hue < 17 || hue > 329) { redPixel++; } else if (hue > 90 && hue < 187) { greenPixel++; } else if (hue < 31 || hue > 200) { purplePixel++; } } } } if (redPixel > greenPixel && redPixel > purplePixel) { foundBlobType.ColorType = ColorTypeEnum.Red; } else if (greenPixel > redPixel && greenPixel > purplePixel) { foundBlobType.ColorType = ColorTypeEnum.Green; } else if (purplePixel > redPixel && purplePixel > greenPixel) { foundBlobType.ColorType = ColorTypeEnum.Purple; } //bmp2.Save(@"c:\users\brush\desktop\brokenout\" + (Count++).ToString() + ".bmp"); return foundBlobType; }
public static Bitmap resize(this Bitmap bitmap, int width, int height) { AForge.Imaging.Filters.ResizeBicubic filter = new AForge.Imaging.Filters.ResizeBicubic(width, height); return(filter.Apply(AForge.Imaging.Image.Clone(bitmap, PixelFormat.Format24bppRgb))); }
public Bitmap ReescaladoBicubico(int anchura, int altura) { ResizeBicubic resize = new ResizeBicubic(anchura, altura); imagen = resize.Apply(imagen); return imagen; }
//Helper method to do all of the processing to solve a wordsearch private void doProcessing() { /* * Get all of the selected Algorithms to be used for the processing */ log("Loading Selected Algorithms . . ."); //Wordsearch Detection Segmentation Algorithm SegmentationAlgorithm wordsearchDetectionSegmentationAlgorithm = getSelectedSegmentationAlgorithm(wordsearchDetectionSegmentationToolStripMenuItem); //Wordsearch Segmentation Algorithm SegmentationAlgorithm wordsearchSegmentationAlgorithm = getSelectedSegmentationAlgorithm(wordsearchSegmentationToolStripMenuItem); //Segmentation Post Processor SegmentationPostProcessing segmentationPostProcessor = getSelectedSegmentationPostProcessor(); //Rotation Correction Classifier object (contains both feature extractor & classifier) Classifier rotationCorrectionClassifier = getSelectedClassifier(rotationCorrectionFeatureExtractionToolStripMenuItem, rotationCorrectionClassificationToolStripMenuItem); //Character Image Extraction: Do we normalise the input (with whitespace) image dimensions before finding the biggest blob? // Note that this is ignored if there is equal segmentation spacing (where resizing will always be used as this is how // the classifier was trained) bool charImageExtractionWithWhitespaceNormaliseDimensions = characterImageExtractionInputDimensionsNormalisedToolStripMenuItem.Checked; //Classifier object used for actual classification (contains both feature extractor & classifier) Classifier classifier = getSelectedClassifier(featureExtractionToolStripMenuItem, classificationToolStripMenuItem); //Wordsearch Solver Algorithm Solver wordsearchSolver = getSelectedWordsearchSolver(); log("Selected Algorithms Loaded Successfully!"); /* * Start Processing */ //Start the timer for all processing setProcessingStageState(ProcessingStage.All, CheckState.Indeterminate); //Get the input image Bitmap img = currentBitmap; //Get the words to find string[] wordsToFind = getWordsToFind(); /* * Wordsearch Detection */ //Show that we're starting Wordsearch Detection setProcessingStageState(ProcessingStage.WordsearchDetection, CheckState.Indeterminate); //TODO: Get all candidates & their scores and show these in the image log //Get the candidate most likely to be a Wordsearch Tuple<List<IntPoint>, Bitmap> wordsearchImageTuple = DetectionAlgorithm.ExtractBestWordsearch( img, wordsearchDetectionSegmentationAlgorithm); //If the system failed to find anything remotely resembling a wordsearch, fail now if(wordsearchImageTuple == null) { throw new ImageProcessingException("Wordsearch Detection could not find anything . . ."); } Bitmap wordsearchImage = wordsearchImageTuple.Item2; log(wordsearchImage, "Extracted Wordsearch Image"); //Mark Wordsearch Detection as completed setProcessingStageState(ProcessingStage.WordsearchDetection, CheckState.Checked); /* * Wordsearch Segmentation */ //Show that we're starting Wordsearch Segmentation setProcessingStageState(ProcessingStage.WordsearchSegmentation, CheckState.Indeterminate); Segmentation segmentation = wordsearchSegmentationAlgorithm.Segment(wordsearchImage); //Log the Segmentation (visually) log(DrawGrid.Segmentation(wordsearchImage, segmentation, DRAW_SEGMENTATION_COLOUR), "Segmentation"); //Mark Wordsearch Segmentation as completed setProcessingStageState(ProcessingStage.WordsearchSegmentation, CheckState.Checked); /* * Wordsearch Segmentation Post-Processing */ //Show that we're starting Segmentation Post-Processing setProcessingStageState(ProcessingStage.SegmentationPostProcessing, CheckState.Indeterminate); switch(segmentationPostProcessor) { case SegmentationPostProcessing.RemoveSmallRowsAndCols: segmentation = segmentation.RemoveSmallRowsAndCols(); break; } //If any post-processing was done, log the segmentation (visually) if(segmentationPostProcessor != SegmentationPostProcessing.None) { log(DrawGrid.Segmentation(wordsearchImage, segmentation, DRAW_SEGMENTATION_COLOUR), "Post-Processed Segmentation"); } //Mark Segmentation Post-Processing as complete setProcessingStageState(ProcessingStage.SegmentationPostProcessing, CheckState.Checked); /* * Wordsearch Rotation Correction */ //Show that we're starting Rotation Correction setProcessingStageState(ProcessingStage.RotationCorrection, CheckState.Indeterminate); WordsearchRotation originalRotation; //If the rows & cols in the Segmentation are all equally spaced apart, optimise by using the number of rows & cols if(segmentation.IsEquallySpaced) { originalRotation = new WordsearchRotation(wordsearchImage, segmentation.NumRows, segmentation.NumCols); } else //Otherwise the Segmentation has varied sized row/col width { originalRotation = new WordsearchRotation(wordsearchImage, segmentation); } WordsearchRotation rotatedWordsearch = WordsearchRotationCorrection.CorrectOrientation( originalRotation, rotationCorrectionClassifier); Bitmap rotatedImage = rotatedWordsearch.Bitmap; //If the wordsearch has been rotated if(rotatedImage != wordsearchImage) { //Update the segmentation //If the wordsearch rotation won't have passed a segmentation if(segmentation.IsEquallySpaced) { //Make a new fixed width segmentation from the wordsearchRotation segmentation = new Segmentation(rotatedWordsearch.Rows, rotatedWordsearch.Cols, rotatedImage.Width, rotatedImage.Height); } else //Otherwise the WordsearchRotation will have been working with a Segmentation { //Use the rotated Segmentation object segmentation = rotatedWordsearch.Segmentation; } } //Log the rotated image log(rotatedImage, "Rotated Wordsearch"); log(DrawGrid.Segmentation(rotatedImage, segmentation, DRAW_SEGMENTATION_COLOUR), "Rotated Segmentation"); //Mark Rotation Correction as completed setProcessingStageState(ProcessingStage.RotationCorrection, CheckState.Checked); /* * Character Image Extraction */ //Show that we're starting Character Image Extraction setProcessingStageState(ProcessingStage.CharacterImageExtraction, CheckState.Indeterminate); //Split the image up using the Segmentation Bitmap[,] rawCharImgs = null; //If we're using equally spaced Segmentation if(segmentation.IsEquallySpaced) { //Resize the image first, so that the characters returned when you split the image will already be the correct size ResizeBicubic resize = new ResizeBicubic(Constants.CHAR_WITH_WHITESPACE_WIDTH * segmentation.NumCols, Constants.CHAR_WITH_WHITESPACE_HEIGHT * segmentation.NumRows); Bitmap resizedImage = resize.Apply(rotatedImage); //Split the image using a standard grid based on the number of rows & cols // (which is correct because of the equally spaced Segmentation) rawCharImgs = SplitImage.Grid(resizedImage, segmentation.NumRows, segmentation.NumCols); //Resized image no longer required resizedImage.Dispose(); } else //Otherwise there is varied spacing between characters { rawCharImgs = SplitImage.Segment(rotatedImage, segmentation); //If we're resizing the raw character images (with whitespace) to consistent dimensions if(charImageExtractionWithWhitespaceNormaliseDimensions) { //Resize the raw char images so that they're all the same dimensions (gives results that are more consistent with how the // classifier was trained: with equally spaced segmentation) ResizeBicubic resize = new ResizeBicubic(Constants.CHAR_WITH_WHITESPACE_WIDTH, Constants.CHAR_WITH_WHITESPACE_HEIGHT); for (int i = 0; i < rawCharImgs.GetLength(0); i++) { for (int j = 0; j < rawCharImgs.GetLength(1); j++) { //Only do the resize if it isn't already that size if (rawCharImgs[i, j].Width != Constants.CHAR_WITH_WHITESPACE_WIDTH || rawCharImgs[i, j].Height != Constants.CHAR_WITH_WHITESPACE_HEIGHT) { Bitmap orig = rawCharImgs[i, j]; rawCharImgs[i, j] = resize.Apply(orig); //Remove the now unnecessary original/not resized image orig.Dispose(); } } } } } //Log the raw character images (if we've resized them) if(segmentation.IsEquallySpaced || charImageExtractionWithWhitespaceNormaliseDimensions) { log(CombineImages.Grid(rawCharImgs), "Raw Character Images (all chars set to equal width & height)"); } //Get the part of the image that actually contains the character (without any whitespace) Bitmap[,] charImgs = CharImgExtractor.ExtractAll(rawCharImgs); //Raw char img's are no longer required rawCharImgs.ToSingleDimension().DisposeAll(); //Log the extracted character images log(CombineImages.Grid(charImgs), "Extracted Character Images"); //Mark Character Image Extraction as completed setProcessingStageState(ProcessingStage.CharacterImageExtraction, CheckState.Checked); /* * Feature Extraction & Classification */ //Show that we're starting Feature Extraction & Classification setProcessingStageState(ProcessingStage.FeatureExtractionAndClassification, CheckState.Indeterminate); double[][][] charProbabilities = classifier.Classify(charImgs); //Actual images of the characters are no longer required charImgs.ToSingleDimension().DisposeAll(); //Log the wordsearch as classified char[,] classifiedChars = NeuralNetworkHelpers.GetMostLikelyChars(charProbabilities); log("Wordsearch as classified (character that was given the highest probability):"); for (int i = 0; i < classifiedChars.GetLength(1); i++) //Rows { StringBuilder builder = new StringBuilder(); //Cols for(int j = 0; j < classifiedChars.GetLength(0); j++) { builder.Append(classifiedChars[j, i]); } log(builder.ToString()); } //Mark Feature Extraction & Classification as completed setProcessingStageState(ProcessingStage.FeatureExtractionAndClassification, CheckState.Checked); /* * Solve Wordsearch */ //Show that we're starting to Solve the Wordsearch setProcessingStageState(ProcessingStage.WordsearchSolver, CheckState.Indeterminate); Solution solution = wordsearchSolver.Solve(charProbabilities, wordsToFind); //Log the solution visually Bitmap bitmapSolution = DrawSolution.Solution(rotatedImage, segmentation, solution, DRAW_WORDS_COLOUR); log(bitmapSolution, "Solution"); log(DrawGrid.Segmentation(bitmapSolution, segmentation, DRAW_SEGMENTATION_COLOUR), "Solution + Segmentation"); //Log an Image for the solution to each word so that you can see where it thinks each word is foreach(KeyValuePair<string, WordPosition> kvp in solution) { string word = kvp.Key; WordPosition position = kvp.Value; //Draw this WordPosition onto the rotated image log(DrawSolution.WordPosition(rotatedImage, segmentation, position, DRAW_WORDS_COLOUR), String.Format("Solution for Word: {0}", word)); } //Mark the wordsearch as having been solved setProcessingStageState(ProcessingStage.WordsearchSolver, CheckState.Checked); //Log the time taken to complete all of the processing setProcessingStageState(ProcessingStage.All, CheckState.Checked); }
protected override unsafe void ProcessFilter(UnmanagedImage image) { UnmanagedImage unmanagedBackgroundImage = null; BitmapData bitmapData = null; int width = image.Width; int height = image.Height; int num3 = image.Stride - ((image.PixelFormat == PixelFormat.Format8bppIndexed) ? width : (width * 3)); if ((this.backgroundImage == null) && (this.unmanagedBackgroundImage == null)) { ResizeBicubic bicubic = new ResizeBicubic(width / 3, height / 3); UnmanagedImage image3 = bicubic.Apply(image); GaussianBlur blur = new GaussianBlur(5.0, 0x15); blur.ApplyInPlace(image3); blur.ApplyInPlace(image3); blur.ApplyInPlace(image3); blur.ApplyInPlace(image3); blur.ApplyInPlace(image3); bicubic.NewWidth = width; bicubic.NewHeight = height; unmanagedBackgroundImage = bicubic.Apply(image3); image3.Dispose(); } else if (this.backgroundImage != null) { if (((width != this.backgroundImage.Width) || (height != this.backgroundImage.Height)) || (image.PixelFormat != this.backgroundImage.PixelFormat)) { throw new InvalidImagePropertiesException("Source image and background images must have the same size and pixel format"); } bitmapData = this.backgroundImage.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, this.backgroundImage.PixelFormat); unmanagedBackgroundImage = new UnmanagedImage(bitmapData); } else { unmanagedBackgroundImage = this.unmanagedBackgroundImage; } ImageStatistics statistics = new ImageStatistics(unmanagedBackgroundImage); byte * numPtr = (byte *)image.ImageData.ToPointer(); byte * numPtr2 = (byte *)unmanagedBackgroundImage.ImageData.ToPointer(); if (image.PixelFormat == PixelFormat.Format8bppIndexed) { double num4 = statistics.Gray.get_Mean(); for (int i = 0; i < height; i++) { int num6 = 0; while (num6 < width) { if (numPtr2[0] != 0) { numPtr[0] = (byte)Math.Min((double)((num4 * numPtr[0]) / ((double)numPtr2[0])), (double)255.0); } num6++; numPtr++; numPtr2++; } numPtr += num3; numPtr2 += num3; } } else { double num7 = statistics.Red.get_Mean(); double num8 = statistics.Green.get_Mean(); double num9 = statistics.Blue.get_Mean(); for (int j = 0; j < height; j++) { int num11 = 0; while (num11 < width) { if (numPtr2[2] != 0) { numPtr[2] = (byte)Math.Min((double)((num7 * numPtr[2]) / ((double)numPtr2[2])), (double)255.0); } if (numPtr2[1] != 0) { numPtr[1] = (byte)Math.Min((double)((num8 * numPtr[1]) / ((double)numPtr2[1])), (double)255.0); } if (numPtr2[0] != 0) { numPtr[0] = (byte)Math.Min((double)((num9 * numPtr[0]) / ((double)numPtr2[0])), (double)255.0); } num11++; numPtr += 3; numPtr2 += 3; } numPtr += num3; numPtr2 += num3; } } if (this.backgroundImage != null) { this.backgroundImage.UnlockBits(bitmapData); } if ((this.backgroundImage == null) && (this.unmanagedBackgroundImage == null)) { unmanagedBackgroundImage.Dispose(); } }
protected unsafe override void ProcessFilter(UnmanagedImage image) { UnmanagedImage unmanagedImage = null; BitmapData bitmapData = null; int width = image.Width; int height = image.Height; int num = image.Stride - ((image.PixelFormat == PixelFormat.Format8bppIndexed) ? width : (width * 3)); if (backgroundImage == null && unmanagedBackgroundImage == null) { ResizeBicubic resizeBicubic = new ResizeBicubic(width / 3, height / 3); UnmanagedImage unmanagedImage2 = resizeBicubic.Apply(image); GaussianBlur gaussianBlur = new GaussianBlur(5.0, 21); gaussianBlur.ApplyInPlace(unmanagedImage2); gaussianBlur.ApplyInPlace(unmanagedImage2); gaussianBlur.ApplyInPlace(unmanagedImage2); gaussianBlur.ApplyInPlace(unmanagedImage2); gaussianBlur.ApplyInPlace(unmanagedImage2); resizeBicubic.NewWidth = width; resizeBicubic.NewHeight = height; unmanagedImage = resizeBicubic.Apply(unmanagedImage2); unmanagedImage2.Dispose(); } else if (backgroundImage != null) { if (width != backgroundImage.Width || height != backgroundImage.Height || image.PixelFormat != backgroundImage.PixelFormat) { throw new InvalidImagePropertiesException("Source image and background images must have the same size and pixel format"); } bitmapData = backgroundImage.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, backgroundImage.PixelFormat); unmanagedImage = new UnmanagedImage(bitmapData); } else { unmanagedImage = unmanagedBackgroundImage; } ImageStatistics imageStatistics = new ImageStatistics(unmanagedImage); byte * ptr = (byte *)image.ImageData.ToPointer(); byte * ptr2 = (byte *)unmanagedImage.ImageData.ToPointer(); if (image.PixelFormat == PixelFormat.Format8bppIndexed) { double mean = imageStatistics.Gray.Mean; for (int i = 0; i < height; i++) { int num2 = 0; while (num2 < width) { if (*ptr2 != 0) { *ptr = (byte)System.Math.Min(mean * (double)(int)(*ptr) / (double)(int)(*ptr2), 255.0); } num2++; ptr++; ptr2++; } ptr += num; ptr2 += num; } } else { double mean2 = imageStatistics.Red.Mean; double mean3 = imageStatistics.Green.Mean; double mean4 = imageStatistics.Blue.Mean; for (int j = 0; j < height; j++) { int num3 = 0; while (num3 < width) { if (ptr2[2] != 0) { ptr[2] = (byte)System.Math.Min(mean2 * (double)(int)ptr[2] / (double)(int)ptr2[2], 255.0); } if (ptr2[1] != 0) { ptr[1] = (byte)System.Math.Min(mean3 * (double)(int)ptr[1] / (double)(int)ptr2[1], 255.0); } if (*ptr2 != 0) { *ptr = (byte)System.Math.Min(mean4 * (double)(int)(*ptr) / (double)(int)(*ptr2), 255.0); } num3++; ptr += 3; ptr2 += 3; } ptr += num; ptr2 += num; } } if (backgroundImage != null) { backgroundImage.UnlockBits(bitmapData); } if (backgroundImage == null && unmanagedBackgroundImage == null) { unmanagedImage.Dispose(); } }