2016-01-17 18:24:34 denny2015 阅读数 2221
  • OpenGL实现Google地图瓦片的绘制漫游视频教程

    OpenGL实现Google地图瓦片的绘制漫游视频培训课程:此次教程所涉及的内容有OpenGL绘制图片、FreeImage加载图片、墨卡托投影、瓦片的金字塔模型、FramebufferObject、地图的移动和缩放优化,采用屏幕瓦片绘制优化、采用ImageBuffer优化、采用多线程优化、地图操作优化、模拟,生成全球瓦片(debug)、MFC-对话框中绘制地图、MFC-View中绘制地图、QT中绘制地图、在线浏览Google地图等。

    8809 人正在学习 去看看 张立铜

实际上前面我们就已经用到了图像的绘制,如:

io.imshow(img)  

这一行代码就是得利用matplotlib包对图片进行绘制,绘制成功后,返回一个matplotlib类型的数据。要显示绘制的图片,我们可以调用show()函数来进行显示,但进行练习的时候,一般我们可以省略show()函数,也能自动显示出来。

from skimage import io,data
img=data.astronaut()
dst=io.imshow(img)
print(type(dst))
io.show()

显示为:

可以看到,类型是'matplotlib.image.AxesImage',它除了图像本身信息,还有坐标尺等其它信息。如果要同时显示两张图片,那么在显示第二张图片的时候,会把第一张图片覆盖掉。

matplotlib是一个专业绘图的库,相当于matlab中的plot,可以设置多个figure,设置figure的标题,隐藏坐标尺,甚至可以使用subplot在一个figure中显示多张图片。一般我们可以这样导入matplotlib库:

import matplotlib.pyplot as plt

也就是说,我们绘图实际上用的是matplotlib包的pyplot模块。

例:分开并同时显示宇航员图片的三个通道

from skimage import data
import matplotlib.pyplot as plt
img=data.astronaut()
plt.figure(num='astronaut',figsize=(8,8))  #创建一个名为astronaut的窗口,并设置大小 

plt.subplot(2,2,1)     #将窗口分为两行两列四个子窗口,则可显示四幅图片
plt.title('origin image')   #第一幅图片标题
plt.imshow(img)      #绘制第一幅图片

plt.subplot(2,2,2)     #第二个子窗口
plt.title('R channel')   #第二幅图片标题
plt.imshow(img[:,:,0],plt.cm.gray)      #绘制第二幅图片,且为灰度图
plt.axis('off')     #不显示坐标尺寸

plt.subplot(2,2,3)     #第三个子窗口
plt.title('G channel')   #第三幅图片标题
plt.imshow(img[:,:,1],plt.cm.gray)      #绘制第三幅图片,且为灰度图
plt.axis('off')     #不显示坐标尺寸

plt.subplot(2,2,4)     #第四个子窗口
plt.title('B channel')   #第四幅图片标题
plt.imshow(img[:,:,2],plt.cm.gray)      #绘制第四幅图片,且为灰度图
plt.axis('off')     #不显示坐标尺寸

plt.show()   #显示窗口

另外一种编写方法也可以:

import matplotlib.pyplot as plt
from skimage import data,color

img = data.immunohistochemistry()
hsv = color.rgb2hsv(img)

fig, axes = plt.subplots(2, 2, figsize=(7, 6))
ax0, ax1, ax2, ax3 = axes.ravel()

ax0.imshow(img)
ax0.set_title("Original image")

ax1.imshow(hsv[:, :, 0], cmap=plt.cm.gray)
ax1.set_title("H")

ax2.imshow(hsv[:, :, 1], cmap=plt.cm.gray)
ax2.set_title("S")

ax3.imshow(hsv[:, :, 2], cmap=plt.cm.gray)
ax3.set_title("V")

for ax in axes.ravel():
    ax.axis('off')

fig.tight_layout()  #自动调整subplot间的参数

两种书写方法效果是一样的,你喜欢哪种就用哪种!!

除了使用matplotlib库来绘制图片,skimage还有另一个模块ImageViewer,也可以显示图片。

它是利用Qt工具来创建一块画布,从而在画布上绘制图像。

例:

from skimage import data
from skimage.viewer import ImageViewer

img = data.coins()
viewer = ImageViewer(img)
viewer.show()

 

2019-04-11 20:48:09 Dujing2019 阅读数 365
  • OpenGL实现Google地图瓦片的绘制漫游视频教程

    OpenGL实现Google地图瓦片的绘制漫游视频培训课程:此次教程所涉及的内容有OpenGL绘制图片、FreeImage加载图片、墨卡托投影、瓦片的金字塔模型、FramebufferObject、地图的移动和缩放优化,采用屏幕瓦片绘制优化、采用ImageBuffer优化、采用多线程优化、地图操作优化、模拟,生成全球瓦片(debug)、MFC-对话框中绘制地图、MFC-View中绘制地图、QT中绘制地图、在线浏览Google地图等。

    8809 人正在学习 去看看 张立铜

数字图像处理—频域处理

(四)从空域滤波器获得频域滤波器

通常,当滤波器较小时,使用空域滤波要比频域滤波在计算上更有效。 “小”的定义是很复杂的问题,答案取决于很多因素,比如使用的机器和算法、缓冲区的大小、所处理数据的复杂度等。空域是指图像平面本身,空域滤波这类方法直接对图像的像素进行处理。频域滤波是变换域滤波的一种,它是指将图像进行变换后(频域是指经过傅里叶变换之后),在变换域中对图像的变换系数进行处理(滤波),处理完毕后再进行逆变换,获得滤波后的图像。

下面我们来进行空域和频域滤波器的比较,编码分析,详细步骤在代码注释:

1 空域滤波器
使用空域模板进行的图像处理,被称为空域滤波。模板本身被称为空域滤波器。

代码编写:

g = imread('D:\数字图像处理\第三章学习\blackhole.png');
f = im2double(rgb2gray(g));    %把图像变为灰度图像
h = fspecial('sobel');         %使用 fspecial 生成空域滤波器
figure;
freqz2(h);                     %查看sobel算子的频域响应图形
gs = imfilter(f,h);            %生成滤波图
figure;
subplot(1, 3, 1), imshow(g), title('原图像');
subplot(1, 3, 2), imshow(f), title('原图像的灰度图像');
subplot(1, 3, 3), imshow(gs,[]), title('空域滤波图像');

代码运行效果如下:

在这里插入图片描述
频域滤波器

频域滤波是在频率域对图像做处理的一种方法。滤波器大小和频谱大小相同,相乘即可得到新的频谱。滤波后结果显示,低通滤波去掉了高频信息,即细节信息,留下的低频信息代表了概貌。

代码编写:

%从空间域中获得频域滤波器,
g = imread('D:\数字图像处理\第三章学习\blackhole.png');
f = im2double(rgb2gray(g));    %把图像变为灰度图像
h = fspecial('sobel');         %生成垂直sobel掩膜
PQ=paddedsize(size(f));        %获取填充尺寸
H=freqz2(h,PQ(1),PQ(2));       %获得sobel算子的频域响应
H1=ifftshift(H);               %重排数据序列,以使频域变换的原点位于频率矩形的左上角(因为freqz2产生的频域响应原点默认在频率矩形中心!)
gs = imfilter(f,h);            %空域滤波图像
gf=dftfilt(f,H1);              %采用默认值 0 填充边缘,频率域滤波函数,第一个参数为原始图像,后者为二维频率域滤器
figure;
subplot(2, 2, 1), imshow(g), title('原图像');
subplot(2, 2, 2), imshow(f), title('原图像的灰度图像');
subplot(2, 2, 3), imshow(gs ,[]), title('空域处理的滤波图像');
subplot(2, 2, 4), imshow(gf ,[]), title('频域处理的滤波图像');
figure;
subplot(1, 2, 1),imshow(abs(gs) ,[]), title('空域处理的滤波图像绝对值'); 
subplot(1, 2, 2),imshow(abs(gf) ,[]), title('频域处理的滤波图像绝对值');
figure;
subplot(1, 2, 1),freqz2(H), title('透视图H'); 
subplot(1, 2, 2),freqz2(H1), title('ifftshift 重排后透视图H1');
figure;
subplot(1, 2, 1), imshow(abs(H), [ ]), title('以图像形式显示H的绝对值');
subplot(1, 2, 2), imshow(abs(H1), [ ]), title('以图像形式显示H1的绝对值');

图像运行效果如下:



代码运行效果显示空域处理与频域处理图像显示一样,我们再通过计算它们的差别来证实这个事实:

d = abs(gs - gf);

最大差别为:
在这里插入图片描述
在现有应用中可以忽略。

最小差别是:
在这里插入图片描述
实验结论:可看见,差异很小。产生原因:频域操作中FFT和IFT中由于复数的存在产生的舍入误差(空域操作中不产生复数)。故结论:使用空间域滤波和频域滤波得到的图像对所有实用目的来说,都是相同的。

(五)在频域中直接生成滤波器

5.1 建立网格数组以实现频域滤波器

对于 M-函数最主要的是:需要在频率矩形中计算任意点到规定点的距离函数。称为dftuv的M-函数提供了距离计算以及其他类似应用所需要的网格数组。由 dftuv 生成的网格数组已经满足 fft2 和 ifft2 处理的需要,不需要数据重排。

dftuv 源码:

function [U, V] = dftuv(M, N) 
u = single(0:(M - 1)); 
v = single(0:(N - 1));
idx =  find(u > M/2}; 
u(idx) = u(idx) - M; 
idy = find(v > N/2); v(idy) = v(idy) - N;
[V, U] == meshgrid(v, u);

举例说明函数 dftuv的使用:

计算 8x5 大小的矩形上每一点到矩形原点距离的平方:

代码编写:

[U, V] = dftuv(8, 5);
DSQ = U.^2 + V.^2;

运行效果如下:

注意:距离在左上角是0,最大距离位置在频域矩形中心。可以使用函数 fftshift 来获得关于频域矩形中心的距离:

现在,距离为 0的点的坐标为(5, 3),数组关于这一点对称。

5.2 频域低通(平滑)滤波器

理想低通滤波器(ILPF)具有如下传递函数:
在这里插入图片描述
其中,D0D_0 为正数,D(u,v)为点(u,v)到滤波器 中心的距离。满足的点的轨迹为圆。 因为滤波器H(u,v)乘以一幅图像的傅立叶变换,我们看到理想滤波器切断(乘以0)圆外的所有 F(u,v)分量,而保留圆上和圆内的点不变(乘以 1)。虽然这个滤波器不能用类似的电子元件实现, 但的确可以在计算机中用前面介绍的传递函数实现。理想滤波器的特性通常用来解释振铃和折叠误差等现象。 图像处理中,对一幅图像进行滤波处理,若选用的频域滤波器具有陡峭的变化,则会使滤波图像产生“振铃”,所谓“振铃”,就是指输出图像的灰度剧烈变化处产生的震荡,就好像钟被敲击后产生的空气震荡。

现在对图像进行理想低通滤波:

编写代码:

X=imread('D:\数字图像处理\第三章学习\blackhole.png');
I1=X;
f=double(I1);
g=fft2(f);
g=fftshift(g);    %傅立叶变换
[N1,N2]=size(g);  %转换数据矩阵
n=1;
d0=30;            %可以通过修改d0来决定过滤掉多少高频,从而查看不同的理想低通的效果
n1=fix(N1/2);
n2=fix(N2/2);
for i=1:N1;
for j=1:N2;
    d=sqrt((i-n1)^2+(j-n2)^2);
if d>d0           %距离频域中心距离超过d0的都被完全过滤,体现理想低通
 h=0; 
else
  h=1; 
end
 result(i,j)=h*g(i,j); %这里是相乘,不是卷积
end
end
result=ifftshift(result);
X2=ifft2(result);
figure;
subplot(1,2,1),imshow(I1,[]),title('原图像');
subplot(1,2,2),imshow(real(X2),[]),title('截断频率d0=30的理想低通滤波结果');%存在振铃效应

代码运行效果如下:

n阶的布特沃斯低通滤波器(BLPF), 具有从滤波器中心到 A) 的距离的截止频率,传递函数为:
在这里插入图片描述
与理想低通滤波器不同,布特沃斯低通滤波器的传递函数在 A) 点没有尖锐的不连续。

现在对图像进行布特沃斯低通滤波:

编写代码:

I1=imread('D:\数字图像处理\第三章学习\blackhole.png');
f=double(I1);                %数据类型转换
g=fft2(f);                   %图像傅里叶转换
g=fftshift(g);               %傅里叶变换平移
F2=log(abs(g));              %对傅里叶变换结果取绝对值,然后取对数
[N1,N2]=size(g);             %傅里叶变换图像尺寸
n=2;                         %参数赋初始值
d0=5;
n1=fix(N1/2);                %数据圆整
n2=fix(N2/2);                %数据圆整
for i=1:N1                   %遍历图像像素
for j=1:N2 
d=sqrt((i-n1)^2+(j-n2)^2);
if d==0
h=0;
else
h=1/(1+(d/d0)^(2*n));
end
result(i,j)=h*g(i,j);         %图像矩阵计算处理
end
end
result=ifftshift(result);
X2=ifft2(result);
X3=uint8(real(X2));
subplot(1,2,1),imshow(I1),title('原图像');
subplot(1,2,2),imshow(X3),title('Butterworth低通滤波图像');


代码运行效果如下:

滤波器就是建立的一个数学模型,通过这个模型来将图像数据进行能量转化,噪声就是属于高频率部分,高斯滤波器平滑处理后降低噪声的影响。若使用理想滤波器,会在图像中产生振铃现象。采用高斯滤波器的话,系统函数是平滑的,避免了振铃现象。它的特性是连续性衰减,而不像理想滤波器那样陡峭变化,即明显的不连续性。因此采用该滤波器滤波在抑制噪声的同时,图像边缘的模糊程度大大减小,没有振铃效应产生。 可用于平滑处理,如图像由于量化不足产生虚假轮廓时,常可用低通滤波进行平滑以改进图像质量。传递函数由下式给出:

在这里插入图片描述
现在对图像进行高斯低通滤波:

编写代码:

w = imread('D:\数字图像处理\第三章学习\blackhole.png');
f = im2double(rgb2gray(w));    %把图像变为灰度图像
PQ = paddedsize(size(f));      %产生滤波时所需大小的矩阵
[U, V] = dftuv(PQ(1),PQ(2)); 
DO = 0.05*PQ(2);               %设定高斯滤波器的阈值
F = fft2(f, PQ(1), PQ(2));     %傅里叶变换
H = exp(-(U.^2+V.^2)/(2*(DO^2))); 
g = dftfilt(f,H);              %用滤波器对图像进行频域滤波
figure;
subplot(2, 2, 1), imshow(w), title('原图像');
subplot(2, 2, 2), imshow(fftshift(H),[]), title('以图像显示的高斯低通滤波器');
subplot(2, 2, 3), imshow(log(1 + abs(fftshift(F))),[]), title('对数增强并居中的fft');
subplot(2, 2, 4), imshow(g,[]), title('高斯低通滤波后的图像的谱');

三个滤波器分别在空域和频域进行对比:

代码编写:

d0=8;
M=60;N=60;
c1=floor(M/2);     
c2=floor(N/2);      
h1=zeros(M,N);      %理想低通滤波
h2=zeros(M,N);      %布特沃斯滤波
h3=zeros(M,N);      %高斯滤波
sigma=4;
n=4;%布特沃斯阶数
for i=1:M
    for j=1:N
        d=sqrt((i-c1)^2+(j-c2)^2);
        if d<=d0
            h1(i,j)=1;
        else
            h1(i,j)=0;
        end
        h2(i,j)=1/(1+(d/d0)^(2*n)); 
        h3(i,j)=exp(-d^2/(2*sigma^2)); 
    end
end
draw2(h1,'理想低通滤波器');
draw2(h2,'布特沃斯滤波器');
draw2(h3,'高斯低通滤波器');
 
function draw2(h,name)
figure;
surf(h);title(strcat('频域',name));
fx=abs(ifft2(h));
fx=fftshift(fx);
figure;surf(fx);title(strcat('空域',name));
end

代码运行效果如下:


实验结论:

理想滤波器有振铃现象发生,可以看出空域滤波函数图像外围有剧烈震荡,平滑效果较为粗糙;布特沃斯滤波器几乎没有振铃现象,图像较理想滤波器而言平滑效果也比较好,高斯滤波器没有振铃现象,其平滑效果是三者最好的。

5.3 线框及表面绘制

要画 MxN大小的二维函数 H 的线框图,最容易的方法是使用函数 mesh。

编写代码:

H = fftshift(lpfilter('gaussian', 500, 500, 50)); 
mesh(double(H(1:10:500, 1:10:500)));
axis tight;

代码运行效果如下:

线框图默认为彩色的,从底部为蓝色渐变到顶部为红色。通 过键入下面的命令,可以把绘图的线条变为黑色,并消除轴和栅格:

编写代码:

H = fftshift(lpfilter('gaussian', 500, 500, 50)); 
mesh(double(H(1:10:500, 1:10:500)));
colormap ( [0 0 0] );   %把绘图的线条变为黑色,
axis off ;      %消除轴
grid off ;      %消除栅格

代码运行效果如下:

将观察者稍微向右移,并保持仰角不变。view(az, el),az 和 el 分别代表方位角和仰角(以度表示)。默认值 是 az=-37.5,el=30。
在这里插入图片描述

编写代码:

H = fftshift(lpfilter('gaussian', 500, 500, 50)); 
mesh(double(H(1:10:500, 1:10:500)));
view (-25, 30);

代码运行效果如下:

保持方位角为-25 并将仰角设置为 0之后,
编写代码:

H = fftshift(lpfilter('gaussian', 500, 500, 50)); 
mesh(double(H(1:10:500, 1:10:500)));
view (-25, 0 );

代码运行效果如下:

有时候,需要能以表面图代替线框图的绘制函数。函数surf 可做这件事。

代码编写:

H = fftshift(lpfilter('gaussian', 500, 500, 50)); 
surf(double(H(1:10:500, 1:10:500)));
axis tight;
colormap(gray);   %将颜色转为灰度
axis off;

代码运行效果如下:

运行下面代码平滑小面描影和消除栅网线:

代码编写:

H = fftshift(lpfilter('gaussian', 500, 500, 50)); 
surf(double(H(1:10:500, 1:10:500)));
axis tight;
colormap(gray);
axis off;
shading interp;    %平滑小面描影和消除栅网线

代码运行效果如下:

如果目的是绘制含有两个变量的解析函数,就用 meshgrid 产生坐标值,并从这些坐标值 中产生将在 mesh 或 surf 中使用的离散(抽样)矩阵。

代码编写:

H = fftshift(lpfilter('gaussian', 500, 500, 50)); 
[Y, X] = meshgrid(-2:0.1:2, -2:0.1:2); 
Z = X.*exp(-X.^2 - Y.^2); 
surf(Z);
axis tight;

代码运行效果如下:

代码编写:

H = fftshift(lpfilter('gaussian', 500, 500, 50)); 
[Y, X] = meshgrid(-2:0.1:2, -2:0.1:2); 
Z = X.*exp(-X.^2 - Y.^2); 
mesh(Z);
axis tight;

代码运行效果如下:

2018-11-17 16:01:22 aaakkk_1996 阅读数 822
  • OpenGL实现Google地图瓦片的绘制漫游视频教程

    OpenGL实现Google地图瓦片的绘制漫游视频培训课程:此次教程所涉及的内容有OpenGL绘制图片、FreeImage加载图片、墨卡托投影、瓦片的金字塔模型、FramebufferObject、地图的移动和缩放优化,采用屏幕瓦片绘制优化、采用ImageBuffer优化、采用多线程优化、地图操作优化、模拟,生成全球瓦片(debug)、MFC-对话框中绘制地图、MFC-View中绘制地图、QT中绘制地图、在线浏览Google地图等。

    8809 人正在学习 去看看 张立铜

