1.图像的基本操作与基本运算
1.编写程序,将自选图像(如图 1)和 OpenCV 的 Logo 图像叠加现实,其中 Logo
图像做背景透明处理。(提示:OpenCV 的 Logo 图像背景是白色的)
实现代码及注释讲解
import cv2
import numpy as np
image = cv2.imread('lena.jpg')
logo = cv2.imread('OpenCV.jpg')
if image is None or logo is None:
print("无法读取图像文件")
exit()
# 调整 Logo 图像的大小,使其与自选图像匹配
height, width, _ = image.shape
logo = cv2.resize(logo, (width, height))
lower_white = np.array([100, 100 , 100], dtype=np.uint8)
upper_white = np.array([255, 255, 255], dtype=np.uint8)
# 创建掩码,将白色像素设置为 1,其余像素设置为 0
mask = cv2.inRange(logo, lower_white, upper_white)
# 将掩码取反,将白色像素设置为 0,其余像素设置为 1
mask = cv2.bitwise_not(mask)
# 将图像与掩码进行按位与操作,将白色像素转换为黑色
result0 = cv2.bitwise_and(logo, logo, mask=mask)
cv2.imwrite("result0.jpg",result0)
cv2.imshow('result0',result0)
# 将图像转换为灰度图像
gray_logo = cv2.cvtColor(logo, cv2.COLOR_BGR2GRAY)
# 定义阈值,用于识别非白色像素
threshold = 200 # 这里使用 200 作为阈值,可以根据需要调整
# 创建一个与原图像相同大小的掩码
mask = (gray_logo < threshold)
# 将掩码中的 True 值(非白色像素)设置为黑色
gray_logo[mask] = 0
#黑白反转
gray_logo = cv2.bitwise_not(gray_logo)
#转为彩色
gray_logo = cv2.cvtColor(gray_logo, cv2.COLOR_GRAY2BGR)
#得到叠加图像
image_with_logo = cv2.add(cv2.subtract(image, gray_logo), result0)
cv2.imwrite('gray_logo.jpg',gray_logo)
cv2.imshow('gray_logo.jpg',gray_logo)
cv2.imwrite('image_with_logo.jpg',image_with_logo)
cv2.imshow('image_with_logo',image_with_logo)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果展示
2.图像的几何变换
编写程序,使用 cv2.warpAffine()函数使一幅图像放大为原来的二倍后,以图像中
心为原点,顺时针旋转 90 度再向左平移 20 个单位,向上平移 20 单位,不改变图片大小。
实现代码及注释讲解
import cv2
import numpy as np
image = cv2.imread('lena.jpg')
height, width = image.shape[:2]
# 计算放大后的图像中心坐标
center_x, center_y = width // 2, height // 2
# 定义放大倍数
scale_factor = 2
new_width, new_height = int(width * scale_factor), int(height * scale_factor)
# 构建放大矩阵
scale_matrix = np.array([[scale_factor, 0, 0],
[0, scale_factor, 0]], dtype=np.float32)
# 进行放大操作
enlarged_image = cv2.warpAffine(image, scale_matrix, (new_width, new_height))
enlarged_image = cv2.resize(image, (2 * width, 2 * height), interpolation=cv2.INTER_LINEAR)
cv2.imwrite('enlarged_image.jpg',enlarged_image)
cv2.imshow('enlarged_image',enlarged_image)
# 构建旋转矩阵(顺时针旋转 90 度)
rotation_matrix = cv2.getRotationMatrix2D((center_x, center_y), 90, 1)
# 进行旋转操作
# rotated_image = cv2.warpAffine(enlarged_image, rotation_matrix, (width * 2, height * 2))
rotated_image = cv2.rotate(enlarged_image,cv2.ROTATE_90_CLOCKWISE)
cv2.imwrite('rotated_image.jpg',rotated_image)
cv2.imshow('rotated_image',rotated_image)
# 构建平移矩阵(向左平移 20 个单位,向上平移 20 个单位)
translation_matrix = np.array([[1, 0, -20],
[0, 1, -20]], dtype=np.float32)
height, width = rotated_image.shape[:2]
# 进行平移操作
final_image=cv2.warpAffine(rotated_image,translation_matrix,(width,
height),borderValue=(255,255,255))
cv2.imwrite('final_image.jpg', final_image)
cv2.imshow('final_image',final_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果展示
3.图像灰度变换
1.参考 cv2.intensity_transform.contrastStretching 函数,手动编写程序,完成彩色图
像的亮度和对比度增强或减弱。并说明当某一像素值超过 255 或小于 0 时如何处理。
实现代码及注释讲解
import cv2
import numpy as np
def contrast_and_brightness(image, alpha, beta):
# 对图像的每个通道进行亮度和对比度调整
result = np.empty_like(image, dtype=np.float32)
for channel in range(3): # 3 表示 RGB 通道
result[:, :, channel] = alpha * image[:, :, channel] + beta
# 处理像素值超过 255 或小于 0 的情况
result[:, :, channel] = np.clip(result[:, :, channel], 0, 255)
return result.astype(np.uint8)
image = cv2.imread('lena.jpg')
# 设置亮度和对比度增强参数
alpha = 1.5 # 调整对比度,大于 1 增强,小于 1 减弱
beta = 30 # 调整亮度,正数增强,负数减弱
# 应用亮度和对比度增强函数
enhanced_image = contrast_and_brightness(image, alpha, beta)
cv2.imshow('Original Image', image)
cv2.imshow('Enhanced Image', enhanced_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果展示
结果分析
调整对比度 alpha,大于 1 增强,小于 1 减弱调整亮度 beta,正数增强,负数减弱
2.编写程序,对彩色图像进行对数变换和伽玛变换,说明参数 c 和伽玛值γ对图像
变换的影响。
实现代码及注释讲解
import cv2
import numpy as np
image = cv2.imread('lena.jpg')
# 对数变换
def log_transform(image, c):
image_float = image.astype(np.float32) / 255.0
# 对每个通道应用对数变换
image_log = c * np.log(1 + image_float)
# 将像素值缩放回[0, 255]
image_log = (image_log * 255).astype(np.uint8)
return image_log
# 伽玛变换
def gamma_transform(image, gamma, c):
image_float = image.astype(np.float32) / 255.0
# 对每个通道应用伽玛变换
image_gamma = c * (image_float ** gamma)
# 将像素值缩放回[0, 255]
image_gamma = (image_gamma * 255).astype(np.uint8)
return image_gamma
# 设置对数变换参数
c_log = [0.2,0.5,1,1.5]
# 设置伽玛变换参数
gamma = [0.05,0.5,1.0,1.5,3.0]
c_gamma = 1
# 应用对数变换和伽玛变换
for i in range(5):
log_transformed_image = log_transform(image, c_log[i])
cv2.imshow('Log Transform', log_transformed_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
for i in range(5):
gamma_transformed_image = gamma_transform(image, gamma[i], c_gamma)
cv2.imshow('Gamma Transform', gamma_transformed_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
img_t = np.hstack((image,log_transformed_image,gamma_transformed_image))
cv2.imshow('img_t', img_t)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果展示
结果分析
对数变换实现了扩展低灰度值而压缩高灰度值的效果,对数变换后,较暗区域的对比度提升,可以增强图像较暗的细节。
伽马变换提升暗部细节,对发白或过暗的图片进行矫正。
当γ<1 时,扩展低灰度级,压缩高灰度级,图像整体变亮;
当γ>1 时,压缩低灰度级,扩展高灰度级,图像整体变暗;
3.对于同一个室外场景,分别在早上、中午和晚上拍摄三张照片,分别对它们进行直方图处理,并对它们进行直方图均衡化处理,仔细观察均衡化前后的变化。
实现代码及注释讲解
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 读取三张照片(早上、中午、晚上)
morning_image = cv2.imread('60b0bdf0a0394027b81df7ce12fce96.jpg')
noon_image = cv2.imread('fa972762274cfc303379226d62fc5c4.jpg')
evening_image = cv2.imread('c4ec4f837e0741391c7826aea7c520a.jpg')
# 定义直方图均衡化函数
def histogram_equalization(image):
# 分离彩色图像的通道
b, g, r = cv2.split(image)
# 对每个通道进行直方图均衡化
b_equalized = cv2.equalizeHist(b)
g_equalized = cv2.equalizeHist(g)
r_equalized = cv2.equalizeHist(r)
# 合并通道以生成均衡化后的彩色图像
equalized_image = cv2.merge((b_equalized, g_equalized, r_equalized))
return equalized_image
morning_equalized = histogram_equalization(morning_image)
noon_equalized = histogram_equalization(noon_image)
evening_equalized = histogram_equalization(evening_image)
plt.figure(figsize=(12, 4))
plt.subplot(2, 3, 1)
plt.imshow(cv2.cvtColor(morning_image, cv2.COLOR_BGR2RGB))
plt.title('Morning (Original)')
plt.axis('off')
plt.subplot(2, 3, 2)
plt.imshow(cv2.cvtColor(noon_image, cv2.COLOR_BGR2RGB))
plt.title(' Noon (Original)')
plt.axis('off')
plt.subplot(2, 3, 3)
plt.imshow(cv2.cvtColor(evening_image, cv2.COLOR_BGR2RGB))
plt.title('Evening (Original)')
plt.axis('off')
plt.subplot(2, 3, 4)
plt.imshow(cv2.cvtColor(morning_equalized, cv2.COLOR_BGR2RGB))
plt.title('Morning (Equalized)')
plt.axis('off')
plt.subplot(2, 3, 5)
plt.imshow(cv2.cvtColor(noon_equalized, cv2.COLOR_BGR2RGB))
plt.title('Noon (Equalized)')
plt.axis('off')
plt.subplot(2, 3, 6)
plt.imshow(cv2.cvtColor(evening_equalized, cv2.COLOR_BGR2RGB))
plt.title('Evening (Equalized)')
plt.axis('off')
plt.tight_layout()
plt.show()
结果展示
结果分析
均衡化后的图像通常具有更好的对比度,可以更清晰地显示细节,特别是在光照不均匀的情
况下,实验结果中效果明显。
4.找一副较暗的图像,分别对这幅图像进行自适应直方图均衡化(CLAHE)处理,观
察处理效果。
文章来源地址https://www.toymoban.com/news/detail-854416.html
实现代码及注释讲解
import cv2
dark_image = cv2.imread('lena.jpg', cv2.IMREAD_GRAYSCALE)
# 创建 CLAHE 对象
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
# 应用 CLAHE 处理
enhanced_image = clahe.apply(dark_image)
cv2.imshow('inital Image', dark_image)
cv2.imshow('Enhanced Image', enhanced_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果展示
结果分析
较小的 clipLimit 值和较大的 tileGridSize 将产生较轻的增强效果,而较大的 clipLimit 值和
较小的 tileGridSize 将产生较强的增强效果。
4.图像空域滤波
1.编写程序,使用不同尺寸的卷积核对带有高斯噪声的图像进行均值滤波和高斯滤
波,仔细观察它们的滤波效果。
实现代码及注释讲解
import cv2
import numpy as np
image = cv2.imread('lena.jpg')
# 添加高斯噪声
noise = np.random.normal(0, 1, image.shape).astype(np.uint8)
noisy_image = cv2.add(image, noise)
cv2.imshow('noisy_image',noisy_image)
# 定义不同尺寸的卷积核
kernel_sizes = [3, 5, 7] # 你可以根据需要修改卷积核的大小
# 对图像进行均值滤波和高斯滤波
for kernel_size in kernel_sizes:
# 均值滤波
mean_blur = cv2.blur(noisy_image, (kernel_size, kernel_size))
# 高斯滤波
gaussian_blur = cv2.GaussianBlur(noisy_image, (kernel_size, kernel_size), 0)
# 显示原始图像、均值滤波结果和高斯滤波结果
cv2.imshow(f'Mean Blur (Kernel {kernel_size}x{kernel_size})', mean_blur)
cv2.imshow(f'Gaussian Blur (Kernel {kernel_size}x{kernel_size})', gaussian_blur)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果展示
结果分析
均值滤波使用卷积核中的像素值的平均值来替代目标像素的值。这种滤波方法对于去除轻度
噪声效果较好。均值滤波会产生一种模糊效果,特别是对于较小的卷积核。卷积核越大,模
糊效果越明显。
它不太适用于去除大范围的噪声或保留图像的细节。
高斯滤波使用卷积核中的像素值的加权平均值来替代目标像素的值,其中像素距离目标像素
越近的像素具有更高的权重。高斯滤波能够较好地平衡去噪和保留图像细节之间的关系,因
此通常比均值滤波更适用于实际应用中。
它可以有效地去除高斯噪声和其他类型的噪声,并且不会引入过多的模糊。
小卷积核:当卷积核大小相对较小(例如 3x3 或 5x5)时,滤波效果通常较弱,可以保留较
多的图像细节。这种情况下,滤波主要用于去除图像中的轻微噪声或平滑图像,但不会引入
太多模糊。
中等卷积核: :中等大小的卷积核(例如 7x7 或 9x9)会产生中等程度的平滑效果,可以有效
去除一些中等程度的噪声。这种滤波通常在需要平衡噪声去除和图像细节保留的情况下使用。
大卷积核:
较大的卷积核(例如 11x11 或更大)会产生强烈的平滑效果,可以有效地去除大范围的噪声。
然而,使用大卷积核可能会引入显著的图像模糊,因此通常在不需要保留细节的情况下使用,
例如用于预处理或特定应用。
2. 编写程序,分别使用高斯均值滤波和中值滤波对带有椒盐噪声的图像进行滤波,观
察并比较滤波效果。
实现代码及注释讲解
import cv2
import numpy as np
image = cv2.imread('lena.jpg')
# 添加椒盐噪声
def add_salt_and_pepper_noise(image, salt_prob, pepper_prob):
noisy_image = np.copy(image)
total_pixels = image.size
num_salt = int(total_pixels * salt_prob)
salt_coords = [np.random.randint(0, i - 1, num_salt) for i in image.shape]
noisy_image[salt_coords[0], salt_coords[1]] = 255
num_pepper = int(total_pixels * pepper_prob)
pepper_coords = [np.random.randint(0, i - 1, num_pepper) for i in image.shape]
noisy_image[pepper_coords[0], pepper_coords[1]] = 0
return noisy_image
salt_prob = 0.01 # 椒噪声概率
pepper_prob = 0.01 # 盐噪声概率
noisy_image = add_salt_and_pepper_noise(image, salt_prob, pepper_prob)
# 高斯均值滤波
gaussian_blur = cv2.GaussianBlur(noisy_image, (5, 5), 0)
# 中值滤波
median_blur = cv2.medianBlur(noisy_image, 5)
cv2.imshow('Noisy Image', noisy_image)
cv2.imshow('Gaussian Blur', gaussian_blur)
cv2.imshow('Median Blur', median_blur)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果展示
结果分析
高斯均值滤波通常用于去除高斯噪声,而中值滤波通常用于去除椒盐噪声。根据实验结果图
可以看出中值滤波的效果明显好于高斯均值滤波。
3.编写程序,分别实现基于拉普拉斯算子和非锐化遮蔽两种方法实现图像锐化处理,
并比较两种方法的结果。
实现代码及注释讲解
import cv2
import numpy as np
image = cv2.imread('lena.jpg')
# 定义拉普拉斯核
laplacian_kernel = np.array([[0, 1, 0],
[1, -4, 1],
[0, 1, 0]], dtype=np.float32)
# 使用拉普拉斯算子进行锐化
laplacian_sharpened = cv2.filter2D(image, -1, laplacian_kernel)
laplacian_sharpened = cv2.add(laplacian_sharpened,image)
# 非锐化遮蔽
imgGauss = cv2.GaussianBlur(image,(5,5),sigmaX=5)
imgGaussNorm =
cv2.normalize(imgGauss,dst=None,alpha=0,beta=255,norm_type=cv2.NORM_MINMAX)
imgMask = image - imgGaussNorm
passivation = image + imgMask
imgPas=cv2.normalize(passivation,dst=None,alpha=0,beta=255,norm_type=cv2.NORM_MINMAX
)
cv2.imshow('Original Image', image)
cv2.imshow('Laplacian Sharpened', laplacian_sharpened)
cv2.imshow('Unsharp Masking Sharpened', imgPas)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果展示
结果分析
拉普拉斯锐化通常用于突出图像中的边缘和细节,而非锐化遮蔽锐化可以增强图像的整体对
比度和细节。
5.图像去噪
1.编写程序,在给定图像上分别添加高斯噪声、椒盐噪声、以及高斯-椒盐混合噪声 ,并将含噪图像保存(噪声的参数自行)。
实现代码及注释讲解
import cv2
import numpy as np
# 1. 添加高斯噪声、椒盐噪声、高斯-椒盐混合噪声并保存图像
def add_noise(image, noise_type, noise_level=0.05):
if noise_type == 'gaussian':
noise = np.random.normal(0, 1, image.shape) * noise_level
noisy_image = image + noise
elif noise_type == 'salt_and_pepper':
ps, pp =0.05,0.02
noise = np.random.choice([0, 0.5, 1], size=image.shape, p=[pp, (1-ps-pp), ps])
noisy_image = image.copy()
noisy_image[noise == 1] = 255
noisy_image[noise == 0] = 0
elif noise_type == 'mixed':
ps, pp = 0.05, 0.02
gaussian_noise = np.random.normal(0, 1, image.shape) * noise_level
salt_and_pepper = np.random.choice([0, 0.5, 1], size=image.shape, p=[pp, (1-ps-pp),
ps])
noisy_image = image + gaussian_noise
noisy_image[salt_and_pepper == 1] = 255
noisy_image[salt_and_pepper == 0] = 0
return np.clip(noisy_image, 0, 255).astype(np.uint8)
# 2. 图像读取
image = cv2.imread('lena.jpg', 0)
# 3. 添加噪声
gaussian_noisy_image = add_noise(image, 'gaussian', noise_level=30)
salt_and_pepper_noisy_image = add_noise(image, 'salt_and_pepper', noise_level=0.05)
mixed_noisy_image = add_noise(image, 'mixed', noise_level=0.1)
# 4. 保存含噪声的图像
cv2.imwrite('gaussian_noisy_image.jpg', gaussian_noisy_image)
cv2.imwrite('salt_and_pepper_noisy_image.jpg', salt_and_pepper_noisy_image)
cv2.imwrite('mixed_noisy_image.jpg', mixed_noisy_image)
结果展示
2. 编写程序,实现两种或两种以上不同空域滤波方法对带有高斯噪声的图像进行去噪,
观察并比较滤波效果。
实现代码及注释讲解
# #算数均值滤波器
img_gray = cv2.imread('lena.jpg', 0)
imgGaussNoise = cv2.imread("gaussian_noisy_image.jpg",0)
kSize = (7,7)
kernalMean = np.ones(kSize, np.float32) / (kSize[0]*kSize[1]) # 生成归一化盒式核
imgConv1 = cv2.filter2D(imgGaussNoise, -1, kernalMean) # cv2.filter2D 方法
cv2.imwrite('denoised_gaussian1.jpg', imgConv1)
# # 几何均值滤波器 (Geometric mean filter)
img_h = img_gray.shape[0]
img_w = img_gray.shape[1]
m, n = 5, 5
order = 1/(m*n)
kernalMean = np.ones((m,n), np.float32) # 生成盒式核
hPad = int((m-1) / 2)
wPad = int((n-1) / 2)
imgPad = np.pad(img_gray.copy(), ((hPad, m-hPad-1), (wPad, n-wPad-1)), mode="edge")
imgGeoMean = imgGaussNoise.copy()
for i in range(hPad, img_h + hPad):
for j in range(wPad, img_w + wPad):
prod = np.prod(imgPad[i-hPad:i+hPad+1, j-wPad:j+wPad+1]*1.0)
imgGeoMean[i-hPad][j-wPad] = np.power(prod, order)
cv2.imwrite('denoised_gaussian2.jpg', imgGeoMean)
# #谐波均值滤波器
m, n = 3, 3
order = m * n
kernalMean = np.ones((m,n), np.float32) # 生成盒式核
hPad = int((m-1) / 2)
wPad = int((n-1) / 2)
imgPad = np.pad(imgGaussNoise.copy(), ((hPad, m-hPad-1), (wPad, n-wPad-1)), mode="edge")
epsilon = 1e-8
imgHarMean = imgGaussNoise.copy()
for i in range(hPad, img_h + hPad):
for j in range(wPad, img_w + wPad):
sumTemp = np.sum(1.0 / (imgPad[i-hPad:i+hPad+1, j-wPad:j+wPad+1] + epsilon))
imgHarMean[i-hPad][j-wPad] = order / sumTemp
cv2.imwrite('denoised_gaussian3.jpg', imgHarMean)
结果展示
结果分析
算数均值滤波器平滑图像中的局部变化,可以降低图像中的噪声,但会模糊图像。
几何均值滤波器与算数均值滤波器相当,但损失的细节更少,总体效果更好。
谐波均值滤波器是一种非线性滤波方法,可处理高斯噪声。
3. 编写程序,实现两种或两种以上不同空域滤波方法对带有椒盐噪声的图像进行去噪,
观察并比较滤波效果。
实现代码及注释讲解
# # 几何均值滤波器 (Geometric mean filter)
img_h = img_gray.shape[0]
img_w = img_gray.shape[1]
m, n = 5, 5
order = 1/(m*n)
kernalMean = np.ones((m,n), np.float32) # 生成盒式核
hPad = int((m-1) / 2)
wPad = int((n-1) / 2)
imgPad = np.pad(img_gray.copy(), ((hPad, m-hPad-1), (wPad, n-wPad-1)), mode="edge")
imgGeoMean = imgSPNoise.copy()
for i in range(hPad, img_h + hPad):
for j in range(wPad, img_w + wPad):
prod = np.prod(imgPad[i-hPad:i+hPad+1, j-wPad:j+wPad+1]*1.0)
imgGeoMean[i-hPad][j-wPad] = np.power(prod, order)
cv2.imwrite('denoised_SP2.jpg', imgGeoMean)
# #谐波均值滤波器
m, n = 3, 3
order = m * n
kernalMean = np.ones((m,n), np.float32) # 生成盒式核
hPad = int((m-1) / 2)
wPad = int((n-1) / 2)
imgPad = np.pad(imgSPNoise.copy(), ((hPad, m-hPad-1), (wPad, n-wPad-1)), mode="edge")
epsilon = 1e-8
imgHarMean = imgSPNoise.copy()
for i in range(hPad, img_h + hPad):
for j in range(wPad, img_w + wPad):
sumTemp = np.sum(1.0 / (imgPad[i-hPad:i+hPad+1, j-wPad:j+wPad+1] + epsilon))
imgHarMean[i-hPad][j-wPad] = order / sumTemp
cv2.imwrite('denoised_SPN.jpg', imgHarMean)
img_h = imgSPNoise.shape[0]
img_w = imgSPNoise.shape[1]
m, n = 3, 3
kernalMean = np.ones((m, n), np.float32) # 生成盒式核
# 边缘填充
hPad = int((m-1) / 2)
wPad = int((n-1) / 2)
imgPad = np.pad(imgSPNoise.copy(), ((hPad, m-hPad-1), (wPad, n-wPad-1)), mode="edge")
imgMedianFilter = np.zeros(imgSPNoise.shape) # 中值滤波器
imgMaxFilter = np.zeros(imgSPNoise.shape) # 最大值滤波器
imgMinFilter = np.zeros(imgSPNoise.shape) # 最小值滤波器
imgMiddleFilter = np.zeros(imgSPNoise.shape) # 中点滤波器
for i in range(img_h):
for j in range(img_w):
# # 1. 中值滤波器 (median filter)
pad = imgPad[i:i+m, j:j+n]
imgMedianFilter[i, j] = np.median(pad)
cv2.imwrite('denoised_salt_and_pepper1.jpg', imgMedianFilter)
结果展示
结果分析
几何均值滤波器与算数均值滤波器相当,但损失的细节更少,总体效果更好。
谐波均值滤波器是一种非线性滤波方法,既可以处理盐粒噪声(白点噪声),又可以处理高
斯噪声,但不能处理胡椒噪声(黑点噪声)。
中值滤波器用预定义的像素领域中的灰度中值来代替像素的值,与线性平滑滤波器相比能有
效地降低某些随机噪声,且模糊度要小得多。
4. 编写程序,对于含有高斯-椒盐混合噪声的图像,设计并实现至少一种空域滤波方
法,有效抑制混合噪声,并分析滤波结果。
实现代码及注释讲解
#中值滤波器与自适应中值滤波器
smax = 7 # 允许最大窗口尺寸
m, n = smax, smax
imgAriMean = cv2.boxFilter(imgSPNoise, -1, (m, n)) # 算术平均滤波
# 边缘填充
hPad = int((m-1) / 2)
wPad = int((n-1) / 2)
imgPad = np.pad(imgSPNoise.copy(), ((hPad, m-hPad-1), (wPad, n-wPad-1)), mode="edge")
imgMedianFilter = np.zeros(imgSPNoise.shape) # 中值滤波器
imgAdaMedFilter = np.zeros(imgSPNoise.shape) # 自适应中值滤波器
for i in range(hPad, hPad+hImg):
for j in range(wPad, wPad+wImg):
# 1. 中值滤波器 (Median filter)
ksize = 3
k = int(ksize/2)
pad = imgPad[i-k:i+k+1, j-k:j+k+1] # 邻域 Sxy, m*n
imgMedianFilter[i-hPad, j-wPad] = np.median(pad)
# 2. 自适应中值滤波器 (Adaptive median filter)
ksize = 3
k = int(ksize/2)
pad = imgPad[i-k:i+k+1, j-k:j+k+1]
zxy = imgSPNoise[i-hPad][j-wPad]
zmin = np.min(pad)
zmed = np.median(pad)
zmax = np.max(pad)
if zmin < zmed < zmax:
if zmin < zxy < zmax:
imgAdaMedFilter[i-hPad, j-wPad] = zxy
else:
imgAdaMedFilter[i-hPad, j-wPad] = zmed
else:
while True:
ksize = ksize + 2
if zmin < zmed < zmax or ksize > smax:
break
k = int(ksize / 2)
pad = imgPad[i-k:i+k+1, j-k:j+k+1]
zmed = np.median(pad)
zmin = np.min(pad)
zmax = np.max(pad)
if zmin < zmed < zmax or ksize > smax:
if zmin < zxy < zmax:
imgAdaMedFilter[i-hPad, j-wPad] = zxy
else:
imgAdaMedFilter[i-hPad, j-wPad] = zmed
cv2.imwrite('denoised_mixed1.jpg', imgAdaMedFilter)
cv2.imwrite('denoised_mixed2.jpg', imgMedianFilter)
结果展示
结果分析
中值滤波器的窗口尺寸是固定大小不变的,不能同时兼顾去噪和保护图像的细节,在噪声的
密度较小时的性能较好,当噪声概率较高时的性能就会劣化。
自适应中值滤波器根据预先设定的条件,在滤波的过程中动态改变滤波器的窗口尺寸大小;
进一步地,根据条件判断当前像素是否噪声,由此决定是否用邻域中值替换当前像素。
自适应中值滤波器可以处理较大概率的脉冲噪声,平滑非脉冲噪声,尽可能保护图像细节信
息,避免图像边缘的细化或者粗化。因此,如果图像中噪声的概率较低,自适应中值滤波器
可以使用较小的窗口尺寸,以提高计算速度;反之,如果噪声的概率较高,则需要增大滤波
器的窗口尺寸,以改善滤波效果。
6.形态学处理
1.编写程序,分别使用 OpenCV 中自带的腐蚀函数、膨胀函数对图像进行腐蚀和膨
胀处理,改变结构元的形状和大小,观察不同结构元的处理效果。
实现代码及注释讲解
import cv2
import numpy as np
# 读取输入图像
image = cv2.imread('dlam.png', 0)
# 定义结构元素的形状和大小(可以根据需要进行调整)
kernel_rect = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
kernel_ellipse = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
kernel_cross = cv2.getStructuringElement(cv2.MORPH_CROSS, (5, 5))
# 对图像进行腐蚀处理
eroded_rect = cv2.erode(image, kernel_rect, iterations=1)
eroded_ellipse = cv2.erode(image, kernel_ellipse, iterations=1)
eroded_cross = cv2.erode(image, kernel_cross, iterations=1)
# 对图像进行膨胀处理
dilated_rect = cv2.dilate(image, kernel_rect, iterations=1)
dilated_ellipse = cv2.dilate(image, kernel_ellipse, iterations=1)
dilated_cross = cv2.dilate(image, kernel_cross, iterations=1)
# 显示处理结果
cv2.imshow('Original Image', image)
cv2.imshow('Eroded (Rectangle)', eroded_rect)
cv2.imshow('Eroded (Ellipse)', eroded_ellipse)
cv2.imshow('Eroded (Cross)', eroded_cross)
cv2.imshow('Dilated (Rectangle)', dilated_rect)
cv2.imshow('Dilated (Ellipse)', dilated_ellipse)
cv2.imshow('Dilated (Cross)', dilated_cross)
结果展示
结果分析
腐蚀减少了毛刺,缩小了图像,减小了背景中的白点噪声,膨胀扩大了图像,增强了背景中
的白点噪声。
结构元素的形状和大小对腐蚀和膨胀操作有着重要的影响。
腐蚀:
结构元素的大小决定了腐蚀操作的程度。较大的结构元素会导致更多的像素被腐蚀掉,从而
使图像中的对象缩小或者分离。
对于具有直线特征的结构元素(如十字形或者矩形),可以更好地保留水平或垂直方向上的
细节信息。
较小的结构元素通常会产生更强烈的腐蚀效果,从而使对象变得更小或者消失。
膨胀:
结构元素的大小也会影响膨胀操作的结果。较大的结构元素将导致更多的像素被膨胀,从而
增加对象的大小或者填充空洞。
对于具有圆形或椭圆形特征的结构元素,可以更好地保留对象的整体形状。
较小的结构元素通常会产生更弱的膨胀效果,仅在对象的边缘周围进行局部膨胀。
总的来说,结构元素的形状和大小会直接影响腐蚀和膨胀操作的结果,因此在图像处理中需
要根据具体情况选择合适的结构元素来实现期望的效果。
2.编写程序,分别使用 OpenCV 中自带的函数对图像进行开运算和膨闭运算,改变
结构元的形状和大小,观察不同结构元的处理效果。
实现代码及注释讲解
import cv2
# 读取图像
image = cv2.imread('dlam.png', 0)
# 定义不同形状和大小的结构元素
kernel_rect = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
kernel_ellipse = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (10, 10))
kernel_cross = cv2.getStructuringElement(cv2.MORPH_CROSS, (15, 15))
# 开运算
opened_rect = cv2.morphologyEx(image, cv2.MORPH_OPEN, kernel_rect)
opened_ellipse = cv2.morphologyEx(image, cv2.MORPH_OPEN, kernel_ellipse)
opened_cross = cv2.morphologyEx(image, cv2.MORPH_OPEN, kernel_cross)
# 闭运算
closed_rect = cv2.morphologyEx(image, cv2.MORPH_CLOSE, kernel_rect)
closed_ellipse = cv2.morphologyEx(image, cv2.MORPH_CLOSE, kernel_ellipse)
closed_cross = cv2.morphologyEx(image, cv2.MORPH_CLOSE, kernel_cross)
# 显示原始图像和处理结果
cv2.imshow('Original Image', image)
cv2.imshow('Opened Rect', opened_rect)
cv2.imshow('Opened Ellipse', opened_ellipse)
cv2.imshow('Opened Cross', opened_cross)
cv2.imshow('Closed Rect', closed_rect)
cv2.imshow('Closed Ellipse', closed_ellipse)
cv2.imshow('Closed Cross', closed_cross)
结果展示
结果分析
开操作和闭操作是形态学图像处理中常用的两种操作,它们对图像的影响如下:
开操作:先进行腐蚀操作,将图像中的细小噪点、毛刺等细节信息去除或减弱。再进行
膨胀操作,将被腐蚀掉的区域重新扩张,使得原本连在一起的物体之间产生分离。
闭操作:先进行膨胀操作,填充空洞,连接断裂的物体等。再进行腐蚀操作,使得原本
连接的物体之间产生分离,同时平滑物体边缘。对于该图像开操作可以减小噪声,闭操作会
放大噪声。
结构元素的形状和大小会对开操作和闭操作产生影响:
形状:矩形结构元素:适合保留水平和垂直方向上的细节信息。
圆形结构元素:适合保持物体的整体形状,可以更好地处理圆形物体。
十字形结构元素:既能够保留水平和垂直方向上的细节信息,又能够保持物体的整体形状。
大小:结构元素的大小决定了腐蚀和膨胀操作的程度。
较大的结构元素会使得腐蚀和膨胀的效果更明显,可以去除较大的噪点或者扩张物体的大小。
较小的结构元素会使得腐蚀和膨胀的效果更细微,适用于去除小的噪点或者微调物体的形状。
对于该图像矩形结构元处理的效果最好,椭圆和十字结构会破坏图像本身的形状。
7.图像分割
1.编写程序,使用 OpenCV 提供的 cv2.threshold,依次使用下表中所示的各种阈值
分割类型对图像进行分割处理,根据实验结果,观察它们的异同。
实现代码及注释讲解
import cv2
import numpy as np
# 读取图像
image = cv2.imread('lena.jpg', 0)
# 二进制阈值化,非黑即白
ret, binary = cv2.threshold(image, 127, 255, cv2.THRESH_BINARY)
# 反二进制阈值化,非白即黑
ret, binary_inv = cv2.threshold(image, 127, 255, cv2.THRESH_BINARY_INV)
# 截断阈值化,大于阈值设为 1
ret, trunc = cv2.threshold(image, 127, 255, cv2.THRESH_TRUNC)
# 阈值化为 0,小于阈值设为 0
ret, tozero = cv2.threshold(image, 127, 255, cv2.THRESH_TOZERO)
# 反阈值化为 0,大于阈值设为 0
ret, tozero_inv = cv2.threshold(image, 127, 255, cv2.THRESH_TOZERO_INV)
# 显示结果
cv2.imshow('Binary', binary)
cv2.imshow('Binary Inverse', binary_inv)
cv2.imshow('Trunc', trunc)
cv2.imshow('To Zero', tozero)
cv2.imshow('To Zero Inverse', tozero_inv)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果展示
结果分析
这几种阈值分割方法在图像显示效果上有以下区别:
cv2.THRESH_BINARY(二进制阈值化):
大于阈值的像素点被设为最大值,小于等于阈值的像素点被设为 0。
输出结果为黑白二值图像,只有两种颜色,即黑色和白色。
cv2.THRESH_BINARY_INV(反二进制阈值化):
大于阈值的像素点被设为 0,小于等于阈值的像素点被设为最大值。
输出结果为黑白二值图像,与 cv2.THRESH_BINARY 相反,即黑色和白色互换。
cv2.THRESH_TRUNC(截断阈值化):
大于阈值的像素点被设为阈值,小于等于阈值的像素点保留原像素值不变。
输出结果的像素值介于 0 到阈值之间,保留了部分灰度级别。
cv2.THRESH_TOZERO(阈值化为 0):
大于阈值的像素点保留原像素值不变,小于等于阈值的像素点被设为 0。
输出结果的像素值介于 0 到原像素值之间,将低于阈值的像素置为黑色。
cv2.THRESH_TOZERO_INV(反阈值化为 0):
大于阈值的像素点被设为 0,小于等于阈值的像素点保留原像素值不变。
输出结果的像素值介于原像素值到最大值之间,将高于阈值的像素置为黑色。
综上所述,这些阈值分割方法在图像显示效果上产生不同的结果。具体使用哪种方法取决于
应用场景和要达到的效果。
2.编写程序,分别使用自适应全局阈值法和 Otsu’s 法分别对图像进行分割处理,比较两种方法的性能。
实现代码及注释讲解
import cv2
# 读取图像
image = cv2.imread('image.jpg', 0)
# 自适应全局阈值法
adaptive_threshold = cv2.adaptiveThreshold(image, 255, cv2.ADAPTIVE_THRESH_MEAN_C,
cv2.THRESH_BINARY,11, 2)
# Otsu's 法
_, otsu_threshold = cv2.threshold(image, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# 比较两种方法的性能
adp_threshold_time = cv2.getTickCount()
adaptive_threshold = cv2.adaptiveThreshold(image, 255, cv2.ADAPTIVE_THRESH_MEAN_C,
cv2.THRESH_BINARY,11, 2)
adp_threshold_time = (cv2.getTickCount() - adp_threshold_time) / cv2.getTickFrequency()
otsu_threshold_time = cv2.getTickCount()
_, otsu_threshold = cv2.threshold(image, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
otsu_threshold_time = (cv2.getTickCount() - otsu_threshold_time) / cv2.getTickFrequency()
# 显示结果
cv2.imshow('Adaptive Threshold', adaptive_threshold)
cv2.imshow("Otsu's Threshold", otsu_threshold)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 输出性能结果
print("自适应全局阈值法时间:", adp_threshold_time, "秒")
print("Otsu's 法时间:", otsu_threshold_time, "秒")
结果展示
结果分析
自适应全局阈值法和 Otsu's 法是常见的图像分割方法,它们各有优劣点,下面对两种方法的
性能进行比较:
自适应全局阈值法:
优点:适用于图像的光照不均匀或存在阴影的情况,能够根据图像局部区域的统计特征来确
定阈值,从而适应不同区域的亮度变化。
缺点:相对于全局阈值法,计算量较大,在大尺寸图像上处理时间会更长。
Otsu's 法:
优点:通过最大类间方差的方法自动确定最佳阈值,不需要人为设定阈值,适用于直方图具
有明显双峰分布的图像。
缺点:对于光照不均匀或直方图单峰的图像效果可能不理想,容易受到噪声干扰。
综上所述,自适应全局阈值法适用于光照不均匀或存在阴影的图像,并且能够根据局部区域
的亮度变化自适应地确定阈值。而 Otsu's 法适用于直方图具有明显双峰分布的图像,并且能
够自动确定最佳阈值。
自适应全局阈值法时间: 0.0003764 秒
Otsu's 法时间: 0.0001113 秒
因此,Otsu 法的执行速度更快。
文章来源:https://www.toymoban.com/news/detail-854416.html
到了这里,关于OpenCV数字图像处理详细教程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!