文章目录
根据导师的项目需求,需要在工厂环境下控制相机拍摄水泥罐车车顶图片,识别出车顶的水泥罐装圆形口并进行坐标定位,这其中需要涉及到 相机标定、单目测距、图像坐标确定、圆形物体识别 等。
进行单目相机测距之前我们首先要做到两点:1.保证测距使用的图片是矫正后的、没有畸变的,可以提高我们的精度(涉及相机标定);2.我们已知相机的焦距(可以通过相机标定得到)。
参考
https://blog.csdn.net/spw_1201/article/details/78417551
我们首先使用MATLAB对相机拍摄图片进行标定得到内外参数,再使用opencv通过已知内外参数进行图片矫正。
使用最简单的黑白棋盘格标定板,可以直接从opencv官网下载得到:
https://docs.opencv.org/2.4/_downloads/pattern.png

使用系统所用的单目相机拍摄带有棋盘格标定板各个角度的照片,保存大概15-20张即可。需要测量记录好棋盘格方格的大小,在标定中会使用。按照opencv官网提供的图片下载打印出的方格大小大约为26mm。

使用MATLAB进行相机标定:首先在命令行窗口中输入cameraCalibrator调用标定应用;

或者在APP中找到cameraCalibrator。

即可打开 Camera Calibrator

将我们之前采集的图片添加进去,会出现选择棋盘格方格大小的窗口,按照我们之前的测量记录选择参数即可。

单击确定后,MATLAB会自动地分析图片

图片分析结束后,会出现结果窗口

可以看到,我们的20张图片中有6个是不可以使用的,可能是由于角度等问题。点击view images也可以具体查看时哪些图片不可以使用。
点击确定后出现检测成功的图片结果

后面就是比较关键的一步,我们需要选择标定的参数
畸变参数,总共有五个,径向畸变3个(k1,k2,k3)和切向畸变2个(p1,p2)。
在OpenCV中的畸变系数的排列(k1,k2,p1,p2,k3),千万不要以为k是连着的


1.camera model : standard(标准) fisheye(鱼眼),我的摄像头是标准。
2.options:选中径向畸变:“2 coefficients”并且选择偏差:“Skew“和切向畸变:“Tangential Distortion“
径向畸变:通常,两个系数足以进行校准。对于严重失真,例如在广角镜头中,您可以选择3″“3 coefficients””个系数来包含k3。
偏差: 选择Compute Skew 复选框时,校准器会估算图像轴偏斜。某些相机传感器包含缺陷,导致图像的x轴和y轴不垂直。您可以使用skew参数对此缺陷进行建模。如果不选中该复选框,则假定图像轴是垂直的,大多数现代相机都是这种情况。
切向畸变: 当镜头和图像平面不平行时,发生切向畸变。切向失真系数模拟了这种类型的失真:
(这些选项根据你的相机进行选择)
然后点击Calibrate按钮即可得到标定的结果。

点击Show Undistorted按钮可以显示无畸变的图像

选择导出数据,即可把参数进行保存

保存后可以退出标定应用,在MATLAB主界面中将保存的cameraParams文件打开。

里面的RadialDistortion对应 **k1,k2(k3设置为0了)。

TangentialDistortion对应 p1,p2。

IntrinsicMatrix对应 内参数矩阵,注意这个和OpenCV中是转置的关系,注意不要搞错。

对应于

FocalLength对应 相机焦距,这个在后面进行测距工作会用到

