光平面标定代码

news2025/1/18 16:51:47

        本篇文章主要给出光平面标定代码,鉴于自身水平所限,如有错误,欢迎批评指正。(欢迎进Q群交流:874653199)

        数据分为棋盘格数据和激光条数据,激光条数据为在第22个位姿至第26个位姿下打在棋盘格标定板上采集的图像。

clc;
clear;

%% 相机标定
image_filename='.\Calibration';%图像路径

physicalLength=10;%物理长度

image_format='jpeg';%图像格式

namelist = dir([image_filename '\*.' image_format]);

num = length(namelist);


for i = 1:num
    filename=namelist(i).name;
    filename_new=[image_filename '\'  filename];
    imageFileNames{i}=filename_new;
end


[imagePoints, boardSize, imagesUsed] = detectCheckerboardPoints(imageFileNames);
imageFileNames = imageFileNames(imagesUsed);


originalImage = imread(imageFileNames{1});
[mrows, ncols, ~] = size(originalImage);


squareSize = physicalLength;  % in units of 'millimeters'
worldPoints = generateCheckerboardPoints(boardSize, squareSize);


[cameraParams, imagesUsed, estimationErrors] = estimateCameraParameters(imagePoints, worldPoints, ...
    'EstimateSkew', false, 'EstimateTangentialDistortion', true, ...
    'NumRadialDistortionCoefficients', 2, 'WorldUnits', 'millimeters', ...
    'InitialIntrinsicMatrix', [], 'InitialRadialDistortion', [], ...
    'ImageSize', [mrows, ncols]);


% h1=figure; showReprojectionErrors(cameraParams);
% h2=figure; showExtrinsics(cameraParams, 'CameraCentric');
% displayErrors(estimationErrors, cameraParams);
% undistortedImage = undistortImage(originalImage, cameraParams);


IntrinsicMatrix=cameraParams.IntrinsicMatrix;
IntrinsicMatrix=IntrinsicMatrix';

RadialDistortion=cameraParams.RadialDistortion;

TangentialDistortion=cameraParams.TangentialDistortion;

MeanReprojectionError =cameraParams.MeanReprojectionError;

%% 光平面标定
boardSize=boardSize-1;

path_laser='.\Laser';

[a, b, c, d] = calibrateLightPlane(cameraParams, 22:26, path_laser,[8,12],0.3, 1);
 

%% 写入标定结果
tempFile=[image_filename '\标定结果.txt'];
fid=fopen(tempFile,'w');

fprintf(fid,'相机内参:\n');
for m=1:3
for n=1:3
    fprintf(fid,'%.6f     ',IntrinsicMatrix(m,n)); 
end
    fprintf(fid,'\n'); 
end

fprintf(fid,'畸变系数 k1,k2,p1,p2:\n');
fprintf(fid,'%.6f \n',RadialDistortion(1,1)); 
fprintf(fid,'%.6f \n',RadialDistortion(1,2)); 
fprintf(fid,'%.6f \n',TangentialDistortion(1,1)); 
fprintf(fid,'%.6f \n',TangentialDistortion(1,2)); 


fprintf(fid,'反投影误差:\n');
fprintf(fid,'%.6f \n',MeanReprojectionError(1,1)); 

fprintf(fid,'光平面系数:\n');
fprintf(fid,'%.6f \n',a); 
fprintf(fid,'%.6f \n',b); 
fprintf(fid,'%.6f \n',c); 
fprintf(fid,'%.6f \n',d); 

fclose(fid);

%% 光平面标定
function [a, b, c, d] = calibrateLightPlane(cameraParams, laserImagesIndex, laserImagesPath,boardSize, thresh, plotFlag)

intriMatrix = cameraParams.IntrinsicMatrix';
radialDistortion = cameraParams.RadialDistortion;
tangentialDistortion=cameraParams.TangentialDistortion;
M1 = [intriMatrix(1,:), 0; intriMatrix(2,:), 0; intriMatrix(3,:), 0];

allLaserPoint = [];
len = length(laserImagesIndex);
for i = 1 : len
    index = laserImagesIndex(i);
    R = cameraParams.RotationMatrices(:, :, index)';
    T = cameraParams.TranslationVectors(index, :)';   
    M2 = [R, T; 0, 0, 0, 1];
    M = M1 * M2;
    M = [M(:, 1:2), M(:, 4)];
    
    frame = imread([laserImagesPath, '\', num2str(index), '_laser.jpeg']);
    if(numel(size(frame))>2)
        frame = rgb2gray(frame);
    end
    points = cameraParams.ReprojectedPoints(:, :, index);
    col = [points(1,1), points(boardSize(1), 1), points(boardSize(1) * boardSize(2), 1), points(boardSize(1) * (boardSize(2) - 1)+1, 1)];
    row = [points(1,2), points(boardSize(1), 2), points(boardSize(1) * boardSize(2), 2), points(boardSize(1) * (boardSize(2) - 1)+1, 2)];

    BW = roipoly(frame, col, row);
    frame = uint8(BW) .* frame;
    laserPixel = getLaserCenter(frame, thresh, 50,  plotFlag);
    laserPixel=undistortCoor(intriMatrix,radialDistortion,tangentialDistortion,laserPixel);
    laserpixel = [laserPixel(:, 1)'; laserPixel(:, 2)'; ones(1, length(laserPixel(:, 1)))];
 
    laser_wcs =  pinv(M)*laserpixel;

    laser_wcs(1, :) = laser_wcs(1, :) ./laser_wcs(3,:);
    laser_wcs(2, :) = laser_wcs(2, :) ./laser_wcs(3,:);

    laser_wcs = [laser_wcs(1, :)', laser_wcs(2, :)', zeros(length(laserpixel(1, :)), 1), ones(length(laserpixel(1, :)), 1)];

    laser_ccs = (M2 * laser_wcs')';
    allLaserPoint = [allLaserPoint; laser_ccs];
end


planeData = allLaserPoint(:, 1:3);
xyz0=mean(planeData, 1);
centeredPlane=bsxfun(@minus, planeData, xyz0);
[U, S, V]=svd(centeredPlane);
 
a=V(1,3);
b=V(2,3);
c=V(3,3);
d=-dot([a b c], xyz0);

fprintf(' 光平面方程为: %f * X + %f * Y +  %f * Z +  %f = 0 \n', a, b, c, d);

% 绘制拟合结果
if plotFlag ~= 0
    figure;
    rangeX = max(allLaserPoint(:, 1)) - min(allLaserPoint(:, 1));
    rangeY = max(allLaserPoint(:, 2)) - min(allLaserPoint(:, 2));
    y_buff = linspace(min(allLaserPoint(:, 2)) -  min(rangeX, rangeY), ...
        max(allLaserPoint(:, 2)) +  min(rangeX, rangeY), 100);
    x_buff = linspace(min(allLaserPoint(:, 1)) -  min(rangeX, rangeY), ...
        max(allLaserPoint(:, 1)) +  min(rangeX, rangeY), 100);
    [X_buff,Y_buff] = meshgrid(x_buff, y_buff);
    Z_buff = -d/c -a/c*X_buff -b/c *Y_buff;  % 依旧是平面方程
    mesh(X_buff,Y_buff,Z_buff);
    xlabel('X'); ylabel('Y'); zlabel('Z');
    title('激光平面');
    hold on;
    plot3(allLaserPoint(:, 1), allLaserPoint(:, 2), allLaserPoint(:, 3), 'rx'); 
    clear x_buff y_buff X_buff Y_buff Z_buff
end

end


function pixels = getLaserCenter(frame_grey, thresh, grey_thresh,plotFlag)
if nargin < 4
    plotFlag = 0; 
end

if max(frame_grey) < grey_thresh
    pixels = [];
    return;
end

[row, col] = size(frame_grey);

% steger算法求中心
pixels= steger(frame_grey, thresh);

if plotFlag ~= 0
    figure;
    imshow(frame_grey);
    hold on
    plot(pixels(:, 1),pixels(:, 2),'r.')
    hold off
end

end

%% steger光条中心提取
function pixel=steger(srcImage,thresh)

if(length(size(srcImage))>2)
  srcImage=rgb2gray(srcImage);  
end

sigma=3;
% thresh= 0.1;%graythresh(srcImage);%otsu  

srcImage=double(srcImage);


[m,n]=size(srcImage);

ky=[-1,1];
kx=[-1;1];
kyy=[1,-2,1];
kxx=[1;-2;1];
kxy=[1,-1;-1,1];


gausFilter = fspecial('gaussian',9,sigma);   %高斯滤波
dstImage=imfilter(srcImage,gausFilter,'replicate');  

dx=imfilter(dstImage,kx);
dy=imfilter(dstImage,ky);
dxx=imfilter(dstImage,kxx);
dyy=imfilter(dstImage,kyy);
dxy=imfilter(dstImage,kxy);

hessian=zeros(2,2);
points=zeros(m*n,2);

for i=1:m
    for j=1:n
        if(srcImage(i,j)/255>thresh)
            hessian(1,1)=dxx(i,j);
            hessian(1,2)=dxy(i,j);
            hessian(2,1)=dxy(i,j);
            hessian(2,2)=dyy(i,j);
            [eigenvectors,eigenvalues]=eig(hessian);
            
            if(abs(eigenvalues(1,1))>= abs(eigenvalues(2,2)))
            nx=eigenvectors(1,1);
            ny=eigenvectors(2,1);
            fmax_dist=eigenvalues(1,1);
            else
            nx=eigenvectors(1,2);
            ny=eigenvectors(2,2);
            fmax_dist=eigenvalues(2,2);
                
            end
            
            t=-(nx*dx(i,j)+ny*dy(i,j))/(nx*nx*dxx(i,j)+2 * nx*ny*dxy(i,j)+ny*ny*dyy(i,j));
            
            if(abs(t*nx) <= 0.5 && abs(t*ny) <= 0.5)
                points((i-1)*m+j,:)=[ j+t*ny,i+t*nx];
            end
            
            
        end
        
    end
end

index = find(points(:,1)==0);
points(index,:) = [];
index = find(points(:,2)==0);
points(index,:) = [];

pixel=points;

figure(1);
imshow(uint8(srcImage));
hold on
plot(points(:,1),points(:,2),'r.','MarkerSize',1)
hold off


end


%% 光条中心坐标迭代去畸变
function undistortPoints=undistortCoor(intrinsic,distortCoff1,distortCoff2,points)
fx=intrinsic(1,1);
fy=intrinsic(2,2);
cx=intrinsic(1,3);
cy=intrinsic(2,3);
k1=distortCoff1(1);
k2=distortCoff1(2);
p1=distortCoff2(1);
p2=distortCoff2(2);
k3=0;

n=size(points,1);
undistortPoints=zeros(n,2);

for i=1:n
    px=(points(i,1)-cx)/fx;
    py=(points(i,2)-cy)/fy;
    px0=px;py0=py;
           for k=1:6
            pxfang = px*px;pyfang = py*py;
            prfang = pxfang + pyfang; pdoublexy = 2*px*py;
            dk = 1 + (k3*prfang^2+k2*prfang+k1)*prfang;%径向畸变校正模型
            dpx= p1*(pdoublexy + p2*(prfang+2*pxfang));
            dpy=p1*((prfang+2*pyfang) + p1*pdoublexy);
            %cm,cn为进行畸变校正后的在相机像平面上的坐标
            px=(px0-dpx)/dk;
            py=(py0-dpy)/dk; 
           end
        x = fx*px + cx ;  
        y = fy*py + cy ; 
       undistortPoints(i,:)=[x,y]; 
end

end

原始数据:

标定结果:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2214209.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

短视频矩阵多账号发布源码

在构建一个短视频矩阵系统时&#xff0c;我们需综合考虑多个关键领域&#xff1a;用户接口设计、后端处理逻辑、数据存储与维护以及系统安全性。该系统的主要功能模块包括&#xff1a; 1. 用户界面&#xff08;UI&#xff09;设计 - 登录/注册功能&#xff0c;允许用户创建并管…

解锁 SDKMAN!:最新教程与全面简介

SDKMAN! 是一个用于管理开发工具的软件开发工具包管理器,特别适用于 JVM 生态系统。 官网地址:https://sdkman.io/ 多版本管理:允许用户在同一台机器上安装和管理多个版本的 SDK(如 Java、Groovy、Scala、Kotlin 等)。 简单安装:通过简单的命令行命令可以安装、更新和卸载…

在三维可视化项目中,B/S和C/S架构该如何选择?

一、什么是B/S和C/S 在3D数据可视化中&#xff0c;有两种常见的架构模式&#xff1a;BS&#xff08;Browser/Server&#xff09;和CS&#xff08;Client/Server&#xff09; B/S模式 B/S模式是指将3D数据可视化的逻辑和处理放在服务器端&#xff0c;而在客户端使用浏览器进行…

Nature 正刊丨生物分子冷凝物介导内体膜的弯曲和断裂

01摘要 多囊体是通过降解膜结合的货物蛋白1,2,3参与细胞质量控制的关键内体隔室。消耗ATP的ESCRT蛋白机制通过多泡体膜的内陷和断裂形成管腔内囊泡&#xff0c;介导膜结合货物蛋白的捕获和吞噬4,5。在这里&#xff0c;我们报告说&#xff0c;植物ESCRT组分FREE16形成与膜结合的…

Hadoop集群基础搭建

目录 一.虚拟机安装 1.配置虚拟机的ip 2.配置本机的ip 3.新建虚拟机 4.克隆三台虚拟机 二.虚拟机网络配置 1.修改ip配置 2.配置主机名和主机映射 3.配置SSH免密登陆 三.安装JDK 1.tar命令解压JDK安装包 2.配置JDK的环境变量 四.安装Hadoop 1.tar命令解压Hadoop安…

Python数据分析-matplotlib数据可视化

1. 初识Matplotlib matplotlib是 Python 最流行的绘图工具之一&#xff0c;广泛用于数据可视化。 1.1基本图表绘制&#xff1a; 图表名称表示函数散点图plt.scatter(x, y)柱状图plt.bar(x, height)折线图plt.plot(x, y)直方图plt.hist(x, bins)箱线图plt.boxplot(x)热力图p…

使用python从头开始预训练RoBERTa模型

本文将介绍如何使用Hugging Face库从头开始构建一个预训练Transformer模型。该模型称为 KantaiBERT。 #title Step 1: Loading the Dataset #1.Load kant.txt using the Colab file manager #2.Downloading the file from GitHubant !curl -L https://raw.githubusercontent.c…

Linux学习第一天

目录 1.引入 计算机的组成&#xff08;图解&#xff09; 操作系统是什么 操作系统的功能 操作系统的组成&#xff08;图解&#xff09; 操作系统内核的功能 常见的操作系统 2.Libux的学习 Linux的特点 Linux应用领域 搭建Linux学习环境 下载 创建虚拟机 新建虚拟机…

短视频矩阵开发,抖音新机遇(技术开发框架解析)

开发前言&#xff1a; 抖音短视频矩阵系统技术开发框架主要利用了VUE&#xff0c; Spring Boot、Django等技术。本技术文档适用于短视频矩阵源码的开发和部署。 #短视频矩阵源码开发部署 #抖音矩阵源码开发 #抖音矩阵源码 #抖音矩阵开发 抖音短视频矩阵系统的技术开发框架可以…

P1320压缩技术(续集版

P1320压缩技术&#xff08;续集版 感觉这题还是蛮难的对我来说&#xff0c;通过这题我才知道原来字符串输入不碰到空格就会一起输进来 我参考了一写题解自己又写了自己的解法&#xff0c;vs中的scanf_s和scanf()用法不太一样&#xff0c;之前按scanf写法写一直在报错&#xff…

彻底掌握Android中的Lifecycle

彻底掌握Android中的Lifecycle Lifecycle 是一个生命周期感知型组件&#xff0c;属于 Jetpack 组件库中的一部分&#xff0c;其核心功能是将组件&#xff08;如Activity 和 Fragment&#xff09;的生命周期状态通知给观察者&#xff08;LifecycleObserver&#xff09;。观察者…

指针 + 数组 较为复杂凌乱的 【笔试题】

2024 - 10 - 10 - 笔记 - 25 作者(Author): 郑龙浩 / 仟濹(CSDN 账号名) 【指针 数组】的 各种题型(笔试题) 来自于鹏哥的网课&#xff0c;我做一下笔记 119. 【C语言进阶】笔试题详解&#xff08;4&#xff09;_哔哩哔哩_bilibili ① 题 #include <stdio.h> int m…

VUE 开发——Vue学习(三)—— 智慧商城项目

目录 解释各个模块 api接口模块&#xff1a;发送ajax请求的接口模块utils工具模块&#xff1a;自己封装的一些工具方法模块components组件模块&#xff1a;全局通用的组件router路由模块&#xff1a;封装要所有路由views&#xff1a;各个页面assets&#xff1a;各种资源 van…

JAVA软开-面试经典题(7)-字符串常量池

字符串常量池 1.定义&#xff1a;字符串常量池&#xff08;String Constant Pool&#xff09;&#xff0c;用于存放字符串常量的运行时内存结构&#xff0c;其底层的实现为Hashtable。 【注意】 在JDK1.6之前&#xff0c;字符串常量池中只会存放具体的String实例&#xff0c;在…

MySQL基础探秘(3)

前面那篇文章是简单介绍了往数据库中插入数据&#xff0c;以及对数据进行有些改动。 但是&#xff0c;细想下&#xff0c;数据能够无限制&#xff0c;无约束进行插入吗&#xff1f; emm……显然是不行的&#xff0c;不然数据就乱套了&#xff0c;看起来不美观。 所以要对数据…

Axure详细介绍及功能对比,常用版本选择和替代软件分享

Axure是一款专门用于原型设计和交互设计的专业软件&#xff0c;广泛应用于用户界面&#xff08;UI&#xff09;和用户体验&#xff08;UX&#xff09;设计领域。它的主要功能是帮助产品经理、设计师以及开发人员创建具有互动性的原型&#xff0c;以便展示和测试各种应用、网站或…

CST学习笔记(二)Floquet模式激励设置

CST学习笔记&#xff08;二&#xff09;Floquet模式激励设置 在CST中我们常常使用Floquet模式来仿真频率选择表面(FSS)或者超材料等&#xff0c;但是我们设置好Zmax的floquet模式数量后&#xff0c;启动仿真&#xff0c;会发现S参数一栏中有很多我们不想要看的S参数&#xff0…

海南聚广众达电子商务咨询有限公司解锁流量密码

在这个瞬息万变的数字时代&#xff0c;电商行业如同一股不可阻挡的洪流&#xff0c;正以前所未有的速度重塑着商业版图。而在这股浪潮中&#xff0c;抖音电商以其独特的魅力&#xff0c;迅速崛起为一颗璀璨的新星&#xff0c;吸引了无数商家与创业者的目光。海南聚广众达电子商…

【题解】【动态规划01背包问题】—— [NOIP2012 普及组] 摆花

【题解】【动态规划01背包问题】—— [NOIP2012 普及组] 摆花 [NOIP2012 普及组] 摆花题目描述输入格式输出格式输入输出样例输入 #1输出 #1 提示 解法1.二维 d p dp dp1.1.思路解析1.2.AC代码 解法2.一维 d p dp dp2.1.思路解析2.2.AC代码 3.扩展:前缀和优化 [NOIP2012 普及组…

python基础知识(十一)面向过程,面向对象,对象属性,魔法方法,继承,私有权限

目录 面向过程是什么 什么是面向对象&#xff1f; 面向对象的三大特性&#xff1a; 继承 多态 类 对象 self关键字 对象属性 类外面访问属性 类内部获取属性 魔法方法 无参init()方法 有参init()方法 str()方法 del()方法 继承基础 什么是继承 单继承 多继…