目录
-
实验描述
本文章是基于MATLAB数字图像处理课程的结课作业,利用MATLAB设计了可视化界面进行基础版图像处理,其中功能包括作业要求的功能,额外还设计了一些创新功能,包括但不限于相对亮度调整、返回上一步等。其中内容多来自于课程内容和上网查询资料获取到的内容的融会贯通,通过本次实验,完成了图像处理app的实现可以进行简单的图像处理,以及特殊功能检测。
-
设计思路
-
功能模块
-
基础界面
-
开发工具
MATLAB R2021a App Designer
-
基础功能
-
最重要的全局变量(写在前面)
properties (Access = private)
originalpicture; % Description
lastpicture;
changedpicture;
changedpicture2;
upgradepicture;
D0;
end
-
导入图片
函数uigetfile()打开文件选择对话框,选择文件,返回文件名和文件路径。有了文件名和文件路径后读文件函数读取相应的文件,将返回的文件路径和文件名赋给图片,使用imshow将其显示在界面指定位置上。如果未选择文件则弹出窗口,显示提醒未选择图片,然后返回图像界面。
[filename,pathname] = uigetfile({'*.jpg';'*.bmp';'*.*'},'选择图片');
if isequal(filename,0)||isequal(pathname,0)
msgbox('您未选择图片','温馨提示','help');
return;
else
x=strcat(pathname,filename);
app.originalpicture=imread(x);
imshow(app.originalpicture,'Parent',app.UIAxes1);
app.lastpicture=app.originalpicture;
app.changedpicture=app.originalpicture;
end
若不选择图像,点击取消的话会弹出提醒窗口
-
从摄像头获取照片
使用videoinput函数生成窗口对象并同步画面。利用函数获取图片的帧,当关闭窗口时,将关闭窗口时的截取图像显示在规定的坐标中。
obj = videoinput('winvideo',1);
h=preview(obj);
while ishandle(h)
app.originalpicture = getsnapshot(obj); % 获取帧
app.changedpicture=app.originalpicture;
imshow(app.originalpicture,'Parent',app.UIAxes1);
title(app.UIAxes1,'原始图片');
drawnow
end
-
彩色图像灰度化
利用im2gray()函数将彩色影像RGB转换成灰度影像Grayscale,由im2gray创建的灰度图像是一个由强度值组成的单一平面。im2gray函数将RGB值转换为灰度值,将R、G、B分量加权和:0.2989*R+0.5870*G+0.1140*B。
if isequal(app.originalpicture,'')
msgbox('无图片','提示',"help");
else
gray=im2gray(app.originalpicture);
app.lastpicture=app.changedpicture;
imshow(gray,'Parent',app.UIAxes2);
app.changedpicture=gray;
end
-
灰度图像二值化
函数im2bw使用阈值(threshold)变换法把灰度图像(grayscale image)转换成二值图像。所谓二值图像, 一般意义上是指只有纯黑(0)、纯白(255)两种颜色的图像。BW = im2bw(I,level),其将灰度图像 I 转换为二进制图像。输出图像 BW 将输入图像中亮度值大于 level 的像素替换为值1 (白色),其他替换为值0(黑色)。你指定 level 在 [0,1]之间,不用管输入图像的等级。函数graythresh 能用来自动计算变量 level 。如果你不指定 level ,im2bw 使用 0.5。
if isequal(app.originalpicture,'')
msgbox('无图片','提示',"help");
else
black=im2bw(app.originalpicture);
app.lastpicture=app.changedpicture;
imshow(black,'Parent',app.UIAxes2);
app.changedpicture=black;
end
-
两幅图像叠加
进行两幅图像的加法,或者给一幅图像加上一个常数,可以调用imadd函数来实现。imadd函数将某一幅输入图像的每一个像素值与另一幅图像相应的像素值相加,返回相应的像素值之和作为输出图像。Z = imadd(X,Y),其中,X和Y表示需要相加的两幅图像,返回值Z表示得到的加法操作结果。
[filename,pathname] = uigetfile({'*.jpg';'*.bmp';'*.*'},'选择图片');
if isequal(filename,0)||isequal(pathname,0)
msgbox('您未选择图片','温馨提示','help');
return;
else
x=strcat(pathname,filename);
addpic=imread(x);
imshow(addpic,'Parent',app.UIAxes2);
end
result=imadd(app.originalpicture,addpic);
imshow(result,'Parent',app.UIAxes3);
-
目标检测(两幅图像相减)
图像减法也称为差分方法,是一种常用于检测图像变化及运动物体的图像处理方法。imsubtract函数可以将一幅图像从另一幅图像中减去,或者从一幅图像中减去一个常数。imsubtract函数将一幅输入图像的像素值从另一幅输入图像相应的像素值中减去,再将这个结果作为输出图像相应的像素值。Z = imsubtract(X,Y),其中,Z是X-Y操作的结果。以下代码首先根据原始图像生成其背景亮度图像,然后再从原始图像中将背景亮度图像减去,从而生成减去后的图像。
[filename,pathname] = uigetfile({'*.jpg';'*.bmp';'*.*'},'选择图片');
if isequal(filename,0)||isequal(pathname,0)
msgbox('您未选择图片','温馨提示','help');
return;
else
x=strcat(pathname,filename);
targetpic=imread(x);
imshow(targetpic,'Parent',app.UIAxes2);
end
result=imabsdiff(targetpic,app.originalpicture);
imshow(result,'Parent',app.UIAxes3);
app.changedpicture=result;
图像的相减可以用来检测两幅图中不同的部分,检测图像之间的差异,增强细节,也可以用于一幅图像减去像素值,使图片变暗。但需要注意的是,相减的两幅图像尺寸应该相同。
-
图像灰度变换(指数变换、对数变换)
采用log函数进行对数变换(参数值必须为double类型),用im2uint8()函数将灰度图像转换为8位图,可视化显示新生成的图。指数变换能增强图像中亮区域的细节(对比度提高),同时弱化图像中暗区域的细节(对比度降低)。
%指数变换
app.lastpicture=app.changedpicture;
if isequal(app.originalpicture,'')
msgbox('无图片','提示',"help");
else
if (ndims(app.originalpicture)==3)
app.originalpicture=rgb2gray(app.originalpicture);
end
A1 = double(app.originalpicture);
A2 = 1.5.^(A1*0.070)-1;
A2 = uint8(A2);
imshow(A2,'Parent',app.UIAxes2);
app.changedpicture=A2;
%对数变换
app.lastpicture=app.changedpicture;
if isequal(app.originalpicture,'')
msgbox('无图片','提示',"help");
else
if (ndims(app.originalpicture)==3)
app.originalpicture=rgb2gray(app.originalpicture);
end
h=log(1+double(app.originalpicture));
h=mat2gray(h);
h=im2uint8(h);
imshow(h,'Parent',app.UIAxes2);
app.changedpicture=h;
end
(指数)
(对数)
指数变换能增强图像中亮区域的细节(对比度提高),同时弱化图像中暗区域的细节(对比度降低),而对数变换可以增强低灰度,减弱高灰度值。
-
显示原图像直方图和将原图像直方图均衡化(写在一起)
图像的直方图事实上就是图像的亮度分布的概率密度函数,是一幅图像的所有象素集合的最基本的统计规律。直方图反映了图像的明暗分布规律,可以通过图像变换进行直方图调整,获得较好的视觉效果。直方图均衡化是通过灰度变换将一幅图像转换为另一幅具有均衡直方图,即在每个灰度级上都具有相同的象素点数的过程。使用imhist函数显示直方图。
if isequal(app.originalpicture,'')
msgbox('无图片','提示',"help");
elseif isequal(app.changedpicture,'')
msgbox('图片未处理','提示',"help");
else
subplot(231),imhist(im2gray(app.originalpicture)),title('原始图像直方图');
subplot(232),imhist(im2gray(app.changedpicture)),title('处理图像直方图');
subplot(233),imhist(im2gray(app.changedpicture2)),title('二次处理直方图');
end
直方图均衡化的目的是使图像在整个灰度值动态变化范围内的分布均匀化,改善图像的亮度分布状态,增强图像的视觉效果。直方图均衡化是通过灰度变换将一幅图像转换为另一幅具有均衡直方图,即在每个灰度级上都具有相同的象素点数的过程。用histeq()函数对图像进行均衡化,均衡化后图像的直方图可以修改灰度级数量。
if isequal(app.originalpicture,'')
msgbox('无图片','提示',"help");
elseif isequal(app.changedpicture,'')
msgbox('图片未处理','提示',"help");
else
hist1=histeq(im2gray(app.originalpicture));
hist2=histeq(im2gray(app.changedpicture));
hist3=histeq(im2gray(app.changedpicture2));
subplot(234),imhist(hist1),title('原始图像直方图');
subplot(235),imhist(hist2),title('处理图像直方图');
subplot(236),imhist(hist3),title('二次处理直方图');
end
灰度直方图反映了图像中各灰度值出现的频数,根据灰度值分布的范围和均匀程度,就可以判断出该图像曝光是否合适。
图像直方图均衡化,是指寻找一个灰度变换函数,使变换后图像的像素值占有全部的灰度级并且分布均匀,从而得到一幅灰度级丰富且动态范围大的图像。
-
添加高斯噪声和椒盐噪声
imnoise 是表示添加噪声污染一幅图像,叫做噪声污染图像函数。利用imnoise 命令在图像上加入高斯(gaussian) 噪声,高斯噪声即呈正态分布的干扰噪声,用作增加光谱的扰动或图像的干扰。利用imnoise 命令在图像上加入椒盐噪声(salt & pepper)。椒盐噪声也称为脉冲噪声,是图像中经常见到的⼀种噪声,它是⼀种随机出现的⽩点或者⿊点,可能是亮的区域有⿊⾊像素或是在暗的区域有⽩⾊像素(或是两者皆有)。
%高斯噪声
changingValue = event.Value;
app.lastpicture=app.changedpicture;
if isequal(app.originalpicture, '')
msgbox("无图片",'warning','help');
return;
else
Image=app.originalpicture;
noisepic=imnoise(Image,'gaussian',changingValue);
imshow(noisepic,'Parent',app.UIAxes2);
app.changedpicture=noisepic;
end
%椒盐噪声
changingValue = event.Value;
app.lastpicture=app.changedpicture;
if isequal(app.originalpicture, '')
msgbox("无图片",'warning','help');
return;
else
Image=app.originalpicture;
noisepic=imnoise(Image,'salt & pepper',changingValue);
imshow(noisepic,'Parent',app.UIAxes2);
app.changedpicture=noisepic;
end
(高斯噪声)
(椒盐噪声)
高斯噪声在每个像素上都会出现,赋值服从高斯分布。椒盐噪声出现位置随机,所以可以控制椒盐噪声的密度,椒盐噪声的幅度确定,椒噪声偏暗,盐噪声偏亮。
-
均值滤波器、中值滤波器、高斯滤波器滤波处
把模板运算运用于图像的空间域增强的技术称为空间域滤波。这三个滤波器主要是对于添加了噪声以后的图像进行依据滤波频率空间域滤波,平滑滤波(减弱和去除高频分量),分别采用不同大小的模板,分别用均值滤波器、中值滤波器以及高斯滤波器,对加入噪声的图像进行处理并观察不同噪声水平下不同滤波器处理的结果。线性滤波器的原始数据与滤波结果是一种算术运算,即用加减乘除等运算实现,如均值滤波器、高斯滤波器等。非线性滤波器的原始数据与滤波结果是一种逻辑关系,也就是用逻辑运算来实现的,比如中值滤波器等,是通过比较一定邻域内的灰度值大小来实现的。
%均值滤波器
changingValue = event.Value;
app.lastpicture=app.changedpicture;
noisepic=app.changedpicture;
h=fspecial('average',changingValue);
reuslt = imfilter(noisepic,h);
imshow(reuslt,'Parent',app.UIAxes3);
app.changedpicture2=reuslt;
%中值滤波器
value = app.Spinner_4.Value;
app.lastpicture=app.changedpicture;
noisepic=app.changedpicture;
if (ndims(noisepic)==3)
noisepic=rgb2gray(noisepic);
end
result=medfilt2(noisepic,[value value]);
imshow(result,'Parent',app.UIAxes3);
%高斯滤波器
value = app.Spinner_5.Value;
app.lastpicture=app.changedpicture;
noisepic=app.changedpicture;
result=imgaussfilt(noisepic,[value value]);
imshow(result,'Parent',app.UIAxes3);
app.changedpicture2=result;
(均值滤波器)
(高斯滤波器)
(中值滤波器)
中值滤波器、均值滤波器、高斯滤波器可以去除图像的噪声,使图像变得模糊。尤其中值滤波对椒盐噪声的处理效果格外好,不但是也需要选取合适的参数。
-
采用robert和二阶算子提取图像边
边缘检测首先检测出图像局部不连续性,然后将这些不连续的边缘像素连成完备的边界。边缘的特性是沿边缘走向的像素变化平缓,而垂直于边缘方向的像素变化剧烈。所以,从这个意义上说,提取边缘的算法就是检出符合边缘特性的边缘像素的数学算子。
把模板运算运用于图像的空间域增强的技术称为空间域滤波。依据滤波频率空间域滤波的锐化滤波,即减弱和去除低频分量。采用Roberts算子,LoG算子分别进行图像锐化。Roberts算子涉及绝对值运算,直接遍历所有点求出其近似梯度幅值。高斯-拉普拉斯算子(Laplacian of a Gaussian)简称LoG算子,也称为Marr边缘检测算子。应用LoG算子时,高斯函数中标准差参数σ的选择很关键,对图像边缘检测效果有很大的影响,对于不同图像应选择不同参数。
%Roberts算子
value = app.RobertsSlider.Value;
value1=value./255;
app.lastpicture=app.changedpicture;
if isequal(app.originalpicture, '')
msgbox("无图片",'warning','help');
return;
else
I=im2gray(app.originalpicture);
J = edge(I, 'Roberts', value1);
imshow(J,'Parent',app.UIAxes2);
app.changedpicture=J;
End
%二阶算子(log)
value = app.Slider_4.Value;
value1 = value./255;
app.lastpicture=app.changedpicture;
if isequal(app.originalpicture, '')
msgbox("无图片",'warning','help');
return;
else
I=im2gray(app.originalpicture);
J=edge(I,'log',value1);
imshow(J,'Parent',app.UIAxes2);
app.changedpicture=J;
end
(Roberts算子)
(二阶算子log)
通过调节不同参数发现,二阶算子在参数比较小是效果较好,对参数的变化很敏感,稍微大一点就无法检测边缘,而Roberts算子检测边缘时噪声比二阶算子更多,不过我还是认为Roberts算子更适合用于检测边缘。
频域滤波分为低通滤波和高通滤波两类,对应的滤波器分别为低通滤波器和高通滤波器。
低通滤波器实质上就是对图像进行平滑处理。低通滤波器包括:理想低通滤波器、n阶巴特沃兹低通滤波器、高斯低通滤波器。频域低通过滤的基本思想:G(u,v)=F(u,v)H(u,v)。F(u,v)是需要钝化图像的傅立叶变换形式,H(u,v)是选取的一个低通过滤器变换函数,G(u,v)是通过H(u,v)减少F(u,v)的高频部分来得到的结果,运用傅立叶逆变换得到钝化后的图像。
高通滤波器实质上就是对图像进行边缘提取(锐化处理)。相应的高通滤波器也包括:理想高通滤波器、n阶巴特沃兹高通滤波器、高斯高通滤波器。相应高通滤波器的传递函数:。
频域滤波最重要的点是指定的非负数D0的的值的选取。这决定了滤波以后的效果。
——————————平滑处理(低通滤波器)————————————————
%理想低通滤波器
s=fftshift(fft2(im2double(app.originalpicture)));%傅里叶变换
if(ndims(s)==3)
s=rgb2gray(s);
end
[m,n]=size(s);
m0=round(m/2);
n0=round(n/2);
for i=1:m %双重for循环计算频率点(i,j)与频域中心的距离 D(i,j)=sqrt((i-round(m/2)^2+(j-round(n/2)^2))
for j=1:n
L=sqrt((i-m0)^2+(j-n0)^2);
if L<=app.D0
%根据理想低通滤波器产生公式,当D(i,j)<=D0,置为1
h=1;
else
h=0;
%根据理想低通滤波器产生公式,当D(i,j)>D0,置为0
end
s1(i,j)=h*s(i,j);%频域图像乘以滤波器的系数
end
end
s1=real(ifft2(ifftshift(s1)));
%最后进行二维傅里叶反变换转换为时域图像
subplot(2,3,1),imshow(s1,[]),title('理想低通滤波器');
%巴特沃斯低通滤波器
I=im2double(app.originalpicture);
if(ndims(I)==3)
I=rgb2gray(I);
end
M=2*size(I,1);
N=2*size(I,2);
u=-M/2:(M/2-1);
v=-N/2:(N/2-1);
[U,V]=meshgrid(u,v);
D=sqrt(U.^2+V.^2);
n=6;
H1=1./(1+(D./app.D0).^(2*n));
J1=fftshift(fft2(I,size(H1,1),size(H1,2)));
K1=J1.*H1;
L1=ifft2(ifftshift(K1));
L1=L1(1:size(I,1),1:size(I,2));
subplot(232);imshow(L1),title('巴特沃斯低通滤波器');
%高斯低通滤波器
s=fftshift(fft2(im2double(app.originalpicture)));
if(ndims(s)==3)
s=rgb2gray(s);
end
[m,n]=size(s);
m0=round(m/2);
n0=round(n/2);
for i=1:m
for j=1:n
L=sqrt((i-m0)^2+(j-n0)^2); %根据高斯低通滤波器公式H(u,v)=e^-[D^2(u,v)/(2*D0^2)]
h=exp(-(L*L)/(2*(app.D0^2))); %exp表示以e为底的指数函数
s0(i,j)=h*s(i,j);%频域图像乘以滤波器的系数
end
end
s=real(ifft2(ifftshift(s0)));%最后进行二维傅里叶反变换转换为时域图像
subplot(233),imshow(s),title('高斯低通滤波器');
——————————————————提取边缘(高通滤波器)——————————————————
%理想低通滤波器
s=fftshift(fft2(im2double(app.originalpicture)));%傅里叶变换
if(ndims(s)==3)
s=rgb2gray(s);
end
[m,n]=size(s);
m0=round(m/2);
n0=round(n/2);
%将理想高通滤波器的截止频率D0设置为5
for i=1:m %双重for循环计算频率点(i,j)与频域中心的距离 D(i,j)=sqrt((i-round(m/2)^2+(j-round(n/2)^2))
for j=1:n
L=sqrt((i-m0)^2+(j-n0)^2);
if L<=app.D0
%根据理想高通滤波器产生公式,当D(i,j)<=D0,置为0
h=0;
else
h=1;
%根据理想高通滤波器产生公式,当D(i,j)>D0,置为1
end
s(i,j)=h*s(i,j);%频域图像乘以滤波器的系数
end
end
%real函数取元素的实部
s=real(ifft2(ifftshift(s)));
%最后进行二维傅里叶反变换转换为时域图像
subplot(234),imshow(s),title('理想高通滤波器');
%巴特沃斯低通滤波器
I=im2double(app.originalpicture);
if(ndims(I)==3)
I=rgb2gray(I);
end
M=2*size(I,1);
N=2*size(I,2);
u=-M/2:(M/2-1);
v=-N/2:(N/2-1);
[U,V]=meshgrid(u,v);
D=sqrt(U.^2+V.^2);
n=6;
h=1-1./(1+(D./app.D0).^(2*n));
j=fftshift(fft2(I,size(h,1),size(h,2)));
k=j.*h;
L=ifft2(ifftshift(k));
L=L(1:size(I,1),1:size(I,2));
subplot(235);imshow(L),title('巴特沃斯高通滤波器');
%高斯低通滤波器
s=fftshift(fft2(im2double(app.originalpicture)));
if(ndims(s)==3)
s=rgb2gray(s);
end
[m,n]=size(s);
m0=round(m/2);
n0=round(n/2);
for i=1:m
for j=1:n
L=sqrt((i-m0)^2+(j-n0)^2); %根据高斯低通滤波器公式 H(u,v)=e^-[D^2(u,v)/(2*D0^2)]
h=1-exp(-(L*L)/(2*(app.D0^2)));
%exp表示以e为底的指数函数
s0(i,j)=h*s(i,j);%频域图像乘以滤波器的系数
end
end
s=real(ifft2(ifftshift(s0)));
%最后进行二维傅里叶反变换转换为时域图像
subplot(236),imshow(s),title('高斯高通滤波器');
低通滤波器对图像进行平滑处理,高通滤波器对图像边缘进行提取,滤波器高通和低通的运算效果对比,高通和低通传递函数H(u,v)的互补,同时并非D0值越大滤波效果更好。
-
运动模糊,并进行图像复原处理
fspecial函数用于创建滤波器,imfilter函数,对影像进行滤波处理:h = fspecial(‘motion’,len,theta),返回一个过滤器,使其在与图像卷积后近似相机的线性运动。len指定运动的长度,theta指定逆时针方向的运动角度(以度为单位)。过滤器将成为水平和垂直运动的矢量。len是20,默认的theta是30,这对应于20个像素的水平运动。J = deconvwnr(I,psf,nsr),使用维纳滤波算法对图像I进行解卷积,返回去模糊图像J。psf是对I进行卷积的点扩展函数(psf)。nsr是加性噪声的噪声与信号功率比。
————————运动模糊————————————
if isequal(app.originalpicture,'')
msgbox('无图片','提示',"help");
return;
else
app.lastpicture=app.changedpicture;
%app.originalpicture=rgb2gray(app.originalpicture);
app.originalpicture=im2double(app.originalpicture);
len=20;
theta=30;
PSF=fspecial('motion',len,theta);%产生PSF obscureway1=imfilter(app.originalpicture,PSF,'conv','circular');
imshow(obscureway1,'Parent',app.UIAxes2);
app.changedpicture=obscureway1;
app.upgradepicture=obscureway1;
——————————————图像复原————————————
if isequal(app.originalpicture,'')
msgbox('无图片','提示',"help");
return;
else
app.lastpicture=app.changedpicture;
len=20;
theta=30;
PSF=fspecial('motion',len,theta);%产生PSF
NSR = 0;
recoverpic = deconvwnr(app.upgradepicture,PSF,NSR);
%维纳滤波复原
imshow(recoverpic,'Parent',app.UIAxes3);
end
对于运动模糊和复原,效果最好的时候是模糊和复原参数数值相同的时候,维纳滤波复原在估计图像和真实图像之间的最小均方误差意义下是最优的.
-
腐蚀、膨胀、开运算、闭运算
膨胀:对边界点进行扩充,填充空洞,使边界向外部扩张的过程。
腐蚀:消除物体边界点,使边界向内部收缩的过程,把小于结构元素的物体去除掉。
开运算: 先腐蚀后膨胀的过程称为开运算,作用:去除孤立的小点,毛刺,消除小物体,平滑较大物体边界,同时不改变其面积。
闭运算:先膨胀后腐蚀的过程是闭运算。作用:填充物体内细小的空洞,连接临近物体,平滑边界,同时不改变其面积。其中,对灰度图像的腐蚀相等于对灰度图像变暗;对灰度图像的膨胀(闭运算)相等于对灰度图像变亮。
————————————膨胀——————————
SE = strel('diamond',3);
if isequal(app.originalpicture,'')
msgbox('无图片','提示',"help");
return;
else
result1=imdilate(app.originalpicture,SE);
%膨胀灰度图像result1=imdilate(Image,se);%膨胀灰度图像
subplot(221),imshow(result1),title('膨胀');
end
——————————————腐蚀——————————————
SE = strel('diamond',3);
if isequal(app.originalpicture,'')
msgbox('无图片','提示',"help");
return;
else
result2=imerode(app.originalpicture,SE);
%腐蚀灰度图像result1=imdilate(Image,se);%膨胀灰度图像
subplot(222),imshow(result2),title('腐蚀');
end
————————————开运算————————————
SE = strel('diamond',3);
if isequal(app.originalpicture,'')
msgbox('无图片','提示',"help");
return;
else
result3=imopen(app.originalpicture,SE);
%开运算灰度图像result1=imdilate(Image,se);%膨胀灰度图像
subplot(223),imshow(result3),title('开运算');
end
————————————闭运算————————————————
SE = strel('diamond',3);
if isequal(app.originalpicture,'')
msgbox('无图片','提示',"help");
return;
else
result4=imclose(app.originalpicture,SE);
%闭运算灰度图像result1=imdilate(Image,se);%膨胀灰度图像
subplot(224),imshow(result4),title('闭运算');
end
基于灰度图像的各种操作,对图像进行腐蚀后,图像变暗,亮细节被削弱,因为亮的区域被缩小了,反之,对图像进行膨胀,使较亮的局部区域被扩大了,而较暗的区域被变小了,图像整体变得更亮。相同的是,进行膨胀腐蚀操作后都会使图像变得模糊。
-
提取红苹果
将图像从rgb转换为hsv,提取图中红色的部分。遍历图像所有像素,不是红色的像素变成黑的像素(R=G=B=0)。图像还是有许多噪声的,可采用数学形态学的方法除去噪声。对图像进行开运算处理,可去除非常小或窄的像素,用MATLAB内置函数先进行腐蚀再进行膨胀,完成开运算。形态学处理尽量去除小的孔洞。
app.lastpicture=app.changedpicture;
hsv=rgb2hsv(app.originalpicture);
h=hsv(:,:,1);
h(h>330/360)=0;
training=h(:);
startdata = [0;60/360;120/360;180/360;240/360;300/360];
[IDX,C]= kmeans(training,6,'Start',startdata);
idbw = (IDX == 1);
template = reshape(idbw, size(h));%重新排列矩阵
SE = strel('diamond',3);
result=imopen(template,SE);
imshow(result,'Parent',app.UIAxes2);
app.changedpicture=result;
通过多组实验图片结果对比,该算法对红色苹果可以实现大致的提取,但会有很多小的噪点无法消除或者是将非红色部分错误提取,也对一些颜色较深的颜色无法进行判断,同时这个算法的本质是对红色进行检验提取,所以对苹果的形状无法保证,苹果自身产生的黑色阴影也会导致被赋为黑色。
将图像转化成灰度图,灰度图二值化成黑白的,以颜色值99作为分界线,灰度图中颜色值大于等于99的将变为1,小于99的变为0,消除噪点,使统计更准确,经过初步除噪后,仍然还有几个小的噪点,选择合适的结构袁术进行腐蚀和膨胀。经过去除噪点后,每一个硬币都已经成为了一个单独的图像区,bwlabel(BW)就是用来对二维二值图像中的连通分量进行标注的,即在BW中找到的连通对象的数量并返回,最后得出的就是计数后的结果使用消息框弹出。
app.lastpicture=app.changedpicture;
if ndims(app.originalpicture)==3
I_gray=rgb2gray(app.originalpicture);
end
%转换为灰度图
BW=I_gray>99;%二值化(重点为确定阈值)
% 去除噪声
I_gray1=imfill(BW,'holes');%填充空洞 消除噪点
imshow(BW,'Parent',app.UIAxes2);
SE = strel('disk',4,4);
%确定半径(此处半径可自行调整,主要应用于后面的膨胀和腐蚀中)
SE1 = strel('octagon',9);
%确定半径(此处半径可自行调整,主要应用于后面的膨胀和腐蚀中)
I_gray2=imerode(I_gray1,SE);%腐蚀
I_gray3=imdilate(I_gray2,SE);%膨胀
I_gray4=imerode(I_gray3,SE1);%腐蚀
imshow(I_gray4,'Parent',app.UIAxes3);
%计算硬币数量
[L,n] = bwlabel(I_gray4);%n为硬币数目
S=sprintf('检测到的硬币个数为:%d',n);
msgbox(S);%弹窗显示运行结果
app.changedpicture=I_gray4
本算法实现对硬币的提取是建立在硬币图像平铺且不连通的情况下,对图片的要求较高,如果硬币连通,膨胀腐蚀操作无法将硬币单独提取,就会使结果不准确。对于挨得较近的硬币图像,在腐蚀的时候要选择腐蚀程度大的结构元素,将硬币区域区分出来才能更好计数。并且在选择检验图片的时候要选择背景深的图片,因为这个算法检测的是白色连通区域,如果背景浅色,二值化填充孔洞会将整幅图填充为白色,检测出硬币个数永远为1。
-
检测圆和矩形
将其转为灰度图像处理,即不利用颜色特征,通过分割,并基于形状特征实现圆和矩形的检测。矩形检测:从理论上看,矩形连通区域与其最小边界矩形的像素比是1,所以可自定义设置阈值大于0.95判断。圆形检测:从理论上看,设圆形半径为R,最小边界矩形即正方形边长为2R,圆形连通区域与其最小边界矩形的面积比为0.7854,所以可自定义二值化设置阈值介于[ 0.76 , 0.80 ]判断。
if ndims(app.originalpicture)==3
app.originalpicture=rgb2gray(app.originalpicture);
end
binary_img=1-im2bw(app.originalpicture,0.73);
%灰度图转换成二值图像,直接进行灰度反转,让图形区域置1
for i=202:265
binary_img(188,i)=1;
end
fill_hole=imfill(binary_img,'holes');
fill_hole=bwareaopen(fill_hole,10);
[B,L]=bwboundaries(fill_hole,'noholes');
out_result=regionprops(fill_hole,'Extent','Centroid','boundingbox');
%Extent:各连通区域像素点与最小边界像素点比值
centroids = cat(1, out_result.Centroid); %各连通区域质心
draw_rect=cat(1,out_result.BoundingBox); %各连通区域最小边界矩形
figure;
subplot(2,2,1);imshow(app.originalpicture,[]);title('原图');
subplot(2,2,2);imshow(binary_img,[]);title('二值化');
subplot(2,2,3);imshow(fill_hole,[]);title('区域填充');
subplot(2,2,4);imshow(fill_hole,[]);title('圆和矩形检测');
for i=1:size(out_result)
rectangle('position',draw_rect(i,:),'EdgeColor','y','LineWidth',2);
%绘出各连通区域最小边界矩形
if out_result(i).Extent>0.95
text(centroids(i,1)-20, centroids(i,2)-10,'矩形 ','Color','b','FontSize',9);
elseif out_result(i).Extent>0.76&&out_result(i).Extent<0.80
text(centroids(i,1)-20, centroids(i,2)-10,'圆形 ','Color','b','FontSize',9);
end
end
矩形和圆形检测的这个算法要求检测的形状和背景有强烈的对比度,若对比不明显,会使检测是图像不完整,从而检测不到完整的图像,产生错误的结果,并且这个算法只对这张图片有效,并不是对所有的图形都可以。(这张图片中最后一个矩形原是浅黄色,然后检测不出来……所以我去调了个色,把黄色变成了橘色…这个算法可以实现,但是没完全实现)
-
一些些创新功能
—————————(这个就没有介绍了,大多(全部)也是借鉴很多大佬的)————————
-
返回上一步
function Button_3Pushed(app, event)
if isequal(app.lastpicture,'')
msgbox('无上一步','温馨提示','help');
return;
else
imshow(app.lastpicture,"Parent",app.UIAxes2);
end
end
进行操作以后返回上一步,未进行操作时显示无上一步
-
水平翻转
app.lastpicture=app.changedpicture;
if isequal(app.originalpicture, '')
msgbox("无图片",'warning','help');
return;
else
levelpic=flip(app.changedpicture,2);
imshow(levelpic,'Parent',app.UIAxes2);
app.changedpicture=levelpic;
End
-
垂直翻转
app.lastpicture=app.changedpicture;
if isequal(app.originalpicture, '')
msgbox("无图片",'warning','help');
return;
else
levelpic=flip(app.changedpicture,1);
imshow(levelpic,'Parent',app.UIAxes2);
app.changedpicture=levelpic;
End
-
角度旋转
value = app.Knob.Value;
value = double(value);
app.lastpicture=app.changedpicture;
if isequal(app.originalpicture, '')
msgbox("无图片",'warning','help');
return;
else
anglepic=imrotate(app.originalpicture,value);
imshow(anglepic,'Parent',app.UIAxes2);
app.changedpicture=anglepic;
End
-
相对亮度
changingValue = event.Value;
if isequal(app.originalpicture,'')
msgbox('无图片','提示',"help");
return;
else
app.lastpicture=app.changedpicture;
brightpic=imadd(app.originalpicture,changingValue);
imshow(brightpic,'Parent',app.UIAxes2);
app.changedpicture=brightpic;
End
(亮)
(暗)
-
锐化
changingValue = event.Value;
changingValue=double(changingValue);
changingValue1=changingValue./1.00;
if isequal(app.originalpicture, '')
msgbox("无图片",'warning','help');
return;
else
app.lastpicture=app.changedpicture;
test = double(im2gray(app.originalpicture));
Gx = [-1 -2 -1;0 0 0;1 2 1];
x = filter2(Gx,test);
Gy = [-1 0 1;-2 0 2;-1 0 1];
y = filter2(Gy,test);
test1 = sqrt(x.^2 + y.^2);
test2 = test + test1*changingValue1;
sharpen=uint8(test2);
imshow(sharpen,'Parent',app.UIAxes2);
app.changedpicture=sharpen;
return;
end
-
实验总结
(以后有空再加)
参考资料(只能找到当时看的一些了)
https://blog.csdn.net/u014655960/article/details/127645119?spm=1001.2014.3001.5502
(老师的代码放第一个)(小声bb)
https://blog.csdn.net/ckyckyzmy/article/details/126922975
https://blog.csdn.net/weixin_31831459/article/details/115956112
https://blog.csdn.net/qq_23023937/article/details/110308203
https://blog.csdn.net/new_EAGLE/article/details/125744992
https://blog.csdn.net/imnoshow/article/details/123808000
遇到问题感谢百度的帮助,课程实验的帮助以及室友、男朋友(划重点)。
还有一个,界面配色参考↓