Python计算机视觉编程 第一章 基本的图像操作和处理

PIL:Python图像处理类库

PIL(Python Imaging Library Python,图像处理类库)提供了通用的图像处理功能,以及大量有用的基本图像操作,比如图像缩放、裁剪、旋转、颜色转换等。下面介绍几种使用PIL的常见操作。

转换图像格式

使用下面代码可将图片转换成JPEG格式

from PIL import Image
 import os
 for infile in filelist:
  outfile = os.path.splitext(infile)[0] + ".jpg"
  if infile != outfile:
    try:
      Image.open(infile).save(outfile)
    except IOError:
      print "cannot convert", infile

上面操作只会改变图片格式为".jpg",图片内容不会改变,如果转换失败,它会在控制台输出一条报告失败的消息。

通过下面代码,可以显示出一副图像(图片格式建议使用".jpg"格式)

from PIL import Image
import matplotlib.pyplot as plt

# 打开并转换图像为灰度模式
pil_im = Image.open('E:\PycharmProjects\BookStudying\jmu.jpg').convert('L')

# 显示图像
plt.imshow(pil_im, cmap='gray')
plt.axis('off')  # 隐藏坐标轴
plt.show()

显示效果如图
在这里插入图片描述
如果需要显示不同图像,只需更改图片路径即可。

图像裁剪操作

运行下面代码即可实现对图像裁剪操作

box = (100, 100, 400, 400)
region = pil_im.crop(box)
region.save('E:\PycharmProjects\BookStudying\jmu_crop.jpg')
region.show()

在这里,代码的第一行确定了图像裁剪的区域。该区域使用四元组来指定。四元组的坐标依次是(左,上,右,下)。运行结果如下
在这里插入图片描述

图像旋转

rotated_im = pil_im.rotate(45)  # 旋转图像45°
axs[2].imshow(rotated_im, cmap='gray')
axs[2].set_title('旋转 45°')
axs[2].axis('off')

结果如图
在这里插入图片描述

Matplotlib

Matplotlib可以绘制出高质量的图表,就像本书中的许多插图一样。Matplotlib中的PyLab接口包含很多方便用户创建图像的函数。下面介绍几种常见操作

绘制图像、点和线

使用下面代码绘制图像

from PIL import Image
from pylab import *
 # 读取图像到数组中
im = array(Image.open('E:\PycharmProjects\BookStudying\jmu.jpg'))
 # 绘制图像
imshow(im)
 # 一些点
x = [100,100,400,400]
y = [200,500,200,500]
 # 使用红色星状标记绘制点
plot(x,y,'r*')
 # 绘制连接前两个点的线
plot(x[:2],y[:2])
 # 添加标题,显示绘制的图像
title('Plotting: "empire.jpg"')
show()

结果如图
在这里插入图片描述
添加 axis(‘off’)代码可以不显示坐标,如下
在这里插入图片描述

相对于PIL来说,Matplotlib能绘制彩色图像而非灰度图像,其次,它可以表示出图像的具体x,y坐标,我们约定图像的左上角为坐标原点。

图像轮廓和直方图

绘制轮廓需要对每个坐标[x, y]的像素值施加同一个阈值,所以首先需要将图像灰度化,代码如下

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

# 读取图像
image_path = 'E:\PycharmProjects\BookStudying\jmu.jpg'  # 替换为你的图像文件路径
img = cv2.imread(image_path)
if img is None:
    print("Error: 图像未正确加载")
    exit()

# 转换成灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 应用Canny边缘检测
edges = cv2.Canny(gray, 100, 200)  # 参数可以根据需要调整

# 查找轮廓
contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# 在原图上绘制轮廓
cv2.drawContours(img, contours, -1, (0, 255, 0), 2)  # 绿色线条,宽度为2像素

# 显示带有轮廓的图像
plt.figure(figsize=(12, 6))

# 显示带有轮廓的图像
plt.subplot(1, 2, 1)
plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
plt.title('Image with Contours')
plt.axis('off')

# 显示灰度直方图
plt.subplot(1, 2, 2)
plt.hist(gray.ravel(), bins=256, range=(0, 256), color='r', alpha=0.7)
plt.title('Grayscale Histogram')
plt.xlabel('Bins')
plt.ylabel('# of Pixels')

plt.show()

运行效果如图
在这里插入图片描述

NumPy

NumPy是非常有名的Python 科学计算工具包,其中包含了大量有用的思想,比如数组对象(用来表示向量、矩阵、图像等)以及线性
代数函数。

图像数组表示

我们以上面图像为例子,使用下面代码可以输出该图像的数组表示形式

from PIL import Image
from numpy import array

im = array(Image.open('E:\PycharmProjects\BookStudying\jmu.jpg'))
print (im.shape, im.dtype)

#对图像进行灰度化处理并将数据类型转化为浮点型
im = array(Image.open('E:\PycharmProjects\BookStudying\jmu.jpg').convert('L'),'f')
print (im.shape, im.dtype)

