Unity MiniCPM-V 让引擎拥有视觉

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.jsonprint(f"Received data: {data}")  # Debug: Log the received dataimage_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 imageimage_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 modelmsgs = [{"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 modelanswer = chat_model.chat(inputs)# Prepare the responseresponse = {'answer': answer,'context': msgs}return jsonify(response)except Exception as e:print(f"Error: {str(e)}")  # Debug: Log any error that occursreturn jsonify({'error': str(e)}), 500if __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 webcamwebCamTexture = 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 readyyield return new WaitUntil(() => webCamTexture.didUpdateThisFrame);// Dispose of the previous snap texture if it existsif (snap != null){Destroy(snap);}// Get the current frame from the webcamsnap = new Texture2D(webCamTexture.width, webCamTexture.height);snap.SetPixels(webCamTexture.GetPixels());snap.Apply();// Convert the image to base64string base64Image = ConvertTextureToBase64(snap);// Analyze the imageyield 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 objectResponse response = JsonConvert.DeserializeObject<Response>(jsonResponse);// Use the response dataDebug.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 webcamif (webCamTexture != null){webCamTexture.Stop();webCamTexture = null;}// Dispose of the snap textureif (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.mzph.cn/web/21154.shtml

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

相关文章

深入理解Java关系运算符,避免常见错误!

哈喽&#xff0c;各位小伙伴们&#xff0c;你们好呀&#xff0c;我是喵手。运营社区&#xff1a;C站/掘金/腾讯云&#xff1b;欢迎大家常来逛逛 今天我要给大家分享一些自己日常学习到的一些知识点&#xff0c;并以文字的形式跟大家一起交流&#xff0c;互相学习&#xff0c;一…

复现CELL文章图片,在线绘制scRNA-seq多个cluster的差异火山图

导读 火山图表示两组间的差异&#xff0c;而在scRNA-seq中&#xff0c;同时会有多个cluster&#xff08;vs其他cluster&#xff09;的差异。如果用常规火山图展示&#xff0c;可能需要绘制十几个图。有没有更高效的展示方法呢&#xff1f;今天给大家带来CELL文章“A Spatiotem…

打造SimPO新算法,微调8B模型超越Claude 3 Opus

前言 大型语言模型&#xff08;LLM&#xff09;近年来取得了巨大进展&#xff0c;但要将其与人类价值观和意图相一致&#xff0c;使其变得有用、诚实和无害&#xff0c;仍然是一个挑战。强化学习从人类反馈中&#xff08;RLHF&#xff09;是一种常用的方法&#xff0c;通过微调…

Charles的安装和web端抓包配置

1.Charles的安装 通过官网下载&#xff1a;https://www.charlesproxy.com/download/&#xff0c;我之前下载的是4.6.2版本&#xff0c;下载成功后点击安装包&#xff0c;点击下一步下一步即可安装成功。 ​​ ​ 安装成功后打开charles页面如下所示。 ​ 2.乱码问题解决 打开…

【C++】STL:栈和队列模拟实现

&#x1f49e;&#x1f49e; 前言 hello hello~ &#xff0c;这里是大耳朵土土垚~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f4a5;个人主页&#x…

绘画参数配置及使用

绘画参数配置及使用 路径&#xff1a;站点后台-功能-AI绘画 进入参数配置 接口选择&#xff1a;多种接口自主选择&#xff08;需自己准备key&#xff09;&#xff0c;对应接口的key对话和绘画通用 存储空间&#xff1a; 位置在超管后台-存储空间 自主选择存储&#xff08;需…

【数据结构与算法】七大排序算法(下)

【数据结构与算法】七大排序算法(下) &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;数据结构与算法&#x1f345; &#x1f33c;文章目录&#x1f33c; 2.3 交换排序 2.3.1 冒泡排序 2.3.2 快速排序 2.3.3 快速排序(非递归) 2.4 归并…

fpga入门 串口定时1秒发送1字节

一、 程序说明 FPGA通过串口定时发送数据&#xff0c;每秒发送1字节&#xff0c;数据不断自增 参考小梅哥教程 二、 uart_tx.v timescale 1ns / 1psmodule uart_tx(input wire sclk,input wire rst_n,output reg uart_tx);parameter …

【Python Cookbook】S01E12 根据字段将记录分组

