球体的双目视觉定位(matlab,附代码)

标签(空格分隔): 机器视觉

引言

双目视觉定位是我们的一个课程设计,最近刚做完,拿出来与大家分享一下,实验的目的是在拍摄的照片中识别球体,并求出该球体到相机的实际距离吗,我们要求需要用matlab,但是matlab调用双目摄像头(一个USB口)却老是只能调用双目摄像头中的一个,但是利用Python的OpenCV库却可以同时调用两个,因此我们选用了Python用于拍摄图片。

1.基本流程

备注:因为根据得出的视差图识别出圆球略困难,我们没有采用视差图深度图去得出球体的深度,而是直接利用校正后的图片像素差,代入公式直接求出距离。

1.相机标定

首先我们要知道在摄像机模型中,一般要涉及四种坐标系:世界坐标系、摄像机坐标系、图像坐标系、像素坐标系。相机标定的作用可以理解为找到一种将世界坐标系和图像坐标系之间的变换关系。

具体标定可以参考这篇文章:双目视觉相机标定

1.像素坐标系(u,v):

顾名思义,每一点都是一个像素,原点通常设置在图像的左上角处,点的横纵坐标分别代表相应的像素在图像中位于第几行第几列;

2.图像坐标系(x,y):

将原点设置在相机光轴与图像平面的交点处,横轴、纵轴与像素坐标系的横轴、纵轴平行; 图像平面的中心为坐标原点,为了描述成像过程中物体从相机坐标系到图像坐标系的投影透射关系而引入,方便进一步得到像素坐标系下的坐标。图像坐标系是用物理单位(例如毫米)表示像素在图像中的位置。

3.相机坐标系(x,y,z):

摄像机站在自己角度上衡量的物体的坐标系。摄像机坐标系的原点在摄像机的光心上,z轴与摄像机光轴平行。它是与拍摄物体发生联系的桥头堡,世界坐标系下的物体需先经历刚体变化转到摄像机坐标系,然后在和图像坐标系发生关系。它是图像坐标与世界坐标之间发生关系的纽带,沟通了世界上最远的距离。单位为长度单位如mm。

4.世界坐标系 (Xw,Yw,Zw):

物体在真实世界中的坐标。

具体标定利用matlab的工具箱,步骤如下:

1.打印标定板:

2.拿着标定板拍照(拍照代码在文末),效果图如图:

3.将上面的照片按left,right分为两组,放到两个文件夹中,打开matlab进行标定。在命令行窗口输入stereoCameraCalibrator,出现如下界面:

4.然后将上面的“Skew”、“Tangential Distortion”以及“2 Coefficients”等选项选上,将“3 Coefficients”选项去掉,如下:

5.载入图像:

备注:标定板打印的标准一点,图中的25是小方格边长,方格!边长!根据你的实际情况修改。

6.点击按钮进行标定:

7.选中直方图中误差较大的一些组,(与此同时左侧的图片也会被选中),将这些删除,然后他会自动重新标定。

8.觉得没问题了,就把标定的数据导出(那个绿色的对勾符号)。之后关掉这个工具箱,会弹出一个框,然后选择yes保存生成的.mat文件。记住自己保存的路径,下次用的时候提前在matlab中打开这个文件。至此,标定完成。

标定的参数包括很多,包括相机的内参,外参等,有旋转矩阵,平移矩阵等。可以自己去查查。

2.图像校正

图像校正是根据标定获取的畸变矩阵,来校正相机拍摄时造成的误差,包括径向畸变和切向畸变。两者合起来是一个15的矩阵,不过matlab标定的时候却只显示两个12的矩阵,查了知道缺失的一个参数可以设置为0,.如果你利用python双目测距这篇文章做的双目视觉定位,这句话肯定会给予你帮助。

3.识别圆球

这里采用了霍夫变换去识别小球,霍夫变换找圆的基本思想是,对于一个圆

