0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Linux下基于GTK人脸识别界面设计(2)

嵌入式技术 来源:嵌入式技术 作者:嵌入式技术 2022-12-03 08:10 次阅读

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.开发流程

poYBAGOKlAiAOIIGAAEBa43qhiI294.png#pic_center

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界面配置。

等待摄像头启动界面

pYYBAGOKlAmAEdJ1AACLd-Nf2CU814.png#pic_center

摄像头启动成功界面

poYBAGOKlAmAOROIAAXPOK827Mc114.png#pic_center

/*定时器处理函数*/

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.百度智能接口及简介pYYBAGOKlAuACBk5ABGwUEgPZEE352.png#pic_centerpYYBAGOKlAyAZo4lAAJz9q08TTg553.png#pic_center

/*按钮处理函数*/
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 < binlength ; i += 3 )
    {
        current = (bindata[i] >> 2) ;
        current &= (unsigned char)0x3F;
        base64[j++] = base64char[(int)current];
        current = ( (unsigned char)(bindata[i] << 4 ) ) & ( (unsigned char)0x30 ) ;
        if ( i + 1 >= binlength )
        {
            base64[j++] = base64char[(int)current];
            base64[j++] = '=';
            base64[j++] = '=';
            break;
        }
        current |= ( (unsigned char)(bindata[i+1] >> 4) ) & ( (unsigned char) 0x0F );
        base64[j++] = base64char[(int)current];
        current = ( (unsigned char)(bindata[i+1] << 2) ) & ( (unsigned char)0x3C ) ;
        if ( i + 2 >= binlength )
        {
            base64[j++] = base64char[(int)current];
            base64[j++] = '=';
            break;
        }
        current |= ( (unsigned char)(bindata[i+2] >> 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] << 2))&0xFC)) |
                ((unsigned char)((unsigned char)(temp[1]>>4)&0x03));
        if ( base64[i+2] == '=' )
            break;
        bindata[j++] = ((unsigned char)(((unsigned char)(temp[1] << 4))&0xF0)) |
                ((unsigned char)((unsigned char)(temp[2]>>2)&0x0F));
        if ( base64[i+3] == '=' )
            break;
        bindata[j++] = ((unsigned char)(((unsigned char)(temp[2] << 6))&0xF0)) |
                ((unsigned char)(temp[3]&0x3F));
    }
    return j;
}

3.4 CJSON格式数据解析

