python+OpenCV笔记(三十八):识别手写数字——基于人工神经网络ANN

本文主要是介绍python+OpenCV笔记(三十八):识别手写数字——基于人工神经网络ANN,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

一、简单理解人工神经网络

理解神经元和感知器

理解神经网络的层

二、基于人工神经网络识别手写数字

流程

一、(训练模块)——digits_ann.py

二、(测试模块)——digits_ann.py

三、(主模块)——detect_and_classify_digits.py

三、全部代码

1.digits_ann.py

2.detect_and_classify_digits.py

四、保存与加载分类器


一、简单理解人工神经网络

        (理解人工神经网络可跳过此节)

        人工神经网络是一个统计模型。统计模型是一对元素,即空间S(一组观测数据)和概率P,其中P是近似于S的一个分布(或者说是一个函数,会产生一系列和S非常相似的观测结果)。
        因此,人工神经网络是将复杂的现实问题进行简化,并推导出函数的一种模型,使推导函数以数学形式(近似地)表示我们期望从那个现实问题中得到的统计观测结果。

        神经网络的一个定义特征是神经元必须能够近似非线性函数。

理解神经元和感知器

        通常,为了解决分类问题,会将人工神经网络设计成多层感知器,其中每个神经元作为一种称为感知器的二值分类器。

        简单地说,感知器是一个函数,它接受多个输入并产生单个值。每个输入都有一个相关的权重,表示该输入在激活函数中的重要性。激活函数应具有非线性响应,例如常见的sigmoid函数(有时也称为s曲线),阈值函数(称为判别函数)被应用到激活函数的输出,将其转换成0或1的二值分类,如图:


输入权重代表什么,如何确定这些权重?
神经元之间是相互连接的,因为一个神经元的输出可以成为许多其他神经元的输入。
输入权重定义了两个神经元之间的连接强度。这些权重是自适应的,这意味着权重会根据学习算法随时间而变化。
由于神经元的互联性,网络有多层。现在,我们来看这些层通常是如何组织的。

理解神经网络的层

         神经网络中至少有3个不同的层:输入层、隐藏层和输出层。

        虽然可以有多个隐藏层,但是,往往一个隐藏层就足以解决许多现实生活中的问题。有时将拥有多个隐藏层的神经网络称为深度神经网络(DNN)。如图:

 输入层:

        输入层的节点数量就是网络的输入数量。例如:如果选择根据重量、长度和牙齿数量对动物进行分类,那么输入集包含3个属性,因此网络需要包含3个输入节点。

输出层:

        对于分类器来说,输出层节点的数量定义为网络能够区分的类的数量。例如:如果我们知道要分类的动物有:狗、秃鹰、海豚和龙,那么可以使用有4个节点的输出层。

隐藏层:

        对于隐藏层大小的选择,并没有统一的经验法则,必须在实验的基础上进行选择。对于想要应用人工神经网络的每个实际问题,都需要对人工神经网络进行训练、测试、再训练,直到找到可以获得可接受准确率的隐藏节点。

什么是过拟合?

        为得到一致假设而使假设变得过度复杂称为过拟合。
        比如:某种学习算法产生了一个过拟合的分类器,这个分类器能够百分之百的正确分类样本数据,即再拿样本中的文档来给它,它绝对不会分错,但也就为了能够对样本完全正确的分类,使得它的构造如此精细复杂,规则如此严格,以至于任何与样本数据稍有不同的文档它全都认为不属于这个类别。
        在这里指的是,与训练数据实际提供的信息相比,隐含层中包含的伪信息过多时,就会发生过拟合,导致分类不是很有意义。

二、基于人工神经网络识别手写数字

流程

