• openCV第一篇


    文章目录

    前言:计算机眼中的图片 

    1. 图片的读取与显示

    1.1 图片的读取 

    1.2 显示的图片

    1.2.1 显示原始图片 

    1.2.2 灰度图

    1.3 BGR转换成灰度图、RGB

    2. 保存图片

    3. 视频的读取与显示

    4. 截取图像部分

    5. 颜色通道提取

    6. 边界填充

    7. 数值计算

    8. 图像融合

    9. 知识点总结*

    前言:计算机眼中的图片 

    • 计算机中图片由许多个像素点组成,如一个500x500的图片,表示长宽各由500个像素点组成。
    • 计算机中一个像素点的值在0-255表示该点亮度  0暗(黑)-255亮(白) 
    • 一张彩图通常是由RGB(red、green、blue)三个颜色通道所组成
    • 一个500x500的图片那他们的 RGB 矩阵也各是500x500。

    ac0ddb3b16ac461f8800a63b014ccb32.png

    上图我们将一个大的图片分割成许多如20x20的小图片,同理每个小图片它们的RGB矩阵也各自是20x20。

    注:opencv默认顺序不是RBG 而是 BGR。

    1. 图片的读取与显示

    1.1 图片的读取 

    1. import cv2
    2. img = cv2.imread('./data/abv.jpg')
    • img = cv2.imread('./data/abv.jpg') 

    比如我读入这样一张图片,命名为img

    9a095a8b15874db5a24eb370f9114921.png

    我们可以看到img是一个三维ndarray结构,内部数据类型dtype=unit8:

    fa66daf6f2e04378ad0a3e9fad429222.png

    • 三维:(1080,1920,3)表示高度、宽度、颜色通道个数(cv彩图BGR)
    • ndarray结构:数据类型dtype=unit8, 0-255。

    1.2 显示的图片

    1.2.1 显示原始图片 

    1. cv2.imshow('image',img) # 第一个参数表示窗口指定的名字 第二个为上方img
    2. cv2.waitKey(5000) # 等待时间  如果是5000则在5s后图片窗口自动关闭  0表示任意键关闭
    3. cv2.destroyAllWindows() # 时间一到关闭窗口

     ps: 图像的显示也可以是多个窗口

    • cv2.imshow('image',img) 自己给将要弹出的窗口起个名  再加入变量img
    • cv2.waitKey(5000) 等待时间  如果是5000则在5s后图片窗口自动关闭  0表示任意键关闭
    • cv2.destroyAllWindows() 时间一到关闭窗口

    为方便下面使用,我们自己定义一个函数cv_show():

    1. def cv_show(name,img):
    2. cv2.imshow(name,img)
    3. cv2.waitKey(0)
    4. cv2.destroyAllWindows()

    执行代码,弹出窗口,显示图片:

    cv_show('winName',img)

    9a095a8b15874db5a24eb370f9114921.png

    1.2.2 灰度图

    在之前的基础之上加入参数:cv2.IMREAD_GRAYSCALE 

    img2=cv2.imread('./data/abv.jpg',cv2.IMREAD_GRAYSCALE)  # cv2.IMREAD_COLOR
    • img2=cv2.imread('./data/abv.jpg',cv2.IMREAD_GRAYSCALE)  
      • cv2.IMREAD_GRAYSCALE  读取为灰度图,也可以写0。
      • cv2.IMREAD_COLOR           读取为彩图

    我们执行:

    cv_show('win2',img2) 

    78e49cf7f9334abbaf807391dcb6dc80.png可以看到该图片最终显示结果为二维(1080,1920) :

    ca9cba0adb754f20b82d6d042013260d.png

    ps: img.size 输出像素点的个数,可以看到同一张图片BGR彩图是灰度图的三倍。

    95b3b5d31c7c4a31b22b22353bfe81dc.png

    1.3 BGR转换成灰度图、RGB

    当然我们也可以把已经读取进来的BGR彩图转换成灰度图,或者转换为RGB。

    1. img2 = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    2. cv_show('win3',img2)
    • img2 = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) 
      • cv2.COLOR_BGR2RGB 将BGR格式转换成RGB
      • cv2.COLOR_BGR2GRAY 将BGR格式转换成灰度图片

    2. 保存图片

    cv2.imwrite('./data/grayPhoto.jpg',img2)
    • cv2.imwrite('./data/grayPhoto.jpg',img2)

    此时我的data文件夹下就多了一张刚刚处理好名为grayPhoto的灰度图。

    899d5d3076bb4e2ebbb5886343545a50.png

    3. 视频的读取与显示

    视频也是由图像组成的,每一帧都可以当作是一个静止的图像,把图像连在一起看着就像是一个视频了。 我们打游戏时,也是追求一些更高的帧率。

    vc = cv2.VideoCapture('./data/stu.mp4')
    • vc = cv2.VideoCapture('./data/stu.mp4')
    1. # 检查是否正确打开
    2. if vc.isOpened():
    3. open,frame = vc.read()
    4. else:
    5. open = Flase
    • vc.read()
      • 读取视频中的第一帧 ,再次执行vc.read()的话读取视频第二帧
      • 返回值中:第一个:布尔类型,能读进来就是True   第二个像是上面的img,这一帧图片的ndarray矩阵

    循环图片播放视频:

    1. while open:
    2. ret,frame = vc.read()
    3. if frame is None:
    4. break
    5. if ret == True:
    6. # 原本frame是(h,w,3)的BGR图片矩阵 经下方加入参数转换成黑白gray
    7. gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
    8. cv2.imshow('result',gray)
    9. # cv2.waitKey(num) 该图片显示时间/速度 自己可以找一个合适的值
    10. # 27指退出键ESC 退出窗口 当然也可以是 =='q'等
    11. if cv2.waitKey(20)&0xFF == 27:
    12. break
    13. vc.release()
    14. cv2.destroyAllWindows()

    注:视频放完 ret, frame = vc.read()返回False和None 再次进行循环无法播放视频,需要重新读取。

    • if cv2.waitKey(20)&0xFF == 27:
      • 不是新知识点了,表示每张图片等20毫秒,如果按ESC键直接退出。

    4. 截取图像部分

    我们上面介绍,img是一个ndarray矩阵,因此对其进行切片操作:

    1. pho = img[100:800,200:800] # 进行切片 高100到800 宽200到800
    2. cv_show('win2',pho)
    • pho = img[100:800,200:800]

    fa3f065b36d64fed8f9be0481322affc.png

    5. 颜色通道提取

    1. b,g,r = cv2.split(img)
    2. # b.shape g.shape r.shape 都为 (1080, 1920)

    执行

    cv_show('win3',g) # 或者填 b、r

    78e49cf7f9334abbaf807391dcb6dc80.png

    结果就是单通道图。

    如果我们想显示单一颜色,如红色:

    1. cur_img = img.copy()
    2. cur_img[:,:,0] = 0 # B不要了 设置为0
    3. cur_img[:,:,1] = 0 # G不要了 设置为0
    4. #cur_img[:,:,2] = 0 # R不要了 设置为0
    5. cv_show('winR',cur_img)

    2b3911f2428745658ca99b850eea7069.png

    6. 边界填充

    这个一般用于卷积,在图像周围填充一些像素。

    我们以这个图片为例:

    1. img = cv2.imread('./data/gd01.jpg')
    2. # img.shape 为 (300, 400, 3)
    3. cv_show('win1',img)

    f4320c38f6d647c684c59065fdaa50c2.jpeg

    在图片的上下左右填充50个像素,介绍5种方法: 

    1. top_size,bottom_size,left_size,right_size=(50,50,50,50)
    2. # 不同的填充方法 最后参数改个type值就行
    3. replicate = cv2.copyMakeBorder(img,top_size,bottom_size,left_size,right_size,borderType=cv2.BORDER_REPLICATE)
    4. reflect = cv2.copyMakeBorder(img,top_size,bottom_size,left_size,right_size,cv2.BORDER_REFLECT)
    5. reflect101=cv2.copyMakeBorder(img,top_size,bottom_size,left_size,right_size,cv2.BORDER_REFLECT_101)
    6. wrap = cv2.copyMakeBorder(img,top_size,bottom_size,left_size,right_size,cv2.BORDER_WRAP)
    7. constant = cv2.copyMakeBorder(img,top_size,bottom_size,left_size,right_size,cv2.BORDER_CONSTANT,value=0)
    1. plt.subplot(231),plt.imshow(img,'gray'),plt.title('ORIGINAL')
    2. plt.subplot(232),plt.imshow(replicate,'gray'),plt.title('REPLICATE')
    3. plt.subplot(233),plt.imshow(reflect,'gray'),plt.title('REFLECT')
    4. plt.subplot(234),plt.imshow(reflect101,'gray'),plt.title('REFLECT_101')
    5. plt.subplot(235),plt.imshow(wrap,'gray'),plt.title('WRAP')
    6. plt.subplot(236),plt.imshow(constant,'gray'),plt.title('CONSTANT')
    7. # 注matplotlib默认R G B本例只介绍边界填充
    8. plt.show()

    496a683aaecc451faf5818c736c4d6d8.png

    • cv2.BORDER_REPLICATE
      • 复制最边缘的像素
    • cv2.BORDER_REFLECT
      • 反射法对感兴趣的图像中的像素在两边进行复制 如fedcba|abcdefgh|hgfedcb 其中abcdefgh是图像"|"外的是填充内容
    • cv2.BORDER_REFLECT_101
      • 反射法,也就是以最边缘的像素为轴,对称,gfedcb|abcdefgh|gfedcba 上面是ba|ab 这个是bab。
    • cv2.BORDER_WRAP
      • 外包装法 如:cdefgh|abcdefgh|abcdefg。
    • cv2.BORDER_CONSTANT
      • 常量法,常数值value填充。

    7. 数值计算

    78fc17d7f1a44630a2c7855a1001adac.png

    由于是uint8类型最大255 超过相当于结果为 num%256了 

    我们使用以下方法保留最大值:

    cv2.add(img,img2)
    • cv2.add(img,img2)

    a3903457723941c786a7d8b1ca915878.png

    8. 图像融合

    效果如下:

    8220c58831cb4036a68f2453b6cf61ef.png

    我们导入宽高相同的2张图片:

    1. img = cv2.imread('./data/gd04.jpg')
    2. img2 = cv2.imread('./data/gd05.jpg')
    3. img3 = cv2.imread('./data/gd06.jpg')
    4. print(img.shape,img2.shape,img3.shape) # (281, 600, 3) (281, 600, 3) (337, 600, 3)

    如果大小不同 需要手动设置成一样的

    1. img3 = cv2.resize(img3,(600,281))
    2. # img3.shape (281, 600, 3)
    • img3 = cv2.resize(img3,(600,281))

    ps: cv2.resize()另一种操作

    img4 = cv2.resize(img3,(0,0),fx=2,fy=1)

    我们执行:

    1. res = cv2.addWeighted(img,0.6,img2,0.4,0)
    2. plt.imshow(res)
    • res = cv2.addWeighted(img,0.6,img2,0.4,0)

    0139f647a62343adbf6c29076b531589.png

    R = ax1 + bx2 + c  a、b为权重 c为偏置 这里意为在原亮度上变化多少

    9. 知识点总结*

    • 读取图片:
    1. import cv2
    2. img = cv2.imread('./data/abv.jpg')
    3. img2 = cv2.imread('./data/abv.jpg',cv2.IMREAD_GRAYSCALE)
    4. img3 = cv2.imread('./data/abv.jpg',cv2.IMREAD_COLOR)
    • 显示图片:
    1. def cv_show(name,img):
    2. cv2.imshow(name,img)
    3. cv2.waitKey(0)
    4. cv2.destroyAllWindows()
    • BGR转换成灰度图、RGB:
    1. img2 = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    2. img3 = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
    • 保存图片:
    cv2.imwrite('./data/grayPhoto.jpg',img2)
    • 视频的读取与显示:
    1. vc = cv2.VideoCapture('./data/stu.mp4')
    2. # 检查是否正确打开
    3. if vc.isOpened():
    4. open,frame = vc.read()
    5. else:
    6. open = Flase
    7. while open:
    8. ret,frame = vc.read()
    9. if frame is None:
    10. break
    11. if ret == True:
    12. # 原本frame是(h,w,3)的BGR图片矩阵 经下方加入参数转换成黑白gray
    13. gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
    14. cv2.imshow('result',gray)
    15. # cv2.waitKey(num) 该图片显示时间/速度 自己可以找一个合适的值
    16. # 27指退出键ESC 退出窗口 当然也可以是 =='q'等
    17. if cv2.waitKey(20)&0xFF == 27:
    18. break
    19. vc.release()
    20. cv2.destroyAllWindows()
    • 截取图片部分:
    pho = img[100:800,200:800]  # 进行切片 高100到800 宽200到800
    • 颜色通道提取:
    b,g,r = cv2.split(img)
    1. cur_img = img.copy()
    2. cur_img[:,:,0] = 0 # B不要了 设置为0
    3. cur_img[:,:,1] = 0 # G不要了 设置为0
    4. #cur_img[:,:,2] = 0 # R不要了 设置为0
    5. cv_show('winR',cur_img)
    • 边界填充:
    1. top_size,bottom_size,left_size,right_size=(50,50,50,50)
    2. # 不同的填充方法 最后参数改个type值就行
    3. replicate = cv2.copyMakeBorder(img,top_size,bottom_size,left_size,right_size,borderType=cv2.BORDER_REPLICATE)
    4. reflect = cv2.copyMakeBorder(img,top_size,bottom_size,left_size,right_size,cv2.BORDER_REFLECT)
    5. reflect101=cv2.copyMakeBorder(img,top_size,bottom_size,left_size,right_size,cv2.BORDER_REFLECT_101)
    6. wrap = cv2.copyMakeBorder(img,top_size,bottom_size,left_size,right_size,cv2.BORDER_WRAP)
    7. constant = cv2.copyMakeBorder(img,top_size,bottom_size,left_size,right_size,cv2.BORDER_CONSTANT,value=0)
    • 数值计算:
    cv2.add(img,img2)
    • 图像融合:
    1. img3 = cv2.resize(img3,(600,281))
    2. res = cv2.addWeighted(img,0.6,img2,0.4,0)

  • 相关阅读:
    【LeetCode算法系列题解】第66~70题
    html渲染优先级
    Spring中的jdbcTemplate模块操作数据库(MySQL)
    PDE求格林函数
    LCR 051. 二叉树中的最大路径和
    查看docker容器中java进程堆栈信息
    【网络服务&数据库教程】09 Rsync 实操
    面试(03)————多线程
    Node当中的事件循环
    SPARKSQL3.0-Optimizer阶段源码剖析
  • 原文地址:https://blog.csdn.net/suic009/article/details/126067063