机器视觉opencv总结

发布于:2025-09-08 ⋅ 阅读:(23) ⋅ 点赞:(0)
import cv2
a =cv2.imread('zzd01.png')
cv2.imshow('cc',a)
d = cv2.waitKey(5000)

c = a.copy()
c[:,:,1] = 0
c[:,:,2] = 0

在 OpenCV 中,图像是以 NumPy 数组的形式存储的,对于彩色图像通常采用 BGR(蓝、绿、红)通道顺序(注意不是 RGB)。

代码中的c[:,:,1] = 0c[:,:,2] = 0这两行的作用是:

  1. c[:,:,1] = 0:将图像中所有像素的绿色通道(G 通道,索引为 1)的值设置为 0
  2. c[:,:,2] = 0:将图像中所有像素的红色通道(R 通道,索引为 2)的值设置为 0

执行这两行代码后,只剩下蓝色通道(B 通道,索引为 0)保留了原始图像的信息,所以最终得到的图像会是原图的蓝色分量单独显示的效果,看起来是一幅蓝色调的图像。

b,g,r =cv2.split(a)
hebing = cv2.merge((b,g,r))
cv2.imshow('cc2',hebing)
cv2.waitKey(5000)
    • 使用cv2.split()函数将原始彩色图像a按通道拆分
    • 拆分后得到三个单通道图像:
      • b:蓝色通道(B 通道)
      • g:绿色通道(G 通道)
      • r:红色通道(R 通道)
  1. hebing = cv2.merge((b, g, r))

    • 使用cv2.merge()函数将拆分后的三个单通道图像重新合并
    • 这里按照(b, g, r)的顺序合并,与 OpenCV 默认的 BGR 格式一致

import cv2

b = cv2.imread("zzd01.png",0)
cv2.imshow('bb',b)
a = cv2.waitKey(2000)
# cv2.destroyWindow('bb')

print(b.shape)
print(b.dtype)
print(b.size)
cv2.imwrite("gery.png",b)

c = b[50:90,50:90]
cv2.imshow("cc",c)
d = cv2.waitKey(2000)
cv2.destroyAllWindows()
  1. b = cv2.imread("zzd01.png",0)

    • 以灰度模式读取图像 "zzd01.png"(参数0表示将图像转为单通道灰度图)
    • 读取后的图像b是一个二维数组(单通道)
  2. print(b.shape):输出图像的尺寸(高度,宽度),例如(480, 640)
  3. print(b.dtype):输出图像数据类型,通常是uint8(8 位无符号整数)
  4. print(b.size):输出图像的总像素数(高度 × 宽度)
  1. c = b[50:90,50:90]

    • 对图像进行裁剪,截取从坐标 (50,50) 到 (90,90) 的区域(行范围 50-90,列范围 50-90)
    • 裁剪后的图像尺寸为 40×40 像素

       
import cv2

a = cv2.VideoCapture('dqvedio.mp4')
if not a.isOpened():
    print("视频损坏,无法读取 ")
    exit()

while True:
    ref,fream=a.read()

    if not ref:
        break

    # fream = cv2.cvtColor(fream,cv2.COLOR_BGR2RGB)
    cv2.imshow('Video',fream)

    if cv2.waitKey(6)==27:
        break
a.release()
cv2.destroyAllWindows()
  1. a = cv2.VideoCapture('dqvedio.mp4')

    • 创建一个视频捕获对象,用于读取指定的视频文件 "dqvedio.mp4"
  2. if not a.isOpened(): 部分:

    • 检查视频文件是否成功打开
    • 如果无法打开(如文件不存在、格式不支持等),则打印提示信息并退出程序
  3. while True: 循环部分:

    • 这是视频播放的主循环,逐帧读取并显示视频
    • ref, fream = a.read():读取一帧视频,ref是布尔值表示是否读取成功,fream是读取到的帧图像
    • if not ref: break:如果读取失败(如已到视频末尾),则退出循环
  4. 视频显示部分:

    • 注释掉的 fream = cv2.cvtColor(fream,cv2.COLOR_BGR2RGB) 表示可以将 BGR 格式转为 RGB 格式(OpenCV 默认读取为 BGR 格式)
    • cv2.imshow('Video',fream):在名为 'Video' 的窗口中显示当前帧
  5. 退出控制:

    • if cv2.waitKey(6)==27: break:等待 6 毫秒(控制播放速度),如果按下 ESC 键(ASCII 码 27)则退出循环
  6. 资源释放:

    • a.release():释放视频捕获对象
    • cv2.destroyAllWindows():关闭所有显示窗口