一、(训练模块)——digits_ann.py

                                ——请先创建该脚本文件

  1. 获取数据
    可在MNIST handwritten digit database, Yann LeCun, Corinna Cortes and Chris Burges上公开获取MNIST数据库。数据库具有 60,000 个示例的训练集和 10,000 个示例的测试集。数字已经过尺寸标准化,并在固定尺寸的图像中居中。且所有的训练和测试图像都是灰度格式,尺寸为28*28像素,下载页面如图:

    (注意:接下来的脚本中,下载的该文件会无法使用,所以我们使用与其相同的其他文件,下载地址GitHub(文件名:mnist.pkl.gz):https://github.com/PacktPublishing/Learning-OpenCV-4-Computer-Vision-with-Python-Third-Edition/tree/master/chapter10/digits_datahttps://github.com/PacktPublishing/Learning-OpenCV-4-Computer-Vision-with-Python-Third-Edition/tree/master/chapter10/digits_data
  2. 选择训练参数
    每个MNIST样本都是一个包含784像素(即28×28像素)的图像。因此,我们的人工神经网络输入层将有784个节点。输出层将有10个节点,因为有10类数字(0到9)。
    我们可以自由选择其他参数的值,如隐含层中的节点数、要使用的训练样本数、训练阶段数等。通常,实验可以帮助我们找到提供可接受训练时间和准确率的参数值,而不会于训练数据上将模型过拟合。基于本书作者所做的一些实验,我们将使用60个隐藏节点、50000个训练样本、10个阶段。这些参数足以进行初步测试,将训练时间控制在几分钟之内(取决于计算机的处理能力)。
  3. 从Python库中导入gzip和pickle模块,以及 OpenCV 和 NumPy
    import gzip
    import pickleimport cv2
    import numpy as np

    我们将使用gzip和pickle模块从下载的文件中加载并解压MNIST数据。
    该文件以嵌套元组的方式包含MNIST数据,格式如下:
    ((training_images, training_ids),
    (test_images, test_ids))

    这些元组的元素依次采用以下格式:
    (1)training-images是一个NumPy数组,由60000幅图像组成,其中每幅图像都是由784个像素值组成的向量(从28×28像素的原始形状展平而来)。像素值是0.0(黑色)到1.0(白色)范围内(含边界值)的浮点数。
    (2)training_ids是一个NumPy数组,包含60000个数字ID,其中每个ID是范围为0到9(包括边界值)的一个数字。training_ids[i]对应于training_images[i]。
    (3)test_images是由10 000幅图像组成的NumPy数组,其中每幅图像都是由784个像素值组成的向量(从原始形状28×28像素展平而来)。像素值是0.0(黑色)到1.0(白色)范围内(含边界值)的浮点数。
    (4)test_ids是一个NumPy数组,包含10000个数字ID,其中每个ID都是范围为0到9(包括边界值)的一个数字。test_ids[i]对应于test_images[i]。

  4. 编写以下辅助函数,加载并解压已下载文件的内容

    def load_data():mnist = gzip.open('mnist.pkl.gz', 'rb')training_data, test_data = pickle.load(mnist)mnist.close()return (training_data, test_data)

    注意,在前面的代码中,training_data是一个元组,相当于(training_images,training_ids),而且test_data也是一个元组,相当于(test_images,test_ids)

  5. 我们必须重新格式化原始数据,以匹配OpenCV所期望的格式。具体来说,当提供样本输出来训练人工神经网络时,它必须是一个有10个元素(对于10类数字)的向量,而不是单个数字ID。为了方便起见,我们还将应用Python内置的zip函数来重新组织数据,这样就可以以元组的形式遍历输入和输出向量的匹配对。我们编写以下辅助函数,重新格式化数据:

    def wrap_data():tr_d, te_d = load_data()training_inputs = tr_d[0]training_results = [vectorized_result(y) for y in tr_d[1]]training_data = zip(training_inputs, training_results)test_data = zip(te_d[0], te_d[1])return (training_data, test_data)

    其中,vectorized_result()函数将ID转换为一个分类向量,如下:

    def vectorized_result(j):e = np.zeros((10,), np.float32)e[j] = 1.0return e

    再回忆一下,从文件读入的 training_data[0] 是图像向量,是NumPy数组,而 training_data[1] 是与前者一一对应的数字ID,未修改格式之前,training_data[1] 的数据如图:

    我们很容易看出,这些数字表示:第一张图像的数字表示是5,第二张表示是0......
    经过vectorized_result()函数之后,转变为了向量,如图:

    也很容易理解,第一个向量的第5位为1,代表数字5...... 

     总之,10个元素的数组对应于人工神经网络的输出层,在训练人工神经网络时,可以将其作为正确输出的一个样本。

  6. 到目前为止,我们已经编写了加载和重新格式化MNIST数据的函数。现在,我们来编写一个函数,用于创建未训练的人工神经网络

    def create_ann(hidden_nodes=60):ann = cv2.ml.ANN_MLP_create()ann.setLayerSizes(np.array([784, hidden_nodes, 10]))ann.setActivationFunction(cv2.ml.ANN_MLP_SIGMOID_SYM, 0.6, 1.0)ann.setTrainMethod(cv2.ml.ANN_MLP_BACKPROP, 0.1, 0.1)ann.setTermCriteria((cv2.TERM_CRITERIA_MAX_ITER | cv2.TERM_CRITERIA_EPS, 100, 1.0))return ann

    解析:
    (1)hidden_nodes代表我们使用60个隐藏结点,步骤2提到过。
    (2)ann = cv2.ml.ANN_MLP_create():创建一个未训练的人工神经网络
    (3)ann.setLayerSizes(np.array([784, hidden_nodes, 10])):配置人工神经网络的层数和节点数,例如,[784, 60, 10] 代表指定784个输入节点,10个输出节点以及包含60个节点的一个隐藏层。如果将其改成 [784, 60, 50, 10] ,将指定两个隐藏层,分别有60个节点和50个节点。
    (4)ann.setActivationFunction:激活函数
    (5)ann.setTrainMethod:训练方法
    (6)ann.setTermCriteria:训练终止标准

  7. 现在,我们需要一个训练函数,允许调用者指定MNIST训练样本数量和阶段数。很多训练功能应该与之前的人工神经网络样本相似,因此,我们先看一下完整的实现:

    def train(ann, samples=50000, epochs=10):tr, test = wrap_data()# 将迭代器转换为列表,以便我们可以在多个阶段中迭代多次tr = list(tr)for epoch in range(epochs):print("已完成 %d/%d 个阶段" % (epoch, epochs))counter = 0for img in tr:if (counter > samples):breakif (counter % 1000 == 0):print("阶段 %d: 对第 %d/%d 个样本进行训练" % \(epoch, counter, samples))counter += 1sample, response = imgdata = cv2.ml.TrainData_create(np.array([sample], dtype=np.float32),cv2.ml.ROW_SAMPLE,np.array([response], dtype=np.float32))if ann.isTrained():ann.train(data,cv2.ml.ANN_MLP_UPDATE_WEIGHTS | cv2.ml.ANN_MLP_NO_INPUT_SCALE | cv2.ml.ANN_MLP_NO_OUTPUT_SCALE)else:ann.train(data, cv2.ml.ANN_MLP_NO_INPUT_SCALE | cv2.ml.ANN_MLP_NO_OUTPUT_SCALE)print("全部完成!")return ann, test

    解析:
    (1)函数参数在步骤2中提到过,代表我们使用50000个训练样本,10个阶段。
    (2)
    对于我们处理的每1000个训练样本,打印一条关于训练进展的消息。
    (3)最后,返回训练好的人工神经网络和MNIST测试数据。本来我们可以直接返回人工神经网络,但是如果想要查看人工神经网络的准确率,返回测试数据是很有用的。

  8. 当然,训练人工神经网络的目标是进行预测,因此我们会提供以下pedict函数,以便封装人工神经网络自己的predict方法:

    def predict(ann, sample):if sample.shape != (784,):if sample.shape != (28, 28):sample = cv2.resize(sample, (28, 28),interpolation=cv2.INTER_LINEAR)sample = sample.reshape(784, )return ann.predict(np.array([sample], dtype=np.float32))

    首先,该函数确保样本图像是28×28并通过调整大小(如果不是28×28的话)来执行最小数量的数据清理。
    然后,该函数将图像数据展平成向量,再交给人工神经网络进行分类。

  9. 最后,我们还要再实现一个_test_函数,对一组给定的测试数据(如MNIST测试数据)进行分类,测量经训练的人工神经网络的准确率:

    def test(ann, test_data):num_tests = 0num_correct = 0for img in test_data:num_tests += 1sample, correct_digit_class = imgdigit_class = predict(ann, sample)[0]if digit_class == correct_digit_class:num_correct += 1print('准确率: %.2f%%' % (100.0 * num_correct / num_tests))

二、(测试模块)——digits_ann.py

  •  在上面的函数之后添加代码:
    ann, test_data = train(create_ann())
    _test_(ann, test_data)
    运行脚本,他应该会打印如下的训练信息:
    .
    .
    .


    .
    .
    .

可以看到,在MINST数据集的10000个测试样本时,人工神经网络的准确率达到了95.39%,那我们来看看人工神经网络的泛化性能如何:即它能对完全不同来源且与MINST无关的数据进行准确的分类吗?我们的主应用程序将为分类器迎接这类挑战。

三、(主模块)——detect_and_classify_digits.py

                            ——请先创建该脚本文件

  1. 首先,导入OpenCV、NumPy以及digits_ann模块
    import cv2
    import numpy as npimport digits_ann
  2. 编写两个辅助函数,分析并调整数字和其他轮廓的矩形框。正如我们在前面章节中看到的,一个常见的问题是重叠检测。下面的函数名为inside,将帮助我们确定边框是否完全包含在另一个边框中:
    def inside(r1, r2):x1, y1, w1, h1 = r1x2, y2, w2, h2 = r2return (x1 > x2) and (y1 > y2) and (x1+w1 < x2+w2) and \(y1+h1 < y2+h2)

    在inside函数的帮助下,我们可以很容易地选择每个数字最外层的边框。这一点很重要,因为我们不希望检测器将数字8同时还能检测出两个0。

  3. 为了进一步确保矩形框满足分类器的需要,我们将使用名为wrap_digit的辅助函数,将紧密拟合的矩形框转换为包围数字的填充正方形。请记住,MNIST数据包含28×28像素的数字图像,所以在尝试使用MNIST训练的人工神经网络进行分类之前,必须将任何感兴趣的区域重新缩放到这个大小。通过使用填充的边框而不是紧密拟合的矩形边框,我们可以确保瘦数字(如1)和胖数字(如0)的拉伸不会不同。
    def wrap_digit(rect, img_w, img_h):x, y, w, h = rectx_center = x + w//2y_center = y + h//2if (h > w):w = hx = x_center - (w//2)else:h = wy = y_center - (h//2)padding = 5x -= paddingy -= paddingw += 2 * paddingh += 2 * paddingif x < 0:x = 0elif x > img_w:x = img_wif y < 0:y = 0elif y > img_h:y = img_hif x+w > img_w:w = img_w - xif y+h > img_h:h = img_h - yreturn x, y, w, h

    解析:
    (1)首先,修改矩形的较短边(不管是宽还是高),使其等于较长的边,修改矩形的x, y位置,使中心保持不变。
    (2)在四周添加5个像素,此时,修改的矩形可能会延伸到图像的外部。
    (3)
    为了避免越界的问题,我们裁剪矩形使矩形完全位于图像内。在这些边缘情况下,我们可能会得到非正方形矩形,但是这是可以接受的。我们更喜欢使用感兴趣的非正方形区域,而不是仅因为检测到的数字在图像的边缘处就必须完全丢弃它
    (4)返回修改后的矩形坐标

  4. 现在,我们进入主程序部分。首先,创建人工神经网络,并在MNIST数据上对其进行训练:

    ann, test_data = digits_ann.train(digits_ann.create_ann(60), 50000, 10)

    (请注意,我们使用的是digits_ann模块中的create_ann和train函数)

  5. 现在,加载一幅测试图像(一页白纸上包含许多手写数字的图像):
    img_path = "654321.jpg"
    img = cv2.imread(img_path, cv2.IMREAD_COLOR)

    (图像可以自己手写,注意最好是白底黑字)

  6. 把图像转换成灰度图像并对其进行模糊,以便去除噪声,并使墨水的颜色均匀一些:
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    cv2.GaussianBlur(gray, (7, 7), 0, gray)

    应用阈值以及形态学运算,确保数字从背景中脱颖而出,而且轮廓相对不规则,这可能会干扰预测

    ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY_INV)
    erode_kernel = np.ones((2, 2), np.uint8)
    thresh = cv2.erode(thresh, erode_kernel, thresh, iterations=2)

    为了检测图片中的每个数字,首先需要找到轮廓:

    contours, hier = cv2.findContours(thresh, cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

    然后,遍历轮廓并找到它们的矩形框。丢弃所有太大或太小而不能视为数字的矩形,同时丢弃所有完全包含在其他矩形中的矩形。把其余的矩形添加到好的矩形列表中,(我们认为)这些矩形包含单个的数字。

    rectangles = []img_h, img_w = img.shape[:2]
    img_area = img_w * img_h
    for c in contours:a = cv2.contourArea(c)if a >= 0.98 * img_area or a <= 0.0001 * img_area:continuer = cv2.boundingRect(c)is_inside = Falsefor q in rectangles:if inside(r, q):is_inside = Truebreakif not is_inside:rectangles.append(r)

    既然有了好的矩形列表,那么就可以遍历它们,使用wrap_digit函数对该列表进行清理,并对其内的图像数据进行分类:

    for r in rectangles:x, y, w, h = wrap_digit(r, img_w, img_h)roi = thresh[y:y+h, x:x+w]digit_class = int(digits_ann.predict(ann, roi)[0])cv2.rectangle(img, (x,y), (x+w, y+h), (255, 0, 0), 2)cv2.putText(img, "%d" % digit_class, (x, y-5),cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)
  7. 在处理完所有感兴趣的区域后,显示这些图像,直到用户按下任意键结束程序
    cv2.imshow("thresh", thresh)
    cv2.imshow("detected and classified digits", img)
    cv2.waitKey()

三、全部代码

digits_ann.py 和 detect_and_classify_digits.py两个文件

1.digits_ann.py

import gzip
import pickleimport cv2
import numpy as np"""OpenCV ANN Handwritten digit recognition exampleWraps OpenCV's own ANN by automating the loading of data and supplying default paramters,
such as 20 hidden layers, 10000 samples and 1 training epoch.The load data code is adapted from http://neuralnetworksanddeeplearning.com/chap1.html
by Michael Nielsen
"""def load_data():mnist = gzip.open('mnist.pkl.gz', 'rb')training_data, test_data = pickle.load(mnist)mnist.close()return (training_data, test_data)def wrap_data():tr_d, te_d = load_data()training_inputs = tr_d[0]training_results = [vectorized_result(y) for y in tr_d[1]]training_data = zip(training_inputs, training_results)test_data = zip(te_d[0], te_d[1])return (training_data, test_data)def vectorized_result(j):e = np.zeros((10,), np.float32)e[j] = 1.0return edef create_ann(hidden_nodes=60):ann = cv2.ml.ANN_MLP_create()ann.setLayerSizes(np.array([784, hidden_nodes, 10]))ann.setActivationFunction(cv2.ml.ANN_MLP_SIGMOID_SYM, 0.6, 1.0)ann.setTrainMethod(cv2.ml.ANN_MLP_BACKPROP, 0.1, 0.1)ann.setTermCriteria((cv2.TERM_CRITERIA_MAX_ITER | cv2.TERM_CRITERIA_EPS, 100, 1.0))return anndef train(ann, samples=50000, epochs=10):tr, test = wrap_data()# 将迭代器转换为列表,以便我们可以在多个阶段中迭代多次tr = list(tr)for epoch in range(epochs):print("已完成 %d/%d 个阶段" % (epoch, epochs))counter = 0for img in tr:if (counter > samples):breakif (counter % 1000 == 0):print("阶段 %d: 对第 %d/%d 个样本进行训练" % \(epoch, counter, samples))counter += 1sample, response = imgdata = cv2.ml.TrainData_create(np.array([sample], dtype=np.float32),cv2.ml.ROW_SAMPLE,np.array([response], dtype=np.float32))if ann.isTrained():ann.train(data,cv2.ml.ANN_MLP_UPDATE_WEIGHTS | cv2.ml.ANN_MLP_NO_INPUT_SCALE | cv2.ml.ANN_MLP_NO_OUTPUT_SCALE)else:ann.train(data, cv2.ml.ANN_MLP_NO_INPUT_SCALE | cv2.ml.ANN_MLP_NO_OUTPUT_SCALE)print("全部完成!")return ann, testdef _test_(ann, test_data):num_tests = 0num_correct = 0for img in test_data:num_tests += 1sample, correct_digit_class = imgdigit_class = predict(ann, sample)[0]if digit_class == correct_digit_class:num_correct += 1print('准确率: %.2f%%' % (100.0 * num_correct / num_tests))def predict(ann, sample):if sample.shape != (784,):if sample.shape != (28, 28):sample = cv2.resize(sample, (28, 28),interpolation=cv2.INTER_LINEAR)sample = sample.reshape(784, )return ann.predict(np.array([sample], dtype=np.float32))# ann, test_data = train(create_ann())
# _test_(ann, test_data)

2.detect_and_classify_digits.py

import cv2
import numpy as npimport digits_annOPENCV_MAJOR_VERSION = int(cv2.__version__.split('.')[0])def inside(r1, r2):x1, y1, w1, h1 = r1x2, y2, w2, h2 = r2return (x1 > x2) and (y1 > y2) and (x1+w1 < x2+w2) and \(y1+h1 < y2+h2)def wrap_digit(rect, img_w, img_h):x, y, w, h = rectx_center = x + w//2y_center = y + h//2if (h > w):w = hx = x_center - (w//2)else:h = wy = y_center - (h//2)padding = 5x -= paddingy -= paddingw += 2 * paddingh += 2 * paddingif x < 0:x = 0elif x > img_w:x = img_wif y < 0:y = 0elif y > img_h:y = img_hif x+w > img_w:w = img_w - xif y+h > img_h:h = img_h - yreturn x, y, w, hann, test_data = digits_ann.train(digits_ann.create_ann(60), 50000, 10)img_path = "654321.jpg"
img = cv2.imread(img_path, cv2.IMREAD_COLOR)gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.GaussianBlur(gray, (7, 7), 0, gray)ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY_INV)
erode_kernel = np.ones((2, 2), np.uint8)
thresh = cv2.erode(thresh, erode_kernel, thresh, iterations=2)if OPENCV_MAJOR_VERSION >= 4:# OpenCV 4 or a later version is being used.contours, hier = cv2.findContours(thresh, cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
else:# OpenCV 3 or an earlier version is being used.# cv2.findContours has an extra return value.# The extra return value is the thresholded image, which is# unchanged, so we can ignore it._, contours, hier = cv2.findContours(thresh, cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)rectangles = []img_h, img_w = img.shape[:2]
img_area = img_w * img_h
for c in contours:a = cv2.contourArea(c)if a >= 0.98 * img_area or a <= 0.0001 * img_area:continuer = cv2.boundingRect(c)is_inside = Falsefor q in rectangles:if inside(r, q):is_inside = Truebreakif not is_inside:rectangles.append(r)for r in rectangles:x, y, w, h = wrap_digit(r, img_w, img_h)roi = thresh[y:y+h, x:x+w]digit_class = int(digits_ann.predict(ann, roi)[0])cv2.rectangle(img, (x,y), (x+w, y+h), (255, 0, 0), 2)cv2.putText(img, "%d" % digit_class, (x, y-5),cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)# cv2.imwrite("detected_and_classified_digits_thresh.png", thresh)
# cv2.imwrite("detected_and_classified_digits.png", img)
cv2.imshow("thresh", thresh)
cv2.imshow("detected and classified digits", img)
cv2.waitKey()

