Python图像处理【18】边缘检测详解

边缘检测详解

    • 0. 前言
    • 1. 图像导数
    • 2. LoG/zero-crossing
      • 2.1 Marr-Hildteth 算法
    • 3. Canny 与 holistically-nested 算法
      • 3.1 Canny 边缘检测
      • 3.2 holistically-nested 边缘检测
    • 小结
    • 系列链接

0. 前言

边缘是图像中两个区域之间具有相对不同灰级特性的边界,或者说是亮度函数突然变化的像素。边缘检测器是一组重要的局部图像预处理方法,用于定位强度函数中的(急剧)变化。可以通过使用以下算法来检测边缘上的点:

  • 一阶导数的局部最大值或最小值
  • 二阶导数的零交叉点 (zero-crossing)

判断一个边缘检测算法是否足够优秀可以使用以下标准:

  • 能够最大程度地减少假阳性(即虚假边缘)和假阴性(即缺失真实边缘)的概率
  • 检测到的边缘必须尽可能接近真正边缘

在本节中,首先,我们将学习如何使用二阶导数的过零点检测图像中的边缘。然后,介绍如何使用深度学习模型进行边缘检测,并将其与 Canny 边缘检测器进行比较。

1. 图像导数

我们首先介绍如何计算图像导数(梯度)以及边缘对图像导数的影响(以便我们可以使用图像导数进行边缘检测)。我们可以使用特定核/掩码的卷积操作近似图像导数:

  • 图像一阶导,掩码 [ − 1 1 ] \left[ \begin{matrix} -1 &1 \end{matrix} \right] [11]
    f ′ ( x ) = lim ⁡ x → ∞ f ( x + h ) − f ( x ) h = f ( x + 1 ) − f ( x ) f'(x)={\lim_{x \to \infty}}\frac {f(x+h)-f(x)}{h}=f(x+1)-f(x) f(x)=xlimhf(x+h)f(x)=f(x+1)f(x)
  • 图像二阶导,掩码 [ 1 − 2 1 ] \left[ \begin{matrix} 1 &-2 &1 \end{matrix} \right] [121]
    f ′ ′ ( x ) = lim ⁡ x → ∞ f ′ ( x + h ) − f ′ ( x ) h = f ′ ( x ) − f ′ ( x − 1 ) = f ( x + 1 ) − 2 f ( x ) + f ( x − 1 ) \begin{aligned} f''(x)&={\lim_{x \to \infty}}\frac {f'(x+h)-f'(x)}{h}=f'(x)-f'(x-1)\\ &=f(x+1)-2f(x)+f(x-1) \end{aligned} f′′(x)=xlimhf(x+h)f(x)=f(x)f(x1)=f(x+1)2f(x)+f(x1)

使用以上近似函数计算二值图像的导数,并注意其对导数的影响,以便理解为什么导数可以用于边缘检测。

(1) 首先导入所需的模块、函数,然后读取二值黑白图像:

from scipy.signal import convolve
from skimage.io import imread
from skimage.color import rgb2gray
import matplotlib.pylab as plt

img = rgb2gray(imread('example.png'))
h, w = img.shape

(2) 构建卷积核,使用空间卷积计算一阶导数 ∂ f ∂ x \frac {∂f} {∂x} xf 和二阶导数 ∂ 2 f ∂ 2 x \frac {∂^2 f} {∂^2x} 2x2f

kd1 = [[1, -1]]
kd2 = [[1, -2, 1]]
imgd1 = convolve(img, kd1, mode='same')
imgd2 = convolve(img, kd2, mode='same')

(3) 最后,绘制输入图像及其导数:

plt.figure(figsize=(20,10))
plt.gray()
plt.subplot(231), plt.imshow(img), plt.title('image', size=10)
plt.subplot(232), plt.imshow(imgd1), plt.title('1st derivative', size=10)
plt.subplot(233), plt.imshow(imgd2), plt.title('2nd derivative', size=10)
plt.subplot(234), plt.plot(range(w), img[0,:]), plt.title('image function', size=10)
plt.subplot(235), plt.plot(range(w), imgd1[0,:]), plt.title('1st derivative function', size=10)
plt.subplot(236), plt.plot(range(w), imgd2[0,:]), plt.title('2nd derivative function', size=10)
plt.show()

图像导数
从以上结果图像可以看出,在边缘像素周围可以观察到以下内容:

  • 原始图像中的边缘像素强度急剧变化
  • 一阶导数在边缘像素处达到最大值
  • 二阶导数在边缘像素处具有零交叉点

