图像的类型和转换
本演示的目的是展示定义图像的方法及其变换的基本原理,特别是基于仿射变换。
Pkg.add(["TestImages", "ImageShow"])
using Images # Библиотека обработки изображений
using ImageShow # Библиотека отрисовки изображений
using TestImages # Библиотека тестовых изображений
颜色空间的类型
任何图像都只是像素对象的数组。 图像的元素称为像素,Julia图像将像素视为一流对象。 例如,我们有灰色阴影的灰色像素,颜色的RGB像素,颜色的Lab像素。
让我们从RGB格式(由英文单词red,green,blue–red,green,blue形成的缩写)开始分析–一种添加剂颜色模型,描述了使用三种颜色编码颜色以进行颜色再现的方法,这些颜色通 原色的选择是由我们眼睛视网膜的颜色感知生理学的特殊性决定的。
img_rgb = [RGB(1.0, 0.0, 0.0), RGB(0.0, 1.0, 0.0), RGB(0.0, 0.0, 1.0)]
dump(img_rgb)
灰色是一个以灰色阴影描述图像的单对角矩阵. 默认情况下,使用8位颜色编码。
img_gray = rand(Gray, 3, 3)
dump(img_gray)
LAB是两个不同(虽然相似)颜色空间名称的缩写。 比较着名和广泛的是CIELAB(更准确地说,CIE1976Lab*),另一个是Hunter Lab(更准确地说,Hunter L,a,b)。 因此,Lab是一个非正式的缩写,没有明确定义颜色空间。 在Engee中,当谈到实验室空间时,他们的意思是CIELAB。
img_lab = rand(Lab, 3, 3)
dump(img_gray)
对象类型之间的转换
Gray.(img_rgb) # RGB => Gray
RGB.(img_gray) # Gray => RGB
RGB.(img_lab) # Lab => RGB
图像变换
首先,从下载图像。jpg文件。
img = load( "$(@__DIR__)/4028965.jpg" )
增加上传图像的对比度。 功能*adjust_histogram(Equalization(),...)*可以处理不同类型的输入数据。 返回图像的类型与输入类型相对应。 对于彩色图像,输入被转换为YIQ类型,并且Y通道被对齐,之后它与通道I和Q组合。
alg = Equalization(nbins = 256)
img_adjusted = adjust_histogram(img, alg)
将图像大小相对于源减小4倍。 Imresize允许您使用相对于原始图像的关系来更改大小,如下例所示,还允许您使用手动设置新图像的尺寸来更改大小,例如:
imresize(img,(400,400))。
img_small = imresize(img_adjusted, ratio=1/4)
print(size(img_adjusted), " --> ", size(img_small))
仿射变换(来自拉丁语affinis"触摸,接近,相邻")是平面或空间到自身的映射,其中平行线变成平行线,相交成相交,交叉成交叉。 基本图像转换使用索引网格对图像进行操作。 该变换由图像变换矩阵根据下图所述的原理设定。

# Вспомогательная функция контроля размерностей
function C_B_V(x, max_val)
x[x .> max_val - 1] .= max_val - 1
x[x .< 1] .= 1
return x
end
接下来,我们声明一个仿射图像变换函数,其中:
- Theta是变换矩阵;
- img是输入图像。;
- out_size-输出图像的大小;
- 网格-像素索引的网格。
function transform(theta, img, out_size)
grid = grid = zeros(3, out_size[1]*out_size[2])
grid[1, :] = reshape(((-1:2/(out_size[1]-1):1)*ones(1,out_size[2])), 1, size(grid,2))
grid[2, :] = reshape((ones(out_size[1],1)*(-1:2/(out_size[2]-1):1)'), 1, size(grid,2))
grid[3, :] = ones(Int, size(grid, 2))
# Умножение theta на grid
T_g = theta * grid
# Вычисление координат x, y
x = (T_g[1, :] .+ 1) .* (out_size[2]) / 2
y = (T_g[2, :] .+ 1) .* (out_size[1]) / 2
# Округление координат
x0 = ceil.(x)
x1 = x0 .+ 1
y0 = ceil.(y)
y1 = y0 .+ 1
# Обрезание значений x0, x1, y0, y1
x0 = C_B_V(x0, out_size[2])
x1 = C_B_V(x1, out_size[2])
y0 = C_B_V(y0, out_size[1])
y1 = C_B_V(y1, out_size[1])
# Вычисление базовых координат
base_y0 = y0 .* out_size[1]
base_y1 = y1 .* out_size[1]
# Работа с изображением
im_flat = reshape(img, :)
# Обрабатываем координаты
A = (x1 .- x) .* (y1 .- y) .* im_flat[Int.(base_y0 .+ x0 .+ 1)]
B = (x1 .- x) .* (y .- y0) .* im_flat[Int.(base_y1 .+ x0 .+ 1)]
C = (x .- x0) .* (y1 .- y) .* im_flat[Int.(base_y0 .+ x1 .+ 1)]
D = (x .- x0) .* (y .- y0) .* im_flat[Int.(base_y1 .+ x1 .+ 1)]
# Расчет результата
result = reshape((A .+ B .+ C .+ D), (out_size[1], out_size[2]))
return result
end
首先,让我们将此函数应用于灰度图像。
img_sg = Gray.(img_small)
从下面的数据中我们可以看到,灰色图像具有8位的颜色深度,其尺寸仅由宽度和高度表示。
dump(img_sg[1])
size(img_sg)
让我们为这个图像设置一个变换矩阵。
theta = [2 0.3 0; -0.3 2 0]
让我们将我们的功能应用于图像。 正如我们所看到的,尺寸已经减半,旋转已经完成。
img_transfor = transform(theta, img_sg, [size(img_sg,1),size(img_sg,2)])
为了获得逆变换,我们找到变换矩阵的逆矩阵并将其四舍五入到第四位。
theta_inv = hcat(inv(theta[1:2,1:2]), [-0.1;0.1])
theta_inv = round.(theta_inv.*10^4)./10^4
img_sg_new = transform(theta_inv, img_transfor, [size(img_transfor,1),size(img_transfor,2)])
现在让我们将此功能应用于RGB图像。 首先,让我们将RGB格式图像转换为通道表示。 让我们分析一下使用此图像表示选项向我们开放的可能性。
img_CHW = channelview(img_small);
print(size(img_small), " --> ", size(img_CHW))
选择图像的红色通道并仅绘制红色通道。
RGB.(img_CHW[1,:,:], 0.0, 0.0) # red
如果所有通道都是均匀分布的,那么我们将获得灰色阴影的图像,因为没有一个基本颜色优于其余颜色。
RGB.(img_CHW[1,:,:], img_CHW[1,:,:], img_CHW[1,:,:]) # Gray
基于通道图像的例子,我们可以通过将RGB图像作为三个独立的一维矩阵运行并组合它们的结果来实现仿射变换。
img_CHW_new = zeros(size(img_CHW))
for i in 1:size(img_CHW,1)
img_CHW_new[i,:,:] = transform(theta, img_CHW[i,:,:], [size(img_CHW,2),size(img_CHW,3)])
end
RGB.(img_CHW_new[1,:,:], img_CHW_new[2,:,:], img_CHW_new[3,:,:])
结论
在这个演示中,我们已经处理了图像的通道表示和各种类型的矩阵表示,以及分析了Engee中的一些图像处理功能。












