【C#-Python通信】c#通过udp通信传输图像给python服务器用于目标检测(使用预训练yolov4模型)...


709e24d44248751cfa83eab5eed3f976.png

截图

演示录屏

d0c64a7dbc88a34a8ed12741dc7a2723.png

预训练模型文件

笔记:

一、udp客户端C#类

using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
using System.Drawing;
using System.Text.Json;


namespace WindowsFormsApp1
{


    public class Upd
    {
        private IPAddress serverIP = IPAddress.Parse("127.0.0.1");//192.168.0.100
        private static int max_size = 65000;//发送单个包大小
        private UdpClient udpClient = new UdpClient(11000);


        private class Packs_Info
        {
            public int packs_num { get; set; }
        }


        public byte[] ImageToByte(Image img)
        {
            using (var stream = new MemoryStream())
            {
                img.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
                return stream.ToArray();
            }
        }
        //发送图像
        public void SendData(Image img)
        {
            try
            {
                udpClient.Connect(serverIP, 11000);
                var buffer = ImageToByte(img);//图像
                var num_packs = 1;
                if (buffer.Length > max_size)
                {
                    num_packs = (int)Math.Ceiling((double)buffer.Length / max_size);
                }
                var packs_info = new Packs_Info { packs_num = num_packs };//包信息 
                var packs_info_json = JsonSerializer.Serialize<Packs_Info>(packs_info);//包信息序列化
                //var packs_info_Bytes = Encoding.ASCII.GetBytes(packs_info_json);
                var packs_info_Bytes = Encoding.ASCII.GetBytes(packs_info_json);
                udpClient.Send(packs_info_Bytes, packs_info_Bytes.Length);//发送数据包信息


                var left = 0;
                var right = max_size;


                if (num_packs == 1)//单个图像占用字节数小于max_size
                {
                    udpClient.Send(buffer, buffer.Length);//一次发送图像
                    Console.WriteLine("package number: {0} ,  Size:  {1}   ", num_packs, buffer.Length);
                }
                else//多包构成一个图像
                {
                    for (int i = 0; i < num_packs; i++)//分多个包发送单个图像
                    {
                        Console.WriteLine("left : {0} , right : {1}", left, right);
                        var temp = 0;
                        var data = new byte[max_size];
                        for (int j = left; j < right; j++)
                        {
                            if (j == buffer.Length)
                                break;
                            data[temp] = buffer[j];
                            temp++;
                        }
                        left = right;//更新下一包的起点
                        right += max_size;//下一包的终点
                        udpClient.Send(data, data.Length);//发送一个包
                        Console.WriteLine("package number: {0} ,  Size:  {1}   ", i, data.Length);
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }
        //接收数据:识别结果字符串
        public string ReceiveData()
        {
            var RemoteIpEndPoint = new IPEndPoint(serverIP, 11000);
            var receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);
           // var jsonString = Encoding.ASCII.GetString(receiveBytes);
            var jsonString = Encoding.ASCII.GetString(receiveBytes);
            var box_info = JsonSerializer.Deserialize<Box_Info>(jsonString);
            Console.WriteLine("box {0} ,  color:  {1}   ", box_info.box, box_info.color);
            return jsonString;
            //var box_info = JsonSerializer.Deserialize<Box_Info>(jsonString);
            //Console.WriteLine("box {0} ,  color:  {1}   ", box_info.box, box_info.color);
        }
        private class Box_Info
        {
            public string name { get; set; }//
            public int[] box { get; set; }//边框x,y,w,h数组
            public string label { get; set; }//标签
            public int[] color { get; set; }//边框颜色数组
        }//边框信息
        public string stopStream()
        {
            udpClient.Close();
            return "stoped";
        }


    }
}

二、C#主窗体类代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.IO;
using System.Windows.Forms;
using Emgu.CV;
using System.Text.Json;
using Emgu.CV.Structure;
using Emgu.CV.CvEnum;


namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        private VideoCapture objCapture;//视频捕获
        private Mat _frame;
        private Mat _frame_before;
        private bool isOpen = true;//打开视频流
        private bool is_stream = true;
        private int Fps;//帧率
        private Thread thread_stream;//udp发送图像线程
        private Thread thread_receive;//接收线程
        public string box_info_str;//边框信息字符串 private
        public static object lockObj = new Object();//锁
        private Upd udp;
        private class Box_Info
        {
            public string name { get; set; }//
            public int[] box { get; set; }//边框x,y,w,h数组
            public string label { get; set; }//标签
            public int[] color { get; set; }//边框颜色数组
        }//边框信息


