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

描述

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 < 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.人脸识别和人脸注册运行效果

界面设计界面设计


 

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

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分