百度身份证C++离线SDK接入

先看身份证正面、背面识别效果。

效果

62935bb3f547c2455d516846ec25b9be.png

88a7621b019d254814f35df5087e9fb1.png

说明

详细的DLL封装和调用可以参考:轻松学习C#:百度行驶证C++离线SDK接入详解,本文分享一些不一样的。

1、乱码问题

如下图,识别出的汉字输出显示是乱码。

9500470cd5aec56260cce83eb36558eb.png

原因

提供的程序内部字符串使用的是UTF8编码,工程项目是Unicode编码,编码方式不一致导致。

915d425f6ba13f89442f5976c3498b34.png

ANSI、Unicode和UTF8三种字符编码及相互转换参考

https://blog.csdn.net/chenlycly/article/details/121070073

解决

UTF8转Unicode,然后Unicode再转ANSI显示

效果

44d19ac3b463015b4359882eb7501829.png

代码

std::cout << "\n---------------------->>" << std::endl;
 WCHAR* pchDest = new WCHAR[64];
 Utf8ToUnicode(final_result.name, pchDest, 64);
 string s(WcharToChar(pchDest));
 delete pchDest;
 std::cout << "识别的姓名:" << s << std::endl;
 std::cout << "---------------------->>\n" << std::endl;

Utf8ToUnicode函数

/*=============================================================================
函 数 名: Utf8ToUnicode
功    能: 实现将char型的buffer(utf8编码)中的内容安全地拷贝到指定的WCHAR型buffer(Unicode编码)中
参    数: char* pchSrc [in]          源字符串
WCHAR* pchDest [out]     目标buf
int nDestLen   [in]      目标buf长度(注意:以字节为单位,不是以字符个数为单位)
注    意: 无
返 回 值: 无
=============================================================================*/
void Utf8ToUnicode(const char* pchSrc, WCHAR* pchDest, int nDestLen)
{
 if (pchSrc == NULL || pchDest == NULL)
 {
  return;
 }

 int nTmpLen = MultiByteToWideChar(CP_UTF8, 0, pchSrc, -1, NULL, 0);
 WCHAR* pWTemp = new WCHAR[nTmpLen + 1];
 memset(pWTemp, 0, (nTmpLen + 1) * sizeof(WCHAR));
 MultiByteToWideChar(CP_UTF8, 0, pchSrc, -1, pWTemp, nTmpLen + 1);

 UINT nLen = wcslen(pWTemp);
 if (nLen + 1 > (nDestLen / sizeof(WCHAR)))
 {
  wcsncpy(pchDest, pWTemp, nDestLen / sizeof(WCHAR) - 1);
  pchDest[nDestLen / sizeof(WCHAR) - 1] = 0;
 }
 else
 {
  wcscpy(pchDest, pWTemp);
 }

 delete[]pWTemp;
}

2、返回结构体

行驶证中返回值我们是自己拼接json格式字符串返回,身份证对接,我们试试直接返回结构体。

SDK定义的结构体如下:

struct IDCardResponse {
 char name[64];         // 姓名
 char gender[64];       //  性别
 char ethnicity[64];    //  民族
 char birth[1024];      //  出身日期
 char address[1024];    //  住址
 char id_number[1024];  //  身份证号

 char authority[1024];     //  签发机关
 char issuing_date[1024];  //  签发日期
 char expiry_date[1024];   //  失效日期

 float name_coord[8];       // 姓名 坐标
 float gender_coord[8];     //  性别 坐标
 float birth_coord[8];      //  出身日期 坐标
 float address_coord[8];    //  住址 坐标
 float id_number_coord[8];  //  身份证号 坐标
 float ethnicity_coord[8];  //  民族 坐标

 float authority_coord[8];     // 签发机关 坐标
 float issuing_date_coord[8];  //  签发日期 坐标
 float expiry_date_coord[8];   // 失效日期 坐标
};

DLL中导出,我们定义如下:

//识别
extern "C" _declspec(dllexport) int __stdcall ocr(void* idcard_sdk, Mat* image, IDCardResponse* final_result);

那么,在C#中我们进行如下对应的定义:

[StructLayout(LayoutKind.Sequential)]
public struct IDCardResponse
{

    [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 64)]
    public byte[] name;         // 姓名

    [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 64)]
    public byte[] gender;       //  性别

    [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 64)]
    public byte[] ethnicity;    //  民族

    [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 1024)]
    public byte[] birth;      //  出身日期

    [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 1024)]
    public byte[] address;    //  住址

    [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 1024)]
    public byte[] id_number;  //  身份证号

    [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 1024)]
    public byte[] authority;     //  签发机关

    [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 1024)]
    public byte[] issuing_date;  //  签发日期

    [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 1024)]
    public byte[] expiry_date;   //  失效日期

    [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 8)]
    public float[] name_coord;       // 姓名 坐标

    [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 8)]
    public float[] gender_coord;     //  性别 坐标

    [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 8)]
    public float[] birth_coord;      //  出身日期 坐标

    [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 8)]
    public float[] address_coord;    //  住址 坐标

    [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 8)]
    public float[] id_number_coord;  //  身份证号 坐标

    [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 8)]
    public float[] ethnicity_coord;  //  民族 坐标

    [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 8)]
    public float[] authority_coord;     // 签发机关 坐标

    [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 8)]
    public float[] issuing_date_coord;  //  签发日期 坐标

    [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 8)]
    public float[] expiry_date_coord;   // 失效日期 坐标

}

C#中申明如下:

[DllImport(DllName, EntryPoint = "ocr", CallingConvention = CallingConvention.Cdecl)]
public extern static int ocr(IntPtr idcard_sdk, IntPtr image, ref IDCardResponse final_result);

调用代码如下:

Mat image = new Mat(image_path);
IDCardResponse final_result = new IDCardResponse();
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
int res = Native.ocr(IDCard, image.CvPtr, ref final_result);
stopwatch.Stop();
double totalTime = stopwatch.Elapsed.TotalSeconds;
textBox1.Text += $"耗时: {totalTime:F2}s";
textBox1.Text += "\r\n-------------------\r\n";

效果

4ac8c3711b7ad34d3d118cab24692917.png

使用Encoding.UTF8.GetString获取字符串效果

c9bfee92d5de309c17bba2c6bb21fb39.png

分享结束,感谢阅读!!!


ae54b721cac367a67fcb26abe6d0dc30.gif

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值