目录
准备工作(预备知识)
图像变换的映射方法
对圆环图像进行展开的时候,不可避免地是需要对图像坐标点进行变换,而由于数字图像的离散性,在图像变换后的坐标可能并不是整数,此时就需要使用其变换后周围的坐标对应灰度值来反映此点灰度值。
(1) 前向映射
直接将原始图像坐标转换为映射后的坐标,此时需要求的像素在坐标网格上。
(2) 后向映射
将映射后的坐标反向变换到原有坐标上,此时已知点在坐标网格上。
图像插值方法
在经过图像的转换映射后,需要对变换后的未定义值进行赋值,此时需要借用其周围已知点的灰度值进行插值处理。
(1) 最近邻插值
(2) 双线性插值
(3) 双三次插值
霍夫变换进行圆检测
在进行图像展开时,需要使用到圆环图像的圆心以及半径参数,此时需要对圆环图像进行圆检测以得到上述参数,在这里我们选择霍夫变换进行圆检测。
其基本原理为在二维笛卡尔坐标系下,一个圆的解析方程表示如下:
其中,(x, y)为圆上任意一点的坐标,(a, b)为圆心,r为半径。
假设给定圆上任意一点(x, y),则由(a, b, r)三个参数张成的空间为三维空间中以(x,y,0)为顶点的倒立圆锥表面,这个空间即为霍夫参数空间。
给定圆上一点(x, y)以及圆的半径r,则霍夫参数空间退化成平面上的一个圆,即参数(a, b)分布在以(x, y)为圆心,r为半径的圆上。
给定四个点的坐标P1、P2、P3、P4,求其拟合成圆的中心坐标(a,b)(这里假设r已知)。
对于每一点Pi,由 Pi 和 r 约束下的参数(a,b)分布在一个圆上,联合所有的Pi,其约束所构成的交集即为所求参数(a,b).
这里是一个理想化的模型,实际操作时,所有的点不可能全在一个半径确定的圆上,因此需要用到投票策略。
将霍夫参数空间离散化为一张二维的网格,若某圆经过该单元格,则该单元网格票数加一,选出票数最高的网格对应的(a,b)值,即为所求参数。
本课题中的霍夫圆检测效果如下。
其代码入下。
[centers_out, radii_out] = imfindcircles(img, [500 600],'ObjectPolarity','bright','Sensitivity',0.99);
[centers_in, radii_in] = imfindcircles(img, [300 400],'ObjectPolarity','dark','Sensitivity',0.95);
圆环图像展开为矩形图像
极坐标直接变换法
经过成像系统所采集的发动机内壁图像由于是通过球面反射的缘故,在相机的成像平面上所成像为一圆环图像,既不利于人眼直接观察,也不利于后续计算机缺陷检测与识别,所以需要将圆环图像展开还原为便于观察的柱面矩形图像。本课题中我们采用图像坐标映射的关系将圆环图像展开为柱面矩形图像,其基本原理如下:
右图是相机成像平面上得到的球面反射图像,左图是经过展开变换后的得到的工件内壁柱面矩形图像,展开图像上的像素点P'(U,V)都能在原圆环图像上找到对应的映射点P(u,v)。不考虑像元尺寸的影响,此处所有单位均由像素数表示,则由图像成像坐标系和图像像素坐标系的关系可知圆形图像中的任一像点P(u,v)均可用极坐标表示:
其中(u0,v0)分别为圆形图像圆心坐标,半径为R,在展开图像中,图像为一个W×H大小的二维矩阵,则P'坐标可如下得到:
由上式,则建立两幅图像的坐标系变换公式为:
其中R为圆环图像半径,H、W分别为矩形展开图像的边长。矩形图像中每一点P'(U,V)上的像素值。当计算结果(u,v)为非整数时,可使用插值方法得到其近似像素值。这样就能得到展开后的柱面矩形图像。
这一部分的代码如下。
function out = flatten(C_x, C_y, R, C_img)
%图像展开算法
img = C_img;
u0=C_x;
v0=C_y;
R=R;
H=round(R);
W=round(2*pi*R);
img0=double(img);
imgt=zeros(H,W);
for V=1:H
for U=1:W
u=R/H*V*cos(2*pi*U/W)+u0;
v=-R/H*V*sin(2*pi*U/W)+v0;
imgt(V,U)=img0(round(v),round(u));
end
end
out = imgt;
end
几何关系映射法
在圆环图像的展开的过程中,我们可以将圆环图像的有效区域看作为一环环圆弧所组成的图像,所以将圆环图像展开的这个任务可以转化为将圆环图像区域中的每一个小圆弧都展开成固定长度的直线,再将这些直线组合在一起就能得到最终展开的矩形图像,其展开原理示意图如下。
在这里,我们假设圆环图像上的一点A(x1,y1)在经过圆环图像展开过后最终成像在矩形图像上的A'(x2,y2)上,同时,我们将展开后的矩形图像的高规定为圆环图像的外圆半径减去内圆半径Rout-Rin,其宽规定为外圆的弧长大小2πRout。由此,能得到圆环展开对应坐标的关系式。
其中l为x1处对应弧长的计算公式如下:
所以可以直接根据这个坐标变换公式求得展开后的矩形图像如下。
这一部分的代码如下。
function out = flatten2(C_x, C_y, R_out, R_in, C_img)
W = ceil(pi*R_out);
H = ceil(R_out - R_in);
[width, height] = size(C_img);
imgt = zeros(H, W);
for i = 1:width
for j = 1:height
x = i-round(C_x);
y = j-round(C_y);
if x^2+y^2>=R_in^2 && x^2+y^2<=R_out^2 && y>=0
index_y = round(sqrt(x^2+y^2)-R_in);
index_x = round(R_out*asin(x/(sqrt(x^2+y^2)))+pi*R_out/2);
if index_x>0 && index_x<=W &&index_y>0 && index_y<=H
imgt(index_y,index_x) = C_img(j,i);
end
end
end
end
out = imgt;
end
我们会发现,图像中存在许多黑点,这是由于我们没有对未定义点进行插值其灰度值默认为0导致的,所以我们需要对图像进行后向映射并进行插值操作,得到较为理想的展开图像。
其中,上面的图像为采用最近邻插值的展开图像,而下面的图像则是采用双线性灰度插值的图像,我们可以放大再进行细节查看。
左图为采用最近邻方式的图像细节,而右图为采用双线性插值的方式的图像细节,可以看出,采用双线性插值的图像边缘地区更加平滑,此部分的代码如下。
%最近邻插值
function out = flatten3(C_x, C_y, R_out, R_in, C_img)
W = ceil(pi*R_out);
H = ceil(R_out - R_in);
[width, height] = size(C_img);
imgt = zeros(H, W);
for index_x = 1:W
for index_y = 1:H
x = (index_y+R_in)*sin(index_x/R_out-pi/2);
y = sqrt((index_y+R_in)^2-x^2);
i = round(x+C_x);
j = round(y+C_y);
imgt(index_y,index_x) = C_img(j,i);
end
end
out = imgt;
end
%双线性插值
function out = flatten4(C_x, C_y, R_out, R_in, C_img)
W = ceil(pi*R_out);
H = ceil(R_out - R_in);
[width, height] = size(C_img);
img = C_img;
imgt = zeros(H, W);
for index_x = 1:W
for index_y = 1:H
x = (index_y+R_in)*sin(index_x/R_out-pi/2);
y = sqrt((index_y+R_in)^2-x^2);
i = x+C_x;
j = y+C_y;
dst1=img(floor(j),floor(i))+(j-floor(j))*(img(floor(j+1),floor(i))-img(floor(j),floor(i)));
dst2=img(floor(j),floor(i+1))+(j-floor(j))*(img(floor(j+1),floor(i+1))-img(floor(j),floor(i+1)));
imgt(index_y,index_x)=dst1+(i-floor(i))*(dst2-dst1);
end
end
out = imgt;
end
矩形图像初步消除径向误差
由于本课题中采用的是球面反射镜对发动机工件内壁图像进行成像,所以除了在所呈圆环图像的周向上存在畸变,其在圆环图像上的径向上也会存在畸变,所以我们根据反射原理以及反射镜参数初步消除径向误差,其基本原理如图所示。
同样,在这里我们假设已经展开的矩形图像的上的一点B,经过图像变换去径向畸变后的坐标为B',满足基本的反射原理,这样我们就能复原出内孔壁的真实图像,根据图中的参数建立其几何关系如下。
进一步推算出图像去畸变后的坐标结果。
其中
根据这个坐标映射关系,我们能得到最终的去畸变图像。
可以看出,其展开的图像上的圆孔几乎是圆形,不存在失真,而同样存在的问题是采用前向映射的方式会存在部分像素点灰度值没定义,图像中存在黑色条纹,需要进一步采用后向映射并插值。其代码如下。
function out = r_flatten(R_in, R_out, img0)
[height, width] = size(img0);
%反射镜参数
k = R_out/6.5;%反映真实尺寸的比例尺
R = 7.73*k;
d = 2*k;
%
theta = asin((R_out-R_in)/R);
H = round(R*cos(theta)+(R_in+d)/(tan(2*theta)));
imgt = zeros(H, width);
%
for y1 = 1:height
for j = 1:width
theta = asin((R_out-y1)/R);
y2 = R*cos(theta)+(y1+d)/(tan(2*theta));
imgt(round(y2), j) = img0(y1, j);
end
end
out = imgt;
end