OpenCV - day01 BasicOperation

256 阅读9分钟

一、图像处理的一般需要导入的包的集合

import cv2
import matplotlib
import matplotlib.pyplot as plt #取别名(用于绘图展示)
import numpy as np #取别名,下面是notepad专用,立即显示图像
%matplotlib inline 

二、图片的读写

1. 读取图像

img = cv2.imread('tgcf.png') 
# opencv的默认读取方式是BGR(从上至下),若要读取灰度图,则应设置参数cv2.IMREAD_GRAYSCALE
# 彩图的参数为cv2.IMREAD_COLOR

2. 输出图像

  • N维阵列:灰度图一般是一维;
  • 彩色图(BGR)一般是三维;
img # 三层
array([[[255, 254, 253],
        [255, 254, 253],
        [255, 254, 253],
        ...,
        [255, 255, 255],
        [255, 255, 255],
        [255, 255, 255]],

       ...,

       [[255, 254, 253],
        [255, 254, 253],
        [255, 254, 253],
        ...,
        [255, 254, 253],
        [255, 254, 253],
        [255, 254, 253]]], dtype=uint8)

3. 使用imwrite保存图片

  • 前一参数为路径+名称
  • 后一参数为需要保存的对象
cv2.imwrite('Graytgcf.png',img)
True
cv_show('Graytgcf',cv2.imread('Graytgcf.png'))

4. 读取、播放视频

 import cv2
 import matplotlib
 import matplotlib.pyplot as plt #取别名(用于绘图展示)
 import numpy as np #取别名,下面是notepad专用,立即显示图像
 %matplotlib inline 
 vdo = cv2.VideoCapture('dfh.mp4')
 # 检查文件是否打开正确
 if vdo.isOpened():
     open, frame = vdo.read()
 else:
     open = False
 while open: # 若打开正常
     ret, frame = vdo.read() # 
     if frame is None:
         break
     if ret == True:
         # gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
         # cv2.imshow('result',frame) #可以直接使用frame进行原彩显示
         gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
         cv2.imshow('result',gray) 
         # 如果不清楚键盘上对应的ASCII码,则可使用ord('')来获取对应字符的ASCII码
         if cv2.waitKey(10) & 0xFF == 27: ##27是退出键Esc
             break
 vdo.release() #释放视频
 cv2.destroyAllWindows()

5. 创建图片显示端口(可创建多个)

  • 注意waitKey值的设置
cv2.imshow('Test',img)
#等待时间
cv2.waitKey(0) #设置以ms为单位的等待时间,0表示任意键停止(按下任意键就停止等待)
cv2.destroyAllWindows()

6. 解决名称乱码:先编码为GBK,再解码为UTF-8


def rename(name):
    return name.encode('gbk').decode('utf-8',errors='ignore')
# ①尚未解决 编码问题

#cv_show(rename('壁纸'),cv2.imread('tgcf.png'))#不要忘了imread是cv2内置方法

三、灰度图操作

1.读取灰度图并显示其阵列

img2 = cv_readgray('tgcf.png')
cv_show('GRAY',img2) #可以将衣服彩色图像以灰度输出

2. 自定义读取为灰度图的函数和显示函数

def cv_readgray(imgname): #(多此一举)根据图片名打开图片,改为读取灰度图
    return cv2.imread(imgname,cv2.IMREAD_GRAYSCALE)
