opencv3

颜色空间转换

RGB

RGB (Red, Green, Blue) 是一种加法颜色模型,由三种颜色通道组成。在 RGB 模型中,颜色是通过三种颜色信号(红色、绿色和蓝色)的不同组合来表示的。通过调整每个通道的亮度和色彩,可以混合出各种颜色。RGB 常用于显示器、数字摄像机和数字图像处理。

HSV

HSV (Hue, Saturation, Value) 是另一种颜色模型,也被称为色调、饱和度和明度模型。HSV 模型基于人类对颜色的感知,将颜色描述为色调(Hue)、饱和度(Saturation)和亮度(Value)。Hue 表示颜色的类型,Saturation 表示颜色的纯度或饱和度,Value 表示颜色的亮度。

CIE 1976 Lab 色彩空间

CIE 1976 Lab 色彩空间是一种基于人类视觉的颜色空间模型。它试图模拟人眼对颜色的感知,并提供了一种更为均匀和全面的颜色描述方式。Lab 模型由三个坐标轴组成:L 表示亮度(明度),a 表示从红色到绿色的轴,b 表示从黄色到蓝色的轴。Lab 色彩空间能够描述更广泛的颜色,并不依赖于设备或媒介,因此在颜色管理和计算机视觉中得到广泛应用。

Grayscale

Grayscale 是一种颜色模型,通常表示为黑白色。它不是彩色模型,而是只有黑、白和灰色(各种不同亮度级别的灰阶)的颜色模型。在 Grayscale 中,每个像素只有一个通道,表示它的亮度级别。通常,数字 0 表示黑色,而最大值(通常是 255)表示白色,中间的值表示不同级别的灰色。

RGB 是基于三种颜色通道的加法颜色模型,HSV 提供了一种更直观的颜色表示,CIE 1976 Lab 色彩空间提供了更准确的颜色描述。而 Grayscale 是灰度模型,通常用于表示黑白图像或者去除彩色信息以简化处理。这些色彩空间各自有其独特的应用领域,用于不同的颜色描述和颜色处理需求。

代码演示

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



def imread(image):
    image = cv2.imread(image)
    image = cv2.cvtColor(image,cv2.COLOR_BGR2RGB)
    return image

def show(image,title='image'):
    plt.imshow(image)
    plt.axis('off')
    plt.title(title)
    plt.show()



image = imread('image.jpg')
show(image)



#RGB

# RGB是从颜色发光的原理来设计定的,
# 通俗点说它的颜色混合方式就好像有红、绿、蓝三盏灯,
# 当它们的光相互叠合的时候,色彩相混,而亮度却等于两者亮度之总和,
# 越混合亮度越高,即加法混合。
# 红、绿、蓝三个颜色通道每种色各分为256阶亮度,
# 在0时“灯”最弱——是关掉的,而在255时“灯”最亮。
# 当三色灰度数值相同时,产生不同灰度值的灰色调,即三色灰度都为0时,
# 是最暗的黑色调;三色灰度都为255时,是最亮的白色调。
#
# 在电脑中,RGB的所谓“多少”就是指亮度,
# 并使用整数来表示。通常情况下,RGB各有256级亮度,
# 用数字表示为从0、1、2...直到255。注意虽然数字最高是255,
# 但0也是数值之一,因此共256级。
# 256 x 256 x 256 = 16,777,216


image = imread('image.jpg')
(R, G, B) = cv2.split(image)
zeros = np.zeros(image.shape[:2],dtype='uint8')
show(cv2.merge([R,zeros,zeros]))
show(cv2.merge([zeros,G,zeros]))
show(cv2.merge([zeros,zeros,B]))

# HSV
# HSV是一种比较直观的颜色模型,HSV颜色空可以更好的数字化处理颜色。
# 这个模型中颜色的参数分别是:色调(H, Hue),
# 饱和度(S,Saturation),明度(V, Value)。
#
# 色调H:
# 用角度度量,取值范围为0°~360°,从红色开始按逆时针方向计算,
# 红色为0°,绿色为120°,蓝色为240°。它们的补色是:黄色为60°,
# 青色为180°,品红为300°
#
# 饱和度S:
# 饱和度S表示颜色接近光谱色的程度。
# 一种颜色,可以看成是某种光谱色与白色混合的结果。
# 其中光谱色所占的比例愈大,颜色接近光谱色的程度就愈高,
# 颜色的饱和度也就愈高。饱和度高,颜色则深而艳。
# 光谱色的白光成分为0,饱和度达到最高。通常取值范围为0%~100%,
# 值越大,颜色越饱和。
#
# 明度V:
# 明度表示颜色明亮的程度,对于光源色,明度值与发光体的光亮度有关;
# 对于物体色,此值和物体的透射比或反射比有关。
# 通常取值范围为0%(黑)到100%(白)。


image = imread('image.jpg')
hsv = cv2.cvtColor(image,cv2.COLOR_BGR2RGB)
zeros = np.zeros(image.shape[:2],dtype='uint8')
for (name,chan) in zip(('H','S','V'),cv2.split(hsv)):
    cv2.imshow(name,chan)
cv2.waitKey(0)
cv2.destroyAllWindows()






# L*a*b*
# CIE1976Lab色空间(CIE LAB 色空间),
# 是1976年由国际照明学会(CIE)推荐的均匀色空间。
# Lab颜色空间用于计算机色调调整和彩色校正。
# 该空间是三维直角坐标系统。是目前最受广用的测色系统。
# 以明度L和色度坐标a*、b来表示颜色在色空间中的位置。
# l表示颜色的明度,a正值表示偏红,负值表示偏绿;b正值表示偏黄,负值表示偏蓝
#
# L* 表示颜色的明度;
#
# a* 正值表示红色,负值表示绿色;
#
# b* 正值表示黄色,负值表示蓝色;


