MATLAB 图像处理

MATLAB 图像处理

  • 基础
    • 简介
    • 图像类型
        • 灰度图像
      • 二值图像
      • RGB图像
      • 索引图像
        • 颜色图
        • colorcube 获取颜色图
        • colormap 更改颜色图
      • HSV彩色空间
        • rgb2hsv 将RGB颜色转换为HSV颜色
    • 图像坐标系
      • 像素索引式
      • 空间坐标式
  • 函数
    • imread 读入图像
    • imshow 显示图像
    • imtool 用窗口显示图像
    • image 矩阵显示图像
    • imagesec 待补充
    • colorbar 显示彩色条
    • montage
    • zoom
    • warp
    • subimage
    • impixel 显示像素信息
    • impixelinfo 显示像素信息
    • imwrite 保存图像
    • imfinfo 显示内存信息
    • mat2gray 矩阵灰度化
    • rgb2gray 彩色灰度化
    • im2uint8 转换为8位
    • im2double 转换为双精度
    • VideoReader 读取视频文件
    • mmfileinfo 多媒体文件信息
    • readFrame 读取视频帧数据
    • hasFrame 判断读取成功
    • movie 播放视频
    • getframe 捕获坐标区或图像作为影片帧
    • immovie
    • imiplay
    • imbinarize 灰度二值化
    • imadjust 调整灰度或颜色图
    • 分段线性变换
    • 对数变换
    • stretchlim 对比度计算 待补充
    • 对数函数-没懂
    • 对比度拉伸函数(公式)-没懂
    • imadd 叠加图像
    • imnoise 添加噪声
    • imsubstrcat 减去图像
    • imabsdiff 两图像的绝对差
    • immultiple 两图像相乘
    • imdivide 两图像相除
    • imcomplement 图像反转
    • imlincomb 图像线性组合
    • imresize 调整图像大小
    • rescale 缩放标定元素值
    • imrotate 旋转图像
    • imcrop 裁剪图像-??返回的坐标位置
    • centerCropWindow2d 创建矩形中心裁切窗口-没看完
    • rectangle 画尖角圆角矩形
    • imtranslate 平移图像
    • affine2d 二维仿射几何变换
      • **待补充**
    • invert 逆几何变换
    • isrigid 判断是否刚性变换
    • isSimilarity 判断是否相似变换
    • isTranslation 判断是否纯平移
    • outputLimits 待补充
    • transformPointsForward 前向几何变换-待补充
    • transformPointsInverse -待补充
    • imwarp 图像几何变换
    • nlfilter 滑动邻域操作
    • colfilt 列方向邻域操作/非线性滤波 待补充
    • im2col 重排矩阵加速块处理
    • col2im im2col的逆-待补充
    • blockproc 非重复块处理 待补充
      • block_struct 块结构体 待补充
    • padarray 填充图像(矩阵)
    • roipoly 指定多边形ROI
    • roicolor 基于颜色选择ROI
    • ismember 待补充
    • createMask 创建二值掩码图像
      • ROI 相关对象
    • regionfill 区域填充
    • roifilt2 ROI区域滤波
    • imhist 图像直方图
    • stem 待补充
    • histeq 直方图均衡化规定化 算法没懂 待补充
    • mean2 计算矩阵均值
    • std2 计算矩阵标准差
      • std 计算向量标准差
    • corr2 二维相关系数
    • corr 线性或秩相关性 没懂
    • fspecial 创建预定义的二维滤波器
    • imfilter 图像滤波
    • conv2 二维卷积
    • filter2 二维数字滤波器
    • medfilt2 中值滤波
    • ordfilt2 排序滤波
    • wiener2 二维自适应滤波 待补充
    • fft 快速傅里叶变换 待补充
    • fft2 二维快速傅里叶变换
    • nextpow2 用于填充fft 待补充
    • fftshift 将零频分量移到频谱中心
    • ifftshift 逆零频平移
    • stem 绘制离散序列数据
    • atan 反正切
    • atan2 四象限反正切
      • imag 取复数的虚部
      • real 取复数实部
      • angle 相位角
    • ifft2 二维快速傅里叶逆变换
    • imapprox 近似索引图
    • rgb2ind 将RGB转换为索引图像
    • dither 转换图像,抖动
    • grayslice 灰度图转换为索引图
    • gray 灰度颜色数组
    • flip 翻转元素顺序
      • flipud 将数组上下翻转
      • fliplr 将数组左右翻转
    • gray2ind 灰度、二值转换为索引图
    • ind2gray 索引转换为灰度图像
    • ind2rgb 索引图像转换为RGB图像
    • 颜色空间转换
    • edge 边缘检测
    • hough 霍夫变换
      • houghpeaks 霍夫变换中的峰值

《数字图像处理matlab版》原书中的图像资源,自取https://pan.baidu.com/s/1NDg_BbVuZipQm1f3KQzJ-Q (提取码x14a)

《数字图像处理matlab版》还是得啃啊,要不然原理都不懂
软件自带的帮助文档,部分没有中文解释,最好配合在线官方文档;同时文档中的“尝试此例”很有用,值得运行

基础

简介

图像关于x,y坐标和幅度是连续的。但是数字图像关于x,y坐标和幅度是离散的。
离散:
采样:坐标值数字化
量化:幅度数字化
MATLAB数字坐标原点为(1,1)
注意某些函数对图像坐标的行列定义是不一样的

图像类型

数据类型:无符号,有符号;8、16、32位;char(16位);logic(8位)类型

灰度图像

无符号8位,无符号16位,double,single。double和single类的灰度图像通常会归一化到0-1范围内(没懂)

二值图像

二值图像是只含有0和1的逻辑数组,不是数值数组

应用类型转换函数(不限于二值图像)
logic,im2uint8,im2unit16,im2double,im2single,mat2gray

  • mat2gray(A,[Amin,Amax])
    将图像转换为标定(自动标定)到[0,1]范围内的double类型的数组,注意返回的还是double类型的数组,范围[0,1]
    mat2grat(A) 没有范围裁剪

  • logical(A)
    如果是只有数值0和1,则转换为逻辑0和1
    如果有其他数,A 中的任意非零元素都将转换为逻辑值 1 (true),零则转换为逻辑值 0 (false)。复数值和 NaN 不能转换为逻辑值

RGB图像

可以看成三幅灰度图像形成的堆叠,显示彩色与显示器有关
如果数据类型为double,那么取值范围为[0,1]
如果为Uint8,uint16则不会归一化到[0,1]

