詳解如何實(shí)現(xiàn)C#和Python間實(shí)時(shí)視頻數(shù)據(jù)交互
我們?cè)谧鯮TSP|RTMP播放的時(shí)候,遇到好多開發(fā)者,他們的視覺算法大多運(yùn)行在python下,需要高效率的實(shí)現(xiàn)C#和Python的視頻數(shù)據(jù)交互,常用的方法如下:
方法一:通過(guò)HTTP請(qǐng)求傳輸視頻數(shù)據(jù)
服務(wù)器端(Python)
使用Flask或Django等Web框架創(chuàng)建一個(gè)HTTP服務(wù)器,通過(guò)API接口提供視頻數(shù)據(jù)。
from flask import Flask, send_file, request, jsonify
import cv2
import io
import base64
app = Flask(__name__)
def get_video_frame():
# 讀取視頻幀
cap = cv2.VideoCapture('your_video.mp4')
ret, frame = cap.read()
cap.release()
if not ret:
return None, "No more frames"
# 轉(zhuǎn)換為RGB格式
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# 轉(zhuǎn)換為字節(jié)流
ret, buffer = cv2.imencode('.jpg', frame_rgb)
if not ret:
return None, "Could not encode frame"
# 將字節(jié)流轉(zhuǎn)換為base64字符串
img_str = base64.b64encode(buffer).decode('utf-8')
return img_str, 200
@app.route('/video_frame', methods=['GET'])
def video_frame():
img_str, status_code = get_video_frame()
if img_str is None:
return jsonify({"error": status_code}), status_code
return jsonify({"image": img_str})
if __name__ == '__main__':
app.run(debug=True)客戶端(C#)
使用HttpClient從Python服務(wù)器獲取視頻幀,并將其顯示在PictureBox中。
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Net.Http;
using System.Windows.Forms;
public class VideoForm : Form
{
private PictureBox pictureBox;
private HttpClient httpClient;
public VideoForm()
{
pictureBox = new PictureBox
{
Dock = DockStyle.Fill,
SizeMode = PictureBoxSizeMode.StretchImage
};
this.Controls.Add(pictureBox);
httpClient = new HttpClient();
Timer timer = new Timer();
timer.Interval = 100; // Adjust the interval as needed
timer.Tick += Timer_Tick;
timer.Start();
}
private async void Timer_Tick(object sender, EventArgs e)
{
try
{
HttpResponseMessage response = await httpClient.GetAsync("http://localhost:5000/video_frame");
response.EnsureSuccessStatusCode();
string jsonResponse = await response.Content.ReadAsStringAsync();
dynamic jsonData = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonResponse);
string base64String = jsonData.image;
byte[] imageBytes = Convert.FromBase64String(base64String);
using (MemoryStream ms = new MemoryStream(imageBytes))
{
Image image = Image.FromStream(ms);
pictureBox.Image = image;
}
}
catch (Exception ex)
{
MessageBox.Show($"Error: {ex.Message}");
}
}
[STAThread]
public static void Main()
{
Application.EnableVisualStyles();
Application.Run(new VideoForm());
}
}方法二:通過(guò)ZeroMQ傳輸視頻數(shù)據(jù)
ZeroMQ是一種高性能的異步消息庫(kù),適用于需要低延遲和高吞吐量的應(yīng)用。
服務(wù)器端(Python)
使用pyzmq庫(kù)發(fā)送視頻幀。
import zmq
import cv2
import numpy as np
context = zmq.Context()
socket = context.socket(zmq.PUB)
socket.bind("tcp://*:5555")
cap = cv2.VideoCapture('your_video.mp4')
while True:
ret, frame = cap.read()
if not ret:
break
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
frame_bytes = frame_rgb.tobytes()
socket.send_string("FRAME", zmq.SNDMORE)
socket.send(frame_bytes, flags=0, copy=False)客戶端(C#)
使用NetMQ庫(kù)接收視頻幀。
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using System.Windows.Forms;
using NetMQ;
using NetMQ.Sockets;
public class VideoForm : Form
{
private PictureBox pictureBox;
private SubscriberSocket subscriber;
public VideoForm()
{
pictureBox = new PictureBox
{
Dock = DockStyle.Fill,
SizeMode = PictureBoxSizeMode.StretchImage
};
this.Controls.Add(pictureBox);
var address = "tcp://localhost:5555";
using (var context = NetMQContext.Create())
{
subscriber = context.CreateSubscriberSocket();
subscriber.Connect(address);
subscriber.Subscribe("FRAME");
Task.Run(() => ReceiveFramesAsync(subscriber));
}
}
private async Task ReceiveFramesAsync(SubscriberSocket subscriber)
{
while (true)
{
var topic = await subscriber.ReceiveFrameStringAsync();
var frameBytes = await subscriber.ReceiveFrameBytesAsync();
if (topic == "FRAME")
{
int width = 640; // Adjust based on your video resolution
int height = 480; // Adjust based on your video resolution
int stride = width * 3;
Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format24bppRgb);
BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, bitmap.PixelFormat);
Marshal.Copy(frameBytes, 0, bitmapData.Scan0, frameBytes.Length);
bitmap.UnlockBits(bitmapData);
pictureBox.Image = bitmap;
}
}
}
[STAThread]
public static void Main()
{
Application.EnableVisualStyles();
Application.Run(new VideoForm());
}
}方法三:通過(guò)共享內(nèi)存或文件
如果C#和Python運(yùn)行在同一臺(tái)機(jī)器上,可以通過(guò)共享內(nèi)存或文件系統(tǒng)進(jìn)行數(shù)據(jù)交換。這種方法相對(duì)簡(jiǎn)單,但性能可能不如前兩種方法。
以上就是詳解如何實(shí)現(xiàn)C#和Python間實(shí)時(shí)視頻數(shù)據(jù)交互的詳細(xì)內(nèi)容,更多關(guān)于C#和Python視頻數(shù)據(jù)交互的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
深入分析C#鍵盤勾子(Hook),屏蔽鍵盤活動(dòng)的詳解
本篇文章是對(duì)C#鍵盤勾子(Hook),屏蔽鍵盤活動(dòng)進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
輕松學(xué)習(xí)C#的預(yù)定義數(shù)據(jù)類型
輕松學(xué)習(xí)C#的預(yù)定義數(shù)據(jù)類型,C#的預(yù)定義數(shù)據(jù)類型包括兩種,一種是值類型,一種是引用類型,需要的朋友可以參考下2015-11-11
C#將布爾類型轉(zhuǎn)換成字節(jié)數(shù)組的方法
這篇文章主要介紹了C#將布爾類型轉(zhuǎn)換成字節(jié)數(shù)組的方法,涉及C#中字符串函數(shù)的使用技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-04-04
C#通過(guò)Python.NET調(diào)用Python?pyd擴(kuò)展模塊的實(shí)踐指南
在工業(yè)軟件與算法融合的場(chǎng)景中,經(jīng)常需要將 Python 生態(tài)的高性能算法庫(kù)集成到 C# 桌面或后端應(yīng)用中,下面我們就來(lái)看看在C#應(yīng)用中調(diào)用Python編譯模塊(pyd)有哪些技術(shù)方案吧2026-05-05
C#通過(guò)經(jīng)緯度計(jì)算2個(gè)點(diǎn)之間距離的實(shí)現(xiàn)代碼
這篇文章主要介紹了C#通過(guò)經(jīng)緯度計(jì)算2個(gè)點(diǎn)之間距離實(shí)現(xiàn)代碼,本文對(duì)實(shí)現(xiàn)原理、經(jīng)緯度基本知識(shí)等一并做了講解,需要的朋友可以參考下2014-08-08
C#/VB.NET 實(shí)現(xiàn)在PDF表格中添加條形碼
條碼的應(yīng)用已深入生活和工作的方方面面。在處理?xiàng)l碼時(shí),常需要和各種文檔格式相結(jié)合。本文,以操作PDF文件為例,介紹如何在編輯表格時(shí),向單元格中插入條形碼,需要的可以參考一下2022-06-06
C#二叉搜索樹算法實(shí)現(xiàn)步驟和實(shí)例代碼
二叉搜索樹(Binary?Search?Tree,簡(jiǎn)稱BST)是一種節(jié)點(diǎn)有序排列的二叉樹數(shù)據(jù)結(jié)構(gòu),這篇文章主要介紹了C#二叉搜索樹算法實(shí)現(xiàn)步驟和實(shí)例代碼,需要的朋友可以參考下2024-08-08

