文章目录

  • 前言
  • 一、 图像颜色处理
    • 1. 颜色加法
      • 1.1 OpenCV加法
      • 1.2 numpy加法
      • 1.3 颜色加权加法
    • 2.颜色空间
      • 2.1 RGB颜色空间
      • 2.2 HSV颜色空间
    • 3. 颜色转换
      • 3.1 读取的图片同时转换
      • 3.2 对已有图片转换
    • 4. 图像灰度化
      • 4.1 灰度图概念
      • 4.2 最大值灰度化
      • 4.3 平均值灰度化
      • 4.4 加权均值灰度化
    • 5. 图像二值化处理
      • 5.1 二值图像
      • 5.2 阈值法(THRESH_BINARY)
      • 5.3 反阈值法(THRESH_BINARY_INV)
      • 5.4 截断阈值法(THRESH_TRUNC)
      • 5.5 低阈值零处理(THRESH_TOZERO)
      • 5.6 超阈值零处理(THRESH_TOZERO_INV)
      • 5.7 OTSU阈值法
      • 5.8 自适应二值化
        • 5.8.1 取均值
        • 5.8.2 加权求和(高斯法)
  • 二、图像仿射变换
    • 1. 图像翻转(图像镜像旋转)
    • 2.仿射变换
      • 2.1 仿射变换的基本原理 -- 单点旋转
      • 2.2 仿射变换函数
  • 总结
  • --- opencv系列相关文章 ---


前言

昨天我们初步了解了opencv-python,学习了利用cv2的相关API对已知路径下的图片进行文件基本操作,最后还完成了对视频的操作。今天我们要学习图像颜色处理及图像仿射变换。


一、 图像颜色处理

1. 颜色加法

1.1 OpenCV加法

  • opencv加法是饱和操作
    • 饱和的意思是若计算的结果超出当前上限,就以当前上限值作为最终结果。
  • 在opencv中,颜色值默认是np.unit8类型,上限为255

示例

import cv2 as cv
import numpy as np
if __name__ == '__main__':# 读取图像cao = cv.imread('../images/cao.png')pig = cv.imread('../images/pig.png')# 饱和操作 -- 范围是np.uint8, 超出上限的取255dst1 = cv.add(cao, pig)print(cao[500,500,:])print(pig[500,500,:])print('cv饱和运算\n',dst1[500,500,:])cv.imshow('dst1', dst1)# 设定显示等待cv.waitKey(0)# 释放内存cv.destroyAllWindows()

1.2 numpy加法

  • 利用numpy加法的前提是进行加法运算的两张图片的形状大小要一样
  • numpy加法是模运算
    • 取模意思是用计算结果对255取模

示例

import cv2 as cv
import numpy as np
if __name__ == '__main__':# 读取图像cao = cv.imread('../images/cao.png')pig = cv.imread('../images/pig.png')# 饱和操作 -- 范围是np.uint8, 超出上限的取255dst2 = cao + pigprint(cao[500,500,:])print(pig[500,500,:])print('numpy取模运算\n',dst2[500,500,:])cv.imshow('dst1', dst2)# 设定显示等待cv.waitKey(0)# 释放内存cv.destroyAllWindows()

1.3 颜色加权加法

同样满足饱和运算

基本格式:

cv2.addWeighted(src1,alpha,src2,deta,gamma)

参数说明:

  • src1src2:输入图像。
  • alphabeta:两张图象权重。
  • gamma:亮度调整值。
    • gamma > 0,图像会变亮。
    • gamma < 0,图像会变暗。
    • gamma = 0,则没有额外的亮度调整。

示例

import cv2 as cv
# import numpy as np
if __name__ == '__main__':# 读图cao = cv.imread('../images/cao.png')pig = cv.imread('../images/pig.png')# cv2.addWeighted(src1,alpha,src2,deta,gamma) dst3 = cv.addWeighted(cao,0.3,pig,0.7,100)print(cao[500,500,:])print(pig[500,500,:])print('cv加权运算\n',dst3[500,500,:])# 显示图片cv.imshow('dst3',dst3)cv.waitKey(0)# 释放内存cv.destroyAllWindows()

2.颜色空间

2.1 RGB颜色空间

在图像处理中,最常见的就是RGB颜色空间。RGB颜色空间是我们接触最多的颜色空间,是一种用于表示和显示彩色图像的一种颜色模型。RGB代表红色(Red)绿色(Green)蓝色(Blue),这三种颜色通过不同强度的光的组合来创建其他颜色,广泛应用于我们的生活中,比如电视、电脑显示屏以及上面实验中所介绍的RGB彩色图。

RGB颜色模型基于笛卡尔坐标系,如下图所示,RGB原色值位于3个角上,二次色青色、红色和黄色位于另外三个角上,黑色位于原点处,白色位于离原点最远的角上。因为黑色在RGB三通道中表现为(0,0,0),所以映射到这里就是原点;而白色是(255,255,255),所以映射到这里就是三个坐标为最大值的点。
RGB颜色空间
RGB颜色空间可以产生大约1600万(2553255^32553)种颜色,几乎包括了世界上的所有颜色,也就是说可以使用RGB颜色空间来生成任意一种颜色。

注意:
在OpenCV中,颜色是以BGR的方式进行存储的,而不是RGB,这也是上面红色的像素值是(0,0,255)而不是(255,0,0)的原因。

2.2 HSV颜色空间

HSV颜色空间指的是HSV颜色模型,这是一种与RGB颜色模型并列的颜色空间表示法。RGB颜色模型使用红、绿、蓝三原色的强度来表示颜色,是一种加色法模型,即颜色的混合是添加三原色的强度。而HSV颜色空间使用色调(Hue)饱和度(Saturation)亮度(Value)三个参数来表示颜色,色调H表示颜色的种类,如红色、绿色、蓝色等;饱和度表示颜色的纯度或强度,如红色越纯,饱和度就越高;亮度表示颜色的明暗程度,如黑色比白色亮度低。

HSV颜色模型是一种六角锥体模型,如下图所示:
HSV

色调H:

使用角度度量,取值范围为0°~360°,从红色开始按逆时针方向计算,红色为0°,绿色为120°,蓝色为240°。它们的补色是:黄色为60°,青色为180°,紫色为300°。通过改变H的值,可以选择不同的颜色

饱和度S:

饱和度S表示颜色接近光谱色的程度。一种颜色可以看成是某种光谱色与白色混合的结果。其中光谱色所占的比例越大,颜色接近光谱色的程度就越高,颜色的饱和度就越高。饱和度越高,颜色就越深而艳,光谱色的白光成分为0,饱和度达到最高。通常取值范围为0%~100%,其中0%表示灰色或无色,100%表示纯色,通过调整饱和度的值,可以使颜色变得更加鲜艳或者更加灰暗。

明度V:

明度表示颜色明亮的程度,对于光源色,明度值与发光体的光亮度有关;对于物体色,此值和物体的透射比或反射比有关。通常取值范围为0%(黑)到100%(白),通过调整明度的值,可以使颜色变得更亮或者更暗。

一般对颜色空间的图像进行有效处理都是在HSV空间进行的,然后对于基本色中对应的HSV分量需要给定一个严格的范围,下面是通过实验计算的模糊范围(准确的范围在网上都没有给出)。

H: 0— 180

S: 0— 255

V: 0— 255

此处把部分红色归为紫色范围:

模糊范围

为什么有了RGB颜色空间我们还是需要转换成HSV颜色空间来进行图像处理呢?

  • 符合人类对颜色的感知方式:人类对颜色的感知是基于色调、饱和度和亮度三个维度的,而HSV颜色空间恰好就是通过这三个维度来描述颜色的。因此,使用HSV空间处理图像可以更直观地调整颜色和进行色彩平衡等操作,更符合人类的感知习惯。
  • 颜色调整更加直观:在HSV颜色空间中,色调、饱和度和亮度的调整都是直观的,而在RGB颜色空间中调整颜色不那么直观。例如,在RGB空间中要调整红色系的颜色,需要同时调整R、G、B三个通道的数值,而在HSV空间中只需要调整色调和饱和度即可。
  • 降维处理有利于计算:在图像处理中,降维处理可以减少计算的复杂性和计算量。HSV颜色空间相对于RGB颜色空间,减少了两个维度(红、绿、蓝),这有利于进行一些计算和处理任务,比如色彩分割、匹配等。

因此,在进行图片颜色识别时,我们会将RGB图像转换到HSV颜色空间,然后根据颜色区间来识别目标颜色。

3. 颜色转换

3.1 读取的图片同时转换

基本格式:

cv2.imread(path  [,读取方式])

参数说明:
昨天我们讲了path,而读取方式有很多种,默认是BGR形式

常见 mode 参数对照表:

模式值(flag)常量名功能说明
1cv2.IMREAD_COLOR(默认)以彩色方式读取图像,忽略透明通道
0cv2.IMREAD_GRAYSCALE以灰度模式读取图像(单通道)
-1cv2.IMREAD_UNCHANGED以原始方式读取图像,保留 alpha 通道
2cv2.IMREAD_ANYDEPTH若图像是 16/32 位深度,将按原深度读取
4cv2.IMREAD_ANYCOLOR以任意颜色格式读取(不强制转换 BGR)
8cv2.IMREAD_IGNORE_ORIENTATION忽略图像的 EXIF 方向元数据

示例

import cv2 as cv
# import numpy as np
if __name__ == '__main__':# 读取图像为灰度图cat = cv.imread('../images/1.jpg',cv.IMREAD_GRAYSCALE)# 显示图像cv.imshow('cat', cat)cv.waitKey(0)cv.destroyAllWindows()

3.2 对已有图片转换

基本格式:

cv2.cvtColor(img, code)

参数说明:

  • img:输入图像,可以是一个Numpy数组绘着一个OpenCV的Mat对象
    • Mat 是一个核心的数据结构,主要用于存储图像和矩阵数据。在 Python 中使用 OpenCV 时,通常直接处理的是 NumPy 数组,cv2 模块自动将 Mat 对象转换为 NumPy 数组。二者之间的转换是透明且自动完成的。例如,当你使用 cv2.imread() 函数读取图像时,返回的是一个 NumPy 数组,但在C++中则是 Mat 对象。
    • code:指定转换的类型,可以使用预定义的转换代码。
      • 例如cv2.COLOR_RGB2GRAY表示从rgb到灰度图像的转换。

示例

import cv2 as cv
# import numpy as np
if __name__ == '__main__':# 读取图像cat = cv.imread('../images/1.jpg')# 颜色转换 cv2.cvtColor(img, code)# 转灰度gray_ = cv.cvtColor(cat, cv.COLOR_BGR2GRAY)# 转HSVhsv = cv.cvtColor(cat, cv.COLOR_BGR2HSV)# 显示图片cv.imshow('cat', cat)cv.imshow('gray',gray_)cv.imshow('hsv',hsv)cv.waitKey(0)cv.destroyAllWindows()

4. 图像灰度化

4.1 灰度图概念

每个像素只有一个采样颜色的图像,这类图像通常显示为从最暗的黑色到最亮的白色灰度,尽管理论上这个采样可以任何颜色的不同深浅,甚至可以是不同亮度上的不同颜色。灰度图像与黑白图像不同,在计算机图像领域中黑白图像只有黑色与白色两种颜色;但是,灰度图像在黑色与白色之间还有许多级的颜色深度。灰度图像经常是在单个电磁波频谱如可见光内测量每个像素的亮度得到的,用于显示的灰度图像通常用每个采样像素8位的非线性尺度来保存,这样可以有256级灰度。

原图灰度图

4.2 最大值灰度化

对于彩色图像的每个像素,它会从R、G、B三个通道的值中选出最大的一个,并将其作为灰度图像中对应位置的像素值。

示例

import cv2 as cv
import numpy as np
if __name__ == '__main__':# 读取图像img_0 = cv.imread('../images/pig.png')shape = img_0.shape # (h, w, c)# 创建一个新图用于存放灰度像素img_1 = []# 最大值法(选取三通道中的最大值)for i in img_0:for j in i:img_1.append(max(j))img_2 = np.array(img_1).reshape(shape[0:2])cv.imshow('old',img_0)cv.imshow('gray', img_2)cv.waitKey(0)cv.destroyAllWindows()

4.3 平均值灰度化

对于彩色图像的每个像素,它会将R、G、B三个通道的像素值全部加起来,然后再除以三,得到的平均值就是灰度图像中对应位置的像素值。

import cv2 as cv
import numpy as np
if __name__ == '__main__':# 读取图像img_0 = cv.imread('../images/1.jpg')shape = img_0.shape # (h, w, c)# 创建一个新图用于存放灰度像素img_1 = []# 平均值法for i in img_0:for j in i:tmp = np.mean(j).astype(np.uint8)img_1.append(tmp)      img_2 = np.array(img_1).reshape(shape[0:2])cv.imshow('old',img_0)cv.imshow('gray', img_2)cv.waitKey(0)cv.destroyAllWindows()