        public Form1()
        {
            InitializeComponent();
        }
        //处理图像
        private void ProcessFrame(object sender, EventArgs e)
        {
            if (objCapture != null && objCapture.Ptr != IntPtr.Zero)
            {
                objCapture.Retrieve(_frame_before, 0);//读取一帧->_frame_before
                Fps = (int)objCapture.Get(CapProp.Fps);//获取帧率
                CvInvoke.Flip(_frame_before, _frame, FlipType.Horizontal);//水平反转图像
                if (box_info_str != null)
                {
                    var box_info = JsonSerializer.Deserialize<Box_Info>(box_info_str);//反序列化边框信息
                    var rectangle = new Rectangle(box_info.box[0], box_info.box[1], box_info.box[2], box_info.box[3]);//边框
                    var mcvScalar = new MCvScalar(box_info.color[0], box_info.color[1], box_info.color[2]);//颜色
                    CvInvoke.Rectangle(_frame, rectangle, mcvScalar, 2);//绘制边框
                                                                        //显示标签
                    CvInvoke.PutText(_frame, box_info.label, new Point(box_info.box[0], box_info.box[1] - 10), FontFace.HersheyComplexSmall, 1, mcvScalar, 2);
                }
                //显示帧率
                CvInvoke.PutText(_frame, Fps.ToString(), new Point(0, 25), FontFace.HersheyComplexSmall, 1.5, new MCvScalar(0, 0, 255), 2);
                Mat temp = new Mat();
                _frame.CopyTo(temp);
                CvInvoke.Resize(temp, temp, pictureBox1.Size);
                pictureBox1.Image = temp.ToBitmap();//显示图像
                temp.Dispose();
                Thread.Sleep(3000 / (Fps));
            }
        }


        private void button1_Click(object sender, EventArgs e)
        {
            if (isOpen)
            {
                button1.Text = "Trun Off Camera";
                objCapture = new VideoCapture("test.mp4");//打开测试视频
                objCapture.ImageGrabbed += ProcessFrame;//捕获帧事件处理函数
                _frame = new Mat();
                _frame_before = new Mat();
                if (objCapture != null)
                    objCapture.Start();//开始播放
                isOpen = false;
            }
            else
            {
                button1.Text = "Trun On Camera";
                objCapture.Stop();//停止播放
                isOpen = true;
            }
           // isOpen = !isOpen;
        }


        private void button2_Click(object sender, EventArgs e)
        {
            if (is_stream)
            {
                udp = new Upd();//实例化udp
                button2.Text = "Stream Stop";
                thread_stream = new Thread(stream);//发送视频流处理函数
                thread_receive = new Thread(receive);//接收python返回的数据
                thread_stream.Start();
                thread_receive.Start();
            }
            else
            {
                thread_stream.Abort();
                thread_receive.Abort();
                udp.stopStream();//关闭udp客户端
                button2.Text = "Stream Start";
            }
            is_stream = !is_stream;
        }


        private void stream()
        {
            try
            {
                while (true)
                {
                    udp.SendData(_frame_before.ToBitmap());//一帧一帧的发送视频图像
                    Thread.Sleep(3000 / (Fps));
                }
            }
            catch (ThreadAbortException e)
            {
                Console.WriteLine("Stream Stopping");
            }
            finally
            {
                Console.WriteLine("Stream Stopped");
            }
        }


        private void receive()
        {
            try
            {
                while (true)
                {
                    lock (lockObj)
                    {
                        box_info_str = udp.ReceiveData();//接收返回的目标检测信息
                    }
                    Console.WriteLine(box_info_str);
                }
            }
            catch (ThreadAbortException e)
            {
                Console.WriteLine("Receive Stopping");
            }
            finally
            {
                Console.WriteLine("Receive Stopped");
            }
        }


    }
}

三、Python udp服务器端

import socket
import json
import numpy as np
#import cv2
from cv2 import cv2
import queue
import time




HOST = '127.0.0.1'#192.168.0.100
PORT = 11000
Max_size = 65000
packs_info = None
frame = None
class_names = []
frame_data = None
CONFIDENCE_THRESHOLD = 0.2
NMS_THRESHOLD = 0.4
COLORS = [(0, 255, 255), (255, 255, 0), (0, 255, 0), (255, 0, 0)]
frame_buffer = queue.Queue()


#net = cv2.dnn.readNet('model/yolov4-tiny.cfg','model/yolov4-tiny.weights')
net = cv2.dnn.readNet('model/yolov4.cfg','model/yolov4.weights')
#net = cv2.dnn.readNet('model/yolov4-custom.cfg','model/yolov4-custom.weights')
net.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA)
net.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA)#_FP16
model = cv2.dnn_DetectionModel(net)
model.setInputParams(size=(416, 416),scale=1/255,swapRB=True)
#model.setInputParams(size=(608, 608),scale=1/255,swapRB=True)#size=(608, 608)