运行第二个脚本文件:

 示例图片下载地址(GitHub):GitHub - PacktPublishing/Learning-OpenCV-4-Computer-Vision-with-Python-Third-Edition: Learning OpenCV 4 Computer Vision with Python 3 – Third Edition, published by Packt

四、保存与加载分类器

我们可以应用一些潜在的改进措施来训练人工神经网络,例如:

  • 可以用不同数据集大小、隐藏节点的数量以及阶段数进行实验,直到找到准确率的峰值水平
  • 可以修改digits_ann.create_ann 函数,使其支持多个隐藏层
  • 还可以尝试不同的激活函数
  • 也可以尝试不同的训练方法。我们使用了cv2.m1.ANN_MLP_BACKPROP。
    其他的包括cV2.M1.ANN_MLP_RPROP 和cv2.m1.ANN_MLP_ANNEAL

总之,请记住,只要我们对分类器的准确率感到满意,我们就可以保存并重新加载这个分类器,这样就可以在应用程序中使用分类器,而不必每次都训练人工神经网络。

使用下面的代码将经过训练的人工神经网络保存到XML文件中:


ann = cv2.ml.ANN_MLP_create()
data = cv2.ml.TrainData_create(
        training_samples, layout, training_responses)
ann.train(data)
ann.save('my_ann.xml')


