OpenCV学习(4.3) 图像阈值

1.目的

在本教程中:

  • 你会学到简单阈值法,自适应阈值法,以及 Otsu 阈值法(俗称大津法)等。
  • 你会学到如下函数:**cv.thresholdcv.adaptiveThreshold** 等。

2.简单阈值法

此方法是直截了当的。如果像素值大于阈值,则会被赋为一个值(可能为白色),否则会赋为另一个值(可能为黑色)。使用的函数是 cv.threshold。第一个参数是源图像,它应该是灰度图像。第二个参数是阈值,用于对像素值进行分类。第三个参数是 maxval,它表示像素值大于(有时小于)阈值时要给定的值。opencv 提供了不同类型的阈值,由函数的第四个参数决定。不同的类型有:

  • cv.THRESH_BINARY
  • cv.THRESH_BINARY_INV
  • cv.THRESH_TRUNC
  • cv.THRESH_TOZERO
  • cv.THRESH_TOZERO_INV

文档清楚地解释了每种类型的含义。请查看文档。

获得两个输出。第一个是 retval,稍后将解释。第二个输出是我们的阈值图像。

代码:

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img = cv.imread('gradient.png',0)
ret,thresh1 = cv.threshold(img,127,255,cv.THRESH_BINARY)
ret,thresh2 = cv.threshold(img,127,255,cv.THRESH_BINARY_INV)
ret,thresh3 = cv.threshold(img,127,255,cv.THRESH_TRUNC)
ret,thresh4 = cv.threshold(img,127,255,cv.THRESH_TOZERO)
ret,thresh5 = cv.threshold(img,127,255,cv.THRESH_TOZERO_INV)
titles = ['Original Image','BINARY','BINARY_INV','TRUNC','TOZERO','TOZERO_INV']
images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]
for i in xrange(6):
    plt.subplot(2,3,i+1),plt.imshow(images[i],'gray')
    plt.title(titles[i])
    plt.xticks([]),plt.yticks([])
plt.show()

在 OpenCV 中,这些是阈值化操作的类型,用于将灰度图像转换为二值图像或将灰度图像中的像素值根据阈值进行分割。阈值化是一种常见的图像处理技术,它根据像素值与设定阈值的比较结果,将像素值设置为0或最大值。

以下是这些阈值的类型及其作用:

  1. cv.THRESH_BINARY:如果像素值大于阈值,则将其设置为最大值(例如255),否则设置为0。这种类型的阈值化产生了一个完全黑白的二值图像。

  2. cv.THRESH_BINARY_INV:与cv.THRESH_BINARY相反,如果像素值大于阈值,则将其设置为0,否则设置为最大值。这种类型的阈值化也会产生一个完全黑白的二值图像,但与cv.THRESH_BINARY相比,黑色和白色的区域会互换。

  3. cv.THRESH_TRUNC:如果像素值大于阈值,则将其截断为阈值,否则保持不变。这种类型的阈值化不会产生二值图像,而是将阈值以上的像素值都设置为相同的值。

  4. cv.THRESH_TOZERO:如果像素值大于阈值,则保持不变,否则将其设置为0。这种类型的阈值化会将低于阈值的像素值变为黑色,而高于阈值的像素值保持其原始灰度。

  5. cv.THRESH_TOZERO_INV:与cv.THRESH_TOZERO相反,如果像素值大于阈值,则将其设置为0,否则保持不变。这种类型的阈值化会将高于阈值的像素值变为黑色,而低于阈值的像素值保持其原始灰度。

在使用这些阈值类型时,通常还会指定一个阈值值和一个最大值。阈值值是用于比较的值,而最大值是用于cv.THRESH_BINARYcv.THRESH_BINARY_INV类型的输出图像中的最大像素值。

 

3.自适应阈值 

在前一节中,我们使用一个全局变量作为阈值。但在图像在不同区域具有不同照明条件的条件下,这可能不是很好。在这种情况下,我们采用自适应阈值。在此,算法计算图像的一个小区域的阈值。因此,我们得到了同一图像不同区域的不同阈值,对于不同光照下的图像,得到了更好的结果。

它有三个“特殊”输入参数,只有一个输出参数。

Adaptive Method-它决定如何计算阈值。

  • cv.ADAPTIVE_THRESH_MEAN_C 阈值是指邻近地区的平均值。
  • cv.ADAPTIVE_THRESH_GAUSSIAN_C 阈值是权重为高斯窗的邻域值的加权和。