import cv2
ys = cv2.imread("zzd02.png")

top,bottom,left,right = 60,60,60,60

constant = cv2.copyMakeBorder(ys,top,bottom,left,right,borderType=cv2.BORDER_CONSTANT,value=(60,60,60))
reflect = cv2.copyMakeBorder(ys,top,bottom,left,right,borderType=cv2.BORDER_REFLECT)
reflect101 = cv2.copyMakeBorder(ys,top,bottom,left,right,borderType=cv2.BORDER_REFLECT101)
replicate = cv2.copyMakeBorder(ys,top,bottom,left,right,borderType=cv2.BORDER_REPLICATE)
wrap =cv2.copyMakeBorder(ys,top,bottom,left,right,borderType=cv2.BORDER_WRAP)

cv2.imshow("ys",ys)
cv2.waitKey(10000)
cv2.imshow("constant",constant)
cv2.waitKey(10000)
cv2.imshow("reflect",reflect)
cv2.waitKey(10000)
cv2.imshow("reflect101",reflect101)
cv2.waitKey(10000)
cv2.imshow("replicate",replicate)
cv2.waitKey(10000)
cv2.imshow("wrap",wrap)
cv2.waitKey(10000)
  1. ys = cv2.imread("zzd02.png")

    • 读取原始图像 "zzd02.png",存储在变量ys
  2. top,bottom,left,right = 60,60,60,60

    • 定义边框尺寸:上下左右各添加 60 像素的边框
  3. 生成不同类型的边框图像:

    • constant:使用cv2.BORDER_CONSTANT类型,添加纯色边框,颜色由value=(60,60,60)指定(暗灰色)
    • reflect:使用cv2.BORDER_REFLECT类型,边框为原图边缘像素的镜像反射(类似镜面效果,边缘像素会被重复)
    • reflect101:使用cv2.BORDER_REFLECT101类型,也是镜像反射效果,但边缘像素不会被重复(更自然的反射)
    • replicate:使用cv2.BORDER_REPLICATE类型,边框由原图边缘像素向外延伸复制(重复边缘像素)
    • wrap:使用cv2.BORDER_WRAP类型,边框采用原图对侧内容填充(类似图像平铺环绕效果)

import numpy as np
import cv2
a = cv2.imread("zzd01.png")
b = cv2.imread("zzd02.png")
b1 = b.copy()
b1[250:450,250:450] = np.random.randint(0,256,(200,200,3))
cv2.imshow("b1",b1)
cv2.waitKey(5000)
  1. 使用b.copy()创建了图像b的副本b1(这样操作不会影响原始图像b)。

  2. 核心操作是b1[250:450,250:450] = np.random.randint(0,256,(200,200,3))

    • 选取b1图像中从 (250,250) 到 (450,450) 的矩形区域(这是一个 200×200 像素的区域)
    • 使用np.random.randint(0,256,(200,200,3))生成一个 200×200×3 的随机数组,数组元素是 0-255 之间的整数(符合图像像素值范围)
import cv2
from cv2 import imshow

a = cv2.imread("zzd02.png")
b = cv2.imread("zzd03.png")

c = a+50
cv2.imshow("a",a)
cv2.imshow("c",c)
cv2.waitKey(0)

c = a[60:120,60:120]+b[60:120,60:120]
cv2.imshow("a+b",c)
cv2.waitKey(0)

a1 = cv2.resize(a,(300,300))
b1 = cv2.resize(b,(300,300))
c = cv2.add(a1,b1)
cv2.imshow("a add b",c)
cv2.waitKey(0)

# cv2.destroyAllWindows()


c = cv2.addWeighted(a1,0.4,b1,0.6,10)
cv2.imshow("a addWeighted b",c)
cv2.waitKey(0)

cv2.destroyAllWindows()

单图像像素 “简单加法”:整体提亮(但存在溢出风险)

