04- 图像卷积及图片的模糊和边缘检测 (OpenCV基础) (机器视觉)

news2024/11/14 15:22:52

知识重点

  • padding指的就是填充的0的圈数
  • 重构图片大小:  img = cv2.resize(img, dsize=(300, 300))
  • 模糊操作:  dst = cv2.filter2D(img, -1, kernel)
kernel = np.ones((5, 5), np.float32)/ 25
dst = cv2.filter2D(img, -1, kernel)  # 卷积操作

模糊操作:

  • 方盒滤波:  dst = cv2.boxFilter(img, -1, (5, 5), normalize = True)   # normalize = True时, a = 1 / (W * H) 滤波器的宽高, 且此时方盒滤波等价于均值滤波 .
  • 均值滤波:  dst = cv2.blur(img, (5, 5))  # blur 模糊不清
  • 高斯滤波:  dst = cv2.GaussianBlur(img, (25, 25), sigmaX = 0)   # 高斯滤波的核心思想是让临近的像素具有更高的重要度. 对周围像素计算加权平均值, 较近的像素具有较大的权重值.
    • 高斯滤波适用于处理有噪点的文件, 降噪.
  • 中值滤波:  dst = cv2.medianBlur(img, 9)    # 取其中的中间值(即中位数)作为卷积后的结果值, 适用于处理有噪声的文件 .
  • 双边滤波对于图像的边缘信息能过更好的保存。其原理为一个与空间距离相关的高斯函数与一个灰度距离相关的高斯函数相乘双边滤波既利用了位置信息又利用了像素信息来定义滤波窗口的权重而高斯滤波只用了位置信息 。
    • dst = cv2.bilateralFilter(img, 7, sigmaColor = 50, sigmaSpace = 20)

边缘检测:

  • 索贝尔算子 : dx = cv2.Sobel(img, -1, dx = 1, dy = 0, ksize = 1)    # sobel算子对图像求一阶导数。一阶导数越大,说明像素在该方向的变化越大,边缘信号越强。
  • 沙尔算子:  dx = cv2.Scharr(img, cv2.CV_64F, dx = 1, dy = 0)    # Scharr算子和Sobel很类似, 只不过使用不同的kernel值, 放大了像素变换的情况:
  • 拉普拉斯算子: 可以同时求两个方向的边缘, 对噪音敏感, 需要先进行去噪再调用拉普拉斯。
    • dst = cv2.Laplacian(img, -1, ksize = 3)    # 适用于处理有噪声的文件
  • Canny: 被很多人认为是边缘检测的 最优算法,  阈值越小, 细节越丰富。
    • lena2 = cv2.Canny(img, 64, 128)


5. 滤波器

5.1 卷积

5.1.1 什么是图片卷积

图像卷积就是卷积核在图像上按行滑动遍历像素时不断的相乘求和的过程 .

                      

5.1.2 步长

步长就是卷积核在图像上移动的步幅. 上面例子中卷积核每次移动一个像素步长的结果, 如果将这个步长修改为2, 结果如何?

为了充分扫描图片, 步长一般设为1.

5.1.3 padding

从上面例子中我们发现, 卷积之后图片的长宽会变小. 如果要保持图片大小不变, 我们需要在图片周围填充0. padding指的就是填充的0的圈数.

我们可以通过公式计算出需要填充的0的圈数.

        

如果要保持卷积之后图片大小不变, 可以得出等式: \small (N + 2P - F + 1) = N从而可以推导出: \small P = \frac{F -1}{2}

5.1.4 卷积核的大小

图片卷积中, 卷积核一般为奇数, 比如 3 * 3, 5 * 5, 7 * 7.为什么一般是奇数呢, 出于以下两个方面的考虑:

  1. 根据上面padding的计算公式, 如果要保持图片大小不变, 采用偶数卷积核的话, 比如4 * 4, 将会出现填充1.5圈零的情况.

  2. 奇数维度的过滤器有中心,便于指出过滤器的位置, 即OpenCV卷积中的锚点.

