【阿里云】图像识别 智能分类识别 增加垃圾桶开关盖功能点和OLED显示功能点(二)

一、增加垃圾桶开关盖功能

  • 环境准备

二、PWM 频率的公式
三、pthread_detach分离线程,使其在退出时能够自动释放资源
四、具体代码实现

  • 图像识别数据及调试信息
  • wget-log打印日志文件

五、增加OLED显示功能
六、功能点实现语音交互视频

一、增加垃圾桶开关盖功能

实现功能:使用语音模块和摄像头在香橙派上做垃圾智能分类识别, 同时根据识别结果开关不同的垃圾桶的盖子。

环境准备

在《语音模块和阿里云图像识别结合》搭建环境的基础上, 接上用于开关盖的舵机(舵机模块可以直接粘在垃圾桶内侧),当前代码里仅用了2个舵机用于示例代码的编写,可以自行多购买3个垃圾桶和舵机用于区分4垃圾类型,接线位置如下:
在这里插入图片描述

实物图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二、PWM 频率的公式

这个 PWM 频率的公式可以更详细地表示为:

P W M f r e q = 1 × 1 0 6 pulse-width × range \\{PWMfreq} = \frac{1 \times 10^6}{\text{pulse-width} \times \text{range}} \ PWMfreq=pulse-width×range1×106 

其中:

  • (\text{PWMfreq}) 是 PWM 的频率(赫兹)。
  • (1 \times 10^6) 是为了将频率从赫兹(Hz)转换为微秒(μs)。
  • (\text{pulse-width}) 是每个 PWM 脉冲的宽度(微秒)。
  • (\text{range}) 是 PWM 的范围,即 PWM 值的最大范围。

这个公式的基本思想是,PWM 的频率与脉冲宽度和范围有关。脉冲宽度表示每个 PWM 脉冲的持续时间,而范围表示 PWM 值的最大范围。通过调整这两个参数,可以控制 PWM 的频率。

三、pthread_detach分离线程,使其在退出时能够自动释放资源

pthread_detach 函数是 POSIX 线程库提供的一个函数,用于将一个线程标记为可被回收的。标记为可被回收的线程在退出时会自动释放其占用的系统资源,无需等待其他线程调用 pthread_join

具体来说,当一个线程被标记为可被回收时,其退出状态会自动被收回。这对于那些不需要其他线程等待其结束的线程是有用的,因为它允许主线程或其他线程继续执行而无需等待这个线程的完成。

#include <pthread.h>int pthread_detach(pthread_t thread);
  • pthread_detach 的参数是一个线程标识符(pthread_t 类型的变量),它表示要被标记为可被回收的线程。
  • 如果线程标识符为 thread 的线程处于 joinable 状态,那么它会被标记为可被回收,并且在线程退出时,其资源将被自动释放。
  • 如果线程已经处于 detached 状态,或者线程标识符不对应一个现存的线程,pthread_detach 函数将返回适当的错误码。

示例用法:

#include <pthread.h>void *thread_function(void *arg) {// 线程的执行体// ...return NULL;
}int main() {pthread_t my_thread;// 创建线程if (pthread_create(&my_thread, NULL, thread_function, NULL) != 0) {// 线程创建失败处理return 1;}// 将线程标记为可被回收if (pthread_detach(my_thread) != 0) {// 线程标记失败处理return 1;}// 主线程继续执行而不用等待子线程的结束// ...return 0;
}

在这个例子中,my_thread 线程被创建后立即被标记为可被回收,主线程可以继续执行而不用等待 my_thread 线程的完成。

总结:
你可以将这种机制称为“分离线程”或“分离父子线程”。当你将一个线程标记为可被回收,这个线程就不再和主线程形成关联,主线程不需要显式地等待它的结束。这样的线程就像“自洁”一样,它在结束时会自动释放资源。

