需求
根据图片中图形的形状,得出对应的用户群体,比如长方形对应严肃的年长人群,圆形对应活泼的少女人群。
步骤
- 获取图片的灰度,使用高斯模糊、Canny算子检测对图片进行滤波
- 获取图形的轮廓和顶点
- 根据图形的顶点数目和周长面积比,进行分类
- 基于第3点,返回对应的人群数组
代码
# -*- coding: utf-8 -*-
import cv2
import numpy as np
# import sys
# 定义形状检测函数
def ShapeDetection(img, imgContour):
# 寻找轮廓点
# cv2.RETR_EXTERNAL只检测最外围轮廓
contours, hierarchy = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
# 总面积
all_area = 0
return_value_list = []
for obj in contours:
# 计算轮廓内区域的面积
contour_area = cv2.contourArea(obj)
all_area += contour_area
for obj in contours:
# 绘制轮廓线
cv2.drawContours(imgContour, obj, -1, (255, 0, 0), 4)
# 计算轮廓周长
perimeter = cv2.arcLength(obj, True)
# print(perimeter)
# 计算轮廓内区域的面积
contour_area = cv2.contourArea(obj)
# 面积占比
area_proportion = contour_area / all_area
area_proportion = round(area_proportion, 2)
# print(contour_area)
# 计算周长面积比
if contour_area != 0:
perimeter_area = perimeter / contour_area
# print(perimeter_area)
# 获取轮廓角点坐标
approx = cv2.approxPolyDP(obj, 0.02*perimeter, True)
# 轮廓角点的数量
CornerNum = len(approx)
# 获取坐标值和宽度、高度
x, y, w, h = cv2.boundingRect(approx)
# 三角形
objType = "None"
return_value = 0
if CornerNum == 3:
objType = "triangle" + str(CornerNum)
return_value = 1
# 矩形
elif CornerNum == 4:
# 正方形
if w == h:
objType = "Square" + str(CornerNum)
return_value = 2
# 非正方形的矩形
else:
objType = "Rectangle" + str(CornerNum)
return_value = 3
elif CornerNum == 5:
# 五边形
objType = "5" + str(CornerNum)
return_value = 4
elif CornerNum == 6:
# 六边形
objType = "6" + str(CornerNum)
return_value = 5
elif CornerNum == 7:
# 七边形
objType = "7" + str(CornerNum)
return_value = 6
# 8个顶点的情况:圆角三角形
elif CornerNum == 8:
# 椭圆形
if 0.015 < perimeter_area < 0.019:
objType = "Ellipse long" + str(CornerNum)
return_value = 7
# 圆角三角形
if 0.049 < perimeter_area < 0.050:
objType = "triangle" + str(CornerNum)
return_value = 1
elif CornerNum > 8:
# 圆
if w == h:
objType = "Circle" + str(CornerNum)
return_value = 8
else:
objType = "Curved edge graphics" + str(CornerNum)
return_value = 0
else:
objType = "Curved edge graphics" + str(CornerNum)
return_value = 0
return_value_list.append([return_value, area_proportion])
return_people = [30, 31, 32, 33, 34]
if len(contours) > 1:
# 遍历图形分类和面积
# 各种面积
# 0 曲面图形
curved_edge_area_sum = 0
# 1 三角图形
triangle_area_sum = 0
# 2 正方形
square_area_sum = 0
# 3 长方形
rectangle_area_sum = 0
pentagon_area_sum = 0
hexagon_area_sum = 0
heptagon_area_sum = 0
ellipse_area_sum = 0
circle_area_sum = 0
for index in return_value_list:
if index[0] == 0:
curved_edge_area_sum += index[1]
elif index[0] == 1:
triangle_area_sum += index[1]
elif index[0] == 2:
square_area_sum += index[1]
elif index[0] == 3:
rectangle_area_sum += index[1]
elif index[0] == 4:
pentagon_area_sum += index[1]
elif index[0] == 5:
hexagon_area_sum += index[1]
elif index[0] == 6:
heptagon_area_sum += index[1]
elif index[0] == 7:
ellipse_area_sum += index[1]
elif index[0] == 8:
circle_area_sum += index[1]
else:
pass
sum456 = pentagon_area_sum + hexagon_area_sum + heptagon_area_sum
# if rectangle_area_sum > 0 and square_area_sum >= triangle_area_sum >= rectangle_area_sum:
if square_area_sum >= triangle_area_sum >= rectangle_area_sum:
return_people = [0]
# if rectangle_area_sum == 0 and triangle_area_sum > 0 and square_area_sum >= triangle_area_sum:
if rectangle_area_sum == 0 and square_area_sum >= triangle_area_sum:
return_people = [1, 4]
# if circle_area_sum == 0 and sum456 > 0 and rectangle_area_sum >= sum456:
if circle_area_sum == 0 and rectangle_area_sum >= sum456:
return_people = [10, 11, 14]
# if circle_area_sum > 0 and rectangle_area_sum >= sum456 >= circle_area_sum:
if rectangle_area_sum >= sum456 >= circle_area_sum:
return_people = [12, 13]
# if ellipse_area_sum == 0 and triangle_area_sum > 0 and sum456 > circle_area_sum > triangle_area_sum:
if ellipse_area_sum == 0 and sum456 > circle_area_sum > triangle_area_sum:
return_people = [20]
# if ellipse_area_sum > 0 and sum456 > circle_area_sum > ellipse_area_sum:
if sum456 > circle_area_sum > ellipse_area_sum:
return_people = [21, 22, 23]
# if ellipse_area_sum > 0 and sum456 > curved_edge_area_sum > ellipse_area_sum:
if sum456 > curved_edge_area_sum > ellipse_area_sum:
return_people = [24]
# if ellipse_area_sum > 0 and sum456 == 0 and circle_area_sum >= ellipse_area_sum:
if sum456 == 0 and circle_area_sum >= ellipse_area_sum:
return_people = [30, 31, 32, 33, 34]
if sum456 == 0 and curved_edge_area_sum >= ellipse_area_sum:
return_people = [40, 41, 42, 43, 44]
else:
if return_value_list[0][0] == 1 or return_value_list[0][0] == 2:
return_people = [10, 11, 12, 13, 14]
elif return_value_list[0][0] == 3:
return_people = [20, 21, 22, 23, 24]
elif return_value_list[0][0] == 4 or return_value_list[0][0] == 5 or return_value_list[0][0] == 6:
return_people = [30, 31, 32, 33, 34]
elif return_value_list[0][0] == 8:
return_people = [30, 31, 32, 33, 34]
elif return_value_list[0][0] == 0:
return_people = [40, 41, 42, 43, 44]
elif return_value_list[0][0] == 7:
return_people = [30, 31, 32, 33, 34, 40, 41, 42, 43, 44]
else:
return_people = [30, 31, 32, 33, 34]
return return_people
# return return_value_list
# 显示
# print(CornerNum)
# objType += str(perimeter) + " " + str(contour_area) # + " " + str(perimeter_area)
# 绘制边界框
# cv2.rectangle(imgContour, (x, y), (x+w, y+h), (0, 0, 255), 2)
# 绘制文字
# cv2.putText(imgContour, objType, (x+(w//2), y + (h//2)), cv2.FONT_HERSHEY_COMPLEX, 0.6, (0, 0, 0), 1)
# 主函数
def contour_calculator_main(filepath):
# 读取图片
img = cv2.imread(filepath)
imgContour = img.copy()
# 转灰度图
imgGray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
# 高斯模糊
imgBlur = cv2.GaussianBlur(imgGray, (5, 5), 1)
# Canny算子边缘检测
imgCanny = cv2.Canny(imgBlur, 60, 60)
# 形状检测
print(ShapeDetection(imgCanny, imgContour))
# cv2.imshow("Original img", img)
# cv2.imshow("imgGray", imgGray)
# cv2.imshow("imgBlur", imgBlur)
# cv2.imshow("imgCanny", imgCanny)
# cv2.imshow("shape Detection", imgContour)
# cv2.waitKey(0)
# 测试代码
# 测试中文路径:不可行
# any_filepath = 'D:/pic/shop.png'
# 圆角长方体
# any_filepath = 'D:/MyProject/OpenCV2/photo/targetRectangle.jpg'
# any_filepath = 'D:/MyProject/OpenCV2/photo/targetOval.jpg'
# any_filepath = 'D:/MyProject/OpenCV2/photo/targetIncludeWord.jpg'
# any_filepath = 'D:/MyProject/OpenCV2/photo/targetInregular.png'
# any_filepath = 'D:/MyProject/OpenCV2/photo/target01.png'
any_filepath = 'D:/Projects/PersonalProjects/ShapeDetection/photo/target02.jpg'
contour_calculator_main(any_filepath)
# 主函数
# if __name__ == '__main__':
# any_filepath = sys.argv[1]
# contour_calculator_main(any_filepath)
# 自动识别几何轮廓,把圆识别
# 圆角的长方形
# 拟合曲线,滤波
# 识别图形的关节角度
# 找图形之间的阈值
# 2022年9月27日
# 可以识别png
# 轮廓太浅,边界颜色太浅无法识别
# 1.识别圆角
# 2.查找比例
# 圆角三角形,8个顶点,周长面积比0.0493567,可以定为0.049-0.050之间
# 长椭圆:6或者8个顶点,周长面积比0.015-0.022
# 分类逻辑:
# 1.单个图形,利用顶点和长宽比进行区分
# 三个顶点:三角形
# 四个顶点:
# 长宽相等:正方形
# 长宽不等: 长方形
# 五个顶点:五边形
# 六个顶点:六边形
# 七个顶点:七边形
# 八个顶点:
# 0.015 < perimeter_area < 0.019:椭圆形
# 0.049 < perimeter_area < 0.050:圆角三角形
# 八个以上顶点:
# 长宽相等:圆形
# 长宽不等:其他图形
# 其余情况:其他图形
#
# 2.多个图形,在1的基础按照面积占比分类。占比顺序与表一致。