上一篇提到文字数据集的合成,现在我们手头上已经得到了3755个汉字(一级字库)的印刷体图像数据集,我们可以利用它们进行接下来的3755个汉字的识别系统的搭建。用深度学习做文字识别,用的网络当然是CNN,那具体使用哪个经典网络?VGG?RESNET?还是其他?我想了下,越深的网络训练得到的模型应该会更好,但是想到训练的难度以及以后线上部署时预测的速度,我觉得首先建立一个比较浅的网络(基于LeNet的改进)做基本的文字识别,然后再根据项目需求,再尝试其他的网络结构。这次任务所使用的深度学习框架是强大的Tensorflow。

网络搭建

第一步当然是搭建网络和计算图

其实文字识别就是一个多分类任务,比如这个3755文字识别就是3755个类别的分类任务。我们定义的网络非常简单,基本就是LeNet的改进版,值得注意的是我们加入了batch normalization。另外我们的损失函数选择sparse_softmax_cross_entropy_with_logits,优化器选择了Adam,学习率设为0.1

#network: conv2d->max_pool2d->conv2d->max_pool2d->conv2d->max_pool2d->conv2d->conv2d->max_pool2d->fully_connected->fully_connected
def build_graph(top_k):keep_prob = tf.placeholder(dtype=tf.float32, shape=[], name='keep_prob')images = tf.placeholder(dtype=tf.float32, shape=[None, 64, 64, 1], name='image_batch')labels = tf.placeholder(dtype=tf.int64, shape=[None], name='label_batch')is_training = tf.placeholder(dtype=tf.bool, shape=[], name='train_flag')with tf.device('/gpu:5'):#给slim.conv2d和slim.fully_connected准备了默认参数:batch_normwith slim.arg_scope([slim.conv2d, slim.fully_connected],normalizer_fn=slim.batch_norm,normalizer_params={'is_training': is_training}):conv3_1 = slim.conv2d(images, 64, [3, 3], 1, padding='SAME', scope='conv3_1')max_pool_1 = slim.max_pool2d(conv3_1, [2, 2], [2, 2], padding='SAME', scope='pool1')conv3_2 = slim.conv2d(max_pool_1, 128, [3, 3], padding='SAME', scope='conv3_2')max_pool_2 = slim.max_pool2d(conv3_2, [2, 2], [2, 2], padding='SAME', scope='pool2')conv3_3 = slim.conv2d(max_pool_2, 256, [3, 3], padding='SAME', scope='conv3_3')max_pool_3 = slim.max_pool2d(conv3_3, [2, 2], [2, 2], padding='SAME', scope='pool3')conv3_4 = slim.conv2d(max_pool_3, 512, [3, 3], padding='SAME', scope='conv3_4')conv3_5 = slim.conv2d(conv3_4, 512, [3, 3], padding='SAME', scope='conv3_5')max_pool_4 = slim.max_pool2d(conv3_5, [2, 2], [2, 2], padding='SAME', scope='pool4')
        flatten = slim.flatten(max_pool_4)fc1 = slim.fully_connected(slim.dropout(flatten, keep_prob), <span class="hljs-number">1024</span>,activation_fn=tf.nn.relu, scope=<span class="hljs-string">'fc1'</span>)logits = slim.fully_connected(slim.dropout(fc1, keep_prob), FLAGS.charset_size, activation_fn=<span class="hljs-keyword">None</span>,scope=<span class="hljs-string">'fc2'</span>)<span class="hljs-comment"># 因为我们没有做热编码,所以使用sparse_softmax_cross_entropy_with_logits</span>loss = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logits, labels=labels))accuracy = tf.reduce_mean(tf.cast(tf.equal(tf.argmax(logits, <span class="hljs-number">1</span>), labels), tf.float32))update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)<span class="hljs-keyword">if</span> update_ops:updates = tf.group(*update_ops)loss = control_flow_ops.with_dependencies([updates], loss)global_step = tf.get_variable(<span class="hljs-string">"step"</span>, [], initializer=tf.constant_initializer(<span class="hljs-number">0.0</span>), trainable=<span class="hljs-keyword">False</span>)optimizer = tf.train.AdamOptimizer(learning_rate=<span class="hljs-number">0.1</span>)train_op = slim.learning.create_train_op(loss, optimizer, global_step=global_step)probabilities = tf.nn.softmax(logits)<span class="hljs-comment"># 绘制loss accuracy曲线</span>tf.summary.scalar(<span class="hljs-string">'loss'</span>, loss)tf.summary.scalar(<span class="hljs-string">'accuracy'</span>, accuracy)merged_summary_op = tf.summary.merge_all()<span class="hljs-comment"># 返回top k 个预测结果及其概率;返回top K accuracy</span>predicted_val_top_k, predicted_index_top_k = tf.nn.top_k(probabilities, k=top_k)accuracy_in_top_k = tf.reduce_mean(tf.cast(tf.nn.in_top_k(probabilities, labels, top_k), tf.float32))<span class="hljs-keyword">return</span> {<span class="hljs-string">'images'</span>: images,<span class="hljs-string">'labels'</span>: labels,<span class="hljs-string">'keep_prob'</span>: keep_prob,<span class="hljs-string">'top_k'</span>: top_k,<span class="hljs-string">'global_step'</span>: global_step,<span class="hljs-string">'train_op'</span>: train_op,<span class="hljs-string">'loss'</span>: loss,<span class="hljs-string">'is_training'</span>: is_training,<span class="hljs-string">'accuracy'</span>: accuracy,<span class="hljs-string">'accuracy_top_k'</span>: accuracy_in_top_k,<span class="hljs-string">'merged_summary_op'</span>: merged_summary_op,<span class="hljs-string">'predicted_distribution'</span>: probabilities,<span class="hljs-string">'predicted_index_top_k'</span>: predicted_index_top_k,<span class="hljs-string">'predicted_val_top_k'</span>: predicted_val_top_k}</code></pre>

