• OpenCV:02基础知识和绘制图形


    OpenCV的色彩空间

    RGB和BGR

    最常见的色彩空间就是RGB,人眼也是基于RGB的色彩空间去分辨颜色的

    OpenCV默认使用的是BGRBGRRGB色彩空间的区别在于图片在色彩通道上的排列顺序不同

    显示图片时要注意适配图片的色彩空间和显示环境的色彩空间:比如传入的图片是BGR色彩空间,显示环境是RGB色彩空间,就会出现颜色混乱的情况
    在这里插入图片描述


    HSV,HSLYUV

    HSV(HSB)

    OpenCV用的最多的色彩空间就是HSV

    • Hue:色相,即色彩,如红色、蓝色,用角度来度量,取值范围为0°~360°,从红色开始按照逆时针方向计算,红色为0°,绿色为120°,蓝色为240°
    • Saturation:饱和度, 表示颜色接近光谱色的程度。一种颜色,可以看成是某种光谱色与白色混合的结果。其中光谱色所占的比例愈大,颜色接近光谱色的程度就愈高,颜色的饱和度也就愈高。饱和度高,颜色则深而艳。光谱色的白光成分为0,饱和度达到最高。通常取值范围为0%~100%,值越大,颜色越饱和。
    • Value(brightness): 明度. 明度表示颜色明亮的程度,对于光源色,明度值与发光体的光亮度有关;对于物体色,此值和物体的透射比或反射比有关。通常取值范围为0%(黑)到100%(白)。
      在这里插入图片描述
      为什么要使用HSV?

    方便OpenCV做图像处理.比如根据hue的值就可以判断背景颜色.


    HSL

    HSLHSV差不多

    • Hue: 色相
    • Saturation: 饱和度
    • Lightness: 亮度

    HSL在顶部是纯白的, 不管是什么颜色.

    HSLHSV的区别
    在这里插入图片描述

    在这里插入图片描述
    理解:
    在这里插入图片描述


    YUV

    YUV是一种颜色编码方法。常使用在各个视频处理组件中。 YUV在对照片或视频编码时,考虑到人类的感知能力,允许降低色度的带宽(因为我们人眼分不出太多的颜色,因此可以节约带宽)

    • Y”表示明亮度(Luminance或Luma),也就是灰阶值,以前的黑白电视就是只用Y调整灰度即可
    • U”和“V”表示的则是色度(Chrominance或Chroma),作用是描述影像色彩及饱和度用于指定像素的颜色。

    Y'UV的发明是由于彩色电视与黑白电视的过渡时期。

    Y'UV最大的优点在于只需占用极少的带宽。

    • 4:4:4表示完全取样。
    • 4:2:2表示2:1的水平取样,垂直完全采样。
    • 4:2:0表示2:1的水平取样,垂直2:1采样。
    • 4:1:1表示4:1的水平取样,垂直完全采样。

    在这里插入图片描述

    4Y只有——>2U或者2V


    颜色空间的转化

    关键API cv2.cvtColor()

    # 关键API cv2.cvtColor()
    import cv2
    
    # 定义一个回调函数callback——> 我们要使用trackbar滑块
    def callback(value):
        pass # 我们不需要功能实现 因此直接pass
    
    # 创建窗口
    cv2.namedWindow('color',cv2.WINDOW_NORMAL)
    cv2.resizeWindow('color',640,480)
    
    # 读取图片 ——> opencv读进来的格式默认是BGR的色彩空间
    img = cv2.imread('./cat.jpeg')
    
    # 定义颜色空间转化列表
    color_spaces = [
        # 记忆:所有颜色空间的转化都是以"COLOR"开头的 
        cv2.COLOR_BGR2RGBA , cv2.COLOR_BGR2BGRA ,# BGRA中的‘A’表示透明度
        cv2.COLOR_BGR2GRAY , cv2.COLOR_BGR2HSV ,
        cv2.COLOR_BGR2YUV
    ]
    
    # 设置一个trackbar滑块
    cv2.createTrackbar('trackbar' , 'color' , 0 , 4 , callback) # (trackbar的名字,在哪个窗口上实现,默认值,最大值)
    
    # 不停地循环展示窗口
    while True:
        # 获取trackbar的值 ——> 转换成索引(用于选择颜色空间转换的形式)
        index = cv2.getTrackbarPos('trackbar','color') # (trackbar的名字,窗口的名字)
        
        # 进行颜色空间转化 ——> 把我们的img图片转换成对应的色彩
        cvt__img = cv2.cvtColor( img , color_spaces[index] )
    
        # 展示图片
        cv2.imshow('color' , cvt__img)
        
        # 退出的条件
        key = cv2.waitKey(1)
        if key == ord('q') or key == ord('Q'):
            break
            
    # 消除窗口
    cv2.destroyAllWindows()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    OpenCV的一种重要数据结构——Mat

    Mat介绍

    Mat是OpenCV在C++语言中用来表示图像数据的一种数据结构,在python中转化为numpy的darray

    • Mat由指针hearder和数据data组成

    在这里插入图片描述


    Mat拷贝

    在python中Mat数据对应numpy的ndarray,使用numpy提供的深浅拷贝方法可以实现对Mat的拷贝

    # 关于深浅拷贝
        # 浅拷贝:仅仅是复制出一个“指针”,共同指向一份data数据 ——> data数据发生改变,浅拷贝的数据也会改变
        # 深拷贝:完全复制出一份和原始数据一样的数据(包括data)——> data数据发生改变,深拷贝的数据不会发生改变!
        
    # 因为在python中,图片数据已经包装成ndarray,而非mat
        # 因此对ndarray的深浅拷贝 ——> 就是对mat的深浅拷贝
        
    import cv2
    import numpy as np
    
    cv2.namedWindow('img',cv2.WINDOW_NORMAL)
    cv2.resizeWindow('img',480,640)
    
    # 读入图片
    img = cv2.imread('./cat.jpeg')
     
    # 浅拷贝
    img2 = img.view() # 其底层数据的内存地址是一样的,仅仅是名字不一样而已
    
    # 深拷贝
    img3 = img.copy() 
    
    # 改变图片中某个位置的颜色,便于观察深浅拷贝结果
    img[10:100,10:100] = [0,0,255] # 把img图像上[10:100,10::100]的位置颜色改为红色[0,0,255]
    
    # 展示图片 ——> 我们让图片一起显示出来 np.hstack()使图像横向堆叠 ;np.vstack()使图像纵向堆叠
    cv2.imshow( 'img' , np.hstack( (img,img2,img3) ) )
    
    # 退出的条件
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    结果:
    在这里插入图片描述

    我们发现前两张图片的颜色给改了,而最后一张图片的颜色没有被修改——> 因为前两个是浅拷贝,所以它们的底层数据是一样的,而最后一个是深拷贝,是一份独立的数据


    访问图像(Mat)的属性

    opencv的Mat在python中已经转换成了ndarray,通过ndarray的属性即可访问Mat图像的属性

    import cv2
    import numpy as np
    
    img = cv2.imread('./cat,jpeg')
    
    # shape 属性中包含了三个信息
    # 高度、长度、通道数
    print(img.shape)
    
    # 图像占用空间计算
    # 高度×长度×通道数
    print(img.size)
    
    # 图像中每一个图像的位深
    print(img.dtype)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    图像通道的分割和合并

    • split(mat)分割图像的色彩通道
    • merge((ch1,ch2,ch3......))融合多个色彩通道
    # 图像的分割与融合
    import cv2
    import numpy as np
    
    # 导入一个全黑的图片
    img = np.zeros((200,200,3),np.uint8)
    
    # 分割通道 ——> 得到原图中三个通道的值
    b , g , r = cv2.split(img)
    
    # 修改颜色:分别改变b蓝色通道和g绿色通道的一小段数据
    b[10:100 , 10:100] = 255
    g[10:100 , 10:100] = 255
    
    # 合并色彩通道 ——> 相当于创建一个新的图片(注意括号内要写元组,并且要按照BGR的顺序写入)
    img2 = cv2.merge((b,g,r))
    
    cv2.imshow('img',np.hstack((img,img2)))
    
    # 我们也顺便展示一下b,g修改后的值,方便理解
    cv2.imshow('b_and_g',np.hstack((b,g)))
    
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    结果:
    先看色彩通道b色彩通道g修改后的样子(我们将两幅图横向拼接在了一起)
    在这里插入图片描述
    由于我们创建的是全黑的图img = np.zeros((200,200,3),np.uint8),因此图像是全黑的,而我们把 [10:100 , 10:100] 区域内的值拉到最大,因此该区域就变白了

    对应在新生成的图上
    在这里插入图片描述
    左半部分是修改前:全黑

    右半部分是将修改后的色彩通道重新叠加:由于我们把b蓝色通道g绿色通道的部分值拉满了,对应蓝色和绿色的合成色即为上图的颜色


    绘制图形

    利用OpenCV提供的绘制图形API可以轻松地在图像上绘制各种图形,比如直线、矩形、圆、椭圆等图形

    绘制直线

    line(img, pt1, pt2, color, thickness, lineType, shift) 画直线

    • img::在哪个图像上画线
    • pt1, pt2: 开始点, 结束点. 指定线的开始与结束位置
    • color::颜色
    • thickness: 线宽
    • lineType: 线型.线型为-1, 4, 8, 16, 默认为8
    • shift: 坐标缩放比例.
    # 绘制直线
    import cv2
    import numpy as np
    
    # 创建一个纯黑的背景图 用于画图
    img = np.zeros((480,640,3),np.uint8)
    
    # 画一条直线:line(img, pt1, pt2, color, thickness, lineType, shift) ——> 位置参数pt1、pt2,颜色color必须为元组形式
    cv2.line(img,(10,20),(300,400),(0,0,255),5,4)
    cv2.line(img,(10,20),(400,700),(0,0,255),5,18)  # lineType越小,线的锯齿状越明显,且值必须是2的幂次方
    
    # 展示图片
    cv2.imshow('draw',img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    结果:

    在这里插入图片描述


    绘制矩形

    rectangle(img, pt1, pt2, color, thickness, lineType, shift) 参数同上— 画矩形

    # 绘制矩形
    import cv2
    import numpy as np
    
    # 创建一个纯黑的背景图 用于画图
    img = np.zeros((480,640,3),np.uint8)
    
    # 画一个矩形:(和画直线的参数一样
    cv2.rectangle(img,(80,200),(300,400),(0,0,255),5,4)
    cv2.rectangle(img,(100,200),(200,300),(0,255,255),5,18)  # lineType越小,线的锯齿状越明显,且值必须是2的幂次方
    
    # 展示图片
    cv2.imshow('draw',img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    结果:

    在这里插入图片描述


    绘制圆

    circle(img, center, radius, color[, thickness[, lineType[, shift]]]) :中括号内参数表示可选参数

    • center:圆形坐标
    • radius:半径
    # 绘制圆
    import cv2
    import numpy as np
    
    # 创建一个纯黑的背景图 用于画图
    img = np.zeros((480,640,3),np.uint8)
    
    # 画一个圆:需要传入圆心、半径
    cv2.circle(img,(320,240),50,(0,0,255)) # 中括号[]内的参数可以不写,有默认值
    
    # 展示图片
    cv2.imshow('draw',img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    绘制椭圆

    关键API:ellipse(img, center, axes, angle, startAngle, endAngle, color[, thickness[, lineType[, shift]]])

    • img:图像
    • center:椭圆圆心 ——> 用元组表示
    • axes:是轴axis的复数,表示横轴X,纵轴Y的长短——>X在前Y在后 (用元组表示)
    • angle:椭圆的角度(顺时针偏转)
    • startAngle&endAngle:控制显示的角度,如果是0,360表示显示整个椭圆(椭圆是从右顶点开始顺时针画的)

    在这里插入图片描述

    # 绘制椭圆
    import cv2
    import numpy as np
    
    # 创建一个纯黑的背景图 用于画图
    img = np.zeros((480,640,3),np.uint8)
    
    # 画一个圆:需要传入圆心、半径
    # ellipse(img, center, axes, angle, startAngle, endAngle, color[, thickness[, lineType[, shift]]])
    # ellipse(img, 中心点, 长宽的一半, 角度, 从哪个角度开始, 从哪个角度结束,...)
    cv2.ellipse(img,(320,240),(100,50),0,0,360,(0,0,255)) # 中括号[]内的参数可以不写,有默认值
    
    # 展示图片
    cv2.imshow('draw',img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    角度为0°,从0-360
    在这里插入图片描述

    角度为0°,从0-180

    在这里插入图片描述

    角度为45°,从0-360
    在这里插入图片描述


    绘制多边形

    polylines(img, pts, isClosed, color[, thickness[, lineType[, shift]]]) 画多边形

    • pts:points的简写,是多边形的点集,并且这个点集必须是有符号32位的整形
    • isClosed:图形是否闭合
    # 绘制多边形
    import cv2
    import numpy as np
    
    # 创建一个纯黑的背景图 用于画图
    img = np.zeros((480,640,3),np.uint8)
    
    # 绘制多边形
    #polylines(img, pts, isClosed, color[, thickness[, lineType[, shift]]]) 画多边形
    pts = np.array([(300,10),(150,100),(450,100)],np.int32) # 创建多边形的点集pts
    cv2.polylines(img,[pts],True,(0,0,255),5,16) # 注意参数格式!!!pts要用"[]"
    
    # 展示图片
    cv2.imshow('draw',img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    结果:
    曲线闭合isClosed = True
    在这里插入图片描述
    曲线闭合isClosed = False
    在这里插入图片描述

    绘制一个填充的多边形

    fillPoly(img, pts, color[, lineType[, shift[, offset]]]) 画填充多边形(函数名P要大写!)

    # 绘制多边形
    import cv2
    import numpy as np
    
    # 创建一个纯黑的背景图 用于画图
    img = np.zeros((480,640,3),np.uint8)
    
    # 绘制多边形
    #polylines(img, pts, isClosed, color[, thickness[, lineType[, shift]]]) 画多边形
    pts = np.array([(300,10),(150,100),(450,100)],np.int32) # 创建多边形的点集pts
    cv2.fillPoly(img,[pts],False,(0,0,255),5,16) # 注意参数格式!!!pts要用"[]"
    
    # 展示图片
    cv2.imshow('draw',img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在这里插入图片描述


    绘制文本

    putText(img, text, org, fontFace, fontScale, color[, thickness[, lineType[, bottomLeftOrigin]]]) 绘制文本
    其中:

    • text :要绘制的文本
    • org :文本框在图片中的左下角坐标
    • fontFace :字体类型(即字体)
    • fontScale :字体大小
    # 绘制多边形
    import cv2
    import numpy as np
    
    # 创建一个纯黑的背景图 用于画图
    img = np.zeros((480,640,3),np.uint8)
    
    # 绘制文本putText(img, text, org, fontFace, fontScale, color[, thickness[, lineType[, bottomLeftOrigin]]]) 绘制文本
    cv2.putText(img, 'Hello OpenCV' , (50,400) , cv2.FONT_HERSHEY_COMPLEX , 2,[0,0,255])# 注意!opencv只能显示英文字体-没有中文字体的包
    
    # 展示图片
    cv2.imshow('draw',img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述

    如果想在系统图片上显示文本,则只用修改img = np.zeros((480,640,3),np.uint8) # 创建全黑图为——> 导入系统中的图img = cv2.imread('./cat.jpeg')即可


    如果我们想在图片上展示中文字体,由于OpenCV没有方法来绘制中文,需要借助其他的包 ——> pillow

    该方法和opencv没啥关系…

    # 安装pillow
    import cv2
    import numpy as np
    from PIL import ImageFont, ImageDraw, Image
    
    # 生成一张纯白的图片
    img = np.full((200, 200, 3), fill_value=255, dtype=np.uint8)
    
    # 定义字体路径(有点多余说实话...) ——> 在我们的电脑C盘-Windows-Fonts-找到对应的文件拷贝到当前目录下
    font_path = 'msyhbd.ttc' # 拷贝的字体文件
    
    # 导入字体文件
    my_font = ImageFont.truetype(font_path, 30) # 30为字体大小fontscal
    
    # 创建一个pillow的图片
    img_pil = Image.fromarray(img)
    
    # 绘制该图片
    draw = ImageDraw.Draw(img_pil)
    
    # 利用draw绘制中文
    draw.text((10, 150), '绘制中文', font=my_font, fill=(0, 255, 0, 0))
    
    # 将格式重新变回ndarray,这样才能用opencv的工具cv2.imshow去显示
    img = np.array(img_pil)
    
    # 中文会显示问号
    cv2.putText(img, '中文', (10, 100), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 1)
    
    cv2.imshow('img', img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    在这里插入图片描述

  • 相关阅读:
    贯标还是ISO认证,哪个更重要?
    【C语言】宏
    多目标追踪——【Transformer】MOTR: End-to-End Multiple-Object Tracking with TRansformer
    <基础训练>旅行家的预算(贪心算法)
    第75步 时间序列建模实战:多步滚动预测 vol-3(以决策树回归为例)
    力扣(LeetCode)20. 有效的括号(C++)
    神经网络算法图像识别,神经网络算法图怎么看
    Flume监听多个文件目录,并根据文件名称不同,输出到kafka不同topic中
    【老生谈算法】matlabBOOST电路的设计与仿真——BOOST电路
    World Tour Finals 2019 D - Distinct Boxes 题解
  • 原文地址:https://blog.csdn.net/m0_59466249/article/details/125487352