c = a + 50
  • 作用:给图像所有像素的 B、G、R 三个通道值都加 50,整体效果是图像变亮(类似调高亮度)。
  • 注意(关键特性)
    这是 NumPy 数组的 “模运算加法”,而非 OpenCV 的图像加法 —— 如果像素值加 50 后超过 255(比如原像素是 240),会自动对 256 取模(240+50=290 → 290-256=34),导致图像出现 “异常亮斑” 或色彩失真(比如白色像素加 50 后会变成低数值的异常颜色)。

两图像局部 “简单像素相加”:指定区域叠加

c = a[60:120, 60:120] + b[60:120, 60:120]
  • 前提:图像 a 和 b 的尺寸必须一致(至少被截取的 60:120 区域存在),否则会报错。
  • 作用:将两张图中 “60 行到 120 行、60 列到 120 列” 的局部区域(60×60 像素)的对应像素值相加,生成新的局部图像 c。
  • 同样有溢出问题:若两图像对应像素值之和超过 255,仍会按 256 取模,导致局部色彩异常(比如两图该区域都是白色,相加后会变成黑色或低亮度颜色)。

两图像 “OpenCV 标准加法”:先 resize 再正常叠加

a1 = cv2.resize(a, (300, 300))  # 将a缩放为300×300像素
b1 = cv2.resize(b, (300, 300))  # 将b缩放为300×300像素(确保两图尺寸一致)
c = cv2.add(a1, b1) 
  • 关键步骤:cv2.resize ()
    先将 a 和 b 都缩放为 300×300 像素 —— 因为 cv2.add() 要求两输入图像的 尺寸、通道数完全一致,否则无法计算,这是与 “简单像素相加” 的第一个区别。
  • 核心函数:cv2.add ()
    这是 OpenCV 专门为图像设计的加法,解决了 “简单加法” 的溢出问题:
    若两图像对应像素值之和超过 255,会直接将结果设为 255(即 “截断处理”,而非取模),符合人眼对图像亮度的认知(比如两白色像素相加后仍为白色,而非异常颜色)。
  • 效果:两图整体叠加,亮度是对应像素的总和(但不超过 255),色彩是两图色彩的混合(比如 a 是红色、b 是绿色,叠加后该区域可能是黄色)。

两图像 “加权加法”:按比例混合(常用作图像融合)

c = cv2.addWeighted(a1, 0.4, b1, 0.6, 10)
  • 核心函数:cv2.addWeighted ()
    这是图像融合的常用函数,公式为:
    dst = src1×alpha + src2×beta + gamma
    其中参数含义:
    • a1:第一张输入图像(src1)
    • 0.4:a1 的权重(alpha)—— 表示 a1 在混合结果中占 40%
    • b1:第二张输入图像(src2)
    • 0.6:b1 的权重(beta)—— 表示 b1 在混合结果中占 60%
    • 10:亮度调节值(gamma)—— 给混合后的每个像素值加 10(可选,用于微调整体亮度)
  • 作用:按比例混合两张图像,避免 “简单加法” 的生硬叠加,常用于 “水印添加”“图像合成”(比如将风景图和人物图按比例融合)。
  • 优势:权重(alpha 和 beta)可灵活调整,gamma 可补偿亮度,混合效果自然,且同样会自动处理溢出(超过 255 则设为 255)。
import cv2
image = cv2.imread("zzd02.png",0)
ret ,binary = cv2.threshold(image,140,200,cv2.THRESH_BINARY)
ret1 ,binary1 = cv2.threshold(image,140,200,cv2.THRESH_BINARY_INV)
ret2 ,binary2 = cv2.threshold(image,140,200,cv2.THRESH_TRUNC)
ret3 ,binary3 = cv2.threshold(image,140,200,cv2.THRESH_TOZERO)
ret4 ,binary4 = cv2.threshold(image,140,200,cv2.THRESH_TOZERO_INV)

cv2.imshow("binary",binary)
cv2.waitKey(0)
cv2.imshow("binary1",binary1)
cv2.waitKey(0)
cv2.imshow("binary2",binary2)
cv2.waitKey(0)
cv2.imshow("binary3",binary3)
cv2.waitKey(0)
cv2.imshow("binary4",binary4)
cv2.waitKey(0)
cv2.destroyAllWindows()

