基于STM32MP157与OpenCV的嵌入式Linux人脸识别系统开发设计流程

一、项目概述

1.1 项目目标和用途

本项目旨在基于嵌入式STM32MP157开发板,搭建一个系统软硬件开发平台,以Linux操作系统为基础,研发一个完整的人脸识别系统。该系统可以用于安防监控、考勤管理等应用场景,实现对人脸的实时检测与识别。

1.2 技术栈关键词

  • 嵌入式开发

  • STM32MP157

  • Linux

  • Qt

  • OpenCV

  • V4L2

  • AdaBoost

  • LBP特征

二、系统架构

2.1 设计系统架构

本项目系统架构分为宿主机与目标机两部分,宿主机用于开发和调试,目标机则负责运行人脸识别功能。以下是系统架构的设计思路:

  • 宿主机:运行Linux操作系统,负责Qt环境搭建与OpenCV库的编译和移植。

  • 目标机:运行嵌入式Linux,负责人脸识别的实时处理。

2.2 选择合适的单片机和技术栈

  • 单片机:STM32MP157

  • 通信协议:使用串口和网络协议进行宿主机与目标机的通信。

  • 传感器:USB摄像头(支持V4L2)

  • 无线通信模块:Wi-Fi模块(用于数据传输)

2.3 系统架构图

开发
编译
调试
图像采集
人脸识别
宿主机
Qt环境
OpenCV库
目标机
USB摄像头
识别结果

三、环境搭建和注意事项

3.1 开发环境搭建

  1. 宿主机环境安装:
  • 安装Ubuntu 20.04或更高版本的Linux操作系统。

  • 使用apt命令安装Qt和OpenCV:

    sudo apt-get install qt5-default libopencv-dev
    
  1. 目标机环境安装:
  • 下载源码并编译:

  • 在STM32MP157上安装Linux系统(建议使用Yocto)。

  • 编译并安装Qt和OpenCV:

    git clone https://code.qt.io/qt/qt5.git
    git clone https://github.com/opencv/opencv.git
    

3.2 注意事项

  • 确保开发板与宿主机之间的网络连接正常。

  • 在编译过程中,注意依赖库的版本兼容性。

四、代码实现过程

本节将详细介绍人脸识别系统中各功能模块的实现过程,包括图像采集模块、基于AdaBoost的人脸检测模块、人脸图像预处理模块和基于LBP特征的人脸识别模块。每个模块的实现将提供代码示例、逻辑解释和时序图,以便清晰展示各模块之间的连接关系。

4.1 图像采集模块(基于V4L2)

4.1.1 模块概述

该模块负责从USB摄像头实时采集图像数据,并将获取的图像传递给后续的人脸检测模块。我们使用OpenCV库来简化图像处理过程,并通过Video4Linux2(V4L2)接口访问摄像头。

