【ARFoundation学习笔记】2D图像检测跟踪

在这里插入图片描述


写在前面的话

本系列笔记旨在记录作者在学习Unity中的AR开发过程中需要记录的问题和知识点。主要目的是为了加深记忆。其中难免出现纰漏,更多详细内容请阅读原文以及官方文档。

汪老师博客


文章目录

  • 2D图像检测
    • 创建一个图像检测工程
    • 图像追踪的禁用和启用
    • 多图像追踪
    • 运行时参考图像库
    • 运行时添加参考图


2D图像检测

在ARFoundation中,图像跟踪系统依据参考图像库中的图像信息尝试在周围环境中检测到匹配的2D图像并跟踪。在接下来的学习中我们将会提到一些术语:

  • Reference Image(参考图像),识别2D图像的过程中,实际上是一个特征值对比的过程。AR Foundation将从摄像头中获取的图像信息与参考图像库的图像特征值信息进行对比,而存储在参考图像库中的用于对比的图像就是Reference Image。
    一旦对比成功,真实环境中的图像就会与参考图像库的参考图像建立对应关系,并且同时检测真实2D图像的姿态信息。

  • Reference Image Library(参考图像库),参考图像库存储了用于对比的参考图像,每一个图像跟踪程序都必须有一个参考图像库。
    在参考图像库中存储的实际是参考图像的特征值信息而不是原始图像,这有助于提高对比速度和增强检测系统的鲁棒性(耐操性,即在异常下依旧运行的能力)(想象一下如果用原始图像进行检测,那么则需要在像素空间上对图像进行对比,对像素的实时检测太消耗资源了!因此如果将图像映射到特征空间使用特征值检测将会方便很多!小到图像检测,大到人工智能都运用了这个原理!)。
    参考图像库越大,图像对比就越慢,因此参考图像库的图像不要超过1000张。

  • Provider(算法提供方),由于AR Foundation是基于底层SDK的图像追踪的API之上的,因此它只提供一个图像检测的接口,具体的图像识别算法由Provider提供。


创建一个图像检测工程

在ARFoundation中,图像跟踪的操作分为两步:

  1. 建立一个参考图像库
  2. 建立一个AR Tracked Image Manager组件,并将需要实例化的Prefab挂载在Tracked Image Prefab上

在这里插入图片描述
按上述步骤,在Unity中新建一个工程,第一步建立一个参考图像库,首先在Project窗口中的ImageLib文件夹下点击鼠标右键并依次选择Create->XR->Reference Image Library新建一个参考图像库,并命名为RefImageLib,如图所示。

在这里插入图片描述
选择新建的RefImageLib参考图像库,为其添加一些参考图像

属性描述
Name一个标识参考图像的名字,这个名字在做图像对比时没有作用,但在比对匹配成功后我们可以通过参考图像名字获知是哪个参考图像,参考图像名字是可以重复的,因为在跟踪时,跟踪系统还会给每一个参考图像一个referenceImage.guid值,这个值是唯一的。
Specify Size这是个可选值,为加速图像检测识别过程,一些底层SDK要求提供一个2D待检测图像的物理尺寸,所以如果要设置,这个值一定会是一个大于0的长宽值对,当一个值发生变化时,Unity会根据参考图像的比例自动调整另一个值。
Keep Texture at Runtime一个默认的纹理,这个纹理可以用于修改Prefab的外观。

在这里插入图片描述

为了实现图像追踪,我们需要选择挂载Trackable的对应Manager在AR Session Origin上,这里我们选择AR Tracked Image Manager。挂载参考图像库和生成预制体,并设定最大可跟踪的动态图像数。

注意:ARFoundation中的图像跟踪是一个非常消耗CPU性能的任务,因此不要设定过多的动态图像追踪数量。
此外,动态图像追踪和底层SDK的算法有很大关系,因此使用时应当阅读对应平台的SDK资料。ARFoundation目前也不支持动态添加参考图像。

在这里插入图片描述
(由于SDK的生成设置,生成的模型方向反了,这只能在模型内部调整朝向来解决)


图像追踪的禁用和启用

    void SetAllImagesActive(bool value)
    {
        foreach (var img in mARTrackedImageManager.trackables)
            img.gameObject.SetActive(value);
    }