2. LoG/zero-crossing

在本节中,我们将使用导数的零交叉 (zero-crossing) 特性查找图像中的边缘。在边缘像素上,一阶导数达到最大化(或最小化),而此处的二阶导数为零。然而,我们并不能总是找到导数为零的离散像素,因此需要寻找零交叉,以近似与梯度最大值/最小值相对应的位置。
但是,这种方法对噪声较为敏感(因为它需要两次求导),为了解决这个问题,我们需要首先平滑图像并去除噪声。因此,有以下两种方法使用二阶导数来识别边缘:

  • 首先执行平滑,然后应用梯度
  • 结合平滑和梯度操作

导数是使用拉普拉斯 (Laplacian ∇ 2 ∇2 ∇2) 算子计算的,并使用高斯算子平滑图像。这两个算子通常可以被组合为高斯拉普拉斯算子 (Laplacian of Gaussian, LoG),因此可以减少卷积运算:
卷积的导数定理可以描述为:

∂ ∂ x ( h ∗ f ) = ( ∂ ∂ x h ) ∗ f \frac \partial {\partial x}(h*f)=(\frac \partial {\partial x}h)*f x(hf)=(xh)f

高斯拉普拉斯算子 (Laplacian of Gaussian, LoG),或称 Marr-Hildteth 算子描述如下:

∇ 2 [ f ( x , y ) ∗ G ( x , y ) ] = ∇ 2 G ( x , y ) ∗ f ( x , y ) \nabla ^2[f(x,y)*G(x,y)]=\nabla ^2G(x,y)*f(x,y) 2[f(x,y)G(x,y)]=2G(x,y)f(x,y)

其中 G ( x , y ) = 1 2 π σ 2 e − x 2 + y 2 2 σ 2 G(x,y)=\frac 1 {2\pi\sigma ^2}e^{-\frac {x^2+y^2}{2\sigma ^2}} G(x,y)=2πσ21e2σ2x2+y2,将 G ( x , y ) G(x,y) G(x,y) 带入上式可得:

L o G ( x , y ) = ∇ 2 G ( x , y ) = ∂ 2 ∂ x 2 G ( x , y ) + ∂ 2 ∂ y 2 G ( x , y ) = − 1 π σ 4 [ 1 − x 2 + y 2 2 σ 2 ] e − x 2 + y 2 2 σ 2 \begin{aligned} LoG(x,y)&=\nabla ^2 G(x,y)=\frac {\partial ^2} {\partial x^2}G(x,y)+\frac {\partial ^2} {\partial y^2}G(x,y)\\ &=-\frac 1 {\pi\sigma ^4}[1-\frac {x^2+y^2} {2\sigma ^2}]e^{-\frac {x^2+y^2}{2\sigma ^2}} \end{aligned} LoG(x,y)=2G(x,y)=x22G(x,y)+y22G(x,y)=πσ41[12σ2x2+y2]e2σ2x2+y2

参数 σ σ σ 是高斯核的宽度,并用于控制平滑量。紧接着图像的 LoG 变换之后,对零交叉的连续计算会输出图像中的边缘,这通常称为 Marr-Hildteth (LoG) 算法。

2.1 Marr-Hildteth 算法

Marr-Hildteth (LoG) 算法描述如下:

  • 计算图像 LoG
  • 在每一行和每一列中找到零交叉点
  • 计算零交叉点的斜率
  • 将阈值应用于梯度并标记边缘

使用该算法检测到的边缘结构根据高斯核宽度参数 σ σ σ 不同而不同:

  • 检测到更大尺度的边缘,减少噪声,但增加边缘位置的不确定性
  • 检测到更精细的细节特征

但该算法不能很好地处理角点;LoG 的零交叉点能够对边缘进行较好的定位,尤其是当边缘不是很锐利时,该方法存在噪声抑制。

(1) 导入所有必需的库,读取输入图像,并根据 LoG/zero-crossings 找到其中的边缘:

import numpy as np
from scipy import ndimage
from skimage.io import imread
import matplotlib.pyplot as plt
from skimage.color import rgb2gray

(2) 定义函数 any_neighbor_neg(),该函数根据给定(正值)像素,返回其周围 8 个邻居中是否有负值像素,如果存在负值像素,则意味着存在零交叉点,将计算并返回相应边的斜率:

def any_neighbor_neg(img, i, j):
    for k in range(-1,2):
        for l in range(-1,2):
            if img[i+k, j+k] < 0:
                return True, img[i, j] - img[i+k, j+k]
    return False, None