image = imread('image.jpg')
lab = cv2.cvtColor(image,cv2.COLOR_BGR2RGB)
zeros = np.zeros(image.shape[:2],dtype='uint8')
for (name,chan) in zip(('L','A','B'),cv2.split(lab)):
    cv2.imshow(name,chan)
cv2.waitKey(0)
cv2.destroyAllWindows()


# Grayscale
# 灰阶图像就是黑白图片,通过调节灰度值来显示影像

image = cv2.imread('image.jpg')
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
cv2.imshow('original',image)
cv2.imshow('gray',gray)
cv2.waitKey(0)
cv2.destroyAllWindows()

这段代码主要是关于颜色空间的不同表示方法以及在 OpenCV 中的展示。下面是对代码中涉及的不同颜色空间的说明:

  1. RGB:
    • imreadshow 函数用于读取和显示图像。
    • RGB(红绿蓝)是一种加法颜色模型,由红、绿、蓝三个通道组成。图像以 RGB 三通道进行表示,每个通道都有 256 级亮度(从 0 到 255)。
    • 通过拆分图像的 R、G、B 通道,然后单独显示每个通道的效果。
      这段代码主要执行了以下操作:

(1)image = imread('image.jpg'): 读取名为 ‘image.jpg’ 的图像文件并转换其颜色通道顺序为 RGB(红绿蓝)格式。这一操作使用 OpenCV 的 cv2.imread() 函数读取图像,并使用 cv2.cvtColor() 函数将图像颜色空间转换为 RGB。

(2). (R, G, B) = cv2.split(image): 将 RGB 图像分离为其三个通道,即红色通道 R、绿色通道 G 和蓝色通道 B。

(3). zeros = np.zeros(image.shape[:2], dtype='uint8'): 创建一个大小与输入图像相同的零矩阵。该矩阵将用作图像通道中的某些通道。

(4). show(cv2.merge([R,zeros,zeros])), show(cv2.merge([zeros,G,zeros])), show(cv2.merge([zeros,zeros,B])): 这三行代码分别将 R、G、B 通道与零矩阵(除了特定通道以外的通道都是零)合并,以生成新的图像。这些图像是将每个通道分别与其他通道设置为零后合并的结果,即红色通道、绿色通道和蓝色通道的分离效果。

每个 show() 函数的调用将合成的图像进行显示,以便比较和观察每个通道对图像的贡献。展示的结果分别是只包含红色、绿色和蓝色的图像,其他颜色通道则没有显示。

  1. HSV (Hue, Saturation, Value):
    • HSV 是另一种颜色模型,用色调、饱和度和明度来描述颜色。代码中通过 cv2.split 拆分 HSV 通道并显示单独的色调(H)、饱和度(S)和明度(V)通道。

这段代码执行了以下操作:

  1. image = imread('image.jpg'): 从名为 ‘image.jpg’ 的文件中读取图像,并以 RGB 格式加载它。

  2. hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV): 将 RGB 图像转换为 HSV(色相、饱和度、明度)颜色空间。HSV 是一种更直观的颜色模型,其中 H 表示色调,S 表示饱和度,V 表示明度。

  3. zeros = np.zeros(image.shape[:2], dtype='uint8'): 这一行代码创建一个大小与输入图像的宽高相同的零矩阵,其数据类型为 ‘uint8’。

  4. for (name, chan) in zip(('H','S','V'), cv2.split(hsv)): 这是一个循环,遍历了 HSV 图像的三个通道(色相、饱和度、明度)。cv2.split() 函数用于将 HSV 图像分离成三个独立的通道。在这里,zip() 函数用于同时迭代通道名称和其对应的值。

  5. cv2.imshow(name, chan): 这行代码通过 OpenCV 的 cv2.imshow() 函数显示了每个通道的图像。cv2.imshow() 函数用于显示图像,它接受两个参数:一个用于显示的窗口名称(在这里是通道的名称,如 ‘H’、‘S’、‘V’),以及要显示的图像通道。

这段代码完成了将 RGB 图像转换为 HSV 颜色空间,并显示了每个通道的图像。

  1. CIE 1976 Lab:
    • CIE 1976 Lab 色彩空间描述颜色的明度、红绿和黄蓝三个通道。
    • 代码通过 cv2.split 拆分 Lab 通道并显示单独的 L、a、b 通道。

这段代码执行了以下操作:

  1. image = imread('image.jpg'): 从名为 ‘image.jpg’ 的文件中读取图像,并以 RGB 格式加载它。

  2. lab = cv2.cvtColor(image, cv2.COLOR_BGR2LAB): 将 RGB 图像转换为 CIE1976Lab(也称为 CIELAB)颜色空间。这个色彩空间是用于描述人类对颜色的感知的一种模型,其中 L 表示亮度,A 和 B 表示颜色。

在OpenCV中,cv2.COLOR_BGR2LABcv2.COLOR_BGR2Lab 其实指代相同的颜色空间转换,表示将BGR(蓝-绿-红)颜色空间转换为CIE 1976 Lab*(也称为 CIELAB)颜色空间。这两种写法仅在大小写上有所不同,但在功能上是相同的。 OpenCV中的颜色转换常量通常是大小写不敏感的,因此这两个写法可以互换使用。

  1. zeros = np.zeros(image.shape[:2], dtype='uint8'): 这一行代码创建了一个与输入图像的宽和高相同的零矩阵,其数据类型为 ‘uint8’。

  2. for (name, chan) in zip(('L','A','B'), cv2.split(lab)): 这是一个循环,遍历了 CIE1976Lab 图像的三个通道(亮度 L,颜色 A,颜色 B)。cv2.split() 函数用于将 CIE1976Lab 图像分离为三个独立的通道。zip() 函数则同时迭代通道名称和其对应的值。

  3. cv2.imshow(name, chan): 这行代码通过 OpenCV 的 cv2.imshow() 函数显示了每个通道的图像。cv2.imshow() 函数用于显示图像,它接受两个参数:一个用于显示的窗口名称(在这里是通道的名称,如 ‘L’、‘A’、‘B’),以及要显示的图像通道。

