From 31cdbbf41675094a5f8eb0bbb3b4c6c94b06df5e Mon Sep 17 00:00:00 2001 From: niksedk Date: Sun, 15 Sep 2013 17:55:35 +0000 Subject: [PATCH] OCR -Image splitting now a bit faster git-svn-id: https://subtitleedit.googlecode.com/svn/trunk@2090 99eadd0c-20b8-1223-b5c4-2a2b2df33de2 --- src/Forms/VobSubOcr.cs | 200 ++++---- src/Logic/ImageSplitterItem.cs | 28 +- src/Logic/NikseBitmap.cs | 27 + src/Logic/NikseBitmapImageSplitter.cs | 690 ++++++++++++++++++++++++++ src/SubtitleEdit.csproj | 1 + 5 files changed, 836 insertions(+), 110 deletions(-) create mode 100644 src/Logic/NikseBitmapImageSplitter.cs diff --git a/src/Forms/VobSubOcr.cs b/src/Forms/VobSubOcr.cs index bb1045ac9..5dc6f31b4 100644 --- a/src/Forms/VobSubOcr.cs +++ b/src/Forms/VobSubOcr.cs @@ -1351,7 +1351,7 @@ namespace Nikse.SubtitleEdit.Forms private static NOcrChar NOcrFindExpandedMatch(Bitmap parentBitmap, ImageSplitterItem targetItem, int topMargin, List nOcrChars) { var nbmp = new NikseBitmap(parentBitmap); - int w = targetItem.Bitmap.Width; + int w = targetItem.NikseBitmap.Width; int index = 0; foreach (NOcrChar oc in nOcrChars) { @@ -1455,7 +1455,7 @@ namespace Nikse.SubtitleEdit.Forms private static NOcrChar NOcrFindBestMatch(Bitmap parentBitmap, ImageSplitterItem targetItem, int topMargin, out bool italic, List nOcrChars, double unItalicFactor, bool tryItalicScaling, bool deepSeek) { italic = false; - var nbmp = new NikseBitmap(targetItem.Bitmap); + var nbmp = targetItem.NikseBitmap; int index = 0; foreach (NOcrChar oc in nOcrChars) { @@ -2158,23 +2158,23 @@ namespace Nikse.SubtitleEdit.Forms // Fix uppercase/lowercase issues (not I/l) if (result.Text == "e") - _nocrLastLowercaseHeight = targetItem.Bitmap.Height; + _nocrLastLowercaseHeight = targetItem.NikseBitmap.Height; else if (_nocrLastLowercaseHeight == -1 && result.Text == "a") - _nocrLastLowercaseHeight = targetItem.Bitmap.Height; + _nocrLastLowercaseHeight = targetItem.NikseBitmap.Height; if (result.Text == "E" || result.Text == "H" || result.Text == "R" || result.Text == "D" || result.Text == "T") - _nocrLastUppercaseHeight = targetItem.Bitmap.Height; + _nocrLastUppercaseHeight = targetItem.NikseBitmap.Height; else if (_nocrLastUppercaseHeight == -1 && result.Text == "M") - _nocrLastUppercaseHeight = targetItem.Bitmap.Height; + _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.Bitmap.Height - _nocrLastLowercaseHeight < 2) + 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.Bitmap.Height < 2) + if (_nocrLastUppercaseHeight > 3 && _nocrLastUppercaseHeight - targetItem.NikseBitmap.Height < 2) result.Text = result.Text.ToUpper(); } @@ -2197,23 +2197,23 @@ namespace Nikse.SubtitleEdit.Forms // Fix uppercase/lowercase issues (not I/l) if (result.Text == "e") - p.NOcrLastLowercaseHeight = targetItem.Bitmap.Height; + p.NOcrLastLowercaseHeight = targetItem.NikseBitmap.Height; else if (p.NOcrLastLowercaseHeight == -1 && result.Text == "a") - p.NOcrLastLowercaseHeight = targetItem.Bitmap.Height; + p.NOcrLastLowercaseHeight = targetItem.NikseBitmap.Height; if (result.Text == "E" || result.Text == "H" || result.Text == "R" || result.Text == "D" || result.Text == "T") - p.NOcrLastUppercaseHeight = targetItem.Bitmap.Height; + p.NOcrLastUppercaseHeight = targetItem.NikseBitmap.Height; else if (p.NOcrLastUppercaseHeight == -1 && result.Text == "M") - p.NOcrLastUppercaseHeight = targetItem.Bitmap.Height; + 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.Bitmap.Height - p.NOcrLastLowercaseHeight < 2) + 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.Bitmap.Height < 2) + if (p.NOcrLastUppercaseHeight > 3 && p.NOcrLastUppercaseHeight - targetItem.NikseBitmap.Height < 2) result.Text = result.Text.ToUpper(); } @@ -2223,22 +2223,23 @@ namespace Nikse.SubtitleEdit.Forms return new CompareMatch(result.Text, result.Italic, 0, null, result); } - private CompareMatch GetCompareMatch(ImageSplitterItem targetItem, Bitmap parentBitmap, out CompareMatch secondBestGuess) + private CompareMatch GetCompareMatch(ImageSplitterItem targetItem, NikseBitmap parentBitmap, out CompareMatch secondBestGuess) { secondBestGuess = null; int index = 0; int smallestDifference = 10000; int smallestIndex = -1; - Bitmap target = targetItem.Bitmap; + NikseBitmap target = targetItem.NikseBitmap; foreach (CompareItem compareItem in _compareBitmaps) { // check for expand match! - if (compareItem.ExpandCount > 0 && compareItem.Bitmap.Width > targetItem.Bitmap.Width) + if (compareItem.ExpandCount > 0 && compareItem.Bitmap.Width > target.Width && + parentBitmap.Width >= compareItem.Bitmap.Width + targetItem.X && + parentBitmap.Height >= compareItem.Bitmap.Height + targetItem.Y) { - Bitmap cutBitmap = ImageSplitter.Copy(parentBitmap, new Rectangle(targetItem.X, targetItem.Y, compareItem.Bitmap.Width, compareItem.Bitmap.Height)); - int dif = ImageSplitter.IsBitmapsAlike(compareItem.Bitmap, cutBitmap); - cutBitmap.Dispose(); + var cutBitmap = parentBitmap.CopyRectangle(new Rectangle(targetItem.X, targetItem.Y, compareItem.Bitmap.Width, compareItem.Bitmap.Height)); + int dif = NikseBitmapImageSplitter.IsBitmapsAlike(compareItem.Bitmap, cutBitmap); if (dif < smallestDifference) { smallestDifference = dif; @@ -2257,58 +2258,48 @@ namespace Nikse.SubtitleEdit.Forms { if (smallestDifference > 0.9 && target.Width > 25) { - Bitmap cutBitmap = CopyBitmapSection(target, new Rectangle(4, 0, target.Width - 4, target.Height)); + var cutBitmap = target.CopyRectangle(new Rectangle(4, 0, target.Width - 4, target.Height)); FindBestMatch(ref index, ref smallestDifference, ref smallestIndex, cutBitmap); - cutBitmap.Dispose(); double differencePercentage = smallestDifference * 100.0 / (target.Width * target.Height); } - if (smallestDifference > 0 && target.Width > 12) { - Bitmap cutBitmap = CopyBitmapSection(target, new Rectangle(1, 0, target.Width - 2, target.Height)); + var cutBitmap = target.CopyRectangle(new Rectangle(1, 0, target.Width - 2, target.Height)); FindBestMatch(ref index, ref smallestDifference, ref smallestIndex, cutBitmap); - cutBitmap.Dispose(); } if (smallestDifference > 0 && target.Width > 12) { - Bitmap cutBitmap = CopyBitmapSection(target, new Rectangle(0, 0, target.Width - 2, target.Height)); + var cutBitmap = target.CopyRectangle(new Rectangle(0, 0, target.Width - 2, target.Height)); FindBestMatch(ref index, ref smallestDifference, ref smallestIndex, cutBitmap); - cutBitmap.Dispose(); } if (smallestDifference > 0 && target.Width > 12) { - Bitmap cutBitmap = CopyBitmapSection(target, new Rectangle(1, 0, target.Width - 2, target.Height)); + var cutBitmap = target.CopyRectangle(new Rectangle(1, 0, target.Width - 2, target.Height)); int topCrop = 0; - Bitmap cutBitmap2 = ImageSplitter.CropTopAndBottom(cutBitmap, out topCrop, 2); + var cutBitmap2 = NikseBitmapImageSplitter.CropTopAndBottom(cutBitmap, out topCrop, 2); if (cutBitmap2.Height != target.Height) FindBestMatch(ref index, ref smallestDifference, ref smallestIndex, cutBitmap2); - cutBitmap.Dispose(); - cutBitmap2.Dispose(); } if (smallestDifference > 0 && target.Width > 15) { - Bitmap cutBitmap = CopyBitmapSection(target, new Rectangle(1, 0, target.Width - 2, target.Height)); + var cutBitmap = target.CopyRectangle(new Rectangle(1, 0, target.Width - 2, target.Height)); int topCrop = 0; - Bitmap cutBitmap2 = ImageSplitter.CropTopAndBottom(cutBitmap, out topCrop); + var cutBitmap2 = NikseBitmapImageSplitter.CropTopAndBottom(cutBitmap, out topCrop); if (cutBitmap2.Height != target.Height) FindBestMatch(ref index, ref smallestDifference, ref smallestIndex, cutBitmap2); - cutBitmap.Dispose(); - cutBitmap2.Dispose(); } if (smallestDifference > 0 && target.Width > 15) { - Bitmap cutBitmap = CopyBitmapSection(target, new Rectangle(1, 0, target.Width - 2, target.Height)); + var cutBitmap = target.CopyRectangle(new Rectangle(1, 0, target.Width - 2, target.Height)); int topCrop = 0; - Bitmap cutBitmap2 = ImageSplitter.CropTopAndBottom(cutBitmap, out topCrop); + var cutBitmap2 = NikseBitmapImageSplitter.CropTopAndBottom(cutBitmap, out topCrop); if (cutBitmap2.Height != target.Height) FindBestMatch(ref index, ref smallestDifference, ref smallestIndex, cutBitmap2); - cutBitmap.Dispose(); - cutBitmap2.Dispose(); } } @@ -2378,9 +2369,8 @@ namespace Nikse.SubtitleEdit.Forms return bmp; } - private void FindBestMatch(ref int index, ref int smallestDifference, ref int smallestIndex, Bitmap target2) + private void FindBestMatch(ref int index, ref int smallestDifference, ref int smallestIndex, NikseBitmap target) { - NikseBitmap target = new NikseBitmap(target2); int numberOfForegroundColors = CalculateNumberOfForegroundColors(target); int minForeColorMatch = 90; @@ -2396,7 +2386,7 @@ namespace Nikse.SubtitleEdit.Forms if (Math.Abs(compareItem.NumberOfForegroundColors - numberOfForegroundColors) < 3) { - int dif = ImageSplitter.IsBitmapsAlike(compareItem.Bitmap, target); + int dif = NikseBitmapImageSplitter.IsBitmapsAlike(compareItem.Bitmap, target); if (dif < smallestDifference) { smallestDifference = dif; @@ -2424,7 +2414,7 @@ namespace Nikse.SubtitleEdit.Forms if (Math.Abs(compareItem.NumberOfForegroundColors - numberOfForegroundColors) < 40) { - int dif = ImageSplitter.IsBitmapsAlike(compareItem.Bitmap, target); + int dif = NikseBitmapImageSplitter.IsBitmapsAlike(compareItem.Bitmap, target); if (dif < smallestDifference) { smallestDifference = dif; @@ -2454,7 +2444,7 @@ namespace Nikse.SubtitleEdit.Forms if (Math.Abs(compareItem.NumberOfForegroundColors - numberOfForegroundColors) < minForeColorMatch) { - int dif = ImageSplitter.IsBitmapsAlike(compareItem.Bitmap, target); + int dif = NikseBitmapImageSplitter.IsBitmapsAlike(compareItem.Bitmap, target); if (dif < smallestDifference) { smallestDifference = dif; @@ -2480,7 +2470,7 @@ namespace Nikse.SubtitleEdit.Forms if (Math.Abs(compareItem.NumberOfForegroundColors - numberOfForegroundColors) < minForeColorMatch) { - int dif = ImageSplitter.IsBitmapsAlike(target, compareItem.Bitmap); + int dif = NikseBitmapImageSplitter.IsBitmapsAlike(target, compareItem.Bitmap); if (dif < smallestDifference) { smallestDifference = dif; @@ -2506,7 +2496,7 @@ namespace Nikse.SubtitleEdit.Forms if (Math.Abs(compareItem.NumberOfForegroundColors - numberOfForegroundColors) < minForeColorMatch) { - int dif = ImageSplitter.IsBitmapsAlike(target, compareItem.Bitmap); + int dif = NikseBitmapImageSplitter.IsBitmapsAlike(target, compareItem.Bitmap); if (dif < smallestDifference) { smallestDifference = dif; @@ -2532,7 +2522,7 @@ namespace Nikse.SubtitleEdit.Forms if (Math.Abs(compareItem.NumberOfForegroundColors - numberOfForegroundColors) < minForeColorMatch) { - int dif = ImageSplitter.IsBitmapsAlike(compareItem.Bitmap, target); + int dif = NikseBitmapImageSplitter.IsBitmapsAlike(compareItem.Bitmap, target); if (dif < smallestDifference) { smallestDifference = dif; @@ -2558,7 +2548,7 @@ namespace Nikse.SubtitleEdit.Forms if (Math.Abs(compareItem.NumberOfForegroundColors - numberOfForegroundColors) < minForeColorMatch) { - int dif = ImageSplitter.IsBitmapsAlike(compareItem.Bitmap, target); + int dif = NikseBitmapImageSplitter.IsBitmapsAlike(compareItem.Bitmap, target); if (dif < smallestDifference) { smallestDifference = dif; @@ -2584,7 +2574,7 @@ namespace Nikse.SubtitleEdit.Forms if (Math.Abs(compareItem.NumberOfForegroundColors - numberOfForegroundColors) < minForeColorMatch) { - int dif = ImageSplitter.IsBitmapsAlike(target, compareItem.Bitmap); + int dif = NikseBitmapImageSplitter.IsBitmapsAlike(target, compareItem.Bitmap); if (dif < smallestDifference) { smallestDifference = dif; @@ -2610,7 +2600,7 @@ namespace Nikse.SubtitleEdit.Forms if (Math.Abs(compareItem.NumberOfForegroundColors - numberOfForegroundColors) < minForeColorMatch) { - int dif = ImageSplitter.IsBitmapsAlike(compareItem.Bitmap, target); + int dif = NikseBitmapImageSplitter.IsBitmapsAlike(compareItem.Bitmap, target); if (dif < smallestDifference) { smallestDifference = dif; @@ -2636,7 +2626,7 @@ namespace Nikse.SubtitleEdit.Forms if (Math.Abs(compareItem.NumberOfForegroundColors - numberOfForegroundColors) < minForeColorMatch) { - int dif = ImageSplitter.IsBitmapsAlike(compareItem.Bitmap, target); + int dif = NikseBitmapImageSplitter.IsBitmapsAlike(compareItem.Bitmap, target); if (dif < smallestDifference) { smallestDifference = dif; @@ -2662,7 +2652,7 @@ namespace Nikse.SubtitleEdit.Forms if (Math.Abs(compareItem.NumberOfForegroundColors - numberOfForegroundColors) < minForeColorMatch) { - int dif = ImageSplitter.IsBitmapsAlike(compareItem.Bitmap, target); + int dif = NikseBitmapImageSplitter.IsBitmapsAlike(compareItem.Bitmap, target); if (dif < smallestDifference) { smallestDifference = dif; @@ -2688,7 +2678,7 @@ namespace Nikse.SubtitleEdit.Forms if (Math.Abs(compareItem.NumberOfForegroundColors - numberOfForegroundColors) < minForeColorMatch) { - int dif = ImageSplitter.IsBitmapsAlike(target, compareItem.Bitmap); + int dif = NikseBitmapImageSplitter.IsBitmapsAlike(target, compareItem.Bitmap); if (dif < smallestDifference) { smallestDifference = dif; @@ -2716,6 +2706,8 @@ namespace Nikse.SubtitleEdit.Forms } } + + private unsafe static int CalculateNumberOfForegroundColors(NikseBitmap nikseBitmap) { int count = 0; @@ -2810,7 +2802,8 @@ namespace Nikse.SubtitleEdit.Forms if (threadText == null) { var matches = new List(); - List list = ImageSplitter.SplitBitmapToLetters(bitmap, (int)numericUpDownPixelsIsSpace.Value, checkBoxRightToLeft.Checked, Configuration.Settings.VobSubOcr.TopToBottom); + NikseBitmap parentBitmap = new NikseBitmap(bitmap); + List list = NikseBitmapImageSplitter.SplitBitmapToLetters(parentBitmap, (int)numericUpDownPixelsIsSpace.Value, checkBoxRightToLeft.Checked, Configuration.Settings.VobSubOcr.TopToBottom); int index = 0; bool expandSelection = false; bool shrinkSelection = false; @@ -2867,14 +2860,14 @@ namespace Nikse.SubtitleEdit.Forms _italicCheckedLast = _vobSubOcrCharacter.IsItalic; } - else if (item.Bitmap == null) + else if (item.NikseBitmap == null) { matches.Add(new CompareMatch(item.SpecialCharacter, false, 0, null)); } else { CompareMatch bestGuess; - CompareMatch match = GetCompareMatch(item, bitmap, out bestGuess); + CompareMatch match = GetCompareMatch(item, parentBitmap, out bestGuess); if (match == null) { _vobSubOcrCharacter.Initialize(bitmap, item, _manualOcrDialogPosition, _italicCheckedLast, false, bestGuess, _lastAdditions, this); @@ -3101,20 +3094,20 @@ namespace Nikse.SubtitleEdit.Forms private void NOCRIntialize(Bitmap bitmap) { var matches = new List(); - List list = ImageSplitter.SplitBitmapToLetters(bitmap, (int)numericUpDownNumberOfPixelsIsSpaceNOCR.Value, checkBoxRightToLeft.Checked, Configuration.Settings.VobSubOcr.TopToBottom); + List list = NikseBitmapImageSplitter.SplitBitmapToLetters(new NikseBitmap(bitmap), (int)numericUpDownNumberOfPixelsIsSpaceNOCR.Value, checkBoxRightToLeft.Checked, Configuration.Settings.VobSubOcr.TopToBottom); foreach (ImageSplitterItem item in list) { - if (item.Bitmap != null) + if (item.NikseBitmap != null) { - var old = item.Bitmap; - var nbmp = new NikseBitmap(item.Bitmap); + //var old = item.Bitmap; + var nbmp = item.NikseBitmap; nbmp.ReplaceNonWhiteWithTransparent(); item.Y += nbmp.CropTopTransparent(0); nbmp.CropTransparentSidesAndBottom(0, true); nbmp.ReplaceTransparentWith(Color.Black); - item.Bitmap = nbmp.GetBitmap(); - old.Dispose(); + //item.Bitmap = nbmp.GetBitmap(); + //old.Dispose(); GetNOcrCompareMatch(item, bitmap, _nocrChars, _unItalicFactor, false, false); } @@ -3131,25 +3124,21 @@ namespace Nikse.SubtitleEdit.Forms line = _nocrThreadResults[listViewIndex]; if (string.IsNullOrEmpty(line)) { - NikseBitmap nbmp = new NikseBitmap(bitmap); - nbmp.ReplaceNonWhiteWithTransparent(); - bitmap = nbmp.GetBitmap(); + var nbmpInput = new NikseBitmap(bitmap); + nbmpInput.ReplaceNonWhiteWithTransparent(); + //bitmap = nbmp.GetBitmap(); var matches = new List(); - List list = ImageSplitter.SplitBitmapToLetters(bitmap, (int)numericUpDownNumberOfPixelsIsSpaceNOCR.Value, checkBoxRightToLeft.Checked, Configuration.Settings.VobSubOcr.TopToBottom); + List list = NikseBitmapImageSplitter.SplitBitmapToLetters(nbmpInput, (int)numericUpDownNumberOfPixelsIsSpaceNOCR.Value, checkBoxRightToLeft.Checked, Configuration.Settings.VobSubOcr.TopToBottom); foreach (ImageSplitterItem item in list) { - if (item.Bitmap != null) + if (item.NikseBitmap != null) { - var old = item.Bitmap; - nbmp = new NikseBitmap(item.Bitmap); - nbmp.ReplaceNonWhiteWithTransparent(); - item.Y += nbmp.CropTopTransparent(0); - nbmp.CropTransparentSidesAndBottom(0, true); - nbmp.ReplaceTransparentWith(Color.Black); - item.Bitmap = nbmp.GetBitmap(); - old.Dispose(); + item.NikseBitmap.ReplaceNonWhiteWithTransparent(); + item.Y += item.NikseBitmap.CropTopTransparent(0); + item.NikseBitmap.CropTransparentSidesAndBottom(0, true); + item.NikseBitmap.ReplaceTransparentWith(Color.Black); } } int index = 0; @@ -3173,16 +3162,12 @@ namespace Nikse.SubtitleEdit.Forms expandSelectionList.Add(list[index]); } item = GetExpandedSelection(bitmap, expandSelectionList, checkBoxRightToLeft.Checked); - if (item.Bitmap != null) + if (item.NikseBitmap != null) { - var old = item.Bitmap; - nbmp = new NikseBitmap(item.Bitmap); - nbmp.ReplaceNonWhiteWithTransparent(); - item.Y += nbmp.CropTopTransparent(0); - nbmp.CropTransparentSidesAndBottom(0, true); - nbmp.ReplaceTransparentWith(Color.Black); - item.Bitmap = nbmp.GetBitmap(); - old.Dispose(); + item.NikseBitmap.ReplaceNonWhiteWithTransparent(); + item.Y += item.NikseBitmap.CropTopTransparent(0); + item.NikseBitmap.CropTransparentSidesAndBottom(0, true); + item.NikseBitmap.ReplaceTransparentWith(Color.Black); } _vobSubOcrNOcrCharacter.Initialize(bitmap, item, _manualOcrDialogPosition, _italicCheckedLast, expandSelectionList.Count > 1, null, _lastAdditions, this); @@ -3224,7 +3209,7 @@ namespace Nikse.SubtitleEdit.Forms _italicCheckedLast = _vobSubOcrNOcrCharacter.IsItalic; } - else if (item.Bitmap == null) + else if (item.NikseBitmap == null) { matches.Add(new CompareMatch(item.SpecialCharacter, false, 0, null)); } @@ -3796,21 +3781,21 @@ namespace Nikse.SubtitleEdit.Forms e.Result = p; Bitmap bitmap = p.Picture; var matches = new List(); - List lines = ImageSplitter.SplitVertical(bitmap); - List list = ImageSplitter.SplitBitmapToLetters(lines, p.NumberOfPixelsIsSpace, p.RightToLeft, Configuration.Settings.VobSubOcr.TopToBottom); + List lines = NikseBitmapImageSplitter.SplitVertical(bitmap); + List list = NikseBitmapImageSplitter.SplitBitmapToLetters(lines, p.NumberOfPixelsIsSpace, p.RightToLeft, Configuration.Settings.VobSubOcr.TopToBottom); int index = 0; int outerIndex = 0; while (outerIndex < list.Count) { ImageSplitterItem item = list[outerIndex]; - if (item.Bitmap == null) + if (item.NikseBitmap == null) { matches.Add(new CompareMatch(item.SpecialCharacter, false, 0, null)); } else { - var target = new NikseBitmap(item.Bitmap); + var target = item.NikseBitmap; int numberOfForegroundColors = CalculateNumberOfForegroundColors(target); int smallestDifference = 10000; @@ -3828,7 +3813,7 @@ namespace Nikse.SubtitleEdit.Forms if (Math.Abs(compareItem.NumberOfForegroundColors - numberOfForegroundColors) < 30) { - int dif = ImageSplitter.IsBitmapsAlike(compareItem.Bitmap, target); + int dif = NikseBitmapImageSplitter.IsBitmapsAlike(compareItem.Bitmap, target); if (dif < smallestDifference) { smallestDifference = dif; @@ -3854,7 +3839,7 @@ namespace Nikse.SubtitleEdit.Forms if (Math.Abs(compareItem.NumberOfForegroundColors - numberOfForegroundColors) < 50) { - int dif = ImageSplitter.IsBitmapsAlike(target, compareItem.Bitmap); + int dif = NikseBitmapImageSplitter.IsBitmapsAlike(target, compareItem.Bitmap); if (dif < smallestDifference) { smallestDifference = dif; @@ -3882,7 +3867,7 @@ namespace Nikse.SubtitleEdit.Forms if (Math.Abs(compareItem.NumberOfForegroundColors - numberOfForegroundColors) < 55) { - int dif = ImageSplitter.IsBitmapsAlike(compareItem.Bitmap, target); + int dif = NikseBitmapImageSplitter.IsBitmapsAlike(compareItem.Bitmap, target); if (dif < smallestDifference) { smallestDifference = dif; @@ -3897,7 +3882,7 @@ namespace Nikse.SubtitleEdit.Forms } CompareMatch match = null; - double differencePercentage = smallestDifference * 100.0 / (item.Bitmap.Width * item.Bitmap.Height); + double differencePercentage = smallestDifference * 100.0 / (item.NikseBitmap.Width * item.NikseBitmap.Height); double maxDiff = (double)p.MaxErrorPercent; if (differencePercentage <= maxDiff) { @@ -4027,10 +4012,10 @@ namespace Nikse.SubtitleEdit.Forms var p = (NOcrThreadParameter)e.Argument; e.Result = p; - Bitmap bitmap = p.Picture; - var nbmp = new NikseBitmap(bitmap); - nbmp.ReplaceNonWhiteWithTransparent(); - bitmap = nbmp.GetBitmap(); + //Bitmap bitmap = p.Picture; + var nbmpInput = new NikseBitmap(p.Picture); + nbmpInput.ReplaceNonWhiteWithTransparent(); +// bitmap = nbmp.GetBitmap(); var matches = new List(); int minLineHeight = p.NOcrLastLowercaseHeight; @@ -4040,34 +4025,32 @@ namespace Nikse.SubtitleEdit.Forms if (maxLineHeight < 10) minLineHeight = 80; - List lines = ImageSplitter.SplitVertical(bitmap, minLineHeight); - List list = ImageSplitter.SplitBitmapToLetters(lines, p.NumberOfPixelsIsSpace, p.RightToLeft, Configuration.Settings.VobSubOcr.TopToBottom); + List lines = NikseBitmapImageSplitter.SplitVertical(nbmpInput, minLineHeight); + List list = NikseBitmapImageSplitter.SplitBitmapToLetters(lines, p.NumberOfPixelsIsSpace, p.RightToLeft, Configuration.Settings.VobSubOcr.TopToBottom); foreach (ImageSplitterItem item in list) { - if (item.Bitmap != null) + if (item.NikseBitmap != null) { - var old = item.Bitmap; - nbmp = new NikseBitmap(item.Bitmap); + var nbmp = item.NikseBitmap; nbmp.ReplaceNonWhiteWithTransparent(); item.Y += nbmp.CropTopTransparent(0); nbmp.CropTransparentSidesAndBottom(0, true); nbmp.ReplaceTransparentWith(Color.Black); - item.Bitmap = nbmp.GetBitmap(); - old.Dispose(); +// item.Bitmap = nbmp.GetBitmap(); } } int index = 0; while (index < list.Count) { ImageSplitterItem item = list[index]; - if (item.Bitmap == null) + if (item.NikseBitmap == null) { matches.Add(new CompareMatch(item.SpecialCharacter, false, 0, null)); } else { - CompareMatch match = GetNOcrCompareMatch(item, bitmap, p); + CompareMatch match = GetNOcrCompareMatch(item, nbmpInput.GetBitmap(), p); if (match == null) { //if (p.AdvancedItalicDetection) @@ -6028,8 +6011,9 @@ namespace Nikse.SubtitleEdit.Forms Cursor = Cursors.WaitCursor; Bitmap bitmap = GetSubtitleBitmap(subtitleListView1.SelectedItems[0].Index); + NikseBitmap parentBitmap = new NikseBitmap(bitmap); var matches = new List(); - List list = ImageSplitter.SplitBitmapToLetters(bitmap, (int)numericUpDownPixelsIsSpace.Value, checkBoxRightToLeft.Checked, Configuration.Settings.VobSubOcr.TopToBottom); + List list = NikseBitmapImageSplitter.SplitBitmapToLetters(parentBitmap, (int)numericUpDownPixelsIsSpace.Value, checkBoxRightToLeft.Checked, Configuration.Settings.VobSubOcr.TopToBottom); int index = 0; var imageSources = new List(); while (index < list.Count) @@ -6043,7 +6027,7 @@ namespace Nikse.SubtitleEdit.Forms else { CompareMatch bestGuess; - CompareMatch match = GetCompareMatch(item, bitmap, out bestGuess); + CompareMatch match = GetCompareMatch(item, parentBitmap, out bestGuess); if (match == null) { matches.Add(new CompareMatch(Configuration.Settings.Language.VobSubOcr.NoMatch, false, 0, null)); diff --git a/src/Logic/ImageSplitterItem.cs b/src/Logic/ImageSplitterItem.cs index 6a121325e..e0f81c4c8 100644 --- a/src/Logic/ImageSplitterItem.cs +++ b/src/Logic/ImageSplitterItem.cs @@ -7,7 +7,23 @@ namespace Nikse.SubtitleEdit.Logic public int X { get; set; } public int Y { get; set; } public int ParentY { get; set; } - public Bitmap Bitmap { get; set; } + public Bitmap Bitmap + { + get + { + if (NikseBitmap == null) + return null; + return NikseBitmap.GetBitmap(); + } + set + { + if (value == null) + NikseBitmap = null; + else + NikseBitmap = new NikseBitmap(value); + } + } + public NikseBitmap NikseBitmap { get; set; } public string SpecialCharacter { get; set; } public ImageSplitterItem(int x, int y, Bitmap bitmap) @@ -18,12 +34,20 @@ namespace Nikse.SubtitleEdit.Logic SpecialCharacter = null; } + public ImageSplitterItem(int x, int y, NikseBitmap bitmap) + { + X = x; + Y = y; + NikseBitmap = bitmap; + SpecialCharacter = null; + } + public ImageSplitterItem(string specialCharacter) { X = 0; Y = 0; SpecialCharacter = specialCharacter; - Bitmap = null; + NikseBitmap = null; } } } diff --git a/src/Logic/NikseBitmap.cs b/src/Logic/NikseBitmap.cs index 65682e62e..a17bde83d 100644 --- a/src/Logic/NikseBitmap.cs +++ b/src/Logic/NikseBitmap.cs @@ -29,6 +29,13 @@ namespace Nikse.SubtitleEdit.Logic _bitmapData = new byte[Width * Height * 4]; } + public NikseBitmap(int width, int height, byte[] bitmapData) + { + Width = width; + Height = height; + _bitmapData = bitmapData; + } + public NikseBitmap(Bitmap inputBitmap) { if (inputBitmap == null) @@ -892,5 +899,25 @@ namespace Nikse.SubtitleEdit.Logic return newBitmap; } + + public NikseBitmap CopyRectangle(Rectangle section) + { + if (section.Bottom > Height) + section = new Rectangle(section.Left, section.Top, section.Width, Height - section.Top); + if (section.Width + section.Left > Width) + section = new Rectangle(section.Left, section.Top, Width - section.Left, section.Height); + var newBitmapData = new byte[section.Width * section.Height * 4]; + int index = 0; + for (int y = section.Top; y < section.Bottom; y++) + { + int pixelAddress = (section.Left * 4) + (y * 4 * Width); + Buffer.BlockCopy(_bitmapData, pixelAddress, newBitmapData, index, 4 * section.Width); + index += 4 * section.Width; + } + return new NikseBitmap(section.Width, section.Height, newBitmapData); + } + + + } } diff --git a/src/Logic/NikseBitmapImageSplitter.cs b/src/Logic/NikseBitmapImageSplitter.cs new file mode 100644 index 000000000..528e163db --- /dev/null +++ b/src/Logic/NikseBitmapImageSplitter.cs @@ -0,0 +1,690 @@ +using System; +using System.Collections.Generic; +using System.Drawing; + +namespace Nikse.SubtitleEdit.Logic +{ + public class NikseBitmapImageSplitter + { + public static bool IsColorClose(Color a, Color b, int tolerance) + { + if (a.A < 120 && b.A < 120) + return true; // transparent + + if (a.A > 250 && a.R > 90 && a.G > 90 && a.B > 90 && + b.A > 250 && b.R > 90 && b.G > 90 && b.B > 90) + return true; // dark, non transparent + + int diff = (a.R + a.G + a.B) - (b.R + b.G + b.B); + return diff < tolerance && diff > -tolerance; + } + + public static NikseBitmap Copy(NikseBitmap sourceBitmap, Rectangle section) + { + return sourceBitmap.CopyRectangle(section); + } + + 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++) + { + Color c = bmp.GetPixel(x, y); + if (c.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; + + for (int y = bmp.Height-1; y > 3; y--) + { + bool allTransparent = true; + for (int x = 1; x < bmp.Width-1; x++) + { + Color c = bmp.GetPixel(x, y); + if (c.A != 0) + { + allTransparent = false; + break; + } + } + if (allTransparent == false) + return Copy(bmp, new Rectangle(0, startTop, bmp.Width - 1, y-startTop+1)); + } + return bmp; + } + + 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++) + { + Color c = bmp.GetPixel(x, y); + if (c.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++) + { + Color c = bmp.GetPixel(x, y); + if (c.A != 0) + { + difference++; + if (difference >= maxDifferentPixelsOnLine) + { + allTransparent = false; + break; + } + } + } + if (allTransparent == false) + return Copy(bmp, new Rectangle(0, startTop, bmp.Width - 1, y - startTop + 1)); + } + return bmp; + } + + public static List SplitVertical(Bitmap bmp) + { + return SplitVertical(new NikseBitmap(bmp)); + } + + public static List SplitVertical(Bitmap bmp, int lineMinHeight) + { + return SplitVertical(new NikseBitmap(bmp), lineMinHeight); + } + + public static List SplitVertical(NikseBitmap bmp) + { // split into lines + int startY = 0; + int size = 0; + var parts = new List(); + 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 != 0) + { + allTransparent = false; + break; + } + } + if (allTransparent) + { + if (size > 2 && size < 6) + { + size++; // at least 5 pixels, like top of 'i' + } + else + { + if (size > 2) + { + NikseBitmap part = Copy(bmp, 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) + { + NikseBitmap part = Copy(bmp, new Rectangle(0, startY, bmp.Width, size+1)); + parts.Add(new ImageSplitterItem(0, startY, part)); + } + return parts; + } + + public static List SplitVertical(NikseBitmap bmp, int lineMinHeight) + { // split into lines + int startY = 0; + int size = 0; + var parts = new List(); + 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 != 0) + { + allTransparent = false; + break; + } + } + if (allTransparent) + { + if (size > 2 && size <= lineMinHeight) + { + size++; // at least 5 pixels, like top of 'i' + } + else + { + if (size > 2) + { + NikseBitmap part = Copy(bmp, 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) + { + NikseBitmap part = Copy(bmp, new Rectangle(0, startY, bmp.Width, size + 1)); + parts.Add(new ImageSplitterItem(0, startY, part)); + } + return parts; + } + + public static int IsBitmapsAlike(Bitmap bmp1, Bitmap bmp2) + { + int different = 0; + int maxDiff = (int)(bmp1.Width * bmp1.Height / 5.0); + + 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; + } + + public static int IsBitmapsAlike(FastBitmap bmp1, Bitmap bmp2) + { + int different = 0; + + for (int x = 1; x < bmp1.Width; x++) + { + for (int y = 1; y < bmp1.Height; y++) + { + Color c1 = bmp1.GetPixel(x, y); + Color c2 = bmp1.GetPixel(x, y); + if (!IsColorClose(c1, c2, 20)) + different++; + } + } + return different; + } + + private static List SplitHorizontal(ImageSplitterItem verticalItem, int xOrMorePixelsMakesSpace) + { // split line into letters + NikseBitmap bmp = verticalItem.NikseBitmap; + var parts = new List(); + int size = 0; + int startX = 0; + int lastEndX = 0; + int y = 0; + bool spaceJustAdded = false; + + for (int x = 0; x < bmp.Width - 1; x++) + { + bool allTransparent = IsVerticalLineTransparent(bmp, ref y, x); + + // check if line is transparent and cursive + bool cursiveOk = false; + int tempY = 0; + if (allTransparent == false && + size > 5 && + y > 3 && + x < bmp.Width-2 && + !IsVerticalLineTransparent(bmp, ref tempY, x + 1)) + { + + //Add space? + if (lastEndX > 0 && lastEndX + xOrMorePixelsMakesSpace < startX) + { + int cleanCount = 0; + for (int j = lastEndX; j < startX; j++) + { + int y1 = j; + if (IsVerticalLineTransparent2(bmp, ref y1, j)) + cleanCount++; + } + if (cleanCount > 0 && !spaceJustAdded) + { + parts.Add(new ImageSplitterItem(" ")); + spaceJustAdded = true; + } + } + + var cursivePoints = new List(); + + cursiveOk = IsCursiveVerticalLineTransparent(bmp, size, y, x, cursivePoints); + + if (cursiveOk) + { + // make letter image + int end = x + 1 - startX; + if (startX > 0) + { + startX--; + end++; + } + NikseBitmap b1 = Copy(bmp, new Rectangle(startX, 0, end, bmp.Height)); +// b1.Save(@"d:\temp\cursive.bmp"); // just for debugging + + // make non-black/transparent stuff from other letter transparent + foreach (Point p in cursivePoints) + { + for (int fixY = p.Y; fixY < bmp.Height; fixY++) + b1.SetPixel(p.X - startX, fixY, Color.Transparent); + } + + RemoveBlackBarRight(b1); +// b1.Save(@"d:\temp\cursive-cleaned.bmp"); // just for debugging + + // crop and save image + int addY; + b1 = CropTopAndBottom(b1, out addY); + parts.Add(new ImageSplitterItem(startX, verticalItem.Y + addY, b1)); + spaceJustAdded = false; + size = 0; + startX = x + 1; + lastEndX = x; + } + } + + if (!cursiveOk) + { + if (allTransparent) + { + if (size > 0) + { + if (size > 1) + { + //Add space? + if (lastEndX > 0 && lastEndX + xOrMorePixelsMakesSpace < startX) + { + int cleanCount = 0; + for (int j = lastEndX; j < startX; j++) + { + int y1=j; + if (IsVerticalLineTransparent2(bmp, ref y1, j)) + cleanCount++; + } + if (cleanCount > 2 && !spaceJustAdded) + { + parts.Add(new ImageSplitterItem(" ")); + spaceJustAdded = true; + } + } + + if (startX > 0) + startX--; + lastEndX = x; + int end = x + 1 - startX; + NikseBitmap part = Copy(bmp, new Rectangle(startX, 0, end, bmp.Height)); + RemoveBlackBarRight(part); + int addY; + // part.Save("c:\\before" + startX.ToString() + ".bmp"); // just for debugging + part = CropTopAndBottom(part, out addY); + // part.Save("c:\\after" + startX.ToString() + ".bmp"); // just for debugging + parts.Add(new ImageSplitterItem(startX, verticalItem.Y + addY, part)); + spaceJustAdded = false; +// part.Save(@"d:\temp\cursive.bmp"); // just for debugging + } + size = 0; + } + startX = x + 1; + } + else + { + size++; + } + } + } + + if (size > 0) + { + if (lastEndX > 0 && lastEndX + xOrMorePixelsMakesSpace < startX && !spaceJustAdded) + parts.Add(new ImageSplitterItem(" ")); + + if (startX > 0) + startX--; + lastEndX = bmp.Width-1; + int end = lastEndX + 1 - startX; + NikseBitmap part = Copy(bmp, new Rectangle(startX, 0, end, bmp.Height - 1)); + int addY; + part = CropTopAndBottom(part, out addY); + parts.Add(new ImageSplitterItem(startX, verticalItem.Y + addY, part)); + //part.Save(@"d:\temp\cursive.bmp"); // just for debugging + } + return parts; + } + + private static void RemoveBlackBarRight(NikseBitmap bmp) + { + int xRemoveBlackBar = bmp.Width-1; + for (int yRemoveBlackBar = 0; yRemoveBlackBar < bmp.Height; yRemoveBlackBar++) + { + Color c = bmp.GetPixel(xRemoveBlackBar, yRemoveBlackBar); + if (c.A == 0 || IsColorClose(c, Color.Black, 280)) + { + if (bmp.GetPixel(xRemoveBlackBar - 1, yRemoveBlackBar).A == 0) + bmp.SetPixel(xRemoveBlackBar, yRemoveBlackBar, Color.Transparent); + } + } + } + + private static bool IsCursiveVerticalLineTransparent(NikseBitmap bmp, int size, int y, int x, List 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 + { + Color c1 = bmp.GetPixel(newX - 1, newY - 1); + Color c2 = bmp.GetPixel(newX - 1, newY); + if ((c1.A == 0 || IsColorClose(c1, Color.Black, 280)) && // still dark color... + (c2.A == 0 || IsColorClose(c2, 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 bool IsVerticalLineTransparent(NikseBitmap bmp, ref int y, int x) + { + bool allTransparent = true; + for (y = 0; y < bmp.Height - 1; y++) + { + Color c = bmp.GetPixel(x, y); + if (c.A == 0 || //c.ToArgb() == transparentColor.ToArgb() || + IsColorClose(c, Color.Black, 280)) // still dark color... + { + } + else + { + allTransparent = false; + break; + } + } + return allTransparent; + } + + private static bool IsVerticalLineTransparent2(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; + } + + public static List SplitBitmapToLetters(NikseBitmap bmp, int xOrMorePixelsMakesSpace, bool rightToLeft, bool topToBottom) + { + var list = new List(); + + // split into seperate lines + List verticalBitmaps = SplitVertical(bmp, xOrMorePixelsMakesSpace); + + 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(); + foreach (ImageSplitterItem item in SplitHorizontal(b, xOrMorePixelsMakesSpace)) + { + item.ParentY = item.Y; + line.Add(item); + } + if (rightToLeft) + line.Reverse(); + foreach (ImageSplitterItem item in line) + list.Add(item); + lineCount++; + } + + return list; + } + + public static List SplitBitmapToLetters(List verticalBitmaps, int xOrMorePixelsMakesSpace, bool rightToLeft, bool topToBottom) + { + var list = new List(); + 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(); + foreach (ImageSplitterItem item in SplitHorizontal(b, xOrMorePixelsMakesSpace)) + { + item.ParentY = item.Y; + line.Add(item); + } + if (rightToLeft) + line.Reverse(); + foreach (ImageSplitterItem item in line) + list.Add(item); + lineCount++; + } + + return list; + } + + internal static unsafe int IsBitmapsAlike(NikseBitmap bmp1, NikseBitmap bmp2) + { + int different = 0; + int maxDiff = (int)(bmp1.Width * bmp1.Height / 5.0); + + 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; + } + + internal static unsafe int IsBitmapsAlike(ManagedBitmap bmp1, NikseBitmap bmp2) + { + int different = 0; + int maxDiff = (int)(bmp1.Width * bmp1.Height / 5.0); + + 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; + } + + internal static unsafe int IsBitmapsAlike(ManagedBitmap bmp1, Bitmap bmp2) + { + int different = 0; + int maxDiff = (int)(bmp1.Width * bmp1.Height / 5.0); + + 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; + } + + internal static unsafe int IsBitmapsAlike(NikseBitmap bmp1, ManagedBitmap bmp2) + { + int different = 0; + int maxDiff = (int)(bmp1.Width * bmp1.Height / 5.0); + + 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; + } + + internal static unsafe int IsBitmapsAlike(Bitmap bmp1, NikseBitmap bmp2) + { + int different = 0; + int maxDiff = (int)(bmp1.Width * bmp1.Height / 5.0); + NikseBitmap nbmp1 = new NikseBitmap(bmp1); + + for (int x = 1; x < bmp1.Width; x++) + { + for (int y = 1; y < bmp1.Height; y++) + { + if (!IsColorClose(nbmp1.GetPixel(x, y), bmp2.GetPixel(x, y), 20)) + { + different++; + } + } + if (different > maxDiff) + return different + 10; + } + return different; + } + + internal static unsafe int IsBitmapsAlike(NikseBitmap bmp1, Bitmap bmp2) + { + int different = 0; + int maxDiff = (int)(bmp1.Width * bmp1.Height / 5.0); + + 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; + } + } +} diff --git a/src/SubtitleEdit.csproj b/src/SubtitleEdit.csproj index 4e6a62e01..55aed2bcb 100644 --- a/src/SubtitleEdit.csproj +++ b/src/SubtitleEdit.csproj @@ -734,6 +734,7 @@ +