您现在的位置是:网站首页> .NET Core

.NET Core开源库收集

摘要

.NET Core开源库收集


C#开源库及辅助程序

DlibDotNet是Dlib的C#封装

NetCoreServer提供了服务器和客户端的实现,支持 TCP, SSL, UDP, HTTP, HTTPS, WebSocket 协议

.NET Core ABP

MudBlazor:一个UI简洁美观漂亮的Blazor开源组件

MAUI低功耗蓝牙通讯的例子

MAUI串口通讯

MAUI的TCP UDP通讯例子

MAUI NFC编程

Titanium Web Proxy——强大的HTTP(S)代理服务器

开源的商城系统

NTQQ机器人

FreeSQL对象关系映射(O/RM)组件

C# 下使用 ViewFaceCore 实现人脸识别功能

Avalonia .NET 的跨平台 UI 框架



DlibDotNet是Dlib的C#封装

点击进入源码

DlibDotNet包含了dlib库中的大部分功能,包括但不限于:

机器学习算法:支持各种常见的机器学习算法,如支持向量机(SVM)、决策树、随机森林等。

特征提取:提供各种特征提取方法,如HOG(Histogram of Oriented Gradients)、SIFT(Scale-Invariant Feature Transform)等。

图像处理:支持图像的各种基本操作,如缩放、裁剪、旋转等。

计算机视觉任务:支持各种计算机视觉任务,如人脸检测、人脸识别、物体检测等。

DlibDotNet通过C++/CLI封装了dlib库,使得.NET开发者可以方便地调用dlib的函数。同时,DlibDotNet还提供了一些辅助类和方法,使得开发者能够更加方便地使用dlib库的功能。


使用DlibDotNet实现机器学习和计算机视觉应用的一般流程如下:

安装DlibDotNet库:首先需要在项目中安装DlibDotNet库。可以通过NuGet包管理器来安装。在Visual Studio中打开项目,然后使用NuGet包管理器搜索DlibDotNet并安装即可。

准备数据:根据具体任务准备相应的数据集。数据集应该包含输入数据和对应的标签。

训练模型:使用DlibDotNet提供的机器学习算法对数据集进行训练,得到一个模型文件。这个模型文件可以用于后续的预测任务。

预测:加载训练好的模型文件,然后使用输入数据进行预测。根据预测结果进行后续的处理或分析。

结果评估:根据实际需求对预测结果进行评估,比如计算准确率、召回率等指标。


使用DlibDotNet实现目标追踪

管理NuGet程序包

分别搜索安装 DlibDotNet 和 OpenCVSharp

加载OpenCVSharp库

注意 Windows下选择 OpenCvSharp4.Windows

关键代码

internal class Program

    {

        /// <summary>

        /// 追踪框X

        /// </summary>

        static double a_X = 60;

        /// <summary>

        /// 追踪框Y

        /// </summary>

        static double a_Y = 60;

        /// <summary>

        /// 追踪框 W

        /// </summary>

        static double a_W = 40;

        /// <summary>

        /// 追踪框H

        /// </summary>

        static double a_H = 40;


        private static void Main(string[] args)

        {

            if (args.Length != 1)

            {

                Console.WriteLine("Call this program like this: ");

                Console.WriteLine("VideoTracking.exe <path of video_frames directory>");

                return;

            }

            var path = args[0];

            var files = new DirectoryInfo(path).GetFiles("*.jpg").Select(info => info.FullName).ToList();


            files.Sort();


            if (files.Count == 0)

            {

                Console.WriteLine($"No images found in {path}");

                return;

            }

            // 定义图像捕捉方式 从摄像头 , 注意 Windows下需要选择 VideoCaptureAPIs.DSHOW

            var cap = new VideoCapture(0, VideoCaptureAPIs.DSHOW);


            // 定义图像捕捉方式 从摄像头 视频文件

            //var cap = new VideoCapture("video.webm");


            //判断捕捉设备是否打开

            if (!cap.IsOpened())

            {

                Console.WriteLine("Unable to connect to camera");

                return;

            }


            Mat temp = null;

            var tracker = new CorrelationTracker();


            int init = 0;


            //定义显示窗口

            using (var win = new ImageWindow())

            {

                Console.WriteLine("对象追踪程序启动");

                Console.WriteLine("选择命令行为当前窗口,通过按键选择需要追踪的区域Width: [A,Z] Height:[S,X] X:[right,left] Y:[up,down] ,点击Enter开始追踪");

                Console.WriteLine("注意:切换命令行窗口输入法为英文输入状态");

                //选择追踪对象

                while (!win.IsClosed())

                {

                    //获得1帧图片

                    temp = cap.RetrieveMat();// new Mat();


                    if (temp == null)

                    {

                        Console.WriteLine("图像获取错误!");

                        return;

                    }


                    var array = new byte[temp.Width * temp.Height * temp.ElemSize()];

                    Marshal.Copy(temp.Data, array, 0, array.Length);

                    using (var cimg = Dlib.LoadImageData<BgrPixel>(array, (uint)temp.Height, (uint)temp.Width, (uint)(temp.Width * temp.ElemSize())))

                    {


                        init++;

                        if (init > 1)

                        {

                            var KK = Console.ReadKey();

                            if (KK.Key == ConsoleKey.Enter)

                            {

                                Console.WriteLine("开始追踪目标!");


                                //确定 追踪 位置

                                var rect2 = DRectangle.CenteredRect(a_X, a_Y, a_W, a_H);

                                //开始追踪

                                tracker.StartTrack(cimg, rect2);

                                win.SetImage(cimg);

                                win.ClearOverlay();

                                win.AddOverlay(rect2);

                                break;

                            }


                            //选择 追踪区域

                            if (KK.Key == ConsoleKey.RightArrow || KK.Key == ConsoleKey.LeftArrow || KK.Key == ConsoleKey.UpArrow || KK.Key == ConsoleKey.DownArrow || KK.Key == ConsoleKey.A || KK.Key == ConsoleKey.Z || KK.Key == ConsoleKey.S || KK.Key == ConsoleKey.X)

                            {

                                if (KK.Key == ConsoleKey.RightArrow)

                                {

                                    a_X++;

                                    if (a_X > cimg.Rect.Width - a_W)

                                    {

                                        a_X = cimg.Rect.Width - a_W;

                                    }

                                }

                                if (KK.Key == ConsoleKey.LeftArrow)

                                {

                                    a_X--;

                                    if (a_X < 0)

                                    {

                                        a_X = 0;

                                    }

                                }


                                if (KK.Key == ConsoleKey.UpArrow)

                                {

                                    a_Y--;

                                    if (a_Y < 0)

                                    {

                                        a_Y = 0;

                                    }


                                }

                                if (KK.Key == ConsoleKey.DownArrow)

                                {

                                    a_Y++;

                                    if (a_Y > cimg.Rect.Height - a_H)

                                    {

                                        a_Y = cimg.Rect.Height - a_H;

                                    }

                                }


                                if (KK.Key == ConsoleKey.A)

                                {

                                    a_W++;

                                    if (a_W >= cimg.Rect.Width - a_X)

                                    {

                                        a_W = cimg.Rect.Width - a_X;

                                    }

                                }

                                if (KK.Key == ConsoleKey.Z)

                                {

                                    a_W--;

                                    if (a_W < 10)

                                    {

                                        a_W = 10;

                                    }

                                }

                                if (KK.Key == ConsoleKey.S)

                                {

                                    a_H++;

                                    if (a_H > cimg.Rect.Height - a_Y)

                                    {

                                        a_H = cimg.Rect.Height - a_Y;

                                    }


                                }

                                if (KK.Key == ConsoleKey.X)

                                {

                                    a_H--;

                                    if (a_H < 10)

                                    {

                                        a_H = 10;

                                    }

                                }

                            }

                        }


                        var rect = DRectangle.CenteredRect(a_X, a_Y, a_W, a_H);

                        Console.WriteLine("Set RECT:" + a_X + " " + a_Y + " " + a_W + " " + a_H);

                        //显示图片

                        win.SetImage(cimg);

                        win.ClearOverlay();

                        //显示框

                        win.AddOverlay(rect);

                    }

                }


                //选择追踪对象

                while (!win.IsClosed())

                {

                    //获得1帧图片

                    temp = cap.RetrieveMat();// new Mat();

                    if (temp == null)

                    {

                        Console.WriteLine("图像获取错误!");

                        return;

                    }


                    var array = new byte[temp.Width * temp.Height * temp.ElemSize()];

                    Marshal.Copy(temp.Data, array, 0, array.Length);

                    using (var cimg = Dlib.LoadImageData<BgrPixel>(array, (uint)temp.Height, (uint)temp.Width, (uint)(temp.Width * temp.ElemSize())))

                    {

                        //更新追踪图像

                        tracker.Update(cimg);

                        win.SetImage(cimg);

                        win.ClearOverlay();


                        //获得追踪到的目标位置

                        DRectangle rect = tracker.GetPosition();

                        win.AddOverlay(rect);

                        Console.WriteLine("OBJ RECT:" + (int)rect.Left + " " + (int)rect.Top + " " + (int)rect.Width + " " + (int)rect.Height);


                        System.Threading.Thread.Sleep(100);

                    }

                }


            }


            Console.WriteLine("任意键退出");

            Console.ReadKey();

        }

    }

