使用Julia进行图像处理--图像表示与匹配算法

  • 图像表示
    • 特征和描述符
    • 快速角点检测
    • 使用imcorner函数进行角点检测
    • 性能比较
  • BRIEF--有效检测重复图像的方法
    • 识别图像重复项
    • 使用多张图像创建全景图
  • ORB--旋转不变图像匹配
  • BRISK--缩放不变图像匹配
  • FREAK--最快的缩放与旋转不变匹配

图像表示

ImageFeatures包用于确定图像的特征或描述符,并用于其他应用程序,例如对象识别,检测,图像匹配。

特征和描述符

在计算机视觉中,最有可能的是,搜索相邻元素特有的图案或特定特征。图像特征通过以一组参数表示图像来使它们易于识别,跟踪和比较,从而进行下游工作。
查看下列猫的两个不同的图像,然后尝试查找图像间相匹配的区域:

首先进行预览,感受算法如何处理以下图像:

从前面的结果中,可以看到该算法专注于猫的耳朵,并且相同的特征由白线相连。

快速角点检测

角点检测是从图像中提取特征的过程。
JuliaFeatures包实现了FAST( Features from accelerated segment test )函数。 FAST是一种计算效率高的角点检测器,适用于实时视频分析。可以使用fastcorners函数调用FAST算法。
由于其出色的性能,质量和简单的配置,在以下所有示例中使用FAST。 FAST通过扫描整个图像的角点来工作。它使用一个16像素的圆来评估点是否为角点。该过程还由两个附加参数配置:

  1. 连续像素数(N):用于比较圆中的像素是比候选点亮还是暗,N通常固定为12。
  2. 阈值:定义了所识别特征的数量,阈值参数设置的值越高,返回的特征越少。

在图像上多次运行FAST算法,用于查看随着阈值参数值的变化,角点数如何改变。
加载图像,调整大小并将其转换为灰度。对三个不同的阈值(例如0.15、0.25和0.35)应用fastcorners函数,并比较结果:

using Images, ImageFeatures, ImageView
img = Gray.(load("cat-3417184_640.jpg"))
img_f = Float16.(restrict(img))
new_img = Gray.(hcat(img_f .* (.~fastcorners(img_f, 12, 0.15)),img_f .* (.~fastcorners(img_f, 12, 0.25)),img_f .* (.~fastcorners(img_f, 12, 0.35))
))
imshow(new_img)

在前面的代码中将存储在img_f变量中的图像的数字表示乘以对快速角点函数结果的求反,从而能够将特征快速放置在图像上:

在猫上看到黑点表示由快速角点函数标识的角点。使用其他来匹配相同的对象。

使用imcorner函数进行角点检测

Imcorner函数是FAST替代方法。它也用于图像的角点,并提供不同的方法集:

  1. harris
  2. shi-tomasi
  3. kitchen-rosenfield

每种方法都以其自己独特的算法执行,因此特征表示将有所不同。为了更好地理解差异,将它们全部绘制在单个图像上。首先加载棋盘图像并将其转换为浮点表示形式:

using Images, ImageFeatures, ImageMorphology, ImageView
img = restrict(load("board-157165_640.png"))
img_f = Float16.(Gray.(img))

接下来,运行四种不同的算法。其中的三个由imcorner函数提供,最后一个是fastcorners:

img_harris = copy(img)
img_harris[dilate(imcorner(img_f, method=harris)) .> 0.01] .= colorant"yellow"
img_shi = copy(img)
img_shi[dilate(imcorner(img_f, method=shi_tomasi)) .> 0.01] .= colorant"yellow"
img_rosenfield = copy(img)
img_rosenfield[dilate(imcorner(img_f, method=kitchen_rosenfeld)) .> 0.01] .= colorant"yellow"
img_fast = copy(img)
img_fast[dilate(fastcorners(img_f, 12, 0.05)) .> 0.01] .= colorant"yellow"

