精华内容
下载资源
问答
  • 下载手写功能中文手写
    2021-12-14 09:24:31

    在如今这个时代,对这个功能的需求量可能已经很少了,但是这也不妨碍我们或多或少的会碰到一些稀奇古怪的需求,多接触一些总归是没错的。

    本篇主要是用到了Microsoft.Ink来实现一个手写输入,也就是类似于手机输入法中的手写功能。

    实现功能:

    用鼠标或者手指在屏幕上写字并识别输入到文本框

    开发环境:

    开发工具: Visual Studio 2013

    .NET Framework版本:4.5

    实现代码:

     

    InkCollector ink;
    RecognizerContext recogn;
    public inputFrm()
    {
        InitializeComponent();
        Control.ControlCollection btnList = panel3.Controls;
        foreach (Control c in btnList)
        {
            (c as Button).Click += (s, e) =>
            {
                if (textBox1.Text.Length > 0)
                {
                    int intStart = textBox1.SelectionStart;
                    textBox1.Text = textBox1.Text.Remove(intStart - 1, 1);
                    textBox1.Text = textBox1.Text.Insert(intStart - 1, (s as Button).Text);
                    textBox1.SelectionStart = intStart;
                }
            };
        }
    }
    
    private void inputFrm_Load(object sender, EventArgs e)
    {
        //创建笔画采集器
        ink = new InkCollector(picText.Handle);
        ink.Enabled = true;
        ink.Stroke += new InkCollectorStrokeEventHandler((s, e1) =>
        {
            recogn.StopBackgroundRecognition();
            recogn.Strokes.Add(e1.Stroke);
            recogn.BackgroundRecognizeWithAlternates(0);
        });
    
    
    
        //创建识别器
        Recognizers recs = new Recognizers();
        Recognizer rec = recs.GetDefaultRecognizer();
        recogn = rec.CreateRecognizerContext();
        recogn.RecognitionFlags = RecognitionModes.WordMode;
        recogn.Strokes = ink.Ink.Strokes;
        recogn.RecognitionWithAlternates += new RecognizerContextRecognitionWithAlternatesEventHandler((s, e1) =>
        {
            string result = "";
            RecognitionAlternates alts;
            if (e1.RecognitionStatus == RecognitionStatus.NoError)
            {
                alts = e1.Result.GetAlternatesFromSelection();
                foreach (RecognitionAlternate alt in alts)
                {
                    result += alt.ToString() + " ";
                }
            }
            result = result.Trim();
            Control.CheckForIllegalCrossThreadCalls = false;
    
            string[] arr = result.Split(' ');
            for (int i = 0; i < arr.Length; i++)
            {
                string str = "btnSelect_" + (i + 1);
                Control btn = panel3.Controls.Find(str, false).First();
                btn.Text = arr[i];
            }
    
            Control.CheckForIllegalCrossThreadCalls = true;
    
        });
    
    }
    
    private void picText_MouseUp(object sender, MouseEventArgs e)
    {
        timer1.Enabled = true;
    }
    
    private void picText_MouseDown(object sender, MouseEventArgs e)
    {
        timer1.Enabled = false;
    }
    
    private void timer1_Tick(object sender, EventArgs e)
    {
        Write();
        if (!ink.CollectingInk)
        {
            Strokes strokesToDelete = ink.Ink.Strokes;
            recogn.StopBackgroundRecognition();
            ink.Ink.DeleteStrokes(strokesToDelete);
            recogn.Strokes = ink.Ink.Strokes;
            ink.Ink.DeleteStrokes();
            picText.Refresh();
        }
        timer1.Stop();
    }
    
    private void Write()
    {
        List<Point> lstPoints = new List<Point>();
        foreach (var stroke in ink.Ink.Strokes)
        {
            lstPoints.AddRange(stroke.GetPoints());
        }
        ink.Ink.DeleteStrokes();
        Stroke sk = ink.Ink.CreateStroke(lstPoints.ToArray());
        recogn.Strokes.Add(sk);
        textBox1.SelectedText = ink.Ink.Strokes.ToString();
    }
    
    private void btnDel_Click(object sender, EventArgs e)
    {
        if (!string.IsNullOrEmpty(textBox1.Text))
            textBox1.Text = textBox1.Text.Substring(0, textBox1.Text.Length - 1);
    }
    private void btnClear_Click(object sender, EventArgs e)
    {
        if (!ink.CollectingInk)
        {
            Strokes strokesToDelete = ink.Ink.Strokes;
            recogn.StopBackgroundRecognition();
            ink.Ink.DeleteStrokes(strokesToDelete);
            recogn.Strokes = ink.Ink.Strokes;
            ink.Ink.DeleteStrokes();
            picText.Refresh();
            textBox1.Clear();
        }
    }

    实现效果:

    最后附上一个关于Microsoft.Ink的API说明文档:Microsoft.Ink Namespace () | Microsoft Docs,以方便大家更加详细的了解以及使用。

    由简入繁,拿来即用

    更多精彩,请关注微信公众号:

     

    更多相关内容
  • ziddo紫貂手写板驱动是适用于该手写板使用的一款驱动程序,安装驱动后可将手写板连接电脑,手写板...ziddo紫貂手写板介绍紫貂电脑手写板流畅迅速,软件界面操作简洁明了,功能全面。该版本驱动支持连笔书,欢迎下载体验
  • 主要为大家详细介绍了python实现基于SVM手写数字识别功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • 本资源基于VS2013开发,是利用MFC开发的输入法,支持各种终端上的嵌入使用。WIN7和WIN10 都曾自测通过,解压即用 支持词组识别 支持手写中文识别。希望能帮助到大家
  • 手写字迹识别C++代码

    2020-02-01 14:25:36
    手写识别(HandWriting Recognition)是指将在手写设备上书写时产生的有序轨迹信息化转化为汉字内码的过程,实际上是手写轨迹的坐标序列到汉字的内码的一个映射过程,是人机交互最自然、最方便的手段之一。...
  • 知识点分析:在Yoga 笔记本的超级本上带了一个触控的键盘,同时具备手写的输入功能。这时在触控屏的使用中就可以使用手写输入了。对于没有触控屏功能电脑,Win8系统的手写输入功能也可使用,可以借助鼠标指针手写输入...

    知识点分析:

    在Yoga 笔记本的超级本上带了一个触控的键盘,同时具备手写的输入功能。这时在触控屏的使用中就可以使用手写输入了。

    对于没有触控屏功能电脑,Win8系统的手写输入功能也可使用,可以借助鼠标指针手写输入。

    操作步骤:

    在桌面界面下,右下角会有些图标,点开后出现屏幕触控键盘;

    145191

    如果是Metro界面从右侧滑出“超级按钮”,选“设置”,点“键盘”后显示有“触摸键盘和手写面板”;

    145191

    以上两个地方可以打开以下界面。这就是屏幕触控键盘。在此键盘的右下角再点出键盘的模式。其中笔和图标表示是手写。

    145191

    手写输入界面

    145191

    选择“所有文字”以后,输入中文、英文均可自动识别。注意每格一字。横向划过多个输入区域即清空所写,重新输入。

    145191

    备注:

    涉及机型:

    V4400U;Z400 TOUCH;G400S TOUCH;S400 TOUCH;U430 TOUCH;Flex 14;YOGA11;Z500 TOUCH;G500S TOUCH;S210 TOUCH;U330 TOUCH;Flex 15;YOGA13;Z410 TOUCH;G510S TOUCH;S500 TOUCH;U310 TOUCH;YOGA11S;Z510 TOUCH;G505S TOUCH;S310 TOUCH;U410 TOUCH;;Z501 CH;G410STOUCH;S410TOUCH;U530TOUCH;;Z505 TOUCH;G405S TOUCH;S415 TOUCH;S410P TOUCH;;;S510P TOUCH;

    展开全文
  • 结合实例,介绍采用ePH1200、电阻式触摸屏和微控制器(MSP430)实现汉字手写输入的硬件接口电路与软件编程方法。关键词手写体辨识触摸屏ePH1200辨识芯片 许多的掌上装置与移动设备采用小型嵌入式系统,而这些装置很...
  • 清华同方手写板通用驱动是一款非常实用的手写板驱动软件,它能让你在手写板上书写的字体变的更加清晰,还能智能调节分辨度,让文字产生各种奇妙的变化,还有更多功能就等你来体验,需要的用户就下载使用吧!...
  • 本次设计要实现的目标就是建立一个图像处理识别的平台,使手写汉字以图像文件格式(BMP)的形式输入FPGA,提取出其特征向量,通过分类识别,转换为汉字文本。我们需要设计和实现脱机手写汉字识别系统,主要实现样本...
  • 主要介绍了vue 使用 canvas 实现手写电子签名功能,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
  • 基于卷积神经网络的手写字体识别,可较为准确识别手写汉字、数字,英文字符 具备手写功能(Matlab 2018 开发,其余版本兼容性未知)
  • 君彩2010版djj8手写板驱动是配合大将军8设备使用的驱动软件。安装后可以智能识别繁体字、连笔字等潦草的字体。...软件介绍君彩2010版DJJ-8手写板驱动,大将军第八代手写板,大将军中文输入系统,让你手,欢迎下载体验
  • iOS 手写汉字,文字转语音,专注力训练功能实现 下载地址https://apps.apple.com/cn/app/%E9%9A%8F%E8%AE%B0%E5%AD%A6%E6%B1%89%E5%AD%97/id1556386282 开放源码
  • 君彩2009手写板驱动是一款适用于君彩2009、君彩2010、君彩djj-6-7-8手写板的万能通用驱动,有了这款驱动程序让你...功能介绍1、繁简合一辨认核心:可辨认繁简体中文23000多字、香港4702字、英文、数字、符,欢迎下载体验
  • TensorFlow 2.0 中文手写字识别(汉字OCR)在开始之前,必须要说明的是,本教程完全基于TensorFlow2.0 接口编写,请误与其他古老的教程混为一谈,本教程除了手把手教大家完成这个挑战性任务之外,更多的会教大家如何...

    TensorFlow 2.0 中文手写字识别(汉字OCR)在开始之前,必须要说明的是,本教程完全基于TensorFlow2.0 接口编写,请误与其他古老的教程混为一谈,本教程除了手把手教大家完成这个挑战性任务之外,更多的会教大家如何分析整个调参过程的思考过程,力求把人工智能算法工程师日常的工作通过这个例子毫无保留的展示给大家。另外,我们建立了一个高端算法分享平台,希望得到大家的支持:http://manaai.cn , 也欢迎大家来我们的AI社区交流: http://talk.strangeai.pro

    还在玩minist?fashionmnist?不如来尝试一下类别多大3000+的汉字手写识别吧!!虽然以前有一些文章教大家如何操作,但是大多比较古老,这篇文章将用全新的TensorFlow 2.0 来教大家如何搭建一个中文OCR系统!

    让我们来看一下,相比于简单minist识别,汉字识别具有哪些难点:搜索空间空前巨大,我们使用的数据集1.0版本汉字就多大3755个,如果加上1.1版本一起,总共汉字可以分为多达7599+个类别!这比10个阿拉伯字母识别难度大很多!

    数据集处理挑战更大,相比于mnist和fasionmnist来说,汉字手写字体识别数据集非常少,而且仅有的数据集数据预处理难度非常大,非常不直观,但是,千万别吓到,相信你看完本教程一定会收货满满!

    汉字识别更考验选手的建模能力,还在分类花?分类猫和狗?随便搭建的几层在搜索空间巨大的汉字手写识别里根本不work!你现在是不是想用很深的网络跃跃欲试?更深的网络在这个任务上可能根本不可行!!看完本教程我们就可以一探究竟!总之一句话,模型太简单和太复杂都不好,甚至会发散!(想亲身体验模型训练发散抓狂的可以来尝试一下!)。

    但是,挑战这个任务也有很多好处:本教程基于TensorFlow2.0,从数据预处理,图片转Tensor以及Tensor的一系列骚操作都包含在内!做完本任务相信你会对TensorFlow2.0 API有一个很深刻的认识!

    如果你是新手,通过这个教程你完全可以深入体会一下调参(或者说随意修改网络)的纠结性和蛋疼性!

    本项目实现了基于CNN的中文手写字识别,并且采用标准的tensorflow 2.0 api 来构建!相比对简单的字母手写识别,本项目更能体现模型设计的精巧性和数据增强的熟练操作性,并且最终设计出来的模型可以直接应用于工业场合,比如 票据识别, 手写文本自动扫描 等,相比于百度api接口或者QQ接口等,具有可优化性、免费性、本地性等优点。

    数据准备

    在开始之前,先介绍一下本项目所采用的数据信息。我们的数据全部来自于CASIA的开源中文手写字数据集,该数据集分为两部分:CASIA-HWDB:离线的HWDB,我们仅仅使用1.0-1.2,这是单字的数据集,2.0-2.2是整张文本的数据集,我们暂时不用,单字里面包含了约7185个汉字以及171个英文字母、数字、标点符号等;

    CASIA-OLHWDB:在线的HWDB,格式一样,包含了约7185个汉字以及171个英文字母、数字、标点符号等,我们不用。

    其实你下载1.0的train和test差不多已经够了,可以直接运行 dataset/get_hwdb_1.0_1.1.sh 下载。原始数据下载链接点击这里.由于原始数据过于复杂,我们使用一个类来封装数据读取过程,这是我们展示的效果:

    看到这么密密麻麻的文字相信连人类都.... 开始头疼了,这些复杂的文字能够通过一个神经网络来识别出来??答案是肯定的.... 不有得感叹一下神经网络的强大。。上面的部分文字识别出来的结果是这样的:

    关于数据的处理部分,从服务器下载到的原始数据是 trn_gnt.zip 解压之后是 gnt.alz, 需要再次解压得到一个包含 gnt文件的文件夹。里面每一个gnt文件都包含了若干个汉字及其标注。直接处理比较麻烦,也不方便抽取出图片再进行操作,虽然转为图片存入文件夹比较直观,但是不适合批量读取和训练, 后面我们统一转为tfrecord进行训练。

    更新:实际上,由于单个汉字图片其实很小,差不多也就最大80x80的大小,这个大小不适合转成图片保存到本地,因此我们将hwdb原始的二进制保存为tfrecord。同时也方便后面训练,可以直接从tfrecord读取图片进行训练。

    在我们存储完成的时候大概处理了89万个汉字,总共汉字的空间是3755个汉字。由于我们暂时仅仅使用了1.0,所以还有大概3000个汉字没有加入进来,但是处理是一样。使用本仓库来生成你的tfrecord步骤如下:cd dataset && python3 convert_to_tfrecord.py, 请注意我们使用的是tf2.0;

    你需要修改对应的路径,等待生成完成,大概有89万个example,如果1.0和1.1都用,那估计得double。

    模型构建

    关于我们采用的OCR模型的构建,我们构建了3个模型分别做测试,三个模型的复杂度逐渐的复杂,网络层数逐渐深入。但是到最后发现,最复杂的那个模型竟然不收敛。这个其中一个稍微简单模型的训练过程:

    大家可以看到,准确率可以在短时间内达到87%非常不错,测试集的准确率大概在40%,由于测试集中的样本在训练集中完全没有出现,相对训练集的准确率来讲偏低。可能原因无外乎两个,一个事模型泛化性能不强,另外一个原因是训练还不够。

    不过好在这个简单的模型也能达到训练集90%的准确率,it's a good start. 让我们来看一下如何快速的构建一个OCR网络模型:

    def build_net_003(input_shape, n_classes):

    model = tf.keras.Sequential([

    layers.Conv2D(input_shape=input_shape, filters=32, kernel_size=(3, 3), strides=(1, 1),

    padding='same', activation='relu'),

    layers.MaxPool2D(pool_size=(2, 2), padding='same'),

    layers.Conv2D(filters=64, kernel_size=(3, 3), padding='same'),

    layers.MaxPool2D(pool_size=(2, 2), padding='same'),

    layers.Flatten(),

    layers.Dense(n_classes, activation='softmax')

    ])

    return model

    这是我们使用keras API构建的一个模型,它足够简单,仅仅包含两个卷积层以及两个maxpool层。下面我们让大家知道,即便是再简单的模型,有时候也能发挥出巨大的用处,对于某些特定的问题可能比更深的网络更有用途。关于这部分模型构建大家只要知道这么几点:如果你只是构建序列模型,没有太fancy的跳跃链接,你可以直接用keras.Sequential 来构建你的模型;

    Conv2D中最好指定每个参数的名字,不要省略,否则别人不知道你的写的事输入的通道数还是filters。

    最后,在你看完本篇博客后,并准备自己动手复现这个教程的时候, 可以思考一下为什么下面这个模型就发散了呢?(仅仅稍微复杂一点):

    def build_net_002(input_shape, n_classes):

    model = tf.keras.Sequential([

    layers.Conv2D(input_shape=input_shape, filters=64, kernel_size=(3, 3), strides=(1, 1),

    padding='same', activation='relu'),

    layers.MaxPool2D(pool_size=(2, 2), padding='same'),

    layers.Conv2D(filters=128, kernel_size=(3, 3), padding='same'),

    layers.MaxPool2D(pool_size=(2, 2), padding='same'),

    layers.Conv2D(filters=256, kernel_size=(3, 3), padding='same'),

    layers.MaxPool2D(pool_size=(2, 2), padding='same'),

    layers.Flatten(),

    layers.Dense(1024, activation='relu'),

    layers.Dense(n_classes, activation='softmax')

    ])

    return model

    数据输入

    其实最复杂的还是数据准备过程啊。这里着重说一下,我们的数据存入tfrecords中的事image和label,也就是这么一个example:

    example = tf.train.Example(features=tf.train.Features(

    feature={

    "label": tf.train.Feature(int64_list=tf.train.Int64List(value=[index])),

    'image': tf.train.Feature(bytes_list=tf.train.BytesList(value=[img.tobytes()])),

    'width': tf.train.Feature(int64_list=tf.train.Int64List(value=[w])),

    'height': tf.train.Feature(int64_list=tf.train.Int64List(value=[h])),

    }))

    然后读取的时候相应的读取即可,这里告诉大家几点坑爹的地方:将numpyarray的bytes存入tfrecord跟将文件的bytes直接存入tfrecord解码的方式事不同的,由于我们的图片数据不是来自于本地文件,所以我们使用了一个tobytes()方法存入的事numpy array的bytes格式,它实际上并不包含维度信息,所以这就是坑爹的地方之一,如果你不同时存储width和height,你后面读取的时候便无法知道维度,存储tfrecord顺便存储图片长宽事一个好的习惯.

    关于不同的存储方式解码的方法有坑爹的地方,比如这里我们存储numpy array的bytes,通常情况下,你很难知道如何解码。。(不看本教程应该很多人不知道)

    最后load tfrecord也就比较直观了:

    def parse_example(record):

    features = tf.io.parse_single_example(record,

    features={

    'label':

    tf.io.FixedLenFeature([], tf.int64),

    'image':

    tf.io.FixedLenFeature([], tf.string),

    })

    img = tf.io.decode_raw(features['image'], out_type=tf.uint8)

    img = tf.cast(tf.reshape(img, (64, 64)), dtype=tf.float32)

    label = tf.cast(features['label'], tf.int64)

    return {'image': img, 'label': label}

    def parse_example_v2(record):

    """latest version format:param record::return:"""

    features = tf.io.parse_single_example(record,

    features={

    'width':

    tf.io.FixedLenFeature([], tf.int64),

    'height':

    tf.io.FixedLenFeature([], tf.int64),

    'label':

    tf.io.FixedLenFeature([], tf.int64),

    'image':

    tf.io.FixedLenFeature([], tf.string),

    })

    img = tf.io.decode_raw(features['image'], out_type=tf.uint8)

    # we can not reshape since it stores with original size

    w = features['width']

    h = features['height']

    img = tf.cast(tf.reshape(img, (w, h)), dtype=tf.float32)

    label = tf.cast(features['label'], tf.int64)

    return {'image': img, 'label': label}

    def load_ds():

    input_files = ['dataset/HWDB1.1trn_gnt.tfrecord']

    ds = tf.data.TFRecordDataset(input_files)

    ds = ds.map(parse_example)

    return ds

    这个v2的版本就是兼容了新的存入长宽的方式,因为我第一次生成的时候就没有保存。。。最后入坑了。注意这行代码:

    img = tf.io.decode_raw(features['image'], out_type=tf.uint8)

    它是对raw bytes进行解码,这个解码跟从文件读取bytes存入tfrecord的有着本质的不同。同时注意type的变化,这里以unit8的方式解码,因为我们存储进去的就是uint8.

    训练过程

    不瞒你说,我一开始写了一个很复杂的模型,训练了大概一个晚上结果准确率0.00012, 发散了。后面改成了更简单的模型才收敛。整个过程的训练pipleline:

    def train():

    all_characters = load_characters()

    num_classes = len(all_characters)

    logging.info('all characters: {}'.format(num_classes))

    train_dataset = load_ds()

    train_dataset = train_dataset.shuffle(100).map(preprocess).batch(32).repeat()

    val_ds = load_val_ds()

    val_ds = val_ds.shuffle(100).map(preprocess).batch(32).repeat()

    for data in train_dataset.take(2):

    print(data)

    # init model

    model = build_net_003((64, 64, 1), num_classes)

    model.summary()

    logging.info('model loaded.')

    start_epoch = 0

    latest_ckpt = tf.train.latest_checkpoint(os.path.dirname(ckpt_path))

    if latest_ckpt:

    start_epoch = int(latest_ckpt.split('-')[1].split('.')[0])

    model.load_weights(latest_ckpt)

    logging.info('model resumed from: {}, start at epoch: {}'.format(latest_ckpt, start_epoch))

    else:

    logging.info('passing resume since weights not there. training from scratch')

    if use_keras_fit:

    model.compile(

    optimizer=tf.keras.optimizers.Adam(),

    loss=tf.keras.losses.SparseCategoricalCrossentropy(),

    metrics=['accuracy'])

    callbacks = [

    tf.keras.callbacks.ModelCheckpoint(ckpt_path,

    save_weights_only=True,

    verbose=1,

    period=500)

    ]

    try:

    model.fit(

    train_dataset,

    validation_data=val_ds,

    validation_steps=1000,

    epochs=15000,

    steps_per_epoch=1024,

    callbacks=callbacks)

    except KeyboardInterrupt:

    model.save_weights(ckpt_path.format(epoch=0))

    logging.info('keras model saved.')

    model.save_weights(ckpt_path.format(epoch=0))

    model.save(os.path.join(os.path.dirname(ckpt_path), 'cn_ocr.h5'))

    在本系列教程开篇之际,我们就立下了几条准则,其中一条就是handle everything, 从这里就能看出,它事一个很稳健的训练代码,同事也很自动化:自动寻找之前保存的最新模型;

    自动保存模型;

    捕捉ctrl + c事件保存模型。

    支持断点续训练

    大家在以后编写训练代码的时候其实可以保持这个好的习惯。

    OK,整个模型训练起来之后,可以在短时间内达到95%的准确率:

    效果还是很不错的!

    模型测试

    最后模型训练完了,时候测试一下模型效果到底咋样。我们使用了一些简单的文字来测试:

    这个字写的还真的。。。。具有鬼神之势。相信普通人类大部分字都能认出来,不过有些字还真的。。。。不好认。看看神经网络的表现怎么样!

    这是大概2000次训练的结果, 基本上能识别出来了!神经网络的认字能力还不错的! 收工!

    总结

    通过本教程,我们完成了使用tensorflow 2.0全新的API搭建一个中文汉字手写识别系统。模型基本能够实现我们想要的功能。要知道,这个模型可是在搜索空间多大3755的类别当中准确的找到最相似的类别!!通过本实验,我们有几点心得:神经网络不仅仅是在学习,它具有一定的想象力!!比如它的一些看着很像的字:拜-佯, 扮-捞,笨-苯.... 这些字如果手写出来,连人都比较难以辨认!!但是大家要知道这些字在类别上并不是相领的!也就是说,模型具有一定的联想能力!

    不管问题多复杂,要敢于动手、善于动手。

    最后希望大家对本文点个赞,编写教程不容易。希望大家多多支持。笨教程将支持为大家输出全新的tensorflow2.0教程!欢迎关注!!

    本文所有代码开源在 (如果由于git仓库定期清理原因找不到项目,参考这个平台:http://manaai.cn):

    https://github.com/jinfagang/ocrcn_tf2.git​github.com

    记得随手star哦!!

    我们的AI社区:

    奇点AI社区​talk.strangeai.pro

    全球最大的开源AI代码平台:神力AI(MANA)-国内最大的AI代码平台​manaai.cn

    展开全文
  • 原标题:中文简历表格提取,手写汉字识别(Python+OpenCV)所有代码获取:简历网上对表格框的提取的相关资料较少,尤其是Python+OpenCV的实现方面。整体流程 如今OpenCV官方的Document里都包含了各API的Python版用法,...

    原标题:中文简历表格提取,手写汉字识别(Python+OpenCV)

    所有代码获取:

    简历

    网上对表格框的提取的相关资料较少,尤其是Python+OpenCV的实现方面。

    整体流程

    b43dd25796ab48fc94107c8d99f08671.jpeg

    如今OpenCV官方的Document里都包含了各API的Python版用法,从C++转换到Python用起来意外的顺手。这里附上官方的在线Document地址,记得选对应版本:https://docs.opencv.org/

    该部分的编译环境如下:

    (1)Ubuntu16.04 64位 支持utf-8编码

    (2)Python2.7

    (3)OpenCV3.4.3 (与Python2.7编译通)

    (4)Python2.7 numpy模块、PIL模块、logging模块、pickle模块、os模块、random模块、time模块、matplotlib模块、math模块、csv模块

    读取表格图片文件

    fce2214762d1443ab38838812b3ac0bf.png

    这段即将test_data文件中的所有文件进行遍历读取,也可注释最下方的两行,并去除docu_num一行的注释,即可对一张图片文件进行反复的读取、处理。

    统计图中长横线的斜率来判断整体需要旋转矫正的角度

    1a89a8df1f6b43b0a2f6e7d91d07c205.jpeg

    这段做的是旋转校正操作,先把表格图片转换为灰度图,再用Canny算子提取边缘(灰度+Canny是提取边缘的标准操作)得到如下这张图片edges_whole.jpg

    ddd1177e5bfb4a7682bab64d3d878dba.jpeg

    085059f4f8a541c5b89a719d4869f090.jpeg

    之后便是用getRotationMatrix2D、warpAffine函数进行旋转变换,此处笔者拷贝了一份不进行绘图操作的图片(不然都涂花了,干嘛为难自己)。旋转后的表格图片如下image_Rotation.jpg:

    b57ea4d72ee744529f7176214f7ebf27.jpeg

    通过对表格左下角直角进行识别,将其顶点统一平移矫正至(78,1581)

    370d78f596b74e2792768202dc65eb4a.jpeg

    这段做的是平移校正操作,其中大部分是为了应对数据集中的各种意外情况,譬如表格形式不同。但对于Github中给出的三幅较为统一的图片,核心的操作只有对旋转校正后的表格左下角进行横线、竖线用HoughLinesP进行提取,归一后求二者的交点。将交点平移至设定好的坐标即可统筹处理所有表格图片。此处对霍夫变换求出的各条直线分别与设定好两个等分点进行距离求解,选出最靠近等分点的横线、竖线作为归一结果。求得交点坐标后用np.array函数与cv.warpAffine函数即可完成平移操作。

    横线、竖线的交点求得后在旋转后的表格图像上作图如下line_detect_possible_demo.jpg:

    4e760934cc3146f5a6413432502d6876.jpeg

    分别通过对二值化后的表格用长横条、长竖条内核进行开操作,将表格分别化为全横线与全竖线,叠加后提取交点,即可得到表格中每个矩形的四个顶点

    e959d8ca3b46449f8c8fd4b0a1642635.jpeg

    此段是功能实现的核心操作:通过对校正图像进行横向、纵向的投影,并提取直线、直线交点,提取轮廓后通过所需表格框的尺寸数据对交点进行筛选、匹配,即可得到表格中的各个框四个顶点的坐标。此处理对表格中的小框效果拔群,对大型框进行提取可能遇到一框中有多个小框的情况,需要后续加以限制(统计该框内是否有别的顶点)。具体操作是:

    对未涂花的原始图像进行灰度变化和自适应阈值的二值化操作adaptiveThreshold,这样能最大可能地保留表格中的直线,效果如下图th2.jpg:

    9690877898834a9f9fc507185e60f24a.jpeg

    之后对图像进行先腐蚀erode后膨胀dilate的闭操作,腐蚀与膨胀分别使用N*1与1*N的形态学操作中的核进行处理。该操作可以理解为把表格中所有的像素进行横向、纵向的投影,且投影会往原先已存在直线上偏移,而文字状的不构成直线的像素则会在腐蚀操作中被抹消。就像从长条形的横、纵栅格中看表格图片一般。将横向、纵向投影好的图片进行叠加即如下图mask.jpg:

    7422d8672b4148369abc12d42d2dd07f.jpeg

    表格被神奇地提取出来了!这一步需要注意,一定要是旋转校正过的图像,因为对于一张倾斜的图像,投影操作会让图像变“正”了,实际上图像并没有被旋转过来,这对后续的坐标提取是致命的。既然已经提取出了表格框,那我们就可以通过bitwise_and函数提取出表格框中的各个交点,如下图joints.jpg:

    ffddb2959aa3447d8930a68cebe5c175.jpeg

    接下来即通过findContours函数寻找图像轮廓,并用contourArea函数求出各个轮廓的面积,以对过小的轮廓进行排除。通过approxPolyDP与boundingRect函数用矩形去包围各个轮廓,即可得到该表格图片中各个矩形框的位置数据。之后通过再次使用findContours函数遍历图像轮廓,用尺寸数据对矩形框进行筛选即可得到表格中所需的框的集合。在校正图像上画出这个集合里的所有框,如下图table_out.jpg:

    9cca3c683b3549388ca1c4cfa21c2e94.jpeg

    矫正后的表格中信息的大致位置各在一定范围内,根据大致位置的坐标点筛选出该表中该信息对应的矩形框具体坐标

    63c1d4fb383d4172af00718b1c7dcff2.jpeg

    既然框都已经被提取出来了,那不是大功告成了吗?

    并没有。因为我们还需要对所需要的位置的框进行提取,先前提取出的框又不附带标签。因此我们此处需要做两步:

    首先是选择标准图像中所需的框位置的中心点作为这个框的“ID”,标准图像即先前所说的坐标(78,1581)所在的那张图片。上文代码里即选择(700,370)作为“性别”数据的所在框的大致位置。

    其次是通过遍历的方式筛选出这个中心点坐标所处在的矩形框的坐标。因为框较大,因此即使校正的不够精准,这种方法一样可以将目标框精准地框出,只要标准图像中的那个大致位置不偏移得太过严重。返回搜狐,查看更多

    责任编辑:

    展开全文
  • 第一次用要先学习,或者把rar文件中的data.rec复制到D盘根目录下面(包含3个汉字:刘、仲、林) 想把他做成输入法,但是目前只能把字符输入到1.txt中。不过先要新建一个1.txt,然后打开这个1.txt(比较烦琐) 但不...
  • 手写汉字识别matlab

    2021-04-23 11:02:47
    大约从 70 年代开始,相继对印刷体汉 字识别、手写印刷体汉字识别及在线手写汉字识别进行了研究。 1980 年进行了印刷体汉 字识别的公开表演, 1981 年 5 月在...... 基于MATLAB BP 神经网络的数字图像识别 基于 ...
  • 手写汉字识别的发展综述

    万次阅读 多人点赞 2019-03-19 20:29:19
    一、手写汉字识别的研究背景与现状 在上个世纪60年代,美国IBM公司开始进行了对印刷体汉字的模式识别研究工作,1996年Casey和Nag用模板匹配法成功的识别出了1000个印刷体汉字,在全球范围内,汉字识别开始展开了。而...
  • 手写借助强大的中文识别能力,丰富的词条联想功能,任何不懂中文输入法的网民也可流畅完成中文输入,其体积小巧,实用方便。自发布以来得到了众多低端网民与电脑初学者的肯定与
  • 银光小蒙恬手写笔特色功能简介:繁简合一辨识核心可辨认繁简体中文23000多字、香港4941字HKSCS2001、英数字、符号、日文平假名及片假名。人工智慧辨认核心可以学习个人书写笔迹,成为个人化的手写系统,越写越聪明。...
  • Android开发中,要想实现中文手写输入法,并带中文自动识别提示功能,是很难的,当然了,android手机端开发则不需要另外实现Android手写输入法,但是在一些平板设备或者电视设备上,就需要汉字手写输入法了。...
  • TensorFlow 2.0 中文手写字识别(汉字OCR)在开始之前,必须要说明的是,本教程完全基于TensorFlow2.0 接口编写,请误与其他古老的教程混为一谈,本教程除了手把手教大家完成这个挑战性任务之外,更多的会教大家如何...
  • 手写汉字识别(分割+卷积识别)[2021课设论文]

    千次阅读 多人点赞 2021-09-12 16:12:28
    6.1 手写体样本训练结果 我们分别在平板和手写纸上分别写了11个汉字(0-10),原始图样如下: 对所有汉字进行裁剪、预处理和放入模型预测,模型一预测结果如下,达到了20/22的准确率,结果如下: 模型二的预测结果...
  • 【vue手写图片预览组件】在vue2.0项目中手写图片预览组件,旋转、放大、滚动、下载功能,同时做了载入动画处理。
  • 来源:小石头www.duanshishi.com/?p=1753这里我会拿到所有的数据集来做训练与测试,算作是对斗大的熊猫上面那篇...具体下载:wgethttp://www.nlpr.ia.ac.cn/databases/download/feature_data/HWDB1.1trn_gnt.zipwge...
  • 机器学习 实验三 手写汉字识别

    千次阅读 2022-03-06 22:03:42
    机器学习 实验三 手写汉字识别 一、实验环境 PC机,Python 二、代码 一、使用神经网络 #%% import pandas as pd import tensorflow as tf import matplotlib.pyplot as plt import os,PIL,pathlib import numpy as ...
  • Android 提供了很多丰富、实用而且很有特色的功能。比如,语音识别、手写签名等等。本篇就为你介绍如何在android上进行个性化的手写签名。首先大致说说需求:这是一个追求时尚、张扬个性的时代,我们希望在签名的...
  • 问题导读:1、相比于简单...不如来尝试一下类别多大3000+的汉字手写识别吧!!虽然以前有一些文章教大家如何操作,但是大多比较古老,这篇文章将用全新的TensorFlow 2.0 来教大家如何搭建一个中文OCR系统!让我...
  • 该课题为基于bp神经网络的中文汉字识别系统,可以用手写板写,现场识别。有界面GUI操作。另外可识别汉字,字母,数字等均可。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 18,727
精华内容 7,490
关键字:

下载手写功能中文手写