Block Size-它决定了计算阈值的窗口区域的大小。

C-它只是一个常数,会从平均值或加权平均值中减去该值。

代码:

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
# img = cv.imread('gradient.png',0)
img = r'D:\study\EmotionDetection_RealTime-master\data\data\te\04.jpg'
img = cv.imread(img,0)



img = cv.medianBlur(img,5)
ret,th1 = cv.threshold(img,127,255,cv.THRESH_BINARY)
th2 = cv.adaptiveThreshold(img,255,cv.ADAPTIVE_THRESH_MEAN_C,cv.THRESH_BINARY,11,2)
th3 = cv.adaptiveThreshold(img,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,cv.THRESH_BINARY,11,2)
titles = ['Original Image', 'Global Thresholding (v = 127)',
            'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding']
images = [img, th1, th2, th3]
for i in range(4):
    plt.subplot(2,2,i+1),plt.imshow(images[i],'gray')
    plt.title(titles[i])
    plt.xticks([]),plt.yticks([])
plt.show()

img = cv.medianBlur(img,5)

在 OpenCV 中,cv.medianBlur 函数用于对图像进行中值滤波。中值滤波是一种非线性的数字图像滤波技术,它用像素点邻域内的中值来代替该像素点的值,从而消除图像中的椒盐噪声和斑点噪声,同时保持图像边缘清晰。 

在 OpenCV 中,可以使用 cv.adaptiveThreshold 函数来实现自适应阈值化。该函数的原型如下:

cv.adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C)

参数说明:

  • src:输入的灰度图像。
  • maxValue:用于阈值化操作的最大值,通常设置为 255。
  • adaptiveMethod:自适应方法,可以是 cv.ADAPTIVE_THRESH_MEAN_C 或 cv.ADAPTIVE_THRESH_GAUSSIAN_C
    • cv.ADAPTIVE_THRESH_MEAN_C:计算局部区域的平均值作为阈值。
    • cv.ADAPTIVE_THRESH_GAUSSIAN_C:计算局部区域的加权平均值作为阈值,权重是一个高斯窗口。
  • thresholdType:阈值类型,与 cv.threshold 函数中的阈值类型相同,例如 cv.THRESH_BINARY
  • blockSize:局部区域的大小,必须是奇数,如 3、5、7 等。
  • C:从平均值或加权平均值中减去的常数,通常是一个正值。

输出图像: 

4.otus二值化

在第一部分中,我告诉过您有一个参数 retval。当我们进行 Otsu 二值化时,它的用途就来了。那是什么?

在全局阈值化中,我们使用一个任意的阈值,对吗?那么,我们如何知道我们选择的值是好的还是不好的呢?答案是,试错法。但是考虑一个双峰图像(简单来说,双峰图像是一个直方图有两个峰值的图像)。对于那个图像,我们可以近似地取这些峰值中间的一个值作为阈值,对吗?这就是 Otsu 二值化所做的。所以简单来说,它会自动从双峰图像的图像直方图中计算出阈值。(对于非双峰图像,二值化将不准确。)

为此,我们使用了 cv.threshold 函数,但传递了一个额外的符号 cv.THRESH_OTSU 。对于阈值,只需传入零。然后,该算法找到最佳阈值,并作为第二个输出返回 retval。如果不使用 otsu 阈值,则 retval 与你使用的阈值相同。

查看下面的示例。输入图像是噪声图像。在第一种情况下,我应用了值为 127 的全局阈值。在第二种情况下,我直接应用 otsu 阈值。在第三种情况下,我使用 5x5 高斯核过滤图像以去除噪声,然后应用 otsu 阈值。查看噪声过滤如何改进结果。

代码:

import cv2 as cv
import numpy as np
from skimage import util
from matplotlib import pyplot as plt
# img = cv.imread('gradient.png',0)
img = r'D:\study\EmotionDetection_RealTime-master\data\data\te\01.jpg'
img = cv.imread(img,cv.IMREAD_GRAYSCALE)
cv.imshow('img',img)



 # 全局阈值