源码地址:https://github.com/LEX-2025/VideoTracking-ZD



NetCoreServer提供了服务器和客户端的实现,支持 TCP, SSL, UDP, HTTP, HTTPS, WebSocket 协议

NetCoreServer 是一个针对 .NET Core 和 .NET 5/6/7 的高性能和可扩展的网络库,它提供了服务器和客户端的实现,支持 TCP, SSL, UDP, HTTP, HTTPS, WebSocket 协议。这个库是为了简化网络编程而设计的,它封装了底层的网络通信细节,使得开发者可以更加专注于实现业务逻辑

NetCoreServer 库的特点包括:

异步处理:基于 .NET 的 System.IO.Pipelines 进行高性能的 I/O 操作。

简单的 API:易于使用的服务器和客户端类。

协议支持:支持多种网络协议,包括不限于 TCP, SSL/TLS, UDP, HTTP, HTTPS, WebSocket。

扩展性:允许开发者自定义协议和处理逻辑。

跨平台:可以在 Windows, Linux, macOS 上运行。

使用 NetCoreServer,你可以快速地创建一个网络服务器或客户端。例如,创建一个 TCP 服务器只需要继承 TcpServer 类并重写一些事件处理函数(如连接建立、接收数据等)。


下面是一个简单的 NetCoreServer TCP 服务器示例:

using System;

using System.Net;

using System.Text;

using NetCoreServer;


class EchoServer : TcpServer

{

    public EchoServer(IPAddress address, int port) : base(address, port) {}


    protected override TcpSession CreateSession() { return new EchoSession(this); }


    protected override void OnError(SocketError error)

    {

        Console.WriteLine($"Echo TCP server caught an error with code {error}");

    }

}


class EchoSession : TcpSession

{

    public EchoSession(TcpServer server) : base(server) {}


    protected override void OnConnected()

    {

        Console.WriteLine($"Echo TCP session with Id {Id} connected!");

    }


    protected override void OnDisconnected()

    {

        Console.WriteLine($"Echo TCP session with Id {Id} disconnected!");

    }


    protected override void OnReceived(byte[] buffer, long offset, long size)

    {

        // Echo the message back to the sender

        SendAsync(buffer, offset, size);

    }


    protected override void OnError(SocketError error)

    {

        Console.WriteLine($"Echo TCP session caught an error with code {error}");

    }

}


class Program

{

    static void Main(string[] args)

    {

        // TCP server port

        int port = 1111;

        Console.WriteLine($"TCP server port: {port}");


        // Create a new TCP echo server

        var server = new EchoServer(IPAddress.Any, port);


        // Start the server

        Console.WriteLine("Server starting...");

        server.Start();

        Console.WriteLine("Done!");


        Console.WriteLine("Press Enter to stop the server or '!' to restart the server...");


        // Perform text input

        for (;;)

        {

            string line = Console.ReadLine();

            if (string.IsNullOrEmpty(line))

                break;


            // Restart the server

            if (line == "!")

            {

                Console.WriteLine("Server restarting...");

                server.Restart();

                Console.WriteLine("Done!");

                continue;

            }

        }


        // Stop the server

        Console.WriteLine("Server stopping...");

        server.Stop();

        Console.WriteLine("Done!");

    }

}

在这个示例中,EchoServer 类继承自 TcpServer,并且实现了必要的事件处理函数。EchoSession 类继承自 TcpSession,用于处理客户端的连接和收发消息。服务器启动后,它会监听指定的端口,并对任何接入的连接进行响应。

如果你想使用 NetCoreServer 库,你可以通过 NuGet 包管理器安装它:

dotnet add package NetCoreServer

然后,你就可以在你的项目中引用并使用它了。


客户端例子:

using System;

using System.Net;

using System.Text;

using System.Threading;

using NetCoreServer;


class EchoClient : TcpClient

{

    public EchoClient(string address, int port) : base(address, port) { }


    protected override void OnConnected()

    {

        Console.WriteLine($"Echo client connected a server.");

        // 发送测试消息

        string message = "Hello, World!";

        byte[] buffer = Encoding.UTF8.GetBytes(message);

        SendAsync(buffer);

    }


    protected override void OnDisconnected()

    {

        Console.WriteLine($"Echo client disconnected from server.");

    }


    protected override void OnReceived(byte[] buffer, long offset, long size)

    {

        string message = Encoding.UTF8.GetString(buffer, (int)offset, (int)size);

        Console.WriteLine("Received from server: " + message);

        // 断开连接

        DisconnectAsync();

    }


    protected override void OnError(SocketError error)

    {

        Console.WriteLine($"Echo client caught an error with code {error}");

    }

}


class Program

{

    static void Main(string[] args)

