数字图像处理——实验二 数字图像增强实验

一、实验目的

(1)熟悉并学会 opencv-python 中图像增强的相关函数;

(2)了解图像增强的方法、去噪的方法和效果。

二、实验主要仪器设备

(1)计算机;

(2)Python 3.x及PyCharm软件;

(3)典型的灰度、彩色图像文件。

  • 注:opencv-python 使用的是3.x 版本

三、实验原理

图像增强是指按特定的需要突出一幅图像中的某些信息,同时消弱或去除某些不需要的信息的处理方法。其主要目的是处理后的图像对某些特定的应用比原来的图像更加有效。图像增强技术主要有直方图修改处理、图像平滑化处理、图像尖锐化处理和彩色处理技术等。本实验以直方图均衡化增强图像对比度的方法为主要内容。

(1) 直方图

直方图是多种空间域处理技术的基础。直方图操作能有效地用于图像增强。除了提供有用的图像统计资料外,直方图固有的信息在其他图像处理应用中也是非常有用的,如图像压缩与分割。直方图在软件中易于计算,也适用于商用硬件设备,因此,它们成为了实时图像处理的一个流行工具。

直方图是图像的最基本的统计特征,它反映的是图像的灰度值的分布情况。直方图均衡化的目的是使图像在整个灰度值动态变化范围内的分布均匀化,改善图像的亮度分布状态,增强图像的视觉效果。灰度直方图是图像预处理中涉及最广泛的基本概念之一。

图像的直方图事实上就是图像的亮度分布的概率密度函数,是一幅图像的所有象素集合的最基本的统计规律。直方图反映了图像的明暗分布规律,可以通过图像变换进行直方图调整,获得较好的视觉效果。

直方图均衡化是通过灰度变换将一幅图像转换为另一幅具有均衡直方图,即在每个灰度级上都具有相同的象素点数的过程。

(2) 图像锐化

图像锐化(image sharpening)是补偿图像的轮廓,增强图像的边缘及灰度跳变的部分,使图像变得清晰,分为空域处理和频域处理两类。

(3) 图像平滑

图像平滑是对图像作低通滤波,可在空间域或频率域实现。

四、实验内容及代码

4.1 实验内容

(1)绘制灰度图像直方图;

(2)对直方图均衡化;

(3)利用模板进行空域滤波;

(4)分别利用常见的低通(平滑)滤波器和高通(锐化)滤波器进行频率域滤波。

4.2 实验数据

本实验使用的图片同实验一,原始图片如 图1 所示:

在这里插入图片描述

图1. 原始图像

4.3 实验代码

4.3.1 绘制灰度直方图

cv2.calcHist() 函数可以帮助我们通过直方图对整个图像的灰度分布有所了解,具体的使用参见博客:opencv学习笔记十七:直方图和直方图均衡化(cv2.calcHist、 cv2.equalizeHist)_耐心的小黑的博客-CSDN博客_cv2直方图均衡

实现代码:

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

img = cv2.imread(r'./data/1.jpg')   # 使用 imread 函数读取图像,并以 numpy 数组形式储存
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 使用 cv.cvtColor 函数转换色彩空间,从RGB空间转换到灰度空间

# 1.绘制灰度直方图
hist = cv2.calcHist([img_gray], [0], None, [256], [0, 255])  # OpenCV 利用 calcHist() 函数来绘制直方图
plt.plot(hist)
plt.show()

灰度图像及其灰度直方图:

在这里插入图片描述

图2(a). 灰度图像

在这里插入图片描述

图2(b). 灰度直方图

4.3.2 对灰度图像进行直方图均衡化

实现代码:

# 2.直方图均衡化
img_equ = cv2.equalizeHist(img_gray)    # equalizeHist()函数输入为灰度图像,输出为直方图均衡化后的图像
cv2.imshow('img_gray_equ', img_equ)
cv2.waitKey(0)
cv2.destroyAllWindows()
hist_equ = cv2.calcHist([img_equ], [0], None, [256], [0, 255])
plt.plot(hist_equ)
plt.show()

直方图均衡化之后的效果:

在这里插入图片描述

图3(a). 直方图均衡化后的图像

在这里插入图片描述

图3(b). 直方图均衡化后的灰度直方图

4.3.3 利用模板进行空域滤波

(1) 平滑滤波

实现代码:

