图像处理基础操作三

目录

一、图像直方图

1、直方图

2、直方图均衡化

二、傅里叶变换

1、Numpy实现傅里叶变换与傅里叶逆变换

2、OpenCV实现傅里叶变换与傅里叶逆变换

3、高通滤波器

4、低通滤波器


一、图像直方图

1、直方图

灰度直方图(histogram)是灰度级的函数,描述的是图像中每种灰度级像素的个数,反映图像中每种灰度出现的频率。横坐标是灰度级,纵坐标是灰度级出现的频率。

直方图是对图像的中的像素点的值进行统计,一般情况下直方图都是灰度图像,直方图x轴是灰度值(一般0~255),y轴就是图像中每一个灰度级对应的像素点的个数,即横坐标表示图像中各个像素点的灰度级,纵坐标表示具有该灰度级的像素个数。

matplotlib绘制直方图

#encoding:utf-8
import cv2  
import numpy as np
import matplotlib.pyplot as plt
#显示图像
def cv_show(name,img):
    cv2.imshow(name,img) 
    cv2.waitKey(0) 
    cv2.destroyAllWindows()
img = cv2.imread('data/cat.jpg')
plt.hist(img.ravel(), 256)
plt.show()
cv_show('src',img)

  • plt.hist(数据源, 像素级) : 数据源必须是一维数组,通常需要通过函数ravel()拉直图像 像素级一般是256,表示[0, 255]

opencv绘制直方图

#encoding:utf-8
import cv2  
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('data/cat.jpg') 
color = ('b','g','r')
for i,col in enumerate(color): 
    histr = cv2.calcHist([img],[i],None,[256],[0,256]) 
    plt.plot(histr,color = col) 
    plt.xlim([0,256]) 

hist=cv2.calcHist(images,channels,mask,histSize,ranges,accumulate)

  • hist表示直方图,返回的是一个二维数组
  • images: 原图像,图像格式为 uint8 或 float32。当传入函数时应 用中括号 [] 括来例如[img]
  • channels: 表示指定通道,通道编号需要用中括号括起,输入图像是灰度图像时,它的值为[0],彩色图像则为[0]、[1]、[2],分别表示B、G、R
  • mask: 表示掩码图像,统计整副图像的直方图,设为None,统计图像的某一部分直方图时,需要掩码图像
  • histSize:表示BINS的数目即灰度级,也应用中括号括来
  • ranges: ranges表示像素值范围,常为 [0,256]
  • accumulate:表示累计叠加标识,默认为false,如果被设置为true,则直方图在开始分配时不会被清零,该参数允许从多个对象中计算单个直方图,或者用于实时更新直方图;多个直方图的累积结果用于对一组图像的直方图计算

使用mask与不使用mask进行对比绘制直方图

#encoding:utf-8
import cv2  
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('data/cat.jpg', 0) #0表示灰度图
# 创建掩膜mask
mask = np.zeros(img.shape[:2], np.uint8)
mask[100:300, 100:400] = 255
masked_img = cv2.bitwise_and(img, img, mask=mask)#利用掩膜(mask)进行“与”操作
hist_full = cv2.calcHist([img], [0], None, [256], [0, 256])
hist_mask = cv2.calcHist([img], [0], mask, [256], [0, 256])
plt.subplot(221), plt.imshow(img, 'gray')
plt.subplot(222), plt.imshow(mask, 'gray')
plt.subplot(223), plt.imshow(masked_img, 'gray')
plt.subplot(224), plt.plot(hist_full,'red'), plt.plot(hist_mask,'black')
plt.xlim([0, 256])
plt.show()

img_mask=cv2.bitwise_and(src1, src2, dst=None, mask=None)

  • src1、src2:为输入图像或标量,标量可以为单个数值或一个四元组
  • dst:可选输出变量,如果需要使用非None则要先定义,且其大小与输入变量相同
  • mask:图像掩膜,可选参数,为8位单通道的灰度图像,用于指定要更改的输出图像数组的元素,即输出图像像素只有mask对应位置元素不为0的部分才输出,否则该位置像素的所有通道分量都设置为0
  • img_mask:结果图像矩阵,如果dst传入了实参,则返回值与dst对应实参相同

2、直方图均衡化

直方图均衡化是一种简单有效的图像增强技术,通过改变图像的直方图来改变图像中各像素的灰度,主要用于增强动态范围偏小的图像的对比度。原始图像由于其灰度分布可能集中在较窄的区间,造成图像不够清晰。例如,过曝光图像的灰度级集中在高亮度范围内,而曝光不足将使图像灰度级集中在低亮度范围内。

采用直方图均衡化,可以把原始图像的直方图变换为均匀分布(均衡)的形式,这样就增加了像素之间灰度值差别的动态范围,从而达到增强图像整体对比度的效果。换言之,直方图均衡化的基本原理是:对在图像中像素个数多的灰度值(即对画面起主要作用的灰度值)进行展宽,而对像素个数少的灰度值(即对画面不起主要作用的灰度值)进行归并,从而增大对比度,使图像清晰,达到增强的目的。

