opencv图像处理基础

图像类型

应用方面

  1. 自然图像
  2. 医学图像
  3. SAR 图像(Synthetic Aperture Raddar)—— 合成孔径雷达图像/遥感图像

图像的形式

  1. 彩色图像
  2. 灰度图像
  3. 二值图像

图像的获取

获取方式

  1. 网页上下载(拷贝)—— 自然图像
  2. numpy 数组生成图片

类型为:dtype = numpy.uint8(不然只是创建数组而不是图像)

numpy.zeros( shape )
numpy.ones( shape )
numpy.array( )

图像的四个属性

  1. img.shape : 返回元组,其值是图像的高度和宽度(即数组的行和列);彩色图像有第三个参数为 BGR 3通道
  2. type(img) : numpy.ndarray ( numpy 数组)
  3. img.dtype : np.uint8 ( 0-255 为 256 个灰度等级,彩色图像即每个通道范围在 0-255)
  4. img.size : 高度*宽度(像素点);若为彩色图像即 高度*宽度*3

图像基础操作

Opencv图像存储方式为 Numpy 数组,其数据类型为 numpy.uint8 ( 8个字节 )

读,写,显示图像

读取图像

Opencv 中的 imread( ) 函数用于将文件中的图像读入内存,该函数支持各种静态图像文件格式(BMP , PNG , JPEG , JPG , TIFF——用于保存分辨率较大的图)

基本格式:
img = cv2.imread('filename',flags)

函数参数说明:

filename:读取图像的文件路径和文件名 ( 路径中使用双斜杠 )
flags:读取图片的方式,可选项如下:

cv2.IMREAD_COLOR(1):始终将图像转换为 3 通道BGR彩色图像,默认方式(Opencv 默认的图像格式为BGR,即 3 通道图像数组的 3 个维度,依次为 B ( 蓝色 ),G ( 绿色 ),R ( 红色 ) 通道的像素)

cv2.IMREAD_GRAYSCALE(0):始终将图像转换为单通道灰度图像

cv2.IMREAD_UNCHANGED(-1):按原样返回加载的图像(使用Alpha通道)

cv2.IMREAD_ANYDEPTH(2):在输入具有相应深度时返回16位/ 32位图像,否则将其转换为8位

cv2.IMREAD_ANYCOLOR(4):以任何可能的颜色格式读取图像
返回值 retval:读取的 OpenCV 图像,np.array 多维数组

写图像(保存图像)

Opencv 中的 imwrite ( ) 函数用于将 NumPy 数组中保存的图像写入文件

基本格式:
cv2.imwrite('filename',img)

函数参数说明:

filename:保存图像的路径,保存的图像名字及类型(后缀名可与读取的图像文件不一致——对NumPy 数组压缩的方式不同)
img:读取的图像文件,也可以是读取的视频中的一帧 frame(读取到的 NumPy 数组)

显示图像

Opencv 中的 imshow ( ) 函数用于在窗口显示图像

基本格式:
cv2.imwshow('filename',img)

函数参数说明:

filename:显示窗口名
img:读取的图像文件,也可以是读取的视频中的一帧 frame(读取到的 NumPy 数组)

代码展示:

import cv2
import numpy as np

img1 = cv2.imread('D:\\opencv\\image\\08_wlq.png',1) #以彩色形式读取

cv2.imshow('duck_color',img1) #显示图像

cv2.waitKey(0) #等待按键跳转到下一语句(该句是按任意按键继续)
cv2.imwrite('save_duck_1.png',img1) #默认保存工程文件夹路径

img2 = cv2.imread('D:\\opencv\\image\\08_wlq.png',0) #以灰度形式读取
cv2.imshow('duck_gray',img2)
cv2.waitKey(0)
cv2.imwrite('save_duck_2.png',img2)

读写显示视频(示例代码)

import cv2

vc = cv2.VideoCapture('C:\\Users\\Administrator\\Desktop\\Minions_banana.mp4')    #创建vidoe对象

buer,frame = vc.read()  #buer是一个布尔值,读取视频成功为 1,frame为读入的一帧