我们可以把它放入以a,b,r为坐标轴的三维坐标系系中,而不是以x,y为坐标轴的二维坐标系中,又因为同一平面不在一条直线的三个点就可以确定一个圆,所以图中对应的A点(a,b,r)就是一个圆心,但是如果这样找的话,图中可以找到很多这样的三个点,所以也肯定能找到很多圆,因此需要进行‘投票’,即如果有很多点交于这一点,那么这个点极有可能是圆心:

具体代码如下,(github上找的):

function [Hough_space,Hough_circle_result,Para] = Hough_circle(BW,Step_r,Step_angle,r_min,r_max,p)

%---------------------------------------------------------------------------------------------------------------------------

% input:

% BW:二值图像;

% Step_r:检测的圆半径步长;

% Step_angle:角度步长,单位为弧度;

% r_min:最小圆半径;

% r_max:最大圆半径;

% p:以p*Hough_space的最大值为阈值,p取0,1之间的数.

% a = x-r*cos(angle); b = y-r*sin(angle);

%---------------------------------------------------------------------------------------------------------------------------

% output:

% Hough_space:参数空间,h(a,b,r)表示圆心在(a,b)半径为r的圆上的点数;

% Hough_circle:二值图像,检测到的圆;

% Para:检测到的圆的圆心、半径.

%---------------------------------------------------------------------------------------------------------------------------

circleParaXYR=[];

Para=[];

%得到二值图像大小

[m,n] = size(BW);

%计算检测半径和角度的步数、循环次数 并取整,四舍五入

size_r = round((r_max-r_min)/Step_r)+1;

size_angle = round(2*pi/Step_angle);

%建立参数空间

Hough_space = zeros(m,n,size_r);

%查找非零元素的行列坐标

[rows,cols] = find(BW);

%非零坐标的个数

ecount = size(rows);

% Hough变换

% 将图像空间(x,y)对应到参数空间(a,b,r)

% a = x-r*cos(angle)

% b = y-r*sin(angle)

i = 1;

ecount = ecount(1);

for i=1:ecount

for r=1:size_r %半径步长数按一定弧度把圆几等分

for k=1:size_angle

a = round(rows(i)-(r_min+(r-1)*Step_r)*cos(k*Step_angle));

b = round(cols(i)-(r_min+(r-1)*Step_r)*sin(k*Step_angle));

if (a>0&&a<=m&&b>0&&b<=n)

Hough_space(a,b,r)=Hough_space(a,b,r)+1;%h(a,b,r)的坐标,圆心和半径

end

end

end

end

% 搜索超过阈值的聚集点,对于多个圆的检测,阈值要设的小一点!通过调此值,可以求出所有圆的圆心和半径返回值就是这个矩阵的最大值

max_para = max(max(max(Hough_space)));

%一个矩阵中,想找到其中大于max_para*p数的位置

index = find(Hough_space>=max_para*p);

length = size(index);%符合阈值的个数

Hough_circle_result=zeros(m,n);

%通过位置求半径和圆心。

length = length(1);

k = 1;

par = 1;

for i=1:ecount

for k=1:length

par3 = floor(index(k)/(m*n))+1;

par2 = floor((index(k)-(par3-1)*(m*n))/m)+1;

par1 = index(k)-(par3-1)*(m*n)-(par2-1)*m;

if((rows(i)-par1)^2+(cols(i)-par2)^2

(rows(i)-par1)^2+(cols(i)-par2)^2>(r_min+(par3-1)*Step_r)^2-5)

Hough_circle_result(rows(i),cols(i)) = 1;%检测的圆

end

end

end

% 从超过峰值阈值中得到

for k=1:length

par3 = floor(index(k)/(m*n))+1;%取整

par2 = floor((index(k)-(par3-1)*(m*n))/m)+1;

par1 = index(k)-(par3-1)*(m*n)-(par2-1)*m;

circleParaXYR = [circleParaXYR;par1,par2,par3];

Hough_circle_result(par1,par2)= 1; %这时得到好多圆心和半径,不同的圆的圆心处聚集好多点,这是因为所给的圆不是标准的圆

end

%集中在各个圆的圆心处的点取平均,得到针对每个圆的精确圆心和半径;

while size(circleParaXYR,1) >= 1

num=1;

XYR=[];