这种机制对于那些主线程不关心其返回值,也不需要等待其结束的辅助线程是非常有用的。这样,主线程和辅助线程可以并行执行,提高了程序的性能。

四、具体代码实现

  1. 增加用于实现开光盖(驱动舵机)的源码文件(pwm.c):
#include <wiringPi.h>
#include <softPwm.h>
#include "pwm.h"// 根据PWM 频率公式:PWMfreq = 1 x 10^6 / (100 x range) 。
// 要得到PWM频率为50Hz,则range设置周期分为200步,周期20ms,控制精度相比硬件PWM较低。// 设置指定PWM引脚的输出,实现模拟PWM
void pwm_write(int pwm_pin)
{pinMode(pwm_pin, OUTPUT);softPwmCreate(pwm_pin, 0, 200);	// 创建软件PWM,初始占空比为0%,范围为0到200softPwmWrite(pwm_pin, 10);		// 设置占空比为10%	45度delay(1000);					// 延时1秒softPwmStop(pwm_pin);			// 停止软件PWM
}// 停止指定PWM引脚的输出
void pwm_stop(int pwm_pin)
{pinMode(pwm_pin, OUTPUT);softPwmCreate(pwm_pin, 0, 200);	// 创建软件PWM,初始占空比为0%,范围为0到200softPwmWrite(pwm_pin, 5);		// 设置占空比为5%	0度delay(1000);					// 延时1秒softPwmStop(pwm_pin);			// 停止软件PWM
}
  1. pwm.h代码:
#ifndef __PWM__H
#define __PWM__H#define PWM_GARBAGE 7				// 干垃圾
#define PWM_RECOVERABLE_GARBAGE 5	// 可回收垃圾
#define PWM_WET_GARBAGE 8			// 湿垃圾
#define PWM_HAZARDOUS_GARBAGE 9		// 有害垃圾void pwm_write(int pwm_pin);		// 设置指定PWM引脚的输出
void pwm_stop(int pwm_pin);			// 停止指定PWM引脚的输出#endif
  1. 修改main.c代码,调整整体main函数的代码架构,利用多线程实现具体的功能(用到了线程里的条件变量控制线程间的数据同步)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <wiringPi.h>
#include <pthread.h>#include "uartTool.h"
#include "garbage.h"
#include "pwm.h"int serial_fd = -1; // 串口文件描述符
pthread_cond_t cond; // 条件变量,用于线程之间的条件同步
pthread_mutex_t mutex; // 互斥锁,用于线程之间的互斥访问// 判断进程是否在运行
static int detect_process(const char * process_name)
{int n = -1; // 存储进程PID,默认为-1FILE *strm;char buf[128] = {0}; // 缓冲区// 构造命令字符串,通过ps命令查找进程sprintf(buf, "ps -ax | grep %s|grep -v grep", process_name);// 使用popen执行命令并读取输出if ((strm = popen(buf, "r")) != NULL) {if (fgets(buf, sizeof(buf), strm) != NULL) {printf("buf = %s\n", buf); 	//打印缓存区的内容n = atoi(buf); 				// 将进程ID字符串转换为整数printf("n = %d\n", n); 		// 打印下进程的PID}}else {return -1; // popen失败}	pclose(strm); // 关闭popen打开的文件流return n;
}// 获取语音线程
void *pget_voice(void *arg)
{unsigned char buffer[6] = {0xAA, 0x55, 0x00, 0x00, 0X55, 0xAA};int len = 0;printf("%s|%s|%d\n", __FILE__, __func__, __LINE__);// 串口未打开,退出线程if (-1 == serial_fd) {printf("%s|%s|%d: open serial failed\n", __FILE__, __func__, __LINE__);pthread_exit(0);}printf("%s|%s|%d\n", __FILE__, __func__, __LINE__);// 循环读取串口数据while (1) {len = my_serialGetstring(serial_fd, buffer);printf("%s|%s|%d, len = %d\n", __FILE__, __func__, __LINE__, len);// 检测到特定数据,发出信号唤醒其他线程if (len > 0 && buffer[2] == 0x46) {printf("%s|%s|%d\n", __FILE__, __func__, __LINE__);pthread_mutex_lock(&mutex);buffer[2] = 0x00;pthread_cond_signal(&cond);pthread_mutex_unlock(&mutex);system(WGET_CMD);}}pthread_exit(0);
}// 发送语音线程
void *psend_voice(void *arg)
{pthread_detach(pthread_self());unsigned char *buffer = (unsigned char *)arg;// 串口未打开,退出线程if (-1 == serial_fd) {printf("%s|%s|%d: open serial failed\n", __FILE__, __func__, __LINE__);pthread_exit(0);}// buffer不为空时,通过串口发送数据(分类结果)if (NULL != buffer) {my_serialSendstring(serial_fd, buffer, 6);}pthread_exit(0);
}// 控制垃圾桶线程
void *popen_trash_can(void *arg)
{pthread_detach(pthread_self());unsigned char *buffer = (unsigned char *)arg;// 根据垃圾类型控制PWMif (buffer[2] == 0x43) {		// 可回收垃圾printf("%s|%s|%d: buffer[2] = 0x%x\n", __FILE__, __func__, __LINE__, buffer[2]);pwm_write(PWM_RECOVERABLE_GARBAGE);delay(2000);pwm_stop(PWM_RECOVERABLE_GARBAGE);}else if (buffer[2] == 0x41) {	// 干垃圾printf("%s|%s|%d: buffer[2] = 0x%x\n", __FILE__, __func__, __LINE__, buffer[2]);pwm_write(PWM_GARBAGE);delay(2000);pwm_stop(PWM_GARBAGE);}else if (buffer[2] == 0x42) {	// 湿垃圾printf("%s|%s|%d: buffer[2]=0x%x\n", __FILE__, __func__, __LINE__,buffer[2]);pwm_write(PWM_WET_GARBAGE);delay(2000);pwm_stop(PWM_WET_GARBAGE);}else if (buffer[2] == 0x44) {	// 有害垃圾printf("%s|%s|%d: buffer[2]=0x%x\n", __FILE__, __func__, __LINE__,buffer[2]);pwm_stop(PWM_HAZARDOUS_GARBAGE);delay(2000);pwm_write(PWM_HAZARDOUS_GARBAGE);}pthread_exit(0);
}// 垃圾分类线程
void *pcategory(void *arg)
{unsigned char buffer[6] = {0xAA, 0x55, 0x00, 0x00, 0X55, 0xAA};char *category = NULL;pthread_t send_voice_tid, trash_tid;while (1) {printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);pthread_mutex_lock(&mutex);pthread_cond_wait(&cond, &mutex);pthread_mutex_unlock(&mutex);printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);buffer[2] = 0x00;// 在执行wget命令之前添加调试输出printf("Executing wget command...\n");// 使用系统命令拍照system(WGET_CMD);// 在执行wget命令之后添加调试输出printf("Wget command executed.\n");// 判断垃圾种类if (0 == access(GARBAGE_FILE, F_OK)) {category = garbage_category(category);if (strstr(category, "干垃圾")) {buffer[2] = 0x41;}else if (strstr(category, "湿垃圾")) {buffer[2] = 0x42;}else if (strstr(category, "可回收垃圾")) {buffer[2] = 0x43;}else if (strstr(category, "有害垃圾")) {buffer[2] = 0x44;}else {buffer[2] = 0x45; // 未识别到垃圾类型}}else {buffer[2] = 0x45; // 识别失败}// 开垃圾桶开关pthread_create(&trash_tid, NULL, psend_voice, (void *)buffer);// 开语音播报线程pthread_create(&send_voice_tid, NULL, popen_trash_can, (void *)buffer);// buffer[2] = 0x00;// 删除拍照文件remove(GARBAGE_FILE); }pthread_exit(0);
}int main(int argc, char *argv[])
{int ret = -1;int len = 0;char *category = NULL;pthread_t get_voice_tid, category_tid;wiringPiSetup();// 初始化串口和垃圾分类模块garbage_init ();// 用于判断mjpg_streamer服务是否已经启动ret = detect_process ("mjpg_streamer");if (-1 == ret) {printf("detect process failed\n");goto END;}// 打开串口serial_fd = my_serialOpen (SERIAL_DEV, BAUD);if (-1 == serial_fd) {printf("open serial failed\n");goto END;}// 开语音线程printf("%s|%s|%d\n", __FILE__, __func__, __LINE__);pthread_create(&get_voice_tid, NULL, pget_voice, NULL);// 开阿里云交互线程printf("%s|%s|%d\n", __FILE__, __func__, __LINE__);pthread_create(&category_tid, NULL, pcategory, NULL);// 创建互斥锁和条件变量pthread_join(get_voice_tid, NULL);pthread_join(category_tid, NULL);// 销毁互斥锁和条件变量pthread_mutex_destroy(&mutex);pthread_cond_destroy(&cond);// 关闭串口close(serial_fd);
END:// 释放垃圾分类资源garbage_final();return 0;
}

图像识别数据及调试信息

在这里插入图片描述
在这里插入图片描述

wget-log打印日志文件

在这里插入图片描述
wget-log 文件名通常是 wget 命令行工具的默认日志文件名,用于记录 wget 下载命令执行过程中的信息、警告和错误。wget 是一个用于在命令行中下载文件的工具,而 wget-log 文件则用于记录执行 wget 命令时产生的输出。

如果你在使用类似如下的 wget 命令:

wget [URL]

wget 默认会将日志输出到 wget-log 文件中。如果你希望更改日志文件的名称,可以使用 -o 选项,例如:

wget -o mylog.txt [URL]

上述命令将日志输出到名为 mylog.txt 的文件中。因此,wget-log 文件的生成通常取决于 wget 命令的使用方式。

阿里云的相关操作(比如通过 wget 下载文件)也可能产生 wget-log 文件,具体情况可能取决于你执行的命令和阿里云环境的设置。如果有特定的 wget 命令或阿里云操作,你可以提供更多的上下文,以便我更好地理解你的问题。

五、增加OLED显示功能

  1. 环境配置
cat /boot/orangepiEnv.txt
ls -a /dev/i2c-3

在这里插入图片描述

  1. 《OLED屏应用-IIC协议》直接添在garbage项目中添加2个OLED实现代码文件

myoled.h

#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdint.h>#include "oled.h"
#include "font.h"#ifndef __MYOLED__H
#define __MYOLED__Hint myoled_init(void);
int oled_show(void *arg);#endif

myoled.c:

#include "myoled.h"#define FILENAME "/dev/i2c-3"static struct display_info disp;// 在 OLED 上显示垃圾分类结果
int oled_show(void *arg)
{unsigned char *buffer = (unsigned char *)arg;// 在 OLED 上显示提示信息oled_putstrto(&disp, 0, 9+1, "THis garbage is:");disp.font = font2;// 根据垃圾类型显示相应信息switch(buffer[2]){case 0x41:oled_putstrto(&disp, 0, 20, "Dry_garbage");break;case 0x42:oled_putstrto(&disp, 0, 20, "Wet_garbage");break;case 0x43:oled_putstrto(&disp, 0, 20, "Recycle_garbage");break;case 0x44:oled_putstrto(&disp, 0, 20, "Hazardous_garbage");break;case 0x45:oled_putstrto(&disp, 0, 20, "recognition failed");break;}disp.font = font2;// 发送显示缓冲区到 OLEDoled_send_buffer(&disp);return 0;
}// 初始化 OLED
int myoled_init(void)
{int e;disp.address = OLED_I2C_ADDR;disp.font = font2;// 打开 OLED 设备文件e = oled_open(&disp, FILENAME);// 初始化 OLEDe = oled_init(&disp);return e;
}
  1. 然后修改下main.c文件, 增加OLED线程,用于显示识别后的垃圾类型:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <wiringPi.h>
#include <pthread.h>#include "uartTool.h"
#include "garbage.h"
#include "pwm.h"
#include "myoled.h"int serial_fd = -1; // 串口文件描述符
pthread_cond_t cond; // 条件变量,用于线程之间的条件同步
pthread_mutex_t mutex; // 互斥锁,用于线程之间的互斥访问// 判断进程是否在运行
static int detect_process(const char * process_name)
{int n = -1; // 存储进程PID,默认为-1FILE *strm;char buf[128] = {0}; // 缓冲区// 构造命令字符串,通过ps命令查找进程sprintf(buf, "ps -ax | grep %s|grep -v grep", process_name);// 使用popen执行命令并读取输出if ((strm = popen(buf, "r")) != NULL) {if (fgets(buf, sizeof(buf), strm) != NULL) {printf("buf = %s\n", buf); 	//打印缓存区的内容n = atoi(buf); 				// 将进程ID字符串转换为整数printf("n = %d\n", n); 		// 打印下进程的PID}}else {return -1; // popen失败}	pclose(strm); // 关闭popen打开的文件流return n;
}// 获取语音线程
void *pget_voice(void *arg)
{unsigned char buffer[6] = {0xAA, 0x55, 0x00, 0x00, 0X55, 0xAA};int len = 0;printf("%s|%s|%d\n", __FILE__, __func__, __LINE__);// 串口未打开,退出线程if (-1 == serial_fd) {printf("%s|%s|%d: open serial failed\n", __FILE__, __func__, __LINE__);pthread_exit(0);}printf("%s|%s|%d\n", __FILE__, __func__, __LINE__);// 循环读取串口数据while (1) {len = my_serialGetstring(serial_fd, buffer);printf("%s|%s|%d, len = %d\n", __FILE__, __func__, __LINE__, len);// 检测到特定数据,发出信号唤醒其他线程if (len > 0 && buffer[2] == 0x46) {printf("%s|%s|%d\n", __FILE__, __func__, __LINE__);pthread_mutex_lock(&mutex);buffer[2] = 0x00;pthread_cond_signal(&cond);pthread_mutex_unlock(&mutex);system(WGET_CMD);}}pthread_exit(0);
}// 发送语音线程
void *psend_voice(void *arg)
{pthread_detach(pthread_self());unsigned char *buffer = (unsigned char *)arg;// 串口未打开,退出线程if (-1 == serial_fd) {printf("%s|%s|%d: open serial failed\n", __FILE__, __func__, __LINE__);pthread_exit(0);}// buffer不为空时,通过串口发送数据(分类结果)if (NULL != buffer) {my_serialSendstring(serial_fd, buffer, 6);}pthread_exit(0);
}// 控制垃圾桶线程
void *popen_trash_can(void *arg)
{pthread_detach(pthread_self());unsigned char *buffer = (unsigned char *)arg;// 根据垃圾类型控制PWMif (buffer[2] == 0x43) {		// 可回收垃圾printf("%s|%s|%d: buffer[2] = 0x%x\n", __FILE__, __func__, __LINE__, buffer[2]);pwm_write(PWM_RECOVERABLE_GARBAGE);delay(2000);pwm_stop(PWM_RECOVERABLE_GARBAGE);}else if (buffer[2] == 0x41) {	// 干垃圾printf("%s|%s|%d: buffer[2] = 0x%x\n", __FILE__, __func__, __LINE__, buffer[2]);pwm_write(PWM_GARBAGE);delay(2000);pwm_stop(PWM_GARBAGE);}else if (buffer[2] == 0x42) {	// 湿垃圾printf("%s|%s|%d: buffer[2]=0x%x\n", __FILE__, __func__, __LINE__,buffer[2]);pwm_write(PWM_WET_GARBAGE);delay(2000);pwm_stop(PWM_WET_GARBAGE);}else if (buffer[2] == 0x44) {	// 有害垃圾printf("%s|%s|%d: buffer[2]=0x%x\n", __FILE__, __func__, __LINE__,buffer[2]);pwm_stop(PWM_HAZARDOUS_GARBAGE);delay(2000);pwm_write(PWM_HAZARDOUS_GARBAGE);}pthread_exit(0);
}// 在线程中显示 OLED
void *poled_show(void *arg)
{// 分离线程,使其在退出时能够自动释放资源pthread_detach(pthread_self());// 初始化 OLEDmyoled_init();// 在 OLED 上显示垃圾分类结果oled_show(arg);// 退出线程	pthread_exit(0);
}// 垃圾分类线程
void *pcategory(void *arg)
{unsigned char buffer[6] = {0xAA, 0x55, 0x00, 0x00, 0X55, 0xAA};char *category = NULL;pthread_t send_voice_tid, trash_tid, oled_tid;while (1) {printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);pthread_mutex_lock(&mutex);pthread_cond_wait(&cond, &mutex);pthread_mutex_unlock(&mutex);printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);buffer[2] = 0x00;// 在执行wget命令之前添加调试输出printf("Executing wget command...\n");// 使用系统命令拍照system(WGET_CMD);// 在执行wget命令之后添加调试输出printf("Wget command executed.\n");// 判断垃圾种类if (0 == access(GARBAGE_FILE, F_OK)) {category = garbage_category(category);if (strstr(category, "干垃圾")) {buffer[2] = 0x41;}else if (strstr(category, "湿垃圾")) {buffer[2] = 0x42;}else if (strstr(category, "可回收垃圾")) {buffer[2] = 0x43;}else if (strstr(category, "有害垃圾")) {buffer[2] = 0x44;}else {buffer[2] = 0x45; // 未识别到垃圾类型}}else {buffer[2] = 0x45; // 识别失败}// 开垃圾桶开关pthread_create(&trash_tid, NULL, psend_voice, (void *)buffer);// 开语音播报线程pthread_create(&send_voice_tid, NULL, popen_trash_can, (void *)buffer);//oled显示线程pthread_create(&oled_tid, NULL, poled_show, (void *)buffer);// buffer[2] = 0x00;// 删除拍照文件remove(GARBAGE_FILE); }pthread_exit(0);
}int main(int argc, char *argv[])
{int ret = -1;int len = 0;char *category = NULL;pthread_t get_voice_tid, category_tid;wiringPiSetup();// 初始化串口和垃圾分类模块garbage_init ();// 用于判断mjpg_streamer服务是否已经启动ret = detect_process ("mjpg_streamer");if (-1 == ret) {printf("detect process failed\n");goto END;}// 打开串口serial_fd = my_serialOpen (SERIAL_DEV, BAUD);if (-1 == serial_fd) {printf("open serial failed\n");goto END;}// 开语音线程printf("%s|%s|%d\n", __FILE__, __func__, __LINE__);pthread_create(&get_voice_tid, NULL, pget_voice, NULL);// 开阿里云交互线程printf("%s|%s|%d\n", __FILE__, __func__, __LINE__);pthread_create(&category_tid, NULL, pcategory, NULL);// 创建互斥锁和条件变量pthread_join(get_voice_tid, NULL);pthread_join(category_tid, NULL);// 销毁互斥锁和条件变量pthread_mutex_destroy(&mutex);pthread_cond_destroy(&cond);// 关闭串口close(serial_fd);
END:// 释放垃圾分类资源garbage_final();return 0;
}

在这里插入图片描述

六、功能点实现语音交互视频

垃圾分类

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

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

相关文章

Flutter之Graphic图表的简单示例

简介 Graphic是一个数据可视化语法和Flutter图表库。 官方github示例 我的gitee示例 网上可用资源很少&#xff0c;只有作者的几篇文章&#xff0c;并且没有特别详细的文档&#xff0c;使用的话还是需要一定的时间去调研&#xff0c;在此简单记录。 示例 以折线图为例&…

我在electron中集成了自己的ai大模型

同学们可以私信我加入学习群&#xff01; 正文开始 前言一、大模型选择二、获取key三、调用api四、调用ai模型api时&#xff0c;解决跨域总结 前言 最近单位把gpt、文心一言、通义千问、星火等等等等你能想到的ai大模型都给禁掉了&#xff0c;简直丧心病狂。 不知道有多少感同…

Kafka配置SASL认证密码登录

​​​​​​1、修改config/server.properties&#xff0c;添加如下内容 listenersSASL_PLAINTEXT://内网ip:9092 advertised.listenersSASL_PLAINTEXT://外网ip:9092 security.inter.broker.protocolSASL_PLAINTEXT sasl.mechanism.inter.broker.protocolPLAIN sasl.enabled.…

青云科技容器平台与星辰天合存储产品完成兼容性互认证

近日&#xff0c; 北京青云科技股份有限公司&#xff08;以下简称&#xff1a;青云科技&#xff09;的 KubeSphere 企业版容器平台成功完成了与 XSKY星辰天合的企业级分布式统一数据平台 V6&#xff08;简称&#xff1a;XEDP&#xff09;以及天合翔宇分布式存储系统 V6&#xf…

Golang并发模型:Goroutine 与 Channel 初探

文章目录 goroutinegoexit() channel缓冲closerangeselect goroutine goroutine 是 Go 语言中的一种轻量级线程&#xff08;lightweight thread&#xff09;&#xff0c;由 Go 运行时环境管理。与传统的线程相比&#xff0c;goroutine 的创建和销毁的开销很小&#xff0c;可以…

部署系列六基于nndeploy的深度学习 图像降噪unet部署

文章目录 1.直接在源代码demo中修改2. 如何修改呢&#xff1f;3. 修改 graph4. 总结 https://github.com/DeployAI/nndeploy https://nndeploy-zh.readthedocs.io/zh/latest/introduction/index.html 通过以上2个官方链接对nndeploy基本的使用方法应该有所了解了。 下面就是利用…

自动语音识别 支持86种语言 Dragon Professional 16 Crack

从个体从业者到全球组织&#xff0c;文档密集型行业的专业人士长期以来一直依靠 Dragon 语音识别来更快、更高效地创建高质量文档&#xff0c;减少管理开销&#xff0c;以便他们能够专注于客户。了解 Dragon Professional v16 如何通过单一解决方案提高标准&#xff0c;为各个业…

ArcGis如何用点连线?

这里指的是根据已有坐标点手动连线&#xff0c;类似于mapgis中的“用点连线”&#xff0c;线的每个拐点是可以自动捕捉到坐标点的&#xff0c;比直接画精确。 我也相信这么强大的软件一定可以实现类似于比我的软件上坐标时自动生成的线&#xff0c;但是目前我还没接触到那里&a…

基于IDEA+SpringBoot+微服务开发的P2P平台项目

基于springboot的社区养老医疗综合服务平台 项目介绍&#x1f481;&#x1f3fb; 项目名称&#xff1a;基于P2P的金融项目 一个基于P2P&#xff08;点对点&#xff09;模式的金融服务平台&#xff0c;致力于提供透明、高效、安全的金融服务。我们的目标是连接借款人与投资者&am…

Clion在Windows下build时出现undefined reference,即使cmake已经正确链接第三方库(如protobuf)?

你是否正在使用clion自带的vcpkg来安装了protobuf&#xff1f; 或者你是否自己使用visual studio自己编译了libprotobuf.lib&#xff1f; 你是否已经正确在CmakeLists.txt中添加了以下命令&#xff1a; find_package(Protobuf CONFIG REQUIRED) include_directories(${Protobu…