    {

        // 服务器的 IP 地址和端口

        string address = "127.0.0.1";

        int port = 1111;


        Console.WriteLine($"Server address: {address}");

        Console.WriteLine($"Server port: {port}");


        // 创建并启动客户端

        var client = new EchoClient(address, port);

        client.ConnectAsync();


        Console.WriteLine("Press any key to shutdown the client...");

        Console.ReadKey();


        // 停止客户端

        client.DisconnectAndStop();

    }

}


NetCoreServer 库创建 WebSocket 服务器的示例如下所示。在这个例子中,我们将创建一个简单的 WebSocket 服务器,它能够接受客户端的连接,接收来自客户端的消息,并将其回传给客户端

using System;

using System.Net;

using System.Text;

using NetCoreServer;


class EchoWebSocketSession : WebSocketSession

{

    public EchoWebSocketSession(WebSocketServer server) : base(server) {}


    protected override void OnWsConnected(HttpRequest request)

    {

        Console.WriteLine($"WebSocket session with Id {Id} connected!");

    }


    protected override void OnWsDisconnected()

    {

        Console.WriteLine($"WebSocket session with Id {Id} disconnected!");

    }


    protected override void OnWsReceived(byte[] buffer, long offset, long size)

    {

        string message = Encoding.UTF8.GetString(buffer, (int)offset, (int)size);

        Console.WriteLine("Incoming: " + message);


        // Echo the message back to the client

        SendTextAsync(message);

    }


    protected override void OnError(SocketError error)

    {

        Console.WriteLine($"WebSocket session caught an error with code {error}");

    }

}


class EchoWebSocketServer : WebSocketServer

{

    public EchoWebSocketServer(IPAddress address, int port) : base(address, port) {}


    protected override WebSocketSession CreateSession() { return new EchoWebSocketSession(this); }


    protected override void OnError(SocketError error)

    {

        Console.WriteLine($"WebSocket server caught an error with code {error}");

    }

}


class Program

{

    static void Main(string[] args)

    {

        // WebSocket server port

        int port = 8080;

        Console.WriteLine($"WebSocket server port: {port}");


        // Create a new WebSocket server

        var server = new EchoWebSocketServer(IPAddress.Any, port);


        // Start the server

        Console.WriteLine("Server starting...");

        server.Start();

        Console.WriteLine("Done!");


        Console.WriteLine("Press Enter to stop the server...");


        // Wait for the user input to stop the server

        Console.ReadLine();


        // Stop the server

        Console.WriteLine("Server stopping...");

        server.Stop();

        Console.WriteLine("Done!");

    }

}


在这个例子中,我们创建了两个类 EchoWebSocketSession 和 EchoWebSocketServer。EchoWebSocketSession 类继承自 WebSocketSession,用于处理客户端的 WebSocket 连接。EchoWebSocketServer 类继承自 WebSocketServer,用于接受客户端的连接并创建会话。

服务器启动后,它会监听指定的端口(在这个例子中是 8080 端口),并对任何尝试建立 WebSocket 连接的客户端进行响应。当客户端发送消息时,服务器会在 OnWsReceived 方法中接收这些消息,并将相同的消息发送回客户端,实现了一个回声(Echo)服务。


创建一个客户端来连接上面创建的 WebSocket 服务器,你可以使用 NetCoreServer 库中的 WebSocketClient 类。下面是一个简单的客户端示例,它连接到 WebSocket 服务器,并发送一条消息,然后接收服务器的响应。

using System;

using System.Net;

using System.Text;

using System.Threading;

using NetCoreServer;


class EchoWebSocketClient : WebSocketClient

{

    public EchoWebSocketClient(string address, int port) : base(address, port) {}


    protected override void OnWsConnected(HttpResponse response)

    {

        Console.WriteLine("WebSocket client connected.");

        // 发送初始消息

        SendTextAsync("Hello, World!");

    }


    protected override void OnWsDisconnected()

    {

        Console.WriteLine("WebSocket client disconnected.");

    }


    protected override void OnWsReceived(byte[] buffer, long offset, long size)

    {

        string message = Encoding.UTF8.GetString(buffer, (int)offset, (int)size);

        Console.WriteLine("Received: " + message);


        // 断开连接

        DisconnectAsync();

    }


    protected override void OnError(SocketError error)

    {

        Console.WriteLine($"WebSocket client caught an error with code {error}");

    }

}


class Program

{

    static void Main(string[] args)

    {

        // WebSocket server IP 地址和端口

        string address = "127.0.0.1";

        int port = 8080;


        Console.WriteLine($"WebSocket server address: {address}");

        Console.WriteLine($"WebSocket server port: {port}");


        // 创建并连接 WebSocket 客户端

        var client = new EchoWebSocketClient(address, port);

        client.ConnectAsync();


        Console.WriteLine("Press any key to shutdown the client...");

        Console.ReadKey();


        // 停止客户端

        client.DisconnectAndStop();

    }

}

在这个客户端示例中,EchoWebSocketClient 类继承自 WebSocketClient。当客户端成功连接到服务器时,OnWsConnected 事件处理函数被调用,并发送一条消息到服务器。当客户端接收到服务器的响应时,OnWsReceived 事件处理函数被调用,并在控制台上打印出收到的消息。然后,客户端主动断开连接。

在运行这个客户端之前,请确保你的 WebSocket 服务器已经启动并在监听端口(本例中为 8080 端口)。这样,客户端才能成功地连接到服务器并进行通信。



.NET Core ABP

ABP是一套基于WEB的快速开发引用框架,和DDD领域驱动开发有很好的结合。

主要特性:模块化,多租户,认证授权,虚拟文件系统,主题系统,后台作业,事件总线,对象映射,依赖注入,数据过滤等。

Nuget中安装volo.abp.core



MudBlazor:一个UI简洁美观漂亮的Blazor开源组件

Blazor,作为.NET生态系统中的一个革命性框架,使得可以使用C#来全栈开发Web应用。下面推荐一个Blazor开源UI组件MudBlazor,方便我们快速开发

MudBlazor 是一个开源的 .NET 库,它为 Blazor 应用程序提供了一套丰富的 Material Design 风格的组件。MudBlazor提供了一套完整的组件库,使得开发者能够快速构建美观且功能丰富的用户界面。

点击打开源码地址

目特点

Material Design 风格:遵循 Material Design 设计语言,这是由 Google 提出的一种视觉语言,它指导了如何设计出直观、一致且美观的界面。

组件丰富:提供了 50 多个预构建的组件,包括按钮、表单控件、导航菜单、数据表格、卡片等,这些组件都遵循 Material Design 规范。

易于使用:组件使用简单,方便我们快速地在 Blazor 应用程序中使用。

高度可定制:组件支持高度定制,方便我们根据项目需求调整组件的样式和行为。

跨平台:由于 Blazor 本身的跨平台特性,MudBlazor 组件可以在 WebAssembly (WASM) 或服务器端的 Blazor 应用程序中运行。


安装依赖库

dotnet add package MudBlazor

2、在_Imports.razor引用

@using MudBlazor

3、在页面,添加字体和样式引用

<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" rel="stylesheet" />

<link href="_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" />

4、添加JavaScript引用

<script src="_content/MudBlazor/MudBlazor.min.js"></script>

5、在项目入口Program.cs注册服务