与平面检测开启和关闭类似,图像追踪的禁用和启用也相当简单,只需对Trackable的gameObject进行SetActive即可。


多图像追踪

在这里插入图片描述

在上图中不难发现,AR Tracked Image Manager中能够生成的预制体只有一个,如果我们想要实现多图像追踪,并生成多个预制体该如何实现呢?

默认的,AR foundation可以对同一个图像进行多个虚拟对象的实例化,但是只能实例化我们在Manager上挂载的那一类Prefab,也就是只能对一类图像进行多个对象的实例化,例如只识别SPIDER的图像或者CAT的图像,而不能同时识别二者。然而实际应用中我们更希望对多类图像都进行识别和实例化,如何能够实现?

挂载一个新的Tracked Image Manager?这个方案是不行的,因为同类的Manager在AR程序中只会实例化一个(单例模式),这是为了防止多个同类Manager同时存在造成追踪混乱。

如果不能实例化多类虚拟对象,这将极大的限制跟踪图像的实际应用,所以为了实例化多类虚拟对象,我们只能动态的修改Tracked Image Prefab属性。

经过测试,我们发现在ARFoundation中,AR Tracked Image Manager组件在trackedImagesChanged事件触发之前就已经实例化了虚拟对象,因此如果在捕获到第一个需要实例化Prefab的图像时,动态的替换Manager中的Prefab为下一个需要实例化的Prefab即可。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.ARFoundation;

public class MultiImageTracking : MonoBehaviour
{
    ARTrackedImageManager ImgTrackedmanager;
    public GameObject[] ObjectPrefabs;

    private void Awake()
    {
        ImgTrackedmanager = GetComponent<ARTrackedImageManager>();
    }


    private void OnEnable()
    {
        ImgTrackedmanager.trackedImagesChanged += OnTrackedImagesChanged;
    }
    void OnDisable()
    {
        ImgTrackedmanager.trackedImagesChanged -= OnTrackedImagesChanged;
    }
    void OnTrackedImagesChanged(ARTrackedImagesChangedEventArgs eventArgs)
    {
        foreach (var trackedImage in eventArgs.added)
        {
            OnImagesChanged(trackedImage.referenceImage.name);
        }
       // foreach (var trackedImage in eventArgs.updated)
       // {
       //     OnImagesChanged(trackedImage.referenceImage.name);
       // }
    }

    private void OnImagesChanged(string referenceImageName)
    {
        if (referenceImageName == "Spider")
        {           
            ImgTrackedmanager.trackedImagePrefab = ObjectPrefabs[1];
            Debug.Log("Tracked Name is .." + referenceImageName);
            Debug.Log("Prefab Name is .." + ImgTrackedmanager.trackedImagePrefab.name);
        }
        if (referenceImageName == "Cat")
        {
            ImgTrackedmanager.trackedImagePrefab = ObjectPrefabs[0];
        }
    }
}

上述代码中,我们提前准备好了一个预制件的数组,并在Image Tracked Manager可用时为其注册了一个事件,一旦可追踪图像产生变化,我们就设定可追踪图像为下一个目标,并同时更新预制件。但这个方法也有弊端,那就是我们对预制件的生成只能顺序地执行。

因此改变思路,我们需要在随机检测到参考图像时生成对应的预制件,因此则需要动态地替换当前需要产生的预制件的目标:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.ARFoundation;

public class MultiImageTracking : MonoBehaviour
{
    ARTrackedImageManager ImgTrackedManager;
    private Dictionary<string, GameObject> mPrefabs =  new Dictionary<string, GameObject>();

    private void Awake()
    {
        ImgTrackedManager = GetComponent<ARTrackedImageManager>();
    }

    void Start()
    {        
        mPrefabs.Add("Cat", Resources.Load("Cat") as GameObject);
        mPrefabs.Add("Spider", Resources.Load("Spider") as GameObject);
    }

