可调大小

img = cv2.imread('5.jpg')
cv2.namedWindow('f',cv2.WINDOW_NORMAL)  
cv2.imshow('f',img)
cv2.waitKey(0)
cv2.destroyAllWindows()

扩边界

BLUE=[255,0,0]
img1=cv2.imread('logo.jpg')
replicate = cv2.copyMakeBorder(img1,30,30,30,30,cv2.BORDER_REPLICATE)
reflect = cv2.copyMakeBorder(img1,30,30,30,30,cv2.BORDER_REFLECT)
reflect101 = cv2.copyMakeBorder(img1,30,30,30,30,cv2.BORDER_REFLECT_101)
wrap = cv2.copyMakeBorder(img1,30,30,30,30,cv2.BORDER_WRAP)
constant= cv2.copyMakeBorder(img1,30,30,30,30,cv2.BORDER_CONSTANT,value=BLUE)plt.subplot(231),plt.imshow(img1,'gray'),plt.title('ORIGINAL')
plt.subplot(232),plt.imshow(replicate,'gray'),plt.title('REPLICATE')
plt.subplot(233),plt.imshow(reflect,'gray'),plt.title('REFLECT')
plt.subplot(234),plt.imshow(reflect101,'gray'),plt.title('REFLECT_101')
plt.subplot(235),plt.imshow(wrap,'gray'),plt.title('WRAP')
plt.subplot(236),plt.imshow(constant,'gray'),plt.title('CONSTANT')
plt.show()

opencv官方手册(一)-编程知识网

掩膜

img1 = cv2.imread('5.jpg')
img2 = cv2.imread('logo.jpg')
rows,cols,channels = img2.shape
roi = img1[0:rows, 0:cols ]
img2gray = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)
ret, mask = cv2.threshold(img2gray, 175, 255, cv2.THRESH_BINARY)  # 抠出前景
mask_inv = cv2.bitwise_not(mask)   img1_bg = cv2.bitwise_and(roi,roi,mask = mask)   # 注意是roi 区域
img2_fg = cv2.bitwise_and(img2,img2,mask = mask_inv)
dst = cv2.add(img1_bg,img2_fg)
img1[0:rows, 0:cols ] = dstcv2.imshow('res',img1)
cv2.waitKey(0)
cv2.destroyAllWindows()

效率检测

cv2.getTickCount() # 返回时钟数 cv2.getTickFrequency() # 返回时钟频率

import cv2
import numpy as np
img1 = cv2.imread('5.jpg')
e1 = cv2.getTickCount()   # or time.time() 但cv本身的函数肯定要好一些。。。
for i in range(5,49,2):img1 = cv2.medianBlur(img1,i) 
e2 = cv2.getTickCount()
t = (e2 - e1)/cv2.getTickFrequency()
print(t)

cv本身的函数经过优化是非常快的,在对视图复制时还是numpy 要快。

%timeit cv2.countNonZero(img1)   
29.4 µs ± 867 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)%timeit np.count_nonzero(img1)
1.17 ms ± 92 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

颜色蒙版

green = np.uint8([[[0,255,0]]])  # 形式要正确,对应cvArray,cvMat,IplImage
blue = np.uint8([[[0,0,255]]])
red = np.uint8([[[255,0,0]]])
hsv_green=cv2.cvtColor(green,cv2.COLOR_BGR2HSV)
>>> array([[[ 60, 255, 255]]], dtype=uint8)    
# 阈值可以设为 [H-100,100,100] 和 [H+100,255,255]cap = cv2.VideoCapture(0)
while (cap.isOpened()):ret,frame = cap.read()if ret:hsv = cv2.cvtColor(frame,cv2.COLOR_BGR2HSV)lower_blue=np.array([100,50,50])upper_blue=np.array([124,255,255])lower_red=np.array([156,50,50])upper_red=np.array([180,255,255])lower_green=np.array([35,50,50])upper_green=np.array([77,255,255])mask1 = cv2.inRange(hsv,lower_blue,upper_blue)mask2 = cv2.inRange(hsv,lower_green,upper_green)mask3 = cv2.inRange(hsv,lower_red,upper_red)mask = cv2.bitwise_or(cv2.bitwise_or(mask1,mask2),mask3)dst = cv2.bitwise_and(frame,frame,mask=mask)cv2.imshow('frame',frame)cv2.imshow('mask',mask)cv2.imshow('dst',dst)if cv2.waitKey(1) == 27:breakcv2.destroyAllWindows()

opencv官方手册(一)-编程知识网

opencv官方手册(一)-编程知识网

几何变换

