c#调用c/c++打包的dll程序实现人脸检测(暨c#和c++之间传递图片解决方案)

这篇博客介绍了如何在C#中调用C/C++编译的DLL来实现人脸检测功能。核心实现依赖于dlib、opencv4.0和jsoncpp库。C++端负责初始化和人脸检测,C#端则通过DllImport调用相应方法,接收和处理返回的JSON数据,展示检测结果。提供的代码示例详细展示了C#和C++之间的交互过程。
摘要由CSDN通过智能技术生成

c#调用c/c++打包的dll程序实现人脸检测(暨c#和c++之间传递图片解决方案)

涉及的环境

这些库的安装在网上应该很容易就可以找到,这里不多做赘述。

  1. dlib人脸检测库
  2. opencv 4.0 静态编译库
  3. jsoncpp 库 (这个是非必要的环境)

涉及的核心实现

c/c++端的实现

头文件

#pragma once
#include "stdafx.h"

//初始化方法 netPath=128人脸数据网络的特征转换文件地址 path68 = 68人脸特征检测文件地址
extern "C" __declspec(dllexport) int Init_descriptors();

//侦测并框选人脸
extern "C" __declspec(dllexport) const char* FaceRects(unsigned char *ImageBuffer, 
	int imageWedth, int imageHeight);

源文件

#include "stdafx.h"
#include "FaceRect.h"

#include <dlib/dnn.h> //构建神经网络必须

#include <dlib/image_processing/frontal_face_detector.h> //两个解析器
#include <dlib/image_processing/render_face_detections.h>
#include <dlib/image_transforms.h> //cv_img 与array2d

#include <dlib/opencv.h> //opencv和dlib数据转换
#include <opencv2\opencv.hpp> //opencv基础库

#include <io.h> //文件读取使用

#include <json/json.h> //用于将反馈值转化为json格式
#pragma comment(lib,"jsoncpp.lib")

using namespace dlib;
using namespace std;


#pragma comment(lib,"ade.lib") 
#pragma comment(lib,"ilmimf.lib") 
#pragma comment(lib,"ippicvmt.lib") 
#pragma comment(lib,"ippiw.lib") 
#pragma comment(lib,"ittnotify.lib") 

#pragma comment(lib,"libjasper.lib") 
#pragma comment(lib,"libjpeg-turbo.lib") 
#pragma comment(lib,"libpng.lib") 
#pragma comment(lib,"libprotobuf.lib") 
#pragma comment(lib,"libtiff.lib") 

#pragma comment(lib,"libwebp.lib") 
#pragma comment(lib,"opencv_calib3d400.lib") 
#pragma comment(lib,"opencv_core400.lib") 
#pragma comment(lib,"opencv_dnn400.lib") 
#pragma comment(lib,"opencv_features2d400.lib") 

#pragma comment(lib,"opencv_flann400.lib") 
#pragma comment(lib,"opencv_gapi400.lib") 
#pragma comment(lib,"opencv_highgui400.lib") 
#pragma comment(lib,"opencv_imgcodecs400.lib") 
#pragma comment(lib,"opencv_imgproc400.lib") 

#pragma comment(lib,"opencv_ml400.lib") 
#pragma comment(lib,"opencv_objdetect400.lib") 
#pragma comment(lib,"opencv_photo400.lib") 
#pragma comment(lib,"opencv_stitching400.lib") 
#pragma comment(lib,"opencv_video400.lib") 

#pragma comment(lib,"opencv_videoio400.lib") 
#pragma comment(lib,"quirc.lib") 
#pragma comment(lib,"zlib.lib") 




//用于人脸截取的处理器
frontal_face_detector detector;


int Init_descriptors() 
{
	try {
		//人脸截取器
		detector = get_frontal_face_detector();
	}
	catch (int) {
		return 0;
	}
	return 1;
}

