1

解决方案必须是通用的(使用不同的字体和颜色)并且稳定。

输入数据是带有 X、Y 坐标的点,输出数据是矩形或更复杂的形状,其中包含单词或短语。

带有输入点(红色)和输出矩形(蓝色)的图像

现在我使用hocr选项对整个图像进行 tesseract 识别,然后从输出 html 中提取所有矩形,最后找到最接近点的 reactangle。代码如下所示。但它效率低下,因为整个图像识别。

当然,可以识别不是整个图像,而是部分图像,但这也不是一个明确的解决方案,因为不同的字体大小和无用的单词识别都是一样的。

更新

public class WordRecognizerTesseractHocr
{
    const string HelperFileName = "temp";

    public string NextVariant()
    {
        Bitmap.Save(HelperFileName + ".png", ImageFormat.Png);
        var startInfo = new ProcessStartInfo("tesseract.exe", HelperFileName + ".png temp hocr");
        startInfo.WindowStyle = ProcessWindowStyle.Hidden;
        var process = Process.Start(startInfo);
        process.WaitForExit();

        var result = GetNearestWord(File.ReadAllText(HelperFileName + ".html"), Position);

        return result;
    }

    public string GetNearestWord(string tesseractHtml, Point position)
    {
        var xml = XDocument.Parse(tesseractHtml);

        RectsWords = new Dictionary<Rectangle, string>();

        var ocr_words = xml.Descendants("span").Where(element => element.Attribute("class").Value == "ocr_word").ToList();
        foreach (var ocr_word in ocr_words)
        {
            var strs = ocr_word.Attribute("title").Value.Split(' ');
            int left = int.Parse(strs[1]);
            int top = int.Parse(strs[2]);
            int width = int.Parse(strs[3]) - left + 1;
            int height = int.Parse(strs[4]) - top + 1;
            RectsWords.Add(new Rectangle(left, top, width, height), ocr_word.Value);
        }

        var nearestWords = RectsWords.OrderBy(rectWord => Distance(position, rectWord.Key));

        return nearestWords.Count() != 0 ? nearestWords.First().Value : string.Empty;
    }

    public static double Distance(Point pos, Rectangle rect)
    {
        if (pos.X < rect.Left)
        {
            if (pos.Y < rect.Top)
                return Math.Sqrt((rect.X - pos.X) * (rect.X - pos.X) + (rect.Top - pos.Y) * (rect.Top - pos.Y));
            else if (pos.Y < rect.Top + rect.Height)
                return rect.Left - pos.X;
            else
                return Math.Sqrt((rect.X - pos.X) * (rect.X - pos.X) + 
                    (rect.Top + rect.Height - 1 - pos.Y) * (rect.Top + rect.Height - 1 - pos.Y));
        }
        else if (pos.X < rect.Left + rect.Width)
        {
            if (pos.Y < rect.Top)
                return rect.Top - pos.Y;
            else if (pos.Y < rect.Top + rect.Height)
                return 0;
            else
                return pos.Y - (rect.Top + rect.Height - 1);
        }
        else
        {
            if (pos.Y < rect.Top)
                return Math.Sqrt((rect.X + rect.Width - 1 - pos.X) * (rect.X + rect.Width - 1 - pos.X) + 
                    (rect.Top - pos.Y) * (rect.Top - pos.Y));
            else if (pos.Y < rect.Top + rect.Height)
                return pos.X - (rect.Left + rect.Width - 1);
            else
                return Math.Sqrt((rect.X + rect.Width - 1 - pos.X) * (rect.X + rect.Width - 1 - pos.X) +
                    (rect.Top + rect.Height - 1 - pos.Y) * (rect.Top + rect.Height - 1 - pos.Y));
        }
    }

    public IDictionary<Rectangle, string> RectsWords
    {
        get;
        protected set;
    }
}
4

1 回答 1

1

这是可能有用的东西。它应该很快,但很容易被噪音伤害。

首先获取文本的歪斜图像,以您最容易使用的任何格式。

接下来,在 x,y 中获取您关心的点。

从 y 坐标开始,上下查看完整的行,直到看到几个完全空的行。这些将为您指定的点标记文本行的顶部和底部。这些是 y 中矩形一词的边界。

对 x 重复相同的操作,但查找列以获取 x 中单词矩形的边界。

现在你应该有整个词的界限,你可以很容易地从中得到这个词。

于 2012-09-17T14:36:41.983 回答