using MudBlazor.Services;


builder.Services.AddMudServices();


6、在MainLayout.razor添加以下组件

<MudThemeProvider/>

<MudDialogProvider/>

<MudSnackbarProvider/>

至此MudBlazor项目配置完成,接下去就可以根据项目需求进行开发了。



MAUI低功耗蓝牙通讯的例子

using Plugin.BLE;

using Plugin.BLE.Abstractions;

using Plugin.BLE.Abstractions.Contracts;

using Plugin.BLE.Abstractions.EventArgs;

using System;

using System.Threading.Tasks;


namespace MauiBLE

{

    public partial class MainPage : ContentPage

    {

        private IBluetoothLE ble;

        private IAdapter adapter;

        private IDevice device;

        private ICharacteristic characteristic;


        public MainPage()

        {

            InitializeComponent();


            ble = CrossBluetoothLE.Current;

            adapter = ble.Adapter;


            // 设置蓝牙状态改变事件

            ble.StateChanged += Ble_StateChanged;

        }


        private async void Ble_StateChanged(object sender, BluetoothStateChangedEventArgs e)

        {

            // 检查蓝牙状态

            if (e.NewState == BluetoothState.On)

            {

                // 开始扫描设备

                await StartScanning();

            }

        }


        private async Task StartScanning()

        {

            // 开始扫描设备

            await adapter.StartScanningForDevicesAsync();


            // 扫描到设备事件

            adapter.DeviceDiscovered += Adapter_DeviceDiscovered;

        }


        private async void Adapter_DeviceDiscovered(object sender, DeviceDiscoveredEventArgs e)

        {

            // 设备发现事件处理逻辑,例如显示设备列表

            await Dispatcher.DispatchAsync(() =>

            {

                // 更新 UI 显示设备

            });

        }


        private async void ConnectButton_Clicked(object sender, EventArgs e)

        {

            if (device == null)

            {

                // 选择设备

                return;

            }


            // 连接设备

            await ConnectToDevice();

        }


        private async Task ConnectToDevice()

        {

            // 连接设备

            await device.ConnectAsync();


            // 连接成功后,获取所需的服务和特征

            var service = await device.GetServiceAsync(new Guid("your-service-uuid"));

            characteristic = await service.GetCharacteristicAsync(new Guid("your-characteristic-uuid"));


            // 设置特征值的改变事件

            characteristic.ValueUpdated += Characteristic_ValueUpdated;

        }


        private void Characteristic_ValueUpdated(object sender, CharacteristicValueUpdatedEventArgs e)

        {

            // 特征值改变事件处理逻辑,例如更新 UI

        }


        private async void SendButton_Clicked(object sender, EventArgs e)

        {

            if (characteristic == null)

            {

                // 未连接或未找到特征

                return;

            }


            // 发送数据

            await characteristic.WriteAsync(new byte[] { 0x01, 0x02, 0x03 });

        }

    }

}

MAUI低功耗蓝牙通讯的例子

打开 NuGet 包管理器

在 NuGet 包管理器窗口的搜索框中输入 Plugin.BLE

引用必要的库:Plugin.BLE库提供低功耗蓝牙功能。

**初始化蓝牙对象:**获取IBluetoothLE和IAdapter对象,用于管理蓝牙连接和扫描。

**监听蓝牙状态变化:**在Ble_StateChanged方法中监听蓝牙状态变化,当蓝牙开启时开始扫描设备。

扫描设备:StartScanning方法开始扫描设备,并监听DeviceDiscovered事件。

连接设备:ConnectToDevice方法连接到选定的设备,并获取所需的服务和特征。

监听特征值变化:Characteristic_ValueUpdated方法监听特征值的改变,并进行相应的处理。

发送数据:SendButton_Clicked方法发送数据到特征值。


注意

将代码中的 your-service-uuid 和 your-characteristic-uuid 替换为实际设备的服务和特征的 UUID。

在使用蓝牙功能前,请确保已在应用程序的 AndroidManifest.xml 文件中添加必要的权限。



MAUI串口通讯

使用.NET MAUI进行串口通讯的例子,你可以利用System.IO.Ports.SerialPort类来实现,尽管在.NET MAUI这样的现代跨平台框架中直接使用可能会受到限制,因为不是所有目标平台都支持这个类库。对于跨平台的串口通信,推荐使用第三方库如SerialPortStream。


1. 添加NuGet包

如果决定使用SerialPortStream,首先需要通过NuGet添加必要的包到项目中。在解决方案的NuGet包管理器中搜索并安装SerialPortStream.Core或其他适合的串口通信库。


2. 初始化串口

在你的页面或视图模型中初始化串口连接。

using SerialPortStream.Core; // 或其他你选择的串口库


private SerialPortStream serialPort;


public void InitializeSerialPort()

{

    try

    {

        serialPort = new SerialPortStream("COM1", 9600, Parity.None, 8, StopBits.One);

        serialPort.Open();

        // 可以在这里设置数据接收事件处理程序

        serialPort.DataReceived += SerialPort_DataReceived;

    }

    catch (Exception ex)

    {

        Console.WriteLine($"Error: {ex.Message}");

    }

}


3. 数据接收处理

定义一个方法来处理接收到的数据。

private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)

{

    var data = new byte[serialPort.BytesToRead];

    serialPort.Read(data, 0, data.Length);

    string receivedData = System.Text.Encoding.UTF8.GetString(data);

    Console.WriteLine(receivedData);

    // 在这里处理接收到的数据,比如更新UI

}


4. 发送数据

定义一个方法来发送数据到串口。

public void SendData(string data)

{

    if (serialPort.IsOpen)

    {

        var bytes = Encoding.UTF8.GetBytes(data);

        serialPort.Write(bytes, 0, bytes.Length);

    }

    else

    {

        Console.WriteLine("Serial port is not open.");

    }

}


5. 关闭串口

记得在不再需要时关闭串口以释放资源。

public void CloseSerialPort()

{

    if (serialPort != null && serialPort.IsOpen)

    {

        serialPort.Close();

    }

}

注意事项

在跨平台应用中,确保所选的串口库支持所有目标平台。

考虑到权限问题,在某些平台上可能需要请求访问硬件端口的权限。

上述代码仅为示例,实际部署前需要充分测试,并根据具体需求调整。



MAUI的TCP UDP通讯例子

在.NET MAUI中实现TCP或UDP通信,可以利用System.Net.Sockets命名空间下的类,如TcpClient、TcpListener、UdpClient等。下面分别给出简单的TCP和UDP通信示例。

TCP通信示例

服务器端

using System;

using System.Net;

using System.Net.Sockets;

using System.Text;

using System.Threading.Tasks;


public class TcpServer

{

    public async Task StartServerAsync(int port)

    {

        TcpListener server = null;

        try

        {

            server = new TcpListener(IPAddress.Any, port);

            server.Start();


            Console.WriteLine("TCP Server started. Waiting for a connection...");


            while (true)

            {

                TcpClient client = await server.AcceptTcpClientAsync();

                HandleClient(client);

            }

        }

        catch (Exception ex)

        {

            Console.WriteLine($"Error: {ex.Message}");

        }

        finally

        {

            server?.Stop();

        }

    }