这段代码完成了将 RGB 图像转换为 CIE1976Lab 颜色空间,并显示了每个通道的图像。

  1. Grayscale:
    • 灰度图像是只有黑、白和灰色的图像,没有彩色。
    • 通过 cv2.cvtColor 将彩色图像转换为灰度图像,然后显示。

每个颜色空间在表达颜色和亮度方面都有不同的特性,适用于不同的应用场景。这段代码通过拆分和显示不同颜色空间的通道,帮助理解这些颜色空间及其通道对图像的影响。

enumerate()zip() 是 Python 中用于迭代和处理序列的两个不同的函数。

  • enumerate():

    • enumerate() 用于在迭代过程中同时获取索引和元素,返回的是元素的索引以及元素本身的元组。
    • 它常用于需要同时获取索引和对应元素值的情况。

    示例:

    my_list = ['apple', 'banana', 'orange']
    
    for index, value in enumerate(my_list):
        print(f"Index: {index}, Value: {value}")
    
  • zip():

    • zip() 用于将两个序列并排组合成元组的列表。
    • 它会返回一个由元组组成的迭代器,每个元组包含来自每个序列的对应元素。

    示例:

    list1 = ['a', 'b', 'c']
    list2 = [1, 2, 3]
    
    for item in zip(list1, list2):
        print(item)
    

主要区别:

  • enumerate() 提供元素的索引以及元素本身。
  • zip() 则将两个或多个序列并排组合成元组的列表。

二值化

概述

图像二值化是图像处理中的一种常见操作,将图像转换为黑白二值图像的过程。这种处理通常使用的是图像的灰度级别信息,将其转换为二值(只有两个值,一般是黑色和白色)的像素值。在图像处理中,Thresholding中文翻译过来叫二值化或者阈值化。二值化就是把图片传换成只有white和black这两种颜色。通过Thresholding,可以让图片中感兴趣的颜色变成主角–white,其余的颜色全部隐藏–black。另外,二值化后的图片也便于计算机进行分析,因为边缘轮廓十分清晰,所以计算机可以轻松找到边界线。然而,在找边界这方面,Thresholding并不是特别好的算法,有些时候遇到某些特殊图片效果也不好。下面是有关二值化的历史、原理、算法和用途的概述:

历史:

图像二值化是数字图像处理中最早的处理技术之一。它由早期的数字图像处理研究发展而来。最早的图像处理设备和技术往往只能处理二值图像。随着技术的发展,现代的图像处理算法和工具使得二值化在许多领域得到了广泛应用。

原理:

图像二值化的目的是将灰度图像中的像素值转换为二进制(0或1)或近似的二进制,使图像只包含黑白两种颜色。其原理主要是基于设定阈值,灰度值大于阈值的像素设置为白色,灰度值小于阈值的像素设置为黑色。这种简单的二值化方法常被称为全局阈值法,但也有其他复杂的算法。

算法:

  • 全局阈值法:应用单一阈值来将整个图像转换为二进制图像。常见的方法有Otsu算法和直方图均衡化。
  • 局部阈值法:将图像划分为小的局部区域,对每个区域应用不同的阈值,有利于处理光照不均匀的图像。常见的方法有Sauvola算法和Niblack算法。

用途:

  • 图像分割:二值化有助于分割对象与背景,识别对象的轮廓。
  • 特征提取:通过二值化,提取图像中的特定特征。
  • OCR(光学字符识别):二值化图像常用于文档扫描和字符识别。
  • 图像增强:可以突出特定细节以及降低噪声。

二值化是图像处理的基础操作,对于许多图像分析和计算机视觉任务都是至关重要的。通过选择合适的二值化算法和参数,可以更好地应用于不同领域的需求。

代码演示

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



def imread(image):
    image = cv2.imread(image)
    image = cv2.cvtColor(image,cv2.COLOR_BGR2RGB)
    return image

def show(image,title='image'):
    plt.imshow(image)
    plt.axis('off')
    plt.title(title)
    plt.waitforbuttonpress()

image = imread('image/coins.jpg')
show(image)



# plt.imshow() 是 Matplotlib 库中用于显示图像的函数,
# 它有一系列参数来控制图像的显示。主要参数包括:
#
# X: 显示的图像数据。
# 它可以是一个二维的数组(灰度图像)或者一个三维的数组(彩色图像)。
# cmap: 用于设定显示图像时采用的颜色图谱。
# 它表示对二维数据(例如灰度图像)进行颜色映射的规则。
# 比如常用的灰度图是使用 'gray' 参数。
# interpolation: 用于设置图像插值的方法。
# 它是一种用于显示图像时填充像素间隙的方法,
# 以改善图像的质量。常用的插值方法包括
# 'nearest', 'bilinear', 'bicubic' 等。
# aspect: 控制图像显示的宽高比。
gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
plt.imshow(gray,'gray')
plt.axis('off')
plt.title('gray')
plt.waitforbuttonpress()

• cv2.THRESH_BINARY
• cv2.THRESH_BINARY_INV
• cv2.THRESH_TRUNC
• cv2.THRESH_TOZERO
• cv2.THRESH_TOZERO_INV
在这里插入图片描述
在 OpenCV 中,cv2.threshold() 函数中的 type 参数表示不同的阈值类型,影响了二值化过程中像素值的变化。

