人脸识别打卡系统--基于QT(附源码)

逃离舒适区


项目源代码放在我的仓库中,有需要自取

项目地址

https://gitcode.com/hujiahangdewa/Face_recognition.git

文章目录

  • 一、项目结构分析
  • 二、服务器的搭建
  • 三、客户端的搭建
  • 四、人脸识别库的申请
  • 五、基于人脸识别库的识别判断
  • 六、QT人脸识别----调用百度ai接口
  • 七、如何在Qt中添加图片素材
  • 八、项目总结


本项目需要准备到的工具:qt6.8.0、VMware17、Ubuntu24.10、百度AI人脸识别库的密钥、摄像头(笔记本电脑自带即可)

一、项目结构分析

在这里插入图片描述

  • 本项目选用Linux系统来搭建服务器,首先我们要明白一点就是在Linux系统中一切
    皆文件
  • 我们的客户端使用QT来搭建
  • 本项目中的客户端与服务器之间的通信采用TCP/IP协议
  • 人脸识别算法采用了百度AI中的人脸识别库(免费)

二、服务器的搭建

  1. 首先先检查我们的虚拟机的USB功能有没有启用
    windows+R调出这个窗口,输入以下命令
    在这里插入图片描述
    找到VMware USB Arbitration Service,将其启动
    在这里插入图片描述
    启动虚拟机,将摄像头连入虚拟机)
    在这里插入图片描述
    检查摄像头是否连接成功:唤起命令行,输入cheese即可检查
  2. 结构分析
    总的来说就是服务器端打开摄像头,将摄像头拍摄的数据传输到客户端中显示出来。
    接下来我们来看看关于摄像头的头文件的结构
#ifndef CAMERA_H
#define CAMERA_H#include <stddef.h> // for size_t#define BUFFER_COUNT 4struct camera
{void *start;size_t length;
};struct buffer_info
{int index;char *pic_buf;int length;
};extern struct camera buffer[BUFFER_COUNT];
extern struct v4l2_buffer buf;
extern struct buffer_info buf_info;/*** @brief 初始化摄像头** @param pathname 摄像头设备的路径。* @return 成功时返回文件描述符,失败时返回 -1。*/
int camera_init(const char *pathname);/*** @brief 启动摄像头采集** @param fd 摄像头设备的文件描述符。* @return 成功时返回 0,失败时返回 -1。*/
int camera_start(int fd);/*** @brief 获取一帧数据** @param fd 摄像头设备的文件描述符。* @param pic_buf 指向图像数据的指针。* @param length 图像数据的长度。* @return 成功时返回 0,失败时返回 -1。*/
int camera_get(int fd, char **pic_buf, int *length);/*** @brief 将已处理的缓冲区重新放入缓存队列** @param fd 摄像头设备的文件描述符。* @return 成功时返回 0,失败时返回 -1。*/
int camera_input(int fd);/*** @brief 停止摄像头流** @param fd 摄像头设备的文件描述符。*/
void camera_stop(int fd);#endif // CAMERA_H
  1. 服务器的具体实现(代码)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>
