Unity MiniCPM-V 让引擎拥有视觉

news2025/1/17 23:23:20

Unity MiniCPM-V 让引擎拥有视觉

  • 前言
  • 项目
    • Python环境布置
    • Unity场景布置
    • 代码编写
    • 添加并设置脚本
    • 总结
  • 鸣谢
  • AI提示

前言

新发布的MiniCPM-V,忍不住玩一下,可以让之前制作的语音助手拥有一定的视觉能力(不是OpenCV不行,而是AI更加符合一个助手所需要的观察力)。这个简单的小项目中我只实现了少量交互代码,大部分全部由ChatGPT 3.5完成,可以在文末链接查看对话记录。

AI视觉识别

项目

Python环境布置

参考官网配置: https://github.com/OpenBMB/MiniCPM-V/tree/main

除了官网的配置还要安装一下flask库

pip install flask

将脚本放到根目录下,并运行

from flask import Flask, request, jsonify
from chat import MiniCPMVChat, img2base64
import torch
import json
import base64
from io import BytesIO
from PIL import Image

# Initialize Flask app
app = Flask(__name__)

# Initialize the chat model
torch.manual_seed(0)
chat_model = MiniCPMVChat('openbmb/MiniCPM-Llama3-V-2_5')

def pil_image_to_base64(img):
    buffer = BytesIO()
    img.save(buffer, format="PNG")
    return base64.b64encode(buffer.getvalue()).decode()

@app.route('/analyze', methods=['POST'])
def analyze_image():
    try:
        data = request.json
        print(f"Received data: {data}")  # Debug: Log the received data
        
        image_base64 = data.get('image')
        question = data.get('question')

        if not image_base64 or not question:
            return jsonify({'error': 'Missing image or question'}), 400

        # Decode base64 image
        image_data = base64.b64decode(image_base64)
        image = Image.open(BytesIO(image_data))
        im_64 = pil_image_to_base64(image)  # Convert PIL image to base64 string

        # Prepare the inputs for the model
        msgs = [{"role": "user", "content": question}]
        inputs = {"image": im_64, "question": json.dumps(msgs)}

        print(f"Inputs for model: {inputs}")  # Debug: Log the inputs for the model

        # Get the answer from the model
        answer = chat_model.chat(inputs)

        # Prepare the response
        response = {
            'answer': answer,
            'context': msgs
        }

        return jsonify(response)

    except Exception as e:
        print(f"Error: {str(e)}")  # Debug: Log any error that occurs
        return jsonify({'error': str(e)}), 500

if __name__ == '__main__':
    app.run(host='127.0.0.1', port=5000)

配置环境并运行Python脚本

Unity场景布置

Unity场景布置

代码编写

创建并挂载ImageAnalyzer.cs脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using System.Text;
using Newtonsoft.Json;
using UnityEngine.UI;

public class Response
{
    [JsonProperty("answer")]
    public string Answer { get; set; }

    [JsonProperty("context")]
    public List<ContextItem> Context { get; set; }
}

public class ContextItem
{
    [JsonProperty("role")]
    public string Role { get; set; }

    [JsonProperty("content")]
    public string Content { get; set; }
}
public class ImageAnalyzer : MonoBehaviour
{
    [SerializeField] private string serverUrl = "http://your_server_ip:5000/analyze";
    [SerializeField] private int webcamWidth = 1280;
    [SerializeField] private int webcamHeight = 720;
    [SerializeField] private int webcamFPS = 30;
    [SerializeField] private WebCamTexture webCamTexture;

    private Texture2D snap;

