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

8 篇文章 4 订阅
7 篇文章 76 订阅

前言

形态学转换是应用于二进制或灰度图像的简单数学运算。它们用于消除小噪音;缩小,分离或识别对象;并增加对象大小或背景空间。

图像二值化

ImageMorphology软件包的核心部分是灰度图像或二值化图像。二进制图像是指用1或0表示像素的图像。大多数示例都具有以下标准符号:

  1. 0或黑色用作背景
  2. 1或白色用于前景,即对象

使用以下代码通过简单的灰度阈值来创建二进制图像,例如,如果像素值大于0.5,则分配1;如果像素值小于0.5,则分配0。
二进制和灰度图像不是完美的,因为它们可能包含许多缺陷,并且会被噪声或纹理扭曲。形态图像转换旨在通过使用图像的形式和结构来消除这些缺陷。这些操作仅依赖于像素值的相对顺序,而不依赖于它们的数值,它们被广泛用于标识和处理文本,文档以及其他形状,例如线条和框。
以下代码将演示如何创建阈值为0.5的二进制图像。首先加载图像并将简单的数学转换应用于图像的灰度版本:

using Images, ImageView, ImageMorphology
# load an image
img = load("sample-images/bird-3183441_640.jpg");
# convert image to grayscale and binarise the only channel
# 1. 将图像转换为灰度
# 2. 将所有大于0.5的值转换为true,而小于0.5的所有值转换为false
# 3. 通过将1乘以结果数组,它将true和false值转换为1或0
img_binary = 1 * (Gray.(img) .> 0.5);

二值图像

将转换为二值版本的图像与原始图像放在一起进行对比:

# 使用restrict函数缩放原始图像和二值图像
img = restrict(img)
img_binary = restrict(RGB.(Gray.(img_binary)))
# 使用size标识图像缩放版本的宽度
img_width = size(img, 2)
# 使用填充功能创建新图像,其宽度是原来的两倍
combined_image = fill(RGB4{Float32}(0.,0.,0.), size(img) .* (1, 2))
# 将图像放在一起进行对比
combined_image[:, 1:img_width] = img
combined_image[:, img_width+1:img_width*2] = img_binary
imshow(combined_image)

图像对比

形态学运算也可以应用于灰度图像。

基本运算

数学形态学是一组与图像的形状或特征有关的非线性运算和技术。图像形态学有两个基本要素:

  1. 二进制或灰度图像
  2. 结构元素

已经讨论了有关图像和配色方案的先决条件,但是结构元素是新的。结构元素通常是一个3x3二值块,可在图像上滑动并更新它。滑动结构元素可以实现两个基本操作:

  1. 图像侵蚀:从对象边界去除像素
  2. 图像膨胀:将像素添加到图像中对象的边界

ImageMorphology包进行的侵蚀和膨胀仅支持3x3结构元素。 3×3正方形是用于形态学运算的最流行的结构元素。较大的结构元素会产生更极端的侵蚀或膨胀效果,通常通过多次重复3x3结构元素运算获得相似的结果。

图像侵蚀

图像侵蚀是数学形态学领域的两个基本运算符之一。侵蚀是缩小图像前景或1值对象的过程。它可以平滑对象边界并去除小物体。
为了了解图像侵蚀的工作方式,首先在包含白噪声的简单图像上进行尝试,然后继续比较将其应用于照片的二值和灰度版本时的结果。

使用侵蚀分离物体

对于此任务,使用如下图片。它具有许多不同的连接图形,并且两侧都添加了噪声:
geometrical_image

从加载图像并将其转换为灰度开始:

using Images, ImageView, ImageMorphology
geom_img = load("pictures/geometrical-figures-and-noise.jpg");
geom_img_binary = Gray.(Gray.(geom_img) .> 0.5);#keeps white objects white

接下来,应用erode函数来进行转换:

geom_img_binary_e = erode(geom_img_binary)
imshow(geom_img_binary_e)

以下结果图像将显示在屏幕上。能够看到噪音大大减少并且对象分离得到改善:
erode_image_1
一次运行侵蚀功能并不能完全消除噪音,它使对象保持连接。运行erode函数数次查看结果:

geom_img_binary_e = erode(erode(geom_img_binary_e))
geom_img_binary_e = erode(erode(geom_img_binary_e))
imshow(geom_img_binary_e)

erode_image_5

准备用于文本识别的图像

将图像侵蚀应用于真实照片,将车牌上的字母和数字与其余内容分开:
车牌示例
首先加载图像,然后创建一个二进制版本,然后多次应用erode函数并比较结果:

using Images, ImageView, ImageMorphology
carplate_img = load("pictures/caribbean-2726429_640.jpg")
carplate_img_binary = Gray.(Gray.(carplate_img) .< 0.5); 
# converts black objects to white and vice-versa
carplate_img_binary_e = erode(carplate_img_binary)
imshow(carplate_img_binary)
carplate_img_binary_e = erode(erode(carplate_img_binary_e))
imshow(carplate_img_binary_e)

三次侵蚀图像的结果。图像上没有其他文字,并且车牌清晰。可以用于文本识别任务:
在侵蚀结果

图像膨胀

膨胀是形态学领域中的另一个基本操作。图像膨胀是逐渐扩大前景像素区域的边界或1值对象的大小的过程。因此,前景像素的区域会增大尺寸,平滑对象边界并封闭对象之间的孔和间隙。

合并几乎连接的对象

同样使用在使用侵蚀分离物体部分中使用的图片。它具有许多不同的连接图形,并且两侧都添加了噪声:
geomtrical_image

首先删除几何对象之间的间隙和孔,并使用以下代码比较一次运行膨胀函数一次和三次的情况:

using Images, ImageView, ImageMorphology
geom_img = load("pictures/geometrical-figures-and-noise.jpg");
geom_img_binary = Gray.(1 * Gray.(geom_img) .> 0.5);
geom_img_binary_d = dilate(geom_img_binary)
imshow(geom_img_binary_d)
geom_img_binary_d = dilate(dilate(geom_img_binary_d))
imshow(geom_img_binary_d)

可以看到三次膨胀后图形之间的重叠增加了很多,并且右侧的噪点变成了单个对象。
dilate_image

突出显示细节

尝试将膨胀函数应用于带有车牌的图像。如果侵蚀功能已将车牌字母和数字分开,则膨胀将扩展每个对象的边界:

using Images, ImageView, ImageMorphology
carplate_img = load("pictures/caribbean-2726429_640.jpg")
carplate_img_binary = Gray.(Gray.(carplate_img) .< 0.5)
carplate_img_binary_d = dilate(carplate_img_binary)
imshow(carplate_img_binary_d)

突出显示细节

派生操作

开运算和闭运算是形态学的另外两个主要运算符。它们都源自基本操作-侵蚀和扩张。它们同样通常用于二进制或灰度图像。
从技术角度来看,可以通过以下方式描述开运算和闭运算:

  1. 开运算:这是侵蚀后再膨胀
  2. 闭运算:这是膨胀后再侵蚀

侵蚀不是膨胀的逆过程。通常,侵蚀和膨胀交替进行会产生与原始图像不同的图像,并且偶然会产生相同的结果。
与基本形态运算符一样,确切的运算由结构元素确定,该元素在Julia中固定为3x3的块。

图像开运算

图像开运算在某种程度上可与侵蚀相媲美。它被用于去除边缘的前景像素。但是,总的来说,它不如侵蚀有效。
图像开运算的目标是保持前景区域具有与结构元素相似的形状或可以完全包含结构元素,同时消除前景像素的所有其他区域。
为了说明它在实际中是如何工作的,使用几何图形,并观察开运算与侵蚀的不同之处,将opening函数应用于上一张图片:

using Images, ImageView, ImageMorphology
geom_img = load("pictures/geometrical-figures-and-noise.jpg");
geom_img_binary = Gray.(1 * Gray.(geom_img) .> 0.5);
geom_img_binary_o = opening(geom_img_binary)
imshow(geom_img_binary_e)

image_opening

比较打开和侵蚀功能所产生的结果,开运算保持大对象不变,同时消除了小点,而侵蚀减少了所有对象的大小。

图像闭运算

图像闭运算是扩张后侵蚀。与开运算类似,它是从侵蚀和膨胀的基本过程创建的,同样,它可以应用于二进制和灰度图像。
闭运算符的结果与膨胀非常相似,但有一些例外。它主要侧重于消除背景色孔,同时又不破坏目标对象的原始边界形状。
与图像开运算类似,使用具有几何图形的图像并调整代码以执行闭运算操作:

using Images, ImageView, ImageMorphology
geom_img = load("pictures/geometrical-figures-and-noise.jpg");
geom_img_binary = Gray.(Gray.(geom_img) .> 0.5);
geom_img_binary_c = closing(geom_img_binary)
imshow(geom_img_binary_c)

image_closing

如果将显示的图像与膨胀的结果进行比较,会看到大物体的尺寸没有增大,背景的一小部分变为白色。

顶帽和低帽操作

当对从图像中获取一些小细节感兴趣时,可以利用 JuliaMorphology软件包的tophat和bothat运算符专注于检索此类细节。
顶帽操作用于增强深色背景上感兴趣的明亮物体。它通过从原始图像中减去运行开运算函数的结果来变换图像。它包含源图像的那些元素,这些元素小于结构元素并且比其相邻元素明亮。
另一方面,低帽操作则相反。也就是说,它用于增强明亮背景上感兴趣的深色物体。低帽操作运算符返回的图像是从图像的形态封闭运算后的图像中减去原始图像的结果。结果包含的对象或元素小于结构元素,并且比其周围环境暗。
Julia使用以下代码在具有几何图形的图像上执行两个滤波器,从而实现了tophat和bothat函数:

using Images, ImageView, ImageMorphology
# apply tophat and bothat to an image
geom_img = load("pictures/geometrical-figures-and-noise.jpg");
geom_img_gray = Gray.(geom_img);
geom_img_th = tophat(geom_img_gray)
geom_img_bh = bothat(geom_img_gray)
# create a preview
geom_img_new = zeros(ColorTypes.Gray{FixedPointNumbers.Normed{UInt8,8}}, size(geom_img_gray) .* (1, 2));
geom_img_new_center = Int(size(geom_img_gray, 2))
geom_img_new[:, 1:geom_img_new_center] = geom_img_th
geom_img_new[:, geom_img_new_center:end - 1] = geom_img_bh
geom_img_new[:, geom_img_new_center] = 1
imshow(Gray.(geom_img_new))

从以下结果中可以看到,tophat函数抑制了所有大对象,只保留了原始图像的小细节:
tophat_and_bothat

调整图像对比度

通过将原始图像添加到经过顶帽过滤的图像中,然后减去经过低帽过滤的图像,可以在灰度图像上调整图像对比度:

using Images, ImageView, ImageMorphology
minmax = scaleminmax(Gray, 0, 1) # limit values on a scale from 0 to 1
# adjust image contrast
img = load("pictures/custom_image_name.jpg");
img_gray = Gray.(img);
img_new = minmax.(img_gray + tophat(img_gray) - bothat(img_gray)) 
# adjust image contrast
# merge the original image with adjusted for preview
img_center = Int(size(img_gray, 2) / 2)
img_gray[:, img_center:end] = img_new[:, img_center:end]
img_gray[:, img_center] .= 0
imshow(img_gray)

调整对比度1

在前面的代码中,首先定义了minmax函数,该函数将像素值限制在0到1的范围内。除了加载图像并将其转换为灰度外,还实现了负责调整对比度的代码部分。
有时,使用tophat和bothat函数的100%值会产生巨大影响,并使图像失真。使用从0到1的比例乘数来最小化tophat和bothat函数的影响,从而解决了失真问题。
在左侧看到原始版本,在右侧看到调整后的版本。从这张照片可以看出,右侧细节的质量有了明显的改善:

img = load("pictures/custom_image_name.jpg");
img_gray = Gray.(img);
img_new = minmax.(img_gray + tophat(img_gray) * 0.5 - bothat(img_gray) * 0.5)
img_center = Int(size(img_gray, 2) / 4)
img_gray[:, img_center:end] = img_new[:, img_center:end]
img_gray[:, img_center] = 0
imshow(img_gray)

调整对比度2

后记

Enjoy coding.

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

盼小辉丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值