# 3.利用模板进行空域滤波
# 3.1 平滑滤波
# 均值滤波
img_blur = cv2.blur(img, (3, 5))    # 模板大小为 3*5, 其大小是可以设定的
cv2.imshow('img_blur', img_blur)
cv2.waitKey(0)
cv2.destroyAllWindows()
img_box = cv2.boxFilter(img, -1, (3, 5))    # 方框滤波
cv2.imshow('img_box', img_box)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 高斯模糊滤波
img_gauss = cv2.GaussianBlur(img, (5, 5), 0)    # (5,5)表示的是卷积模板的大小,0 表示的是沿 x 与 y 方向上的标准差
cv2.imshow('img_gauss', img_gauss)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 中值滤波
img_median = cv2.medianBlur(img, 5)
cv2.imshow('img_median', img_median)
cv2.waitKey(0)
cv2.destroyAllWindows()

三种平滑滤波后的效果图:

  • 均值滤波

在这里插入图片描述

图4(a). 3*5的模板进行均值滤波

在这里插入图片描述

图4(b). 方框均值滤波(cv2.boxFilter()函数)
  • 高斯模糊滤波

在这里插入图片描述

图5. 高斯模糊滤波效果
  • 中值滤波

在这里插入图片描述

图6. 中值滤波效果

(2) 锐化滤波

实现代码:

# 3.2 锐化滤波
# 3.2.1 Roberts算子(交叉微分算法)
# 图像阈值化处理
ret, img_binary = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)    # 二进制阈值化
# 调用Roberts算法的OpenCV库函数进行图像轮廓提取
kernelx_Robert = np.array([[-1, 0], [0, 1]], dtype=int)
kernely_Robert = np.array([[0, -1], [1, 0]], dtype=int)
x_Robert = cv2.filter2D(img_binary, cv2.CV_16S, kernelx_Robert)
y_Robert = cv2.filter2D(img_binary, cv2.CV_16S, kernely_Robert)
# 转uint8
absX_Robert = cv2.convertScaleAbs(x_Robert)
absY_Robert = cv2.convertScaleAbs(y_Robert)
img_Roberts = cv2.addWeighted(absX_Robert, 0.5, absY_Robert, 0.5, 0)
# 展示处理后的结果
cv2.imshow("img_Roberts", img_Roberts)
cv2.waitKey(0)
cv2.destroyAllWindows()

# 3.2.2 Prewitt算子
kernelx_Prewitt = np.array([[1, 1, 1], [0, 0, 0], [-1, -1, -1]], dtype=int)
kernely_Prewitt = np.array([[-1, 0, 1], [-1, 0, 1], [-1, 0, 1]], dtype=int)
x_Prewitt = cv2.filter2D(img_binary, -1, kernelx_Prewitt)
y_Prewitt = cv2.filter2D(img_binary, -1, kernely_Prewitt)
absX_Prewitt = cv2.convertScaleAbs(x_Prewitt)
absY_Prewitt = cv2.convertScaleAbs(y_Prewitt)
img_Prewitt = cv2.addWeighted(absX_Prewitt, 0.5, absY_Prewitt, 0.5, 0)
cv2.imshow("img_Prewitt", img_Prewitt)
cv2.waitKey(0)
cv2.destroyAllWindows()

# 3.2.3 Sobel算子(用于边缘检测的离散微分算子)
x_Sobel = cv2.Sobel(img_binary, cv2.CV_16S, 1, 0)  # 对x求一阶导
y_Sobel = cv2.Sobel(img_binary, cv2.CV_16S, 0, 1)
absX_Sobel = cv2.convertScaleAbs(x_Sobel)   # 对x取绝对值,并将图像转换为8位图
absY_Sobel = cv2.convertScaleAbs(y_Sobel)
img_Sobel = cv2.addWeighted(absX_Sobel, 0.5, absY_Sobel, 0.5, 0)
cv2.imshow("img2_Sobel.jpg", img_Sobel)
cv2.waitKey(0)
cv2.destroyAllWindows()

三种锐化滤波后的效果图:

  • Roberts算子

在这里插入图片描述

图7. Roberts算子滤波效果图
  • Prewitt算子

在这里插入图片描述

图8. Prewitt算子滤波效果图
  • Sobel算子

在这里插入图片描述

图9. Sobel算子滤波效果图

4.3.4 利用低通(平滑)滤波器和高通(锐化)滤波器进行频域滤波

实现代码:

# 4.利用低通(平滑)滤波器和高通(锐化)滤波器进行频域滤波
# 4.1 低通滤波器
def lowPassFiltering(input_img, size):
    h, w = input_img.shape[0:2]
    h_center, w_center = int(h / 2), int(w / 2)
    img_black = np.zeros((h, w), np.uint8)
    # 中心点加减滤波尺寸的一半,刚好形成一个定义尺寸的滤波大小,然后设置为1,保留低频部分
    img_black[h_center-int(size/2):h_center+int(size/2), w_center-int(size/2):w_center+int(size/2)] = 1
    output_img = input_img*img_black    # 将定义的低通滤波与传入的傅里叶频谱图一一对应相乘,得到低通滤波
    return output_img