    public Text tipText;
    public Button clickButton;
    public RawImage rawImage;
    private void Start()
    {
        // Start the webcam
        webCamTexture = new WebCamTexture(webcamWidth, webcamHeight);
        webCamTexture.Play();

        tipText.text = "请点击按钮询问";
        clickButton.interactable = true;
        rawImage.texture = webCamTexture;
    }


    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Q))
        {
            Debug.Log("按下了按钮");
            StartCoroutine(AnalyzeImageFromWebcam("用简短易懂的语言告诉我这张图上有什么?"));
        }
    }

    public void ClickButtonFunction()
    {
        tipText.text = "请等待。。。";
        clickButton.interactable = false;
        StartCoroutine(AnalyzeImageFromWebcam("用简短易懂的语言告诉我这张图上有什么?"));
    }

    public IEnumerator AnalyzeImageFromWebcam(string question)
    {
        // Wait until the webcam is ready
        yield return new WaitUntil(() => webCamTexture.didUpdateThisFrame);

        // Dispose of the previous snap texture if it exists
        if (snap != null)
        {
            Destroy(snap);
        }

        // Get the current frame from the webcam
        snap = new Texture2D(webCamTexture.width, webCamTexture.height);
        snap.SetPixels(webCamTexture.GetPixels());
        snap.Apply();

        // Convert the image to base64
        string base64Image = ConvertTextureToBase64(snap);

        // Analyze the image
        yield return StartCoroutine(AnalyzeImage(base64Image, question));
    }

    private string ConvertTextureToBase64(Texture2D texture)
    {
        byte[] imageBytes = texture.EncodeToPNG();
        return System.Convert.ToBase64String(imageBytes);
    }
    public IEnumerator AnalyzeImage(string base64Image, string question)
    {
        var formData = new Dictionary<string, string>
        {
            { "image", base64Image },
            { "question", question }
        };

        string jsonData = JsonConvert.SerializeObject(formData);
        byte[] postData = Encoding.UTF8.GetBytes(jsonData);

        UnityWebRequest request = new UnityWebRequest(serverUrl, "POST");
        request.uploadHandler = new UploadHandlerRaw(postData);
        request.downloadHandler = new DownloadHandlerBuffer();
        request.SetRequestHeader("Content-Type", "application/json");

        yield return request.SendWebRequest();

        if (request.result == UnityWebRequest.Result.ConnectionError || request.result == UnityWebRequest.Result.ProtocolError)
        {
            Debug.LogError(request.error);
            tipText.text = request.error;
            clickButton.interactable = true;
        }
        else
        {
            string jsonResponse = request.downloadHandler.text;
            Debug.Log("Response JSON: " + jsonResponse); // Log the response for debugging

            // Process the JSON response here
            // Deserialize the JSON response to the Response object
            Response response = JsonConvert.DeserializeObject<Response>(jsonResponse);

            // Use the response data
            Debug.Log("Answer: " + response.Answer);


            foreach (var contextItem in response.Context)
            {
                Debug.Log($"Role: {contextItem.Role}, Content: {contextItem.Content}");
            }

            tipText.text = response.Answer;
            clickButton.interactable = true;
        }
        request.Dispose();
    }


    void OnDestroy()
    {
        // Stop the webcam
        if (webCamTexture != null)
        {
            webCamTexture.Stop();
            webCamTexture = null;
        }
        // Dispose of the snap texture
        if (snap != null)
        {
            Destroy(snap);
            snap = null;
        }
    }
}

添加并设置脚本

在按钮上添加一下事件,给ImageAnalyzer物体赋值即可
按钮添加事件

总结

除了交互部分,一行代码没写,这也是未来趋势,提前适应一下。

鸣谢

https://chatgpt.com/
https://github.com/OpenBMB/MiniCPM-V/tree/main

AI提示

点击下方链接可以查看我和ChatGPT 3.5的聊天记录并了解详细开发过程
Image Q&A Service

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【数据分享】中国第三产业统计年鉴(1991-2022)

大家好&#xff01;今天我要向大家介绍一份重要的中国第三产业统计数据资源——《中国第三产业统计年鉴》。这份年鉴涵盖了从1991年到2022年中国第三产业统计全面数据&#xff0c;并提供限时免费下载。&#xff08;无需分享朋友圈即可获取&#xff09; 数据介绍 每年的《中国…