res = cv2.resize(img,None,fx=0.5,fy=0.5,interpolation = cv2.INTER_CUBIC)
x=cv2.flip(img,0)  # 反转M = np.float32([[1, 0, x], [0, 1, y]])   # x,y 对应 移动的距离
move=cv2.warpAffine(img,M,(width,height))   # 平移M=cv2.getRotationMatrix2D((width/2,height/2),45,0.6)   # 旋转
rotate=cv2.warpAffine(img,M,(width,height))M=cv2.getAffineTransform(p1,p2)      # 三个点 左上 右上 左下
dst=cv2.warpAffine(img,M,(cols,rows))   # 仿射M=cv2.getPerspectiveTransform(pts1,pts2)  # 四个点,
dst=cv2.warpPerspective(img,M,(300,300))    # 透视,透视后的图片大小

阈值

opencv官方手册(一)-编程知识网

ret, dst = cv2.threshold(img,low,high,cv2.THRESH_**)# 自适应阈值
# 计算每个像素点周围邻近区域的加权平均值获得阈值
dst = cv.adaptiveThreshold( src, maxValue, adaptiveMethod, thresholdType, blockSize, C )
# adaptiveMethod  cv2.ADPTIVE_THRESH_MEAN_C 平均值
# cv2.ADAPTIVE_THRESH_GAUSSIAN_C 高斯加权,blockSize 指定领域大小,C 阈值在减去这个常数# Otsu's 二值化
# 根据当前图像给出最佳的分割阈值,就是他会历遍所有阈值,然后找出最佳。
t2,otsu=cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

图像平滑

低通滤波LPF去除噪音,模糊图像,高通滤波 HPF 获取边缘

# 均值滤波
dst = cv2.blur( src, ksize, anchor, borderType )
# 方框滤波,ddepth 图像深度-1 ,normalize是否归一化,1 用均值与上面一样,0就使用像素值之和。
dst = cv2.boxFilter(src,ddepth,ksize,anchor,normalize,boderType)
# 高斯滤波,核是高斯分,宽和高要是奇数,cv2.getGaussianKernel()自己构建
dst = cv2.GaussianBlur( src, ksize, sigmaX, sigmaY, borderType )
r=cv2.GaussianBlur(o,(5,5),0,0)
# 中值滤波,用中间值,去除椒盐噪声,
dst = cv2.medianBlur( src, ksize)
# 双边滤波,考虑边缘和色彩信息,慢
dst = cv2.bilateralFilter( src, d, sigmaColor, sigmaSpace, borderType )
# 2D卷积,delta 修正值,在结果上在加这个值。
dst = cv2.filter2D( src, ddepth, kernel, anchor, delta, borderType )
kernel = np.ones((5,5),np.float32)/25

双边滤波在同时使用空间高斯权重和灰度值相似性高斯权重。空间高斯函
数确保只有邻近区域的像素对中心点有影响,灰度值相似性高斯函数确保只有
与中心像素灰度值相近的才会被用来做模糊运算。所以这种方法会确保边界不
会被模糊掉,因为边界处的灰度值变化比较大。

形态学操作

# 腐蚀,前景区域变小(白色)
dst = cv2.erode( src, kernel[, anchor[, iterations[, borderType[, borderValue]]]] )
# 膨胀,增加前景区域
dst = cv2.dilate( src, kernel[, anchor[, iterations[, borderType[, borderValue]]]])dst = cv2.morphologyEx( src, op, kernel[, anchor[, iterations[, borderType[, borderValue]]]]] )
# 开运算,去除噪声,断开连接
# 闭运算,填充前景的小洞之类的
# 梯度 ,轮廓
# 礼帽,获得噪声信息,或比原始图像更亮的边缘信息
# 黑帽,获取图像内部的小孔,或前景色中的小黑点,或者比原始图像的边缘更暗的边缘部分。

opencv官方手册(一)-编程知识网
结构化元素,构建一个椭圆形/圆形的核

retval = cv2.getStructuringElement( shape, ksize[, anchor])
cv2.MORPH_RECT 
cv2.MORPH_CROSS
cv2.MORPH_ELLIPSE # Rectangular Kernel
>>> cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))
array([[1, 1, 1, 1, 1],[1, 1, 1, 1, 1],[1, 1, 1, 1, 1],[1, 1, 1, 1, 1],[1, 1, 1, 1, 1]], dtype=uint8)
# Elliptical Kernel
>>> cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
array([[0, 0, 1, 0, 0],[1, 1, 1, 1, 1],[1, 1, 1, 1, 1],[1, 1, 1, 1, 1],[0, 0, 1, 0, 0]], dtype=uint8)
# Cross-shaped Kernel
>>> cv2.getStructuringElement(cv2.MORPH_CROSS,(5,5))
array([[0, 0, 1, 0, 0],[0, 0, 1, 0, 0],[1, 1, 1, 1, 1],[0, 0, 1, 0, 0],[0, 0, 1, 0, 0]], dtype=uint8)