(3) 定义函数 zero_crossing(),该函数以黑色输出图像开始,如果以下条件均为真,则将像素颜色更改为白色,即边缘像素:

  • 像素是一个正像素
  • 它的 8 个邻居中至少有一个负像素
  • 边缘的斜率(如果存在负像素)高于给定的阈值(仅检测强边缘)
def zero_crossing(img, th):
    out_img = np.zeros(img.shape)
    for i in range(1,img.shape[0]-1):
        for j in range(1,img.shape[1]-1):
            found, slope = any_neighbor_neg(img, i, j)
            if img[i,j] > 0 and found and slope > th:
                out_img[i,j] = 255
    return out_img

(4) 读取输入图像并将其转换为灰度图像,使用不同 σ σ σ 值调用 scipy.ndimage 模块的 gaussian_lapace() 函数将 LoG 运算符应用于图像。使用不同 σ σ σ 值以及不同阈值计算所得图像中的零交叉点,随着 σ σ σ 的增加,使用的阈值会降低,并绘制使用不同 σ \sigma σ 检测到到的的边缘:

img = rgb2gray(imread('1.png'))
#img = misc.imread('../new images/tagore.png')[...,3]
print(np.max(img))
fig = plt.figure(figsize=(10,16))
plt.subplots_adjust(0,0,1,0.95,0.05,0.05)
plt.gray() # show the filtered result in grayscale
for sigma, thres in zip(range(3,10,2), [1e-3, 1e-4, 1e-5, 1e-6]):
    plt.subplot(2,2,sigma//2)
    result = ndimage.gaussian_laplace(img, sigma=sigma)
    result = zero_crossing(result, thres)
    plt.imshow(result)
    plt.axis('off')
    plt.title('LoG with zero-crossing, sigma=' + str(sigma), size=10)

plt.tight_layout()
plt.show()

LoG边缘检测

3. Canny 与 holistically-nested 算法

在本节中,我们将学习一种基于深度学习的边缘检测技术,称为 holistically-nested 边缘检测。我们还将结果与另一种主流的基于梯度的边缘检测算法 Canny 进行比较,我们首先将介绍这两种不同的算法。

3.1 Canny 边缘检测

Canny 边缘检测是一种多阶段算法,依赖于找到图像导数的极值。接下来,我们将使用 OpenCV 实现 Canny 边缘检测:

  • 降噪:作为一种基于梯度的边缘检测技术,它易受图像中的噪声的影响;因此,第一步是用高斯滤波器去除图像中的噪声(例如,使用核尺寸 5 x 5)
  • 然后,用水平和垂直方向的 Sobel 核(使用卷积)对图像平滑图像的强度梯度计算执行滤波,Sobel 垂直和水平核如下,本质上只是导数算子的变体:
    S x = [ + 1 + 2 + 1 0 0 0 − 1 − 2 − 1 ] , S y = [ + 1 0 − 1 + 2 0 − 2 + 1 0 − 1 ] S_x= \left[ \begin{matrix} +1 &+2 &+1 \\ 0 &0 &0\\ -1 &-2 &-1 \\ \end{matrix} \right], S_y= \left[ \begin{matrix} +1 &0 &-1 \\ +2 &0 &-2 \\ +1 &0 &-1 \\ \end{matrix} \right] Sx= +101+202+101 ,Sy= +1+2+1000121
    根据以上公式,每个像素的边缘梯度和方向计算如下,梯度方向始终垂直于边缘:
    • 梯度大小: ∣ G ∣ = S x 2 + S y 2 |G|=\sqrt {S_x^2+S_y^2} G=Sx2+Sy2
    • 角度: θ = t a n − 1 S x S y \theta=tan^{-1}\frac {S_x}{S_y} θ=tan1SySx
  • 非极大值抑制:在计算梯度大小和方向之后,对图像进行全扫描以去除可能不构成边缘的任何不需要的像素。为此,在每个像素上,检查该像素在梯度方向上是否是其邻域中的局部最大值,得到具有较小边缘的二值图像
  • 滞后性:这个阶段在决定在以上步骤中检测到的边缘中,哪些是真实的边缘,哪些边缘是虚假的边缘。为此,使用阈值 minValmaxVal,强度大于 maxVal 的边缘都是确定的真实边缘, 而小于 minVal 的边缘都是确定的虚假边缘,因此需要将其丢弃。而位于这两个阈值之间的边缘,如果它们连接到确定的边缘像素,则认为它们是边缘的一部分;否则,它们也会被丢弃。

3.2 holistically-nested 边缘检测

Holistically-nested 边缘检测 (Holistically-nested Edge Detection, HED) 是一种新的边缘检测算法,该算法解决了边缘检测算法中的两个重要问题:

  • 端到端的模型训练和预测
  • 多尺度多层次特征学习

该模型使用深度学习模型执行端到端的预测,可以充分利用全卷积神经网络和深度监督网络。HED 会自动学习丰富的层次表示,它比基于 CNN 的边缘检测算法快数个数量级。
首先下载预处理模型,并保存在 models 文件夹中,网络架构如下所示:

HED
(1) 导入所需库和函数:

import cv2
import numpy as np
import matplotlib.pylab as plt

(2) 加载输入图像并获取其尺寸:

image = cv2.imread('2.png')
(h, w) = image.shape[:2]

(3) 将图像转换为灰度图像,用高斯模糊进行模糊,并使用 Canny 边缘检测获得边缘,滞后阈值分别为 80150

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
canny = cv2.Canny(blurred, 80, 150) 

(4) 接下来,我们将用一个居中的裁剪层替换 OpenCV 的裁剪层,使用 getMemoryShapes()forward() 方法创建类 CropLayer()。在 getMemoryShapes() 方法中,裁剪层接收两个输入,并保持批大小和通道数量,计算开始和结束裁剪坐标,并返回数据集形状;在 forward() 方法中,使用 divide(x) 执行裁剪:

class CropLayer(object):
    def __init__(self, params, blobs):
        self.xstart = 0
        self.xend = 0
        self.ystart = 0
        self.yend = 0
        
    def getMemoryShapes(self, inputs):
        inputShape, targetShape = inputs[0], inputs[1]
        batchSize, numChannels = inputShape[0], inputShape[1]
        height, width = targetShape[2], targetShape[3]
        self.ystart = (inputShape[2] - targetShape[2]) // 2
        self.xstart = (inputShape[3] - targetShape[3]) // 2
        self.yend = self.ystart + height
        self.xend = self.xstart + width
        return [[batchSize, numChannels, height, width]]
    
    def forward(self, inputs):
        return [inputs[0][:,:,self.ystart:self.yend,self.xstart:self.xend]]

(5) 接下来,读取预训练的模型:

prototxt_path = "models/deploy.prototxt"
model_path = "models/hed_pretrained_bsds.caffemodel"

net = cv2.dnn.readNetFromCaffe(prototxt_path, model_path)

(6) 使用 dnn_registerLayer() 将新层注册到模型中:

cv2.dnn_registerLayer('Crop', CropLayer)

(7) 使用 blobFromImage()HED 模型从输入图像构造输入 blob:

blob = cv2.dnn.blobFromImage(image, scalefactor=1.0, size=(w, h), mean=(104.00698793, 116.66876762, 122.67891434),  swapRB=False, crop=False)

(8)blob 设置为网络的输入,并运行正向传播 format 方法计算输出:

net.setInput(blob)
outs = net.forward()
hed = cv2.resize(outs[0][0,:,:], (w, h))
hed = (255 * hed).astype("uint8")

(9) 通过 CannyHolistically-nested 边缘检测获得的输出边缘检测结果如下所示:

plt.figure(figsize=(20, 8))
plt.gray()
plt.subplots_adjust(0,0,1,0.975,0.05,0.05)
plt.subplot(131), plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)), plt.axis('off'), plt.title('input', size=10)
plt.subplot(132), plt.imshow(canny), plt.axis('off'), plt.title('canny', size=10)
plt.subplot(133), plt.imshow(hed), plt.axis('off'), plt.title('holistically-nested', size=10)
plt.show()