    private async void HandleClient(TcpClient client)

    {

        using (NetworkStream stream = client.GetStream())

        {

            byte[] buffer = new byte[1024];

            int read;


            while ((read = await stream.ReadAsync(buffer, 0, buffer.Length)) != 0)

            {

                string data = Encoding.UTF8.GetString(buffer, 0, read);

                Console.WriteLine($"Received: {data}");

                // Echo back the data to the client

                byte[] response = Encoding.UTF8.GetBytes(data);

                await stream.WriteAsync(response, 0, response.Length);

            }

        }

    }

}

客户端

using System;

using System.Net.Sockets;

using System.Text;

using System.Threading.Tasks;


public class TcpClientExample

{

    public static async Task SendMessageAsync(string server, int port, string message)

    {

        try

        {

            using (TcpClient client = new TcpClient(server, port))

            {

                Console.WriteLine("Connected to server.");

                NetworkStream stream = client.GetStream();


                byte[] data = Encoding.UTF8.GetBytes(message);

                await stream.WriteAsync(data, 0, data.Length);


                // Optionally receive a response

                byte[] responseBuffer = new byte[1024];

                int responseLength = await stream.ReadAsync(responseBuffer, 0, responseBuffer.Length);

                string response = Encoding.UTF8.GetString(responseBuffer, 0, responseLength);

                Console.WriteLine($"Response: {response}");

            }

        }

        catch (Exception ex)

        {

            Console.WriteLine($"Error: {ex.Message}");

        }

    }

}

UDP通信示例

服务器端

using System;

using System.Net;

using System.Net.Sockets;


public class UdpServer

{

    public void StartListening(int port)

    {

        UdpClient listener = new UdpClient(port);

        IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, port);


        try

        {

            Console.WriteLine("UDP Server started. Waiting for messages...");


            while (true)

            {

                Byte[] receiveBytes = listener.Receive(ref groupEP);

                string message = Encoding.ASCII.GetString(receiveBytes);

                Console.WriteLine($"Received: {message}");

                // Optionally send a response

                string response = "Message received";

                Byte[] sendBytes = Encoding.ASCII.GetBytes(response);

                listener.Send(sendBytes, sendBytes.Length, groupEP);

            }

        }

        catch (Exception ex)

        {

            Console.WriteLine($"Error: {ex.Message}");

        }

        finally

        {

            listener.Close();

        }

    }

}


客户端

using System;

using System.Net;

using System.Net.Sockets;


public class UdpClientExample

{

    public void SendMessage(string server, int port, string message)

    {

        try

        {

            UdpClient client = new UdpClient();

            IPEndPoint endPoint = new IPEndPoint(Dns.GetHostAddresses(server)[0], port);

            Byte[] data = Encoding.ASCII.GetBytes(message);

            client.Send(data, data.Length, endPoint);


            // Optionally receive a response

            IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0);

            Byte[] receiveData = client.Receive(ref remoteEP);

            string response = Encoding.ASCII.GetString(receiveData);

            Console.WriteLine($"Response: {response}");

        }

        catch (Exception ex)

        {

            Console.WriteLine($"Error: {ex.Message}");

        }

        finally

        {

            client.Close();

        }

    }

}

这些示例展示了如何在.NET MAUI应用中实现基本的TCP和UDP通信。请根据实际需求调整代码,并确保在使用网络功能时处理好异常和资源释放。



MAUI NFC编程

安装Plugin.NFC NuGet包

在你的.NET MAUI项目中,添加一个新的ContentPage,命名为"NfcPage.xaml"。

在NfcPage.xaml中添加以下XAML代码:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"

             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"

             x:Class="NFCExample.NfcPage">


    <StackLayout>

        <Label x:Name="TagInfoLabel" FontSize="18" HorizontalTextAlignment="Center" />


        <Entry x:Name="WriteDataEntry" Placeholder="Enter data to write" />


        <Button Text="Write to NFC Tag" Clicked="WriteButton_Clicked" />

    </StackLayout>


</ContentPage>

完整的NfcPage.xaml.cs代码:

using Plugin.NFC;


namespace NFCExample

{

    public partial class NfcPage : ContentPage

    {

        private NFCNdefTypeFormat _type;

        private bool _makeReadOnly = false;

        private bool _eventsAlreadySubscribed = false;


        public NfcPage()

        {

            InitializeComponent();

        }


        protected override async void OnAppearing()

        {

            base.OnAppearing();


            if (!_eventsAlreadySubscribed)

            {

                _eventsAlreadySubscribed = true;


                CrossNFC.Current.OnMessageReceived += Current_OnMessageReceived;

                CrossNFC.Current.OnTagDiscovered += Current_OnTagDiscovered;

                CrossNFC.Current.OnNfcStatusChanged += Current_OnNfcStatusChanged;


                if (CrossNFC.Current.IsAvailable)

                    await CrossNFC.Current.StartListeningForNdefMessages();

            }

        }


        protected override bool OnBackButtonPressed()

        {

            CrossNFC.Current.StopListening();

            return base.OnBackButtonPressed();

        }


        private void Current_OnMessageReceived(ITagInfo tagInfo)

        {

            MainThread.BeginInvokeOnMainThread(() =>

            {

                if (tagInfo == null)

                {

                    TagInfoLabel.Text = "No tag found";

                }

                else if (tagInfo.Records != null && tagInfo.Records.Length > 0)

                {

                    var record = tagInfo.Records[0];

                    TagInfoLabel.Text = $"Message: {record.Message}";

                }

            });

        }


        private void Current_OnTagDiscovered(ITagInfo tagInfo)

        {

            MainThread.BeginInvokeOnMainThread(() =>

            {

                if (tagInfo != null)

                    TagInfoLabel.Text = $"Tag ID: {tagInfo.Identifier}";

            });

        }


        private void Current_OnNfcStatusChanged(bool isEnabled)

        {

            MainThread.BeginInvokeOnMainThread(() =>

            {

                if (isEnabled)

                    TagInfoLabel.Text = "NFC is enabled";

                else

                    TagInfoLabel.Text = "NFC is disabled";

            });

        }


        private async void WriteButton_Clicked(object sender, EventArgs e)

        {

            if (!CrossNFC.Current.IsAvailable)

            {

                await DisplayAlert("NFC", "NFC is not available", "OK");

                return;

            }


            if (!CrossNFC.Current.IsWritingTagSupported)

            {

                await DisplayAlert("NFC", "Writing tag is not supported on this device", "OK");

                return;

            }


            try

            {

                CrossNFC.Current.StartPublishing(WriteDataEntry.Text, _type, _makeReadOnly);

                await DisplayAlert("NFC", "Approach the tag to write data", "OK");

            }

            catch (Exception ex)

            {

                await DisplayAlert("NFC", $"Error writing tag: {ex.Message}", "OK");

            }

            finally

            {

                CrossNFC.Current.StopPublishing();

            }

        }

    }

}

在这个示例中,我们创建了一个NFC页面,其中包含以下功能:

