首页 > 其他分享 >光平面标定代码

光平面标定代码

时间:2024-10-14 20:52:38浏览次数:10  
标签:laser allLaserPoint 代码 标定 cameraParams fprintf fid 平面 buff

        本篇文章主要给出光平面标定代码,鉴于自身水平所限,如有错误,欢迎批评指正。(欢迎进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

原始数据:

标定结果:

标签:laser,allLaserPoint,代码,标定,cameraParams,fprintf,fid,平面,buff
From: https://blog.csdn.net/weixin_43997893/article/details/142928521

相关文章

  • C语言经典100例-第八题(想提升C语言代码能力的看过来!)
    持续更新!!!1.刷题链接和地址: C语言教程|菜鸟教程 菜鸟教程C语言专栏这里的"C经典100例"(看红色框框)2.解题:2.1读题:题目呢,就是输出99乘法表,就是1*1=12*1=2,然后一直到9*9,也是很简单的一道题目 这个就是输出的结果样式 2.2解题思路:首先呢,我们是不是应该考虑......
  • 代码随想录算法训练营第三十四天|134. 加油站 135. 分发糖果 860.柠檬水找零 406.根据
    134.加油站在一条环路上有 N 个加油站,其中第 i 个加油站有汽油 gas[i] 升。你有一辆油箱容量无限的的汽车,从第i个加油站开往第i+1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发,开始时油箱为空。如果你可以绕环路行驶一周,则返回出发时加油站的......
  • 代码随想录算法训练营第三十二天|122.买卖股票的最佳时机 II 55. 跳跃游戏 45.跳跃游
    122.买卖股票的最佳时机II给定一个数组,它的第 i个元素是一支给定股票第i天的价格。设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。示例1:输入:[7,1,5......
  • 代码随想录算法训练营第三十一天|455.分发饼干 376. 摆动序列 53. 最大子序和
    455.分发饼干假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。对每个孩子i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干j,都有一个尺寸s[j] 。如果s[j] >=g[i],我们可以将这个饼干j分配给孩子i,......
  • 代码随想录算法训练营第八天(1)|哈希表理论基础
    文档讲解:代码随想录难度:有一点哈希表理论基础哈希表首先什么是哈希表,哈希表(英文名字为Hashtable,国内也有一些算法书籍翻译为散列表,大家看到这两个名称知道都是指hashtable就可以了)。哈希表是根据关键码的值而直接进行访问的数据结构。这么官方的解释可能有点懵,其实......
  • 双向RRT路径搜索算法matlab代码
    一、实现效果见:双向RRT路径搜索算法流程、注意事项-CSDN博客二、代码完整代码见:https://download.csdn.net/download/m0_69611489/89882862clcclearcloseall%%设置环境S=[0.50.5];E=[99.599.5];Limit=[01000100];ob=[5050;7080];ob_r=[15;7];step=1;iu......
  • Cascader 级联选择器代码实现
    当一个数据集合有清晰的层级结构时,可通过级联选择器Cascader 逐级查看并选择,在开发过程中,非常常见,解决选择列表数量过多的情况。结果1、组件<el-cascader:props="props":options="unitData"v-model="query.UnitName"size="small"style="margin-left:10px;margin-rig......
  • 0xc0000225错误代码终极解决方案:全面攻克系统启动障碍
    在使用Windows操作系统时,用户可能会遇到各种错误代码,其中0xc0000225是一个较为常见的启动错误。这个错误通常会导致系统无法正常启动,屏幕上会显示一条错误信息,指出“你的电脑/设备需要修复。无法加载操作系统,原因是关键系统驱动程序丢失或包含错误。文件:\Windows\system32\driv......
  • 程序员必看!用 Eagle 读懂 GitHub 项目代码
    程序员一定要学会这一招,悄悄充电,偷是技术大牛,惊艳所有人!作为程序员,GitHub是一定要看的,学习并理解优秀的项目代码,让你事半功倍。一起来看看技术大牛是怎么在GitHub上充电的吧!GitHub上有一个叫Trending的榜单,它会帮你列出最近一天、一周、一个月最火的项目。这些项目一般都有......
  • python代码将文件夹里面pdf全部出现单词出现频次显示出来并且出现意思,保存到excle
    英语考试和代码结合(自动化人哭了)需要教程可以私信我,我可以出视频B站importcsvimportrefromcollectionsimportCounterfrompdfminer.pdfparserimportPDFParserfrompdfminer.pdfdocumentimportPDFDocumentfrompdfminer.pdfpageimportPDFPagefrompdfmine......