代码如下
import cv2
import numpy as np
#将相机的参数设置好,固定值
#相机内参数矩阵,3*3矩阵
cameraMatrix = np.array([[3.520275278305173e+03, 7.951186274833666, 2.302224660073940e+03],
[0, 3.521771625935550e+03, 1.729056461937039e+03],
[0, 0, 1]])
#相机畸变系数矩阵,5*1矩阵(k1,k2,p1,p2,k3)
distCoeffs = np.array([0.092142020349690, -0.532537876414274, -0.002400984624408, 0.001577353702050, 0])
# 读入原图片
img = cv2.imread("E:/Cement Canning/600.jpg")
h, w = img.shape[:2]
newCameraMatrix, roi = cv2.getOptimalNewCameraMatrix(cameraMatrix, distCoeffs, (w,h), 1, (w,h), 0)
# 计算无畸变和修正转换关系
mapx, mapy = cv2.initUndistortRectifyMap(cameraMatrix, distCoeffs, None, newCameraMatrix, (w,h), cv2.CV_16SC2)
# 重映射
dst = cv2.remap(img, mapx, mapy, cv2.INTER_LINEAR)
# 调整显示窗口大小
cv2.namedWindow("dst",0);
cv2.resizeWindow("dst", 1268, 952);
cv2.imshow("dst", dst)
#按任意键退出
cv2.waitKey(0)
cv2.destroyAllWindows()
矫正后的结果如下:

可以看到矫正的效果并不理想,可能是选择options时不合适。
对比其他博主的效果,我认为问题可能是由于,我的图片是用手机拍摄的,手机可能已经带有去畸变矫正,所以导致实验效果不佳?
参考
https://blog.csdn.net/m0_37811342/article/details/80394935
通过阅读其他资料可以得知 焦距F(单位像素值)、目标物体宽度W(单位m)、目标物体在图片中的像素宽度P(单位像素值)、目标物体距离相机距离X(单位m) 之间的关系:
F = (P*X) / W
那么在我们已知F、P、W的情况下即可求得物体距离D:
X = (F*W) / P
F我们在上面可以得到:
Fx = 3.520275278305173e+03
Fy = 3.521771625935550e+03
至于为什么一个相机出现两个焦距可以参考下面的讲解:
https://www.cnblogs.com/zipeilu/p/6658177.html
目标物体我使用的是标准的A4纸对折,宽度W为:0.21m,高度H为:0.1485m。

至于像素宽度P我们可以使用霍夫变换检测并求出白纸在图像中的像素宽度值
代码如下,用霍夫变换检测到图像中的矩形,即可得到矩形的,并通过得到的矩阵的轮廓长度和面积来计算像素宽度和像素高度
(需要注意的是: 拍摄的图片中最后不要出现太多无关物体,否则识别白纸时会造成干扰。)
import cv2
import math
import numpy as np
img = cv2.imread("E:/Cement Canning/400.jpg") #读取图像
cv2.namedWindow("img",0);
cv2.resizeWindow("img", 1268, 952);
cv2.imshow("img",img) #显示原图像
dst = img.copy()
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #转为灰度值图
gaussian = cv2.GaussianBlur(gray, (5, 5), 0, 0) #高斯去噪
cv2.namedWindow("gaussian",0);
cv2.resizeWindow("gaussian", 1268, 952);
cv2.imshow("gaussian", gaussian)
ret, binary = cv2.threshold(gaussian,127,255,cv2.THRESH_BINARY) #转为二值图
cv2.namedWindow("binary",0);
cv2.resizeWindow("binary", 1268, 952);
cv2.imshow("binary", binary)
contours, hierarchy = cv2.findContours(binary,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE) #寻找轮廓
#n=len(contours) #轮廓个数
#for i in range(n):
#去除掉根本不可能是要识别的矩形的物体,这个可以在
# if len(contours[i]) >= 4:
# print(contours[i])
# length = cv2.arcLength(contours[i], True) #获取轮廓长度
# area = cv2.contourArea(contours[i]) #获取轮廓面积
# print('length['+str(i)+']长度=',length)
# print("contours["+str(i)+"]面积=",area)
# cv2.drawContours(dst, contours, i, (0, 0, 255), 3) #绘制轮廓
#通过面积来筛选出我们要识别的矩形
c = max(contours, key=cv2.contourArea)
print(c)
cv2.drawContours(dst, c, -1, (0, 0, 255), 3) #绘制轮廓
#轮廓长度
length = cv2.arcLength(c, True)
#轮廓面积
area = cv2.contourArea(c)
#通过周长和面积计算矩形的高度和宽度
x = length/4 - (math.sqrt(math.pow(length, 2)/16 - area))
y = length/2 - x
print("高度或宽度:", x)
print("高度或宽度:", y)
cv2.namedWindow("dst",0);
cv2.resizeWindow("dst", 1268, 952);
cv2.imshow("dst", dst)
cv2.waitKey()
cv2.destroyAllWindows()


