public NikseBitmap(NikseBitmap input) { Width = input.Width; Height = input.Height; _bitmapData = new byte[input._bitmapData.Length]; Buffer.BlockCopy(input._bitmapData, 0, _bitmapData, 0, _bitmapData.Length); }
public ImageSplitterItem(int x, int y, NikseBitmap bitmap) { X = x; Y = y; NikseBitmap = bitmap; SpecialCharacter = null; }
public static NikseBitmap CropTopAndBottom(NikseBitmap bmp, out int topCropping) { int startTop = 0; int maxTop = bmp.Height - 2; if (maxTop > bmp.Height) { maxTop = bmp.Height; } for (int y = 0; y < maxTop; y++) { bool allTransparent = true; for (int x = 1; x < bmp.Width - 1; x++) { int a = bmp.GetAlpha(x, y); if (a != 0) { allTransparent = false; break; } } if (!allTransparent) { break; } startTop++; } //if (startTop > 9) //startTop -= 5; // if top space > 9, then allways leave blank 5 pixels on top (so . is not confused with '). topCropping = startTop; int height = bmp.Height; bool bottomCroppingDone = false; for (int y = bmp.Height - 1; y > 3; y--) { for (int x = 1; x < bmp.Width - 1; x++) { int a = bmp.GetAlpha(x, y); if (a != 0) { bottomCroppingDone = true; break; } } height = y; if (bottomCroppingDone) { break; } } return bmp.CopyRectangle(new Rectangle(0, startTop, bmp.Width, height - startTop + 1)); }
public void TestMethodBinOcrSaveLoad() { string tempFileName = Path.GetTempFileName(); var db = new BinaryOcrDb(tempFileName); var nbmp = new NikseBitmap(2, 2); nbmp.SetPixel(0, 0, Color.Transparent); nbmp.SetPixel(1, 0, Color.Transparent); nbmp.SetPixel(1, 0, Color.Transparent); nbmp.SetPixel(1, 1, Color.White); var bob = new BinaryOcrBitmap(nbmp); bob.Text = "Debug"; db.Add(bob); nbmp.SetPixel(0, 0, Color.White); var bob2 = new BinaryOcrBitmap(nbmp); bob2.X = 2; bob2.Y = 4; bob2.Text = "tt"; bob2.Italic = true; bob2.ExpandCount = 2; bob2.ExpandedList = new System.Collections.Generic.List<BinaryOcrBitmap>(); bob2.ExpandedList.Add(bob2); db.Add(bob2); db.Save(); db = new BinaryOcrDb(tempFileName, true); Assert.IsTrue(db.CompareImages.Count == 1); Assert.IsTrue(db.CompareImagesExpanded.Count == 1); Assert.IsTrue(bob.Width == db.CompareImages[0].Width); Assert.IsTrue(bob.Height == db.CompareImages[0].Height); Assert.IsTrue(bob.NumberOfColoredPixels == db.CompareImages[0].NumberOfColoredPixels); Assert.IsTrue(bob.Hash == db.CompareImages[0].Hash); Assert.IsTrue(bob.Italic == db.CompareImages[0].Italic); Assert.IsTrue(bob.ExpandCount == db.CompareImages[0].ExpandCount); Assert.IsTrue(bob.Text == db.CompareImages[0].Text); Assert.IsTrue(bob2.Width == db.CompareImagesExpanded[0].Width); Assert.IsTrue(bob2.Height == db.CompareImagesExpanded[0].Height); Assert.IsTrue(bob2.NumberOfColoredPixels == db.CompareImagesExpanded[0].NumberOfColoredPixels); Assert.IsTrue(bob2.Hash == db.CompareImagesExpanded[0].Hash); Assert.IsTrue(bob2.Italic == db.CompareImagesExpanded[0].Italic); Assert.IsTrue(bob2.ExpandCount == db.CompareImagesExpanded[0].ExpandCount); Assert.IsTrue(bob2.Text == db.CompareImagesExpanded[0].Text); Assert.IsTrue(bob2.X == db.CompareImagesExpanded[0].X); Assert.IsTrue(bob2.Y == db.CompareImagesExpanded[0].Y); try { File.Delete(tempFileName); } catch { } }
public static NikseBitmap CropTopAndBottom(NikseBitmap bmp, out int topCropping, int maxDifferentPixelsOnLine) { int startTop = 0; int maxTop = bmp.Height - 2; if (maxTop > bmp.Height) maxTop = bmp.Height; for (int y = 0; y < maxTop; y++) { int difference = 0; bool allTransparent = true; for (int x = 1; x < bmp.Width - 1; x++) { int a = bmp.GetAlpha(x, y); if (a != 0) { difference++; if (difference >= maxDifferentPixelsOnLine) { allTransparent = false; break; } } } if (!allTransparent) break; startTop++; } if (startTop > 9) startTop -= 5; // if top space > 9, then allways leave blank 5 pixels on top (so . is not confused with '). topCropping = startTop; for (int y = bmp.Height - 1; y > 3; y--) { int difference = 0; bool allTransparent = true; for (int x = 1; x < bmp.Width - 1; x++) { int a = bmp.GetAlpha(x, y); if (a != 0) { difference++; if (difference >= maxDifferentPixelsOnLine) { allTransparent = false; break; } } } if (allTransparent == false) return bmp.CopyRectangle(new Rectangle(0, startTop, bmp.Width - 1, y - startTop + 1)); } return bmp; }
internal void Initialize(Bitmap vobSubImage, ImageSplitterItem character, Point position, bool italicChecked, bool showShrink) { listBoxLinesForeground.Items.Clear(); listBoxlinesBackground.Items.Clear(); NikseBitmap nbmp = new NikseBitmap(vobSubImage); nbmp.ReplaceTransparentWith(Color.Black); vobSubImage = nbmp.GetBitmap(); radioButtonHot.Checked = true; ShrinkSelection = false; ExpandSelection = false; textBoxCharacters.Text = string.Empty; _nocrChar = new NOcrChar(); _nocrChar.MarginTop = character.Y - character.ParentY; _imageWidth = character.NikseBitmap.Width; _imageHeight = character.NikseBitmap.Height; _drawLineOn = false; _warningNoNotForegroundLinesShown = false; buttonShrinkSelection.Visible = showShrink; if (position.X != -1 && position.Y != -1) { StartPosition = FormStartPosition.Manual; Left = position.X; Top = position.Y; } pictureBoxSubtitleImage.Image = vobSubImage; pictureBoxCharacter.Image = character.NikseBitmap.GetBitmap(); Bitmap org = (Bitmap)vobSubImage.Clone(); Bitmap bm = new Bitmap(org.Width, org.Height); Graphics g = Graphics.FromImage(bm); g.DrawImage(org, 0, 0, org.Width, org.Height); g.DrawRectangle(Pens.Red, character.X, character.Y, character.NikseBitmap.Width, character.NikseBitmap.Height - 1); g.Dispose(); pictureBoxSubtitleImage.Image = bm; pictureBoxCharacter.Top = labelCharacters.Top + 16; SizePictureBox(); checkBoxItalic.Checked = italicChecked; _history = new List<NOcrChar>(); _historyIndex = -1; _nocrChar.Width = _imageWidth; _nocrChar.Height = _imageHeight; GenerateLineSegments(150, false, _nocrChar, new NikseBitmap(pictureBoxCharacter.Image as Bitmap)); ShowOcrPoints(); pictureBoxCharacter.Invalidate(); }
public ManagedBitmap(NikseBitmap nbmp) { Width = nbmp.Width; Height = nbmp.Height; _colors = new Color[Width * Height]; for (int y = 0; y < Height; y++) { for (int x = 0; x < Width; x++) { this.SetPixel(x, y, nbmp.GetPixel(x, y)); } } }
internal void Initialize(Bitmap bitmap, int pixelsIsSpace, bool rightToLeft, NOcrDb nOcrDb, VobSubOcr vobSubOcr) { _bitmap = bitmap; var nbmp = new NikseBitmap(bitmap); nbmp.ReplaceNonWhiteWithTransparent(); bitmap = nbmp.GetBitmap(); _bitmap2 = bitmap; _nocrChars = nOcrDb.OcrCharacters; _matchList = new List<VobSubOcr.CompareMatch>(); _vobSubOcr = vobSubOcr; int minLineHeight = 6; _imageList = NikseBitmapImageSplitter.SplitBitmapToLettersNew(nbmp, pixelsIsSpace, rightToLeft, Configuration.Settings.VobSubOcr.TopToBottom, minLineHeight); // _imageList = NikseBitmapImageSplitter.SplitBitmapToLetters(nbmp, pixelsIsSpace, rightToLeft, Configuration.Settings.VobSubOcr.TopToBottom); int index = 0; while (index < _imageList.Count) { ImageSplitterItem item = _imageList[index]; if (item.NikseBitmap == null) { listBoxInspectItems.Items.Add(item.SpecialCharacter); _matchList.Add(null); } else { nbmp = item.NikseBitmap; nbmp.ReplaceNonWhiteWithTransparent(); item.Y += nbmp.CropTopTransparent(0); nbmp.CropTransparentSidesAndBottom(0, true); nbmp.ReplaceTransparentWith(Color.Black); //get nocr matches Nikse.SubtitleEdit.Forms.VobSubOcr.CompareMatch match = vobSubOcr.GetNOcrCompareMatchNew(item, nbmp, nOcrDb, false, false); if (match == null) { listBoxInspectItems.Items.Add("?"); _matchList.Add(null); } else { listBoxInspectItems.Items.Add(match.Text); _matchList.Add(match); } } index++; } }
internal void Initialize(Bitmap vobSubImage, ImageSplitterItem character, Point position, bool italicChecked, bool showShrink, VobSubOcr.CompareMatch bestGuess, List<VobSubOcr.ImageCompareAddition> additions, VobSubOcr vobSubForm) { NikseBitmap nbmp = new NikseBitmap(vobSubImage); nbmp.ReplaceTransparentWith(Color.Black); vobSubImage = nbmp.GetBitmap(); radioButtonHot.Checked = true; ShrinkSelection = false; ExpandSelection = false; textBoxCharacters.Text = string.Empty; _vobSubForm = vobSubForm; _additions = additions; _nocrChar = new NOcrChar(); _nocrChar.MarginTop = character.Y - character.ParentY; _imageWidth = character.NikseBitmap.Width; _imageHeight = character.NikseBitmap.Height; _drawLineOn = false; _warningNoNotForegroundLinesShown = false; buttonShrinkSelection.Visible = showShrink; if (position.X != -1 && position.Y != -1) { StartPosition = FormStartPosition.Manual; Left = position.X; Top = position.Y; } pictureBoxSubtitleImage.Image = vobSubImage; pictureBoxCharacter.Image = character.NikseBitmap.GetBitmap(); Bitmap org = (Bitmap)vobSubImage.Clone(); Bitmap bm = new Bitmap(org.Width, org.Height); Graphics g = Graphics.FromImage(bm); g.DrawImage(org, 0, 0, org.Width, org.Height); g.DrawRectangle(Pens.Red, character.X, character.Y, character.NikseBitmap.Width, character.NikseBitmap.Height - 1); g.Dispose(); pictureBoxSubtitleImage.Image = bm; pictureBoxCharacter.Top = labelCharacters.Top + 16; SizePictureBox(); checkBoxItalic.Checked = italicChecked; _history = new List<NOcrChar>(); _historyIndex = -1; }
private void listBoxSubtitles_SelectedIndexChanged(object sender, EventArgs e) { int idx = listBoxSubtitles.SelectedIndex; if (idx < 0) return; int pid = _tsParser.SubtitlePacketIds[listBoxTracks.SelectedIndex]; var list = _tsParser.GetDvbSubtitles(pid); var dvbBmp = list[idx].GetActiveImage(); var nDvbBmp = new NikseBitmap(dvbBmp); nDvbBmp.CropTopTransparent(2); nDvbBmp.CropTransparentSidesAndBottom(2, true); dvbBmp.Dispose(); var oldImage = pictureBox1.Image; pictureBox1.Image = nDvbBmp.GetBitmap(); if (oldImage != null) oldImage.Dispose(); }
internal static ImageSplitterItem GetExpandedSelectionNew(NikseBitmap bitmap, List<ImageSplitterItem> expandSelectionList) { int minimumX = expandSelectionList[0].X; int maximumX = expandSelectionList[expandSelectionList.Count - 1].X + expandSelectionList[expandSelectionList.Count - 1].NikseBitmap.Width; int minimumY = expandSelectionList[0].Y; int maximumY = expandSelectionList[0].Y + expandSelectionList[0].NikseBitmap.Height; var nbmp = new NikseBitmap(bitmap.Width, bitmap.Height); foreach (ImageSplitterItem item in expandSelectionList) { for (int y = 0; y < item.NikseBitmap.Height; y++) { for (int x = 0; x < item.NikseBitmap.Width; x++) { int a = item.NikseBitmap.GetAlpha(x, y); if (a > 100) nbmp.SetPixel(item.X + x, item.Y + y, Color.White); } } if (item.Y < minimumY) minimumY = item.Y; if (item.Y + item.NikseBitmap.Height > maximumY) maximumY = item.Y + item.NikseBitmap.Height; } nbmp.CropTransparentSidesAndBottom(0, true); int topCropping; nbmp = NikseBitmapImageSplitter.CropTopAndBottom(nbmp, out topCropping); return new ImageSplitterItem(minimumX, minimumY, nbmp); }
internal static ImageSplitterItem GetExpandedSelection(NikseBitmap bitmap, List<ImageSplitterItem> expandSelectionList, bool rightToLeft) { if (rightToLeft) { int minimumX = expandSelectionList[expandSelectionList.Count - 1].X - expandSelectionList[expandSelectionList.Count - 1].NikseBitmap.Width; int maximumX = expandSelectionList[0].X; int minimumY = expandSelectionList[0].Y; int maximumY = expandSelectionList[0].Y + expandSelectionList[0].NikseBitmap.Height; foreach (ImageSplitterItem item in expandSelectionList) { if (item.Y < minimumY) minimumY = item.Y; if (item.Y + item.NikseBitmap.Height > maximumY) maximumY = item.Y + item.NikseBitmap.Height; } var part = bitmap.CopyRectangle(new Rectangle(minimumX, minimumY, maximumX - minimumX, maximumY - minimumY)); return new ImageSplitterItem(minimumX, minimumY, part); } else { int minimumX = expandSelectionList[0].X; int maximumX = expandSelectionList[expandSelectionList.Count - 1].X + expandSelectionList[expandSelectionList.Count - 1].NikseBitmap.Width; int minimumY = expandSelectionList[0].Y; int maximumY = expandSelectionList[0].Y + expandSelectionList[0].NikseBitmap.Height; foreach (ImageSplitterItem item in expandSelectionList) { if (item.Y < minimumY) minimumY = item.Y; if (item.Y + item.NikseBitmap.Height > maximumY) maximumY = item.Y + item.NikseBitmap.Height; } var part = bitmap.CopyRectangle(new Rectangle(minimumX, minimumY, maximumX - minimumX, maximumY - minimumY)); return new ImageSplitterItem(minimumX, minimumY, part); } }
private static bool IsVerticalLineTransparent(NikseBitmap bmp, ref int y, int x) { for (y = 0; y < bmp.Height - 1; y++) { var argb = bmp.GetPixelColors(x, y); if (argb[0] < 10 || IsColorClose(argb[0], argb[1], argb[2], argb[3], Color.Black, 280)) // still dark color... { } else { return false; } } return true; }
private static void RemoveBlackBarRight(NikseBitmap bmp) { int xRemoveBlackBar = bmp.Width - 1; for (int yRemoveBlackBar = 0; yRemoveBlackBar < bmp.Height; yRemoveBlackBar++) { byte[] c = bmp.GetPixelColors(xRemoveBlackBar, yRemoveBlackBar); if (c[0] == 0 || IsColorClose(c[0], c[1], c[2], c[3], Color.Black, 280)) { if (bmp.GetAlpha(xRemoveBlackBar - 1, yRemoveBlackBar) == 0) bmp.SetPixel(xRemoveBlackBar, yRemoveBlackBar, Color.Transparent); } } }
public static List<ImageSplitterItem> SplitVerticalTransparentOrBlack(NikseBitmap bmp) { int startY = 0; int size = 0; var parts = new List<ImageSplitterItem>(); for (int y = 0; y < bmp.Height; y++) { bool allTransparent = true; for (int x = 0; x < bmp.Width; x++) { Color c = bmp.GetPixel(x, y); if (c.A > 20 && c.R + c.G + c.B > 20) { allTransparent = false; break; } } if (allTransparent) { if (size > 2 && size <= 15) { size++; // at least 15 pixels, like top of 'i' or top of 'È' } else { if (size > 8) { NikseBitmap part = bmp.CopyRectangle(new Rectangle(0, startY, bmp.Width, size + 1)); // part.Save("c:\\line_0_to_width.bmp"); parts.Add(new ImageSplitterItem(0, startY, part)); // bmp.Save("c:\\original.bmp"); } size = 0; startY = y; } } else { size++; } } if (size > 2) { if (size == bmp.Height) parts.Add(new ImageSplitterItem(0, startY, bmp)); else parts.Add(new ImageSplitterItem(0, startY, bmp.CopyRectangle(new Rectangle(0, startY, bmp.Width, size + 1)))); } return parts; }
private Bitmap GenerateImageFromTextWithStyle(string text, bool bold) { bool subtitleFontBold = bold; bool subtitleAlignLeft = true; bool subtitleAlignRight = false; text = Utilities.RemoveHtmlTags(text); Font font; try { var fontStyle = FontStyle.Regular; if (subtitleFontBold) fontStyle = FontStyle.Bold; font = new Font(_subtitleFontName, _subtitleFontSize, fontStyle); } catch (Exception exception) { MessageBox.Show(exception.Message); font = new Font(FontFamily.Families[0].Name, _subtitleFontSize); } var bmp = new Bitmap(400, 200); var g = Graphics.FromImage(bmp); SizeF textSize = g.MeasureString("Hj!", font); var lineHeight = (textSize.Height * 0.64f); textSize = g.MeasureString(Utilities.RemoveHtmlTags(text), font); g.Dispose(); bmp.Dispose(); int sizeX = (int)(textSize.Width * 0.8) + 40; int sizeY = (int)(textSize.Height * 0.8) + 30; if (sizeX < 1) sizeX = 1; if (sizeY < 1) sizeY = 1; bmp = new Bitmap(sizeX, sizeY); g = Graphics.FromImage(bmp); var lefts = new List<float>(); foreach (string line in Utilities.RemoveHtmlFontTag(text.Replace("<i>", string.Empty).Replace("</i>", string.Empty)).Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries)) { if (subtitleAlignLeft) lefts.Add(5); else if (subtitleAlignRight) lefts.Add(bmp.Width - (TextDraw.MeasureTextWidth(font, line, subtitleFontBold) + 15)); else lefts.Add((float)(bmp.Width - g.MeasureString(line, font).Width * 0.8 + 15) / 2); } g.TextRenderingHint = TextRenderingHint.AntiAliasGridFit; g.SmoothingMode = SmoothingMode.AntiAlias; g.CompositingQuality = CompositingQuality.HighQuality; var sf = new StringFormat(); sf.Alignment = StringAlignment.Near; sf.LineAlignment = StringAlignment.Near;// draw the text to a path var path = new GraphicsPath(); // display italic var sb = new StringBuilder(); int i = 0; bool isItalic = false; float left = 5; if (lefts.Count > 0) left = lefts[0]; float top = 5; bool newLine = false; int lineNumber = 0; float leftMargin = left; int newLinePathPoint = -1; Color c = _subtitleColor; var colorStack = new Stack<Color>(); var lastText = new StringBuilder(); while (i < text.Length) { if (text.Substring(i).StartsWith(Environment.NewLine)) { TextDraw.DrawText(font, sf, path, sb, isItalic, subtitleFontBold, false, left, top, ref newLine, leftMargin, ref newLinePathPoint); top += lineHeight; newLine = true; i += Environment.NewLine.Length - 1; lineNumber++; if (lineNumber < lefts.Count) { leftMargin = lefts[lineNumber]; left = leftMargin; } } else { sb.Append(text.Substring(i, 1)); } i++; } if (sb.Length > 0) TextDraw.DrawText(font, sf, path, sb, isItalic, subtitleFontBold, false, left, top, ref newLine, leftMargin, ref newLinePathPoint); if (_borderWidth > 0) g.DrawPath(new Pen(_borderColor, _borderWidth), path); g.FillPath(new SolidBrush(c), path); g.Dispose(); var nbmp = new NikseBitmap(bmp); nbmp.CropTransparentSidesAndBottom(2, true); return nbmp.GetBitmap(); }
/// <summary> /// split into lines /// </summary> public static List<ImageSplitterItem> SplitToLines(NikseBitmap bmp, int minLineHeight, double averageLineHeight = -1) { int startY = 0; int size = 0; var parts = new List<ImageSplitterItem>(); for (int y = 0; y < bmp.Height; y++) { if (bmp.IsLineTransparent(y)) { // check for appendix below text bool appendix = y >= bmp.Height - minLineHeight; if (!appendix && y < bmp.Height - 10 && size > minLineHeight && minLineHeight > 15) { bool yp1 = bmp.IsLineTransparent(y + 1); bool yp2 = bmp.IsLineTransparent(y + 2); bool yp3 = bmp.IsLineTransparent(y + 3); bool yp4 = bmp.IsLineTransparent(y + 4); bool yp5 = bmp.IsLineTransparent(y + 5); if (!yp1 || !yp2 || !yp3 || !yp4 || !yp5) { bool yp6 = bmp.IsLineTransparent(y + 6); bool yp7 = bmp.IsLineTransparent(y + 7); bool yp8 = bmp.IsLineTransparent(y + 8); bool yp9 = bmp.IsLineTransparent(y + 9); if (yp6 && yp7 && yp8 && yp9) { appendix = true; } } } if (appendix || size > 1 && size <= minLineHeight) { size++; // at least 'lineMinHeight' pixels, like top of 'i' } else { if (size > 1) { var part = bmp.CopyRectangle(new Rectangle(0, startY, bmp.Width, size + 1)); parts.Add(new ImageSplitterItem(0, startY, part)); } size = 0; startY = y; } } else { size++; } } if (size > 1) { if (size == bmp.Height) { if (size > 100) { return SplitToLinesTransparentOrBlack(bmp); } parts.Add(new ImageSplitterItem(0, startY, bmp)); } else { parts.Add(new ImageSplitterItem(0, startY, bmp.CopyRectangle(new Rectangle(0, startY, bmp.Width, size + 1)))); } } if (parts.Count == 1 && averageLineHeight > 5 && bmp.Height > averageLineHeight * 3) { return SplitToLinesAggressive(bmp, minLineHeight, averageLineHeight); } return parts; }
private static List<ImageSplitterItem> SplitToLinesAggressive(NikseBitmap bmp, int minLineHeight, double averageLineHeight) { int startY = 0; int size = 0; var parts = new List<ImageSplitterItem>(); for (int y = 0; y < bmp.Height; y++) { int a; bool allTransparent = bmp.IsLineTransparent(y); if (size > 5 && size >= minLineHeight && size > averageLineHeight && !allTransparent && bmp.Width > 50 && y < bmp.Height - 5) { var leftX = 0; while (leftX < bmp.Width) { a = bmp.GetAlpha(leftX, y); if (a != 0) { break; } leftX++; } var rightX = bmp.Width; while (rightX > 0) { a = bmp.GetAlpha(rightX, y - 1); if (a != 0) { break; } rightX--; } if (leftX >= rightX) { allTransparent = true; } leftX = 0; while (leftX < bmp.Width) { a = bmp.GetAlpha(leftX, y - 1); if (a != 0) { break; } leftX++; } rightX = bmp.Width; while (rightX > 0) { a = bmp.GetAlpha(rightX, y); if (a != 0) { break; } rightX--; } if (leftX >= rightX) { allTransparent = true; } } if (allTransparent) { if (size > 2 && size <= minLineHeight) { size++; // at least 'lineMinHeight' pixels, like top of 'i' } else { if (size > 2) { var part = bmp.CopyRectangle(new Rectangle(0, startY, bmp.Width, size + 1)); parts.Add(new ImageSplitterItem(0, startY, part)); } size = 0; startY = y; } } else { size++; } } if (size > 2) { if (size == bmp.Height) { if (size > 100) { return SplitToLinesTransparentOrBlack(bmp); } parts.Add(new ImageSplitterItem(0, startY, bmp)); } else { parts.Add(new ImageSplitterItem(0, startY, bmp.CopyRectangle(new Rectangle(0, startY, bmp.Width, size + 1)))); } } if (parts.Count == 1 && averageLineHeight > 5 && bmp.Height > averageLineHeight * 3) { return parts; } return parts; }
public static List<ImageSplitterItem> SplitBitmapToLettersNew(NikseBitmap bmp, int xOrMorePixelsMakesSpace, bool rightToLeft, bool topToBottom, int minLineHeight, bool autoHeight, double averageLineHeight = -1) { var list = new List<ImageSplitterItem>(); // split into separate lines var splitOld = SplitToLines(bmp, minLineHeight, averageLineHeight); List<ImageSplitterItem> lineBitmaps; if (autoHeight) { // fast horizontal split by x number of whole lines (3-4) var splitThreeBlankLines = SplitToLinesByMinTransparentHorizontalLines(bmp, minLineHeight, 3); var splitFourBlankLines = SplitToLinesByMinTransparentHorizontalLines(bmp, minLineHeight, 4); var splitBlankLines = splitThreeBlankLines.Count == splitFourBlankLines.Count ? splitFourBlankLines : splitThreeBlankLines; lineBitmaps = splitOld.Count > splitBlankLines.Count ? splitOld : splitBlankLines; if (lineBitmaps.Count == 1 && lineBitmaps[0].NikseBitmap?.Height > minLineHeight * 2.2) { lineBitmaps = SplitToLinesNew(lineBitmaps[0], minLineHeight, averageLineHeight); // more advanced split (allows for up/down) } } else { lineBitmaps = splitOld; } //foreach (var bitmap in tempBitmaps) //{ // // var height = bitmap.NikseBitmap.GetNonTransparentHeight(); // var bitmaps = SplitToLinesNew(bitmap, minLineHeight, averageLineHeight); // more advanced split (allows for up/down) // lineBitmaps.AddRange(bitmaps); //} if (!topToBottom) { lineBitmaps.Reverse(); } // split into letters for (int index = 0; index < lineBitmaps.Count; index++) { var b = lineBitmaps[index]; if (index > 0) { list.Add(new ImageSplitterItem(Environment.NewLine)); } var line = new List<ImageSplitterItem>(); foreach (var item in SplitHorizontalNew(b, xOrMorePixelsMakesSpace)) { item.Top = index > 0 ? item.Y - b.Y : item.Y; item.ParentY = item.Y; line.Add(item); } if (rightToLeft) { line.Reverse(); } list.AddRange(line); } return list; }
/// <summary> /// split into lines /// </summary> public static List<ImageSplitterItem> SplitToLinesByMinTransparentHorizontalLines(NikseBitmap bmp, int minLineHeight, int minTransparentLines) { var parts = new List<ImageSplitterItem>(); var startY = 0; var lastTransparentY = -1; var keysInSequence = 0; for (int y = minLineHeight; y < bmp.Height - minLineHeight; y++) { var isLineTransparent = bmp.IsLineTransparent(y); if (startY == y && isLineTransparent) { startY++; continue; // skip start } if (isLineTransparent) { if (lastTransparentY == y - 1) { if (keysInSequence == 0) { keysInSequence++; } keysInSequence++; } if (keysInSequence > 2 && lastTransparentY - startY > minLineHeight) { var part = bmp.CopyRectangle(new Rectangle(0, startY, bmp.Width, lastTransparentY - startY - 1)); if (!part.IsImageOnlyTransparent() && part.GetNonTransparentHeight() >= minLineHeight) { var croppedTop = part.CropTopTransparent(0); parts.Add(new ImageSplitterItem(0, startY + croppedTop, part)); startY = lastTransparentY + 1; } } lastTransparentY = y; } else { keysInSequence = 0; lastTransparentY = -1; } } if (bmp.Height - startY > 1) { var part = bmp.CopyRectangle(new Rectangle(0, startY, bmp.Width, bmp.Height - startY)); if (!part.IsImageOnlyTransparent()) { var croppedTop = part.CropTopTransparent(0); parts.Add(new ImageSplitterItem(0, startY + croppedTop, part)); } } return parts; }
internal static CompareMatch GetNOcrCompareMatch(ImageSplitterItem targetItem, NikseBitmap parentBitmap, NOcrThreadParameter p) { bool italic; var expandedResult = NOcrFindExpandedMatch(parentBitmap, targetItem, targetItem.Y - targetItem.ParentY, p.NOcrChars); if (expandedResult != null) return new CompareMatch(expandedResult.Text, expandedResult.Italic, expandedResult.ExpandCount, null, expandedResult); var result = NOcrFindBestMatch(parentBitmap, targetItem, targetItem.Y - targetItem.ParentY, out italic, p.NOcrChars, p.UnItalicFactor, p.AdvancedItalicDetection, true); if (result == null) return null; // Fix uppercase/lowercase issues (not I/l) if (result.Text == "e") p.NOcrLastLowercaseHeight = targetItem.NikseBitmap.Height; else if (p.NOcrLastLowercaseHeight == -1 && result.Text == "a") p.NOcrLastLowercaseHeight = targetItem.NikseBitmap.Height; if (result.Text == "E" || result.Text == "H" || result.Text == "R" || result.Text == "D" || result.Text == "T") p.NOcrLastUppercaseHeight = targetItem.NikseBitmap.Height; else if (p.NOcrLastUppercaseHeight == -1 && result.Text == "M") p.NOcrLastUppercaseHeight = targetItem.NikseBitmap.Height; if (result.Text == "V" || result.Text == "W" || result.Text == "U" || result.Text == "S" || result.Text == "Z" || result.Text == "O" || result.Text == "X" || result.Text == "Ø" || result.Text == "C") { if (p.NOcrLastLowercaseHeight > 3 && targetItem.NikseBitmap.Height - p.NOcrLastLowercaseHeight < 2) result.Text = result.Text.ToLower(); } else if (result.Text == "v" || result.Text == "w" || result.Text == "u" || result.Text == "s" || result.Text == "z" || result.Text == "o" || result.Text == "x" || result.Text == "ø" || result.Text == "c") { if (p.NOcrLastUppercaseHeight > 3 && p.NOcrLastUppercaseHeight - targetItem.NikseBitmap.Height < 2) result.Text = result.Text.ToUpper(); } if (italic) return new CompareMatch(result.Text, true, 0, null, result); else return new CompareMatch(result.Text, result.Italic, 0, null, result); }
public static NikseBitmap CropTopAndBottom(NikseBitmap bmp, out int topCropping, int maxDifferentPixelsOnLine) { int startTop = 0; int maxTop = bmp.Height - 2; if (maxTop > bmp.Height) { maxTop = bmp.Height; } for (int y = 0; y < maxTop; y++) { int difference = 0; bool allTransparent = true; for (int x = 1; x < bmp.Width - 1; x++) { int a = bmp.GetAlpha(x, y); if (a != 0) { difference++; if (difference >= maxDifferentPixelsOnLine) { allTransparent = false; break; } } } if (!allTransparent) { break; } startTop++; } if (startTop > 9) { startTop -= 5; // if top space > 9, then always leave blank 5 pixels on top (so . is not confused with '). } topCropping = startTop; for (int y = bmp.Height - 1; y > 3; y--) { int difference = 0; bool allTransparent = true; for (int x = 1; x < bmp.Width - 1; x++) { int a = bmp.GetAlpha(x, y); if (a != 0) { difference++; if (difference >= maxDifferentPixelsOnLine) { allTransparent = false; break; } } } if (allTransparent == false) { return bmp.CopyRectangle(new Rectangle(0, startTop, bmp.Width - 1, y - startTop + 1)); } } return bmp; }
internal CompareMatch GetNOcrCompareMatch(ImageSplitterItem targetItem, NikseBitmap parentBitmap, NOcrDb nOcrDb, double unItalicFactor, bool tryItalicScaling, bool deepSeek) { bool italic; var expandedResult = NOcrFindExpandedMatch(parentBitmap, targetItem, targetItem.Y - targetItem.ParentY, nOcrDb.OcrCharacters); if (expandedResult != null) return new CompareMatch(expandedResult.Text, expandedResult.Italic, expandedResult.ExpandCount, null, expandedResult); var result = NOcrFindBestMatchNew(parentBitmap, targetItem, targetItem.Y - targetItem.ParentY, out italic, nOcrDb, unItalicFactor, tryItalicScaling, deepSeek); if (result == null) { if (checkBoxNOcrCorrect.Checked) return null; else return new CompareMatch("*", false, 0, null); } // Fix uppercase/lowercase issues (not I/l) if (result.Text == "e") _nocrLastLowercaseHeight = targetItem.NikseBitmap.Height; else if (_nocrLastLowercaseHeight == -1 && result.Text == "a") _nocrLastLowercaseHeight = targetItem.NikseBitmap.Height; if (result.Text == "E" || result.Text == "H" || result.Text == "R" || result.Text == "D" || result.Text == "T") _nocrLastUppercaseHeight = targetItem.NikseBitmap.Height; else if (_nocrLastUppercaseHeight == -1 && result.Text == "M") _nocrLastUppercaseHeight = targetItem.NikseBitmap.Height; if (result.Text == "V" || result.Text == "W" || result.Text == "U" || result.Text == "S" || result.Text == "Z" || result.Text == "O" || result.Text == "X" || result.Text == "Ø" || result.Text == "C") { if (_nocrLastLowercaseHeight > 3 && targetItem.NikseBitmap.Height - _nocrLastLowercaseHeight < 2) result.Text = result.Text.ToLower(); } else if (result.Text == "v" || result.Text == "w" || result.Text == "u" || result.Text == "s" || result.Text == "z" || result.Text == "o" || result.Text == "x" || result.Text == "ø" || result.Text == "c") { if (_nocrLastUppercaseHeight > 3 && _nocrLastUppercaseHeight - targetItem.NikseBitmap.Height < 2) result.Text = result.Text.ToUpper(); } if (italic) return new CompareMatch(result.Text, true, 0, null, result); else return new CompareMatch(result.Text, result.Italic, 0, null, result); }
public static List<ImageSplitterItem> SplitBitmapToLettersNew(NikseBitmap bmp, int xOrMorePixelsMakesSpace, bool rightToLeft, bool topToBottom, int minLineHeight) { var list = new List<ImageSplitterItem>(); // split into seperate lines List<ImageSplitterItem> verticalBitmaps = SplitVertical(bmp, minLineHeight); if (!topToBottom) verticalBitmaps.Reverse(); // split into letters int lineCount = 0; foreach (ImageSplitterItem b in verticalBitmaps) { if (lineCount > 0) list.Add(new ImageSplitterItem(Environment.NewLine)); var line = new List<ImageSplitterItem>(); foreach (ImageSplitterItem item in SplitHorizontalNew(b, xOrMorePixelsMakesSpace)) { item.ParentY = item.Y; line.Add(item); } if (rightToLeft) line.Reverse(); foreach (ImageSplitterItem item in line) list.Add(item); lineCount++; } return list; }
private void TrainLetter(ref int numberOfCharactersLeaned, ref int numberOfCharactersSkipped, NOcrDb nOcrD, List<string> charactersLearned, string s, bool bold) { Bitmap bmp = GenerateImageFromTextWithStyle(s, bold); var nbmp = new NikseBitmap(bmp); nbmp.MakeTwoColor(210, 280); var list = NikseBitmapImageSplitter.SplitBitmapToLettersNew(nbmp, 10, false, false, 25); if (list.Count == 1) { NOcrChar match = nOcrD.GetMatch(list[0].NikseBitmap); if (match == null) { pictureBox1.Image = list[0].NikseBitmap.GetBitmap(); this.Refresh(); Application.DoEvents(); System.Threading.Thread.Sleep(100); NOcrChar nOcrChar = new NOcrChar(s); nOcrChar.Width = list[0].NikseBitmap.Width; nOcrChar.Height = list[0].NikseBitmap.Height; VobSubOcrNOcrCharacter.GenerateLineSegments((int)numericUpDownSegmentsPerCharacter.Value, checkBoxVeryAccurate.Checked, nOcrChar, list[0].NikseBitmap); nOcrD.Add(nOcrChar); charactersLearned.Add(s); numberOfCharactersLeaned++; labelInfo.Text = string.Format("Now training font '{1}', total characters leaned is {0}, {2} skipped", numberOfCharactersLeaned, _subtitleFontName, numberOfCharactersSkipped); bmp.Dispose(); } else { numberOfCharactersSkipped++; } } }
private static List<Point> IsVerticalLineTransparetNew(NikseBitmap bmp, int x, out bool right, out bool clean) { right = false; bool left = false; clean = true; var points = new List<Point>(); int y = 0; while (y < bmp.Height) { if (bmp.GetAlpha(x, y) > 100) { clean = false; if (x == 0) return null; if (x < bmp.Width - 1 && y < bmp.Height - 1 && bmp.GetAlpha(x + 1, y) == 0 && bmp.GetAlpha(x + 1, y + 1) == 0) { //if pixels to the left - move right? if (bmp.GetAlpha(x - 1, y) > 0) { x++; //(requires search for min/max x in points right = true; } else if (x > 0 && bmp.GetAlpha(x - 1, y) == 0) { x--; //(requires search for min/max x in points left = true; } else { return null; } } else if (x < bmp.Width - 1 && y == bmp.Height - 1 && bmp.GetAlpha(x + 1, y) == 0 && bmp.GetAlpha(x + 1, y - 1) == 0) { //if pixels to the left - move right? if (bmp.GetAlpha(x - 1, y) > 0) { x++; //(requires search for min/max x in points right = true; } else { return null; } right = true; } else if (bmp.GetAlpha(x - 1, y) == 0) { x--; left = true; } else if (y > 5 && bmp.GetAlpha(x - 1, y - 1) == 0) { x--; y--; left = true; while (points.Count > 0 && points[points.Count - 1].Y > y) points.RemoveAt(points.Count - 1); } else if (y > 5 && bmp.GetAlpha(x - 1, y - 2) == 0) { x--; y -= 2; left = true; while (points.Count > 0 && points[points.Count - 1].Y > y) points.RemoveAt(points.Count - 1); } else { return null; } if (left && right) return null; } else { points.Add(new Point(x, y)); y++; } } return points; }
public static List<ImageSplitterItem> SplitVertical(NikseBitmap bmp, int minLineHeight) { // split into lines int startY = 0; int size = 0; var parts = new List<ImageSplitterItem>(); for (int y = 0; y < bmp.Height; y++) { bool allTransparent = true; for (int x = 0; x < bmp.Width; x++) { int a = bmp.GetAlpha(x, y); if (a != 0) { allTransparent = false; break; } } if (allTransparent) { if (size > 2 && size <= minLineHeight) { size++; // at least 'lineMinHeight' pixels, like top of 'i' } else { if (size > 2) { NikseBitmap part = bmp.CopyRectangle(new Rectangle(0, startY, bmp.Width, size + 1)); // part.Save("c:\\line_0_to_width.bmp"); parts.Add(new ImageSplitterItem(0, startY, part)); // bmp.Save("c:\\original.bmp"); } size = 0; startY = y; } } else { size++; } } if (size > 2) { if (size == bmp.Height) { if (size > 100) return SplitVerticalTransparentOrBlack(bmp); else parts.Add(new ImageSplitterItem(0, startY, bmp)); } else { parts.Add(new ImageSplitterItem(0, startY, bmp.CopyRectangle(new Rectangle(0, startY, bmp.Width, size + 1)))); } } return parts; }
internal static unsafe int IsBitmapsAlike(NikseBitmap bmp1, ManagedBitmap bmp2) { int different = 0; int maxDiff = bmp1.Width * bmp1.Height / 5; for (int x = 1; x < bmp1.Width; x++) { for (int y = 1; y < bmp1.Height; y++) { if (!IsColorClose(bmp1.GetPixel(x, y), bmp2.GetPixel(x, y), 20)) different++; } if (different > maxDiff) return different + 10; } return different; }
private static bool IsCursiveVerticalLineTransparent(NikseBitmap bmp, int size, int y, int x, List<Point> cursivePoints) { bool cursiveOk = true; int newY = y; int newX = x; while (cursiveOk && newY < bmp.Height - 1) { Color c0 = bmp.GetPixel(newX, newY); if (c0.A == 0 || IsColorClose(c0, Color.Black, 280)) { newY++; } else { byte[] c1 = bmp.GetPixelColors(newX - 1, newY - 1); byte[] c2 = bmp.GetPixelColors(newX - 1, newY); if ((c1[0] == 0 || IsColorClose(c1[0], c1[1], c1[2], c1[3], Color.Black, 280)) && // still dark color... (c2[0] == 0 || IsColorClose(c2[0], c2[1], c2[2], c2[3], Color.Black, 280))) { cursivePoints.Add(new Point(newX, newY)); if (newX > 1) newX--; else cursiveOk = false; newY++; } else { cursiveOk = false; } } if (newX < x - size) cursiveOk = false; } return cursiveOk; }
private static List <Point> IsVerticalLineTransparetNew(NikseBitmap bmp, int x, out bool right, out bool clean) { right = false; bool left = false; int leftCount = 0; int rightCount = 0; clean = true; var points = new List <Point>(); int y = 0; int maxSlide = bmp.Height / 4; while (y < bmp.Height) { if (bmp.GetAlpha(x, y) > 100) { clean = false; if (x == 0) { return(null); } if (x < bmp.Width - 1 && y < bmp.Height - 1 && bmp.GetAlpha(x + 1, y) == 0 && bmp.GetAlpha(x + 1, y + 1) == 0) { //if pixels to the left - move right? if (bmp.GetAlpha(x - 1, y) > 0) { x++; //(requires search for min/max x in points right = true; } else if (x > 0 && bmp.GetAlpha(x - 1, y) == 0) { x--; //(requires search for min/max x in points left = true; } else { return(null); } } else if (x < bmp.Width - 1 && y == bmp.Height - 1 && bmp.GetAlpha(x + 1, y) == 0 && bmp.GetAlpha(x + 1, y - 1) == 0) { //if pixels to the left - move right? if (bmp.GetAlpha(x - 1, y) > 0) { x++; //(requires search for min/max x in points } else { return(null); } right = true; } else if (bmp.GetAlpha(x - 1, y) == 0) { x--; left = true; } else if (y > 5 && bmp.GetAlpha(x - 1, y - 1) == 0) { x--; y--; left = true; while (points.Count > 0 && points[points.Count - 1].Y > y) { points.RemoveAt(points.Count - 1); } } else if (y > 5 && bmp.GetAlpha(x - 1, y - 2) == 0) { x--; y -= 2; left = true; while (points.Count > 0 && points[points.Count - 1].Y > y) { points.RemoveAt(points.Count - 1); } } else { return(null); } if (left) { leftCount++; } if (right) { rightCount++; } if (leftCount > maxSlide || rightCount > maxSlide) { return(null); } } else { points.Add(new Point(x, y)); y++; } } return(points); }
private static bool IsVerticalLineTransparentAlphaOnly(NikseBitmap bmp, ref int y, int x) { bool allTransparent = true; for (y = 0; y < bmp.Height - 1; y++) { int a = bmp.GetAlpha(x, y); if (a == 0) // still dark color... { } else { allTransparent = false; break; } } return allTransparent; }
/// <summary> /// split into lines /// </summary> public static List<ImageSplitterItem> SplitToLinesNew(ImageSplitterItem item, int minLineHeight, double averageLineHeight = -1) { var bmp = new NikseBitmap(item.NikseBitmap); var parts = new List<ImageSplitterItem>(); bool started = false; var splitLines = new Dictionary<int, List<Point>>(); var startY = 0; for (int y = minLineHeight; y < bmp.Height - minLineHeight; y++) { if (startY == y && bmp.IsLineTransparent(y)) { startY++; continue; } var points = new List<Point>(); var yChange = 0; var completed = false; var backJump = 0; int x = 0; var maxUp = Math.Min(10, minLineHeight / 2); while (x < bmp.Width) { var a1 = bmp.GetAlpha(x, y + yChange); var a2 = bmp.GetAlpha(x, y + 1 + yChange); if (a1 > 150 || a2 > 150) { if (x > 1 && yChange < 8 && y + 3 + yChange < bmp.Height && bmp.GetAlpha(x - 1, y + yChange) < 150 && bmp.GetAlpha(x - 1, y + yChange) < 150 && bmp.GetAlpha(x - 1, y + 1 + yChange) < 150 && bmp.GetAlpha(x - 1, y + 2 + yChange) < 150 && bmp.GetAlpha(x - 1, y + 2 + yChange) < 150 && bmp.GetAlpha(x - 1, y + 3 + yChange) < 150 && bmp.GetAlpha(x, y + 2 + yChange) < 150 && bmp.GetAlpha(x, y + 3 + yChange) < 150) { yChange += 2; } else if (x > 1 && yChange < 8 && y + 4 + yChange < bmp.Height && bmp.GetAlpha(x - 1, y + yChange) < 150 && bmp.GetAlpha(x - 1, y + yChange) < 150 && bmp.GetAlpha(x - 1, y + 1 + yChange) < 150 && bmp.GetAlpha(x - 1, y + 2 + yChange) < 150 && bmp.GetAlpha(x - 1, y + 2 + yChange) < 150 && bmp.GetAlpha(x - 1, y + 3 + yChange) < 150 && bmp.GetAlpha(x - 1, y + 3 + yChange) < 150 && bmp.GetAlpha(x - 1, y + 4 + yChange) < 150 && bmp.GetAlpha(x, y + 3 + yChange) < 150 && bmp.GetAlpha(x, y + 4 + yChange) < 150) { yChange += 3; } else if (x > 1 && yChange < 7 && y + 5 + yChange < bmp.Height && bmp.GetAlpha(x - 1, y + yChange) < 150 && bmp.GetAlpha(x - 1, y + yChange) < 150 && bmp.GetAlpha(x - 1, y + 1 + yChange) < 150 && bmp.GetAlpha(x - 1, y + 2 + yChange) < 150 && bmp.GetAlpha(x - 1, y + 2 + yChange) < 150 && bmp.GetAlpha(x - 1, y + 3 + yChange) < 150 && bmp.GetAlpha(x - 1, y + 3 + yChange) < 150 && bmp.GetAlpha(x - 1, y + 4 + yChange) < 150 && bmp.GetAlpha(x - 1, y + 4 + yChange) < 150 && bmp.GetAlpha(x - 1, y + 5 + yChange) < 150 && bmp.GetAlpha(x, y + 4 + yChange) < 150 && bmp.GetAlpha(x, y + 5 + yChange) < 150) { yChange += 4; } else if (x > 1 && yChange > -7 && bmp.GetAlpha(x - 1, y + yChange) < 150 && bmp.GetAlpha(x - 1, y + yChange) < 150 && bmp.GetAlpha(x - 1, y - 1 + yChange) < 150 && bmp.GetAlpha(x - 1, y - 2 + yChange) < 150 && bmp.GetAlpha(x - 1, y - 2 + yChange) < 150 && bmp.GetAlpha(x - 1, y - 3 + yChange) < 150 && bmp.GetAlpha(x, y - 2 + yChange) < 150 && bmp.GetAlpha(x, y - 3 + yChange) < 150) { yChange -= 2; } else if (x > 1 && yChange > -7 && bmp.GetAlpha(x - 1, y + yChange) < 150 && bmp.GetAlpha(x - 1, y + yChange) < 150 && bmp.GetAlpha(x - 1, y - 1 + yChange) < 150 && bmp.GetAlpha(x - 1, y - 2 + yChange) < 150 && bmp.GetAlpha(x - 1, y - 2 + yChange) < 150 && bmp.GetAlpha(x - 1, y - 3 + yChange) < 150 && bmp.GetAlpha(x - 1, y - 3 + yChange) < 150 && bmp.GetAlpha(x - 1, y - 4 + yChange) < 150 && bmp.GetAlpha(x, y - 3 + yChange) < 150 && bmp.GetAlpha(x, y - 4 + yChange) < 150) { yChange -= 3; } else if (x > 1 && yChange > -7 && bmp.GetAlpha(x - 1, y + yChange) < 150 && bmp.GetAlpha(x - 1, y + yChange) < 150 && bmp.GetAlpha(x - 1, y - 1 + yChange) < 150 && bmp.GetAlpha(x - 1, y - 2 + yChange) < 150 && bmp.GetAlpha(x - 1, y - 2 + yChange) < 150 && bmp.GetAlpha(x - 1, y - 3 + yChange) < 150 && bmp.GetAlpha(x - 1, y - 3 + yChange) < 150 && bmp.GetAlpha(x - 1, y - 4 + yChange) < 150 && bmp.GetAlpha(x - 1, y - 4 + yChange) < 150 && bmp.GetAlpha(x - 1, y - 5 + yChange) < 150 && bmp.GetAlpha(x, y - 4 + yChange) < 150 && bmp.GetAlpha(x, y - 5 + yChange) < 150) { yChange -= 4; } else if (x > 10 && backJump < 3 && x > 5 && yChange > -7) // go left + up + check 12 pixels right { var done = false; for (int i = 1; i < maxUp; i++) { for (int k = 1; k < 9; k++) { if (CanGoUpAndRight(bmp, i, 12, x - k, y + yChange, minLineHeight)) { backJump++; x -= k; points.RemoveAll(p => p.X > x); done = true; yChange -= (i + 1); break; } } if (done) { break; } } if (!done) { started = true; break; } } else { started = true; break; } } if (started) { points.Add(new Point(x, y + yChange)); } completed = x == bmp.Width - 1; x++; } if (completed) { splitLines.Add(y, points); } } var transparentColor = Color.FromArgb(0, 0, 0, 0); foreach (var line in splitLines) { var key = line.Key; if (key - startY > minLineHeight && line.Value.Count > 0) { var maxY = line.Value.Max(p => p.Y); var part = bmp.CopyRectangle(new Rectangle(0, startY, bmp.Width, maxY - startY)); //part.GetBitmap().Save(@"j:\temp\split_" + parts.Count + "_before.bmp"); foreach (var point in line.Value) { // delete down for (var y = point.Y - 1; y < startY + part.Height; y++) { part.SetPixel(point.X, y - startY, transparentColor); } } //part.GetBitmap().Save(@"j:\temp\split_" + parts.Count + "_after.bmp"); if (!part.IsImageOnlyTransparent() && part.GetNonTransparentHeight() >= minLineHeight) { var minY = line.Value.Min(p => p.Y); // bmp.GetBitmap().Save(@"j:\temp\main_" + parts.Count + "_before.bmp"); foreach (var point in line.Value) { // delete up for (var y = point.Y; y >= minY; y--) { bmp.SetPixel(point.X, y, transparentColor); } } // bmp.GetBitmap().Save(@"j:\temp\main_" + parts.Count + "_after.bmp"); // part.GetBitmap().Save(@"j:\temp\split_" + parts.Count + "_after.bmp"); var croppedTop = part.CropTopTransparent(0); parts.Add(new ImageSplitterItem(0 + item.X, startY + croppedTop + item.Y, part)); startY = key + 1; } } } if (bmp.Height - startY > 1 && parts.Count > 0) { var part = bmp.CopyRectangle(new Rectangle(0, startY, bmp.Width, bmp.Height - startY)); if (!part.IsImageOnlyTransparent()) { //part.GetBitmap().Save(@"j:\temp\split_" + parts.Count + ".bmp"); var croppedTop = part.CropTopTransparent(0); parts.Add(new ImageSplitterItem(0 + item.X, startY + croppedTop + item.Y, part)); } } if (parts.Count <= 1) { return new List<ImageSplitterItem> { item }; } return parts; }
private static IEnumerable<ImageSplitterItem> SplitHorizontalNew(ImageSplitterItem lineSplitterItem, int xOrMorePixelsMakesSpace) { var bmp = new NikseBitmap(lineSplitterItem.NikseBitmap); bmp.AddTransparentLineRight(); var parts = new List<ImageSplitterItem>(); int startX = 0; int width = 0; int spacePixels = 0; int subtractSpacePixels = 0; for (int x = 0; x < bmp.Width; x++) { bool right; bool clean; List<Point> points = IsVerticalLineTransparetNew(bmp, x, out right, out clean); if (points != null && clean) { spacePixels++; } if (right && points != null) { int add = FindMaxX(points, x) - x; width = width + add; subtractSpacePixels = add; } if (points == null) { width++; } else if (width > 1) { var bmp0 = new NikseBitmap(bmp); // remove pixels after current; int k = 0; foreach (Point p in points) { bmp0.MakeVerticalLinePartTransparent(p.X, p.X + k, p.Y); k++; } width = FindMaxX(points, x) - startX; width++; NikseBitmap b1 = bmp0.CopyRectangle(new Rectangle(startX, 0, width, bmp.Height)); if (spacePixels >= xOrMorePixelsMakesSpace && parts.Count > 0) parts.Add(new ImageSplitterItem(" ")); int addY; b1 = CropTopAndBottom(b1, out addY); parts.Add(new ImageSplitterItem(startX + lineSplitterItem.X, addY + lineSplitterItem.Y, b1)); //y is what? // remove pixels before next letter; int begin = 0; foreach (Point p in points) { bmp.MakeVerticalLinePartTransparent(begin, p.X, p.Y); } width = 1; startX = FindMinX(points, x); spacePixels = -subtractSpacePixels; subtractSpacePixels = 0; } else { width = 1; startX = FindMinX(points, x); } } return parts; }
/// <summary> /// Ocr via image compare /// </summary> private string SplitAndOcrBitmapNormalNew(Bitmap bitmap, int listViewIndex) { if (_ocrFixEngine == null) LoadOcrFixEngine(null, LanguageString); string threadText = null; //if (_icThreadResults != null && !string.IsNullOrEmpty(_icThreadResults[listViewIndex])) // threadText = _icThreadResults[listViewIndex]; string line = string.Empty; if (threadText == null) { var matches = new List<CompareMatch>(); var parentBitmap = new NikseBitmap(bitmap); int minLineHeight = _binOcrLastLowercaseHeight - 3; if (minLineHeight < 5) minLineHeight = _nocrLastLowercaseHeight; if (minLineHeight < 5) minLineHeight = 6; List<ImageSplitterItem> list = NikseBitmapImageSplitter.SplitBitmapToLettersNew(parentBitmap, (int)numericUpDownPixelsIsSpace.Value, checkBoxRightToLeft.Checked, Configuration.Settings.VobSubOcr.TopToBottom, minLineHeight); int index = 0; bool expandSelection = false; bool shrinkSelection = false; var expandSelectionList = new List<ImageSplitterItem>(); while (index < list.Count) { ImageSplitterItem item = list[index]; if (expandSelection || shrinkSelection) { expandSelection = false; if (shrinkSelection && index > 0) { shrinkSelection = false; } else if (index + 1 < list.Count && list[index + 1].NikseBitmap != null) // only allow expand to EndOfLine or space { index++; expandSelectionList.Add(list[index]); } item = GetExpandedSelectionNew(parentBitmap, expandSelectionList); _vobSubOcrCharacter.Initialize(bitmap, item, _manualOcrDialogPosition, _italicCheckedLast, expandSelectionList.Count > 1, null, _lastAdditions, this); DialogResult result = _vobSubOcrCharacter.ShowDialog(this); _manualOcrDialogPosition = _vobSubOcrCharacter.FormPosition; if (result == DialogResult.OK && _vobSubOcrCharacter.ShrinkSelection) { shrinkSelection = true; index--; if (expandSelectionList.Count > 0) expandSelectionList.RemoveAt(expandSelectionList.Count - 1); } else if (result == DialogResult.OK && _vobSubOcrCharacter.ExpandSelection) { expandSelection = true; } else if (result == DialogResult.OK) { string text = _vobSubOcrCharacter.ManualRecognizedCharacters; string name = SaveCompareItemNew(item, text, _vobSubOcrCharacter.IsItalic, expandSelectionList); var addition = new ImageCompareAddition(name, text, item.NikseBitmap, _vobSubOcrCharacter.IsItalic, listViewIndex); _lastAdditions.Add(addition); matches.Add(new CompareMatch(text, _vobSubOcrCharacter.IsItalic, expandSelectionList.Count, null)); expandSelectionList = new List<ImageSplitterItem>(); } else if (result == DialogResult.Abort) { _abort = true; } else { matches.Add(new CompareMatch("*", false, 0, null)); } _italicCheckedLast = _vobSubOcrCharacter.IsItalic; } else if (item.NikseBitmap == null) { matches.Add(new CompareMatch(item.SpecialCharacter, false, 0, null)); } else { CompareMatch bestGuess; CompareMatch match = GetCompareMatchNew(item, parentBitmap, out bestGuess, list, index); if (match == null) // Try line ocr if no image compare match { if (_nOcrDb != null && _nOcrDb.OcrCharacters.Count > 0) match = GetNOcrCompareMatchNew(item, parentBitmap, _nOcrDb, _unItalicFactor, true, true); } if (match == null) { _vobSubOcrCharacter.Initialize(bitmap, item, _manualOcrDialogPosition, _italicCheckedLast, false, bestGuess, _lastAdditions, this); DialogResult result = _vobSubOcrCharacter.ShowDialog(this); _manualOcrDialogPosition = _vobSubOcrCharacter.FormPosition; if (result == DialogResult.OK && _vobSubOcrCharacter.ExpandSelection) { expandSelectionList.Add(item); expandSelection = true; } else if (result == DialogResult.OK) { string text = _vobSubOcrCharacter.ManualRecognizedCharacters; string name = SaveCompareItemNew(item, text, _vobSubOcrCharacter.IsItalic, null); var addition = new ImageCompareAddition(name, text, item.NikseBitmap, _vobSubOcrCharacter.IsItalic, listViewIndex); _lastAdditions.Add(addition); matches.Add(new CompareMatch(text, _vobSubOcrCharacter.IsItalic, 0, null)); SetBinOcrLowercaseUppercase(item.NikseBitmap.Height, text); } else if (result == DialogResult.Abort) { _abort = true; } else { matches.Add(new CompareMatch("*", false, 0, null)); } _italicCheckedLast = _vobSubOcrCharacter.IsItalic; } else // found image match { matches.Add(new CompareMatch(match.Text, match.Italic, 0, null)); if (match.ExpandCount > 0) index += match.ExpandCount - 1; } } if (_abort) return string.Empty; if (!expandSelection && !shrinkSelection) index++; if (shrinkSelection && expandSelectionList.Count < 2) { shrinkSelection = false; expandSelectionList = new List<ImageSplitterItem>(); } } line = GetStringWithItalicTags(matches); } else { line = threadText; } if (checkBoxAutoFixCommonErrors.Checked) line = OcrFixEngine.FixOcrErrorsViaHardcodedRules(line, _lastLine, null); // TODO: add abbreviations list if (checkBoxRightToLeft.Checked) line = ReverseNumberStrings(line); //ocr fix engine string textWithOutFixes = line; if (_ocrFixEngine.IsDictionaryLoaded) { if (checkBoxAutoFixCommonErrors.Checked) line = _ocrFixEngine.FixOcrErrors(line, listViewIndex, _lastLine, true, checkBoxGuessUnknownWords.Checked); int correctWords; int wordsNotFound = _ocrFixEngine.CountUnknownWordsViaDictionary(line, out correctWords); if (wordsNotFound > 0 || correctWords == 0 || textWithOutFixes != null && textWithOutFixes.ToString().Replace("~", string.Empty).Trim().Length == 0) { _ocrFixEngine.AutoGuessesUsed.Clear(); _ocrFixEngine.UnknownWordsFound.Clear(); line = _ocrFixEngine.FixUnknownWordsViaGuessOrPrompt(out wordsNotFound, line, listViewIndex, bitmap, checkBoxAutoFixCommonErrors.Checked, checkBoxPromptForUnknownWords.Checked, true, checkBoxGuessUnknownWords.Checked); } if (_ocrFixEngine.Abort) { ButtonStopClick(null, null); _ocrFixEngine.Abort = false; return string.Empty; } // Log used word guesses (via word replace list) foreach (string guess in _ocrFixEngine.AutoGuessesUsed) listBoxLogSuggestions.Items.Add(guess); _ocrFixEngine.AutoGuessesUsed.Clear(); // Log unkown words guess (found via spelling dictionaries) LogUnknownWords(); if (wordsNotFound >= 3) subtitleListView1.SetBackgroundColor(listViewIndex, Color.Red); if (wordsNotFound == 2) subtitleListView1.SetBackgroundColor(listViewIndex, Color.Orange); else if (wordsNotFound == 1) subtitleListView1.SetBackgroundColor(listViewIndex, Color.Yellow); else if (line.Trim().Length == 0) subtitleListView1.SetBackgroundColor(listViewIndex, Color.Orange); else subtitleListView1.SetBackgroundColor(listViewIndex, Color.LightGreen); } if (textWithOutFixes.Trim() != line.Trim()) { _tesseractOcrAutoFixes++; labelFixesMade.Text = string.Format(" - {0}", _tesseractOcrAutoFixes); LogOcrFix(listViewIndex, textWithOutFixes.ToString(), line); } return line; }
private string Tesseract3DoOcrViaExe(Bitmap bmp, string language, string psmMode) { // change yellow color to white - easier for Tesseract var nbmp = new NikseBitmap(bmp); nbmp.ReplaceYellowWithWhite(); // optimized replace bool useHocr = true; string tempTiffFileName = Path.GetTempPath() + Guid.NewGuid().ToString() + ".png"; var b = nbmp.GetBitmap(); b.Save(tempTiffFileName, System.Drawing.Imaging.ImageFormat.Png); string tempTextFileName = Path.GetTempPath() + Guid.NewGuid().ToString(); b.Dispose(); var process = new Process(); process.StartInfo = new ProcessStartInfo(Configuration.TesseractFolder + "tesseract.exe"); process.StartInfo.UseShellExecute = true; process.StartInfo.Arguments = "\"" + tempTiffFileName + "\" \"" + tempTextFileName + "\" -l " + language; if (checkBoxTesseractMusicOn.Checked) process.StartInfo.Arguments += "+music"; if (!string.IsNullOrEmpty(psmMode)) process.StartInfo.Arguments += " " + psmMode.Trim(); if (useHocr) process.StartInfo.Arguments += " hocr"; process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; if (Utilities.IsRunningOnLinux() || Utilities.IsRunningOnMac()) { process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardError = true; process.StartInfo.FileName = "tesseract"; } else { process.StartInfo.WorkingDirectory = (Configuration.TesseractFolder); } try { process.Start(); } catch { MessageBox.Show("Unable to start 'tesseract' - make sure tesseract-ocr 3.x is installed!"); throw; } process.WaitForExit(5000); string result = string.Empty; if (useHocr) { string outputFileName = tempTextFileName + ".html"; try { if (File.Exists(outputFileName)) { result = File.ReadAllText(outputFileName); result = ParseHocr(result); File.Delete(outputFileName); } File.Delete(tempTiffFileName); } catch { } } else { string outputFileName = tempTextFileName + ".txt"; try { if (File.Exists(outputFileName)) { result = File.ReadAllText(outputFileName); File.Delete(outputFileName); } File.Delete(tempTiffFileName); } catch { } } return result; }
public ImageCompareAddition(string name, string text, NikseBitmap image, bool italic, int index) { Name = name; Text = text; Image = image; Text = text; Italic = italic; Index = index; }
internal static unsafe int IsBitmapsAlike(NikseBitmap bmp1, Ocr.Binary.BinaryOcrBitmap bmp2) { int different = 0; int maxDiff = bmp1.Width * bmp1.Height / 5; for (int x = 1; x < bmp1.Width; x++) { for (int y = 1; y < bmp1.Height; y++) { if (bmp1.GetAlpha(x, y) < 100 && bmp2.GetPixel(x, y) > 0) different++; } if (different > maxDiff) return different + 10; } return different; }
private static IEnumerable <ImageSplitterItem> SplitHorizontalNew(ImageSplitterItem lineSplitterItem, int xOrMorePixelsMakesSpace) { var bmp = new NikseBitmap(lineSplitterItem.NikseBitmap); bmp.AddTransparentLineRight(); var parts = new List <ImageSplitterItem>(); int startX = 0; int width = 0; int spacePixels = 0; int subtractSpacePixels = 0; for (int x = 0; x < bmp.Width; x++) { bool right; bool clean; List <Point> points = IsVerticalLineTransparetNew(bmp, x, out right, out clean); if (points != null && clean) { spacePixels++; } if (right && points != null) { int add = FindMaxX(points, x) - x; width += add; subtractSpacePixels = add; } var newStartX = points != null?FindMinX(points, x) : 0; if (points == null) { width++; } else if (width > 0 && newStartX > startX + 1) { var bmp0 = new NikseBitmap(bmp); // remove pixels after current; for (int index = 0; index < points.Count; index++) { var p = points[index]; bmp0.MakeVerticalLinePartTransparent(p.X, p.X + index, p.Y); } width = FindMaxX(points, x) - startX; width--; startX++; var b1 = bmp0.CopyRectangle(new Rectangle(startX, 0, width, bmp.Height)); int addY; b1 = CropTopAndBottom(b1, out addY); if (spacePixels >= xOrMorePixelsMakesSpace && parts.Count > 0) { parts.Add(new ImageSplitterItem(" ") { Y = addY + lineSplitterItem.Y }); } if (b1.Width > 0 && b1.Height > 0) { parts.Add(new ImageSplitterItem(startX + lineSplitterItem.X, addY + lineSplitterItem.Y, b1)); //y is what? } // remove pixels before next letter; const int begin = 0; foreach (var p in points) { bmp.MakeVerticalLinePartTransparent(begin, p.X, p.Y); } width = 1; startX = FindMinX(points, x); spacePixels = -subtractSpacePixels; subtractSpacePixels = 0; } else if (clean) { width = 1; startX = newStartX; } } return(parts); }