文章目录

  • 前言
  • 爬取图像
  • 创建图像列表
  • 定义模型
  • 定义数据读取
  • 训练模型
  • 预测图片

GitHub地址:https://github.com/yeyupiaoling/LearnPaddle2/tree/master/note11

前言

本章将介绍如何使用PaddlePaddle训练自己的图片数据集,在之前的图像数据集中,我们都是使用PaddlePaddle自带的数据集,本章我们就来学习如何让PaddlePaddle训练我们自己的图片数据集。

爬取图像

在本章中,我们使用的是自己的图片数据集,所以我们需要弄一堆图像来制作训练的数据集。下面我们就编写一个爬虫程序,让其帮我们从百度图片中爬取相应类别的图片。

创建一个download_image.py文件用于编写爬取图片程序。首先导入所需的依赖包。

import re
import uuid
import requests
import os
import numpy
import imghdr
from PIL import Image

然后编写一个下载图片的函数,这个是程序核心代码。参数是下载图片的关键、保存的名字、下载图片的数量。关键字是百度搜索图片的关键。

# 获取百度图片下载图片
def download_image(key_word, save_name, download_max):download_sum = 0str_gsm = '80'# 把每个类别的图片存放在单独一个文件夹中save_path = 'images' + '/' + save_nameif not os.path.exists(save_path):os.makedirs(save_path)while download_sum < download_max:# 下载次数超过指定值就停止下载if download_sum >= download_max:breakstr_pn = str(download_sum)# 定义百度图片的路径url = 'http://image.baidu.com/search/flip?tn=baiduimage&ie=utf-8&' \'word=' + key_word + '&pn=' + str_pn + '&gsm=' + str_gsm + '&ct=&ic=0&lm=-1&width=0&height=0'print('正在下载 %s 的第 %d 张图片.....' % (key_word, download_sum))try:# 获取当前页面的源码result = requests.get(url, timeout=30).text# 获取当前页面的图片URLimg_urls = re.findall('"objURL":"(.*?)",', result, re.S)if len(img_urls) < 1:break# 把这些图片URL一个个下载for img_url in img_urls:# 获取图片内容img = requests.get(img_url, timeout=30)img_name = save_path + '/' + str(uuid.uuid1()) + '.jpg'# 保存图片with open(img_name, 'wb') as f:f.write(img.content)download_sum += 1if download_sum >= download_max:breakexcept Exception as e:print('【错误】当前图片无法下载,%s' % e)download_sum += 1continueprint('下载完成')

图片下载完成之后,需要删除一家损坏的图片,因为在下载的过程中,由于图片本身的问题或者下载过程造成的图片损坏,需要把这些已经损坏的图片上传。下面的函数就是删除所有损坏的图片,根据图像数据集的目录读取获取所有图片文件的路径,然后使用imghdr工具获取图片的类型是否为png或者jpg来判断图片文件是否完整,最后再删除根据图片的通道数据来删除灰度图片。

# 删除不是JPEG或者PNG格式的图片
def delete_error_image(father_path):# 获取父级目录的所有文件以及文件夹try:image_dirs = os.listdir(father_path)for image_dir in image_dirs:image_dir = os.path.join(father_path, image_dir)# 如果是文件夹就继续获取文件夹中的图片if os.path.isdir(image_dir):images = os.listdir(image_dir)for image in images:image = os.path.join(image_dir, image)try:# 获取图片的类型image_type = imghdr.what(image)# 如果图片格式不是JPEG同时也不是PNG就删除图片if image_type is not 'jpeg' and image_type is not 'png':os.remove(image)print('已删除:%s' % image)continue# 删除灰度图img = numpy.array(Image.open(image))if len(img.shape) is 2:os.remove(image)print('已删除:%s' % image)except:os.remove(image)print('已删除:%s' % image)except:pass

最后在main入口中通过调用两个函数来完成下载图像数据集,使用中文进行百度搜索图片,使用英文是为了出现中文路径导致图片读取错误。