图像位深度,RGB图像,如果数据类型为8位,则为深度为8X3=24位

  • 组成RGB图像
    串联三个灰度图像形成RGB图像,rgb=cat(3,r,g,b) 形成RGB图像的方式可以不同,行串联,列串联,第三方向串联

  • 提取RGB的每个通道分量

r=rgb(:,:,1)
g=rgb(:,:,2)
b=rgb(:,:,3)
RGB(2,5,:) 返回25列像素的RGB值

《书》自定义函数,可以从某个点观察RGB彩色空间立方体,P120

索引图像

索引图像将图像的灰度值直接映射到彩色值,
索引图像有两个分量,整数矩阵x,和彩色映射矩阵map。
map:mX3数组,double类型的[0,1]范围内数组,m等于颜色数
索引图与灰度图,map索引数组每行的三列值相等,则为灰度图
索引图像,对于

颜色图

颜色图数值取值范围为[0,1],的矩阵,用于定义诸如曲面、图像以及补片之类的图形对象的颜色,可以 通过将数据值映射到颜色图中的颜色来绘制这些对象

colorcube 获取颜色图

文档没懂

colormap 更改颜色图

更改所属坐标区或图窗的颜色图

colormap(map) map是定义的颜色图矩阵,注意数值元素为[0,1]

colormap map 将当前(相邻绘图语句)图窗的颜色图设置为系统自带的一种预定义颜色图

colormap(target,map) 为特定图窗指定不同的颜色图
ax1 = subplot(2,1,1); 
surf(peaks)
colormap(ax1,spring)

map=colormap 返回当前图窗的颜色图,颜色图为矩阵形式

mesh(peaks)
colormap(parula(5)) 设定数值来指定颜色图的颜色数,parula为系统预定义的一个颜色图

HSV彩色空间

rgb2hsv 将RGB颜色转换为HSV颜色

HSV = rgb2hsv(RGB) 转换为色调、饱和度、明度
hsvmap = rgb2hsv(rgbmap) RGB颜色图,转换为HSV颜色图,见文档

输入是RGB图像
返回的HSV色彩三通道的值为[0,1],其为double类型

HSV空间待补充

图像坐标系

像素索引式

离散的形式,相当于矩阵索引

空间坐标式

表示图像中位置的另一种方法是使用连续变化的坐标系,而不是离散的索引。对于这种坐标,您可以想象图像覆盖在一个方形补片之上。在像这样的空间坐标系中,图像中的位置是平面上的位置,它们用 x 和 y(而不是像素索引系统中的行和列)来描述。从笛卡尔坐标角度来看,(x,y) 位置(如 (3.2,5.3))是有意义的,并且不同于像素 (5,3)
MATLAB 图像处理_第1张图片
内部坐标系
默认情况下,工具箱使用与图像像素索引对应的图像空间坐标系。它称为内部坐标系
任何像素的中心点的内部坐标 (x,y) 与该像素的列和行索引相同
注意,相对于像素索引 (5,3),坐标设定 (3.0,5.0) 的顺序在内部坐标中是反向的。
一般如果函数使用空间坐标式会指明,
世界坐标系
见文档

函数

imread 读入图像

读图像

I=imread('pout.tif') 读取特定格式的图像
I=imread('filename') 从指定文件读取图像,若文件包含多幅图像则读取第一幅图像
I=imrad('filename',idx) 从多福图像中读取指定图像,idx=1:5读取前5[X,map]=imread('filename') X为索引图像,map为关联的图像,自动将map索引彩色图像转换为double类型的[0,1]区间内

其他类型图像间文档

imshow 显示图像

显示图像

imshow(I)

[A,map]=imshow('1.jpg')
A为索引图,uint8类型,map为阈值关联的彩色图,颜色图的数值范围为[0,1]且为double类型

imshow(I,[low high]) (等价于语法imshow(I,'DisplayRange',[low high]) )
小于low的值显示为黑色,大于high的值显示为白色,范围内的灰度值不变,

imshow(I,[]) low=min(I(:)) high=max(I(:))
imshow(I)  没有指定显示范围,则根据读入的数据类型,确定显示范围 uint8最大显示范围为[0,255],single和double[0,1]z

注意:输入类型为single和double类型的数据,范围必须在[0,1],数值超出范围需要进行缩放处理
其他见文档

当数据元素超出显示范围时,即正负均存在时,负数变为0,正数变为1

imtool 用窗口显示图像

在图像工具浏览器中显示图像

imtool('1.jpg') 直接读取图像,图像不会被存储到工作空间中

I=imread('1.jpg')
imtool(I) 读取图像,该图像先被存储到工作空间中
多帧图像智慧读取第一帧

imtool(I,'IntialMagnification','adaptive') 按图像原始大小显示,若尺寸过大,则适应屏幕
'IntialMagnification'-'fit' 缩放图像适应显示窗口
'IntialMagnification'-具体数字,但图像大小的具体数字%显示图像,100表示原始显示,屏幕一个像素对应图像一个像素

imtool close all 关闭所有显示图像

imtool可以全景查看图像(当图像过大时)
可以查看特定区域像素,
可以查看图像信息=imfinfo

image 矩阵显示图像

将矩阵元素值映射为颜色

image(C) C为数组或矩阵
会将数组 C 中的数据显示为图像。C 的每个元素指定图像的 1 个像素的颜色。生成的图像是一个 m×n 像素网格,其中 m 和 n 分别是 C 中的行数和列数。这些元素的行索引和列索引确定了对应像素的中心(相当于处于空间坐标系下)

image(x,y,C) 相当于改变的是图像坐标的位置,相当于平移操作,改变C(1,1)的位置
注意:空间坐标系是连续的,xy的值是整数,定义的是图像像素的中心位置(索引位置)
imshow(X,map)
等价于
image(X);colormap(map);

其他控制与解释没看,见文档

imagesec 待补充

colorbar 显示彩色条

显示色阶的颜色栏

colorbar 在当前坐标区或图的右侧显示一个垂直栏,颜色栏显示当前颜色图,并指示数据值(具体数值)到颜色图的映射(不同颜色显示不同的值)

colorbar(location) 改变颜色栏位置,不是所有图都能更改 localtion为不同的字段值
colorbar(target,location) 在指定特定坐标区或图显示颜色栏
c=coloorbar() 创建句柄c,用于后续改变属性值
colorbar('off') 关闭所有颜色栏 colorbar(target,'关闭指定目标的颜色栏')