    private void OnEnable()
    {
        ImgTrackedManager.trackedImagesChanged += OnTrackedImagesChanged;
    }
    void OnDisable()
    {
        ImgTrackedManager.trackedImagesChanged -= OnTrackedImagesChanged;
    }
    void OnTrackedImagesChanged(ARTrackedImagesChangedEventArgs eventArgs)
    {
        foreach (var trackedImage in eventArgs.added)
        {
            OnImagesChanged(trackedImage);
        }
       // foreach (var trackedImage in eventArgs.updated)
       // {
       //     OnImagesChanged(trackedImage.referenceImage.name);
       // }
    }

    private void OnImagesChanged(ARTrackedImage referenceImage)
    {
        Debug.Log("Image name:"+ referenceImage.referenceImage.name);
        Instantiate(mPrefabs[referenceImage.referenceImage.name], referenceImage.transform);
    }
}

在上述代码中,我们用字典提前存储了对应模型的键值对。如果图像信息变化,检测所有当前追踪的图像,并在当检测到参考图像名称的模型时就生成对应的预制件。

为了实现代码所描述功能,我们还要完成两项工作,第一项工作是将Prefabs放到Resources文件夹中方便动态加载,第二项工作是保证mPrefabs中的key与RefImageLib参考图像库中的参考图像名一致。至此,我们已实现自由的多图像多模型功能。


运行时参考图像库

在前文中使用参考图像库的时候,我们提前为库编辑好了检测的参考图内容。但有时我们想要动态的创建参考图像库。由于AR Tracked Image Manager在启动时其参考图像库不能为null值,我们可以使用下列代码动态添加AR Tracked Image Manager和参考图像库。

trackImageManager = gameObject.AddComponent<ARTrackedImageManager>();
trackImageManager.referenceLibrary = trackImageManager.CreateRuntimeLibrary(runtimeImageLibrary);
trackImageManager.maxNumberOfMovingImages = 2;
trackImageManager.trackedImagePrefab = prefabOnTrack;
trackImageManager.enabled = true;

参考图像库可以是XRReferenceImageLibrary或者RuntimeReferenceImageLibrary类型,XRReferenceImageLibrary可以在Editor编辑器中创建,但不能在运行时修改,不过在运行时XRReferenceImageLibrary会自动转换成RuntimeReferenceImageLibrary。(XR参考图像库就是我们之前在创建时使用的图像库类型,在运行时该类型会自动转换为Runtime参考图像库)

使用下列代码将XR参考图像库转为Runtime参考图像库

XRReferenceImageLibrary serializedLibrary = ...
RuntimeReferenceImageLibrary runtimeLibrary = trackedImageManager.CreateRuntimeLibrary(serializedLibrary);

使用提前准备好的XR图像参考库也可以在运行时来动态转换:

[SerializeField]
XRReferenceImageLibrary[] mReferenceImageLibrary;
private int currentSelectedLibrary = 0;
private ARTrackedImageManager trackImageManager;

public void SetReferenceImageLibrary(int selectedLibrary = 0)
{
    trackImageManager.referenceLibrary = trackImageManager.CreateRuntimeLibrary(mReferenceImageLibrary[selectedLibrary]);
    mLog.text = System.String.Format("切换参考图像库{0}成功!",selectedLibrary);
}

运行时添加参考图

一些底层SDK支持在运行时动态添加新的参考图像到参考图像库,目前ARCore与ARKit都支持在运行时添加参考图像。要检测是否支持添加参考图(或者任意某功能),我们可以对描述符进行检测:

if (trackedImageManager.descriptor.supportsMutableLibrary)

如果SDK支持在运行时动态添加参考图,那么使用该功能时需要将RuntimeReferenceImageLibrary转为MutableReferenceImageLibrary再使用,如果需要在运行时创建全新的参考图像库,也可以使用无参的CreateRuntimeLibrary()方法,然后将其转换为MutableRuntimeReferenceImageLibrary使用:

var library = trackedImageManager.CreateRuntimeLibrary();
if (library is MutableRuntimeReferenceImageLibrary mutableLibrary)
{
  // 添加图像到参考图像库
}

在运行时动态添加参考图像是一个计算密集型任务,因为需要提取参考图像的特征值信息,这大概需要花费几十毫秒时间,因此需要很多帧才能完成添加,为防止同步操作造成应用卡顿,可以利用Unity Job系统(一个安全的无锁多线程系统)异步处理这种操作。