图像梯度

就是求导,计算的是图像变化的速度

# Sobel
dst = cv2.Sobel( src, ddepth, dx, dy[,ksize[, scale[, delta[, borderType]]]] )
dst = cv2.Scharr( src, ddepth, dx, dy[, scale[, delta[, borderType]]] )# ddepth cv2.CV_64F 放置信息丢失再通过取绝对值将其映射为 cv2.CV_8U 八位图类型
# dx,dy x,y方向上的求导阶数,最大2,计算x 方向边缘(梯度) dx=1, dy=0, 只计算水平方向的边缘。
# ksize Sobel 核的大小,ksize=-1,会使用 3x3 的 Scharr 滤波器(更好)
# scale 代表计算导数值时采用的缩放因子,默认1,没有缩放
# delta 代表加在目标图像dst 上的值,可选,默认0
# dst = cv2.convertScaleAbs( src [, alpha[, beta]] )  位深转化函数,来取绝对值的
# or abs_sobel64f = np.absolute(sobelx64f)o = cv2.imread('5.jpg',0)
Sobelx = cv2.Sobel(o,cv2.CV_64F,1,0)
Sobely = cv2.Sobel(o,cv2.CV_64F,0,1)
Sobelx = cv2.convertScaleAbs(Sobelx) 
Sobely = cv2.convertScaleAbs(Sobely) 
Sobelxy = cv2.addWeighted(Sobelx,0.5,Sobely,0.5,0) # 两个方向的叠加
Sobelxy11=cv2.Sobel(o,cv2.CV_64F,1,1)
Sobelxy11=cv2.convertScaleAbs(Sobelxy11)     # 只是两个方向的交点。
cv2.imshow("original",o)
cv2.imshow("xy",Sobelxy)
cv2.imshow("xy11",Sobelxy11)
cv2.waitKey()
cv2.destroyAllWindows()# 拉普拉斯算子,二阶导数算子,ksize 正的奇数,旋转不变性
dst = cv2.Laplacian( src, ddepth[, ksize[, scale[, delta[, borderType]]]] )
lap= cv2.Laplacian(o,cv2.CV_64F)
lap = cv2.convertScaleAbs(lap) 

Cany 边缘检测

edges = cv.Canny( image, threshold1, threshold2[, apertureSize[, L2gradient]])
'''
edges 计算得到的边缘图像
image 8位输入图像
threshold1,2 两个阈值
apertureSize Sobel算子孔径大小
L2gradient 计算图像梯度幅度的标志,Ture就用L2范数计算,默认False 使用L1范数
'''
def minth(a):minth = cv2.getTrackbarPos('minth','canny')maxth = cv2.getTrackbarPos('maxth','canny')edges = cv2.Canny(img,minth,maxth)cv2.imshow('canny',edges)img = cv2.imread('5.jpg',0)
cv2.namedWindow('canny')
cv2.createTrackbar('minth','canny',0,255,minth)
cv2.createTrackbar('maxth','canny',0,255,minth)
cv2.imshow('canny',img)
cv2.waitKey(0)
cv2.destroyAllWindows()

图像金字塔

同一图像的不同分辨率的子图像。

# 向下采样,分辨率降低,dstsize 目标图像的大小
dst = cv2.pyrDown( src[, dstsize[, borderType]] ) 
# 向上采样
dst = cv2.pyrUp( src[, dstsize[, borderType]] ) # 拉普拉斯金字塔
Li = Gi - pyrUp(Gi + 1)o=cv2.imread('14.jpg')
G0=o
G1=cv2.pyrDown(G0)
G2=cv2.pyrDown(G1)        # 构建高斯金字塔
G3=cv2.pyrDown(G2)L0=G0-cv2.pyrUp(G1)
L1=G1-cv2.pyrUp(G2)          # 拉普拉斯金字塔
L2=G2-cv2.pyrUp(G3)RG0=L0+cv2.pyrUp(G1)                   # 其实就是上面式子的移项
print('G0.shape=',G0.shape)
print('RG0.shape=',RG0.shape)
result=RG0-G0 #将 RG0 和 G0 相减            # 获得的result 是一个数组
result=abs(result)
print("原始图像 G0 与恢复图像 RG0 差值的绝对值和:",np.sum(result))           
# 结果是0,表示两个图像是一样的。

