使用ORB探测器搜索关键点
ORB探测器用于视频稳定,全景创建,目标检测,3D重建,相机运动估计,图像对齐和增强现实的定位。 它还用于通过关键点数据库识别建筑物或地标等位置。
理论部分
ORB(Oriented FAST And Rotated BRIEF)是一个快速的关键字检测器和描述符。 它结合了快速算法(用于检测关键点)和简要(用于描述它们)。
**FAST(来自加速分段测试的功能)算法用于查找图像中的角点。
Harris角点度量用于选择最显着点,这减少了弱关键点的数量。 为每个关键点计算方位。
这使得ORB对图像旋转不变。
Algorithm**BRIEF(Binary Robust Independent Elementary Features)**创建二进制描述符。 为了比较图像之间的点,ORB使用二进制描述符与汉明度量的两两比较。
在这个例子中,我们将考虑ORB探测器的经典使用,在两幅图像中找到关键点并进行比较。 基于计算的单应性,图像将被对齐和合并,从而产生全景图,显示将两个图像组合成单个图像的过程。
我们连接处理图像所需的软件包
import Pkg;
Pkg.add("Images")
Pkg.add("ImageFeatures")
Pkg.add("ImageDraw")
Pkg.add("ImageProjectiveGeometry")
Pkg.add("LinearAlgebra")
Pkg.add("OffsetArrays")
Pkg.add("ImageTransformations")
Pkg.add("StaticArrays");
using Pkg, Images, ImageFeatures, ImageDraw
using ImageProjectiveGeometry
using LinearAlgebra, OffsetArrays
using ImageTransformations, StaticArrays
上传图片
我们指定图像的路径,上传并显示它们:
path_to_img_1 = "$(@__DIR__)/1.jpg"
path_to_img_2 = "$(@__DIR__)/2.jpg"
Image_1 = load(path_to_img_1)
Image_2 = load(path_to_img_2)
ORB的应用
初始化描述符
orb_params = ORB(num_keypoints = 1000);
让我们定义一个函数,它使用描述符来搜索图像中的关键点。
function find_features(img::AbstractArray, orb_params)
desc, ret_features = create_descriptor(Gray.(img), orb_params)
end;
让我们定义一个在两个图像中搜索公共关键点的函数。 首先,计算每幅图像的关键点和描述符,然后使用指定的阈值对描述符进行匹配。
function match_points(img1::AbstractArray, img2::AbstractArray, orb_params, threshold::Float64=0.1)
desc_1, ret_features_1 = find_features(img1, orb_params)
desc_2, ret_features_2 = find_features(img2, orb_params)
matches = match_keypoints(ret_features_1, ret_features_2, desc_1, desc_2, threshold);
end;
找到匹配的关键点
matches = match_points(Image_1, Image_2, orb_params, 0.35);
让我们定义一个可视化关键点关系的函数。 功能 pad_display 将图像并排放置,水平放置在同一画布上。 draw_matches 绘制连接公共关键点的线。
function pad_display(img1, img2)
img1h = length(axes(img1, 1))
img2h = length(axes(img2, 1))
mx = max(img1h, img2h);
hcat(vcat(img1, zeros(RGB{Float64},
max(0, mx - img1h), length(axes(img1, 2)))),
vcat(img2, zeros(RGB{Float64},
max(0, mx - img2h), length(axes(img2, 2)))))
end
function draw_matches(img1, img2, matches)
grid = pad_display(parent(img1), parent(img2));
offset = CartesianIndex(0, size(img1, 2));
for m in matches
draw!(grid, LineSegment(m[1], m[2] + offset))
end
grid
end;
让我们看看出口处有什么。
draw_matches(Image_1, Image_2, matches)
构建全景图
为了计算单应性(几何变换),需要在两个图像中彼此对应的点的坐标。
这里从匹配的关键点列表 matches 提取两幅图像的点的坐标。 x1 -这些是第一幅图像的坐标, x2 -从第二个。
x1 = hcat([Float64[m[1].I[1], m[1].I[2]] for m in matches]...) # 2xN
x2 = hcat([Float64[m[2].I[1], m[2].I[2]] for m in matches]...); # 2xN
这里使用RANSAC方法求单应性矩阵 H,它尽可能精确地对齐两组点 x1 和 x2.
t = 0.01
# Вычисление гомографии с помощью RANSAC
H, inliers = ransacfithomography(x1, x2, t);
t -这是决定在应用单应性后点可以有多大差异的阈值,以便被认为是"正确的"(嵌体)。
结构 Homography 来表示单应性矩阵。 它包含一个3x3矩阵,用于定义两个图像之间的转换。
struct Homography{T}
m::SMatrix{3, 3, T, 9}
end
Homography(m::AbstractMatrix{T}) where {T} = Homography{T}(SMatrix{3, 3, T, 9}(m))
function (trans::Homography{M})(x::SVector{3}) where M
out = trans.m * x
out = out / out[end]
SVector{2}(out[1:2])
end
function (trans::Homography{M})(x::SVector{2}) where M
trans(SVector{3}([x[1], x[2], 1.0]))
end
function (trans::Homography{M})(x::CartesianIndex{2}) where M
trans(SVector{3}([collect(x.I)..., 1]))
end
function (trans::Homography{M})(x::Tuple{Int, Int}) where M
trans(CartesianIndex(x))
end
function (trans::Homography{M})(x::Array{CartesianIndex{2}, 1}) where M
CartesianIndex{2}.([tuple(y...) for y in trunc.(Int, collect.(trans.(x)))])
end
function Base.inv(trans::Homography{M}) where M
i = inv(trans.m)
Homography(i ./ i[end])
end
该函数用于 warp 应用单应矩阵 H 到图像 Image_1,创建变换后的图像 new_img.
new_img = warp(Image_1, Homography(H))
该功能将两个图像(原始图像和转换图像)组合成一个共同的画布,在旧图像的顶部添加一个新图像。
function merge_images(img1, new_img)
# Вычисляем размеры холста
axis1_size = max(last(axes(new_img, 1)), size(img1, 1)) - min(first(axes(new_img, 1)), 1) + 1
axis2_size = max(last(axes(new_img, 2)), size(img1, 2)) - min(first(axes(new_img, 2)), 1) + 1
# Создаем OffsetArray для объединённого изображения
combined_image = OffsetArray(
zeros(RGB{N0f8}, axis1_size, axis2_size), (
min(0, first(axes(new_img, 1))),
min(0, first(axes(new_img, 2)))))
# Копируем первое изображение в общий холст
combined_image[1:size(img1, 1), 1:size(img1, 2)] .= img1
# Копируем второе изображение в общий холст
for i in axes(new_img, 1)
for j in axes(new_img, 2)
if new_img[i, j] != colorant"black" # Пропускаем чёрные пиксели
combined_image[i, j] = new_img[i, j]
end
end
end
combined_image
end
panorama = merge_images(Image_1, new_img)
结论
该示例演示了使用ORB探测器自动查找关键点并在两幅图像上匹配它们。 构建的单应性使得对齐图像成为可能,并且组合它们使得创建全景图成为可能。