对颜色栏可改变名称、数值等
改变属性见文档

montage

zoom

warp

subimage

impixel 显示像素信息

返回选中像素和像素集的数据值,可以将像素坐标值作为输入或者是用鼠标选中像素

P=impixel(I) 交互式显示像素的信息,鼠标选择后显示像素信息

[X,map]=imread('peppers.png');
p=impixel(X,map) 返回map中的值

p=impixel(I,c,r) c、r为行值和列值,返回指定位置的像素值
p=impixel(I,map,c,r) 同理

[c,r,p]=impixel()出了颜色(灰度)像素值外,还显示输出对应的坐标值

impixelinfo 显示像素信息

在当前窗口显示像素信息,对光标自动改变,位置默认为像素的左下角

impixelinfo 创建一个显示工具,包含坐标和像素值
impixelinfo(h) 句柄h指定窗口,可以是一个图像、一个轴等

set(hp,'Position',[5 1 300 20]); 改变显示信息的位置
impixellinfoval 不显示前缀

imwrite 保存图像

保存图像

imwrite(I,'pout.png')

具体类型见文档

imfinfo 显示内存信息

显示图像信息

info=imfinfo('filename.type') %包括路径等信息 注意不能是图像变量名
info返回的是一个结构体,其中包括多个成员,如果filename包含多个图像,则info返回的是一个结构体数组info(3)定位到结构体数组中的某个图像的结构

mat2gray 矩阵灰度化

将矩阵转换为灰度图像

I=mat2gray(A,[amin amax])
将A矩阵中[amin amax]范围内的值,标定到[0 1]区间,返回I,是double类型

I=mat2gray(A)
默认[amin amax]为矩阵的最大值和最小值,标定到[0,1]区间,返回double类型

rgb2gray 彩色灰度化

将RGB真彩色图像灰度化,将彩色图(索引)灰度化

gray_image=rgb2gray(rgb) 
返回uint8类型

[X,map]=imread('1.jpg')
newmap=rgb2gray(map) map是double类型,则newmap也是double类型,只不过每行RGB[0,1]的范围内的值都相同
imshow(X,map)

算法见文档

im2uint8 转换为8位

将灰度图、RGB、二值图转换为uint8,
如果输入是logic,则将整数1变换为255
官网文档的注意事项
注意:如果是double和single图像,则输入范围必须是[0,1],否则需要利用rescale函数重新缩放到[0,1]

im2double 转换为双精度

将图像转换为双精度

I=im2double(I) I可以是灰度图像、真彩色图像、二值图像,注意im2double会将范围值缩放到[0,1]区间

如果输入是double、single、logical则输出的像素值与输入相同,即255还是255.0,
如果是uint8类型的数据,变成double的同时会被标定到[0,1]区间

如果函数要求double像素值在[0,1]区间,那么对输入是double类型利用Im2double1后,再使用rescale函数将像素值缩放到[0,1]区间上

属于对索引图像的区别,加偏移量1,(与颜色图有关)见文档

VideoReader 读取视频文件

读取视频文件

v=VideoReader('1.mp4') v是一个结构体,包含视频的信息

v.属性名可返回多个属性信息
像素位数、设定从哪读取的时间戳、文件长度、帧率、高、宽、文件名
帧数、路径...

mmfileinfo 多媒体文件信息

info=mmfileinfo('1.mp4')
info是一个结构体,返回基本信息(文件名、路径、长度(秒)、Audio音频结构体,vidoe视频结构体)
video=info.video 包括(该文件的格式、宽、高)

readFrame 读取视频帧数据

最好不要使用 VideoReader.read函数

v=VideoReader('1.mp4')
while hasFrame(v) %hasFrame判断是否可读取该帧,返回逻辑值
	video=readFrame(v); 读取每一帧的数据
end

hasFrame 判断读取成功

movie 播放视频

有问题

movie(M),在当前坐标区播放矩阵M的影片,值播放一次,如果要在当前图窗中播放影片,则movie(gcf,M) M必须是影片帧数组

Movie(M,n) 影片播放n次,n可以是数组向量,n=[10 4 4 2 1]播放10次,播放顺序为第4帧、第4..

Movie(M,n,fps) fps设置帧率,默认12

Movie(M,n,fps,loc) 指定影片帧的位置

注意要调整图窗的尺寸的大小
movie值接受8位图像帧,不接受16为灰度和24为真彩色(那么只能是8位伪彩色图像)

getframe 捕获坐标区或图像作为影片帧

捕获坐标区或图像作为影片帧

F=getframe 
捕获显示在屏幕上的当前坐标区作为影片帧。F 是一个包含图像数据的结构体。getframe 按照屏幕上显示的大小捕获这些坐标区。它并不捕获坐标区轮廓外部的刻度标签或其他内容。

见文档

显示得到的影片帧
imshow(F.cdata)

捕获特定坐标区内容
F=grtframe(ax)
ax2 = subplot(2,1,1);
F = getframe(ax2);
imshow(F.cdata)

捕获图窗
F=getframe(fig);imshow(F.cdata) fig表示图窗
当捕获的是图窗内容是,即表示截取的图像窗口的所有内容F=getframe(gcf) 

捕获特定位置
F=getframe(_,rect) rect=[left bottom width height]

immovie

imiplay

imbinarize 灰度二值化

将灰度图像转换为二值图像
如果是其他类型的图像都要转换成灰度图像
输入图像最好为single或double类型[0,1]区间内的元素值,其他类型应该也可以
输出图像为Logic图像

BW=imbinarize(I) 
默认使用otsu算法 官方文当有算法

BW=imbinarize(I,method) 
使用global或adaptive的方法
默认为global方法(即otsu方法)(otsuthresh函数和graythresh函数)
adapitive表示局部自适应阈值方法(adaptthresh函数)官方文档有算法

BW=imbinarize(I,T)
T为全局阈值或局部自适应阈值,
如果T为标量,则将T作为全局阈值,利用otsuthresh函数和graythresh函数计算全局图像阈值
如果T为数值矩阵,则将T作为局部自适应阈值,利用adaptthresh函数计算局部自适应阈值
相当于上述method利用的是函数的默认值,T为特定计算值

BW=imbinarize(I,'adaptive',Nanme,Value)
控制自适应阈值方法
见官方文档