核心操作:不同类型的阈值化函数 cv2.threshold()

cv2.threshold() 是 OpenCV 的阈值化函数,语法为:
retval, dst = cv2.threshold(src, thresh, maxval, type)
参数含义:

  • src:输入图像(必须是单通道灰度图)
  • thresh:阈值(这里设为 140)
  • maxval:最大值(当像素值超过 / 低于阈值时,被赋予的值,这里设为 200)
  • type:阈值化类型(决定像素值如何根据阈值处理)
  • 返回值:retval是使用的阈值(这里即 140),dst是处理后的图像
cv2.THRESH_BINARY(二进制阈值化)
  • 规则
    像素值 > 阈值(140) → 设为 maxval(200)
    像素值 ≤ 阈值(140) → 设为 0(黑色)
  • 效果:图像被分为两部分,亮区域(>140)变为 200 的灰度,暗区域(≤140)变为纯黑。
cv2.THRESH_BINARY_INV(反二进制阈值化)
  • 规则:与THRESH_BINARY相反
    像素值 > 阈值(140) → 设为 0(黑色)
    像素值 ≤ 阈值(140) → 设为 maxval(200)
  • 效果:亮区域(>140)变黑,暗区域(≤140)变为 200 的灰度,是THRESH_BINARY的反转
cv2.THRESH_TRUNC(截断阈值化)
  • 规则
    像素值 > 阈值(140) → 设为阈值(140)
    像素值 ≤ 阈值(140) → 保持原始值不变
  • 效果:亮于阈值的区域被 “截断” 为阈值亮度(140),暗区域保持原样,图像整体对比度降低。
cv2.THRESH_TOZERO(零阈值化)
  • 规则
    像素值 > 阈值(140) → 保持原始值不变
    像素值 ≤ 阈值(140) → 设为 0(黑色)
  • 效果:暗于阈值的区域变黑,亮区域保持原样,突出图像中较亮的部分。
cv2.THRESH_TOZERO_INV(反零阈值化)
  • 规则:与THRESH_TOZERO相反
    像素值 > 阈值(140) → 设为 0(黑色)
    像素值 ≤ 阈值(140) → 保持原始值不变
  • 效果:亮于阈值的区域变黑,暗区域保持原样,突出图像中较暗的部分。
     

滤波器选择

# 打开视频文件
a = cv2.VideoCapture('dqvedio.mp4')  # 创建视频捕获对象,参数为视频文件路径

# 检查视频是否成功打开
if not a.isOpened():  # isOpened()方法返回布尔值,表示是否成功打开
    print("视频损坏,无法读取 ")
    exit()  # 退出程序

# 循环读取视频帧
while True:
    ref, fream = a.read()  # read()方法读取一帧,ref是布尔值(是否成功读取),fream是帧图像
    
    if not ref:  # 如果没有读取到帧(视频结束)
        break  # 退出循环

    # fream = cv2.cvtColor(fream,cv2.COLOR_BGR2RGB)  # 注释掉的代码:将BGR格式转为RGB格式
    
    # 显示原始视频帧
    cv2.imshow("fream", fream)  # 第一个参数是窗口名称,第二个是要显示的图像

    # 对当前帧添加椒盐噪声
    noise = add_peppersalt_noise(fream)
    cv2.imshow("noise", noise)  # 显示带噪声的帧
# 定义一个添加椒盐噪声的函数
def add_peppersalt_noise(image, n=10000):  # n是噪声点数量,默认10000个
    result = image.copy()  # 复制原图像,避免直接修改原图
    h, w = image.shape[:2]  # 获取图像的高度和宽度(shape[:2]取前两个维度)
    
    # 循环添加n个噪声点
    for i in range(n):
        x = np.random.randint(1, h)  # 随机生成x坐标(高度方向)
        y = np.random.randint(1, w)  # 随机生成y坐标(宽度方向)
        
        # 50%概率添加黑色点(椒噪声),50%概率添加白色点(盐噪声)
        if np.random.randint(0, 2) == 0:
            result[x, y] = 0  # 黑色点(BGR值都为0)
        else:
            result[x, y] = 255  # 白色点(BGR值都为255)
    
    return result  # 返回添加噪声后的图像
 # 对噪声图像进行高斯滤波
    GaussianB = cv2.GaussianBlur(noise, (3, 3), 1)  # 参数:源图像、卷积核大小、标准差
    cv2.imshow('GaussianBlur', GaussianB)  # 显示高斯滤波结果

    # 对噪声图像进行中值滤波
    medianB = cv2.medianBlur(noise, 3)  # 参数:源图像、卷积核大小(必须是奇数)
    cv2.imshow('medianBlur', medianB)  # 显示中值滤波结果

    # 等待6毫秒,若按下ESC键(ASCII码27)则退出循环
    if cv2.waitKey(6) == 27:
        break

