Linux下基于百度智能云平台人脸识别
Linux下基于百度智能云平台人脸识别1.百度智能云接口及简介https://cloud.baidu.com/product/face 接口技术文档:2.人脸检测属性分析项目示例 硬件平台: ubuntu18.04、USB免驱摄像头 图像渲染: SDL库 开发语言: C语言 效果展示:3.摄像头应用框架V4L2示例#include <stdio.h>#include <sys
·
Linux下基于百度智能云平台人脸识别
1.百度智能云接口及简介
https://cloud.baidu.com/product/face
接口技术文档:
2.人脸检测属性分析项目示例
硬件平台: ubuntu18.04、USB免驱摄像头
图像渲染: SDL库
开发语言: C语言
效果展示:



3.摄像头应用框架V4L2示例
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include "video.h"
/*摄像头应用编程框架*/
int Video_Init(u8 *dev,int video_fd,struct video *video_info)
{
/*1.打开摄像设备文件*/
video_fd=open(dev,O_RDWR);
if(video_fd<0)return -1;
/*2.图像数据格式*/
struct v4l2_format video_format;
memset(&video_format,0,sizeof(struct v4l2_format));
video_format.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;//捕获格式
video_format.fmt.pix.width=800;
video_format.fmt.pix.height=480;
video_format.fmt.pix.pixelformat=V4L2_PIX_FMT_YUYV;
if(ioctl(video_fd,VIDIOC_S_FMT,&video_format))return -2;
video_info->width=video_format.fmt.pix.width;
video_info->height=video_format.fmt.pix.height;
printf("图像尺寸:%d * %d\n",video_info->width,video_info->height);
/*3.申请空间*/
struct v4l2_requestbuffers video_requestbuffers;
memset(&video_requestbuffers,0,sizeof(struct v4l2_requestbuffers));
video_requestbuffers.count=4;//缓冲区个数
video_requestbuffers.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;//V4L2捕获框架格式
video_requestbuffers.memory=V4L2_MEMORY_MMAP;//内存映射
if(ioctl(video_fd,VIDIOC_REQBUFS,&video_requestbuffers))return -3;
printf("缓冲区个数:%d\n",video_requestbuffers.count);
/*4.将缓冲映射到进程空间*/
int i=0;
struct v4l2_buffer video_buffer;
for(i=0;i<video_requestbuffers.count;i++)
{
memset(&video_buffer,0,sizeof(struct v4l2_buffer));
video_buffer.index=i;//
video_buffer.memory=V4L2_MEMORY_MMAP;//内存映射
video_buffer.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;//V4L2捕获框架格式
if(ioctl(video_fd,VIDIOC_QUERYBUF,&video_buffer))return -4;
video_info->mmap_size=video_buffer.length;/*映射大小*/
video_info->mmapbuf[i]=mmap(NULL,video_buffer.length,PROT_READ|PROT_WRITE,MAP_SHARED,video_fd,video_buffer.m.offset);
}
/*5.将缓冲区添加到采集队列*/
for(i=0;i<video_requestbuffers.count;i++)
{
memset(&video_buffer,0,sizeof(struct v4l2_buffer));
video_buffer.index=i;//
video_buffer.memory=V4L2_MEMORY_MMAP;//内存映射
video_buffer.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;//V4L2V4L2捕获框架格式
if(ioctl(video_fd,VIDIOC_QBUF,&video_buffer))return -5;
}
/*开启摄像头*/
int type=V4L2_BUF_TYPE_VIDEO_CAPTURE;//V4L2V4L2捕获框架格式
if(ioctl(video_fd,VIDIOC_STREAMON,&type))
{
printf("摄像头开启失败\n");
return -6;
}
return video_fd;
}
4.调用百度人家属性分析接示例与base64图像编码
#include "connect.h"
// libcurl库下载链接:https://curl.haxx.se/download.html
// jsoncpp库下载链接:https://github.com/open-source-parsers/jsoncpp/
char platform_data[2048];
size_t callback(void *ptr, size_t size, size_t nmemb, void *stream)
{
strncpy(platform_data,(char *)ptr, size * nmemb);
printf("\n--------------------------------\n");
printf("platform_data=%s\n",platform_data);
return size * nmemb;
}
/**
* 人脸检测与属性分析
* @return 调用成功返回0,发生错误返回其他错误码
*/
int faceDetect(const char *request_url,const char *access_token,const char *image_base64,const char *format_data)
{
char url[200];
snprintf(url,sizeof(url),"%s?access_token=%s",request_url,access_token);
CURL *curl = NULL;
CURLcode result_code;
int is_success=0;
char iamge[1024*1024*2];
snprintf(iamge,sizeof(iamge),"{\"image\":\"%s\",\"image_type\":\"BASE64\",%s",image_base64,format_data);
curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, url);/*存放http地址*/
curl_easy_setopt(curl, CURLOPT_POST, 1);//
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Content-Type:application/json;charset=UTF-8");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);//设置HTTP头字段的数组
curl_easy_setopt(curl, CURLOPT_POSTFIELDS,iamge);/*向服务器post出去一段数据*/
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, callback); //设置回调函数
result_code=curl_easy_perform(curl);//访问数据
if (result_code != CURLE_OK) {
fprintf(stderr, "curl_easy_perform() failed: %s",curl_easy_strerror(result_code));
is_success = 1;
return is_success;
}
curl_easy_cleanup(curl);
is_success = 0;
} else {
fprintf(stderr, "curl_easy_init() failed.");
is_success = 1;
}
return is_success;
}
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] = '\0';
return 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] != '\0' ; 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;
}
5.人脸注册
/*注册人脸*/
int face_register(const char *image_base64,char *format_data,SDL_Window *window,SDL_Renderer *rend,TTF_Font *ttffont)
{
SDL_Color color={0,0,0,255};/*字体颜色 RGBA*/
char data[50];
char name[50];
char phone[20];
SDL_Rect rect;
rect.x=640;
rect.y=0;
rect.w=160;
rect.h=300;
SDL_SetRenderDrawColor(rend, 255, 255, 255, 255);
SDL_RenderFillRect(rend, &rect);/*清空指定区域*/
int text1_width,text2_width;
SDL_SetRenderDrawColor(rend, 255, 0, 0, 255);
text1_width=SDL_ttfDisplayFont(650,100,window,ttffont,14,color,"姓名:",rend);
SDL_RenderDrawLine(rend,650+(text1_width&0xff),103+(text1_width>>8),800-10,103+(text1_width>>8));
text2_width=SDL_ttfDisplayFont(650,150,window,ttffont,14,color,"手机号:",rend);
SDL_SetRenderDrawColor(rend, 0, 0, 0, 255);
SDL_RenderDrawLine(rend,650+(text2_width&0xff),153+(text1_width>>8),800-10,153+(text2_width>>8));
SDL_RenderPresent(rend); // 渲染
SDL_Event event;
int x=(text1_width&0xff)+ 650;
int y=100;
int x0=x;
int font_size=0;
char font_w[100];/*保存每个字符的宽度*/
int cnt=0;
int stat=0;
while(quit)
{
while(SDL_PollEvent(&event))
{
if(event.type==SDL_QUIT)/*获取事件*/
{
quit=false;
video_flag=0;
pthread_cancel(pthid);/*杀死指定线程*/
continue;
}
else if(event.type==SDL_KEYDOWN)//键盘事件
{
if(event.key.keysym.sym==SDLK_RETURN)/*回车键*/
{
data[cnt]='\0';
cnt=0;
stat++;
if(stat!=2)
{
printf("请输入手机号\n");
strncpy(name,data,sizeof(name));
printf("name=%s\n",name);
SDL_SetRenderDrawColor(rend, 255, 0, 0, 255);
SDL_RenderDrawLine(rend,650+(text2_width&0xff),153+(text1_width>>8),800-10,153+(text2_width>>8));
SDL_RenderPresent(rend);
cnt=0;/*下标清零*/
y+=50;
x=655+(text2_width&0xff);
x0=x;
}
else if(stat==2)
{
strncpy(phone,data,sizeof(phone));
printf("phone=%s\n",phone);
quit=false;
continue;
}
}
else if(event.key.keysym.sym==SDLK_TAB)/*TAB键*/
{
stat++;
data[cnt]='\0';
if(stat==1)
{
strncpy(name,data,sizeof(name));
printf("name=%s\n",name);
SDL_SetRenderDrawColor(rend, 255, 0, 0, 255);
SDL_RenderDrawLine(rend,650+(text2_width&0xff),153+(text1_width>>8),800-10,153+(text2_width>>8));
SDL_RenderPresent(rend);
}
else if(stat==2)
{
strncpy(phone,data,sizeof(name));
printf("phone=%s\n",phone);
}
cnt=0;/*下标清零*/
y+=50;
x=655+(text2_width&0xff);
x0=x;
}
else if(event.key.keysym.sym==SDLK_BACKSPACE)/*退格键*/
{
if(cnt>0)
{
cnt--;
x0-=font_w[cnt];
}
SDL_Rect rect;
rect.x=x0;
rect.y=y;
rect.w=font_w[cnt];
rect.h=(font_size>>8)&0xff;
SDL_SetRenderDrawColor(rend, 255, 255, 255, 255);
SDL_RenderFillRect(rend, &rect);
SDL_RenderPresent(rend);
}
}
else if(event.type == SDL_TEXTINPUT)/*文本输入*/
{
font_size=SDL_ttfDisplayFont(x0,y,window,ttffont,12,color,event.text.text,rend);
data[cnt]=event.text.text[0];
x0+=font_size&0xff;
font_w[cnt++]=font_size&0xff;/*保存每个字符宽度*/
SDL_RenderPresent(rend);
}
}
}
if(stat==2)quit=true;
int res=0;
snprintf(format_data,512,"\"group_id\":\"wbyq\",\"user_id\":\"%s\",\"user_info\":\"%s\",\"quality_control\":\"LOW\",\"liveness_control\":\"NORMAL\"}",phone,name);
faceDetect(request_url,access_token,image_base64,format_data);
if(res)return -1;/*访问服务器失败*/
/*
{"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}}}
*/
if(JsonData_analysis(platform_data,"\"error_msg\"",format_data))return -3;/*注册失败*/
printf("format_data=%s\n",format_data);
if(strcmp(format_data,"SUCCESS"))return -4;/*注册失败*/
return 0;
}
6.人脸识别和主函数
/*
token值获取:
#!/bin/bash
curl -i -k 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=【百度云应用的AK】&client_secret=【百度云应用的SK】'
*/
const static char * request_url = "https://aip.baidubce.com/rest/2.0/face/v3/faceset/user/add"; //人脸注册
const static char * face_search= "https://aip.baidubce.com/rest/2.0/face/v3/search"; //人脸搜索
const static char *access_token="24.3839bfa18d023457841cd083bfcd9057d55.2592000.1644480673.282335-25497897";
#define CAMERA_DEV "/dev/video0" //摄像头设备节点
int video_fd;/*摄像头描述符*/
struct video video_info;/*摄像头结构体信息*/
u8 *rgb_buff=NULL;
int video_flag;/*摄像头采集线程状态*/
pthread_t pthid;/*线程ID*/
pthread_mutex_t fastmutex = PTHREAD_MUTEX_INITIALIZER;//互斥锁
pthread_mutex_t fastmutex2 = PTHREAD_MUTEX_INITIALIZER;//互斥锁
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;//条件变量
typedef enum
{
false=0,
true,
}bool;
bool quit=true;
/*ttf显示字符串*/
int SDL_ttfDisplayFont(int x,int y,SDL_Window *window,TTF_Font *ttffont,int size,SDL_Color color,const char *str,SDL_Renderer *rend);
void *Video_CollectImage(void *arg);/*图像采集线程*/
u8 JsonData_analysis(u8* buff,u8 *flag,u8 *data);/*JSON数据解析*/
int Josn_faceSearch(const char *buff,char *user_info);/*人脸搜索数据解析*/
int face_register(const char *image_base64,char *format_data,SDL_Window *window,SDL_Renderer *rend,TTF_Font *ttffont);/*注册人脸*/
int main()
{
int w,h;
SDL_Event event;
/*TTF 初始化*/
TTF_Init();
/*打开字库*/
TTF_Font *ttffont=TTF_OpenFont("方正粗黑宋简体.ttf",30);
if(ttffont==NULL)
{
printf("字库打开失败\n");
return 0;
}
/*创建窗口 */
SDL_Window *window=SDL_CreateWindow("人脸识别", SDL_WINDOWPOS_CENTERED,SDL_WINDOWPOS_CENTERED,800,480,SDL_WINDOW_ALLOW_HIGHDPI|SDL_WINDOW_SHOWN);
if(window==NULL)
{
printf("创建创建失败\n");
return 0;
}
SDL_GetWindowSize(window,&w,&h);
/*创建渲染器*/
SDL_Renderer *render=SDL_CreateRenderer(window,-1,SDL_RENDERER_ACCELERATED);
int cnt=200;
/*检查设备头设备*/
SDL_Color color={255,255,255,255};/*字体颜色 RGBA*/
while(quit)
{
while(SDL_PollEvent(&event))/*事件监测*/
{
if(event.type==SDL_QUIT)/*退出事件*/
{
quit=false;
continue;
}
}
SDL_Delay(10);
cnt++;
if(cnt>=200)
{
cnt=0;
/*初始化摄像头*/
video_fd=Video_Init(CAMERA_DEV,video_fd,&video_info);
if(video_fd<=0)
{
SDL_RenderClear(render);
printf("摄像头打开失败,请接入摄像头\n");
SDL_ttfDisplayFont(-1,200,window,ttffont,30,color,"摄像头打开失败,请检查摄像头设备!",render);
SDL_RenderPresent(render); // 渲染
}
else break;
}
}
if(quit==false)
{
SDL_DestroyRenderer(render);/*销毁渲染器*/
SDL_DestroyWindow(window);/*销毁窗口 */
SDL_Quit();/*关闭SDL*/
return 0;
}
SDL_SetRenderDrawColor(render,255, 255, 255,255);
/*清空渲染器*/
SDL_RenderClear(render);
printf("设备打开成功\n");
printf("图像尺寸:%d * %d\n",video_info.width,video_info.height);
/*创建纹理*/
SDL_Texture*sdltext=SDL_CreateTexture(render,SDL_PIXELFORMAT_RGB24,SDL_TEXTUREACCESS_STREAMING,video_info.width,video_info.height);
/*创建摄像头采集线程*/
u8 *rgb_data=malloc(video_info.height*video_info.width*3);
rgb_buff=malloc(video_info.height*video_info.width*3);//保存RGB颜色数据
u8 *jpg_data=malloc(video_info.height*video_info.width*3);//保存RGB颜色数据
u8 *imagebase64_data=malloc((video_info.height*video_info.width*3)*8/6);/*base64编码后数据*/
int jpg_size;/*jpg图像大小*/
video_flag=1;/*摄像头采集标志*/
int display_stat=1;
int count=0;
pthread_create(&pthid,NULL,Video_CollectImage, NULL);
SDL_Surface *imgsurface=IMG_Load("button.jpg");
if(imgsurface==NULL)
{
printf("图标加载失败\n");
pthread_cancel(pthid);/*杀死指定线程*/
quit=false;
}
SDL_Texture *imgsdltext=SDL_CreateTextureFromSurface(render, imgsurface);
SDL_Rect rect;
SDL_Rect image_rect;
rect.x=w-imgsurface->w-30;/*注册按钮坐标位置x*/
rect.y=h-3*imgsurface->h-20;/*注册按钮坐标位置y*/
SDL_Rect rect2;
rect2.x=w-imgsurface->w-30;/*注册按钮坐标位置x*/
rect2.y=h-2*imgsurface->h;/*注册按钮坐标位置y*/
while(quit)
{
while(SDL_PollEvent(&event))/*事件监测*/
{
if(event.type==SDL_QUIT)/*退出事件*/
{
quit=false;
video_flag=0;
pthread_cancel(pthid);/*杀死指定线程*/
continue;
}
else if(event.type==SDL_MOUSEBUTTONDOWN)/*点击事件*/
{
SDL_Color color={255,0,0,255};/*字体颜色 RGBA*/
if(event.button.button==SDL_BUTTON_LEFT)/*左键*/
{
char format_data[512];
if((event.motion.x>=rect.x && event.motion.x<=rect.x+imgsurface->w) &&
(event.motion.y>=rect.y && event.motion.y<=rect.y+imgsurface->h))
{
pthread_mutex_lock(&fastmutex);//互斥锁上锁
pthread_cond_wait(&cond,&fastmutex);
memcpy(rgb_data,rgb_buff,video_info.height*video_info.width*3);
pthread_mutex_unlock(&fastmutex);//互斥锁解锁
jpg_size=rgb_to_jpeg(video_info.width,video_info.height,video_info.height*video_info.width*3,rgb_data,jpg_data, 80);
base64_encode(jpg_data, imagebase64_data, jpg_size);
//face_register(imagebase64_data,format_data);
int res=face_register(imagebase64_data,format_data,window,render,ttffont);
if(res)
{
SDL_Rect rect={640,200,160,100};
SDL_SetRenderDrawColor(render, 255, 255, 255, 255);
SDL_RenderFillRect(render,&rect);/*矩形填充*/
snprintf(format_data,sizeof(format_data),"注册失败");
}
else
{
SDL_Rect rect={640,200,160,100};
SDL_SetRenderDrawColor(render, 255, 255, 255, 255);
SDL_RenderFillRect(render,&rect);/*矩形填充*/
snprintf(format_data,sizeof(format_data),"注册成功");
}
SDL_ttfDisplayFont(650,260,window,ttffont,25,color,format_data,render);
SDL_RenderPresent(render); // 渲染
}
if((event.motion.x>=rect2.x && event.motion.x<=rect2.x+imgsurface->w) &&
(event.motion.y>=rect2.y && event.motion.y<=rect2.y+imgsurface->h))
{
pthread_mutex_lock(&fastmutex);//互斥锁上锁
pthread_cond_wait(&cond,&fastmutex);
memcpy(rgb_data,rgb_buff,video_info.height*video_info.width*3);
pthread_mutex_unlock(&fastmutex);//互斥锁解锁
jpg_size=rgb_to_jpeg(video_info.width,video_info.height,video_info.height*video_info.width*3,rgb_data,jpg_data, 80);
base64_encode(jpg_data, imagebase64_data, jpg_size);
snprintf(format_data,sizeof(format_data),"\"group_id_list\":\"wbyq\",\"quality_control\":\"LOW\",\"liveness_control\":\"NORMAL\"}");
int res=0;
res=faceDetect(face_search,access_token,imagebase64_data,format_data);
if(res)continue;
if(Josn_faceSearch(platform_data,format_data))
{
SDL_Rect rect={640,0,160,300};
SDL_SetRenderDrawColor(render, 255, 255, 255, 255);
SDL_RenderFillRect(render,&rect);/*矩形填充*/
strcpy(format_data,"请重试\n");
}
else
{
display_stat=0;
count=0;
SDL_SetRenderDrawColor(render, 255, 255, 255, 255);
SDL_Rect rect={640,0,160,300};
SDL_RenderFillRect(render,&rect);/*矩形填充*/
SDL_ttfDisplayFont(650,250,window,ttffont,25,color,"识别成功",render);
}
SDL_ttfDisplayFont(650,200,window,ttffont,20,color,format_data,render);
SDL_RenderPresent(render); // 渲染
printf("人脸识别\n");
}
}
}
}
if(!video_flag)
{
quit=false;
continue;
}
pthread_mutex_lock(&fastmutex);//互斥锁上锁
pthread_cond_wait(&cond,&fastmutex);
memcpy(rgb_data,rgb_buff,video_info.height*video_info.width*3);
pthread_mutex_unlock(&fastmutex);//互斥锁解锁
SDL_UpdateTexture(sdltext,NULL,rgb_data, video_info.width*3);
//SDL_RenderCopy(render, sdltext, NULL,NULL); // 拷贝纹理到渲染器
image_rect.x=0;
image_rect.y=0;
image_rect.w=640;
image_rect.h=480;
SDL_RenderCopyEx(render, sdltext,NULL,&image_rect,0,NULL,SDL_FLIP_HORIZONTAL);
rect.w=imgsurface->w;
rect.h=imgsurface->h;
SDL_RenderCopyEx(render,imgsdltext,NULL,&rect,0,NULL,SDL_FLIP_NONE);
SDL_ttfDisplayFont(rect.x,rect.y+5,window,ttffont,18,color,"人脸注册",render);
rect2.w=imgsurface->w;
rect2.h=imgsurface->h;
SDL_RenderCopyEx(render,imgsdltext,NULL,&rect2,0,NULL,SDL_FLIP_NONE);
SDL_ttfDisplayFont(rect2.x,rect2.y+5,window,ttffont,18,color,"人脸识别",render);
if(display_stat)SDL_RenderPresent(render); // 渲染
else count++;
SDL_Delay(1);
if(count>=30)/*自动恢复图像监控状态*/
{
count=0;
display_stat=1;
}
}
SDL_DestroyTexture(sdltext);/*销毁纹理*/
SDL_DestroyRenderer(render);/*销毁渲染器*/
SDL_DestroyWindow(window);/*销毁窗口 */
SDL_Quit();/*关闭SDL*/
pthread_mutex_destroy(&fastmutex);/*销毁互斥锁*/
pthread_cond_destroy(&cond);/*销毁条件变量*/
free(rgb_buff);
free(rgb_data);
}
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)