通常,imcorner和fastcorners的结果很小,例如一个像素。从ImageMorphology软件包中应用了膨胀函数,以突出显示通过imcorner或FAST确定的结果,可以让用户在绘制和预览特征时更好地表示特征。还使用了着色剂技术来获得精确的颜色值。
将所有四个图像合并为一个图像:

new_img = vcat(hcat(img_harris, img_shi),hcat(img_rosenfield, img_fast)
)
new_img[Int(size(new_img, 1) / 2), :] .= colorant"yellow"
new_img[:, Int(size(new_img, 2) / 2)] .= colorant"yellow"
imshow(new_img)

尝试在猫的图像上运行相同的代码,然后再次比较结果以查看是否有任何变化:

using Images, ImageFeatures, ImageMorphology, ImageViewimg = Gray.(restrict(load("cat-3417184_640.jpg")))
img_f = Float16.(Gray.(img))
img_harris = copy(img)
img_harris[dilate(imcorner(img_f, method=harris)) .> 0.01] .= colorant"yellow"
img_shi = copy(img)
img_shi[dilate(imcorner(img_f, method=shi_tomasi)) .> 0.01] .= colorant"yellow"
img_rosenfield = copy(img)
img_rosenfield[dilate(imcorner(img_f, method=kitchen_rosenfeld)) .> 0.01] .= colorant"yellow"
img_fast = copy(img)
img_fast[dilate(fastcorners(img_f, 12, 0.05)) .> 0.01] .= colorant"yellow"
new_img = vcat(hcat(img_harris, img_shi),hcat(img_rosenfield,img_fast)
)
imshow(new_img)

除FAST以外的所有方法在图像周围都有角点。原因是,imcorner函数返回所有角点而没有任何阈值参数。

更新阈值以仅检索特征的前5%,然后再次比较结果:

img = Gray.(restrict(load("cat-3417184_640.jpg")))
img_f = Float16.(Gray.(img))
img_harris = copy(img)
img_harris[dilate(imcorner(img_f, Percentile(95), method=harris)) .> 0.01] = colorant"yellow"
img_shi = copy(img)
img_shi[dilate(imcorner(img_f, Percentile(95), method=shi_tomasi)) .> 0.01] = colorant"yellow"
img_rosenfield = copy(img)
img_rosenfield[dilate(imcorner(img_f, Percentile(95), method=kitchen_rosenfeld)) .> 0.01] = colorant"yellow"
img_fast = copy(img)
img_fast[dilate(fastcorners(img_f, 12, 0.05)) .> 0.01] = colorant"yellow"
new_img = vcat(hcat(img_harris, img_shi),hcat(img_rosenfield, img_fast)
)
imshow(new_img)

从下图可以看到,结果已经相似:

性能比较

进行性能比较以查看哪种算法更快也很重要。为了运行分析,在以下代码中使用了BenchmarkTools包中的@btime宏:

julia> using Images, ImageFeatures, BenchmarkTools
julia> @btime fastcorners(img_f, 12, 0.15);
# 667.308 μs (7 allocations: 40.33 KiB)
julia> @btime fastcorners(img_f, 12, 0.05);
# 916.183 μs (7 allocations: 40.33 KiB)
julia> @btime imcorner(img_f, method=harris);
# 1.050 ms (3041 allocations: 2.12 MiB)
julia> @btime imcorner(img_f, Percentile(95), method=harris);
# 821.515 μs (317 allocations: 2.13 MiB)
julia> @btime imcorner(img_f, method=shi_tomasi);
# 1.123 ms (3814 allocations: 2.15 MiB)
julia> @btime imcorner(img_f, method=kitchen_rosenfeld);
# 1.055 ms (4626 allocations: 2.05 MiB)

尽管使用fastcorners函数时阈值较小的时间会增加,但是内存消耗仍然很小且固定。

BRIEF–有效检测重复图像的方法

二元鲁棒独立基本特征(Binary Robust Independent Elementary Features, BRIEF)是二元特征点描述符。 BRIEF是一个非常简单的特征描述符,因此不能应用于缩放或旋转的图像。尽管有其局限性,它也可以有效地用于诸如重复检测之类的任务。