模型训练

训练之前我们应设计好数据怎么样才能高效地喂给网络训练。

首先,我们先创建数据流图,这个数据流图由一些流水线的阶段组成,阶段间用队列连接在一起。第一阶段将生成文件名,我们读取这些文件名并且把他们排到文件名队列中。第二阶段从文件中读取数据(使用Reader),产生样本,而且把样本放在一个样本队列中。根据你的设置,实际上也可以拷贝第二阶段的样本,使得他们相互独立,这样就可以从多个文件中并行读取。在第二阶段的最后是一个排队操作,就是入队到队列中去,在下一阶段出队。因为我们是要开始运行这些入队操作的线程,所以我们的训练循环会使得样本队列中的样本不断地出队。

盗个图说明一下具体的数据读入流程:

入队操作都在主线程中进行,Session中可以多个线程一起运行。 在数据输入的应用场景中,入队操作是从硬盘中读取输入,放到内存当中,速度较慢。 使用QueueRunner可以创建一系列新的线程进行入队操作,让主线程继续使用数据。如果在训练神经网络的场景中,就是训练网络和读取数据是异步的,主线程在训练网络,另一个线程在将数据从硬盘读入内存。

# batch的生成
def input_pipeline(self, batch_size, num_epochs=None, aug=False):# numpy array 转 tensorimages_tensor = tf.convert_to_tensor(self.image_names, dtype=tf.string)labels_tensor = tf.convert_to_tensor(self.labels, dtype=tf.int64)# 将image_list ,label_list做一个slice处理input_queue = tf.train.slice_input_producer([images_tensor, labels_tensor], num_epochs=num_epochs)
labels = input_queue[<span class="hljs-number">1</span>]
images_content = tf.read_file(input_queue[<span class="hljs-number">0</span>])
images = tf.image.convert_image_dtype(tf.image.decode_png(images_content, channels=<span class="hljs-number">1</span>), tf.float32)
<span class="hljs-keyword">if</span> <span class="hljs-symbol">aug:</span>images = <span class="hljs-keyword">self</span>.data_augmentation(images)
new_size = tf.constant([FLAGS.image_size, FLAGS.image_size], dtype=tf.int32)
images = tf.image.resize_images(images, new_size)
image_batch, label_batch = tf.train.shuffle_batch([images, labels], batch_size=batch_size, capacity=<span class="hljs-number">50000</span>,min_after_dequeue=<span class="hljs-number">10000</span>)
<span class="hljs-comment"># print 'image_batch', image_batch.get_shape()</span>
<span class="hljs-keyword">return</span> image_batch, label_batch</code></pre>

训练时数据读取的模式如上面所述,那训练代码则根据该架构设计如下:

def train():print('Begin training')# 填好数据读取的路径train_feeder = DataIterator(data_dir='./dataset/train/')test_feeder = DataIterator(data_dir='./dataset/test/')model_name = 'chinese-rec-model'with tf.Session(config=tf.ConfigProto(gpu_options=gpu_options, allow_soft_placement=True)) as sess:# batch data 获取train_images, train_labels = train_feeder.input_pipeline(batch_size=FLAGS.batch_size, aug=True)test_images, test_labels = test_feeder.input_pipeline(batch_size=FLAGS.batch_size)graph = build_graph(top_k=1)  # 训练时top k = 1saver = tf.train.Saver()sess.run(tf.global_variables_initializer())# 设置多线程协调器coord = tf.train.Coordinator()threads = tf.train.start_queue_runners(sess=sess, coord=coord)
    train_writer = tf.summary.FileWriter(FLAGS.log_dir + <span class="hljs-string">'/train'</span>, sess.graph)test_writer = tf.summary.FileWriter(FLAGS.log_dir + <span class="hljs-string">'/val'</span>)start_step = <span class="hljs-number">0</span><span class="hljs-comment"># 可以从某个step下的模型继续训练</span><span class="hljs-keyword">if</span> FLAGS.restore:ckpt = tf.train.latest_checkpoint(FLAGS.checkpoint_dir)<span class="hljs-keyword">if</span> ckpt:saver.restore(sess, ckpt)print(<span class="hljs-string">"restore from the checkpoint {0}"</span>.format(ckpt))start_step += int(ckpt.split(<span class="hljs-string">'-'</span>)[<span class="hljs-number">-1</span>])logger.info(<span class="hljs-string">':::Training Start:::'</span>)<span class="hljs-keyword">try</span>:i = <span class="hljs-number">0</span><span class="hljs-keyword">while</span> <span class="hljs-keyword">not</span> coord.should_stop():i += <span class="hljs-number">1</span>start_time = time.time()train_images_batch, train_labels_batch = sess.run([train_images, train_labels])feed_dict = {graph[<span class="hljs-string">'images'</span>]: train_images_batch,graph[<span class="hljs-string">'labels'</span>]: train_labels_batch,graph[<span class="hljs-string">'keep_prob'</span>]: <span class="hljs-number">0.8</span>,graph[<span class="hljs-string">'is_training'</span>]: <span class="hljs-keyword">True</span>}_, loss_val, train_summary, step = sess.run([graph[<span class="hljs-string">'train_op'</span>], graph[<span class="hljs-string">'loss'</span>], graph[<span class="hljs-string">'merged_summary_op'</span>], graph[<span class="hljs-string">'global_step'</span>]],feed_dict=feed_dict)train_writer.add_summary(train_summary, step)end_time = time.time()logger.info(<span class="hljs-string">"the step {0} takes {1} loss {2}"</span>.format(step, end_time - start_time, loss_val))<span class="hljs-keyword">if</span> step &gt; FLAGS.max_steps:<span class="hljs-keyword">break</span><span class="hljs-keyword">if</span> step % FLAGS.eval_steps == <span class="hljs-number">1</span>:test_images_batch, test_labels_batch = sess.run([test_images, test_labels])feed_dict = {graph[<span class="hljs-string">'images'</span>]: test_images_batch,graph[<span class="hljs-string">'labels'</span>]: test_labels_batch,graph[<span class="hljs-string">'keep_prob'</span>]: <span class="hljs-number">1.0</span>,graph[<span class="hljs-string">'is_training'</span>]: <span class="hljs-keyword">False</span>}accuracy_test, test_summary = sess.run([graph[<span class="hljs-string">'accuracy'</span>], graph[<span class="hljs-string">'merged_summary_op'</span>]],feed_dict=feed_dict)<span class="hljs-keyword">if</span> step &gt; <span class="hljs-number">300</span>:test_writer.add_summary(test_summary, step)logger.info(<span class="hljs-string">'===============Eval a batch======================='</span>)logger.info(<span class="hljs-string">'the step {0} test accuracy: {1}'</span>.format(step, accuracy_test))logger.info(<span class="hljs-string">'===============Eval a batch======================='</span>)<span class="hljs-keyword">if</span> step % FLAGS.save_steps == <span class="hljs-number">1</span>:logger.info(<span class="hljs-string">'Save the ckpt of {0}'</span>.format(step))saver.save(sess, os.path.join(FLAGS.checkpoint_dir, model_name),global_step=graph[<span class="hljs-string">'global_step'</span>])<span class="hljs-keyword">except</span> tf.errors.OutOfRangeError:logger.info(<span class="hljs-string">'==================Train Finished================'</span>)saver.save(sess, os.path.join(FLAGS.checkpoint_dir, model_name), global_step=graph[<span class="hljs-string">'global_step'</span>])<span class="hljs-keyword">finally</span>:<span class="hljs-comment"># 达到最大训练迭代数的时候清理关闭线程</span>coord.request_stop()coord.join(threads)</code></pre>

执行以下指令进行模型训练。因为我使用的是TITAN X,所以感觉训练时间不长,大概1个小时可以训练完毕。训练过程的loss和accuracy变换曲线如下图所示

然后执行指令,设置最大迭代步数为16002,每100步进行一次验证,每500步存储一次模型。

python Chinese_OCR.py --mode=train --max_steps=16002 --eval_steps=100 --save_steps=500

模型性能评估

我们的需要对模模型进行评估,我们需要计算模型的top 1 和top 5的准确率。

执行指令

python Chinese_OCR.py --mode=validation

验证开始

最后给出预测的top1 和top5正确率如下:

def validation():print('Begin validation')test_feeder = DataIterator(data_dir='./dataset/test/')
final_predict_val = []
final_predict_index = []
groundtruth = []<span class="hljs-keyword">with</span> tf.Session(config=tf.ConfigProto(gpu_options=gpu_options,allow_soft_placement=<span class="hljs-keyword">True</span>)) <span class="hljs-keyword">as</span> sess:test_images, test_labels = test_feeder.input_pipeline(batch_size=FLAGS.batch_size, num_epochs=<span class="hljs-number">1</span>)graph = build_graph(top_k=<span class="hljs-number">5</span>)saver = tf.train.Saver()sess.run(tf.global_variables_initializer())sess.run(tf.local_variables_initializer())  <span class="hljs-comment"># initialize test_feeder's inside state</span>coord = tf.train.Coordinator()threads = tf.train.start_queue_runners(sess=sess, coord=coord)ckpt = tf.train.latest_checkpoint(FLAGS.checkpoint_dir)<span class="hljs-keyword">if</span> ckpt:saver.restore(sess, ckpt)print(<span class="hljs-string">"restore from the checkpoint {0}"</span>.format(ckpt))logger.info(<span class="hljs-string">':::Start validation:::'</span>)<span class="hljs-keyword">try</span>:i = <span class="hljs-number">0</span>acc_top_1, acc_top_k = <span class="hljs-number">0.0</span>, <span class="hljs-number">0.0</span><span class="hljs-keyword">while</span> <span class="hljs-keyword">not</span> coord.should_stop():i += <span class="hljs-number">1</span>start_time = time.time()test_images_batch, test_labels_batch = sess.run([test_images, test_labels])feed_dict = {graph[<span class="hljs-string">'images'</span>]: test_images_batch,graph[<span class="hljs-string">'labels'</span>]: test_labels_batch,graph[<span class="hljs-string">'keep_prob'</span>]: <span class="hljs-number">1.0</span>,graph[<span class="hljs-string">'is_training'</span>]: <span class="hljs-keyword">False</span>}batch_labels, probs, indices, acc_1, acc_k = sess.run([graph[<span class="hljs-string">'labels'</span>],graph[<span class="hljs-string">'predicted_val_top_k'</span>],graph[<span class="hljs-string">'predicted_index_top_k'</span>],graph[<span class="hljs-string">'accuracy'</span>],graph[<span class="hljs-string">'accuracy_top_k'</span>]], feed_dict=feed_dict)final_predict_val += probs.tolist()final_predict_index += indices.tolist()groundtruth += batch_labels.tolist()acc_top_1 += acc_1acc_top_k += acc_kend_time = time.time()logger.info(<span class="hljs-string">"the batch {0} takes {1} seconds, accuracy = {2}(top_1) {3}(top_k)"</span>.format(i, end_time - start_time, acc_1, acc_k))<span class="hljs-keyword">except</span> tf.errors.OutOfRangeError:logger.info(<span class="hljs-string">'==================Validation Finished================'</span>)acc_top_1 = acc_top_1 * FLAGS.batch_size / test_feeder.sizeacc_top_k = acc_top_k * FLAGS.batch_size / test_feeder.sizelogger.info(<span class="hljs-string">'top 1 accuracy {0} top k accuracy {1}'</span>.format(acc_top_1, acc_top_k))<span class="hljs-keyword">finally</span>:coord.request_stop()coord.join(threads)
<span class="hljs-keyword">return</span> {<span class="hljs-string">'prob'</span>: final_predict_val, <span class="hljs-string">'indices'</span>: final_predict_index, <span class="hljs-string">'groundtruth'</span>: groundtruth}</code></pre>

文字预测

刚刚做的那一步只是使用了我们生成的数据集作为测试集来检验模型性能,这种检验是不大准确的,因为我们日常需要识别的文字样本不会像是自己合成的文字那样的稳定和规则。那我们尝试使用该模型对一些实际场景的文字进行识别,真正考察模型的泛化能力。

首先先编写好预测的代码

def inference(name_list):print('inference')image_set=[]# 对每张图进行尺寸标准化和归一化for image in name_list:temp_image = Image.open(image).convert('L')temp_image = temp_image.resize((FLAGS.image_size, FLAGS.image_size), Image.ANTIALIAS)temp_image = np.asarray(temp_image) / 255.0temp_image = temp_image.reshape([-1, 64, 64, 1])image_set.append(temp_image)
<span class="hljs-comment"># allow_soft_placement 如果你指定的设备不存在,允许TF自动分配设备</span>
<span class="hljs-keyword">with</span> tf.Session(config=tf.ConfigProto(gpu_options=gpu_options,allow_soft_placement=<span class="hljs-keyword">True</span>)) <span class="hljs-keyword">as</span> sess:logger.info(<span class="hljs-string">'========start inference============'</span>)<span class="hljs-comment"># images = tf.placeholder(dtype=tf.float32, shape=[None, 64, 64, 1])</span><span class="hljs-comment"># Pass a shadow label 0. This label will not affect the computation graph.</span>graph = build_graph(top_k=<span class="hljs-number">3</span>)saver = tf.train.Saver()<span class="hljs-comment"># 自动获取最后一次保存的模型</span>ckpt = tf.train.latest_checkpoint(FLAGS.checkpoint_dir)<span class="hljs-keyword">if</span> ckpt:       saver.restore(sess, ckpt)val_list=[]idx_list=[]<span class="hljs-comment"># 预测每一张图</span><span class="hljs-keyword">for</span> item <span class="hljs-keyword">in</span> image_set:temp_image = itempredict_val, predict_index = sess.run([graph[<span class="hljs-string">'predicted_val_top_k'</span>], graph[<span class="hljs-string">'predicted_index_top_k'</span>]],feed_dict={graph[<span class="hljs-string">'images'</span>]: temp_image,graph[<span class="hljs-string">'keep_prob'</span>]: <span class="hljs-number">1.0</span>,graph[<span class="hljs-string">'is_training'</span>]: <span class="hljs-keyword">False</span>})val_list.append(predict_val)idx_list.append(predict_index)
<span class="hljs-comment">#return predict_val, predict_index</span>
<span class="hljs-keyword">return</span> val_list,idx_list

