
1.图像色彩操作
1)彩色图像转换为灰度图像
#彩色图像转换为灰度图像
import cv2
img = cv2.imread("../data/Linus.png", 1) # 默认RGB 1彩色 0灰度
cv2.imshow("img", img)
# cvtcolor方法转换色彩空间
res = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imshow("img1", res)
cv2.waitKey()
cv2.destroyAllWindows()

2)色彩通道操作
# 处理图像通道操作
import cv2
img = cv2.imread("../data/opencv2.png")
cv2.imshow("img1", img)
# 取出蓝色通道,单个通道显示
b_img = img[:, :, 0]
cv2.imshow("img2", b_img)
# 将蓝色通道取出置0:去掉蓝色通道(索引为0的通道)
img[:, :, 0] = 0
cv2.imshow("img3", img) # 绿+红 = 黄色背景
# 在蓝色通道设置为0的基础上,把绿色也设置0:去掉绿色通道(索引为1的通道)
img[:, :, 1] = 0
cv2.imshow("img4", img)
cv2.waitKey()
cv2.destroyAllWindows()

3)灰度直方图均衡化
# 灰度图像直方图均衡化
import cv2
import numpy as np
# import matplotlib as plt
import matplotlib.pyplot as plt
img = cv2.imread("../data/sunrise.jpg", 0)
cv2.imshow("img1", img)
res = cv2.equalizeHist(img)
cv2.imshow('img2', res)
# 绘制灰度直方图
## 原始直方图
print(res.shape) # 查看图像维度:2维
plt.subplot(2, 1, 1)
plt.hist(img.ravel(), # ravel返回一个连续的扁平数组:二维数据拉成一维
256, [0, 256], label="orig")
plt.legend()
plt.show()
## 均衡化处理后的直方图
plt.subplot(2, 1, 2)
plt.hist(res.ravel(), 256, [0, 256], label="equalize")
plt.legend()
plt.show()
cv2.waitKey()
cv2.destroyAllWindows()

4)彩色图像直方图均衡化
# 彩色图像的亮度通道直方图均衡化:图片更亮
import cv2
img = cv2.imread('../data/sunrise.jpg')
cv2.imshow("img1", img)
# 把色彩BGR转化成YUV进行均衡化:YUV才有亮度通道
yuv = cv2.cvtColor(img, cv2.COLOR_BGR2YUV) # 没必要显示yuv
print(yuv.shape)
yuv[...,0] = cv2.equalizeHist(yuv[..., 0])
res = cv2.cvtColor(yuv, cv2.COLOR_YUV2BGR)
cv2.imshow("img2", res)
cv2.waitKey()
cv2.destroyAllWindows()

5)色彩提取
# 颜色提取
import cv2
import numpy as np
img = cv2.imread('../data/opencv2.png')
cv2.imshow('img', img)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# =============指定蓝色值的范围=============
# 蓝色H通道值为120,通常取120上下10的范围
# S通道和V通道通常取50~255间,饱和度太低、色调太暗计算出来的颜色不准确
minblue = np.array([110, 50, 50])
maxblue = np.array([130, 255, 255])
mask = cv2.inRange(hsv, minblue, maxblue) # 确定蓝色区域
blue = cv2.bitwise_and(img, img, mask=mask) # 原始图像与原始图像位与运算
cv2.imshow('blue', blue)
# =============指定绿色值的范围=============
minGreen = np.array([50, 50, 50])
maxGreen = np.array([70, 255, 255])
# 确定绿色区域
mask = cv2.inRange(hsv, minGreen, maxGreen)
# cv2.imshow("mask", mask)
# 通过掩码控制的按位与运算,锁定绿色区域
green = cv2.bitwise_and(img, img, mask=mask) # 执行掩模运算
cv2.imshow('green', green)
# =============指定红色值的范围=============
minRed = np.array([0, 50, 50])
maxRed = np.array([30, 255, 255])
# 确定红色区域
mask = cv2.inRange(hsv, minRed, maxRed)
# cv2.imshow("mask", mask)
# 通过掩码控制的按位与运算,锁定红色区域
red = cv2.bitwise_and(img, img, mask=mask) # 执行掩模运算
cv2.imshow('red', red)
cv2.waitKey()
cv2.destroyAllWindows()