# 傅里叶变换
img_dft = np.fft.fft2(img_gray)
dft_shift_low = np.fft.fftshift(img_dft)
# 低通滤波
dft_shift_low = lowPassFiltering(dft_shift_low, 100)
res = np.log(np.abs(dft_shift_low))
# 傅里叶逆变换
idft_shift = np.fft.ifftshift(dft_shift_low)
ifimg = np.fft.ifft2(idft_shift)
ifimg = np.abs(ifimg)
cv2.imshow("img_lowPassFilter", np.int8(ifimg))
cv2.waitKey(0)
cv2.destroyAllWindows()


# 4.2 高通滤波器
def highPassFiltering(input_img, size):     # 传递参数为傅里叶变换后的频谱图和滤波尺寸
    h, w = input_img.shape[0:2]     # 获取图像属性(高、宽和图像通道数)
    h_center, w_center = int(h/2), int(w/2)     # 找到傅里叶频谱图的中心点
    output_img = input_img
    # 中心点加减滤波尺寸的一半,刚好形成一个定义尺寸的滤波大小,然后设置为0
    output_img[h_center-int(size/2):h_center+int(size/2), w_center-int(size/2):w_center+int(size/2)] = 0
    return output_img


# 傅里叶变换
img_dft = np.fft.fft2(img_gray)
dft_shift = np.fft.fftshift(img_dft)    # 将频域从左上角移动到中间
# 高通滤波
dft_shift = highPassFiltering(dft_shift, 50)
res = np.log(np.abs(dft_shift))
# 傅里叶逆变换
idft_shift = np.fft.ifftshift(dft_shift)    # 将频域从中间移动到左上角
img_idft = np.fft.ifft2(idft_shift)
img_idft = np.abs(img_idft)
cv2.imshow("img_highPassFilter", np.int8(img_idft))
cv2.waitKey(0)
cv2.destroyAllWindows()

两种滤波器频域滤波效果:

  • 低通滤波器

在这里插入图片描述

图10. 低通滤波器滤波效果图
  • 高通滤波器

在这里插入图片描述

图11. 高通滤波器滤波效果图

附录:整体代码

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

img = cv2.imread(r'./data/1.jpg')   # 使用 imread 函数读取图像,并以 numpy 数组形式储存
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 使用 cv.cvtColor 函数转换色彩空间,从RGB空间转换到灰度空间

# 1.绘制灰度直方图
hist = cv2.calcHist([img_gray], [0], None, [256], [0, 255])  # OpenCV 利用 calcHist() 函数来绘制直方图
plt.plot(hist)
plt.show()

# 2.直方图均衡化
img_equ = cv2.equalizeHist(img_gray)    # equalizeHist()函数输入为灰度图像,输出为直方图均衡化后的图像
cv2.imshow('img_gray_equ', img_equ)
cv2.waitKey(0)
cv2.destroyAllWindows()
hist_equ = cv2.calcHist([img_equ], [0], None, [256], [0, 255])
plt.plot(hist_equ)
plt.show()

# 3.利用模板进行空域滤波
# 3.1 平滑滤波
# 均值滤波
img_blur = cv2.blur(img, (3, 5))    # 模板大小为 3*5, 其大小是可以设定的
cv2.imshow('img_blur', img_blur)
cv2.waitKey(0)
cv2.destroyAllWindows()
img_box = cv2.boxFilter(img, -1, (3, 5))    # 方框滤波
cv2.imshow('img_box', img_box)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 高斯模糊滤波
img_gauss = cv2.GaussianBlur(img, (5, 5), 0)    # (5,5)表示的是卷积模板的大小,0 表示的是沿 x 与 y 方向上的标准差
cv2.imshow('img_gauss', img_gauss)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 中值滤波
img_median = cv2.medianBlur(img, 5)
cv2.imshow('img_median', img_median)
cv2.waitKey(0)
cv2.destroyAllWindows()

# 3.2 锐化滤波
# 3.2.1 Roberts算子(交叉微分算法)
# 图像阈值化处理
ret, img_binary = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)    # 二进制阈值化
# 调用Roberts算法的OpenCV库函数进行图像轮廓提取
kernelx_Robert = np.array([[-1, 0], [0, 1]], dtype=int)
kernely_Robert = np.array([[0, -1], [1, 0]], dtype=int)
x_Robert = cv2.filter2D(img_binary, cv2.CV_16S, kernelx_Robert)
y_Robert = cv2.filter2D(img_binary, cv2.CV_16S, kernely_Robert)
# 转uint8
absX_Robert = cv2.convertScaleAbs(x_Robert)
absY_Robert = cv2.convertScaleAbs(y_Robert)
img_Roberts = cv2.addWeighted(absX_Robert, 0.5, absY_Robert, 0.5, 0)
# 展示处理后的结果
cv2.imshow("img_Roberts", img_Roberts)
cv2.waitKey(0)
cv2.destroyAllWindows()