cv2.THRESH_BINARY:将像素值大于阈值的设为最大值(通常为255),小于等于阈值的设为0。
cv2.THRESH_BINARY_INV:与 cv2.THRESH_BINARY 相反,将像素值大于阈值的设为0,小于等于阈值的设为最大值。
cv2.THRESH_TRUNC:将像素值大于阈值的设为阈值,小于等于阈值的像素值不变。
cv2.THRESH_TOZERO:将像素值大于阈值的像素值不变,小于等于阈值的设为0。
cv2.THRESH_TOZERO_INV:与 cv2.THRESH_TOZERO 相反,将像素值小于等于阈值的像素值不变,大于阈值的设为0。
这些类型允许你根据阈值对图像进行不同的处理和二值化。选择不同的类型可以实现不同的效果,以满足图像处理的不同需求。

代码演示:

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



def imread(image):
    image = cv2.imread(image)
    image = cv2.cvtColor(image,cv2.COLOR_BGR2RGB)
    return image

def show(image,title='image'):
    plt.imshow(image)
    plt.axis('off')
    plt.title(title)
    plt.waitforbuttonpress()


show(cv2.bitwise_and(image,image,mask=thresh1),'bitwise_and_image_thresh1')


# Otsu’s Method
# 自动选择阈值


image = imread('image/opencv_logo.png')
show(image,'image/opencv_logo.png')


gray=cv2.cvtColor(image,cv2.COLOR_RGB2GRAY)
plt.imshow(gray,'gray')
plt.axis('off')
plt.waitforbuttonpress()

ret1,thresh1 = cv2.threshold(gray,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)
ret2,thresh2 = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)
print('ret1:',ret1)
print('ret2:',ret2)


plt.imshow(thresh1,'gray')
plt.axis('off')
plt.waitforbuttonpress()

plt.imshow(thresh2,'gray')
plt.axis('off')
plt.waitforbuttonpress()

# Adaptive Thresholding自适应阈值
# 在前面的部分我们使用是全局阈值,整幅图像采用同一个数作为阈值。当 时这种方法并不适应与所有情况,尤其是当同一幅图像上的不同部分的具有不 同亮度时。这种情况下我们需要采用自适应阈值。此时的阈值是根据图像上的 每一个小区域计算与其对应的阈值。因此在同一幅图像上的不同区域采用的是 不同的阈值,从而使我们能在亮度不同的情况下得到更好的结果。
#
# Adaptive Method- 指定计算阈值的方法。
# – cv2.ADPTIVE_THRESH_MEAN_C:阈值取自相邻区域的平 均值
# – cv2.ADPTIVE_THRESH_GAUSSIAN_C:阈值取值相邻区域 的加权和,权重为一个高斯窗口。
# • Block Size - 邻域大小(用来计算阈值的区域大小)。
# • C - 这就是是一个常数,阈值就等于平均值或者加权平均值减去这个常 数。



image = imread('image/license_plate.png')
show(image)




# 变灰度图
image = cv2.cvtColor(image,cv2.COLOR_RGB2GRAY)
# 中值滤波
image = cv2.medianBlur(image,5)
# 普通二值化
ret,th1 = cv2.threshold(image,127,255,cv2.THRESH_BINARY)
# 平均值阈值
th2 = cv2.adaptiveThreshold(image,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,11,3)
# 高斯阈值
th3 = cv2.adaptiveThreshold(image,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,11,3)
titles = ['original', 'Global Thresholding', 'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding']
images = [image, th1, th2, th3]
plt.figure(figsize=(10,5))
for i in range(4):
    plt.subplot(2,2,i+1)
    plt.imshow(images[i],'gray')
    plt.axis('off')
    plt.title(titles[i])
plt.waitforbuttonpress()



image = imread('image/sudoku.jpg')
show(image)




# 变灰度图
image = cv2.cvtColor(image,cv2.COLOR_RGB2GRAY)
# 中值滤波
image = cv2.medianBlur(image,5)
# 普通二值化
ret,th1 = cv2.threshold(image,127,255,cv2.THRESH_BINARY)
# 平均值阈值
th2 = cv2.adaptiveThreshold(image,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,11,3)
# 高斯阈值
th3 = cv2.adaptiveThreshold(image,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,11,3)
titles = ['original', 'Global Thresholding', 'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding']
images = [image, th1, th2, th3]
plt.figure(figsize=(10,5))
for i in range(4):
    plt.subplot(2,2,i+1)
    plt.imshow(images[i],'gray')
    plt.axis('off')
    plt.title(titles[i])
plt.waitforbuttonpress()

这段代码用于对输入的车牌图像进行不同的阈值处理,并显示结果。

  1. imread('image/license_plate.png') 读取名为 license_plate.png 的图像。
  2. show(image) 使用 matplotlib 库显示原始图像。

接下来,针对车牌图像进行了一系列处理:

  1. cv2.cvtColor(image, cv2.COLOR_RGB2GRAY) 将图像转换为灰度图。
  2. cv2.medianBlur(image, 5) 使用中值滤波器进行模糊处理,以减少图像中的噪点。
  3. cv2.threshold(image, 127, 255, cv2.THRESH_BINARY) 对灰度图应用全局固定阈值处理。
  4. cv2.adaptiveThreshold(image, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 3) 使用自适应均值阈值处理。
  5. cv2.adaptiveThreshold(image, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 3) 使用自适应高斯阈值处理。

最后,matplotlibplt.subplot() 被用来创建图像展示的子图,每个子图显示了处理后的图像及相应的标题。这些子图排列成 2x2 网格布局。plt.waitforbuttonpress() 用于等待用户点击按钮后才继续执行代码,显示结果图像。