这里需要说明一下,我会把我要识别的文字图像存入一个叫做tmp的文件夹内,里面的图像按照顺序依次编号,我们识别时就从该目录下读取所有图片仅内存进行逐一识别。

# 获待预测图像文件夹内的图像名字
def get_file_list(path):list_name=[]files = os.listdir(path)files.sort()for file in files:file_path = os.path.join(path, file)list_name.append(file_path)return list_name

那我们使用训练好的模型进行汉字预测,观察效果。首先我从一篇论文pdf上用截图工具截取了一段文字,然后使用文字切割算法把文字段落切割为单字,如下图,因为有少量文字切割失败,所以丢弃了一些单字。

从论文中用截图工具截取文字段落。

切割出来的单字,黑底白字。

执行指令,开始文字识别。

 python Chinese_OCR.py --mode=inference 

因为我使用的是GPU,预测速度非常快,除去系统初始化时间,全部图像预测完成所花费的时间不超过1秒。

其中打印日志的信息分别是:当前识别的图片路径、模型预测出的top 3汉字(置信度由高到低排列)、对应的汉字id、对应的概率。

最后将所有的识别文字按顺序组合成段落,可以看出,汉字识别完全正确,说明我们的基于深度学习的OCR系统还是相当给力!

总结

至此,支持3755个汉字识别的OCR系统已经搭建完毕,经过测试,效果还是很不错。这是一个没有经过太多优化的模型,在模型评估上top 1的正确率达到了99.9%,这是一个相当优秀的效果了,所以说在一些比较理想的环境下的文字识别的效果还是比较给力,但是对于复杂场景的或是一些干扰比较大的文字图像,识别起来的效果可能不会太理想,这就需要针对特定场景做进一步优化。

完整代码在我的github获取。