边缘检测算法对比

小结

边缘检测是图像处理和计算机视觉中的基本问题,边缘检测的目的是标识图像中亮度变化明显的点,图像属性中的显著变化通常反映了图像中的重要变化和特征。边缘检测是图像处理和计算机视觉中,尤其是特征提取中的一个重要研究领域。在本节中,我们学习了多种边缘检测算法,包括基于梯度的算法以及基于深度神经网络的方法。

系列链接

Python图像处理【1】图像与视频处理基础
Python图像处理【2】探索Python图像处理库
Python图像处理【3】Python图像处理库应用
Python图像处理【4】图像线性变换
Python图像处理【5】图像扭曲/逆扭曲
Python图像处理【6】通过哈希查找重复和类似的图像
Python图像处理【7】采样、卷积与离散傅里叶变换
Python图像处理【8】使用低通滤波器模糊图像
Python图像处理【9】使用高通滤波器执行边缘检测
Python图像处理【10】基于离散余弦变换的图像压缩
Python图像处理【11】利用反卷积执行图像去模糊
Python图像处理【12】基于小波变换执行图像去噪
Python图像处理【13】使用PIL执行图像降噪
Python图像处理【14】基于非线性滤波器的图像去噪
Python图像处理【15】基于非锐化掩码锐化图像
Python图像处理【16】OpenCV直方图均衡化
Python图像处理【17】指纹增强和细节提取

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Configure Virtual Serial Port Driver串口模拟器VSPD