medianBlur,threshold,adaptiveThreshold 这三个函数分别用于图像处理中的模糊、全局阈值和自适应阈值处理。它们之间的主要区别在于其处理图像的方法以及如何应用阈值。

  1. medianBlur(image, ksize): 这个函数执行中值模糊操作,对图像进行降噪处理。它以像素的中值替换其邻域像素的值。这种方法特别擅长去除图像中的椒盐噪声或其他非常明显的噪点。ksize 参数表示中值模糊核的大小。此函数主要用于去除噪声,以提高后续阈值处理的准确性。

  2. threshold(image, thresh, maxval, type): threshold() 函数用于将灰度图像转换为二值图像。它通过设定一个阈值将灰度图像中的像素分为两个部分:高于阈值的像素值设为 maxval,低于等于阈值的像素值设为 0 或其他指定的值。thresh 是阈值,maxval 是高于阈值的像素值,type 是阈值化操作的类型,例如 cv2.THRESH_BINARY 表示二值化操作。

  3. adaptiveThreshold(image, maxval, adaptiveMethod, thresholdType, blockSize, C): 这个函数执行自适应阈值处理。与 threshold 不同,adaptiveThreshold() 操作时会对图像的不同区域采用不同的阈值。这个方法特别适用于场景中有明显光照变化或噪声影响的情况。参数 blockSize 指定计算阈值的区域大小,C 是从计算出的平均值或加权平均值减去的常数。adaptiveMethod 可以是 cv2.ADAPTIVE_THRESH_MEAN_Ccv2.ADAPTIVE_THRESH_GAUSSIAN_C,分别代表均值和高斯加权的自适应方法。

这三种方法在图像处理中的应用相对独特,中值模糊用于降噪、threshold 用于二值化图像、自适应阈值处理常用于光照不均匀的图像场景。选择合适的方法取决于处理的具体任务和图像特性。

图像梯度

图像梯度是指图像中像素强度的变化率。它对图像处理和计算机视觉领域至关重要,因为它能帮助我们了解图像中不同区域的变化和边缘信息。下面是有关图像梯度的历史、原理、算法和应用的详细说明:

历史

  • 1970s: 图像处理和计算机视觉领域开始出现梯度算法。
  • 1980s: 边缘检测技术逐渐成为主流,Sobel 和 Prewitt 算子等梯度算法开始流行。
  • 1990s: Canny 边缘检测算法的提出,开启了新的边缘检测范式。

图像梯度是一种数学概念,用于表示图像中像素值的变化情况。它在图像处理中非常重要,因为梯度能提供图像中局部像素强度变化的信息。

图像梯度源自微积分中对多变量函数的梯度概念。在图像中,梯度代表着图像亮度或颜色的变化速率。图像梯度主要从灰度图像的强度变化和彩色图像的颜色变化中计算而来。

原理

梯度代表了图像中像素值的变化速率。在灰度图像中,梯度是表示图像强度变化的一阶导数。它是在像素值的空间中计算的。
I是图像像素的值(如:RGB值)
一阶导数:
x的梯度:Gx = I(x+1,y)-I(x,y)
y的梯度:Gy = I(x,y+1)-I(x,y)
二阶导数:
x的梯度:I(x+1,y)+I(x-1,y)-2I(x,y) y的梯度:I(x,y+1)+I(x,y-1)-2I(x,y) OpenCV 提供了三种不同的梯度滤波器,或者说高通滤波器: Sobel,Scharr 和 Laplacian。Sobel, Scharr 其实就是求一阶或二阶导数。 Scharr 是对 Sobel的优化。Laplacian 是求二阶导数。
梯度大小和方向的公式为
在这里插入图片描述
梯度的方向一般总是与边界垂直。梯度方向被归为四类:垂直,水平,和两个对角线。
在这里插入图片描述

算法

Sobel 算子
  • 基于离散微分算子的边缘检测算法。
  • 通过将一阶微分和离散卷积结合来计算图像梯度。
Prewitt 算子
  • 类似于 Sobel 算子,用于边缘检测。
Scharr 算子
  • 更精确的边缘检测算子,用于计算梯度。

Sobel算子和Scharr算子:
Sobel 算子是高斯平滑与微分操作的结合体,所以它的抗噪声能力很好。你可以设定求导的方向(xorder 或 yorder)。还可以设定使用的卷积核的大小(ksize)。

在这里插入图片描述

如果 ksize=-1,会使用 3x3 的 Scharr 滤波器,它的的效果要比 3x3 的 Sobel 滤波器好(而且速度相同,所以在使用 3x3 滤波器时应该尽量使用 Scharr 滤波器)。 3x3 的 Scharr 滤波器卷积核如下:

在这里插入图片描述

Roberts 算子
  • 使用二阶微分方法检测图像中的边缘。
Canny 边缘检测
  • 多步骤的边缘检测算法,包括高斯平滑、梯度计算、非极大值抑制、双阈值和边缘跟踪等步骤。
Laplacian算子:

拉普拉斯算子使用的卷积核:
在这里插入图片描述

应用

  • 边缘检测: 识别图像中的边缘和物体边界。
  • 特征提取: 通过梯度信息,检测和描述图像中的特征。
  • 图像增强: 使用梯度信息增强图像对比度和清晰度。
  • 目标检测与跟踪: 在目标识别和跟踪中利用梯度信息。

梯度算法在图像处理中有着广泛的应用,尤其在边缘检测、特征提取和计算机视觉领域。其不断发展和改进使得图像处理技术不断进步。

代码演示:

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





def imread(image):
    image = cv2.imread(image)
    image = cv2.cvtColor(image,cv2.COLOR_BGR2RGB)
    return image


def show(image,title='image'):
    plt.imshow(image)
    plt.axis('off')
    plt.title(title)
    plt.waitforbuttonpress()

