theta=pi+atan2(-dis_y,-dis_x);
end
ify==re_m/2
theta=atan2(dis_y,dis_x)+0.0001;
end
xx=ceil(n*theta/(2*pi));
yy=ceil(l-r1);
ifyy>=1&&yy<=m&&xx>=1&&xx<=nimgn(y,x)=img(yy,xx);
end
end
end
end
figure;
imshow(imgn,[])
最后要说的是,一般我们要是有一全景图,通常会用cubic映射,将图像变换为立方体的六个面,然后通过图形学方法贴到立方体上,就能做岀类似谷歌街景的样子。
cubic映射应该才是全景图
最常用的处理方法,不过那又是另一类变换了。
2.GUI保存图像
%---Executesonbuttonpressinpushbutton5.
functionpushbutton5_Callback(hObject,eventdata,handies)
%hObjecthandletopushbutton5(seeGCBO)
%eventdatareserved-tobedefinedinafutureversionofMATLAB
%handiesstructurewithhandiesanduserdata(seeGUIDATA)globalsrc_img;
[filename,pathname]=
uiputfile({'*.jpg';'*.bmp';'*.gif;'*.png';'*.tif},'WritePic');
str=[pathnamefilename];
ifstr~=0
imwrite(src_img,str);
end
3.GUI读入图像
%---Executesonbuttonpressinpushbutton1.
functionpushbutton1_Callback(hObject,eventdata,handles)
%hObjecthandletopushbutton1(seeGCBO)
%eventdatareserved-tobedefinedinafutureversionofMATLAB
%handlesstructurewithhandlesanduserdata(seeGUIDATA)
[filename,pathname]=
uigetfile({'*.*';'*.jpg';'*.bmp';'*.gif;'*.png';'*.tif},'Read
Pic');
str=[pathnamefilename];
globalsrc_img;
if~isequal([pathname,filename],[0,0])
src_img=imread(str);
axes(handles.axesl);
imshow(src_img);
end
4.GUI选项卡
1.在这个网址下载一个工具包,里面应该有四个文件:
tabselectionfcp.p、tabselectionfcn.mtabpanel.p和tabpanel.m,显然代码用.p格式进行加密了。
2.建立一个空GUI文件,就起名kong.fig吧。
3.在kong.fig上画一个StaticText,默认的tag为textl。
4.终端运行tabpanel('kong.fig','text1');命令,得到如下界面:
kong
6.选中不同的选项卡,点击edit,就能进入常见的GUI编辑模式:
FiteEditViewLayoutTqqIs旦管Ip
石曰■I*■⑪町*腎鷹銅■Qrii*
TagiCurrentPoint[2恥.215]Position:
|27T69,42A,218]
7.编辑完保存下就行了,所有的功能都在kong.m文件中实现。
注意,不同选项卡添加的组建时,
tag会有重复,因此需要修改tag名。
8.终端输入kong就能得到如下结果:
5.structuretensor结构量
根据结构量能区分图像的平坦区域、边缘区域与角点区域。
此算法也算是计算机科学最重要的32个算法之一了。
的文章中此算法名称为Strukturtensor
算法,不过我搜索了一下,Strukturtensor这个单词好像是德语,翻译过来就是structuretensor
结构量了。
黎曼几何的量好多论文都叫量场了。
也不是数学界
主要是量分解。
这里的结构量就是一个矩阵,一个对
此处所说的量不是相对论或黎曼几何里的量,还没研究明白的对矩阵进行扩展的高阶量,图像像素进行组织的数据结构而已。
像素组织而成的矩阵如下:
这个公式太常见了,在harris角点检测中就用到了。
其中lx,Iy就是原对原图像在x和y方向
求得的偏导。
然后求矩阵E的行列式K和迹H。
然后根据K和H的关系就能区分图像的区域模式了
模式分以下三类:
平坦区域:
H=0;
边缘区域:
H>0&&K=0;
角点区域:
H>0&&K>0;
harris角点检测就用到了第三类判断。
当然,在实际应用的时候H和K的值肯定都不会是理想,所以我用的都是近似判断。
处理结果如下:
原图:
平坦区域:
边缘区域:
角点区域(好像也不全角点,求角点还是harris好了):
结构量行列式与迹的关系:
I
其中红框为平坦区域,黄框为边缘区域,铝框为角点区域。
matlab代码如下:
clearall;closeall;clc;
img=double(imread('lena.jpg'));
[mn]=size(img);
imshow(img,[])
[lxIy]=gradient(img);
Ix2=Ix.a2;
ly2=ly.A2;
Ixy=lx.*ly;
k=1;
lambda=zeros(m*n,2);
fori=
1:
m
for
j=1:
n
st
=[lx2(i,j)lxy(i,j);lxy(i,j)ly2(i,j)];%
结构量
K
=det(st);%
求行列式
H
=trace(st);%
求迹
%
所有的判断都是近似的
%
ifH<50%
认为是平坦区域
%
ifH>50&&abs(K)<0.01*10A(-9)
%认为是边缘区域
ifH>50&&abs(K)>0.01*10A(-9)
%认为是角点区域
img(i,j)=255;
end
lambda(k,:
)=[KH];
k=k+1;
end
end
figure;
plot(lambda(:
1),lambda(:
2),'.');
ylabel('trace');xlabel('det');
figure;
imshow(img,[])
6.模糊集图像增强算法有很多变种。
不过主要就是以下三步。
1.设计隶属度函数将图像从空间域变换到模糊集域。
2.设计模糊增强算子,在模糊集域对图像进行处理。
3.根据第1步的隶属度函数重新将图像从模糊集域变换到空间域。
这和频域处理中的变换反变换不是很像么。
我使用的隶属度函数和模糊增强算子在这篇论文里,也算相关算法的经典论文了
处理结果如下:
原图:
模糊集增强后:
matlab代码如下:
clearall;closeall;clc;
img=double(imread('lena.jpg'));
imshow(img,[])
[mn]=size(img);
Fe=1;%空制参数
Fd=128;
xmax=max(max(img));
u=(1+(xmax-img)/Fd)4(-Fe);%空间域变换到模糊域
%也可以多次迭代
fori=1:
m%模糊域增强算子
forj=1:
n
ifu(i,j)<0.5
u(i,j)=2*u(i,j)A2;
else
u(i,j)=1-2*(1-u(i,j))A2;
end
end
end
img=xmax-Fd.*(u.A(-1/Fe)-1);%模糊域变换回空间域
figure;
imshow(uint8(img));
7.随机游走图像
随机游走类似布朗运动,就是随机的向各个方向走吧。
虽然代码没什么技术含量,不过产生的图像实在太漂亮了,所以还是贴上来吧。
产生的图像:
clearall;closeall;clc
n=70000;%游走的步数。
也是图像中像素个数,有些位置可能重复,所
以白像素小于等于n
x=0;%初始x坐标
y=0;%初始y坐标
pix=zeros(n,2);%游走产生的像素坐标
neighbour=[-1-1;-10;-
11;0-1;01;1-1;10;11];%当前像素邻域
for
i=1:
n
r
=floor(1+8*rand());
%
八邻域随机选一个来走
y
=y+neighbour(r,
1);
%y
方向游走
x
=x+neighbour(r,
2);
%x
方向游走
pix(i,:
)=[yx];%保存坐标
end
pix(:
1)=pix(:
1)-miny+1;%像素坐标整体变为正
pix(:
2)=pix(:
2)-minx+1;
maxy=max(pix(:
maxx=max(pix(:
.
1));
2));
%
找最大坐标值,为开辟图像做准备
img=zeros(maxy,maxx);
%
根据maxymaxx产生图像
fori=1:
n
img(pix(i,
%
1),pix(i,
2))=
将游走的值赋给图像
1;
end
imshow(img)
8.最大流/最小割
学习这个算法是为学习图像处理中的图割算法做准备的。
基本概念:
1.最大流是一个有向图。
2.一个流是最大流,当且仅当它的残余网络中不包括增广路径。
3.最小割就是网络中所有割中值最小的那个割,最小割是不唯一的,不过最小割的值是唯一的
4.最大流的流量等于某一最小割的容量。
算法思想就是Ford-Fulkerson方法。
具体流程:
1.首先使用广度优先搜索找到源节点到汇节点的一条路径,为增广路径。
2.如果找不到新的从源到汇的增广路径,则上一次求得的网络就是最大流,否则向下执行。
3.找出增广路径中最小的路径的值。
5.用路径中最小的值构造最大流网络,原网络包含这个网络。
4.将增广路径中所有的路径减去最小路径这个值,形成新的网络图。
6.对新的网络图继续执行第1步。
网络图如下,没什么好办法形象表示。
我比较懒,不想画图了,真想看明白过程就看算法导论
405页。
最大流:
matlab代码如下:
clearall;closeall;clc
%初始化邻接压缩表,算法导论405页的图
b=[1
2
16;
1
4
13;
2
3
12;
2
4
10;
3
4
9;
3
6
20;
4
2
4;
4
5
14;
537;
564];
m=max(max(b(:
1:
2)));%压缩表中最大值就是邻接矩阵的宽与高
A=compresstable2matrix(b);%从邻接压缩表构造图的矩阵表示netplot(A,1);
maxflow=zeros(m,m);
while1
%
下面用广度优先搜索找增广路径
flag
=[];
%
相当于closed表,已访冋过的节点
flag
=[flag
1];
head
=1;
tail
=1;
queue
=[];
%
队列,相当于open表,将要访冋的节点
queue(head)
=1;
head
=head+1;
%
pa=zeros(1,m);pa
(1)=1;%
whiletail~=headi
每个节点的前趋
源节点前趋是自己
广度优先搜索,具体细节就不注释了
tail
end
=queue(tail);forj=1:
mifA(i,j)>queue(head)headflagpa(j)endend=tail+
1;
0&&isempty(find(flag==j,1))
=j;
=head+1;
=[flagj];
=i;
ifpa(m)==0%如果搜索不到汇节点,退出循环
break;
end
path=[];
i=m;
%
从汇节点开始
k=0;
%
路径包含的边的个数
while
i~=1
%
使用前趋构造从源节点到汇节点的路径
path
=[path;pa(i)iA(pa(i),i)];%存入路径
i
=pa(i);
%
使用前趋表反向搜寻,借鉴Dijsktra
方法
k
=k+1;
中的松弛
end
Mi=min(path(:
3));%寻找增广路径中最小的那条边
fori=1:
k
A(path(i,1),path(i,2))=A(path(i,1),path(i,2))-Mi;%增广路径中每条路径减去最小的边
maxflow(path(i,1),path(i,2))=maxflow(path(i,1),path(i,2))+Mi;%最大流,原网络包含这个网络,我只能这样表示了
end%使用新的图A进入下一循环,从新开始找增广
路径
end
figure;
netplot(maxflow,1)
9.单元最短路径
图的相关算法也算是自己的一个软肋了,当年没选修图论也是一大遗憾。
图像处理中,也有使用图论算法作为基础的相关算法,比如图割,这个算法就需要求最大流、最
小割。
所以熟悉一下图论算法对于图像处理还是很有帮助的。
Dijkstra和Bellman-Ford类似,都是解决单源最短路径问题,不同的是这个方法只能解决边为非负的问题,实现的好的Dijkstra算法运行时间要快于Bellman-ford。
算法步骤如下:
1.首先设置队列,所有节点入列,源节点值为0,其他节点值为无穷。
2.然后在队列中找值最小的节点并岀列。
3.计算出列的节点所有后继节点的距离。
4.松弛方法,如果新计算的距离小于上次计算的距离,那么更新距离,即将后继节点值设为较小
的距离,并将后继节点的前趋设为当前的出列节点。
5.对剩余的节点队列继续找最小值并岀列,不断循环2、3、4步直到队列中没有节点了。
步骤是上面没错,不过我程序中没有完全按照上述的步骤实现。
不同的地方在于我没有做出列操
作,而是通过标记节点的形式实现的。
m=max(max(b(:
1:
2)));%
A=compresstable2matrix(b);%
netplot(A,1)%
S=inf(1,m);%
S
(1)=0;%
pa=zeros(1,m);%
和上一篇使用的一样:
main.m
clearall;closeall;clc
捌始化邻接压缩表,1210表示从节点1到节点2,边的权重为10b=[1210;145;231;
242;354;423;
439;452;517;
536];
压缩表中最大值就是邻接矩阵的宽与高从邻接压缩表构造图的矩阵表示形象表示
从开始的源点到每一个节点的距离
源点到自己的距离为0
存储每个节点的前驱,在松弛过程中赋值
visit=zeros(1,m);%标记某个节点是否访问过了
index=1;%从index节点开始搜索
%判断是否对所有节点都找的最短路径了。
可能会有源点没有路径到目标节点的情况,那就无限循环了
whilesum(visit)~=m%没有出队列操作,不过通过visit来等价的表示了
visit(index)=1;%标记第index节点为已入列的节
占
八、、
[Spa]=relax(S,pa,A,visit,index,m);%松弛,如果两个节点间
有更短的距离,则用更短的距离
index=extract_min(S,visit,index,m);%使用已访问的最小的节点作为下
一次搜索的开始节点
end
%最终我们需要的就是这两个值
S%源点到其他每一点的距离
pa%其他每一节点的前趋
%算法到此结束,下面只是为了形象的表示而写的。
re=[];
fori=2:
m
re=[re;pa(i)iA(pa(i),i)];
end
A=compresstable2matrix(re);%从邻接压缩表构造图的矩阵表示
figure;
netplot(A,1)%形象表示
relax.m
%边缘松弛,使用更短的距离作为节点的值function[Spa]=relax(S,pa,A,visit,index,m)
i=index;
1%搜索没有标记过的节点
%将较小的值赋给正在搜寻的节点
forj=1:
m
ifA(i,j)~=inf&&visit(j)~=ifS(j)>S(i)+A(i,j)
S(j)=S(i)+A(i,j);
pa(j)=i;
end
end
end
end
extract_min.m
%!
取队列未标记的最小的值的序号
functionindex=extract_min(S,visit,index,m)
Mi=inf;
forj=1:
m
ifvisit(j)~=1ifS(j)Mi=S(j);
index=j;
end
end
endend
10.单元最短路径
只能解决权值非
直到达到最短的路
该算法可以用来解决一般(边的权值为负)的单源最短路径问题,而dijkstra
负的情况。
此算法使用松弛技术,对每一个顶点,逐步减少源到该顶点的路径的估计值,径。
算法运算结果:
matlab代码如下,netplot函数在这里,不过当时函数中表示两节点没有路径用的是0,而现在
需要改成inf:
clearall;closeall;clc
%初始化邻接压缩表b=[126;
147
235;
248;
25-4;
32-2;
43-3;
459;
512;
537];
m=max(max(b(:
1:
2)));%
A=compresstable2matrix(b);%netplot(A,1)%
压缩表中最大值就是邻接矩阵的宽与高从邻接压缩表构造图的矩阵表示形象表示
S=inf(1,m);%
S
(1)=0;%
pa=zeros(1,m);%
pa
(1)=1;%
源到其他节点的最短距离,开始为inf
源点到自己的距离为0
寻找到的节点的前趋
源点的前趋是自己
pre_pa=ones(1,m);
whilesum(pre_pa==pa)~=m是最佳实践一
%终止条件,判断终止的方法很多,这个应该不
pre_pa=pa;fork=1:
m
ifpre_pa(k)~=0%对每一个已搜寻到的节点,从此
节点寻找后继节点
i=k;
forj=1:
m
ifA(i,j)~=inf
ifS(j)>S(i)+A(i,j)
S(j)=S(i)+A(i,j);%边缘松弛,取两节点间
最小权值作为实际权值
pa(j)=i;%寻找前趋
end
end
end
end
end
end
%最终我们需要的就是这两个值
S%源点到其他每一点的距离pa%其他每一节点的前趋
%算法到此结束,下面只是为了形象的表示而写的。
re=[];
fori=2:
m
re=[re;pa(i)iA(pa(i),i)];
end
A=compresstable2matrix(re