if __name__ == '__main__':# 定义要下载的图片中文名称和英文名称,ps:英文名称主要是为了设置文件夹名key_words = {'西瓜': 'watermelon', '哈密瓜': 'cantaloupe','樱桃': 'cherry', '苹果': 'apple', '黄瓜': 'cucumber', '胡萝卜': 'carrot'}# 每个类别下载一千个max_sum = 500for key_word in key_words:save_name = key_words[key_word]download_image(key_word, save_name, max_sum)# 删除错误图片delete_error_image('images/')

输出信息:

正在下载 哈密瓜 的第 0 张图片.....
【错误】当前图片无法下载,HTTPConnectionPool(host='www.boyingsj.com', port=80): Read timed out.
正在下载 哈密瓜 的第 10 张图片.....

注意: 下载处理完成之后,还可能存在其他杂乱的图片,所以还需要我们手动删除这些不属于这个类别的图片,这才算完成图像数据集的制作。

创建图像列表

创建一个create_data_list.py文件,在这个程序中,我们只要把爬取保存图片的路径的文件夹路径传进去就可以了,生成固定格式的列表,格式为图片的路径 <Tab> 图片类别的标签

import json
import osdef create_data_list(data_root_path):with open(data_root_path + "test.list", 'w') as f:passwith open(data_root_path + "train.list", 'w') as f:pass# 所有类别的信息class_detail = []# 获取所有类别class_dirs = os.listdir(data_root_path)# 类别标签class_label = 0# 获取总类别的名称father_paths = data_root_path.split('/')while True:if father_paths[len(father_paths) - 1] == '':del father_paths[len(father_paths) - 1]else:breakfather_path = father_paths[len(father_paths) - 1]all_class_images = 0other_file = 0# 读取每个类别for class_dir in class_dirs:if class_dir == 'test.list' or class_dir == "train.list" or class_dir == 'readme.json':other_file += 1continueprint('正在读取类别:%s' % class_dir)# 每个类别的信息class_detail_list = {}test_sum = 0trainer_sum = 0# 统计每个类别有多少张图片class_sum = 0# 获取类别路径path = data_root_path + "/" + class_dir# 获取所有图片img_paths = os.listdir(path)for img_path in img_paths:# 每张图片的路径name_path = class_dir + '/' + img_path# 如果不存在这个文件夹,就创建if not os.path.exists(data_root_path):os.makedirs(data_root_path)# 每10张图片取一个做测试数据if class_sum % 10 == 0:test_sum += 1with open(data_root_path + "test.list", 'a') as f:f.write(name_path + "\t%d" % class_label + "\n")else:trainer_sum += 1with open(data_root_path + "train.list", 'a') as f:f.write(name_path + "\t%d" % class_label + "\n")class_sum += 1all_class_images += 1# 说明的json文件的class_detail数据class_detail_list['class_name'] = class_dirclass_detail_list['class_label'] = class_labelclass_detail_list['class_test_images'] = test_sumclass_detail_list['class_trainer_images'] = trainer_sumclass_detail.append(class_detail_list)class_label += 1# 获取类别数量all_class_sum = len(class_dirs) - other_file# 说明的json文件信息readjson = {}readjson['all_class_name'] = father_pathreadjson['all_class_sum'] = all_class_sumreadjson['all_class_images'] = all_class_imagesreadjson['class_detail'] = class_detailjsons = json.dumps(readjson, sort_keys=True, indent=4, separators=(',', ': '))with open(data_root_path + "readme.json", 'w') as f:f.write(jsons)print('图像列表已生成')

最后执行就可以生成图像的列表。

if __name__ == '__main__':# 把生产的数据列表都放在自己的总类别文件夹中data_root_path = "images/"create_data_list(data_root_path)

输出信息:

正在读取类别:apple
正在读取类别:cantaloupe
正在读取类别:carrot
正在读取类别:cherry
正在读取类别:cucumber
正在读取类别:watermelon
图像列表已生成

运行这个程序之后,会生成在data文件夹中生成一个单独的大类文件夹,比如我们这次是使用到蔬菜类,所以我生成一个vegetables文件夹,在这个文件夹下有3个文件:

文件名 作用
trainer.list 用于训练的图像列表
test.list 用于测试的图像列表
readme.json 该数据集的json格式的说明,方便以后使用

