使用Julia进行图像处理--图像表示与匹配算法,2024年最新华为的面试难吗

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Python全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img



既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Python知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip1024c (备注Python)
img

正文

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)

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

result

性能比较

进行性能比较以查看哪种算法更快也很重要。为了运行分析,在以下代码中使用了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)))

imshow_compare

接下来,使用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)

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

result_match

如果大规模运行重复检测,可以将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)

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

imshow_pic

因此,使用以下代码从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)

imshow_matches

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

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))

result_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)

image_orb

尽管图像已旋转,但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函数通过以下代码显示结果:

在这里插入图片描述

感谢每一个认真阅读我文章的人,看着粉丝一路的上涨和关注,礼尚往来总是要有的:

① 2000多本Python电子书(主流和经典的书籍应该都有了)

② Python标准库资料(最全中文版)

③ 项目源码(四五十个有趣且经典的练手项目及源码)

④ Python基础入门、爬虫、web开发、大数据分析方面的视频(适合小白学习)

⑤ Python学习路线图(告别不入流的学习)

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注python)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
20210511152217670.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3poaWd1aWd1,size_16,color_FFFFFF,t_70)

感谢每一个认真阅读我文章的人,看着粉丝一路的上涨和关注,礼尚往来总是要有的:

① 2000多本Python电子书(主流和经典的书籍应该都有了)

② Python标准库资料(最全中文版)

③ 项目源码(四五十个有趣且经典的练手项目及源码)

④ Python基础入门、爬虫、web开发、大数据分析方面的视频(适合小白学习)

⑤ Python学习路线图(告别不入流的学习)

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注python)
[外链图片转存中…(img-aBdEDk8s-1713462479645)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值