ret1,th1 = cv.threshold(img,127,255,cv.THRESH_BINARY)
# Otsu 阈值
ret2,th2 = cv.threshold(img,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)
# 经过高斯滤波的 Otsu 阈值
blur = cv.GaussianBlur(img,(5,5),0)
ret3,th3 = cv.threshold(blur,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)
# 画出所有的图像和他们的直方图
images = [img, 0, th1,
          img, 0, th2,
           blur, 0, th3]
 titles = ['Original Noisy Image','Histogram','Global Thresholding (v=127)',
           'Original Noisy Image','Histogram',"Otsu's Thresholding",
           'Gaussian filtered Image','Histogram',"Otsu's Thresholding"]
 for i in range(3):
     plt.subplot(3,3,i*3+1),plt.imshow(images[i*3],'gray')
     plt.title(titles[i*3]), plt.xticks([]), plt.yticks([])
     plt.subplot(3,3,i*3+2),plt.hist(images[i*3].ravel(),256)
     plt.title(titles[i*3+1]), plt.xticks([]), plt.yticks([])
     plt.subplot(3,3,i*3+3),plt.imshow(images[i*3+2],'gray')
     plt.title(titles[i*3+2]), plt.xticks([]), plt.yticks([])
 plt.show()

 在您的代码中,您使用了 OpenCV 的 `cv.threshold` 函数来应用不同的阈值化方法。这里简要解释一下每个步骤:
1. `ret1, th1 = cv.threshold(img, 127, 255, cv.THRESH_BINARY)`:
   - `img` 是输入图像。
   - `127` 是阈值。
   - `255` 是最大值。
   - `cv.THRESH_BINARY` 是阈值类型,它将像素值设置为 0 或 255,具体取决于它们是否大于阈值。
   - 返回值 `ret1` 是一个布尔值,表示阈值化操作是否成功。
   - `th1` 是阈值化后的输出图像。
2. `ret2, th2 = cv.threshold(img, 0, 255, cv.THRESH_BINARY + cv.THRESH_OTSU)`:
   - 与第一个步骤类似,但这次您使用了 `cv.THRESH_OTSU`。
   - `cv.THRESH_OTSU` 是一个特殊的阈值类型,它会自动选择一个阈值,使得前景和背景之间的类间方差最大。
   - `th2` 是应用 Otsu 阈值后的输出图像。
3. `blur = cv.GaussianBlur(img, (5, 5), 0)`:
   - `img` 是输入图像。
   - `(5, 5)` 是高斯滤波器的尺寸,它定义了滤波器的宽度和高度。
   - `0` 是高斯核的标准差,它决定了滤波器的模糊程度。
   - `blur` 是应用高斯滤波后的输出图像。
4. `ret3, th3 = cv.threshold(blur, 0, 255, cv.THRESH_BINARY + cv.THRESH_OTSU)`:
   - 与第二个步骤类似,但这次您使用了经过高斯滤波的图像 `blur`。
   - `th3` 是应用 Otsu 阈值后的输出图像。
请注意,`cv.threshold` 函数的第二个参数 `0` 通常是不必要的,因为它是默认值。您可以直接使用 `cv.threshold(img, 0, 255, cv.THRESH_BINARY + cv.THRESH_OTSU)`。
最后,`ret1`、`ret2` 和 `ret3` 都是布尔值,表示阈值化操作是否成功。`th1`、`th2` 和 `th3` 是阈值化后的输出图像。

可以看到是没什么区别,因为图像噪声很小,进行高斯滤波后变化不大 

添加高斯噪声后,可以看到有明显的效果 

加入噪声的代码:
img = util.random_noise(img, mode='gaussian', mean=0, var=0.05)
img = np.uint8(img * 255)

在 OpenCV 中,util.random_noise(img, mode='gaussian', mean=0, var=0.05) 函数的 img 参数是一个图像数据,而 util.random_noise 函数是添加高斯噪声的函数。

当您调用 util.random_noise 函数并将 img 作为第一个参数传递时,它会根据您指定的参数(在这个例子中是 mode='gaussian'mean=0 和 var=0.05)为图像添加高斯噪声。

  • mode='gaussian' 指定使用高斯噪声模式。
  • mean=0 指定噪声的均值(中心点),这里设置为 0,意味着噪声的平均值是 0。
  • var=0.05 指定噪声的方差,它决定了噪声的强度。方差值越大,噪声越强。在这个例子中,方差为 0.05,意味着噪声强度较小。

添加噪声后,util.random_noise 函数将返回一个包含噪声的图像。这个图像的数据类型将与输入图像的数据类型相同。如果输入图像是一个浮点数图像,那么添加噪声后的输出也将是一个浮点数图像。如果输入图像是一个整数图像,那么添加噪声后的输出将是一个浮点数图像。