4.1.2 代码实现
#include <opencv2/opencv.hpp>
#include <iostream>class ImageCapture {
public:ImageCapture() {// 构造函数,初始化摄像头cap.open(0); // 0表示默认摄像头if (!cap.isOpened()) {std::cerr << "Error: Could not open camera." << std::endl;exit(EXIT_FAILURE);}}cv::Mat getFrame() {cv::Mat frame;cap >> frame; // 从摄像头读取图像return frame;}private:cv::VideoCapture cap; // OpenCV的视频捕获对象
};// 使用示例
int main() {ImageCapture imageCapture;while (true) {cv::Mat frame = imageCapture.getFrame(); // 获取图像cv::imshow("Captured Image", frame); // 显示图像if (cv::waitKey(30) >= 0) break; // 按任意键退出}return 0;
}
4.1.3 逻辑解释
  1. 初始化摄像头:在ImageCapture类的构造函数中,通过cv::VideoCapture对象打开默认摄像头(设备编号为0)。如果摄像头打开失败,程序会输出错误信息并终止运行。

  2. 获取图像:getFrame方法调用cap >> frame从摄像头获取当前帧图像并返回该图像。这一过程是实时进行的,确保系统能够持续地接收图像数据。

  3. 图像显示:在主函数中,使用cv::imshow函数实时显示捕获的图像。当用户按下任意键时,循环将结束,程序将退出。

4.1.4 时序图
User Camera OpenCV 请求图像 发送图像 显示图像 User Camera OpenCV

4.2 人脸检测模块(基于AdaBoost)

4.2.1 模块概述

本模块利用OpenCV提供的Haar特征分类器基于AdaBoost算法对图像中的人脸进行检测。该模块接收图像输入,输出检测到的人脸区域,以便后续处理。

4.2.2 代码实现
#include <opencv2/opencv.hpp>
#include <iostream>class FaceDetector {
public:FaceDetector() {// 加载Haar特征分类器if (!faceCascade.load("haarcascade_frontalface_alt.xml")) {std::cerr << "Error: Could not load classifier." << std::endl;exit(EXIT_FAILURE); // 如果加载失败,则终止程序}}std::vector<cv::Rect> detectFaces(const cv::Mat& frame) {std::vector<cv::Rect> faces;// 使用Haar分类器检测人脸faceCascade.detectMultiScale(frame, faces, 1.1, 3, 0, cv::Size(30, 30));return faces; // 返回检测到的人脸矩形列表}private:cv::CascadeClassifier faceCascade; // 分类器对象
};// 使用示例
int main() {cv::VideoCapture cap(0); // 打开默认摄像头if (!cap.isOpened()) {std::cerr << "Error: Could not open camera." << std::endl;return -1; // 如果打开摄像头失败,则退出程序}FaceDetector faceDetector; // 创建人脸检测器while (true) {cv::Mat frame;cap >> frame; // 从摄像头读取图像if (frame.empty()) {std::cerr << "Error: Empty frame." << std::endl;break; // 如果读取到空图像,则跳出循环}std::vector<cv::Rect> faces = faceDetector.detectFaces(frame); // 检测人脸// 绘制检测到的人脸矩形框for (const auto& face : faces) {cv::rectangle(frame, face, cv::Scalar(255, 0, 0), 2); // 用蓝色矩形框标出人脸}cv::imshow("Face Detection", frame); // 显示检测结果if (cv::waitKey(30) >= 0) break; // 按任意键退出}return 0;
}
4.2.3 逻辑解释
  1. 加载分类器:

    • FaceDetector类的构造函数中,调用faceCascade.load方法加载预训练的Haar特征分类器文件haarcascade_frontalface_alt.xml。如果加载失败,程序将输出错误信息并终止。这一过程是确保人脸检测模块能够正常工作的前提。
  2. 人脸检测:

    • frame:输入的图像,类型为cv::Mat

    • faces:输出参数,返回检测到的人脸区域,类型为std::vector<cv::Rect>

    • scaleFactor:每次图像尺寸减小的比例(1.1表示每次缩小10%),有助于检测不同大小的人脸。

    • minNeighbors:检测到的人脸必须至少有多少个邻近矩形(设置为3,以减少错误检测)。

    • flags:一般设置为0,表示使用默认行为。

    • minSize:检测人脸的最小尺寸(30x30像素),用于排除过小的检测区域。

    • detectFaces方法通过调用faceCascade.detectMultiScale进行人脸检测。该方法的参数如下:

  3. 绘制人脸矩形:

    • 在主函数中,使用循环从摄像头获取图像,并调用detectFaces方法进行人脸检测。对于每个检测到的人脸,使用cv::rectangle在图像上绘制矩形框,框的颜色为蓝色(cv::Scalar(255, 0, 0)),线条宽度为2像素。最后,使用cv::imshow显示。

4.2.4 时序图

以下是人脸检测模块的时序图,展示了模块之间的交互和数据流:

User Camera OpenCV FaceDetector 请求图像 发送图像 传递图像 返回检测到的人脸 显示图像与人脸框 User Camera OpenCV FaceDetector

4.3 人脸图像预处理模块

4.3.1 模块概述

在检测到人脸后,预处理模块对获取的人脸图像进行处理,以提高后续识别的准确性。常见的预处理操作包括灰度化、直方图均衡化和归一化等。这些操作有助于增强人脸特征,减小光照变化和肤色差异的影响。

4.3.2 代码实现
#include <opencv2/opencv.hpp>class FacePreprocessor {
public:cv::Mat preprocess(const cv::Mat& face) {cv::Mat gray, equalized;// 将人脸图像转换为灰度图cv::cvtColor(face, gray, cv::COLOR_BGR2GRAY);// 直方图均衡化cv::equalizeHist(gray, equalized);// 归一化到0-1范围cv::Mat normalized;equalized.convertTo(normalized, CV_32F, 1.0 / 255.0);return normalized; // 返回处理后的图像}
};// 使用示例
int main() {cv::VideoCapture cap(0); // 打开默认摄像头if (!cap.isOpened()) {std::cerr << "Error: Could not open camera." << std::endl;return -1; // 如果打开摄像头失败,则退出程序}FaceDetector faceDetector; // 创建人脸检测器FacePreprocessor facePreprocessor; // 创建人脸预处理器while (true) {cv::Mat frame;cap >> frame; // 从摄像头读取图像if (frame.empty()) {std::cerr << "Error: Empty frame." << std::endl;break; // 如果读取到空图像,则跳出循环}std::vector<cv::Rect> faces = faceDetector.detectFaces(frame); // 检测人脸// 处理每个检测到的人脸for (const auto& face : faces) {cv::Mat detectedFace = frame(face); // 提取人脸区域cv::Mat processedFace = facePreprocessor.preprocess(detectedFace); // 预处理人脸图像// 显示处理后的人脸图像cv::imshow("Processed Face", processedFace);}cv::imshow("Face Detection", frame); // 显示检测结果if (cv::waitKey(30) >= 0) break; // 按任意键退出}return 0;
}
4.3.3 逻辑解释
  1. 灰度化:

    • preprocess方法中,首先使用cv::cvtColor将输入的人脸图像转换为灰度图像。灰度化有助于减少数据处理的复杂性,并强调人脸的结构信息。
  2. 直方图均衡化:

    • 接着,调用cv::equalizeHist对灰度图像进行直方图均衡化。该操作可以增强图像的对比度,使得人脸特征更加明显,从而提高后续识别的准确性。
  3. 归一化:

    • 最后,将均衡化后的图像转换为浮点型,并归一化到0-1的范围,便于后续的特征提取和分类。这一过程通过convertTo函数完成,设置转换到CV_32F类型并乘以1.0 / 255.0

4.3.4 时序图

以下是人脸图像预处理模块的时序图,展示输入和输出的关系:

User FaceDetector Preprocessor 传递人脸图像 处理人脸图像 返回处理后的人脸图像 显示处理后的人脸图像 User FaceDetector Preprocessor

4.4 人脸识别模块(基于LBP特征)

4.4.1 模块概述

该模块负责从预处理后的图像中提取人脸特征并进行识别。在本项目中,我们采用局部二值模式(Local Binary Pattern, LBP)作为特征描述符,并使用简单的分类器(如K近邻算法)进行识别。LBP是一种纹理特征提取方法,通过比较每个像素与其周围像素的灰度值,生成二进制模式。

4.4.2 代码实现
#include <opencv2/opencv.hpp>
#include <opencv2/ml.hpp> // 引入机器学习模块
#include <iostream>class FaceRecognizer {
public:FaceRecognizer() {// 初始化K近邻分类器model = cv::ml::KNearest::create();}void train(const std::vector<cv::Mat>& images, const std::vector<int>& labels) {// 准备训练数据cv::Mat trainingData;for (const auto& img : images) {cv::Mat lbpImage = extractLBP(img); // 提取LBP特征trainingData.push_back(lbpImage.reshape(1, 1)); // 将图像展平并添加到训练数据}model->train(trainingData, cv::ml::ROW_SAMPLE, cv::Mat(labels)); // 训练模型}int predict(const cv::Mat& face) {cv::Mat lbpImage = extractLBP(face); // 提取特征int response = static_cast<int>(model->predict(lbpImage.reshape(1, 1))); // 预测类别return response; // 返回识别结果}private:cv::Ptr<cv::ml::KNearest> model; // K近邻分类器cv::Mat extractLBP(const cv::Mat& image) {// LBP特征提取实现cv::Mat lbpImage(image.size(), CV_8UC1, cv::Scalar(0)); // 创建LBP图像for (int i = 1; i < image.rows - 1; ++i) {for (int j = 1; j < image.cols - 1; ++j) {unsigned char center = image.at<uchar>(i, j);unsigned char code = 0;// 计算LBP值code |= (image.at<uchar>(i - 1, j - 1) > center) << 7; // 左上code |= (image.at<uchar>(i - 1, j) > center) << 6;     // 上code |= (image.at<uchar>(i - 1, j + 1) > center) << 5; // 右上code |= (image.at<uchar>(i, j + 1) > center) << 4;     // 右code |= (image.at<uchar>(i + 1, j + 1) > center) << 3; // 右下code |= (image.at<uchar>(i + 1, j) > center) << 2;     // 下code |= (image.at<uchar>(i + 1, j - 1) > center) << 1; // 左下code |= (image.at<uchar>(i, j - 1) > center) << 0;     // 左lbpImage.at<uchar>(i, j) = code; // 存储LBP值}}return lbpImage; // 返回LBP图像}
};// 使用示例
int main() {cv::VideoCapture cap(0); // 打开默认摄像头if (!cap.isOpened()) {std::cerr << "Error: Could not open camera." << std::endl;return -1; // 如果打开摄像头失败,则退出程序}FaceDetector faceDetector; // 创建人脸检测器FacePreprocessor facePreprocessor; // 创建人脸预处理器FaceRecognizer faceRecognizer; // 创建人脸识别器// 假设我们已经准备好训练数据std::vector<cv::Mat> trainingImages; // 存储训练图像std::vector<int> labels; // 存储标签// 假设我们已经准备好训练数据// 这里可以使用相应的代码加载训练图像和标签// 例如:// trainingImages.push_back(cv::imread("path/to/image1.jpg", cv::IMREAD_GRAYSCALE));// labels.push_back(1); // 标签1代表某个身份// 继续添加更多训练数据...// 开始训练模型faceRecognizer.train(trainingImages, labels); // 训练模型while (true) {cv::Mat frame;cap >> frame; // 从摄像头读取图像if (frame.empty()) {std::cerr << "Error: Empty frame." << std::endl;break; // 如果读取到空图像,则跳出循环}std::vector<cv::Rect> faces = faceDetector.detectFaces(frame); // 检测人脸// 处理每个检测到的人脸for (const auto& face : faces) {cv::Mat detectedFace = frame(face); // 提取人脸区域cv::Mat processedFace = facePreprocessor.preprocess(detectedFace); // 预处理人脸图像int label = faceRecognizer.predict(processedFace); // 识别人脸std::string labelText = "Label: " + std::to_string(label);// 在图像上标注识别结果cv::putText(frame, labelText, cv::Point(face.x, face.y - 10), cv::FONT_HERSHEY_SIMPLEX, 0.8, cv::Scalar(0, 255, 0), 2);cv::rectangle(frame, face, cv::Scalar(255, 0, 0), 2); // 用蓝色矩形框标出人脸}cv::imshow("Face Recognition", frame); // 显示检测与识别结果if (cv::waitKey(30) >= 0) break; // 按任意键退出}return 0;
}

4.4.3 逻辑解释

  1. 训练模型:

    • 在主函数中,程序假设已经准备好训练数据,包括训练图像和相应的标签。通过调用faceRecognizer.train(trainingImages, labels)来训练模型。
  2. 实时识别:

    • 在循环中,从摄像头获取图像并进行人脸检测。

    • 对每个检测到的人脸区域,使用facePreprocessor.preprocess方法进行图像预处理,然后调用faceRecognizer.predict(processedFace)进行人脸识别。

    • 识别结果(标签)通过cv::putText在图像上标注,并在检测到的人脸周围绘制矩形框以突出显示。

  3. 显示结果:

    • 使用cv::imshow函数实时显示检测和识别结果,直到用户按下任意键结束程序。

4.4.4 时序图

下面是人脸识别模块的时序图,展示了各模块之间的交互和数据流。

User Camera FaceDetector FacePreprocessor FaceRecognizer 请求图像 发送图像 提取人脸区域 返回处理后的人脸图像 显示检测到的人脸 传递处理后的人脸图像 返回识别结果 显示识别结果 User Camera FaceDetector FacePreprocessor FaceRecognizer

五、项目总结

本项目基于嵌入式STM32MP157开发板,成功搭建了一个以Linux操作系统为基础的人脸识别系统,形成了一个合理有效的软硬件开发平台。项目的实现过程包括多个关键模块的设计与开发,具体包括以下几个方面:

5.1 系统架构

系统架构分为宿主机和目标机两部分,宿主机用于开发与调试,目标机则负责实时运行人脸识别功能。宿主机环境中安装了Qt和OpenCV库,并进行了必要的配置,以支持后续的开发工作。同时,目标机运行嵌入式Linux,实现了对人脸图像的采集、检测、预处理和识别。

5.2 功能模块

在项目中实现了四个主要功能模块:

  1. 图像采集模块:

    • 通过USB摄像头实时采集图像,并将图像数据传递给后续处理模块。该模块使用OpenCV库,确保了图像采集的实时性和稳定性。
  2. 人脸检测模块(基于AdaBoost):

    • 利用Haar特征分类器实现对图像中人脸的快速检测。该模块能够有效地识别不同大小和位置的人脸,为后续处理提供了准确的输入。
  3. 人脸图像预处理模块:

    • 对检测到的人脸图像进行灰度化、直方图均衡化和归一化等预处理操作,以提高后续识别的准确性。通过这些处理,减少了光照变化和肤色差异的影响,使得人脸特征更加突出。
  4. 人脸识别模块(基于LBP特征):

    • 使用局部二值模式(LBP)作为特征描述符,并利用K近邻(KNN)分类器进行人脸识别。该模块能够高效、准确地识别出不同身份的人脸,通过实时反馈提高了系统的互动性。

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

E2VPT: An Effective and Efficient Approach for Visual Prompt Tuning

论文汇总 存在的问题 1.以前的提示微调方法那样只关注修改输入&#xff0c;而应该明确地研究在微调过程中改进自注意机制的潜力&#xff0c;并探索参数效率的极限。 2.探索参数效率的极值来减少可调参数的数量? 解决办法 提示嵌入进行transformer中 提示剪枝 Token-wise …

OpenCV_距离变换的图像分割和Watershed算法详解

在学习watershed算法的时候&#xff0c;书写代码总会出现一些错误&#xff1a; 上述代码运行报错&#xff0c;显示OpenCV(4.10.0) Error: Assertion failed (src.type() CV_8UC3 && dst.type() CV_32SC1) in cv::watershed 查找资料&#xff1a;目前已解决 这个错…

CentOS7搭建Hadoop3集群教程

一、集群环境说明 1、用VMware安装3台Centos7虚拟机 2、虚拟机配置&#xff1a;2C&#xff0c;2G内存&#xff0c;50G存储 3、集群架构设计 从表格中&#xff0c;可以看出&#xff0c;Hadoop集群&#xff0c;主要有2个模块服务&#xff0c;一个是HDFS服务&#xff0c;一个是YAR…

wordpress更换域名后用户图片头像不显示

&#x1f3c6;本文收录于《全栈Bug调优(实战版)》专栏&#xff0c;主要记录项目实战过程中所遇到的Bug或因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&am…

【Python报错已解决】AttributeError: ‘DataFrame‘ object has no attribute ‘append‘

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 专栏介绍 在软件开发和日常使用中&#xff0c;BUG是不可避免的。本专栏致力于为广大开发者和技术爱好者提供一个关于BUG解决的经…

基于深度学习的文本情感原因提取研究综述——论文阅读

前言 既然要学习情感分析&#xff0c;那么肯定还要了解情感原因对抽取的发展历程&#xff0c;所以我又搜了一篇研究综述&#xff0c;虽然是2023年发表的&#xff0c;但是里面提及到的历程仅停留到2022年。这篇综述发布在TASLP期刊&#xff0c;是音频、声学、语言信号处理的顶级…

【论文解读系列】用于自监督点云表示的生成变分对比学习

Generative Variational-Contrastive Learning for Self-Supervised Point Cloud Representation | IEEE Transactions on Pattern Analysis and Machine Intelligence (acm.org) 作者&#xff1a;Bohua Wang; Zhiqiang Tian; Aixue Ye; Feng Wen; Shaoyi Du; Yue Gao 摘要 三…

Coggle数据科学 | 科大讯飞AI大赛:玉米雄穗识别挑战赛

本文来源公众号“Coggle数据科学”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;科大讯飞AI大赛&#xff1a;玉米雄穗识别挑战赛 赛题名称&#xff1a;玉米雄穗识别挑战赛 赛题类型&#xff1a;计算机视觉、物体检测 赛题任务&…

LeetCode_sql_day30(1264.页面推荐)

描述 1264.页面推荐 朋友关系列表&#xff1a; Friendship ------------------------ | Column Name | Type | ------------------------ | user1_id | int | | user2_id | int | ------------------------ (user1_id, user2_id) 是这张表具有唯一值的…

HT326 免电感滤波2x20W D类立体声音频功放

特点 输出功率(BTL模式) 2x20W (VDD14.5V,RL4Ω,THDN1%) 单电源系统: 4.5V-18V; 超过90%效率&#xff0c;无需散热器 扩频功能&#xff0c;免电感滤波 模拟差分/单端输入可选 增益:32dB 保护功能:过压/过流/过热/欠压异常&#xff0c;直流检测 和短路保护 无铅无卤封装&#x…

Python画笔案例-054 绘制流光溢彩动画

1、绘制流光溢彩动画 通过 python 的turtle 库绘制 流光溢彩动画&#xff0c;如下图&#xff1a; 2、实现代码 绘制流光溢彩动画&#xff0c;以下为实现代码&#xff1a; """本程序实现流光溢彩的动画效果 """ from turtle import * from color…

流动网红打卡车!苏州金龙海格双层巴士带你体验别样津门津韵

近日&#xff0c;由文化和旅游部主办&#xff0c;天津市文化和旅游局等单位承办的2024中国文化旅游产业博览会在天津拉开帷幕&#xff0c;展会期间&#xff0c;来自全国各地的文旅产品精彩亮相。而在天津交通集团展台&#xff0c;来自苏州金龙海格客车制造的网红双层观光“音乐…

YOLOv8改进 - 注意力篇 - 引入ECA注意力机制

一、本文介绍 作为入门性第一篇&#xff0c;这里介绍了ECA注意力在YOLOv8中的使用。包含ECA原理分析&#xff0c;ECA的代码、ECA的使用方法、以及添加以后的yaml文件及运行记录。 二、ECA原理分析 ECA官方论文地址&#xff1a;ECA文章 ECA的pytorch版代码&#xff1a;ECA的…

Unet改进41:添加gConvBlock(2024最新改进方法)|

本文内容:在不同位置添加gConvBlock 目录 论文简介 1.步骤一 2.步骤二 3.步骤三 4.步骤四 论文简介 图像去雾是低层次视觉中的一个活跃话题,随着深度学习的快速发展,许多图像去雾网络被提出。尽管这些网络的管道运行良好,但改善图像去雾性能的关键机制仍不清楚。因此…

[Simpfun游戏云1]搭建MC Java+基岩互通生存游戏服务器

众所周知&#xff0c;MC有多个客户端&#xff0c;像常见的比如Java Edition和基岩等&#xff0c;这就导致&#xff0c;比如我知道一个超级好玩的JE服务器&#xff0c;但我又想使用基岩版来玩&#xff0c;肯定是不行的&#xff0c;因为通讯协议不一样。 这就有一些人才发明了多…

【linux】4张卡,坏了1张,怎么办?

先禁用这张卡 grub 禁用&#xff0c;防止加载驱动 禁用这张卡的 PCI # 禁用 PCI 设备 0000:b1:00.0 (NVIDIA GPU) ACTION"add", SUBSYSTEM"pci", ATTR{vendor}"0x10de", KERNELS"0000:b1:00.0", RUN"/bin/sh -c echo 0000:b1:00…

javaseday28 IO

IO流 IO流;存储和读取数据的解决方案。 纯文本文件&#xff1a;Windows自带的记事本打开能读懂的文件&#xff0c;word和Excel不是纯文本文件&#xff0c;txt和md是纯文本文件。 小结 IO流体系 FileOutputStream public class Demo1 {public static void main(String[] args)…

Ping32加密利器 vs ipguard,企业数据防护的实战对比

在数字化时代&#xff0c;企业数据的安全防护已成为不可忽视的重要议题。随着数据泄露事件的频发&#xff0c;企业迫切需要采用高效、可靠的数据防泄漏解决方案来保护其敏感信息。Ping32和IP-Guard作为市场上备受瞩目的两款数据保护工具&#xff0c;各自以其独特的功能和优势赢…

深入分析几个难以理解的Comparator源码

1.分析comparing单参数方法 网上很多帖子说实话&#xff0c;不咋地&#xff0c;讲的不细节&#xff0c;抄来抄去&#xff0c;就让我这个大二的垃圾&#xff0c;给大家梳理一下Comparator这几个难以理解public static方法吧。 1.1函数式接口Function 这个函数是使用的函数式编程…

OrCAD使用,快捷键,全选更改封装,导出PCB网表

1 模块名称 2 快捷键使用 H: 镜像水平 V&#xff1a;镜像垂直 R: 旋转 I: 放大 O&#xff1a; 放小 P&#xff1a;放置元器件 W&#xff1a; 步线 B&#xff1a; 总线&#xff08;无电气属性&#xff09; E: 总线连接符&#xff08;和BUS一起用&#xff09…