6)二值化与反二值化
# 二值化与反二值化
import cv2
img = cv2.imread("../data/lena.jpg", 0)
# 二值化:阈值根据我们实际需求定
t, rst = cv2.threshold(img, 111, 255, cv2.THRESH_BINARY) # t是阈值111
print(t)
cv2.imshow('res', rst)
# 反二值化
t, rst = cv2.threshold(img, 111, 255, cv2.THRESH_BINARY_INV) # t是阈值111
print(t)
cv2.imshow('res1', rst)
cv2.waitKey()
cv2.destroyAllWindows()

2.图像形态操作
1)图像翻转:水平与垂直
# 图像翻转示例
import numpy as np
import cv2
im = cv2.imread("../data/Linus.png")
cv2.imshow("src", im)
# 0-垂直镜像
im_flip0 = cv2.flip(im, 0)
cv2.imshow("im_flip0", im_flip0)
# 1-水平镜像
im_flip1 = cv2.flip(im, 1)
cv2.imshow("im_flip1", im_flip1)
cv2.waitKey()
cv2.destroyAllWindows()
2)图像仿射变换:平移与旋转
# 图像仿射变换:平移与旋转
import numpy as np
import cv2
def translate(img, x, y):
"""
坐标平移变换
:param img: 原始图像数据
:param x:平移的x坐标
:param y:平移的y坐标
:return:返回平移后的图像
"""
h, w = img.shape[:2] # 获取图像高、宽
# 定义平移矩阵:规定好的矩阵核
M = np.float32([[1, 0, x], [0, 1, y]])
# 使用openCV仿射操作实现平移变换
shifted = cv2.warpAffine(img, M, (w, h)) # 第三个参数为输出图像尺寸
return shifted # 返回平移后的图像
def rotate(img, angle, center=None, scale=1.0):
"""
图像旋转变换
:param img: 原始图像数据
:param angle: 旋转角度
:param center: 旋转中心,如果为None则以原图中心为旋转中心
:param scale: 缩放比例,默认为1
:return: 返回旋转后的图像
"""
h, w = img.shape[:2] # 获取图像高、宽
# 旋转中心默认为图像中心
if center is None:
center = (w / 2, h / 2)
# 计算旋转矩阵:生成的旋转矩阵
M = cv2.getRotationMatrix2D(center, angle, scale)
# 使用openCV仿射变换实现函数旋转
rotated = cv2.warpAffine(img, M, (w, h))
return rotated # 返回旋转后的矩阵
if __name__ == "__main__":
# 读取并显示原始图像
im = cv2.imread("../data/Linus.png")
cv2.imshow("SrcImg", im)
# 图像向下移动50像素
shifted = translate(im, 0, 50)#-50向上平移
cv2.imshow("Shifted1", shifted)
# 图像向左移动40, 下移动40像素
shifted = translate(im, -40, 40)
cv2.imshow("Shifted2", shifted)
# 逆时针旋转45度
rotated = rotate(im, 45)
cv2.imshow("rotated1", rotated)
# 顺时针旋转45度
rotated = rotate(im, -45)
cv2.imshow("rorated2", rotated)
cv2.waitKey()
cv2.destroyAllWindows()

3)图像缩小放大
# 图像缩放示例
import numpy as np
import cv2
im = cv2.imread("../data/Linus.png")
cv2.imshow("src", im)
h, w = im.shape[:2] # 获取图像尺寸 216x160
print(h, w)
#缩小
dst_size = (int(w / 2), int(h / 2)) # 缩放目标尺寸,宽高均为原来1/2
resized = cv2.resize(im, dst_size) # 执行缩放
cv2.imshow("reduce", resized)
#放大:最邻近插值法放大
dst_size = (200, 300) # 缩放目标尺寸,宽200,高300
method = cv2.INTER_NEAREST # 最邻近插值
resized = cv2.resize(im, dst_size, interpolation=method) # 执行缩放
cv2.imshow("NEAREST", resized)
#放大:双线性插值法放大
dst_size = (200, 300) # 缩放目标尺寸,宽200,高300
method = cv2.INTER_LINEAR # 双线性插值
resized = cv2.resize(im, dst_size, interpolation=method) # 执行缩放
cv2.imshow("LINEAR", resized)
cv2.waitKey()
cv2.destroyAllWindows()