while buer:
    gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)  #灰度读取
    cv2.imshow('stn',gray)
    buer,frame = vc.read()
    key = cv2.waitKey(25)   #延迟时间
    if key == 27:  #按esc键结束
        break
vc.release()  #关闭视频
cv2.destroyAllWindows()

色彩空间的改变

彩色图像变为灰度图像(BGR 转 GRAY)

  1. dst = cv2.cvtColor(src,cv2.COLOR_BGR2GRAY)
  2. cv2.imread(path,0) 以灰度形式读入
  3. 拆分通道 ( 每个单独的通道都是一个灰度图像 )

扩展:

利用函数原理实现灰度图的转换

cv2.COLOR_BGR2GRAY 的实现原理 :
Gray = 0.299R + 0.587G + 0.114B (加权求和)

Opencv 中的 cv2.cvtColor ( ) 函数用于转换色彩空间类型 NumPy 数组中保存的图像写入文件

基本格式:
dst = cv2.cvtColor(src,code[,dstcn])

函数参数说明:

dst:表示转换后的图像
src:表示转换前的图像
code:表示色彩空间类型转换码
dstCn:表示目标图像的通道数

常用的空间类型转换码:
cv2.COLOR_BGR2RGB:将BGR色彩空间转换为RGB色彩空间
cv2.COLOR_BGR2GRAY:将BGR色彩空间转换为GRAY色彩空间(灰度)

示例代码

img = cv2.imread('C:\\Users\\Administrator\\Desktop\\08_wlq.png',1)

cv2.imshow('img_BGR',img)
cv2.waitKey(0) 

img2 = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
cv2.imshow('img_RGB',img2)
cv2.waitKey(0)

img3 = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
cv2.imshow('img_GRAY',img3)
cv2.waitKey(0)

BGR 色彩空间转 RGB 色彩空间以及灰度

图像通道操作

图像通道的拆分

opencv函数拆分通道:split函数

b,g,r = cv2.split(img)
cv2.imshow('img_B',b)
cv2.imshow('img_G',g)
cv2.imshow('img_R',r)

cv2.waitKey(0)

numpy数组拆分通道

blue = img[:,:,0]
green = img[:,:,1]
red = img[:,:,2]

cv2.imshow('img_B',blue)
cv2.imshow('img_G',green)
cv2.imshow('img_R',red)

cv2.waitKey(0)

通道拆分效果

图像通道的合并

opencv函数合并通道:merge

img_2 = cv2.merge([b,g,r])

cv2.imshow('img_merge_2',img_2)
cv2.waitKey(0)

numpy数组合并通道

#先创建一个numpy数组,再对其赋值
height,width,_ = img.shape[:]
#img_1 = np.zeros((height,width,3),dtype = np.uint8)
img_1 = np.zeros((img.shape[0],img.shape[1],3),dtype = np.uint8)
img_1[:,:,0] = b
img_1[:,:,1] = g
img_1[:,:,2] = r

cv2.imshow('img_merge',img_1)
cv2.waitKey(0)

ROI ( region of interest )

通过 numpy 数组的切片操作提取感兴趣的区域,即 ROI

举个例子看看吧

#只留下人物的眼部
import cv2
import numpy as np

img = cv2.imread('图片路径',1)

cv2.imshow('start',img)   #原始图像
cv2.waitKey(0)
cv2.imwrite('start.png',img)

eye = img[112:150,112:260,:]  #ROI 区域

cv2.imshow('ROI',eye)
cv2.waitKey(0)
cv2.imwrite('ROI.png',eye)

原图

ROI 区域

图像的阈值/二值化(逐元素操作)

逐个元素操作的特点

  • 都可以通过循环遍历实现
  • 操作之后的图像分辨率不变(即图像无缩放操作)

全局阈值处理

将大于阈值的像素值设置为 255,将其他像素值设置为 0;或者将大于阈值的像素值设置为 0,其他像素设置为 255

opencv函数实现阈值处理:threshold 函数

Opencv 中的 cv2.threshold( ) 函数用于实现全局阈值处理

基本格式 :
retval,dst = cv2.threshold(src,thresh,max,type)