temp1=circleParaXYR(1,1);

temp2=circleParaXYR(1,2);

temp3=circleParaXYR(1,3);

c1=temp1;

c2=temp2;

c3=temp3;

temp3= r_min+(temp3-1)*Step_r;

if size(circleParaXYR,1)>1

for k=2:size(circleParaXYR,1)

if (circleParaXYR(k,1)-temp1)^2+(circleParaXYR(k,2)-temp2)^2 > temp3^2

XYR=[XYR;circleParaXYR(k,1),circleParaXYR(k,2),circleParaXYR(k,3)]; %保存剩下圆的圆心和半径位置

else

c1=c1+circleParaXYR(k,1);

c2=c2+circleParaXYR(k,2);

c3=c3+circleParaXYR(k,3);

num=num+1;

end

end

end

c1=round(c1/num);

c2=round(c2/num);

c3=round(c3/num);

c3=r_min+(c3-1)*Step_r;

Para=[Para;c1,c2,c3]; %保存各个圆的圆心和半径的值

circleParaXYR=XYR;

End

4.计算距离

计算距离采用了一个公式:

,其中f为焦距,T为两个相机之间的距离,分母为两个图片的像素差,例如校正之后,球心在第一张图片的像素坐标为(u,v1),在第二章图片的像素坐标为(u,v2),则像素差为|v1-v2|。

注意这个参数,rectifyStereoImages()这个函数要用:

代码如下,读入两幅图,但是只在一张图上进行了距离标注,另一张图只负责提供圆心坐标

注意如果不能准确识别出圆球,需要修改最小,最大圆半径这两个参数:

I1 = imread('E:\image\left_0.jpg');%读取左右图片

I2 = imread('E:\image\right_0.jpg');

%%%注意校正的第三个参数,他的名字由你得到的标定文件得到,看上图%%%%

[J1, J2] = rectifyStereoImages(I1,I2,calibrationSession.CameraParameters);

I1=rgb2gray(J1)

I=rgb2gray(J2)

%------------------------------------------

BW1=edge(I1,'sobel')

BW=edge(I2,'sobel')

%----------

Step_r = 0.5;

%角度步长0.1,单位为弧度

Step_angle = 0.1;

%最小圆半径2

minr =5;

%最大圆半径30

maxr = 8;

%以thresh*hough_space的最大值为阈值,thresh取0-1之间的数

thresh = 1;

%-----------这个只负责提供其中一张图片的圆心坐标,这个函数是上一段代码

[Hough_space,Hough_circle_result,Para] = Hough_circle(BW1,Step_r,Step_angle,minr,maxr,thresh);

%开始检测另一个圆

[Hough_space,Hough_circle_result,Para1] = Hough_circle(BW,Step_r,Step_angle,minr,maxr,thresh);

%两幅图像素差

sub=(Para(2)-Para1(2)) %*100/67%如果这里有67%缩放比例

%焦距

jiaoju=3.6

%相机距离

jixian=12.2

depth=(jiaoju*jixian)/abs(sub)

%距离,转成字符串才能放上去

depth=num2str(depth)

axis equal

figure(1);

imshow(BW,[]),title('边缘(图一)');

axis equal

figure(2);

imshow(Hough_circle_result,[]),title('检测结果(图一)');

axis equal

figure(3),imshow(I,[]),title('检测出图中的圆(图一)')

hold on;

%--------------------------------------------------------------

%以红色线标记出的检测圆心与圆

plot(circleParaXYR(:,2), circleParaXYR(:,1), 'r+');

%打上距离值

text(circleParaXYR(:,2)+circleParaXYR(3), circleParaXYR(:,1)-circleParaXYR(3),depth,'color','red')

for k = 1 : size(circleParaXYR, 1)

t=0:0.01*pi:2*pi;

x=cos(t).*circleParaXYR(k,3)+circleParaXYR(k,2);

y=sin(t).*circleParaXYR(k,3)+circleParaXYR(k,1);

plot(x,y,'r-');

End

得到的效果图:

随便改改代码甚至还可以皮一下:

5.生成视差图