image = imread('image/bricks.png')
show(image)



def gradient(image):
    image = cv2.cvtColor(image,cv2.COLOR_RGB2GRAY)
    # cv2.CV_64F输出图像的深度(数据类型)64为浮点数据类型,因为梯度也有可能是负
    laplacian = cv2.Laplacian(image,cv2.CV_64F)
    # 1,0表示在X方向求一阶导数,最大可以求2节导数
    sobelx = cv2.Sobel(image,cv2.CV_64F,1,0,ksize=3)
    #0,1表示在y方向求一阶导数,最大可以求2阶导数
    sobely = cv2.Sobel(image,cv2.CV_64F,0,1,ksize=3)

    titles = ['Origin','Laplacian','SobelX',"SobelY"]
    images = [image,laplacian,sobelx,sobely]
    plt.figure(figsize=(10,5))
    for i in range(4):
        plt.subplot(2,2,i+1)
        plt.imshow(images[i],'gray')
        plt.title(titles[i])
        plt.axis('off')
    plt.waitforbuttonpress()


gradient(image)


image = imread('image/license_plate.png')
gradient(image)

这段代码演示了如何使用 OpenCV(cv2)在图像上应用梯度变换。具体来说:

  1. imread 函数使用 OpenCV 读取图像文件,并将其转换为 RGB 格式。

  2. show 函数使用 Matplotlib 显示图像。

  3. gradient 函数接收一个图像作为输入,并执行以下操作:

    • 将图像转换为灰度图像,因为梯度操作通常在灰度图上执行。
    • 使用 cv2.Laplacian 函数计算图像的拉普拉斯梯度。拉普拉斯算子是一种二阶微分算子,可突出图像中的边缘。
    • 使用 cv2.Sobel 函数计算图像的 Sobel 梯度。Sobel 算子是一种离散微分算子,用于计算图像亮度的一阶导数。
    • 创建标题和图像列表,然后使用 Matplotlib 的 subplot 在同一图像窗口中显示原始图像、拉普拉斯梯度、Sobel X 梯度和 Sobel Y 梯度。

这段代码通过展示拉普拉斯和Sobel梯度,帮助分析图像中的边缘、纹理和梯度方向,有助于检测图像的特征。

cv2.Laplaciancv2.Sobel 是 OpenCV 中用于图像处理的函数,常用于边缘检测和图像梯度计算。

  • Laplacian(拉普拉斯算子)

    cv2.Laplacian 函数用于计算图像的拉普拉斯梯度。拉普拉斯算子是一种二阶微分算子,它对图像中的像素进行二阶导数运算,有助于突出图像中的边缘和纹理。这个算子可以增强图像中的高频成分,对检测边缘非常有效。常用于图像的模糊和平滑,可以帮助凸显图像的细节和边缘。

    laplacian = cv2.Laplacian(image, cv2.CV_64F)
    
  • Sobel(Sobel算子)

    cv2.Sobel 函数用于计算图像的梯度,通常用于边缘检测。它执行离散微分算子,可用于计算图像亮度的一阶导数。这个算子能够检测出图像中水平和垂直方向的边缘。通常,可以计算X方向和Y方向的梯度。

    sobelx = cv2.Sobel(image, cv2.CV_64F, 1, 0, ksize=3)
    sobely = cv2.Sobel(image, cv2.CV_64F, 0, 1, ksize=3)
    

    在这里,1, 0 表示在 X 方向求一阶导数,0, 1 表示在 Y 方向求一阶导数,ksize 是 Sobel 核的大小。

cv2.Laplaciancv2.Sobel 函数具有一些共同的参数,以及特定的参数。

共同参数:

  • 参数1:

    • src:输入图像。数据类型为 uint8 或 float32。
  • 参数2:

    • ddepth:输出图像的深度,通常为 cv2.CV_64F 或 -1。-1 表示输出图像与输入图像深度相同。
  • 参数3和参数4:

    • dxdy:分别代表 X 方向和 Y 方向的求导阶数。dx=1 且 dy=0 意味着对 X 方向进行一阶导数的计算,dy=1 且 dx=0 意味着对 Y 方向进行一阶导数的计算。
  • 参数5:

    • ksize:Sobel 算子的大小,用于计算梯度。如果未指定,默认是 3。
  • 参数6:

    • scale:可选的缩放因子,用来缩放导数值。默认为 1。
  • 参数7:

    • delta:可选的一个值,添加到最终的导数计算中。默认为 0。

Laplacian 特有参数:

  • 参数2:
    • ksize:拉普拉斯算子的核大小,通常为 1、3、5 或 7。

Sobel 特有参数:

  • 参数5:
    • ksize:Sobel 算子的核大小。

这些参数用于调整边缘检测和梯度计算的方式,以及输出图像的深度和大小。

这些函数通常被用于图像处理中,以帮助检测边缘、纹理以及图像中的特定特征。

Canny边缘检测

Canny边缘检测
Canny 边缘检测是一种非常流行的边缘检测算法,是 John F.Canny 在1986 年提出的。它是一个有很多步构成的算法,我们接下来会逐步介绍。

1.噪声去除

由于边缘检测很容易受到噪声影响,所以第一步是使用 5x5 的高斯滤波器去除噪声,这个前面我们已经学过了。

2.计算图像梯度

对平滑后的图像使用 Sobel 算子计算水平方向和竖直方向的一阶导数(图像梯度)(Gx 和 Gy)。根据得到的这两幅梯度图(Gx 和 Gy)找到边界的梯度和方向,公式如下:

在这里插入图片描述
梯度的方向一般总是与边界垂直。梯度方向被归为四类:垂直,水平,和两个对角线。

3.非极大值抑制