识别图像重复项

在以下示例中,将比较猫的原始图像与经过稍微修改和加水印的猫。
首先,加载图像并将其转换为灰度版本:

using Images, ImageFeatures, ImageDraw, ImageView
img1 = Gray.(load("cat-3417184_640.jpg"))
img2 = Gray.(load("cat-3417184_640_watermarked.jpg"))
imshow(restrict(hcat(img1, img2)))

接下来,使用fastcorners函数检索关键点或角点,并比较每个图像的计数。通过在调用fastcorners时使用阈值参数的高值来减少返回的关键点的数量:

keypoints_1 = Keypoints(fastcorners(img1, 12, 0.5));
# 0.5 - very high threshold
keypoints_2 = Keypoints(fastcorners(img2, 12, 0.5));
size(keypoints_1) # result varies from 190 to 200
size(keypoints_2) # result varies from 190 to 200

参数的数量非常接近。下一步是初始化Brief,并调用create_descriptor函数来创建特征。调用match_keypoints函数以匹配两个图像的结果:

brief_params = BRIEF()
desc_1, ret_features_1 = create_descriptor(img1, keypoints_1, brief_params);
desc_2, ret_features_2 = create_descriptor(img2, keypoints_2, brief_params);
matches = match_keypoints(ret_features_1, ret_features_2, desc_1, desc_2, 0.5)

matchs变量应返回特征之间的匹配数。返回size将显示计数,如以下代码所示:

size(matches) # returns (197,)

所以,匹配的数目是197,预览结果以确认一切正确。通过合并两个图像并绘制一条连接匹配项的白线来实现此目的:

grid = hcat(img1, img2)
offset = CartesianIndex(0, size(img1, 2))
map(m -> draw!(grid, LineSegment(m[1], m[2] + offset)), matches)
imshow(grid)

尽管图像发生了变化,但可以看到主要特征已正确匹配。该过程运行相对较快,而且效果很好:

如果大规模运行重复检测,可以将create_descriptor的结果保存在某种数据库中。因此,当出现新图像时,只需要将其与已经预先计算的特征进行比较即可。
因为BRIEF仅针对单个像素使用信息,所以它对噪声敏感。为了克服此限制,它应用了高斯模糊,可以在初始化BRIEF时对其进行配置。

使用多张图像创建全景图

可以使用BRIEF执行的另一有趣活动是创建全景视图。假设有一个样本地点的许多图像,并且希望将它们连接在一起得出一张图片。可以尝试使用Brief来基于它们的共同特征来拼接图像。
先将图像加载到Julia中,然后将其分为两部分,再尝试进行连接:

using Images, ImageFeatures, ImageDraw, ImageShow
img = load("cat-3418815_640.jpg")
img_width = size(img, 2)
img_left_width = 400
img_right_width = 340

接下来,使用前面的设置创建两个新图像。保留原始版本和灰度版本。灰度版本将用于查找关键点,而彩色版本将用于创建最终结果:

img_left = view(img, :, 1:img_left_width)
img_left_gray = Gray.(img_left)
img_right = view(img, :, (img_width - img_right_width):img_width)
img_right_gray = Gray.(img_right)
imshow(img_left)
imshow(img_right)

以下图像是接下来将尝试连接的两个新图像:

因此,使用以下代码从fastcorners函数的结果中找到关键点:

keypoints_1 = Keypoints(fastcorners(img_left_gray, 12, 0.3));
keypoints_2 = Keypoints(fastcorners(img_right_gray, 12, 0.3));

初始化BRIEF并找到特征之间的匹配:

brief_params = BRIEF()
desc_1, ret_features_1 = create_descriptor(img_left_gray, keypoints_1, brief_params);
desc_2, ret_features_2 = create_descriptor(img_right_gray, keypoints_2, brief_params);
matches = match_keypoints(ret_features_1, ret_features_2, desc_1, desc_2, 0.1)

查看关键点是否正确匹配:

grid = hcat(img_left, img_right)
offset = CartesianIndex(0, size(img_left_gray, 2))
map(m -> draw!(grid, LineSegment(m[1], m[2] + offset)), matches)
imshow(grid)

下一步假设大多数点都已正确识别,可以计算每个关键点对之间的距离,并找到代表真实值的中值并将其称为偏移量:

offset_x = mean(map(m -> (img_left_width - m[1][2]) + m[2][2], matches))

为了简化其余步骤,将偏移量除以2,并将两个图像均缩小以适配结果。最后预览结果:

offset_x_half = Int(trunc(offset_x / 2))
img_output = hcat(img_left[:, 1:(img_left_width-offset_x_half)],img_right[:, offset_x_half:img_right_width]
)
imshow(hcat(img, img_output))

ORB–旋转不变图像匹配

ORB描述符是Brief的改进版本;它结合了FAST关键点检测器和经过改进和增强的Brief版本。
使用ORB的一个好处是使用了ORB内置的harris角点度量。它提供了选择前N个不相关的关键点的机会。最重要的是,描述符本身得到了增强,并且旋转不变。
不仅通过使用上一节中的类似示例来探索ORB,而且还将旋转应用于第二张图像。使用CoordinateTransformations包围绕中心旋转图像:

using Images, ImageFeatures, CoordinateTransformations
img1 = Gray.(load("cat-3417184_640.jpg"))
img2 = Gray.(load("cat-3417184_640_watermarked.jpg"))

由于图像已加载,并且想查看ORB是否旋转不变,因此将经变形应用于img2并使用以下代码将其围绕中心旋转:

rot = recenter(RotMatrix(5pi/6), [size(img2)...] .÷ 2)
tform = rot ∘ Translation(-50, -40)
img2 = warp(img2, tform, axes(img2))

接下来,使用一组默认参数初始化ORB。默认设置创建一组500个关键点,并使用阈值为0.25的FAST。默认设置应适合运行的大多数任务。看一下这段代码:

orb_params = ORB()

因为ORB开箱即用,所以直接进入create_descriptor函数来创建图像特征,并使用以下代码来匹配它们:

desc_1, ret_keypoints_1 = create_descriptor(img1, orb_params)
desc_2, ret_keypoints_2 = create_descriptor(img2, orb_params)
matches = match_keypoints(ret_keypoints_1, ret_keypoints_2, desc_1, desc_2, 0.2)

尝试合并图像并预览结果:

grid = Gray.(hcat(img1, img2))
offset = CartesianIndex(0, size(img1, 2))
map(m -> draw!(grid, LineSegment(m[1], m[2] + offset)), matches)
imshow(grid)

尽管图像已旋转,但ORB能够匹配两个图像中的许多主要关键点。

BRISK–缩放不变图像匹配

BRISK是Julia中可用的另一种检测器。 BRISK的最大优点是缩放和旋转不变。规模不变性是以计算成本为代价的,这使其比ORB稍慢。
BRISK还允许使用例如imriser提供的任何其他关键点描述符,例如harris。像前面的示例一样继续使用FAST。
因此,开始使用BRISK。与往常一样,首先加载程序包和图像:

using Images, ImageFeatures, CoordinateTransformations, ImageDraw, ImageView,Rotations
img1 = Gray.(load("cat-3417184_640.jpg"))
img2 = Gray.(load("cat-3417184_640_watermarked.jpg"))

设定目标以证明BRISK是规模和旋转不变的。然后,使用以下代码对img2进行两种类型的转换:围绕中心旋转和调整图像大小:

rot = recenter(RotMatrix(5pi/6), [size(img2)...] .÷ 2)
tform = rot ∘ Translation(-50, -40)
img2 = warp(img2, tform, axes(img2))
img2 = imresize(img2, Int.(trunc.(size(img2) .* 0.7)))

类似于BRIEF,应用FAST算法查找角点。使用的阈值为0.25:

features_1 = Features(fastcorners(img1, 12, 0.25));
features_2 = Features(fastcorners(img2, 12, 0.25));