视差图还好说,深度图却相当诡异,所以我们把深度图注释掉了。

clear all

clc

I1 = imread('E:\image\left_0.jpg');%读取左右图片

I2 = imread('E:\image\right_0.jpg');

%I1=imcrop(I1,[0,118,320,320])%去除黑边

%I2=imcrop(I2,[0,118,320,320])

figure

imshowpair(I1, I2, 'montage');

title('Original Images');

%---------------------------------------------------------------

load('E:\image\calibrationSession.mat');%加载你保存的相机标定的mat

%校正图片

[J1, J2] = rectifyStereoImages(I1,I2,calibrationSession.CameraParameters);

% figure

% imshow(J1)

figure

imshowpair(J1, J2, 'montage');

title('Undistorted Images');

%-----------------------------------------

figure; imshow(cat(3, J1(:,:,1), J2(:,:,2:3)), 'InitialMagnification', 100)

%----------------------------------------------------------------------------

%disparityRange = [-6 10];如此果想生成彩色视差图,将此注释解除

disparityMap1 = disparity(rgb2gray(J1),rgb2gray(J2),'DisparityRange',[0,16],'BlockSize',5,'ContrastThreshold',0.3,'UniquenessThreshold',5);

figure

imshow(disparityMap1)%%%,disparityRange);如此果想生成彩色视差图,将此注释解除

% title('Disparity Map');%生成彩色视差图,将此注释解除

% colormap(gca,jet) %生成彩色视差图,将此注释解除

% colorbar%生成彩色视差图,将此注释解除

%---深度图注释掉

%pointCloud3D = reconstructScene(disparityMap1, %calibrationSession.CameraParameters);%深度图

%figure;

%imshow(pointCloud3D);

效果图:

6.拍照用的Python代码,参考python双目测距:

import cv2

import time

AUTO = True # 自动拍照,或手动按s键拍照

INTERVAL = 2 # 自动拍照间隔

cv2.namedWindow("shuangmu")

cv2.moveWindow("shuangmu", 400, 0)

shuangmu_camera = cv2.VideoCapture(1)#打开双目摄像头

counter = 0

utc = time.time()

###pattern = (12, 8) # 棋盘格尺寸

folder = "e:/keshe/" # 拍照文件目录

def shot(pos, frame):

global counter

path = folder + pos + "_" + str(counter) + ".jpg"

cv2.imwrite(path, frame)#保存图像

print("snapshot saved into: " + path)

while True:

#ret是布尔值,如果读取帧是正确的则返回True,frame就是每一帧的图像

ret,double_frame = shuangmu_camera.read()

heigh=len(double_frame)

width=len(double_frame[0])

width2=int(width/2)

left1=double_frame[:heigh,0:width2]

right1=double_frame[:heigh,width2:width]

cv2.imshow("shuangmu", double_frame)

now = time.time()

if AUTO and now - utc >= INTERVAL:

shot("left", left1)

shot("right", right1)

counter += 1

utc = now

key = cv2.waitKey(1)#等待键盘输入,1表示延时1ms切换到下一帧图像,对于视频而言

if key == ord("q"):

break

elif key == ord("s"):

shot("right", right_frame)

counter += 1

cv2.destroyWindow("shuangmu")#释放窗口