4.4 加权均值灰度化

对于彩色图像的每个像素,它会按照一定的权重去乘以每个通道的像素值,并将其相加,得到最后的值就是灰度图像中对应位置的像素值。本实验中,权重的比例为: R乘以0.299G乘以0.587B乘以0.114,这是经过大量实验得到的一个权重比例,也是一个比较常用的权重比例

所使用的权重之和应该等于1。这是为了确保生成的灰度图像素值保持在合理的亮度范围内,并且不会因为权重的比例不当导致整体过亮或过暗。

opencv中的灰度化默认使用的加权均值

示例

import cv2 as cv
import numpy as np
if __name__ == '__main__':# 读取图像img_0 = cv.imread('../images/1.jpg')shape = img_0.shape # (h, w, c)# 创建一个新图用于存放灰度像素img_1 = []# 权重weights = np.array([1/4,1/2,1/4])# 加权均值法for i in img_0:for j in i:tmp = np.average(j,weights=weights).astype(np.uint8)img_1.append(tmp)img_2 = np.array(img_1).reshape(shape[0:2])cv.imshow('old',img_0)cv.imshow('gray', img_2)cv.waitKey(0)cv.destroyAllWindows()

5. 图像二值化处理

将某张图像的所有像素改成只有两种值之一。

5.1 二值图像

一幅二值图像的二维矩阵仅由0、1两个值构成,“0”代表黑色,“1”代白色。由于每一像素(矩阵中每一元素)取值仅有0、1两种可能,所以计算机中二值图像的数据类型通常为1个二进制位。二值图像通常用于文字、线条图的扫描识别(OCR)和掩膜图像的存储。
二值化
其操作的图像也必须是灰度图。也就是说,二值化的过程,就是将一张灰度图上的像素根据某种规则修改为0和maxval(maxval表示最大值,一般为255,显示白色)两种像素值,使图像呈现黑白的效果,能够帮助我们更好地分析图像中的形状、边缘和轮廓等特征。

  • 特点和功能:

    • 简便:降低计算量和计算需求,加快处理速度。
    • 节约资源:二值图像占用空间远小于彩色图。
    • 边缘检测:二值化常作为边缘检测的预处理步骤,因为简化后的图易于识别出轮廓和边界。

全局阈值法基本格式:

_,binary = cv2.threshold(img,thresh,maxval,type)

参数说明:

  • img:输入图像,要进行二值化处理的灰度图。
  • thresh:设定的阈值。当像素值大于(或小于,取决于阈值类型)thresh时,该像素被赋予的值。
  • type:阈值处理的类型。
  • 返回值:
    • 第一个值(通常用下划线表示):计算出的阈值,若使用自适应阈值法,会根据算法自动计算出这个值。
    • 第二个值(binary):二值化后的图像矩阵。与输入图像尺寸相同。

5.2 阈值法(THRESH_BINARY)

阈值法就是通过设置一个阈值,将灰度图中的每一个像素值与该阈值进行比较,小于等于阈值的像素就被设置为0(通常代表背景)大于阈值的像素就被设置为maxval(通常代表前景)。对于我们的8位图像(0~255)来说,通常是设置为255。
二值化
示例

import cv2 as cv
import numpy as np
if __name__ == '__main__':# 读取图像flower = cv.imread('../images/flower.png')# 调整图片大小flower = cv.resize(flower,(360, 360))# 灰度化处理gray_ = cv.cvtColor(flower, cv.COLOR_BGR2GRAY)# 二值化 阈值法thresh, binary = cv.threshold(gray_, 127, 255, cv.THRESH_BINARY)print(thresh)# 显示效果cv.imshow('binary', binary)cv.waitKey(0)cv.destroyAllWindows()

5.3 反阈值法(THRESH_BINARY_INV)

顾名思义,就是与阈值法相反。反阈值法是当灰度图的像素值大于阈值时,该像素值将会变成0(黑),当灰度图的像素值小于等于阈值时,该像素值将会变成maxval。
反阈值法

示例

import cv2 as cv
import numpy as np
if __name__ == '__main__':# 读取图像flower = cv.imread('../images/flower.png')# 调整图片大小flower = cv.resize(flower,(360, 360))# 灰度化处理gray_ = cv.cvtColor(flower, cv.COLOR_BGR2GRAY)# 二值化 反阈值法thresh, binary_inv = cv.threshold(gray_, 127, 255, cv.THRESH_BINARY_INV)print(thresh)# 显示效果cv.imshow('binary_inv', binary_inv)cv.waitKey(0)cv.destroyAllWindows()

5.4 截断阈值法(THRESH_TRUNC)

截断阈值法,指将灰度图中的所有像素与阈值进行比较,像素值大于阈值的部分将会被修改为阈值,小于等于阈值的部分不变。
截断阈值法

经过截断阈值法处理过的二值化图中的最大像素值就是阈值,此时参数maxval不起作用

示例

import cv2 as cv
import numpy as np
if __name__ == '__main__':# 读取图像flower = cv.imread('../images/flower.png')# 调整图片大小flower = cv.resize(flower,(360, 360))# 灰度化处理gray_ = cv.cvtColor(flower, cv.COLOR_BGR2GRAY)# 二值化 截断阈值法_, trunc = cv.threshold(gray_,127,255, cv.THRESH_TRUNC)# 显示效果cv.imshow('trunc', trunc)cv.waitKey(0)cv.destroyAllWindows()

5.5 低阈值零处理(THRESH_TOZERO)

低阈值零处理,字面意思,就是像素值小于等于阈值的部分被置为0(也就是黑色),大于阈值的部分不变。
低阈值零处理

示例

import cv2 as cv
import numpy as np
if __name__ == '__main__':# 读取图像flower = cv.imread('../images/flower.png')# 调整图片大小flower = cv.resize(flower,(360, 360))# 灰度化处理gray_ = cv.cvtColor(flower, cv.COLOR_BGR2GRAY)# 低阈值零处理_, tozero = cv.threshold(gray_,127,255, cv.THRESH_TOZERO)# 显示效果cv.imshow('tozero', tozero)cv.waitKey(0)cv.destroyAllWindows()

5.6 超阈值零处理(THRESH_TOZERO_INV)

超阈值零处理就是将灰度图中的每个像素与阈值进行比较,像素值大于阈值的部分置为0(也就是黑色),像素值小于等于阈值的部分不变。

超阈值零处理

示例