# 3.2.2 Prewitt算子
kernelx_Prewitt = np.array([[1, 1, 1], [0, 0, 0], [-1, -1, -1]], dtype=int)
kernely_Prewitt = np.array([[-1, 0, 1], [-1, 0, 1], [-1, 0, 1]], dtype=int)
x_Prewitt = cv2.filter2D(img_binary, -1, kernelx_Prewitt)
y_Prewitt = cv2.filter2D(img_binary, -1, kernely_Prewitt)
absX_Prewitt = cv2.convertScaleAbs(x_Prewitt)
absY_Prewitt = cv2.convertScaleAbs(y_Prewitt)
img_Prewitt = cv2.addWeighted(absX_Prewitt, 0.5, absY_Prewitt, 0.5, 0)
cv2.imshow("img_Prewitt", img_Prewitt)
cv2.waitKey(0)
cv2.destroyAllWindows()

# 3.2.3 Sobel算子(用于边缘检测的离散微分算子)
x_Sobel = cv2.Sobel(img_binary, cv2.CV_16S, 1, 0)  # 对x求一阶导
y_Sobel = cv2.Sobel(img_binary, cv2.CV_16S, 0, 1)
absX_Sobel = cv2.convertScaleAbs(x_Sobel)   # 对x取绝对值,并将图像转换为8位图
absY_Sobel = cv2.convertScaleAbs(y_Sobel)
img_Sobel = cv2.addWeighted(absX_Sobel, 0.5, absY_Sobel, 0.5, 0)
cv2.imshow("img2_Sobel.jpg", img_Sobel)
cv2.waitKey(0)
cv2.destroyAllWindows()


# 4.利用低通(平滑)滤波器和高通(锐化)滤波器进行频域滤波
# 4.1 低通滤波器
def lowPassFiltering(input_img, size):
    h, w = input_img.shape[0:2]
    h_center, w_center = int(h / 2), int(w / 2)
    img_black = np.zeros((h, w), np.uint8)
    # 中心点加减滤波尺寸的一半,刚好形成一个定义尺寸的滤波大小,然后设置为1,保留低频部分
    img_black[h_center-int(size/2):h_center+int(size/2), w_center-int(size/2):w_center+int(size/2)] = 1
    output_img = input_img*img_black    # 将定义的低通滤波与传入的傅里叶频谱图一一对应相乘,得到低通滤波
    return output_img


# 傅里叶变换
img_dft = np.fft.fft2(img_gray)
dft_shift_low = np.fft.fftshift(img_dft)
# 低通滤波
dft_shift_low = lowPassFiltering(dft_shift_low, 100)
res = np.log(np.abs(dft_shift_low))
# 傅里叶逆变换
idft_shift = np.fft.ifftshift(dft_shift_low)
ifimg = np.fft.ifft2(idft_shift)
ifimg = np.abs(ifimg)
cv2.imshow("img_lowPassFilter", np.int8(ifimg))
cv2.waitKey(0)
cv2.destroyAllWindows()


# 4.2 高通滤波器
def highPassFiltering(input_img, size):     # 传递参数为傅里叶变换后的频谱图和滤波尺寸
    h, w = input_img.shape[0:2]     # 获取图像属性(高、宽和图像通道数)
    h_center, w_center = int(h/2), int(w/2)     # 找到傅里叶频谱图的中心点
    output_img = input_img
    # 中心点加减滤波尺寸的一半,刚好形成一个定义尺寸的滤波大小,然后设置为0
    output_img[h_center-int(size/2):h_center+int(size/2), w_center-int(size/2):w_center+int(size/2)] = 0
    return output_img


# 傅里叶变换
img_dft = np.fft.fft2(img_gray)
dft_shift = np.fft.fftshift(img_dft)    # 将频域从左上角移动到中间
# 高通滤波
dft_shift = highPassFiltering(dft_shift, 50)
res = np.log(np.abs(dft_shift))
# 傅里叶逆变换
idft_shift = np.fft.ifftshift(dft_shift)    # 将频域从中间移动到左上角
img_idft = np.fft.ifft2(idft_shift)
img_idft = np.abs(img_idft)
cv2.imshow("img_highPassFilter", np.int8(img_idft))
cv2.waitKey(0)
cv2.destroyAllWindows()

猜你喜欢

转载自blog.csdn.net/alan1ly/article/details/125368000