目录 问题解决方案讨论 问题 如果有一系列的字典或对象实例&#xff0c;我们想根据某个特定的字段来分组迭代数据。 解决方案 假设有如下字典列表&#xff1a; rows [{address: 5412 N CLARK, date: 07/01/2012},{address: 5148 N CLARK, date: 07/04/2012},{address: 580…

W25Q64CV SPI Flash Memory

SPI简介 SPI是一种同步串行通信接口规范&#xff0c;用于短距离通信&#xff0c;主要应用于嵌入式系统。SPI通信由一个主设备和一个或多个从设备组成&#xff0c;其中主设备生成时钟信号并控制通信的开始和结束。 SPI通信的基本组成 四个基本信号 SCK (Serial Clock) - 时钟…

centos7下安装MySQL,Oracle数据库

&#x1f4d1;打牌 &#xff1a; da pai ge的个人主页 &#x1f324;️个人专栏 &#xff1a; da pai ge的博客专栏 ☁️宝剑锋从磨砺出&#xff0c;梅花香自苦寒来 操作系统版本为CentOS 7 使⽤ MySQ…

python数据分析——datetime数据类型2

参考资料&#xff1a;活用pandas库 # 导入pandas库 import pandas as pd # 加载数据集 teslapd.read_csv(r"...\data\tesla_stock_yahoo.csv") # 查看数据 print(tesla.head()) 1、基于日期取数据子集 # 将Date数据列转换为datetime类型 tesla[Date]pd.to_datetime…

学习笔记——网络参考模型——TCP/IP模型(传输层)

四、TCP/IP模型-传输层 一、TCP 1、TCP定义 TCP(Transmission Control Protocol&#xff0c;传输控制协议)∶为应用程序提供可靠的面向连接的通信服务。目前&#xff0c;许多流行的应用程序都使用TCP。 连接&#xff1a;正式发送数据之前&#xff0c;提前建立好一种虚拟的&…

ES6-03-模版字符串、对象的简化写法

一、模版字符串 1-1、声明 反引号。 1-2、特性 1、字符串内容可以直接换行 得用号连接 2、变量拼接 现在&#xff1a; 二、对象的简化写法 ES6允许在大括号里面&#xff0c;直接写入变量和函数&#xff0c;作为对象的属性和方法。 let name milk;let chage function(){con…

脚本实现登陆滑块

脚本实现登陆滑块 仅供学习参考&#xff0c;简单操作 你知道吗&#xff0c;滑动验证码居然是为了验证人类比机器人蠢而设计的。 你以为自己快速、准确地滑动拼图、对齐图案&#xff0c;才被允许通过&#xff0c;系统还说你超越了99%的用户&#xff0c;夸你“比闪电还快”&am…

STM32_SPI

1、SPI简介 1.1 什么是SPI SPI&#xff0c;即Serial Peripheral Interface&#xff0c;串行外设接口。SPI是一种高速的、全双工、同步的串行通信总线&#xff1b;SPI采用主从方式工作&#xff0c;一般有一个主设备和一个或多个从设备&#xff1b;SPI需要至少4根线&#xff0c;…

FLINK-窗口算子

参考资料 官方文档- WindowFlink中的时间和窗口之窗口 窗口 在流处理中&#xff0c;我们往往需要面对的是连续不断、无休无止的无界流&#xff0c;不可能等到所有所有数据都到齐了才开始处理。所以聚合计算其实只能针对当前已有的数据——之后再有数据到来&#xff0c;就需要继…

chat4-Server端保存聊天消息到mysql

本文档描述了Server端接收到Client的消息并转发给所有客户端或私发给某个客户端 同时将聊天消息保存到mysql 服务端为当前客户端创建一个线程&#xff0c;此线程接收当前客户端的消息并转发给所有客户端或私发给某个客户端同时将聊天消息保存到mysql 本文档主要总结了将聊天…

JavaWeb_SpringBootWeb基础

先通过一个小练习简单了解以下SpringBootWeb。 小练习&#xff1a; 需求&#xff1a;使用SpringBoot开发一个Web应用&#xff0c;浏览器发起请求/hello后&#xff0c;给浏览器返回字符串"Hello World~"。 步骤&#xff1a; 1.创建SpringBoot项目&#xff0c;勾选We…

epoll模型下的简易版code

epoll模型下的简易版code c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/epoll.h> #include <fcntl.h>#define MAX_EVENTS 10 #define NUM_DESCRIPTORS 5 // 模拟多个文件描述符// …