先看身份证正面、背面识别效果。
效果
说明
详细的DLL封装和调用可以参考:轻松学习C#:百度行驶证C++离线SDK接入详解,本文分享一些不一样的。
1、乱码问题
如下图,识别出的汉字输出显示是乱码。
原因
提供的程序内部字符串使用的是UTF8编码,工程项目是Unicode编码,编码方式不一致导致。
ANSI、Unicode和UTF8三种字符编码及相互转换参考
https://blog.csdn.net/chenlycly/article/details/121070073
解决
UTF8转Unicode,然后Unicode再转ANSI显示
效果
代码
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";
效果
使用Encoding.UTF8.GetString获取字符串效果
分享结束,感谢阅读!!!