python 双目视觉_球体的双目视觉定位(matlab,附代码)相关推荐

  1. python批量json文件转xml文件脚本(附代码)

    场景:在使用了mask rcnn跑实验后标注了大量地json格式文件,现在打算使用yolo和faster rcnn 跑实验 所以需要将之前地json文件转为xml     但是找了很久,没发现有批量处 ...

  2. opencv双目视觉标定、匹配和测量 (附代码)

    from:https://blog.csdn.net/bcj296050240/article/details/52778741 双目视觉原理方面参照<学习Opencv>和大牛博客 htt ...

  3. opencv双目视觉标定、匹配和测量 (附代码)(转载)

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/bcj296050240/article/details/52778741 双目视觉原理方面参照< ...

  4. matlab svm工具箱_机器学习笔记--SVM(MATLAB 实现代码)

    我们知道SVM的基本原理就是找一个超平面(广义平面)将样本分为几个部分,即分类. MATLAB中自带SVM包,使用起来也十分方便,假如X是特征矩阵,Y是分类标签(可以是数值(1.2)也可以是strin ...

  5. python历史性分布计算代码_量化交易中,如何使用Python计算「筹码分布」指标【附代码】 [量化小讲堂-64]...

    引言: 邢不行的系列帖子"量化小讲堂",通过实际案例教初学者使用python进行量化投资,了解行业研究方向,希望能对大家有帮助. [历史文章汇总] 请点击此处 这是邢不行第  64 ...

  6. python开发bs系统_一文告诉你,如何使用Python构建一个“谷歌搜索”系统|内附代码...

    来源 | hackernoon 编译 | 武明利 责编 | Carol 在这篇文章中,我将向您展示如何使用Python构建自己的答案查找系统.基本上,这种自动化可以从图片中找到多项选择题的答案. 有一 ...

  7. 哲学家就餐问题python解决_关于哲学家就餐问题的分析代码.

    ①总体思路: 都去拿左边的筷子,并且最后一个人不能去拿筷子(防止大家都拿了左边的筷子,没有右边的筷子,导致死锁了),解决死锁问题的办法就是同时只允许四位哲学家同时拿起同一边的筷子,这样就能保证一定会有 ...

  8. python代码画土拨鼠_万圣节快到了,让我们用Python画一只蝙蝠图表吧(附代码)...

    本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理 以下文章来源于可以叫我才哥 ,作者小乐老师 前言 万圣节来啦! 今天带给大家一个简 ...

  9. 基于麻雀算法改进的无线传感器网络Dv-hop定位算法 - 附代码

    基于麻雀算法改进的无线传感器网络Dv-hop定位算法 文章目录 基于麻雀算法改进的无线传感器网络Dv-hop定位算法 1.DV-Hop算法原理 2.麻雀算法改进DV-Hop算法原理 3.算法测试 4. ...

最新文章

  1. UI设计十戒--设计师的艺术
  2. html table 筛选记录,JS实现table表格内针对某列内容进行即时搜索筛选功能
  3. 【赠书】金融领域可解释机器学习模型与实践
  4. 解决JavaFX报错缺少 JavaFX 运行时组件, 需要使用该组件来运行此应用程序
  5. TensorFlow学习笔记(六)Variable变量
  6. SimpleXMLRPC_python xmlrpclib SimpleXMLRPCServer 模块
  7. P3076,jzoj3187-的士【贪心】
  8. SpringCloud Openfeign
  9. 腾讯,创新工场,淘宝等公司最新面试三十题(第171-200题)
  10. 设计模式那点事读书笔记(2)----抽象工厂模式
  11. MSMQ 和 MQTT
  12. python客户端与服务器端通信数据库原理_python学习之网络部分
  13. Webview 非http或者https的网络请求拦截
  14. 自媒体原创检测工具,了解了这个离收获大量粉丝不会远啦!
  15. Connext DDSQoS参考
  16. moses 编译_傻瓜式MOSES安装
  17. 超全万字汇总!科研论文绘图实操干货!11类Matplotlib图表,含代码
  18. ajax java首字母检索_AJAX的拼音首字母查找对应中文的portlet
  19. 基于JAVA词典设计碰到的问题,Hanlp配置自定义词典遇到的问题与解决方法
  20. 基于Linux+6818开发板实现普通电子相册翻页功能

热门文章

  1. 详细介绍如何读懂STM32开发板电路原理图以及芯片文档和开发手册,并编写一个测试程序:点亮一个LED灯
  2. Pytorch实现迁移学习
  3. SVG_6_矢量图_transform_animateTransform_豚_鼠?
  4. [由零开始] 手写Mybatis-自定义持久层框架
  5. go 服务器如何优雅的退出、重启
  6. JasperReport中文无法显示
  7. 即使是做咸鱼,也要做最咸的那一条
  8. K8S集群安装配置教程
  9. Mp中的or和and
  10. 排序算法——选择排序法(Select Sorting)