4)图像裁剪
# 图像裁剪
import numpy as np
import cv2
# 图像随机裁剪
def random_crop(im, w, h):
start_x = np.random.randint(0, im.shape[1]) # 裁剪起始x像素
start_y = np.random.randint(0, im.shape[0]) # 裁剪起始y像素
new_img = im[start_y:start_y + h, start_x: start_x + w] # 执行裁剪
return new_img
# 图像中心裁剪
def center_crop(im, w, h):
start_x = int(im.shape[1] / 2) - int(w / 2) # 裁剪起始x像素
start_y = int(im.shape[0] / 2) - int(h / 2) # 裁剪起始y像素
new_img = im[start_y:start_y + h, start_x: start_x + w] # 执行裁剪
return new_img
im = cv2.imread("../data/banana_1.png", 1)
new_img = random_crop(im, 200, 200) # 随机裁剪
new_img2 = center_crop(im, 200, 200) # 中心裁剪
cv2.imshow("orig", im)
cv2.imshow("random_crop", new_img)
cv2.imshow("center_crop", new_img2)
cv2.waitKey()
cv2.destroyAllWindows()
5)图像相加
# 图像相加示例:加水印与降解椒盐噪声
import cv2
a = cv2.imread("../data/lena.jpg", 0)
b = cv2.imread("../data/lily_square.png", 0)
dst1 = cv2.add(a, b) # 图像直接相加,会导致图像过亮、过白
# 加权求和:addWeighted
# 图像进行加权和计算时,要求src1和src2必须大小相同,resize缩放完成这个功能
dst2 = cv2.addWeighted(a, 0.6, b, 0.4, 0)
# 最后一个参数为亮度调节量:两个图像计算后在加上这个偏置
cv2.imshow("a", a)
cv2.imshow("b", b)
cv2.imshow("dst1", dst1)
cv2.imshow("dst2", dst2)
cv2.waitKey()
cv2.destroyAllWindows()

6)图像相减
# 图像相减运算示例
import cv2
a = cv2.imread("../data/3.png", 0)
b = cv2.imread("../data/4.png", 0)
dst = cv2.subtract(a, b) # 两幅图像相减,是求出图像的差异
cv2.imshow("a", a)
cv2.imshow("b", b)
cv2.imshow("dst1", dst)
cv2.waitKey()
cv2.destroyAllWindows()
7)透视变换
# 透视变换
import cv2
import numpy as np
img = cv2.imread('../data/pers.png')
rows, cols = img.shape[:2]
print(rows, cols)
# 输入图像四个顶点坐标:提前算出来的
pts1 = np.float32([[58, 2], [167, 9], [8, 196], [126, 196]])
# 输出图像四个顶点坐标:提前算出来的
pts2 = np.float32([[16, 2], [167, 8], [8, 196], [169, 196]])
# 生成透视变换矩阵:矩阵核 3x3
M = cv2.getPerspectiveTransform(pts1, # 输入图像四个顶点坐标
pts2) # 输出图像四个顶点坐标
print(M.shape)
# 执行透视变换,返回变换后的图像
dst = cv2.warpPerspective(img, # 原始图像
M, # 3*3的变换矩阵
(cols, rows)) # 输出图像大小
# 生成透视变换矩阵
M = cv2.getPerspectiveTransform(pts2, # 输入图像四个顶点坐标
pts1) # 输出图像四个顶点坐标
# 执行透视变换,返回变换后的图像
dst2 = cv2.warpPerspective(dst, # 原始图像
M, # 3*3的变换矩阵
(cols, rows)) # 输出图像大小
cv2.imshow("img", img)
cv2.imshow("dst", dst)
cv2.imshow("dst2", dst2)
cv2.waitKey()
cv2.destroyAllWindows()