使用Job定义一个添加图像的异步方法:

public static JobHandle ScheduleAddImageJob(this MutableRuntimeReferenceImageLibrary library, Texture2D texture, 
string name, float? widthInMeters,JobHandle inputDeps = null)

使用JobHandle作为返回值,我们可以检查任务是否完成。通常再使用完毕后应当销毁JobHandle以避免性能开销。我们可以使用该方法同时添加多个参考图像到参考图像库中,即使当前的参考图像库正在追踪图像或是处于使用中也没关系。

动态添加参考图像对图像有一些特定要求。
第一要求图像可读写,因为添加图像时需要提取图像特征值信息
第二要求图像格式必须为应用平台上支持的格式,通常选择RGB 24bit或者RGBA 32bit格式。这个需要在图像的import setting中设置,如图所示:

在这里插入图片描述

经过测试,动态添加参考图像对图像编码格式也有要求,通常只支持JPG、PNG格式

Hint
如果作为动态添加的参考图像没有启用Read/Write Enable,编译时将提示The texture must be readable to be used as the source for a reference image;
如果所选定的格式平台不支持,编译时将提示The texture format ETC_RGB4 is not supported by the current image tracking subsystem。

1[SerializeField]
2private Text mlog;
3[SerializeField]
4private Button addImageButton;
56[SerializeField]
7private GameObject prefabOnTrack;
89private Vector3 scaleFactor = new Vector3(0.2f, 0.2f, 0.1f);
1011private XRReferenceImageLibrary runtimeImageLibrary;
1213private ARTrackedImageManager trackImageManager;
1415[SerializeField]
16private Texture2D AddedImage;
1718void Start()
19{
20.    trackImageManager = gameObject.AddComponent<ARTrackedImageManager>();
21.    trackImageManager.referenceLibrary = trackImageManager.CreateRuntimeLibrary  
       (runtimeImageLibrary);
22.    trackImageManager.maxNumberOfMovingImages = 2;
23.    trackImageManager.trackedImagePrefab = prefabOnTrack;
24.    trackImageManager.enabled = true;
25.    trackImageManager.trackedImagesChanged += OnTrackedImagesChanged;
26.    addImageButton.onClick.AddListener(() => StartCoroutine(AddImageJob(AddedImage)));
27}
2829void OnDisable()
30{
31.    trackImageManager.trackedImagesChanged -= OnTrackedImagesChanged;
32}
3334public IEnumerator AddImageJob(Texture2D texture2D)
35{
36yield return null;
3738try
39{
4041MutableRuntimeReferenceImageLibrary mutableRuntimeReferenceImageLibrary =   
          trackImageManager.referenceLibrary as MutableRuntimeReferenceImageLibrary;
42var jobHandle = mutableRuntimeReferenceImageLibrary.ScheduleAddImageJob  
          (texture2D, "Spider", scaleFactor.x);
4344while (!jobHandle.IsCompleted)
45{
46new WaitForSeconds(0.5f);
47}
48.       mlog.text = "添加图像成功!";
49}
50catch (System.Exception e)
51{
52.       mlog.text = e.Message;
53}
54}
5556void OnTrackedImagesChanged(ARTrackedImagesChangedEventArgs eventArgs)
57{
58foreach (ARTrackedImage trackedImage in eventArgs.added)
59{
60.       trackedImage.transform.Rotate(Vector3.up, 180);
61}
6263foreach (ARTrackedImage trackedImage in eventArgs.updated)
64{
65.       trackedImage.transform.Rotate(Vector3.up, 180);
66}
67}

在上述代码中,当检测图像改变的事件触发,就会对追踪图像进行旋转。在点击按钮后开启一个协程,在其中开辟一个Job线程为MutableRuntimeReferenceImageLibrary动态的添加参考图。使用jobHandle.IsCompleted来检测该Job的成功状态。

这里需要注意的是,我们使用了Unity Job系统,目前该系统已作为一个Package单独列出来了,因此需要使用Package Manager添加Burst包。Burst包依赖于NDK,所以还需要正确设置Unity中的NDK路径,如Unity 2019.3.0.6b需要NDK r19包。

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

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

