C#调用skiasharp操作并绘制图片

  之前学习ViewFaceCore时采用Panel控件和GDI+将图片及识别出的人脸方框和关键点绘制出来,本文将其修改为基于SKControl和SKCanvas实现相同的显示效果并支持保存为本地图片。
在这里插入图片描述
  新建Winform项目,在Nuget包管理器中搜索并安装一下SkiaSharp和ViewFaceCore包,同时在主界面添加SKControl控件。
在这里插入图片描述
  使用SKBitmap类的Decode方法加载本地图片文件,然后在skControl1的PaintSurface事件中调用SKCanvas.DrawBitmap函数绘制图形,函数原型如下所示:
在这里插入图片描述
  对于ViewFaceCore识别出的人脸区域及关键点坐标,调用SKCanvas的DrawRect、DrawCircle绘制矩形和圆形,同时调用DrawText函数绘制人脸区域顺序号,这些函数在GDI+的Graphics类中都有对应的函数,但是函数名又不完全相同,看着很别扭。还有感觉很怪的是DrawRect函数(如下图所示),如果是直接输入矩形坐标(第一行重载函数),参数格式是左上角坐标及矩形宽和高,而输入矩形对象(第二行重载函数),构建矩形对象时输入的是矩形左上角和右下角坐标,同时绘制圆形时输入参数是圆心坐标和半径,并没有像Graphics类中的绘图函数参数模式那么一致(也可能是用GDI+习惯了,还没有转变过来)。

在这里插入图片描述
在这里插入图片描述
    主要绘图代码和运行效果如下所示:

SKCanvas canvas = e.Surface.Canvas;
canvas.Clear();

if (m_image != null)
{
    canvas.DrawBitmap(m_image, new SKRect(m_startX, m_startY, m_startX + m_image.Width * m_scale, m_startY + m_image.Height * m_scale));

    if (m_faces.Count > 0)
    {
        using var paint = new SKPaint
        {
            Color = SKColors.Red,
            Style = SKPaintStyle.Stroke,
            IsAntialias = true,
            StrokeWidth = 2
        };

        for (int i = 0; i < m_faces.Count; i++)
        {
            canvas.DrawRect(m_startX + m_faces[i].Face.Location.X * m_scale,
                            m_startY + m_faces[i].Face.Location.Y * m_scale,
                            m_faces[i].Face.Location.Width * m_scale,
                            m_faces[i].Face.Location.Height * m_scale,
                            paint);

            canvas.DrawText(Convert.ToString(i + 1),
                            m_startX + m_faces[i].Face.Location.X * m_scale,
                            m_startY + m_faces[i].Face.Location.Y * m_scale - skControl1.Font.Height * 1.5f,
                            paint);

            if (m_faces[i].MarkPoints != null && m_faces[i].MarkPoints.Length > 0)
            {
                foreach (FaceMarkPoint mp in m_faces[i].MarkPoints)
                {
                    canvas.DrawCircle(m_startX + Convert.ToInt32(mp.X) * m_scale, m_startY + Convert.ToInt32(mp.Y) * m_scale, 3 * m_scale, paint);
                }
            }
        }
    }
}

在这里插入图片描述
  将SKBitmap对象保存到本地的包括以下步骤:
 &emsp1)新建SKBitmap对象;
 &emsp2)基于SKBitmap对象创建SKCanvas对象;
 &emsp3)依次绘制原始图片、人脸区域及关键点坐标;
 &emsp4)将SKBitmap对象数据保存到本地文件,主要有两种方式,第一种是使用bitmap.Encode方法以指定格式写入本地文件流,测试过程中能以png格式保存,其它格式报错,暂时不清楚原因;第二种方式,安装的SkiaSharp.Views包的SkiaSharp.Views.Desktop提供有扩展函数ToBitmap,支持将SKBitmap对象转换为System.Drawing.Bitmap对象,再调用Bitmap对象的Save函数保存为需要的格式即可。主要代码如下:

using SKBitmap bitmap=new SKBitmap(m_image.Width, m_image.Height);
using SKCanvas canvas = new SKCanvas(bitmap);
canvas.DrawBitmap(m_image, 0, 0);

if (m_faces.Count > 0)
{
    ...
    ...
}

canvas.Flush();

bitmap.ToBitmap().Save(sfd.FileName, ImageFormat.Bmp);

//using (FileStream fsStream = new FileStream(sfd.FileName,FileMode.CreateNew,FileAccess.Write))
//{
//    if(bitmap.Encode(fsStream,SKEncodedImageFormat.Png, 100))
//    {
//        MessageBox.Show("保存成功");
//    }
//}

参考文献:
[1]https://github.com/mono/SkiaSharp
[2]https://learn.microsoft.com/en-us/dotnet/api/skiasharp?view=skiasharp-2.88
[3]https://blog.csdn.net/ken0online/article/details/132363856
[4]https://www.cnblogs.com/bigben0123/p/14984984.html
[5]https://www.jb51.net/article/257125.htm

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C#调用 C++ DLL 发送图片、并完成图片回调的步骤如下: 1. 在 C++ DLL 中定义一个函数,用于发送图片,并将发送结果通过回调函数返回给 C#。 2. 在 C# 中声明回调函数,并使用 Marshal.GetFunctionPointerForDelegate 方法获取回调函数的指针。 3. 在 C# 中声明 DLLImport 属性,用于指定 C++ DLL 的名称和函数签名。 4. 在 C#调用 C++ DLL 中的函数,并将回调函数的指针作为参数传递给该函数。 下面是一个简单的示例,演示如何在 C#调用 C++ DLL 发送图片,并完成图片回调: C++ DLL 代码: ```cpp // example.cpp #include "stdafx.h" typedef void(__stdcall *callback)(const char* result); extern "C" __declspec(dllexport) void send_image(const char* filename, callback cb) { // 发送图片的代码 // ... // 调用回调函数,将发送结果返回给 C# cb("发送成功"); } ``` C# 代码: ```csharp using System; using System.Runtime.InteropServices; class Program { // 定义回调函数 public delegate void ImageCallback(string result); // 获取回调函数的指针 static IntPtr imageCallbackPtr = Marshal.GetFunctionPointerForDelegate(new ImageCallback(ImageCallbackMethod)); [DllImport("example.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void send_image(string filename, IntPtr callback); static void Main(string[] args) { // 调用 C++ DLL 中的函数,并将回调函数的指针作为参数传递给该函数 send_image("test.jpg", imageCallbackPtr); } // 实现回调函数 static void ImageCallbackMethod(string result) { Console.WriteLine(result); } } ``` 在上面的示例中,我们首先在 C++ 中定义了一个名为 send_image 的函数,并使用 callback 类型定义了一个回调函数。然后我们在该函数中发送图片,并调用回调函数,将发送结果返回给 C#。在 C# 中,我们首先定义了一个名为 ImageCallback 的回调函数,并使用 Marshal.GetFunctionPointerForDelegate 方法获取该函数的指针。然后我们在 Main 函数中调用 send_image 函数,并将回调函数的指针作为参数传递给该函数。最后,我们在 ImageCallbackMethod 函数中实现回调函数,将发送结果打印到控制台上。 注意:在使用回调函数时,由于 C++ 与 C# 有不同的函数调用约定,因此需要使用 CallingConvention 属性指定函数调用约定。在上面的示例中,我们使用了 __stdcall 调用约定。另外,需要注意回调函数的参数类型和返回值类型,必须与 C++ DLL 中定义的回调函数完全匹配。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值