浅记录一下学院数模赛的算法流程

题目

自拟场景和尺寸,在有参照物的情况下,依据图片,建立模型估计以下土堆的立方数

image-20220401142622068

思路及算法

思路

  1. 筛选出需要的土堆和挖掘机部分

  2. 根据轮廓利用古鲁金定理计算像素体积

    gulujin
  3. 根据挖掘机在图片中的面积以及实际尺寸计算图片和实际长度的转化关系

  4. 代入计算的土堆像素体积获得实际体积

因为python的opencv只能识别HSV三通道参数,需要根据HSV表来粗筛选土堆和挖掘机

HSV颜色参考:

image-20220401143415448

算法

封装了一个计算形心相对图片坐标的函数ShapeHeart,输入为图片,标识名称,HSV高低数组,返回值为形心坐标cx和cy,和轮廓的像素面积,输出二值化图片,红线轮廓图片以及蓝色形心图片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2022/3/30 14:44
# @Author : YH
import math
import cv2 as cv
import numpy as np
def ShapeHeart(img,name,low,high):
img = cv.GaussianBlur(img, (5, 5), 0)
cv.imwrite("./pic"+"/"+name+"_Gauss.jpg",img)
"""
提取颜色
"""
hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV)
low_hsv = np.array(low)
high_hsv = np.array(high)
mask = cv.inRange(hsv, lowerb=low_hsv, upperb=high_hsv)
# 展示二值图
cv.imshow(name+"_Grayscale",mask)
cv.waitKey(0)
cv.destroyAllWindows()
# 保存土堆轮廓
cv.imwrite("./pic"+"/"+name+"_Grayscale.jpg", mask)
contours, hierarchy = cv.findContours(mask, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
cv.drawContours(img, contours, -1, (0, 0, 255), 1)
# 保存轮廓线图片
cv.imwrite("./pic"+"/"+name+"_Outline.jpg",img)
cv.imshow(name+"_Outline",img)
cv.waitKey(0)
cv.destroyAllWindows()
areas = []
for c in range(len(contours)):
areas.append(cv.contourArea(contours[c]))
MAX = areas.index(max(areas)) # 求最大轮廓序号
M = cv.moments(contours[MAX]) # 求矩
cx = int(M['m10'] / M['m00']) # 求x坐标
cy = int(M['m01'] / M['m00']) # 求y坐标
cv.circle(img, (cx, cy), 1, (255,0,0), 0)
cv.imwrite("./pic" + "/" + name + "_ShapeHeart.jpg", img) #保存形心图片
area = cv.contourArea(contours[MAX])
return cx, cy, area

土堆计算的主函数:

1
2
3
4
5
6
7
8
9
if __name__ == "__main__":
img = cv.imread('tudui.jpg')
cx,cy,area = ShapeHeart(img,name="Mound",low=[78, 40, 120],high=[100, 255, 255])
print(cx,cy,area)
img1 = img[0:img.shape[0], 0:cx]
cx1,cy1,area1 = ShapeHeart(img1,name="Mound1",low=[78, 40, 120],high=[100, 255, 255])
print(cx1,cy1,area1)
V = 2*abs(cx-cx1)*math.pi*area/2*math.pow(0.033082679182000536,3)
print(V)

其中V计算中math.pow用的是计算获得的像素与实际长度转化关系,这个值准确性有待提高,因为挖掘机的具体参数并未获得,计算过程中没有很好考虑视角造成的长度影响

卡车计算的额外步骤:

1
2
3
space = (math.cos(math.pi/3)+math.cos(math.pi/6))*0.84*2.22
#计算像素和实际长度转化关系
a = math.sqrt(space/area)

这个算法只能初步实现分离物体,如果需要更加精细还需要改进