def cv_show(name, img): #定义函数用于显示图片,此处name为窗口名,img为cv2调用imread方法的返回值
    cv2.imshow(name,img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

3. 查看灰度图属性

img2 #注意看数组层数仅有一层
array([[254, 254, 254, ..., 255, 255, 255],
       [254, 254, 254, ..., 255, 255, 255],
       [254, 254, 254, ..., 255, 255, 255],
       ...,
       [254, 254, 254, ..., 254, 254, 254],
       [254, 254, 254, ..., 254, 254, 254],
       [254, 254, 254, ..., 254, 254, 254]], dtype=uint8)
img2.shape #仅有一个颜色通道时,不会显示 1
(1880, 854)

四、查看图像属性及切片

1. 显示图片对象的各项属性

  • shape
  • size
  • type()
  • ntype()
img.shape #作为CV2的实例对象,查看其尺寸,3表示三个通道,即BGR方式
(1880, 854, 3)
img2.size
1605520
type(img2) #显示对象类型,N维数组
numpy.ndarray
img2.dtype #显示对象数据类型
dtype('uint8')

2. 利用切片读取图片部分(ROI的提取)

  • 注意图片数组的排列方式: 以左上角为原点,x轴正方向向右,y轴正方向向下
#利用Python切片来读取部分图像数据,三个参数(起始点,终止点,步长)
# 利用步长可以达到模糊效果——失真
cv_show('SliceDisplay',img2[0:-1:4,0:-1:4])
cv_show('SliceDisplay',img2[940:-1,450:-1]) # 注意图片截取的方向,

3. 颜色通道的提取

  • 0表示黑色
  • 255表示白色
  • OpenCV是 8 比特表示法,也就是说灰度区间为[0, 255]
sys = cv2.imread('sys.jpg')
b, g, r = cv2.split(sys)
b
array([[ 0,  2, 15, ..., 61, 70, 62],
       [ 6, 13, 29, ..., 63, 64, 54],
       [ 7, 15, 32, ..., 57, 53, 54],
       ...,
       [ 8,  5, 13, ..., 63, 68, 56],
       [ 0,  3, 14, ..., 59, 68, 61],
       [ 4, 12, 18, ..., 54, 64, 59]], dtype=uint8)
g
array([[ 9, 11, 24, ..., 45, 54, 46],
       [15, 22, 38, ..., 50, 48, 41],
       [16, 24, 41, ..., 46, 40, 43],
       ...,
       [ 8,  5, 13, ..., 68, 72, 60],
       [ 0,  3, 15, ..., 64, 71, 64],
       [ 4, 12, 19, ..., 59, 67, 62]], dtype=uint8)
r
array([[ 0,  1, 14, ..., 62, 71, 63],
       [ 5, 12, 28, ..., 66, 65, 57],
       [ 6, 14, 31, ..., 62, 56, 59],
       ...,
       [24, 21, 29, ..., 71, 77, 65],
       [15, 19, 29, ..., 67, 75, 68],
       [20, 28, 33, ..., 62, 71, 66]], dtype=uint8)
b.shape #bgr每个变量都是单通道了
(540, 720)

五、图像通道

1. 显示单个通道的图片信息

  • 这三个通道的元素值只是对应的通道的灰度值,不会显示颜色
  • 衡量值是对应色光的光强
cv_show('RED',r)
cv_show('Green',g)
cv_show('Blue',b)

2. 三个通道的的过滤显示仍需在三维数组中进行

  • 两个冒号分离三个维度
# 只显示红色通道
img0 = sys.copy()
# 这里的 , 起到了分割维度的作用,其实还可以简写: img0[...:0] ,就会自动补齐了。
# 前两维都是对应通道的坐标
img0[:,:,0] = 0 #B
img0[:,:,1] = 0 #G
cv_show('R',img0)
# 只显示绿色通道
img0 = sys.copy()
img0[:,:,0] = 0 #B
img0[:,:,2] = 0 #R
cv_show('G',img0)
# 只显示蓝色通道
img0 = sys.copy()
img0[:,:,1] = 0 #G
img0[:,:,2] = 0 #R
cv_show('B',img0)

3. 三个通道合并

  • merge的用法
_img = cv2.merge((b, g, r)) ## merge必须传入元组
cv_show('Test',_img) #不能直接用imshow()输出显示,另外还要设置waitKey与destroyAllWindows信息
---------------------------------------------------------------------------

NameError                                 Traceback (most recent call last)

F:\Temp1/ipykernel_4296/1515998152.py in <module>
      1 _img = cv2.merge((b, g, r)) ## merge必须传入元组
----> 2 cv_show('Test',_〇img) #不能直接用imshow()输出显示,另外还要设置waitKey与destroyAllWindows信息


NameError: name '_〇img' is not defined

六、图像基本操作

1. 边界填充

  • 卷积:对图像进行特征提取
  • 参数说明:(那么四个角是如何复制的呢?)
    • BORDER_REPLICATE:直接复制边缘像素

    • BORDER_REFLECT:镜面反射 —— hgfedcba|abcdefgh|hgfedcba(会复制边缘像素)

    • BORDER_REFLECT_101:以最边缘元素为轴,不会复制最边缘像素—— hgfedcb|abcdefgh|gfedcba

    • BORDER_WRAP:外包装法—— cdefgh|abcdefgh|abcdef,区内部像素向外平移

    • BORDER_CONSTANT:常数填充,需要设置value值

#初始化边界填充的边界大小,定义成tuple不能赋值
top, bottom, left, right = (100, 100, 100, 100) 

replicate = cv2.copyMakeBorder(img, top, bottom, left, right, borderType = cv2.BORDER_REPLICATE)
reflect = cv2.copyMakeBorder(img, top, bottom, left, right, borderType = cv2.BORDER_REFLECT)
reflect101= cv2.copyMakeBorder(img, top, bottom, left, right, borderType = cv2.BORDER_REFLECT_101)
wrap = cv2.copyMakeBorder(img, top, bottom, left, right, borderType = cv2.BORDER_WRAP)
constant = cv2.copyMakeBorder(img, top, bottom, left, right, borderType = cv2.BORDER_CONSTANT, value = 0)

import matplotlib.pyplot as plt
plt.subplot(351), plt.imshow(img,'gray'), plt.title('ORIGINAL')
plt.subplot(352), plt.imshow(replicate,'gray'), plt.title('replicate')
plt.subplot(353), plt.imshow(reflect,'gray'), plt.title('reflect')
plt.subplot(354), plt.imshow(reflect101,'gray'), plt.title('reflect101')
plt.subplot(355), plt.imshow(wrap,'gray'), plt.title('wrap')
plt.subplot(356), plt.imshow(constant,'gray'), plt.title('constant')
(<AxesSubplot:title={'center':'constant'}>,
 <matplotlib.image.AxesImage at 0x20c3c52dc70>,
 Text(0.5, 1.0, 'constant'))

output_49_1.png

2. 数值计算

  • 加法:
    • 常数:所有阵列像素都会加上对应常数

      • 注意:若常数加法所得结果超过了 n 比特表示法的最大值也即大于 (2^n-1) 则会将结果取余。也即若为 8 比特表示法,运算结果为509,则会将509 % 255 = 254 填入
    • 两个尺寸匹配的图像相加:对应阵列元素相加,

      • 应该注意:超出部分直接取最大值,不会进行取余(上例则取255)
img_sys = cv2.imread('sys.jpg')
img_tgcf = cv2.imread('tgcf.png')
img_sys[:5,:,0] #只打印B通路的前5行
array([[ 0,  2, 15, ..., 61, 70, 62],
       [ 6, 13, 29, ..., 63, 64, 54],
       [ 7, 15, 32, ..., 57, 53, 54],
       [ 4,  8, 18, ..., 46, 44, 64],
       [16,  9,  7, ..., 45, 43, 65]], dtype=uint8)
img_sys2 = img_sys + 255 ##可以看出加法就是所有阵列元素都加
img_sys2[:5,:,0] 
array([[255,   1,  14, ...,  60,  69,  61],
       [  5,  12,  28, ...,  62,  63,  53],
       [  6,  14,  31, ...,  56,  52,  53],
       [  3,   7,  17, ...,  45,  43,  63],
       [ 15,   8,   6, ...,  44,  42,  64]], dtype=uint8)
(img_sys2 + img_sys)[:5,:,0]
array([[255,   3,  29, ..., 121, 139, 123],
       [ 11,  25,  57, ..., 125, 127, 107],
       [ 13,  29,  63, ..., 113, 105, 107],
       [  7,  15,  35, ...,  91,  87, 127],
       [ 31,  17,  13, ...,  89,  85, 129]], dtype=uint8)

3. 图像融合

img_sys + img_tgcf #宽长不同不能相加,必须进行调整
---------------------------------------------------------------------------

ValueError                                Traceback (most recent call last)

F:\Temp1/ipykernel_4296/2369869610.py in <module>
----> 1 img_sys + img_tgcf 


ValueError: operands could not be broadcast together with shapes (540,720,3) (1880,854,3) 
img_tgcf.shape
(1880, 854, 3)
img_sys = cv2.resize(img_sys,(854, 1880)) #利用CV模块中的resize方法调整大小,注意传入参数的顺序,宽在前,而shape是宽在后
img_sys + img_tgcf
array([[[255,   7, 253],
        [  0,   9, 254],
        [  9,  17,   6],
       
       ...,
        
        [ 63,  47,  64],
        [ 67,  51,  68],
        [ 61,  45,  62]],
       
       ...,
        
        [ 58,  61,  63],
        [ 62,  64,  68],
        [ 58,  60,  63]],

      
        [ 57,  60,  62],
        [ 62,  64,  67],
        [ 58,  60,  63]]], dtype=uint8)