接下来,使用默认参数初始化BRISK,并尝试通过使用以下代码来匹配关键点:

brisk_params = BRISK()
desc_1, ret_features_1 = create_descriptor(img1, features_1, brisk_params);
desc_2, ret_features_2 = create_descriptor(img2, features_2, brisk_params);
matches = match_keypoints(Keypoints(ret_features_1), Keypoints(ret_features_2), desc_1, desc_2, 0.2)

将结果存储在matchs变量中。matchs变量是两个元素组成的数组,每个元素对应于一张图像上的一个位置。
由于希望将结果显示为单个图像,因此需要将img2的高度调整为等于img1的高度:

img3 = zeros(Gray, size(img1))
img3[1:size(img2, 1), 1:size(img2, 2)] = img2

绘制连接匹配的线。使用ImageDraw包中的函数draw!,并使用imshow函数通过以下代码显示结果:

grid = hcat(img1, img3)
offset = CartesianIndex(0, size(img1, 2))
map(m -> draw!(grid, LineSegment(m[1], m[2] + offset)), matches)
imshow(grid)

BRISK已成功识别并匹配缩放和旋转图像的特征:

FREAK–最快的缩放与旋转不变匹配

Julia中可用的最后一个描述符是FREAK描述符。该算法引入了一个新的关键点描述符,该描述符是由人类视觉系统(更确切地说是视网膜)启发而来的,是快速视网膜关键点(Fast Retina Keypoint, FREAK)创造的。
通常,FREAK以较低的计算需求来更快地进行计算。它使它们成为上一节中介绍的方法的绝佳替代方法。 FREAK被认为是最快的缩放,旋转和噪声不变算法。
首先使用以下代码加载软件包和图像:

using Images, ImageFeatures, CoordinateTransformations, ImageDraw, ImageView
img1 = Gray.(load("cat-3417184_640.jpg"))
img2 = Gray.(load("cat-3417184_640_watermarked.jpg"))

对第二张图片应用了多种变换。使用以下代码围绕中心旋转并调整图像大小:

rot = recenter(RotMatrix(5pi/6), [size(img2)...] .÷ 2)
tform = rot ∘ Translation(-50, -40)
img2 = warp(img2, tform, axes(img2))
img2 = imresize(img2, Int.(trunc.(size(img2) .* 0.7)))

执行FAST算法以找到角点,并通过以下代码使用FREAK匹配关键点:

keypoints_1 = Keypoints(fastcorners(img1, 12, 0.35));
keypoints_2 = Keypoints(fastcorners(img2, 12, 0.35));
freak_params = FREAK()
desc_1, ret_keypoints_1 = create_descriptor(img1, keypoints_1, freak_params);
desc_2, ret_keypoints_2 = create_descriptor(img2, keypoints_2, freak_params);
matches = match_keypoints(ret_keypoints_1, ret_keypoints_2, desc_1, desc_2, 0.2)

使用以下代码绘制结果并生成预览:

img3 = zeros(size(img1, 1), size(img2, 2))
img3[1:size(img2, 1), 1:size(img2, 2)] = img2
grid = Gray.(hcat(img1, img3))
offset = CartesianIndex(0, size(img1, 2))
map(m -> draw!(grid, LineSegment(m[1], m[2] + offset)), matches)
imshow(grid)