8)图像腐蚀
# 图像腐蚀
import cv2
import numpy as np
# 读取原始图像
im = cv2.imread("../data/5.png")
cv2.imshow("im", im)
# 定义腐蚀核
kernel = np.ones((3, 3), np.uint8) # 用于腐蚀计算的核,越大腐蚀性越大
erosion = cv2.erode(im, # 原始图像
kernel, # 腐蚀核
iterations=3) # 迭代次数:腐蚀核用几次,越大腐蚀性越大
cv2.imshow("erosion", erosion)
cv2.waitKey()
cv2.destroyAllWindows()
9)图像膨胀
# 图像膨胀
import cv2
import numpy as np
# 读取原始图像
im = cv2.imread("../data/6.png")
cv2.imshow("im", im)
# 膨胀
kernel = np.ones((3, 3), np.uint8) # 用于膨胀计算的核
dilation = cv2.dilate(im, # 原始图像
kernel, # 膨胀核
iterations=5) # 迭代次数
cv2.imshow("dilation", dilation)
cv2.waitKey()
cv2.destroyAllWindows()
10)图像开运算:先腐蚀再膨胀
# 开运算示例
import cv2
import numpy as np
# 读取原始图像
im1 = cv2.imread("../data/7.png")
im2 = cv2.imread("../data/8.png")
# 执行开运算
kernel = np.ones((10, 10), np.uint8) # 开运算核
r1 = cv2.morphologyEx(im1, cv2.MORPH_OPEN, kernel)
r2 = cv2.morphologyEx(im2, cv2.MORPH_OPEN, kernel)
cv2.imshow("im1", im1)
cv2.imshow("result1", r1)
cv2.imshow("im2", im2)
cv2.imshow("result2", r2)
cv2.waitKey()
cv2.destroyAllWindows() 
11)图像闭运算:先膨胀再腐蚀
# 闭运算示例
import cv2
import numpy as np
# 读取图像
im1 = cv2.imread("../data/9.png")
im2 = cv2.imread("../data/10.png")
# 闭运算
k = np.ones((8, 8), np.uint8)
r1 = cv2.morphologyEx(im1, cv2.MORPH_CLOSE, k, iterations=2)
r2 = cv2.morphologyEx(im2, cv2.MORPH_CLOSE, k, iterations=2)
cv2.imshow("im1", im1)
cv2.imshow("result1", r1)
cv2.imshow("im2", im2)
cv2.imshow("result2", r2)
cv2.waitKey()
cv2.destroyAllWindows()
12)形态学梯度:膨胀减去腐蚀
# 形态学梯度示例:膨胀减去腐蚀
import cv2
import numpy as np
img = cv2.imread("../data/6.png")
kernel = np.ones((3, 3), np.uint8) # 计算核
r = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)
cv2.imshow("original", img)
cv2.imshow("result", r)
cv2.waitKey()
cv2.destroyAllWindows()













3. 图像梯度处理
1)模糊处理3个方法
# 梯度处理之图像模糊处理3个方法的示例
import cv2
import numpy as np # 构建滤波器用
im = cv2.imread("../data/lena.jpg", 0)
cv2.imshow("orig", im)
## 中值滤波
# 调用medianBlur中值模糊
# 第二个参数为滤波模板的尺寸大小5x5,必须是大于1的奇数,如3、5、7
im_median_blur = cv2.medianBlur(im, 5)
cv2.imshow('median_blur', im_median_blur)
# 均值滤波
# 第二个参数为滤波模板的尺寸大小3x3
im_mean_blur = cv2.blur(im, (3, 3))
cv2.imshow("mean_blur", im_mean_blur)
# 高斯滤波
# 第三个参数为高斯核在X方向的标准差
im_gaussian_blur = cv2.GaussianBlur(im, (5, 5), 3)
cv2.imshow("gaussian_blur", im_gaussian_blur)
# 自己手动定义高斯算子和filter2D自定义滤波操作
gaussan_blur = np.array([
[1, 4, 7, 4, 1],
[4, 16, 26, 16, 4],
[7, 26, 41, 26, 7],
[4, 16, 26, 16, 4],
[1, 4, 7, 4, 1]], np.float32) / 273 #273自己看图像试出来的
# 使用filter2D用来搞自己定义算子,
# 第二个参数为目标图像的所需深度, -1表示和原图像相同通道数目
im_gaussian_blur2 = cv2.filter2D(im, -1, gaussan_blur)
cv2.imshow("gaussian_blur2", im_gaussian_blur2)
cv2.waitKey()
cv2.destroyAllWindows()