数据结构的归并排序(c语言版)

一.归并排序的基本概念 1.基本概念 归并排序是一种高效的排序算法,它采用了分治的思想。它的基本过程如下: 将待排序的数组分割成两个子数组,直到子数组只有一个元素为止。然后将这些子数组两两归并,得到有序的子数组。不断重复第二步,直到最终得到有序的整个数组。 2.核心…

MES系统生产计划的实施流程

在工厂的生产运营中&#xff0c;首先需要制定生产计划&#xff0c;MES系统软件可以监控从原材料进入工厂到产品进入仓库的整个生产过程&#xff0c;记录生产过程中使用的材料&#xff0c;设备&#xff0c;产品检验数据和结果&#xff0c;以及生产时间&#xff0c;人员和其他信息…

项目-双人五子棋对战:匹配模块的实现(3)

完整代码见: 邹锦辉个人所有代码: 测试仓库 - Gitee.com 模块详细讲解 功能需求 匹配就类似于大家平常玩的王者荣耀这样的匹配功能, 当玩家点击匹配之后, 就会进入到一个匹配队列, 当匹配到足够数量的玩家后, 就会进入确认页. 在这里, 我们主要实现的是1 - 1匹配功能, 首先先…

PPP-B2b精密产品使用注意事项及分析

1、因为在使用PPP-B2b进行定轨的时候&#xff0c;发的精密轨道产品是B3频点的&#xff0c;需要改正的卫星质心&#xff08;Com&#xff09;与SP3精密星历对比。 2、PPP-B2b产品吸收了电离层误差&#xff0c;因此电离层提取方面与IGS电离层完全无法对其。 3、由于PPP-B2b产品精…

【微信小程序】初识小程序

项目结构 项目基本组成结构 页面基础组成结构 JSON 配置文件 App.json app.json是当前小程序的全局配置&#xff0c;包括了小程序的所有页面路径、窗口外观、界面表现、底部tab等。 在 pages 中加入路径&#xff0c;保存后&#xff0c;开发者工具可以自动帮我们创建对应的页…

SAS:什么时候用kcompress呀?

问题&#xff1a;如何截取ECGTPT变量中的后三个字符&#xff1f; 下图展示了以k开头的以及非k开头的substr函数和length函数&#xff0c;发现在UTF-8编码下&#xff0c;仅以k开头的函数能够截取成功。 释疑&#xff08;以下内容来自SAS Help&#xff09; SAS提供的字符函数…

微软云计算[2]之微软云关系数据库SQL Azure

微软云关系数据库SQL Azure SQL Azure概述SQL Azure关键技术SQL Azure数据库SQL Azure报表服务SQL Azure数据同步 SQL Azure和SQL Server对比 SQL Azure概述 SQL Azure是微软的云中关系型数据库。 SQL Azure数据库简化了多数据库的供应和部署。 SQL Azure还为用户提供内置的高…

FPGA新起点V1开发板(九)——流水灯