5.1.5 卷积案例

  • filter2D(src, ddepth, kernel[, dst[, anchor[, delta[, borderType]]]])

    • ddepth是卷积之后图片的位深, 即卷积之后图片的数据类型, 一般设为-1, 表示和原图类型一致.

    • kernel是卷积核大小, 用元组或者ndarray表示, 要求数据类型必须是float型.

    • anchor 锚点, 即卷积核的中心点, 是可选参数, 默认是(-1,-1)

    • delta 可选参数, 表示卷积之后额外加的一个值, 相当于线性方程中的偏差, 默认是0.

    • borderType 边界类型.一般不设.

# opencv 中的卷积操作
import cv2
import numpy as np

img = cv2.imread('./dog.jpeg')
# kernel 必须是float类型
kernel = np.ones((5, 5), np.float32)/ 25

# 卷积操作
dst = cv2.filter2D(img, -1, kernel)

cv2.imshow('img', np.hstack((img, dst)))
cv2.waitKey(0)
cv2.destroyAllWindows()
  • 卷积核为 5*5, 将所有数据均匀分布, 以周边25个元素分别取 1/25 然后合并来得到中间值.

浮雕效果操作

# opencv 中的卷积操作
import cv2
import numpy as np

gray_img = cv2.imread('./dog.jpeg')
# gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# kernel 必须是float类型
# kernel = np.ones((5, 5), np.float32)/ 25
kernel = np.array([[-4, 1, 0], [-1, 1, 1], [1, 1, 1]])
# 卷积操作
dst = cv2.filter2D(gray_img, -1, kernel)

cv2.imshow('gray_img', np.hstack((gray_img, dst)))
cv2.waitKey(0)
cv2.destroyAllWindows()

锐化效果操作

# opencv 中的卷积操作
import cv2
import numpy as np

img = cv2.imread('./dog.jpeg')
# kernel 必须是float类型
# kernel = np.ones((5, 5), np.float32)/ 25
kernel = np.array([[0, -1, 0], [-1, 5, -1], [0, -1, 0]])
# 卷积操作
dst = cv2.filter2D(img, -1, kernel)

cv2.imshow('img', np.hstack((img, dst)))
cv2.waitKey(0)
cv2.destroyAllWindows()

5.2 方盒滤波与均值滤波

  • boxFilter(src, ddepth, ksize[, dst[, anchor[, normalize[, borderType]]]])  方盒滤波.

    • 方盒滤波的卷积核的形式如下:

    • normalize = True时, a = 1 / (W * H) 滤波器的宽高

    • normalize = False是. a = 1

    • 一般情况我们都使用normalize = True的情况. 这时 方盒滤波 等价于 均值滤波

# opencv 中的卷积操作
import cv2
import numpy as np

img = cv2.imread('./dog.jpeg')
# 不用手动创建卷积核,只需要告诉方盒滤波,卷积核的大小
dst = cv2.boxFilter(img, -1, (5, 5), normalize = True)  # destination 目标

cv2.imshow('img', np.hstack((img, dst)))
cv2.waitKey(0)
cv2.destroyAllWindows()

  •  blur(src, ksize[, dst[, anchor[, borderType]]]) 均值滤波.
# 均值滤波
import cv2
import numpy as np

img = cv2.imread('./dog.jpeg')
# 不用手动创建卷积核,只需要告诉方盒滤波,卷积核的大小
# 均值滤波没有 位深这个操作
dst = cv2.blur(img, (5, 5))  # blur 模糊不清

cv2.imshow('img', np.hstack((img, dst)))
cv2.waitKey(0)
cv2.destroyAllWindows()

5.3 高斯滤波

高斯滤波的核心思想是让临近的像素具有更高的重要度. 对周围像素计算加权平均值, 较近的像素具有较大的权重值.要理解高斯滤波首先要知道什么是高斯函数.高斯函数在是符合高斯分布(也叫正态分布)的数据的概率密度函数.画出来长这样子:

高斯函数的特点是以x轴某一点(这一点称为均值)为对称轴, 越靠近中心数据发生的概率越高, 最终形成一个两边平缓, 中间陡峭的钟型(有的地方也叫帽子)图形.

高斯函数的一般形式为:

高斯滤波就是使用符合高斯分布的卷积核对图片进行卷积操作. 所以高斯滤波的重点就是如何计算符合高斯分布的卷积核, 即高斯模板.

