opencv图像处理基础
图像类型
应用方面
- 自然图像
- 医学图像
- SAR 图像(Synthetic Aperture Raddar)—— 合成孔径雷达图像/遥感图像
图像的形式
- 彩色图像
- 灰度图像
- 二值图像
图像的获取
获取方式
- 网页上下载(拷贝)—— 自然图像
- numpy 数组生成图片
类型为:dtype = numpy.uint8(不然只是创建数组而不是图像)
numpy.zeros( shape )
numpy.ones( shape )
numpy.array( )
图像的四个属性
img.shape : 返回元组,其值是图像的高度和宽度(即数组的行和列);彩色图像有第三个参数为 BGR 3通道
type(img) : numpy.ndarray ( numpy 数组)
img.dtype : np.uint8 ( 0-255 为 256 个灰度等级,彩色图像即每个通道范围在 0-255)
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)
dst = cv2.cvtColor(src,cv2.COLOR_BGR2GRAY)
cv2.imread(path,0) 以灰度形式读入
- 拆分通道 ( 每个单独的通道都是一个灰度图像 )
扩展:
利用函数原理实现灰度图的转换
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
图像算术运算
加法运算(逐元素运算)
- 两个图像之间叠加
- 对一个图像的像素值进行修改
使用加法运算符 "+" 执行图像加法运算
使用 "+" 运算符执行灵鬼图像数组加法时,如果两个像素相加大于 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_LINEARdst:可选参数,输出结果保存的变量,默认值为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)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下