readme.json文件的格式如下,可以很清楚看到整个数据的图像数量,总类别名称和类别数量,还有每个类对应的标签,类别的名字,该类别的测试数据和训练数据的数量:

{"all_class_images": 2200,"all_class_name": "images","all_class_sum": 2,"class_detail": [{"class_label": 1,"class_name": "watermelon","class_test_images": 110,"class_trainer_images": 990},{"class_label": 2,"class_name": "cantaloupe","class_test_images": 110,"class_trainer_images": 990}]
}

定义模型

创建一个mobilenet_v1.py文件,在本章我们使用的是MobileNet神经网络,MobileNet是Google针对手机等嵌入式设备提出的一种轻量级的深层神经网络,它的核心思想就是卷积核的巧妙分解,可以有效减少网络参数,从而达到减小训练时网络的模型。因为太大的模型模型文件是不利于移植到移动设备上的,比如我们把模型文件迁移到Android手机应用上,那么模型文件的大小就直接影响应用安装包的大小。以下就是使用PaddlePaddle定义的MobileNet神经网络:

import paddle.fluid as fluiddef conv_bn_layer(input, filter_size, num_filters, stride,padding, channels=None, num_groups=1, act='relu', use_cudnn=True):conv = fluid.layers.conv2d(input=input,num_filters=num_filters,filter_size=filter_size,stride=stride,padding=padding,groups=num_groups,act=None,use_cudnn=use_cudnn,bias_attr=False)return fluid.layers.batch_norm(input=conv, act=act)
def depthwise_separable(input, num_filters1, num_filters2, num_groups, stride, scale):depthwise_conv = conv_bn_layer(input=input,filter_size=3,num_filters=int(num_filters1 * scale),stride=stride,padding=1,num_groups=int(num_groups * scale),use_cudnn=False)pointwise_conv = conv_bn_layer(input=depthwise_conv,filter_size=1,num_filters=int(num_filters2 * scale),stride=1,padding=0)return pointwise_conv
def net(input, class_dim, scale=1.0):# conv1: 112x112input = conv_bn_layer(input=input,filter_size=3,channels=3,num_filters=int(32 * scale),stride=2,padding=1)# 56x56input = depthwise_separable(input=input,num_filters1=32,num_filters2=64,num_groups=32,stride=1,scale=scale)input = depthwise_separable(input=input,num_filters1=64,num_filters2=128,num_groups=64,stride=2,scale=scale)# 28x28input = depthwise_separable(input=input,num_filters1=128,num_filters2=128,num_groups=128,stride=1,scale=scale)input = depthwise_separable(input=input,num_filters1=128,num_filters2=256,num_groups=128,stride=2,scale=scale)# 14x14input = depthwise_separable(input=input,num_filters1=256,num_filters2=256,num_groups=256,stride=1,scale=scale)input = depthwise_separable(input=input,num_filters1=256,num_filters2=512,num_groups=256,stride=2,scale=scale)# 14x14for i in range(5):input = depthwise_separable(input=input,num_filters1=512,num_filters2=512,num_groups=512,stride=1,scale=scale)# 7x7input = depthwise_separable(input=input,num_filters1=512,num_filters2=1024,num_groups=512,stride=2,scale=scale)input = depthwise_separable(input=input,num_filters1=1024,num_filters2=1024,num_groups=1024,stride=1,scale=scale)feature = fluid.layers.pool2d(input=input,pool_size=0,pool_stride=1,pool_type='avg',global_pooling=True)net = fluid.layers.fc(input=feature,size=class_dim,act='softmax')return net

定义数据读取

创建一个reader.py文件,这个程序就是用户训练和测试的使用读取数据的。训练的时候,通过这个程序从本地读取图片,然后通过一系列的预处理操作,最后转换成训练所需的Numpy数组。

首先导入所需的包,其中cpu_count是获取当前计算机有多少个CPU,然后使用多线程读取数据。

import os
import random
from multiprocessing import cpu_count
import numpy as np
import paddle
from PIL import Image

