1.开发环境及运行效果
硬件平台:ubuntu18.04、usb免驱摄像头
ui界面:gtk+_2.0
开发语言:c/c++
2.gtk简介
gtk(gimp toolkit)是一套源码以lgpl许可协议分发、跨平台的图形工具包。最初是为gimp写的,已成为一个功能强大、设计灵活的一个通用图形库,是gnu/linux下开发图形界面的应用程序的主流开发工具之一。当然,gtk也是支持跨平台的,支持unix类的系统、windows,甚至手机平台。
gtk是使用c语言写的,所以其原生api都是面向c的,同时gtk的一大特点是,在c语言层面实现了面向对象的特性。gtk是完全免费的,而且基于lgpl协议,这可以保证私有软件通过链接使用gtk可以不把软件源代码开放,对商业应用较友好,这跟gpl协议是不一样的。也正是lgpl协议,使得早些年gnome(基于gtk编写)风头胜过kde(基于qt编写)。
3.开发流程
3.1 gtk初始化和摄像头初始化
初始化gtk,创建窗口,初始化摄像头设备,检测摄像头设备是否正常。
int main(int argc,char **argv){ gtkwidget *dialog; /*gtk初始化*/ gtk_init(&argc,&argv); /*创建窗口*/ window=gtk_window_new(gtk_window_toplevel); gtk_window_set_title(gtk_window(window),人脸识别); /*固定窗口大小*/ gtk_window_set_resizable (gtk_window(window),false); /*设置窗口大小*/ gtk_widget_set_size_request(window,800,480); gtk_window_set_position(gtk_window(window),gtk_win_pos_center_always);//居中显示 /*连接信号*/ g_signal_connect(g_object(window),destroy,g_callback(on_delete_event),null); /*创建标签*/ gdkcolor color; color.red=0xffff; color.green=0; color.blue=0; label=gtk_label_new(); /*设置字体大小和颜色*/ gtk_label_set_markup(gtk_label(label),正在启动摄像头,请稍等...); g_timeout_add(500,timer_func, label);//开启定时器1s时间 gtk_label_set_justify (gtk_label(label),gtk_justify_center); gtk_container_add(gtk_container(window), label); gtk_widget_show(label); change_background(window, 800, 480, 1.bmp); gtk_widget_show(window); gtk_main(); return 0;}
在定时器中等待摄像头启动成功,完成人脸识别ui界面配置。
等待摄像头启动界面
摄像头启动成功界面
/*定时器处理函数*/gtkwidget *window;gboolean timer_func(gpointer data){ gtkwidget *widget=(gtkwidget *)data; int ret; ret=camera_init(&video_info); if(ret==0) { g_print(摄像头启动成功n); gtk_widget_destroy(label);//关闭对话框 gtkwidget *hbox; gtkwidget *vbox,*box; gtkwidget *button; gtktooltips *tiptool; /*图像宽高*/ width=video_info.image_w; height=video_info.image_h; rgbbuf=malloc(width*height*3); jpg_data=malloc(width*height*3);//保存rgb颜色数据 imagebase64_data=malloc((height*width*3)*8/6);/*base64编码后数据*/ /*创建横向盒*/ hbox=gtk_hbox_new(false,0); gtk_container_add(gtk_container(window),hbox); gtk_widget_show(hbox); /*初始化gdk的rgb*/ gdk_rgb_init(); /*将gdk视件和颜色表放入gtk构件中*/ gtk_widget_push_visual(gdk_rgb_get_visual()); gtk_widget_push_colormap(gdk_rgb_get_cmap()); /*创建绘图区域*/ drawarea=gtk_drawing_area_new(); gtk_widget_pop_visual(); gtk_widget_pop_colormap(); gtk_box_pack_start(gtk_box(hbox),drawarea,false,false,0); g_signal_connect(g_object(drawarea),expose_event,g_callback(draw_image),null); guint id=gtk_idle_add((gtkfunction)read_data,null); /*设置窗口大小*/ gtk_widget_set_size_request(gtk_widget(drawarea),width,height); /*创建纵向盒*/ vbox=gtk_vbox_new(false,0); gtk_box_pack_start(gtk_box(hbox),vbox,true,false,0); gtk_widget_show(vbox); /*人脸注册时输入姓名*/ box=gtk_hbox_new(false,0); gtk_box_pack_start(gtk_box(vbox),box,false,true,30); gtk_widget_show(box); label=gtk_label_new(姓名:); gtk_box_pack_start(gtk_box(box),label,false,true,0); gtk_widget_show(label); /*创建输入文本框*/ entry1=gtk_entry_new(); /*设置输入文本框尺寸*/ gtk_widget_set_size_request(entry1,120,-1); gtk_entry_set_max_length(gtk_entry(entry1),20); gtk_box_pack_start(gtk_box(box),entry1,false,false,0); g_signal_connect(g_object(entry1),key-press-event, g_callback(entry_callback),1); gtk_widget_show(entry1); /*创建提示对象工具*/ tiptool=gtk_tooltips_new(); /*添加提示信息到按钮*/ gtk_tooltips_set_tip(tiptool,entry1,填写姓名,null); /*人脸注册时输入手机号*/ box=gtk_hbox_new(false,0); gtk_box_pack_start(gtk_box(vbox),box,false,true,15); gtk_widget_show(box); label=gtk_label_new(电话:); gtk_box_pack_start(gtk_box(box),label,false,true,0); gtk_widget_show(label); /*创建输入文本框*/ entry2=gtk_entry_new(); /*设置输入文本框尺寸*/ gtk_widget_set_size_request(entry2,120,-1); gtk_entry_set_max_length(gtk_entry(entry2),20); gtk_box_pack_start(gtk_box(box),entry2,false,false,0); g_signal_connect(g_object(entry2),key-press-event, g_callback(entry_callback),2); gtk_widget_show(entry2); /*创建提示对象工具*/ tiptool=gtk_tooltips_new(); /*添加提示信息到按钮*/ gtk_tooltips_set_tip(tiptool,entry2,填写手机号,null); /*设置标签,用于显示状态信息*/ box=gtk_hbox_new(false,0); gtk_box_pack_start(gtk_box(vbox),box,false,false,80); gtk_widget_show(box); label=gtk_label_new(); gtk_label_set_justify (gtk_label(label),gtk_justify_center); gtk_box_pack_start(gtk_box(box),label,true,false,20); gtk_widget_show(label); box=gtk_hbox_new(false,0); gtk_box_pack_end(gtk_box(vbox),box,false,false,20); gtk_widget_show(box); button=gtk_button_new_with_label(人脸识别); gtk_box_pack_start(gtk_box(box),button,true,true,0); g_signal_connect(g_object(button),clicked,g_callback(button_callback),1); gtk_widget_show(button); box=gtk_hbox_new(false,0); gtk_box_pack_end(gtk_box(vbox),box,false,false,20); gtk_widget_show(box); button=gtk_button_new_with_label(人脸注册); gtk_box_pack_start(gtk_box(box),button,true,true,0); g_signal_connect(g_object(button),clicked,g_callback(button_callback),2); gtk_widget_show(button); gtk_widget_show_all(window); return false;//返回false结束定时器 } g_print(摄像头打开失败ret=%dn,ret); gtk_label_set_markup(gtk_label(widget),摄像头启动失败,请检测设备是否正常!); return true;//返回ture继续触发定时器}
6.2 人脸识别和人脸注册
将摄像头采集的图像进行base64编码,然后调用百度ai接口进行人脸注册和人脸比对。
1.百度智能云接口及简介
/*按钮处理函数*/void button_callback(gtkwidget *widget,gpointer data){ gint res=0; gchar format_data[512]; gchar *p=(gchar *)data; guint size=(height*width*3)*8/6; gchar *imagebase64=malloc(size);/*base64编码后数据*/ if(strcmp(p,1))//人脸注册 { g_print(人脸注册n); /*保证线程安全,上锁*/ gdk_threads_enter(); memcpy(imagebase64,imagebase64_data,size); /*保证线程安全,释放*/ gdk_threads_leave(); if(user_info.name[0]=='' || user_info.phone[0]=='' || strlen(user_info.phone)!=11) { //g_print(请正常填写名字手机号码n); gtk_label_set_markup(gtk_label(label),请正常填写名字n手机号码); //开启定时器1s时间 time_flag=g_timeout_add(1000,timer_func2,label); free(imagebase64); return ; } /*人脸注册*/ g_print(phone:%s,name:%sn,user_info.phone,user_info.name); snprintf(format_data,512,group_id:wbyq,user_id:%s,user_info:%s,quality_control:low,liveness_control:normal},user_info.phone,user_info.name); g_print(format=%sn,format_data); facedetect(request_url,access_token,imagebase64,format_data); if(res)/*访问服务器失败*/ { gtk_label_set_markup(gtk_label(label),注册失败); } /* {error_code:0,error_msg:success,log_id:9465001899925,timestamp:1641801995,cached:0,result:{face_token:66d2d1512ec57835ec4ef25ed95bec77, location:{left:265.38,top:251.49,width:201,height:192,rotation:0}}} */ else if(jsondata_analysis(platform_data,error_msg,format_data))/*查找“error_msg”标志失败*/ { gtk_label_set_markup(gtk_label(label),注册失败); } else if(strcmp(format_data,success))/*返回状态标志失败*/ { gtk_label_set_markup(gtk_label(label),注册失败); } else gtk_label_set_markup(gtk_label(label),注册成功); } else if(strcmp(p,2))//人脸识别 { if(time_flag)g_source_remove(time_flag);//关闭定时器 /*保证线程安全,上锁*/ gdk_threads_enter(); memcpy(imagebase64,imagebase64_data,size); /*保证线程安全,释放*/ gdk_threads_leave(); snprintf(format_data,sizeof(format_data),group_id_list:wbyq,quality_control:low,liveness_control:normal}); res=facedetect(face_search,access_token,imagebase64,format_data);//人脸比对 if(res==0) { struct user user_data; if(josn_facesearch(platform_data,&user_data)) { //g_print(比对失败n); gtk_label_set_markup(gtk_label(label),请重试); gtk_entry_set_text(gtk_entry(entry1),); gtk_entry_set_text(gtk_entry(entry2),); } else { //g_print(比对成功:%sn,format_data); gtk_label_set_markup(gtk_label(label),识别成功); gtk_entry_set_text(gtk_entry(entry1),user_data.name); gtk_entry_set_text(gtk_entry(entry2),user_data.phone); } } } free(imagebase64);}
3.3 base64格式编码
base64是网络上最常见的用于传输8bit字节码的编码方式之一,base64就是一种基于64个可打印字符来表示二进制数据的方法。可查看rfc2045~rfc2049,上面有mime的详细规范。
base64编码是从二进制到字符的过程,可用于在http环境下传递较长的标识信息。采用base64编码具有不可读性,需要解码后才能阅读。
base64由于以上优点被广泛应用于计算机的各个领域,然而由于输出内容中包括两个以上“符号类”字符(+, /, =),不同的应用场景又分别研制了base64的各种“变种”。为统一和规范化base64的输出,base62x被视为无符号化的改进版本。
base64要求把每三个8bit的字节转换为四个6bit的字节(38 = 46 = 24),然后把6bit再添两位高位0,组成四个8bit的字节,也就是说,转换后的字符串理论上将要比原来的长1/3。
3.3.1 base64编码示例
static const char * base64char = abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz0123456789+/;char * base64_encode( const unsigned char * bindata, char * base64, int binlength ){ int i, j; unsigned char current; for ( i = 0, j = 0 ; i > 2) ; current &= (unsigned char)0x3f; base64[j++] = base64char[(int)current]; current = ( (unsigned char)(bindata[i] > 4) ) & ( (unsigned char) 0x0f ); base64[j++] = base64char[(int)current]; current = ( (unsigned char)(bindata[i+1] > 6) ) & ( (unsigned char) 0x03 ); base64[j++] = base64char[(int)current]; current = ( (unsigned char)bindata[i+2] ) & ( (unsigned char)0x3f ) ; base64[j++] = base64char[(int)current]; } base64[j] = ''; return base64;}
3.3.2 base64解码示例
int base64_decode( const char * base64, unsigned char * bindata ){ int i, j; unsigned char k; unsigned char temp[4]; for ( i = 0, j = 0; base64[i] != '' ; i += 4 ) { memset( temp, 0xff, sizeof(temp) ); for ( k = 0 ; k < 64 ; k ++ ) { if ( base64char[k] == base64[i] ) temp[0]= k; } for ( k = 0 ; k < 64 ; k ++ ) { if ( base64char[k] == base64[i+1] ) temp[1]= k; } for ( k = 0 ; k < 64 ; k ++ ) { if ( base64char[k] == base64[i+2] ) temp[2]= k; } for ( k = 0 ; k < 64 ; k ++ ) { if ( base64char[k] == base64[i+3] ) temp[3]= k; } bindata[j++] = ((unsigned char)(((unsigned char)(temp[0] 4)&0x03)); if ( base64[i+2] == '=' ) break; bindata[j++] = ((unsigned char)(((unsigned char)(temp[1] 2)&0x0f)); if ( base64[i+3] == '=' ) break; bindata[j++] = ((unsigned char)(((unsigned char)(temp[2]
valuestring,success))return -2; } item=cjson_getobjectitem(root,result); if(item) { item=cjson_getobjectitem(item,user_list); cjson *array_item=cjson_getarrayitem(item,0); if(array_item==null)return -1; cjson *obj=cjson_getobjectitem(array_item,user_info); if(obj)printf(info=%sn,obj->valuestring); strcpy(user_info->name,obj->valuestring); obj=cjson_getobjectitem(array_item,user_id); strcpy(user_info->phone,obj->valuestring); } cjson_delete(root);//释放空间 return 0;}
4.人脸识别和人脸注册运行效果
在家制作高质量双面PCB板的全过程
iOS11最新消息:iOS11.0.1已更新推送,修复Bug提升性能你升级了吗?
变压器受潮的原因_变压器受潮的处理办法
苹果13手机价格多少钱
物联网核心是什么?各个环节是如何工作的?
Linux下基于GTK人脸识别界面设计(2)
软启动器好坏测量
瑞萨电子发布了业界第一款使用28nm工艺的集成闪存微控制器
Omdia发布《5G R16标准和芯片推动垂直行业应用智能化升级》白皮书
小米6最新消息:小米6评测,安兔兔跑分高达17.3万分,多项功能解析
物联网智商是怎么一回事
声发射的概念
这几款高颜值长续航智能手表值得关注
NI推出LabVIEW新特性和新功能,进一步推动创新加速
上研院联合华为发布5G定位能力开放产业白皮书
日盈电子拟不超1.64亿元收购惠昌传感器90%股权
Oculus Quest 2发布,将为消费者提供目前最先进、最具沉浸感的VR游戏体验
可穿戴等智能设备出路在哪?做物联网入口
【CDD】诊断数据库创建速成班-课堂(二)
Xilinx全局时钟的使用和DCM模块的使用