《基于MATLABGUI的数字图像处理程序的设计说明.doc》由会员分享,可在线阅读,更多相关《基于MATLABGUI的数字图像处理程序的设计说明.doc(33页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、类别_ 编 号_数字电视系统设计课程项目报告基于MATLAB GUI的数字图像处理程序设计 院 别 技术学院 专 业 电子信息工程 班 级 10电信 姓 名 第二组 指导教师 何光威中国大学南广学院2013年 10月29日31 / 33摘 要基于数字信号处理原理,在数字滤波器设计理论和Matlab 编程技术与其GUI 图形用户界面设计的基础上,开发了具有交互式特点的数字图像处理GUI软件,界面操作简单方便。MATLAB既是一种直观、高效的计算机语言,同时又是一个科学计算平台。它为数据分析和数据可视化、算法和应用程序开发提供了最核心的数学和高级图形工具。根据它提供的500多个数学和工程函数,工程
2、技术人员和科学工作者可以在它的集成环境互或编程以完成各自的计算。MATLAB中集成了功能强大的图像处理工具箱。由于MATLAB语言的语法特征与C语言极为相似,而且更加简单、更加符合科技人员对数学表达式的书写格式,而且可移植性好、可扩展性强,再加上其中有丰富的图像处理函数,所以MATLAB在图像处理的应用中具有很大的优势。关键词:MatlabGUI;数字图像处理;图形用户界面目 录摘 要I一、设计基本原理2(一)、GUIDE 操作界面的使用方法2二、GUI程序总体设计3(一)MATLAB GUI程序要实现的功能:3三、具体设计与实现43.1、文件操作43.1.1、打开43.1.2、保存43.1.
3、3、退出43.2、编辑43.2.1、灰度43.2.2、亮度53.2.3、截图73.2.4、缩放73.3、旋转83.3.1、上下翻转83.3.2、左右翻转93.3.3、任意角度翻转93.4、加入噪声103.5、滤波103.6、直方图统计113.7、频谱分析123.7.1、频谱图123.7.2、通过高通滤波器133.7.3、通过低通滤波器133.8、灰度图像处理143.8.1、二值图像143.8.2、创建索引图像143.9、颜色模型转换153.10、操作界面设计15四、程序调试与结果分析16(一)在程序设计过程中遇到的问题16结 语17参考文献18附录19一、设计基本原理图形用于界面(GUI)是提
4、供人机交互的工具和方法。GUI 是包含图形对象(如窗口、图标、菜单和文本)的用户界面。MATLAB 的GUI 为开发者提供了一个不脱离MATLAB 的开发环境,有助于MATLAB 程序的GUI 集成。在MATLAB 中的GUIDE 就是图形用户 界面开发环境(Graphical User Interface Development Environment),它向用户提供了一系列的创建用户图形界面的工具。这些工具大大简化了GUI 设计和生成的过程。(一)、GUIDE 操作界面的使用方法 下面对GUIDE 的操作界面与使用方法做一简单介绍。 在命令窗口中直接键入guide, 启动GUIDE, 利用
5、GUIDE 模板创建GUI,或者打开已经存在的GUI, GUIDE 把GUI 设计的容保存在两个文件中,它们在第一次保存或运行时生成。一个是FIG 文件,扩展名为Fig,它包含对GUI 和GUI 组件的完整描述;另外一个是M 文件,扩展名为.M,它包含控制GUI 的代码和组件的回调事件代码。这两个文件与GUI 显示和编程任务相对应。在版面设计器中创建GUI 时, 容保存在FIG 文件中;对GUI 编程时,容保存在M 文件中。用GUIDE 版面设计器,根据设计需要:首先拖拽两个图形窗口(Axes),一个作为待处理图片区域,另一个作为已处理图片区域;其次,拖拽五个电子按钮(Radio Button
6、),作为边缘检测操作按钮;第三,拖拽五个按钮(Push Button),作为输入等的按钮;最后,将上面的所有按钮与图形窗口合理的布局,达到美观工整的效果,然后运行一下GUI,系统会自动生成GUI 文件。信息化社会中,计算机在各种信息处理中发挥着重要的作用。我们可以借助计算机,对数字图像进行处理,以达到不同的效果。根据题目的要求,除了实现要求的功能外,还有很多的功能需要用到。(1)、将一个RGB图像转换为灰度图像。(2)、可以对图像做各种变换,如旋转等。(3)、有时并不需要图像显示其细节部分,只要其轮廓,这时候不要很高的灰度级。可以把图像转换为二值图像,进行图像腐蚀,或是创建索引图像等。(4)、
7、分析一个图像的频谱特征,利用傅里叶变换,将图像从空间域变换到频域,然后进行各种处理,经过高通滤波器或是低通滤波器。(5)、为了科学地定量描述和使用颜色,人们提出了各种颜色模型,按用途可分为三类:计算颜色模型,视觉颜色模型和工业颜色模型。有时为了不同的需要,要对颜色模型进行转换。二、GUI程序总体设计(一)MATLAB GUI程序要实现的功能:将一个RGB图像转换为灰度图像。可以对图像做各种变换,如旋转等。可以对图像进行任意的亮度和对比度调整,显示和对比变换前后的图像。通过最近邻插值和双线性插值算法,将用户所选取的图像区域,进行放大和缩小整数倍,并保存,比较几种插值的效果。对颜色模型进行转换。为
8、了科学地定量描述和使用颜色,人们提出了各种颜色模型,按用途可分为三类:计算颜色模型,视觉颜色模型和工业颜色模型。有时为了不同的需要,要对颜色模型进行转换。在调节亮度时,虽然可以用对话框的形式输入调节的比例系数,但是这样效果不好,不容易调节。因此这里考虑用滚动条来调节。总设计界面如上图所示。三、具体设计与实现3.1、文件操作3.1.1、打开为了让使用者更方便的使用,所以在设计的时候,通过对话框的形式来选择文件,选择uigetfile函数来实现,uigetfile函数显示一个打开文件对话框,该对话框自动列出当前路径下的目录和文件,由于这个GUI程序的操作对象是图像文件,所以设置这里的缺省后缀名为“
9、.bmp”。Uigetfile函数的调用格式为name,path=yigetfile(), 在按下对话框中的执行按钮“打开”后,返回选择的文件名和路径,分别保存到“name”和“path”中。如果按下取消按钮或是发生错误,则返回值是0。 根据返回值的情况,如果是0,则弹出提示错误的对话框,否则,通过imread函数读出图像数据,把图像数据赋值给全局变量handles.img。3.1.2、保存同样也通过对话框的形式来保存图像数据,通过uigetfile函数选择文件名和路径,用getimage(gca)取出坐标2变换后的图像数据保存到变量i,最后用imwrite函数,把数据i存到指定的文件。3.1
10、.3、退出退出比较简单,程序如下所示:clc;close all;close(gcf);3.2、编辑3.2.1、灰度由于RGB图像是三维图像,所以图像数据是一个三维数组,为了显示灰度图像,把三维图像降为二维,可以只取其中的二维数据,实现方法程序为:y=(handles.img(:,:,1);%当然也可以选择(:,:,2) 或(:,:,3)imshow(y);但是这样的话,根据程序所选的不同,图像数据也不同,显示也就不一样。另一种方法就是,运用rgb2gray函数实现彩色图像到灰度图像的转换。程序为:y=rgb2gray(handles.img); imshow(y);这个程序只能用于RGB图像
11、转换灰度图像,当原始图像本来就是灰度图像时,运行该程序时就会出错,但是使用者在使用时有时并不知道这些,为了使该程序更加完善,应该在使用者原先图像时灰度图像时使用该功能时,应该要显示提示类信息。所以在开始时应该要有一个RGB图像或是灰度图像的判断过程。完整的程序如下: if isrgb(handles.img) y=rgb2gray(handles.img);imshow(y);else msgbox(这已经是灰度图像,转换失败);end如果原图是RGB,执行该操作的结果如下图:如果原图本身已经是灰度图像了,执行该操作弹出如 右图所示的提示对话框3.2.2、亮度用imadjust函数,其调用格式
12、如下:g=imadust(f,low_in high_in,low_out high_out),gamma)gamma 表示映射性质,默认值是1 表示线性映射。由于该函数有五个参数需要输入,为了方便用户改变,所以这里设计一个输入对话框,用户通过对话框把五个参数赋值给low_in high_in,low_out high_out,gamma这五个参数,如下一组命令建立了如图所示的输入对话框:prompt=输入参数1,输入参数2,输入gamma;defans=0 0.7,0 1,1;p=inputdlg(prompt,输入参数,1,defans);但是,这种方法并不能很好的让用户能够对图像进行任意
13、的亮度和对比度变化调整,有时并不事先知道参数的值要多少,也不关心,而是任意调节的,直到满意为止。所以应该用滑动条来调节图像的亮度和对比度,这样更适合用户的使用习惯。由于imadjust函数有五个参数,所以原则上需要设计五个滑动条来调节对比度,这对用户来说显然比较麻烦,因此在设计的时候固定其中的三个参数,通过调节两个参数的值来改变亮度和对比度。0 handles.beta,0 1,handles.gm,这里的变量handles.beta和handles.gm就通过滑动条得到,滑动条设计如下图:亮度调整的tag名为ld,取值围01,gamma值的tag名为gamma,取值围为05。获取滑动条参数的
14、程序如下:handles.beta=get(handles.ld,value);handles.gm=get(handles.gamma,value);执行该操作,调节滑动条到上图所示位置,结果如下图:3.2.3、截图在MATLAB中,用函数imcrop实现对图像的剪切操作。该操作剪切的是图像中的一个矩形子图,用户可以通过参数指定这个矩形四个顶点的坐标,也可以交互地用鼠标选取这个矩形。Imcrop函数的调用格式如下:y=imcrop(handles.img);不管handles.img是三维的还是二维数据,该函数都能进行操作。下图就是对三维图像的截图:3.2.4、缩放在MATLAB中,用函数i
15、mresize来实现对图像的放大或缩小。插值方法可选用三种方法,最近邻插值,双线性插值,双三次插值。该函数的调用格式如下:Bimresize(A,m,method)其中:参数method用于指定插值的方法,可选的值为“nearest”(最近邻法),“bilinear”(双线性插值)、“bicubic”(双三次插值),缺省值为“nearest”。Bimresizee(Am,method)表示返回原图A的m倍放大图像(m小于1时实际上是缩小);下图就是采用邻近插值法的放大和缩小图像,参数值保持默认设置: 虽然处理后看不出放大的效果,这是由于坐标轴限制的原因,如果把处理后的图片保存起来,再把处理后的
16、文件打开,就可以看到比较明显的放大效果。 缩小后的结果如下:3.3、旋转3.3.1、上下翻转函数flipud是实现一个二维矩阵的上下翻转,如a=1 2;3 4,经过该函数处理后,原矩阵变为3 4;1 2;所以利用该函数也可以对图像进行上下翻转处理,但由于该函数针对二维数据的处理,所以在写程序时,要对RGB图像和灰度图像分开处理,这就要用到isrgb函数来判断,如果是灰度图像,则可以直接用这个函数进行处理,否则就要对RGB图像进行降维处理, for k=1:3 y(:,:,k)=flipud(x(:,:,k);end 处理结果如图:3.3.2、左右翻转对图像的左右翻转也可以用fliplr函数来处
17、理,同样的,也要对灰度和彩色图像分开处理,处理结果如图:3.3.3、任意角度翻转 用函数imrotate来实现对图像的插值旋转。该函数的调用格式如下: Bimrotate(A,angle,method,crop) 其中,参数method用于指定插值的方法,可选的值可以有三种,分别为邻近插值,双线性插值,双三次插值,缺省时为邻近插值,参数angle代表旋转的角度。一般来说,旋转后的图像会比原图大,用户可以指定“crop”参数对旋转后的图像进行剪切(取图像的中间部分),使返回的图像与原图大小一样。执行结果为:3.4、加入噪声经常用到的噪声有三种,高斯噪声,椒盐噪声,乘性噪声,可以通过以下三个函数来
18、实现:y=imnoise(handles.img,gaussian,p1,p2);%高斯噪声y=imnoise(x,salt & pepper,p1); %椒盐噪声y=imnoise(handles.img,speckle,p1); %乘性噪声p1,p2的参数也通过输入对话框的形式得到,原图加入高斯噪声后结果如下所示:3.5、滤波 这里选择三种滤波方法,k=medfilt2(handles.noise_img);%中值滤波k=wiener2(handles.noise_img,5,5);%自适应滤波k=filter2(fspecial(average,3),handles.noise_img)
19、/255;%平滑滤波 同样的,这些函数也是针对二维数据,所以要先判断是彩色图像还是灰度图像,然后分别进行处理,下面是对彩色图像的自适应滤波处理:i=handles.noise_img;if isrgb(i) a=handles.noise_img(:,:,1);b=handles.noise_img(:,:,2);c=handles.noise_img(:,:,3); k(:,:,1)=wiener2(a,5,5);k(:,:,2)=wiener2(b,5,5); k(:,:,3)=wiener2(c,5,5);imshow(k);执行结果如图:对其他方法的滤波程序也类似,由于把各个滤波方法放
20、在一个选择框里,所以程序要用以下的选择语句:switch str case 中值滤波 case 自适应滤波 case 平滑滤波end3.6、直方图统计 用imhist函数对图像数据进行直方图统计,x=imhist(handles.img(:,:,1); bar(horz,x); 其中,x矩阵的数据是0255灰度值的统计个数,如果直接对x矩阵数据进行图形图显示,由于有256个数据,在坐标系中就会很密集,为了更清楚的显示条形图,所以在程序设计时,把x数据进行部分提取,x1=x(1:10:256);horz=1:10:256;bar(horz,x1);除了显示数据的直方图统计外,还可以对图像进行均衡
21、处理,所用到的函数是histeq,这两个函数同样只使用于二维数据,所以也要对二维和三维数据分开处理。 直方图显示和均衡后的图像分别如下图所示3.7、频谱分析3.7.1、频谱图为了得到图像的频谱图,先要对数据进行傅里叶变换,用fft2函数对二维数据进行快速傅里叶变换,同时为了更好的观察频谱图,需要把fft2变换后的数据进行平移,利用fftshift函数,把快速傅里叶变换的DC 组件移到光谱中心。这样图像能量的低频成分将集中到频谱中心,图像上的边缘、线条细节信息等高频成分将分散在图像频谱的边缘。如下图所示:3.7.2、通过高通滤波器axes(handles.axes2);x=(handles.im
22、g);if isrgb(x) msgbox(这是彩色图像,不能通过高通滤波器,失败);elsey1=imnoise(x,gaussian); %加高斯噪声f=double(y1); % 数据类型转换k=fft2(f); % 傅立叶变换g=fftshift(k); % 转换数据矩阵M,N=size(g);nn=2;d0=3; %截止频率为3m=fix(M/2); n=fix(N/2);for i=1:M for j=1:N d=sqrt(i-m)2+(j-n)2); % 计算高通滤波器传递函数 if d=d0 h=0; else h=1; end result(i,j)=h*g(i,j); en
23、dendresult=ifftshift(result);y2=ifft2(result);y3=uint8(real(y2);imshow(y3); end3.7.3、通过低通滤波器axes(handles.axes2);x=(handles.img);if isrgb(x) msgbox(这是彩色图像,不能通过低通滤波器,失败);elsey1=imnoise(x,salt & pepper); % 叠加椒盐噪声f=double(y1); % 数据类型转换,不支持图像的无符号整型的计算g=fft2(f); % 傅立叶变换g=fftshift(g); % 转换数据矩阵M,N=size(g);n
24、n=2; % 二阶巴特沃斯(Butterworth)低通滤波器d0=10; %截止频率为10m=fix(M/2); n=fix(N/2);for i=1:M for j=1:N d=sqrt(i-m)2+(j-n)2); h=1/(1+0.414*(d/d0)(2*nn);% 计算低通滤波器传递函数 result(i,j)=h*g(i,j); endendresult=ifftshift(result);y2=ifft2(result);y3=uint8(real(y2);imshow(y3); % 显示滤波处理后的图像end3.8、灰度图像处理3.8.1、二值图像 用j=im2bw(x);来
25、对灰度图像到二值图像的转换。转换结果为:3.8.2、创建索引图像用X = grayslice(I,n)函数来实现,转换后得到的图像为:3.9、颜色模型转换下面是RGB颜色模型到HSV模型的转换程序:axes(handles.axes2);x=(handles.img);if isrgb(x) HSV=rgb2hsv(x); imshow(HSV);else msgbox(这是灰度图像,不能转换,转换失败);end转换后的结果为:同样的,转化为ntsc和ycbcr模型,只要改为相应的函数即可。函数如下:rgb2ntsc(x);% rgb模型转ntsc模型rgb2ycbcr(x);% rgb模型转
26、ycbcr模型3.10、操作界面设计为了使整个操作界面更加的美观,对背景颜色和字体颜色进行设置。四、程序调试与结果分析(一)在程序设计过程中遇到的问题1、 一个函数只能对灰度图像处理,不能对RGB图像处理,那么如何才能对RGB图像处理呢?这主要是对MATLAB函数的不够清楚,用到的很多函数是针对二维数据的,而RGB图像的数据是一个三维矩阵,所以处理要与灰度图像不同,在开始的时候,我认为应该找一个能够应用于三维矩阵的函数,结果却没找到,后来想到可以把三维数据进行降维处理,同样使用二维的函数,只要是同样处理三次。比如,彩色图像的滤波处理,直方图均衡等。2、 同一个操作对灰度图像可以使用,当用户选择
27、的是彩色图像时,该操作就会出错?这是由于设计程序时,本身程序是有针对性的,有些程序只能对灰度图像有效,有些对彩色图像有效,但是用户并不清楚这些,所以在设计的过程中就要考虑全面,要分开设计。在本次课程设计中,我均对每个程序的开始时,用if isrgb(x)进行判断。3、 在没有加入噪声的情况下,点击“中值滤波”或是其它滤波,会提示错误?这是由于在滤波程序设计的过程中,开始用到的变量是handles.noise_img,而这个变量是在加入噪声时候才定义的,所以在没有加入噪声的情况下,点击各个滤波就会弹出变量没有定义的错误,解决方法就是在文件打开的时候就给定义handles.noise_img=x。
28、a) 本次设计存在一个比较大的问题,就是每次操作都是独立的,比如:要对图像加入噪声,然后在此基础上进行亮度调整,截图,频谱分析等等就不行。我认为应该是整个程序设计过程中对变量的设置没有做好,应该每次操作后,把处理后的数据保存在一个全局变量,这样还要对处理后的数据进行在处理时,只要把这个全局变量作为原始数据带入就可。4、在这次课程设计过程中,感触很深,由于对MATLAB图像处理的函数不熟悉,导致自己走了很多的弯路,比如在设计图像左转90度和右转90度时,由于开始并不知道imrotate函数,只知道上下翻转flipud和左右翻转fliplr函数,想着要怎么用这两个函数来实现左转和右转呢,如果当当只
29、用矩阵转置的话,并不能达到要求,后来想可以结合flipud和fliplr函数来实现,下面程序是实现左转90度:axes(handles.axes2);x=(handles.img);if isrgb(handles.img) a=x(:,:,1);b=x(:,:,2);c=x(:,:,3);e=a;g=b;f=c;y(:,:,1)=e;y(:,:,2)=g;y(:,:,3)=f;axes(handles.axes2);for k=1:3 f(:,:,k)=flipud(y(:,:,k);endimshow(f);else m=x;y=flipud(m); imshow(y);end同理,也可以
30、通过转置和fliplr函数实现右转90度。但是后来发现其实只要用imrotate函数就可以解决问题。通过这次经历后,后来在设计其它程序时,尽量找MATLAB自带的现成函数,而不是一碰到问题就自己想算法,这样可以节省较多的时间。结 语通过本次课程设计,使自己对MATLAB GUI设计流程有了比较深刻的体会,同时也了解了一般软件设计的过程。在设计过程中碰到了很多的问题,通过这些问题,使自己分析问题,解决问题的能力得到了较大的提高。在理工科的专业应用背景下,用matlab 进行相关计算与仿真编程的优势非常突出。特定的问题处理算法,我们通常都以M文件的文本形式给定最终的解决方案,自己设计的程序是在MA
31、TLAB环境下,用MATLAB语言编写的,这对于有安装MATLAB软件的计算机上运行并不存在什么问题,关键是一般的计算机很少有去安装MATLAB软件的,那么要在这些机子上运行该程序要怎么办呢,难道要先安装MATLAB软件,这显然太麻烦了,对于一个通用的,比较成熟的解决方案,我们当然期望它能应用到更多的场合,而.exe (可执行)文件可运行于所有的通用WINDOWS操作系统,为此,将M文件转换成.exe文件倒是个不错的想法。参考文献【1】 阿奇,戈,阳.MATLAB实用教程M.:电子工业【2】 程卫国,峰,东,徐听.MATLAB5.3应用指南M.:人民邮电【3】 .MATLAB 6.X图像编程与
32、图像处理M.:电子科技大学附录%菜单的程序-function file_Callback(hObject, eventdata, handles)-%文件打开程序function open_Callback(hObject, eventdata, handles) name,path=uigetfile(*.bmp,载入图像);if isequal(name,0)|isequal(path,0) errordlg(没有选中文件,出错); return;else x=imread(path,name); axes(handles.axes1); imshow(x); handles.img=x;
33、 handles.noise_img=x; guidata(hObject,handles)end-function save_Callback(hObject, eventdata, handles)%文件保存 filename,pathname = uiputfile(*.bmp,图片保存为);if isequal(filename,pathname,0,0) errordlg(没有保存,出错); return;elsefile=strcat(pathname,filename);(handles.axes2);i=getimage(gca);imwrite(i,file);end-fun
34、ction exit_Callback(hObject, eventdata, handles)clc;close all;close(gcf);-%编辑菜单的程序-function edit_Callback(hObject, eventdata, handles)-function huidu_Callback(hObject, eventdata, handles)%灰度处理axes(handles.axes2);if isrgb(handles.img) y=rgb2gray(handles.img); %RGBimshow(y);else msgbox(这已经是灰度图像,转换失败);
35、end -function liangdu_Callback(hObject, eventdata, handles)%亮度处理 prompt=输入参数1,输入参数2,输入gamma; defans=0 0.7,0 1,1; p=inputdlg(prompt,输入参数,1,defans); p1=str2num(p1); p2=str2num(p2); p3=str2num(p3); gamma=p3; x=(handles.img); y=imadjust(x,p1,p2,gamma); axes(handles.axes2); imshow(y);-function jietu_Call
36、back(hObject, eventdata, handles)%截图set(handles.axes2,HandleVisibility,ON);axes(handles.axes2);y=imcrop(handles.img);imshow(y); handles.Timage=y;-function fangda_Callback(hObject, eventdata, handles)-function lingjz_Callback(hObject, eventdata, handles)%邻近插值放大axes(handles.axes2);prompt=输入放大倍数:;defan
37、s=2;p=inputdlg(prompt,输入放大倍数,1,defans);p1=str2num(p1);y=imresize(handles.img,p1,nearest); %最近邻插值法放大imshow(y);-functionshuangxianfa_Callback(hObject, eventdata, handles)%双线放大axes(handles.axes2);prompt=输入放大倍数:;defans=2;p=inputdlg(prompt,输入放大倍数,1,defans);p1=str2num(p1);y=imresize(handles.img,p1,bilinea
38、r); %最近邻插值法放大imshow(y); -function shuangsanci_Callback(hObject, eventdata, handles)%双三次放大axes(handles.axes2);prompt=输入放大倍数:;defans=2;p=inputdlg(prompt,输入放大倍数,1,defans);p1=str2num(p1);y=imresize(handles.img,p1,bicubic); imshow(y);-function suoxiao_Callback(hObject, eventdata, handles)%邻近插值缩小 axes(han
39、dles.axes2); prompt=输入放大倍数:; defans=0.2; p=inputdlg(prompt,输入放大倍数,1,defans);p1=str2num(p1);y=imresize(handles.img,p1,nearest); %最近邻插值法缩小 imshow(y);-function shuangxian_Callback(hObject, eventdata, handles)%双线性缩小axes(handles.axes2);prompt=输入放大倍数:;defans=0.2;p=inputdlg(prompt,输入放大倍数,1,defans);p1=str2n
40、um(p1);y=imresize(handles.img,p1,bilinear); %最近邻插值法缩小imshow(y); -function shuangsancisuox_Callback(hObject, eventdata, handles)%双三次缩小axes(handles.axes2);prompt=输入放大倍数:;defans=0.2;p=inputdlg(prompt,输入放大倍数,1,defans);p1=str2num(p1);y=imresize(handles.img,p1,bicubic); imshow(y); -function xuanzhuan_Callback(hObject, eve