轮廓可以简单认为成将连续的点(连着边界)连在一起的曲线,具有相同的颜色或者灰度。轮廓在形状分析和物体的检测和识别中很有用。
函数 cv2.findContours() 有三个参数,第一个是输入图像,第二个是轮廓检索模式,第三个是轮廓近似方法。返回值有三个,第一个是图像,第二个是轮廓,第三个是(轮廓的)层析结构。轮廓(第二个返回值)是一个 Python列表,其中存储这图像中的所有轮廓。每一个轮廓都是一个 Numpy 数组,包含对象边界点( x, y)的坐标。
ret, thresh = cv2.threshold(imgray, 127, 255, 0)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cv2.CHAIN_APPROX_NONE:储存所有的边界点(点数很多)
cv2.CHAIN_APPROX_SIMPLE:储存所有的近似直线点(点数很少)
函数 cv2.drawContours() 可以被用来绘制轮廓。它可以根据你提供的边界点绘制任何形状。它的第一个参数是原始图像,第二个参数是轮廓,一个 Python 列表。第三个参数是轮廓的索引(在绘制独立轮廓是很有用,当设置为 -1 时绘制所有轮廓)。接下来的参数是轮廓的颜色和厚度等。
import numpy as np
import cv2
# 轮廓:连着边界连续的点连在一起的曲线,具有相同的颜色或者灰度。
# 轮廓在形状分析和物体的检测和识别中很有用。
# 1.为了准确,要使用二值化图像。需要进行阀值化处理或Canny边界检测。
# 2.查找轮廓的函数会修改元素图像。
# 3.在OpenCV中,查找轮廓就像在黑色背景中找白色物体。
# cv2.findContours() # 查找轮廓
# cv2.drawContours() # 绘制轮廓
img = cv2.imread('./resource/image/opencv-logo2.png')
imgcp = cv2.imread('./resource/image/opencv-logo2.png')
imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(imgray, 127, 255, 0)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# contours 轮廓
# hierarchy 层次
# image = cv2.drawContours(img, contours, -1, (0, 255, 0), 3) # 绘制所有轮廓
image = cv2.drawContours(img, contours, 3, (0, 255, 0), 3) # 绘制第4个轮廓
print(cv2.getVersionString())
print(type(contours))
print(len(contours))
cv2.imshow('img', imgcp)
cv2.imshow('image', image)
cv2.waitKey(0)
cv2.destroyAllWindows()
import numpy as np
import cv2
from matplotlib import pyplot as plt
# 矩:图像的矩可以帮助我们计算图像的质心,面积等
# cv2.moments() 计算得到矩,以一个字典形式返回
# 读取图像
img = cv2.imread('./resource/opencv/image/box2.png', cv2.IMREAD_COLOR)
img1 = img.copy()
gray = cv2.imread('./resource/opencv/image/box2.png', cv2.IMREAD_GRAYSCALE)
# 阀值处理
(ret, thresh) = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# 查找所有轮廓
(contours, hierarchy) = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
print('找到轮廓数:',len(contours))
# 计算轮廓索引为0的图像矩
cnt = contours[0]
M = cv2.moments(cnt)
print('moments()计数结果M:',M)
# 计算重心(质点)
#根据这些矩值计算出对象的重心:
# Cx = M10/M00
# Cy = M01/M00
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
print(cx,cy)
# 绘制轮廓
cv2.drawContours(img1, contours, 0, (0, 255, 0), 2)
# 绘制质点
cv2.circle(img1, (cx, cy), 5, (255, 0, 0), -1)
plt.subplot(121), plt.imshow(img)
plt.subplot(122), plt.imshow(img1)
plt.show()
程序运行结果:
找到轮廓数: 1
moments()计数结果M: {‘m00’: 10032.0, ‘m10’: 1294128.0, ‘m01’: 1284096.0, ‘m20’: 177807168.0, ‘m11’: 165648384.0, ‘m02’: 170838272.0, ‘m30’: 25740205920.0, ‘m21’: 22759317504.0, ‘m12’: 22038137088.0, ‘m03’: 23524638720.0, ‘mu20’: 10864656.0, ‘mu11’: 0.0, ‘mu02’: 6473984.0, ‘mu30’: 0.0, ‘mu21’: 0.0, ‘mu12’: 0.0, ‘mu03’: 0.0, ‘nu20’: 0.10795454545454546, ‘nu11’: 0.0, ‘nu02’: 0.06432748538011696, ‘nu30’: 0.0, ‘nu21’: 0.0, ‘nu12’: 0.0, ‘nu03’: 0.0}
质点: 129 128
import numpy as np
import cv2
from matplotlib import pyplot as plt
img = cv2.imread('./resource/opencv/image/box2.png', cv2.IMREAD_COLOR)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
(ret, thresh) = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
(contours, hierarchy) = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnt = contours[0]
M = cv2.moments(cnt)
area = cv2.contourArea(cnt)
print(cnt)
print(area)
print(M['m00'])
[[[ 72 84]]
[[ 72 172]]
[[186 172]]
[[186 84]]]
10032.0
10032.0
import numpy as np
import cv2
img = cv2.imread('./resource/opencv/image/box2.png', cv2.IMREAD_COLOR)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
(ret, thresh) = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
(contours, hierarchy) = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# 第一个参数轮廓,第二次参数形状闭合的(True),还是打开的一条曲线
perimeter = cv2.arcLength(contours[0], True)
print(perimeter) #404.0
import numpy as np
import cv2
from matplotlib import pyplot as plt
img = cv2.imread('./resource/opencv/image/approx2.jpg', cv2.IMREAD_COLOR)
img_draw1 = img.copy()
img_draw2 = img.copy()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
(ret, thresh) = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
(contours, hierarchy) = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# epsilon=10%
epsilon01 = 0.1 * cv2.arcLength(contours[0], True)
# epsilon=1%
epsilon001 = 0.01 * cv2.arcLength(contours[0], True)
approx_01 = cv2.approxPolyDP(contours[0], epsilon01, True)
approx_001 = cv2.approxPolyDP(contours[0], epsilon001, True)
cv2.drawContours(img_draw1, approx_01, -1, (0, 0, 255), 5)
cv2.drawContours(img_draw2, approx_001, -1, (0, 0, 255), 5)
plt.subplot(131), plt.imshow(img), plt.title('original')
plt.subplot(132), plt.imshow(img_draw1), plt.title('epsilon=10%')
plt.subplot(133), plt.imshow(img_draw2), plt.title('epsilon=1%')
plt.show()
import numpy as np
import cv2
from matplotlib import pyplot as plt
# 轮廓边界矩形
# 读取图像
img = cv2.imread('./resource/image/opencv-logo2.png', cv2.IMREAD_COLOR)
# 转成灰度
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 图像阀值处理
ret, thresh = cv2.threshold(img_gray, 127, 255, 0)
# 查找轮廓
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# 绘制轮廓边界矩形
for i in range(0, len(contours)):
x, y, w, h = cv2.boundingRect(contours[i])
print(x,y,w,h)
img = cv2.rectangle(img, (x,y), (x+w, y+h), (0,255,255), 3)
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()