Improve "exanded hit" for nOCR + work on casing

This commit is contained in:
Nikolaj Olsson 2020-05-31 21:35:27 +02:00
parent 922bfbc1a6
commit a8536393a0
6 changed files with 210 additions and 111 deletions

View File

@ -958,22 +958,13 @@ namespace Nikse.SubtitleEdit.Core
_bitmapData[_pixelAddress + 3] = color.A;
}
public void SetPixelNext(Color color)
{
_pixelAddress += 4;
_bitmapData[_pixelAddress] = color.B;
_bitmapData[_pixelAddress + 1] = color.G;
_bitmapData[_pixelAddress + 2] = color.R;
_bitmapData[_pixelAddress + 3] = color.A;
}
public Bitmap GetBitmap()
{
var bitmap = new Bitmap(Width, Height, PixelFormat.Format32bppArgb);
var bitmapdata = bitmap.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
var destination = bitmapdata.Scan0;
var bitmapData = bitmap.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
var destination = bitmapData.Scan0;
Marshal.Copy(_bitmapData, 0, destination, _bitmapData.Length);
bitmap.UnlockBits(bitmapdata);
bitmap.UnlockBits(bitmapData);
return bitmap;
}

View File

@ -166,6 +166,7 @@
this.toolStripMenuItem3 = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItemMusicSymbol1 = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItemMusicSymbol2 = new System.Windows.Forms.ToolStripMenuItem();
this.labelStatus = new System.Windows.Forms.Label();
this.groupBoxInspectItems.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.pictureBoxInspectItem)).BeginInit();
this.contextMenuStripAddBetterMultiMatch.SuspendLayout();
@ -1215,11 +1216,22 @@
this.toolStripMenuItemMusicSymbol2.Size = new System.Drawing.Size(134, 22);
this.toolStripMenuItemMusicSymbol2.Text = "♫";
//
// labelStatus
//
this.labelStatus.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.labelStatus.AutoSize = true;
this.labelStatus.Location = new System.Drawing.Point(15, 424);
this.labelStatus.Name = "labelStatus";
this.labelStatus.Size = new System.Drawing.Size(59, 13);
this.labelStatus.TabIndex = 38;
this.labelStatus.Text = "labelStatus";
//
// VobSubNOcrCharacterInspect
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(826, 446);
this.Controls.Add(this.labelStatus);
this.Controls.Add(this.groupBoxInspectItems);
this.Controls.Add(this.groupBoxCurrentCompareImage);
this.Controls.Add(this.buttonOK);
@ -1241,6 +1253,7 @@
((System.ComponentModel.ISupportInitialize)(this.pictureBoxCharacter)).EndInit();
this.contextMenuStripLetters.ResumeLayout(false);
this.ResumeLayout(false);
this.PerformLayout();
}
@ -1383,5 +1396,6 @@
private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem3;
private System.Windows.Forms.ToolStripMenuItem toolStripMenuItemMusicSymbol1;
private System.Windows.Forms.ToolStripMenuItem toolStripMenuItemMusicSymbol2;
private System.Windows.Forms.Label labelStatus;
}
}

View File

@ -27,6 +27,7 @@ namespace Nikse.SubtitleEdit.Forms.Ocr
InitializeComponent();
UiUtil.FixFonts(this);
labelImageSize.Text = string.Empty;
labelStatus.Text = string.Empty;
foreach (ToolStripItem toolStripItem in contextMenuStripLetters.Items)
{
@ -95,7 +96,7 @@ namespace Nikse.SubtitleEdit.Forms.Ocr
}
else
{
var match = vobSubOcr.GetNOcrCompareMatchNew(item, nbmp, nOcrDb, false, false);
var match = vobSubOcr.GetNOcrCompareMatchNew(item, nbmp, nOcrDb, false, false, index, _imageList);
if (match == null)
{
_indexLookup.Add(listBoxInspectItems.Items.Count, index);
@ -267,18 +268,30 @@ namespace Nikse.SubtitleEdit.Forms.Ocr
{
_nocrChar.Text = textBoxText.Text;
_nocrChar.Italic = checkBoxItalic.Checked;
_vobSubOcr.SaveNOcrWithCurrentLanguage();
MessageBox.Show("nOCR saved!");
ShowStatus("Character updated");
}
}
private void ShowStatus(string text)
{
labelStatus.Text = text;
labelStatus.Refresh();
System.Threading.SynchronizationContext.Current.Post(TimeSpan.FromMilliseconds(1500), () =>
{
if (!IsDisposed)
{
labelStatus.Text = string.Empty;
labelStatus.Refresh();
}
});
}
private void buttonDelete_Click(object sender, EventArgs e)
{
if (_nocrChar != null)
{
_nocrChars.Remove(_nocrChar);
_vobSubOcr.SaveNOcrWithCurrentLanguage();
MessageBox.Show("nOCR saved!");
ShowStatus("Character deleted");
}
}
@ -352,7 +365,6 @@ namespace Nikse.SubtitleEdit.Forms.Ocr
}
_nocrChars.Add(vobSubOcrNOcrCharacter.NOcrChar);
_vobSubOcr.SaveNOcrWithCurrentLanguage();
DialogResult = DialogResult.OK;
}
}

