c#调c++,用opencv+dlib识别照片中的人脸并返回结果图片
c++部分代码如下
#include
#include
#include
#include "dlib/image_processing/frontal_face_detector.h"
#include "dlib/image_processing/render_face_detections.h"
#include "dlib/image_processing.h"
#include "dlib/gui_widgets.h"
#include "dlib/image_io.h"
#include
#include
#include "opencv2/core/core.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include
#include
#include
#include
#include
#include
#ifdef MYDLL_EXPORTS
#define MYDLL_API __declspec(dllexport)//注意decl前面是两个下划线
#else
#define MYDLL_API __declspec(dllimport)
#endif
using namespace dlib;
using namespace std;
using namespace cv;
using namespace std;
static frontal_face_detector detector;
static shape_predictor sp;
static int isIni = 0;
std::string TCHAR2STRING(TCHAR *STR)
{
int iLen = WideCharToMultiByte(CP_ACP, 0, STR, -1, NULL, 0, NULL, NULL);
char* chRtn = new char[iLen * sizeof(char)];
WideCharToMultiByte(CP_ACP, 0, STR, -1, chRtn, iLen, NULL, NULL);
std::string str(chRtn);
return str;
}
//获取当前目录下的shape_predictor_68_face_landmarks.dat文件路径
std::string getDataPath() {
TCHAR szPath[MAX_PATH] = { 0 };
if (!GetModuleFileName(NULL, szPath, MAX_PATH)) {
return 0;
}
int i = MAX_PATH - 1;
while (szPath[i] != '\\') {
i--;
}
i++;
string name = "shape_predictor_68_face_landmarks.dat";
for (int j = 0; j < name.length(); j++) {
szPath[i] = name[j];
i++;
}
szPath[i] = 0;
return TCHAR2STRING(szPath);
}
void ini() {
if (isIni == 0) {
detector = get_frontal_face_detector();
deserialize(getDataPath()) >> sp;
}
isIni = 1;
}
//bimage图片的数组,nH图片的高度,nW图片的宽度,stride图片的stride值,data返回的图片内容,size图片内容长度,count识别的人脸个数
MYDLL_API void FindFaces(BYTE * bimage, int nH, int nW, int stride, uchar *data, size_t &size, uint &count);
template <typename T, long NR, long NC, typename mm, typename l>
void dlibMatrix2cvBGR(cv::Mat &dest, const dlib::matrix<T, NR, NC, mm, l> &src)
{
dlib::matrix<dlib::bgr_pixel> tmp;
dlib::assign_image(tmp, src);
dest = dlib::toMat(tmp).clone();
}
void FindFaces(BYTE* pImg, int nH, int nW, int stride, uchar *data, size_t &size,uint &count) {
Mat image = Mat(nH, nW, CV_8UC3, pImg, stride).clone();
ini();
dlib::cv_image<bgr_pixel> dlib_img(image);
std::vector<dlib::rectangle> dets = detector(dlib_img);
std::vector<full_object_detection> shapes;
if (dets.size() == 0)
{
count = 0;
return;
}
count = dets.size();
for (unsigned long j = 0; j < dets.size(); ++j)
{
full_object_detection shape = sp(dlib_img, dets[j]);
shapes.push_back(shape);
}
dlib::array<array2d<bgr_pixel> > face_chips;
extract_image_chips(dlib_img, get_face_chip_details(shapes, 100, 0.1), face_chips);
cv::Mat src;
dlibMatrix2cvBGR(src, tile_images(face_chips));
std::vector<uchar> buf;
cv::imencode(".bmp", src, buf); //将Mat以bmp格式存入内存中,转换为uchar数组
size = buf.size();
for each(uchar var in buf) //将buf拷贝到C#的输出byte[] 内存中
{
*data = var;
data++;
}
}
c#调用代码
[DllImport("FaceSearch.dll", EntryPoint = "FindFaces", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode)]
public static extern void FindFaces(byte[] bimage, int nH, int nW, int stride, ref byte data, out ulong size,out uint count);
Bitmap bmp = (Bitmap)Bitmap.FromFile(@"C:\Users\wu\Pictures\a.jpg");
System.Drawing.Rectangle rect = new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height);
System.Drawing.Imaging.BitmapData bmpData = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat);
//Get the address of the first line.
IntPtr ptr = bmpData.Scan0;
// Declare an array to hold the bytes of the bitmap.
int bytesLength = Math.Abs(bmpData.Stride) * bmp.Height;
int imageWeidth = bmp.Width;
int imageHeight = bmp.Height;
//图像的Stride
int imageStride = bmpData.Stride;
byte[] buffer = new byte[bytesLength];
// Copy the RGB values into the array.
Marshal.Copy(ptr, buffer, 0, bytesLength);
bmp.UnlockBits(bmpData);
byte[] ptrData = new byte[2048 * 2048 * 3]; //尽可能大的byte[]
ulong size = new ulong();
GetMat(ref ptrData[0], out size); //将C++的内存数据转入C#的内存中
uint count = 0;
FindFaces(buffer, imageHeight, imageWeidth, imageStride,ref ptrData[0], out size, out count);
pictureBox1.Image = Image.FromStream(new MemoryStream(ptrData, 0, (int)size));
label1.Text = count.ToString();