系列文章目录
关于OpenCV的一些图像处理函数
图象基本操作(读取、显示、通道提取、边界填充、融合、保存)
Retinex图像增强算法——SSR,MSR,MSRCR,MSRCP,autoMSRCR
文章目录
前言
一、Opencv常用图像处理函数汇总
1、cv2.threshold阈值处理函数
图像阈值
ret, dst = cv2.threshold(src, thresh, maxval, type)
-
src: 输入图,只能输入单通道图像,通常来说为灰度图
-
dst: 输出图
-
thresh: 阈值
-
maxval: 当像素值超过了阈值(或者小于阈值,根据type来决定),所赋予的值
-
type:二值化操作的类型,包含以下5种类型: cv2.THRESH_BINARY; cv2.THRESH_BINARY_INV; cv2.THRESH_TRUNC; cv2.THRESH_TOZERO;cv2.THRESH_TOZERO_INV
-
cv2.THRESH_BINARY 超过阈值部分取maxval(最大值),否则取0
-
cv2.THRESH_BINARY_INV THRESH_BINARY的反转
-
cv2.THRESH_TRUNC 大于阈值部分设为阈值,否则不变
-
cv2.THRESH_TOZERO 大于阈值部分不改变,否则设为0
-
cv2.THRESH_TOZERO_INV THRESH_TOZERO的反转
import cv2 #opencv读取的格式是BGR
import numpy as np
import matplotlib.pyplot as plt#Matplotlib是RGB
%matplotlib inline
# 显示函数
def cv_show1(name, img): # 长宽高
cv2.imshow(name, img)
cv2.waitKey(0)
cv2.destroyAllWindows()
#img = cv2.imread("D:/code/jupyter_code/data/lena.jpg")
img=cv2.imread('./data/cat.jpg')
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) # 转灰度图
#cv_show1('lena',img)
ret, thresh1 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)
ret, thresh2 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY_INV)
ret, thresh3 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TRUNC)
ret, thresh4 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TOZERO)
ret, thresh5 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TOZERO_INV)
titles = ['Original Image', 'BINARY', 'BINARY_INV', 'TRUNC', 'TOZERO', 'TOZERO_INV']
images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]
for i in range(6):
plt.subplot(2, 3, i + 1), plt.imshow(images[i], 'gray')
plt.title(titles[i])
plt.xticks([]), plt.yticks([])
plt.show()
2、均值滤波blur、中值滤波、方框滤波、高斯滤波
import cv2 #opencv读取的格式是BGR
import numpy as np
import matplotlib.pyplot as plt#Matplotlib是RGB
%matplotlib inline
# 显示函数
def cv_show1(name, img): # 长宽高
cv2.imshow(name, img)
cv2.waitKey(0)
cv2.destroyAllWindows()
img = cv2.imread("D:/code/jupyter_code/data/lena.jpg")
cv_show1('lena',img)
# 均值滤波
# 简单的平均卷积操作
blur = cv2.blur(img, (3, 3))
# 中值滤波
# 相当于用中值代替
median = cv2.medianBlur(img, 5) # 中值滤波
# 方框滤波
# 基本和均值一样,可以选择归一化
box = cv2.boxFilter(img,-1,(3,3), normalize=True)
# 高斯滤波
# 高斯模糊的卷积核里的数值是满足高斯分布,相当于更重视中间的
aussian = cv2.GaussianBlur(img, (5, 5), 1)
# cv_show1('blur',blur)
# cv_show1('box',box)
# cv_show1('median',median)
# cv_show1('aussian',aussian)
# 展示所有的
res = np.hstack((img,blur,box,aussian,median))
cv_show1('res',res)
3、形态学-腐蚀操作
卷积核沿着图像滑动,如果与卷积核对应的原图像的所有像素值都是1,那么中心元素就保持原来的像素值,否则就变为零。
将前景物体变小,理解成将图像断开裂缝变大。
import cv2 #opencv读取的格式是BGR
import numpy as np
import matplotlib.pyplot as plt#Matplotlib是RGB
%matplotlib inline
def cv_show1(name, img): # 长宽高
cv2.imshow(name, img)
cv2.waitKey(0)
cv2.destroyAllWindows()
img = cv2.imread("D:/code/jupyter_code/data/lena.jpg")
cv_show1('img',img)
kernel = np.ones((3,3),np.uint8)
# 函数参数, img是输入的图片, Kernel是卷积核的大小, iterations是重复运行次数。
erosion = cv2.erode(img,kernel,iterations = 1)
cv_show1('erosion',erosion)
kernel = np.ones((30,30),np.uint8)
erosion_1 = cv2.erode(img,kernel,iterations = 1)
erosion_2 = cv2.erode(img,kernel,iterations = 2)
erosion_3 = cv2.erode(img,kernel,iterations = 3)
res = np.hstack((erosion_1,erosion_2,erosion_3))
cv_show1('res',res)
3、形态学-膨胀操作
将前景物体变大,理解成将图像断开裂缝变小,与腐蚀相反。
import cv2 #opencv读取的格式是BGR
import numpy as np
import matplotlib.pyplot as plt#Matplotlib是RGB
%matplotlib inline
def cv_show1(name, img): # 长宽高
cv2.imshow(name, img)
cv2.waitKey(0)
cv2.destroyAllWindows()
img = cv2.imread("D:/code/jupyter_code/data/dige.png")
cv_show1('img',img)
kernel = np.ones((3,3),np.uint8)
# 函数参数, img是输入的图片, Kernel是卷积核的大小, iterations是重复运行次数。
erosion = cv2.dilate(img,kernel,iterations = 1)
cv_show1('erosion',erosion)
kernel = np.ones((30,30),np.uint8)
img = cv2.imread("D:/code/jupyter_code/data/pie.png")
erosion_1 = cv2.dilate(img,kernel,iterations = 1)
erosion_2 = cv2.dilate(img,kernel,iterations = 2)
erosion_3 = cv2.dilate(img,kernel,iterations = 3)
res = np.hstack((erosion_1,erosion_2,erosion_3))
cv_show1('res',res)
4、开运算与闭运算
import cv2 #opencv读取的格式是BGR
import numpy as np
import matplotlib.pyplot as plt#Matplotlib是RGB
%matplotlib inline
def cv_show1(name, img): # 长宽高
cv2.imshow(name, img)
cv2.waitKey(0)
cv2.destroyAllWindows()
img = cv2.imread("D:/code/jupyter_code/data/dige.png")
cv_show1('img',img)
# 开:先腐蚀,再膨胀
kernel = np.ones((5,5),np.uint8)
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
cv_show1('opening',opening)
# 闭:先膨胀,再腐蚀
closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
cv_show1('closing',closing)
5、梯度运算
import cv2 #opencv读取的格式是BGR
import numpy as np
import matplotlib.pyplot as plt#Matplotlib是RGB
%matplotlib inline
def cv_show1(name, img): # 长宽高
cv2.imshow(name, img)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 梯度=膨胀-腐蚀
pie = cv2.imread("D:/code/jupyter_code/data/pie.png")
kernel = np.ones((7,7),np.uint8)
dilate = cv2.dilate(pie,kernel,iterations = 5)
erosion = cv2.erode(pie,kernel,iterations = 5)
gradient = cv2.morphologyEx(pie, cv2.MORPH_GRADIENT, kernel)
res = np.hstack((dilate,erosion,gradient))
cv_show1('res',res)
6、礼帽与黑帽
- 礼帽 = 原始输入-开运算结果
- 黑帽 = 闭运算-原始输入
import cv2 #opencv读取的格式是BGR
import numpy as np
import matplotlib.pyplot as plt#Matplotlib是RGB
%matplotlib inline
def cv_show1(name, img): # 长宽高
cv2.imshow(name, img)
cv2.waitKey(0)
#礼帽
img = cv2.imread("D:/code/jupyter_code/data/dige.png")
tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
#黑帽
blackhat = cv2.morphologyEx(img,cv2.MORPH_BLACKHAT, kernel)
res = np.hstack((img,tophat,blackhat))
cv_show1('res',res)
7、图像梯度-Sobel算子、Scharr算子、laplacian算子
1、Sobel算子
Sobel算子是典型的基于一阶导数的边缘检测算子,算子引入了类似局部平均的运算,对噪声具有平滑作用,能够很好的消除噪声的影响。缺点:并没有将图像的主题与背景严格地区分开。
dst = cv2.Sobel(src, ddepth, dx, dy, ksize)
- ddepth:图像的深度
- dx和dy分别表示水平和竖直方向
- ksize是Sobel算子的大小
import cv2 #opencv读取的格式是BGR
import numpy as np
import matplotlib.pyplot as plt#Matplotlib是RGB
%matplotlib inline
def cv_show1(name, img): # 长宽高
cv2.imshow(name, img)
cv2.waitKey(0)
img = cv2.imread("D:/code/jupyter_code/data/pie.png")
# 水平方向
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
sobelx = cv2.convertScaleAbs(sobelx)
# 竖直方向
sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
sobely = cv2.convertScaleAbs(sobely)
# 求和
sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)
res = np.hstack((img,sobelx,sobely,sobelxy))
cv_show1('res',res)
2、Scharr算子
Scharr算子,具有和Sobel算子同样的速 度,且精度更高。可以将Scharr算子看作对Sobel算子的改进,其核通常为:
cv.Scharr(src, ddepth, dx, dy[, dst[, scale[, delta[, borderType]]]])
src:输入图像
dst:输出图像,大小和类型与 src 相同
ddepth:输出图片的数据深度,由输入图像的深度进行选择
dx:x 轴方向导数的阶数
dy:y 轴方向导数的阶数
scale:缩放比例因子,可选项,默认值为 1
delta:输出图像的偏移量,可选项,默认值为 0
borderType:边界扩充的类型,注意不支持对侧填充(BORDER_WRAP)
3、laplacian算子
Laplacian算子是一种各向同性算子,二阶微分算子,在只关心边缘位置,不考虑其周围的像素灰度差值时较为合适,具有无方向性的优点。对孤立像素的响应要比对边缘或线的响应更强烈,只适用于无噪声图像。存在噪声情况下,使用Laplacian算子检测边缘之前,要进行低通滤波。分割算法都是把Laplacian算子和平滑算子结合起来,生成一个新的模板。
4、代码
import cv2 #opencv读取的格式是BGR
import numpy as np
import matplotlib.pyplot as plt#Matplotlib是RGB
%matplotlib inline
def cv_show1(name, img): # 长宽高
cv2.imshow(name, img)
cv2.waitKey(0)
img = cv2.imread("D:/code/jupyter_code/data/lena.jpg")
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
sobelx = cv2.convertScaleAbs(sobelx)
sobely = cv2.convertScaleAbs(sobely)
sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)
scharrx = cv2.Scharr(img,cv2.CV_64F,1,0)
scharry = cv2.Scharr(img,cv2.CV_64F,0,1)
scharrx = cv2.convertScaleAbs(scharrx)
scharry = cv2.convertScaleAbs(scharry)
scharrxy = cv2.addWeighted(scharrx,0.5,scharry,0.5,0)
laplacian = cv2.Laplacian(img,cv2.CV_64F)
laplacian = cv2.convertScaleAbs(laplacian)
res = np.hstack((sobelxy,scharrxy,laplacian))
cv_show1('res',res)
8、Canny边缘检测
Canny算子是一个具有滤波,增强,检测的多阶段的优化算子,在进行处理前,Canny算子先利用高斯平滑滤波器来平滑图像以除去噪声,Canny分割算法采用一阶偏导的有限差分来计算梯度幅值和方向,在处理过程中,Canny算子还将经过一个非极大值抑制的过程,最后Canny算子还采用两个阈值来连接边缘。
1、使用高斯滤波器,以平滑图像,滤除噪声。
2、计算图像中每个像素点的梯度强度和方向。
3、应用非极大值(Non-Maximum Suppression)抑制,以消除边缘检测带来的杂散响应。
4、应用双阈值(Double-Threshold)检测来确定真实的和潜在的边缘。
5、通过抑制孤立的弱边缘最终完成边缘检测。
优点:该方法不容易受噪声干扰,能够检测到真正的弱边缘。
缺点: 易使高频边缘被平滑掉,从而造成边缘丢失。
edges=cv.Canny(image,threshold1,threshold2[,apertureSize[,L2gradient]])
● edges为计算得到的边缘图像。
● image为8位输入图像。
● threshold1表示处理过程中的第一个阈值。
● threshold2表示处理过程中的第二个阈值。
● apertureSize表示Sobel算子的孔径大小。
● L2gradient为计算图像梯度幅度(gradient magnitude)的标识。其默认值为False。
import cv2 #opencv读取的格式是BGR
import numpy as np
import matplotlib.pyplot as plt#Matplotlib是RGB
%matplotlib inline
def cv_show1(name, img): # 长宽高
cv2.imshow(name, img)
cv2.waitKey(0)
img = cv2.imread("D:/code/jupyter_code/data/lena.jpg")
v1=cv2.Canny(img,80,150)
v2=cv2.Canny(img,50,100)
res = np.hstack((v1,v2))
cv_show1('res',res)
9、图像金字塔
1、高斯金字塔下采样 cv2.pyrDown()
cv2.pyrDown()函数首先对原始图像进行高斯变换,再通过抛弃偶数行和偶数列实现下采样。
dst_img = cv2.pyrDown(src_img, dstsize)
dst_img:目标图像
src_img:原始图像
dstsize:目标图像大小。 默认行和列都会变成原始图像行和列的1/2, 整幅图像会变成原始图像的1/4。
2、高斯金字塔上采样 cv2.pyrUp()
cv2.pyrUp() 函数首先在原始图像的每个像素的右侧和下侧分别插入零值列和零值行,得到一个偶数行,偶数列(新增的行和列)都是零值的新图,在进行高斯变换,得到上采样的结果图像。
dst_img = cv2.pyrUp(src_img, dstsize)
dst_img:目标图像
src_img:原始图像
dstsize:目标图像大小。 默认行和列都会变成原始图像行和列的2倍, 整幅图像会变成原始图像的4倍。
3、拉普拉斯金字塔
拉普拉斯金字塔的目的就是为了恢复高分辨率的图像。
4、代码
import cv2 #opencv读取的格式是BGR
import numpy as np
import matplotlib.pyplot as plt#Matplotlib是RGB
%matplotlib inline
def cv_show1(name, img): # 长宽高
cv2.imshow(name, img)
cv2.waitKey(0)
img = cv2.imread("D:/code/data/AM.png")
down= cv2.pyrDown(img)
up=cv2.pyrUp(img)
down_up=cv2.pyrUp(down)
l_1=img-down_up
cv_show1('img',img)
cv_show1('down',down)
cv_show1('up',up)
cv_show1('l_1',l_1)
10、图像轮廓
1、cv2.findContours()
cv2.findContours(img,mode,method)
输入变量:
mode:轮廓检索模式
RETR_EXTERNAL :只检索最外面的轮廓;
RETR_LIST:检索所有的轮廓,并将其保存到一条链表当中;
RETR_CCOMP:检索所有的轮廓,并将他们组织为两层:顶层是各部分的外部边界,第二层是空洞的边界;
RETR_TREE:检索所有的轮廓,并重构嵌套轮廓的整个层次;
method:轮廓逼近方法
CHAIN_APPROX_NONE:以Freeman链码的方式输出轮廓,所有其他方法输出多边形(顶点的序列)。
CHAIN_APPROX_SIMPLE:压缩水平的、垂直的和斜的部分,也就是,函数只保留他们的终点部分。
输出变量:
contours:一个包含了图像中所有轮廓的list对象。其中每一个独立的轮廓信息以边界点坐标(x,y)的形式储存在numpy数组中。
hierarchy:一个包含4个值的数组:[Next, Previous, First Child, Parent],一般不使用hierarchy。
2、cv2.drawContours()
显示函数
cv.drawContours(img, contours, -1, (0,0,255), 3)
参数说明:
第一个参数是图像,第二个参数轮廓信息的python 列表,第三个参数是轮廓索引,第四个是轮廓颜色,还有厚度 等等。
import cv2 #opencv读取的格式是BGR
import numpy as np
import matplotlib.pyplot as plt#Matplotlib是RGB
%matplotlib inline
def cv_show1(name, img): # 长宽高
cv2.imshow(name, img)
cv2.waitKey(0)
img = cv2.imread("D:/code/jupyter_code/data/contours.png")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
cv_show1('thresh',thresh)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
#传入绘制图像,轮廓,轮廓索引,颜色模式,线条厚度
# 注意需要copy,要不原图会变。。。
draw_img = img.copy()
res = cv2.drawContours(draw_img, contours, -1, (0, 0, 255), 2)
cv_show1('res',res)
11、傅里叶变换
1、傅里叶变换
傅里叶变换的作用:
-
高频:变化剧烈的灰度分量,例如边界
-
低频:变化缓慢的灰度分量,例如一片大海
-
低通滤波器:只保留低频,会使得图像模糊
-
高通滤波器:只保留高频,会使得图像细节增强
opencv中主要就是cv2.dft()和cv2.idft(),输入图像需要先转换成np.float32 格式。
得到的结果中频率为0的部分会在左上角,通常要转换到中心位置,可以通过shift变换来实现。
cv2.dft()返回的结果是双通道的(实部,虚部),通常还需要转换成图像格式才能展示(0,255)。
import cv2 #opencv读取的格式是BGR
import numpy as np
import matplotlib.pyplot as plt#Matplotlib是RGB
%matplotlib inline
# 显示函数
def cv_show1(name, img): # 长宽高
cv2.imshow(name, img)
cv2.waitKey(0)
cv2.destroyAllWindows()
img = cv2.imread("D:/code/jupyter_code/data/lena.jpg",0)
img_float32 = np.float32(img)
dft = cv2.dft(img_float32, flags = cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)
# 得到灰度图能表示的形式
magnitude_spectrum = 20*np.log(cv2.magnitude(dft_shift[:,:,0],dft_shift[:,:,1]))
plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(magnitude_spectrum, cmap = 'gray')
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.show()
2、低通
import cv2 #opencv读取的格式是BGR
import numpy as np
import matplotlib.pyplot as plt#Matplotlib是RGB
%matplotlib inline
# 显示函数
def cv_show1(name, img): # 长宽高
cv2.imshow(name, img)
cv2.waitKey(0)
cv2.destroyAllWindows()
img = cv2.imread("D:/code/jupyter_code/data/lena.jpg",0)
img_float32 = np.float32(img)
dft = cv2.dft(img_float32, flags = cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)
rows, cols = img.shape
crow, ccol = int(rows/2) , int(cols/2) # 中心位置
# 低通滤波
mask = np.zeros((rows, cols, 2), np.uint8)
mask[crow-30:crow+30, ccol-30:ccol+30] = 1
# IDFT
fshift = dft_shift*mask
f_ishift = np.fft.ifftshift(fshift)
img_back = cv2.idft(f_ishift)
img_back = cv2.magnitude(img_back[:,:,0],img_back[:,:,1])
plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(img_back, cmap = 'gray')
plt.title('Result'), plt.xticks([]), plt.yticks([])
plt.show()
3、 高通
import cv2 #opencv读取的格式是BGR
import numpy as np
import matplotlib.pyplot as plt#Matplotlib是RGB
%matplotlib inline
# 显示函数
def cv_show1(name, img): # 长宽高
cv2.imshow(name, img)
cv2.waitKey(0)
cv2.destroyAllWindows()
img = cv2.imread("D:/code/jupyter_code/data/lena.jpg",0)
img_float32 = np.float32(img)
dft = cv2.dft(img_float32, flags = cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)
rows, cols = img.shape
crow, ccol = int(rows/2) , int(cols/2) # 中心位置
# 高通滤波
mask = np.ones((rows, cols, 2), np.uint8)
mask[crow-30:crow+30, ccol-30:ccol+30] = 0
# IDFT
fshift = dft_shift*mask
f_ishift = np.fft.ifftshift(fshift)
img_back = cv2.idft(f_ishift)
img_back = cv2.magnitude(img_back[:,:,0],img_back[:,:,1])
plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(img_back, cmap = 'gray')
plt.title('Result'), plt.xticks([]), plt.yticks([])
plt.show()