文章目录 一、模块框图二、代码编写三、注意点四、总结 一、模块框图 二、代码编写 endmodule下面需要敲出一个回车代码拼接是大括号 led < {led[2:0],led[3]}注意二进制和十进制 module flow_led(input sys_clk50,input rst_n,output reg [3:0] le…

探索 Adobe Illustrator 2023 (AI 2023) for Mac/Win——创意设计的强大工具

Adobe Illustrator 2023 (AI 2023) for Mac/Win 是一款在设计领域备受推崇的专业矢量图形编辑软件软件&#xff0c;为设计师们提供了无尽的创意可能性。 它具有强大而精确的绘图功能&#xff0c;让用户能够轻松绘制出各种复杂的图形、线条和形状。无论是简洁的图标设计还是精美…

STM32作业实现(八)触摸按键TPAD

目录 STM32作业设计 STM32作业实现(一)串口通信 STM32作业实现(二)串口控制led STM32作业实现(三)串口控制有源蜂鸣器 STM32作业实现(四)光敏传感器 STM32作业实现(五)温湿度传感器dht11 STM32作业实现(六)闪存保存数据 STM32作业实现(七)OLED显示数据 STM32作业实现(八)触摸按…

vscode中选择pytorch虚拟环境中库没有导入报错,但是本机命令行下载过了

这是下载成功的结果 这个时候你会发现matplotlib的库是下载过的&#xff0c;没法下载 这个的原因是你的matplotlib库是下载到本机的python上但是pytorch框架上的是没有这个库的&#xff0c;此时应该打开ananconda promopt 然后输入activate pytorch转换成pytorch环境 然后pip…

gitlabcicd-k8s部署runner

一.环境信息 存储使用nfs挂载持久化 k8s环境 helm安装 建议helm 3 二.部署gitlab-runner 1.查看gitlab版本 进入容器可通过执行&#xff1a;gitlab-rake gitlab:env:info rootgitlab-647f4bd8b4-qz2j9:/# gitlab-rake gitlab:env:info System information System: Current Us…

zimo221软件和PCtoLCD2002软件的使用

Zimo221软件和PCtoLCD2002软件的使用 在没有字库时&#xff0c;我们可能需要自建汉字库&#xff0c;这时&#xff0c;汉字取模软件就会变得很重要。 一、zimo221取模方式&#xff1a; 1、打开软件 2、点击“基本操作” 3、一定要先点击“新建图像”按钮&#xff0c;见下图…

vue3中 window绑定scroll事件滚动页面获取不到e.target.scrollTop

遇到的问题 vue3项目 onMounted(() > {window.addEventListener(scroll, (e) > {console.log(e.target.scrollTop)}) })想要监听页面中的滚动&#xff0c;然后获取滚动距离实现一些功能&#xff0c;发现event参数中获取不到e.target.scrollTop&#xff08;印象中以前使…

NSIS 安装包默认支持的参数

NSIS 安装包默认支持的参数 NSIS 制作的安装包默认支持 /NCRC、/S、/D 三个参数&#xff0c;详见下文 3.2 Installer Usage&#xff08;来自 Command Line Usage&#xff09;。 以上三个参数对应的功能分别为禁止 CRC 校验、静默安装、设置安装路径&#xff0c;这三个功能不需…

JAVA家政系统小程序源码,家政系统源码,支持店铺入驻接单,师傅入驻接单:专业团队自主研发的一套上门家政APP系统成品源码,支持商用

JAVA家政系统小程序源码&#xff0c;家政系统源码&#xff0c;支持店铺入驻接单&#xff0c;师傅入驻接单&#xff1a;专业团队自主研发的一套上门家政APP系统成品源码&#xff0c;支持商用 家政系统是一套可提供上门家政的系统&#xff0c;可在线预约开荒保洁、上门维修、美容…

使用 Node.js 和 Azure Function App 自动更新 Elasticsearch 索引

作者&#xff1a;来自 Elastic Jessica Garson 维护最新数据至关重要&#xff0c;尤其是在处理频繁变化的动态数据集时。这篇博文将指导你使用 Node.js 加载数据&#xff0c;并通过定期更新确保数据保持最新。我们将利用 Azure Function Apps 的功能来自动执行这些更新&#xf…

Vue中引入elementUI中的container组件失效

1.不用修改官网中任何css或者html 2.按需引入&#xff0c;不是只是引入官网的就可以 import Vue from vue import Router from vue-router import HelloWorld from /components/HelloWorld import First from /components/views/First import Second from /components/views/…

操作失败——后端

控制台观察&#xff0c;页面发送的保存菜品的请求 返回的response显示&#xff1a; ---------- 我开始查看明明感觉都挺正常&#xff0c;没啥错误&#xff0c;就是查不出来。结果后面电脑关机重启后&#xff0c;隔一天看&#xff0c;就突然可以了。我觉着可能是浏览器的缓存没…