inBuilder低代码平台新特性推荐-第十期

各位知乎的友友们&#xff0c;大家好~ 今天来给大家带来的是inBuilder低代码平台特性推荐系列第十期——查看变更日志 场景介绍 【销售订单列表】中添加查看变更日志按钮&#xff0c;可以查看列表当前行数据的历史变更记录。 运行时效果 概念 系统中有些关键业务关键数据&am…

【极客技术】真假GPT-4?微调 Llama 2 以替代 GPT-3.5/4 已然可行!

近日小编在使用最新版GPT-4-Turbo模型&#xff08;主要特点是支持128k输入和知识库截止日期是2023年4月&#xff09;时&#xff0c;发现不同商家提供的模型回复出现不一致的情况&#xff0c;尤其是模型均承认自己知识库达到2023年4月&#xff0c;但当我们细问时&#xff0c;Fak…

如何开发有趣而富有创意的营销小游戏

在数字化时代&#xff0c;企业通过创意而独特的方式与目标受众互动&#xff0c;已成为提高品牌知名度和用户参与度的重要手段之一。其中&#xff0c;设计一款引人入胜的营销小游戏&#xff0c;不仅能吸引用户的眼球&#xff0c;还能有效传达品牌信息。以下是一些建议&#xff0…

AI赋能数据表设计

数据表设计软件用过多种&#xff0c;用Ai 设计表几年Ai大模型爆发之后提升了新的高度 用navicat 设计表就是在跟团队的人介绍这次功能的表结构时&#xff0c;没办法看备注&#xff0c;只能看英文字段&#xff0c;导致在比较复杂的表中&#xff0c;总是在表结构和图形结构中来回…

转录组学习第5弹-比对参考基因组

比对参考基因组 在构建文库的过程中需要将DNA片段化&#xff0c;因此测序得到的序列只是基因组的部分序列。为了确定测序reads在基因组上的位置&#xff0c;需要将reads比对回参考基因组上&#xff0c;这个步骤叫做比对&#xff0c;即文献中所提到的alignment或mapping。包括基…

2023.11.23使用flask实现在指定路径生成文件夹操作

2023.11.23使用flask实现在指定路径生成文件夹操作 程序比较简单&#xff0c;实现功能&#xff1a; 1、前端输入文件夹 2、后端在指定路径生成文件夹 3、前端反馈文件夹生成状态 main.py from flask import Flask, request, render_template import osapp Flask(__name__)a…

SAP从放弃到入门系列之-制造商零件编号-MPN 物料

文章目录 一、概念二、 配置点配置点1&#xff1a;启用MPN配置点2&#xff1a;MPN配置参数文件配置点3&#xff1a;激活库存管理的MPN所有功能变化1&#xff1a;MM01界面有库存管理制造商零部件号的字段&#xff1a;变化2&#xff1a;MM60界面的查询条件多了MPN物料号变化3&…

Mac开发环境——MacOSX安装与配置Anaconda与PyCharm详细流程

一、安装与使用Anaconda 1.简介 Anaconda 是一个用于数据科学、机器学习和科学计算的开源发行版和包管理器。有许多可用于数据处理、分析和建模的工具和库&#xff0c;并提供了一个方便的环境管理系统。Anaconda 包含了 Python 解释器和许多常用的 Python 包&#xff0c;以及…

【Unity入门】碰撞检测

碰撞器由来 1.系统默认会给每个对象(GameObject)添加一个碰撞组件(ColliderComponent)&#xff0c;一些背景对象则可以取消该组件。 2.在unity3d中&#xff0c;能检测碰撞发生的方式有两种&#xff0c;一种是利用碰撞器&#xff0c;另一种则是利用触发器。这两种方式的应用非…

Android Studio 显示build variants工具栏

工具栏&#xff1a; 如下图所示 依次点击View-->ToolWindows-->Build Variants。 在此记个笔记