View File

@ -193,7 +193,7 @@ namespace Nikse.SubtitleEdit.Forms.Ocr
{
// e.g. quote (")
var expandItem = VobSubOcr.GetExpandedSelectionNew(nikseBitmap, new List<ImageSplitterItem> { list[2], list[3] });
var match = nOcrD.GetMatchExpanded(nikseBitmap, expandItem);
var match = nOcrD.GetMatchExpanded(nikseBitmap, expandItem, 2, list);
if (match != null && match.Text == s)
{
numberOfCharactersSkipped++;
@ -216,7 +216,7 @@ namespace Nikse.SubtitleEdit.Forms.Ocr
{
// e.g. "%"
var expandItem = VobSubOcr.GetExpandedSelectionNew(nikseBitmap, new List<ImageSplitterItem> { list[2], list[3], list[4] });
var match = nOcrD.GetMatchExpanded(nikseBitmap, expandItem);
var match = nOcrD.GetMatchExpanded(nikseBitmap, expandItem, 2, list);
if (match != null && match.Text == s)
{
numberOfCharactersSkipped++;

View File

@ -2711,35 +2711,65 @@ namespace Nikse.SubtitleEdit.Forms.Ocr
}
if (result.Text == "V" || result.Text == "W" || result.Text == "U" || result.Text == "S" ||
result.Text == "Z" || result.Text == "Ź" || result.Text == "Ż" || result.Text == "O" || result.Text == "Ó" ||
result.Text == "X" || result.Text == "Ø" || result.Text == "C" || result.Text == "Ć")
result.Text == "Z" || result.Text == "O" ||
result.Text == "X" || result.Text == "Ø" || result.Text == "C")
{
var averageLowercase = _binOcrLowercaseHeightsTotal / _binOcrLowercaseHeightsTotalCount;
var averageUppercase = _binOcrUppercaseHeightsTotal / _binOcrUppercaseHeightsTotalCount;
if (_binOcrLowercaseHeightsTotalCount > 2 &&
_binOcrUppercaseHeightsTotalCount > 2 &&
Math.Abs(_binOcrLowercaseHeightsTotal / _binOcrLowercaseHeightsTotalCount - targetItem.NikseBitmap.Height) <
Math.Abs(_binOcrUppercaseHeightsTotal / _binOcrUppercaseHeightsTotalCount - targetItem.NikseBitmap.Height))
Math.Abs(averageLowercase - targetItem.NikseBitmap.Height) <
Math.Abs(averageUppercase - targetItem.NikseBitmap.Height))
{
result.Text = result.Text.ToLowerInvariant();
}
}
else if (result.Text == "v" || result.Text == "w" || result.Text == "u" || result.Text == "s" ||
result.Text == "z" || result.Text == "ź" || result.Text == "ż" || result.Text == "ó" ||
result.Text == "o" || result.Text == "x" || result.Text == "ø" || result.Text == "c" || result.Text == "ć")
result.Text == "z" ||
result.Text == "o" || result.Text == "x" || result.Text == "ø" || result.Text == "c")
{
var averageLowercase = _binOcrLowercaseHeightsTotal / _binOcrLowercaseHeightsTotalCount;
var averageUppercase = _binOcrUppercaseHeightsTotal / _binOcrUppercaseHeightsTotalCount;
if (_binOcrLowercaseHeightsTotalCount > 2 &&
_binOcrUppercaseHeightsTotalCount > 2 &&
Math.Abs(_binOcrLowercaseHeightsTotal / _binOcrLowercaseHeightsTotalCount - targetItem.NikseBitmap.Height) >
Math.Abs(_binOcrUppercaseHeightsTotal / _binOcrUppercaseHeightsTotalCount - targetItem.NikseBitmap.Height))
Math.Abs(averageLowercase - targetItem.NikseBitmap.Height) >
Math.Abs(averageUppercase - targetItem.NikseBitmap.Height))
{
result.Text = result.Text.ToUpperInvariant();
}
}
// Polish
else if (result.Text == "Ć" || result.Text == "Ź" || result.Text == "Ż" || result.Text == "Ą" || result.Text == "Ó" || result.Text == "Ś")
{
var averageLowercase = _binOcrLowercaseHeightsTotal / (double)_binOcrLowercaseHeightsTotalCount * 1.5;
var averageUppercase = _binOcrUppercaseHeightsTotal / (double)_binOcrUppercaseHeightsTotalCount * 1.3;
if (_binOcrLowercaseHeightsTotalCount > 2 &&
_binOcrUppercaseHeightsTotalCount > 2 &&
Math.Abs(averageLowercase - targetItem.NikseBitmap.Height) <
Math.Abs(averageUppercase - targetItem.NikseBitmap.Height))
{
result.Text = result.Text.ToLowerInvariant();
}
}
else if (result.Text == "ć" || result.Text == "ź" || result.Text == "ż" || result.Text == "ą" || result.Text == "ó" || result.Text == "ś")
{
var averageLowercase = _binOcrLowercaseHeightsTotal / (double)_binOcrLowercaseHeightsTotalCount * 1.5;
var averageUppercase = _binOcrUppercaseHeightsTotal / (double)_binOcrUppercaseHeightsTotalCount * 1.3;
if (_binOcrLowercaseHeightsTotalCount > 2 &&
_binOcrUppercaseHeightsTotalCount > 2 &&
Math.Abs(averageLowercase - targetItem.NikseBitmap.Height) >
Math.Abs(averageUppercase - targetItem.NikseBitmap.Height))
{
result.Text = result.Text.ToUpperInvariant();
}
}
}
internal CompareMatch GetNOcrCompareMatchNew(ImageSplitterItem targetItem, NikseBitmap parentBitmap, NOcrDb nOcrDb, bool tryItalicScaling, bool deepSeek)
internal CompareMatch GetNOcrCompareMatchNew(ImageSplitterItem targetItem, NikseBitmap parentBitmap, NOcrDb nOcrDb, bool tryItalicScaling, bool deepSeek, int index, List<ImageSplitterItem> list)
{
deepSeek = true;
var expandedResult = nOcrDb.GetMatchExpanded(parentBitmap, targetItem);
var expandedResult = nOcrDb.GetMatchExpanded(parentBitmap, targetItem, index, list);
if (expandedResult != null)
{
return new CompareMatch(expandedResult.Text, expandedResult.Italic, expandedResult.ExpandCount, null, expandedResult) { ImageSplitterItem = targetItem };
@ -3608,7 +3638,7 @@ namespace Nikse.SubtitleEdit.Forms.Ocr
{
if (_nOcrDb != null && _nOcrDb.OcrCharacters.Count > 0)
{
match = GetNOcrCompareMatchNew(item, parentBitmap, _nOcrDb, true, true);
match = GetNOcrCompareMatchNew(item, parentBitmap, _nOcrDb, true, true, index, list);
}
}
@ -3904,7 +3934,7 @@ namespace Nikse.SubtitleEdit.Forms.Ocr
item.Y += nbmp.CropTopTransparent(0);
nbmp.CropTransparentSidesAndBottom(0, true);
nbmp.ReplaceTransparentWith(Color.Black);
GetNOcrCompareMatchNew(item, nikseBitmap, _nOcrDb, false, false);
GetNOcrCompareMatchNew(item, nikseBitmap, _nOcrDb, false, false, list.IndexOf(item), list);
}
}
}
@ -3930,7 +3960,7 @@ namespace Nikse.SubtitleEdit.Forms.Ocr
}
var list = NikseBitmapImageSplitter.SplitBitmapToLettersNew(nbmpInput, (int)numericUpDownNumberOfPixelsIsSpaceNOCR.Value, checkBoxRightToLeft.Checked, Configuration.Settings.VobSubOcr.TopToBottom, minLineHeight);
foreach (ImageSplitterItem item in list)
foreach (var item in list)
{
item.NikseBitmap?.ReplaceTransparentWith(Color.Black);
}
@ -4005,7 +4035,7 @@ namespace Nikse.SubtitleEdit.Forms.Ocr
}
else
{
var match = GetNOcrCompareMatchNew(item, nbmpInput, _nOcrDb, checkBoxNOcrItalic.Checked, !checkBoxNOcrCorrect.Checked);
var match = GetNOcrCompareMatchNew(item, nbmpInput, _nOcrDb, checkBoxNOcrItalic.Checked, !checkBoxNOcrCorrect.Checked, index, list);
if (match == null)
{
_vobSubOcrNOcrCharacter.Initialize(bitmap, item, _manualOcrDialogPosition, _italicCheckedLast, false, string.Empty);
@ -8251,6 +8281,13 @@ namespace Nikse.SubtitleEdit.Forms.Ocr
{
Cursor = Cursors.WaitCursor;
SaveNOcrWithCurrentLanguage();
_nOcrDb.LoadOcrCharacters();
Cursor = Cursors.Default;
}
else
{
Cursor = Cursors.WaitCursor;
_nOcrDb.LoadOcrCharacters();
Cursor = Cursors.Default;
}

View File

@ -87,7 +87,7 @@ namespace Nikse.SubtitleEdit.Logic.Ocr
}
}
public NOcrChar GetMatchExpanded(NikseBitmap nikseBitmap, ImageSplitterItem targetItem)
public NOcrChar GetMatchExpanded(NikseBitmap nikseBitmap, ImageSplitterItem targetItem, int listIndex, List<ImageSplitterItem> list)
{
int w = targetItem.NikseBitmap.Width;
for (var i = 0; i < OcrCharactersExpanded.Count; i++)
@ -97,125 +97,131 @@ namespace Nikse.SubtitleEdit.Logic.Ocr
{
bool ok = true;
var index = 0;
if (true)
while (index < oc.LinesForeground.Count && ok)
{
while (index < oc.LinesForeground.Count && ok)
var op = oc.LinesForeground[index];
foreach (var point in op.GetPoints())
{
var op = oc.LinesForeground[index];
foreach (var point in op.GetPoints())
var p = new Point(point.X + targetItem.X, point.Y + targetItem.Y);
if (p.X >= 0 && p.Y >= 0 && p.X < nikseBitmap.Width && p.Y < nikseBitmap.Height)
{
var p = new Point(point.X + targetItem.X, point.Y + targetItem.Y);
if (p.X >= 0 && p.Y >= 0 && p.X < nikseBitmap.Width && p.Y < nikseBitmap.Height)
{
var c = nikseBitmap.GetPixel(p.X, p.Y);
if (c.A <= 150 || c.R + c.G + c.B <= VobSubOcr.NocrMinColor)
{
ok = false;
break;
}
}
else if (p.X >= 0 && p.Y >= 0)
var c = nikseBitmap.GetPixel(p.X, p.Y);
if (c.A <= 150 || c.R + c.G + c.B <= VobSubOcr.NocrMinColor)
{
ok = false;
break;
}
}
index++;
else if (p.X >= 0 && p.Y >= 0)
{
ok = false;
break;
}
}
index = 0;
while (index < oc.LinesBackground.Count && ok)
index++;
}
index = 0;
while (index < oc.LinesBackground.Count && ok)
{
var op = oc.LinesBackground[index];
foreach (var point in op.GetPoints())
{
var op = oc.LinesBackground[index];
foreach (var point in op.GetPoints())
var p = new Point(point.X + targetItem.X, point.Y + targetItem.Y);
if (p.X >= 0 && p.Y >= 0 && p.X < nikseBitmap.Width && p.Y < nikseBitmap.Height)
{
var p = new Point(point.X + targetItem.X, point.Y + targetItem.Y);
if (p.X >= 0 && p.Y >= 0 && p.X < nikseBitmap.Width && p.Y < nikseBitmap.Height)
{
var c = nikseBitmap.GetPixel(p.X, p.Y);
if (c.A > 150 && c.R + c.G + c.B > VobSubOcr.NocrMinColor)
{
ok = false;
break;
}
}
else if (p.X >= 0 && p.Y >= 0)
var c = nikseBitmap.GetPixel(p.X, p.Y);
if (c.A > 150 && c.R + c.G + c.B > VobSubOcr.NocrMinColor)
{
ok = false;
break;
}
}
index++;
else if (p.X >= 0 && p.Y >= 0)
{
ok = false;
break;
}
}
if (ok)
index++;
}
if (ok)
{
var size = GetTotalSize(listIndex, list, oc.ExpandCount);
if (Math.Abs(size.X - oc.Width) < 3 && Math.Abs(size.Y - oc.Height) < 3)
{
return oc;
}
}
}
}
// double widthPercent = targetItem.NikseBitmap.Height * 100.0 / targetItem.NikseBitmap.Width;
if (true) //Math.Abs(oc.WidthPercent - widthPercent) < 15)
for (var i = 0; i < OcrCharactersExpanded.Count; i++)
{
var oc = OcrCharactersExpanded[i];
if (oc.ExpandCount > 1 && oc.Width > w && targetItem.X + oc.Width < nikseBitmap.Width)
{
bool ok = true;
var index = 0;
while (index < oc.LinesForeground.Count && ok)
{
ok = true;
index = 0;
while (index < oc.LinesForeground.Count && ok)
var op = oc.LinesForeground[index];
foreach (var point in op.ScaledGetPoints(oc, oc.Width, oc.Height - 1))
{
var op = oc.LinesForeground[index];
foreach (var point in op.ScaledGetPoints(oc, oc.Width, oc.Height - 1))
var p = new Point(point.X + targetItem.X, point.Y + targetItem.Y);
if (p.X >= 0 && p.Y >= 0 && p.X < nikseBitmap.Width && p.Y < nikseBitmap.Height)
{
var p = new Point(point.X + targetItem.X, point.Y + targetItem.Y);
if (p.X >= 0 && p.Y >= 0 && p.X < nikseBitmap.Width && p.Y < nikseBitmap.Height)
{
var c = nikseBitmap.GetPixel(p.X, p.Y);
if (c.A <= 150 || c.R + c.G + c.B <= VobSubOcr.NocrMinColor)
{
ok = false;
break;
}
}
else if (p.X >= 0 && p.Y >= 0)
var c = nikseBitmap.GetPixel(p.X, p.Y);
if (c.A <= 150 || c.R + c.G + c.B <= VobSubOcr.NocrMinColor)
{
ok = false;
break;
}
}
index++;
else if (p.X >= 0 && p.Y >= 0)
{
ok = false;
break;
}
}
index = 0;
while (index < oc.LinesBackground.Count && ok)
index++;
}
index = 0;
while (index < oc.LinesBackground.Count && ok)
{
var op = oc.LinesBackground[index];
foreach (var point in op.ScaledGetPoints(oc, oc.Width, oc.Height - 1))
{
var op = oc.LinesBackground[index];
foreach (var point in op.ScaledGetPoints(oc, oc.Width, oc.Height - 1))
var p = new Point(point.X + targetItem.X, point.Y + targetItem.Y);
if (p.X >= 0 && p.Y >= 0 && p.X < nikseBitmap.Width && p.Y < nikseBitmap.Height)
{
var p = new Point(point.X + targetItem.X, point.Y + targetItem.Y);
if (p.X >= 0 && p.Y >= 0 && p.X < nikseBitmap.Width && p.Y < nikseBitmap.Height)
{
var c = nikseBitmap.GetPixel(p.X, p.Y);
if (c.A > 150 && c.R + c.G + c.B > VobSubOcr.NocrMinColor)
{
ok = false;
break;
}
}
else if (p.X >= 0 && p.Y >= 0)
var c = nikseBitmap.GetPixel(p.X, p.Y);
if (c.A > 150 && c.R + c.G + c.B > VobSubOcr.NocrMinColor)
{
ok = false;
break;
}
}
index++;
else if (p.X >= 0 && p.Y >= 0)
{
ok = false;
break;
}
}
if (ok)
index++;
}
if (ok)
{
var size = GetTotalSize(listIndex, list, oc.ExpandCount);
var widthPercent = size.Y * 100.0 / size.X;
if (Math.Abs(widthPercent - oc.WidthPercent) < 15)
{
return oc;
}
@ -226,6 +232,45 @@ namespace Nikse.SubtitleEdit.Logic.Ocr
return null;
}
private static Point GetTotalSize(int listIndex, List<ImageSplitterItem> items, int count)
{
if (listIndex + count >= items.Count)
{
return new Point(-100, -100);
}
var minimumX = int.MaxValue;
int maximumX = int.MinValue;
int minimumY = int.MaxValue;
int maximumY = int.MinValue;
for (var idx = listIndex; idx < listIndex + count; idx++)
{
var item = items[idx];
if (item.Y < minimumY)
{
minimumY = item.Y;
}
if (item.Y + item.NikseBitmap.Height > maximumY)
{
maximumY = item.Y + item.NikseBitmap.Height;
}
if (item.X < minimumX)
{
minimumX = item.X;
}
if (item.X + item.NikseBitmap.Width > maximumX)
{
maximumX = item.X + item.NikseBitmap.Width;
}
}
return new Point(maximumX - minimumX, maximumY - minimumY);
}
public NOcrChar GetMatch(NikseBitmap bitmap, int topMargin, bool deepSeek, bool italic, double italicAngle, int maxWrongPixels)
{
// only very very accurate matches