2)图像锐化处理2个方法
# 图像锐化示例:增强像素之间差异
import cv2
import numpy as np
im = cv2.imread("../data/lena.jpg", 0)
cv2.imshow("orig", im)
# 锐化算子1:滤波器,卷积核,算子一个东西
sharpen_1 = np.array([[-1, -1, -1],
[-1, 9, -1],
[-1, -1, -1]])
# 使用filter2D进行滤波操作
im_sharpen1 = cv2.filter2D(im, -1, sharpen_1)
cv2.imshow("sharpen_1", im_sharpen1)
# 锐化算子2
sharpen_2 = np.array([[0, -1, 0],
[-1, 8, -1],
[0, 1, 0]]) / 4.0
# 使用filter2D进行滤波操作
im_sharpen2 = cv2.filter2D(im, -1, sharpen_2)
cv2.imshow("sharpen_2", im_sharpen2)
cv2.waitKey()
cv2.destroyAllWindows()
3)边沿检测3个方法
# 边沿检测示例:提取边缘信息
import cv2 as cv
im = cv.imread('../data/lily.png', 0)
cv.imshow('Original', im)
# # 水平方向滤波 1,0
# hsobel = cv.Sobel(im, cv.CV_64F, 1, 0, ksize=5)
# cv.imshow('H-Sobel', hsobel)
# # 垂直方向滤波0,1
# vsobel = cv.Sobel(im, cv.CV_64F, 0, 1, ksize=5)
# cv.imshow('V-Sobel', vsobel)
# 两个方向滤波
sobel = cv.Sobel(im,
cv.CV_64F,#图像的深度
1, 1, #水平与垂直两个方向
ksize=5)#滤波器大小
cv.imshow('Sobel', sobel)
# Laplacian滤波:对细节反映更明显
laplacian = cv.Laplacian(im, cv.CV_64F)
cv.imshow('Laplacian', laplacian)
# Canny边沿提取
canny = cv.Canny(im,
50, # 滞后阈值
240) # 模糊度:去除小的边缘噪声,保留大轮廓
cv.imshow('Canny', canny)
cv.waitKey()
cv.destroyAllWindows()

4.图像轮廓(封边)处理









6. 轮廓处理
边缘检测虽然能够检测出边缘,但边缘是不连续的,检测到的边缘并不是一个整体。图像轮廓是指将边缘连接起来形成的一个整体,用于后续的计算。
OpenCV提供了查找图像轮廓的函数cv2.findContours(),该函数能够查找图像内的轮廓信息,而函数cv2.drawContours()能够将轮廓绘制出来。图像轮廓是图像中非常重要的一个特征信息,通过对图像轮廓的操作,我们能够获取目标图像的大小、位置、方向等信息。一个轮廓对应着一系列的点,这些点以某种方式表示图像中的一条曲线。
1)查找并绘制轮廓
查找轮廓函数:cv2.findContours
语法格式:image,contours,hierarchy=cv2.findContours(image,mode,method)
返回值
image:与函数参数中的原始图像image一样
contours:返回的轮廓(检测到的坐标)。该返回值返回的是一组轮廓信息,每个轮廓都是由若干个点所构成的(每个轮廓为一个list表示)。例如,contours[i]是第i个轮廓(下标从0开始),contours[i][j]是第i个轮廓内的第j个点
hierarchy:图像的拓扑信息(反映轮廓层次关系)。图像内的轮廓可能位于不同的位置。比如,一个轮廓在另一个轮廓的内部。在这种情况下,我们将外部的轮廓称为父轮廓,内部的轮廓称为子轮廓。按照上述关系分类,一幅图像中所有轮廓之间就建立了父子关系。每个轮廓contours[i]对应4个元素来说明当前轮廓的层次关系。其形式为:[Next,Previous,First_Child,Parent],分别表示后一个轮廓的索引编号、前一个轮廓的索引编号、第1个子轮廓的索引编号、父轮廓的索引编号
参数
image:原始图像,需要是二值化图像。灰度图像会被自动处理为二值图像。在实际操作时,可以根据需要,提前预先使用阈值处理等函数将待查找轮廓的图像处理为二值图像。
mode:轮廓检索模式,有以下取值和含义:
取值 含义 cv2.RETR_EXTERNAL 只检测外轮廓 cv2.RETR_LIST 检测所有轮廓,对检测到的轮廓不建立等级关系 cv2.RETR_CCOMP 检索所有轮廓并将它们组织成两级层次结构,上面的一层为外边界,下面的一层为内孔的边界,不常用 cv2.RETR_TREE 建立一个等级树结构的轮廓,不常用 method:记录轮廓坐标点方法,轮廓的近似方法,主要有如下取值:
取值 含义 cv2.CHAIN_APPROX_NONE 存储所有的轮廓点。相邻两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))=1 cv2.CHAIN_APPROX_SIMPLE 压缩水平方向、垂直方向、对角线方向的元素,即只保留该方向的终点坐标 cv2.CHAIN_APPROX_TC89_L1 使用teh-Chinl chain近似算法的一种风格,不常用 cv2.CHAIN_APPROX_TC89_KCOS 使用teh-Chinl chain近似算法的一种风格,不常用 注意事项
待处理的源图像必须是灰度二值图
都是从黑色背景中查找白色对象。因此,对象必须是白色的,背景必须是黑色的
在OpenCV 4.x中,函数cv2.findContours()仅有两个返回值
绘制轮廓:drawContours函数
语法格式:image=cv2.drawContours(image, contours,contourIdx, color)
参数
image:待绘制轮廓的图像
contours:需要绘制的轮廓坐标,该参数的类型与函数 cv2.findContours()的输出 contours 相同,都是list类型
contourIdx:需要绘制的轮廓索引(检测出每个轮廓都有个索引),告诉函数cv2.drawContours()要绘制某一条轮廓还是全部轮廓。如果该参数是一个整数或者为零,则表示绘制对应索引号的轮廓;如果该值为负数(通常为“-1”),则表示绘制全部轮廓。
color:绘制的颜色,用BGR格式表示
# 查找图像轮廓并绘制
#查找轮廓->绘制轮廓->拟合轮廓
import cv2
import numpy as np
im = cv2.imread("../data/3.png")
cv2.imshow("orig", im)
gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)#转成灰度图像
# 图像二值化处理,将大于阈值的设置为最大值,其它设置为0
ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
cv2.imshow("binary",binary)#保险起见看一下是不是黑底白图
# 查找图像边沿:cv2.findContours
img, contours, hierarchy = cv2.findContours(binary, # 二值化处理后的图像
cv2.RETR_EXTERNAL, # 只检测外轮廓
cv2.CHAIN_APPROX_NONE) # 存储所有的轮廓点
# 打印所有轮廓值 arr_cnt结构是列表里面套4个三维数组
arr_cnt = np.array(contours)
print(arr_cnt[0].shape)
print(arr_cnt[1].shape)
print(arr_cnt[2].shape)
print(arr_cnt[3].shape)
# print(arr_cnt[0])
# 绘制边沿坐标点
im_cnt = cv2.drawContours(im, # 绘制图像:在原图上进行绘制
contours, # 轮廓点坐标信息列表
-1, # 绘制全部轮廓
(0, 0, 255), # 轮廓颜色BGR:红色
2) # 轮廓粗细
cv2.imshow("im_cnt", im_cnt)
cv2.waitKey()
cv2.destroyAllWindows()执行结果:

2)绘制矩形包围框(拟合轮廓)
函数cv2.boundingRect()能够绘制轮廓的矩形边界。该函数的语法格式为:
retval = cv2.boundingRect(array) # 格式一
x,y,w,h = cv2.boundingRect(array) # 格式二
"""
参数:
array:是灰度图像或轮廓
返回值:一个接收也行,4个也行
retval:表示返回的矩形边界的左上角顶点的坐标值及矩形边界的宽度和高度
x, y, w, h: 矩形边界左上角顶点的x坐标、y坐标、宽度、高度
"""代码:
# 绘制图像矩形轮廓
import cv2
import numpy as np
im = cv2.imread("../data/cloud.png", 0) # 直接灰度化
cv2.imshow("orig", im)
# 二值化
ret, binary = cv2.threshold(im, 127, 255, cv2.THRESH_BINARY)
# 提取图像轮廓
img, contours, hierarchy = cv2.findContours(binary,
cv2.RETR_LIST, # 不建立等级关系
cv2.CHAIN_APPROX_NONE) # 存储所有的轮廓点
print("contours[0].shape:", contours[0].shape)
# 返回拟合矩形轮廓定点及边长
x, y, w, h = cv2.boundingRect(contours[0]) # 计算矩形包围框的x,y,w,h
print("x:", x, "y:", y, "w:", w, "h:", h)
# 绘制矩形包围框
brcnt = np.array([[[x, y]], [[x + w, y]], [[x + w, y + h]], [[x, y + h]]])
cv2.drawContours(im, # 绘制图像
[brcnt], # 轮廓点列表
-1, # 绘制全部轮廓
(255, 255, 255), # 轮廓颜色:白色
2) # 轮廓粗细
cv2.imshow("result", im) # 显示绘制后的图像
cv2.waitKey()
cv2.destroyAllWindows()
执行结果:










































