Tesseract5でOCRを試してみたところ、傾いている文字を全く認識しなかったので、
OCRをかける前に文字の傾きを水平補正しようと思ったのだった。
■ 事前作業
NuGetパッケージマネージャーでOpenCvSharp4.Windowsをインストールします。
OpenCvSharp.Extensionsも同時にインストールされます。
■ 留意点
読み取る画像に直線が含まれている必要があります。
C#
using OpenCvSharp;
using OpenCvSharp.Extensions;
private Bitmap tiltPicture(Bitmap img_src)
{
// 画像の読み込み
//Mat img = Cv2.ImRead(@"c:\temp\naname.png");
Mat img = BitmapConverter.ToMat(img_src);
// モノクロ・グレースケール画像へ変換
Mat imgGray = new Mat();
Cv2.CvtColor(img, imgGray, ColorConversionCodes.BGR2GRAY);
// エッジ検出
Mat edges = new Mat();
Cv2.Canny(imgGray, edges, 50, 150, 3);
// 直線検出
LineSegmentPoint[] lines = Cv2.HoughLinesP(edges, 1, Math.PI / 180, 100, 100, 10);
// 直線の角度を計算
double[] angles = new double[lines.Length];
for (int i = 0; i < lines.Length; i++)
{
LineSegmentPoint line = lines[i];
double medianAngle = Math.Atan2(line.P2.Y - line.P1.Y, line.P2.X - line.P1.X) * 180.0 / Math.PI;
angles[i] = medianAngle;
}
// 直線の角度の中央値を計算
double angle = CalculateMedian(angles);
// アフィン変換を適用してスキュー角度を修正
(int h, int w) = (img.Rows, img.Cols);
Point2f center = new Point2f(w / 2f, h / 2f);
Mat rotationMatrix = Cv2.GetRotationMatrix2D(center, angle, 1.0);
Mat rotateImg = new Mat();
Cv2.WarpAffine(img, rotateImg, rotationMatrix, new OpenCvSharp.Size(w, h), flags: InterpolationFlags.Cubic, borderMode: BorderTypes.Replicate);
Bitmap bitmap = BitmapConverter.ToBitmap(rotateImg);
// プログラムを終了する前に解放する
img.Release();
imgGray.Release();
edges.Release();
rotateImg.Release();
return bitmap;
}
/// <summary>
/// 直線の角度の中央値を計算
/// </summary>
/// <param name="values"></param>
/// <returns>中央値</returns>
static double CalculateMedian(double[] values)
{
Array.Sort(values);
int length = values.Length;
if (length % 2 == 0)
{
// 偶数の場合は中央の2つの値の平均を取る
int midIndex1 = length / 2 - 1;
int midIndex2 = length / 2;
return (values[midIndex1] + values[midIndex2]) / 2.0;
}
else
{
// 奇数の場合は中央の値をそのまま返す
int midIndex = length / 2;
return values[midIndex];
}
}