相关文章

rosbag录制的bag文件修复

参考链接&#xff1a;【ROS】ERROR bag unindexed错误解决 在使用.bag文件时遇到的报错&#xff1a; rosbag.bag.ROSBagUnindexedException: Unindexed bag 使用命令查看bag&#xff1a; rosbag info re.bag&#xff08;bag_name&#xff09;此时会报错&#xff1a; ERROR b…

【23真题】四电之一!附免费真题直播!

今天分享的是23年桂林电子科技大学806的信号与系统&#xff08;回忆版&#xff09;试题及解析。 本套试卷难度分析&#xff1a;平均分在110分左右&#xff0c;最高分为140分&#xff01;本套试题难度中等&#xff0c;该院校考察电路部分和信号部分&#xff0c;考察的题目还是比…

YOLOv8更换骨干网络HorNet:递归门控卷积的高效高阶空间交互——涨点神器!

🗝️YOLOv8实战宝典--星级指南:从入门到精通,您不可错过的技巧   -- 聚焦于YOLO的 最新版本, 对颈部网络改进、添加局部注意力、增加检测头部,实测涨点 💡 深入浅出YOLOv8:我的专业笔记与技术总结   -- YOLOv8轻松上手, 适用技术小白,文章代码齐全,仅需 …

AMEYA360:蔡司扫描电镜Sigma系列:扫描电子显微镜的用途原来这么多

扫描电子显微镜是一种全自动的、非破坏性的显微分析系统&#xff0c;可针对无机材料和部分有机材料&#xff0c;迅速提供在统计学上可靠且可重复的矿物学、岩相学和冶金学数据&#xff0c;在采矿业&#xff0c;可用于矿产勘查、矿石表征和选矿工艺优化&#xff0c;在石油和天然…

运动器材经营配送小程序商城效果如何

运动是每天不可少的&#xff0c;公园、健身房随处可见健身的人&#xff0c;在家庭场景中也有不少人会购买运动器材直接运动&#xff0c;如哑铃、跑步机、单车等都有较高的需求&#xff0c;这对于运动器材经销商或品牌来说是生意增长的机会&#xff0c;由于价格不算很高&#xf…

在Spring Boot中使用Thymeleaf开发Web页面

引言&#xff1a; 为啥写这篇文章呢&#xff1f;我明明就没怎么用过这个Thymeleaf进行web开发&#xff0c;用JSP也行&#xff0c;三剑客也行&#xff0c;或者Vue&#xff0c;React&#xff0c;PHP等等&#xff0c;不好吗&#xff1f; 那我为啥写这篇博客呢&#xff1f;这个写了…

Java高级编程-----网络编程

网络通信协议 通过计算机网络可以实现多台计算机连接&#xff0c;但是不同计算机的操作系统和硬件体系结构不同&#xff0c;为了提供通信支持&#xff0c;位于同一个网络中的计算机在进行连接和通信时必须要遵守一定的规则&#xff0c;这就好比在道路中行驶的汽车一定要遵守交…

SMART PLC向导PID和一阶低通滤波器组合编程应用(恒压控制)

一阶滞后滤波器算法和代码详细介绍请参考下面的文章链接: 【精选】PLC信号处理系列之一阶低通(RC)滤波器算法_数字rc滤波-CSDN博客文章浏览阅读3.6k次。1、先看看RC滤波的优缺点 优点:采用数字滤波算法来实现动态的RC滤波,则能很好的克服模拟滤波器的缺点; 1、在模拟常数要…

【python FastAPI】fastapi中如何限制输入参数,如何让docs更好看,如何自定义错误码json返回

原则&#xff1a; 输入输出都基于BaseModel依靠JSONResponse制定返回错误的json信息依靠装饰器中app.post制定responses字典从而让docs文档更丰富 import uvicorn from pydantic import BaseModel, Field from fastapi import FastAPI, HTTPException from fastapi.middleware…

单片机和FreeRTOS上跑机器人ROS的应用