JSON(JavaScript Object Notation, JS对象简谱)是一种轻量级的数据交换格式。它基于 ECMAScript(European Computer Manufacturers Association, 欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率

JSON是一个标记符的序列。这套标记符包含六个构造字符、字符串、数字和三个字面名。

  JSON是一个序列化的对象或数组。

JSON格式数据解析示例

/******************json数据解析****************
形参:u8* buff原始数据
			u8 *flag数据标志
			u8 *data解析获取到的数据
返回值:0---成功,其他值---失败
************************************************/
guchar JsonData_analysis(guchar* buff,guchar *flag,guchar *data)
{
	guchar *p=NULL;
	guint i=0;
	p=strstr((char *)buff,(char *)flag);
	if(p)
	{
		p+=strlen((char *)flag)+2;
		i=0;
		while(*p!='"' && *p!='')
		{
			data[i++]=*p++;
		}
		data[i]='';
		return 0;
	}
	else return -1;
}

/*
josn数据解析
buff --要解析的内
user_info--解析成功返回用户名和id
返回值:成功返回0,失败返回其它值

*/
int Josn_faceSearch(const char *buff,struct USER *user_info)
{
    /*
     data={"error_code":0,"error_msg":"SUCCESS","log_id":2014555550012,"timestamp":1641792320,"cached":0,
    "result":{"face_token":"6473abd658b76d6843de9a0820aeb2d2","user_list":[{"group_id":"wbyq","user_id":"18172864683","user_info":"u738bu65b0u6c34","score":99.232490539551}]}}
    */
    /*创建cJSON对象*/
	cJSON *root=cJSON_CreateObject();
	char *p=strstr(buff,"{"error_code"");
	root=cJSON_Parse(p);/*载入JSON数据*/
    if(root==NULL)return -1;
    /*2.解析字段*/
	cJSON *item;
    item=cJSON_GetObjectItem(root,"error_msg");
    if(item)
	{
		printf("error_code:%sn",item->valuestring);
        if(strcmp(item->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.人脸识别和人脸注册运行效果

pYYBAGOKlA2AJ7jPAAXZuGlyHQs028.png#pic_centerpoYBAGOKlA6AXQNsAAWHeGCer7c304.png#pic_center


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Linux
    +关注

    关注

    87

    文章

    10990

    浏览量

    206734
  • 人脸识别
    +关注

    关注

    76

    文章

    3955

    浏览量

    80556
  • 界面设计
    +关注

    关注

    0

    文章

    22

    浏览量

    10400
收藏 人收藏

    评论

    相关推荐

    Qt界面设计素材

    `Qt界面设计素材,需要的可以下载,可以使自己的图形界面做的更美观:`
    发表于 11-12 17:15

    【NanoPi2申请】基于opencv的人脸识别门禁系统

    防与监控的系统,望批准!谢谢!项目描述:项目简述:本项目旨在一个较高性能的嵌入式平台上搭建一个linux系统,利用opencv编程实现人脸识别。为了实现图像采集,需要编写linux驱动
    发表于 12-18 14:34

    基于PCA和2DPCA的人脸识别

    求大神分享基于PCA与2DPCA的人脸识别的资料。帮我推荐一学习PCA和2DPCA的书籍。谢谢。
    发表于 04-06 15:31

    人脸识别测温产品+Linux系统

    `最近市场门禁+测温比较流行,市场有Android系统和Linux系统,考察市场大都都是linux系统人脸识别产品比较多。Linux系统主要
    发表于 04-29 15:11

    基于嵌入式LInux人脸识别系统

    1,基于嵌入式LInux人脸识别系统
    发表于 10-27 07:02

    基于linux操作系统实现一个人脸识别门禁系统

    形成组网,实现一个人脸识别门禁系统。客户端为嵌入式Linux设备,采用QT库显示界面,通过摄像头采集图像。服务器为PC上 Ubuntu系统,采用QT库显示
    发表于 12-14 06:24

    MATLAB图形用户界面设计

    MATLAB图形用户界面设计:7.1 MATLAB 图形界面编程基础7.2 MATLAB 标准对话框7.3 MATLAB 图形界面设计基本控件7.4 MATLAB 界面菜单系统设计7.
    发表于 09-03 12:20 0次下载

    触摸屏界面设计原则

    本论文通过对于用户界面设计的认识和触摸屏界面的了解,其中包括自身使 用体会、他人的评价和感想、设计人员的资源共享等,发现了在触摸屏界面设计上存 在的问题,深感触摸屏界面可用性的重要性以
    发表于 02-28 14:42 1039次下载

    LabVIEW 界面设计秘诀

    LabVIEW 界面设计秘诀对想做漂亮LV界面的童鞋来说是有用的。
    发表于 05-17 16:41 108次下载

    Android界面设计

    Android界面设计规范,这些你都知道嘛?
    发表于 09-15 09:42 7次下载

    实训4-1 Android读据读取——界面设计

    Android 界面设计
    发表于 10-25 17:02 0次下载

    采用GtkBuilder设计Gtk+界面

    Gtk+使用glade进行界面设计能有效地加快项目进度和提高程序的可维护性
    发表于 04-25 17:42 2188次阅读

    嵌入式Linux 中的应用中的GTK+

    在嵌入式 Linux 下有很多图形界面系统 GUI,包括 Qt/Embedded,FLTK,Microwindows 和 GTK+ 等。作为一个开发者,到底使用什么样的 GUI 系统呢?对一个系统,将它改造为符合你的需求,你要做
    发表于 04-27 19:06 2373次阅读

    Linux下基于GTK人脸识别界面设计

    人脸识别,是基于人的脸部特征信息进行身份识别的一种生物识别技术。用摄像机或摄像头采集含有人脸的图像或视频流,并自动在图像中检测和跟踪
    的头像 发表于 12-02 09:53 4267次阅读

    嵌入式Linux开发秘籍!工程师大佬亲历分享项目样例

    、HAL库)、PCB电路设计、Linux下进程、线程、网络编程等。 Linux下基于GTK人脸识别界面设
    的头像 发表于 05-23 08:20 764次阅读