一、颜色空间
1、颜色空间
图像空间包括:
RGB:由R(红)G(绿)B(蓝)三个通道组成的颜色空间,每个通道的分量为0~255。三个通道的数据类型均为uint8,在三个通道的基础上再加一个透明度分量就形成了RGBA颜色空间。
例子:
黑色(0,0,0) 白色(255,255,255) 红色(255,0,0)
YUV:由亮度(Y)、红色分量与亮度差(U)、蓝色分量与亮度差(V)三个分量组成,主要用于电视信号的传输。
HSV:由色调(H)、饱和度(S)和亮度(V)组成,HSV是最为接近人体感知颜色的方式。
Lab:由亮度(L)、ab两个颜色通道组成,是一种与设备无关,基于生理特征的颜色空间。
GRAY:灰度颜色空间,只有一个通道,每个灰度值由0~255的整数表示。
RGB转GRAY = GRAY = 0.3R+0.59R+0.11B
2、不同的颜色空间转换 cv.cvtColor
cv.cvtColor()函数用于将图像从一个颜色空间转换为另一个颜色空间,并将转化之后的结果通过值返回。
#函数原型:
dst = cv.cvtColor(src,
code
[, dst
[, dstCn]])
# src:待转化颜色空间的图像
# code:颜色空间转化的标志
# dst:颜色空间转化后的目标图像
# dstCn:目标图像中的通道数,默认值为0
cv.COLOR_BGR2BGRA 0 为RGB添加alpha通道
cv.COLOR_BGR2RGB 4 更改彩色图像通道颜色的顺序
cv.COLOR_BGR2GRAY 10 把彩色图像转成灰度图像
cv.COLOR_GRAY2BGR 8 把灰度图像转成彩色图像(伪彩色)
cv.COLOR_BGR2YUV 82 从RGB颜色空间转成YUV颜色空间
cv.COLOR_YUV2BGR 84 从YUV颜色空间转成RGB颜色空间
cv.COLOR_BGR2HSV 40 从RGB颜色空间转成HSV颜色空间
cv.COLOR_HSV2BGR 54 从HSV颜色空间转成RGB颜色空间
cv.COLOR_BGR2Lab 44 从RGB颜色空间转成Lab颜色空间
cv.COLOR_Lab2BGR 56 从Lab颜色空间转成RGB颜色空间
代码:
if __name__ == "__main__":
image = cv2.imread('beach.png')
if image is None:
print('faile to read image')
sys.exit()
#将图像转化空间
#将图像转换为float32
HSV = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
image1 = image.astype('float32')
image1 *= 1.0/255
YUV = cv2.cvtColor(image1,cv2.COLOR_BGR2YUV)
Lab = cv2.cvtColor(image1,cv2.COLOR_BGR2Lab)
GRAY = cv2.cvtColor(image1,cv2.COLOR_BGR2GRAY)
#结果展示
cv2.imshow('HSV',HSV)
cv2.imshow("YUV",YUV)
cv2.imshow('Lab',Lab)
cv2.imshow('GRAY',GRAY)
cv2.imwrite('lab.jpg',Lab)
cv2.imread('lab.jpg')
cv2.imshow('lab',Lab)
cv2.waitKey()
cv2.destroyAllWindows()
3、类型转换
dst = ndarray.astype(dtype
[,order = 'K']
[,cast = 'unsafe']
[,subok = True]
[,copy = True] )
#dtype:转化后的图像数据类型
#order:在内存中的存储顺序,默认K
#cast:数据类型转化的级别,默认值为‘unsafe’
#subok:声明是否传递子类。
#copy:声明是否返回新分配的数组
参数:
- dtype:接受字符串或者numpy类型。
- order:可选{‘C’, ‘F’, ‘A’, ‘K’}控制结果的内存布局顺序。
- casting:可选{‘no’, ‘equiv’, ‘safe’, ‘same_kind’, ‘unsafe’},控制可能发生的数据类型转换。
‘no’ 表示根本不应该转换数据类型。
‘equiv’ 表示只允许字节顺序更改。
‘safe’ 意味着只允许可以保留值的强制转换。
‘same_kind’ 表示只允许安全类型转换或类型中的类型转换,如 float64 到 float32。
‘unsafe’ 意味着可以进行任何数据转换。
subok:接收bool值,如果为 True(默认),子类将被传递,否则返回的数组将被强制为基类数组。
- copy:接受bool值,是否赋值数据,默认为True。
返回值:
- ndarray
代码:
HSV = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
#将图像转化为float32类型
image1 = image.astype('float32')
#将数据归化为0~1的值
image1 *= 1.0/255
需要注意该函数在进行转换前后的图像取值范围不能超出像素取值范围。
uint8: 0~255
uint16: 0~65535
float32: 0~1
4、通道的分离与合并
1、图像通道分离split
在图像颜色空间中,不同的分量存放在不同的通道中。如果我们只需要颜色空间中的某一个分量(例如,只需要处理 RGB 图像中的红色通道),则可以将红色通道从三通道的数据中分离出来再进行处理。这种方式可以减少数据所占用的内存,加快程序的运行速度。同时,当我们分别处理完多个通道后需要将所有通道合并在一起重新生成RGB图像。这就需要用到cv.split()函数和cv.merge()函数。
mv = cv.split(m,
[,mv])
#m:待分离的图像
#mv:分离后的单通道图像
2、通道合并merge
该函数主要用于将多幅图像合并成一幅多通道图像,并将合并后的结果通过值返回。其功能与cv.split()相对应,对于输入尺寸和数据类型一致的多幅图像,输出结果是一幅多通道的图像,其通道数目是所有输入图像通道数目的总和。
注意:所有输入的图像的通道数可以不相同,但是所有图像需要具有相同的尺寸和数据类型
dst = cv.merge(mv
[,dst])
#mv:需要合并的图像
#dst:合并后输出的图像
代码:
import cv2
import numpy as np
import sys
import matplotlib.pyplot as plt
if __name__ =='__main__':
#读取图像
image = cv2.imread('beach.png')
if image is None:
print('failed to read image')
sys.exit()
#分离图像通道
(b,g,r) = cv2.split(image)
zeros = np.zeros(image.shape[:2],dtype='uint8')
#将通道数相同的图像合并
bg = cv2.merge([b,g,zeros])
gr = cv2.merge([zeros,g,r])
br = cv2.merge([b,zeros,r])
#将通道数目不同的图像矩阵进行合并
bgr_6 = cv2.merge([bg,r,zeros,zeros])
#展示结果
cv2.imshow('Blue',b)
cv2.imshow('Green',g)
cv2.imshow('Red',r)
cv2.imshow('Blue_Green',bg)
cv2.imshow('Green_Red',gr)
cv2.imshow('Blue_Red',br)
#cv2.imshow('BGR-6',bgr_6)
cv2.waitKey()
cv2.destroyAllWindows()
二、图像像素操作
1、像素统计
(1) OpenCV 4中提供了寻找图像像素最大值、最小值的函数 cv.minMaxLoc()
#cv.minMaxLoc()函数原型
minVal, maxVal, minLoc, maxLoc = cv.minMaxLoc(src
[, mask])
#minVal:像素最小值
#maxVal:像素最大值
#minLoc:最小值坐标
#maxLoc:最大值坐标
#src:图像
代码1:
import cv2
import numpy as np
import sys
if __name__== '__main__':
array = np.array([1,2,3,4,5,10,6,7,8,9,10,0])
image = cv2.imread('beach.png')
gray = cv2.cvtColor(image,cv2.COLOR_RGB2GRAY)
#将array调整为3*4的单通道图像
img1 = array.reshape((3,4))
minVal,maxVal,minLoc,maxLoc = cv2.minMaxLoc(gray)
print('图像img1的最小值为%s,其位置为%s'%(minVal,minLoc))
print('图像img1的最大值为%s,其位置为%s'%(maxVal,maxLoc))
#将array重塑为3*2*2的多通道图像
img2 = array.reshape((3,2,2))
print(img2)
#将通道图像重塑
img2_re = img2.reshape((1,-1))
minVal1,maxVal1,minLoc1,maxLoc1 = cv2.minMaxLoc(img2_re)
print('图像img2的最小值%s,其位置是%s'%(minVal1,minLoc1))
print('图像img2的最大值%s,其位置是%s' % (maxVal1, maxLoc1))
cv2.waitKey()
代码2:
def MinMaxLoc(self,rec_img):
'''
获取最大最小値
:param rec_img: 图像
:return:处理后的图像
'''
try:
img = rec_img.reshape((1,-1))
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(img)
cv2.putText(rec_img,'minVal{}'.format(min_val,3),(0,30),cv2.FONT_HERSHEY_SIMPLEX,0.5,(0,255,0),1)
cv2.putText(rec_img,'maxVal{}'.format(max_val,3),(0,60),cv2.FONT_HERSHEY_SIMPLEX,0.5,(0,255,0),1)
cv2.putText(rec_img,'minVallLoc{}'.format(min_loc,3),(0,90),cv2.FONT_HERSHEY_SIMPLEX,0.5,(0,255,0),1)
cv2.putText(rec_img,'maxValLoc{}'.format(max_loc,3),(0,120),cv2.FONT_HERSHEY_SIMPLEX,0.5,(0,255,0),1)
return False,rec_img
except Exception as e:
QMessageBox.warning(None, "错误", "{}".format(str(e)))
return
(2)cv.mean()函数可计算图像的均值。
#cv.mean()函数原型
retal = cv.mean(src
[,mask])
其中各返回值和参数的含义分别为:
retal:为一个长度为4的元组,四个位置分别代表相应通道的均值,若通道不存在,则对应值为0.0
src:需要计算均值的图像或者矩阵
mask:图像掩模(可选参数)
(3)cv.meanStdDev()函数可同时计算图像的均值和标准差。
#cv.meanStdDev()函数原型
mean, stddev = cv.meanStdDev(src
[, mean
[, stddev
[, mask]]])
其中各返回值参数的含义分别为:
mean:图像每个通道的均值
stddev:图像每个通道的标准差
src:需要计算均值的图像或者矩阵
mask:图像掩模(可选参数)
代码1:
import cv2
import numpy as np
import sys
if __name__ == '__main__':
#新建array
array = np.array([1,2,3,4,5,10,6,7,8,9,10,0])
#转换为3*4单通道
img1 = array.reshape((3,4))
#转换为3*2*2多通道
img2 = array.reshape((3,2,2))
img = cv2.imread('beach.png')
#分别计算图像img1和img2的均值与标准差
mean_img1 = cv2.mean(img)
mean_img2 = cv2.mean(img2)
stDev1 = cv2.meanStdDev(img)
stDev2 = cv2.meanStdDev(img2)
print(stDev2)
print('cv.mean的计算结果:')
print('img1的平均值为{}'.format(mean_img1))
print('img2的平均值为{},其中1通道为{},2通道为{}'.format(mean_img2,mean_img2[0],mean_img2[1]))
print('cv.meanStdDev的计算结果:')
print('img1的平均值为{},标准差为{}'.format(float(stDev1[0][0]),float(stDev1[0][1])))
print('img2的平均值为{},其中1通道为{},\n2通道为{} 标准差为{},\n其中通道1为{},通道2为{}'.format(stDev2,stDev2[0][0],stDev2[0][1],stDev2[1],stDev2[1][0],stDev2[1][1]))
cv2.waitKey()
代码2:
def Mean(self,rec_img):
'''
图像平均值
:param rec_img: 图像
:return: 处理后的图像
'''
try:
mean = cv2.mean(rec_img)
mean1 = mean[0]
mean2 = mean[1]
mean3 = mean[2]
cv2.putText(rec_img,'Channel1Mean{}'.format(round(mean1,3)),(0,30),cv2.FONT_HERSHEY_SIMPLEX,0.5,(0,255,0),1)
cv2.putText(rec_img,'Channel2Mean{}'.format(round(mean2,3)),(0,60),cv2.FONT_HERSHEY_SIMPLEX,0.5,(0,255,0),1)
cv2.putText(rec_img,'Channel3Mean{}'.format(round(mean3,3)),(0,90),cv2.FONT_HERSHEY_SIMPLEX,0.5,(0,255,0),1)
return False, rec_img
except Exception as e:
QMessageBox.warning(None, "错误", "{}".format(str(e)))
return
def MeanstdDev(self,rec_img):
'''
图像均值标准差
:param rec_img: 图像
:return: 处理后的图像
'''
try:
mean, stddev = cv2.meanStdDev(rec_img)
mean1 = mean[0]
mean2 = mean[1]
mean3 = mean[2]
stddev1 = stddev[0]
stddev2 = stddev[1]
stddev3 = stddev[2]
cv2.putText(rec_img,'Channel1Mean{}'.format(round(float(mean1),3)),(0,30),cv2.FONT_HERSHEY_SIMPLEX,0.5,(0,255,0),1)
cv2.putText(rec_img,'Channel2Mean{}'.format(round(float(mean2),3)),(0,60),cv2.FONT_HERSHEY_SIMPLEX,0.5,(0,255,0),1)
cv2.putText(rec_img,'Channel3Mean{}'.format(round(float(mean3),3)),(0,90),cv2.FONT_HERSHEY_SIMPLEX,0.5,(0,255,0),1)
cv2.putText(rec_img,'Channel1StdDev{}'.format(stddev1),(0,120),cv2.FONT_HERSHEY_SIMPLEX,0.5,(0,255,0),1)
cv2.putText(rec_img,'Channel2StdDev{}'.format(stddev2),(0,150),cv2.FONT_HERSHEY_SIMPLEX,0.5,(0,255,0),1)
cv2.putText(rec_img,'Channel3StdDev{}'.format(stddev3),(0,180),cv2.FONT_HERSHEY_SIMPLEX,0.5,(0,255,0),1)
return False,rec_img
except Exception as e:
QMessageBox.warning(None, "错误", "{}".format(str(e)))
return
2、两图像间像素操作
#cv.max()和cv.min()函数原型
dst = cv.max(src1,
src2,
[, dst])
dst = cv.min(src1,
src2,
[, dst])
其中各返回值和参数的含义分别为:
dst:保留对应位置上较大(较小)灰度值后的图像,尺寸、通道数和数据类型与输入参数一致
src1:第一幅图像,可以是任意通道数的矩阵
src2:第二幅图像,图像的尺寸、通道数以及数据类型需要与第一幅图像一致
代码1:
import cv2
import numpy as np
import sys
import datetime
if __name__ == '__main__':
#新建a和b
a = np.array([1,2,3.3,4,5,9,5,7,8.2,9,10,2])
b = np.array([1,2.2,3,1,3,10,6,7,8,9.3,10,1])
img1 = np.reshape(a,(3,4))
img2 = np.reshape(b,(3,4))
img3 = np.reshape(a,(2,3,2))
img4 = np.reshape(b,(2,3,2))
#对两幅单通道图像进行比较
max12 = cv2.max(img1,img2)
min12 = cv2.min(img1,img2)
#对两幅多通道图像进行对比
max34 = cv2.max(img3,img4)
min34 = cv2.min(img3,img4)
#对两幅彩色图进行比较
img5 = cv2.imread('beach.png')
img6 = cv2.imread('bend.png')
img5 = img5[0:300,0:300]
img6 = img6[0:300,0:300]
max56 = cv2.max(img5,img6)
min56 = cv2.min(img5,img6)
cv2.imshow('max56',max56)
cv2.imshow('min56',min56)
#对两幅灰度图像进行比较
img7 = cv2.cvtColor(img5,cv2.COLOR_BGR2GRAY)
img8 = cv2.cvtColor(img6, cv2.COLOR_BGR2GRAY)
max78 = cv2.max(img7,img8)
min78 = cv2.min(img7,img8)
cv2.imshow('max78',max78)
cv2.imshow('min78',min78)
#与掩膜图像进行比较
#生成一个300*300的掩膜
src= np.zeros((300,300,3),dtype='uint8')
src[0:100,0:100,:] = 255
cv2.imshow('AAAA',src)
cv2.waitKey()
#保留低的,图像中0~100比255低的部分被留下,图像中黑色的部分被留下
min_img5_src = cv2.min(img5,src)
cv2.imshow('min img5 src',min_img5_src)
src1 = np.zeros((300,300,3),dtype='uint8')
src1[:,:,2] = 255
min_img5_src1 = cv2.min(img5,src1)
cv2.imshow('min img5 src1',min_img5_src1)
cv2.waitKey()
代码2:
def Max(self,params):
'''
两图像最大值
:param rec_img1:图像1
:param rec_img2:图像2
:return:返回最大图像
'''
try:
rec_img1, rec_img2 = params
if rec_img1.shape != rec_img2.shape:
if rec_img1.shape > rec_img2.shape:
rec_img1 = cv2.resize(rec_img1, (rec_img2.shape[1], rec_img2.shape[0]), cv2.INTER_AREA)
else:
rec_img2 = cv2.resize(rec_img2, (rec_img1.shape[1], rec_img1.shape[0]), cv2.INTER_AREA)
max = cv2.max(rec_img1, rec_img2)
return False,max
except Exception as e:
QMessageBox.warning(None, "错误", "{}".format(str(e)))
return
def Min(self,params):
'''
两图像最小値
:param rec_img1:图像1
:param rec_img2:图像2
:return:返回最小图像
'''
try:
rec_img1, rec_img2 = params
if rec_img1.shape != rec_img2.shape:
if rec_img1.shape > rec_img2.shape:
rec_img1 = cv2.resize(rec_img1, (rec_img2.shape[1], rec_img2.shape[0]), cv2.INTER_AREA)
else:
rec_img2 = cv2.resize(rec_img2, (rec_img1.shape[1], rec_img1.shape[0]), cv2.INTER_AREA)
min = cv2.min(rec_img1, rec_img2)
return False,min
except Exception as e:
QMessageBox.warning(None, "错误", "{}".format(str(e)))
return
3、图像按位操作
OpenCV4提供了针对两幅图像像素之间的“与”、“或”、“异或”及“非”运算的函数。具体运算规则如下图所示。
//对像素求"与"运算
dst = cv.bitwise_and(src1,
src2,
[, dst
[, mask]])
//对像素求"或"运算
dst = cv.bitwise_or(src1,
src2,
[, dst
[, mask]])
//对像素求"异或"运算
dst = cv.bitwise_xor(src1,
src2,
[, dst
[, mask]])
//对像素求"非"运算
dst = cv.bitwise_not(src1,
src2,
[, dst
[, mask]])
其中各返回值和参数的含义分别为:
dst:逻辑运算之后的结果,尺寸、通道数和数据类型与输入参数一致
src1:第一幅图像,可以是任意通道数的矩阵
src2:第二幅图像,图像的尺寸、通道数以及数据类型需要与第一幅图像一致
mask:掩模矩阵,用于设置图像或矩阵中逻辑运算的范围
代码1:
import cv2
import numpy as np
import sys
if __name__ == '__main__':
#创建两幅黑白图像
img1 = np.zeros((200,200),dtype='uint8')
img2 = np.zeros((200,200),dtype='uint8')
img1[50:150,50:150] = 255
img2[100:200,100:200] = 255
#读取图像并判断是否读取成功
img = cv2.imread('bend.png')
if img is None:
print('failed to read image')
sys.exit()
#进行逻辑运算
Not = cv2.bitwise_not(img1)
And = cv2.bitwise_and(img1,img2)
Or = cv2.bitwise_or(img1,img2)
Xor = cv2.bitwise_xor(img1,img2)
img_not = cv2.bitwise_not(img)
#展示结果
cv2.imshow('img1',img1)
cv2.imshow('img2',img2)
cv2.imshow('Not',Not)
cv2.imshow('And',And)
cv2.imshow('Or',Or)
cv2.imshow('Xor',Xor)
cv2.imshow('Origin',img)
cv2.imshow('img_not',img_not)
cv2.waitKey()
cv2.destroyAllWindows()
代码2:
def bitwise_and(self,params):
'''
两图像位进进行与操位
:param rec_img1:图像1
:param rec_img2:图像2
:return:返回两图像位与操作结果
'''
try:
rec_img1,rec_img2 = params
if rec_img1.shape != rec_img2.shape:
if rec_img1.shape > rec_img2.shape:
rec_img1 = cv2.resize(rec_img1, (rec_img2.shape[1], rec_img2.shape[0]), cv2.INTER_AREA)
else:
rec_img2 = cv2.resize(rec_img2, (rec_img1.shape[1], rec_img1.shape[0]), cv2.INTER_AREA)
bit_and = cv2.bitwise_and(rec_img1, rec_img2)
return False,bit_and
except Exception as e:
QMessageBox.warning(None, "错误", "{}".format(str(e)))
return
def bitwise_or(self,params):
'''
两图像位进进行或操位params
:param rec_img1:图像1
:param rec_img2:图像2
:return:返回两图像位或操�结果
'''
try:
rec_img1, rec_img2 = params
if rec_img1.shape != rec_img2.shape:
if rec_img1.shape > rec_img2.shape:
rec_img1 = cv2.resize(rec_img1, (rec_img2.shape[1], rec_img2.shape[0]), cv2.INTER_AREA)
else:
rec_img2 = cv2.resize(rec_img2, (rec_img1.shape[1], rec_img1.shape[0]), cv2.INTER_AREA)
bit_or = cv2.bitwise_or(rec_img1, rec_img2)
return False,bit_or
except Exception as e:
QMessageBox.warning(None, "错误", "{}".format(str(e)))
return
def bitwise_xor(self,params):
'''
两图像位进进行差操位
:param rec_img1:图像1
:param rec_img2:图像2
:return:返回两图像位差操�结果
'''
try:
rec_img1, rec_img2 = params
if rec_img1.shape != rec_img2.shape:
if rec_img1.shape > rec_img2.shape:
rec_img1 = cv2.resize(rec_img1, (rec_img2.shape[1], rec_img2.shape[0]), cv2.INTER_AREA)
else:
rec_img2 = cv2.resize(rec_img2, (rec_img1.shape[1], rec_img1.shape[0]), cv2.INTER_AREA)
bit_xor =cv2.bitwise_xor(rec_img1, rec_img2)
return False,bit_xor
except Exception as e:
QMessageBox.warning(None, "错误", "{}".format(str(e)))
return
def bitwise_not(self,rec_img):
'''
两图像位进进行取反操位
:param rec_img:图像
:return:返回图像取反结果
'''
try:
bit_not =cv2.bitwise_not(rec_img)
return False,bit_not
except Exception as e:
QMessageBox.warning(None, "错误", "{}".format(str(e)))
return
4、图像二值化
什么是图像二值化,将图像根据一个阈值将图像变为只有两个黑(0)白(255)两种灰度的图像。非黑即白。
OpenCV提供了 cv.threchold()与cv.AdaptiveThreshold()这两个函数用于实现图像的二值化
1、cv.threshold()函数
retval,dat = cv2.threshold(src,
thresh,
maxval,
type
[,dst])
参数 | 说明 |
---|---|
src | 表示变换操作的输入图像,nparray 二维数组, 必须是单通道灰度图像! |
thresh | 表示阈值,取值范围 0~255。 |
maxval | 表示填充色,取值范围 0~255,一般取 255。 |
type | 表示变换类型。 |
dst | 表示返回阈值变换的输出图像。 |
type类型说明
cv.THRESH_BINARY 表示大于阈值时置 255,否则置 0。
cv.THRESH_BINARY_INV 表示大于阈值时置 0,否则置 255。
cv.THRESH_TRUNC 表示大于阈值时置为阈值 thresh,否则不变(保持原色)。
cv.THRESH_TOZERO 表示大于阈值时不变(保持原色),否则置 0。
cv.THRESH_TOZERO_INV 表示大于阈值时置 0,否则不变(保持原色)。
cv.THRESH_OTSU 表示使用 OTSU 算法选择阈值。
cv.THRESH_TRIANGLE 表示使用三角法自动设定阈值
cv.THRESH_OTSU与cv.THRESH_TRIANGLE可以与其它类型的type一起使用
num1,img_O = cv2.threshold(img1,100,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)
注意:cv.THRESH_OTSU与cv.THRESH_TRIANGLE只支持8位图像
代码:
img = cv2.imread('bend.png')
if img is None:
print('failed to read the image')
sys.exit()
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#彩色图像二值化
_,img_B = cv2.threshold(img,125,255,cv2.THRESH_BINARY)
_,img_B_V = cv2.threshold(img,125,255,cv2.THRESH_BINARY_INV)
cv2.imshow('img',img)
cv2.imshow('img_B',img_B)
cv2.imshow('img_B_V',img_B_V)
#灰度图像二值化
_,gray_B = cv2.threshold(gray,125,255,cv2.THRESH_BINARY)
_,gray_B_V = cv2.threshold(gray,125,255,cv2.THRESH_BINARY_INV)
cv2.imshow('gray',gray)
cv2.imshow('gray_B',gray_B)
cv2.imshow('gray_B_V',gray_B_V)
#灰度图像TOZERO变化
_,gray_T = cv2.threshold(gray,125,255,cv2.THRESH_TOZERO)
_,gray_T_V = cv2.threshold(gray,125,255,cv2.THRESH_TOZERO_INV)
cv2.imshow('gray_T',gray_T)
cv2.imshow('gray_T_V',gray_T_V)
#灰度图像TRUNC变化
_,gray_TRUNC = cv2.threshold(gray,125,255,cv2.THRESH_TRUNC)
cv2.imshow('gray_TRUNC',gray_TRUNC)
2、cv.adaptiveThreshold()函数
将灰度图转化为二值化图像,通过自适应阈值再次进行二值化处理。
dst = cv2.adaptiveThreshold(src,
maxValue,
adaptiveMethod,
thresholdType,
blockSize,
C
[,dst])
src:需要进行二值化的一张灰度图像
maxValue:满足条件的像素点需要设置的灰度值。(将要设置的灰度值)
adaptiveMethod:自适应阈值算法。可选ADAPTIVE_THRESH_MEAN_C 或 ADAPTIVE_THRESH_GAUSSIAN_C
thresholdType:opencv提供的二值化方法,只能THRESH_BINARY或者THRESH_BINARY_INV
blockSize:要分成的区域大小,上面的N值,一般取奇数
C:常数,每个区域计算出的阈值的基础上在减去这个常数作为这个区域的最终阈值,可以为负数
dst:输出图像,可以忽略
adaptiveMethod自适应阈值的两种方法:
ADAPTIVE_THRESH_MEAN_C,为局部邻域块的平均值,该算法是先求出块中的均值。
ADAPTIVE_THRESH_GAUSSIAN_C,为局部邻域块的高斯加权和。该算法是在区域中(x, y)周围的像素根据高斯函数按照他们离中心点的距离进行加权计算。
代码:
#灰度图像大津法和三角法二值化
img_s = cv2.imread('adapterThreshold.png')
img1 = cv2.cvtColor(img_s,cv2.COLOR_BGR2GRAY)
num1,img_O = cv2.threshold(img1,100,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)
num2,img_T = cv2.threshold(img1,125,255,cv2.THRESH_BINARY|cv2.THRESH_TRIANGLE)
print('num1=',num1)
print('num2=',num2)
cv2.imshow('img_O',img_O)
cv2.imshow('img_T',img_T)
#灰度图像自适应二值化
adaptive_mean = cv2.adaptiveThreshold(img1,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,13,0)
adaptive_gauss = cv2.adaptiveThreshold(img1,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,13,0)
cv2.imshow('adaptive_mean',adaptive_mean)
cv2.imshow('adaptive_gauss',adaptive_gauss)
5、LUT
根据LUT映射表,将图像映射为指定的灰度图像。
dst = cv2.LUT(src,
lut
[,dst])
src:输入数据array,类型为8位整型(np.uin8)
lut
:查找表
,如果输入src是多通道的,例如是BGR三通到的图像,而查表是单通道的,则此时B、G、R三个通道使用的是同一个查找表
dst=None
:输出数组,大小和通道数与src相同,而深度depth与lut相同
使用LUT进行映射
代码:
#LUI第一层
LUT_1 = np.zeros(256,dtype='uint8')
LUT_1[101:201] = 100
LUT_1[201:] = 255
#LUI第二层
LUT_2 = np.zeros(256, dtype='uint8')
LUT_2[101:151] = 100
LUT_2[151:201] = 150
LUT_2[201:] = 255
#LUI第三层
LUI_3 = np.zeros(256, dtype='uint8')
LUI_3[0:101] = 100
LUI_3[101:201] = 200
LUI_3[201:] = 255
#合并三个通道
LUT = cv2.merge((LUT_1,LUT_2,LUI_3))
#读取图像并判断是否读取成功
img = cv2.imread('bend.png')
if img is None :
print('failed to read image')
sys.exit()
#彩色图转换为灰度图
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#LUI转化
out0 = cv2.LUT(img,LUT_1)
out1 = cv2.LUT(gray,LUT_1)
out2 = cv2.LUT(img,LUT)
#显示结果
cv2.imshow('out0',out0)
cv2.imshow('out1',out1)
cv2.imshow('out2',out2)
使用LUT进行提升图像亮度
代码:
img = cv2.imread(img_path)
# clip(0, 255)会把处理后的像素值的大小,现在在[0, 255]范围内,如果有值大于255则取255,如果有值小于0则取值0
table = np.array([i * brightness_factor for i in range (0,256)]).clip(0,255).astype('uint8')
# 单通道img
if img.shape[2] == 1:
return cv2.LUT(img, table)[:,:,np.newaxis]
# 多通道img
else:
result = cv2.LUT(img, table)
# 左边原图、右边增加亮度后的图
imgs_hstack = np.hstack((img, result))
cv2.imwrite("adjust_brightness_result.png", imgs_hstack)
cv2.imshow("result", imgs_hstack)
cv2.waitKey(0)
return result
三、图像连接与图像变换
1、图像连接
OpenCV中提供了两种图像连接的方法垂直连接和水平连接。
垂直连接:
dst = cv2.vconcat(src
[,dst])
水平连接:
dst = cv2.hconcat(src
[,dst])
src:需要连接的图像
dst:连接后的图像
代码:
import cv2
import numpy as np
import sys
import datetime
if __name__ =="__main__":
#矩阵垂直水平连接
#定义矩阵AB
A = np.array([[1,7],[2,8]])
B = np.array([[4,10],[5,11]])
#垂直连接
V_C = cv2.vconcat((A,B))
#水平连接
V_H = cv2.hconcat((A,B))
print('垂直连接结果:\n{}'.format(V_C))
print('水平连接结果:\n{}'.format(V_H))
#图像的垂直水平连接
#读取图像
img = cv2.imread('beach.png')
img00 = img[0:300,0:300]
img01 = img[0:300 ,300:600]
img10 = img[300:600,0:300]
img11 = img[300:475,300:600]
#垂直连接
img_V = cv2.hconcat((img00,img01))
#水平连接
img_H = cv2.hconcat((img10, img11))
#垂直连接
img_V_H = cv2.vconcat((img_V,img_H))
cv2.imshow('img', img)
cv2.imshow('img00',img00)
cv2.imshow('img01', img01)
cv2.imshow('img10',img10)
cv2.imshow('img11', img11)
cv2.imshow('img_V', img_V)
cv2.imshow('img_H', img_H)
cv2.imshow('img_V_H', img_V_H)
cv2.waitKey()
cv2.destroyAllWindows()
注:图像垂直连接时需要图像垂直方向尺寸一致,图像水平连接时需要图像水平方向尺寸一致。
2、图像尺寸变换
OpenCV中图像尺寸变换函数
dst = cv2.resize(src,
dsize
[,dst
[,fx
[,fy
[,interpolation]]]])
src:输入图像
dsize:输出图像尺寸
dst:输出图像
fx:水平轴的比例因子,如果沿水平轴将图像放大为原来的2倍,则指定为2.
fy:垂直轴的比例因子,如果沿水平轴将图像放大为原来的2倍,则指定为2.
interpolation:插值方法的标志,可以选择参数
cv.INTER_NEAREST 最近邻插值
cv.INTER_LINEAR 双线性插值
cv.INTER_CUBIC 双线性插值
cv.INTER_AREA 使用像素区域关系重新采样。它可能是图像抽取的首选方法,因为它可以提供
代码:
import cv2
import numpy as np
import sys
import datetime
if __name__ =='__main__':
#读取图像
img = cv2.imread('beach.png',cv2.IMREAD_GRAYSCALE)
if img is None:
print('failed to read image')
sys.exit()
#图像缩放
small_img = cv2.resize(img,(300,300),fx=0,fy= 0,interpolation = cv2.INTER_AREA)
#图像放大
big_img1 = cv2.resize(img,(800,800),fx=0,fy=0,interpolation= cv2.INTER_CUBIC)
#图像放大
big_img2 = cv2.resize(img,(800,800),fx = 0,fy = 0 ,interpolation=cv2.INTER_LINEAR)
cv2.imshow('small_img',small_img)
cv2.imshow('big_img1',big_img1)
cv2.imshow('big_img2',big_img2)
cv2.waitKey()
cv2.destroyAllWindows()
3、图像翻转
OpenCV中提供了图像的翻转函数
dst = cv2.flip(src,
flipCode
[,dst])
src:输入图像
flipCode:翻转标志,数值大于0,表示绕y轴旋转,数值等于0,表示绕x轴旋转,数值小于0,表示绕两个轴旋转。
dst:输出图像,与scr同样的尺寸大小。
import cv2
import sys
import numpy as np
if __name__ == '__main__':
#读取图像
img = cv2.imread('beach.png',cv2.IMREAD_GRAYSCALE)
if img is None:
print('failed to read image')
sys.exit()
#垂直翻转
flip_V = cv2.flip(img,1)
#垂直翻转
flip_H = cv2.flip(img,0)
#都反转
flip_H_V = cv2.flip(img,-1)
cv2.imshow('img',img)
cv2.imshow('Y',flip_V)
cv2.imshow('X',flip_H)
cv2.imshow('Y_X',flip_H_V)
cv2.waitKey()
cv2.destroyAllWindows()
4、图像仿射变换
OpenCV中没有旋转图像的函数,要想实现图像的旋转需要使用仿射变换进行旋转。先根据角度和旋转中心确定旋转矩阵,最后通过仿射变换实现图像的旋转。
计算旋转矩阵
retal = cv2.getRotationMatrix2D(center,
angle,
scale)
center:图像旋转中心。
angle:图像旋转的角度,单位为度,正值表示逆时针旋转。
scale:沿两条轴的缩放比例,可以实现旋转过程中的图像缩放,若不缩放则输入1。
仿射变换
dst = cv2.warpAffine(src,
M,
dsize
[,dst
[,flags
[,borderMode
[,borderValue]]]])
src:输入图像
M:2*3变换矩阵
dsize:输出图像的尺寸
dst:仿射变换后的输出图像,与第一个参数的数据类型相同,但是尺寸与dsize相同。
flags:插值方法的标志。
borderMode:像素边界外推方法的标志。
borderValue:填充边界使用的数值,默认情况下为0。
flags插值方法标志
cv.WARP_FILL_OUTLIERS 8 填充所有输出图像的像素,如果部分像素落到输入图像的边界外,那么它们的值设定为fillval。
cv.WARP_INVERSE_MAP 16 表示参数M为输出图像到输入图像的反变换。
borderMode像素边界外推方法标志。
cv.BORDER_CONSTANT 0 用特定值填充,如:iiii|abcdefgh|iiii
cv.BORDER_REPLICATE 1 两端复制填充,如:aaaa|abcdefgh|hhhhh
cv.BORDER_REFLECT 2 倒序填充,如:fedcba|abcdefgh|hgfedcba
cv.BORDER_WRAP 3 正序填充,如:cdefgh|abcdefgh|abcdefg
cv.BORDER_REFLECT_101 4 不包括边界值倒序填充,如:gfedcb|abcdefgh|gfedcba
cv.BORDER_TRANSPARENT 5 随机填充
cv. BORDER_REFLECT101 4 与cv.BORDER_REFLECT_101相同
cv.BORDER_DEFAULT 4 与cv.BORDER_REFLECT_101相同
cv.BORDER_ISOLATED 16 不关心感兴趣区域之外的部分。
变换矩阵M
retval = cv2.getAffineTransform(src,
dst)
src:原图中3个像素坐标
dst:目标图像中3个像素坐标
代码:
import cv2
import numpy as np
import sys
import matplotlib.pyplot as plt
import argparse
if __name__ =='__main__':
#读取图像
img = cv2.imread('beach.png')
if img is None:
print('failed to read image')
sys.exit()
#设置图像旋转角度
angle = 30
h,w = img.shape[0:2]
size = (w,h)
center = (w/2.0,h/2.0)
#计算仿射变换矩阵
M = cv2.getRotationMatrix2D(center,angle,1)
#进行仿射变换
img_warp0 = cv2.warpAffine(img,M,size)
#根据定义的三点进行仿射变换
src_points = np.array([[0,0],[0,h-1],[w - 1,h - 1]],dtype='float32')
dst_points = np.array([[w*0.11,h*0.2],[w*0.15,h*0.7],[w*0.81,h*0.85]],dtype='float32')
#根据对应的三个点计算仿射变换
M1 = cv2.getAffineTransform(src_points,dst_points)
img_warp1 = cv2.warpAffine(img,M1,size)
#展示结果
cv2.imshow("img_warp0",img_warp0)
cv2.imshow('img_warp1',img_warp1)
cv2.waitKey()
cv2.destroyAllWindows()
5、图像透视变换
将图像按照物体成像投影规律进行变换,即将物体重新投影到新的成像平面上。
4点变换矩阵
retval = cv2.getPerspectiveTransform(src,
dst
[,solveMethod])
src:原图像中4个像素坐标
dst:目标图像中4个像素坐标
solveMethod:选择计算透视变换矩阵方法的标志
cv.DECOMP_LU 0 最佳主轴元素的高斯消元法
cv.DECOMP_SVD 1 奇异值分解(svd)方法
cv.DECOMP_EID 2 特征值分解法
cv.DECOMP_CHOLESKY 3 Cholesky分解法
cv.DECOMP_OR 4 QR分解法
cv.DECOMP_NORMAL 16 使用归一化公式,可以与前面的标志一起使用。
透视变换
dst = cv2.warpPerspective(src,
M,
dsize
[,dst
[,flags
[,borderMode
[,borderValue]]]])
src:输入图像矩阵
M:3*3的透视变换矩阵,可以通过getPerspectiveTransform等函数获取
dsize:结果图像大小,为宽和高的二元组
dst:输出结果图像,可以省略,结果图像会作为函数处理结果输出
flags:可选参数,插值方法的组合(int 类型),默认值 INTER_LINEAR,本函数官方材料说明取值为INTER_LINEAR 或 INTER_NEAREST与 WARP_INVERSE_MAP的组合,但老猿测试其他标志也是支持的。
borderMode:可选参数,边界像素模式(int 类型),默认值 BORDER_CONSTANT,本函数官方材料说明取值为BORDER_CONSTANT 或 BORDER_REPLICATE,实际上所有取值类型都支持,包括形态变换中不支持的BORDER_WRAP、BORDER_TRANSPARENT都能支持,并且不同取值有不同效果。
borderValue:填充边界使用的数值,默认情况下为 0。
代码:
import cv2
import sys
import numpy as np
if __name__ =='__main__':
#读取图像
img = cv2.imread('F:\\Python\\opencv-python\\chapter3\\images\\noobcvqr.png')
if img is None:
print('failed to read image')
sys.exit()
h,w = img.shape[0:2]
size = (w,h)
#读取透视变换前的四个点
points_path = "F:\\Python\\opencv-python\\chapter3\data\\noobcvqr_points.txt"
with open(points_path,'r') as f:
src_point = np.array([tx.split(' ') for tx in f.read().split('\n')],dtype='float32')
#设置透视变换后的4个点
max_pt = np.max(src_point)
dst_points = np.array([[0.0,0.0],[max_pt,0.0],[0.0,max_pt],[max_pt,max_pt]],dtype='float32')
#计算透视变换后的矩阵
rotation =cv2.getPerspectiveTransform(src_point,dst_points)
img_warp = cv2.warpPerspective(img,rotation,size)
#展示结果
cv2.imshow('Origin',img)
cv2.imshow('img_warp',img_warp)
cv2.waitKey()
cv2.destroyAllWindows()
效果图:
6、极坐标变换
将圆形图像展开成矩形图像 。
dst = cv2.warpPolar(src,
dsize,
center,
maxRadius
flags
[,dst])
src:原图像
dsize:目标图像的大小
center:极坐标变换时极坐标在原图像中的原点
maxRadius:变换时边界圆的半径
flags:插值方法与极坐标映射方法的标志
dst:极坐标变换后的输出图像。
flags插值方法与极坐标映射方法标志
cv.WARP_POLAR_LINEAR 极坐标变换
cv.WARP_POLAR_LOG 半对数极坐标变换
cv.WARP_INVERSE_MAP 逆变换
代码:
import cv2
import sys
import numpy as np
import datetime
if __name__ == '__main__':
#读取图像
img = cv2.imread('F:\\Python\\opencv-python\\chapter3\\images\\dial.png')
if img is None:
print('falited to read image')
sys.exit()
#获取图像尺寸
h,w = img.shape[0:2]
#极坐标原点
center = [w/2,h/2]
#极坐标正变换
img_res = cv2.warpPolar(img,[300,600],center,center[0],cv2.WARP_POLAR_LINEAR+cv2.INTER_LINEAR)
#极坐标逆变换
img_resl = cv2.warpPolar(img,(w,h),center,center[0],cv2.INTER_LINEAR+cv2.WARP_POLAR_LINEAR+cv2.WARP_INVERSE_MAP)
#展示结果
cv2.imshow('Origin',img)
cv2.imshow('img_res',img_res)
cv2.imshow('img_resl',img_resl)
cv2.waitKey()
cv2.destroyAllWindows()
效果:
四、绘制集合图形和生成文字
1、绘制圆
img = cv2.circle(img,
center,
radius,
color
[,thickness
[,linecache
[,shift]]])
img:需要在其上绘制圆的图像
center:圆心坐标
radius:圆的半径
color:圆的颜色
thinckness:轮廓的宽度
lineType:线条的类型
shift:center和radius的小数位数
2、绘制线
img = cv2.line(img,
pt1,
pt2,
color
[,thickness
[,lineType
[,shift]]])
img:绘制线段所在的图像
pt1:线段的起点
pt2:线段的终点
color:线的颜色
thinckness:轮廓的宽度
lineType:线条的类型
shift:center和radius的小数位数
3、绘制椭圆
img = cv2.ellipse(img,
center,
axes,
angle,
startAngle,
endAngle,
color,
[, thickness
[, lineType
[, shift]]])
img:绘制椭圆所在的图像
center:椭圆中心
axes:椭圆的长半轴角度,单位度
angle:椭圆旋转角度,单位度
startAngle:椭圆起始角度,单位度
endAngle:椭圆终止角度,单位度
color:线条颜色
thinckness:轮廓的宽度
lineType:线条的类型
shift:center和radius的小数位数
4、计算近似椭圆坐标
pts = cv2.ellipse2Poly(center,
axes,
angle,
startAngle,
endAngle,
delta)
center:椭圆中心
axes:椭圆长半轴的长度
angle:椭圆旋转的角度
startAngle:椭圆弧起始角度,单位为度
endAngle:椭圆终止角度,单位为度
delta:后续折线顶点之间的角度,相当于定义了近似精度
pts:近似的椭圆边界的像素坐标集合
5、绘制多边形
1、绘制矩形
img = cv2.rectangle(img,
pt1,
pt2
color,
[,thinckness
[,lineType
[,shift]]])
img = cv2.rectangle(img,
rec,
color,
[,thinckness
[,lineType
[,shift]]])
img:绘制矩形所在图像
pt1:矩形的一个顶点
pt2:矩形中与pt1相对的顶点,即两个点在对角线上
color:线条的颜色,用三通道表示
thinckness:线条的粗细,默认值为:1
lineType:线条的类型,默认值为:cv.LINE_8
shift:点坐标中的小数位数,默认为0
rec:矩形左上角的顶点,以及矩形的长宽
2、绘制多边形
img = cv2.fillPoly(img,
pts,
color,
[,lineType
[,shift
[,offset]]])
img:绘制多边形所在图像
pts:多边形顶点的数组,既可以存放多个多边形顶点坐标的数据
color:线条的颜色,用三通道表示
lineType:线条的类型,默认值为:cv.LINE_8
shift:点坐标中的小数位数,默认为0
offset:所有顶点的可选偏移量
代码:
import cv2
import numpy as np
import sys
if __name__ == "__main__":
#生成黑色图像用于绘制
img= np.zeros((512,512,3),dtype='uint8')
#绘制实心圆
img = cv2.circle(img,(100,100),50,(255,0,0),-1)
cv2.imshow('Circle',img)
#绘制空心圆
img = cv2.circle(img,(50,50),50,(255,0,0),1)
cv2.imshow('Filled Circle',img)
#绘制直线
img = cv2.line(img,(0,0),(511,511),(255,255,255),2,cv2.LINE_8,0)
cv2.imshow('Line',img)
#画椭圆
img = cv2.ellipse(img,(300,255),(100,70),0,0,270,(255,255,255),-1)
cv2.imshow('Ellipse',img)
#获取近似椭圆上的坐标
points = cv2.ellipse2Poly((200,400),(100,70),0,0,360,2)
#用线将上述点显示出来
for idx,point in enumerate(points):
if idx+1 >= len(points):
break
img = cv2.line(img,(point),points[idx+1],(255,0,0),2,cv2.LINE_4,0)
img = cv2.line(img,(points[0]),(points[-1]),(255,0,0),2,cv2.LINE_4,0)
cv2.imshow('CC',img)
#绘制矩形
img = cv2.rectangle(img,(400,400),(500,500),(255,255,255),-1)
cv2.imshow('Rectangle',img)
img = cv2.rectangle(img,(20,400,100,100),(255,255,255),2)
cv2.imshow('Filled Rectangle',img)
#绘制多边形
pts = np.array([[350,83],[463,90],[500,171],[421,194],[338,141]],dtype='int32')
img = cv2.fillPoly(img,[pts],(255,0,0),8)
cv2.imshow('Polygon',img)
#添加文字
img = cv2.putText(img,'Lean OpenCV',(150,70),cv2.FONT_HERSHEY_SIMPLEX,1,(255,255,255),1,cv2.LINE_AA)
cv2.imshow('Text',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
6、生成文字
img = cv2.putText(img,
text,
org,
fontFace,
fontScale,
color
[,thinckness
[,lintType
[,bottomLeftOrigin]]])
img:显示文字的图像
text:输出到图像中的文字,目前OpenCV4只支持英文
org:图像中的文字字符串左下角的像素坐标
fontFace:字体类型选择标志
fontScale:字体大小
color:字体颜色,通常用三通道表示
thinckness:线条的粗细,默认值为:1
lineType:线条的类型,默认值为:cv.LINE_8
bottomLeftOrigin:图像数据原点位置,默认位于左上角,如果参数值改为True,则原点位于左下角。
fontFace字体类型选择标志
cv.FONT_HERSHEY_SIMPLEX 0 正常大小的无衬线字体
cv.FONT_HERSHEY_PLAIN 1 小尺寸无衬线字体
cv.FONT_HERSHEY_DUPLEX 2 正常大小的较复杂的无衬线字体
cv.FONT_HERSHEY_COMPLEX 3 正常大小的衬线字体
cv.FONT_HERSHEY_TRIPLEX 4 正常大小的较复杂的衬线字体
cv.FONT_HERSHEY_COMPLEX_SMALL 5 小尺寸衬线字体
img = cv2.putText(img,'Lean OpenCV',(150,70),cv2.FONT_HERSHEY_SIMPLEX,1,(255,255,255),1,cv2.LINE_AA)
cv2.imshow('Text',img)
五、感兴趣区域
感兴趣区域的作用就是从原图截取一部分作为检测区域。
ROI = img[x1:x2,y1:y2]
ROI:提取的感兴趣区域结果
img:待提取感兴趣区域的所在图像
x1:感兴趣区域的左上角x坐标
x2:感兴趣区域的右下角x坐标
y1:感兴趣区域的左上角y坐标
y2:感兴趣区域的右下角y坐标
import cv2
import sys
import numpy as np
if __name__ == '__main__':
#读取图像
img = cv2.imread('lena.jpg')
noobcv = cv2.imread('noobcv.jpg')
if img is None or noobcv is None:
print('Failed to read lena.jpg or noobcv.jpg.')
sys.exit()
mask = cv2.resize(noobcv, (200,200))
#深拷贝
img1 = img.copy()
#浅拷贝
img2 = img
#截取ROI
ROI = img[206:406,206:406]
#深拷贝
ROI_copy = ROI.copy()
img[206:406,206:406] = mask
cv2.imshow('img1', img1)
cv2.imshow('img2', img2)
cv2.imshow('ROI', ROI)
cv2.imshow('ROI_copy', ROI_copy)
#在图像中绘制图形
img = cv2.circle(img,(300,300),20,(0,0,255),-1)
#展示结果
cv2.imshow('深拷贝无变化',img1)
cv2.imshow('浅拷贝有变化',img2)
cv2.imshow('浅拷贝ROI无变化',ROI)
cv2.imshow('深拷贝ROI_copy无变化',ROI_copy)
cv2.waitKey(0)
cv2.destroyAllWindows()
注意:拷贝方式分为浅拷贝和深拷贝。浅拷贝数据等与源数据,地址相同。深拷贝是将源数据另存为一个地址,重新生成一个数据。
深拷贝:a = b.copy()
a = b.deepcopy()
a :拷贝结果
b:原拷贝区域
六、图像金字塔
1、高斯金字塔
构建图像的高斯金字塔是解决尺寸不确定性的一种常用方法。高斯金字塔是指通过下采样不断的将图片尺寸缩小。
dst = cv2.pyrDown(src,
[,dst
[,dstsize
[,borderType]]])
src:输入等待下采样的图像
dst:输出下采样后的图像
dstsize:输出图像的尺寸,可以使用默认值
borderType:像素边缘外推方法的标志
2、拉普拉斯金字塔
拉普拉斯金字塔利用上层小尺寸图像构建下方大尺寸图像。
dst = cv2.pyrUp(src,
[,dst
[,dstsize
[,borderType]]])
src:输入待上采样图像
dst:输出上采样后的图像
代码:
import cv2
import numpy as np
import sys
def gauss_image(image):
#设置下采样次数
level = 3
img = image.copy()
gauss_images = []
gauss_images.append(G0)
cv2.imshow('G0',G0)
for i in range(level):
img = cv2.pyrDown(img)
gauss_images.append(img)
cv2.imshow('Gauss_{}'.format(i+1),img)
return gauss_images
def laplian_image(image):
gauss_images = gauss_image(image)
level = len(gauss_images)
for i in range(level-1,0,-1):
expand = cv2.pyrUp(gauss_images[i],dstsize = gauss_images[i-1].shape[:2])
cv2.imshow('expand_{}'.format(level-i),expand)
lpls = cv2.subtract(gauss_images[i-1],expand)
cv2.imshow('Laplacian_{}'.format(level-i),lpls)
#为构建最上面一层,需要先进行下采样在进行上采样
expand = cv2.pyrUp(cv2.pyrDown(gauss_images[3]),dstsize = gauss_images[3].shape[:2])
lpls = cv2.subtract(gauss_images[3],expand)
cv2.imshow('Laplacian_{}'.format(0),lpls)
if __name__ == "__main__":
G0 = cv2.imread('lena.jpg')
if G0 is None:
print('Failed to read lena.jpg')
sys.exit()
laplian_image(G0)
cv2.waitKey(0)
cv2.destroyAllWindows()
七、窗口交互操作
1、图像窗口滑动条
通过创建滑动条改变数值大小,来改变图像效果。
cv2.createTrackbar(trackbarName,
windowName,
value,
count
[,onChange
[,userdata]])
trackbarname:滑动条的名称
winname:在其中创建滑动条的窗口名称
value:指向整数变量的指针
count:滑动条的最大值
onChange:每次滑动更改位置时要调用的函数指针
userdata:传递给回调函数的可选参数
代码:
import cv2
import numpy as np
import sys
def call_back1_brightness(x):
global value,img,img1
value = cv2.getTrackbarPos('brightness','Brighter')
#np.clip将img中的数都乘以小数,并限制其值在0与255之间
img1 = np.uint8(np.clip((value/100*img),0,255))
if __name__ == '__main__':
#读取图像并判断是否读取成功
img = cv2.imread('lena.jpg')
if img is None:
print('读取图片失败!')
sys.exit()
img1 = img.copy()
cv2.namedWindow('Brighter')
#设置滑动条的初始值
value = 100
#创建滑动条
cv2.createTrackbar('brightness','Brighter',value,100,call_back1_brightness)
while True:
cv2.imshow('Brighter',img1)
if cv2.waitKey(1) == ord('q'):
break
cv2.destroyAllWindows()
2、鼠标响应
鼠标在窗体内操作时,需要得到鼠标状态时,可以添加鼠标响应函数。
cv2.setMouseCallback(windowName,
onMouse
[,userdata])
winname:添加鼠标响应事件的窗口名称
onMouse:鼠标相应的回调函数
userdata:传递给回调函数的可选参数
回调函数中鼠标响应事件的可选标志
cv.EVENT_MOUSEMOVE 0 鼠标指针在窗口上移动
cv.EVENT_LBUTTONDOWN 1 按下鼠标左键
cv.EVENT_RBUTTONDOWN 2 按下鼠标右键
cv.EVENT_MBOTTONDOWN 3 按下鼠标中键
cv.EVENT_LBUTTONUP 4 释放鼠标左键
cv.EVENT_RBUTTONUP 5 释放鼠标右键
cv.EVENT_MBOTTONUP 6 释放鼠标中键
cv.EVENT_LBUTTONBLCLK 7 双击鼠标左键
cv.EVENT_RBUTTONBLCLK 8 双击鼠标右键
cv.EVENT_MBOTTONBLCLK 9 双击鼠标中键
cv.EVENT_MOUSEWHEEL 10 正值表示向前滚动,负值表示向后滚动
cv.EVENT_MOUSEHWHEEL 11 正值表示向前左滚动,负值表示向右滚动
回调函数中鼠标响应的标志
cv.EVENT_FLAG_LBUTTON 1 按住鼠标左键拖曳
cv.EVENT_FLAG_RBUTTON 2 按住鼠标右键拖曳
cv.EVENT_FLAG_MBUTTON 4 按住鼠标中键拖曳
cv.EVENT_FLAG_CTRLKEY 8 按下Ctrl键
cv.EVENT_FLAG_SHIFTKEY 8 按下Shift键
cv.EVENT_FLAG_ALTKEY 8 按下Alt键
代码:
import cv2
import numpy as np
import sys
def draw(event,x,y,flags,param):
global img, pre_pts
#按下鼠标右键
if event == cv2.EVENT_RBUTTONDOWN:
print('按下左键进行图像绘制')
#按下鼠标左键
if event == cv2.EVENT_LBUTTONDOWN:
pre_pts = (x,y)
print('起始位置为:{},{}'.format(x,y))
if event == cv2.EVENT_MOUSEMOVE and flags == cv2.EVENT_FLAG_LBUTTON:
pts = (x,y)
img = cv2.line(img,pre_pts,pts,(255,0,255),5)
pre_pts = pts
cv2.imshow('image',img)
if __name__ == '__main__':
#读取图像
img = cv2.imread('lena.jpg')
img1 = img.copy()
if img is None:
print('Failed to read lena.jpg.')
sys.exit()
pre_pts = -1,-1
cv2.imshow('image',img)
cv2.setMouseCallback('image',draw)
cv2.waitKey(0)
cv2.destroyAllWindows()
本章小结:
函数总览:
1、cv.cvtColor():实现图像颜色空间转换。
2、np.astype():实现图像数据类型的转换
3、cv.split():实现图像多通道分离
4、cv.minMaxLoc():寻找矩阵中最大值和最小值,以及最大值和最小值再矩阵中的位置。
5、np.reshape():改变矩阵的维度和通道数。
6、cv.mean():计算矩阵中的每个通道平均值和平方差。
7、cv.meanStdDev():计算矩阵中每个通道的平均值。
8、cv.max()/cv.min():计算矩阵中的每个对应元素的最大值和最小值。
9、cv.bitwise_and():实现像素的与运算。
10、cv.bitwise_or():实现像素的或运算。
11、cv.bitwise_xor():实现像素的非运算。
12、cv.bitwise_not():实现像素的异或运算。
13、cv.threshold():实现像素的阈值操作。
14、cv.adaptiveThreshold():实现像素自适应阈值操作。
15、cv.LUT():实现图像查找表。
16、cv.vconcat():/cv.hconcat():实现图像的水平垂直拼接。
17、cv.resize():改变图像尺寸。
18、cv.flip():实现图像的翻转。
19、cv.warpAffine():实现图像的仿射变换
20、cv.warpPerspective():实现图像透视变换。
21、cv.warpPolar():实现图像极坐标变换。
22、cv.circle():在图像中绘制圆形。
23、cv.line():在图像中根据两点绘制一条直线。
24、cv.ellipse():在图像中绘制椭圆。
25、cv.ellipse2Poly():输出近似椭圆的像素坐标。
26、cv.rectangle():在图像中绘制矩形。
27、cv.fillPoly():在图像中绘制多边形。
28、cv.putText():在图像中绘制文字
30、copy():实现图像的深拷贝。
31、cv.pyrDown():实现图像下采样。
32、cv.pyrUp():实现图像的上采样。
33、cv.createTrackbar():在图像窗口中创建滑动条。
34、cv.setMouseCallback():添加鼠标响应事件。