因此,util.random_noise(img, mode='gaussian', mean=0, var=0.05) 的输出结果将是一个浮点数图像,其中包含了根据指定参数添加的高斯噪声。

5. 二值化原理

 由于我们使用的是双峰图像,因此 Otsu 的算法试图找到一个阈值(t),该阈值将由下式计算得到的类内加权方差最小化。

它实际上找到一个 T 值,它位于两个峰值之间,使得两个类的方差最小。它可以简单地在 python 中实现,如下所示:

img = cv.imread('noisy2.png',0)
blur = cv.GaussianBlur(img,(5,5),0)
# 找到归一化直方图还有累计分布函数
hist = cv.calcHist([blur],[0],None,[256],[0,256])
hist_norm = hist.ravel()/hist.max()
Q = hist_norm.cumsum()
bins = np.arange(256)
fn_min = np.inf
thresh = -1
for i in xrange(1,256):
    p1,p2 = np.hsplit(hist_norm,[i]) # 概率
    q1,q2 = Q[i],Q[255]-Q[i] # 类别总和
    b1,b2 = np.hsplit(bins,[i]) # 权重
    # f 找到均值与方差
    m1,m2 = np.sum(p1*b1)/q1, np.sum(p2*b2)/q2
    v1,v2 = np.sum(((b1-m1)**2)*p1)/q1,np.sum(((b2-m2)**2)*p2)/q2
    # 计算最小函数
    fn = v1*q1 + v2*q2
    if fn < fn_min:
        fn_min = fn
        thresh = i
# 用 OpenCV 函数的 otsu'阈值
ret, otsu = cv.threshold(blur,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)
print( "{} {}".format(thresh,ret) )

Q = hist_norm.cumsum()

在您提供的代码片段中,您正在计算直方图的累积分布函数(CDF)。累积分布函数(CDF)是概率论中的一个概念,它给出了随机变量小于或等于某个值的概率。在图像处理中,累积分布函数通常用于阈值选择,特别是在 Otsu 阈值化方法中。
在您的代码中,`Q = hist_norm.cumsum()` 意味着:
- `hist_norm` 是归一化的直方图,其值范围在 [0, 1]。
- `hist_norm.cumsum()` 计算直方图的累积和,即从左到右遍历直方图,计算累积的概率。
这个累积和形成了一个新的数组 `Q`,其中 `Q[i]` 表示随机变量小于或等于 `i` 的概率。这个数组 `Q` 就是累积分布函数(CDF)。
累积分布函数在 Otsu 阈值化方法中的作用是帮助选择一个阈值,使得背景和前景之间的类间方差最大。Otsu 阈值化的基本思想是找到一个阈值,使得前景和背景之间的类间方差最大。在这个上下文中,类间方差可以通过计算前景和背景的概率分布的方差来估计。
请注意,Otsu 阈值化通常使用 OpenCV 的 `cv.threshold(blur, 0, 255, cv.THRESH_BINARY + cv.THRESH_OTSU)` 函数来实现,而不是手动计算累积分布函数。手动计算可能会导致不准确的结果,并且通常不如 OpenCV 的内置函数高效。 

p1,p2 = np.hsplit(hist_norm,[i]) # 概率

在您提供的代码片段中,您似乎正在尝试实现一个自定义的 Otsu 阈值选择方法。在这个方法中,您使用了 NumPy 的 `np.hsplit` 函数来分割直方图。
`np.hsplit` 函数用于将一个数组水平分割成多个子数组。它接受一个数组和一个或多个分割点作为参数,并将数组分割成多个子数组。
在您的代码中,`p1, p2 = np.hsplit(hist_norm, [i])` 意味着:
- `hist_norm` 是归一化的直方图。
- `[i]` 是分割点,表示您想要将直方图分割成两部分,其中一部分包含小于或等于 `i` 的像素,另一部分包含大于 `i` 的像素。
函数 `np.hsplit` 返回两个子数组,分别对应于小于或等于 `i` 的像素和大于 `i` 的像素。这两个子数组分别被赋值给 `p1` 和 `q2`。
请注意,如果您想要使用 OpenCV 的 `cv.threshold` 函数来应用 Otsu 阈值,您应该使用 `cv.threshold(blur, 0, 255, cv.THRESH_BINARY + cv.THRESH_OTSU)`,而不是手动计算阈值。手动计算阈值可能会导致不准确的结果,并且通常不如 OpenCV 的内置函数高效。