假定中心点的坐标是(0,0),那么取距离它最近的8个点坐标,为了计算,需要设定σ的值。假定σ=1.5,则模糊半径为1的高斯模板就算如下:

我们可以观察到越靠近中心, 数值越大, 越边缘的数值越小.符合高斯分布的特点.

通过高斯函数计算出来的是概率密度函数, 所以我们还要确保这九个点加起来为1,这9个点的权重总和等于0.4787147,因此上面9个值还要分别除以0.4787147,得到最终的高斯模板。

注: 有些整数高斯模板是在归一化后的高斯模板的基础上每个数除上左上角的值, 然后取整.

 有了卷积核, 计算高斯滤波.假设现有9个像素点,灰度值(0-255)的高斯滤波计算如下:

将这9个值加起来,就是中心点的高斯滤波的值。对所有点重复这个过程,就得到了高斯模糊后的图像。

  • GaussianBlur(src, ksize, sigmaX[, dst[, sigmaY[, borderType]]])

    • kernel 高斯核的大小.

    • sigmaX, X轴的标准差

    • sigmaY, Y轴的标准差, 默认为0, 这时sigmaY = sigmaX

    • 如果没有指定sigma值, 会分别从ksize的宽度和高度中计算sigma.

  • 选择不同的sigma值会得到不同的平滑效果, sigma越大, 平滑效果越明显.

import cv2
import numpy as np
img = cv2.imread('./lena.png')
print(img.shape)
img = cv2.resize(img, dsize=(300, 300))

dst = cv2.GaussianBlur(img, (25, 25), sigmaX = 0)
# 可以不指定 sigma,, 指定为0, 使用ksize 指定
dst1 = cv2.GaussianBlur(img, (25, 25), sigmaX = 1)
dst2 = cv2.GaussianBlur(img, (25, 25), sigmaX = 3)
dst3 = cv2.GaussianBlur(img, (25, 25), sigmaX = 5)

cv2.imshow('img', np.hstack((img, dst, dst1, dst2, dst3)))
cv2.waitKey(0)
cv2.destroyAllWindows()
  •  当sigma 为0时, 自动模糊 .

  •  没有指定sigma时, ksize越大, 平滑效果越明显
import cv2
import numpy as np
img = cv2.imread('./lena.png')
print(img.shape)
img = cv2.resize(img, dsize=(300, 300))

dst = cv2.GaussianBlur(img, (3, 3), sigmaX = 3)
# 可以不指定 sigma,, 指定为0, 使用ksize 指定
dst1 = cv2.GaussianBlur(img, (7, 7), sigmaX = 3)
dst2 = cv2.GaussianBlur(img, (15, 15), sigmaX = 3)
dst3 = cv2.GaussianBlur(img, (63, 63), sigmaX = 3)

cv2.imshow('img', np.hstack((img, dst, dst1, dst2, dst3)))
cv2.waitKey(0)
cv2.destroyAllWindows()

 高斯滤波实战

  • 适用于处理有噪声的文件, 减少噪点 .
import cv2
import numpy as np

img = cv2.imread('./gaussian.png')  # 适用于处理有噪声的文件
dst = cv2.GaussianBlur(img, (5,5), sigmaX = 1)
# 可以不指定 sigma,, 指定为0, 使用ksize 指定
dst = cv2.GaussianBlur(img, (25, 25), sigmaX = 0)

cv2.imshow('img', np.hstack((img, dst)))
cv2.waitKey(0)
cv2.destroyAllWindows()

5.4 中值滤波

中值滤波原理非常简单, 假设有一个数组[1556789], 取其中的中间值(即中位数)作为卷积后的结果值即可. 中值滤波对胡椒噪音(也叫椒盐噪音)效果明显.

#  中值滤波
import cv2
import numpy as np

img = cv2.imread('./papper.png')  # 适用于处理有噪声的文件
dst = cv2.medianBlur(img, 9)     # 中值滤波

cv2.imshow('img', np.hstack((img, dst)))
cv2.waitKey(0)
cv2.destroyAllWindows()

5.5 双边滤波

双边滤波对于图像的边缘信息能过更好的保存。其原理为一个与空间距离相关的高斯函数与一个灰度距离相关的高斯函数相乘

双边滤波本质上是高斯滤波, 双边滤波和高斯滤波不同的就是: 双边滤波既利用了位置信息又利用了像素信息来定义滤波窗口的权重。而高斯滤波只用了位置信息 。

两者权重系数相乘,得到最终的卷积模板。由于双边滤波需要每个中心点邻域的灰度信息来确定其系数,所以其速度与比一般的滤波慢很多,而且计算量增长速度为核大小的平方,双边滤波可以保留边缘, 同时可以对边缘内的区域进行平滑处理. 双边滤波的作用就相当于做了美颜。

bilateralFilter(src, d, sigmaColor, sigmaSpace[, dst[, borderType]])

  • sigmaColor是计算像素信息使用的sigma

  • sigmaSpace是计算空间信息使用的sigma

import cv2
import numpy as np

img = cv2.imread('./lena.png')  # 适用于处理有噪声的文件
#  双边滤波
dst = cv2.bilateralFilter(img, 7, sigmaColor = 50, sigmaSpace = 20)

cv2.imshow('img', np.hstack((img, dst)))
cv2.waitKey(0)
cv2.destroyAllWindows()

5.6 索贝尔(sobel)算子

边缘是像素值发生跃迁的位置,是图像的显著特征之一,在图像特征提取,对象检测,模式识别等方面都有重要的作用。比如有一幅图,图里面有一条线,左边很亮,右边很暗,那人眼就很容易识别这条线作为边缘.也就是像素的灰度值快速变化的地方.

sobel算子对图像求一阶导数一阶导数越大,说明像素在该方向的变化越大,边缘信号越强。因为图像的灰度值都是离散的数字, sobel算子采用离散差分算子计算图像像素点亮度值的近似梯度.  图像是二维的, 即沿着宽度/高度两个方向. 我们使用两个卷积核对原图像进行处理:

  • 水平方向

  • 垂直方向

这样的话,我们就得到了两个新的矩阵,分别反映了每一点像素在水平方向上的亮度变化情况和在垂直方向上的亮度变换情况.综合考虑这两个方向的变化,我们使用以下公式反映某个像素的梯度变化情况.

        \small G= \sqrt{G^2_x+G^2_y}

有时候为了简单起见,也直接用绝对值相加替代 \small G = |G_X| + |G_Y|.​

import cv2
import numpy as np

img = cv2.imread('./chess.png')  # 适用于处理有噪声的文件
img = cv2.resize(img, dsize=(450, 450))
# 计算X轴方向的梯度,只有垂直方向的边缘
dx = cv2.Sobel(img, -1, dx = 1, dy = 0, ksize = 1)
# 计算Y轴方向的梯度, 只有水平方向的边缘
dy = cv2.Sobel(img, -1, dx = 0, dy = 1, ksize = 5)
# 使用sobel 算子,别忘了把x, y 的梯度合并在一起
# dst = cv2.add(dx, dy)
dst = cv2.addWeighted(dx, 2, dy, 2, gamma = 1)  # 等同于cv2.add()

cv2.imshow('dx:', np.hstack((img, dx, dy, dst)))
cv2.waitKey(0)
cv2.destroyAllWindows()

5.7 沙尔(Scharr)算子

  • Scharr(src, ddepth, dx, dy[, dst[, scale[, delta[, borderType]]]])

  • 内核大小为 3 时, 以上Sobel内核可能产生比较明显的误差(毕竟,Sobel算子只是求取了导数的近似值)。 为解决这一问题,OpenCV提供了 Scharr函数,但该函数仅作用于大小为3的内核。该函数的运算与Sobel函数一样快,但结果却更加精确.

  • Scharr算子和Sobel很类似, 只不过使用不同的kernel值, 放大了像素变换的情况:

  • Scharr算子只支持3 * 3 的kernel所以没有kernel参数了.

  • Scharr算子只能求x方向或y方向的边缘.

  • Sobel算子的ksize设为-1就是Scharr算子.

  • Scharr擅长寻找细小的边缘, 一般用的较少.

import cv2
import numpy as np