接下来就可以计算相机距离拍摄的白纸的距离,我们在拍摄时测量了手机镜头到白纸的距离为0.21m,后面我们通过计算来看看误差是多少。
(1)通过高度计算:
距离 = (Fy * H)/ 2251.85589
距离 = 0.23225m
误差: 10.595%
(2)通过宽度计算:
距离 = (Fx * W)/ 4381.74687
距离 = 0.16871m
误差:19.662%
分析:(1)x,y方向到白纸的距离有差别,可能是我用手机拍摄时,手机镜头不是水平的原因;(2)误差较大,可能是我测量镜头到白纸的距离用尺子测得不准确,还有就是拍摄的图片效果不好,后面可以使用工业相机再次进行尝试;(3)霍夫变换检测矩形时,检测到矩形边缘上的点不是连续的,这就导致计算出来的轮廓长度和面积有误差,导致计算出来的像素宽度和高度有误差。
根据(3)中原因,我尝试使用手动测量像素宽度和高度,高度为:2711.0158px,宽度为:3757.6278px。
高度计算出的距离为:0.19291m, 误差为:8.138%
宽度计算出的距离为:0.19674m, 误差为:6.314%
📢博客主页:https://blog.csdn.net/weixin_43197380📢欢迎点赞👍收藏⭐留言📝如有错误敬请指正!📢本文由Loewen丶原创,首发于CSDN,转载注明出处🙉📢现在的付出,都会是一种沉淀,只为让你成为更好的人✨文章预览:一.分辨率(Resolution)1、工业相机的分辨率是如何定义的?2、工业相机的分辨率是如何选择的?二.精度(Accuracy)1、像素精度(PixelAccuracy)2、定位精度和重复定位精度(RepeatPrecision)三.公差(Tolerance)四.课后作业(Post-ClassExercises)视觉行业的初学者,甚至是做了1~2年
在本文中,我们将探讨摄影机的外参,并通过Python中的一个实践示例来加强我们的理解。相机外参摄像头可以位于世界任何地方,并且可以指向任何方向。我们想从摄像机的角度来观察世界上的物体,这种从世界坐标系到摄像机坐标系的转换被称为摄像机外参。那么,我们怎样才能找到相机外参呢?一旦我们弄清楚相机是如何变换的,我们就可以找到从世界坐标系到相机坐标系的基变换的变化。我们将详细探讨这个想法。具体来说,我们需要知道相机是如何定位的,以及它在世界空间中的位置,有两种转换可以帮助我们:有助于确定摄影机方向的旋转变换。有助于移动相机的平移变换。让我们详细看看每一个。旋转通过旋转改变坐标让我们看一下将点旋转一个角度
俯拍相机中心和吸嘴中心的标定文章目录俯拍相机中心和吸嘴中心的标定前言适用模型如下:一、使用一个标定片进行标定1.关键注意:2.标定步骤:二、使用一个L型的工件1.关键注意:2.标定步骤:总结前言在自动化设备领域,使用相机进行定位是很普遍存在的,而使用相机定位就必定会用到标定,本文介绍两种关于吸嘴上方的俯拍相机和吸嘴中心的标定方法(前提是带有仰拍相机和俯拍相机)。【还有很多相机的使用场景的标定方法将在以后的文章中进行阐述】适用模型如下:一、使用一个标定片进行标定1.关键注意:关键是使用两个相机的中心和识别偏差,得到两个相机的中心固定偏差。注:后续俯拍相机拍物料识别得到的偏差以吸嘴中心在俯拍相机中
相机内参标定,相机和激光雷达联合标定一、相机标定原理1.1成像过程1.2标定详解二、相机和激光雷达联合标定2.1标定方法汇总2.2Autoware的安装与运行2.2.1安装方式2.2.2安装Autoware的依赖(Ubuntu16.04/kinetic)2.2.3编译Autoware1.创造工作空间2.下载Autoware源码3.其他依赖4.编译5.效果2.3Autoware标定激光雷达和相机的外参过程一、相机标定原理1.1成像过程现实物体在相机中的成像过程离不开世界坐标系、相机坐标系、图像坐标系以及像素坐标系,只有理解了这些才能对获取的图像进行准确的分析。成像过程:四个坐标系如下图所示:世界
1,Camera基本工作原理答案:光线通过镜头Lens进入摄像头内部,然后经过IRFilter过滤红外光,最后到达sensor(传感器),senor分为按照材质可以分为CMOS和CCD两种,可以将光学信号转换为电信号,再通过内部的ADC电路转换为数字信号,然后传输给DSP(如果有的话,如果没有则以DVP的方式传送数据到基带芯片baseband,此时的数据格式RawData,后面有讲进行加工)加工处理,转换成RGB、YUV等格式输出。数据流是如何从sensor到APP的?上述描述结束后,在ISP处理后面的阶段,数据会进行分流,分为capture,preview,video等以供后续动作使用。例如
项目场景Baumer工业相机堡盟相机是一种高性能、高质量的工业相机,可用于各种应用场景,如物体检测、计数和识别、运动分析和图像处理。 Baumer的万兆网相机拥有出色的图像处理性能,可以实时传输高分辨率图像。此外,该相机还具有快速数据传输、低功耗、易于集成以及高度可扩展性等特点。 Baumer堡盟VCX相机为堡盟全系列相机中的主流常用相机,性能强大、坚固可靠,易于集成,常用与一般行业的检测定位识别使用。问题描述工业相机的触发有多种方式:1.硬件触发:使用外部硬件设备来触发相机,如传感器或开关。2.软件触发:使用软件来触发相机,可以是手动的也可以是自动的。3.同步触发:使相机的触发与其他设备或系
自定义相机起因由于最近用uniapp调用原生相机容易出现闪退问题,找了很多教程又是压缩图片又是优化代码,我表示并没有太大作用!!实现自定义相机使用效果图拓展实现多种自定义相机水印相机身份证相机人像相机起因由于最近用uniapp调用原生相机容易出现闪退问题,找了很多教程又是压缩图片又是优化代码,我表示并没有太大作用!!于是开启了我的解决之路利用livePusher实现实现自定义相机拓展性挺强的,可以实现自定义水印、身份证拍摄、人像拍摄等这里我简单实现一个相机功能主要用于解决闪退Tip:这里需要创建nvue文件哦~创建camera.nvuetemplate> viewclass="pengke-c
虽然我已经将它传递给我的渲染方法,但我为什么要将它添加到场景中?我在存储库中看到的每个示例都将相机添加到场景中,例如weggl_geometries.但是在删除scene.add(camera)之后它仍然有效......初始化函数camera=newTHREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,1,2000);camera.position.y=400;scene.add(camera);渲染函数renderer.render(scene,camera); 最佳答案
我在看两个例子,一个是Canvas交互对象,另一个是鼠标工具提示。我尝试将两者结合起来在每个单独的立方体上生成文本标签,这就是我目前所拥有的。但是,文本会随着旋转的立方体移动,并且有时会向后或向侧面显示文本。我怎样才能像鼠标工具提示(http://stemkoski.github.io/Three.js/Mouse-Tooltip.html)示例中那样将文本固定在Sprite中?我试图合并Sprite,但我不断收到错误。我不知道该怎么做。你能解释一下我该如何去做吗?谢谢。到目前为止,这是我的代码:three.jscanvas-interactive-cubesbody{font-fam
在three.js中,我试图创建一个纹理,其图像是从相机看到的当前场景。使用CubeCamera来创建类似的效果是有据可查的;我用CubeCamera创建了一个场景示例来说明我的目标:http://stemkoski.github.com/Three.js/Camera-Texture-Almost.html但是,我想使用普通相机(而不是立方体相机)作为纹理。我怎么能这样做? 最佳答案 理想情况下这会起作用。初始化:renderTarget=newTHREE.WebGLRenderTarget(512,512,{format:THR