| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319 |
- using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
- using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Drawing;
- using System.Drawing.Imaging;
- using System.IO;
- using System.IO.Compression;
- using System.IO.Ports;
- using System.Linq;
- using System.Text;
- using System.Threading;
- using System.Threading.Tasks;
- using System.Windows;
- using System.Windows.Controls;
- using System.Windows.Data;
- using System.Windows.Documents;
- using System.Windows.Input;
- using System.Windows.Interop;
- using System.Windows.Media;
- using System.Windows.Media.Imaging;
- using System.Windows.Navigation;
- using System.Windows.Shapes;
- using Brush = System.Drawing.Brush;
- using Color = System.Drawing.Color;
- using Pen = System.Drawing.Pen;
- using PixelFormat = System.Drawing.Imaging.PixelFormat;
- using Rectangle = System.Drawing.Rectangle;
- namespace Air105Camera
- {
- /// <summary>
- /// MainWindow.xaml 的交互逻辑
- /// </summary>
- [PropertyChanged.AddINotifyPropertyChangedInterface]
- public partial class MainWindow : Window
- {
- public MainWindow()
- {
- InitializeComponent();
- }
- //将Bitmap对象转换成bitmapImage对象
- private BitmapImage ConvertBitmapToBitmapImage(Bitmap bitmap)
- {
- MemoryStream stream = new MemoryStream();
- bitmap.Save(stream, ImageFormat.Bmp);
- BitmapImage image = new BitmapImage();
- image.BeginInit();
- image.StreamSource = stream;
- image.EndInit();
- return image;
- }
- //刷新显示当前图片
- private void ShowImage()
- {
- this.Dispatcher.Invoke(() =>
- {
- var temp = ConvertBitmapToBitmapImage(image);
- CameraImage.Source = temp;
- });
- }
- //缓存图片数据
- Bitmap image = new Bitmap(320, 240, PixelFormat.Format16bppRgb565);
- Graphics imageGraphic = null;
- //串口对象
- private SerialPort Uart = new SerialPort();
- //总共收到多少包
- public int totalPack { get; set; } = 0;
- //总共刷了多少张
- public int totalPic { get; set; } = 0;
- //FPS数
- public double fpsNow { get; set; } = 0;
- public bool connectEnable { get; set; } = true;
- public bool disconnectEnable { get; set; } = true;
- private void Window_Loaded(object sender, RoutedEventArgs e)
- {
- this.DataContext = this;
- imageGraphic = Graphics.FromImage(image);
- //刷白
- imageGraphic.FillRectangle(new SolidBrush(Color.White), 0, 0, image.Width, image.Height);
- //图片显示一下
- ShowImage();
- // 绑定事件监听,用于监听HID设备插拔
- (PresentationSource.FromVisual(this) as HwndSource)?.AddHook(WndProc);
- RefreshPortList();
- //串口数据处理,随便写写
- new Thread(Uart2Image).Start();
- }
- private void ConnectButton_Click(object sender, RoutedEventArgs e)
- {
- if (Uart.IsOpen)
- {
- return;
- }
- if (((string)SerialComboBox.SelectedItem).Length > 0)
- {
- var portName = (string)SerialComboBox.SelectedItem;
- Task.Run(() =>
- {
- try
- {
- Uart.PortName = portName;
- Uart.Open();
- }
- catch (Exception ex)
- {
- MessageBox.Show(ex.Message);
- }
- });
- }
- }
- private void DisconnectButton_Click(object sender, RoutedEventArgs e)
- {
- if (!Uart.IsOpen)
- {
- return;
- }
- try
- {
- Uart.Close();
- }
- catch(Exception ex)
- {
- MessageBox.Show(ex.Message);
- }
- }
- private static int UsbPluginDeley = 0;
- private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
- {
- if (msg == 0x219)// 监听USB设备插拔消息
- {
- if (UsbPluginDeley == 0)
- {
- ++UsbPluginDeley; // Task启动需要准备时间,这里提前对公共变量加一
- Task.Run(() =>
- {
- do Task.Delay(100).Wait();
- while (++UsbPluginDeley < 10);
- UsbPluginDeley = 0;
- RefreshPortList();
- });
- }
- else UsbPluginDeley = 1;
- handled = true;
- }
- return IntPtr.Zero;
- }
- /// <summary>
- /// 刷新设备列表,并在断开恢复后重连
- /// </summary>
- /// <returns>串口列表是否成功获取</returns>
- private bool RefreshPortList()
- {
- bool result = true;
- var list = SerialPort.GetPortNames();
- Dispatcher.Invoke(delegate
- {
- SerialComboBox.ItemsSource = list;
- if (SerialComboBox.Items.Count == 0)
- {
- result = false;
- }
- else if (SerialComboBox.Items.Contains(Uart.PortName))
- {
- SerialComboBox.SelectedItem = Uart.PortName;
- }
- else SerialComboBox.SelectedIndex = 0;
- });
- return result;
- }
- bool closed = false;
- private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
- {
- closed = true;
- //直接强关软件
- Environment.Exit(0);
- }
- private void RefreshButton_Click(object sender, RoutedEventArgs e)
- {
- RefreshPortList();
- }
- /*
- 16字节头+N字节数据
- 4字节字符串 “VCAM” + 2字节图像宽度 + 2字节图像高度 + 4字节本次数据从哪行开始刷 + 2字节未压缩数据长度 + 2字节压缩后图像数据长度
- 如果压缩前和压缩后数据长度是一致的,那就没有压缩;如果不一致,则后面的N字节要用zlib解压
- RGB565大端格式
- */
- //串口数据处理
- private void Uart2Image()
- {
- byte[] temp = new byte[10 * 1024 * 1024];//缓冲区
- int p = 0;//上次的位置
- Stopwatch sw = new Stopwatch();
- sw.Start();
- bool getNewData = false;//记一下是不是收到新数据了
- while (true)
- {
- if (closed)
- return;
- connectEnable = !Uart.IsOpen;
- disconnectEnable = Uart.IsOpen;
- try
- {
- if (Uart.IsOpen && Uart.BytesToRead > 0)
- {
- //读数据
- var toread = Uart.BytesToRead;
- Uart.Read(temp, p, toread);
- p += toread;
- getNewData = true;
- }
- else if (!Uart.IsOpen)
- {
- fpsNow = 0;
- p = 0;
- }
- if(getNewData)
- {
- getNewData = false;//收到新数据再刷
- for (int i = 3; i < p; i++)
- {
- //匹配VCAM头
- if (temp[i - 3] == 'V' && temp[i - 2] == 'C' && temp[i - 1] == 'A' && temp[i] == 'M'
- && p - i > 16)
- {
- var width = BitConverter.ToUInt16(temp, i + 1);
- var height = BitConverter.ToUInt16(temp, i + 3);
- var start = BitConverter.ToUInt32(temp, i + 5);
- var rawLen = BitConverter.ToUInt16(temp, i + 9);
- var comLen = BitConverter.ToUInt16(temp, i + 11);
- Debug.WriteLine($"found VCAM: {BitConverter.ToString(temp, i - 3, 16)}\r\n" +
- $"{width},{height},{start},{rawLen},{comLen},{i},{p}");
- //获取实际数据长度
- var realLength = comLen < rawLen ? comLen : rawLen;
- if (realLength <= p - i - 13)//一包数据够了
- {
- totalPack++;
- Debug.WriteLine($"{realLength} bytes, start unpack");
- //存储rgb数据
- byte[] data = null;
- if (comLen < rawLen)//包压缩了
- {
- //Debug.WriteLine(BitConverter.ToString(temp, i + 13, comLen));
- using MemoryStream compressed = new MemoryStream(temp, i + 13, comLen);
- using MemoryStream decompressed = new MemoryStream();
- using InflaterInputStream inputStream = new InflaterInputStream(compressed);
- inputStream.CopyTo(decompressed);
- data = decompressed.ToArray();
- }
- else//没压缩
- {
- Debug.WriteLine($"rawLen,{rawLen},{i + 13 + rawLen}");
- data = new byte[rawLen];
- for (int n = i + 13; n < i + 13 + rawLen; n++)
- data[n - (i + 13)] = temp[n];
- }
- //直接把rgb565数据写入bitmap,这样快
- //先把数据改成小端
- for (int n = 0; n < data.Length; n += 2)
- {
- (data[n], data[n + 1]) = (data[n + 1], data[n]);
- }
- var rect = new Rectangle(0, (int)start, width, data.Length / 2 / width);
- BitmapData bmpData = image.LockBits(rect, ImageLockMode.ReadWrite, image.PixelFormat);
- IntPtr ptr = bmpData.Scan0;// Get the address of the first line.
- System.Runtime.InteropServices.Marshal.Copy(data, 0, ptr, data.Length);
- image.UnlockBits(bmpData);
- //刷到最后一行时再显示当前图片
- if (start >= height - 16)
- {
- sw.Stop();
- fpsNow = 1000.0 / sw.ElapsedMilliseconds;
- sw.Restart();
- totalPic++;
- ShowImage();
- }
- //剩下的数据全部左移到开头
- for (int n = i + 13 + realLength; n < p; n++)
- temp[n - (i + 13 + realLength)] = temp[n];
- p -= i + 13 + realLength;
- Debug.WriteLine($"done, p now {p}");
- if (p > 3)
- i = 2;
- else
- break;
- }
- }
- }
- }
- Thread.Sleep(1);
- }
- catch (Exception e)
- {
- Debug.WriteLine(e.Message);
- }
- }
- }
- }
- }
|