#encoding:utf-8
import cv2  
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('data/cat.jpg',0) #0表示灰度图
equ = cv2.equalizeHist(img)  #将要均衡化的原图像【要求是灰度图像】作为参数传入,则返回值即为均衡化后的图像。
plt.hist(equ.ravel(),256)
plt.show()
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8)) #自适应直方图均衡化
res_clahe = clahe.apply(img)
res = np.hstack((img,equ,res_clahe))
cv_show('res',res)

直方图均衡化结果:

原始图、直方图均衡化后的图与自适应直方图均衡化后的结果图展示:

  • cv2.equalizeHist(img)  表示进行直方图均衡化
  • cv2.createCLAHA(clipLimit=8.0, titleGridSize=(8, 8)) 用于生成自适应均衡化图像:clipLimit颜色对比度的阈值, titleGridSize进行像素均衡化的网格大小,即在多少网格下进行直方图的均衡化操作

二、傅里叶变换

傅里叶变换(Fourier Transform,简称FT)常用于数字信号处理,它的目的是将时间域上的信号转变为频率域上的信号。随着域的不同,对同一个事物的了解角度也随之改变,因此在时域中某些不好处理的地方,在频域就可以较为简单的处理。同时,可以从频域里发现一些原先不易察觉的特征。傅里叶定理指出“任何连续周期信号都可以表示成(或者无限逼近)一系列正弦信号的叠加。

傅里叶变换可以应用于图像处理中,经过对图像进行变换得到其频谱图。从谱频图里频率高低来表征图像中灰度变化剧烈程度。图像中的边缘信号和噪声信号往往是高频信号,而图像变化频繁的图像轮廓及背景等信号往往是低频信号。这时可以有针对性的对图像进行相关操作,例如图像除噪、图像增强和锐化等。

傅里叶变换的目的更多情况下是为了对频率进行过滤,通过修改频率以达到图像增强、图像去噪、边缘检测、特征提取、压缩加密等效果。

1、Numpy实现傅里叶变换与傅里叶逆变换

# -*- coding: utf-8 -*-
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
#读取图像
img = cv.imread('data/cat.jpg', 0)
#傅里叶变换
f = np.fft.fft2(img)  #快速傅里叶变换算法得到频率分布
fshift = np.fft.fftshift(f) #默认结果中心点位置是在左上角,,调用fftshift()函数转移到中间位置
res = np.log(np.abs(fshift)) #fft结果是复数, 其绝对值结果是振幅

#傅里叶逆变换
ishift = np.fft.ifftshift(fshift) 
iimg = np.fft.ifft2(ishift) #实现图像逆傅里叶变换,返回一个复数数组
iimg = np.abs(iimg) #将复数转换为0至255范围

#展示结果
plt.subplot(131), plt.imshow(img, 'gray'), plt.title('Original Image')
plt.axis('off')
plt.subplot(132), plt.imshow(res, 'gray'), plt.title('Fourier Image')
plt.axis('off')
plt.subplot(133), plt.imshow(iimg, 'gray'), plt.title('Inverse Fourier Image')
plt.axis('off')
plt.show()

2、OpenCV实现傅里叶变换与傅里叶逆变换

# -*- coding: utf-8 -*-
import numpy as np
import cv2
from matplotlib import pyplot as plt
#读取图像
img = cv2.imread('data/cat.jpg', 0)

#傅里叶变换
dft = cv2.dft(np.float32(img), flags = cv2.DFT_COMPLEX_OUTPUT)
dftshift = np.fft.fftshift(dft)  #将频谱低频从左上角移动至中心位置
res1= 20*np.log(cv2.magnitude(dftshift[:,:,0], dftshift[:,:,1])) #频谱图像双通道复数转换为0-255区间

#傅里叶逆变换
ishift = np.fft.ifftshift(dftshift)
iimg = cv2.idft(ishift)
res2 = cv2.magnitude(iimg[:,:,0], iimg[:,:,1])

#显示图像
plt.subplot(131), plt.imshow(img, 'gray'), plt.title('Original Image')
plt.axis('off')
plt.subplot(132), plt.imshow(res1, 'gray'), plt.title('Fourier Image')
plt.axis('off')
plt.subplot(133), plt.imshow(res2, 'gray'), plt.title('Inverse Fourier Image')
plt.axis('off')
plt.show()

  • cv2.dft()输出结果是是双通道的,第一个通道是结果的实数部分,第二个通道是结果的虚数部分,并且输入图像要首先转换成 np.float32 格式。由于输出的频谱结果是一个复数,需要调用cv2.magnitude()函数将傅里叶变换的双通道结果转换为0到255的范围。
  • cv2.magnitude(x, y):x表示浮点型X坐标值,即实部;y表示浮点型Y坐标值,即虚部;最终输出结果为幅值。

3、高通滤波器