加载:


ann = cv2,m1.ANN_MLP_create()
ann.load('my_ann.xml') 


 

【参考】:OpenCV 4计算机视觉 Python语言实现(原书第三版) 作者:Joseph Howse

这篇关于python+OpenCV笔记(三十八):识别手写数字——基于人工神经网络ANN的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/613347

相关文章

python管理工具之conda安装部署及使用详解

《python管理工具之conda安装部署及使用详解》这篇文章详细介绍了如何安装和使用conda来管理Python环境,它涵盖了从安装部署、镜像源配置到具体的conda使用方法,包括创建、激活、安装包... 目录pytpshheraerUhon管理工具:conda部署+使用一、安装部署1、 下载2、 安装3

Python进阶之Excel基本操作介绍

《Python进阶之Excel基本操作介绍》在现实中,很多工作都需要与数据打交道,Excel作为常用的数据处理工具,一直备受人们的青睐,本文主要为大家介绍了一些Python中Excel的基本操作,希望... 目录概述写入使用 xlwt使用 XlsxWriter读取修改概述在现实中,很多工作都需要与数据打交

使用Python实现在Word中添加或删除超链接

《使用Python实现在Word中添加或删除超链接》在Word文档中,超链接是一种将文本或图像连接到其他文档、网页或同一文档中不同部分的功能,本文将为大家介绍一下Python如何实现在Word中添加或... 在Word文档中,超链接是一种将文本或图像连接到其他文档、网页或同一文档中不同部分的功能。通过添加超