import cv2 as cv
import numpy as np
if __name__ == '__main__':# 读取图像flower = cv.imread('../images/flower.png')# 调整图片大小flower = cv.resize(flower,(360, 360))# 灰度化处理gray_ = cv.cvtColor(flower, cv.COLOR_BGR2GRAY)# 超阈值零处理_, tozero_inv = cv.threshold(gray_,127,255, cv.THRESH_TOZERO_INV)# 显示效果cv.imshow('tozero_inv', tozero_inv)cv.waitKey(0)cv.destroyAllWindows()

5.7 OTSU阈值法

cv2.THRESH_OTS 并不是一个有效的阈值类型或标。THRESH_OTSU 本身并不是一个独立的阈值化方法,而是与 OpenCV 中的二值化方法结合使用的一个标志。具体来说,THRESH_OTSU 通常与 THRESH_BINARYTHRESH_BINARY_INV 结合使用。在实际应用中,如果你使用 THRESH_OTSU 标志但没有指定其他二值化类型,默认情况下它会与 THRESH_BINARY 结合使用。也就是说,当你仅指定了 cv2.THRESH_OTSU,实际上等同于同时指定了 cv2.THRESH_BINARY + cv2.THRESH_OTSU

在介绍OTSU阈值法之前,我们首先要了解一下双峰图片的概念。

双峰图片就是指灰度图的直方图上有两个峰值,直方图就是对灰度图中每个像素值的点的个数的统计图,如下图所示。
双峰图

  • 灰度图直方图的基础概念
  1. 灰度级
    • 在灰度图像中,每个像素的值代表其亮度,通常范围是 0 到 255(对于 8 位灰度图像)。
    • 0 表示黑色,255 表示白色,中间的值表示不同程度的灰色。
  2. 直方图定义
    • 直方图是一个柱状图,其中 x 轴表示灰度级(从 0 到 255),y 轴表示对应灰度级在图像中出现的次数(频率)。
    • 每个柱子的高度代表该灰度级在图像中出现的像素数量。

OTSU算法是通过一个值将这张图分前景色和背景色(也就是灰度图中小于这个值的是一类,大于这个值的是一类。例如,如果你设置阈值为128,则所有大于128的像素点可以被视作前景,而小于等于128的像素点则被视为背景。),通过统计学方法(最大类间方差)来验证该值的合理性,当根据该值进行分割时,使用最大类间方差计算得到的值最大时,该值就是二值化算法中所需要的阈值。通常该值是从灰度图中的最小值加1开始进行迭代计算,直到灰度图中的最大像素值减1,然后把得到的最大类间方差值进行比较,来得到二值化的阈值。以下是一些符号规定:

T:阈值

N0N_{0}N0:前景像素点数

N1N_{1}N1:背景像素点数

ω0\omega_{0}ω0:前景的像素点数占整幅图像的比例

ω1\omega_{1}ω1:背景的像素点数占整幅图像的比例

U0\mathcal{U_{0}}U0:前景的平均像素值

U1\mathcal{U_{1}}U1:背景的平均像素值

U\mathcal{U}U:整幅图的平均像素值

rows×cols:图像的行数和列数

下面举个例子,有一张大小为4×4的图片,假设阈值T为1,则:
otsu

也就是这张图片根据阈值1分为了前景(像素为2的部分)和背景(像素为0)的部分,并且计算出了OTSU算法所需要的各个数据,根据上面的数据,我们给出计算类间方差的公式:
g=ω0(μ0−μ)2+ω1(μ1−μ)2g=\omega_{0}(\mu_{0}-\mu)^{2}+\omega_{1}(\mu_{1}-\mu)^{2} g=ω0(μ0μ)2+ω1(μ1μ)2
g就是前景与背景两类之间的方差,这个值越大,说明前景和背景的差别就越大,效果就越好。OTSU算法就是在灰度图的像素值范围内遍历阈值T,使得g最大,基本上双峰图片的阈值T在两峰之间的谷底。

通过OTSU算法得到阈值之后,就可以结合上面的方法根据该阈值进行二值化,在本实验中有THRESH_OTSUTHRESH_INV_OTSU两种方法,就是在计算出阈值后结合了阈值法和反阈值法。

THRESH_OTSUTHRESH_INV_OTSU
在这里插入图片描述

注意:
使用OTSU算法计算阈值时,组件中的thresh参数将不再有任何作用。
THRESH_OTSU默认是cv2.THRESH_BINARY + cv2.THRESH_OTSU

示例
otsu反阈值法

import cv2 as cv
import numpy as np
if __name__ == '__main__':# 读取图像flower = cv.imread('../images/flower.png')# 调整图片大小flower = cv.resize(flower,(360, 360))# 灰度化处理gray_ = cv.cvtColor(flower, cv.COLOR_BGR2GRAY)# OTSU结合反阈值_, otsu_inv = cv.threshold(gray_,127,255, cv.THRESH_OTSU + cv.THRESH_BINARY_INV)# 显示效果cv.imshow('otsu_inv', otsu_inv)cv.waitKey(0)cv.destroyAllWindows()

5.8 自适应二值化

与二值化算法相比,自适应二值化更加适合用在明暗分布不均的图片,因为图片的明暗不均,导致图片上的每一小部分都要使用不同的阈值进行二值化处理,这时候传统的二值化算法就无法满足我们的需求了,于是就出现了自适应二值化。

自适应二值化方法会对图像中的所有像素点计算其各自的阈值,这样能够更好的保留图片里的一些信息。自适应二值化组件内容如下图所示:


基本格式:

cv2.adaptiveThreshold(image_np_gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 7, 10)

参数说明:

maxval:最大阈值,一般为255

adaptiveMethod:小区域阈值的计算方式:

ADAPTIVE_THRESH_MEAN_C:小区域内取均值

ADAPTIVE_THRESH_GAUSSIAN_C:小区域内加权求和,权重是个高斯核

thresholdType:二值化方法,只能使用THRESH_BINARYTHRESH_BINARY_INV,也就是阈值法和反阈值法

blockSize:选取的小区域的面积,如7就是7*7的小块。

c:最终阈值等于小区域计算出的阈值再减去此值

5.8.1 取均值

假如我们使用的小区域是3*3的,那么就会从图片的左上角开始(也就是像素值为162的地方)计算其邻域内的平均值,如果处于边缘地区就会对边界进行填充,填充值就是边界的像素点,如下图所示:

那么对于左上角像素值为162的这个点,161(也就是上图中括号内的计算结果,结果会进行取整)就是根据平均值计算出来的阈值,接着减去一个固定值C,得到的结果就是左上角这个点的二值化阈值了,接着根据选取的是阈值法还是反阈值法进行二值化操作。紧接着,向右滑动计算每个点的邻域内的平均值,直到计算出右下角的点的阈值为止。我们所用到的不断滑动的小区域被称之为核,比如3*3的小区域叫做3*3的核,并且核的大小都是奇数个,也就是3*3、5*5、7*7等。(取奇数个是为了能有中心)

自适应二值化(Adaptive Thresholding)的核心思想就是为图像中的每个像素点计算一个局部阈值。这种方法与全局阈值化不同,后者对整个图像使用同一个固定的阈值。而在自适应二值化中,每个像素的阈值是基于其周围邻域内的像素值动态确定的。

示例

import cv2 as cv
import numpy as np
if __name__ == '__main__':# 读取图像flower = cv.imread('../images/flower.png')# 调整图片大小flower = cv.resize(flower,(360, 360))# 灰度化处理gray_ = cv.cvtColor(flower, cv.COLOR_BGR2GRAY)# 自适应二值化adaption_mean = cv.adaptiveThreshold(gray_, 255, cv.ADAPTIVE_THRESH_MEAN_C, cv.THRESH_BINARY,3,2)# 显示效果cv.imshow('adaption_mean', adaption_mean)cv.waitKey(0)cv.destroyAllWindows()
5.8.2 加权求和(高斯法)

对小区域内的像素进行加权求和得到新的阈值,其权重值来自于高斯分布。

高斯分布,通过概率密度函数来定义高斯分布,一维高斯概率分布函数为:
p(y)=1σ2πe−(y−μ)22σ2p(y)={\frac{1}{\sigma{\sqrt{2\pi}}}}e^{{\frac{-(y-\mu)^{2}}{2\sigma^{2}}}} p(y)=σ2π1e2σ2(yμ)2
通过改变函数中和的值,我们可以得到如下图像,其中均值为μ\muμ,标准差为σ2\sigma^{2}σ2
高斯分布

此时我们拓展到二维图像,一般情况下我们使x轴和y轴的相等并且,此时我们可以得到二维高斯函数的表达式为:
g(x,y)=12πσ2e−(x2+y2)2σ2g(x,y)=\frac{1}{2\pi\sigma ^{2}}e^{-\frac{(x^{2}+y^{2})}{2\sigma^{2}}} g(x,y)=2πσ21e2σ2(x2+y2)
高斯概率函数是相对于二维坐标产生的,其中(x,y)为点坐标,要得到一个高斯滤波器模板,应先对高斯函数进行离散化,将得到的值作为模板的系数。例如:要产生一个3*3的高斯权重核,以核的中心位置为坐标原点进行取样,其周围的坐标如下图所示(x轴水平向右,y轴竖直向上)

将坐标带入上面的公式中,即可得到一个高斯权重核。

而在opencv里,当kernel(小区域)的尺寸为1、3、5、7并且用户没有设置sigma的时候(sigma <= 0),核值就会取固定的系数,这是一种默认的值是高斯函数的近似。

kernel尺寸核值
1[1]
3[0.25, 0.5, 0.25]
5[0.0625, 0.25, 0.375, 0.25, 0.0625]
7[0.03125, 0.109375, 0.21875, 0.28125, 0.21875, 0.109375, 0.03125]

比如kernel的尺寸为3*3时,使用
[0.250.50.25]×[0.250.50.25]\left[\begin{array}{c}{{0.25}}\\ {{0.5}}\\ {{0.25}}\end{array}\right]\times\left[0.25~~~~0.5~~~~0.25\right] 0.250.50.25×[0.25    0.5    0.25]
进行矩阵的乘法,就会得到如下的权重值,其他的类似。
kernel=[0.06250.1250.06250.1250.250.1250.06250.1250.0625]kernel=\left[\begin{array}{c}{{0.0625~~~0.125~~~0.0625}}\\{{0.125~~~~0.25~~~~0.125}}\\ {{0.0625~~~0.125~~~0.0625}} \end{array}\right] kernel=0.0625   0.125   0.06250.125    0.25    0.1250.0625   0.125   0.0625
通过这个高斯核,即可对图片中的每个像素去计算其阈值,并将该阈值减去固定值得到最终阈值,然后根据二值化规则进行二值化。

而当kernels尺寸超过7的时候,如果sigma设置合法(用户设置了sigma),则按照高斯公式计算.当sigma不合法(用户没有设置sigma),则按照如下公式计算sigma的值:
σ=0.3∗((ksize−1)∗0.5−1)+0.8\sigma=0.3*\big((k s i z e-1)*0.5-1\big)+0.8 σ=0.3((ksize1)0.51)+0.8
某像素点的阈值计算过程如下图所示:

首先还是对边界进行填充,然后计算原图中的左上角(也就是162像素值的位置)的二值化阈值,其计算过程如上图所示,再然后根据选择的二值化方法对左上角的像素点进行二值化,之后核向右继续计算第二个像素点的阈值,第三个像素点的阈值…直到右下角(也就是155像素值的位置)为止。

当核的大小不同时,仅仅是核的参数会发生变化,计算过程与此是一样的。

示例

import cv2 as cv
import numpy as np
if __name__ == '__main__':# 读取图像flower = cv.imread('../images/flower.png')# 调整图片大小flower = cv.resize(flower,(360, 360))# 灰度化处理gray_ = cv.cvtColor(flower, cv.COLOR_BGR2GRAY)# 自适应二值化--高斯核gauss = cv.adaptiveThreshold(gray_, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY,3,2)# 显示效果cv.imshow('gauss', gauss)cv.waitKey(0)cv.destroyAllWindows()

二、图像仿射变换

1. 图像翻转(图像镜像旋转)

在OpenCV中,图片的镜像旋转是以图像的中心为原点进行镜像翻转的。
基本格式:

cv2.flip(img,flipcode

参数说明:

  • im.\ 要翻转的图像
  • flipcode: 指定翻转类型的标志
    • flipcode=0: 垂直翻转,图片像素点沿x轴翻转
    • flipcode>0: 水平翻转,图片像素点沿y轴翻转
    • flipcode<0: 水平垂直翻转,水平翻转和垂直翻转的结合

示例

import cv2 as cvif __name__ == '__main__':# 读取图片face = cv.imread('../images/face.png')# flipcode = 0 垂直翻转,图片像素点沿x轴翻转flip_0 = cv.flip(face, 0)# flipcode >0 水平翻转,图片像素点沿y轴翻转flip_1 = cv.flip(face, 2)# flipcode <0 水平垂直翻转,水平翻转和垂直翻转的结合flip__1 = cv.flip(face, -1)# 显示效果cv.imshow('face', face)cv.imshow('flip_0', flip_0)cv.imshow('flip_1', flip_1)cv.imshow('flip_-1', flip__1)cv.waitKey(0)cv.destroyAllWindows()

2.仿射变换

​ 仿射变换(Affine Transformation)是一种线性变换,保持了点之间的相对距离不变。

  • 仿射变换的基本性质

    • 保持直线
    • 保持平行
    • 比例不变性
    • 不保持角度和长度
  • 常见的仿射变换类型

    • 旋转:绕着某个点或轴旋转一定角度。
    • 平移:仅改变物体的位置,不改变其形状和大小。
    • 缩放:改变物体的大小。
    • 剪切:使物体发生倾斜变形。

2.1 仿射变换的基本原理 – 单点旋转

首先我们以最简单的一个点的旋转为例子,且以最简单的情况举例,令旋转中心为坐标系中心O(0,0)O(0,0)O(00),假设有一点P0(x0,y0)P_{0}(x_{0},y_{0})P0(x0,y0)P0P_{0}P0离旋转中心OOO的距离为rrrOP0OP_{0}OP0与坐标轴x轴的夹角为α\alphaαP0P_{0}P0绕O顺时针旋转θ\thetaθ角后对应的点为P(x,y)P(x,y)P(x,y)

那么我们可以得到如下关系:
x0=r×cos⁡αx_{0}=r\times\cos\alpha x0=r×cosα

y0=r×sin⁡αy_{0}=r\times\sin\alpha y0=r×sinα

x=r×cos⁡(α−θ)=rcos⁡αcos⁡θ+rsin⁡αsin⁡θ=x0cos⁡θ+y0sin⁡θx=r\times\cos(\alpha-\theta)=r\cos\alpha\cos\theta+r\sin\alpha\sin\theta=x_{0}\cos\theta+y_{0}\sin\theta x=r×cos(αθ)=rcosαcosθ+rsinαsinθ=x0cosθ+y0sinθ

y=r×sin⁡(α−θ)=rsin⁡αcos⁡θ−rcos⁡αsin⁡θ=−x0sin⁡θ+y0cos⁡θy=r\times\sin(\alpha-\theta)=r\sin\alpha\cos\theta-r\cos\alpha\sin\theta=-x_{0}\sin\theta+y_{0}\cos\theta y=r×sin(αθ)=rsinαcosθrcosαsinθ=x0sinθ+y0cosθ

用矩阵来表示就是
[xy]=[cos⁡θsin⁡θ−sin⁡θcos⁡θ]∗[x0y0]\left[\begin{array}{l l}{{x}}\\{{y}}\end{array}\right]=\left[\begin{array}{l l}{{\cos\theta~~~~\sin\theta}}\\{{-\sin\theta~~~~\cos\theta}}\\ \end{array}\right]*\left[\begin{array}{c}{{x_{0}}}\\{{y_{0}}}\end{array}\right] [xy]=[cosθ    sinθsinθ    cosθ][x0y0]
然而,在OpenCV中,旋转时是以图像的左上角为旋转中心,且以逆时针为正方向,因此上面的例子中其实是个负值,那么该矩阵可写为:
[xy]=[cos⁡θ−sin⁡θsin⁡θcos⁡θ]∗[x0y0]\left[\begin{array}{l l}{{x}}\\{{y}}\end{array}\right]=\left[\begin{array}{l l}{{\cos\theta~~~~-\sin\theta}}\\{{\sin\theta~~~~\cos\theta}}\\ \end{array}\right]*\left[\begin{array}{c}{{x_{0}}}\\{{y_{0}}}\end{array}\right] [xy]=[cosθ    sinθsinθ    cosθ][x0y0]
其中,
[cos⁡θ−sin⁡θsin⁡θcos⁡θ]\left[\begin{array}{l l}{{\cos\theta~~~~-\sin\theta}}\\{{\sin\theta~~~~\cos\theta}}\\ \end{array}\right] [cosθ    sinθsinθ    cosθ]
也被称作旋转矩阵。然而我们所要的不仅仅是可以围绕图像左上角进行旋转,而是可以围绕任意点进行旋转。那么我们可以将其转化成绕原点的旋转,其过程为:

  1. 首先将旋转点移到原点
  2. 按照上面的旋转矩阵进行旋转得到新的坐标点
  3. 再将得到的旋转点移回原来的位置

也就是说,在以任意点为旋转中心时,除了要进行旋转之外,还要进行平移操作。那么当点经过平移后得到P点时,如下图所示:

那么我们就可以得到:
x=x0+txx=x_{0}+t_{x} x=x0+tx

y=y0+tyy=y_{0}+t_{y} y=y0+ty

写成矩阵的形式为:
[xy1]=[10tx01ty001]∗[x0y01]\left[\begin{array}{l l l}{{x}}\\{{y}}\\{1}\end{array}\right]=\left[\begin{array}{c}{{1~~~~0~~~~t_{x}}}\\{{0~~~~1~~~~t_{y}}}\\{{0~~~~0~~~~1}} \end{array}\right]*\left[\begin{array}{c}{{x_0}}\\{{y_0}}\\{1}\end{array}\right] xy1=1    0    tx0    1    ty0    0    1x0y01
于是
[10tx01ty001]\left[\begin{array}{l l l}{{1~~~~0~~~~t_{x}}}\\{{0~~~~1~~~~t_{y}}}\\{{0~~~~0~~~~1}} \end{array}\right] 1    0    tx0    1    ty0    0    1
也被叫做平移矩阵,相反的,从P移到点时,其平移矩阵为:
[10−tx01−ty001]\left[\begin{array}{l l l}{1}&{0}&{-\,t_{x}}\\ {0}&{1}&{-\,t_{y}}\\ {0}&{0}&{1}\end{array}\right] 100010txty1
我们将原始的旋转矩阵也扩展到3*3的形式:
[xy1]=[cos⁡θ−sin⁡θ0sin⁡θcos⁡θ0001]∗[x0y01]\begin{array}{l l l}{{\left[\begin{array}{c}{{x}}\\{{y}}\\{1} \end{array}\right]=\left[\begin{array}{c c c}{{\cos\theta}}&{{-\sin\theta}}&{{0}}\\ {{\sin\theta}}&{{\cos\theta}}&{{0}}\\ {{0}}&{{0}}&{{1}}\end{array}\right]*\left[\begin{array}{c}{{x_{0}}}\\{{y_{0}}}\\{{1}}\end{array}\right]}}\end{array} xy1=cosθsinθ0sinθcosθ0001x0y01
从平移和旋转的矩阵可以看出,3x3矩阵的前2x2部分是和旋转相关的,第三列与平移相关。有了上面的表达式之后,我们就可以得到二维空间中绕任意点旋转的旋转矩阵了,只需要将旋转矩阵先左乘
[10tx01ty001]\left[\begin{array}{l l l}{{1~~~~0~~~~t_{x}}}\\{{0~~~~1~~~~t_{y}}}\\{{0~~~~0~~~~1}} \end{array}\right] 1    0    tx0    1    ty0    0    1
,再右乘
[10−tx01−ty001]\left[\begin{array}{l l l}{1}&{0}&{-\,t_{x}}\\ {0}&{1}&{-\,t_{y}}\\ {0}&{0}&{1}\end{array}\right] 100010txty1
即可得到最终的矩阵其结果为:( 知道就好!!!)
M=[cos⁡θ−sin⁡θ(1−cos⁡θ)tx+ty∗sin⁡θsin⁡θcos⁡θ(1−cos⁡θ)ty+tx∗sin⁡θ001]M=\left[\begin{array}{l l l}{{\cos\theta~~-\sin\theta~~(1-\cos\theta)t_{x}+t_{y}*\sin\theta}}\\{{\sin\theta~~~\cos\theta~~~~~(1-\cos\theta)t_{y}+t_{x}*\sin\theta}}\\{{0~~~~~~~~~~~~~0~~~~~~~~~~~~~1}} \end{array}\right] M=cosθ  sinθ  (1cosθ)tx+tysinθsinθ   cosθ     (1cosθ)ty+txsinθ0             0             1
于是我们就可以根据这个矩阵计算出图像中任意一点绕某点旋转后的坐标了,这个矩阵学名叫做仿射变换矩阵,而仿射变换是一种二维坐标到二维坐标之间的线性变换,也就是只涉及一个平面内二维图形的线性变换,图像旋转就是仿射变换的一种。

​ 仿射变换(Affine Transformation)是一种线性变换,保持了点之间的相对距离不变。

2.2 仿射变换函数

cv2.warpAffine(img,M,dsize)

参数说明:

  • img:输入图像。

  • M:2x3的变换矩阵,类型为np.float32

  • dsize:输出图像的尺寸,形式为(width,height)

示例

  • 旋转
import cv2 as cv
import numpy as np# 利用仿射变换矩阵
if __name__ == '__main__':# 读取图片old = cv.imread('../images/1.jpg')shape = old.shape# 获取旋转的仿射矩阵M = cv.getRotationMatrix2D((shape[0]//2, shape[1]//2),-45, 1)# 旋转new_rotation = cv.warpAffine(old, M, (shape[1],shape[0]))# 显示对象cv.imshow('new_1', new_rotation)cv.waitKey(0)cv.destroyAllWindows()
  • 平移
import cv2 as cv
import numpy as np# 利用仿射变换矩阵
if __name__ == '__main__':# 读取图片old = cv.imread('../images/1.jpg')shape = old.shape# 获取旋转的仿射矩阵tx = -100ty = -50M = np.float32([[1, 0, tx],[0, 1, ty]])# 平移new_pingyi = cv.warpAffine(old, M, (shape[1],shape[0]))# 显示对象cv.imshow('new_2', new_pingyi)cv.waitKey(0)cv.destroyAllWindows()
  • 缩放
import cv2 as cv
import numpy as np# 利用仿射变换矩阵
if __name__ == '__main__':# 读取图片old = cv.imread('../images/1.jpg')shape = old.shape# 获取旋转的仿射矩阵Sx = 0.5 Sy = 1.2M = np.float32([[ 1.5, 0, 0],[ 0, 0.5, 0]])# 缩放new_pingyi = cv.warpAffine(old, M, (shape[1],shape[0]))# 显示对象cv.imshow('new_2', new_pingyi)cv.waitKey(0)cv.destroyAllWindows()

总结

今天我们学习了图像颜色处理及图像仿射变换,其中颜色处理重点掌握二值化的OTSU阈值法和自适应二值化,仿射变换用到了旋转角和矩阵,总的来说知识与线性代数结合很紧密,需要有一定的数学基础。
让我们下期再见!


— opencv系列相关文章 —

opencv–day01–opencv基础知识及基础操作

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第一层nginx访问url如何透传到第二层nginx

要让第一层Nginx将客户端请求的URL完整透传到第二层Nginx&#xff0c;关键在于正确配置proxy_pass指令及路径拼接规则。以下是具体配置方法和注意事项&#xff1a; 核心配置原则 proxy_pass指令末尾是否添加/会直接影响URL的透传方式&#xff1a; 不带/&#xff1a;会将locatio…

【2025最新毕业设计】外卖点餐小程序(外卖点餐管理系统)

外卖点餐小程序的设计与实现技术大纲&#xff08;Vue.js Element UI&#xff09;需求分析与功能设计用户需求调研&#xff1a;分析目标用户群体的核心需求&#xff08;如快速点餐、支付便捷、订单跟踪等&#xff09;核心功能模块划分&#xff1a;用户端&#xff08;登录/注册、…

两台电脑连接交换机,使用其中一台电脑的网络上网(NAT转发)

场景 windows 电脑和 linux电脑连在同一台交换机上&#xff0c;linux电脑有通过无线网络。要实现Windows电脑通过交换机共享Linux电脑的无线网络上网&#xff0c;需将Linux设为网关并进行网络共享&#xff0c;步骤如下&#xff1a; 一、Linux电脑设置&#xff08;网关配置&…

OpenCV Mat UMat GpuMat Matx HostMem InputArray等设计哲学

一、概览&#xff1a; GpuMat对应于cuda&#xff1b;HostMem 可以看作是一种特殊的Mat&#xff0c;其存储对应cuda在主机分配的锁页内存&#xff0c;可以不经显示download upload自动转变成GpuMat&#xff08;但是和GpuMat并无继承关系&#xff09;&#xff1b;UMat对应于openc…

ATR2652SGNSS全频段低噪声放大器

ATR2652S是一款具有高增益、低噪声系数的低噪声放大器芯片。支持GNSS全频段信号&#xff0c;同时GNSS 的两个频段可以应用于GNSS双频导航接收机中。 采用先进的 SiGe 工艺设计和制作&#xff0c;工艺稳定&#xff0c;低噪声放大器在 GNSS 整个频段内可以获得非常好的射频性能&a…

大数据中心——解读60页IDC云数据中心机房运维服务解决方案【附全文阅读】

该方案主要面向云数据中心运营管理者、IT 运维人员、企业决策者等&#xff0c;旨在解决云资源和业务网络管理难题&#xff0c;提升 IT 资源掌控能力。方案核心是 EVM VirtualViz 仿真可视化系统&#xff0c;它整合多源数据&#xff0c;提供 3D 仿真展示&#xff0c;实现数据中心…

环境变量-进程概念(7)

文章目录Linux 真实调度算法1. queue[140]2. bitmap[5] 位图3. nr_active4. 活跃进程与过期进程环境变量1. 基本概念2. 命令行参数3. PATH 环境变量4. 环境变量具体操作Linux 真实调度算法 下图是Linux2.6内核中进程队列的数据结构&#xff0c;也有Linux2.6内核进程O(1)调度算…

为什么数组可以做到时间复杂度为O(1)的随机访问

这个问题涉及数组底层结构与内存寻址机制 一、数组元素在内存中连续存储 数组在内存中会开辟一块连续地址空间。假设数组A为int类型&#xff0c;共有n个元素&#xff0c;每个元素大小为4字节&#xff0c;那么他们在内存中的存储结构可能如下&#xff1a;内存地址数组元素A0x100…

《使用Qt Quick从零构建AI螺丝瑕疵检测系统》——5. 集成OpenCV:让程序拥有“视力”

目录一、概述1.1 背景介绍&#xff1a;赋予应用“视力”1.2 学习目标二、集成OpenCV2.1 安装OpenCV2.2 在Qt项目中配置CMake三、项目数据集介绍与准备四、图像的桥梁&#xff1a;ImageProvider与格式转换五、加载、转换并显示图像六、总结与展望一、概述 1.1 背景介绍&#xf…

智慧驾驶疲劳检测算法的实时性优化

智慧驾驶疲劳检测&#xff1a;从技术突破到场景革命全球每年因疲劳驾驶引发的交通事故占比超20%&#xff0c;夜间及长途驾驶场景中这一比例更高。当驾驶员出现疲劳甚至晕倒等危险驾驶行为时&#xff0c;传统检测手段因依赖单一传感器或受环境干扰&#xff0c;存在误报率高、响应…

USRP X440

产品概述 USRP X440 是 Ettus Research 推出的高性能、多通道、宽带软件定义无线电&#xff08;SDR&#xff09;系统。基于 Xilinx Zynq UltraScale RFSoC 架构&#xff0c;它提供高密度、相干性的信号收发能力&#xff0c;帮助您快速构建雷达、电子战&#xff08;EW&#xff0…

[特殊字符] GitHub 2025年7月月度精选项目 Top5

&#x1f680; GitHub 2025年7月月度精选项目 Top5 本月GitHub有哪些值得关注的优质开源项目&#xff1f;我从数千个新项目中&#xff0c;精选了5个有趣 实用 可演示的仓库 无论你是开发者、AI爱好者、工具控&#xff0c;还是正在做副业产品&#xff0c;这篇文章都值得收藏&a…

微服务架构下的自动化测试策略调优经验分享

微服务架构下,自动化测试策略需针对分布式特性、服务自治性和高耦合风险进行针对性调整的关键调整方向及实施方法: 一、​​测试策略重构:分层与契约驱动​​ 1. ​​测试金字塔升级为钻石模型​​ ​​调整逻辑​​:传统金字塔中UI测试占比过高,而微服务需强化契约测试与…

图论:并查集

入门 久闻并查集的大名&#xff0c;今天来一探究竟&#xff0c;到底什么是并查集&#xff0c;并查集有什么用&#xff1f; 并查集(Disjoint Set Union, DSU)是一种处理不相交集合的合并及查询问题的数据结构。 其实并查集的作用主要就有两个&#xff1a; 1、将两个元素添加到…

告别静态文档!Oracle交互式技术架构图让数据库学习“活“起来

&#x1f5fa;️ 当数据库架构图学会"互动" 想象一下&#xff0c;你正在学习Oracle数据库架构&#xff0c;面对密密麻麻的静态文档和复杂的组件关系图&#xff0c;是不是常常感到&#xff1a; 像在迷宫里找路&#xff0c;不知道组件间如何协作&#xff1f;想深入了…

day62-可观测性建设-全链路监控zabbix+grafana

&#x1f31f;监控api接口 &#x1f50d;监控zabbix-api接口 生成API tokens命令行测试 curl -s -X POST -H "Content-Type: application/json-rpc" -d {"jsonrpc": "2.0","method": "host.get","params": {&quo…

通过Deepseek找工作

推送的结果如下,对应的AI提示词在底部: 计算机方向远程工作职位汇总 整合全球远程技术岗位 | 支持全地域远程办公 | 涵盖开发、安全、云计算等方向 覆盖方向:8+个技术领域 薪资范围:10K-40K/月 工作模式:100%远程 远程技术职位列表 职位名称 技能要求 经验要求 薪资…

vscode文件颜色,只显示自己更改的文件颜色、刚git下来的库,vscode打开后,显示所有文件都被修改了

问题&#xff1a;git新的库&#xff0c;然后我用vscode打开&#xff0c;默认显示所有的文件都更改了&#xff0c;但是我打开他们修改的对比&#xff0c;没有显示任何有被修改的地方&#xff0c;是怎么回事 linux/wsl下这么设置就可以了&#xff1a;git config core.autocrlf in…

基于ENMeval包的MaxEnt模型参数优化总结

MaxEnt模型参数优化1. MaxEnt模型优化&#xff1a;增加RM&#xff0c;降低模型过拟合风险&#xff0c;简易模型&#xff0c;平滑响应曲线&#xff0c;增强模型可解释性和转移性&#xff08;生物入侵&#xff09;2. 默认参数&#xff1a;FCLQHP&#xff0c;RM12.1. 基于优化的 M…

Docker实践:使用Docker部署blog轻量级博客系统

Docker实践&#xff1a;使用Docker部署blog轻量级博客系统一、blog系统介绍1.1 blog介绍1.2 个人博客系统介绍1.3 个人博客使用场景二、本地环境介绍2.1 本地环境规划2.2 本次实践介绍三、本地环境检查3.1 检查Docker服务状态3.2 检查Docker版本3.3 检查docker compose 版本四、…