机器人的应用越来越广泛了&#xff0c;大家熟知的稚晖君直接创业搞机器人&#xff0c;可想而至&#xff0c;接下来的十年&#xff0c;机器人绝对是热门的行业。 目前市面上很多机器人都是基于一套叫做ROS的系统开发的&#xff0c;今天就给大家分享一个跑在MCU上&#xff0c;基…

红葡萄酒和白葡萄酒哪个好?哪个更适合你?

云仓酒庄的品牌雷盛红酒分享接触葡萄酒不久的小伙伴不知道红葡萄和白葡萄酒哪个更好&#xff0c;更适合自己。其实&#xff0c;任何葡萄酒不论价位、风格、颜色&#xff0c;没有哪个更好&#xff0c;只有哪个更适合品饮者。 红葡萄酒之所以呈现出浓艳的颜色&#xff0c;是在酿造…

网站监控的重要性及实施策略

随着互联网的快速发展&#xff0c;网站已经成为企业和个人不可或缺的在线服务平台。然而&#xff0c;网站的安全性和稳定性一直是企业及个人非常关注的问题。一旦网站出现故障或者被攻击&#xff0c;将会给企业和个人带来严重的损失。因此&#xff0c;实施有效的网站监控策略对…

我了解的3D游戏引擎和图形开发框架

如果你像我一样&#xff0c;没有什么比编写或设计软件更让人兴奋的了。 当我编写代码时&#xff0c;我所获得的巨大快乐促使我开发了跨越许多软件领域的项目。 这些领域之一是为本机应用程序、桌面展示或 Web 创建 3D 图形。 我从未创建过任何 3D 游戏&#xff0c;但很多时候我…

基于JAVA+SSM+VUE+微信小程序的前后端分离的生活日用品交易平台的设计与实现

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&#xff1a; 随着互联网的快速发展…

Python Web框架的三强之争:Flask、Django和FastAPI

JetBrains 公布 2022 Python 开发者调查结果。 完整报告地址&#xff1a;https://lp.jetbrains.com/zh-cn/python-developers-survey-2022/ 这是由 Python 软件基金会 (PSF) 和 JetBrains 共同开展的第六次官方年度 Python 开发者调查&#xff0c;回复于 2022 年 10 月至 12 …

国外客户要求免费样品?我来教你如何应对

这一次的问题对外贸业务员来说是非常重要。无论你是做什么行业&#xff0c;无论你是做什么产品我相信这个问题对你来说超级有用。 关于发样品给客户我有四个方案来跟大家分享&#xff0c;我希望你能够喜欢希望你很认真的思考一下&#xff1a; 方法一【样品费及运费一起收】&am…

【网络编程】简述TCP通信程序,三次握手,四次挥手

文章目录 &#x1f384;TCP通信程序⭐打印字符串✨中文乱码问题&#x1f388;解决方法 &#x1f33a;TCP三次握手&#x1f33a;TCP四次挥手&#x1f6f8;其他 &#x1f38a;专栏【网络编程】 &#x1f354;喜欢的诗句&#xff1a;更喜岷山千里雪 三军过后尽开颜。 &#x1f386…

腾讯云标准型S5云主机性能评测_CPU内存_带宽系统盘测评

腾讯云服务器CVM标准型S5实例具有稳定的计算性能&#xff0c;CVM 2核2G S5活动优惠价格280.8元一年自带1M带宽&#xff0c;15个月313.2元、2核4G配置748.2元15个月&#xff0c;CPU内存配置还可以选择4核8G、8核16G等配置&#xff0c;公网带宽可选1M、3M、5M或10M&#xff0c;腾…

buildAdmin 后端控制器的代码分析

buildAdmin的代码生成&#xff0c;很像是 fastadmin 的生成模式&#xff0c;当我们利用数据库生成了一个控制器的时候&#xff0c;我们可以看到&#xff0c; 它的生成代码很简洁 <?phpnamespace app\admin\controller\askanswer;use app\common\controller\Backend;/*** 回…

2023.11.19使用flask制作一个文件夹生成器

2023.11.19使用flask制作一个文件夹生成器 实现功能&#xff1a; &#xff08;1&#xff09;在指定路径上建立文件夹 &#xff08;2&#xff09;返回文件夹的路径和建立成功与否的提示 main.py import os from flask import Flask, request, jsonify, render_templateapp F…