树莓派4B-搭建一个本地车牌识别服务器

实现目标:

一、设备自启后能够获得服务的ip与端口号,用于计算机连接设备;
二、计算机可以通过服务ip与端口访问设备服务;
三、上传需要处理的数据,返回结果反馈给用户;
四、上传到服务器的数据不会导致设备内存耗尽,自动删除多余的数据;
进阶(未实现):
五、提供用户登陆功能,设备支持唯一damin管理员用户。其他用户可注册;
六、提供登陆界面,用户通过登陆界面输入用户名与密码登录;
七、支持已处理的数据记录在设备数据库当中,提供web页面可查;
八、查询的历史数据支持查看:数据处理时间、处理前上传图片和处理后车牌结果。

使用到的工具与方法

一、systemctl自启服务
二、oled
二、python
三、flask
四、bootstrap框架
五、hyperlpr车牌识别的v1版本

实现过程:

一、配置自启服务,开机显示服务ip与端口
使用systemctl配置开机自启由oled显示ip与端口(在前面另一篇文章)。

在这里插入图片描述
二、将基于flask的web程序加入到run.sh执行脚本当中

在这里插入图片描述

前提是bootShowIP.service文件已经放到/lib/usr/systemd/system目录当中并已启用:

在这里插入图片描述

三、在将flask程序部署到树莓派上前,在本地进行了测试。
1、本地可以正常安装使用hyperlpr3,但是在设备上运行时提示由于无法安装onnxruntime导致的无法使用车牌识别功能。
2、无法安装onnxruntime可能是因为onnxruntime没有支持设备的处理器架构的版本。尝试安装hyperlpr v1成功:

python -m pip install -i https://pypi.tuna.tsinghua.edu.cn/simple hyperlpr
#防止下载过慢,使用-i指定下载镜像

3、由于hyperlpr v1版本比较旧,依赖的numpy版本也比较旧,如果直接安装最新的numpy会导致无法使用:
尝试解决:

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple --upgrade --force-reinstall numpy

在这里插入图片描述

安装失败,按提示“Can't roll back numpy; was not uninstalled”,卸载pip uninstall numpy

在这里插入图片描述

卸载之后发现hyperlpr正常了,并且已经存在numpy,可能是安装了多次

在这里插入图片描述

四、测试安装的hyperlpr模块正常后,将以hyperlpr作为后端的falsk程序部署到树莓派

车牌识别系统主页:

在这里插入图片描述

提交待识别车牌:

在这里插入图片描述

获取车牌识别结果与车牌抠图:

在这里插入图片描述

所有源代码

一、项目代码目录结构:

在这里插入图片描述
目录文件夹与文件作用说明:
1、css文件夹是boostrap框架的静态文件,用于控制web页面的样式,可以从bootstrap快捷简单的获得美观的表单;
2、static文件夹是字体(目录fonts)、web页面默认展示图片(目录src)、保存用户上传图片和经过处理的图片结果保存目录(目录img);
3、templates文件夹是web页面的html文件保存目录;
4、app.py文件是flask程序的入口函数文件;
5、mu_util.py文件是本人收集实现的一些工具函数文件;
6、plateNoRegPy.py文件是基于hyperlpr的车牌识别处理实现代码文件。

二、hyperlpr模块测试文件夹目录:

在这里插入图片描述

from hyperlpr import *
import cv2

if __name__ == '__main__':
    image = cv2.imread("test.jpg")
    # 打印识别结果
    lpr_result = HyperLPR_plate_recognition(image)
    print("[0]")
    print(lpr_result[0])
    result = lpr_result[0]
    print("plateNo:")
    print(lpr_result[0][0])
    print("location:")
    print("x1{},y1{},x2{},y2{}".format(result[2][0], result[2][1], result[2][2], result[2][3]))

三、css文件中的文件由bootstrap中下载

在这里插入图片描述
四、static文件夹
1、fonts文件夹

在这里插入图片描述
2、img文件夹,程序第一次使用前为空

在这里插入图片描述
3、src文件夹

在这里插入图片描述
五、templates文件夹