#include "camera.h"int main(int argc, char *argv[])
{// 创建socket套接字int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0){perror("socket");return -1;}printf("create socket success!\n");// 设置地址信息struct sockaddr_in addr;addr.sin_family = AF_INET;                   // 地址协议族IPv4addr.sin_port = htons(65432);                // 端口号addr.sin_addr.s_addr = inet_addr("0.0.0.0"); // IP地址socklen_t addrlen = sizeof(addr);// bind绑定地址信息 端口号int bind_info = bind(sockfd, (const struct sockaddr *)&addr, addrlen);if (bind_info < 0){perror("bind");return -1;}printf("bind socket success!\n");// listen监听if (listen(sockfd, 5) < 0){perror("listen");return -1;}printf("listen socket success!\n");// 摄像头的初始化int camera_fd = camera_init("/dev/video0");if (camera_fd < 0){printf("camera init failed\n");return -1;}printf("camera_init success\n");// 服务器搭建完毕,保证服务器不停while (1){struct sockaddr_in c_addr;socklen_t c_addrlen = sizeof(c_addr);int conn_fd = accept(sockfd, (struct sockaddr *)&c_addr, &c_addrlen);if (conn_fd < 0){perror("accept");continue;}printf("client connect success! conn_fd:%d\n", conn_fd);// 开启摄像头----------->摄像头开始获取数据if (camera_start(camera_fd) < 0){printf("camera start failed\n");return -1;}// 连接成功,保证服务程序持续运行while (1){// 服务程序--->发送视频信息// 采集(获取)一帧图像char *pic_buf = NULL; // 定义存放图像数据的指针int length = 0;       // 定义保存图像大小的变量if (camera_get(camera_fd, &pic_buf, &length) < 0){printf("camera get failed\n");continue;}// 1.先发送图像的大小char len[8] = {0};sprintf(len, "%d", length);write(conn_fd, len, 8);// 2.发送图像的数据write(conn_fd, pic_buf, length);// 清除存放图像的缓冲区if (camera_input(camera_fd) < 0){printf("camera_input close failed\n");continue;}}}// 摄像头停止工作camera_stop(camera_fd);// 关闭文件描述符close(camera_fd);// 关闭通信的套接字close(sockfd);return 0;
}

以上服务器代码中的第55行中,由于设备的不同,我们需要进行更换,如果以上代码出现摄像头无法显示的问题,将/dev/video0修改为dev/video1,即可解决。

接下来编译这个服务器文件,使用gcc来编译

gcc server.c -o app -L ./ -lcamera
其中lcamera是摄像头的一些驱动库
  1. 启动服务器
    在这里插入图片描述
    这即是服务器启动成功之后的界面,如若启动失败,在评论区留下错误原因。

三、客户端的搭建

  1. 创建项目

打开我们的QT软件,创建一个qt项目,具体如何创建可参考这个文章https://blog.csdn.net/hujiahangdewa/article/details/143915238?spm=1001.2014.3001.5501

我们需要在项目文件的.pro文件中添加以下模块,这里面含有tcp/ip协议的构造函数

QT       += network

2.设计ui界面
点击左侧的widget.ui即可进入到ui界面的设计
从左侧的控件栏中拖出三个按钮(Push Button),根据需要可以进行更名如下:
在这里插入图片描述
那我们用什么来显示摄像头传输给我们的图像数据呢?---------使用label或者TextEdit
这里我们就使用label来显示我们的图像数据
在这里插入图片描述
我们还需要两个文本框来输入我们服务器的IP地址和端口号
在控件栏中拖出两个LineEdit即可,如下
在这里插入图片描述

ui界面的简单布局就是这样,美化的事情可以后期再做。
接下来我们要理解一个很重要的一个QT的核心理念就是----信号与槽
当我们点击登录按钮就是一个鼠标的点击事件。

  1. 按钮槽函数的设计
    (1)登录按钮的槽函数
    我们先选中登录按钮,右键,转到槽,在弹出的提示框中选择clicked()
void Widget::on_pushButton_clicked()
{QString IP=ui->lineEdit->text(); //获取IP地址int PORT=ui->lineEdit_2->text().toInt(); //获取端口号client->connectToHost(IP,PORT);//连接到服务器,前提是服务器是启动状态
}

接下来就是当我们登录成功之后,在label框中实时显示我们摄像头拍摄的数据
我们来到widget.cpp这个文件中,新建一个recv函数

void Widget::recv()
{static int flag=0;//第一次读取图像的大小//第二次读取图像的数据if(flag==0){//判断数据是否有效if(client->bytesAvailable()<8){return;}length = client->read(8).toInt();flag=1;}else if(flag==1){//判断数据是否有效if(client->bytesAvailable()<length)//说明图片没有传完{return;}pic = client->read(length);QPixmap pix;//定义一个图片类型变量pix.loadFromData(pic);//显示图像ui->label_3->setPixmap(pix);ui->label_3->setScaledContents(true);flag=0;}
}