1.当页面出现时,开始监听NFC标签和NDEF消息。

2.当NFC状态改变时,更新标签信息标签的文本。

3.当发现NFC标签时,显示标签的ID。

4.当接收到NDEF消息时,显示消息的内容。

5.提供一个文本输入框和按钮,用于将数据写入NFC标签。

6.在写入NFC标签之前,检查设备是否支持NFC和NFC写入功能。

7.使用CrossNFC.Current.StartPublishing方法将数据写入NFC标签,并在写入完成后使用CrossNFC.Current.StopPublishing方法停止写入。

8.处理写入过程中可能发生的异常,并显示相应的错误消息。

请注意,在使用Plugin.NFC之前,你需要确保你的设备支持NFC功能,并且已经在项目的平台特定项目中进行了必要的配置。


对于Android平台,你需要在AndroidManifest.xml中添加以下权限:

<uses-permission android:name="android.permission.NFC" />


对于iOS平台,你需要在Info.plist中添加以下键值对:

<key>NFCReaderUsageDescription</key>

<string>NFC Tag Reader</string>


此外,还需要在你的MauiProgram.cs文件中注册Plugin.NFC服务:


using Plugin.NFC;

public static class MauiProgram

{

    public static MauiApp CreateMauiApp()

    {

        var builder = MauiApp.CreateBuilder();

        

        // ...

        

        builder.Services.AddSingleton(typeof(INFCDevice), CrossNFC.Current);

        

        // ...

    }

}

这个示例展示了如何使用Plugin.NFC在.NET MAUI应用程序中进行NFC标签的读写操作。你可以根据自己的需求对其进行修改和扩展



Titanium Web Proxy——强大的HTTP(S)代理服务器

Titanium Web Proxy是一个多线程、异步的代理服务器,具备请求和响应拦截、修改、重定向和阻止的能力。它支持SSL双向认证、代理认证和自动上游代理检测,同时也提供了SOCKS4/5代理协议的支持。通过NuGet包管理器即可轻松安装使用,并且适用于.NET Standard 2.0及以上版本和.NET Framework 4.5及以上版本。

点击进入开源地址

安装:

Install-Package Titanium.Web.Proxy

典型使用例子:抖音弹幕监听器点击查看

以下是使用Titanium.Web.Proxy实现HTTP代理服务器的基本步骤:

1.安装Titanium.Web.Proxy库;

2.创建代理服务器,并设置基本配置;

3.响应事件处理,可以根据需要进行自定义;

4.添加终结点;

5.启动代理服务器,并设置为系统代理。


创建代理

using System.Net;

using Titanium.Web.Proxy;

using Titanium.Web.Proxy.EventArguments;

using Titanium.Web.Proxy.Http;

using Titanium.Web.Proxy.Models;


var proxyServer = new ProxyServer();


创建证书

// 此代理使用的本地信任根证书 

//proxyServer.CertificateManager.TrustRootCertificate = true;

//proxyServer.CertificateManager.TrustRootCertificate(true);

//使用BouncyCastle库来生成证书

proxyServer.CertificateManager.CertificateEngine = Titanium.Web.Proxy.Network.CertificateEngine.DefaultWindows; 

proxyServer.CertificateManager.EnsureRootCertificate();

//在Mono之下,只有BouncyCastle将得到支持

//proxyServer.CertificateManager.CertificateEngine = Network.CertificateEngine.BouncyCastle;

proxyServer.CertificateManager.SaveFakeCertificates = true;

proxyServer.CertificateManager.RootCertificate = proxyServer.CertificateManager.LoadRootCertificate();

if (proxyServer.CertificateManager.RootCertificate == null)

{

    Console.WriteLine("正在进行证书安装,需要安装证书才可进行https解密,若有提示请确定");

    proxyServer.CertificateManager.CreateRootCertificate();

}


添加端点

显式端点

var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000, true)

{

    // 在所有https请求上使用自颁发的通用证书

    // 通过不为每个启用https的域创建证书来优化性能

    // 当代理客户端不需要证书信任时非常有用

   //GenericCertificate = new X509Certificate2(Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "genericcert.pfx"), "password")

};


// 显式端点是客户端知道代理存在的地方,因此,客户端以代理友好的方式发送请求

proxyServer.AddEndPoint(explicitEndPoint);


透明端点

透明endpoint 对于反向代理很有用(客户端不知道代理的存在); 透明endpoint 通常需要一个网络路由器端口来转发HTTP(S)包或DNS发送数据到此endpoint

var transparentEndPoint = new TransparentProxyEndPoint(IPAddress.Any, 8001, true)

{

    // 客户端禁用SNI时要使用的通用证书主机名

    GenericCertificateName = "google.com"

};

proxyServer.AddEndPoint(transparentEndPoint);



处理事件

添加事件

proxyServer.ServerCertificateValidationCallback += ProxyServer_ServerCertificateValidationCallback; 

proxyServer.BeforeRequest += ProxyServer_BeforeRequest;

proxyServer.BeforeResponse += ProxyServer_BeforeResponse;

explicitEndPoint.BeforeTunnelConnectRequest += ExplicitEndPoint_BeforeTunnelConnectRequest;

explicitEndPoint.BeforeTunnelConnectResponse += ExplicitEndPoint_BeforeTunnelConnectResponse;


proxyServer.AddEndPoint(explicitEndPoint);


处理事件

async Task<bool> OnBeforeTunnelConnect(string hostname)

{

    if (hostname.Contains("rscode.cn"))

    {

        //排除rscode.cn被解密,而是通过安全的TCP隧道中继

        return await Task.FromResult(true);

    }

    else

    {

        return await Task.FromResult(false);

    }

}

async Task OnBeforeTunnelConnectRequest(object sender, TunnelConnectSessionEventArgs e)

{

    await Task.Run(() =>

    {

        string hostname = e.HttpClient.Request.RequestUri.Host;

        if (hostname.Contains("rscode.cn"))

        {

            // 排除您不想代理的Https地址

            // 对于使用证书固定的客户端很有用

            // 例如本例 dropbox.com

            e.DecryptSsl = false;

        }

    });

}

async Task OnRequest(object sender, SessionEventArgs e)

{

    Console.WriteLine(e.HttpClient.Request.Url);

    // read request headers

    var requestHeaders = e.HttpClient.Request.Headers;

    var method = e.HttpClient.Request.Method.ToUpper();

    if ((method == "POST" || method == "PUT" || method == "PATCH"))

    {

        // Get/Set request body bytes

        byte[] bodyBytes = await e.GetRequestBody();

        e.SetRequestBody(bodyBytes);

        // Get/Set request body as string

        string bodyString = await e.GetRequestBodyAsString();

        e.SetRequestBodyString(bodyString);

        // store request 

        // 这样你就能从响应处理器中找到它

        e.UserData = e.HttpClient.Request;

    }

    // 取消带有自定义HTML内容的请求

    // Filter URL

    if (e.HttpClient.Request.RequestUri.AbsoluteUri.Contains("rscode.cn"))

    {

        e.Ok("<!DOCTYPE html>" +

            "<html><body><h1>" +

            "Website Blocked" +

            "</h1>" +

            "<p>Blocked by titanium web proxy.</p>" +

            "</body>" +

            "</html>");

    }

    // Redirect example

    if (e.HttpClient.Request.RequestUri.AbsoluteUri.Contains("wikipedia.org"))

    {

        e.Redirect("https://www.paypal.com");

    }

}