背景 串口通讯想必做硬件开发和软件的人来说都相当了解&#xff0c;以前的电脑&#xff0c;基本标配都包含一个串口。但现在的电脑&#xff0c;基本都没有配置串口了&#xff0c;如果要使用串口的功能&#xff0c;基本就要用一个USB转串口的硬件模块。 虚拟串口&#xff08;虚…

不同打包工具下的环境变量配置方式对比

本文作者为 360 奇舞团前端开发工程师 天明 前言 在现代的JavaScript应用程序开发中&#xff0c;环境变量的配置是至关重要的。不同的应用场景和部署环境可能需要不同的配置&#xff0c;例如开发、测试和生产环境。最常见的需求是根据不同的环境&#xff0c;配置如是否开启sour…

Transformer从菜鸟到新手(七)

引言 上篇文章加速推理的KV缓存技术&#xff0c;本文介绍让我们可以得到更好的BLEU分数的解码技术——束搜索。 束搜索 我们之前生成翻译结果的时候&#xff0c;使用的是最简单的贪心搜索&#xff0c;即每次选择概率最大的&#xff0c;但是每次生成都选择概率最大的并不一定…

C++实战Opencv第一天——win11下配置vs,opencv环境和运行第一个c++代码(从零开始,保姆教学)

OpenCV&#xff08;Open Source Computer Vision Library&#xff09;是一个开源的计算机视觉和机器学习软件库&#xff0c;它提供了大量的通用算法和功能&#xff0c;用于处理图像和视频数据。C 通常提供比 Python 更高的执行速度&#xff0c;对于需要高性能处理的任务&#x…

【XR806开发板试用】留言板功能开发

开发板简介 XR806开源鸿蒙开发板是一款基于XR806芯片设计&#xff0c;高度集成WiFi/BLE/常用外设&#xff0c;可供开发者进行方案评估、DIY或小规模产品研发&#xff0c;可广泛应用于智能家居、智能楼宇、智能城市和工业互联等领域。 搭载OpenHarmony系统&#xff08;已通过O…

Linux中的yum源仓库和NFS文件共享服务

一.yum简介 1.1 yum简介 yum&#xff0c;全称“Yellow dog Updater, Modified”&#xff0c;是一个专门为了解决包的依赖关系而存在的软件包管理器。类似于windows系统的中电脑软件关键&#xff0c;可以一键下载&#xff0c;一键安装和卸载。yum 是改进型的 RPM 软件管理器&am…

使用CloudFlare-Woker搭建简易网站

使用CloudFlare-Woker搭建简易网站 1、首先到CloudFlare官网登录或注册自己的账号&#xff1a;Cloudflare 中国官网 | 智能化云服务平台 | 免费CDN安全防护 | Cloudflare (cloudflare-cn.com) 注册一个账号 2、登录账号后进入仪表盘网页&#xff0c;选择Workers & Pages页…

2019年认证杯SPSSPRO杯数学建模C题(第二阶段)保险业的数字化变革全过程文档及程序

2019年认证杯SPSSPRO杯数学建模 基于统计建模的车险业数字变革研究 C题 保险业的数字化变革 原题再现&#xff1a; 车险&#xff0c;即机动车辆保险。保险自身是一种分散风险、消化损失的经济补偿制度&#xff0c;车险即为分散机动车辆在行驶过程中可能发作的未知风险和损失…

uni-app引用矢量库图标

矢量库引用 导入黑色图标 1.生成连接&#xff0c;下载样式 2.导入项目&#xff08;字体样式&#xff09; 3.引入css样式 4.替换font-face 5.使用图标&#xff08;字体图标&#xff0c;只有黑色&#xff09; 导入彩色图标 1.安装插件 npm install -g iconfont-tools2.…

