OpenCV 图像处理核心技术 (第二部分)
欢迎来到 OpenCV 图像处理的第二部分!在第一部分,我们学习了如何加载、显示、保存图像以及访问像素等基础知识。现在,我们将深入探索如何利用 OpenCV 提供的强大工具来修改和分析图像。
图像处理是计算机视觉领域的基石。通过对图像进行各种操作,我们可以改善图像质量、提取重要特征、准备图像用于更复杂的任务(如目标识别或图像分割)。
本部分将涵盖以下关键主题:
- 图像增强与滤波
- 亮度与对比度调整
- 图像平滑(均值滤波、高斯滤波)
- 图像锐化(拉普拉斯算子)
- 图像形态学操作
- 腐蚀与膨胀
- 开运算与闭运算
- 形态学梯度
- 边缘检测
- Sobel 算子
- Canny 边缘检测
- 实战:检测图像中的边缘
让我们开始吧!
1. 图像增强与滤波
图像增强旨在改善图像的视觉效果或为后续处理提供更好的输入。滤波则是通过对图像像素及其邻域像素进行计算,来达到平滑、锐化或提取特征的目的。
1.1 亮度与对比度调整
调整图像的亮度和对比度是最常见的图像增强操作之一。
- 亮度 (Brightness): 控制图像的整体明暗程度。增加亮度就像给图像"加光"。
- 对比度 (Contrast): 控制图像中明暗区域之间的差异程度。增加对比度会使亮区更亮,暗区更暗,图像看起来更"鲜明"。
数学上,简单的亮度和对比度调整可以通过线性变换实现:
OpenCV 提供了 cv2.convertScaleAbs()
函数来实现这个线性变换,并且会自动处理像素值超出 [0, 255] 范围的情况(截断到 0 或 255)。
Python
import cv2
import numpy as np# --- 练习 1.1: 调整图像亮度与对比度 ---# 1. 加载图像
# 请替换成你自己的图片路径
image_path = 'your_image.jpg'
try:image = cv2.imread(image_path)if image is None:raise FileNotFoundError(f"图片文件未找到: {image_path}")
except FileNotFoundError as e:print(e)print("请确保你的图片文件存在并位于正确路径。")# 使用一个虚拟图片代替,以便代码可以运行(实际操作中请替换)image = np.zeros((300, 500, 3), dtype=np.uint8)cv2.putText(image, "Image not found", (50, 150), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2)cv2.putText(image, "Please replace 'your_image.jpg'", (50, 200), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)print(f"原始图像尺寸: {image.shape}")# 2. 定义调整参数
alpha = 1.5 # 对比度控制 (增益),大于1增强对比度
beta = 30 # 亮度控制 (偏置),正数增加亮度# 3. 应用线性变换进行亮度与对比度调整
# 注意: cv2.convertScaleAbs 会自动将结果转换为 uint8 并取绝对值 (虽然对于亮度/对比度调整,结果通常是非负的)
adjusted_image = cv2.convertScaleAbs(image, alpha=alpha, beta=beta)# 4. 显示原始图像和调整后的图像
cv2.imshow('Original Image', image)
cv2.imshow('Adjusted Image (alpha=1.5, beta=30)', adjusted_image)# 5. 尝试不同的参数组合
alpha_low_contrast = 0.7
beta_dark = -50
adjusted_low_contrast_dark = cv2.convertScaleAbs(image, alpha=alpha_low_contrast, beta=beta_dark)
cv2.imshow('Adjusted Image (alpha=0.7, beta=-50)', adjusted_low_contrast_dark)# 等待按键,然后关闭窗口
cv2.waitKey(0)
cv2.destroyAllWindows()print("\n--- 练习 1.1 完成 ---")
练习提示:
- 尝试不同的
alpha
和beta
值,观察图像的变化。 alpha
可以是小数(例如 0.5 会降低对比度)。beta
可以是负数(例如 -50 会降低亮度)。
1.2 图像平滑 (滤波)
图像平滑(也称为模糊)是一种常用的滤波技术,主要用于减少图像中的噪声或在进行边缘检测等操作前平滑图像。平滑的原理是使用一个核(Kernel)或掩膜(Mask)与图像进行卷积。核是一个小矩阵,它在图像上滑动,在每个位置,将核的元素与对应的图像像素值相乘,然后将结果求和,得到中心像素的新值。
均值滤波 (Mean Filter)
Python
import cv2
import numpy as np# --- 练习 1.2.1: 均值滤波 ---# 1. 加载图像
image_path = 'your_image.jpg'
try:image = cv2.imread(image_path)if image is None:raise FileNotFoundError(f"图片文件未找到: {image_path}")
except FileNotFoundError as e:print(e)print("请确保你的图片文件存在并位于正确路径。")image = np.zeros((300, 500, 3), dtype=np.uint8)cv2.putText(image, "Image not found", (50, 150), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2)cv2.putText(image, "Please replace 'your_image.jpg'", (50, 200), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)# 2. 定义核的大小 (必须是正奇数,如 (3, 3), (5, 5) 等)
ksize_mean = (5, 5)# 3. 应用均值滤波
# cv2.blur() 函数用于进行均值滤波
# 参数: src (输入图像), ksize (核大小)
mean_blurred_image = cv2.blur(image, ksize_mean)# 4. 显示原始图像和均值滤波后的图像
cv2.imshow('Original Image', image)
cv2.imshow(f'Mean Blurred Image (ksize={ksize_mean})', mean_blurred_image)# 5. 尝试不同的核大小
ksize_mean_large = (15, 15)
mean_blurred_image_large = cv2.blur(image, ksize_mean_large)
cv2.imshow(f'Mean Blurred Image (ksize={ksize_mean_large})', mean_blurred_image_large)cv2.waitKey(0)
cv2.destroyAllWindows()print("\n--- 练习 1.2.1 完成 ---")
练习提示:
- 尝试使用不同大小的核。核越大,平滑效果越明显,但图像细节丢失越多。
- 均值滤波对去除“椒盐噪声”等随机噪声有一定效果。
高斯滤波 (Gaussian Filter)
高斯滤波是一种更常用的平滑滤波器。它使用一个符合高斯分布(正态分布)的核。与均值滤波不同,高斯核中的元素不是相等的,而是距离核中心越近的元素权重越大,距离越远权重越小。这使得高斯滤波在平滑图像的同时,能够更好地保留边缘信息。
高斯核的形状由标准差 σ 控制。σ 越大,核越“胖”,平滑范围越大。
Python
import cv2
import numpy as np# --- 练习 1.2.2: 高斯滤波 ---# 1. 加载图像
image_path = 'your_image.jpg'
try:image = cv2.imread(image_path)if image is None:raise FileNotFoundError(f"图片文件未找到: {image_path}")
except FileNotFoundError as e:print(e)print("请确保你的图片文件存在并位于正确路径。")image = np.zeros((300, 500, 3), dtype=np.uint8)cv2.putText(image, "Image not found", (50, 150), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2)cv2.putText(image, "Please replace 'your_image.jpg'", (50, 200), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)# 2. 定义核的大小 (必须是正奇数) 和 高斯标准差 (sigmaX, sigmaY)
# sigmaX 和 sigmaY 分别表示高斯核在X和Y方向上的标准差
# 如果 sigmaY 为 0,则 sigmaY = sigmaX
# 如果 sigmaX 和 sigmaY 都为 0,则它们由核大小计算得出
ksize_gaussian = (5, 5)
sigma_x = 0 # 通常设置为 0,让 OpenCV 根据核大小自动计算# 3. 应用高斯滤波
# cv2.GaussianBlur() 函数用于进行高斯滤波
# 参数: src (输入图像), ksize (核大小), sigmaX, sigmaY (标准差), borderType (边界处理方式,通常不需要指定)
gaussian_blurred_image = cv2.GaussianBlur(image, ksize_gaussian, sigma_x)# 4. 显示原始图像和高斯滤波后的图像
cv2.imshow('Original Image', image)
cv2.imshow(f'Gaussian Blurred Image (ksize={ksize_gaussian}, sigmaX={sigma_x})', gaussian_blurred_image)# 5. 尝试不同的核大小和 sigmaX 值
ksize_gaussian_large = (15, 15)
sigma_x_large = 5 # 明确指定较大的标准差
gaussian_blurred_image_large = cv2.GaussianBlur(image, ksize_gaussian_large, sigma_x_large)
cv2.imshow(f'Gaussian Blurred Image (ksize={ksize_gaussian_large}, sigmaX={sigma_x_large})', gaussian_blurred_image_large)cv2.waitKey(0)
cv2.destroyAllWindows()print("\n--- 练习 1.2.2 完成 ---")
练习提示:
- 比较均值滤波和高斯滤波的效果,注意它们在边缘处的差异。
- 尝试不同的
ksize
和sigmaX
值。sigmaX
对平滑效果影响很大。当sigmaX
较大时,即使核较小,平滑效果也很明显。
1.3 图像锐化
与平滑相反,图像锐化旨在增强图像的边缘和细节,使图像看起来更清晰。锐化通常通过突出图像中的变化区域(如边缘)来实现。
一种常见的锐化方法是使用拉普拉斯算子 (Laplacian Operator)。拉普拉斯算子是二阶微分算子,它检测图像中灰度变化率最大的区域,这些区域通常对应于边缘。对图像应用拉普拉斯算子后得到的是边缘信息。
要实现图像锐化,可以将原始图像与拉普拉斯算子检测到的边缘信息进行结合。一个简单的锐化核是:
[ 0, 1, 0 ]
[ 1, -4, 1 ]
[ 0, 1, 0 ]
或
[-1, -1, -1]
[-1, 8, -1]
[-1, -1, -1]
使用这些核进行卷积可以直接得到锐化效果。
OpenCV 提供了 cv2.Laplacian()
函数来计算拉普拉斯算子,或者你可以使用 cv2.filter2D()
函数和自定义的锐化核进行卷积。对于初学者,使用 filter2D
配合锐化核可能更直观。
Python
import cv2
import numpy as np# --- 练习 1.3: 图像锐化 ---# 1. 加载图像 (灰度图通常更适合滤波操作)
# 如果你的图片是彩色图,可以先转换为灰度图
image_path = 'your_image.jpg'
try:image_color = cv2.imread(image_path)if image_color is None:raise FileNotFoundError(f"图片文件未找到: {image_path}")image = cv2.cvtColor(image_color, cv2.COLOR_BGR2GRAY) # 转换为灰度图
except FileNotFoundError as e:print(e)print("请确保你的图片文件存在并位于正确路径。")# 使用一个虚拟灰度图片代替image = np.zeros((300, 500), dtype=np.uint8)cv2.putText(image, "Image not found", (50, 150), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2)cv2.putText(image, "Please replace 'your_image.jpg'", (50, 200), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)print(f"灰度图像尺寸: {image.shape}")# 2. 定义锐化核 (一个常用的拉普拉斯锐化核)
sharpening_kernel = np.array([[0, -1, 0],[-1, 5, -1],[0, -1, 0]
], dtype=np.float32) # 使用 float32 类型# 3. 应用自定义核进行滤波 (锐化)
# cv2.filter2D() 函数使用自定义核对图像进行卷积
# 参数: src (输入图像), ddepth (输出图像深度,-1 表示与输入图像相同), kernel (核)
sharpened_image = cv2.filter2D(image, -1, sharpening_kernel)# 4. 显示原始灰度图像和锐化后的图像
cv2.imshow('Original Grayscale Image', image)
cv2.imshow('Sharpened Image (using filter2D)', sharpened_image)# 5. 使用 cv2.Laplacian 函数(仅获取边缘信息,不是直接锐化)
# 需要指定输出深度,通常使用 cv2.CV_64F 以避免溢出
laplacian = cv2.Laplacian(image, cv2.CV_64F)
# 将结果转换回 uint8
# 注意: 拉普拉斯结果可能有负值,需要取绝对值并缩放到 0-255 范围
laplacian_abs = cv2.convertScaleAbs(laplacian)
cv2.imshow('Laplacian Edge Information', laplacian_abs)cv2.waitKey(0)
cv2.destroyAllWindows()print("\n--- 练习 1.3 完成 ---")
练习提示:
cv2.filter2D()
非常灵活,你可以尝试定义其他核(例如,一个简单的边缘检测核np.array([[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]])
)来观察效果。cv2.Laplacian()
直接计算的是图像的二阶导数,它更常用于边缘检测,而不是直接产生锐化后的图像(虽然可以通过与原图叠加实现锐化)。理解filter2D
和Laplacian
的区别。- 注意
filter2D
的ddepth
参数,-1
表示输出与输入深度相同,如果核导致结果超出 0-255,可能会发生截断。对于一些滤波操作,可能需要将输入转换为更高的数据类型(如float32
)进行计算,然后再转换回uint8
。但在上面的锐化例子中,[-1, 5, -1]
核通常不会导致严重溢出,所以直接用-1
输出深度是可行的。
2. 图像形态学操作
形态学操作是基于图像中特定形状(称为结构元素或核)的几何操作。它们主要应用于二值图像(只有黑白两种像素值,0 或 255),但也适用于灰度图像。形态学操作在处理图像中的对象形状、大小、连接等方面非常有用,例如去除噪声、分割独立元素、连接相邻元素、查找图像中的孔洞等。
形态学操作的关键在于结构元素。它是一个小矩阵,定义了在操作过程中如何探测或影响邻域像素。OpenCV 提供了 cv2.getStructuringElement()
函数来创建不同形状和大小的结构元素。
Python
import cv2
import numpy as np# --- 练习 2.0: 创建结构元素 ---# 1. 定义结构元素的形状和大小
# 形状: cv2.MORPH_RECT (矩形), cv2.MORPH_ELLIPSE (椭圆形), cv2.MORPH_CROSS (交叉形)
shape = cv2.MORPH_RECT
ksize = (5, 5) # 大小 (宽度, 高度)# 2. 创建结构元素
kernel_rect = cv2.getStructuringElement(shape, ksize)
print(f"矩形结构元素 ({ksize}):\n{kernel_rect}")shape_ellipse = cv2.MORPH_ELLIPSE
ksize_ellipse = (7, 7)
kernel_ellipse = cv2.getStructuringElement(shape_ellipse, ksize_ellipse)
print(f"\n椭圆形结构元素 ({ksize_ellipse}):\n{kernel_ellipse}")shape_cross = cv2.MORPH_CROSS
ksize_cross = (5, 5)
kernel_cross = cv2.getStructuringElement(shape_cross, ksize_cross)
print(f"\n交叉形结构元素 ({ksize_cross}):\n{kernel_cross}")# 注意:形态学操作通常用于二值图像,所以我们创建一个简单的二值图像作为例子
# 创建一个包含白色方块的黑色图像
binary_image = np.zeros((100, 100), dtype=np.uint8)
binary_image[20:80, 20:80] = 255# 添加一些小的噪声点 (白色点)
binary_image[10, 10] = 255
binary_image[90, 90] = 255
binary_image[10, 90] = 255
binary_image[90, 10] = 255# 添加一些小的孔洞 (黑色点)
binary_image[45:55, 45:55] = 0cv2.imshow('Original Binary Image', binary_image)
cv2.waitKey(0)
cv2.destroyAllWindows()print("\n--- 练习 2.0 完成 ---")
练习提示:
- 理解不同形状和大小的结构元素。它们定义了形态学操作的“感受野”。
- 注意形态学操作通常在二值图像上效果最明显。你需要先将图像转换为二值图像(例如使用
cv2.threshold()
)。
2.1 腐蚀 (Erosion)
腐蚀操作会“缩小”二值图像中的前景物体(白色区域)。它的工作原理是:对于输出图像的每个像素,如果其对应的输入图像像素的邻域中,完全被结构元素覆盖的区域都是前景像素,则输出像素为前景(白色);否则为背景(黑色)。
简单来说,如果结构元素在某个位置包含任何背景像素,并且其中心对应输入图像的一个前景像素,那么这个前景像素在输出中就会变成背景。这会导致前景物体的边缘被“腐蚀”掉。腐蚀可以用来去除图像中的小噪声点。
Python
import cv2
import numpy as np# --- 练习 2.1: 腐蚀操作 ---# 1. 加载或创建二值图像 (使用上面创建的带噪声和孔洞的二值图像)
binary_image = np.zeros((150, 150), dtype=np.uint8)
binary_image[30:120, 30:120] = 255 # 大方块
binary_image[10, 10] = 255 # 噪声点
binary_image[10, 130] = 255
binary_image[130, 10] = 255
binary_image[130, 130] = 255
binary_image[60:90, 60:90] = 0 # 孔洞# 2. 创建结构元素
kernel_erode = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))# 3. 应用腐蚀操作
# cv2.erode() 函数用于进行腐蚀
# 参数: src (输入图像), kernel (结构元素), iterations (迭代次数,可选,默认为1)
eroded_image = cv2.erode(binary_image, kernel_erode, iterations=1)# 4. 显示原始二值图像和腐蚀后的图像
cv2.imshow('Original Binary Image', binary_image)
cv2.imshow('Eroded Image (iterations=1)', eroded_image)# 5. 尝试多次迭代腐蚀
eroded_image_3_iter = cv2.erode(binary_image, kernel_erode, iterations=3)
cv2.imshow('Eroded Image (iterations=3)', eroded_image_3_iter)cv2.waitKey(0)
cv2.destroyAllWindows()print("\n--- 练习 2.1 完成 ---")
练习提示:
- 观察小的噪声点是如何被腐蚀掉的。
- 观察大的白色方块的边缘是如何向内收缩的。
- 尝试增加
iterations
参数的值,观察腐蚀效果如何增强。
2.2 膨胀 (Dilation)
膨胀操作会“放大”二值图像中的前景物体(白色区域)。它的工作原理是:对于输出图像的每个像素,如果其对应的输入图像像素的邻域中,至少有一个像素被结构元素覆盖的区域是前景像素,则输出像素为前景(白色);否则为背景(黑色)。
简单来说,如果结构元素的中心对应输入图像的一个背景像素,但该结构元素覆盖的区域内包含任何前景像素,那么这个背景像素在输出中就会变成前景。这会导致前景物体的边缘向外扩展。膨胀可以用来填补物体内部的小孔洞或连接相邻的物体。
Python
import cv2
import numpy as np# --- 练习 2.2: 膨胀操作 ---# 1. 加载或创建二值图像 (使用上面创建的带噪声和孔洞的二值图像)
binary_image = np.zeros((150, 150), dtype=np.uint8)
binary_image[30:120, 30:120] = 255 # 大方块
binary_image[10, 10] = 255 # 噪声点
binary_image[10, 130] = 255
binary_image[130, 10] = 255
binary_image[130, 130] = 255
binary_image[60:90, 60:90] = 0 # 孔洞# 2. 创建结构元素
kernel_dilate = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))# 3. 应用膨胀操作
# cv2.dilate() 函数用于进行膨胀
# 参数: src (输入图像), kernel (结构元素), iterations (迭代次数,可选,默认为1)
dilated_image = cv2.dilate(binary_image, kernel_dilate, iterations=1)# 4. 显示原始二值图像和膨胀后的图像
cv2.imshow('Original Binary Image', binary_image)
cv2.imshow('Dilated Image (iterations=1)', dilated_image)# 5. 尝试多次迭代膨胀
dilated_image_3_iter = cv2.dilate(binary_image, kernel_dilate, iterations=3)
cv2.imshow('Dilated Image (iterations=3)', dilated_image_3_iter)cv2.waitKey(0)
cv2.destroyAllWindows()print("\n--- 练习 2.2 完成 ---")
练习提示:
- 观察小的孔洞是如何被膨胀操作填补的。
- 观察大的白色方块的边缘是如何向外扩展的。
- 尝试增加
iterations
参数的值,观察膨胀效果如何增强。
2.3 开运算 (Opening)
开运算是先腐蚀后膨胀的操作。它常用于去除图像中的小噪声点(孤立的前景像素),同时基本保持较大物体的大小和形状不变。先腐蚀可以去除小的噪声点,再膨胀则可以恢复被腐蚀掉的较大物体。
Opening(Image)=Dilate(Erode(Image))
2.4 闭运算 (Closing)
闭运算是先膨胀后腐蚀的操作。它常用于填充物体内部的小孔洞或连接物体之间的狭窄间隙,同时基本保持物体的大小和形状不变。先膨胀可以填补孔洞和连接间隙,再腐蚀则可以恢复因膨胀而稍有增大的物体大小。
Closing(Image)=Erode(Dilate(Image))
OpenCV 提供了 cv2.morphologyEx()
函数,它可以执行包括开运算、闭运算在内的多种形态学操作。
Python
import cv2
import numpy as np# --- 练习 2.3 & 2.4: 开运算与闭运算 ---# 1. 加载或创建二值图像 (使用上面创建的带噪声和孔洞的二值图像)
binary_image = np.zeros((150, 150), dtype=np.uint8)
binary_image[30:120, 30:120] = 255 # 大方块
binary_image[10, 10] = 255 # 噪声点
binary_image[10, 130] = 255
binary_image[130, 10] = 255
binary_image[130, 130] = 255
binary_image[60:90, 60:90] = 0 # 孔洞# 2. 创建结构元素
kernel_morph = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))# 3. 应用开运算
# cv2.morphologyEx() 函数用于执行多种形态学操作
# 参数: src (输入图像), op (操作类型), kernel (结构元素), iterations (迭代次数,可选)
# cv2.MORPH_OPEN 表示开运算
opening_image = cv2.morphologyEx(binary_image, cv2.MORPH_OPEN, kernel_morph)# 4. 应用闭运算
# cv2.MORPH_CLOSE 表示闭运算
closing_image = cv2.morphologyEx(binary_image, cv2.MORPH_CLOSE, kernel_morph)# 5. 显示原始、开运算和闭运算后的图像
cv2.imshow('Original Binary Image', binary_image)
cv2.imshow('Opening Operation', opening_image)
cv2.imshow('Closing Operation', closing_image)cv2.waitKey(0)
cv2.destroyAllWindows()print("\n--- 练习 2.3 & 2.4 完成 ---")
练习提示:
- 观察开运算如何有效地去除了小的噪声点,同时保留了较大的白色方块。
- 观察闭运算如何填补了方块内部的孔洞。
- 尝试使用不同大小和形状的结构元素,以及不同的迭代次数,看看它们如何影响开闭运算的效果。
2.5 形态学梯度 (Morphological Gradient)
形态学梯度是膨胀图像与腐蚀图像之间的差值。它会突显出物体的边缘轮廓。
MorphologicalGradient=Dilate(Image)−Erode(Image)
这个操作的结果通常可以看作是物体边界的“厚度”。
Python
import cv2
import numpy as np# --- 练习 2.5: 形态学梯度 ---# 1. 加载或创建二值图像 (使用上面创建的二值图像)
binary_image = np.zeros((150, 150), dtype=np.uint8)
binary_image[30:120, 30:120] = 255 # 大方块# 2. 创建结构元素
kernel_grad = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))# 3. 应用形态学梯度
# cv2.morphologyEx() 函数, op=cv2.MORPH_GRADIENT 表示形态学梯度
gradient_image = cv2.morphologyEx(binary_image, cv2.MORPH_GRADIENT, kernel_grad)# 4. 显示原始二值图像和形态学梯度图像
cv2.imshow('Original Binary Image', binary_image)
cv2.imshow('Morphological Gradient', gradient_image)cv2.waitKey(0)
cv2.destroyAllWindows()print("\n--- 练习 2.5 完成 ---")
练习提示:
- 形态学梯度结果是物体的边界区域,其宽度取决于结构元素的大小。
- 将其与后面的边缘检测结果进行比较,理解它们的不同用途。形态学梯度侧重于根据物体形状来提取边界,而边缘检测侧重于像素灰度变化。
3. 边缘检测
边缘是图像中像素强度发生显著变化的区域。边缘携带着图像中物体形状、边界等重要信息,因此边缘检测是许多高级计算机视觉任务(如目标识别、图像分割)的基础步骤。
边缘检测通常涉及计算图像的梯度。梯度表示图像在某个方向上的变化率。在边缘位置,梯度的大小通常较大。
3.1 Sobel 算子
OpenCV 提供了 cv2.Sobel()
函数来计算 Sobel 梯度。
Python
import cv2
import numpy as np# --- 练习 3.1: Sobel 算子边缘检测 ---# 1. 加载图像并转换为灰度图 (边缘检测通常在灰度图上进行)
image_path = 'your_image.jpg'
try:image_color = cv2.imread(image_path)if image_color is None:raise FileNotFoundError(f"图片文件未找到: {image_path}")image = cv2.cvtColor(image_color, cv2.COLOR_BGR2GRAY)
except FileNotFoundError as e:print(e)print("请确保你的图片文件存在并位于正确路径。")image = np.zeros((300, 500), dtype=np.uint8)cv2.putText(image, "Image not found", (50, 150), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2)cv2.putText(image, "Please replace 'your_image.jpg'", (50, 200), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)# 2. 计算水平方向的 Sobel 梯度
# 参数: src (输入图像), ddepth (输出图像深度), dx (x方向导数阶数), dy (y方向导数阶数), ksize (Sobel核大小)
# 为了避免计算过程中出现负值截断,通常将输出深度设为 cv2.CV_64F
sobelx = cv2.Sobel(image, cv2.CV_64F, 1, 0, ksize=3)# 3. 计算垂直方向的 Sobel 梯度
sobely = cv2.Sobel(image, cv2.CV_64F, 0, 1, ksize=3)# 4. 计算梯度幅值 (这里使用近似值: |Gx| + |Gy|)
# 将结果转换为 uint8,cv2.convertScaleAbs 会取绝对值并截断到 0-255
sobelx_abs = cv2.convertScaleAbs(sobelx)
sobely_abs = cv2.convertScaleAbs(sobely)
sobel_combined = cv2.addWeighted(sobelx_abs, 0.5, sobely_abs, 0.5, 0) # 简单相加作为合并# 也可以使用更精确的梯度幅值计算: sqrt(Gx^2 + Gy^2)
# combined_magnitude = np.sqrt(sobelx**2 + sobely**2)
# combined_magnitude = cv2.normalize(combined_magnitude, None, 0, 255, cv2.NORM_MINMAX, cv2.CV_8U) # 归一化到 0-255# 5. 显示结果
cv2.imshow('Original Grayscale Image', image)
cv2.imshow('Sobel X', sobelx_abs)
cv2.imshow('Sobel Y', sobely_abs)
cv2.imshow('Sobel Combined (|Gx| + |Gy|)', sobel_combined)cv2.waitKey(0)
cv2.destroyAllWindows()print("\n--- 练习 3.1 完成 ---")
练习提示:
- 观察 Sobel X 结果主要突出垂直方向的边缘,Sobel Y 结果主要突出水平方向的边缘。
- 合并后的结果显示了各个方向的边缘。
- 理解为什么需要使用
cv2.CV_64F
作为输出深度,以及cv2.convertScaleAbs()
的作用。 - 尝试不同的
ksize
值。
3.2 Canny 边缘检测
Canny 边缘检测是一种多阶段的边缘检测算法,被广泛认为是目前效果最好的边缘检测算法之一。它比 Sobel 算子更复杂,但能产生更细、更准确的边缘。Canny 算法主要包括以下步骤:
- 噪声抑制: 使用高斯滤波器平滑图像,去除噪声。
- 计算梯度: 计算图像在水平和垂直方向的梯度(通常使用 Sobel 算子)。
- 非极大值抑制 (Non-maximum Suppression): 细化边缘。在梯度方向上,只保留梯度局部最大值,抑制非最大值,使得边缘变细。
- 双阈值处理 (Double Thresholding): 定义两个阈值:高阈值 (
high_threshold
) 和低阈值 (low_threshold
)。- 梯度值高于
high_threshold
的点被确定为强边缘。 - 梯度值低于
low_threshold
的点被排除。 - 梯度值介于
low_threshold
和high_threshold
之间的点被称为弱边缘,它们可能成为边缘,也可能不是。
- 梯度值高于
- 边缘跟踪 (Edge Tracking by Hysteresis): 连接边缘。通过分析弱边缘的邻域,将与强边缘相连的弱边缘也视为边缘。
OpenCV 提供了 cv2.Canny()
函数来执行 Canny 边缘检测。
Python
import cv2
import numpy as np# --- 练习 3.2: Canny 边缘检测 ---# 1. 加载图像并转换为灰度图
image_path = 'your_image.jpg'
try:image_color = cv2.imread(image_path)if image_color is None:raise FileNotFoundError(f"图片文件未找到: {image_path}")image = cv2.cvtColor(image_color, cv2.COLOR_BGR2GRAY)
except FileNotFoundError as e:print(e)print("请确保你的图片文件存在并位于正确路径。")image = np.zeros((300, 500), dtype=np.uint8)cv2.putText(image, "Image not found", (50, 150), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2)cv2.putText(image, "Please replace 'your_image.jpg'", (50, 200), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)# 2. 定义双阈值
low_threshold = 50
high_threshold = 150 # 通常 high_threshold 是 low_threshold 的 2 到 3 倍# 3. 应用 Canny 边缘检测
# cv2.Canny() 函数执行 Canny 边缘检测
# 参数: src (8位输入图像), threshold1 (低阈值), threshold2 (高阈值),
# apertureSize (Sobel算子大小,默认为3), L2gradient (是否使用更精确的L2范数计算梯度幅值,默认为False)
canny_edges = cv2.Canny(image, low_threshold, high_threshold)# 4. 显示原始灰度图像和 Canny 边缘图像
cv2.imshow('Original Grayscale Image', image)
cv2.imshow(f'Canny Edges (low={low_threshold}, high={high_threshold})', canny_edges)# 5. 尝试不同的阈值组合
canny_edges_loose = cv2.Canny(image, 30, 100) # 较低阈值,可能检测到更多弱边缘
canny_edges_strict = cv2.Canny(image, 100, 200) # 较高阈值,只检测到强边缘
cv2.imshow(f'Canny Edges (low=30, high=100)', canny_edges_loose)
cv2.imshow(f'Canny Edges (low=100, high=200)', canny_edges_strict)cv2.waitKey(0)
cv2.destroyAllWindows()print("\n--- 练习 3.2 完成 ---")
练习提示:
- Canny 边缘通常比 Sobel 边缘更细。
- 双阈值的选择对结果影响很大。较低的阈值组合会检测到更多细节和噪声,较高的阈值组合则只保留强边缘。
- 理解双阈值处理和边缘跟踪的工作原理。
4. 实战:检测图像中的边缘
现在,我们将结合学到的知识,在一个实际图像上进行边缘检测的实战练习。我们将加载一张图片,将其转换为灰度图,然后应用 Canny 边缘检测来找到物体的轮廓。
Python
import cv2
import numpy as np# --- 实战练习: 使用 Canny 边缘检测 ---# 1. 加载你的图像
# 请替换 'your_real_image.jpg' 为你的图片路径
image_path = 'your_real_image.jpg'
try:image_color = cv2.imread(image_path)if image_color is None:raise FileNotFoundError(f"图片文件未找到: {image_path}")print(f"成功加载彩色图像: {image_path}")
except FileNotFoundError as e:print(e)print("请确保你的图片文件存在并位于正确路径。")print("将使用一个内置的 OpenCV 示例图像进行演示。")# 如果图片加载失败,使用 OpenCV 的内置图像# 需要确保安装了 opencv-contrib-python 或手动下载图片# 例如,可以使用 './data/lena.jpg' 如果你有opencv_extra库的data文件夹# 或者简单创建一个模拟图像image_color = np.zeros((400, 600, 3), dtype=np.uint8)cv2.putText(image_color, "Placeholder Image", (100, 200), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2)# 2. 将图像转换为灰度图
gray_image = cv2.cvtColor(image_color, cv2.COLOR_BGR2GRAY)# 3. 应用 Canny 边缘检测
# 可以尝试不同的阈值来获得最佳效果
low_threshold = 100
high_threshold = 200
edges = cv2.Canny(gray_image, low_threshold, high_threshold)# 4. 显示原始图像和边缘检测结果
cv2.imshow('Original Image', image_color)
cv2.imshow('Grayscale Image', gray_image)
cv2.imshow(f'Canny Edges (low={low_threshold}, high={high_threshold})', edges)# 5. 等待按键,然后关闭窗口
cv2.waitKey(0)
cv2.destroyAllWindows()print("\n--- 实战练习 完成 ---")
实战提示:
- 更换不同的图片文件进行测试。
- 仔细调整 Canny 函数的
low_threshold
和high_threshold
参数,观察边缘检测结果的变化。这是获得满意边缘检测结果的关键步骤。 - 对于一些有噪声的图片,你可能需要在 Canny 之前先进行高斯平滑,虽然
cv2.Canny()
函数内部已经包含了高斯平滑的步骤,但有时外部的预处理平滑可以改善结果。
总结
在这一部分,我们深入学习了 OpenCV 中的核心图像处理技术,包括:
- 图像增强和滤波: 通过调整亮度对比度改善视觉效果,使用均值滤波和高斯滤波进行平滑,使用拉普拉斯算子或自定义核进行锐化。
- 形态学操作: 利用结构元素进行腐蚀、膨胀、开运算、闭运算和形态学梯度等操作,常用于二值图像处理和形状分析。
-
边缘检测: 学习了 Sobel 算子和更强大的 Canny 算法,用于检测图像中像素强度变化显著的边缘区域。
相关文章:
OpenCV 图像处理核心技术 (第二部分)
欢迎来到 OpenCV 图像处理的第二部分!在第一部分,我们学习了如何加载、显示、保存图像以及访问像素等基础知识。现在,我们将深入探索如何利用 OpenCV 提供的强大工具来修改和分析图像。 图像处理是计算机视觉领域的基石。通过对图像进行各种…...
Git从入门到精通-第二章-工具配置
目录 命令行 安装Git 初次运行Git前的配置 git config基本概念 常用命令 配置用户信息 配置文本编辑器 查看配置 配置别名(简化命令) 高级配置 换行符处理(方便跨平台协作) 忽略文件权限变更(常用于团队协…...
树状结构转换工具类
项目中使用了很多树状结构,为了方便使用开发一个通用的工具类。 使用工具类的时候写一个类基础BaseNode,如果有个性化字段添加到类里面,然后就可以套用工具类。 工具类会将id和pid做关联返回一个树状结构的集合。 使用了hutool的工具包判空…...
C#基础简述
C#基础详解 一、C#语言概述 C#(读作"C Sharp")是微软开发的面向对象的编程语言,运行在.NET平台上。它结合了C的强大功能和Visual Basic的简单性,具有以下特点: 面向对象:支持封装、继…...
AI赋能烟草工艺革命:虫情监测步入智能化时代
在当今竞争激烈且品质至上的烟草行业中,生产流程的每一个细微环节都关乎着企业的生死存亡与品牌的兴衰荣辱。烟草工艺部门与制丝、卷包车间作为生产链条的核心驱动,犹如精密仪器中的关键齿轮,彼此紧密咬合、协同运转,任何一处的小…...
小刚说C语言刷题—1462小明的游泳时间
1.题目描述 伦敦奥运会要到了,小明在拼命练习游泳准备参加游泳比赛。 这一天,小明给自己的游泳时间做了精确的计时(本题中的计时都按 24 小时制计算),它发现自己从 a 时 b 分一直游泳到当天的 c 时 d 分。 请你帮小…...
StarRocks Lakehouse 如何重构大数据架构?
随着数据分析需求的不断演进,企业对数据处理架构的期望也在不断提升。在这一背景下,StarRocks 凭借其高性能的实时分析能力,正引领数据分析进入湖仓一体的新时代。 4 月 18 日,镜舟科技高级技术专家单菁茹做客开源中国直播栏目《…...
用TCP实现服务器与客户端的交互
引言: 这篇文章主要是用TCP构造的回显服务器,也就是客户端发什么,就返回什么。用实现这个过程方式来学会TCP套接字的使用。 一、TCP的特点 TCP是可靠的:这个需要去了解TCP的机制,这是一个大工程,博主后面写…...
用于实时辐射场渲染的3D高斯溅射——3D Gaussian Splatting for Real-Time Radiance Field Rendering
用于实时辐射场渲染的3D高斯溅射——3D Gaussian Splatting for Real-Time Radiance Field Rendering 文章目录 用于实时辐射场渲染的3D高斯溅射——3D Gaussian Splatting for Real-Time Radiance Field Rendering摘要Abstract1. 预备知识1.1 三维的几何表示1.2 计算机中的集合…...
Vue3 Echarts 3D立方体柱状图实现教程
文章目录 前言一、实现原理二、series ——type: "pictorialBar" 简介2.1 常用属性 三、代码实战3.1 封装一个echarts通用组件 echarts.vue3.2 实现一个立方体柱状图(1)首先实现一个基础柱状图(2)添加立方体棱线&#x…...
Soildworks怎样在装配体中建立局部剖视图
1思路:建立拉伸切除 2步骤 1-打开点线面显示按钮 2-在装配体中依据某个基准面(例如前视基准面)建立一个待切除的草图 3-点击顶部工具栏的装配体--->装嫩配体特征---->拉伸切除---Ok 3具体图示 1-点击,使其变成灰色 即…...
基于C++的IOT网关和平台5:github项目ctGateway开发指南
初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C++的,可以在任何平台上使用。 源码指引:github源码指引_初级代码游戏的博客-CSDN博客 …...
虚拟机centos7安装docker
虚拟机CentOS 7上安装 Docker流程 1. 更新系统软件包 需要确保系统软件包是最新的 sudo yum -y update sudo:以超级用户权限执行命令。 yum:CentOS的包管理器工具。 -y:自动确认所有提示,直接执行。 2. 安装 Docker 依赖 在安装 …...
11.Spring Boot 3.1.5 中使用 SpringDoc OpenAPI(替代 Swagger)生成 API 文档
Spring Boot 3.1.5 中使用 SpringDoc OpenAPI(替代 Swagger)生成 API 文档 1. 项目结构 假设项目名为 springboot-openapi-demo,以下是项目的基本结构: springboot-openapi-demo/ ├── src/ │ ├── main/ │ │ ├─…...
pytorch对应gpu版本是否可用判断逻辑
# gpu_is_ok.py import torchdef check_torch_gpu():# 打印PyTorch版本print(f"PyTorch version: {torch.__version__}")# 检查CUDA是否可用cuda_available torch.cuda.is_available()print(f"CUDA available: {cuda_available}")if cuda_available:# 打印…...
Kubernetes 集群概念详解
Kubernetes 集群概念详解 Kubernetes 集群是由多个计算节点组成的容器编排系统,用于自动化部署、扩展和管理容器化应用。以下是 Kubernetes 集群的核心概念和架构解析: 一、集群基础架构 1. 集群组成要素 graph TBMaster[控制平面] --> Node1[工作…...
BT137-ASEMI机器人功率器件专用BT137
编辑:LL BT137-ASEMI机器人功率器件专用BT137 型号:BT137 品牌:ASEMI 封装:TO-220F 批号:最新 引脚数量:3 封装尺寸:如图 特性:双向可控硅 工作结温:-40℃~150℃…...
ArcGIS+GPT:多领域地理分析与决策新方案
技术点目录 AI大模型应用ArcGIS工作流程及功能prompt的使用技巧AI助力工作流程AI助力数据读取AI助力数据编辑与处理AI助力空间分析AI助力遥感分析AI助力二次开发AI助力科研绘图ArcGISAI综合应用了解更多 ——————————————————————————————————…...
鸿蒙文件上传-从前端到后端详解,对比jq请求和鸿蒙arkts请求区别,对比new FormData()和鸿蒙arktsrequest.uploadFile
需要权限:ohos.permission.INTERNET 1.nodejs自定义书写上传后端接口 传输过来的数据放在files?.image下 router.post(/upload,(req, res) > {var form new multiparty.Form();form.uploadDirpublic/images/uploads; //上传图片保存的地址(目录必须存在)fo…...
【DBeaver】如何连接MongoDB
MongoDB驱动 在 DBeaver 社区版是没有的,得自己下载 一、下载mongo-jdbc-standalone.jar 二、在工具栏找到数据库,选择驱动管理器 三、在驱动管理器点击新建 四、选择库,添加mongo-jdbc-standalone.jar;然后点击找到类 五、选择设置&#x…...
Unity 粒子同步,FishNet
Github的工程 同步画面 使用FishNet插件同步,可使用这个选项来克隆第二个项目进行测试...
自然语言处理之命名实体识别:Bi-LSTM-CRF模型的评估与性能分析
命名实体识别(Named Entity Recognition, NER)是自然语言处理(NLP)的核心任务之一,旨在从文本中识别出具有特定意义的实体(如人名、地名、机构名等),并为其分类。随着深度学习的发展,**Bi-LSTM-CRF**(双向长短期记忆网络结合条件随机场)模型因其强大的序列建模能力成…...
【SpringBoot】基于mybatisPlus的博客系统
1.实现用户登录 在之前的项目登录中,我使用的是Session传递用户信息实现校验登录 现在学习了Jwt令牌技术后我尝试用Jwt来完成校验工作 Jwt令牌 令牌一词在网络编程一节我就有所耳闻,现在又拾了起来。 这里讲应用:令牌也就用于身份标识&a…...
[Android]任务列表中有两个相机图标
现象: 修改AndroidManifest.xml <activityandroid:name"com.android.camera.PermissionsActivity"android:label"string/app_name"android:launchMode"singleTop"android:configChanges"orientation|screenSize|keyboardH…...
VINS-FUSION:配置参数说明与配置自己的参数
文章目录 📚简介📍配置文件说明📷相机配置参数🔧设备参数🎯配置自己的参数📷相机参数🔧设备参数📚简介 VINS-Fusion 是一个基于优化的多传感器状态估计器,实现了视觉惯性里程计(VIO)和视觉惯性全球导航卫星系统(VI-GNSS)融合。 📍配置文件说明 VINS-Fus…...
Polars: 新一代高性能数据处理库
<------最重要的是订阅“鲁班模锤”------> 在数据科学和数据分析领域,性能和效率一直是从业者关注的焦点。随着数据量的爆炸式增长,传统的数据处理工具如pandas在处理大规模数据时逐渐显露出其局限性。在这样的背景下,一个名为Polars…...
大屏/门户页面兼容各种分辨率或电脑缩放
需求要求: 需要支持缩放功能(缩放后 页面各元素模块正常展示)、 需要适配各种分辨率(初始加载不应出现横向滚动条) 选择的实现方案 利用 zoom 或者 transform 来缩放兼容页面样式,不动业务模块代码 const isMobile /iPhone|iPad|iPod|Android|Harmony/i.test(navi…...
自定义项目中导入文件import顺序
项目中import 顺序 分类顺序 可以根据模块或文件的功能、类型等进行分类,比如将所有的组件放在一起、工具函数放在一起等。这样的组织方式更有利于对项目结构和代码逻辑的理解,当需要查找某一类功能的代码时,可以快速定位到相应的 import 区…...
Git 本地提交撤销
引言 在 Git 版本控制系统中,偶尔会遇到需要撤销本地提交的情况。本文将详细介绍如何优雅地处理这种情况,帮助您在不慌乱的情况下恢复错误提交。 撤销本地提交的主要方法 当您意外提交了错误文件到 Git 仓库,但尚未推送到远程服务器时&…...
k8s术语之Replication Controller
Replication Controller 在kubernetes中简称RC,它其实是定义了一个期望的场景,即声明某种Pod的副本数量在任意时刻都符合某个预期值,包括一下几个值: 1.Pod期待的副本数(replicas) 2.用于筛选目标Pod的Lable Selector 3.当…...
AI驱动视频批量智能混剪软件生产技术实践
一、引言:短视频工业化生产的技术革新 在电商带货、知识分享等领域,高效产出差异化视频内容成为核心竞争力。本文结合AI技术与工程实践,解析如何通过智能素材处理、参数化合成引擎、多维度质量控制构建全自动视频生产流水线,实现…...
SPL 量化 回测
回测是一种评估交易策略的通用方法。它通过计算策略在历史数据上的表现来评估交易策略的可行性。如果回测结果良好,交易者和分析师可能会有信心在未来继续使用该策略。 1. 回测脚本 首先要编写回测脚本,将回测脚本保存为 backtest.splx。 脚本代码如下…...
2025年“深圳杯”数学建模挑战赛A题-芯片热弹性物理参数估计
芯片热弹性物理参数估计 小驴数模 当今时代,芯片无疑是现代社会发展的 “核心引擎”。它深度嵌入智能手机,实现全球即时通讯;助力汽车智能驾驶,精准导航、自动操控;赋能工业自动化生产线,高效运转。但随着…...
前端笔记-Element-Plus
结束了vue的基础学习,现在进一步学习组件 Element-Plus部分学习目标: Element Plus1、查阅官方文档指南2、学习常用组件的使用方法3、Table、Pagination、Form4、Input、Input Number、Switch、Select、Date Picker、Button5、Message、MessageBox、N…...
vue3封装全局方法
场景:各个模块详情中存在附件列表数据,需要再每个中添加一个预览附件的方法,是后期提出的需求,所以要在每个模块中进行添加,就去将预览方法封装一下。 将公共方法封装在utils下 utils/filePreview.ts import router…...
Django 学习指南:从入门到精通(大体流程)
想要快速掌握 Django 开发技能吗?按照以下学习流程,带你从零基础成长为独立开发 Web 应用的高手。 一、准备工作:打下坚实基础 在开启 Django 之旅前,先确保你已掌握以下 Python 基础知识: 数据类型:熟悉数…...
Java对集合进行操作,赋值新字段
1、方法一:增强for循环 List<Refund> list refundService.selectRefundList(queryParam); for (Refund refund : list) {refund.setPayWay(refund.getPaymentMethod()); // 将支付方式赋值给付款方式 }在 Java 中,当你使用 for 循环遍历 List<…...
【网工第6版】第6章 网络安全③
目录 ■ 虚拟专用网VPN ◆虚拟专用网基础 ◆VPN分类 ▲根据应用场景不同分类 ▲根据VPN技术实现的网络层次分类 ◎ 二层隧道协议:L2TP和PPTP ◎ 网络层隧道协议:IPSec和GRE ※ IPSec IPSec基础 IPSec原理 IPSec两种封装模式 ※ GRE ■ 应用…...
20250430在ubuntu14.04.6系统上查看系统实时网速
rootrootubuntu:~$ sudo apt-get install iftop 【不需要root权限】 rootrootubuntu:~$ sudo apt-get install nload rootrootubuntu:~$ sudo apt-get install vnstat 【失败】 rootrootubuntu:~$ sudo apt-get install speedtest-cli rootrootubuntu:~$ sudo apt-get install …...
远程 Debugger 多用户环境下的用户隔离实践
远程 Debugger 多用户环境下的用户隔离实践 在现代分布式开发和云原生环境下,远程 Debugger 的应用愈发普遍。然而,随着多人协作和多租户场景的出现,**远程 Debugger 的“用户隔离”**变得至关重要。只有实现了良好的用户隔离,才…...
Neo4j多关系或多路径
目录 一、双向关系 1.创建2个节点间的双向关系 2.创建多个路径的节点,双向关系 3.查询带有方向性的关系 4.查询路径上的多个关系 5.查询出a到b的最短距离 6.查询特定长度的路径 二、将之前的关系清空下,如图所示,在操作一次 1.查询出…...
Locate 3D:Meta出品自监督学习3D定位方法
标题: Locate 3D: Real-World Object Localization via Self-Supervised Learning in 3D 摘要: 我们提出了 Locate 3D,这是一种可根据指代表达(如“沙发和灯之间的小咖啡桌”)在三维场景中定位物体的模型。Locate 3…...
Copilot for Excel 一键词云分析与情绪分析
在Excel中使用copilot对数据进行高级分析,我们已经领略过copilot的强悍能力: 零代码、超越DeepSeek:Excel高级数据分析,copilot加持、Python助力 Python in Excel高级分析:一键RFM分析 然而,很多时候我们…...
【Linux 网络】网络工具ifconfig和iproute/iproute2工具详解
【Linux 网络】网络工具ifconfig和iproute/iproute2工具详解 前言1、安装2、常用命令3、命令使用详解 前言 本篇文章主要介绍Linux下网络工具ifconfig/iproute(iproute2)的安装、使用示例和场景。操作系统Ubuntu 18.04。 1、安装 使用apt-get install 命令安装ifconfig和ipr…...
硬盘分区丢失≠末日!3步逻辑恢复法+物理修复全流程图解
引言:硬盘分区丢失——数据安全的“隐形杀手” 在数字化时代,硬盘作为数据存储的核心载体,承载着个人、企业乃至社会的关键信息。然而,硬盘分区丢失这一突发状况,往往让用户措手不及:文件系统突然报错、盘…...
数据接收全流程图(物理网卡 → 应用层)
以下是 DPDK VPP 在 Linux 系统中从网卡收包到应用层的完整数据流程图及分步解析,结合了内核旁路和用户态协议栈的协同工作: 数据接收全流程图(物理网卡 → 应用层) plaintext 复制 下载 ----------------------------------…...
【AI】DeepSeek 流程图 / 时序图制作,Word 排版错乱问题,文字转直观图形
一:动态流程图 / 时序图制作(DeepSeek Draw.IO) 工具准备 DeepSeek(AI 生成代码):官网(免费)Draw.IO(可视化渲染):官网(免费&#…...
C++继承(上)
目录 一、继承的概念及定义 1. 继承的概念 2. 继承的定义 2.1 定义格式 2.2 继承关系和访问限定符 2.3 继承基类成员访问方式的变化 二、基类和派生类对象赋值转换 三、继承中的作用域 四、派生类的默认成员函数 一、继承的概念及定义 1. 继承的概念 继承是面向对象编…...
分布式-redisson
分布式锁redisson 加锁流程缓存相关问题 加锁流程 redisson底层通过lua脚本实现加锁的原子性lock动作包含:加锁、设置超时时间、锁续命未获取到锁的线程通过获取信号量许可等待,所释放后释放信号量通知等待线程 缓存相关问题 缓存失效(击穿…...
Java学习手册:Spring MVC 架构与实现
一、Spring MVC 概述 Spring MVC 是 Spring 框架的一个模块,它提供了一套 Web 应用开发的解决方案,实现了 MVC(Model-View-Controller)设计模式。Spring MVC 提供了清晰的分离逻辑层、视图层和控制器层的结构,便于开发…...