// Modify response

public async Task OnResponse(object sender, SessionEventArgs e)

{

    // read response headers

    var responseHeaders = e.HttpClient.Response.Headers;

    //if (!e.ProxySession.Request.Host.Equals("medeczane.sgk.gov.tr")) return;

    if (e.HttpClient.Request.Method == "GET" || e.HttpClient.Request.Method == "POST")

    {

        if (e.HttpClient.Response.StatusCode == 200)

        {

            if (e.HttpClient.Response.ContentType != null && e.HttpClient.Response.ContentType.Trim().ToLower().Contains("text/html"))

            {

                byte[] bodyBytes = await e.GetResponseBody();

                e.SetResponseBody(bodyBytes);

                string body = await e.GetResponseBodyAsString();

                e.SetResponseBodyString(body);

            }

        }

    }

    if (e.UserData != null)

    {

        // 从存储在RequestHandler中的UserData属性的访问请求

        var request = (Request)e.UserData;

    }

}

// 允许重写默认的证书验证逻辑

public Task OnCertificateValidation(object sender, CertificateValidationEventArgs e)

{

    // 根据证书错误,设置IsValid为真/假

    if (e.SslPolicyErrors == System.Net.Security.SslPolicyErrors.None)

        e.IsValid = true;

    return Task.CompletedTask;

}

// 允许在相互身份验证期间重写默认客户端证书选择逻辑

public Task OnCertificateSelection(object sender, CertificateSelectionEventArgs e)

{

    // set e.clientCertificate to override

    return Task.CompletedTask;

}    



websocket处理

var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000, true);

//收到CONNECT请求时触发

explicitEndPoint.BeforeTunnelConnectRequest += ExplicitEndPoint_BeforeTunnelConnectRequest;

explicitEndPoint.BeforeTunnelConnectResponse += ExplicitEndPoint_BeforeTunnelConnectResponse;

private async Task ExplicitEndPoint_BeforeTunnelConnectRequest(object sender, TunnelConnectSessionEventArgs e)

{

    string hostname = e.HttpClient.Request.RequestUri.Host;

    if (!barrageWsHostNames.Contains(hostname))

    {

        e.DecryptSsl = false;

    }

}

private Task ExplicitEndPoint_BeforeTunnelConnectResponse(object sender, TunnelConnectSessionEventArgs e)

{

    string hostname = e.HttpClient.Request.RequestUri.Host;

    if (!barrageWsHostNames.Contains(hostname))

    {

        e.DecryptSsl = false;

    }

    Console.WriteLine($"ExplicitEndPoint_BeforeTunnelConnectResponse url={hostname}");

    if (e.UserData != null)

    {


    }

    return Task.CompletedTask;

}


private async void WebSocket_DataReceived(object sender, DataEventArgs e)

{

    var args = (SessionEventArgs)sender;


    string hostname = args.HttpClient.Request.RequestUri.Host;

    var processid = args.HttpClient.ProcessId.Value;

    var frames = args.WebSocketDecoderReceive.Decode(e.Buffer, e.Offset, e.Count).ToList();


    foreach (var frame in frames)

    {

        base.SendWebSocketData(new WsMessageEventArgs()

        {

            ProcessID = processid,

            HostName = hostname,

            Payload = frame.Data.ToArray(),

            ProcessName = base.GetProcessName(processid)

        });

    }

}


设为系统代理

//proxyServer.UpStreamHttpProxy = new ExternalProxy() { HostName = "localhost", Port = 8888 };

//proxyServer.UpStreamHttpsProxy = new ExternalProxy() { HostName = "localhost", Port = 8888 };

foreach (var endPoint in proxyServer.ProxyEndPoints)

Console.WriteLine("Listening on '{0}' endpoint at Ip {1} and port: {2} ",

    endPoint.GetType().Name, endPoint.IpAddress, endPoint.Port);

// 只有显式代理可以设置为系统代理!

proxyServer.SetAsSystemHttpProxy(explicitEndPoint);

proxyServer.SetAsSystemHttpsProxy(explicitEndPoint);


打开代理

Console.WriteLine("打开代理");

proxyServer.AddEndPoint(explicitEndPoint);

proxyServer.Start();

proxyServer.SetAsSystemHttpProxy(explicitEndPoint);



关闭代理

Console.WriteLine("关闭代理");

proxyServer.ServerCertificateValidationCallback -= ProxyServer_ServerCertificateValidationCallback; 

proxyServer.BeforeRequest -= ProxyServer_BeforeRequest;

proxyServer.BeforeResponse -= ProxyServer_BeforeResponse;

explicitEndPoint.BeforeTunnelConnectRequest -= ExplicitEndPoint_BeforeTunnelConnectRequest;

explicitEndPoint.BeforeTunnelConnectResponse -= ExplicitEndPoint_BeforeTunnelConnectResponse;


proxyServer.Stop();

proxyServer.Dispose();



开源的商城系统

CoreShop

点击查看软件主页

点击进入源码页

1.png

核心商城(CoreShop)介绍

核心商城系统(CoreShop) 是基于 Asp.Net 8.0、Uni-App开发、支持可视化布局的小程序商城系统;前后端分离,支持跨平台运行;拥有分销、代理、团购秒杀、接龙、拼团、直播、优惠券、自定义表单等众多营销功能,拥有完整SKU、下单、售后、物流流程,支持可视化自定义首页模块布局效果。


支持一套代码编译发布微信小程序版、H5版、Android版、iOS版、支付宝小程序版、百度小程序版、字节跳动小程序版、QQ小程序版、快应用、360小程序共10个平台。


后台管理系统包含会员管理、商品管理、订单管理、服务商品、财务管理、促销中心、分销管理、代理管理、库存管理、报表统计、自定义表单、文章管理、广告管理、商城设置、后台管理、短信管理、日志管理等模块,强大的促销引擎,多种促销方式自由搭配,满足各种场景的促销方式需求,做活动更灵活简单,并且在促销的扩展上也非常方便。



nopCommerce

nopCommerce是一个功能丰富、免费、灵活且可定制的开源电子商务解决方案,可以直接使用该项目进行二次开发,省时省力。

项目源码地址:https://github.com/nopSolutions/nopCommerce



Module Shop

Module Shop是一个基于.NET Core构建的简单、跨平台、模块化、完全开源免费(MIT License)的商城系统。

目源码地址:https://github.com/trueai-org/module-shop


NTQQ机器人

点击查看源码

查看中文文档

查看具体文档




FreeSQL对象关系映射(O/RM)组件

点击进入库主页

FreeSQL多表查询说明



C# 下使用 ViewFaceCore 实现人脸识别功能

点击查看原文