首先定义一个train_mapper()函数,这个函数是根据传入进来的图片路径来对图片进行预处理,比如训练的时候需要统一图片的大小,同时也使用多种的数据增强的方式,如水平翻转、垂直翻转、角度翻转、随机裁剪,这些方式都可以让有限的图片数据集在训练的时候成倍的增加。最后因为PIL打开图片存储顺序为H(高度),W(宽度),C(通道),PaddlePaddle要求数据顺序为CHW,所以需要转换顺序。最后返回的是处理后的图片数据和其对应的标签。

# 训练图片的预处理
def train_mapper(sample):img_path, label, crop_size, resize_size = sampletry:img = Image.open(img_path)# 统一图片大小img = img.resize((resize_size, resize_size), Image.ANTIALIAS)# 随机水平翻转r1 = random.random()if r1 > 0.5:img = img.transpose(Image.FLIP_LEFT_RIGHT)# 随机垂直翻转r2 = random.random()if r2 > 0.5:img = img.transpose(Image.FLIP_TOP_BOTTOM)# 随机角度翻转r3 = random.randint(-3, 3)img = img.rotate(r3, expand=False)# 随机裁剪r4 = random.randint(0, int(resize_size - crop_size))r5 = random.randint(0, int(resize_size - crop_size))box = (r4, r5, r4 + crop_size, r5 + crop_size)img = img.crop(box)# 把图片转换成numpy值img = np.array(img).astype(np.float32)# 转换成CHWimg = img.transpose((2, 0, 1))# 转换成BGRimg = img[(2, 1, 0), :, :] / 255.0return img, int(label)except:print("%s 该图片错误,请删除该图片并重新创建图像数据列表" % img_path)

这个train_reader()函数是根据已经创建的图像列表解析得到每张图片的路径和其他对应的标签,然后使用paddle.reader.xmap_readers()把数据传递给上面定义的train_mapper()函数进行处理,最后得到一个训练所需的reader。

# 获取训练的reader
def train_reader(train_list_path, crop_size, resize_size):father_path = os.path.dirname(train_list_path)def reader():with open(train_list_path, 'r') as f:lines = f.readlines()# 打乱图像列表np.random.shuffle(lines)# 开始获取每张图像和标签for line in lines:img, label = line.split('\t')img = os.path.join(father_path, img)yield img, label, crop_size, resize_sizereturn paddle.reader.xmap_readers(train_mapper, reader, cpu_count(), 102400)

这是一个测试数据的预处理函数test_mapper(),这个没有做太多处理,因为测试的数据不需要数据增强操作,只需统一图片大小和设置好图片的通过顺序和数据类型即可。

# 测试图片的预处理
def test_mapper(sample):img, label, crop_size = sampleimg = Image.open(img)# 统一图像大小img = img.resize((crop_size, crop_size), Image.ANTIALIAS)# 转换成numpy值img = np.array(img).astype(np.float32)# 转换成CHWimg = img.transpose((2, 0, 1))# 转换成BGRimg = img[(2, 1, 0), :, :] / 255.0return img, int(label)

这个是测试的reader函数test_reader(),这个跟训练的reader函数定义一样。

# 测试的图片reader
def test_reader(test_list_path, crop_size):father_path = os.path.dirname(test_list_path)def reader():with open(test_list_path, 'r') as f:lines = f.readlines()for line in lines:img, label = line.split('\t')img = os.path.join(father_path, img)yield img, label, crop_sizereturn paddle.reader.xmap_readers(test_mapper, reader, cpu_count(), 1024)

训练模型

万事俱备,只等训练了。关于PaddlePaddle训练流程,我们已经非常熟悉了,那么我们就简单地过一遍。

创建train.py文件,首先导入所需的包,其中包括我们定义的MobileNet模型和数据读取程序:

import os
import shutil
import mobilenet_v1
import paddle as paddle
import reader
import paddle.fluid as fluid

然后定义数据输入层,这次我们使用的是图片大小是224,这比之前使用的CIFAR数据集的32大小要大很多,所以训练其他会慢不少。至于resize_size是用于统一缩放到这个大小,然后再随机裁剪成crop_size大小,crop_size才是最终训练图片的大小。