q1,q2 = Q[i],Q[255]-Q[i] 

在您提供的代码片段中,您似乎正在尝试实现一个自定义的 Otsu 阈值选择方法。在这个方法中,您使用了累积分布函数(CDF)来分割直方图,并计算两个类别的概率。
在 Otsu 阈值化方法中,累积分布函数(CDF)被用来分割直方图,从而得到两个类别的概率分布。具体来说,您正在计算两个类别(前景和背景)的概率。
在您的代码中,`q1, q2 = Q[i], Q[255] - Q[i]` 意味着:
- `Q` 是累积分布函数(CDF)。
- `i` 是分割点,表示您想要将直方图分割成两部分,其中一部分包含小于或等于 `i` 的像素,另一部分包含大于 `i` 的像素。
- `Q[i]` 表示随机变量小于或等于 `i` 的概率,即背景的概率。
- `Q[255] - Q[i]` 表示随机变量大于 `i` 的概率,即前景的概率。
这两个概率值 `q1` 和 `q2` 用于后续的计算,以估计前景和背景的方差。Otsu 阈值化的基本思想是找到一个阈值,使得前景和背景之间的类间方差最大。类间方差可以通过计算前景和背景的概率分布的方差来估计。
请注意,Otsu 阈值化通常使用 OpenCV 的 `cv.threshold(blur, 0, 255, cv.THRESH_BINARY + cv.THRESH_OTSU)` 函数来实现,而不是手动计算累积分布函数。手动计算可能会导致不准确的结果,并且通常不如 OpenCV 的内置函数高效。

b1,b2 = np.hsplit(bins,[i]) # 权重 

在您提供的代码片段中,您似乎正在尝试实现一个自定义的 Otsu 阈值选择方法。在这个方法中,您使用了 NumPy 的 `np.hsplit` 函数来分割一个包含像素值的数组。
在您的代码中,`b1, b2 = np.hsplit(bins, [i])` 意味着:
- `bins` 是一个包含像素值的数组,这些像素值代表图像的灰度级。
- `[i]` 是分割点,表示您想要将像素值数组分割成两部分,其中一部分包含小于或等于 `i` 的像素值,另一部分包含大于 `i` 的像素值。
函数 `np.hsplit` 返回两个子数组,分别对应于小于或等于 `i` 的像素值和大于 `i` 的像素值。这两个子数组分别被赋值给 `b1` 和 `b2`。
在 Otsu 阈值化方法中,`b1` 和 `b2` 通常被称为权重,它们代表图像中不同灰度级像素的数量。这些权重被用来计算前景和背景的加权方差,从而找到最佳的阈值。
请注意,Otsu 阈值化通常使用 OpenCV 的 `cv.threshold(blur, 0, 255, cv.THRESH_BINARY + cv.THRESH_OTSU)` 函数来实现,而不是手动计算权重。手动计算可能会导致不准确的结果,并且通常不如 OpenCV 的内置函数高效。

m1,m2 = np.sum(p1*b1)/q1, np.sum(p2*b2)/q2 v1,v2 = np.sum(((b1-m1)**2)*p1)/q1,np.sum(((b2-m2)**2)*p2)/q2

在您提供的代码片段中,您似乎正在尝试实现一个自定义的 Otsu 阈值选择方法。在这个方法中,您正在计算两个类别(前景和背景)的均值和方差。
在 Otsu 阈值化方法中,均值和方差被用来估计前景和背景的加权方差,从而找到最佳的阈值。加权方差是类内方差和类间方差的组合,用于评估不同阈值下的分割质量。
在您的代码中,`m1, m2 = np.sum(p1*b1)/q1, np.sum(p2*b2)/q2` 意味着:
- `p1` 和 `p2` 是前景和背景的概率分布。
- `b1` 和 `b2` 是前景和背景的权重,即对应灰度级的像素数量。
- `q1` 和 `q2` 是前景和背景的概率。
这些概率和权重被用来计算两个类别的均值:
- `m1` 是前景的均值,计算方法是将前景的概率分布 `p1` 乘以前景的权重 `b1`,然后除以前景的概率 `q1`。
- `m2` 是背景的均值,计算方法是将背景的概率分布 `p2` 乘以背景的权重 `b2`,然后除以背景的概率 `q2`。
接着,您计算了两个类别的方差:
- `v1` 是前景的方差,计算方法是将前景的权重 `b1` 与前景的均值 `m1` 的差的平方乘以前景的概率分布 `p1`,然后除以前景的概率 `q1`。
- `v2` 是背景的方差,计算方法是将背景的权重 `b2` 与背景的均值 `m2` 的差的平方乘以背景的概率分布 `p2`,然后除以背景的概率 `q2`。
这些方差和均值值用于后续的计算,以估计前景和背景的加权方差,从而找到最佳的阈值。
请注意,Otsu 阈值化通常使用 OpenCV 的 `cv.threshold(blur, 0, 255, cv.THRESH_BINARY + cv.THRESH_OTSU)` 函数来实现,而不是手动计算均值和方差。手动计算可能会导致不准确的结果,并且通常不如 OpenCV 的内置函数高效。 

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

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