Python MySQL如何通过Binlog获取变更记录恢复数据

《PythonMySQL如何通过Binlog获取变更记录恢复数据》本文介绍了如何使用Python和pymysqlreplication库通过MySQL的二进制日志(Binlog)获取数据库的变更记录... 目录python mysql通过Binlog获取变更记录恢复数据1.安装pymysqlreplicat

利用Python编写一个简单的聊天机器人

《利用Python编写一个简单的聊天机器人》这篇文章主要为大家详细介绍了如何利用Python编写一个简单的聊天机器人,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 使用 python 编写一个简单的聊天机器人可以从最基础的逻辑开始,然后逐步加入更复杂的功能。这里我们将先实现一个简单的

基于Python开发电脑定时关机工具

《基于Python开发电脑定时关机工具》这篇文章主要为大家详细介绍了如何基于Python开发一个电脑定时关机工具,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 简介2. 运行效果3. 相关源码1. 简介这个程序就像一个“忠实的管家”,帮你按时关掉电脑,而且全程不需要你多做

Python实现高效地读写大型文件

《Python实现高效地读写大型文件》Python如何读写的是大型文件,有没有什么方法来提高效率呢,这篇文章就来和大家聊聊如何在Python中高效地读写大型文件,需要的可以了解下... 目录一、逐行读取大型文件二、分块读取大型文件三、使用 mmap 模块进行内存映射文件操作(适用于大文件)四、使用 pand

python实现pdf转word和excel的示例代码

《python实现pdf转word和excel的示例代码》本文主要介绍了python实现pdf转word和excel的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价... 目录一、引言二、python编程1,PDF转Word2,PDF转Excel三、前端页面效果展示总结一

Python xmltodict实现简化XML数据处理

《Pythonxmltodict实现简化XML数据处理》Python社区为提供了xmltodict库,它专为简化XML与Python数据结构的转换而设计,本文主要来为大家介绍一下如何使用xmltod... 目录一、引言二、XMLtodict介绍设计理念适用场景三、功能参数与属性1、parse函数2、unpa

Python中使用defaultdict和Counter的方法

《Python中使用defaultdict和Counter的方法》本文深入探讨了Python中的两个强大工具——defaultdict和Counter,并详细介绍了它们的工作原理、应用场景以及在实际编... 目录引言defaultdict的深入应用什么是defaultdictdefaultdict的工作原理