在这里插入图片描述

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>车牌识别</title>
    <link rel="stylesheet" href="/static/css/bootstrap.css">
  <style>
    /*static 文件夹是默认用于存放静态文件的,比如 CSS、JavaScript、图片和字体文件等。
    Flask 会自动为 static 文件夹下的所有文件提供静态文件的路由,使得这些文件可以被直接访问,
    而不需要你为每个文件单独编写路由。*/
    @font-face {
        font-family: 'KingHwa'; /* 自定义字体名称 */
        /*此处将字体文件加入到static文件夹当中,就省去了编写路由的工作,ttf文件对应路由格式truetype*/
        src: url('../static/fonts/KingHwa_OldSong.ttf') format('truetype');/* 字体文件路径和格式 */
        font-weight: normal;
        font-style: normal;
    }
    body {
      background-color: rgba(173, 216, 230, 0.5); /*设置页面背景颜色*/
      font-family: "KingHwa", sans-serif; /*设置字体*/
    }
    .center-image {
      /*position: fixed;*/
      display: block;
      margin-top: 4%;
      margin-left: 40%;
      margin-right: 40%;
      border-radius: 4%; /* 设置圆角大小 */
      width: 20%; /* 你可以根据需要调整宽度 */
    }
    .center-bnt {
      /*position: fixed;*/
      display: block;
      {#margin-top: 10%;#}
      margin-top: 5%;
      margin-left: 45%;
      margin-right: 45%;
      width: 10%; /* 你可以根据需要调整宽度 */
    }
    .rounded-font {
      display: block;
      margin-top: 8%;
      border-radius: 2%; /* 设置圆角大小 */
      font-size: 360%; /* 设置字体大小 */
      text-align: center; /* 将文本居中 */
    }
    #backToTop {
      position: fixed;
      bottom: 20px;
      right: 30px;
      z-index: 99;
      border: none;
      outline: 1px solid black;/*设置轮廓*/
      background-color: rgba(0, 0, 230, 0.5);
      color: white;
      cursor: pointer;
      padding: 4px 5px;
      border-radius: 2px;/*设置圆角*/
    }
    .default-img {
      /*position: fixed;*/
      display: block;
      {#margin-top: 10%;#}
      {#margin-top: 5%;#}
      margin-left: 30%;
      margin-right: 30%;
      width: 20%; /* 你可以根据需要调整宽度 */
      border-radius: 2%;/*设置圆角*/
    }
    .back-home {
        position: fixed;
        bottom: 15px; /* 初始时,将元素移出视口 */
        right: 100px;
        /* 其他样式 */
    }
  </style>
</head>
<h1 class="rounded-font">车牌识别</h1>
<body>
{#    <form style="width:100%;margin:2% auto;" method="post">#}
{#      <button type="submit"  class="btn btn-primary center-bnt" style="font-size: 150%">提交图片文件</button>#}
{#    </form>#}
    <center>
	<div class="body-container">
		<div class="jumbotron">
		 	<form style="width:100%;margin:2% auto;" method="post" enctype = "multipart/form-data">
		 	    <h3> {{ data.success }} </h3>
	   			<input class = "btn btn-primary" type="file" name="image" accept="image/*">
	  			<input class = "btn btn-primary" type="submit">
	  		</form>
	  		<img src="static/img/{{ name }}" alt="{{ name }}" class="default-img">
	    	{% for d in data.predictions %}
	      		<h5> {{ d.label}}, 置信度:{{d.probability }}% </h5>
	    	{% endfor %}
	    </div>
	</div>
    </center>
{#    <a href="{{ url_for('process_plateReg')}}" class="back-home">返回首页</a>#}
{#  <button onclick="topFunction()" id="backToTop" title="回到顶部">#}
{#    <img src="{{ url_for('send_image', path='src/toTop.jpg') }}" alt="返回顶部">#}
{#  </button>#}
  <script>
    function topFunction() {
      window.scrollTo(0, 0);
    }
  </script>
</body>
</html>

六、app.py

from flask import Flask,render_template,request,redirect,send_file
import os
import plateNoRegPy

app = Flask(__name__)

# 设置配置
UPLOAD_FOLDER = os.path.join(app.root_path, 'static', 'img')
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
SOURCE_FOLDER = os.path.join(app.root_path, 'static', 'src')
app.config['SOURCE_FOLDER'] = SOURCE_FOLDER
# 注册路由和其他配置
app.register_blueprint(plateNoRegPy.blueprint)  # 车牌图片识别蓝图注册

@app.route('/src/<path:path>')#网页的所有文件都是来自服务器
def send_image(path):
    return send_file(path, mimetype='image/jpeg')

@app.route('/')
def hello_world():  # put application's code here
    return redirect('/plateReg')#跳转车牌识别
    return 'Hello World!'


if __name__ == '__main__':
    # app.run()
    app.run(host='0.0.0.0', port=8000)#服务访问ip与端口

七、plateNoRegPy.py

# 功能实现模型来源
# hyperlpr3在树莓派上可能无法安装 https://github.com/szad670401/HyperLPR?tab=readme-ov-file
# https://github.com/szad670401/HyperLPR/tree/v1
import cv2
# import hyperlpr3 as lpr3
from hyperlpr import *
from PIL import Image
from flask import request, url_for, render_template, redirect, Blueprint, current_app
from my_util import Logger, copy_file, delete_files
import os
import random

# initialize our Flask application and the lpr object
blueprint = Blueprint('processPlatNoImg', __name__)

lprObject = None
loger = Logger()
default_pic_name = "defaultPlate.jpg"

def init_default_source():
    # 删除多余的图片
    max_files_allowed = 30 #后续拷贝一个默认图片,加上上传图片,实际文件夹当中有32个文件
    delete_files(current_app.config['UPLOAD_FOLDER'], max_files_allowed)
    # 默认图片拷贝
    source_path = os.path.join(current_app.config['SOURCE_FOLDER'], default_pic_name)
    dest_path = os.path.join(current_app.config['UPLOAD_FOLDER'], default_pic_name)
    if not os.path.exists(dest_path) or not os.path.isfile(dest_path):
        copy_file(source_path, dest_path)

# Instantiate object
def load_object():
    # 默认图片拷贝
    source_path = os.path.join(current_app.config['SOURCE_FOLDER'], default_pic_name)
    dest_path = os.path.join(current_app.config['UPLOAD_FOLDER'], default_pic_name)
    copy_file(source_path, dest_path)
    global lprObject
    lprObject = HyperLPR_plate_recognition

'''
def load_object3():
    # 默认图片拷贝
    source_path = os.path.join(current_app.config['SOURCE_FOLDER'], default_pic_name)
    dest_path = os.path.join(current_app.config['UPLOAD_FOLDER'], default_pic_name)
    copy_file(source_path, dest_path)
    global lprObject
    lprObject = lpr3.LicensePlateCatcher()
'''

def prepare_image(image):
    loger.debug("Preparing image"+image)
    image = cv2.imread(image)
    return image

def crop_image(image1, image2, x1, y1, x2, y2):
    # 打开图片
    img = Image.open(image1)
    # 截取图片,参数为左上角和右下角的坐标
    cropped_img = img.crop((x1, y1, x2, y2))
    # 保存截取的图片
    cropped_img.save(image2)
    
    loger.debug("recognize plateNo: " + image2)

@blueprint.route('/plateReg', methods=['GET', 'POST'])  # 访问的路径
def process_plateReg():
    init_default_source()
    data = {"success": "未上传"}
    title = "Upload an image"
    name = default_pic_name
    if request.method == "POST":
        if request.files.get("image"):

            image1 = request.files["image"]
            imagePath = os.path.join(current_app.config['UPLOAD_FOLDER'], image1.filename)
            image = image1.save(imagePath)
            loger.debug("接受车牌图片路径"+imagePath)

            processed_image = prepare_image(imagePath)

            data["predictions"] = []
            
            '''
            try:
                if lprObject == None:
                    load_object3()
                    loger.info("lpr object not initialzed")
                lpr3_results = lprObject(processed_image)
            except Exception as e:
                print("Exception  load hyperlpr3", e)
            '''
                
            try:
                if lprObject == None:
                    load_object()
                    loger.info("lpr object not initialzed")
                lpr_results = lprObject(processed_image)
            except Exception as e:
                print("Exception load hyperlpr", e)
                lpr_results = ""

            if len(lpr_results):
                print("lpr_results:")
                print(lpr_results[0])
                
                result = lpr_results[0]
                # image2Name = "outputPlatNo"
                image2Name = result[0] + ".jpg"
                image2 = os.path.join(current_app.config['UPLOAD_FOLDER'], image2Name)
                    
                crop_image(imagePath, image2, result[2][0], result[2][1], result[2][2], result[2][3])
                
                r = {"label": result[0], "probability": int(100*result[1])}
            else:
                image2Name = image1.filename
                r = {"label": "unkonw", "probability": int(0)}

            data["predictions"].append(r)

            # indicate that the request was a success
            data["success"] = "已上传"
            title = "predict"

            return render_template('plateNoReg.html', data=data, title=title, name=image2Name)
    return render_template('plateNoReg.html', data=data, title=title, name=name)

八、my_util.py

import os
import sys
import time
import shutil
import logging
import time
from datetime import datetime

#进度条
def print_progress_bar(iteration, total, prefix='', suffix='', decimals=1, length=100, fill='█', print_end="\r"):
    """
    调用在Python终端中打印自定义进度条的函数
    iteration - 当前迭代(Int)
    total - 总迭代(Int)
    prefix - 前缀字符串(Str)
    suffix - 后缀字符串(Str)
    decimals - 正数的小数位数(Int)
    length - 进度条的长度(Int)
    fill - 进度条填充字符(Str)
    print_end - 行尾字符(Str)
    """
    percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total)))
    filled_length = int(length * iteration // total)
    bar = fill * filled_length + '-' * (length - filled_length)
    print(f'\r{prefix} |{bar}| {percent}% {suffix}', end=print_end)
    # 打印新行,完成进度条
    if iteration == total:
        print()

class Logger(object):
    """
    终端打印不同颜色的日志
    """
    ch = logging.StreamHandler()  # 创建日志处理器对象,在__init__外创建,是类当中的静态属性,不是__init__中的实例属性

    # #创建静态的日志处理器可以减少内存消耗

    # # 创建 FileHandler 实例,指定日志文件路径
    # ch = logging.FileHandler(filename='app1.log')

    def __init__(self):
        self.logger = logging.getLogger()  # 创建日志记录对象
        self.logger.setLevel(logging.DEBUG)  # 设置日志等级info,其他低于此等级的不打印

    def debug(self, message):
        self.fontColor('\033[0;37m%s\033[0m')
        self.logger.debug(message)

    def info(self, message):
        self.fontColor('\033[0;32m%s\033[0m')
        self.logger.info(message)

    def warning(self, message):
        self.fontColor('\033[0;33m%s\033[0m')
        self.logger.warning(message)

    def error(self, message):
        self.fontColor('\033[0;31m%s\033[0m')
        self.logger.error(message)

    def fontColor(self, color):
        formatter = logging.Formatter(color % '%(asctime)s - %(name)s - %(levelname)s - %(message)s')  # 控制日志输出颜色
        self.ch.setFormatter(formatter)
        self.logger.addHandler(self.ch)  # 向日志记录对象中加入日志处理器对象


def delete_files(folder_path, max_files):
    """
    监控指定文件夹中的文件数量,并在超过max_files时删除最旧的文件。
    """
    print("进入删除图片文件夹"+folder_path)
    print("需要删除文件数量")
    print(max_files)
    if True:
        # 获取文件夹中的文件列表
        files = os.listdir(folder_path)
        file_count = len(files)
        print(f"当前文件夹 {folder_path} 中的文件数量: {file_count}")

        # 如果文件数量超过max_files,则删除最旧的文件
        if file_count > max_files:
            # 获取文件夹中所有文件的完整路径,并带上修改时间
            file_paths_with_mtime = [(os.path.join(folder_path, f), os.path.getmtime(os.path.join(folder_path, f))) for
                                     f in files]
            # 按修改时间排序
            sorted_files = sorted(file_paths_with_mtime, key=lambda x: x[1])

            # 删除最旧的文件,直到文件数量在阈值以下
            for file_path, mtime in sorted_files[:file_count - max_files]:
                try:
                    os.remove(file_path)
                    print(f"已删除文件: {file_path}")
                except OSError as e:
                    print(f"删除文件时出错: {e.strerror}")

def copy_file(src, dst):
    shutil.copy2(src, dst)  # copy2会尝试保留文件的元数据

整体实现效果

项目代码仓库
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/618171.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

车载测试系列:CAPL脚本语法

HFP测试内容与测试方法 2.3 接听来电&#xff1a;测试手机来电时&#xff0c;能否从车载蓝牙设备和手机侧正常接听】拒接、通话是否正常。 1、预置条件&#xff1a;待测手机与车载车载设备处于连接状态 2、测试步骤&#xff1a; 1&#xff09;用辅助测试机拨打待测手机&…

本地电脑hosts强制解析指定IP的方法

网站接入CDN后&#xff0c;很多时候需要本地强制解析回源查看状态&#xff0c;比如查看是不是源服务器故障&#xff0c;网站修改是否正确&#xff0c;网站更新是否及时&#xff0c;故障查看是CDN问题还是源服务器问题&#xff0c;都需要hosts回源。 今天云加速教大家如何本地电…

AI工具摸索-关于写作(1)

虽然人工智能工具非常多,但是如果想要成为生产力,能达标的工具仍然非常少,除了最常用的chatgpt,其他的工具真的能达标吗,这篇文章主要就是对比市面上的一些工具&#xff0c; 但我这个人非常执拗,我认为作为生产力工具的功能必然是可以真正帮助我们的,而不是说作为一个写作工具结…

docker部署springboot+Vue项目

项目介绍&#xff1a;后台springboot项目&#xff0c;该项目环境mysql、redis 。前台Vue&#xff1a;使用nginx反向代理 方法一&#xff1a;docker run 手动逐个启动容器 1.docker配置nginx代理 将vue项目打包上传到服务器上。创建文件夹存储数据卷&#xff0c;html存放打包…

【Dash】开始学习dash

安装Dash 网上很多安装dash的教程&#xff0c;不再赘述 开始Dash 一个dash页面的基本写法 # dash 的基本写法 import dash from dash import html,dcc,callback,Input,Output# 创建一个 dash 应用 app dash.Dash()# 定义布局&#xff0c;定义一个输入框和一个输出框 app.l…

NIOS II实现LED流水灯以及串口输出(DE2-115开发板)

NIOS II实现LED流水灯以及串口输出&#xff08;DE2-115开发板&#xff09; 前言什么是Qsys?什么是NIOSII?注意事项1、管脚配置2、配置NIOSII时的连接3、注意中断配置好后是这样的4、注意名称的配置5、设置双功能引脚 NIOS II的报错代码以及效果演示流水灯输出到电脑串口助手 …

【020】基于JavaWeb实现的批报管理系统

项目介绍 基于jspservlet实现的批报管理系统采用B/S架构,该项目设计了一个角色管理员&#xff0c;管理员实现了我的案件、查询统计、项目维护等三大功能模块 技术栈 开发工具&#xff1a;Idea2020.3 运行环境&#xff1a;jdk1.8tomcat9.0mysql5.7 服务端技术&#xff1a;j…

【机器学习数据可视化-04】Pyecharts数据可视化宝典

一、引言 在大数据和信息爆炸的时代&#xff0c;数据可视化成为了信息传递和展示的关键手段。通过直观的图表和图形&#xff0c;我们能够更好地理解数据&#xff0c;挖掘其背后的信息。Pyecharts&#xff0c;作为一款基于Python的数据可视化库&#xff0c;凭借其丰富的图表类型…

获取Linux上的Redis的用户名、密码、端口、host等信息

目录 进入redis-cli的目录 启动./redis-cli服务 查询密码 查询用户名 查询端口 查询host 参考文章&#xff1a;解决redis-cli连接时出现Could not connect to Redis at 127.0.0.1:6379: Connection refused-阿里云开发者社区 (aliyun.com) linux查看redis用户和密码_mo…

Java构造方法详解

在Java方法内部定义一个局部变量时&#xff0c;必须要初始化&#xff0c;否则就会编译失败&#xff0c;如下&#xff1a; 要让上述代码通过编译&#xff0c;只需在使用a之前给a赋一个初始值即可 如果是对象&#xff1a;下面用一个日期类演示 我们没有给年月日赋值&#xff0c;…

纯血鸿蒙APP实战开发——首页下拉进入二楼效果案例

介绍 本示例主要介绍了利用position和onTouch来实现首页下拉进入二楼、二楼上划进入首页的效果场景&#xff0c;利用translate和opacity实现动效的移动和缩放&#xff0c;并将界面沉浸式&#xff08;全屏&#xff09;显示。 效果图预览 使用说明 向下滑动首页页面超过触发距…

实验室纳新宣讲会(java后端)

前言 2024-5-12 22:00:39 这是陈旧已久的草稿 2021-09-16 15:41:38 发布一下 当时我进入实验室&#xff0c;也是大二了&#xff0c;实验室纳新需要宣讲&#xff0c; 但是当时有疫情&#xff0c;又没宣讲成。 实验室纳新宣讲会&#xff08;java后端&#xff09; 首先&#x…

【计算机网络】物理层 通信基础、奈氏准则、香农公式 习题2

下列说法中正确的是( )。 A. 信道与通信电路类似&#xff0c;一条可通信的电路往往包含一个信道 B.调制是指把模拟数据转换为数字信号的过程 C. 信息传输速率是指通信信道上每秒传输的码元数 D.在数值上&#xff0c;波特率等于比特率与每符号所含的比特数的比值 信息传输速率&a…

【进程通信】了解信号以及信号的产生

文章目录 0.前言1.信号的基本概念1.1中断1.1.1 软中断1.1.2硬中断 1.2异步1.2.1异步和同步的比较 2.信号的主要用途3.信号的特点4.查看信号4.1Core和Term的区别4.2生成Core文件 5.初识捕捉信号5.1signal函数 6.产生信号的方式6.1.通过终端按键产生信号6.2.调用系统函数向进程发…

浅谈如何做好软件项目

如何做好软件项目&#xff0c;这是摆在软件实施团队每个人面前的关键问题。笔者在此提出一些浅见&#xff0c;供大家参考。欢迎在评论区交流&#xff01; 目录 【摘要】 【正文】 一、树立正确的需求调研理念 二、谋定而后动的开发工作 三、大道至简的系统设计 四、专注项…

hcip实验6:BGP综合实验

实验拓扑&#xff1a; 实验配置&#xff1a; ip地址配置&#xff1a; #R1 [R1]int g0/0/0 [R1-GigabitEthernet0/0/0]ip add 12.1.1.1 24 [R1-GigabitEthernet0/0/0]int l0 [R1-LoopBack0]ip add 172.16.0.1 32 [R1-LoopBack0]int l1 [R1-LoopBack1]ip add 192.168.1.1 24#R2…

算法笔记——数位DP

一、前置知识 1.DP小知识 D P DP DP 是一种算法思想&#xff0c;用递推方程的方式解决问题。但是使用它要满足如下性质&#xff1a; 最优子结构&#xff1a; 子结构优秀&#xff0c;整个就优秀。无后效性&#xff1a;当前决策不会影响后面。 2.DP实现方法 众所周知&#xf…

环境变量(全)

概念 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数 如&#xff1a;我们在编写C/C代码的时候&#xff0c;在链接的时候&#xff0c;从来不知道我们的所链接的动态静态库在哪里&#xff0c;但是照样可以链接成功&#xff0c;生成可执…

2024中国(重庆)机器人展览会8月举办

2024中国(重庆)机器人展览会8月举办 邀请函 主办单位&#xff1a; 中国航空学会 重庆市南岸区人民政府 招商执行单位&#xff1a; 重庆港华展览有限公司 2024中国重庆机器人展会将汇聚机器人全产业链知名企业&#xff0c;世界科技领先的生产制造企业与来自多个国家和地区…

Python | Leetcode Python题解之第78题子集

题目&#xff1a; 题解&#xff1a; class Solution:def subsets(self, nums: List[int]) -> List[List[int]]:self.res []self.backtrack([], 0, nums)return self.resdef backtrack(self, sol, index, nums):self.res.append(sol)for i in range(index, len(nums)):self…