img = cv2.imread('./lena.png')  # 适用于处理有噪声的文件
img = cv2.resize(img, dsize=(450, 450))
# 计算X轴方向的梯度,只有垂直方向的边缘
dx = cv2.Scharr(img, cv2.CV_64F, dx = 1, dy = 0)
# 计算Y轴方向的梯度, 只有水平方向的边缘
dy = cv2.Scharr(img, cv2.CV_64F, dx = 0, dy = 1)
# 使用sobel 算子,别忘了把x, y 的梯度合并在一起
# dst = cv2.add(dx, dy)
dst = cv2.addWeighted(dx, 2, dy, 2, gamma = 1)

cv2.imshow('img:', img)
cv2.imshow('img', np.hstack((dx, dy, dst)))
cv2.waitKey(0)
cv2.destroyAllWindows()

5.8 拉普拉斯算子

索贝尔算子是模拟一阶求导,导数越大的地方说明变换越剧烈,越有可能是边缘.

那如果继续对f'(t)求导呢?

可以发现"边缘处"的二阶导数=0, 我们可以利用这一特性去寻找图像的边缘. 注意有一个问题,二阶求导为0的位置也可能是无意义的位置.

  • 拉普拉斯算子推导过程

    • 以x方向求解为例:  \small f''(x) = f(x - 1) - 2 f(x)) + f(x + 1)

    • 同理可得:   f''(y) = f(y - 1) - 2 f(y)) + f(y + 1)

    • 把x,y方向的梯度叠加在一起:

          \small f''(x,y) = \left[\begin{matrix}0 & 1 & 0\\1 & -4 & 1\\0 & 1 & 0\end{matrix}\right] \bigodot \left[\begin{matrix}f(x-1, y-1) & f(x, y-1) & f(x+1,y-1)\\f(x-1,y) & f(x,y) & f(x+1,y)\\f(x-1,y+1) & f(x,y+1) & f(x+1,y+1)\end{matrix}\right]

  • Laplacian(src, ddepth[, dst[, ksize[, scale[, delta[, borderType]]]]])

  • 可以同时求两个方向的边缘 .

  • 对噪音敏感, 一般需要先进行去噪再调用拉普拉斯 .

import cv2
import numpy as np

img = cv2.imread('./chess.png')  # 适用于处理有噪声的文件
dst = cv2.Laplacian(img, -1, ksize = 3)

cv2.imshow('img', np.hstack((img, dst)))
cv2.waitKey(0)
cv2.destroyAllWindows()

  •  lena 图片使用拉普拉斯算子 的结果

  • 中值滤波及拉普拉斯算子
import cv2
import numpy as np

img = cv2.imread('./papper.png')  # 适用于处理有噪声的文件
# 中值滤波
dst = cv2.medianBlur(img, 9)
lap = cv2.Laplacian(dst, -1, ksize = 3)  # 拉普拉斯算子

cv2.imshow('img', np.hstack((img, dst, lap)))
cv2.waitKey(0)
cv2.destroyAllWindows()

5.9 边缘检测Canny

Canny 边缘检测算法 是 John F. Canny 于 1986年开发出来的一个多级边缘检测算法,也被很多人认为是边缘检测的 最优算法, 最优边缘检测的三个主要评价标准是:

  • 低错误率: 标识出尽可能多的实际边缘,同时尽可能的减少噪声产生的误报。

  • 高定位性: 标识出的边缘要与图像中的实际边缘尽可能接近。

  • 最小响应: 图像中的边缘只能标识一次。

  • Canny边缘检测的一般步骤:

    • 去噪. 边缘检测容易受到噪声影响, 在进行边缘检测前通常需要先进行去噪, 一般用高斯滤波去除噪声.

    • 计算梯度: 对平滑后的图像采用sobel算子计算梯度和方向.

    • 非极大值抑制

      • 在获取了梯度和方向后, 遍历图像, 去除所有不是边界的点.

      • 实现方法: 逐个遍历像素点, 判断当前像素点是否是周围像素点中具有相同方向梯度的最大值.

      • 下图中, 点A,B,C具有相同的方向, 梯度方向垂直于边缘.

      • 判断点A是否为A,B,C中的局部最大值, 如果是, 保留该点;否则,它被抑制(归零)

    • 滞后阈值

  • Canny(img, minVal, maxVal, ...)