相关文章

echart使用

安装方式从 npm 获取 npm install echarts 使用的页面js部分引入&#xff1a; import * as echarts from "echarts"; // 图标引入 html&#xff1a;需要带id标签的div <div class"bottom"><div id"main1"></div></di…

opencv-python(五)

opencv的颜色通道中顺序是B&#xff0c;G&#xff0c;R。 图像属性 import cv2img cv2.imread(jk.jpg) print(fshape{img.shape}) print(fsize{img.size}) print(fdtype{img.dtype}) shape&#xff1a;图像像素的行&#xff0c;列&#xff0c;通道 size&#xff1a;行数 X …

磁盘怎么分区?3 款最佳免费磁盘分区软件

您可能已经注意到&#xff0c;大多数计算机至少有 2 个分区&#xff1a;一个安装 Windows 操作系统和程序&#xff08;C:&#xff09;&#xff0c;另一个安装其他文件&#xff08;D:&#xff09;。 默认情况下&#xff0c;计算机只有一个硬盘和一个分区。建议创建 2 个或更多分…

逐步掌握最佳Ai Agents框架-AutoGen 九 RAG应用

在最近的几篇文章里&#xff0c;我们使用AutoGen实现了一些Demo。这篇文章&#xff0c;我们将使用AutoGen来完成RAG应用开发。 RAG应用 RAG全称"Retrieval-Augmented Generation",即检索增强生成&#xff0c;它是自然语言处理中的一项技术。这种模型结合了检索式&a…

try…except语句

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 在程序开发时&#xff0c;有些错误并不是每次运行都会出现。例如&#xff0c;实例01&#xff0c;只要输入的数据符合程序的要求&#xff0c;程序就可…

智能监测,无忧续航!Battery Indicator for Mac,让电池状态尽在掌握

Battery Indicator for Mac 是一款设计精良的电池状态监测软件&#xff0c;它极大地增强了Mac用户对电池使用情况的感知和管理能力。 首先&#xff0c;Battery Indicator for Mac 能够实时显示电池电量百分比。这意味着&#xff0c;无论你是在处理文件、浏览网页还是观看视频&…

vue无需引入第三方, 将web页面内容直接下载为docx

vue无需引入第三方&#xff0c; 将web页面内容直接下载为docx 将web页面内容重绘 html &#xff0c;通过 a 标签直接下载 通过写行内样式&#xff0c;控制docx中的文字图效果 let echHtmlWithIf ;if (this.chartImg.length) {if (this.exceed10Min) {echHtmlWithIf <div…

c++ - list常用接口模拟实现

文章目录 一、模拟list类的框架二、函数接口实现1、迭代器接口2、常用删除、插入接口3、常用其他的一些函数接口4、默认成员函数 一、模拟list类的框架 1、使用带哨兵的双向链表实现。 2、链表结点&#xff1a; // List的结点类 template<class T> struct ListNode {Li…

opencv进阶 ——(十一)基于RMBG实现生活照生成寸照

实现步骤 1、检测人脸&#xff0c;可以使用opencv自带的级联分类器或者dlib实现人脸检测 2、放大人脸范围&#xff0c;调整到正常寸照尺寸 3、基于RMGB算法得到人像掩码 4、生成尺寸相同的纯色背景与当前人像进行ALPHA融合即可 alpha融合实现 void alphaBlend(cv::Mat&…

场外个股期权交易最新指南