修复系统和修复常见安卓问题的 10 个应用

我们都喜欢我们的 Android 智能手机&#xff0c;对吧&#xff1f;有很多值得喜欢的地方。 Android 手机易于使用且通常无故障&#xff0c;但毕竟它只是一台机器&#xff0c;偶尔也会出现问题。面对现实吧&#xff0c;我们的智能手机并不完美。用户经常遇到的一些常见 Android …

使用scipy处理图片——滤镜处理

大纲 black_tophatwhite_tophatconvolvecorrelategaussian_filtergaussian_laplacemaximum_filtermedian_filterminimum_filterpercentile_filterprewittrank_filtersobelspline_filteruniform_filter基础代码代码仓库 在《使用numpy处理图片——模糊处理》一文中&#xff0c;我…

【python】py-spy 实时显示python进程内的线程堆栈CPU消耗 python CPU消耗分析

安装 pip install py-spy AI调用源码&#xff0c;红色调用时&#xff0c;python进程CPU 100% 启动程序&#xff0c;输入问题&#xff0c;观察CPU top sudo .local/bin/py-spy top --pid 7150 可以看到&#xff0c;此时与显卡交互占用了绝大部分CPU&#xff0c;有点死循环检测…

HNU-模式识别-作业1-视频监控系统

模式识别-作业1 计科210X 甘晴void 202108010XXX 【评分&#xff1a;98/100】 题目&#xff1a; 查阅相关技术资料&#xff0c;根据自己家庭相应的情况&#xff0c;设计一个视频监控系统。要求&#xff1a; 系统功能说明系统布线图及说明系统软硬件配置说明 饱和式自家用…

isis小实验

要求: 1.合理规划level1-2 2.r1访问r5走r6且走上面 3.全网可达 个人理解:以重发布的视角:is-level level1即L1可以看做rip,L2可以看做OSPF,L1-2可以看作是既要rip又要OSPF,优点:isis只用在每个路由器上宣告一次 缺点:isis需要每个接口上输isis enable 1(序号)特点:L1-2会自动下…

民营经济迎来新发展,创维汽车创始人黄宏生谈创业之道

2024年1月15日&#xff0c;上海高金金融研究院民营经济研究中心高净值研究院年度大咖论坛正式召开&#xff0c;多位来自不同行业的优秀民营企业家在本次论坛上分享企业的创新与发展之道。创维集团、创维汽车创始人黄宏生先生作为本次论坛的首位分享嘉宾&#xff0c;为其他奋斗创…

HCIA——10实验:跨路由转发。静态路由、负载均衡、缺省路由、手工汇总、环回接口。空接口与路由黑洞、浮动静态。

学习目标&#xff1a; 跨路由转发、负载均衡、环回接口、手工汇总、缺省路由、空接口与路由黑洞、浮动静态 学习内容&#xff1a; 跨路由转发静态路由、负载均衡、缺省路由、手工汇总。环回接口空接口与路由黑洞、浮动静态 目录 学习目标&#xff1a; 学习内容&#xff1a…

群晖NAS上安装部署开源工作流自动化工具n8n

一、开源工作流自动化工具n8n简介 n8n是它是一个与其他应用集成的应用程序&#xff0c;目标是自动化各应用之间的流程;利用 n8n 你可以方便地实现当 A 条件发生&#xff0c;触发 B 服务这样的自动工作流程。 n8n优点是&#xff1a;代码开源、可以自托管、下载安装方便、易于使用…

SQL性能分析手段

SQL执行频率 MySQL 客户端连接成功后&#xff0c;通过 show [session|global] status 命令可以提供整个服务器执行sql的状态信息。通过如下指令&#xff0c;可以查看当前数据库的INSERT、UPDATE、DELETE、SELECT的访问频次&#xff1a; -- session 是查看当前会话 ; -- globa…

ioctl操作实现

ioctl&#xff0c;避免使用三个全局变量&#xff0c;因此写进一个结构体里面 ioctl对文件属性进行操作 #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/cdev.h> #include <asm/uaccess.h>#define…

HarmonyOS之sqlite数据库的使用

从API Version 9开始&#xff0c;鸿蒙开发中sqlite使用新接口ohos.data.relationalStore 但是 relationalStore在 getRdbStore操作时&#xff0c;在预览模式运行或者远程模拟器运行都会报错&#xff0c;导致无法使用。查了一圈说只有在真机上可以正常使用&#xff0c;因此这里…