const char* FaceRects(unsigned char *ImageBuffer, int imageWedth, int imageHeight) 
{

	//定义根节点
	Json::Value jsonRoot;
	cv::Mat compMat;

	try {
		//接受图像
		compMat = cv::Mat(imageHeight, imageWedth, CV_8UC3, ImageBuffer);
		//色彩问题,注意反色
		cv::cvtColor(compMat, compMat, cv::COLOR_BGR2RGB);
		cv::imshow("接收到的图像", compMat);
	}
	catch (exception e) {
		const char* is_what = e.what();
		return is_what;
	}
	
	if (compMat.rows <=0 || compMat.cols <=0)
	{
		return "rows or cols is 0";
	}

	//转为dlib图片
	array2d<rgb_pixel> img;
	dlib::assign_image(img, dlib::cv_image<dlib::bgr_pixel>(compMat));

	//解析其中所有人脸
	std::vector<rectangle> faces = detector(img);
	std::vector<matrix<rgb_pixel>> faces_R;
	int facesNum = faces.size();
	if (facesNum == 0)
	{
		return NULL;//无任何图像数据,直接反馈null
	}
	for (int i = 0; i < facesNum; i++)
	{
		Json::Value item;
		item["top"] = faces[i].top();
		item["bottom"] = faces[i].bottom();
		item["left"] = faces[i].left();
		item["right"] = faces[i].right();
		jsonRoot.append(item);
		item = NULL;
	}
	//转为json格式
	std::string result = jsonRoot.toStyledString();
	jsonRoot = NULL;
	compMat.release();
	ImageBuffer = NULL;

	return result.data();
}


C#端的实现

DataAdapter

namespace WF_FaceRect.Core
{
    public class DataAdapter
    {
        /// <summary>
        /// 寻找所有的人脸区域
        /// </summary>
        /// <param name="img">传入opencv的mat对象</param>
        /// <returns>json 解析字符串</returns>
        public static List<RectModel> FaceRects(Mat img)
        {
            //扫描宽度
            int s_width;
            //扫描高度
            int s_height;
            //图像实际宽度
            int imgWidth;
            //图像实际高度
            int imgHeight;

            imgWidth = img.Width;
            imgHeight = img.Height;

            //将图像数据lock在内存
            Bitmap bmp = img.ToBitmap();
            Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
            System.Drawing.Imaging.BitmapData bmpData =
                bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,
                bmp.PixelFormat);
            IntPtr ptr = bmpData.Scan0;
            //------------判断实际应该显示的大小--------------
            s_width = bmpData.Stride;
            s_height = bmp.Height;
            imgHeight = bmpData.Height;
            if (s_width > imgWidth * 3)
            {
                imgWidth++;
            }
            //------------------------------------------------
            int bytes = s_width * s_height;
            byte[] rgbValues = new byte[bytes];
            Marshal.Copy(ptr, rgbValues, 0, bytes);

            IntPtr repI = DllLinker.FaceRects(rgbValues, imgWidth, imgHeight);
            if (repI == IntPtr.Zero)
            {
                return null;
            }
            string strContent = Marshal.PtrToStringAnsi(repI);
            List<RectModel> result = Newtonsoft.Json.JsonConvert.DeserializeObject<List<RectModel>>(strContent,
                         new Newtonsoft.Json.JsonSerializerSettings { NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore });

            //相关释放
            bmp.UnlockBits(bmpData);
            //Marshal.FreeHGlobal(repI); 

            return result;
        }


        /// <summary>
        /// 基础文件和环境加载
        /// </summary>
        /// <returns>是否加载成功</returns>
        public static Boolean InitBaseEvm()
        {
            int result = DllLinker.Init_descriptors();
            if (result == 1)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    }
}

DllLinker

namespace WF_FaceRect.Core
{
    //注,请勿直接调用本类方法,入口在 DataAdapter.cs
    public class DllLinker
    {
        [DllImport("Asserts/Dll_FaceRect.dll", EntryPoint = "Init_descriptors", CallingConvention = CallingConvention.Cdecl)]
        public static extern int Init_descriptors();

        [DllImport("Asserts/Dll_FaceRect.dll", CharSet = CharSet.Ansi, EntryPoint = "FaceRects", CallingConvention = CallingConvention.Cdecl)]
        public static extern IntPtr FaceRects(byte[] ImageBuffer, int imageWedth, int imageHeight);
    }
}

main