在获得梯度的方向和大小之后,应该对整幅图像做一个扫描,去除那些非边界上的点。对每一个像素进行检查,看这个点的梯度是不是周围具有相同梯度方向的点中最大的。如下所示:
在这里插入图片描述
上图中的数字代表了像素点的梯度强度,箭头方向代表了梯度方向。以第二排第三个像素点为例,由于梯度方向向上,则将这一点的强度(7)与其上下两个像素点的强度(5和4)比较,由于这一点强度最大,则保留。

4.滞后阈值

现在要确定那些边界才是真正的边界。这时我们需要设置两个阈值:minVal 和 maxVal。当图像的灰度梯度高于 maxVal 时被认为是真的边界,那些低于 minVal 的边界会被抛弃。如果介于两者之间的话,就要看这个点是否与某个被确定为真正的边界点相连,如果是就认为它也是边界点,如果不是就抛弃。如下图:
在这里插入图片描述
A 高于阈值 maxVal 所以是真正的边界点, B 虽然低于 maxVal 但高于minVal 并且与 A 相连,所以也被认为是真正的边界点。而 C 就会被抛弃,因为他不仅低于 maxVal 而且不与真正的边界点相连。D也会被抛弃,因为低于minVal。所以选择合适的 maxVal和 minVal 对于能否得到好的结果非常重要。在这一步一些小的噪声点也会被除去,因为我们假设边界都是一些长的线段。

Canny使用

在 OpenCV 中只需要一个函数: cv2.Canny(),就可以完成以上几步。让我们看如何使用这个函数。这个函数的第一个参数是输入图像。第二和第三个分别是 minVal 和 maxVal。第四个参数设置用来计算图像梯度的 Sobel卷积核的大小,默认值为 3。最后一个参数是 L2gradient,它可以用来设定求梯度大小的方程。如果设为 True,就会使用我们上面提到过的方程: G = ( G x 2 + G y 2 ) G=\sqrt{(G_x^2+G_y^2 )} G=(Gx2+Gy2) ,否则使用方程: G = ∣ G x 2 ∣ + ∣ G y 2 ∣ G=|G_x^2|+|G_y^2| G=Gx2+Gy2代替,默认值为 False。

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



def imread(image):
    image = cv2.imread(image)
    image = cv2.cvtColor(image,cv2.COLOR_BGR2RGB)
    return image

def show(image,title='image'):
    plt.imshow(image)
    plt.axis('off')
    plt.title(title)
    plt.waitforbuttonpress()


image = imread('image/school.jpg')
show(image)



def edge_detection(image,minVal=100,maxVal=200):
    image = cv2.cvtColor(image,cv2.COLOR_RGB2GRAY)
    edges = cv2.Canny(image,minVal,maxVal)
    plt.imshow(edges,'gray')
    plt.axis('off')
    plt.title('Canny')
    plt.waitforbuttonpress()

edge_detection(image)




image = imread('image/license_plate.png')
show(image)


edge_detection(image)

image = imread('image/bricks.png')
show(image)


edge_detection(image)


image = imread('image/coins.jpg')
show(image)


image = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
image = cv2.GaussianBlur(image,(3,3),0)
Values = [(10,150),(100,200),(180,230)]
plt.figure(figsize=(20,5))
for i,(minVal,maxVal) in enumerate(Values):
    plt.subplot(1,3,i+1)
    edges = cv2.Canny(image,minVal,maxVal)
    plt.imshow(edges,'gray')
    plt.title(str((minVal,maxVal)))
    plt.axis('off')
plt.waitforbuttonpress()



#自动确定阈值的一种方法

def auto_canny(image,sigma=0.33):
    v = np.median(image)
    lower = int(max(0,(1.0-sigma)*v))
    upper = int(min(255,(1+sigma)*v))
    edged = cv2.Canny(image,lower,upper)
    title="lower = %d,upper = %d"%(lower,upper)
    return edged,title


edges,title = auto_canny(image)
edges= cv2.GaussianBlur(edges,(3,3),0)
plt.imshow(edges,'gray')
plt.axis('off')
plt.title(str(('auto_canny:',title)))
plt.waitforbuttonpress()

这段代码使用了OpenCV中的Canny边缘检测算法。Canny边缘检测算法可用于检测图像中的多种边缘。

代码详细说明如下:

  1. 导入及实用函数

    • imread(image): 使用OpenCV读取图像,并将其颜色模式转换为RGB。
    • show(image, title): 使用Matplotlib显示图像。
  2. 边缘检测函数 edge_detection

    • 此函数接受图像,将其转换为灰度图像,然后使用cv2.Canny函数应用Canny边缘检测算法。
    • 使用Matplotlib显示检测到的边缘。
    • 可调整Canny阈值minValmaxVal进行边缘检测。如果未指定,则使用默认值100200
  3. 对多种图像进行边缘检测

    • edge_detection(image): 对’school.jpg’图像应用Canny函数进行边缘检测,使用默认的minValmaxVal
    • edge_detection(image): 对’license_plate.png’图像应用Canny函数进行边缘检测,使用默认的minValmaxVal
    • 类似地,对’bricks.png’和’coins.jpg’图像执行边缘检测操作。
  4. 手动设置阈值

    • 对’coins.jpg’图像:
      • 设置不同的minValmaxVal阈值,以演示不同阈值对边缘检测的影响。
      • 使用三组阈值来显示具有不同阈值组合的边缘。
  5. 自动Canny边缘检测

    • auto_canny(image, sigma): 一个自动确定Canny边缘检测阈值的函数,基于图像的中值像素值。
    • 根据指定的sigma因子(默认值为0.33)计算上下阈值,并使用cv2.Canny执行Canny边缘检测。
    • 显示的边缘带有显示较低和较高阈值计算值的标题。