使用Julia进行图像处理--图像表示与匹配算法相关推荐

  1. 使用Julia进行图像处理--使用形态学运算进行图像调整

    使用Julia进行图像处理--使用形态学运算进行图像调整 前言 图像二值化 基本运算 图像侵蚀 使用侵蚀分离物体 准备用于文本识别的图像 图像膨胀 合并几乎连接的对象 突出显示细节 派生操作 图像开运 ...

  2. 使用Julia进行图像处理--图像分割

    使用Julia进行图像处理--图像分割 前言 监督方法 种子区域增长 识别简单的对象 识别复杂对象 无监督方法 基于图的方法 快速扫描算法 辅助函数 后记 前言 使用Julia的ImageSegmen ...

  3. 使用Julia进行图像处理--用于扩充训练集的图像增强

    使用Julia进行图像处理--用于扩充训练集的图像增强 前言 "访问"像素 将像素转换成数字数组 将数字数组转换为色彩 改变色彩饱和度 将图像转化为灰度图像 创建自定义滤镜 填充图 ...

  4. 使用Julia进行图像处理--JuliaImages介绍与基础使用

    使用Julia进行图像处理--JuliaImages介绍与基础使用 安装包 读取图像 从磁盘读取单个图像 从URL读取单个图像 批量读取文件夹中的图像 保存图像 使用TestImages 预览图像 裁 ...

  5. 数字图像处理图像反转的实现_使用8086微处理器反转16位数字

    数字图像处理图像反转的实现 Problem statement: 问题陈述: Write an assembly language program in 8086 microprocessor to ...

  6. 数字图像处理图像反转的实现_反转8位数字| 8085微处理器

    数字图像处理图像反转的实现 Problem statement: 问题陈述: To reverse 8 bits number using 8085 microprocessors. 使用8085微处 ...

  7. 数字图像处理课设图像的锐化_数字图像处理图像锐化处理.ppt

    数字图像处理图像锐化处理 4.7.2 灰度级到彩色转换 灰度级到彩色转换(例) 在HSI彩色空间的直方图均衡强度均衡处理没有改变图像的色调和饱和度值,但它的确影响了整体图像的彩色感观. 向量分量可以用 ...

  8. 图像处理------图像细化

    图像处理------图像细化 算法流程参考自:图像处理细化算法 参考博文中没有细化算法的代码实现,只有算法的具体流程,在本文中,使用python实现图像细化的代码实现,但其运行效率没有考虑,只为理解算 ...

  9. matlab 求其骨架,数字图像处理图像的骨架生成和提取(Matlab)三种方法

    [实例简介] 数字图像处理图像的骨架生成和提取(Matlab),有三种方法,推荐给大家! [实例截图] [核心代码] Programe ├── Programe1 │   ├── 00.JPG │   ...

最新文章

  1. next.js_Next.js手册
  2. HTML和JavaScript代码分离、平稳退化(1)
  3. 补补算术基础:编程中的进制问题
  4. 万字长文了解免疫算法原理 及求解复杂约束问题(源码实现)
  5. 通过反射获得引用程序集信息
  6. php declare 作用,php declare用法详解
  7. BZOJ 3270: 博物馆
  8. 兼容FF/IE的添加收藏夹的代码
  9. python语言的核心理念是_Python 编程语言的核心是什么?
  10. SQLLoader2(导入EXCEL或csv格式的文件)
  11. PostgreSQL 的 target_list分析(三)
  12. IDEA常用快捷键总结(附导入其他IDE快捷键)
  13. 中国象棋软件制作感想
  14. 关于链表初始化typedef struct LNode{}LNode,*linklist的理解
  15. python 方差齐性检验_SPSS正态分布以及方差齐性检验以及Wilcox检验
  16. js-鼠标事件-拖放图片(对鼠标事件进一步加深印象)
  17. 联想电脑计算机怎么设置十进制,联想笔记本win10老友系统如何给电池设置充电阈值【图文】...
  18. 安卓虚拟键盘_安卓这些年变化多惊人?那些老玩家才懂的回忆
  19. redis 基础数据类型及应用 1
  20. 上传声音 微信小程序_微信小程序之----audio音频播放

热门文章

  1. HTML中的几种空格
  2. NSArray 的遍历
  3. 80后开网店卖故事:1500多位为感觉而埋单
  4. tricks about and-or in python
  5. Linux性能监控(转)
  6. [转载] Python字典及基本操作(超级详细)
  7. 学校与工作(献于在校大学生及入职不久的工作者)
  8. 关于这个错误的不明原因的解决之道
  9. jmeter正则中常见的转义字符-笔记三
  10. [NOIP2003普及组]麦森数(快速幂+高精度)