Skip to content

Instantly share code, notes, and snippets.

@synctam
Last active August 13, 2020 12:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save synctam/1345430efe0fae1cd6f86fa7d076c543 to your computer and use it in GitHub Desktop.
Save synctam/1345430efe0fae1cd6f86fa7d076c543 to your computer and use it in GitHub Desktop.
OpenCVで輪郭検出を行いテキスト領域を抽出するサンプル。 This program is released under the MIT license.
namespace LibTextDetector.TextDetector
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Emgu.CV;
using Emgu.CV.Structure;
public class GcaTextDetector
{
/// <summary>
/// 指定した画像からテキスト領域のリストを返す。
/// (輪郭検出を利用しテキスト領域を抽出)
/// </summary>
/// <param name="img">画像</param>
/// <returns>テキスト領域のリスト</returns>
public static List<Rectangle> DetectText(Image<Bgr, byte> img)
{
//// sobel(エッジ抽出)
Image<Gray, byte> sobel =
img
.Convert<Gray, byte>()
.Sobel(1, 0, 3)
.AbsDiff(new Gray(0.0))
.Convert<Gray, byte>()
.ThresholdBinary(new Gray(100), new Gray(255));
////
Mat se = CvInvoke.GetStructuringElement(
Emgu.CV.CvEnum.ElementShape.Rectangle,
new Size(10, 2),
new Point(-1, -1));
////
sobel = sobel.MorphologyEx(
Emgu.CV.CvEnum.MorphOp.Dilate,
se,
new Point(-1, -1),
1,
Emgu.CV.CvEnum.BorderType.Reflect,
new MCvScalar(255));
//// 輪郭検出
var contours = new Emgu.CV.Util.VectorOfVectorOfPoint();
var m = new Mat();
CvInvoke.FindContours(
sobel,
contours,
m,
Emgu.CV.CvEnum.RetrType.External,
Emgu.CV.CvEnum.ChainApproxMethod.ChainApproxSimple);
//// テキストラインの矩形領域のリスト
var list = new List<Rectangle>();
for (int i = 0; i < contours.Size; i++)
{
var brect = CvInvoke.BoundingRectangle(contours[i]);
//// 矩形領域を条件に従い抽出する
double ar = brect.Width / brect.Height;
if (ar > 2 && brect.Width > 25 && brect.Height > 5 && brect.Height < 100)
{
//// 領域の縦横比が1:2。2文字以上?
//// 領域の幅が > 25 pixel
//// 5 pixel < 領域の高さ < 100
list.Add(brect);
}
}
//// X > Y でソート
IOrderedEnumerable<Rectangle> sortList = list.OrderBy(rec => rec.Y).ThenBy(rec => rec.X);
List<Rectangle> result = new List<Rectangle>();
foreach (var aaa in sortList)
{
result.Add(aaa);
}
return result;
}
}
}
namespace LibTextDetector.TextDetector
{
using Emgu.CV;
using Emgu.CV.Structure;
using LibTextDetector.Ocr;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
public class GcaVideoEffector
{
public static List<string> GetImageToTexts(string imagePath, string outImagePath)
{
Image<Bgr, byte> img = new Image<Bgr, byte>(imagePath);
var regions = GcaTextDetector.DetectText(img);
var ocr = new GcaOcr();
var result = ocr.GetText(img, regions);
var outImage = TextDetectedImage(img, regions);
outImage.Save(outImagePath);
return result;
}
public static double Process(string inputVideoPath, string outputVideoPath)
{
Stopwatch sw = new Stopwatch();
double max = 0.0f;
//// @"data\Eschalon_ Book I_001.mp4"
var capture = new VideoCapture(inputVideoPath);
var fps = capture.GetCaptureProperty(Emgu.CV.CvEnum.CapProp.Fps);
System.Drawing.Size size = new System.Drawing.Size(capture.Width, capture.Height);
int fourcc = VideoWriter.Fourcc('H', '2', '6', '4');
Backend[] backends = CvInvoke.WriterBackends;
int backend_idx = 0;
foreach (Backend be in backends)
{
if (be.Name.Equals("MSMF"))
{
backend_idx = be.ID;
break;
}
}
var writer = new VideoWriter(outputVideoPath, backend_idx, fourcc, fps, size, true);
var ocr = new GcaOcr();
try
{
while (true)
{
var m = new Mat();
capture.Read(m);
if (!m.IsEmpty)
{
var img = m.ToImage<Bgr, byte>();
sw.Start();
var regions = GcaTextDetector.DetectText(img);
sw.Stop();
max = Math.Max(max, sw.ElapsedMilliseconds);
sw.Reset();
List<string> textList = ocr.GetText(img, regions);
Image<Bgr, byte> imgout = img.CopyBlank();
foreach (var r in regions)
{
CvInvoke.Rectangle(img, r, new MCvScalar(0, 0, 255), 2);
CvInvoke.Rectangle(imgout, r, new MCvScalar(0, 255, 255), -1);
}
imgout._And(img);
writer.Write(img.Mat);
}
else
{
break;
}
}
}
finally
{
writer.Dispose();
}
return max;
}
/// <summary>
/// テキスト検出結果のイメージを返す。
/// </summary>
/// <param name="img">元イメージ</param>
/// <param name="regions">テキスト領域のリスト</param>
/// <returns>テキスト検出結果のイメージ</returns>
private static Image<Bgr, byte> TextDetectedImage(Image<Bgr, byte> img, List<Rectangle> regions)
{
Image<Bgr, byte> imgout = img.CopyBlank();
foreach (var r in regions)
{
CvInvoke.Rectangle(img, r, new MCvScalar(0, 0, 255), 2);
CvInvoke.Rectangle(imgout, r, new MCvScalar(0, 255, 255), -1);
}
imgout._And(img);
return imgout;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment