当前位置: 首页 > news >正文

OpenCV C++案例实战三十一《动态时钟》

OpenCV C++案例实战三十一《动态时钟》

  • 前言
  • 一、绘制表盘
  • 二、绘制刻线
  • 三、获取系统时间
  • 四、结果展示
  • 五、源码
  • 总结


前言

本案例将使用OpenCV C++实现动态时钟效果。原理也很简单,主要分为绘制表盘、以及获取系统时间两步。

一、绘制表盘

首先为了效果显示美观一点,选取一张背景图。
在这里插入图片描述
接着需要绘制一个圆形表盘,直接上代码、效果演示。注释都在源码上有标注。
在这里插入图片描述

	Point center(background.cols / 2, background.rows / 2);//圆心int radius = min(background.cols / 2, background.rows / 2) - 20; //时钟半径Mat mask = Mat::zeros(background.size(), CV_8UC3);circle(mask, center, radius, Scalar::all(255), -1);//掩模Mat canvas = Mat(background.size(), CV_8UC3, Scalar(175, 165, 0));//创建画布background.copyTo(canvas, mask);//将背景拷贝到画布中,形成表盘背景circle(canvas, center, radius, Scalar::all(0), 3);//表盘

二、绘制刻线

接下来,需要在表盘上绘制时针、分针刻线。其中原理就是计算点的旋转坐标。可以参考一下我的这篇博文OpenCV C++案例实战二十七《角度测量》

	int margin = 5;//若margin为0,则点在表盘上//画分针刻线int minute_len = 10; //刻线长度for (int i = 0; i < 60; i++){//圆上坐标点计算公式,对于分针刻线,360/60=6,即每隔6°一刻线int x1 = center.x + (radius - margin) * cos(i*6.0*CV_PI / 180.0);int y1 = center.y + (radius - margin) * sin(i*6.0*CV_PI / 180.0);int x2 = center.x + (radius - minute_len) * cos(i*6.0*CV_PI / 180.0);int y2 = center.y + (radius - minute_len) * sin(i*6.0*CV_PI / 180.0);line(canvas, Point(x1, y1), Point(x2, y2), Scalar::all(0), 2, LINE_AA);}//画时针刻线int hour_len = 20;for (int i = 0; i < 12; i++){//对于时针刻线,每隔360/12=30,即每隔30°一刻线int x1 = center.x + (radius - margin) * cos(i*30.0*CV_PI / 180.0);int y1 = center.y + (radius - margin) * sin(i*30.0*CV_PI / 180.0);int x2 = center.x + (radius - hour_len)*cos(i*30.0*CV_PI / 180.0);int y2 = center.y + (radius - hour_len)*sin(i*30.0*CV_PI / 180.0);line(canvas, Point(x1, y1), Point(x2, y2), Scalar::all(0), 3, LINE_AA);//在表盘上显示3、6、9、12时,坐标位置自行根据图像大小设定if (i == 0){putText(canvas, to_string(i + 3), Point(x2 - 30, y2 + 10), FONT_HERSHEY_SIMPLEX, 1, Scalar::all(0), 3);}else if (i == 3){putText(canvas, to_string(i + 3), Point(x2 - 10, y2 - 10), FONT_HERSHEY_SIMPLEX, 1, Scalar::all(0), 3);}else if (i == 6){putText(canvas, to_string(i + 3), Point(x2 + 10, y2 + 10), FONT_HERSHEY_SIMPLEX, 1, Scalar::all(0), 3);}else if (i == 9){putText(canvas, to_string(i + 3), Point(x2 - 20, y2 + 30), FONT_HERSHEY_SIMPLEX, 1, Scalar::all(0), 3);}}

在这里插入图片描述
效果如上图所示,至此前期的预处理工作已经完成了。接下来,需要获取系统时间,然后绘制到表盘上。

三、获取系统时间

当我们获取到相应的系统时间后,有一点需要注意的是,opencv是以3点钟方向为起点,即0°方向,且为顺时针旋转,故秒针、分针、时针在0~3点钟区间需要换算。具体换算请看源码注释。

	//使用while循环,不断更新时间while (true){	char key = waitKey(1000);if (key == 27)break;Mat clockImg = canvas.clone();//将表盘复制一份,用于不断更新时钟刻线//获取系统时间SYSTEMTIME Time;GetLocalTime(&Time);int second = Time.wSecond; //秒int minute = Time.wMinute; //分int hour = Time.wHour; //时int day = Time.wDay; //日int month = Time.wMonth; //月int year = Time.wYear; //年printf("%4d/%02d/%02d %02d:%02d:%02d\n", year, month, day, hour, minute, second);//由于opencv是以3点钟方向为起点,且为顺时针旋转,故秒针、分针、时针在0~3点钟区间需要换算//秒针int sec_angle = 0;if (second <= 15){//当秒针处于0~15秒时,对应角度应处于270~360°,每隔6°走一刻线sec_angle = second * 6 + 270;}else{sec_angle = (second - 15) * 6;}int sec_x = center.x + (radius - margin * 12) *cos(sec_angle*CV_PI / 180);int sec_y = center.y + (radius - margin * 12) *sin(sec_angle*CV_PI / 180);line(clockImg, center, Point(sec_x, sec_y), Scalar(0, 255, 0), 2, LINE_AA);//分针int min_angle = 0;if (minute <= 15){//当分针处于0~15分时,对应角度应处于270~360°,每隔6°走一刻线min_angle = minute * 6 + 270;}else{min_angle = (minute - 15) * 6;}int min_x = center.x + (radius - margin*18)*cos(min_angle*CV_PI / 180);int min_y = center.y + (radius - margin*18)*sin(min_angle*CV_PI / 180);line(clockImg, center, Point(min_x, min_y), Scalar(0, 255, 255), 4, LINE_AA);//时针int hour_angle = 0;if (hour <= 3){//当时针处于0~3时,对应角度应处于270~360°,每隔30°走一刻线hour_angle = hour * 30 + 270;}else{hour_angle = (hour - 3) * 30;}int hour_x = center.x + (radius - margin * 24)*cos(hour_angle*CV_PI / 180);int hour_y = center.y + (radius - margin * 24)*sin(hour_angle*CV_PI / 180);line(clockImg, center, Point(hour_x, hour_y), Scalar(255, 255, 0), 6, LINE_AA);circle(clockImg, center, 5, Scalar::all(0), -1);//将时间显示在表盘上char text1[100], text2[100];sprintf_s(text1, "%04d%s%02d%s%02d", year, "/", month, "/", day);sprintf_s(text2, "%02d%s%02d%s%02d", hour, ":", minute, ":", second);putText(clockImg, text1, Point(center.x-100, center.y+200), FONT_HERSHEY_SIMPLEX, 1, Scalar(21, 23, 161), 3);putText(clockImg, text2, Point(center.x-70, center.y+250), FONT_HERSHEY_SIMPLEX, 1, Scalar(21, 23, 161), 2);imshow("dynamic clock", clockImg);imwrite("dynamic clock.jpg", clockImg);}

四、结果展示

在这里插入图片描述

五、源码

#include<iostream>
#include<opencv2/opencv.hpp>
#include<Windows.h>
using namespace std;
using namespace cv;int main()
{Mat background = imread("background.jpg");if (background.empty()){cout << "can not read the image..." << endl;system("pause");return -1;}Point center(background.cols / 2, background.rows / 2);//圆心int radius = min(background.cols / 2, background.rows / 2) - 20; //时钟半径Mat mask = Mat::zeros(background.size(), CV_8UC3);circle(mask, center, radius, Scalar::all(255), -1);//掩模Mat canvas = Mat(background.size(), CV_8UC3, Scalar(175, 165, 0));//创建画布background.copyTo(canvas, mask);//将背景拷贝到画布中,形成表盘背景circle(canvas, center, radius, Scalar::all(0), 3);//表盘int margin = 5;//若margin为0,则点在表盘上//画分针刻线int minute_len = 10; //刻线长度for (int i = 0; i < 60; i++){//圆上坐标点计算公式,对于分针刻线,360/60=6,即每隔6°一刻线int x1 = center.x + (radius - margin) * cos(i*6.0*CV_PI / 180.0);int y1 = center.y + (radius - margin) * sin(i*6.0*CV_PI / 180.0);int x2 = center.x + (radius - minute_len) * cos(i*6.0*CV_PI / 180.0);int y2 = center.y + (radius - minute_len) * sin(i*6.0*CV_PI / 180.0);line(canvas, Point(x1, y1), Point(x2, y2), Scalar::all(0), 2, LINE_AA);}//画时针刻线int hour_len = 20;for (int i = 0; i < 12; i++){//对于时针刻线,每隔360/12=30,即每隔30°一刻线int x1 = center.x + (radius - margin) * cos(i*30.0*CV_PI / 180.0);int y1 = center.y + (radius - margin) * sin(i*30.0*CV_PI / 180.0);int x2 = center.x + (radius - hour_len)*cos(i*30.0*CV_PI / 180.0);int y2 = center.y + (radius - hour_len)*sin(i*30.0*CV_PI / 180.0);line(canvas, Point(x1, y1), Point(x2, y2), Scalar::all(0), 3, LINE_AA);//在表盘上显示3、6、9、12时,坐标位置自行根据图像大小设定if (i == 0){putText(canvas, to_string(i + 3), Point(x2 - 30, y2 + 10), FONT_HERSHEY_SIMPLEX, 1, Scalar::all(0), 3);}else if (i == 3){putText(canvas, to_string(i + 3), Point(x2 - 10, y2 - 10), FONT_HERSHEY_SIMPLEX, 1, Scalar::all(0), 3);}else if (i == 6){putText(canvas, to_string(i + 3), Point(x2 + 10, y2 + 10), FONT_HERSHEY_SIMPLEX, 1, Scalar::all(0), 3);}else if (i == 9){putText(canvas, to_string(i + 3), Point(x2 - 20, y2 + 30), FONT_HERSHEY_SIMPLEX, 1, Scalar::all(0), 3);}}//使用while循环,不断更新时间while (true){	char key = waitKey(1000);if (key == 27)break;Mat clockImg = canvas.clone();//将表盘复制一份,用于不断更新时钟刻线//获取系统时间SYSTEMTIME Time;GetLocalTime(&Time);int second = Time.wSecond; //秒int minute = Time.wMinute; //分int hour = Time.wHour; //时int day = Time.wDay; //日int month = Time.wMonth; //月int year = Time.wYear; //年printf("%4d/%02d/%02d %02d:%02d:%02d\n", year, month, day, hour, minute, second);//由于opencv是以3点钟方向为起点,且为顺时针旋转,故秒针、分针、时针在0~3点钟区间需要换算//秒针int sec_angle = 0;if (second <= 15){//当秒针处于0~15秒时,对应角度应处于270~360°,每隔6°走一刻线sec_angle = second * 6 + 270;}else{sec_angle = (second - 15) * 6;}int sec_x = center.x + (radius - margin * 12) *cos(sec_angle*CV_PI / 180);int sec_y = center.y + (radius - margin * 12) *sin(sec_angle*CV_PI / 180);line(clockImg, center, Point(sec_x, sec_y), Scalar(0, 255, 0), 2, LINE_AA);//分针int min_angle = 0;if (minute <= 15){//当分针处于0~15分时,对应角度应处于270~360°,每隔6°走一刻线min_angle = minute * 6 + 270;}else{min_angle = (minute - 15) * 6;}int min_x = center.x + (radius - margin*18)*cos(min_angle*CV_PI / 180);int min_y = center.y + (radius - margin*18)*sin(min_angle*CV_PI / 180);line(clockImg, center, Point(min_x, min_y), Scalar(0, 255, 255), 4, LINE_AA);//时针int hour_angle = 0;if (hour <= 3){//当时针处于0~3时,对应角度应处于270~360°,每隔30°走一刻线hour_angle = hour * 30 + 270;}else{hour_angle = (hour - 3) * 30;}int hour_x = center.x + (radius - margin * 24)*cos(hour_angle*CV_PI / 180);int hour_y = center.y + (radius - margin * 24)*sin(hour_angle*CV_PI / 180);line(clockImg, center, Point(hour_x, hour_y), Scalar(255, 255, 0), 6, LINE_AA);circle(clockImg, center, 5, Scalar::all(0), -1);//将时间显示在表盘上char text1[100], text2[100];sprintf_s(text1, "%04d%s%02d%s%02d", year, "/", month, "/", day);sprintf_s(text2, "%02d%s%02d%s%02d", hour, ":", minute, ":", second);putText(clockImg, text1, Point(center.x-100, center.y+200), FONT_HERSHEY_SIMPLEX, 1, Scalar(21, 23, 161), 3);putText(clockImg, text2, Point(center.x-70, center.y+250), FONT_HERSHEY_SIMPLEX, 1, Scalar(21, 23, 161), 2);imshow("dynamic clock", clockImg);imwrite("dynamic clock.jpg", clockImg);}destroyAllWindows();system("pause");return 0;
}

总结

本文使用OpenCV C++ 进行动态时钟绘制,主要操作有以下几点。
1、图像预处理,绘制表盘
2、绘制表盘刻线
3、获取系统时间,注意角度与时间之间的转换

相关文章:

OpenCV C++案例实战三十一《动态时钟》

OpenCV C案例实战三十一《动态时钟》 前言一、绘制表盘二、绘制刻线三、获取系统时间四、结果展示五、源码总结 前言 本案例将使用OpenCV C实现动态时钟效果。原理也很简单&#xff0c;主要分为绘制表盘、以及获取系统时间两步。 一、绘制表盘 首先为了效果显示美观一点&…...

字节后端入门 - Go 语言原理与实践

1.1什么是Go语言 1.2Go语言入门 环境 1.3基础语法 1.3.1变量 var name"value" 自己推断变量类型&#xff1b; 也可以显式类型 var c int 1 name: type(value) 常量&#xff1a; const name "value" g : a"foo" 字符串拼接 1.3.2 if else {}花括号…...

锂电材料浆料匀浆搅拌设备轴承经常故障如何处理?

锂电材料浆料匀浆搅拌设备是锂电池生产中重要的设备之一&#xff0c;用于将活性材料、导电剂、粘结剂和溶剂混合成均匀的浆料&#xff0c;是电极制备过程中不可或缺的步骤。然而&#xff0c;由于高速搅拌和化学腐蚀等因素的影响&#xff0c;轴承经常会出现故障&#xff0c;导致…...

设计模式——设计模式介绍和单例设计模式

导航&#xff1a; 【黑马Java笔记踩坑汇总】JavaSEJavaWebSSMSpringBoot瑞吉外卖SpringCloud黑马旅游谷粒商城学成在线设计模式牛客面试题 目录 一、设计模式概述和分类 1.1 设计模式介绍 1.2 设计模式分类 二、创建型设计模式-单例模式 2.1 介绍 2.2 八种单例模式的创…...

利用Iptables构建虚拟路由器

利用Iptables构建虚拟路由器 &#xff08;1&#xff09;修改网络类型 在VMware Workstation软件中选择“编辑→虚拟网络编辑器”菜单命令&#xff0c;在虚拟网络列表中选中VMnet1&#xff0c;将其配置为“仅主机模式&#xff08;在专用网络内连接虚拟机&#xff09;”&#x…...

C++——类和对象[中]

