距离上次的栈板识别的思考已经过去3个月,中间根据客户的需求和自己的思考,对软件又重新做了调整。但是整体上还是不满意。
对于软件架构,我实在没有太多的参考。没办法,公司根本不关心软件是什么玩意。对于一个销售型公司,在2023年了,还认为软件是硬件的附赠品。所以对于软件,公司的态度就是很随意。所以根本也不会有软件框架可以参考,或者类似的需求。但是我们可以看看雷卡慢的。不说具体的细节,因为我也没用过。之前我提出要公司弄一套给我们参考,但是显然不现实,
视觉工程最重要的就是相机拍照,视觉算法,通讯。
其实这个软件就是一个图形化的工程工具,他把视觉工程通过拖拉ui的方式搭建成一整个流程图。但是内置的算法,我理解的就是一深度学习推理端的部署。因为他把训练的模块又弄了一个软件
模型训练工具
这个我最感兴趣的是他的标定工具。当然这种类似的软件其实是每一个视觉厂家必须有的东西。当然我们除外。
我们公司可以说以上3种软件全部没有,那么作为视觉工程师。我们接到任务后,需要哪方面的技术呢。
之前我们说过,就不再赘述。现在出现的新问题,需要解决
之前使用了各种方式去增强图像数据的对比度。使得我们要检测的1500-3000范围内的栈板有很好的对比度。结论就是还是对数变换。
经过了几个客户的测试,我最终还是换成了yolov5。但是瞎折腾也有瞎折腾的好处不是么。yolov5的适应性显然强过yolov7。
推理后端我还是改成了onnx。相比pytorch的真的是体积小速度快。当然win下还是openvino快一点。但是我现在不仅要考虑win linux 还要考虑 树莓派。真的是一个简单的软件弄得特别复杂。具体的测试结果看其他文章。
这里我不得不吐槽一下open3d ,我使用pyinstaller打包竟然一个open3d就占了900m 打包的软件加上权重,足足1。5g 客户直接骂娘。而我只用了它其中的一个拟合平面的函数。所以果断去找源码,照着改了一份。这里参考我的其他文章。
我是真的服了老外的SDK,真的不当人。当然也怪我,水平不够,看Demo完全没用。前前后后我又把相机的SDK 看了2遍。算是懂了一大半,但是他还是很多漏洞。。。。
之前我一直通过拟合直线获取平面的法向量。
但是这种方式有个问题,那就是另外一个方向是不知道的。所以如果我的相机的安装方式不规整,那么我们就需要3个坐标轴的旋转角度。
我的想法是通过找的矩形框去拟合对应的平面
其实这个是让我最着迷的,研究了2天,最后发现瞎折腾。我偶然间发现cloudcomepare 中有个拟合平面的工具竟然拟合的平面是带有旋转矩阵的。这个发现让我欣喜若狂。这样问题不久解决了么。我去看看了他妈的源码。竟然是计算点云的协方差矩阵,然后算矩阵的特征值和特征向量。其中特征值最小的的特征向量就是z轴,特征值最大的特征向量是x轴。z,x叉乘就是y轴。简直不要太牛逼。然后我发现误差贼大。
那就把之前的拟合平面的算法加上去,筛选出正确的点云数据。
然后通过求解协方差矩阵的特征向量获取坐标轴。
def getboxfrompoints(points, inliers):
# 计算点云的协方差矩阵
cov_matrix = np.cov(points[inliers], rowvar=False)
eigenvalues, eigenvectors = np.linalg.eig(cov_matrix)
# 创建特征向量
z_indx = np.argmin(eigenvalues)
z = eigenvectors[:, z_indx]
x_indx = np.argmax(eigenvalues)
x = eigenvectors[:, x_indx]
y = np.cross(z, x)
# 创建 Open3D 点云对象
point_cloud = o3d.geometry.PointCloud()
point_cloud.points = o3d.utility.Vector3dVector(points[inliers])
# 创建坐标轴
coordinate_frame = o3d.geometry.TriangleMesh.create_coordinate_frame(size=100.0, origin=np.array([0, 0, 0]))
# 计算旋转角度
theta_x = np.arctan2(y[2], z[2])
theta_y = np.arctan2(-x[2], np.sqrt(x[0]**2 + x[1]**2))
theta_z = np.arctan2(x[1], x[0])
# 获取旋转矩阵
rotation_matrix = np.eye(3)
# rotation_matrix = np.dot(rotation_matrix, np.array([x,y,z]))
rotation_matrix = np.dot(rotation_matrix, o3d.geometry.get_rotation_matrix_from_xyz([theta_x, theta_y, theta_z]))
# 旋转坐标轴
coordinate_frame.rotate(rotation_matrix)
# 缩放坐标轴
coordinate_frame.scale(1.0, center=np.mean(points[inliers], axis=0))
# 平移坐标系
coordinate_frame.translate(np.mean(points[inliers], axis=0))
# 将点云和坐标轴合并到一个列表中
geometries = [point_cloud, coordinate_frame]
# 显示点云和坐标轴
o3d.visualization.draw_geometries(geometries)
# return matrix_to_euler(np.array([x,y,z]))
return np.degrees(np.array([theta_x,theta_y,theta_z]))