with open("model/coco_classes.txt", "r") as f:
    class_names = [cname.strip() for cname in f.readlines()]


s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
s.bind((HOST, PORT))


print('server start at: %s:%s' % (HOST, PORT))
print('wait for connection...')




def img_decode(indata):
    _frame = np.frombuffer(indata, dtype=np.uint8)
    _frame = _frame.reshape(_frame.shape[0], 1)
    _frame = cv2.imdecode(_frame, cv2.IMREAD_COLOR)
    _frame = cv2.flip(_frame, 1)
    return _frame


while True:
    indata, addr = s.recvfrom(Max_size)
    print('recvfrom ' + str(addr) + ': ' + str(len(indata)))


    #check package is information or image data
    if len(indata) < 50:
        packs_info = json.loads(indata.decode())
        print(packs_info)


    else:
        indata_buffer = []
        indata_buffer.append(indata)


        if packs_info:
            package_size = packs_info['packs_num']
            if package_size == 1:
                frame = img_decode(indata_buffer[0])
                frame_buffer.put(frame)


            #combine the image data, whilch is oversize
            else:
                frame_data = None
                waiting_num = 0
                start = 0
                end = 0
                run_time = 0
                while True:
                    start = time.process_time()
                    indata, addr = s.recvfrom(Max_size)


                    if len(indata) > 50:
                        print('recvfrom2 ' + str(addr) + ': ' + str(len(indata)))
                        indata_buffer.append(indata)


                    if len(indata_buffer) == package_size:
                        for i in indata_buffer:
                            if frame_data is None:
                                frame_data = i
                            else:
                                frame_data += i
                        frame = img_decode(frame_data)
                        frame_buffer.put(frame)
                        break


                    end = time.process_time()
                    run_time += start-end
                    if run_time > 0.1 :
                        break


            #predict and send to client
            if frame_buffer.empty() is False and frame_buffer.qsize() > 1:
                try:
                    classes, scores, boxes = model.detect(frame_buffer.get(), CONFIDENCE_THRESHOLD, NMS_THRESHOLD)
                    for (classid, score, box) in zip(classes, scores, boxes):
                        color = COLORS[int(classid) % len(COLORS)]
                        label = "%s : %f" % (class_names[int(classid)], score)
                        cv2.rectangle(frame, box, color, 2)
                        cv2.putText(frame, label, (box[0], box[1] - 10), cv2.FONT_HERSHEY_SIMPLEX, 1, color, 2)
                        tempList = {"name":"box_info","box":box.tolist(),"label":label,"color":color}
                        json_str = json.dumps(tempList)
                        
                        s.sendto(json_str.encode(), addr)#发送数据有问题
                        packs_info = None


                except:
                    print("pass")
           
            if frame is not None and type(frame) == np.ndarray:
                cv2.imshow("Stream", frame)
                if cv2.waitKey(1) & 0xFF == ord('q'):
                    break

The End

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用UDP进行PythonC#之间的通信时,你需要在两个应用程序中分别实现UDP发送和接收功能。下面是一个简单的示例代码,演示了PythonC#之间通过UDP进行通信的过程。 Python端代码(发送端): ```python import socket def main(): target_ip = "192.168.1.100" # 目标IP地址 target_port = 1111 # 目标端口号 # 创建UDP套接字 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) while True: message = input("请输入要发送的消息:") if message == "exit": break # 发送消息到目标IP和端口 sock.sendto(message.encode(), (target_ip, target_port)) sock.close() if __name__ == '__main__': main() ``` C#端代码(接收端): ```csharp using System; using System.Net; using System.Net.Sockets; using System.Text; namespace udp_server { class Program { static int port = 1111; // 接收端口号 static void Main(string[] args) { Console.WriteLine("服务器启动....."); // 创建UDP套接字 UdpClient udpClient = new UdpClient(port); IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, port); while (true) { // 接收消息 byte[] bytes = udpClient.Receive(ref remoteEP); string message = Encoding.UTF8.GetString(bytes); Console.WriteLine("接收到消息:" + message); } udpClient.Close(); } } } ``` 这个示例中,Python端通过创建UDP套接字,然后从用户输入读取消息,并将消息发送到指定的目标IP和端口。C#端通过创建UDP套接字,然后循环接收来自Python发送的消息,并在控制台显示接收到的消息。 注意:在实际使用中,你需要根据具体的网络配置和需求进行适当的调整和处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值