图像金字塔的一个应用就是图像融合。

A = cv2.imread(r'D:\pycham\opencv3\you.jpg')
B = cv2.imread(r'D:\pycham\opencv3\zuo.jpg')
A = cv2.resize(A,(512,512),interpolation=cv2.INTER_AREA)  # 各种尺寸问题。。。
B = cv2.resize(B,(512,512),interpolation=cv2.INTER_AREA)G = A.copy()
gpA = [G]
for i in range(6):    # 构建高斯金字塔G = cv2.pyrDown(G)gpA.append(G)G = B.copy()
gpB = [G]         # 一共七层
for i in range(6):G = cv2.pyrDown(G)gpB.append(G)lpA = [gpA[5]]
for i in range(5,0,-1):GE = cv2.pyrUp(gpA[i])L = cv2.subtract(gpA[i-1],GE)     # 构建拉普拉斯金字塔lpA.append(L)lpB = [gpB[5]]
for i in range(5,0,-1):GE = cv2.pyrUp(gpB[i])L = cv2.subtract(gpB[i-1],GE)lpB.append(L)LS = []
for la,lb in zip(lpA,lpB):rows,cols,dpt = la.shapeprint(la.shape,lb.shape)ls = np.hstack((la[:,0:cols//2], lb[:,cols//2:]))LS.append(ls)ls_ = LS[0]
for i in range(1,6):ls_ = cv2.pyrUp(ls_)ls_ = cv2.add(ls_, LS[i])real = np.hstack((A[:,:cols//2],B[:,cols//2:]))
cv2.imshow('real',real)
cv2.imshow('ls',ls_)
cv2.waitKey(0)
cv2.destroyAllWindows()

opencv官方手册(一)-编程知识网

轮廓

首先进行二值化或是canny 边缘检测。查找轮廓会修改原始图像,记得保存。要找的物体应该是白色的前景。

contours, hierarchy = cv2.findContours( image, mode, method)
'''
contours 是一个列表,存储图像中的所有轮廓,每个轮廓都是一个numpy数组,包含边界的的(x,y)的坐标
hierarchy 轮廓的层次信息 [Next,Previous,First_Child,Parent],由mode 决定
mode 轮廓的提取方式:cv2.RETR_EXTERNAL:只检测外轮廓。cv2.RETR_LIST:对检测到的轮廓不建立等级关系。cv2.RETR_CCOMP:检索所有轮廓并将它们组织成两级层次结构。cv2.RETR_TREE:建立一个等级树结构的轮廓。
method 轮廓的表达方式,cv2.CHAIN_APPROX_CONE 存储所有轮廓点,相邻两个点的像素位置差不超过1,cv2.CHAIN_APPROX_SIMPLE 压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,极端情况下,四个点来保存一个矩形的轮廓信息
'''
image=cv2.drawContours( image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset]]]]] )img = cv2.drawContours(img, contours, 3, (0,255,0), 3)   # 说这个更有用是为啥呢。。。retval = cv2.moments( array[, binaryImage] )   # 矩特征,binaryImage 将图像的非零值处理为0
# 返回矩特征 cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])       # 重心  M['m00'] 轮廓的面积retval =cv2.contourArea(contour [, oriented] ))   # 面积,oriented 表示轮廓是顺时针还是逆时针retval = cv2.arcLength( curve, closed )   # 周长hu = cv2.HuMoments( m )        #  Hu 矩,图像经过缩放,平移旋转等操作后Hu 矩基本保持稳定,,retval = cv2.matchShapes( contour1, contour2, method, parameter )  # 形状匹配,匹配两个对象的Hu 矩
ret0 = cv2.matchShapes(cnt1,cnt1,1,0.0)    # method 比较两个对象Hu 矩的方法。

轮廓拟合

retval = cv2.boundingRect( array )     # 矩形包围框,返回矩形边界左上角顶点坐标和矩形边界的宽度和高度
x,y,w,h = cv2.boundingRect( cnt)
img = cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)points =cv2.minAreaRect( points )   # 最小外包矩形框 返回(最小外接矩形的中心(x,y),(宽度,高度),旋转角度)
points = np.int64(points)  # 取整
points = cv2.boxPoints(points)    # 将返回值转换成轮廓绘制参数的结构
image=cv2.drawContours(o,[points],0,(255,255,255),2)center, radius = cv2.minEnclosingCircle( points )   # 最小外包圆retval = cv2.fitEllipse( points )  # 椭圆 中心点,轴长度,旋转角度
ellipse = cv2.fitEllipse(contours[0])
print("ellipse=",ellipse)
cv2.ellipse(o,ellipse,(0,255,0),3)line = cv2.fitLine( points, distType, param, reps, aeps )     # 最优拟合直线
[vx,vy,x,y] = cv2.fitLine(contours[0], cv2.DIST_L2,0,0.01,0.01) 
lefty = int((-x*vy/vx) + y)                   # 说白了就是一个方向和一个点
righty = int(((cols-x)*vy/vx)+y)                # 计算两个点,代值计算就行
cv2.line(o,(cols-1,righty),(0,lefty),(0,255,0),2)   
# 返回值是共线的归一化向量,和线上一点retval, triangle = cv2.minEnclosingTriangle( points )   # 三角形
area,trgl = cv2.minEnclosingTriangle(contours[0])
for i in range(0, 3):cv2.line(o, tuple(trgl[i][0]), tuple(trgl[(i + 1) % 3][0]), (255,255,255), 2)  # 逼近多边形
approxCurve = cv2.approxPolyDP( curve, epsilon, closed )  # 轮廓,精度,是否封闭
epsilon = 0.02*cv2.arcLength(contours[0],True)     # 精度为0.02*周长
approx = cv2.approxPolyDP(contours[0],epsilon,True)
adp=cv2.drawContours(adp,[approx],0,(0,0,255),2)