4. resize的用法

  • resize(img, (width, length)):直接指定宽长

  • resize(img, (0, 0), fx = n, fy = n):传入(0, 0)表示不直接指定宽长,后面参数是宽长的放缩比例。

res = cv2.resize(img_sys, (0, 0), fx = 3, fy = 1) #参数含义依次为:图像对象、不给予具体数值、横轴倍数、纵轴倍数
plt.imshow(res)
<matplotlib.image.AxesImage at 0x2090800e790>






output_59_1.png

res = cv2.resize(img_sys, (0, 0), fx = 1, fy=3)
cv_show('Test', res) #注意,若我们要在当前界面显示而非弹出新窗口,则应调用plt模块
plt.imshow(res)
<matplotlib.image.AxesImage at 0x2090adc46d0>




output_61_1.png

img_tgcf = cv2.imread('tgcf.png')
res = cv2.resize(img_tgcf, (0, 0), fx = 0.5, fy= 0.5) 
plt.imshow(res)
<matplotlib.image.AxesImage at 0x2090ae0ca00>




output_62_1.png

5. 图像融合公式

  • New = α * img1 + β * img2 + b
    • 阿尔法和贝塔都是图片所占的权值,取值范围为 0-1 ,取值越大代表在图片中占比越大
    • b是偏移量,对整体亮度的改变
  • addWeighted(img1, α, img2, β, b)
img_tgcf = cv2.imread('tgcf.png')
img_tgcf = cv2.resize(img_tgcf, (0,0) ,fx=0.4, fy=0.4)
cv_show('Half',img_tgcf)
img_tgcf.shape
img_sys = cv2.resize(img_sys, (342, 752))
cv_show('Adjust',img_sys)
res = cv2.addWeighted(img_tgcf, 0.5, img_sys, 0.5, 0)
plt.imshow(res)
<matplotlib.image.AxesImage at 0x209083a7280>
cv_show('Mixed',res)

output_66_1.png