然后我们需要在Widget的构造函数中进行信号和槽的绑定

//实例化客户端对象,通信协议client=new QTcpSocket;
//接收信号与接收槽函数的绑定//信号对象       信号    槽函数对象    对象connect(client, &QTcpSocket::readyRead, this, &Widget::recv);

同时启动服务器和客户端,在客户端输入服务器的IP和端口号,登陆成功之后,我们的label框中会显示摄像头拍摄到的数据。如下
在这里插入图片描述
(2)注册人脸信息按钮的槽函数

//人脸信息的注册
void Widget::on_pushButton_3_clicked()
{QPixmap pix;//定义一个图片类型变量pix.loadFromData(pic);//显示图像ui->label_4->setPixmap(pix);ui->label_4->setScaledContents(true);//上传的人脸信息QImage image;image.loadFromData(pic);//获取用户的组QString group_id = ui->lineEdit_3->text();//获取用户的IDQString user_id = ui->lineEdit_4->text();//进行人脸信息的注册AI->insert_user(image,group_id,user_id);}

(3)打卡按钮的槽函数

//打卡的槽函数
void Widget::on_pushButton_2_clicked()
{QPixmap pix;//定义一个图片类型变量pix.loadFromData(pic);//显示图像ui->label_4->setPixmap(pix);ui->label_4->setScaledContents(true);//上传的人脸信息QImage image;image.loadFromData(pic);//获取用户的组QString group_id = ui->lineEdit_3->text();//进行人脸检测AI->search_face(image,group_id);}
//绑定信号与槽//1.绑定识别成功的信号与槽connect(AI, &face::recv_nub, this, &Widget::face_success);
//人脸识别成功的槽函数
void Widget::face_success(QString user_id,double number)
{QString data = "打卡成功,欢迎" + user_id +"业主回家!"+"  "+"相似度为:"+QString::number(number);ui->textEdit->setText(data);}

四、人脸识别库的申请

接下来我们将教大家如何申请
首先进入到百度AI的控制台
https://console.bce.baidu.com/#/index/overview
在这里插入图片描述
在这个界面中,在人工智能的那一列找到人脸识别,点击应用列表,点击创建应用,根据提示完成创建。然后在返回到应用列表界面,
在这里插入图片描述
这里的API KEY和Secret Key很重要,是我们调用百度ai的密钥

返回到我们的qt软件
来到widget.cpp,在widget的构造函数中初始化百度ai,以及输入密钥

//实例化一个百度ai对象AI = new face("API_KEY","SECRET_KEY");   //API_KEY  SECRET_KEY

五、基于人脸识别库的识别判断

  1. 识别失败
  2. 识别成功
    //绑定信号与槽//1.绑定识别成功的信号与槽connect(AI, &face::recv_nub, this, &Widget::face_success);//2.绑定识别失败的信号与槽connect(AI, &face::recv_dis, this, &Widget::face_failure); //连接人脸识别失败信号到新的槽函数connect(AI, &face::recv_error_msg, this, &Widget::showErrorMsg); // 连接接收错误信息信号到显示错误信息的槽函数
//人脸识别成功的槽函数
void Widget::face_success(QString user_id,double number)
{QString data = "打卡成功,欢迎" + user_id +"业主回家!"+"  "+"相似度为:"+QString::number(number);ui->textEdit->setText(data);
}
void Widget::face_failure()
{QMessageBox::warning(this, "打卡失败", "人脸识别未通过,请重新尝试打卡。");
}
//显示错误信息的槽函数,弹出提示框显示具体错误消息
void Widget::showErrorMsg(QString errorMsg)
{QMessageBox::critical(this, "错误", "发生错误:" + errorMsg);
}

六、QT人脸识别----调用百度ai接口

我们注册的人脸信息将会保存在百度AI的人脸库中,每隔一个月会消除一次。
以下代码就是调用这个接口的具体实现

#ifndef FACE_H
#define FACE_H#include <QObject>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QImage>
#include <QBuffer>
#include <QDebug>
#include <QPixmap>class face : public QObject
{Q_OBJECT
public:explicit face(QObject *parent = nullptr);//构造face类,需要传递api_key值和secret_keyface(QString,QString);/********************************************************************************************** 进行人脸库搜索* 参数说明:*  1.图像内容为Qimage类型*  2.查询的用户组*********************************************************************************************/void search_face(QImage,QString);/********************************************************************************************** 添加用户信息,即实现用户人脸注册,当用户存在时添加用户图片,用户不存在添加用户和图片* 参数说明:*  1.图像内容为Qimage类型*  2.添加的用户组*  3.添加到的用户名id*********************************************************************************************/void insert_user(QImage,QString,QString);/********************************************************************************************** 添加用户组* 参数说明:*  添加的用户*********************************************************************************************/void insert_group(QString);/**********************************************************************************************获取access_token值* api_key和secret_key来自于构造该对象时传的参数*********************************************************************************************/void get_access_token();signals:/********************************************************************************************** 该对象的信号,触发该信号返回人脸搜索的用户名id和对比度得分* 触发条件,人脸对比与用户信息阈值超过80则触发*********************************************************************************************/void recv_nub(QString,double);/********************************************************************************************** 触发条件,人脸对比与用户信息阈值低于80则触发*********************************************************************************************/void recv_dis();//用于返回错误码的信号,该信号触发返回错误信息void recv_error_msg(QString);public slots://接收由networkaccessmanager发起的网络请求的网络返回数据,并解析void recv_json(QNetworkReply*);private:QNetworkAccessManager *my_access_manager;QString api_key;QString secret_key;QString access_token;QString user_id;double score;
};#endif // FACE_H
#include "face.h"face::face(QObject *parent) : QObject(parent)
{}face::face(QString ak,QString sk)
{api_key = ak;secret_key = sk;//实例化网络请求管理工具my_access_manager = new QNetworkAccessManager;//关联信号与槽connect(my_access_manager,SIGNAL(finished(QNetworkReply*)),this,SLOT(recv_json(QNetworkReply*)));get_access_token();}
//获取access_token值,发起网络请求
void face::get_access_token()
{QNetworkRequest req;req.setUrl(QUrl(QString("https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=%0&client_secret=%1").arg(api_key).arg(secret_key)));req.setHeader(QNetworkRequest::ContentTypeHeader,"Content-Type:application/json");QByteArray buf;my_access_manager->post(req,buf);
}
//发起人脸检测的网络请求
void face::search_face(QImage image,QString group_id)
{//将接收到的image类型转化为qpixmap类QPixmap pic = QPixmap::fromImage(image);//存储图像数据到字节数组内QByteArray buf;QBuffer b(&buf);b.open(QIODevice::ReadWrite);pic.save(&b,"jpg");b.close();//封装百度api请求需要的json格式类型数据QJsonObject obj;//图像数据格式要求base64格式obj.insert("image",QString(buf.toBase64()));obj.insert("image_type","BASE64");obj.insert("group_id_list",group_id);//实例化网络请求QNetworkRequest req;//表明网络请求发起的请求地址req.setUrl(QUrl(QString("https://aip.baidubce.com/rest/2.0/face/v3/search?access_token=%0").arg(access_token)));//设置网络请求头req.setHeader(QNetworkRequest::ContentTypeHeader,"Content-Type:application/json");//发起post网络请求my_access_manager->post(req,QJsonDocument(obj).toJson());
}
//发起添加用户的网络请求
void face::insert_user(QImage image,QString group_id,QString user_id)
{QPixmap pic = QPixmap::fromImage(image);QByteArray buf;QBuffer b(&buf);b.open(QIODevice::ReadWrite);pic.save(&b,"jpg");b.close();//封装数据内添加需要增加到的用户组,用户id以及该用户的图像数据QJsonObject obj;obj.insert("image",QString(buf.toBase64()));obj.insert("image_type","BASE64");obj.insert("group_id",group_id);obj.insert("user_id",user_id);obj.insert("action_type","APPEND");QNetworkRequest req;req.setUrl(QUrl(QString("https://aip.baidubce.com/rest/2.0/face/v3/faceset/user/add?access_token=%0").arg(access_token)));req.setHeader(QNetworkRequest::ContentTypeHeader,"Content-Type:application/json");my_access_manager->post(req,QJsonDocument(obj).toJson());
}
//发起添加用户组的网络请求
void face::insert_group(QString group_id)
{//封装组idQJsonObject obj;obj.insert("group_id",group_id);QNetworkRequest req;req.setUrl(QUrl(QString("https://aip.baidubce.com/rest/2.0/face/v3/faceset/group/add?access_token=%0").arg(access_token)));req.setHeader(QNetworkRequest::ContentTypeHeader,"Content-Type:application/json");my_access_manager->post(req,QJsonDocument(obj).toJson());
}
//解析接收到的网络请求的返回数据
void face::recv_json(QNetworkReply *rep)
{//读取网络请求后的返回数据QByteArray replay = rep->readAll();//将数据转化为json文档QJsonDocument doc = QJsonDocument::fromJson(replay);if(doc.isObject()){//将json文档转化为json对象QJsonObject replay_obj = doc.object();//判定json数据内所包含的字样,并获取字样对应的数据值if(replay_obj.contains("result")){QJsonValue val = replay_obj.value("result");if(val.isObject()){QJsonObject replay_obj = val.toObject();if(replay_obj.contains("user_list")){QJsonValue val = replay_obj.value("user_list");if(val.isArray()){QJsonArray arr = val.toArray();QJsonValue val = arr.at(0);if(val.isObject()){QJsonObject replay_obj = val.toObject();if(replay_obj.contains("user_id"))//解析用户id{user_id = replay_obj.value("user_id").toString();}if(replay_obj.contains("score"))//解析人脸比对的阈值{score = replay_obj.value("score").toDouble();if(score > 80)//比对得分超过80认为是同一个人,可以触发信号返回用户id和对比值{qDebug()<<score;emit this->recv_nub(user_id,score);}else{emit this->recv_dis();}}}}}}}//解析access_token值if(replay_obj.contains("access_token")){access_token = replay_obj.value("access_token").toString();}//解析错误码if(replay_obj.contains("error_msg")){QString error_msg = replay_obj.value("error_msg").toString();if(error_msg!="SUCCESS"){//触发信号返回错误信息emit this->recv_error_msg(error_msg);}}//解析access_token值的错误码else if(replay_obj.contains("error_description")){QString error_description = replay_obj.value("error_description").toString();emit this->recv_error_msg(error_description);}}
}

完成以上之后,我们的项目基本完成,剩下的就是美化工作,我们可以根据自己的喜好来进行美化。

七、如何在Qt中添加图片素材

在这里插入图片描述
在这个界面中选择Qt,然后选择Qt Resource File
在这里插入图片描述

取一个名字,存放位置建议默认,也可根据情况而修改,接下来的设置默认就可。
在这里插入图片描述
完成以上步骤之后,会出现这样一个界面,点击添加前缀
在这里插入图片描述

在这里插入图片描述
建议是设置成以下这样
在这里插入图片描述
然后点击添加文件,我们就可以自由的添加图片文件了。我们的文件列表中会出现一个.prc的资源文件

八、项目总结

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/66628.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

人工智能在数字化转型中的角色:从数据分析到智能决策

引言 在数字化转型浪潮中&#xff0c;人工智能&#xff08;AI&#xff09;正迅速崛起&#xff0c;成为推动企业创新和变革的关键力量。面对日益复杂的市场环境和激烈的行业竞争&#xff0c;企业亟需借助技术手段提高运营效率、优化决策过程&#xff0c;并增强市场竞争力。而AI…

react install

react 安装 React 是一个用于构建用户界面的 JavaScript 库。以下是安装 React 的步骤&#xff1a; 使用 Create React App Create React App 是一个官方支持的命令行工具&#xff0c;用于快速搭建 React 应用。 安装 Node.js 和 npm 确保你的计算机上安装了 Node.js 和 npm…

Android系统开发(二十):字体活起来,安卓自定义字体改造指南

为什么要写这篇文章&#xff1f; 你是否厌倦了千篇一律的安卓默认字体&#xff1f;想让你的设备从“乏味的配角”变成“炫酷的主角”&#xff1f;好消息&#xff01;从Android 12到Android 15&#xff0c;自定义字体变得更简单、更强大。尤其是表情字体的更新&#xff0c;不仅…

将 AzureBlob 的日志通过 Azure Event Hubs 发给 Elasticsearch(3.纯python的实惠版)

前情&#xff1a; 将 AzureBlob 的日志通过 Azure Event Hubs 发给 Elasticsearch&#xff08;1.标准版&#xff09;-CSDN博客 将 AzureBlob 的日志通过 Azure Event Hubs 发给 Elasticsearch&#xff08;2.换掉付费的Event Hubs&#xff09;-CSDN博客 python脚本实现 厉害的…

python学opencv|读取图像(四十)掩模:三通道图像的局部覆盖

【1】引言 前序学习了使用numpy创建单通道的灰色图像&#xff0c;并对灰色图像的局部进行了颜色更改&#xff0c;相关链接为&#xff1a; python学opencv|读取图像&#xff08;九&#xff09;用numpy创建黑白相间灰度图_numpy生成全黑图片-CSDN博客 之后又学习了使用numpy创…

Linux系统常用指令

查找文件 find / -name "<文件名>" 2>/dev/null //遍历系统查找指定文件名文件ls -l | grep "<文件名>" //列出当前目录下有关文件名的文件find -name sw_sfp_alarm_cfg.xml //查找文件名对应路径 切换目录 编辑文件 vi <文件…

【Unity】ScrollViewContent适配问题(Contentsizefilter不刷新、ContentSizeFilter失效问题)

最近做了一个项目&#xff0c;菜单栏读取数据后自动生成&#xff0c;结果用到了双重布局 父物体 尝试了很多方式&#xff0c;也看过很多大佬的文章&#xff0c;后来自己琢磨了一下&#xff0c;当子物体组件自动生成之后&#xff0c;使用以下以下代码效果会好一些&#xff1a; …

AI辅助医学统计分析APP

AI辅助医学统计分析APP 医学统计分析的困难点在于开始阶段分析的规划和得出分析结果之后分析结果的解释&#xff0c;前者之所以困难是因为分析方法繁多又有不同的使用条件&#xff0c;后者则是因为结果中术语较多&#xff0c;且各种分析方法术语又有不同&#xff0c;非统计专业…

[STM32 HAL库]串口中断编程思路

一、前言 最近在准备蓝桥杯比赛&#xff08;嵌入式赛道&#xff09;&#xff0c;研究了以下串口空闲中断DMA接收不定长的数据&#xff0c;感觉这个方法的接收效率很高&#xff0c;十分好用。方法配置都成功了&#xff0c;但是有一个点需要进行考虑&#xff0c;就是一般我们需要…

AutoSar架构学习笔记

1.AUTOSAR&#xff08;Automotive Open System Architecture&#xff0c;汽车开放系统架构&#xff09;是一个针对汽车行业的软件架构标准&#xff0c;旨在提升汽车电子系统的模块化、可扩展性、可重用性和互操作性。AUTOSAR的目标是为汽车电子控制单元&#xff08;ECU&#xf…

算法竞赛之差分进阶——等差数列差分 python

目录 前置知识进入正题实战演练 前置知识 给定区间 [ l, r ]&#xff0c;让我们把数组中的[ l, r ] 区间中的每一个数加上c,即 a[ l ] c , a[ l 1 ] c , a[ l 2] c , a[ r ] c; 怎么做&#xff1f;很简单&#xff0c;差分一下即可 还不会的小伙伴点此进入学习 进入正题 …

TDengine 做 Apache SuperSet 数据源

‌Apache Superset‌ 是一个现代的企业级商业智能&#xff08;BI&#xff09;Web 应用程序&#xff0c;主要用于数据探索和可视化。它由 Apache 软件基金会支持&#xff0c;是一个开源项目&#xff0c;它拥有活跃的社区和丰富的生态系统。Apache Superset 提供了直观的用户界面…

金融场景 PB 级大规模日志平台:中信银行信用卡中心从 Elasticsearch 到 Apache Doris 的先进实践

导读&#xff1a;中信银行信用卡中心每日新增日志数据 140 亿条&#xff08;80TB&#xff09;&#xff0c;全量归档日志量超 40PB&#xff0c;早期基于 Elasticsearch 构建的日志云平台&#xff0c;面临存储成本高、实时写入性能差、文本检索慢以及日志分析能力不足等问题。因此…

虚幻商城 Fab 免费资产自动化入库

文章目录 一、背景二、实现效果展示三、实现自动化入库一、背景 上一次写了个这篇文章 虚幻商城 Quixel 免费资产一键入库,根据这个构想,便决定将范围扩大,使 Fab 商城的所有的免费资产自动化入库,是所有!所有! 上一篇文章是根据下图这部分资产一键入库: 而这篇文章则…

游戏为什么失败?回顾某平庸游戏

1、上周玩了一个老鼠为主角的游戏&#xff0c;某平台喜1送的&#xff0c; 下载了很久而一直没空玩&#xff0c;大约1G&#xff0c;为了清硬盘空间而玩。 也是为了拔掉心中的一根刺&#xff0c;下载了而老是不玩总感觉不舒服。 2、老鼠造型比较写实&#xff0c;看上去就有些讨…

亲测有效!如何快速实现 PostgreSQL 数据迁移到 时序数据库TDengine

小T导读&#xff1a;本篇文章是“2024&#xff0c;我想和 TDengine 谈谈”征文活动的优秀投稿之一&#xff0c;作者从数据库运维的角度出发&#xff0c;分享了利用 TDengine Cloud 提供的迁移工具&#xff0c;从 PostgreSQL 数据库到 TDengine 进行数据迁移的完整实践过程。文章…

C#,入门教程(01)—— Visual Studio 2022 免费安装的详细图文与动画教程

通过本课程的学习&#xff0c;你可以掌握C#编程的重点&#xff0c;享受编程的乐趣。 在本课程之前&#xff0c;你无需具备任何C#的基础知识&#xff0c;只要能操作电脑即可。 不过&#xff0c;希望你的数学不是体育老师教的。好的程序是数理化的实现与模拟。没有较好的数学基础…

Linux探秘坊-------3.开发工具详解(2)

1.动静态库和动静态链接&#xff08;操作&#xff09; 静态库是指编译链接时,把库⽂件的代码全部加⼊到可执⾏⽂件中,因此⽣成的⽂件 ⽐较⼤,但在运⾏时也就不再需要库⽂件了。其后缀名⼀般为“.a” 动态库与之相反,在编译链接时并 没有把库⽂件的代码加⼊到可执⾏⽂件中 ,⽽…

电脑开机出现Bitlock怎么办

目录 1.前言 2.产生原因&#xff1a; 1.系统异常关机 2.系统更新错误 3.硬件更换 4.CMOS电池问题 5.出厂设置 6.意外情况 3.解锁步骤&#xff1a; 3.1&#xff1a;记住密钥ID&#xff08;前6位&#xff09; 3.2&#xff1a;打开aka.ms/myrecoverykey网址 3.3&#…

Avalonia系列文章之小试牛刀

最近有朋友反馈&#xff0c;能否分享一下Avalonia相关的文章&#xff0c;于是就抽空学习了一下&#xff0c;发现Avalonia真的是一款非常不错的UI框架&#xff0c;值得花时间认真学习一下&#xff0c;于是边学习边记录&#xff0c;整理成文&#xff0c;分享给大家&#xff0c;希…