关于cv2.Canny函数,它用于Canny边缘检测,使用以下参数:

  • image:输入的灰度图像。
  • minVal:较低的阈值值。低于此阈值的任何梯度值被视为非边缘。
  • maxVal:较高的阈值值。高于此阈值的任何梯度值被视为边缘。
  • edges:输出的边缘图,其中标记了边缘。

Canny边缘检测算法可用于检测图像中的多种边缘,广泛应用于图像处理和计算机视觉应用。调整阈值对于获得理想的边缘映射至关重要。

视频操作

import cv2
import numpy as mp




# 摄像头读取


# cap = cv2.VideoCapture(0)
#
# while(True):
#     #ret 读取成功True
#     # frame读取到的图像内容
#     #读取每一帧数据
#     ret,frame = cap.read()
#     #变为灰度图
#     if ret:
#         gray = cv2.cvtColor(frame,cv2.COLOR_RGB2GRAY)
#         cv2.imshow('frame',gray)
#         #waitkey功能是不断刷新图像,单位ms,返回值是当前键盘按键值
#         # ord 返回ASCII的数值
#         if cv2.waitKey(1) & 0xff == ord('q'):
#             break
#     else:
#         print('ret = %d'%ret)
#         break
# cap.release()
# cv2.destroyAllWindows()




# cap.read() 返回一个布尔值(True/False)。
# 如果帧读取的是正确的,就是 True。
# 所以最后你可以通过检查他的返回值来查看视频文件是否已经到了结尾。
# 有时 cap 可能不能成功的初始化摄像头设备。这种情况下上面的代码会报错。
# 你可以使用 cap.isOpened(),来检查是否成功初始化了。
# 如果返回值是True,那就没有问题。否则就要使用函数 cap.open()。
# 你可以使用函数 cap.get(propId) 来获得视频的一些参数信息。
# 这里propId 可以是 0 到 18 之间的任何整数。每一个数代表视频的一个属性。

# 其中的一些值可以使用 cap.set(propId,value) 来修改,
# value 就是你想要设置成的新值。
# 例如,我可以使用 cap.get(3) 和 cap.get(4) 来查看每一帧的宽和高。
# 默认情况下得到的值是 640X480。
# 但是我们可以使用 ret=cap.set(3,320)和
# ret=cap.set(4,240) 来把宽和高改成 320X240。

# #从视频中文件读取
#
# cap = cv2.VideoCapture('videos/cats.mp4')
#
# #视频每秒传输帧数
# fps = cap.get(cv2.CAP_PROP_FPS)
#
# #视频图像的宽度
# frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
# #视频的高度
# frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
#
# print("fps= %f"%fps)
# print('width=%d'%frame_width)
# print('height=%d'%frame_height)
#
#
# while(True):
#     ret,frame = cap.read()
#     if ret != True:
#         break
#     cv2.imshow('frame',frame)
#     if cv2.waitKey(25) & 0xff == ord('q'):
#         break
#
# cap.release()
# cv2.destroyAllWindows()


#视频写入
# 在我们捕获视频,并对每一帧都进行加工之后我们想要保存这个视频。
# 对于图片来时很简单只需要使用 cv2.imwrite()。但对于视频来说就要多做点工作。
# 这次我们要创建一个 VideoWriter 的对象。
# 我们应该确定一个输出文件的名字。接下来指定 FourCC 编码(下面会介绍)。
# 播放频率和帧的大小也都需要确定。最后一个是 isColor 标签。
# 如果是 True,每一帧就是彩色图,否则就是灰度图。
# FourCC 就是一个 4 字节码,用来确定视频的编码格式。
# 可用的编码列表可以从fourcc.org查到。
# • In Fedora: DIVX, XVID, MJPG, X264, WMV1, WMV2.
# (XVID is more preferable. MJPG results in high size video.
# X264 gives very small size video)

# 从文件读取视频内容
cap = cv2.VideoCapture('videos/cats.mp4')
# 视频每秒传输帧数
fps = cap.get(cv2.CAP_PROP_FPS)
# 视频图像的宽度
frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
# 视频图像的长度
frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
print(fps)
print(frame_width)
print(frame_height)



fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('video/output.avi',fourcc,fps,(frame_width,frame_height))

while(True):
    ret, frame = cap.read()
    if ret==True:
        # 水平翻转
        frame = cv2.flip(frame,1)
        out.write(frame)
        cv2.imshow('frame',frame)
        if cv2.waitKey(25) & 0xff == ord('q'):
            break
    else:
        break
out.release()
cap.release()
cv2.destroyAllWindows()

这段代码展示了如何使用OpenCV读取摄像头捕获的图像、从视频文件读取图像、以及将视频文件进行处理后保存成新的视频。

  1. 代码中使用cv2.VideoCapture(0)捕获摄像头图像。通过cap.read()获取每一帧的图像内容。cv2.imshow()方法可以在窗口中显示捕获到的图像。使用cv2.waitKey()检测键盘输入,当按下"q"键时退出捕获窗口。最后,cap.release()释放摄像头资源,cv2.destroyAllWindows()关闭所有打开的窗口。

  2. 从视频文件中读取图像帧的过程与捕获摄像头的方式类似,只是使用cv2.VideoCapture('videos/cats.mp4')打开一个视频文件,通过cap.read()逐帧读取,显示并播放视频。

  3. 最后部分展示了如何将处理后的视频保存为新的视频文件。这里使用了cv2.VideoWriter()来创建视频写入对象。首先读取视频文件,然后将每一帧进行水平翻转处理,并使用cv2.VideoWriter()保存处理后的帧,最终生成一个新的视频文件。

这段代码主要涉及摄像头捕获、视频处理和视频保存等功能。

人脸检测识别

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值