函数说明:

retval : 返回的阈值
dst(目的地) : 全局阈值处理后的结果图像
src : 原始图像(取灰度图像)
thresh : 设置的阈值(一般取 127 或者 255)
maxval : 即超过阈值后改变的值(一般取 255 )
dtype : 阈值类型

THRESH_BINARY —— 阈值处理参数
THRESH_BINGARY_INV —— 反阈值处理参数
THRESH_TRUNC —— 截断式阈值处理参数
THRESH_TOZERO_INV —— 超阈值处理参数
THRESH_TOZERO —— 低阈值处理参数

阈值和反阈值化处理
import cv2
import numpy as np

img = cv2.imread('图像路径(依情况而定)',0) #以灰度图像读入
cv2.imshow('begin',img)
cv2.waitkey(0)

ret,img2 = cv2,threshold(img,127,255,cv2.THRESH_BINARY)  #二值化阈值处理
ret,img2 = cv2,threshold(img,127,255,cv2.THRESH_BINARY_INV) #反阈值化处理
cv2.imshow('finally',img2)
cv2.waitkey(0)
截断阈值化处理(cv2.THRESH_TRUNC)

将大于阈值的像素设为阈值,小于或等于阈值的不变,改变函数 cv.threshold 的最后一个参数为 cv2.THRESH_TRUNC

超阈值零处理(cv2.THRESH_TOZERO_INV)

大于阈值的像素点设置为0,小于的就不变,改变函数 cv.threshold 的最后一个参数为 cv2.THRESH_TOZERO_INV

低阈值零处理(cv2.THRESH_TOZERO)

小于等于阈值的像素点设置为0,大于的不变,改变函数 cv.threshold 的最后一个参数为 cv2.THRESH_TOZERO

numpy数组实现阈值处理

示例代码
import cv2
import numpy as np

def my_thresh(img,src):
    '''
    函数功能:对灰度图进行二值化处理
    :param img: 原始图像
    :param src: 阈值
    :return: 二值化处理后的图像
    '''
    for row in range(len(img)):
        for line in range(len(img[0])):
            if img[row][line] > src:
                img[row][line] = 255
            else :
                img[row][line] = 0
    return img


def img_is_euqal(img1,img2):
    '''
    函数功能:判断两个图像是否相等
    :param img1: opencv函数处理图像
    :param img2: 自定义函数处理图像
    :return: 布尔值
    '''
    flag = 1
    for row in range(len(img)):
        for line in range(len(img[0])):
            if img1[row][line] != img2[row][line]:
                flag = 0
                break
            else :
                continue
    return flag

img = cv2.imread('图像路径',1)

cv2.imshow('Color_img',img)
cv2.waitKey(0)
cv2.imwrite('Color_img.png',img)

#转灰度图像(因为二值化对灰度图进行操作才有意义)
#cv2.imread(path,0)
#利用函数原理实现灰度图的转换
#拆分通道(每个单独的通道都是一个灰度图像)
img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) 
'''
cv2.COLOR_BGR2GRAY的实现原理:
Gray = 0.299R + 0.587G + 0.114B (加权求和)
'''

#阈值处理
_,img_1 = cv2.threshold(img,180,255,cv2.THRESH_BINARY)
cv2.imshow('binary_08_wlq',img_1)
cv2.waitKey(0)
cv2.imwrite('binary_08_wlq.jpg',img_1)

#显示和保存相应结果
img_2 = my_threshold(img,180)
cv2.imshow('binary_08_wlq_my',img_2)
cv2.waitKey(0)
cv2.imwrite('binary_08_wlq_my.jpg',img_2)

bool = img_is_euqal(img_1,img_2)
if bool == 1:
    print('the designed my_threshold function correctly')
else :
    print('the designed my_threshold function wrong')

自适应阈值处理

对于色彩均匀的图像,一个阈值就可以完成。但是色彩不均匀,只有一个阈值无法清晰有效的得到阈值分割后的图像

自适应阈值处理可以使用变换的阈值。它通过计算每个像素点周围邻近区域的加权平均值获得阈值,然后处理。