0.关注博主有更多知识 C知识合集 目录 1.类的默认成员函数 2.构造函数和析构函数基础 3.构造函数进阶 4.析构函数进阶 5.拷贝构造函数 6.运算符重载 7.日期类 7.1输入&输出&友元函数 8.赋值运算符重载 9.const成员函数 9.1日期类完整代码 10.取地址重载 …...

Symbol.iterator和Symbol.asyncIterator

Symbol是什么&#xff1f; symbol是ES6标准中新增的一种基本数据类型&#xff0c;symbol 的值是通过 Symbol()函数返回的&#xff0c;每一个 symbol 的值都是唯一的&#xff0c;即使传入相同的描述值。 注&#xff1a;Symbol 函数不允许通过 new 的方式调用 Symbol的作用是什…...

忆暖行动|“他一个人推着老式自行车在厚雪堆的道路上走,车上带着学生考试要用的司机”

忆暖行动|“他一个人推着老式自行车在厚雪堆的道路上走&#xff0c;车上带着学生考试要用的sj” 一头白发&#xff0c;满山青葱 在那斑驳的物件褶皱中&#xff0c;透过泛黄的相片&#xff0c;掩藏着岁月的冲刷和青葱的时光。曾经的青年早已经不复年轻&#xff0c;但是那份热爱…...

Python中True、False、None的判断(避坑)

2.4 Python中True、False、None的判断 在Python中&#xff0c;所有的空值和0在作为条件表达式时&#xff0c;隐式的进行bool转换后都是False&#xff0c;比如&#xff1a;空列表&#xff1a;[]、空字符串&#xff1a;‘’、空字典&#xff1a;{}等等。 from icecream import …...

Spring Bean定义有哪些方式?

概述 对于学习Spring的兄弟姐妹来说&#xff0c;觉得这个问题很熟悉&#xff0c;若是要把它回答得很清楚&#xff0c;却是很为难&#xff1f;平时写代码的时候&#xff0c;不会在意这些概念问题&#xff0c;但面试时这个问题出现的频率却是很高&#xff0c;所以还是必须要掌握…...

JVM内存模型的演变

1&#xff0c;背景 class文件、类的加载过程。我们的class文件就要进入到JVM内存里&#xff0c;我们沿着经典的JDK1.6&#xff0c;JDK1.7&#xff0c;JDK1.8看看在其中都经历了哪些改变 概念的统一&#xff1a; 方法区&#xff1a; 方法区可以看作是JVM逻辑上管理一片区域的…...

DataX3同步Mysql数据库数据到Mysql数据库和DataX3同步mysql数据库数据到Starrocks数据库

DataX3同步Mysql数据库数据到Mysql数据库和DataX3同步mysql数据库数据到Starrocks 一、认识DataX二、DataX3概览三、DataX3框架设计四、DataX3插件体系五、DataX3核心架构六、DataX 3六大核心优势1.可靠的数据质量监控2.丰富的数据转换功能3.精准的速度控制4.强劲的同步性能5.健…...

你是否曾经为自己写的代码而感到懊恼?那如何才能写出高质量代码呢?

这里写目录标题 一、 前言二、高质量代码的特征三、编程实践技巧1. 遵循编码规范2. 使用有意义的变量名和函数名3. 减少代码重复4. 使用注释5. 编写单元测试6. 使用设计模式7. 使用版本控制工具8. 保持代码简洁9. 优化代码性能10. 学习和借鉴他人的代码总结 一、 前言 写出高质…...

常用 Composition API【VUE3】

二、常用 Composition API 7. 计算属性与监视 7.1 computed函数 与Vue2.x中computed配置功能一致写法 <template><h1>一个人的信息</h1>姓&#xff1a;<input type"text" v-model"person.firstName"><br><br>名&a…...

--商业模式--

O2O O2O&#xff0c;网络用语中指Online To Offline的缩写&#xff0c;即在线离线/线上到线下&#xff0c;是指将线下的商务机会与互联网结合&#xff0c;让互联网成为线下交易的平台。 O2O概念最早来源于美国。O2O的概念非常广泛&#xff0c;既可涉及到线上&#xff0c;又可…...

JavaWeb《HTML基础标签》

本笔记学习于Acwing平台 MDN官方文档https://developer.mozilla.org/zh-CN/ 目录 1. html文件结构 2. 文本标签 3. 图片 4. 音频和视频 5. 超链接 6. 表单 7. 列表 8. 表格 9. 语义标签 10. 特殊符号 1. html文件结构 文档结构 html的所有标签为树形结构&#xff…...

ChatGpt 能取代人类吗?

目录 前言 一、ChatGpt是什么&#xff1f; 二、ChatGpt能做什么 总结 前言 随着人工智能的不断发展&#xff0c;很多人都开启了学习机器学习&#xff0c;以及现在ChatGpt的出现&#xff0c;对人类社会带来了很多变化。 智能化交流方式&#xff1a;ChatGpt的出现为人们提供了…...

PHP内存溢出Allowed memory size of 解决办法

以前追踪过这个问题,但是那个时候工具用的不太好,没看的这么细,这次搞的比较细,修正了偶以前的看法 .于是写小文一篇总结一下. PHP偶尔会爆一下如下 错误Allowed memory size of xxx bytes exhausted at xxx:xxx (tried to allocate xxx bytes) 不想看原理的,直接跳到最后…...

重回代码,学习总结

回顾加总结 2021年 自动化测试 1.ETL 数据库开发维护(oracle pl/sql) 2.自动化测试(javaseleniumcucumber) 2022年 功能测试 1.功能测试&#xff08;学习测试用例&#xff0c;postman测试&#xff09; 2.性能测试&#xff08;jmeter初学&#xff09; 2023年 测试开发 1.学习了…...

【Leetcode -86.分隔链表 -92.反转链表Ⅱ】

Leetcode Leetcode -86.分隔链表Leetcode -92.反转链表Ⅱ Leetcode -86.分隔链表 题目&#xff1a;给你一个链表的头节点 head 和一个特定值 x &#xff0c;请你对链表进行分隔&#xff0c;使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。 你应当 保留 两个分区中每…...

基于大模型的 UI 自动化系统

基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...

C++_核心编程_多态案例二-制作饮品

#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为&#xff1a;煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例&#xff0c;提供抽象制作饮品基类&#xff0c;提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互

物理引擎&#xff08;Physics Engine&#xff09; 物理引擎 是一种通过计算机模拟物理规律&#xff08;如力学、碰撞、重力、流体动力学等&#xff09;的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互&#xff0c;广泛应用于 游戏开发、动画制作、虚…...

Python:操作 Excel 折叠

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)

服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

生成 Git SSH 证书

&#x1f511; 1. ​​生成 SSH 密钥对​​ 在终端&#xff08;Windows 使用 Git Bash&#xff0c;Mac/Linux 使用 Terminal&#xff09;执行命令&#xff1a; ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" ​​参数说明​​&#xff1a; -t rsa&#x…...

Yolov8 目标检测蒸馏学习记录

yolov8系列模型蒸馏基本流程&#xff0c;代码下载&#xff1a;这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中&#xff0c;**知识蒸馏&#xff08;Knowledge Distillation&#xff09;**被广泛应用&#xff0c;作为提升模型…...

R语言速释制剂QBD解决方案之三

本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...

在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)

考察一般的三次多项式&#xff0c;以r为参数&#xff1a; p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]&#xff1b; 此多项式的根为&#xff1a; 尽管看起来这个多项式是特殊的&#xff0c;其实一般的三次多项式都是可以通过线性变换化为这个形式…...

PostgreSQL——环境搭建

一、Linux # 安装 PostgreSQL 15 仓库 sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-$(rpm -E %{rhel})-x86_64/pgdg-redhat-repo-latest.noarch.rpm# 安装之前先确认是否已经存在PostgreSQL rpm -qa | grep postgres# 如果存在&#xff0…...