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创建一个功能完整的Windows风格计算器程序

《使用Python创建一个功能完整的Windows风格计算器程序》:本文主要介绍如何使用Python和Tkinter创建一个功能完整的Windows风格计算器程序,包括基本运算、高级科学计算(如三... 目录python实现Windows系统计算器程序(含高级功能)1. 使用Tkinter实现基础计算器2.

Python开发文字版随机事件游戏的项目实例

《Python开发文字版随机事件游戏的项目实例》随机事件游戏是一种通过生成不可预测的事件来增强游戏体验的类型,在这篇博文中,我们将使用Python开发一款文字版随机事件游戏,通过这个项目,读者不仅能够... 目录项目概述2.1 游戏概念2.2 游戏特色2.3 目标玩家群体技术选择与环境准备3.1 开发环境3

Python中模块graphviz使用入门

《Python中模块graphviz使用入门》graphviz是一个用于创建和操作图形的Python库,本文主要介绍了Python中模块graphviz使用入门,具有一定的参考价值,感兴趣的可以了解一... 目录1.安装2. 基本用法2.1 输出图像格式2.2 图像style设置2.3 属性2.4 子图和聚

Python使用Matplotlib绘制3D曲面图详解

《Python使用Matplotlib绘制3D曲面图详解》:本文主要介绍Python使用Matplotlib绘制3D曲面图,在Python中,使用Matplotlib库绘制3D曲面图可以通过mpl... 目录准备工作绘制简单的 3D 曲面图绘制 3D 曲面图添加线框和透明度控制图形视角Matplotlib

一文教你Python如何快速精准抓取网页数据

《一文教你Python如何快速精准抓取网页数据》这篇文章主要为大家详细介绍了如何利用Python实现快速精准抓取网页数据,文中的示例代码简洁易懂,具有一定的借鉴价值,有需要的小伙伴可以了解下... 目录1. 准备工作2. 基础爬虫实现3. 高级功能扩展3.1 抓取文章详情3.2 保存数据到文件4. 完整示例

使用Python实现IP地址和端口状态检测与监控

《使用Python实现IP地址和端口状态检测与监控》在网络运维和服务器管理中,IP地址和端口的可用性监控是保障业务连续性的基础需求,本文将带你用Python从零打造一个高可用IP监控系统,感兴趣的小伙... 目录概述:为什么需要IP监控系统使用步骤说明1. 环境准备2. 系统部署3. 核心功能配置系统效果展

基于Python打造一个智能单词管理神器

《基于Python打造一个智能单词管理神器》这篇文章主要为大家详细介绍了如何使用Python打造一个智能单词管理神器,从查询到导出的一站式解决,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 项目概述:为什么需要这个工具2. 环境搭建与快速入门2.1 环境要求2.2 首次运行配置3. 核心功能使用指

Python实现微信自动锁定工具

《Python实现微信自动锁定工具》在数字化办公时代,微信已成为职场沟通的重要工具,但临时离开时忘记锁屏可能导致敏感信息泄露,下面我们就来看看如何使用Python打造一个微信自动锁定工具吧... 目录引言:当微信隐私遇到自动化守护效果展示核心功能全景图技术亮点深度解析1. 无操作检测引擎2. 微信路径智能获

Python中pywin32 常用窗口操作的实现

《Python中pywin32常用窗口操作的实现》本文主要介绍了Python中pywin32常用窗口操作的实现,pywin32主要的作用是供Python开发者快速调用WindowsAPI的一个... 目录获取窗口句柄获取最前端窗口句柄获取指定坐标处的窗口根据窗口的完整标题匹配获取句柄根据窗口的类别匹配获取句

利用Python打造一个Excel记账模板

《利用Python打造一个Excel记账模板》这篇文章主要为大家详细介绍了如何使用Python打造一个超实用的Excel记账模板,可以帮助大家高效管理财务,迈向财富自由之路,感兴趣的小伙伴快跟随小编一... 目录设置预算百分比超支标红预警记账模板功能介绍基础记账预算管理可视化分析摸鱼时间理财法碎片时间利用财