Opencv 中的 cv2.adaptiveThreshold( ) 函数用于实现自适应阈值处理

基本格式 :
dst = cv2.adaptiveThreshold(src,maxValue,adaptiveMethod,thresholdType,blockSize,C)

函数说明:

dst(目的地) : 全局阈值处理后的结果图像
src : 原始图像(必须为8位单通道的图像)
maxValue : 最大值
adaptiveMethod : 自适应方法

  • cv2.ADAPTIVE_THRESH_MEAN_C:邻域所有像素点的权重值是一致的
  • cv2.ADAPTIVE_THRESH_GAUSSIAN_C:与领域各个像素点到中心点的距离有关,通过高斯方程得到各个点的权重值

thresholdType : 阈值处理方法(如上)
blockSize:块大小,计算阈值时使用的大小(通常为 3,5,7)

C:常量,自适应阈值等于每个像素由参数 blockSize 所指定的领域的加权平均值减去常量 C

图像算术运算

加法运算(逐元素运算)

  1. 两个图像之间叠加
  2. 对一个图像的像素值进行修改

使用加法运算符 "+" 执行图像加法运算

使用 "+" 运算符执行灵鬼图像数组加法时,如果两个像素相加大于 255 ,则对 256 取模。

cv2.add( ) 函数执行图像加法运算

形式1:result = cv2.add(图像1,图像2)
  • 两个参数都是图像,此时参与运算的图像大小和类型必须保持一致
形式2: result = cv2.add(数值,图像)
  • 第一个参数是数值,第二个参数是图像,此时将超过图像饱和值的数值处理为饱和值
形式3:result = cv2.add(图像,数值)
  • 第一个参数是图像,第二个参数是数值,此时将超过图像饱和值的数值处理为饱和值

Opencv 中的 cv2.add( ) 函数执行两个图像数组加法,如果两个像素相加大于 256 ,则取 255(截断)。

基本格式 :
add(src1, src2, dst=None, mask=None, dtype=None)

函数说明:

src1,src2 : 需要相加的两幅大小和通道数相等的图像(若 shape 不一样,则改为一样的)或一副图像和一个标量(即单一的值)

修改图片大小的函数:cv2.resize ( src , dsize , interpolation )
src:需要修改的图像
dsize:目标尺寸(宽在前 —— 列数,高在后 —— 行数)
interpolation:一般使用双线性插值方法对图像进行缩放,即 interpolation = cv2.INTER_LINEAR

dst:可选参数,输出结果保存的变量,默认值为None,如果为非None,输出图像保存到dst对应实参中,其大小和通道数与输入图像相同,图像的深度(即图像像素的位数)由dtype参数或输入图像确认

mask:图像掩膜,可选参数,为8位单通道的灰度图像,用于指定要更改的输出图像数组的元素,即输出图像像素只有mask对应位置元素不为0的部分才输出,否则该位置像素的所有通道分量都设置为0

dtype:可选参数,输出图像数组的深度,即图像单个像素值的位数(如RGB用三个字节表示,则为24位)

返回值:相加的结果图像

示例代码
import cv2

img_people = cv2.imread('C:\\Users\\Administrator\\Desktop\\people.png',1)
img_bicycle = cv2.imread('C:\\Users\\Administrator\\Desktop\\bicycle.png',1)

cv2.imshow('people',img_people)
cv2.waitKey(0)
cv2.imshow('bicycle',img_bicycle)
cv2.waitKey(0)

high_p,width_p,_ = img_people.shape[:]
high_b,width_b,_ = img_bicycle.shape[:]

img_people = cv2.resize(img_people,(width_b,high_b),interpolation=cv2.INTER_LINEAR)

peole_and_bicycle = cv2.add(img_people,img_bicycle)
cv2.imshow('peole_and_bicycle',peole_and_bicycle)
cv2.waitKey(0)
cv2.imwrite('peole_and_bicycle.png',peole_and_bicycle)
效果图(可以看到效果不怎么样)

加权加法运算(逐元素运算)

cv2.addWeighted( ) 函数可执行加权加法运算