imadjust 调整灰度或颜色图

J = imadjust(I)
将灰度图像 I 中的强度值映射到 J 中的新值。默认情况下,imadjust 对所有像素值中最低的 1% 和最高的 1% 进行饱和处理。此运算可提高输出图像 J 的对比度

J = imadjust(I,[low_in high_in]) 将I中[low_in high_in]的值映射到[0,1]
J = imadjust(I,[low_in high_in],[low_out high_out]) 将I中[low_in high_in]的值映射到[low_out high_out]
J = imadjust(I,[low_in high_in],[low_out high_out],gamma)
gamma控制I与J的输出关系(控制关系曲线形状),gamma小于1变亮,gamma大于1变暗,等于1线性输出

J = imadjust(RGB,[low_in high_in],___) 将真彩色图像 RGB 中的值映射到 J 中的新值。您可以为每个颜色通道应用相同的映射或互不相同的映射。
newmap = imadjust(cmap,[low_in high_in],___) 将颜色图 cmap 中的值映射到 newmap 中的新值。您可以为每个颜色通道应用相同的映射或互不相同的映射。

输入是灰度图像或者是RGB图像,注意输入的限制[0,1],见文档

分段线性变换

输入图像灰度所在区间[0,a],[a,b],[b,L]
输入目标图像对应区间[0,c],[c,d],[d,L]
c a ⋅ f \frac{c}{a}·f acf ( 0 < f < a ) (0(0<f<a)

d − c b − a ( f − a ) + c \frac{d-c}{b-a}(f-a)+c badc(fa)+c ( a < f < b ) (a(a<f<b)

L − d L − b ( f − b ) + d \frac{L-d}{L-b}(f-b)+d LbLd(fb)+d ( b < f < L ) (b(b<f<L)

对数变换

l o g ( 1 + f ) b \frac{log(1+f)}{b} blog(1+f)

stretchlim 对比度计算 待补充

对比度拉伸

lowhigh=stretchlim(I) 计算上下限,上下限为图像像素值的上1%和下%,返回两个值[0.01 0.99]
J=imadjust(I,stretchlim(I),[]);

lowhigh=stretchlim(I,Tol) 没懂

对数函数-没懂

与gamma曲线相比,gamma曲线是可以变的,对数函数的形状就是一个函数是不可以变的

对比度拉伸函数(公式)-没懂

输入图像f,输出图像g
g=1./(1+(m./f).^E)
E是控制该函数的斜率,g的范围不能超过[0,1]

imadd 叠加图像

叠加两幅图像,或将标量加到图像上
数据溢出会圆整(截断)

I=imadd(x,y)
I=imadd(x,y,'uint16') 指定数据类型,避免数据溢出
I=imadd(x,50) 如果是标量则为double类型

imnoise 添加噪声

J=imnoise(I,'method')
高斯噪声、泊松噪声、椒盐噪声、乘性噪声、

输入类型和算法见文档

imsubstrcat 减去图像

减去图像或常量

I=imsubstract(x,y) 表示X-Y 注意数据溢出会圆整
实际上就是I=X-Y

imabsdiff 两图像的绝对差

Z=imabsdiff(X,Y)

immultiple 两图像相乘

相当于矩阵 .乘
可以是矩阵或者是常量

imdivide 两图像相除

imcomplement 图像反转

输入可以是灰度、二值、RGB

J=imcomplement(I)

imlincomb 图像线性组合

相当于矩阵的线性加权

Z = imlincomb(K1,A1,K2,A2,...,Kn,An)
Z = imlincomb(K1,A1,K2,A2,...,Kn,An,K) 最后会增加偏移量k
Z = imlincomb(_,classtype) 定义输出的数据类型

系数为double类型 矩阵类型不限,注意数据溢出

imresize 调整图像大小

B=imresize(A,scale)
将A的长宽缩放scale倍
A可以是灰度、RGB、二值图像
(如果A有两个维度以上,只调整前两个维度)默认使用双三次插值

B=imresize(A,[numrows numcols]) 将A缩放到确定的行数或列数

[Y,newmap]=imresize(x,map,scale) 将索引图像缩放到新的索引图像,newmap是自动优化后的颜色图

[]=imresize(_,method) 
使用最近邻插值(输出像素就是输入点所在像素的值)、双线性插值(输出像素是最近2X2邻域中像素的加权平均值)、双三次插值(是4X4像素的加权平均值)还可以指定插值核(见文档)(利用元胞数组定义插值核)

其他属性控制见文档

rescale 缩放标定元素值

B=rescale(A) 将元素值缩放到[0,1]之间
B=rescale(A,l,u) 将元素值缩放到区间[l,u]

公式见文档

imrotate 旋转图像

J=imrotate(I,angle) 以中点为中心,angle大于0逆时针,小于0顺时针,默认为最近邻插值方法
J=imrotate(I,angle,method) 指定插值方法,最近邻、双线性插值、双三次插值
J=imrotate(I,angle,method,bbox) 输出图像的大小,crop与原图大小相同,会裁切,loose自适应全包含输出图像 

imcrop 裁剪图像-??返回的坐标位置

J=imcrop 创建一个交互式工具,
J=imcrop(I) 对图像I创建交互式工具
Xout=imcrop(X,cmap) 对索引图像创建交互式工具

J=imcrop(I,rect) rect是一个向量,定义裁切的位置、长宽,注意(文档)返回的像素数

centerCropWindow2d 创建矩形中心裁切窗口-没看完

win=centerCropWindow2d(inputsize,tragetsize)

rectangle 画尖角圆角矩形

rectangle('Position',pos) pos=[x y w h] 指定位置和大小 x,y为左下角矩阵的位置
rectangle('Position',pos,'Curvature',cur) cur为边添加曲率,沿水平边和垂直边使用不同的曲率,0为无曲率、1为最大曲率
水平曲率为沿上下边缘的宽度的比率,(沿上下边缘进行弯曲)
垂直曲率为沿左右边缘的宽度的比率,(沿左右边缘进行弯曲)

imtranslate 平移图像

B = imtranslate(A,translation) translation定义平移的向量,

属性控制
OutputView 展示全部转换后图像或窗口与原始图像大小一样
外部像素的控制,见文档

affine2d 二维仿射几何变换

创建affine2d对象

待补充

imregtform — Estimates a geometric transformation that maps a moving image to a fixed image using similarity optimization

imregcorr — Estimates a geometric transformation that maps a moving image to a fixed image using phase correlation

fitgeotrans — Estimates a geometric transformation that maps pairs of control points between two images

randomAffine2d — Creates a randomized 2-D affine transformation

利用函数创建affine2d对象

tform=affine2d 默认设置,全等变换
toform=affine2d(A) 由非奇异矩阵A定义的有效仿射变换

tform对象有输定Dimesnsionality 此时为2
tform对象有属性T,成员T是一个矩阵就是A定义的
T 为正仿射变换,由一个非奇异的3X3的数值矩阵定义
引用T tform.T
矩阵转换定义为:[x y 1]= [u v 1] * T ; T=[a b 0; c d 0; e f 1] 默认情况下T是一个恒等变换 数值元素为single或double**
书本中常见的形式是[ x y 1]’=T’ * [u v 1]’
注意: 从公式来看T矩阵中表示平移的向量不在右上角,而是在左下角(e f 1)从下面的公式中也可以看出这一点

invert 逆几何变换

可以应用于 tform 对象

invtform=invert(tform) 返回几何变换tform的逆

先定义一个tform对象
invtform = invert(tform);
invtform.T

isrigid 判断是否刚性变换

可以应用于 tform 对象


TF=isrigid(tform) 判断这个仿射变换是否为刚性变换

A = [ 1  0  0
      0  1  0
     40 40  1 ];
tform = affine2d(A)
tf=isrigid(tform) 逻辑判断

true为刚性,反之为非刚性
刚性变换:只包括旋转和平移,不包括仿射,即不包含形状和尺寸上的改变

isSimilarity 判断是否相似变换

可以应用于 tform 对象

TF=isSimilarity(tform) 判断这个仿射变换是否为相似变换

true为相似,反之为不详细
相似变换:旋转、平移、各向同性缩放、反射变换(好像是对称变换),不改变形状,即直线保持直线,平行保持平行
注意:有的函数支持反射、有的函数不支持反射

isTranslation 判断是否纯平移

可以应用于 tform 对象

tf=isTranslation(tform)

纯平移矩阵的定义:

[1 0 0;
  0 1 0;
  e f 1];

outputLimits 待补充

transformPointsForward 前向几何变换-待补充

先定义一个tform转换矩阵

[x,y] = transformPointsForward(tform,u,v) 应用于2D坐标 
[x,y,z] = transformPointsForward(tform,u,v,w) 应用于3D坐标 
X = transformPointsForward(tform,U) U为坐标矩阵

transformPointsInverse -待补充

imwarp 图像几何变换

tform是前述定义的仿射变换对象

B=imwarp(A,tform) 根据几何变换tform变换A得到B,tform是一个几何变换对象

其他语法形式待补充,见文档
算法
仿射变换输出图像的像素值由逆映射得到,即现将输出图像的坐标映射到输入图像对应的坐标,然后在输入图像坐标处应用插值计算像素值,最终作为输入像素的像素值
算法图解见文档

nlfilter 滑动邻域操作

处理时间过长,可用colfilt代替
通过定义fun可以实现滤波等行为,与直接内部函数效果相同

B = nlfilter(A,[m n],fun) 对A中每个mXn的滑动领域块应用函数fun,可以是向量平均值mean、矩阵平均值mean2、方向向量std、矩阵方差std2,向量最小值min,最大值max、方差var,或者是自定义的函数
注意fun的输入必须可以是矩阵,并输出一个标量值作为像素元素

B = nlfilter(A,'indexed',___) 将A作为索引图像,如果A是uint8、16、logical用0填充,否则用1填充

必要的的时候fun用0填充邻域边缘,可以看出输出的图像尺寸不会减小

colfilt 列方向邻域操作/非线性滤波 待补充

注意要先填充图像,不会自动填充

B = colfilt(A,[m n],block_type,fun)
将A中的每个m·n块重新按列排成一个临时矩阵,并应用函数fun对矩阵进行操作,必要时利用0进行填充

B = colfilt(A,[m n],[mblock nblock],block_type,fun)
先将图像A分成mblockXnblock个子块,在进行操作
**这个函数没懂**

B = colfilt(A,'indexed',___) 对索引图像进行处理

colfilt处理图像依赖block_type的控制

块(滤波器处理模式)
与im2col介绍的相似

distinct 首先利用im2col函数,再利用fun函数,最后利用col2im函数

sliding 像素滑动,首先利用im2col函数,然后利用fun函数,最后利用reshape函数

im2col 重排矩阵加速块处理

将图像块重列排列为列向量

B = im2col(A,[m n],'distinct')
对于每一个m·n的块,将块对应的邻域中的像素按列组成一个列向量,然后将所有的块形成的列向量组成一个由多列组成的矩阵,
这个矩阵中的列的顺序,对应于块的遍历方式
就是块按矩阵的列进行遍历, if A consists of distinct blocks Aij arranged as A = [A11 A12; A21 A22], then B = [A11(:) A21(:) A12(:) A22(:)]
注意必要的时候要填充图像
注意这个是对离散的块进行排列,块与块之间不重叠

B = im2col(A,[m n],'sliding')
以逐像素的方式进行排列,块与块之间有重列,块与块滑动是按列滑动整个矩阵,而块内邻域像素也是按列排成一个列向量,最终将每个块形成的列向量组成一个矩阵
B = im2col(A,[m n]) 等价于B = im2col(A,[m n],'sliding')

B = im2col(A,'indexed',___) 对索引图像进行操作

返回的B矩阵的形式

返回的B矩阵的行数为m*n,因为一个块所在的邻域对应一个列向量,所以行数是邻域块的像素数
对于distinct处理, if the size of A is [mm nn], then B has (mm/m)*(nn/n) columns.可以看出是离散互不重叠的邻域块进行操作
对于sliding,if the size of A is [mm nn], then B has ((mm-m+1)*(nn-n+1)) columns.

mm-m+1这个公式很重要

col2im im2col的逆-待补充

将列矩阵重排成块

A = col2im(B,[m n],[M N]) 等价于A = col2im(B,[m n],[M N],'sliding')
A = col2im(B,[m n],[M N],'sliding')

A = col2im(B,[m n],[M N],'distinct')

blockproc 非重复块处理 待补充

B = blockproc(A,[m n],fun)

B = blockproc(src_filename,[m n],fun)
B = blockproc(adapter,[m n],fun)
blockproc(___,Name,Value)

block_struct 块结构体 待补充

block_struct.border 返回[v h]向量,指定数据块周围垂直和水平填充的大小
block_struct.blockSize 返回[rows cols]向量,指定块数据的大小,如果指定了边框,大小不包含边框像素
block_struct.data 块数据的m·n或m·n·p矩阵

padarray 填充图像(矩阵)

B = padarray(A,padsize)
默认在每维度的第一元素之前和最后元素之后填充 padsize为一个数值向量[m n],定义每个维度增加的数量

B = padarray(A,padsize,padval) 
padval 填充的方式 填充方式可见imfilter的shape选项,默认用0填充

B = padarray(___,direction) 

控制方向

pre 每一维度第一个像素前
post 每一维度最后一个元素后
both 每一维度最后一个每一维度的第一个像素前和最后一个元素后

roipoly 指定多边形ROI

BW = roipoly 
创建一个交互式多边形工具,函数返回一个二值图像作为掩码,ROI区域内的像素为1,外部像素为0
BW = roipoly(I) I可以是灰度图像和RGB图像

BW = roipoly(I,r,c) r c为向量,表明顶点坐标向量组,注意是在空间坐标系下定义的
BW = roipoly(x,y,I,xi,yi) 利用X Y 向量定义非默认的空间坐标系,xi和yi是在新定义的空间坐标系下定义的顶点向量

[BW,xi2,yi2] = roipoly(___) BW返回一个二值掩码图像,并返回顶点坐标

输入可以是灰度和RGB图像,输出返回的是二值logical矩阵
注意该函数总是返回一个封闭的多边形,且无论输入的特定的顶点向量最后一个元素是否等于第一个元素
其他语法见文档

利用drawpolygon可以定义一个ROI区域
利用createMask(roi) 可以创建一个掩码区域,此时相当于创建了一个二值掩码图像

roicolor 基于颜色选择ROI

基于颜色范围选择ROI,相当于颜色阈值

BW = roicolor(I,low,high)
依赖范围[low high],返回的还是二值图像

BW = roicolor(I,v)
选择与向量V匹配的像素

输入是索引和灰度图像(文档没说有RGB图像)

ismember 待补充

createMask 创建二值掩码图像

根据ROI创建掩码,注意ROI和掩码图像不是一个概念

bw = createMask(ROI)
返回二值掩码图像,ROI中像素为1,外部为0

bw = createMask(ROI,m,n)
返回二值掩码图像,大小为[m,n]

bw = createMask(ROI,I)
返回的大小与输入图像I相同

h为创建的一个ROI
mask=createMask(h) 返回二值掩码图像

输入为ROI对象,

ROI 相关对象

AssistedFreehand
Freehand
Polyline
Circle
Line
Rectangle
Ellipse
Polygon
regionfill

regionfill 区域填充

利用内向插值实现区域填充

J = regionfill(I,mask)
填充由掩码定义的图像,非零像素被填充
利用该函数可以剔除图像中的对象,或者利用邻域像素替换无效的像素值
注意填充的时候利用的是邻域的像素值,然后填充的算法是向内插值
I为输入原始图像

J = regionfill(I,x,y)
填充由xy定义的顶点的多边形,然后如上述一样,利用邻域像素填充图像,I为输入原始图像

输入是灰度图像,文档没说有RGB图像
返回的输出图像也是灰度图像,与原始类型想同

可以交互式的创建多边形ROI见文档
求内插的算法写的比较简洁,没看懂

roifilt2 ROI区域滤波

仅对ROI区域进行滤波

J = roifilt2(h,I,BW)
利用2D线性滤波h,处理图像I中的ROI,BW是一个二值掩码图像,大小与I相同,返回的是具有局部滤波的值
J = roifilt2(I,BW,fun) 利用函数fun来处理函数,fun必须是一个函数句柄

imhist 图像直方图

[counts,binLocations] = imhist(I)
I为灰度图像,counts
默认区间有256[counts,binLocations] = imhist(I,n) n定义区间数量,用来计算直方图
counts和binLocations返回的都是等长度的向量,binLocations表示区间的位置,counts表示对应区间上的值
[counts,binLocations] = imhist(X,map) 为索引图像计算直方图

输入是灰度图像或二值图像(默认有两个区间),文档中没有RGB图像,
但是好像可以读RGB图像
注意不同类型图片的存储格式,不是随便存储的,有些函数只针对特定的存储形式的图像
算法-没看懂

stem 待补充

histeq 直方图均衡化规定化 算法没懂 待补充

用来扩大动态范围,增强对比度
通过灰度级的该链表密度函数来求出灰度变换函数,是一种以累积分布函数变化法为基础的直方图修正法
求出待处理直方图;利用累积分布函数对原图像的统计直方图做变换,得到新的图像灰度;近似处理,将新灰度代替旧灰度,同时将灰度值相等或近似的每个灰度直方图合并到一起

概率、概率密度、概率分布(累积分布函数)https://www.jianshu.com/p/0cfc3204af77
直方图均衡化https://blog.csdn.net/schwein_van/article/details/84336633
直方图规定化https://www.jianshu.com/p/b9f29f78786b?from=timeline&isappinstalled=0

J = histeq(I,hgram)
J = histeq(I,n) 输出的图像具有n个灰度级
[J,T] = histeq(I)

mean2 计算矩阵均值

返回的是标量

std2 计算矩阵标准差

返回标量

std 计算向量标准差

S = std(A) A为向量,返回标量;A为矩阵,则按列计算标准差,返回行向量
S = std(A,w) 指定归一化的方式
S = std(A,w,'all') 计算所有元素的标准差,返回的是标量
S = std(A,w,dim) 指定计算标准差的维度

权重是什么意思,其他语法没看懂

corr2 二维相关系数

返回的是标量

R=corr2(A,B)

MATLAB 图像处理_第2张图片

corr 线性或秩相关性 没懂

rho = corr(X)
返回输入矩阵 X 中各列之间的两两线性相关系数矩阵。
rho = corr(X,Y)
返回输入矩阵 X 和 Y 中各列之间的两两相关系数矩阵。
[rho,pval] = corr(X,Y)
[rho,pval] = corr(___,Name,Value)

fspecial 创建预定义的二维滤波器

h = fspecial(type)
h = fspecial('average',hsize) 平均值滤波器,大小hsize 默认3·3
h = fspecial('disk',radius) 圆形平均值滤波器,半径为r,包含在大小2*radius+1的方形中

不建议使用,见imagaussfilt,imagaussfilt3
h = fspecial('gaussian',hsize,sigma) 旋转对称高斯低通滤波器,标准差为sigma

h = fspecial('laplacian',alpha)
返回逼近二维拉普拉斯算子形状的 3×3 滤波器,alpha 控制拉普拉斯算子的形状,[0,1]范围内,默认为0.2

h = fspecial('log',hsize,sigma)
大小为 hsize 的旋转对称高斯拉普拉斯滤波器,标准差为 sigma

h = fspecial('motion',len,theta) 没懂
运动滤波器
 返回与图像卷积后逼近照相机线性运动的滤波器。len 指定运动的长度,theta 以逆时针方向度数指定运动的角度。滤波器成为一个水平和垂直运动的向量。默认 len 是 9,默认 theta 是 0,对应于 9 个像素的水平运动
输出一个滤波器来近似计算len个像素的线性运动,类似于相机与景物的关系
 
h = fspecial('prewitt')
返回一个 3×3 滤波器,该滤波器通过逼近垂直梯度来强调水平边缘。要强调垂直边缘,请转置滤波器 h'

h = fspecial('sobel')
返回一个 3×3 滤波器,该滤波器通过逼近垂直梯度来使用平滑效应强调水平边缘。要强调垂直边缘,请转置滤波器 h'

算法见《书》

imfilter 图像滤波

B = imfilter(A,h) h为滤波器
B = imfilter(A,h,options,...) 控制选项

控制滤波

corr 相关处理
conv 卷积处理,卷积处理是将模板旋转180°,然后对图像做相关操作

控制边界填充的类型

标量x 使用数值x对边界进行填充,默认使用0填充
symmetric 利用边界镜像反射进行填充
replicate 复制图像边界外的值进行填充,假设与最近的边界值相等
circular 将图像当做一个二维周期函数的一个周期来扩展

输出大小的控制

same 表示与输入大小相同,函数默认为same
full 输出为填充后的尺寸,主义一维和二维不太一样

注意默认情况下使用的是相关核而不是卷积核,可以定义参数使用卷积核
注意做相关操作时,相关的顺序影响输出的结果,而卷积的顺序不影响输出的结果;
如果滤波器模板为对称矩阵,则卷积与相关操作相同
注意偶数卷积核的定义,见文档
注意输入的元素类型,整数还是浮点

conv2 二维卷积

C = conv2(A,B) 返回矩阵 A 和 B 的二维卷积

与sobel有关,待补充
C = conv2(u,v,A) 首先求 A 的各列与向量 u 的卷积,然后求每行结果与向量 v 的卷积

C = conv2(___,shape) 根据 shape 返回卷积的子区
控制输出
full 为全填充
same 与输入大小相同
valid 返回计算的没有补零边缘的卷积部分,大小尺寸小于输入

文档的公式还得看

filter2 二维数字滤波器

Y = filter2(H,X) 相当于H是滤波器
根据矩阵 H 中的系数,对数据矩阵 X 应用有限脉冲响应滤波器
Y = filter2(H,X,shape) 等价于conv2(X,rot90(H,2),shape)
根据 shape 返回滤波数据的子区 

控制输出

full 为全填充
same 与输入大小相同
valid 返回计算的没有补零边缘的卷积部分,大小尺寸小于输入

medfilt2 中值滤波

J = medfilt2(I) 默认3·3邻域操作
J = medfilt2(I,[m n]) 定义m·n邻域
J = medfilt2(___,padopt) padopt控制填充,默认为0,symmetric镜像反射,indexed针对double类型为1,其他为0

输入是灰度图像或者是二值图像
注意事项没看,见文档

ordfilt2 排序滤波

B = ordfilt2(A,order,domain) 
order表示选择中的顺序,domain表示邻域,数值矩阵或逻辑矩阵,值为0,11表示邻域对应的元素被用来计算,0表示不进行运算
B = ordfilt2(A,order,domain,S) S增加的是偏移量
B = ordfilt2(___,padopt) padopt定义如何填充边界,默认为0,symmetric 表示镜像反射填充

注意事项没看,见文档

wiener2 二维自适应滤波 待补充

fft 快速傅里叶变换 待补充

fft2 二维快速傅里叶变换

Y = fft2(X) 输出大小与输入相同
等价于fft(fft(x).') .'表示非共轭原值

Y = fft2(X,m,n)
使用傅里叶变换滤波时,需要对输入数据进行填充,截断X或对输入图像填充所需的0,使结果大小为M·N

注意返回的傅里叶数值有正有负

获得傅里叶频谱

abs(fft(x))

移频,注意应该是fftshift(fft2(f))
而不是fft2(fftshift(f))

傅里叶变换看《书》,《matlab版》不详细

nextpow2 用于填充fft 待补充

fftshift 将零频分量移到频谱中心

Y = fftshift(X) 将零频分量移动到数组中心,重新排列傅里叶变换X
如果 X 是向量,则 fftshift 会将 X 的左右两半部分进行交换。
如果 X 是矩阵,则 fftshift 会将 X 的第一象限与第三象限交换,将第二象限与第四象限交换。
如果 X 是多维数组,则 fftshift 会沿每个维度交换 X 的半空间。

Y = fftshift(X,dim) 指定维度

例子还没看

ifftshift 逆零频平移

将fftshift零频平移的结果重新排列回原始变换输出的样子

stem 绘制离散序列数据

stem(Y)
沿X轴,并垂直于X轴绘制Y,绘制针状图,
Y为矩阵则按每一列为一组输出值Y,在相同的X轴刻度上进行绘制
stem(X,Y)
在 X 指定的值的位置绘制数据序列 Y。X 和 Y 输入必须是大小相同的向量或矩阵。另外,X 可以是行或列向量,Y 必须是包含 length(X) 行的矩阵

stem(___,'filled') 表示填充圆形
stem(___,LineSpec) 控制线型
stem(___,Name,Value) 其他控制见文档

atan 反正切

atan 以弧度为单位
atand 以度为单位

Y = atan(X) X为实数时,返回范围在[-pi/2,pi/2]之间

atan2 四象限反正切

P = atan2(Y,X) 注意参数的顺序,Y是虚部,X是实部

imag 取复数的虚部

real 取复数实部

angle 相位角

theta = angle(z) 直接返回角度

ifft2 二维快速傅里叶逆变换

X = ifft2(Y)
X = ifft2(Y,m,n)
X = ifft2(___,symflag)

imapprox 近似索引图

通过减少颜色数量近似处理索引图像
用具有较少颜色的映射来近似一个索引映射

[Y,newmap] = imapprox(X,map,Q)
限定newmap具有Q种颜色,用来近似表示索引X及其关联的map,Y为返回的近似的索引图像

其他函数与算法见文档和rgb2ind

rgb2ind 将RGB转换为索引图像

[X,cmap] = rgb2ind(RGB,Q) 
使用具有 Q 种量化颜色的最小方差量化法并加入抖动,将 RGB 图像转换为索引图像 X,关联颜色图为 cmap,即指定输出索引图像具有Q个颜色

[X,cmap] = rgb2ind(RGB,tol)
使用均匀量化法并加入抖动,将 RGB 图像转换为索引图像,容差为 tol

X = rgb2ind(RGB,inmap)
使用逆颜色图算法并加入抖动,将 RGB 图像转换为索引图像,指定的颜色图为 inmap

___ = rgb2ind(___,dithering)  启用或禁用抖动;抖动以损失空间分辨率为代价来提高颜色分辨率

算法见文档:对RGB立方体进行修改,逆颜色图法,没懂

dither 转换图像,抖动

转换图像,通过抖动提高表观颜色分辨率
https://blog.csdn.net/wzz110011/article/details/78170516

X = dither(RGB,map)
X = dither(RGB,map,Qm,Qe)
BW = dither(I) 
通过抖动将灰度图像 I 转换为二值(黑白)图像 BW,返回的是二值图像
虽然显示的是二值图像,但是由于抖动,图像近似呈现不同的灰度级

grayslice 灰度图转换为索引图

利用阈值处理,对灰度图像处理输出索引图像
算法见文档

X = grayslice(I,N),N为指定算法的数量,相当于阈值后重新分成了N个灰度级别
X = grayslice(I,thresholds) 这个函数没懂

gray 灰度颜色数组

c = gray
以三列数组形式返回 gray 颜色图,其中包含的行数与当前图窗的颜色图相同。如果不存在图窗,则行数等于默认长度 256。数组中的每一行包含一种特定颜色的红、绿、蓝强度。强度介于 [0,1] 范围内

c = gray(m) 返回包含 m 种颜色的颜色图

flip 翻转元素顺序

B = flip(A)
A为矩阵,按列翻转;A为向量,沿向量长度翻转
B = flip(A,dim) 按不同维度进行翻转

按第三个维度,则全翻转(见文档例子)

flipud 将数组上下翻转

B = flipud(A)
A为列向量则颠倒顺序,A为行向量则不变,A为矩阵则按列翻转,A为多维数组则独立翻转每一页

fliplr 将数组左右翻转

B = flipud(A)
A为行向量,则元素翻转;A为列向量,则不变,

gray2ind 灰度、二值转换为索引图

[X,cmap] = gray2ind(I,c) 设定输出索引图像对应的颜色图像具有c个颜色,省略c则默认有64个颜色
[X,cmap] = gray2ind(BW,c) 将二值图像转换为索引图像

ind2gray 索引转换为灰度图像

I = ind2gray(X,cmap)

算法没看

ind2rgb 索引图像转换为RGB图像

RGB = ind2rgb(X,map) 返回的是double类型的数据

颜色空间转换

见《书》和文档,转换函数这里不做说明
其实文档我也没看https://ww2.mathworks.cn/help/images/understanding-color-spaces-and-color-space-conversion.html

  • NTSC
    用于模拟电视,灰度和彩色数据分离

  • YCbCr
    用于数字视频

  • HSV
    更接近于人眼描述

  • CMY、CMYK
    用于打印设备

  • HSI
    最接近人眼解释
    注意内部函数中没有对应的转换

与设备无关的色彩空间-没看

edge 边缘检测

BW = edge(I) 
默认使用sobel边缘检测方法,返回的是二值图像

BW = edge(I,method) 指定使用的方法

BW = edge(I,method,threshold) 返回强度高于 threshold 的所有边缘。

BW = edge(I,method,threshold,direction)
 指定要检测的边缘的方向。Sobel 和 Prewitt 方法可以检测垂直方向和/或水平方向的边缘。Roberts 方法可以检测与水平方向成 45 度角和/135 度角的边缘。仅当 method 是 'Sobel''Prewitt''Roberts' 时,此语法才有效。
 方向:horizontal、vertical、both
 
BW = edge(___,'nothinning')  跳过边缘细化阶段,这可以提高性能。仅当 method 是 'Sobel''Prewitt''Roberts' 时,此语法才有效。

BW = edge(I,method,threshold,sigma) 
指定 sigma,即滤波器的标准差。仅当 method 是 'log''Canny' 时,此语法才有效。
log时,sigma默认为2,canny时,默认为sqrt(2),滤波器的大小函数自动和sigma计算
log先高斯平滑再拉普拉斯计算
canny算法见《书》

BW = edge(I,method,threshold,h)
使用 'zerocross' 方法和您指定的滤波器 h 检测边缘。仅当 method 是 'zerocross' 时,此语法才有效。与log的原理一样,就是滤波器的选择不一样

method

Sobel 利用sobel模板近似导数
Prewitt 利用prewitt模板近似导数
Roberts Roberts模板
log 利用高斯拉普拉斯模板(算子)进行滤波,通过寻找零交叉点检测边缘
zerocross 利用指定的滤波器,通过寻找零点进行检测
Canny 见文档
approxcanny 近似版canny

输入是灰度图像或二值图像,对approxcanny要将输入图像归一到[0,1]

hough 霍夫变换

[H,theta,rho] = hough(BW)
BW为二值图像,theta、rho为直线参数,H为返回的参数空间矩阵
注意输入为二值图像

[H,theta,rho] = hough(BW,Name,Value,...) 用于控制参数

算法见《书》、文档
霍夫变换矩阵-没太懂

houghpeaks 霍夫变换中的峰值

找到霍夫变换中的峰值,即累加器的高计数单元

peaks = houghpeaks(H,numpeaks) 
H为计算出的霍夫变换矩阵,numpeaks指定峰值的数量,peaks表示返回的峰值的行列坐标表示的矩阵

peaks = houghpeaks(H,numpeaks,Name,Value)

控制参数

Threshold 

你可能感兴趣的:(matlab)