(结合左侧的目录学习体验会更好)
本篇内容是我用matlab学习图像处理的记录,分为两个部分。
第一部分总结了matlab基础语法;第二部分实现了一个图像处理入门的算法。
图像处理基础算法
参考代码都是可以优化的,下面示例定位是简单入门。
图像导入与格式转换
clc;
clear;
close all;
%-----读--取--图--片--并--显--示---------
% imread 读一张图片,括号里格式为字符串,这字符串表示你要读取图片的路径
img = imread('1.jpg');
% 函数figure: 建立一个窗口 可以直接用数字去编号:
% figure(1);
% 关于figure的用法参考:https://blog.csdn.net/qq_30387863/article/details/80301996
% 命名编号:括号里两个参数:第一个是指定参数为'name', 第二个写你要起的名字
figure('name', '小黑')
% 函数imshow:显示图片 括号里面是需要显示的图片的名字
imshow(img);
% -----图--像--的--表--示-----
% 关于图像里面的数据格式,常见的是uint8和double
% 其中,uint8指的是没有符号的整数,即非负整数,double指的是精确度比较高的浮点数
% 彩图和灰度图的转化不是可逆的,彩图到灰度图可以用函数rgb2gray
gray = rgb2gray(img);
figure('name', 'gray');
imshow(gray);
% ---保存图片到指定位置---
% 用 imwrite(A,filename)
% 将图像数据 A 写入 filename 指定的文件,并从扩展名推断出文件格式。
均值滤波
说明
均值滤波的代码:code.m
示例用的思路是:
选取相邻3x3的范围,用9个数字的平均作为滤波结果,进行赋值。
均值滤波的两种方法:一个是示例的邻域平均,另一个是根据距离目标像素点的远近乘以加权的系数,叫做加权平均,像高斯滤波就是如此。
参考
这篇文章介绍得挺好:
代码
code.m
clc;
clear;
close all;
img = imread('1.jpg');
gray = rgb2gray(img);
figure('name', 'gray');
imshow(gray);
[m, n] = size(gray);
avg_filter = gray;
for i = 2:m-1
for j = 2:n-1
filter_con = gray(i-1:i+1, j-1:j+1);
k = sum(sum(filter_con))/9;
avg_filter(i, j) = k;
end
end
figure('name', 'avg_filter');
imshow(avg_filter);
sobel算法
说明
文件code.m,
利用sobel算子可以将图像周围像素灰度有阶跃变化的像素检测出来,这些像素组成的集合就是该图像的边缘。
实现: 分别用检测垂直边缘和检测水平边缘的算子对图像一点作平面卷积,然后开平方得到该点的灰度值。
参考
sobel参考 原理可以,里面参考代码不太行,漏洞太多。
代码
code.m
clc;
clear;
close all;
img = imread('1.jpg');
figure('name', '原图');
imshow(img);
gray = rgb2gray(img);
[m, n] = size(gray);
% 预设好矩阵大小
x_sobel = double(gray);
y_sobel = double(gray);
img_sobel = gray;
for i = 2:m-1
for j = 2:n-1
% 分别用x、y方向的算子检测边缘,然后合成
% x_con = [-1,0,1; -2,0,2; -1,0,1];
% y_con = [-1,-2,-1; 0,0,0; 1,2,1];
x_sobel(i,j) = (-1*gray(i-1, j-1) + gray(i-1, j+1) ... % 三个省略号表示接着下一行
-2*gray(i, j-1) + 2*gray(i, j+1) ...
-1*gray(i+1, j-1) + gray(i+1, j+1));
y_sobel(i, j) = (-1*gray(i-1, j-1) - 2*gray(i-1, j) - gray(i-1, j+1) ...
+gray(i+1, j-1) + 2*gray(i+1, j) + gray(i+1, j+1));
end
end
img_sobel = sqrt(x_sobel.^2 + y_sobel.^2);
figure('name', 'img_sobel');
imshow(uint8(img_sobel));
腐蚀膨胀
说明
文件 code1.m:
膨胀,使图像中亮的区域增长
使用卷积核B对图片A进行卷积运算,求局部最大值,这个卷积核可以有任意的形状和大小,通常是一个方形或者圆形。卷积核B通常有个锚点,通常位于卷积核的中央位置。
随着卷积核扫描图像,计算叠加区域的最大像素值,并将锚点的位置用最大值替换,从而导致图片中亮的区域增长。
文件code2.m:
腐蚀,使亮色的区域减少
文件code3.m:
开操作, 先腐蚀后膨胀;先膨胀后腐蚀是闭操作;
顶帽操作和底帽操作是灰度图像所特有的,其原理是开操作将使峰顶消去,具体消去了多少呢,可以用原图减去开操作结果,这样就能得到其消去的部分,而这个过程成为顶帽操作,顶帽就是开操作消去的峰顶,这一部分对应于图像中较亮的部分,也叫白色顶帽。
开运算放大了裂缝或者局部低亮度的区域,所以,从原图中减去开运算后的图,得到的结果突出了比原图轮廓周围的区域更明亮的区域,这个操作与选择的核的大小有关。TopHat运算一般用来分离比邻近点亮一些的斑块,可以使用这个运算提取背景。
同理,底帽操作是用闭操作的结果减去原图就得到被闭操作填充的谷底部分,这一部分对应于图像中较暗的部分,也叫黑色底帽。黑帽运算的结果突出了比原图轮廓周围区域更暗的区域,所以黑帽运算用来分离比邻近点暗一些的斑块。
参考
代码
code1.m
clc;
clear;
close all;
path = '1.jpg';
img = imread(path);
figure('name', '原图')
imshow(img);
% 膨胀:这里对灰度图腐蚀,其他类型图像同理
gray = rgb2gray(img);
figure('name', '灰度图')
imshow(gray);
[m,n] = size(gray);
pz = gray; % 提前预分配,优化速度
for i = 2 : m-1
for j = 2 : n-1
% con是选了3*3大小的卷积区域,然后腐蚀
con = gray(i-1:i+1, j-1:j+1);
% 一次max求每列最大,二次是整体最大
pz(i,j) = max(max(con));
end
end
figure('name', 'fs');
imshow(pz);
code2.m
clc;
clear;
close all;
path = '1.jpg';
img = imread(path);
figure('name', '原图')
imshow(img);
% ----------对--灰--度--图--腐--蚀---------
% gray = rgb2gray(img);
% figure('name', '灰度图')
% imshow(gray);
%
% [m,n] = size(gray);
% fs = gray; % 提前预分配,优化速度
% for i = 2 : m-1
% for j = 2 : n-1
% % con是选了3*3大小的卷积区域,然后腐蚀
% con = gray(i-1:i+1, j-1:j+1);
% fs(i,j) = min(min(con));
%
% end
% end
%
% figure('name', 'fs');
% imshow(fs);
%------------对--彩--色--图-------------
r = img(:, :, 1);
g = img(:, :, 2);
b = img(:, :, 3);
[m, n] = size(r);
r_out = r;
for i = 2 : m-1
for j = 2 : n-1
con = r(i-1:i+1, j-1:j+1);
r_out(i,j) = min(min(con));
end
end
g_out = g;
for i = 2 : m-1
for j = 2 : n-1
con = g(i-1:i+1, j-1:j+1);
g_out(i,j) = min(min(con));
end
end
b_out = b;
for i = 2 : m-1
for j = 2 : n-1
con = b(i-1:i+1, j-1:j+1);
b_out(i,j) = min(min(con));
end
end
out = cat(3, r_out, g_out, b_out);
figure('name', 'fs_color');
imshow(out);
code3.m
clc;
clear;
close all;
path = '1.jpg';
img = imread(path);
figure('name', '原图')
imshow(img);
% ----开--运--算------
gray = rgb2gray(img);
figure('name', '灰度图')
imshow(gray);
% 先腐蚀
[m,n] = size(gray);
fs = gray;
for i = 2 : m-1
for j = 2 : n-1
con = gray(i-1:i+1, j-1:j+1);
fs(i,j) = min(min(con));
end
end
% 后膨胀
pz = fs;
for i = 2 : m-1
for j = 2 : n-1
con = fs(i-1:i+1, j-1:j+1);
pz(i,j) = max(max(con));
end
end
open_img = pz;
figure('name', 'open_img');
imshow(open_img);
% ------顶--帽:找出多膨胀的那一块亮度--------
% 原图-开运算的图
top_hat = gray - open_img;
figure('name', 'top_hat');
imshow(top_hat);
% 备注: 由上面代码变换顺序做一下微调整,便可以得到闭运算、黑帽
直方图均衡化
说明
原理
当图像直方图完全均匀分布的时候,此时图像的熵是最大的(随机变量每个值的概率都相同时,概率最大),图像对比度是最大的。直方图均衡化就是让图像的像素值所组成的直方图均匀分布,达到提高亮度的作用。
code.m 是用灰度图实现
code_color.m 是彩色图
coloraverage.m 是对code_color.m 的写法改进
参考
代码
code.m
clc
clear
close all;
% 读图
img = imread('1.jpg');
%灰度图处理
gray = rgb2gray(img);
figure('name', 'original gray');
imshow(gray);
%读取灰度图 及直方图
[R,C]=size(gray);
% figure(2);
% imhist(I);
%统计灰度
s=zeros(1,256);
for i=1:R
for j=1:C
s(1,gray(i,j)+1)=s(1,gray(i,j)+1)+1;
end
end
%算概率
p=zeros(1,256);
for i=1:256
p(i)=s(i)/(R*C*1.0);
end
%累计直方图
c=zeros(1,256);
c(1)=p(1);
for i=2:256
c(i)=c(i-1)+p(i);
end
%取整
% c = uint8(255.*c+0.5);
c= round(255.*c);
% 均衡
for i=1:R
for j=1:C
gray(i,j)=c(gray(i,j)+1);
end
end
%8 输出直方图均衡化后的图像
figure('name', 'out_hisq');
imshow(gray);
% figure(4);
% imhist(I);
code_color.m
clc
clear
close all;
% 读图
img = imread('1.jpg');
figure('name', 'original image');
imshow(img);
figure(12);
imshow(histeq(img, 256));
%彩图处理
r = img(:, :, 1);
g = img(:, :, 2);
b = img(:, :, 3);
% 获得图像的尺寸大小
[R, C]=size(r);
% ----分--图--层--处--理------
% ----r----
r_out = r;
s = zeros(1,256);
for i = 1:R
for j=1:C
s(1, r_out(i,j)+1)=s(1, r_out(i,j)+1)+1;
end
end
%算概率
p = zeros(1,256);
for i = 1:256
p(i)=s(i)/(R*C*1.0);
end
%累计直方图
c=zeros(1,256);
c(1)=p(1);
for i=2:256
c(i)=c(i-1)+p(i);
end
%取整
% c = uint8(255.*c+0.5);
c= round(255.*c);
% 均衡
for i=1:R
for j=1:C
r_out(i,j)=c(r_out(i,j)+1);
end
end
% -----g-------
g_out = g;
s=zeros(1,256);
for i=1:R
for j=1:C
s(1, g_out(i,j)+1) = s(1, g_out(i,j)+1)+1;
end
end
%算概率
p=zeros(1,256);
for i=1:256
p(i)=s(i)/(R*C*1.0);
end
%累计直方图
c=zeros(1,256);
c(1)=p(1);
for i=2:256
c(i)=c(i-1)+p(i);
end
%取整
% c = uint8(255.*c+0.5);
c= round(255.*c);
% 均衡
for i=1:R
for j=1:C
g_out(i,j) = c(g_out(i,j)+1);
end
end
% -----b-------
b_out = b;
s=zeros(1,256);
for i=1:R
for j=1:C
s(1, b_out(i,j)+1) = s(1, b_out(i,j) + 1) + 1;
end
end
%算概率
p=zeros(1,256);
for i=1:256
p(i)=s(i)/(R*C*1.0);
end
%累计直方图
c=zeros(1,256);
c(1)=p(1);
for i=2:256
c(i)=c(i-1)+p(i);
end
%取整
% c = uint8(255.*c+0.5);
c= round(255.*c);
% 均衡
for i = 1:R
for j = 1:C
b_out(i,j) = c(b_out(i,j)+1);
end
end
out = cat(3, r_out, g_out, b_out);
% 输出直方图均衡化后的图像
figure('name', 'out_hisq');
imshow(out);
coloraverage.m
%主函数
function coloraverage()
I=imread('1.jpg');
imshow(I);
I1=I(:,:,1);%提取红色分量
I2=I(:,:,2);%提取绿色分量
I3=I(:,:,3);%提取蓝色分量
I1=histogram(I1); %构造的函数
I2=histogram(I2);
I3=histogram(I3);
c=cat(3,I1,I2,I3); %cat用于构造多维数组
subplot(1,2,1);imshow(I);
subplot(1,2,2);imshow(c);
%调用的(直方图均衡化)构造函数
function d=histogram(I)%构造histogram函数
J=I;
[m,n]=size(I); %确定矩阵大小
area=m*n;
a=zeros(1,256); %产生1*256的零矩阵a,用来存放原始图像各个灰度值的个数
b=zeros(1,256);
for i=1:m %记录各个灰度值的个数
for j=1:n
d=I(i,j)+1; %获取(i,j)位置的灰度值(注意:灰度值为0-255,对应矩阵的1-256)
a(1,d)=a(1,d)+1; %矩阵a上对应灰度值的计数+1
end
end
for i=1:256 %均衡化
sum=0;
for j=1:i
sum=sum+a(1,j);
end
b(1,i)=sum*255/area;
end
for i=1:m %用均衡化后的数据代替原位置的数据
for j=1:n
d=J(i,j)+1;
J(i,j)=b(1,d);
end
end
d=J;
Reference
1、书:数字图像处理,朱虹等著
2、知乎/CSDN等网友的博客贴: