【OpenCV实现图像的算数运算,性能测试和优化,改变颜色空间】
文章目录
- OpenCV功能概要
- 图像的算数运算
- 性能测试和优化
- 改变颜色空间
- 对象追踪
OpenCV功能概要
OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉和机器学习库,提供了丰富的图像处理和计算机视觉算法。它支持多种编程语言,包括Python、C++和Java。以下是OpenCV的主要功能概要:
-
图像的算数运算:
OpenCV提供了多种算数运算函数,包括加法、减法、位运算等,可以用来处理图像。这些函数能够执行图像间的像素级别操作,例如图像加法和减法,以及与常数的算数运算。 -
性能测试和优化:
OpenCV提供了丰富的性能测试工具和优化技术,可以帮助开发者评估和提高图像处理算法的性能。使用OpenCV的性能测试功能,可以度量不同操作的执行时间,从而找出性能瓶颈。优化技术包括使用OpenCV的内置函数,以及利用硬件加速(如CUDA和OpenCL)来加速图像处理任务。 -
改变颜色空间:
OpenCV支持多种颜色空间的转换,例如RGB到灰度、RGB到HSV等。这些转换可以帮助开发者在不同颜色空间中进行图像处理,从而更好地理解和操作图像的颜色信息。
图像的算数运算
一些图像上的运算操作,就像加法,减法,位操作等等
函数:cv.add()、cv.addWeighted()等等
1.图像添加
图像的添加是图像处理中常见的操作之一,用于将两幅图像叠加在一起。在OpenCV中,你可以使用cv2.add()函数来实现图像的添加。另外,你也可以使用NumPy进行相似的操作,但需要注意OpenCV和NumPy在处理饱和运算方面的差异。
使用OpenCV的cv2.add()函数时,它会执行饱和运算(saturate operation),即当像素值超过255时,会被截断到255,不会溢出。这是因为图像的像素值通常是8位无符号整数(0到255之间的值),超出这个范围的值会被截断。
import cv2
import numpy as np# 读取两幅图像
img1 = cv2.imread('img.png')
img2 = cv2.imread('img_1.png')# 调整第二幅图像的尺寸与第一幅图像相同
img2_resized = cv2.resize(img2, (img1.shape[1], img1.shape[0]))# 使用NumPy进行图像相加(饱和运算)
added_image_numpy = np.clip(img1.astype(int) + img2_resized.astype(int), 0, 255).astype(np.uint8)# 输出结果
print("NumPy添加结果(饱和运算):", added_image_numpy)
cv2.imshow('Blended Image', added_image_numpy)
cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.add()函数执行了饱和运算,确保了结果图像的像素值不会超出255。而使用NumPy进行图像相加时,需要使用np.clip()函数来进行饱和运算,确保结果在合理范围内。
2.图片混合
这种图像叠加操作是通过赋予不同权重给两幅图像,从而实现混合或透明效果的一种方法。具体地,通过以下的线性组合公式:
g(x)=(1−α)f0(x)+αf1(x)g(x)=(1−α)f0(x)+αf1(x)
其中,f0(x)f0(x)和f1(x)f1(x)分别代表两幅输入图像的像素值,αα表示权重,可以调整从0到1,实现不同程度的混合。在OpenCV中,这种混合效果可以通过cv2.addWeighted()函数实现,其公式如下:
dst=α⋅img1+β⋅img2+γdst=α⋅img1+β⋅img2+γ
在这个公式中,img1和img2分别是两幅输入图像,αα和ββ是相应图像的权重,而γγ通常被设置为0。
以下是一个使用OpenCV进行两幅图像混合的例子:
import cv2# 读取两幅图像
img1 = cv2.imread('img.png')
img2 = cv2.imread('img_1.png')# 调整第二幅图像的尺寸与第一幅图像相同
img2_resized = cv2.resize(img2, (img1.shape[1], img1.shape[0]))# 设置权重
alpha = 0.7
beta = 0.3# 图像混合
blended_img = cv2.addWeighted(img1, alpha, img2_resized, beta, 0)# 显示混合结果
cv2.imshow('Blended Image', blended_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果:
3.位操作
我想把OpenCV的图标放到一个图片上面。如果我直接相加两个图像,图标的颜色就会被改变。如果是选择混合他们,那么透明度就会受影响。但我希望它是不透明的。如果这是一个规则的区域,我就可以用上一个章节使用的ROI来操作。但是OpenCV图标并不是一个规则的形状。所以你可以通过下面的例子进行位运算。
使用位运算来处理两幅图像,将OpenCV的图标放置在另一幅图像的特定区域上,并确保它是不透明的。以下是代码的详细解释:
- 加载图片:
img1 = cv.imread('messi5.jpg')
img2 = cv.imread('opencv-logo-white.png')
2.创建ROI区域:
我们希望将img2(OpenCV的图标)放在img1的左上角。因此,我们创建一个ROI区域,其大小与img2相同。
rows, cols, channels = img2.shape
roi = img1[0:rows, 0:cols]
3.创建徽标蒙版和反向蒙版:
我们将img2转换为灰度图像,然后使用阈值将其二值化(变为黑白图像)。接着,我们通过cv.bitwise_not()函数创建反向蒙版。
img2gray = cv.cvtColor(img2, cv.COLOR_BGR2GRAY)
ret, mask = cv.threshold(img2gray, 10, 255, cv.THRESH_BINARY)
mask_inv = cv.bitwise_not(mask)
4.背景提取和前景提取:
使用cv.bitwise_and()函数,我们将ROI区域中的徽标区域涂黑,得到背景提取的图像(img1_bg)。然后,我们从徽标图像中提取徽标区域,得到前景提取的图像(img2_fg)。
img1_bg = cv.bitwise_and(roi, roi, mask=mask_inv)
img2_fg = cv.bitwise_and(img2, img2, mask=mask)
5.合并前景和背景:
将前景和背景图像相加,得到最终的结果图像。
dst = cv.add(img1_bg, img2_fg)
img1[0:rows, 0:cols] = dst
6.显示结果:
最终,通过cv.imshow()函数显示结果图像,你也可以在代码中插入其他步骤来查看中间结果。
cv.imshow('res', img1)cv.waitKey(0)cv.destroyAllWindows()
这个例子中使用位运算,将OpenCV的图标合并到了另一幅图像的特定区域上,同时确保了不透明度。
性能测试和优化
函数:cv.getTickCount,cv.getTickFrequency 等等
在OpenCV中,你可以使用cv.getTickCount()函数来获取一个时间戳,该时间戳表示自系统启动以来的时钟周期数。你还可以使用cv.getTickFrequency()函数来获取时钟周期的频率,即每秒的时钟周期数。通过这两个函数,你可以计算函数的运行时间。
具体步骤如下:
使用cv.getTickCount()获取函数开始时的时间戳。
e1 = cv.getTickCount()
在你的代码执行完毕后,再次调用cv.getTickCount()获取函数结束时的时间戳。
# 你的代码
e2 = cv.getTickCount()
计算函数的运行时间(以秒为单位)。
time = (e2 - e1) / cv.getTickFrequency()
这样,time变量将包含函数的运行时间(以秒为单位)。
OpenCV中默认的优化方法
OpenCV中的许多函数都利用了现代处理器的特殊指令集(如SSE2、AVX等)进行优化,以提高性能。OpenCV同时也包含了未经过优化的代码。因此,如果系统支持这些特殊指令集(几乎所有现代处理器都支持),应该充分利用它们。
在编译时,OpenCV默认会启用这些优化,因此在运行时,OpenCV会尽量使用经过优化的代码。只有在不支持这些指令集的情况下,OpenCV才会使用未优化的代码。可以使用cv.useOptimized()函数来检查优化是否启用,以及使用cv.setUseOptimized()函数来手动启用或禁用优化。
# 检查是否启用优化
print(cv.useOptimized()) # 输出: True# 使用优化进行中值滤波,循环10次,计算平均每次循环的时间
%timeit res = cv.medianBlur(img, 49)# 禁用优化
cv.setUseOptimized(False)# 检查是否禁用了优化
print(cv.useOptimized()) # 输出: False# 禁用优化后进行中值滤波,循环10次,计算平均每次循环的时间
%timeit res = cv.medianBlur(img, 49)
在IPython中的测量方法
在IPython中,你可以使用神奇的timeit命令来完成这个任务。timeit通过多次运行代码获取准确的结果,同样也适用于单行代码。
比如,你想知道以下几种操作哪个更快:x = 5; y = x**2,x = 5; y = x * x,x = np.uint8([5]); y = x * x,或者是 y = np.square(x)。我们可以在IPython中找到答案。
x = 5%timeit y = x**2
# 输出结果:10000000 loops, best of 3: 73 ns per loop%timeit y = x * x
# 输出结果:10000000 loops, best of 3: 58.3 ns per loopz = np.uint8([5])%timeit y = z * z
# 输出结果:1000000 loops, best of 3: 1.25 us per loop%timeit y = np.square(z)
# 输出结果:1000000 loops, best of 3: 1.16 us per loop
你会发现,x = 5; y = x * x 的速度要比Numpy的快20倍。如果考虑到创建一个数组,这个差距可能会更大,这真的很酷(实际上,Numpy就是用来解决这类问题的)。
需要注意的是,Python的标量运算远比Numpy的快。所以,如果你只是对一两个元素进行操作,可能没有必要使用Numpy。Numpy的真正优势体现在大量数据的矩阵运算上。
接下来,我们尝试比较cv.countNonZero()和np.count_nonzero()函数在操作同一张图片时的性能表现。
%timeit z = cv.countNonZero(img)
# 输出结果:100000 loops, best of 3: 15.8 us per loop%timeit z = np.count_nonzero(img)
# 输出结果:1000 loops, best of 3: 370 us per loop
可以看到,OpenCV的函数比Numpy的快了大约25倍。
需要注意的是,通常情况下,OpenCV的函数比Numpy的函数更快。因此,在进行相同操作时,OpenCV的性能会更好。不过,也有一些例外情况,具体取决于操作的性质,特别是当Numpy使用视图而不是副本时。
改变颜色空间
图像从一个颜色空间转换到另外一个,就像 BGR ↔ Gray, BGR ↔ HSV ,等等。
创建一个应用程序来提取视频中的色彩对象。
函数:cv.cvtColor(),cv.inRange()等等。
注意:Note 对于 HSV,色调范围为 [0,179],饱和度范围为 [0,255],值范围为 [0,255]。不同的软件使用不同的尺度。因此,如果您将 OpenCV 值与它们进行比较,则需要对这些范围进行归一化。
改变颜色空间
在OpenCV中,有超过150种颜色空间转换方法,但我们通常关注其中两种最常用的:BGR到灰度(BGR ↔ Gray)和BGR到HSV(BGR ↔ HSV)的转换。
在颜色转换中,我们使用cv.cvtColor(input_img, flag)函数,其中flag参数用于确定转换的类型。
对于BGR到灰度的转换,我们将cv.COLOR_BGR2GRAY传递给flag参数。类似地,对于BGR到HSV的转换,我们将cv.COLOR_BGR2HSV传递给flag参数。可以在Python中运行以下代码:
import cv2 as cvflags = [i for i in dir(cv) if i.startswith('COLOR_')]print(flags)
需要注意的是,在HSV颜色空间中,色调范围是0,1790,179,饱和度范围是0,2550,255,值范围是0,2550,255。不同的软件使用不同的尺度。因此,如果你想将OpenCV中的值与其他软件进行比较,你需要对这些范围进行归一化处理。
对象追踪
现在,我们已经学会如何将一幅BGR图像转换成HSV颜色空间。接下来,我们可以利用这个知识来提取特定颜色的对象。在这个例子中,我们将尝试提取蓝色对象的图像。
以下是具体的步骤:
获取每一帧图像: 从视频中捕获每一帧图像。颜色空间转换: 将BGR图像转换为HSV颜色空间,这样更容易提取特定颜色的对象。颜色阈值处理: 在HSV颜色空间中,指定蓝色的阈值范围(lower_blue和upper_blue)。这样,我们可以定位在该范围内的蓝色像素。创建掩码: 使用cv.inRange()函数创建一个掩码,该掩码仅包含在指定蓝色范围内的像素。提取蓝色对象: 将掩码应用到原始图像上,使用cv.bitwise_and()函数,这样就可以提取出蓝色对象的图像。显示图像: 分别显示原始图像、掩码和提取出的蓝色对象的图像。等待用户操作: 等待用户按下键盘上的ESC键(ASCII码为27)来退出循环。释放资源: 当用户按下ESC键后,释放所有窗口资源。
import cv2 as cv
import numpy as npcap = cv.VideoCapture(0)while True:# 获取每一帧_, frame = cap.read()# 从BGR转换到HSVhsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)# 在HSV中定位蓝色范围lower_blue = np.array([110, 50, 50])upper_blue = np.array([130, 255, 255])# 设置HSV图像仅获得蓝色图像mask = cv.inRange(hsv, lower_blue, upper_blue)# 按位与掩码和原始图像res = cv.bitwise_and(frame, frame, mask=mask)# 显示图像cv.imshow('Original', frame)cv.imshow('Mask', mask)cv.imshow('Blue Object', res)# 等待用户按下ESC键退出k = cv.waitKey(5) & 0xFFif k == 27:break# 释放资源
cap.release()
cv.destroyAllWindows()
Note 图像中有些噪声。我们将在后面演示如何去除它。这个是一个简单的项目追踪方法。一旦你学会了轮廓的函数,你就可以做一系列事情,就像是找到一个物体的质心并用它去跟踪物体,或者是只需要在相机前移动你的手就可以画出图表,或者其他有趣的事情。
要找到需要跟踪的颜色的HSV值,可以使用OpenCV中的cv.cvtColor()函数。不需要传递整个图像,只需传递所需的BGR值即可。以下是一个示例,假设想找到绿色的HSV值:
import numpy as np
import cv2 as cv# 定义一个绿色的BGR值
green = np.uint8([[[0, 255, 0]]])# 将BGR转换为HSV
hsv_green = cv.cvtColor(green, cv.COLOR_BGR2HSV)print(hsv_green)
运行这段代码,会得到绿色的HSV值:[[[60 255 255]]]。现在,可以将这个HSV值作为跟踪绿色的下限(Lower Bound):[H-10, 100, 100],和上限(Upper Bound):[H+10, 255, 255]。在这个例子中,绿色的H值为60,所以下限为50,上限为70。这个范围可以根据实际情况微调。
另外,除了使用代码计算HSV值外,也可以使用图像编辑工具(如GIMP)或在线颜色转换器来找到这些值。但是请记住,确保在使用这些工具时调整HSV范围,因为不同的工具可能使用不同的HSV标准。
相关文章:

【OpenCV实现图像的算数运算,性能测试和优化,改变颜色空间】
文章目录 OpenCV功能概要图像的算数运算性能测试和优化改变颜色空间对象追踪 OpenCV功能概要 OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉和机器学习库,提供了丰富的图像处理和计算机视觉算法。它支持多种编程语言&…...

多级缓存入门
文章目录 什么是多级缓存JVM进程缓存环境准备安装MySQL导入Demo工程导入商品查询页面 初识Caffeine Lua语法初识Lua第一个lua程序变量和循环Lua的数据类型声明变量循环 条件控制、函数函数条件控制 多级缓存安装OpenRestyOpenResty快速入门反向代理流程OpenResty监听请求编写it…...
CentOS卸载LVM磁盘的方法
在客户环境上遇到一个问题,本身的磁盘满了,需要把没有用的lvm逻辑卷卸载掉,然后挂上去,下面记录一下过程。 卸载原磁盘 umount /data # 如果/data目录正在被其他进程使用中,则使用fuser强制关闭,然后Umou…...
ChatGPT:Spring Boot和Maven——Java应用开发的关键工具和区别
ChatGPT:Spring Boot和Maven——Java应用开发的关键工具和区别 Springboot是什么? ChatGPT: Spring Boot是一个用于构建Java应用程序的开源框架,它是Spring Framework的一部分,但旨在简化Spring应用程序的开发。Sprin…...

智能振弦传感器:参数智能识别技术的重要科技创新
智能振弦传感器:参数智能识别技术的重要科技创新 智能振弦传感器是一种能够自动识别传感器参数的高科技产品。它的研发得益于河北稳控科技的不断创新和努力,其电子标签专用读数模块模块TR01将传感器生产和标定过程实现了自动化。该模块将温度电阻两芯线…...

tooltip实现悬停内容染色
一: 通过highlight.js项目实现对json字符串的染色高亮 此项目是jsp文件,并且引用了element-ui/highlight.js的组件 二: 实现效果 三: 代码实现 关键点在于成功引入相关的js及css,并且在tooltip渲染时进行数据染色。再将染色后的数据放到v-html中进行页面渲染(关键方…...

“深入探讨Java JUC中的ReentrantLock锁:实现多线程同步与并发控制“
简介 1、从Java5开始,Java提供了一种功能更强大的线程同步机制——通过显式定义同步锁对象来实现同步,在这种机制下,同步锁由Lock对象充当。 2、Lock 提供了比synchronized方法和synchronized代码块更广泛的锁定操作,Lock允许实…...

Java|学习|多线程
1.多线程的一些概念 进程:是正在运行的程序 是系统进行资源分配和调用的独立单位 每一个进程都有它自己的内存空间和系统资源。 线程:是进程中的单个顺序控制流,是一条执行路径。 单线程:一个进程如果只有一条执行路径࿰…...
【Python机器学习】零基础掌握VotingClassifier集成学习
为什么一些数据预测模型在复杂场景下表现不如预期? 在当今数据驱动的世界中,企业和研究者面临着如何从大量数据中提取有价值信息的挑战。假设一个电商公司想要通过用户行为数据预测产品销量,通常会使用单一的算法模型,如逻辑回归、随机森林或朴素贝叶斯。但问题来了,如果…...

深入了解JavaScript中的AJAX和HTTP请求
在现代Web开发中,AJAX(Asynchronous JavaScript and XML)和HTTP请求被广泛应用于实现动态交互式网页。本文将深入探讨AJAX的概念、工作原理以及使用方法。 什么是AJAX? AJAX是一种利用JavaScript和HTTP请求与服务器进行异步通信的…...

第87步 时间序列建模实战:LSTM回归建模
基于WIN10的64位系统演示 一、写在前面 这一期,我们介绍大名鼎鼎的LSTM回归。 同样,这里使用这个数据: 《PLoS One》2015年一篇题目为《Comparison of Two Hybrid Models for Forecasting the Incidence of Hemorrhagic Fever with Renal…...

GB/T28181协议介绍
GB/T28181协议介绍 文章目录 GB/T28181协议介绍总体介绍GB/T28181基本结构GB/T28181关键协议流程设备注册设备目录查询实时视频播放流程 GB/T28181协议总结 说到GB/T28181协议,如果你是从事视频监控领域的工作,那对他一定不陌生,在公共安全、…...

光致发光荧光量子检测的作用
光致发光荧光量子检测是一种测试技术,可以用来测量荧光材料的荧光光谱、荧光量子效率和发光寿命等参数,具有高灵敏度、高分辨率和自动化程度高等优点。 光致发光荧光量子检测的应用范围广泛,可以应用于材料科学、生物科学、医学、光学器件、能…...

深度学习第四课
第九章 卷积神经网络解读 9.1 计算机视觉 目标分类 目标识别 64x64x312288 1000x1000x33000000 使用传统神经网络处理机器视觉面临的一个挑战是:数据的输入会非常大 一般的神经网络很难处理海量图像数据。解决这一问题的方法就是卷积神经网络 9.2 卷积运算 …...

Linux创建临时文件mkstemp()tmpfile()
有些程序需要创建一些临时文件,仅供其在运行期间使用,程序终止后即行删除。 很多编译器程序会在编译过程中创建临时文件。GNU C 语言函数库为此而提供了一系列库函数。(之所以有“一系列”的库函数,部分原因是由于这些函数分别继…...
js的节流和防抖详解
防抖和节流是JavaScript中的常见优化技巧,它们可以帮助我们控制代码在特定的时间间隔内执行的频率,从而优化性能。下面详细讲解它们的原理和使用方法。 防抖(Debounce): 防抖的原理是当一个事件频繁触发时࿰…...

基于SpringBoot的水果销售网站
基于SpringBootVue的水果销售网站系统的设计与实现~ 开发语言:Java数据库:MySQL技术:SpringBootMyBatis工具:IDEA/Ecilpse、Navicat、Maven角色:管理员、商家、用户 系统展示 主页 水果详情 可直接购买,…...

vue2进阶学习知识汇总
目录 1.组件之处理边界情况 1.1 子组件访问根组件数据 1.2 子组件访问父组件数据 1.3 父组件访问子组件 1.4 依赖注入 1.5 程序化的事件侦听器 1.6 递归组件 1.7 内联模板 1.8 X-Template 1.9 强制更新 1.10 v-once 2.过渡效果与状态 2.1 过渡效果 2.1.1 单元素/…...
SQL SERVER连接oracle数据库几种方法
--1 方式 --查询oracle数据库中的表 SELECT * FROM OPENDATASOURCE( MSDAORA, Data SourceGE160;User IDDAIMIN;PasswordDAIMIN )..DAIMIN.JOBS 举一反三:在查询分析器中输入: SELECT * FROM OPENDATASOURCE( MSDAORA, Data SourceORCL;User…...

存储优化知识复习三详细版解析
存储优化 知识复习三 一、 选择题 1、 数据库领域的三位图灵奖得主是( )。 A、C.W.Bachman B、E.F.Codd C、Peter Naur D、James Gray 【参考答案】ABD2、 数据库DB、数据库系统DBS、数据库管理系统DBMS三者之间得关系是( )。 A、DB&#…...
程序代码篇---Python串口
在 Python 里,serial库(一般指pyserial)是串口通信的常用工具。下面为你介绍其常用的读取和发送操作函数及使用示例: 1. 初始化串口 要进行串口通信,首先得对串口对象进行初始化,代码如下: i…...
AI不会杀死创作,但会杀死平庸
作为一个敲了8年Java代码的普通本科程序员,日常主要泡在会议后台管理系统的开发里。从2023年底被朋友拽着试了第一把AI工具到现在,电脑手机上的AI软件比外卖App还多——写代码的Copilot、画时序图的工具、聊天的ChatGPT、Deepseek,基本市面上…...
十一、【ESP32开发全栈指南: TCP通信服务端】
一、TCP与UDP协议对比 1.1 基本特性比较 TCP(传输控制协议)和UDP(用户数据报协议)是两种最常用的传输层协议,它们在ESP32网络编程中都有广泛应用: 连接方式 TCP是面向连接的协议,通信前需要先建立连接(三次握手)UDP是无连接的协议ÿ…...

RabbitMQ 学习
MQ 的相关概念 什么是 MQ MQ(message queue),从字面意思上看,本质是个队列,FIFO 先入先出,只不过队列中存放的内容是 message 而已,还是一种跨进程的通信机制,用于上下游传递消息。…...
5.1 HarmonyOS NEXT系统级性能调优:内核调度、I/O优化与多线程管理实战
HarmonyOS NEXT系统级性能调优:内核调度、I/O优化与多线程管理实战 在HarmonyOS NEXT的全场景生态中,系统级性能调优是构建流畅、高效应用的关键。通过内核调度精细化控制、存储与网络I/O深度优化,以及多线程资源智能管理,开发者…...

Windows账户管理,修改密码,创建帐户...(无需密码)
前言 我们使用wWindows操作系统时,账户是非常重要的概念 它不仅能够帮助我们区分文档主题权限等等 嗯还有最重要的解锁电脑的作用! 但想要管理他,不仅需要原本的密码,而且设置中的管理项也非常的不全。 Windows有一款netplwi…...

Java 大视界 -- 基于 Java 的大数据分布式计算在蛋白质组学数据分析中的加速与优化(255)
💖亲爱的朋友们,热烈欢迎来到 青云交的博客!能与诸位在此相逢,我倍感荣幸。在这飞速更迭的时代,我们都渴望一方心灵净土,而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识,也…...

MySQL体系架构解析(二):MySQL目录与启动配置全解析
MySQL中的目录和文件 bin目录 在 MySQL 的安装目录下有一个特别重要的 bin 目录,这个目录下存放着许多可执行文件。与其他系统的可执行文件类似,这些可执行文件都是与服务器和客户端程序相关的。 启动MySQL服务器程序 在 UNIX 系统中,用…...
uni-app 如何实现选择和上传非图像、视频文件?
在 uni-app 中实现选择和上传非图像、视频文件,可根据不同端(App、H5、小程序)的特点,采用以下方法: 一、通用思路(多端适配优先推荐) 借助 uni.chooseFile 选择文件,再用 uni.upl…...

分布式锁-Redisson实现
目录 本地锁的局限性 Redisson解决分布式锁问题 在分布式环境下,分布式锁可以保证在多个节点上的并发操作时数据的一致性和互斥性。分布式锁有多种实现方案,最常用的两种方案是:zookeeper和redis,本文介绍redis实现分布式锁方案…...