原博地址:https://www.cnblogs.com/silence-cho/p/10926248.html
目录:
opencv-python基础知识学习笔记
1.图像的读入和存储
2.图像像素获取和编辑
3.添加边界
4.像素算术运算
5.图像位运算
6.图像颜色空间转换
7.性能评价
8.绑定TrackBar到图像
9.图像阈值分割
10.图像缩放
11.仿射变换
12.透视变换
13:直方图绘制
14.对比度增强
15.二维离散卷积
16.图像平滑
17.腐蚀处理
18.膨胀处理
19.开运算/闭运算/形态学梯度/顶帽/底帽
20.直线、圆、矩形、文字的绘制
21.边缘检测
22.模版匹配
23.凸包
24.计算轮廓特征
25.霍夫变换
26.图像梯度提取
27.角点检测
28.图像通道分离与合并
27.角点检测
28.图像通道分离与合并
29.图像算术运算
30.像素的均值和方差
31.漫水填充
32.K近邻
33.拟合
34.图像连通域
35.骨架提取
36.SVM
37.频域处理
38.图像数据类型转换
39.生成随机颜色
40.图像掩码处理
1.图像的读入和存储:
(1)函数格式:
#【1】读取图片,返回图片对象
imread(img_path,flag)
img_path: 图片的路径,即使路径错误也不会报错,但打印返回的图片对象为None
flag:cv2.IMREAD_COLOR,读取彩色图片,图片透明性会被忽略,为默认参数,也可以传入1
cv2.IMREAD_GRAYSCALE,按灰度模式读取图像,也可以传入0
cv2.IMREAD_UNCHANGED,读取图像,包括其alpha通道,也可以传入-1
#【2】
# (1)显示图片,窗口自适应图片大小
imshow(window_name,img):
window_name: 指定窗口的名字
img:显示的图片对象
可以指定多个窗口名称,显示多个图片
# (2)键盘绑定事件,阻塞监听键盘按键,返回一个数字(不同按键对应的数字不同)
waitKey(millseconds)
millseconds: 传入时间毫秒数,在该时间内等待键盘事件;传入0时,会一直等待键盘事件
# (3)关闭窗口
destroyAllWindows(window_name)
window_name: 需要关闭的窗口名字,不传入时关闭所有窗口
#【3】保存图像
imwrite(img_path_name,img)
img_path_name:保存的文件名
img:文件对象
(2)应用举例:
import cv2
img = cv2.imread("2.jpg")
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,img_threshold = cv2.threshold(img_gray,127,255,cv2.THRESH_BINARY)
cv2.imshow("img",img)
cv2.imshow("thre",img_threshold)
key = cv2.waitKey(0)
if key==27: #按esc键时,关闭所有窗口
print(key)
cv2.destroyAllWindows()
cv2.imwrite("2-1.jpg", img_threshold)
2.图像像素获取和编辑:
img = cv2.imread("2.jpg")
# 【1】像素值获取
(1)
pixel = img[100,100] #[57 63 68],获取(100,100)处的像素值
img[100,100]=[57,63,99] #设置像素值
b = img[100,100,0] #57, 获取(100,100)处,blue通道像素值
g = img[100,100,1] #63
r = img[100,100,2] #68
r = img[100,100,2]=99 #设置red通道值
(2)
piexl = img.item(100,100,2)
img.itemset((100,100,2),99)
# 【2】图像性质获取
img.shape #返回(280, 450, 3), 宽280(rows),长450(cols),3通道(channels)
img.size #返回378000,所有像素数量,=280*450*3
img.dtype #dtype('uint8')
# 【3】ROI截取:
roi = img[100:200,300:400] #截取100行到200行,列为300到400列的整块区域
img[50:150,200:300] = roi #将截取的roi移动到该区域 (50到100行,200到300列)
b = img[:,:,0] #截取整个蓝色通道
b,g,r = cv2.split(img) #截取三个通道,比较耗时
img = cv2.merge((b,g,r))
3.添加边界:
(1)函数格式:
cv2.copyMakeBorder()
参数:
img:图像对象
top,bottom,left,right: 上下左右边界宽度,单位为像素值
borderType:
cv2.BORDER_CONSTANT, 带颜色的边界,需要传入另外一个颜色值
cv2.BORDER_REFLECT, 边缘元素的镜像反射做为边界
cv2.BORDER_REFLECT_101/cv2.BORDER_DEFAULT
cv2.BORDER_REPLICATE, 边缘元素的复制做为边界
CV2.BORDER_WRAP
value: borderType为cv2.BORDER_CONSTANT时,传入的边界颜色值,如[0,255,0]
(2)应用举例:
import cv2 as cv
import matplotlib.pyplot as plt
img2 = cv.imread("2.jpg")
img = cv.cvtColor(img2,cv.COLOR_BGR2RGB) #matplotlib的图像为RGB格式
constant = cv.copyMakeBorder(img,20,20,20,20,cv.BORDER_CONSTANT,value=[0,255,0]) #绿色
reflect = cv.copyMakeBorder(img,20,20,20,20,cv.BORDER_REFLECT)
reflect01 = cv.copyMakeBorder(img,20,20,20,20,cv.BORDER_REFLECT_101)
replicate = cv.copyMakeBorder(img,20,20,20,20,cv.BORDER_REPLICATE)
wrap = cv.copyMakeBorder(img,20,20,20,20,cv.BORDER_WRAP)
titles = ["constant","reflect","reflect01","replicate","wrap"]
images = [constant,reflect,reflect01,replicate,wrap]
for i in range(5):
plt.subplot(2,3,i+1),plt.imshow(images[i]),plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
4.像素算术运算:
(1)函数格式:
# 【1】注意:图像相加时应该用cv2.add(img1,img2)代替img1+img2
cv2.add()
参数:
img1:图片对象1
img2:图片对象2
mask:None (掩膜,一般用灰度图做掩膜,img1和img2相加后,和掩膜与运算,从而达到掩盖部分区域的目的)
dtype:-1
# 【2】两张图片相加,分别给予不同权重,实现图片融合和透明背景等效果
cv2.addWeighted()
参数:
img1:图片对象1
alpha:img1的权重
img2:图片对象2
beta:img1的权重
gamma:常量值,图像相加后再加上常量值
dtype:返回图像的数据类型,默认为-1,和img1一样
(img1*alpha+img2*beta+gamma)
(2)应用举例:
# 【1】
import cv2 as cv
import numpy as np
img1 = cv.imread("2.jpg",0)
roi_img = np.zeros(img1.shape[0:2],dtype=np.uint8)
roi_img[100:280,400:550] = 255
img_add = cv.add(img1,img1)
img_add_mask = cv.add(img1,img1,mask=roi_img)
cv.imshow("img_add",img_add)
cv.imshow("img_add_mask",img_add_mask)
cv.waitKey(0)
cv.destroyAllWindows()
# 【2】
import cv2 as cv
img1 = cv.imread("1.jpg")
img = img1[0:426,43:683]
img2 = cv.imread("2.jpg")
blend = cv.addWeighted(img,0.5,img2,0.9,0) #两张图的大小和通道也应该相同
cv.imshow("blend",blend)
cv.waitKey()
cv.destroyAllWindows()
5.图像位运算:
(1)函数格式:
# 【1】与运算
cv2.btwise_and():
参数:
img1:图片对象1
img2:图片对象2
mask:掩膜
# 【2】或运算
cv2.bitwise_or():
参数:
img1:图片对象1
img2:图片对象2
mask:掩膜
# 【3】非运算
cv2.bitwise_not():
img1:图片对象1
mask:掩膜
# 【4】异或运算,相同为1,不同为0(1^1=0,1^0=1)
cv2.bitwise_xor():
img1:图片对象1
img2:图片对象2
mask:掩膜
(2)应用举例:
import cv2 as cv
import matplotlib.pyplot as plt
img1 = cv.imread("1.png")
rows,cols = img1.shape[0:2]
img2 = cv.imread("2.jpg")
roi = img2[0:rows,0:cols]
img1_gray = cv.cvtColor(img1,cv.COLOR_BGR2GRAY)
ret,img1_thres = cv.threshold(img1_gray,200,255,cv.THRESH_BINARY_INV)
img1_fg =cv.add(img1,img1,mask=img1_thres) #logo图案的前景
img1_thres_inv = cv.bitwise_not(img1_thres)
roi_bg = cv.add(roi,roi,mask=img1_thres_inv) #roi图案的背景
img_add = cv.add(img1_fg,roi_bg) #背景和前景相加
img2[0:rows,0:cols] = img_add
cv.imshow("gray",img1_gray)
cv.imshow("thres",img1_thres)
cv.imshow("fg",img1_fg)
cv.imshow("tinv",img1_thres_inv)
cv.imshow("roi_bg",roi_bg)
cv.imshow("img_add",img_add)
cv.imshow("img2",img2)
cv.waitKey(0)
cv.destroyAllWindows()
6.图像颜色空间转换:
# 【1】
cv2.cvtColor()
参数:
img: 图像对象
code:
cv2.COLOR_RGB2GRAY: RGB转换到灰度模式
cv2.COLOR_RGB2HSV: RGB转换到HSV模式(hue,saturation,Value)
# 【2】
cv2.inRange()
参数:
img: 图像对象/array
lowerb: 低边界array, 如lower_blue = np.array([110,50,50])
upperb:高边界array, 如 upper_blue = np.array([130,255,255])
mask = cv2.inRange(hsv, lower_green, upper_green)
# 【3】将arr从fromspace颜色空间转换到tospace颜色空间
import skimage
skimage.color.convert_colorspace(arr, fromspace, tospace)
7.性能评价:
import cv2
img1 = cv2.imread("1.png")
e1 = cv2.getTickCount()
for i in xrange(5,49,2):
img1 = cv2.medianBlur(img1,i)
e2 = cv2.getTickCount()
t = (e2 - e1)/cv2.getTickFrequency()
print(t)
8.绑定TrackBar到图像:
(1)函数格式:
# 【1】为窗口添加trackbar
cv2.createTrackbar()
参数:
trackbarname: trackbar的名字
winname: 窗口的名字
value: trackbar创建时的值
count:trackbar能设置的最大值,最小值总为0
onChange:trackbar值发生变化时的回调函数,trackbar的值作为参数传给onchange
# 【2】获取某个窗口中trackbar的值
cv2.getTrackbarPos()
参数:
trackbarname: trackbar的名字
winname: 窗口的名字
(2)应用举例:
import cv2 as cv
import numpy as np
def nothing(args):
pass
img = cv.imread("1.png")
img_hsv = cv.cvtColor(img,cv.COLOR_BGR2HSV)
cv.namedWindow('tracks')
cv.createTrackbar("LH","tracks",0,255,nothing)
cv.createTrackbar("LS","tracks",0,255,nothing)
cv.createTrackbar("LV","tracks",0,255,nothing)
cv.createTrackbar("UH","tracks",255,255,nothing)
cv.createTrackbar("US","tracks",255,255,nothing)
cv.createTrackbar("UV","tracks",255,255,nothing)
while(1):
l_h = cv.getTrackbarPos("LH","tracks")
l_s = cv.getTrackbarPos("LS","tracks")
l_v = cv.getTrackbarPos("LV","tracks")
u_h = cv.getTrackbarPos("UH","tracks")
u_s = cv.getTrackbarPos("US","tracks")
u_v = cv.getTrackbarPos("UV","tracks")
lower_b = np.array([l_h,l_s,l_v])
upper_b = np.array([u_h,u_s,u_v])
mask = cv.inRange(img_hsv,lower_b,upper_b)
res = cv.add(img,img,mask=mask)
cv.imshow("img",img)
cv.imshow("mask",mask)
cv.imshow("res",res)
k = cv.waitKey(1)
if k==27:
break
cv.destroyAllWindows()
9.图像阈值分割:
(1)函数格式:
# 【1】
cv2.threshold():
参数:
img:图像对象,必须是灰度图
thresh:阈值
maxval:最大值
type:
cv2.THRESH_BINARY: 小于阈值的像素置为0,大于阈值的置为maxval
cv2.THRESH_BINARY_INV: 小于阈值的像素置为maxval,大于阈值的置为0
cv2.THRESH_TRUNC: 小于阈值的像素不变,大于阈值的置为thresh
cv2.THRESH_TOZERO 小于阈值的像素置0,大于阈值的不变
cv2.THRESH_TOZERO_INV 小于阈值的不变,大于阈值的像素置0
返回值:
ret:阈值
img:阈值化处理后的图像
# 【2】
cv2.adaptiveThreshold() 自适应阈值处理,图像不同部位采用不同的阈值进行处理
参数:
img: 图像对象,8-bit单通道图
maxValue:最大值
adaptiveMethod: 自适应方法
cv2.ADAPTIVE_THRESH_MEAN_C :阈值为周围像素的平均值
cv2.ADAPTIVE_THRESH_GAUSSIAN_C : 阈值为周围像素的高斯均值(按权重)
threshType:
cv2.THRESH_BINARY: 小于阈值的像素置为0,大于阈值的置为maxValuel
cv2.THRESH_BINARY_INV: 小于阈值的像素置为maxValue,大于阈值的置为0
blocksize: 计算阈值时,自适应的窗口大小,必须为奇数 (如3:表示附近3个像素范围内的像素点,进行计算阈值)
C: 常数值,通过自适应方法计算的值,减去该常数值
(2)应用举例:
import cv2 as cv
import matplotlib.pyplot as plt
img = cv.imread("1.png",0)
ret,thre1 = cv.threshold(img,127,255,cv.THRESH_BINARY)
adaptive_thre1 = cv.adaptiveThreshold(img,255,cv.ADAPTIVE_THRESH_MEAN_C,cv.THRESH_BINARY,7,2)
adaptive_thre2 = cv.adaptiveThreshold(img,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,cv.THRESH_BINARY,7,2)
titles = ["img","thre1","adaptive_thre1","adaptive_thre2"]
imgs = [img,thre1,adaptive_thre1,adaptive_thre2 ]
for i in range(4):
plt.subplot(2,2,i+1), plt.imshow(imgs[i],"gray")
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
10.图像缩放:
(1)函数格式:
# 放大和缩小图像
cv2.resize()
参数:
src: 输入图像对象
dsize:输出矩阵/图像的大小,为0时计算方式如下:dsize = Size(round(fx*src.cols),round(fy*src.rows))
fx: 水平轴的缩放因子,为0时计算方式: (double)dsize.width/src.cols
fy: 垂直轴的缩放因子,为0时计算方式: (double)dsize.heigh/src.rows
interpolation:插值算法
cv2.INTER_NEAREST : 最近邻插值法
cv2.INTER_LINEAR 默认值,双线性插值法
cv2.INTER_AREA 基于局部像素的重采样(resampling using pixel area relation)。对于图像抽取(image decimation)来说,这可能是一个更好的方法。但如果是放大图像时,它和最近邻法的效果类似。
cv2.INTER_CUBIC 基于4x4像素邻域的3次插值法
cv2.INTER_LANCZOS4 基于8x8像素邻域的Lanczos插值
其中cv2.INTER_AREA 适合于图像缩小, cv2.INTER_CUBIC (slow) & cv2.INTER_LINEAR 适合于图像放大
(2)应用举例 :
import cv2
import numpy as np
img = cv2.imread('1.jpg')
res = cv2.resize(img,None,fx=2, fy=2, interpolation = cv2.INTER_CUBIC)
height, width = img.shape[:2]
res = cv2.resize(img,(2*width, 2*height), interpolation = cv2.INTER_CUBIC)
11.仿射变换:
(1)函数格式 :
# 【1】仿射变换(从二维坐标到二维坐标之间的线性变换,且保持二维图形的“平直性”和“平行性”。仿射变换可以通过一系列的原子变换的复合来实现,包括平移,缩放,翻转,旋转和剪切)
cv2.warpAffine()
参数:
img: 图像对象
M:2*3 transformation matrix (转变矩阵)
dsize:输出矩阵的大小,注意格式为(cols,rows) 即width对应cols,height对应rows
flags:可选,插值算法标识符,有默认值INTER_LINEAR,
如果插值算法为WARP_INVERSE_MAP, warpAffine函数使用如下矩阵进行图像转dst(x,y)=src(M11*x+M12*y+M13,M21*x+M22*y+M23)
borderMode:可选, 边界像素模式,有默认值BORDER_CONSTANT
borderValue:可选,边界取值,有默认值Scalar()即0
# 【2】返回2*3的转变矩阵(浮点型)
cv2.getRotationMatrix2D()
参数:
center:旋转的中心点坐标
angle:旋转角度,单位为度数,证书表示逆时针旋转
scale:同方向的放大倍数
# 【3】仿射变换矩阵的计算,返回2*3的转变矩阵
cv2.getAffineTransform()
参数:
src:原图像中的三组坐标,如np.float32([[50,50],[200,50],[50,200]])
dst: 转换后的对应三组坐标,如np.float32([[10,100],[200,50],[100,250]])
(2)应用举例 :
# 【1】
import cv2
import numpy as np
img = cv2.imread('1.jpg',0)
rows,cols = img.shape
M = np.float32([[1,0,100],[0,1,50]])
dst = cv2.warpAffine(img,M,(cols,rows))
cv2.imshow('img',dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 【2】
import cv2
import numpy as np
import matplotlib.pylab as plt
img = cv2.imread('2.jpg', 0)
rows, cols= img.shape
pts1 = np.float32([[50,50],[200,50],[50,200]])
pts2 = np.float32([[10,100],[200,50],[100,250]])
M = cv2.getAffineTransform(pts1,pts2)
dst = cv2.warpAffine(img,M,(cols,rows))
plt.subplot(121),plt.imshow(img)
plt.subplot(122),plt.imshow(dst)
plt.show()
12.透视变化:
(1)函数格式 :
# 【1】
cv2.getPerspectiveTransform() 返回3*3的转变矩阵
参数:
src:原图像中的四组坐标,如 np.float32([[56,65],[368,52],[28,387],[389,390]])
dst: 转换后的对应四组坐标,如np.float32([[0,0],[300,0],[0,300],[300,300]])
# 【2】
cv2.wrapPerspective()
参数:
src: 图像对象
M:3*3 transformation matrix (转变矩阵)
dsize:输出矩阵的大小,注意格式为(cols,rows) 即width对应cols,height对应rows
flags:可选,插值算法标识符,有默认值INTER_LINEAR,
如果插值算法为WARP_INVERSE_MAP, warpAffine函数使用如下矩阵进行图像转dst(x,y)=src(M11*x+M12*y+M13,M21*x+M22*y+M23)
borderMode:可选, 边界像素模式,有默认值BORDER_CONSTANT
borderValue:可选,边界取值,有默认值Scalar()即0
(2)应用举例:
img = cv2.imread('1.png')
rows,cols,ch = img.shape
pts1 = np.float32([[56,65],[368,52],[28,387],[389,390]])
pts2 = np.float32([[0,0],[300,0],[0,300],[300,300]])
M = cv2.getPerspectiveTransform(pts1,pts2)
dst = cv2.warpPerspective(img,M,(300,300))
plt.subplot(121),plt.imshow(img),plt.title('Input')
plt.subplot(122),plt.imshow(dst),plt.title('Output')
plt.show()
13:直方图绘制:
灰度直方图绘制:
1)可以利用opencv的calcHist()统计像素值出现次数,通过matploblib的plot()绘制;
2)可以直接利用matploblib的hist()方法。
(1)函数格式 :
# 【1】
cv2.calcHist()
参数:
img:输入图像,为列表,如[img]
channels: 计算的通道,为列表,如[0]表示单通道,[0,1]统计两个通道
mask: 掩模,和输入图像大小一样的矩阵,为1的地方会进行统计(与图像逻辑与后再统计);无掩模时为None
histSize: 每一个channel对应的bins个数,为列表,如[256]表示256个像素值
ranges: bins的边界,为列表,如[0,256]表示像素值范围在0-256之间
accumulate: Accumulation flag
(2)应用举例 :
# 【1】cv.calcHist
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
img = cv.imread("2.jpg",0)
hist = cv.calcHist([img],[0],None,[256],[0,256])
plt.subplot(1,3,1),plt.plot(hist,color="r"),plt.axis([0,256,0,np.max(hist)])
plt.xlabel("gray level")
plt.ylabel("number of pixels")
plt.subplot(1,3,2),plt.hist(img.ravel(),bins=256,range=[0,256]),plt.xlim([0,256])
plt.xlabel("gray level")
plt.ylabel("number of pixels")
plt.subplot(1,3,3)
plt.plot(hist,color="r"),plt.axis([0,256,0,np.max(hist)])
plt.hist(img.ravel(),bins=256,range=[0,256]),plt.xlim([0,256])
plt.xlabel("gray level")
plt.ylabel("number of pixels")
plt.show()
# 【2】np.histogram
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
img = cv.imread("2.jpg",0)
histogram,bins = np.histogram(img,bins=256,range=[0,256])
print(histogram)
plt.plot(histogram,color="g")
plt.axis([0,256,0,np.max(histogram)])
plt.xlabel("gray level")
plt.ylabel("number of pixels")
plt.show()
# 【3】plt.hist
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
img = cv.imread("2.jpg",0)
rows,cols = img.shape
hist = img.reshape(rows*cols)
histogram,bins,patch = plt.hist(hist,256,facecolor="green",histtype="bar") #histogram即为统计出的灰度值分布
plt.xlabel("gray level")
plt.ylabel("number of pixels")
plt.axis([0,255,0,np.max(histogram)])
plt.show()
14:对比度增强:
(1)线性变换 :
1)函数格式:
cv2.convertScaleAbs(src,alpha,beta)
src: 图像对象矩阵
dst:输出图像矩阵
alpha:y=ax+b中的a值
beta:y=ax+b中的b值
(对于计算后大于255的像素值会截断为255)
2)应用举例:
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
img = cv.imread("2.jpg")
print(img)
img_bright = cv.convertScaleAbs(img,alpha=1.5,beta=0)
print(img_bright)
cv.imshow("img",img)
cv.imshow("img_bright",img_bright)
cv.waitKey(0)
cv.destroyAllWindows()
(2)直方图规范化 :
直方图正规化的系数固定,一般将原图片的像素值范围映射到[0,255]范围内。
1)函数格式:
cv2.normalize(src,dst,alpha,beta,normType,dtype,mask)
参数:
src: 图像对象矩阵
dst:输出图像矩阵(和src的shape一样)
alpha:正规化的值,如果是范围值,为范围的下限 (alpha – norm value to normalize to or the lower range boundary in case of the range normalization.)
beta:如果是范围值,为范围的上限;正规化中不用到 ( upper range boundary in case of the range normalization; it is not used for the norm normalization.)
norm_type:normalize的类型
cv2.NORM_L1:将像素矩阵的1-范数做为最大值(矩阵中值的绝对值的和)
cv2.NORM_L2:将像素矩阵的2-范数做为最大值(矩阵中值的平方和的开方)
cv2.NORM_MINMAX:将像素矩阵的∞-范数做为最大值 (矩阵中值的绝对值的最大值)
dtype: 输出图像矩阵的数据类型,默认为-1,即和src一样
mask:掩模矩阵,只对感兴趣的地方归一化
2)应用实例:
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
img = cv.imread("2.jpg")
img_norm=cv.normalize(img,dst=None,alpha=350,beta=10,norm_type=cv.NORM_MINMAX)
cv.imshow("img",img)
cv.imshow("img_norm",img_norm)
cv.waitKey(0)
cv.destroyAllWindows()
(3)伽玛变换:
将输入图像的像素值除以255,归一化到[0,1]区间,然后计算其γ次方值,用公式表示如下,其中I(r,c)为归一化后的像素值,当γ=1时原像素值不影响,当0<γ<1时,增大像素值,提高图片对比度;反之γ>1时能降低图片对比度。
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
img = cv.imread("2.jpg")
img_norm = img/255.0 #注意255.0得采用浮点数
img_gamma = np.power(img_norm,0.4)*255.0
img_gamma = img_gamma.astype(np.uint8)
cv.imshow("img",img)
cv.imshow("img_gamma",img_gamma)
cv.waitKey(0)
cv.destroyAllWindows()
(4)全局直方图均衡化:
直方图均衡化的目的是将原图片每个像素值的像素点个数进行重新分配到[0,255]的256个像素值上,使得每个像素值对应的像素点个数近似相等,即重新分配后,0-255的每个像素值对应的像素点个数近似为(rows*cols/256)。
1)函数格式:
cv2.equalizeHist(src,dst)
src: 图像对象矩阵,必须为单通道的uint8类型的矩阵数据
dst:输出图像矩阵(和src的shape一样)
2)应用举例:
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
import math
img = cv.imread("2.jpg",0)
img_equalize = cv.equalizeHist(img)
cv.imshow("img",img)
cv.imshow("img_equalize",img_equalize)
cv.waitKey(0)
cv.destroyAllWindows()
(5)限制对比度自适应直方图均衡化:
相比全局直方图均衡化,自适应直方图均衡化将图像划分为不重叠的小块,在每一小块进行直方图均衡化,但若小块内有噪声,影响很大,需要通过限制对比度来进行抑制,即限制对比度自适应直方图均衡化。如果限制对比度的阈值设置会40,在局部直方图分布中某个像素值出现次数为45,那么多出的5次像素点会被去掉,平均成其他像素值。
1)函数格式:
# 【1】
clahe=cv2.createCLAHE(clipLimit,tileGridSize)
clipLimit:限制对比度的阈值,默认为40,直方图中像素值出现次数大于该阈值,多余的次数会被重新分配
tileGridSize:图像会被划分的size, 如tileGridSize=(8,8),默认为(8,8)
# 【2】
calhe.apply(img) #对img进行限制对比度自适应直方图均衡化
2)应用举例:
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
import math
img = cv.imread("2.jpg",0)
clahe = cv.createCLAHE(3,(8,8))
dst = clahe.apply(img)
cv.imshow("img",img)
cv.imshow("dst",dst)
cv.waitKey(0)
cv.destroyAllWindows()
15.二维离散卷积:
三种卷积类型:
1)Full卷积:从filter和图像刚相交开始做卷积;
2)Same卷积:当filter的锚点(K)与图像的边角重合时,开始做卷积运算,filter的运动范围比full模式小了一圈,Same卷积为Full卷积的子集,即Full卷积的处理结果包括Same mode;
3)Valid卷积:当filter全部在图像里面的时候,进行卷积运算,可见filter的移动范围较Same卷积更小了,同样Valid 卷积为Same卷积的子集。valid mode的卷积计算,填充边界中的像素值不会参与计算,即无效的填充边界不影响卷积,所以称为Valid mode。
from scipy import signal
# 【1】
signal.convolve2d(src,kernel,mode,boundary,fillvalue)
参数:
src: 输入的图像矩阵,只支持单通的(即二维矩阵)
kernel:卷积核
mode:卷积类型:full, same, valid
boundary:边界填充方式:fill,wrap, symm
fillvalue: 当boundary为fill时,边界填充的值,默认为0
# 【2】 翻转卷积核
dst = cv2.flip(src,flipCode)
src: 输入矩阵
flipCode:0表示沿着x轴翻转,1表示沿着y轴翻转,-1表示分别沿着x轴,y轴翻转
dst:输出矩阵(和src的shape一样)
# 【3】filter2D()进行same卷积
cv2.filter2D(src,dst,ddepth,kernel,anchor=(-1,-1),delta=0,borderType=cv2.BORDER_DEFAULT)
src: 输入图像对象矩阵
dst:输出图像矩阵
ddepth:输出矩阵的数值类型
kernel:卷积核
anchor:卷积核锚点,默认(-1,-1)表示卷积核的中心位置
delat:卷积完后相加的常数
borderType:填充边界类型
16.图像平滑:
(1)高斯平滑:
1)函数格式:
# 【1】进行高斯平滑
dst = cv2.GaussianBlur(src,ksize,sigmaX,sigmay,borderType)
src: 输入图像矩阵,可为单通道或多通道,多通道时分别对每个通道进行卷积
dst:输出图像矩阵,大小和数据类型都与src相同
ksize:高斯卷积核的大小,宽,高都为奇数,且可以不相同
sigmaX: 一维水平方向高斯卷积核的标准差
sigmaY: 一维垂直方向高斯卷积核的标准差,默认值为0,表示与sigmaX相同
borderType:填充边界类型
# 【2】生成一维高斯卷积核
cv2.getGaussianKernel(ksize,sigma,ktype)
ksize:奇数,一维核长度
sigma:标准差
ktype:数据格式,应该为CV_32F 或者 CV_64F
2)应用举例:
# 【1】
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
img = cv.imread("2.jpg")
img_gauss = cv.GaussianBlur(img,(3,3),1)
cv.imshow("img",img)
cv.imshow("img_gauss",img_gauss)
cv.waitKey(0)
cv.destroyAllWindows()
# 【2】
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
from scipy import signal
def gaussianBlur(img,h,w,sigma,boundary="fill",fillvalue=0):
kernel_x = cv.getGaussianKernel(w,sigma,cv.CV_64F) #默认得到的为垂直矩阵
kernel_x = np.transpose(kernel_x) #转置操作,得到水平矩阵
#convolve2d只是对单通道进行卷积,若要实现cv.GaussianBlur()多通道高斯卷积,需要拆分三个通道进行,再合并
#水平方向卷积
gaussian_x = signal.convolve2d(img,kernel_x,mode="same",boundary=boundary,fillvalue=fillvalue)
#垂直方向卷积
kernel_y = cv.getGaussianKernel(h,sigma,cv.CV_64F)
gaussian_xy = signal.convolve2d(gaussian_x,kernel_y,mode="same",boundary=boundary,fillvalue=fillvalue)
#cv.CV_64F数据转换为uint8
gaussian_xy = np.round(gaussian_xy)
gaussian_xy = gaussian_xy.astype(np.uint8)
return gaussian_xy
if __name__=="__main__":
img = cv.imread("2.jpg",0)
img_gauss = gaussianBlur(img,3,3,1)
cv.imshow("img",img)
cv.imshow("img_gauss",img_gauss)
cv.waitKey(0)
cv.destroyAllWindows()
(2)均值滤波:
1)函数格式:
# 【1】
cv2.boxFilter(src,ddepth,ksize,dst,anchor,normalize,borderType)
src: 输入图像对象矩阵,
ddepth:数据格式,位深度
ksize:高斯卷积核的大小,格式为(宽,高)
dst:输出图像矩阵,大小和数据类型都与src相同
anchor:卷积核锚点,默认(-1,-1)表示卷积核的中心位置
normalize:是否归一化 (若卷积核3*5,归一化卷积核需要除以15)
borderType:填充边界类型
# 【2】
cv2.blur(src,ksize,dst,anchor,borderType)
src: 输入图像对象矩阵,可以为单通道或多通道
ksize:高斯卷积核的大小,格式为(宽,高)
dst:输出图像矩阵,大小和数据类型都与src相同
anchor:卷积核锚点,默认(-1,-1)表示卷积核的中心位置
borderType:填充边界类型
2)应用举例:
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
img = cv.imread("2.jpg")
img_blur = cv.blur(img,(3,5))
# img_blur = cv.boxFilter(img,-1,(3,5))
cv.imshow("img",img)
cv.imshow("img_blur",img_blur)
cv.waitKey(0)
cv.destroyAllWindows()
(3)中值滤波:
1)函数格式:
cv2.medianBlur(src,ksize,dst)
src: 输入图像对象矩阵,可以为单通道或多通道
ksize:核的大小,格式为 3 #注意不是(3,3)
dst:输出图像矩阵,大小和数据类型都与src相同
2)应用举例:
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
import random
img = cv.imread("2.jpg")
rows,cols = img.shape[:2]
#加入椒盐噪声
for i in range(100):
r = random.randint(0,rows-1)
c = random.randint(0,cols-1)
img[r,c]=255
img_medianblur = cv.medianBlur(img,5)
cv.imshow("img",img)
cv.imshow("img_medianblur",img_medianblur)
cv.waitKey(0)
cv.destroyAllWindows()
(4)双边滤波:
双边滤波在平滑的同时还能保持图像中物体的轮廓信息。双边滤波在高斯平滑的基础上引入了灰度值相似性权重因子,所以在构建其卷积核核时,要同时考虑空间距离权重和灰度值相似性权重。在进行卷积时,每个位置的邻域内,根据和锚点的距离d构建距离权重模板,根据和锚点灰度值差异r构建灰度值权重模板,结合两个模板生成该位置的卷积核。
1)函数格式:
dst = cv2.bilateralFilter(src,d,sigmaColor,sigmaSpace,borderType)
src: 输入图像对象矩阵,可以为单通道或多通道
d:用来计算卷积核的领域直径,如果d<=0,从sigmaSpace计算d
sigmaColor:颜色空间滤波器标准偏差值,决定多少差值之内的像素会被计算(构建灰度值模板)
sigmaSpace:坐标空间中滤波器标准偏差值。如果d>0,设置不起作用,否则根据它来计算d值(构建距离权重模板)
2)应用举例:
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
import random
import math
img = cv.imread("2.jpg")
img_bilateral = cv.bilateralFilter(img,0,0.2,40)
cv.imshow("img",img)
cv.imshow("img_bilateral",img_bilateral)
cv.waitKey(0)
cv.destroyAllWindows()
(5)联合双边滤波:
双边滤波是根据原图中不同位置灰度相似性来构建相似性权重模板,而联合滤波是先对原图进行高斯平滑,然后根据平滑后的图像灰度值差异建立相似性模板,再与距离权重模板相乘得到最终的卷积核,最后再对原图进行处理。所以相比于双边滤波,联合双边滤波只是建立灰度值相似性模板的方法不一样。
opencv 2中不支持联合双边滤波,opencv 3中除了主模块还引入了contrib,其中的ximgproc模块包括了联合双边滤波的算法。因此如果需要使用opencv的联合双边滤波,需要安装opencv-contrib-python包。
1)函数格式:
dst = cv2.xmingproc.jointBilateralFilter(joint,src,d,sigmaColor,sigmaSpace,borderType)
joint: 进行联合滤波的导向图像,可以为单通道或多通道,保持边缘的滤波算法时常采用src
src: 输入图像对象矩阵,可以为单通道或多通道
d:用来计算卷积核的领域直径,如果d<0,从sigmaSpace计算d
sigmaColor:颜色空间滤波器标准偏差值,决定多少差值之内的像素会被计算(构建灰度值模板)
sigmaSpace:坐标空间中滤波器标准偏差值。如果d>0,设置不起作用,否则根据它来计算d值(构建距离权重模板)
2)应用举例:
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
import random
import math
src = cv.imread("2.jpg")
joint = cv.GaussianBlur(src,(7,7),1,0)
dst = cv.ximgproc.jointBilateralFilter(joint,src,33,2,0)
# dst = cv.ximgproc.jointBilateralFilter(src,src,33,2,0) #采用src作为joint
cv.imshow("img",src)
cv.imshow("joint",joint)
cv.imshow("dst",dst)
cv.waitKey(0)
cv.destroyAllWindows()
(6)导向滤波:
导向滤波也是需要一张图片作为引导图片,来表明边缘,物体等信息,作为保持边缘滤波算法,可以采用自身作为导向图片。opencv2中暂不支持导向滤波, 同样在opencv-contrib-python包的ximgproc模块提供了导向滤波函数。
1)函数格式:
cv2.ximgproc.guidedFilter(guide,src,radius,eps,dDepth)
guide: 导向图片,单通道或三通道
src: 输入图像对象矩阵,可以为单通道或多通道
radius:用来计算卷积核的领域直径
eps:规范化参数, eps的平方类似于双边滤波中的sigmaColor(颜色空间滤波器标准偏差值)
(regularization term of Guided Filter. eps2 is similar to the sigma in the color space into bilateralFilter.)
dDepth: 输出图片的数据深度
2)应用实例:
import cv2 as cv
src = cv.imread("2.jpg")
dst = cv.ximgproc.guidedFilter(src,src,33,2,-1)
cv.imshow("img",src)
cv.imshow("dst",dst)
cv.waitKey(0)
cv.destroyAllWindows()
17.腐蚀处理:
(1)函数格式:
# 【1】获得腐蚀核
kernel=cv2.getStructuringElement(shape,ksize,anchor)
shape:核的形状
cv2.MORPH_RECT: 矩形
cv2.MORPH_CROSS: 十字形(以矩形的锚点为中心的十字架)
cv2.MORPH_ELLIPSE:椭圆(矩形的内切椭圆)
ksize: 核的大小,矩形的宽,高格式为(width,height)
anchor: 核的锚点,默认值为(-1,-1),即核的中心点
# 【2】执行腐蚀操作
dst=cv2.erode(src,kernel,anchor,iterations,borderType,borderValue):
src: 输入图像对象矩阵,为二值化图像
kernel:进行腐蚀操作的核,可以通过函数getStructuringElement()获得
anchor:锚点,默认为(-1,-1)
iterations:腐蚀操作的次数,默认为1
borderType: 边界种类,有默认值
borderValue:边界值,有默认值
(2)应用实例:
import cv2 as cv
img = cv.imread("2.png")
img_cvt = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
ret,img_thr = cv.threshold(img_cvt,200,255,cv.THRESH_BINARY_INV)
kernel = cv.getStructuringElement(cv.MORPH_RECT,(3,5))
dst = cv.erode(img_thr,kernel,iterations=1)
cv.imshow("img",img)
cv.imshow("img_thr",img_thr)
cv.imshow("dst",dst)
cv.waitKey(0)
cv.destroyAllWindows()
18.膨胀处理:
(1)函数格式:
dst = cv2.dilate(src,kernel,anchor,iterations,borderType,borderValue)
src: 输入图像对象矩阵,为二值化图像
kernel:进行腐蚀操作的核,可以通过函数getStructuringElement()获得
anchor:锚点,默认为(-1,-1)
iterations:腐蚀操作的次数,默认为1
borderType: 边界种类
borderValue:边界值
(2)应用实例:
import cv2 as cv
img = cv.imread("2.jpg")
img_cvt = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
ret,img_thr = cv.threshold(img_cvt,500,255,cv.THRESH_BINARY_INV)
kernel = cv.getStructuringElement(cv.MORPH_RECT,(3,5))
dst = cv.dilate(img_thr,kernel,iterations=1)
cv.imshow("img",img)
cv.imshow("img_thr",img_thr)
cv.imshow("dst",dst)
cv.waitKey(0)
cv.destroyAllWindows()
19.开运算/闭运算/形态学梯度/顶帽/底帽:
开运算:先进行腐蚀操作,后进行膨胀操作,主要用来去除一些较亮的部分,即先腐蚀掉不要的部分,再进行膨胀;
闭运算:先进行膨胀操作,后进行腐蚀操作,主要用来去除一些较暗的部分;
形态学梯度:膨胀运算结果减去腐蚀运算结果,可以拿到轮廓信息;
顶帽运算:原图像减去开运算结果;
底帽运算:原图像减去闭运算结果。
(1)函数格式:
dst = cv2.morphologyEx(src,op,kernel,anchor,iterations,borderType,borderValue)
src: 输入图像对象矩阵,为二值化图像
op: 形态学操作类型
cv2.MORPH_OPEN 开运算
cv2.MORPH_CLOSE 闭运算
cv2.MORPH_GRADIENT 形态梯度
cv2.MORPH_TOPHAT 顶帽运算
cv2.MORPH_BLACKHAT 底帽运算
kernel:进行腐蚀操作的核,可以通过函数getStructuringElement()获得
anchor:锚点,默认为(-1,-1)
iterations:腐蚀操作的次数,默认为1
borderType: 边界种类
borderValue:边界值
(2)应用实例:
import cv2 as cv
import matplotlib.pyplot as plt
img = cv.imread("2.jpg")
img_cvt = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
ret,img_thr = cv.threshold(img_cvt,20,255,cv.THRESH_BINARY_INV)
kernel = cv.getStructuringElement(cv.MORPH_RECT,(3,5))
open = cv.morphologyEx(img_thr,cv.MORPH_OPEN,kernel,iterations=1)
close = cv.morphologyEx(img_thr,cv.MORPH_CLOSE,kernel,iterations=1)
gradient = cv.morphologyEx(img_thr,cv.MORPH_GRADIENT,kernel,iterations=1)
tophat = cv.morphologyEx(img_thr,cv.MORPH_TOPHAT,kernel,iterations=1)
blackhat = cv.morphologyEx(img_thr,cv.MORPH_BLACKHAT,kernel,iterations=1)
images=[img_thr,open,close,gradient,tophat,blackhat]
titles=["img_thr","open","close","gradient","tophat","blackhat"]
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()
20.直线、圆、矩形、文字的绘制:
# 【1】绘制直线
# img、ps、pe、color为必须参数,其它为可选项
cv2.line(img, ps, pe, color, thickness, lineType, shift)
参数:
img:要画的直线所在的矩形或图像
ps:直线的起点位置,注意这是一个坐标点,类似(X,Y)
pe:直线的终点位置,同上
color:直线的颜色,颜色值为BGR,即:(0,0,255)为红色
thickness:线条宽度
lineType:线条类型,三个参数可选LINE_4、LINE_8、LINE_AA,感兴趣的可以自己试一下
shift:不常用,直线坐标点小数点位数
# 【2】绘制圆
# img、center、radius、color为必须参数,其它为可选项
cv2.circle(img, center, radius, color, thickness, lineType, shift)
参数:
img:要画的圆所在的矩形或图像
center:圆心坐标
radius:圆的半径值
color:圆边框颜色,颜色值为BGR,即:(0,0,255)为红色
thickness:圆边框大小,负值表示该圆是一个填充图形
lineType:线条类型,三个参数可选0,4,8,感兴趣的亲测
shift:圆心坐标和半径的小数点位数
# 【3】绘制椭圆
# img/center/axes/rotateAngle/startAngle/endAngle/color为必须参数,其它为可选项
cv2.ellipse(img, center, axes, rotateAngle, startAngle, endAngle, color, thickness, lineType, shift)
参数:
img:要画的椭圆所在的矩形或图像
center:椭圆的圆心坐标,注意这是一个坐标值
axes:椭圆的长轴和短轴的长度,这是一个元组信息
rotateAngle:椭圆旋转的角度
startAngle:椭圆弧起始角度
endAngle:椭圆弧终止角度
color:椭圆线条颜色,颜色值为BGR,即:(0,0,255)为红色
thickness:椭圆的线条宽度
lineType:线条类型,三个参数可选LINE_4、LINE_8、LINE_AA,感兴趣的可以亲测
shift:椭圆坐标点小数点位数
# 【4】绘制矩形
# img/ps/pe/color为必须参数,其它为可选项
cv2.rectangle(img, ps, pe, color, thickness, lineType, shift)
参数:
img:矩形所在的矩形或图像
ps:矩形左上角点的坐标
pe:矩形右下角点的坐标
color:线条颜色,颜色值为BGR,即:(0,0,255)为红色
thickness:矩形线条宽度
lineType:线条类型,三个参数可选LINE_4、LINE_8、LINE_AA,感兴趣的可以亲测
shift:坐标点小数点位数
# 【5】绘制多边形
# img/pts/isClosed/color为必须参数,其它为可选项
cv2.polylines(img, pts, isClosed, color, thickness, lineType, shift)
参数:
img:多边形所在的矩形或图像
pts:多边形各边的坐标点组成的一个列表,是一个numpy的数组类型
isClosed:值为True或False,若为True则表示一个闭合的多边形,若为False则不闭合
color:线条颜色,颜色值为BGR,即:(0,0,255)为红色
thickness:线条宽度
lineType:线条类型,三个参数可选LINE_4、LINE_8、LINE_AA,感兴趣的可以亲测
shift:坐标点小数点位数
# 【6】绘制字符
# img/text/org/fontFace/fontScale/color为必须参数,其它为可选项
cv2.putText(img, text, org, fontFace, fontScale, color, thickness, lineType, bottomLeftOrigin)
参数:
img:文字要放置的矩形或图像
text:文字内容
org:文字在图像中的左下角坐标
fontFace:字体类型,可选参数有以下几种
FONT_HERSHEY_SIMPLEX,
FONT_HERSHEY_PLAIN,
FONT_HERSHEY_DUPLEX,
FONT_HERSHEY_COMPLEX,
FONT_HERSHEY_TRIPLEX,
FONT_HERSHEY_COMPLEX_SMALL,
FONT_HERSHEY_SCRIPT_SIMPLEX,
orFONT_HERSHEY_SCRIPT_COMPLEX
上述类型的字体可以结合FONT_HERSHEY_ITALIC一起来使用,从而使字体产生斜体效果。
fontScale:缩放比例,用该值乘以程序字体默认大小即为字体大小
color:字体颜色,颜色值为BGR,即:(0,0,255)为红色
thickness:字体线条宽度
bottomLeftOrigin:默认为 true,即表示图像数据原点在左下角;若为False则表示图像数据原点在左上角。
21.边缘检测:
(1)Canny边缘检测:
平滑图像:使用高斯滤波器与图像进行卷积,平滑图像,以减少边缘检测器上明显的噪声影响;
计算图像的梯度和方向:图像中的边缘可以指向各个方向,这里计算图像的梯度,并将梯度分类为垂直、水平和斜对角;
非最大值抑制:利用上一步计算出来的梯度方向,检测某一像素在梯度的正方向和负方向上是否是局部最大值,如果是,则该像素点保留为边缘点,否则该像素点将被抑制;
双阈值算法检测和连接边缘:仍然存在由于噪声和颜色变化引起的一些边缘像素。为了解决这些杂散响应,必须用弱梯度值过滤边缘像素,并保留具有高梯度值的边缘像素,可以通过选择高低阈值来实现。
1)函数格式:
canny = cv2.Canny(image, threshold1, threshold2[, edges[, apertureSize[, L2gradient ]]])
参数:
image: 处理的原图像,该图像必须为单通道的灰度图
threshold1: 最小阈值
threshold2 最大阈值
2)应用实例:
import os
import cv2
img = cv2.imread('2.jpg', 0) #转化为灰度图
img_color = img
blur = cv2.GaussianBlur(img, (3, 3), 0) # 用高斯滤波处理原图像降噪
canny = cv2.Canny(blur, 50, 150) # 50是最小阈值,150是最大阈值
cv2.namedWindow("canny",0);#可调大小
cv2.namedWindow("1",0);#可调大小
cv2.imshow('1', img)
cv2.imshow('canny', canny)
cv2.waitKey(0)
cv2.destroyAllWindows()
(2)Sobel边缘检测:
Sobel算子包含两个3*3矩阵,分别为横向和纵向,将之与图像做平面卷积,可分别得出横向及纵向的高度差分近似值,图像的每一个像素点的横向与纵向灰度值平方和开方获得该点灰度的大小。
1)函数格式:
# 【1】
Sobel_x_or_y = cv2.Sobel(src, ddepth, dx, dy, dst, ksize, scale, delta, borderType)
参数:
src:需要处理的图像;
ddepth:图像的深度,-1表示采用的是与原图像相同的深度,目标图像的深度必须大于等于原图像的深度;
dx和dy:求导的阶数,0表示这个方向上没有求导,一般为0、1、2。
# 【2】
convertScaleAbs()
# Sobel函数求完导数后会有负值,还有会大于255的值,convertScaleAbs()函数将sobel算子的处理结果转换为uint8形式,否则将无法显示图像
2)应用实例:
import os
import cv2
img = cv2.imread('2.jpg', 0) #转化为灰度图
x = cv2.Sobel(img, cv2.CV_16S, 1, 0)
y = cv2.Sobel(img, cv2.CV_16S, 0, 1)
# cv2.convertScaleAbs(src[, dst[, alpha[, beta]]])
# alpha是伸缩系数,beta是加到结果上的一个值,结果返回uint类型的图像
Scale_absX = cv2.convertScaleAbs(x)
Scale_absY = cv2.convertScaleAbs(y)
result = cv2.addWeighted(Scale_absX, 0.5, Scale_absY, 0.5, 0)
cv2.namedWindow("result",0);#可调大小
cv2.namedWindow("1",0);#可调大小
cv2.imshow('1', img)
cv2.imshow('result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()
(3)findContours()函数:
1)函数格式:
# 【1】
cv2.findContours(image, mode, method[, contours[, hierarchy[, offset ]]])
参数:
image:寻找轮廓的图像;
mode:轮廓的检索模式,有四种:
1)cv2.RETR_EXTERNAL表示只检测外轮廓
2)cv2.RETR_LIST检测的轮廓不建立等级关系
3)cv2.RETR_CCOMP建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层。
4)cv2.RETR_TREE建立一个等级树结构的轮廓。
method:为轮廓的近似办法
1)cv2.CHAIN_APPROX_NONE存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1
2)cv2.CHAIN_APPROX_SIMPLE压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息
3) cv2.CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似
返回值:
opencv2返回两个值:contours:hierarchy。
opencv3会返回三个值,分别是img, countours, hierarchy。
# 【2】在图像上绘制轮廓。
cv2.drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset ]]]]])
参数:
image:指明在哪幅图像上绘制轮廓;
contours:轮廓本身,在Python中是一个list。
contourIdx:指定绘制轮廓list中的哪条轮廓,如果是-1,则绘制其中的所有轮廓。
thickness:表明轮廓线的宽度,如果是-1(cv2.FILLED),则为填充模式。
22.模版匹配:
模板匹配的原理就是不断地在原图中移动模板图像去比较,模板匹配也是应用卷积来实现的:假设原图大小为W×H,模板图大小为w×h,那么生成图大小是(W-w+1)×(H-h+1),生成图中的每个像素值表示原图与模板的匹配程度。
(1)函数格式:
# 【1】执行目标匹配
cv2.matchTemplate(image, templ, method, result=None, mask=None)
参数:
image:待搜索图像
templ:模板图像
result:匹配结果
method:计算匹配程度的方法:
1)平方差匹配CV_TM_SQDIFF:用两者的平方差来匹配,最好的匹配值为0
2)归一化平方差匹配CV_TM_SQDIFF_NORMED
3)相关匹配CV_TM_CCORR:用两者的乘积匹配,数值越大表明匹配程度越好
4)归一化相关匹配CV_TM_CCORR_NORMED
5)相关系数匹配CV_TM_CCOEFF:用两者的相关系数匹配,1表示完美的匹配,-1表示最差的匹配
6)归一化相关系数匹配CV_TM_CCOEFF_NORMED
# 【2】获取最后的最佳匹配结果获取最后的最佳匹配结果
# 获取一个矩阵a的最小值,最大值,并得到最大值,最小值的索引。
cv2.minMaxLoc(src, mask=None)
(2)应用实例:
# 【1】
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('2.jpg', 0)
template = cv2.imread('pattern.jpg', 0)
h, w = template.shape[:2] # rows->h, cols->w
# 相关系数匹配方法:cv2.TM_CCOEFF
res = cv2.matchTemplate(img, template, cv2.TM_CCOEFF)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
left_top = max_loc # 左上角
right_bottom = (left_top[0] + w, left_top[1] + h) # 右下角
cv2.rectangle(img, left_top, right_bottom, 255, 2) # 画出矩形位置
# 【2】多目标模版匹配
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 1.读入原图和模板
img_rgb = cv2.imread('marioimg.jpg')
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
template = cv2.imread('mariopattern.jpg', 0)
h, w = template.shape[:2]
# 2.标准相关模板匹配
res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)
threshold = 0.8
# 3.np.where返回res中值大于0.8的所有坐标
loc = np.where(res >= threshold) # 匹配程度大于%80的坐标y,x
for pt in zip(*loc[::-1]): # 因为loc是先y坐标再x坐标,所以用loc[::-1]翻转一下,然后再用zip函数拼接在一起
right_bottom = (pt[0] + w, pt[1] + h)
cv2.rectangle(img_rgb, pt, right_bottom, (0, 0, 255), 2)
cv2.imshow('1', img_rgb)
cv2.waitKey(0)
23.凸包:
(1)函数格式:
# 【1】多边形逼近
approx = cv2.approxPolyDP(cnt, epsilon, Flag)
参数:
cnt:待处理轮廓
epsilon: 距离值,表示多边形的轮廓接近实际轮廓的程度,值越小,越精确;
Flag:表示是否闭合
# 【2】寻找凸包,获取凸包的角点
hull2 = cv2.convexHull(cnt, returnPoints=False)
参数:
cnt:待处理轮廓
returnPoints:可选参数,默认是True,代表返回角点的x/y坐标;如果为False的话,表示返回轮廓中是凸包角点的索引
# 【3】判断轮廓是否是凸形的
cv2.isContourConvex(hull)
# 【4】计算点到轮廓的最短距离(也就是垂线)
dist = cv2.pointPolygonTest(cnt, (100, 100), True)
(2)应用实例:
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 1.先找到轮廓
img = cv2.imread('marioimg.jpg', 0)
_, thresh = cv2.threshold(img, 100, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
contours, hierarchy = cv2.findContours(thresh, 3, 2)
image1 = cv2.drawContours(img, contours, -1, 255)
cv2.imshow('1', image1)
cnt = contours[0]
# 2.寻找凸包,得到凸包的角点
hull = cv2.convexHull(cnt)
# 3.绘制凸包
image = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
cv2.polylines(image, [hull], True, (0, 255, 0), 2)
cv2.imshow('3', image)
cv2.waitKey(0)
24.计算轮廓特征:
(1)函数格式:
# 【1】轮廓面积
area = cv2.contourArea(cnt)
# 【2】轮廓周长
perimeter = cv2.arcLength(cnt, True)
参数:
参数2表示轮廓是否封闭,True表示封闭
# 【3】图像矩(其中包含很多轮廓的特征信息)
M = cv2.moments(cnt)
# 【4】rectangle1
x, y, w, h = cv2.boundingRect(cnt)
cv2.rectangle(img_color1, (x, y), (x + w, y + h), (0, 255, 0), 2)
# 【5】rectangle2
rect = cv2.minAreaRect(cnt)
box = np.int0(cv2.boxPoints(rect)) # 矩形的四个角点取整
cv2.drawContours(img_color1, [box], 0, (255, 0, 0), 2) # 绘制矩形
# 【6】最小外接圆
(x, y), radius = cv2.minEnclosingCircle(cnt)
(x, y, radius) = np.int0((x, y, radius)) # 圆心和半径取整
cv2.circle(img_color2, (x, y), radius, (0, 0, 255), 2) # 绘制圆
# 【7】椭圆拟合
ellipse = cv2.fitEllipse(cnt)
cv2.ellipse(img_color2, ellipse, (255, 255, 0), 2)
# 【8】利用hu矩阵返回两个轮廓的形状相似度,返回值越小,越相似
cv2.matchShapes(cnt_b, cnt_b, 1, 0.0)
参数:
参数3:匹配方法
参数4:是OpenCV的预留参数
25.霍夫变换:
(1)霍夫直线变换:
1)函数格式:
# 【1】霍夫直线变换
lines = cv2.HoughLines(edges, 0.8, np.pi / 180, 90)
参数:
参数1:要检测的二值图(一般是阈值分割或边缘检测后的图)
参数2:距离r的精度,值越大,考虑越多的线
参数3:角度θ的精度,值越小,考虑越多的线
参数4:累加数阈值,值越小,考虑越多的线
# 【2】统计概率霍夫直线变换
lines = cv2.HoughLinesP(edges, 0.8, np.pi/180, 90, minLineLength=50, maxLineGap=10)
参数:
参数1:要检测的二值图(一般是阈值分割或边缘检测后的图)
参数2:距离r的精度,值越大,考虑越多的线
参数3:角度θ的精度,值越小,考虑越多的线
参数4:累加数阈值,值越小,考虑越多的线
minLineLength:最短长度阈值,比这个长度短的线会被排除
maxLineGap:同一直线两点之间的最大距离
2)应用实例:
# 【1】
import cv2
import numpy as np
img = cv2.imread('1.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 50, 150)
# 霍夫直线变换
lines = cv2.HoughLines(edges, 0.8, np.pi / 180, 90)
# 绘制直线
for line in lines:
rho, theta = line[0]
a = np.cos(theta)
b = np.sin(theta)
x0 = a * rho
y0 = b * rho
x1 = int(x0 + 1000 * (-b))
y1 = int(y0 + 1000 * (a))
x2 = int(x0 - 1000 * (-b))
y2 = int(y0 - 1000 * (a))
cv2.line(img, (x1, y1), (x2, y2), (0, 0, 255))
cv2.imshow('1', img)
cv2.waitKey(0)
# 【2】
import cv2
import numpy as np
img = cv2.imread('1.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 50, 150)
lines = cv2.HoughLinesP(edges, 0.8, np.pi / 180, 90, minLineLength=50, maxLineGap=10)
for line in lines:
x1, y1, x2, y2 = line[0]
cv2.line(img, (x1, y1), (x2, y2), (0, 255, 0), 1, lineType=cv2.LINE_AA)
cv2.imshow('1', img)
cv2.waitKey(0)
(2)霍夫圆变换:
1)函数格式:
circles = cv2.HoughCircles(edges, cv2.HOUGH_GRADIENT, 1, 20, param2=30)
参数:
参数1:轮廓
参数2:变换方法,一般使用霍夫梯度法,详情:HoughModes
参数3 dp=1:表示霍夫梯度法中累加器图像的分辨率与原图一致
参数4:两个不同圆圆心的最短距离
参数5:param2跟霍夫直线变换中的累加数阈值一样
2)应用实例:
import cv2
import numpy as np
img = cv2.imread('marioimg.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 50, 150)
circles = cv2.HoughCircles(edges, cv2.HOUGH_GRADIENT, 1, 50, param2=30)
circles = np.int0(np.around(circles))
for i in circles[0, :]:
cv2.circle(img, (i[0], i[1]), i[2], (0, 255, 0), 2) # 画出外圆
cv2.circle(img, (i[0], i[1]), 2, (0, 0, 255), 3) # 画出圆心
cv2.imshow('1', img)
cv2.waitKey(0)
26.图像梯度提取:
(1)函数格式:
# 【1】Sobel算子
sobelx = cv2.Sobel(img, -1, 1, 0, ksize=3) # 只计算x方向
sobely = cv2.Sobel(img, -1, 0, 1, ksize=3) # 只计算y方向
# 【2】Laplacian算子
laplacian = cv2.Laplacian(img, -1) # 使用Laplacian算子
#【3】Scharr算子
scharr = cv2.Scharr(src, ddepth, dx, dy, dst=None, scale=None, delta=None, borderType=None, /)
(2)应用实例:
import cv2
def scharr_demo(image):
grad_x = cv2.Scharr(image, cv2.CV_32F, 1, 0) # 采用Scharr边缘更突出
grad_y = cv2.Scharr(image, cv2.CV_32F, 0, 1)
gradx = cv2.convertScaleAbs(grad_x) # 由于算完的图像有正有负,所以对其取绝对值
grady = cv2.convertScaleAbs(grad_y)
# 计算两个图像的权值和,dst = src1*alpha + src2*beta + gamma
gradxy = cv2.addWeighted(gradx, 0.5, grady, 0.5, 0)
cv2.imshow("gradx", gradx)
cv2.imshow("grady", grady)
cv2.imshow("gradient", gradxy)
src = cv2.imread("2.jpg")
cv2.imshow("lena", src)
scharr_demo(src)
cv2.waitKey(0)
cv2.destroyAllWindows()
27.角点检测:
(1)函数格式:
# 【1】harris角点检测
cv.cornerHarris(img,blocksize,ksize,k)
参数:
img:图片
blocksize:角点检测区域的大小
ksize:sobel求导中使用的窗口的大小
k:取值参数
# 【2】Fast检测器
cv.FastFeatureDetector_create([, threshold[, nonmaxSuppression[, type]]])
# 【3】绘制重要点
cv2.drawKeypoints(image,keypoints,outImage[,color[,flags]])
(2)应用实例:
# 【1】
import cv2 as cv
import numpy as np
img = cv.imread('1.jpg')
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
dst = cv.cornerHarris(gray,2,3,0.04)
img[dst>0.01*dst.max()] = [0,0,255]
cv.imshow('res',img)
cv.waitKey(0)
# 【2】
import numpy as np
import cv2
from matplotlib import pyplot as plt
img = cv2.imread('1.jpg',0)
fast=cv2.FastFeatureDetector_create(threshold=20,nonmaxSuppression=True,type=cv2.FAST_FEATURE_DETECTOR_TYPE_9_16) #获取FAST角点探测器
kp=fast.detect(img,None) #描述符
img = cv2.drawKeypoints(img,kp,img,color=(255,0,0)) #画到img上面
print ("Threshold: ", fast.getThreshold()) #输出阈值
print ("nonmaxSuppression: ", fast.getNonmaxSuppression())#是否使用非极大值抑制
print ("Total Keypoints with nonmaxSuppression: ", len(kp))#特征点个数
cv2.imshow('sp',img)
cv2.waitKey(0)
28.图像通道分离与合并:
# 【1】图像通道分离
b, g, r = cv2.split(img)
# 【2】图像通道合并
merge = cv2.merge([b, g, r])
29.图像算术运算:
# 【1】加
dst = cv2.add(m1, m2)
# 【2】减
dst = cv2.subtract(m1, m2)
# 【3】乘
dst = cv2.multiply(m1, m2)
# 【4】除
dst = cv2.divide(m1, m2)
30.像素的均质和方差:
# 【1】均值
M1 = cv2.mean(img)
# 【2】均值和方差
M1, dev1 = cv2.meanStdDev(img)
31.漫水填充:
(1)函数格式:
def floodFill(image, mask, seedPoint, newVal, loDiff=None, upDiff=None, flags=None)
参数:
image:原图像
mask:掩码,单通道8位图像,比image的高度多2个像素,宽度多2个像素。
seedPoint:起始点(原像素点,相当于鼠标点击的那个像素点)
newVal:在重绘区域像素的新值(RBG值,相当于上图指定的红色)
loDiff:像素值的下限差值(最多比原像素点低多少)
upDiff:像素值的上限差值(最多比原像素点高多少)
Flag:
FLOODFILL_FIXED_RANGE:改变图像,泛洪填充
FLOODFILL_MASK_ONLY:不改变图像,只填充遮罩层本身,忽略新的颜色值参数
(2)应用实例:
import cv2
import numpy as np
def fill_color_demo(img):
copyImg = img.copy()
h, w = img.shape[:2]
mask = np.zeros([h + 2, w + 2], np.uint8)
cv2.floodFill(copyImg, mask, (100, 200), (0, 255, 0), (100, 100, 100), (50, 50, 50), cv2.FLOODFILL_FIXED_RANGE)
cv2.imshow("fill_color_demo", copyImg)
def fill_binary_demo():
img2 = np.zeros([400, 400, 3], np.uint8)
img2[100:300, 100:300, :] = 255
mask = np.ones([402, 402], np.uint8)
mask[101:301, 101:301] = 0
cv2.floodFill(img2, mask, (200, 200), (0, 0, 255), cv2.FLOODFILL_MASK_ONLY)
cv2.imshow("fill_binary_demo", img2)
fill_binary_demo()
img = cv2.imread('2.jpg')
fill_color_demo(img)
cv2.waitKey(0)
cv2.destroyAllWindows()
32.K近邻(KNN):
(1)函数格式:
# 【1】
knn = cv.ml.KNearest_create()
# 【2】
knn.train(trainData, cv.ml.ROW_SAMPLE, responses)
# 【3】
ret, results, neighbours ,dist = knn.findNearest(newcomer, 3)
(2)函数格式:
import numpy as np
import cv2
#读取图片转为灰度图
img = cv2.imread('digits.png')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#把图片分隔成5000个,每个20x20大小
cells = [np.hsplit(row,100) for row in np.vsplit(gray,50)]
#再转成numpy数组
x = np.array(cells)
#一半用来训练的数组,一半用来测试的数组
train = x[:, :50].reshape(-1, 400).astype(np.float32)
test = x[:, 50:100].reshape(-1, 400).astype(np.float32)
#创建训练和测试的标签
k = np.arange(10)
train_labels = np.repeat(k,250)[:,np.newaxis]
test_labels = train_labels.copy()
#创建一个K-Nearest Neighbour分类器,训练数据,然后用测试数据测试它
knn = cv2.ml.KNearest_create()
knn.train(train,cv2.ml.ROW_SAMPLE,train_labels)
ret,result,neighbours,dist = knn.findNearest(test,k=5)
#最终检查测试的精确度,比较结果,检查哪些是错误的,最终输出正确率
matches = result == test_labels
correct = np.count_nonzero(matches)
accuracy = correct*100.0 / result.size
print(accuracy)
33.拟合:
(1)直线拟合:
1)函数格式:
line =cv.fitLine(nptest,cv.DIST_L2,0,0.01,0.01)
参数:
points :nparray类型的点集(一般的数列直接报错),待拟合的点的坐标
distType:有关距离的定义,可用最快最简单的L2距离,就是常用的最小二乘法
param:一些距离计算类型(distType)中用到的参数,写0系统会自动选用最优的参数。
reps和aeps:用于表示拟合直线所需要的径向和角度精度,通常情况下两个值均被设定为0.01。
2)应用实例:
import cv2 as cv
import numpy as np
test =[(1,2),(2,4),(3,6)]
nptest=np.array(test)
line =cv.fitLine(nptest,cv.DIST_L2,0,0.01,0.01)
(2)椭圆拟合:
1)函数格式:
ellipse = cv2.fitEllipse(cnt)
2)应用实例:
rrt = cv2.fitEllipse(contours[i])
# 绘制拟合椭圆
cv2.ellipse(ellipse1, rrt,255, 2, cv2.LINE_AA)
x, y = rrt[0]
# 中心
cv2.circle(ellipse1, (np.int(x), np.int(y)), 4, 255, -1, 8, 0)
plt.subplot(2, 3, 6),plt.imshow(ellipse1)
34.图像连通域:
(1)函数格式:
ret, labels = cv2.connectedComponents(gray_img, connectivity=None)
# connectivity 4或8,临近像素为周围4像素或8像素
(2)应用举例:
import cv2
import numpy as np
img = np.array([
[0, 255, 0, 0],
[0, 0, 0, 255],
[0, 0, 0, 255],
[255, 0, 0, 0]
], np.uint8)
_, labels = cv2.connectedComponents(img)
print(labels)
res = cv2.equalizeHist(cv2.convertScaleAbs(labels))
print(res)
35.骨架提取:
import os
import numpy as np
import cv2
import sys
im = cv2.imread("cvLetter.jpg", 0)
ret, im = cv2.threshold(im, 127, 255, cv2.THRESH_BINARY)
element = cv2.getStructuringElement(cv2.MORPH_CROSS, (3, 3))
skel = np.zeros(im.shape, np.uint8)
erode = np.zeros(im.shape, np.uint8)
temp = np.zeros(im.shape, np.uint8)
i = 0
while True:
cv2.imshow('im %d' % (i), im)
erode = cv2.erode(im, element)
temp = cv2.dilate(erode, element)
# 消失的像素是skeleton的一部分
temp = cv2.subtract(im, temp)
cv2.imshow('skeleton part %d' % (i,), temp)
skel = cv2.bitwise_or(skel, temp)
im = erode.copy()
if cv2.countNonZero(im) == 0:
break;
i += 1
cv2.imshow('Skeleton', skel)
cv2.waitKey()
代码来自:https://blog.csdn.net/aipush/article/details/84840870
骨架提取原理请见:https://www.cnblogs.com/xianglan/archive/2011/01/01/1923779.html
# -*- coding: utf-8 -*-
import cv2
def VThin(image, array):
h, w = image.shape
NEXT = 1
for i in range(h):
for j in range(w):
if NEXT == 0:
NEXT = 1
else:
M = int(image[i, j - 1]) + int(image[i, j]) + int(image[i, j + 1]) if 0 < j < w - 1 else 1
if image[i, j] == 0 and M != 0:
a = [0] * 9
for k in range(3):
for l in range(3):
if -1 < (i - 1 + k) < h and -1 < (j - 1 + l) < w and image[i - 1 + k, j - 1 + l] == 255:
a[k * 3 + l] = 1
sum = a[0] * 1 + a[1] * 2 + a[2] * 4 + a[3] * 8 + a[5] * 16 + a[6] * 32 + a[7] * 64 + a[8] * 128
image[i, j] = array[sum] * 255
if array[sum] == 1:
NEXT = 0
return image
def HThin(image, array):
h, w = image.shape
NEXT = 1
for j in range(w):
for i in range(h):
if NEXT == 0:
NEXT = 1
else:
M = int(image[i - 1, j]) + int(image[i, j]) + int(image[i + 1, j]) if 0 < i < h - 1 else 1
if image[i, j] == 0 and M != 0:
a = [0] * 9
for k in range(3):
for l in range(3):
if -1 < (i - 1 + k) < h and -1 < (j - 1 + l) < w and image[i - 1 + k, j - 1 + l] == 255:
a[k * 3 + l] = 1
sum = a[0] * 1 + a[1] * 2 + a[2] * 4 + a[3] * 8 + a[5] * 16 + a[6] * 32 + a[7] * 64 + a[8] * 128
image[i, j] = array[sum] * 255
if array[sum] == 1:
NEXT = 0
return image
def Xihua(image, array, num=10):
for i in range(num):
VThin(image, array)
HThin(image, array)
return image
def main():
# 映射表
array = [0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, \
1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, \
0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, \
1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, \
1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, \
1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, \
0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, \
1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, \
1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, \
1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, \
1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0]
# 读取灰度图片,并显示
img = cv2.imread("cvLetter.jpg", 0) # 直接读为灰度图像
cv2.imshow('image', img)
gaussian_img = cv2.GaussianBlur(img, (5, 5), 5)
kernel3 = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
dilate_img = cv2.dilate(gaussian_img, kernel3)
binary_img = cv2.adaptiveThreshold(dilate_img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY,7, 5)
cv2.imshow('binary', binary_img)
xihua_img = Xihua(binary_img, array)
cv2.imshow('xihua', xihua_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
main()
36.SVM:
(1)函数格式:
https://www.cnblogs.com/xixixing/p/12377090.html
svm = cv.ml.SVM_create()
# 设置核函数:LINEAR/POLY/RBF/SIGMOID
svm.setKernel(cv.ml.SVM_LINEAR)
# 设置迭代终止条件,默认:TermCriteria( TermCriteria::MAX_ITER + TermCriteria::EPS, 1000, FLT_EPSILON )
setTermCriteria()
# 指定SVM的类型:C_SVC/NU_SVC/ONE_CLASS/EPS_SVR/NU_SVR
svm.setType(cv.ml.SVM_C_SVC)
# 核函数相关:适用类型:SVM::POLY, SVM::RBF, SVM::SIGMOID or SVM::CHI2
svm.setGamma(5.383)
# 核函数相关:coef0(默认0)适用类型:SVM::POLY,SVM::SIGMOID
setCoef0()
# 核函数相关:degree(默认0)适用类型:SVM::POLY
setDegree()
# 优化相关:C(默认0)适用类型:SVM::C_SVC, SVM::EPS_SVR ,SVM::NU_SVR
svm.setC(2.67)
# 优化相关:nu(默认0)适用类型:SVM::NU_SVC, SVM::ONE_CLASS,SVM::NU_SVR
setNu()
# 优化相关:epsilon(默认0)适用类型:SVM::EPS_SVR
setP()
(2)应用实例:
import cv2 as cv
import numpy as np
SZ=20
# Number of bins
bin_n = 16
affine_flags = cv.WARP_INVERSE_MAP|cv.INTER_LINEAR
def deskew(img):
m = cv.moments(img)
if abs(m['mu02']) < 1e-2:
return img.copy()
skew = m['mu11']/m['mu02']
M = np.float32([[1, skew, -0.5*SZ*skew], [0, 1, 0]])
img = cv.warpAffine(img,M,(SZ, SZ),flags=affine_flags)
return img
def hog(img):
gx = cv.Sobel(img, cv.CV_32F, 1, 0)
gy = cv.Sobel(img, cv.CV_32F, 0, 1)
mag, ang = cv.cartToPolar(gx, gy)
bins = np.int32(bin_n*ang/(2*np.pi)) # quantizing binvalues in (0...16)
bin_cells = bins[:10,:10], bins[10:,:10], bins[:10,10:], bins[10:,10:]
mag_cells = mag[:10,:10], mag[10:,:10], mag[:10,10:], mag[10:,10:]
hists = [np.bincount(b.ravel(), m.ravel(), bin_n) for b, m in zip(bin_cells, mag_cells)]
hist = np.hstack(hists) # hist is a 64 bit vector
return hist
img = cv.imread('digits.png',0)
cells = [np.hsplit(row,100) for row in np.vsplit(img,50)]
# 前一半是训练数据,其余是测试数据
train_cells = [ i[:50] for i in cells ]
test_cells = [ i[50:] for i in cells]
deskewed = [list(map(deskew,row)) for row in train_cells]
hogdata = [list(map(hog,row)) for row in deskewed]
trainData = np.float32(hogdata).reshape(-1,64)
responses = np.repeat(np.arange(10),250)[:,np.newaxis]
svm = cv.ml.SVM_create()
svm.setKernel(cv.ml.SVM_LINEAR)
svm.setType(cv.ml.SVM_C_SVC)
svm.setC(2.67)
svm.setGamma(5.383)
svm.train(trainData, cv.ml.ROW_SAMPLE, responses)
svm.save('svm_data.dat')
deskewed = [list(map(deskew,row)) for row in test_cells]
hogdata = [list(map(hog,row)) for row in deskewed]
testData = np.float32(hogdata).reshape(-1,bin_n*4)
result = svm.predict(testData)[1]
mask = result==responses
correct = np.count_nonzero(mask)
print(correct*100.0/result.size)
37.频域处理:
https://blog.csdn.net/on2way/article/details/46981825
(1)傅立叶正变换/反变换:
1)函数格式:
# 【1】傅立叶正变换
f = np.fft.fft2(img)
# 【2】中心化
fshift = np.fft.fftshift(f)
#取绝对值:将复数变化成实数
# 【3】去中心化
f1shift = np.fft.ifftshift(fshift)
# 【4】傅立叶逆变换
img_back = np.fft.ifft2(f1shift)
2)应用实例:
import cv2
import numpy as np
import matplotlib.pyplot as plt
#直接读为灰度图像
img = cv2.imread('2.jpg',0)
# 傅立叶正变换
f = np.fft.fft2(img)
fshift = np.fft.fftshift(f)
#取绝对值:将复数变化成实数
#取对数的目的为了将数据变化到0-255
s1 = np.log(np.abs(fshift))
plt.subplot(131),plt.imshow(img,'gray'),plt.title('original')
plt.subplot(132),plt.imshow(s1,'gray'),plt.title('center')
# 傅立叶逆变换
f1shift = np.fft.ifftshift(fshift)
img_back = np.fft.ifft2(f1shift)
#取绝对值:将复数变化成实数
img_back = np.abs(img_back)
plt.subplot(133),plt.imshow(img_back,'gray'),plt.title('img back')
3)图像的相位和振幅:
恢复一个频域图像需要图像的振幅以及相位,振幅就是实部虚部的平方和开方,相位就是atan(实部/虚部),振幅用来描述图像灰度的亮度,影响哪些部分偏亮或者暗,而图像实际上是由它的相位决定的。
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('2.jpg',0)
# 【1】傅立叶正变换
f = np.fft.fft2(img)
fshift = np.fft.fftshift(f)
#取绝对值的目的是将复数变化成实数;取对数的目的为了将数据变化到0-255
s1 = np.log(np.abs(fshift))
plt.subplot(221),plt.imshow(img,'gray'),plt.title('original')
plt.xticks([]),plt.yticks([])
# 【2】傅立叶逆变换:只取振幅恢复图像
f1shift = np.fft.ifftshift(np.abs(fshift))
img_back = np.fft.ifft2(f1shift)
# 取绝对值的目的是将复数变化成实数
img_back = np.abs(img_back)
# 调整大小范围便于显示
img_back = (img_back-np.amin(img_back))/(np.amax(img_back)-np.amin(img_back))
plt.subplot(222),plt.imshow(img_back,'gray'),plt.title('only Amplitude')
plt.xticks([]),plt.yticks([])
# 【3】傅立叶逆变换:只取相位恢复图像
f2shift = np.fft.ifftshift(np.angle(fshift))
img_back = np.fft.ifft2(f2shift)
img_back = np.abs(img_back)
#调整大小范围便于显示
img_back = (img_back-np.amin(img_back))/(np.amax(img_back)-np.amin(img_back))
plt.subplot(223),plt.imshow(img_back,'gray'),plt.title('only phase')
plt.xticks([]),plt.yticks([])
# 【4】傅立叶逆变换--将相位/振幅合成恢复图像
s1 = np.abs(fshift) #取振幅
s1_angle = np.angle(fshift) #取相位
s1_real = s1*np.cos(s1_angle) #取实部
s1_imag = s1*np.sin(s1_angle) #取虚部
s2 = np.zeros(img.shape,dtype=complex)
s2.real = np.array(s1_real) #重新赋值给s2
s2.imag = np.array(s1_imag)
f2shift = np.fft.ifftshift(s2) #对新的进行逆变换
img_back = np.fft.ifft2(f2shift)
img_back = np.abs(img_back)
#调整大小范围便于显示
img_back = (img_back-np.amin(img_back))/(np.amax(img_back)-np.amin(img_back))
plt.subplot(224),plt.imshow(img_back,'gray'),plt.title('another way')
plt.xticks([]),plt.yticks([])
plt.show()
(2)频域滤波器:
1)高通滤波器:
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 读取图像
img_man = cv2.imread('2.jpg',0)
plt.subplot(121),plt.imshow(img_man,'gray'),plt.title('origial')
plt.xticks([]),plt.yticks([])
# 生成高通滤波器mask
rows,cols = img_man.shape
mask = np.ones(img_man.shape,np.uint8)
mask[rows//2-30:rows//2+30,cols//2-30:cols//2+30] = 0
# 傅立叶正变换
f1 = np.fft.fft2(img_man)
f1shift = np.fft.fftshift(f1)
# 高通滤波
f1shift = f1shift*mask
# 傅立叶反变换
f2shift = np.fft.ifftshift(f1shift)
img_new = np.fft.ifft2(f2shift)
img_new = np.abs(img_new)
img_new = (img_new-np.amin(img_new))/(np.amax(img_new)-np.amin(img_new))
plt.subplot(122),plt.imshow(img_new,'gray'),plt.title('Highpass')
plt.xticks([]),plt.yticks([])
plt.show()
2)低通滤波器:
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 读取图像
img_man = cv2.imread('2.jpg',0)
plt.subplot(121),plt.imshow(img_man,'gray'),plt.title('origial')
plt.xticks([]),plt.yticks([])
# 低通滤波器mask
rows,cols = img_man.shape
mask = np.zeros(img_man.shape,np.uint8)
mask[rows//2-20:rows//2+20,cols//2-20:cols//2+20] = 1
# 傅立叶正变换
f1 = np.fft.fft2(img_man)
f1shift = np.fft.fftshift(f1)
# 低通滤波
f1shift = f1shift*mask
# 傅立叶反变换
f2shift = np.fft.ifftshift(f1shift)
img_new = np.fft.ifft2(f2shift)
img_new = np.abs(img_new)
img_new = (img_new-np.amin(img_new))/(np.amax(img_new)-np.amin(img_new))
plt.subplot(122),plt.imshow(img_new,'gray'),plt.title('Highpass')
plt.xticks([]),plt.yticks([])
plt.show()
3)带通滤波器:
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 读取图像
img_man = cv2.imread('2.jpg',0)
plt.subplot(121),plt.imshow(img_man,'gray'),plt.title('origial')
plt.xticks([]),plt.yticks([])
# 带通滤波器mask
rows,cols = img_man.shape
mask1 = np.ones(img_man.shape,np.uint8)
mask1[rows//2-8:rows//2+8,cols//2-8:cols//2+8] = 0
mask2 = np.zeros(img_man.shape,np.uint8)
mask2[rows//2-80:rows//2+80,cols//2-80:cols//2+80] = 1
mask = mask1*mask2
# 傅立叶正变换
f1 = np.fft.fft2(img_man)
f1shift = np.fft.fftshift(f1)
# 带通滤波
f1shift = f1shift*mask
# 傅立叶反变换
f2shift = np.fft.ifftshift(f1shift)
img_new = np.fft.ifft2(f2shift)
img_new = np.abs(img_new)
img_new = (img_new-np.amin(img_new))/(np.amax(img_new)-np.amin(img_new))
plt.subplot(122),plt.imshow(img_new,'gray'),plt.title('Highpass')
plt.xticks([]),plt.yticks([])
plt.show()
38.图像数据类型转换:
from skimage import io,data,img_as_float, img_as_ubyte, img_as_uint,img_as_int
# 输出图像数据类型
print(img.dtype.name)
# 【1】unit8转float
dst=img_as_float(img)
# 【2】float转uint8
# float转为unit8,有可能会造成数据的损失,因此会有警告提醒
dst=img_as_ubyte(img)
# 【3】转换为unit16
dst= img_as_uint(img)
# 【4】转换为int16
dst= img_as_int(img)
39.生成随机颜色:
(1)函数格式:
random.randint(0, 255)
(2)应用举例:
import cv2
import numpy as np
import random
# 画圆
def draw_circle(event, x, y, flags, param):
# 鼠标左键双击
if event == cv2.EVENT_LBUTTONDOWN:
# 每次点击,都是一种 新颜色
r = random.randint(0, 255)
g = random.randint(0, 255)
b = random.randint(0, 255)
cv2.circle(img, (x, y), 100, (b, g, r), -1)
img = np.zeros((600, 1000, 3), np.uint8)
cv2.namedWindow('draw circles')
# 鼠标点击的位置 = 传入函数的圆心
cv2.setMouseCallback('draw circles', draw_circle)
while True:
# 每次鼠标点击事件都会触发draw_circle,而函数体内会改变img
cv2.imshow('draw circles', img)
if cv2.waitKey(1) & 0xFF == ord('q'): # 按q键退出
break
cv2.destroyAllWindows()
40.图像掩码处理(reduce_domain):
# 生成mask图像
sss=np.zeros([480,640],dtype=np.uint8)
sss[300:350,310:400]=255
# 生成新的掩膜处理之后的图片
image=cv2.add(img0, np.zeros(np.shape(img0), dtype=np.uint8), mask=sss)