凸包

hull = cv2.convexHull( points[, clockwise[, returnPoints]] ) 
# hull 凸包角点,clockwise凸包角点按顺时针还是逆时针排序,returnPoints 真返回xy 轴坐标 否则返回轮廓的索引convexityDefects = cv2.convexityDefects( contour, convexhull )  # 凸缺陷,需要convexHull returnPoints= False
# 返回[起点,终点,轮廓上距离凸包最远的点,最远点到凸包的近似距离]hull = cv2.convexHull(cnt,returnPoints = False)    # 需要索引          
defects = cv2.convexityDefects(cnt,hull)          # shape(23, 1, 4) 
for i in range(defects.shape[0]):s,e,f,d = defects[i,0]     start = tuple(cnt[s][0])           # 得到的是索引,要再轮廓中选出来end = tuple(cnt[e][0])far = tuple(cnt[f][0])cv2.line(o,start,end,[0,0,255],2)cv2.circle(o,far,5,[255,0,0],-1)retval = cv2.isContourConvex( contour )  # 检测一个曲线(轮廓类似的点集)是否是凸型的,,没什么大不了的。。(文档说的)retval = cv2.pointPolygonTest( contour, pt, measureDist )  # 点到轮廓的最短距离,mearsureDist False时返回相对位置,真返回距离,第三个参数设置为False可以大幅度提高速度# 计算形状场景距离,使用距离作为形状比较的度量标准。
sd = cv2.createShapeContextDistanceExtractor()  # 构造距离提取算子,,
d1 = sd.computeDistance(cnt1,cnt1)
print("与自身的距离 d1=", d1)
与自身的距离 d1= 0.0

轮廓的特征值

# 宽高比
x,y,w,h = cv2.boundingRect(cnt)
aspect_ratio = float(w)/h# Extent,轮廓面积与边界矩形面积的比。
area = cv2.contourArea(cnt)
x,y,w,h = cv2.boundingRect(cnt)
rect_area = w*h
extent = float(area)/rect_area# Solidity,轮廓面积与凸包面积的比。
area = cv2.contourArea(cnt)
hull = cv2.convexHull(cnt)
hull_area = cv2.contourArea(hull)
solidity = float(area)/hull_area# Equivalent Diameter,与轮廓面积相等的圆形的直径
area = cv2.contourArea(cnt)
equi_diameter = np.sqrt(4*area/np.pi)# 掩模和像素点,获取某对象的掩膜图像和 对应的点。
idx = cv2.findNonZero( src )  # 非零元素的索引,返回(列号,行号)
pixelpoints = np.transpose(np.nonzero(mask))    # (行号,列号)
>>> np.nonzero(x)
(array([0, 1, 2]), array([0, 1, 2]))      
>>> np.transpose(np.nonzero(x))
array([[0, 0],[1, 1],[2, 2]])# 极值
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(imgray,mask = mask) # 单通道,返回最大最小值和坐标# 平均颜色和平均灰度,可以计算各通道的均值
mean_val = cv2.mean(im,mask = mask)# 四个极点
leftmost = tuple(cnt[cnt[:,:,0].argmin()][0])     # 轮廓点(y,x)
rightmost = tuple(cnt[cnt[:,:,0].argmax()][0])
topmost = tuple(cnt[cnt[:,:,1].argmin()][0])
bottommost = tuple(cnt[cnt[:,:,1].argmax()][0])