# coding: utf-8
# !/usr/bin/python
"""
@File : 轮廓特征.py
@Author : jiaming
@Modify Time: 2020/2/4 12:49
@Contact :
@Version : 1.0
@Desciption : 查找轮廓的不同特征,例如面积,周长,重心,边界框。
"""
import os
import sys
import numpy as np
import cv2
import pprint
from matplotlib import pyplot as plt
rawPath = os.path.abspath(__file__)
currentFile = os.path.basename(sys.argv[0])
dataPath = rawPath[:rawPath.find(currentFile)] + r'static\\'
矩
"""
矩
图像的矩可以帮助我们计算图像的质心,面积
cv2.moments()会将计算得到的矩以一个字典的形式返回。
"""
img = cv2.imread(dataPath + 'j.png', 0)
ret, thresh = cv2.threshold(img, 127, 255, 0)
contours, hierarchy = cv2.findContours(thresh, 1, 2)
cnt = contours[0]
M = cv2.moments(cnt)
print(M) # {'m10': 16295.166666666666, 'm02': 2139434.833333333, 'nu20': 0.14816793811555762, 'm03': 153389761.15, 'nu12': 0.0006475903394347398, 'm01': 30024.833333333332, 'nu11': -0.06573717801941524, 'nu30': 0.01047213916167356, 'm21': 45301100.46666667, 'mu30': 38765.91563599929, 'mu02': 13277.718487945385, 'nu02': 0.07385701366114156, 'nu03': 0.0023967466246527977, 'm20': 652892.8333333333, 'mu03': 8872.311188548803, 'm11': 1142096.3333333333, 'm00': 424.0, 'm12': 80551411.9, 'mu12': 2397.259249293944, 'nu21': -0.006486127329685832, 'm30': 27178170.450000003, 'mu20': 26637.03924266249, 'mu21': -24010.439604086336, 'mu11': -11817.966915618395}
# 计算重心
cx = int(M['m10'] / M['m00'])
cy = int(M['m01'] / M['m00'])
轮廓面积
"""
轮廓面积
cv2.contourArea(), 也可以使用矩 M['m00']
area = cv2.contourArea(cnt)
"""
轮廓周长
"""
轮廓周长
cv2.arcLength() 计算得到
perimeter = cv2.arcLength(cnt, True)
"""
轮廓近似
"""
轮廓近似
将轮廓形状近似到另外一种由更少点组成的轮廓形状,新轮廓的点的数目由我们设定
的准确度来决定。
使用的 Douglas-Peucker 算法。
epsilon = 0.1*cv2.arcLength(cnt, True) 原始轮廓到近似轮廓的最大距离
approx = cv2.approxPolyDP(cnt, epslion, True)
"""
凸包
"""
凸包
凸包与近似轮廓相似,虽然有些情况下它们给出的结果是一样的。
cv2.convecHull() 可以用来检测一个曲线是否具有凸性缺陷,并能纠正缺陷。
hull = cv2.convexHull(points[, hull[, clockwise[, returnPoints])
points: 我们要传入的轮廓
hull: 输出
clockwise: 方向标志。如果设置为 True,输出的凸包是顺时针方向的。否则为逆时针方向。
returnPoints 默认值为 True,它会返回凸包上点的坐标。如果设置为 False。
凸性检测
函数 cv2.isContourConvex(),可以用来检测一个曲线是不是凸的,它只能返回 True 或 False
k = cv2.isContourConvex(cnt)
"""
边界矩形
"""
边界矩形
直边界矩形: 一个直矩形,不会考虑对象是否旋转。
所以边界的面积不是最小的。可以使用cv2.boundingRect()
x,y,w,h = cv2.boundingRect(cnt)
img = cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2)
旋转的边界矩形:这个边界矩形是面积最小的,因为它考虑了对象的旋转。
x,y,w,h = cv2.boundingRect(cnt)
img = cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2)
"""
最小外接圆
"""
最小外接圆
cv2.minEnclosingCircle() 可以帮我们找到一个对象的外切圆,它是所有能够包括
对象的圆中面积最小的一个。
(x, y), radius = cv2.minEnclosingCircle(cnt)
center = (int(x), int(y))
radius = int(radius)
img = cv2.circle(img, center, radius, (0, 255, 0), 2)
"""
椭圆拟合
"""
椭圆拟合
cv2.ellipse(),返回值其实就是旋转边界矩形的内切圆
ellipse = cv2.fitEllipse(cnt)
im = cv2.ellipse(im, ellipse, (0, 255, 0), 2)
"""
直线拟合
"""
直线拟合
我么可以根据一组点拟合出一条直线,同样我们也可以为图像中的白色点拟合出一条直线。
[vx, vy, x, y] = cv2.firLine(cnt, cv2.DIST_L2, 0, 0.01, 0.01)
lefty = int((-x*xy/vx) + y)
righty = int((cols-x)*vy/vx) + y)
img = cv2.line(img, (cols-1, righty), (0, lefty), (0, 255, 0), 2)
"""