crop_size = 224
resize_size = 250# 定义输入层
image = fluid.layers.data(name='image', shape=[3, crop_size, crop_size], dtype='float32')
label = fluid.layers.data(name='label', shape=[1], dtype='int64')

接着获取MobileNet网络的分类器,传入的第一个参数就是上面定义的输入层,第二个是分类的类别大小,比如我们这次爬取的图像类别数量是6个。

# 获取分类器,因为这次只爬取了6个类别的图片,所以分类器的类别大小为6
model = mobilenet_v1.net(image, 6)

再接着是获取损失函数和平均准确率函数,还有测试程序和优化方法,这个优化方法我加了正则,因为爬取的图片数量太少,在训练容易过拟合,所以加上正则一定程度上可以抑制过拟合。

# 获取损失函数和准确率函数
cost = fluid.layers.cross_entropy(input=model, label=label)
avg_cost = fluid.layers.mean(cost)
acc = fluid.layers.accuracy(input=model, label=label)# 获取训练和测试程序
test_program = fluid.default_main_program().clone(for_test=True)# 定义优化方法
optimizer = fluid.optimizer.AdamOptimizer(learning_rate=1e-3,regularization=fluid.regularizer.L2DecayRegularizer(1e-4))
opts = optimizer.minimize(avg_cost)

这里就是获取训练测试是所以想的数据读取reader,通过使用paddle.batch()函数可以把多条数据打包成一个批次,训练的时候是按照一个个批次训练的。

# 获取自定义数据
train_reader = paddle.batch(reader=reader.train_reader('images/train.list', crop_size, resize_size), batch_size=32)
test_reader = paddle.batch(reader=reader.test_reader('images/test.list', crop_size), batch_size=32)

执行训练之前,还需要创建一个执行器,建议使用GPU进行训练,因为我们训练的图片比较大,所以使用CPU训练速度会相当的慢。

# 定义一个使用GPU的执行器
place = fluid.CUDAPlace(0)
# place = fluid.CPUPlace()
exe = fluid.Executor(place)
# 进行参数初始化
exe.run(fluid.default_startup_program())# 定义输入数据维度
feeder = fluid.DataFeeder(place=place, feed_list=[image, label])

最后终于可以执行训练了,这里跟在前些章节都几乎一样,就不重复介绍了。

# 训练100次
for pass_id in range(100):# 进行训练for batch_id, data in enumerate(train_reader()):train_cost, train_acc = exe.run(program=fluid.default_main_program(),feed=feeder.feed(data),fetch_list=[avg_cost, acc])# 每100个batch打印一次信息if batch_id % 100 == 0:print('Pass:%d, Batch:%d, Cost:%0.5f, Accuracy:%0.5f' %(pass_id, batch_id, train_cost[0], train_acc[0]))# 进行测试test_accs = []test_costs = []for batch_id, data in enumerate(test_reader()):test_cost, test_acc = exe.run(program=test_program,feed=feeder.feed(data),fetch_list=[avg_cost, acc])test_accs.append(test_acc[0])test_costs.append(test_cost[0])# 求测试结果的平均值test_cost = (sum(test_costs) / len(test_costs))test_acc = (sum(test_accs) / len(test_accs))print('Test:%d, Cost:%0.5f, Accuracy:%0.5f' % (pass_id, test_cost, test_acc))

训练的过程中可以保存预测模型,用于之后的预测。笔者一般是每一个pass保存一次模型。

    # 保存预测模型save_path = 'infer_model/'# 删除旧的模型文件shutil.rmtree(save_path, ignore_errors=True)# 创建保持模型文件目录os.makedirs(save_path)# 保存预测模型fluid.io.save_inference_model(save_path, feeded_var_names=[image.name], target_vars=[model], executor=exe)

训练输出的信息:

Pass:0, Batch:0, Cost:1.84754, Accuracy:0.15625
Test:0, Cost:4.66276, Accuracy:0.17857
Pass:1, Batch:0, Cost:1.04008, Accuracy:0.59375
Test:1, Cost:1.23828, Accuracy:0.54464
Pass:2, Batch:0, Cost:1.04778, Accuracy:0.65625
Test:2, Cost:0.99189, Accuracy:0.64286
Pass:3, Batch:0, Cost:1.21555, Accuracy:0.65625
Test:3, Cost:1.01552, Accuracy:0.57589
Pass:4, Batch:0, Cost:0.64620, Accuracy:0.81250
Test:4, Cost:1.19264, Accuracy:0.63393

