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正则表达式语法及re模块中的常用函数详解

《Python正则表达式语法及re模块中的常用函数详解》这篇文章主要给大家介绍了关于Python正则表达式语法及re模块中常用函数的相关资料,正则表达式是一种强大的字符串处理工具,可以用于匹配、切分、... 目录概念、作用和步骤语法re模块中的常用函数总结 概念、作用和步骤概念: 本身也是一个字符串,其中

Python使用getopt处理命令行参数示例解析(最佳实践)

《Python使用getopt处理命令行参数示例解析(最佳实践)》getopt模块是Python标准库中一个简单但强大的命令行参数处理工具,它特别适合那些需要快速实现基本命令行参数解析的场景,或者需要... 目录为什么需要处理命令行参数?getopt模块基础实际应用示例与其他参数处理方式的比较常见问http

python实现svg图片转换为png和gif

《python实现svg图片转换为png和gif》这篇文章主要为大家详细介绍了python如何实现将svg图片格式转换为png和gif,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录python实现svg图片转换为png和gifpython实现图片格式之间的相互转换延展:基于Py

Python中的getopt模块用法小结

《Python中的getopt模块用法小结》getopt.getopt()函数是Python中用于解析命令行参数的标准库函数,该函数可以从命令行中提取选项和参数,并对它们进行处理,本文详细介绍了Pyt... 目录getopt模块介绍getopt.getopt函数的介绍getopt模块的常用用法getopt模

Python利用ElementTree实现快速解析XML文件

《Python利用ElementTree实现快速解析XML文件》ElementTree是Python标准库的一部分,而且是Python标准库中用于解析和操作XML数据的模块,下面小编就来和大家详细讲讲... 目录一、XML文件解析到底有多重要二、ElementTree快速入门1. 加载XML的两种方式2.

Python如何精准判断某个进程是否在运行

《Python如何精准判断某个进程是否在运行》这篇文章主要为大家详细介绍了Python如何精准判断某个进程是否在运行,本文为大家整理了3种方法并进行了对比,有需要的小伙伴可以跟随小编一起学习一下... 目录一、为什么需要判断进程是否存在二、方法1:用psutil库(推荐)三、方法2:用os.system调用

使用Python从PPT文档中提取图片和图片信息(如坐标、宽度和高度等)

《使用Python从PPT文档中提取图片和图片信息(如坐标、宽度和高度等)》PPT是一种高效的信息展示工具,广泛应用于教育、商务和设计等多个领域,PPT文档中常常包含丰富的图片内容,这些图片不仅提升了... 目录一、引言二、环境与工具三、python 提取PPT背景图片3.1 提取幻灯片背景图片3.2 提取

Python实现图片分割的多种方法总结

《Python实现图片分割的多种方法总结》图片分割是图像处理中的一个重要任务,它的目标是将图像划分为多个区域或者对象,本文为大家整理了一些常用的分割方法,大家可以根据需求自行选择... 目录1. 基于传统图像处理的分割方法(1) 使用固定阈值分割图片(2) 自适应阈值分割(3) 使用图像边缘检测分割(4)

一文带你搞懂Python中__init__.py到底是什么

《一文带你搞懂Python中__init__.py到底是什么》朋友们,今天我们来聊聊Python里一个低调却至关重要的文件——__init__.py,有些人可能听说过它是“包的标志”,也有人觉得它“没... 目录先搞懂 python 模块(module)Python 包(package)是啥?那么 __in

使用Python实现图像LBP特征提取的操作方法

《使用Python实现图像LBP特征提取的操作方法》LBP特征叫做局部二值模式,常用于纹理特征提取,并在纹理分类中具有较强的区分能力,本文给大家介绍了如何使用Python实现图像LBP特征提取的操作方... 目录一、LBP特征介绍二、LBP特征描述三、一些改进版本的LBP1.圆形LBP算子2.旋转不变的LB