ViewFaceCore 是一个开源的、人脸识别 SDK,支持 .NET/.NET Core/.NET Framework 平台。它提供了高效且准确的人脸检测和特征提取功能,可以用于各种与人脸识别相关的应用场景中。本文将探讨如何在 C# 应用程序中使用 ViewFaceCore 实现基本的人脸识别功能,并通过一些实际例子来展示其使用方法。


安装 ViewFaceCore 包

首先,我们需要将 ViewFaceCore 导入到我们的项目中。可以使用 NuGet 包管理器来安装它。


在终端中运行以下命令:


dotnet add package 以下包


ViewFaceCore

ViewFaceCore.all_models

ViewFaceCore.Extension.SkiaSharp

ViewFaceCore.runtime.win.x64

1.jpg


或者在 Visual Studio 中,通过 NuGet 包管理器搜索 ViewFaceCore 并安装。


基本使用

在开始之前,我们需要引入相关的命名空间:


using SkiaSharp;

using System.Drawing;

using System.Reflection;

using System.Windows.Forms;

using ViewFaceCore;

using ViewFaceCore.Core;

using ViewFaceCore.Model;


人脸检测

载入图片


private void btnLoad_Click(object sender, EventArgs e)

{

    using (OpenFileDialog openFileDialog = new OpenFileDialog())

    {

        openFileDialog.Filter = "Image Files|*.jpg;*.jpeg;*.png;";

        if (openFileDialog.ShowDialog() == DialogResult.OK)

        {

            pic.Image = Image.FromFile(openFileDialog.FileName);

            pic.ImageLocation = openFileDialog.FileName;

        }

    }

}


首先,我们进行人脸检测,识别图像中的人脸。


private async void btnStatisticsFaces_Click(object sender, EventArgs e)

{

    // 使用 SKBitmap.Decode 方法从图片路径中加载图像

    // 这里使用的是 SkiaSharp 库来处理图片

    var bitmap = SKBitmap.Decode(pic.ImageLocation);


    // 从 PictureBox 控件中加载图像并转换为 Bitmap 对象

    Bitmap bitmap2 = new Bitmap(pic.Image);


    // 初始化一个 FaceDetector 对象

    FaceDetector faceDetector = new FaceDetector();


    // 将 SkiaSharp 的 Bitmap 对象转换为 FaceImage 对象

    FaceImage faceImage = bitmap.ToFaceImage();


    // 异步检测图像中的面部

    var faces = await faceDetector.DetectAsync(bitmap);


    // 在 bitmap2 图像上绘制矩形框以标记检测到的面部

    using (Graphics g = Graphics.FromImage(bitmap2))

    {

        foreach (var face in faces)

        {

            // 绘制红色矩形框标记面部区域

            g.DrawRectangle(Pens.Red, new Rectangle()

            {

                X = face.Location.X, 

                Y = face.Location.Y, 

                Height = face.Location.Height, 

                Width = face.Location.Height 

            });

        }

    }


    // 将处理后的图像重新赋值给 PictureBox 控件

    pic.Image = bitmap2;


    // 释放 bitmap 对象

    bitmap.Dispose();


    // 显示包含检测到的面部数量的消息框

    MessageBox.Show($"找到了 {faces.Length} 张人脸!");

}

1.png


提取特征值

一旦检测到人脸,我们需要提取人脸的特征值,以便后续的比对。


public float[] ExtractFeature(string imagePath)

{

    using var faceImage = SKBitmap.Decode(imagePath);


    //检测人脸信息

    FaceDetector faceDetector = new FaceDetector();

    FaceInfo[] fi = faceDetector.Detect(faceImage);


    //标记人脸位置

    FaceLandmarker faceMark = new FaceLandmarker();

    FaceMarkPoint[] points = faceMark.Mark(faceImage, fi[0]);


    FaceRecognizer faceRecognizer = new FaceRecognizer();

    float[] data0 = faceRecognizer.Extract(faceImage, points);

    return data0;

}


比对人脸

最后,我们可以通过比较两个人脸的特征值来确定两张图片是否是同一个人。


private void btnMatching_Click(object sender, EventArgs e)

{

    DrawFace(pic);

    DrawFace(pic1);

    float[] f1 = ExtractFeature(pic.ImageLocation);

    float[] f2 = ExtractFeature(pic1.ImageLocation);

    FaceRecognizer faceRecognizer = new FaceRecognizer();

    //对比特征值

    bool isSelf = faceRecognizer.IsSelf(f1, f2);

    //计算相似度

    float similarity = faceRecognizer.Compare(f1, f2);

    string msg = "识别到的人脸是否为同一人:" + isSelf + ",相似度:" + similarity;

    MessageBox.Show(msg);

}


1.png

年龄预测

private void btnAgePrediction_Click(object sender, EventArgs e)

{

    // 从 PictureBox 控件的图像路径加载图像,并将其转换为 FaceImage 对象

    FaceImage img = SKBitmap.Decode(pic.ImageLocation).ToFaceImage(); 

    // 初始化一个 FaceDetector 对象,用于检测人脸

    FaceDetector faceDetector = new FaceDetector();

    // 检测图像中的人脸,返回的结果取第一个人脸信息

    var info = faceDetector.Detect(img).First();

    // 初始化一个 AgePredictor 对象,用于预测年龄

    AgePredictor agePredictor = new AgePredictor();

    // 初始化一个 FaceLandmarker 对象,用于标记人脸的特征点

    FaceLandmarker faceMark = new FaceLandmarker();

    // 获取人脸的特征点

    var points = faceMark.Mark(img, info);

    // 使用 AgePredictor 对象预测年龄

    int age = agePredictor.PredictAge(img, points);

    // 显示预测的年龄

    MessageBox.Show(age.ToString());

}


性别预测

private void btnGenderPrediction_Click(object sender, EventArgs e)

{

    // 从 PictureBox 控件的图像路径加载图像,并将其转换为 FaceImage 对象

    FaceImage img = SKBitmap.Decode(pic.ImageLocation).ToFaceImage();

    // 初始化一个 FaceDetector 对象,用于检测人脸

    FaceDetector faceDetector = new FaceDetector();

    // 检测图像中的人脸,返回的结果取第一个人脸信息

    var info = faceDetector.Detect(img).First();

    // 初始化一个 genderPredictor 对象,用于预测性别

    GenderPredictor genderPredictor = new GenderPredictor();

    // 初始化一个 FaceLandmarker 对象,用于标记人脸的特征点

    FaceLandmarker faceMark = new FaceLandmarker();

    // 获取人脸的特征点

    var points = faceMark.Mark(img, info);

    // 使用 GenderPredictor 对象预测性别

    Gender gender = genderPredictor.PredictGender(img, points);

    // 显示预测的年龄

    MessageBox.Show(gender.ToString());

}


5. 结论

通过本文,我们学习了如何使用 ViewFaceCore 在 C# 中进行人脸识别。我们探讨了初始化、检测人脸、提取特征值和比较人脸特征的基本流程,并提供了完整的示例代码来演示这些方法的使用。希望这篇文章能帮助你在实际项目中应用 ViewFaceCore 实现人脸识别功能。



Avalonia .NET 的跨平台 UI 框架

点击查看库文档

扩展安装

Avalonia入门及学习


































Top