涂涂乐的详细实现之四--unity3d调用EmguCV实现图片识别

涂涂乐严格来说有两个版本,一种是前面详细介绍过的,鼠标控制画图截图发送给服务端实现模型上色;另一种是通过实物图彩笔绘图之后通过扫描仪生成图片发送给服务端来实现模型上色。

动物模型有多种,贴图有多种,在画板的版本中,我们可以通过图片名称来识别图片来给具体的模型上色;但在扫描仪的版本中,我们无法确定图片名称,因此我们需要一种方法实现图片的识别。基本思路是在实物图的右下角印制不同字母,通过识别字母来确定图片。接下来的问题就在于如何识别图片上的字母了。

我最初的想法是写一个简单的算法来比较图片右下角来实现,但考虑到诸多原因(分辨率;扫描仪不能完全正确扫描图片位置等)只好放弃寻找其它方法,最终发现了EmguCV,在官方OCR的案例中找到了可以完全实现识别图片上字母的功能。然而新的问题是貌似几乎没有人使用unity来调用Emgu,在配置unity的过程中出现了一些问题,基本过程就是在unity的project中新建一个plugins文件夹添加了几十个.dll文件。然后在buildingsetting中的optimiza中将.net设为2.0。

在官方的案例中,我们只需获得图片路径调用一个函数就搞定了。在我要实现的功能中,客户端检测文件夹发送图片到服务端,服务端得到的是byte[],这里是这步之后的操作。

using UnityEngine;
using System.Collections;
using Emgu.CV;
using Emgu.CV.OCR;
using Emgu.CV.Util;
using Emgu.CV.UI;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using System.Runtime.InteropServices;
using System;
using System.Drawing;
using System.IO;

public class EmguTest : MonoBehaviour
{
    private Tesseract _ocr;
    
    void Start()
    {
       
    }
    public static  void GetBytes(byte[] bytes)
    {
        string LetterPath;
        //LetterPath = Application.dataPath + "/ServerGet/Letter";
        LetterPath = Directory.GetParent(Application.dataPath) + "/ServerGet/Letter";
        if (!Directory.Exists(LetterPath))
        {
            Directory.CreateDirectory(LetterPath);
        }
        string filename = System.DateTime.Now.Year.ToString("0000") + System.DateTime.Now.Month.ToString("00") +
                System.DateTime.Now.Day.ToString("00") + System.DateTime.Now.Hour.ToString("00") +
                System.DateTime.Now.Minute.ToString("00") + System.DateTime.Now.Second.ToString("00") +
                UnityEngine.Random.Range(0, 9999).ToString("0000");
        FileStream file = new FileStream(LetterPath+"/"+filename+".png",FileMode.Create);
        file.Write(bytes, 0, bytes.Length);
        file.Flush();
        file.Close();
        Tesseract _ocr;

        _ocr = new Tesseract(Application.dataPath+"//tessdata", "eng", OcrEngineMode.TesseractCubeCombined);
        Image picture = new Image(LetterPath + "/" + filename + ".png");
        Bgr myWhiteColor = new Bgr(255, 0, 255);
        using (Image gray = picture.Convert())
        {
            _ocr.Recognize(gray);
            Tesseract.Character[] characters = _ocr.GetCharacters();
            foreach (Tesseract.Character c in characters)
            {
                picture.Draw(c.Region, myWhiteColor, 1);
            }
            String text = _ocr.GetText();
            Debug.Log("text:" + text);
        }
    }

}

example:对于图片

识别结果为:



除了字母q被识别成了Cl之外,其它字母都得到了正确的识别。

这样我们就可以给不同的动物图右下角标记不同字母,这样就实现了识别图片的功能。

这里顺便写一下我遇到的问题之一:我们需要的来自扫描仪的动物图应该是横向的,但扫描仪的结果是纵向的,我们得到纵向图后需要将其顺时针旋转九十度生成横向图,代码如下:

Texture2D rotateNinty(Texture2D tex)
    {
        Texture2D TextureRotate = new Texture2D(tex.height, tex.width);
        for (int widthi = 0; widthi < tex.width; widthi++)
            for (int heighti = 0; heighti < tex.height; heighti++)
            {

                int a = widthi;
                int b = heighti;
                int m = StartTexture[0].width / 2;
                int n = StartTexture[0].height / 2;
                TextureRotate.SetPixel(b - n + m, m - a + n, tex.GetPixel(widthi, heighti));
            }
        TextureRotate.Apply();
        return TextureRotate;
    }
实际上解决的问题是,平面上任一点绕指定点旋转一定角度的算法。

平面上一点(a,b)绕(m,n)顺时针旋转九十度后的坐标为(b-n+m,m-a+n)。用两个for循环为整个Texture的每一个像素点设置相应位置来得到新的Texture,接下来才是截取右下角的字母格,最后应用EmguCV识别字母。









你可能感兴趣的:(unity3d)