场外个股期权交易最新指南 场外个股期权作为一种灵活的衍生品工具&#xff0c;允许投资者在特定条件下对交易所指定的股票进行买卖。相较于标准化的场内个股期权&#xff0c;场外个股期权为投资者提供了更大的自由度。以下是关于场外个股期权交易的基本步骤和要点&#xff1a;…

股票期权是什么意思?期权懂为你介绍股票期权操作方法

今天带你了解股票期权是什么意思&#xff1f;期权懂为你介绍股票期权操作方法。股票期权是一种有着多种用途的金融工具&#xff0c;它给企业、员工、投资人和公司带来了丰厚的收益&#xff0c;对于投资人而言&#xff0c;在市场风险和机会之间寻找平衡&#xff0c;从而实现稳健…

bbbike下载OSM路网数据后使用GraphHopper离线进行路径规划

一、bbbike下载OSM路网数据 GraphHopper是一种快速且内存有效的Java导航引擎&#xff0c;默认使用OSM和GTFS数据&#xff0c;也可导入其他的数据源。支持CH&#xff08;Contraction Hierarchies&#xff09;、A*、Dijkstra算法。 1、搭建之前要保证jdk安装完成&#xff0c;且完…

openeuler系统配置dns

openeuler系统配置dns 第1步 在/etc/sysconfig/network-scripts/ifcfg-ens192文件配置 注意PEERDNSno一定要配上 第2步 vim /etc/resolv.conf #编辑dns指向文件 nameserver 192.168.187.129 #添加我们配置的dns服务器的ip第3步 # 配置完以后需要重启网卡 systemctl res…

每天的CTF小练--6.5(ascll码高级运用)

题目&#xff1a;[HUBUCTF 2022 新生赛]baby_encrypt hint&#xff1a; 781612443113954655886887407898899451044114412011257135914071455155316031651170318041861191719652013207021272183228423832485254125932643269827992924 注意查看前面的数字&#xff0c;这题不想现…

python入门3

文章目录 前言一、函数为什么要使用函数&#xff1f;函数定义函数定义和调用定义函数返回值定义空函数函数参数传递传递实参位置实参关键词实参默认值实参等效函数调用实参可选传递任意数量的实参任意数量关键字实参任意参数*与** 的区别使用元组和字典传参如果既有实参又有任意…

高效管理近30万稳定运力,科技物流企业万联易达这样做

万联易达物流科技有限公司&#xff08;以下简称“万联易达”&#xff09;&#xff0c;是由中泽集团投资设立的创新型物流科技企业。为提高平台数智化服务水平&#xff0c;提升业务开展效率&#xff0c;达到运输全场景合规化管理&#xff0c;万联易达平台引用法大大电子合同&…

Hadoop3:MapReduce之MapTask的FileInputFormat的切片原理解读(2)

Job那块的断点代码截图省略&#xff0c;直接进入切片逻辑 参考&#xff1a;Hadoop3&#xff1a;MapReduce之MapTask的Job任务提交流程原理解读&#xff08;1&#xff09; 4、FileInputFormat切片源码解析 切片入口 获取切片数 获取最大和最小切片数 判断文件是否可以切片&…

MFC 模态对话框的实现原理

参考自MFC 模态对话框的实现原理 - 西昆仑 - OSCHINA - 中文开源技术交流社区 1. 模态对话框 在涉及 GUI 程序开发的过程中&#xff0c;常常有模态对话框以及非模态对话框的概念 模态对话框&#xff1a;在模态对话框活动期间&#xff0c;父窗口是无法进行消息响应&#xff0…

JVM类加载机制和双亲委派

类加载机制 java文件需要编译成字节码文件(.class文件)&#xff0c;jvm是通过类加载机制&#xff0c;将.class文件加载进内存&#xff0c;经过验证连接->初始化直到使用该对象的过程就是类加载机制&#xff0c;当new对象的时候&#xff0c;jvm首先去常量池寻找该类的符号引用…

罗永浩创业史!普通人也能逆袭!2024轻资产创业项目!2024普通人的出路! 2024普通人做什么行业赚钱!

罗永浩出身草根&#xff0c;一路打拼至今&#xff0c;虽然屡屡受挫但是从未妥协&#xff0c;罗永浩真正的诠释了什么叫“彪悍的人生不需要解释”&#xff01; 回顾罗永浩的传奇创业史: 1. 从新东方出来做牛博网--失败 2.创办老罗英语培训学校--失败 3.致敬乔布斯做锤子科技-…