在猫上看到黑点表示由快速角点函数标识的角点。使用其他来匹配相同的对象。
使用imcorner函数进行角点检测
Imcorner函数是FAST替代方法。它也用于图像的角点,并提供不同的方法集:
-
harris
-
shi-tomasi
-
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, ImageView
img = 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函数时阈值较小的时间会增加,但是内存消耗仍然很小且固定。
二元鲁棒独立基本特征(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)
最后
不知道你们用的什么环境,我一般都是用的Python3.6环境和pycharm解释器,没有软件,或者没有资料,没人解答问题,都可以免费领取(包括今天的代码),过几天我还会做个视频教程出来,有需要也可以领取~
给大家准备的学习资料包括但不限于:
Python 环境、pycharm编辑器/永久激活/翻译插件
python 零基础视频教程
Python 界面开发实战教程
Python 爬虫实战教程
Python 数据分析实战教程
python 游戏开发实战教程
Python 电子书100本
Python 学习路线规划
小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Python工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Python爬虫全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注:python)
-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ZlaTM0Nzc5NTc5MA==,size_16,color_FFFFFF,t_70)
小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Python工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Python爬虫全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注:python)
[外链图片转存中…(img-4CIkchnJ-1711210933131)]