基本格式:
dst = cv2.addWeighted(src1,alpha,src2,beta,gamma)
函数说明:

src1,src2:进行相加的两个图像
alpha:src1 所占权重
beta:src2 所占权重(注:alpha + beta = 1)
gamma:灰度系数,图像校正的偏移量,用于调节亮度(一般不使用,所以为0)

示例代码

import cv2

img_people = cv2.imread('C:\\Users\\Administrator\\Desktop\\people.png',1)
img_bicycle = cv2.imread('C:\\Users\\Administrator\\Desktop\\bicycle.png',1)

cv2.imshow('people',img_people)
cv2.waitKey(0)
cv2.imshow('bicycle',img_bicycle)
cv2.waitKey(0)

high_p,width_p,_ = img_people.shape[:]
high_b,width_b,_ = img_bicycle.shape[:]

new_people = cv2.resize(img_people,(width_b,high_b),interpolation=cv2.INTER_LINEAR)

#加权加法运算
peole_and_bicycle = cv2.addWeighted(new_people,0.7,img_bicycle,0.3,0)
cv2.imshow('peole_and_bicycle',peole_and_bicycle)
cv2.waitKey(0)
cv2.imwrite('peole_and_bicycle.png',peole_and_bicycle)

来看个效果图吧!

这里我设置的 people图像的权重较大

图像的批量处理

一、os.listdir(列举出当前目录下的文件)

os.listdir() 方法用于返回指定的文件夹包含的文件或文件夹的名字的列表

基本格式:
list = os.listdir(path)

参数说明
path —— 需要列出的目录路径(绝对路径)

二、os.mkdir(创建目录)

os.mkdir() 以数字权限模式创建目录(单级目录)
默认的模式为 0777 ( 八进制 )

基本格式:
name_dir = path
os.mkdir(name_dir)

注意:
不能创建同级目录下已经创建过的同名文件
所以,我们创建文件之前可以先判断(使用 os.path.exists()

三、os.path.join(路径的拼接)

os.path.join() 用于路径拼接,可以传入多个路径

基本格式:
path = os.path.join(path_1,path_2,...,path_n)

给图像批量命名

import cv2  
import os  
  
img_name = os.listdir('D:\\python\\py lan\\source_img')  
  
name_list = ['.png','.jpg','.jpeg']  #后缀名  
  
for i in range(len(img_name)):  
    tmp_path = os.path.join('D:\\python\\py lan\\source_img',img_name[i])  
  
    img = cv2.imread(tmp_path,1)  
    new_img_name = '08_wlq_{:02}'.format(i+1)+name_list[i%3]  
  
    path = os.path.join('D:\\python\\py lan\\08_wlq_source_img',new_img_name)  
    print(path)  
    cv2.imwrite(path,img)

对图像批量二值化

import cv2  
import os  
  
path_source = 'D:\\python\\py lan\\ttduck\\08_wlq_source_img'  
list_img = os.listdir(path_source)  
  
path_make = 'D:\\python\\py lan\\ttduck\\08_wlq_dst_img'  
if os.path.exists(path_make) == 'False':  
    os.mkdir(path_make)  
  
name = '_binary'  
  
for i in range(len(list_img)):  
    # 1.读取图像  
    img = cv2.imread(os.path.join(path_source,list_img[i]),1)  
    # 2.图像处理(转换色彩空间,缩放,二值化,图像模糊,加法)  
    # 转灰度图  
    img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)  
    # 二值化处理  
    _,img = cv2.threshold(img,150,255,cv2.THRESH_BINARY)  
    path_temp = list(list_img[i])  
    #因为 insert 只能在列表中使用  
    path_temp.insert(9,name)  
    #直接转为 str 类型的话,path_temp是一个字符串数组,所以使用.join()来合并  
    path_temp = "".join(path_temp)  
    # 3.显示并保存  
    path_dst = path_make+'\\'+path_temp  
    print(path_dst)  
    cv2.imwrite(path_dst,img)
posted @ 2022-10-24 11:27  魏图图  阅读(288)  评论(0编辑  收藏  举报