import cv2
import numpy as np

img = cv2.imread('./lena.png')
# 阈值越小,细节越丰富
lena1 = cv2.Canny(img, 100, 200)
lena2 = cv2.Canny(img, 64, 128)

cv2.imshow('img', img)
cv2.imshow('lena', np.hstack((lena1, lena2)))
cv2.waitKey(0)
cv2.destroyAllWindows()

import cv2
import numpy as np

img = cv2.imread('./chess.png')
# 阈值越小,细节越丰富
lena1 = cv2.Canny(img, 100, 200)
lena2 = cv2.Canny(img, 64, 128)

cv2.imshow('img', img)
cv2.imshow('lena', np.hstack((lena1, lena2)))
cv2.waitKey(0)
cv2.destroyAllWindows()

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

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

相关文章

AD使用教程 图文并茂 AD2020四层板

文章目录设计流程图:资源下载:自定义快捷键:(按照个人习惯)默认快捷键:一、软件主页面1.主界面2.Panels面板3.系统设置3.自定义快捷键4.新建工程二、原理图库1.原理图库面板2.管脚属性三、原理图绘制绘制步…

C++011-C++循环+枚举

文章目录C011-C循环枚举枚举枚举思想枚举举例题目描述 统计因数题目描述 质数判定错误方法一:优化方法1: 用break实现优化优化方法2: sqrt(n)题目描述 水仙花数题目描述 7744问题实现方法1优化方法2题目描述 余数相同问题题目描述 特殊自然数…

《第一行代码》 第六章:数据库与存储方案

一,持久化技术简介 也就是数据存储在内存中,会丢失。需要存储在存储设备中。而持久化技术,就是提供了手段,让数据再试瞬时状态和持久状态之间转换。 安卓开发提供了三种数据的持久化技术: 二,文件存储 …

【HDFS】FsDatasetImpl#getReplicaVisibleLength

调用点 DataNode.getReplicaVisibleLength(ExtendedBlock) (org.apache.hadoop.hdfs.server.datanode) // ClientDataNodeProtocolBlockChecksumComputer in BlockChecksumHelper.BlockChecksumComputer(DataNode, ExtendedBlock, BlockChecksumOptions) (org.apache.hadoop.hd…

ros中时间的概念:ros::Time、ros::Duration、定时器ros::Timerros::Rate、ros::WallTime

1. ros时间格式说明 有时刻和持续时长(可以是负数),分为秒和纳秒,换算关系:1sec1e9nsec。Time指的是某个时刻,而Duration指的是某个时段。 int32 sec int32 nsec 2. ros::Time::now() 记录当前时刻 3. ros::Duration 代表持续的…

Linux 输出重定向 “>”、“>>”、“freopen”

有时候,我们编码时会使用printf或fprintf去打印输出调试信息或者报错信息,但正常这样去打印,只会显示在终端,如果终端关闭了,或者系统宕机了等,这些输出信息就没有了,为了将这些重要的信息保存下…

java诊断与调优常用命令jmap、jstack、jstat使用实战

java应用运行过程中难免会出现问题,特别是在生产环境,发生异常或宕机情况,需要诊断与分析,定位原因,进行优化,避免下次再次出现问题。 虽然现在有很多可视化工具,使用起来比命令行更方便&#x…

开学季好用电容笔有哪些?好用实惠的电容笔推荐

随着科学技术的快速发展,ipad的影响力越来越大,而且ipad的用户也越来越多,如果要提高ipad的功能,让ipad更加有趣,那么就需要一款非常适合自己,并且非常实用的电容笔。那么,究竟该选择哪个品牌的…

SpringBoot整合分布式锁redisson

1、导入maven坐标<!-- 用redisson作为所有分布式锁&#xff0c;分布式对象等功能框架--><dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.12.5</version></dependency>2、red…

蓝牙 - BLE中的连接和扫描参数设定