预测图片

经过上面训练后,得到了一个预测模型,下面我们就使用一个预测模型来预测一些图片。

创建一个infer.py文件作为预测程序。首先导入所需的依赖包。

import paddle.fluid as fluid
from PIL import Image
import numpy as np

创建一个执行器,这些不需要训练,所以可以使用CPU进行预测,速度不会太慢,当然,使用GPU的预测速度会更快一些。

# 创建执行器
place = fluid.CPUPlace()
exe = fluid.Executor(place)
exe.run(fluid.default_startup_program())

然后加载预测模型,获取预测程序和输入层的名字,还有网络的分类器。

# 保存预测模型路径
save_path = 'infer_model/'
# 从模型中获取预测程序、输入数据名称列表、分类器
[infer_program, feeded_var_names, target_var] = fluid.io.load_inference_model(dirname=save_path, executor=exe)

预测图片之前,还需要对图片进行预处理,处理的方式跟测试的时候处理的方式一样。

# 预处理图片
def load_image(file):img = Image.open(file)# 统一图像大小img = img.resize((224, 224), Image.ANTIALIAS)# 转换成numpy值img = np.array(img).astype(np.float32)# 转换成CHWimg = img.transpose((2, 0, 1))# 转换成BGRimg = img[(2, 1, 0), :, :] / 255.0img = np.expand_dims(img, axis=0)return img

最后获取经过预处理的图片数据,再使用这些图像数据进行预测,得到分类结果。

# 获取图片数据
img = load_image('images/apple/0fdd5422-31e0-11e9-9cfd-3c970e769528.jpg')# 执行预测
result = exe.run(program=infer_program,feed={feeded_var_names[0]: img},fetch_list=target_var)

我们可以通过解析分类的结果,获取概率最大类别标签。关于预测输出的result是数据,它是3维的,第一层是输出本身就是一个数组,第二层图片的数量,因为PaddlePaddle支持多张图片同时预测,最后一层就是每个类别的概率,这个概率的总和为1,概率最大的标签就是预测结果。

# 显示图片并输出结果最大的label
lab = np.argsort(result)[0][0][-1]names = ['苹果', '哈密瓜', '胡萝卜', '樱桃', '黄瓜', '西瓜']print('预测结果标签为:%d, 名称为:%s, 概率为:%f' % (lab, names[lab], result[0][0][lab]))

预测输出的结果:

预测结果标签为:0, 名称为:苹果, 概率为:0.948698

PaddlePaddle入门整理十:PaddlePaddle训练自己的数据集相关推荐

  1. pyTorch入门(五)——训练自己的数据集

    学更好的别人, 做更好的自己. --<微卡智享> 本文长度为1749字,预计阅读5分钟 前言 前面四篇将Minist数据集的训练及OpenCV的推理都介绍完了,在实际应用项目中,往往需要用 ...

  2. 深度学习入门——利用卷积神经网络训练CIFAR—10数据集

    CIFAR-10数据集简介 CIFAR-10是由Hinton的学生Alex Krizhevsky和Ilya Sutskever整理的一个用于普适物体的小型数据集.它一共包含10个类别的RGB彩色图片: ...

  3. yolov5训练自己的数据集,OpenCV DNN推理

    学更好的别人, 做更好的自己. --<微卡智享> 本文长度为4238字,预计阅读9分钟 前言 上一篇<OpenCV--自学笔记>搭建好了yolov5的环境,作为目标检测在应用中 ...

  4. 图像分类任务不用冷启动,PaddlePaddle一口气发布十大预训练模型

    https://www.toutiao.com/a6645090596073505293/ 2019-01-11 12:25:20 PaddlePaddle在不断增加官方支持的模型的同时,也在关注预训 ...

  5. 新手入门机器学习十大算法

    新手入门机器学习十大算法 2018年9月17日 磐石 TensorFlowNews, 机器学习 0 在机器学习的世界中,有一种被称为"无免费午餐"的定理. 它意在说明没有哪种算法能 ...

  6. 无人驾驶汽车系统入门(十二)——卷积神经网络入门,基于深度学习的车辆实时检测

    无人驾驶汽车系统入门(十二)--卷积神经网络入门,基于深度学习的车辆实时检测 上篇文章我们讲到能否尽可能利用上图像的二维特征来设计神经网络,以此来进一步提高识别的精度.在这篇博客中,我们学习一类专门用 ...

  7. 推荐系统入门(十):新闻推荐实践5(附代码)

    推荐系统入门(十):新闻推荐实践5(附代码) 目录 推荐系统入门(十):新闻推荐实践5(附代码) 前言 LGB模型 DIN模型 一.排序模型 1.LGB排序模型 2.LGB分类模型 3.DIN模型 二 ...

  8. VPLC系列机器视觉运动控制一体机快速入门(十)

    此前,我们依次讲解了软硬件介绍及计数实例.相机的基本使用.基于形状匹配的视觉定位.BLOB有无检测.测量尺寸.机器视觉方案中使用到的标定功能.ZDevelop软件实现识别条形码和二维码,测量点/直线/ ...

  9. UWP开发入门(十六)——常见的内存泄漏的原因

    原文:UWP开发入门(十六)--常见的内存泄漏的原因 本篇借鉴了同事翔哥的劳动成果,在巨人的肩膀上把稿子又念了一遍. 内存泄漏的概念我这里就不说了,之前<UWP开发入门(十三)--用Diagno ...

  10. UWP开发入门(十九)——10分钟学会在VS2015中使用Git

    原文:UWP开发入门(十九)--10分钟学会在VS2015中使用Git 写程序必然需要版本控制,哪怕是个人项目也是必须的.我们在开发UWP APP的时候,VS2015默认提供了对微软TFS和Git的支 ...

最新文章

  1. Flex报错Error #2048: 安全沙箱冲突
  2. 入职后发现公司是外包全职_我如何通过全职工作,伴侣和3岁的双胞胎男孩打造产品...
  3. oracle按照时间过滤
  4. ANSYS配合时如何选择重合面(打开爆炸视图)
  5. linux打包压缩命令汇总
  6. 提高办公效率的个Excel技巧,告别苦加班!
  7. Unofficial Windows Binaries for Python Extension Packages
  8. 使用机器学习预测天气_使用机器学习的二手车价格预测
  9. 数据基本类型以及相关举例
  10. 为拯救爸妈朋友圈,达摩院造了“谣言粉碎机” 1
  11. 面试官:Netty的线程模型可不是Reactor这么简单
  12. Bootstrap自适应居中问题
  13. opencv 编译安装时出现报错 modules/videoio/src/cap_ffmpeg_impl.hpp:585:34: error: ‘AVStream {aka struct AVStre
  14. Excel 公式 lenB无效 解决方案
  15. 大数据时代,海量数据处理常用思路和方法总结
  16. 经验分享 | 我是如何从小白到收获几个不错的offer!
  17. 新手小白学吉他,如何掌握基础快速入门
  18. hdu 1873 看病要排队
  19. 宋体能力从业的一些感悟
  20. 盘古开源丨数据大爆炸时代,云存储成为企业存储必然发展方向

热门文章

  1. Andrew Ng-ML习题答案1
  2. Android WebView 图片加载不出来
  3. 海康威视网络摄像机远程监控配置(DDNS)
  4. 厦门大学马来西亚分校打造更美好的智慧校园
  5. Linux下怎么mount下载宝硬盘为本地目录
  6. 数组的常用算法(1)--由“为了集齐108将买多少袋干脆面”展开去
  7. Hexo+腾讯云+Icarus主题 搭建自定义个人博客
  8. PTA 求链式线性表的倒数第K项 给定一系列正整数,请设计一个尽可能高效的算法,查找倒数第K个位置上的数字。
  9. 云计算基础平台iaas(openstack)超级详细搭建(三)安装服务
  10. Cabbage教学(3)——数学计算和文件操作