# 释放资源
a.release()  # 释放视频捕获对象
cv2.destroyAllWindows()  # 关闭所有OpenCV创建的窗口

均值滤波 (cv2.blur)

blur1 = cv2.blur(noise, (3,3))  # 使用3x3的卷积核进行均值滤波
cv2.imshow('blur1', blur1)      # 显示滤波结果
cv2.waitKey(0)                  # 等待按键(按任意键继续)
  • 均值滤波是最简单的滤波方式,计算卷积核区域内所有像素的平均值作为中心像素的值
  • (3,3) 表示卷积核大小,数值越小,模糊效果越弱

更大核的均值滤波

blur2 = cv2.blur(noise, (63,63))  # 使用63x63的大卷积核
cv2.imshow('blur2', blur2)
cv2.waitKey(0)
  • 使用 63x63 的大卷积核会产生非常明显的模糊效果
  • 对比 blur1 和 blur2 可以直观看到卷积核大小对模糊程度的影响

归一化的方框滤波

boxFilter1 = cv2.boxFilter(noise, -1, (3,3), normalize=True)
cv2.imshow('boxFilter1', boxFilter1)
cv2.waitKey(0)
  • cv2.boxFilter是更灵活的方框滤波
  • normalize=True表示会对结果进行归一化(除以卷积核面积),此时效果等同于cv2.blur()
  • 参数-1表示输出图像的深度与输入图像相同

非归一化的方框滤波

boxFilter2 = cv2.boxFilter(noise, -1, (3,3), normalize=False)
cv2.imshow('boxFilter 2', boxFilter2)
cv2.waitKey(0)
  • normalize=False表示不进行归一化,直接计算卷积核区域内像素值的总和
  • 这种情况下容易出现像素值溢出(超过 255),导致图像出现白色斑块
  • 通常用于特殊场景,需要手动处理溢出问题
GaussianB = cv2.GaussianBlur(noise, (3,3), 1)  # 执行高斯滤波
cv2.imshow('GaussianBlur', GaussianB)          # 显示高斯滤波后的图像
cv2.waitKey(0)                                 # 等待任意按键(0表示无限等待)
函数原理

高斯滤波本质是 “加权平均”:对图像中每个像素,以它为中心构建一个「滤波核」(如代码中的 3×3 矩阵),再根据「高斯函数」计算核内每个位置的权重(中心像素权重最大,越往边缘权重越小,符合人眼对 “中心信息更重要” 的感知),最后用权重乘以对应像素值并求和,得到当前像素的新值。
这种加权方式能平滑图像、抑制噪声,同时最大程度保留图像的边缘细节(比普通均值滤波更柔和)。

medianB = cv2.medianBlur(noise, 3)             # 执行中值滤波
cv2.imshow('medianBlur', medianB)              # 显示中值滤波后的图像
cv2.waitKey(0)
cv2.destroyAllWindows()                        # 关闭所有显示窗口
函数原理

中值滤波与高斯滤波的 “加权平均” 不同,它是 “排序取中值”:对图像中每个像素,同样构建一个「奇数尺寸的滤波核」(如 3×3),将核内所有像素值按大小排序,取排序后的「中间值」作为当前像素的新值。
例如:核内像素值为 [10, 200, 30, 150, 50, 80, 250, 70, 60],排序后为 [10,30,50,60,70,80,150,200,250],取中间值 70 替换原中心像素值 —— 这种方式能直接 “剔除” 极端的噪声值(如 200、250 这类椒盐噪声)。


网站公告

今日签到

点亮在社区的每一天
去签到