高通滤波器是指通过高频的滤波器,衰减低频而通过高频,常用于增强尖锐的细节,但会导致图像的对比度会降低。该滤波器将检测图像的某个区域,根据像素与周围像素的差值来提升像素的亮度。通过高通滤波器覆盖掉中心低频部分,将255两点变换为0,同时保留高频部分。

通过高通滤波器将提取图像的边缘轮廓

img = cv2.imread('data/cat.jpg',0)

img_float32 = np.float32(img)

dft = cv2.dft(img_float32, flags = cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)

rows, cols = img.shape
crow, ccol = int(rows/2) , int(cols/2)     # 中心位置

# 高通滤波
mask = np.ones((rows, cols, 2), np.uint8)
mask[crow-30:crow+30, ccol-30:ccol+30] = 0

# IDFT傅里叶逆变换
fshift = dft_shift*mask
f_ishift = np.fft.ifftshift(fshift)
img_back = cv2.idft(f_ishift)
img_back = cv2.magnitude(img_back[:,:,0],img_back[:,:,1])

#显示原始图像和高通滤波处理图像
plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(img_back, cmap = 'gray')
plt.title('Result'), plt.xticks([]), plt.yticks([])
plt.show()

4、低通滤波器

低通滤波器是指通过低频的滤波器,衰减高频而通过低频,常用于模糊图像。低通滤波器与高通滤波器相反,当一个像素与周围像素的插值小于一个特定值时,平滑该像素的亮度,常用于去燥和模糊化处理。如PS软件中的高斯模糊,就是常见的模糊滤波器之一,属于削弱高频信号的低通滤波器。低通滤波器中心区域为白色255,其他区域为黑色0。

import numpy as np
import cv2
from matplotlib import pyplot as plt

img = cv2.imread('data/cat.jpg',0)

img_float32 = np.float32(img)
#傅里叶变换
dft = cv2.dft(img_float32, flags = cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)

rows, cols = img.shape
crow, ccol = int(rows/2) , int(cols/2)     # 中心位置

# 设置低通滤波
mask = np.zeros((rows, cols, 2), np.uint8)
mask[crow-30:crow+30, ccol-30:ccol+30] = 1

# IDFT 傅里叶逆变换
fshift = dft_shift*mask
f_ishift = np.fft.ifftshift(fshift)
img_back = cv2.idft(f_ishift)
img_back = cv2.magnitude(img_back[:,:,0],img_back[:,:,1])
#显示原始图像和低通滤波处理图像
plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(img_back, cmap = 'gray')
plt.title('Result'), plt.xticks([]), plt.yticks([])
plt.show() 

 

 

已标记关键词 清除标记
我知道,fftshift和ifftshift对于偶数长度的数组,两者无区别;对于奇数长度数组,fftshift相当于把数组的第一个放到数组中间,而ifftshift则是把最后一个放到中间。但是在用fft进行滤波等处理时,什么时候用fftshift或ifftshift感到很糊涂了,因为这个问题已经遇到很多次了. 现在想实现对一组数据进行低通滤波,代码如下: Nf = 2^12; xAxisf = linspace(-10,10,Nf); % plot(xaxis, data); % FFT xsize = numel(data); Xf = zeros([1 Nf]); indices = Nf/2-floor(xsize/2):Nf/2-floor(xsize/2)+xsize - 1; Xf(indices) = data; % Xf = fftshift(Xf); Xf = fft(Xf); Xf = fftshift(Xf); % plot Xfa = abs(Xf); plot(xAxisf, Xfa); % generate super-gaussian filter function Nf = numel(Xf); widthfilter = 0.12; filterpower = 2; filter = exp(-(xAxisf.^2./widthfilter^2).^filterpower); % filter filtertimes = 20; Xf = Xf .* filter.^filtertimes; % plot Xfa = abs(Xf); plot(Xfa); % iFFt Xfs = ifftshift(Xf); Xif = ifft(Xfs); % Xif = ifftshift(Xif); result = abs(Xif); plot(result(indices)) 现在针对这个程序,我有一些疑问,希望大家能帮忙看看,谢谢大神门了!! 问题1: 在fft用之前,不需要用fftshift对data进行操作吗?就像如下操作: Xf = fftshift(data); % NOT NEEDED??? Xf = fft(Xf); 问题2: 程序中是用ffitshift对Xf操作的(Xf = fftshift(Xf)),我想为什么不能用ifftshift操作呢? 问题3: 在使用ifft之前,为什么用ifftshift操作呢?(Xfs = ifftshift(Xf)而不是用ffishift呢? 问题4; Xif = ifft(Xfs)反傅里叶变换之后,要用iffshift操作吗?如果需要,为什么不是用ffishift呢? 其实,问题总的来说,就是fftshift和ifftshift在什么场合下使用,为什么有时候用fftshift操作,而不是用ifftshift操作呢?或者为什么有时候用ifftshift操作,而不是用fftshift操作呢?
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页