连接参数 / Connection Parameters 连接参数由发起设备与连接请求一起发送&#xff0c;当连接建立后&#xff0c;任何一个设备都可以修改。这些参数如下&#xff1a; 连接间隔 / Connection Interval 在低功耗蓝牙连接中&#xff0c;使用了跳频方案。两台设备发送各自数据和接…

day48【代码随想录】动态规划之最长递增子序列、最长连续递增序列、最长重复子数组

文章目录前言一、最长递增子序列&#xff08;力扣300&#xff09;二、最长连续递增序列&#xff08;力扣674&#xff09;三、最长重复子数组&#xff08;力扣718&#xff09;前言 1、最长递增子序列 2、最长连续递增序列 3、最长重复子数组 一、最长递增子序列&#xff08;力扣…

rocketmq延时消息自定义配置;topic下tag使用

概述 使用的是开源版本的rocketmq4.9.4 rocketmq也是支持延时消息的。 rocketmq一般是4个部分&#xff1a; nameserver&#xff1a;保存路由信息broker&#xff1a;保存消息生产者&#xff1a;生产消息消费者&#xff1a;消费消息 延时消息的处理是在其中的broker中。 但是…

我为什么放弃WinUI3

基于WinUI3开发HiNote已经有一个多月的时间了&#xff0c;算是做出来一个简单能用的C端软件。 基于个人的经历&#xff0c;说说其中的开发体验。 UI设计语言 无论是否抄袭苹果&#xff0c;WinUI3给人的感觉都是眼前一亮的。简洁美观&#xff0c;现代化&#xff0c;毛玻璃的美…

rk3568网口CAN串口通信速率性能

通信接口性能参数外设接口性能参数测试结果为实验室实测值&#xff0c;可作为设计参考&#xff0c;但因测试环境和器件批次差异&#xff0c;可能会存在一定的误差&#xff0c;且测试结果依赖评估板性能&#xff0c;核心板搭配不同底板性能也可能存在差异&#xff0c;请结合实际…

Redis之分布式锁

随着业务发展的需要&#xff0c;原单体单机部署的系统被演化成分布式集群系统后&#xff0c;由于分布式系统多线程、多进程并且分布在不同机器上&#xff0c;这将使原单机部署情况下的并发控制锁策略失效&#xff0c;单纯的 Java API并不能提供分布式锁的能力。为了解决这个问题…

Java:顶级Java应用程序服务器 — Tomcat、Jetty、GlassFish、WildFly

如果你想编写Java web应用程序&#xff0c;首先需要做出一个艰难的决定&#xff1a;选择运行应用程序的Java应用程序服务器。什么是应用服务器?一般来说&#xff0c;应用程序服务器执行Java应用程序。在操作系统中启动它们&#xff0c;然后将应用程序部署到其中。将应用程序服…

盘点2023年大企业都在用的优秀项目管理软件

行内有句话&#xff1a;每个成功的项目背后肯定有一个成功的项目经理&#xff0c;而每个项目经理背后都少不了一些专业的项目管理工具。要在任何项目中取得成功&#xff0c;对项目进行全面的管理非常关键&#xff0c;包括项目的执行、计划、推进、监控、结果等&#xff0c;有了…

谈谈我对ai发展的看法

最近难得有时间&#xff0c;通过白话&#xff0c;聊聊我对AI的看法&#xff0c;仅代表个人观点首先表明我的观点&#xff1a;人类当前的人工智能成果&#xff0c;仍然停留在一知半解程度。技术的发展是需要长期的积累和进步&#xff0c;目前AI的发展仍处于入门阶段人类的发展必…

ar远程协助可视化云平台提高患者的医疗体验

“专家的指导意见很科学&#xff0c;患者恢复很快&#xff0c;情况稳定就可以转入普通病房了!这种云急救对基层医院来说太及时太必要了!大专家不用奔波&#xff0c;我们又提高了救治能力和效率!”这是来自某市基层主任的心里话。 传统远程协助的局限性 传统远程带来了便捷的线上…

【Java基础】输入与输出

输入与输出 输入 获取用键盘输入常用的两种方法 方法 1&#xff1a;通过 Scanner Scanner input new Scanner(System.in); String s input.nextLine(); input.close();方法 2&#xff1a;通过 BufferedReader BufferedReader input new BufferedReader(new InputStrea…