输出结果如下:在这里插入图片描述
下面是几个有关灰度图像的例子
在这里插入图片描述
若只使用一个下标访问数组,则默认该下标为行下标;负数切片表示从最后一个元素逆向计数。

灰度变换

下面是实验代码

from PIL import Image

def grayscale_image(image_path):
    """
    将输入的彩色图像转换为灰度图像。

    :param image_path: 图像文件的路径
    :return: 灰度图像对象
    """
    # 打开图像文件
    img = Image.open("E:\PycharmProjects\BookStudying\jmu.jpg")

    # 转换为灰度图像
    gray_img = img.convert('L')

    return gray_img

# 示例用法
if __name__ == '__main__':
    image_path = 'E:\PycharmProjects\BookStudying\jmu.jpg'
    gray_image = grayscale_image(image_path)
    gray_image.show()  # 显示灰度图像
    gray_image.save('output_gray_image.jpg')  # 保存灰度图像

结果如图
在这里插入图片描述

直方图均衡化

直方图均衡化是指将一幅图像的灰度直方图变平,使变换后的图像中每个灰度值的分布概率都相同。在对图像做进一步处理之前,直方图均衡化通常是对图像灰度值进行归一化的一个非常好的方法,并且可以增强图像的对比度。
代码如下

    # 打开图像文件并转换为灰度模式
    img = Image.open(image_path).convert('L')
    
    # 将图像转换为NumPy数组
    img_array = np.array(img)
    
    # 计算图像的直方图
    hist, bins = np.histogram(img_array.flatten(), bins=256, range=(0, 256))
    
    # 绘制图像的原始直方图
    plt.hist(img_array.flatten(), bins=256, range=(0, 256), color='gray')
    plt.title('Original Histogram')
    plt.show()

    # 将均衡化后的图像转换为NumPy数组
    eq_img_array = np.array(eq_image)
    
    # 计算图像数组的直方图,bins_eq为 bin 的边缘,包括最小值和最大值
    hist_eq, bins_eq = np.histogram(eq_img_array.flatten(), bins=256, range=(0, 256))
    
    # 使用Matplotlib绘制均衡化后的图像数组的直方图
    plt.hist(eq_img_array.flatten(), bins=256, range=(0, 256), color='gray')
    
    # 设置图表标题
    plt.title('Equalized Histogram')
    
    # 显示图表
    plt.show()

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

上面图片是均衡化之前的灰度图,中间是均衡化之后的灰度图,最后是均衡化后的图像。可以看到均衡化之后图像灰度在区间分布地更加均匀。

图像平均

图像平均操作是减少图像噪声的一种简单方式,我们可以简单地从图像列表中计算出一幅平均图像。假设所有的图像具有相同的大小,我们可以将这些图像简单地相加,然后除以图像的数目,来计算平均图像。
代码如下:

from PIL import Image
from numpy import array


def compute_average(imlist):
  """ 计算图像列表的平均图像"""
#打开第一幅图像,将其存储在浮点型数组中

  averageim = array(Image.open(imlist[0]), 'f')
  for imname in imlist[1:]:
    try:
      averageim += array(Image.open(imname))
    except:
      print (imname + '...skipped')
  averageim /= len(imlist)

#返回uint8 类型的平均图像
  return array(averageim, 'uint8')

SciPy

SciPy是建立在NumPy 基础上,用于数值运算的开源工具包。SciPy 提供很多高效的操作,可以实现数值积分、优化、统计、信号处理,以及对我们来说最重要的图像处理功能。下面介绍几个重要模块:

图像模糊

下面是实验代码

import cv2
import numpy as np

#读取图像
image_path = 'E:\\PycharmProjects\\BookStudying\\jmu.jpg'  # 替换为你的图像文件路径
img = cv2.imread(image_path)
if img is None:
  print("Error: 图像未正确加载")
  exit()

#应用高斯模糊
blurred = cv2.GaussianBlur(img, (21, 21), 0)  # 高斯核大小为21x21,标准差为0

#调整图像尺寸
new_width = 400  # 设定新的宽度
new_height = int(new_width * img.shape[0] / img.shape[1])  # 计算新的高度

img_resized = cv2.resize(img, (new_width, new_height))
blurred_resized = cv2.resize(blurred, (new_width, new_height))

#水平拼接原图和模糊后的图像
combined_image = cv2.hconcat([img_resized, blurred_resized])

#显示拼接后的图像
cv2.imshow('Combined Image', combined_image)
cv2.waitKey(0)
cv2.destroyAllWindows()

结果如下:
在这里插入图片描述

图像导数

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

# 读取图像并转为灰度图
image_path = 'path_to_your_image.jpg'  # 替换为你的图像文件路径
img = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
if img is None:
    print("Error: 图像未正确加载")
    exit()

# 计算x方向和y方向的Sobel导数
sobel_x = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=5)
sobel_y = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=5)

# 计算梯度的幅度
sobel_mag = np.hypot(sobel_x, sobel_y)
sobel_mag = np.uint8(sobel_mag / np.max(sobel_mag) * 255)  # 归一化到[0,255]

# 计算梯度的方向
sobel_angle = np.arctan2(sobel_y, sobel_x)

# 使用matplotlib显示结果
plt.figure(figsize=(12, 6))

plt.subplot(1, 3, 1)
plt.imshow(img, cmap='gray')
plt.title('Original Image')
plt.axis('off')

plt.subplot(1, 3, 2)
plt.imshow(sobel_mag, cmap='gray')
plt.title('Gradient Magnitude')
plt.axis('off')

plt.subplot(1, 3, 3)
plt.imshow(sobel_angle, cmap='hsv', vmin=-np.pi/2, vmax=np.pi/2)
plt.colorbar()  # 添加颜色条显示角度值
plt.title('Gradient Direction')
plt.axis('off')

plt.tight_layout()
plt.show()

结果如图
在这里插入图片描述

形态学:对象计数

代码如下:

import cv2
import numpy as np
from skimage.measure import label, regionprops

#读取图像
image_path = 'E:\PycharmProjects\BookStudying\jmu.jpg'  # 替换为你的图像文件路径
img = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
if img is None:
    print("Error: 图像未正确加载")
    exit()

#阈值分割,将图像转换为二值图像
_, binary_img = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY_INV)

#定义结构元素
selem = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))

#开运算去除噪声
opening = cv2.morphologyEx(binary_img, cv2.MORPH_OPEN, selem)

#标记连通区域
label_image = label(opening)

#统计连通区域的数量
num_labels = label_image.max()

#显示连通区域的数量
print(f"Number of objects detected: {num_labels}")

#使用matplotlib显示处理后的图像
import matplotlib.pyplot as plt

plt.figure(figsize=(12, 6))

plt.subplot(1, 3, 1)
plt.imshow(img, cmap='gray')
plt.title('Original Image')
plt.axis('off')

plt.subplot(1, 3, 2)
plt.imshow(binary_img, cmap='gray')
plt.title('Binary Image')
plt.axis('off')

plt.subplot(1, 3, 3)
plt.imshow(label_image, cmap='jet')
plt.title('Labelled Objects')
plt.colorbar()  # 显示颜色条
plt.axis('off')

plt.tight_layout()
plt.show()

结果如下
在这里插入图片描述

高级示例:图像去噪

图像去噪是在去除图像噪声的同时,尽可能地保留图像细节和结构的处理技术。我们这里使用ROF(Rudin-Osher-Fatemi)去噪模型。图像去噪对于很多应用来说都非常重要;这些应用范围很广,小到让你的假期照片看起来更漂亮,大到提高卫星图像的质量。ROF模型具有很好的性质:使处理后的图像更平滑,同时保持图像边缘和结构信息。

以下是实验代码

from matplotlib import pyplot as plt
from PIL import Image
import numpy as np
from scipy.ndimage import gaussian_filter

def denoise(image, initial_guess, tolerance=0.1, tau=0.125, K=100):
    m, n = image.shape
    U = initial_guess
    px = image.copy()
    py = image.copy()
    error = 1

    while error > tolerance:
        U_old = U.copy()
        grad_x = np.roll(U, -1, axis=1) - U
        grad_y = np.roll(U, -1, axis=0) - U
        px_new = px + (tau / K) * grad_x
        py_new = py + (tau / K) * grad_y
        norm_new = np.maximum(1, np.sqrt(px_new**2 + py_new**2))

        px = px_new / norm_new
        py = py_new / norm_new

        rx_px = np.roll(px, 1, axis=1)
        ry_py = np.roll(py, 1, axis=0)
        div_p = (px - rx_px) + (py - ry_py)
        U = image + K * div_p
        error = np.linalg.norm(U - U_old) / np.sqrt(m * n)

    return U, image - U

#读取图像并转换为灰度图像
image_path = r'E:\PycharmProjects\BookStudying\jmu.jpg'
original_image = Image.open(image_path).convert('L')
image_array = np.array(original_image)

#去噪处理
denoised_image, _ = denoise(image_array, image_array)

#应用高斯模糊
blurred_image = gaussian_filter(image_array, sigma=10)

#可视化结果
plt.rcParams['font.sans-serif'] = ['SimHei']  # 支持中文字体

fig, axes = plt.subplots(1, 3, figsize=(18, 6))

#显示原始图像
axes[0].imshow(image_array, cmap='gray')
axes[0].set_title('原始图像')
axes[0].axis('off')

#显示经过高斯模糊后的图像
axes[1].imshow(blurred_image, cmap='gray')
axes[1].set_title('高斯模糊后')
axes[1].axis('off')

#显示去噪后的图像
axes[2].imshow(denoised_image, cmap='gray')
axes[2].set_title('去噪后')
axes[2].axis('off')

plt.tight_layout()
plt.show()

实验结果如下
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只小小程序猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值