namespace WF_FaceRect
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
        }

        //初始化状态
        bool isInited = false;
        //摄像机持续运行关键字
        bool statCarm = false;
        //摄像机播放线程
        Thread videoThread;
        //测试图片
        string testPicturePath = @"Asserts\test.jpg";


        // First of all ,在你使用检测功能之前请务必优先进行初始化
        private void InitBtn_Click(object sender, EventArgs e)
        {
            if (!isInited)
            {
                bool initRes = DataAdapter.InitBaseEvm();
                if (initRes)
                {
                    MessageBox.Show("加载成功!");
                    isInited = true;
                }
                else
                {
                    MessageBox.Show("加载失败!");
                    isInited = false;
                }
            }
            else
            {
                MessageBox.Show("请勿重复初始化","警告",MessageBoxButtons.OK,MessageBoxIcon.Warning);
            }
        }
        

        //启动对一张图片的检验
        private void startBtn_Click(object sender, EventArgs e)
        {
            if (!isInited)
            {
                MessageBox.Show("请优先对系统进行初始化", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
            else
            {
                //===============================单个图像===============================
                //Mat myImage = new Mat(testPicturePath, ImreadModes.Color);
                如果图像太小可能影响识别准确度,你可以使用resize()方法适当放大
                //List<RectModel> rects = DataAdapter.FaceRects(myImage);
                //foreach(RectModel item in rects)
                //{
                //    myImage.Rectangle(
                //        new OpenCvSharp.Point(item.Left, item.Top), //左上
                //        new OpenCvSharp.Point(item.Right, item.Bottom),  //右下
                //        Scalar.Red,  //线色
                //        2  //线粗
                //        );
                //}
                展现
                //pictureBox.Image = myImage.ToBitmap();


                //===============================摄像头=====================================
                videoThread = new Thread(videoShownFunc);
                statCarm = true;
                videoThread.Start();

            }
        }


        /// <summary>
        /// 视频播放实际执行方法
        /// </summary>
        private void videoShownFunc()
        {
            //加载视频
            //VideoCapture capture = new VideoCapture(@"C:\Users\Administrator\Desktop\movice\source9.mp4"); //测试
            VideoCapture capture = new VideoCapture(0);
            //capture.Set(CaptureProperty.FrameWidth, 1280);
            //capture.Set(CaptureProperty.FrameHeight, 680);


            if (capture.IsOpened())
            {
                Console.WriteLine("摄像头已经打开");
            }
            else
            {
                MessageBox.Show("警告,摄像头未开启!");
                return;
            }

            //图像人脸识别(注意,这里是true死循环,跳出循视频请Abort)
            while (statCarm)
            {
                //读取一帧
                //Mat myImage = new Mat(cs_pic,ImreadModes.Color);//测试
                Mat myImage = new Mat();
                capture.Read(myImage);

                //Cv2.Flip(myImage, myImage, FlipMode.XY);

                if (myImage.Empty()) //判断当前帧是否捕捉成功 这步很重要
                {
                    Cv2.WaitKey(60);
                    myImage.Release();
                    continue;
                }

                //人脸图像检测
                List<RectModel> rects = DataAdapter.FaceRects(myImage);
                if(rects != null && rects.Count > 0)
                {
                    // 绘制人脸框选区
                    foreach (RectModel item in rects)
                    {
                        myImage.Rectangle(
                            new OpenCvSharp.Point(item.Left, item.Top), //左上
                            new OpenCvSharp.Point(item.Right, item.Bottom),  //右下
                            Scalar.Red,  //线色
                            2  //线粗
                            );
                    }
                }
                

                //Cv2.ImShow("摄像头图像", myImage); //测试
                Image imgshow = myImage.ToBitmap();
                pictureBox.Image = imgshow;

                Cv2.WaitKey(30);
                //myImage.Release();//手动释放
                //imgshow.Dispose(); 
                GC.Collect(); //这里要使用gc,手动释放会造成GDI异常
            }
        }
}

声明与源码

我TM要下班了要下班了,再不赶紧回去饭菜都凉了!
代码就随便贴这么多吧,毕竟懂的都懂, CTRL+C就完了。

为表歉意源码奉上,免费下载,分文不取。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值