OCR技术系列之四】基于深度学习的文字识别(3755个汉字)(转)相关推荐

  1. 【OCR技术系列之四】基于深度学习的文字识别(3755个汉字)

    上一篇提到文字数据集的合成,现在我们手头上已经得到了3755个汉字(一级字库)的印刷体图像数据集,我们可以利用它们进行接下来的3755个汉字的识别系统的搭建.用深度学习做文字识别,用的网络当然是CNN ...

  2. python深度文字识别_【OCR技术系列之四】基于深度学习的文字识别(3755个汉字)...

    上一篇提到文字数据集的合成,现在我们手头上已经得到了3755个汉字(一级字库)的印刷体图像数据集,我们可以利用它们进行接下来的3755个汉字的识别系统的搭建.用深度学习做文字识别,用的网络当然是CNN ...

  3. 中国人工智能学会通讯——基于视频的行为识别技术 1.5 基于深度学习的视频识别方法...

    1.5 基于深度学习的视频识别方法 下面介绍面向视频分类的深度学习方 法.深度卷积神经网络在图像分类取得 成功后,研究人员就希望把它推广到视 频分类中.但这不是一件很容易的事, 一个原因是缺乏足够的训 ...

  4. 表单识别(五)——票据识别-论文研读:基于深度学习的票据识别系统设计与实现,卞飞飞(上)

    (论文研读:基于深度学习的票据识别系统设计与实现,卞飞飞:) 引言: 传统的文本检测与识别算法主要指利用数字图像处理等非深度学习技术进行文本检测的方法,依赖于数字图像特征(如颜色.纹理.轮廓.形状等特 ...

  5. 基于深度学习的人脸识别系统系列(Caffe+OpenCV+Dlib)——【六】设计人脸识别的识别类...

    前言 基于深度学习的人脸识别系统,一共用到了5个开源库:OpenCV(计算机视觉库).Caffe(深度学习库).Dlib(机器学习库).libfacedetection(人脸检测库).cudnn(gp ...

  6. 基于深度学习的动物识别方法研究与实现

    基于深度学习的动物识别方法研究与实现 目  录 摘  要 I ABSTRACT II     第一章  绪论 1 1.1 研究的目的和意义 1 1.2国内外研究现状 1 1.2.1 目标检测国内外研究 ...

  7. 基于深度学习的车型识别系统(Python+清新界面+数据集)

    摘要:基于深度学习的车型识别系统用于识别不同类型的车辆,应用YOLO V5算法根据不同尺寸大小区分和检测车辆,并统计各类型数量以辅助智能交通管理.本文详细介绍车型识别系统,在介绍算法原理的同时,给出P ...

  8. 基于深度学习的动物识别系统(YOLOv5清新界面版,Python代码)

    摘要:动物识别系统用于识别和统计常见动物数量,通过深度学习技术检测日常几种动物图像识别,支持图片.视频和摄像头画面等形式.在介绍算法原理的同时,给出Python的实现代码.训练数据集以及PyQt的UI ...

  9. 基于深度学习的口罩识别与检测PyTorch实现

    基于深度学习的口罩识别与检测PyTorch实现 1. 设计思路 1.1 两阶段检测器:先检测人脸,然后将人脸进行分类,戴口罩与不戴口罩. 1.2 一阶段检测器:直接训练口罩检测器,训练样本为人脸的标注 ...

最新文章

  1. 创业公司如何实施敏捷开发(转载)
  2. 时隔5年,再次接触数字图像处理
  3. Dev C++ 无法调试问题的解决——小白也能看懂!
  4. Oracle SQL语句收集
  5. TP-Link路由器设置上网知识笔记
  6. delphi 获取打印机默认纸张_Delphi 动态调整打印机纸张大小
  7. 计算机编程竞赛怎么入门,acm编程比赛入门题目集..pdf
  8. 阶段3-团队合作\项目-网络安全传输系统\sprint3-账号管理子系统设计\第2课-账号管理子系统设计...
  9. HTML课程表应用,可在PC和Android运行
  10. 理解偏倚:可靠结果的先决条件
  11. 长虹智慧厨房解决方案,让你AI上智慧家居生活
  12. 利用tomcat配置网站
  13. 四叉树(QuadTree)图例、应用、实现
  14. 单片机设计经验设计技巧集锦
  15. python火车票票价_python的requests库爬取火车票信息和所需价钱
  16. 5G语音回落4G解决方案-EPS Fallback IPLOOK
  17. 【算法导论】 内部排序算法总结
  18. Occupancy Flow: 4D Reconstruction by Learning Particle Dynamics(2)
  19. 三菱fx1n40mr001接线图_三菱FX1N-40MR-001使用说明书 - 广州凌控
  20. 锦上添花之元音音标学习(上)

热门文章

  1. [02]基于webservice权限系统
  2. mysql配置主从数据库_mysql配置主从数据库
  3. 博客园博客美化相关文章目录
  4. ETL 工具的比较:Talend,Kettle,Informatica 等
  5. fopen /open,read/write和fread/fwrite区别
  6. pytorch 入门学习加载数据集-8
  7. CentOS 6.5 安装 Python3
  8. TurboMail邮件服务器腾云驾务云化邮件办公
  9. java if 局部变量_java – 为什么局部变量在if-else构造中启动而在if-else-if构造中不启动?...
  10. mybatisplus中的xml如何添加like条件,进行模糊查询