ZZU的学弟学妹们不要抄作业哦~(`Д´)

一、实验目的

1、掌握2D太阳系绘制方法

2、掌握矩阵堆栈流程

3、进一步掌握复合2D图形变换

 

二、实验内容

1.已知太阳半径Rs,地球半径Re,月球半径Rm,每个球都会自转,地球绕太阳公转,月球绕地球公转。

2.基本框架程序2DSunSystem.cpp

3.设计世界坐标系,设计裁剪窗口大小,编写2D太阳系代码。

4.效果截图  

                                       图7-2 2D太阳系效果    

5、分别在太阳、地球、月球位置添加中文字体“太阳”、“地球”、“月球”

                                        图7-3 添加文字

 

6、在修改的代码上加上自己的一些点缀修饰性图形

图7-4 添加了地球和月球轨道

三、参考函数:  

1.void glPushMatrix(void)

2.void glPopMatrix(void)

3.相关参数设置:

glPoinSize(16);//设置点大小

glLineWidth(10);//设置线宽

 

4.中文字体绘制

1)在程序头部声明所用到的字体函数

void selectFont(int size, int charset, const char* face); //选择字体

void drawCNString(const char* str); //生成中文字体函数

 

2)程序尾部定义选择的字体函数和生成中文字体函数:

//选择字体函数                                                                     

void selectFont(int size, int charset, const char* face)

{

HFONT hFont = CreateFontA(size, 0, 0, 0, FW_MEDIUM, 0, 0, 0,

charset, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,

DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, face);

HFONT hOldFont = (HFONT)SelectObject(wglGetCurrentDC(), hFont);

DeleteObject(hOldFont);

}

//生成中文字体函数

void drawCNString(const char* str)

{

int len, i;

wchar_t* wstring;

HDC hDC = wglGetCurrentDC();

GLuint list = glGenLists(1);

 

//计算字符的个数

//如果是双字节字符的(比如中文字符),两个字节才算一个字符

//否则一个字节算一个字符

len = 0;

for(i=0; str[i]!='\0'; ++i)

{

if( IsDBCSLeadByte(str[i]) )

++i;

++len;

}

 

// 将混合字符转化为宽字符

wstring = (wchar_t*)malloc((len+1) * sizeof(wchar_t));

MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str, -1, wstring, len);

wstring[len] = L'\0';

 

// 逐个输出字符

for(i=0; i<len; ++i)

{

wglUseFontBitmapsW(hDC, wstring[i], 1, list);

glCallList(list);

}

 

//回收所有临时资源

free(wstring);

glDeleteLists(list, 1);

}

 

3)在绘制部分调用字体函数,写中文字

  selectFont(48, GB2312_CHARSET, "楷体_GB2312");  //设置楷体48 glRasterPos2f(250, 250);  //定位首字位置250,250

drawCNString("Hello,大家好");  //写字“Hello,大家好”

 

四、思考题

1、如果太阳在平面任意位置,程序应该如何修改?

答:修改太阳坐标xs,ys的值。

 

2.OpenGL图形变换靠什么来完成?在OpenGL中完成矩阵操作,需要注意哪些问题?

答:靠变换矩阵完成。压栈出栈要注意堆栈平衡。

 

3.glPushMatrix(), glPopMatrix()是如何工作的?试运用这两个函数设计其他复合(或动画)图形。

答:调用glPushMatrix事实上就是把当前状态做一个副本放入堆栈之中。当你做了一些移动或旋转等变换后,使用glPushMatrix();OpenGL 会把这个变换后的位置和角度保存起来。然后你再随便做第二次移动或旋转变换,再用glPopMatrix();OpenGL 就把刚刚保存的那个位置和角度恢复。

 

试运用这两个函数设计其他复合(或动画)图形

 

描述:两个自转的六芒星,和两个环,小六芒星绕大六芒星公转。

 

 

五、完整代码(太阳系和六芒星)

1.太阳系

#include "stdafx.h"
#include <glut.h>
#include <math.h>

float PI = 3.1415926f;
float Re = 150, Rm = 50;  //地球轨道半径,月球轨道半径

float rs = 50, re = 30, rm = 10;//太阳,地月,球半径
float xs = 0, ys = 0, xe = 150, ye = 0, xm = 200, ym = 0;//太阳,地球,月球球心坐标
float as, ae, am, aes, ame, ams;//各自转角度,地球绕太阳公转角度,月绕地公转,月绕太公转

void Display(void);
void Reshape(int w, int h);
void mytime(int value);
void myinit(void);
void sun();
void earth();
void moon();
void pathEarth();
void selectFont(int size, int charset, const char*face);//选择字体
void drawCNString(const char*str);//生成中文字体函数

int APIENTRY _tWinMain(HINSTANCE hInstance,
	HINSTANCE hPrevInstance,
	LPTSTR    lpCmdLine,
	int       nCmdShow)
{
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdLine);
	char *argv[] = { "2D太阳系", " " };
	int argc = 2; // must/should match the number of strings in argv
	glutInit(&argc, argv);  //初始化GLUT库;
	glutInitWindowSize(700, 700);  //设置显示窗口大小
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);  //设置显示模式;(注意双缓冲)
	glutCreateWindow("A Rotating Sun System"); // 创建显示窗口
	glutDisplayFunc(Display);  //注册显示回调函数
	glutReshapeFunc(Reshape);  //注册窗口改变回调函数
	myinit();
	glutTimerFunc(200, mytime, 10);
	glutMainLoop();  //进入事件处理循环
	return 0;
}

void myinit()
{
	glPointSize(10);
	glLineWidth(5);
	/*反走样代码*/
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glEnable(GL_BLEND);
	glEnable(GL_POINT_SMOOTH);
	glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
	glEnable(GL_LINE_SMOOTH);
	glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
	glEnable(GL_POLYGON_SMOOTH);
	glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
}

void Display(void)
{
	glClear(GL_COLOR_BUFFER_BIT);
	glMatrixMode(GL_MODELVIEW); //设置矩阵模式为模型变换模式,表示在世界坐标系下
	glLoadIdentity();   //将当前矩阵设置为单位矩阵
	sun();
	earth();
	moon();
	glutSwapBuffers();   //双缓冲的刷新模式;
}

void sun()
{
	glPushMatrix();
	glLineWidth(10);
	glRotatef(as, 0, 0, 1);//绕太阳中心点自转
	/*绘制太阳*/
	glColor3f(1, 0, 0);
	glutWireSphere(rs, 30, 30);//画球,半径,经线纬线的数量

	glColor3f(0, 1, 0);
	glLineWidth(1);
	glutWireSphere(Re, 30, 30);//增加的地球轨道
	/*在太阳圆弧上画点*/
	glColor3f(1, 1, 0);
	glBegin(GL_POINTS);
		glVertex2f(xs + rs, ys);
	glEnd();
	/*在绘制部分调用字体函数,写中文字*/
	glColor3f(1, 1, 0);
	selectFont(30, GB2312_CHARSET, "楷体GB2312");//设置字体
	glRasterPos3f(xs, ys, 0);//定位首字
	//drawCNString("太阳");//写字
	glPopMatrix();

}

void earth()
{
	glPushMatrix();
	glLineWidth(10);
	/*绕太阳中心点公转*/
	glRotatef(aes, 0, 0, 1);

	/*绕地球中心点自转*/
	glTranslatef(xe, ye, 0);
	glRotatef(ae, 0, 0, 1);
	glTranslatef(-xe, -ye, 0);

	glPushMatrix();
	glPushMatrix();
	glColor3f(0, 0, 1);
	glTranslatef(xe, ye, 0);
	glutWireSphere(re, 30, 30);

	glColor3f(0, 1, 0);
	glLineWidth(1);
	glutWireSphere(Rm, 30, 30);//增加的月球轨道

	glPopMatrix();

	glColor3f(1, 1, 0);
	glBegin(GL_POINTS);
	glVertex2f(xe + re, ye);
	glEnd();
	glColor3f(1, 1, 0);
	selectFont(25, GB2312_CHARSET, "楷体GB2312");
	glRasterPos3f(xe, ye, 0);
	//drawCNString("地球");
	glPopMatrix();
	glPopMatrix();
}
void moon()
{
	glPushMatrix();
	glLineWidth(10);
	glRotatef(ams, 0, 0, 1);
	glTranslatef(xe, ye, 0);
	glRotatef(ame, 0, 0, 1);
	glTranslatef(-xe, -ye, 0);

	glTranslatef(xm, ym, 0);
	glRotatef(am, 0, 0, 1);
	glTranslatef(-xm, -ym, 0);

	glPushMatrix();
	glPushMatrix();
	glColor3f(1, 1, 1);
	glTranslatef(xm, ym, 0);
	glutWireSphere(rm, 20, 20);
	glPopMatrix();

	glColor3f(1, 1, 0);
	glBegin(GL_POINTS);
	glVertex2f(xm + rm, ym);
	glEnd();
	glColor3f(1, 1, 0);
	selectFont(20, GB2312_CHARSET, "楷体GB2312");
	glRasterPos3f(xm, ym, 0);
	//drawCNString("月球");
	glPopMatrix();
	glPopMatrix();
}

void mytime(int value)
{
	as += 1;//太阳自转角度递增
	ae += 1;//地球自转角度递增
	am += 1;//月球自转角度递增
	aes += 2;//地球绕太阳公转角度递增
	ame += 2;//月球绕地球公转角度递增
	ams += 2;//月球绕太阳公转角度递增
	glutPostRedisplay();  //重画,相当于重新调用Display(),改编后的变量得以传给绘制函数
	glutTimerFunc(100, mytime, 10);//设置时间间隔

}
void Reshape(GLsizei w, GLsizei h)
{
	glMatrixMode(GL_PROJECTION);  //投影矩阵模式
	glLoadIdentity();  //矩阵堆栈清空
	glViewport(0, 0, w, h); //设置视区大小
   /* if (w <= h)//保持形状不变
		gluOrtho2D(-xm - rm - 10, xm + rm + 10, (-xm - rm - 10) * GLfloat(h) / GLfloat(w), 2 * GLfloat(h) / GLfloat(w));
	else
		gluOrtho2D((-xm - rm - 10) * GLfloat(w) / GLfloat(h), (xm + rm + 10) * GLfloat(w) / GLfloat(h), -xm - rm - 10, xm + rm + 10);*/
	gluOrtho2D((-xm - rm - 10)*((GLfloat)w / (GLfloat)h), (xm + rm + 10)*((GLfloat)w / (GLfloat)h), (-xm - rm - 10), (xm + rm + 10));   //设置裁剪窗口大小 
   //gluPerspective(90,w/h,20,500);
	glMatrixMode(GL_MODELVIEW);  //模型矩阵模式
	glLoadIdentity();  //矩阵堆栈清空
}

//选择字体函数
void selectFont(int size, int charset, const char*face)
{
	HFONT hFont = CreateFontA(size, 0, 0, 0, FW_MEDIUM, 0, 0, 0,
		charset, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
		DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, face);

	HFONT hOldFont = (HFONT)SelectObject(wglGetCurrentDC(), hFont);
	DeleteObject(hOldFont);
}

//生成中文字体
void drawCNString(const char* str)
{
	int len, i;
	wchar_t* wstring;
	HDC hDC = wglGetCurrentDC();
	GLuint list = glGenLists(1);
	//计算字符的个数
	//如果是双字节字符的(比如中文字符),两个字节才算一个字符
	//否则一个字节算一个字符
	len = 0;
	for (i = 0; str[i] != '\0'; ++i)
	{
		if (IsDBCSLeadByte(str[i]))
			++i;
		++len;
	}
	//将混合字符转化为宽字符
	wstring = (wchar_t*)malloc((len + 1) * sizeof(wchar_t));
	MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str, -1, wstring, len);
	wstring[len] = L'\0';
	//逐个输出字符
	for (i = 0; i < len; ++i)
	{
		wglUseFontBitmapsW(hDC, wstring[i], 1, list);
		glCallList(list);
	}
	//回收所有临时资源
	free(wstring);
	glDeleteLists(list, 1);
}

/*--------------------------------分割线------------------------------------*/

/*--------------------------------分割线------------------------------------*/

 

 

 

2.六芒星(思考题)

#include "stdafx.h"
#include <glut.h>
#include <math.h>

float Re = 150, Rm = 50;  //大环半径,小环半径

float rs = 50, re = 30;//大六芒星,小六芒星半径
float xs = 0, ys = 0, xe = 150, ye = 0;//大六芒星,小六芒星中心坐标
float as, ae, am, aes, ame, ams;//各自转角度,小六芒星绕大六芒星公转角度等

void Display(void);
void Reshape(int w, int h);
void mytime(int value);
void myinit(void);
void bigStar();
void smallStar();

int APIENTRY _tWinMain(HINSTANCE hInstance,
	HINSTANCE hPrevInstance,
	LPTSTR    lpCmdLine,
	int       nCmdShow)
{
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdLine);
	char *argv[] = { "思考题", " " };
	int argc = 2; // must/should match the number of strings in argv
	glutInit(&argc, argv);  //初始化GLUT库;
	glutInitWindowSize(700, 700);  //设置显示窗口大小
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);  //设置显示模式;(注意双缓冲)
	glutCreateWindow("思考题"); // 创建显示窗口
	glutDisplayFunc(Display);  //注册显示回调函数
	glutReshapeFunc(Reshape);  //注册窗口改变回调函数
	myinit();
	glutTimerFunc(200, mytime, 10);
	glutMainLoop();  //进入事件处理循环
	return 0;
}

void myinit()
{
	glPointSize(10);
	glLineWidth(5);
	/*反走样代码*/
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glEnable(GL_BLEND);
	glEnable(GL_POINT_SMOOTH);
	glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
	glEnable(GL_LINE_SMOOTH);
	glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
	glEnable(GL_POLYGON_SMOOTH);
	glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
}

void Display(void)
{
	glClear(GL_COLOR_BUFFER_BIT);
	glMatrixMode(GL_MODELVIEW); //设置矩阵模式为模型变换模式,表示在世界坐标系下
	glLoadIdentity();   //将当前矩阵设置为单位矩阵
	bigStar();
	smallStar();
	glutSwapBuffers();   //双缓冲的刷新模式;
}

void bigStar()
{
	glPushMatrix();
	glLineWidth(10);
	glRotatef(as, 0, 0, 1);//绕大六芒星中心点自转

	glColor3f(0, 1, 0);
	glLineWidth(1);
	glutWireSphere(Re, 30, 30);//大环

	/*画大大六芒星*/
	glBegin(GL_TRIANGLES);
		glVertex2f(0, 50);
		glVertex2f(-43.3, -25);
		glVertex2f(43.3, -25);
	glEnd();
	glBegin(GL_TRIANGLES);
		glVertex2f(0, -50);
		glVertex2f(-43.3, 25);
		glVertex2f(43.3, 25);
	glEnd();

	glPopMatrix();

}

void smallStar()
{
	glPushMatrix();
	glLineWidth(10);
	/*绕大六芒星中心点公转*/
	glRotatef(aes, 0, 0, 1);

	/*绕小六芒星中心点自转*/
	glTranslatef(xe, ye, 0);
	glRotatef(ae, 0, 0, 1);
	glTranslatef(-xe, -ye, 0);

	glPushMatrix();
	glPushMatrix();

	glTranslatef(xe, ye, 0);
	glColor3f(0, 1, 0);
	glLineWidth(1);
	glutWireSphere(Rm, 30, 30);//小环
	glPopMatrix();


	/*画小六芒星*/
	glBegin(GL_TRIANGLES);
		glVertex2f(150, 30);
		glVertex2f(175.98, -15);
		glVertex2f(124.02, -15);
		glEnd();
		glBegin(GL_TRIANGLES);
		glVertex2f(150, -30);
		glVertex2f(175.98, 15);
		glVertex2f(124.02, 15);
	glEnd();

	glPopMatrix();
	glPopMatrix();
}

void mytime(int value)
{
	as += 1;//大六芒星自转角度递增
	ae += 1;//小六芒星自转角度递增
	am += 1;//月球自转角度递增
	aes += 2;//小六芒星绕大六芒星公转角度递增
	ame += 2;//月球绕小六芒星公转角度递增
	ams += 2;//月球绕大六芒星公转角度递增
	glutPostRedisplay();  //重画,相当于重新调用Display(),改编后的变量得以传给绘制函数
	glutTimerFunc(100, mytime, 10);//设置时间间隔

}
void Reshape(GLsizei w, GLsizei h)
{
	glMatrixMode(GL_PROJECTION);  //投影矩阵模式
	glLoadIdentity();  //矩阵堆栈清空
	glViewport(0, 0, w, h); //设置视区大小
   /* if (w <= h)//保持形状不变
		gluOrtho2D(-200 - 10 - 10, 200 + 10 + 10, (-200 - 10 - 10) * GLfloat(h) / GLfloat(w), 2 * GLfloat(h) / GLfloat(w));
	else
		gluOrtho2D((-200 - 10 - 10) * GLfloat(w) / GLfloat(h), (200 + 10 + 10) * GLfloat(w) / GLfloat(h), -200 - 10 - 10, 200 + 10 + 10);*/
	gluOrtho2D((-200 - 10 - 10)*((GLfloat)w / (GLfloat)h), (200 + 10 + 10)*((GLfloat)w / (GLfloat)h), (-200 - 10 - 10), (200 + 10 + 10));   //设置裁剪窗口大小 
   //gluPerspective(90,w/h,20,500);
	glMatrixMode(GL_MODELVIEW);  //模型矩阵模式
	glLoadIdentity();  //矩阵堆栈清空
}

 

2019-08-15 14:00:03 charleszyy 阅读数 47
  • OpenGL实现Google地图瓦片的绘制漫游视频教程

    OpenGL实现Google地图瓦片的绘制漫游视频培训课程:此次教程所涉及的内容有OpenGL绘制图片、FreeImage加载图片、墨卡托投影、瓦片的金字塔模型、FramebufferObject、地图的移动和缩放优化,采用屏幕瓦片绘制优化、采用ImageBuffer优化、采用多线程优化、地图操作优化、模拟,生成全球瓦片(debug)、MFC-对话框中绘制地图、MFC-View中绘制地图、QT中绘制地图、在线浏览Google地图等。

    8809 人正在学习 去看看 张立铜

@[TOC]基于open cv中RGB直方图绘制及图像处理
通过大三一年对计算机视觉与模式识别的学习,对opencv有了更深一层的理解与认识,
以下是配置完成opencv之后RGB直方图绘制及图像处理的步骤及代码。
(步骤简单分为图像导入,RGB直方图绘制,及对图像进行包括腐蚀、模糊处理、canny边缘检测算法的处理)
以下是代码实现:
#include
#include<opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp> //图像处理头文件

using namespace cv;

int main()
{
// 读入一张图片(poyanghu缩小图)
Mat img = imread(“C:\Pictures\Saved Pictures\7444.jpg_wh300.jpg”);
imshow(“原图”, img);
//绘制RGB三色直方图
//1 参数准备
int bins = 256;
int hist_size[] = { bins };
float range[] = { 0,256 };
const float* ranges[] = { range };
MatND redhist, greenhist, bluehist;
int channels_r[] = { 0 };

//进行直方图的计算(包括红色分量、绿色分量、蓝色分量)
calcHist(&img, 1, channels_r, Mat(),//不使用掩膜
redhist, 1, hist_size, ranges,
true, false);

int channels_g[] = { 1 };
calcHist(&img, 1, channels_g, Mat(),//不使用掩膜
greenhist, 1, hist_size, ranges,
true, false);

int channels_b[] = { 2 };
calcHist(&img, 1, channels_b, Mat(),//不使用掩膜
bluehist, 1, hist_size, ranges,
true,
false);
//-----------------------------------绘制出三色直方图------------------------------------------
//参数准备
double maxvalue_red, maxvalue_green, maxvalue_blue;
minMaxIdx(redhist, 0, &maxvalue_red, 0, 0);
minMaxIdx(greenhist, 0, &maxvalue_green, 0, 0);
minMaxIdx(bluehist, 0, &maxvalue_blue, 0, 0);
int scale = 1;
int hisheight = 256;
Mat hisimage = Mat::zeros(hisheight, bins * 3, CV_8UC3);

//正式开始绘制
for (int i = 1; i < bins; i++)
{
//参数准备
float binvalue_red = redhist.at(i);
float binvalue_green = greenhist.at(i);
float binvalue_blue = bluehist.at(i);

int intensity_red =
cvRound(binvalue_redhisheight / maxvalue_red); //要绘制的高度
int intensity_green =
cvRound(binvalue_green
hisheight / maxvalue_green);
int intensity_blue=
cvRound(binvalue_bluehisheight / maxvalue_blue);
//绘制红色分量的直方图
rectangle(hisimage, Point(i
scale, hisheight - 1), Point((i + 1)*scale - 1, hisheight - intensity_red), Scalar(255, 0, 0));

//绘制绿色分量的直方图
rectangle(hisimage, Point((i+bins)*scale, hisheight - 1), Point((i+bins + 1)*scale - 1, hisheight - intensity_green), Scalar( 0, 255, 0));

//绘制蓝色分量的直方图
rectangle(hisimage, Point((i+bins*2)scale, hisheight - 1), Point((i+bins2 + 1)*scale - 1, hisheight - intensity_blue), Scalar(0,0,255));
}

//在窗口中显示出绘制好的直方图
imshow(“图像的RGB直方图”,hisimage);
waitKey(5);

//进行图像腐蚀操作
Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));
Mat dstimage1;
Mat dstimage2;
erode(img, dstimage1, element);
//进行均值滤波图像模糊操作
blur(img, dstimage2, Size(7, 7));
//进行canny边缘检测
Mat edge, grayimage; //参数定义
//将原图像转换为灰度图像
cvtColor(img, grayimage, CV_BGR2GRAY);
blur(grayimage, edge, Size(3, 3)); //先是用3*3内核来降噪
//运行canny算子
Canny(edge, edge, 3, 9, 3);
// 在窗口中显示图片
imshow(“原图”, img);
//显示效果图
imshow(“效果图-腐蚀操作”,dstimage1);
imshow(“效果图-模糊操作”, dstimage2);
imshow(“效果图-canny边缘监测操作”, edge);

// 等待60000ms后窗口自动关闭
waitKey(60000);
return 0;
}

2019-04-14 08:16:21 Dujing2019 阅读数 309
  • OpenGL实现Google地图瓦片的绘制漫游视频教程

    OpenGL实现Google地图瓦片的绘制漫游视频培训课程:此次教程所涉及的内容有OpenGL绘制图片、FreeImage加载图片、墨卡托投影、瓦片的金字塔模型、FramebufferObject、地图的移动和缩放优化,采用屏幕瓦片绘制优化、采用ImageBuffer优化、采用多线程优化、地图操作优化、模拟,生成全球瓦片(debug)、MFC-对话框中绘制地图、MFC-View中绘制地图、QT中绘制地图、在线浏览Google地图等。

    8809 人正在学习 去看看 张立铜

数字图像处理—频域处理

(六)高通(锐化)频域滤波器

低通滤波使图像变得模糊那样,相反的处理过程一高通滤波,通过削弱傅立叶变换的低频以及保持高频相对不变来锐化图像。图像锐化是一种补偿轮廓 、突出边缘信息以使图像更为清晰的处理方法 。 锐化的目标实质上是要增强原始图像的高频成分 。与图像平滑不同,图像平滑通过积分过程使图像边模糊,图像锐化则是通过微分过程使图像变清晰。图像锐化的目的:

  1. 增强图像边缘,使模糊的图像变得更加清晰,颜色变得鲜明突出,图像的质量有所改善,产生更适合人眼观察和识别的图像;
  2. 希望通过锐化处理后,目标物体的边缘鲜明,以便于提取目标的边缘、对图像进行分割、目标区域识别、区域形状提取等,进一步的图像理解与分析奠定基础。

高通滤波器: 理想高通滤波器IHPF;巴特沃思高通滤波器BHPF;高斯高通滤波器GHPF;

高通滤波器的传递函数由下式给出:
在这里插入图片描述

6.1 高通滤波函数

使用函数 lpfilter 构建另一个函数hpfilter,使用它可以产生高通滤波器:

function H = hpfilter(typef M, N, DO, n) 
if nargin 4 == 4
  n = 1;
end
Hlp = lpfilter(type, M, N,DO, n); 
H = 1 - Hlp;

下面分别介绍三种滤波器:理想、布特沃斯和高斯高通滤波器的绘图和图像

理想高通滤波器:与低通滤波器相对,IHPF将以D0为半径的圆周内的所有频率置为0,而毫不衰减地通过圆周外的任何频率。 IHPF 也是物理不可实现的,只能通过计算机实现。和ILPF一样有振铃现象 。

函数公式:
在这里插入图片描述
编写代码:

H = fftshift(hpfilter('ideal', 500, 500, 50));   %对图像频谱进行移动,使0频率点在中心
figure;
subplot(1, 2, 1), surf(double(H(1:10:500, 1:10:500))), title('理想高通滤波器绘图');
subplot(1, 2, 2), imshow(H,[]), title('理想高通滤波器图像');

代码运行效果如下:

布特沃斯高通滤波器:BHPF比IHPF更平滑,它在高低频之间有比较光滑的过渡;BHPF振铃不明显,对微小物体的过滤比IHPF清晰。

函数公式:
在这里插入图片描述
编写代码:

H = fftshift(hpfilter('btw', 500, 500, 50)); 
figure;
subplot(1, 2, 1), surf(double(H(1:10:500, 1:10:500))), title('布特沃斯高通滤波器透视图');
subplot(1, 2, 2), imshow(H,[]), title('布特沃斯高通滤波器图像');

代码运行效果如下:

高斯高通滤波器:GHPF比前2种更平滑,它在高低频之间有光滑的过渡,无振铃效果,对微小物体的过滤更清晰。

函数公式:
在这里插入图片描述
编写代码:

H = fftshift(hpfilter('gaussian', 500, 500, 50)); 
figure;
subplot(1, 2, 1), surf(double(H(1:10:500, 1:10:500))), title('高斯高通滤波器透视图');
subplot(1, 2, 2), imshow(H,[]), title('高斯高通滤波器图像');

代码运行效果如下:

下面对比下不同滤波器对图像的处理效果:

理想高通滤波器:
编写代码:

w = imread('D:\数字图像处理\第三章学习\blackhole.png');
f = im2double(rgb2gray(w));    %把图像变为灰度图像
PQ = paddedsize(size(f));      %获取填充尺寸
[U,V] = dftuv(PQ(1),PQ(2));
DO = 0.05*PQ(2);               %设定滤波器的阈值
F = fft2(f,PQ(1),PQ(2));       %傅里叶变换
H = hpfilter('ideal', PQ(1),PQ(2), DO, 2);   %理想高通滤波
g = dftfilt(f,H);              %用滤波器对图像进行频域滤波
subplot(2, 2, 1), imshow(w), title('原图像');
subplot(2, 2, 2), imshow(fftshift(H),[]), title('以图像显示的理想高通滤波器');
subplot(2, 2, 3), imshow(log(1+abs(fftshift(F))),[]), title('对数增强并居中的fft');
subplot(2, 2, 4), imshow(g,[]), title('理想高通滤波后图像的谱');

运行代码效果如下:
在这里插入图片描述
布特沃斯高通滤波器:
编写代码:

w = imread('D:\数字图像处理\第三章学习\blackhole.png');
f = im2double(rgb2gray(w));    %把图像变为灰度图像
PQ = paddedsize(size(f));      %获取填充尺寸
DO = 0.05*PQ(1);               %设定滤波器的阈值
H = fftshift(hpfilter('btw', PQ(1),PQ(2), DO)); 
g = dftfilt(f,H);
figure;
subplot(1, 3, 1), imshow(w), title('原图像');
subplot(1, 3, 2), imshow(f), title('图像的灰度图像');
subplot(1, 3, 3), imshow(g), title('理想高通滤波后结果');

代码运行效果如下:
在这里插入图片描述

高斯高通滤波器:
编写代码:

w = imread('D:\数字图像处理\第三章学习\blackhole.png');
f = im2double(rgb2gray(w));    %把图像变为灰度图像
PQ = paddedsize(size(f));      %获取填充尺寸
[U,V] = dftuv(PQ(1),PQ(2));
DO = 0.05*PQ(2);               %设定滤波器的阈值
F = fft2(f,PQ(1),PQ(2));       %傅里叶变换
H = hpfilter('gaussian', PQ(1),PQ(2), DO, 2); 
g = dftfilt(f,H);              %用滤波器对图像进行频域滤波
subplot(2, 2, 1), imshow(w), title('原图像');
subplot(2, 2, 2), imshow(fftshift(H),[]), title('以图像显示的高斯高通滤波器');
subplot(2, 2, 3), imshow(log(1+abs(fftshift(F))),[]), title('对数增强并居中的fft');
subplot(2, 2, 4), imshow(g,[]), title('高斯高通滤波后图像的谱');

在这里插入图片描述
实验结论:不同的滤波器对图像的滤波效果是不同的。它们的共同点是图像在经过高通滤波后,消除了模糊,突出了边缘,使低频分量得到了抑制,从而增强了高频分量,使图像的边沿或线条变得清晰,实现了图像的锐化。但理想高通滤波器出现了明显的振铃现象,即图像边缘有抖动现象;而布特沃斯滤波器高通效果较好,但是计算复杂,其优点是有少量的低频通过,故H(u,v)是渐变的,振铃不明显;高斯高通滤波效果比前两者都要好些,更为平滑,没有振铃现象。而且不同的滤波半径和不同的滤波器阶数对图像的滤波效果也是不同的。滤波半径越越小,则图像的滤波效果越好;滤波器阶数越高,则滤波效果越好。

6.2 高频强调滤波

高通滤波器偏离了 dc的0项,因此减少了图像中平均值为 0的值。 一种补偿方法是为高通滤波器加上偏移量。如果偏移量与将滤波器乘以某个大于 1 的常数结合 起来,这种方法就叫做高频强调滤波,因为这个常量乘数突出了高频部分。这个乘数也增加了 低频部分的幅度,但是只要偏移量与乘数相比较小,低频增强的影响就弱于高频增强的影响。 高频强调滤波有如下传递函数:

在这里插入图片描述
a是偏移量,b 是乘数。

下面尝试将将高频强调滤波和直方图均衡化结合起来

编写代码:

w = imread('D:\数字图像处理\第三章学习\blackhole.png');
f = im2double(rgb2gray(w));    %把图像变为灰度图像
PQ = paddedsize(size(f)); 
DO = 0.05*PQ(1);    %,Do的值等于填充过 的图像垂直尺寸的5%
HBW = hpfilter('btw', PQ(1),PQ(2), DO, 2); 
H = 0.5 + 2*HBW;
gbw = dftfilt(f, HBW, 'fltpoint');       %函数 dftfilt 中用 fltpoint 选项以得到浮点结果
gbw = gscale(gbw); 
ghf = dftfilt(f, H, 'fltpoint'); 
ghf = gscale(ghf);
ghe = histeq(ghf, 256); 
subplot(2, 2, 1), imshow(w), title('原图像');
subplot(2, 2, 2), imshow(gbw,[]), title('布特沃斯滤波器滤波后的结果');
subplot(2, 2, 3), imshow(ghf,[]), title('高频强调的结果');
subplot(2, 2, 4), imshow(ghe,[]), title('高频强调后经直方图均衡化结果');

在这里插入图片描述
实验结论:(b)图显示了用二阶布特沃斯高通滤波器对图 (a)滤波后的结果,Do的值等于填充过的图像垂直尺寸的5%。假设滤波器的半径不小于通过变换原点附近的频率,高通滤波就不会对Do的值过度敏感。正如预料的那样,滤波的结果并无特色,但却显示出图像的主要边缘有点模糊。如果某些灰度值是负的,仅有一条途径使一幅非 0 图像的平均值为 0。图 (b)的滤波结果就是这种情况。由于这个原因,我们必须在函数 dftfilt 中用 fltpoint 选项以得到浮点结果。如果不这样做,在默认情况下,负值将被裁剪而转换为 uint8 类(输入图像的类),微弱的细节将丟失。用函数gscale 考虑负值,将会保留这些细节。 高频强调滤波(在这种情况下,a=0.5, b=2.0)的优点显示在图©中,图像中由低频成分引起的灰度色调得以保持。由图可以看出在灰度级窄范围内以灰度为特征的图像直方图均衡化是理想选择。

(七)选择性滤波

7.1带阻和带通滤波器

将低通滤波器和高通滤波器串联,就可以得到带通滤波器。将输入电压同时作用于低通滤波器和高通滤波器,再将两个电路的输出电压求和,就可以得到带阻滤波器。带阻滤波器可以通过高频和低频,但是中频通不过;带通滤波器,能通过中频,但是高频和低频不能通过。

理想带阻滤波器表达式为:
在这里插入图片描述

布特沃斯带阻滤波器表达式为:
在这里插入图片描述
高斯带阻滤波器表达式为:
在这里插入图片描述
带通滤波器表达式与此相反,1减带阻即可。

7.2 陷波带阻和陷波带通滤波器

陷波滤波器也用于去除周期噪声,虽然带阻滤波器也能可以去除周期噪声,但是带阻滤波器对噪声以外的成分也有衰减。而陷波滤波器主要对某个点进行衰减,对其余的成分不损失。

用陷波滤波器减少波纹模式:

w = imread('D:\数字图像处理\第三章学习\blackhole.png');
f = im2double(rgb2gray(w));       %把图像变为灰度图像
[M N] = size(f); 
[f,revertclass] = tofloat(f);     %存储输入的类,以便以后使用。
F = fft2(f);                      %傅里叶变换
S = gscale(log(1+abs(fftshift(F))));
C1 = [99 154;128 163];
H1 = cnotch('gaussian','reject', M,N,C1,5);
P1 = gscale(fftshift(H1).*(tofloat(S)));
g1 = dftfilt(f, H1);   %采用默认值 0 填充边缘,频率域滤波函数,第一个参数为原始图像,后者为二维频率域滤器
figure;
subplot(2, 2, 1), imshow(g), title('原图像');
g1 = revertclass(g1);     
C2 = [99 154;128 163;49 160;133 233;55 132;108 255;112 74];
H2 = cnotch('gaussian','reject',M,N,C2,5);
P2 = gscale(fftshift(H2).*(tofloat(S)));      %用gscale来进行将数据缩放到默认值0~255
g2 = dftfilt(f,H2);
g2 = revertclass(g2);          %revertclass 可以用于把输出转换回与 f 相同的类。
subplot(2, 3, 1), imshow(w), title('原图像');
subplot(2, 3, 2), imshow(S), title('谱');
subplot(2, 3, 3), imshow(P1), title('应用于由波纹模式导致的低频脉冲的陷波滤波器');
subplot(2, 3, 4), imshow(g1), title('滤波结果');
subplot(2, 3, 5), imshow(P2), title('用更多的滤波器消除高频“结构”噪声');
subplot(2, 3, 6), imshow(g2), title('滤波结果');

代码运行效果如下:

实验结论:在频域中,周期干扰导致很强的局部能量脉冲, 因为干扰相对处于低频,我们开始滤除接近原点的尖刺。使用下面的 cnotch 函数来做。(i)显示了加在谱上的陷波滤波,而(j)图是滤波后的结果。与(h)比较, 我们可以看到高频干扰的减少。虽然这个最终结果远不完美,但相对原始图像来说改进还是有意义的。

Python数字图像处理

阅读数 2027

没有更多推荐了,返回首页