Opencv

1. opencv图像读取与显示



# 导入 OpenCV 库
import cv2

# 1. 读取图像
# 替换为实际的图像路径,这里是当前目录下的 "bird.jpg"
image_path = "./bird.jpg"
image = cv2.imread(image_path)

# 检查图像是否成功读取
if image is None:
    print("错误:无法加载图像,请检查路径是否正确。")
    exit()

# 2. 显示图像
# 创建一个名为 "Display Image" 的窗口,并在其中显示图像
cv2.imshow("Display Image", image)

# 3. 等待用户按键
# 参数 0 表示无限等待,直到用户按下任意键
key = cv2.waitKey(0)

# 4. 根据用户按键执行操作
if key == ord('s'):  # 如果按下 's' 键
    # 保存图像
    output_path = "saved_image.jpg"
    cv2.imwrite(output_path, image)
    print(f"图像已保存为 {output_path}")
else:  # 如果按下其他键
    print("图像未保存。")

# 5. 关闭所有窗口
cv2.destroyAllWindows()

扩展练习

接下来我们可以尝试做一些代码的修改。

1、修改窗口名称:将 "Display Image" 改为其他名称,例如 "My Image"。

cv2.imshow("My Image", image)

2、保存为不同格式:将 "saved_image.jpg" 改为 "saved_image.png",观察保存结果。

# 4. 根据用户按键执行操作
if key == ord('s'):  # 如果按下 's' 键
    # 保存图像为PNG格式
    output_path = "saved_image.png"
    cv2.imwrite(output_path, image)
    print(f"图像已保存为 {output_path}")

3、添加更多交互:例如,按下 'q' 键直接退出程序。

elif key == ord('q'):  # 如果按下 'q' 键直接退出

2. opencv基本操作

常用方法如下:

2.1 图像变换

通过对图像进行变换,我们可以实现图像的旋转、缩放、平移等操作,从而达到不同的视觉效果和分析目的。在OpenCV中,图像变换操作具有灵活性和高效性,本章节将介绍一些基础的图像变换操作。

2.1.1 图像旋转

图像旋转的基本原理

旋转操作是将图像绕着其中心点旋转一定的角度。这个旋转的过程可以通过一个矩阵来表示,即旋转矩阵。对于2D图像,旋转矩阵的表达式为: 

对于图像旋转,我们通常使用 cv2.getRotationMatrix2D 函数来获取旋转矩阵。 在常规的坐标系中,逆时针旋转被认为是正方向。因此,正的旋转角度 θ 表示逆时针旋转,而负的旋转角度表示顺时针旋转。

import cv2

# 读取图像
img = cv2.imread('tulips1.jpg')

# 获取图像的高度和宽度
height, width = img.shape[:2]

# 定义旋转角度
angle = 45

# 计算旋转矩阵
rotation_matrix = cv2.getRotationMatrix2D((width/2, height/2), angle, 1)

# 进行图像旋转
rotated_img = cv2.warpAffine(img, rotation_matrix, (width, height))

# 显示旋转后的图像
cv2.imshow('Rotated Image', rotated_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

2.1.2 图像缩放

缩放是调整图像大小的基本操作,通过改变图像的宽度和高度,我们可以实现图像的缩小或放大。在图像处理中,缩放操作经常用于调整图像大小以适应不同的显示需求或分析环境。

图像缩放基本原理

插值:在缩放过程中,为了得到新的像素位置和值,需要使用插值方法。插值是一种估算未知数据点的方法,基于已知数据点的值。

缩放公式: 

import cv2
import numpy as np

# 读取图像
img = cv2.imread('tulips1.jpg')

# 定义缩放比例
scale_percent = 30

# 计算缩放后的宽度和高度
width = int(img.shape[1] * scale_percent / 100)
height = int(img.shape[0] * scale_percent / 100)

# 进行图像缩放
resized_img = cv2.resize(img, (width, height))

# 使用不同的插值方法放大图像
resized_nearest = cv2.resize(resized_img, (img.shape[1], img.shape[0]), interpolation=cv2.INTER_NEAREST)
resized_linear = cv2.resize(resized_img, (img.shape[1], img.shape[0]), interpolation=cv2.INTER_LINEAR)
resized_cubic = cv2.resize(resized_img, (img.shape[1], img.shape[0]), interpolation=cv2.INTER_CUBIC)

# 创建黑色背景图像
black_background = np.zeros((max(height, img.shape[0]), max(width, img.shape[1]), 3), dtype=np.uint8)
# 将缩放后的图像放置在黑色背景上
resized_img_bg = black_background.copy()
resized_img_bg[:resized_img.shape[0], :resized_img.shape[1], :] = resized_img

# 水平拼接原图和缩小的图像
hconcat_img = cv2.hconcat([img, resized_img_bg, black_background])

# 垂直拼接不同放大方法的图像
vconcat_img = cv2.hconcat([resized_nearest, resized_linear, resized_cubic])

# 最终水平拼接
final_result = cv2.vconcat([hconcat_img, vconcat_img])

# 显示图像
cv2.imshow('Resized Image', final_result)
cv2.waitKey(0)
cv2.destroyAllWindows()
 

2.1.3 图像平移

平移是将图像沿着x和y轴移动的操作,通过改变图像的位置,我们可以实现图像的平移。在图像处理中,平移操作常用于调整图像在画布上的位置,以便进一步的处理或显示。在OpenCV中,可以使用 cv2.warpAffine 函数实现图像的平移。

平移操作原理

平移操作的原理是通过构建一个平移矩阵,将图像中的每个像素移动到新的位置。平移矩阵的形式如下:  其中,tx是沿x轴的平移量,ty是沿y轴的平移量。通过 cv2.warpAffine 函数应用这个平移矩阵,即可完成图像的平移操作。

import cv2
import numpy as np

# 读取图像
img = cv2.imread('tulips1.jpg')

# 定义平移矩阵
translation_matrix = np.float32([[1, 0, 50], [0, 1, 30]])  # 沿x轴平移50个像素,沿y轴平移30个像素

# 进行图像平移
translated_img = cv2.warpAffine(img, translation_matrix, (img.shape[1], img.shape[0]))

# 显示平移后的图像
cv2.imshow('Translated Image', translated_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

2.1.4 图像翻转

水平翻转

import cv2

# 读取图像
img = cv2.imread('tulips1.jpg')

# 进行水平翻转
horizontal_flip = cv2.flip(img, 1)

# 显示原始图像和水平翻转后的图像
cv2.imshow('Horizontal Flip', cv2.hconcat([img, horizontal_flip]))
cv2.waitKey(0)
cv2.destroyAllWindows()

垂直翻转

import cv2

# 读取图像
img = cv2.imread('tulips1.jpg')

# 进行垂直翻转
vertical_flip = cv2.flip(img, 0)

# 显示原始图像和垂直翻转后的图像
cv2.imshow('Vertical Flip', cv2.vconcat([img, vertical_flip]))
cv2.waitKey(0)
cv2.destroyAllWindows()

2.1.5 两个图像之间的操作

# 图像加法
import cv2

# 读取两张图像
img1 = cv2.imread('tulips1.jpg')
img2 = cv2.imread('tulips2.jpg')

# 确保两张图像具有相同的尺寸
img2_resized = cv2.resize(img2, (img1.shape[1], img1.shape[0]))

# 图像加法
result = cv2.add(img1, img2_resized)

# 显示结果
cv2.imshow('Image Addition', result)
cv2.waitKey(0)
cv2.destroyAllWindows()

除了简单的图像加法,OpenCV还支持图像的加权混合。这种混合是通过为每个图像分配一个权重,然后将它们相加得到的。具体而言,对于两个图像 A 和 B,其加权混合操作可以表示为: 

# 图像加权混合
import cv2

# 读取两张图像
img1 = cv2.imread('tulips1.jpg')
img2 = cv2.imread('tulips2.jpg')

# 确保两张图像具有相同的尺寸
img2_resized = cv2.resize(img2, (img1.shape[1], img1.shape[0]))

# 设置加权混合的权重
alpha = 0.7
beta = 0.3
gamma = 0

# 图像加权混合
result = cv2.addWeighted(img1, alpha, img2_resized, beta, gamma)

# 显示结果
cv2.imshow('Image Blend', result)
cv2.waitKey(0)
cv2.destroyAllWindows()

通过调整 alpha 和 beta 的值,可以控制两张图像在混合中的权重。通常情况下,alpha + beta 应该等于 1。 gamma 用于调整亮度。

3. 图像边缘检测

图像边缘检测是计算机视觉和图像处理中的一项基本任务,它用于识别图像中亮度变化明显的区域,这些区域通常对应于物体的边界。

是 OpenCV 中常用的边缘检测函数及其说明: 

3.1 Canny边缘检测

Canny 边缘检测算法主要包括以下几个步骤:

噪声抑制:使用高斯滤波器对图像进行平滑处理,以减少噪声的影响。

计算梯度:使用 Sobel 算子计算图像的梯度幅值和方向。

非极大值抑制:沿着梯度方向,保留局部梯度最大的像素点,抑制其他像素点。

双阈值检测:使用两个阈值(低阈值和高阈值)来确定真正的边缘。高于高阈值的像素点被认为是强边缘,低于低阈值的像素点被抑制,介于两者之间的像素点如果与强边缘相连则保留。

边缘连接:通过滞后阈值处理,将弱边缘与强边缘连接起来,形成完整的边缘。

import cv2
import numpy as np

# 读取图像
image = cv2.imread('image.jpg', cv2.IMREAD_GRAYSCALE)

# 应用 Canny 边缘检测
edges = cv2.Canny(image, 100, 200)

# 显示结果
cv2.imshow('Canny Edges', edges)
cv2.waitKey(0)
cv2.destroyAllWindows()
import cv2

# 读取图像
image = cv2.imread("tulips.jpg")

# 应用Canny算子
edges_low = cv2.Canny(image, 0, 50)
edges_mid = cv2.Canny(image, 100, 150)
edges_high = cv2.Canny(image, 200, 250)

# 共享的参数
shared_params = {
    "org": (10, 30),
    "fontFace": cv2.FONT_HERSHEY_SIMPLEX,
    "fontScale": 1,
    "thickness": 2,
    "color": (0, 255, 0),
    "lineType": cv2.LINE_AA,
}
# 创建包含三个相同通道的图像
edges_low_bgr = cv2.merge([edges_low, edges_low, edges_low])
edges_mid_bgr = cv2.merge([edges_mid, edges_mid, edges_mid])
edges_high_bgr = cv2.merge([edges_high, edges_high, edges_high])
# 添加文字
original_image = cv2.putText(image.copy(), "Original Image", **shared_params)
edges_low_image = cv2.putText(edges_low_bgr, "Low Canny Edges", **shared_params)
edges_mid_image = cv2.putText(edges_mid_bgr, "Mid Canny Edges", **shared_params)
edges_high_image = cv2.putText(edges_high_bgr, "High Canny Edges", **shared_params)

# 显示原始图像和Canny算子的结果
cv2.imshow("Canny Edges",
           cv2.vconcat(
               [cv2.hconcat([original_image, edges_low_image]),
                cv2.hconcat([edges_mid_image, edges_high_image])]
           ))
cv2.waitKey(0)
cv2.destroyAllWindows()

3.2 Sobel 算子

Sobel 算子是一种基于梯度的边缘检测算子,它通过计算图像在水平和垂直方向上的梯度来检测边缘。

Sobel 算子结合了高斯平滑和微分操作,因此对噪声具有一定的抑制作用。

原理:

Sobel算子是一种基于卷积操作的边缘检测算子,常用于图像处理中。它的基本原理是通过对图像进行卷积操作,计算每个像素点的梯度,从而突出图像中的边缘信息。Sobel算子分为水平方向和垂直方向两种,分别用于检测图像中的水平边缘和垂直边缘。 

import cv2
import numpy as np

# 读取图像
image = cv2.imread('image.jpg', cv2.IMREAD_GRAYSCALE)

# 计算 x 方向的梯度
sobel_x = cv2.Sobel(image, cv2.CV_64F, 1, 0, ksize=3)

# 计算 y 方向的梯度
sobel_y = cv2.Sobel(image, cv2.CV_64F, 0, 1, ksize=3)

# 计算梯度幅值
sobel_combined = np.sqrt(sobel_x**2 + sobel_y**2)

# 显示结果
cv2.imshow('Sobel X', sobel_x)
cv2.imshow('Sobel Y', sobel_y)
cv2.imshow('Sobel Combined', sobel_combined)
cv2.waitKey(0)
cv2.destroyAllWindows()
import cv2
import numpy as np

# 读取图像
image = cv2.imread("tulips.jpg")

# 应用Sobel算子
sobel_x = cv2.Sobel(image, cv2.CV_64F, 1, 0, ksize=3)
sobel_y = cv2.Sobel(image, cv2.CV_64F, 0, 1, ksize=3)

# 计算梯度幅值和方向
gradient_magnitude = np.sqrt(sobel_x**2 + sobel_y**2)
gradient_direction = np.arctan2(sobel_y, sobel_x)

# # 分别显示原始图像和Sobel算子的结果
# cv2.imshow("Original Image", image)
# cv2.imshow("Gradient Magnitude", cv2.convertScaleAbs(gradient_magnitude))
# cv2.imshow("Gradient Direction", gradient_direction)
# cv2.imshow("Sobel X", cv2.convertScaleAbs(sobel_x))
# cv2.imshow("Sobel Y", cv2.convertScaleAbs(sobel_y))
# cv2.imshow("Sobel X+Y", cv2.convertScaleAbs(sobel_x)+cv2.convertScaleAbs(sobel_y))

# 将浮点数图像缩放到0到255的范围
normal_gradient_direction = cv2.normalize(gradient_direction, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8)

# 共享的参数
shared_params = {
    "org": (10, 30),
    "fontFace": cv2.FONT_HERSHEY_SIMPLEX,
    "fontScale": 1,
    "thickness": 2,
    "color": (0, 255, 0),
    "lineType": cv2.LINE_AA,
}
# 添加文字
original_image = cv2.putText(image.copy(), "Original Image",**shared_params)
gradient_magnitude_image = cv2.putText(cv2.convertScaleAbs(gradient_magnitude.copy()), "Gradient Magnitude", **shared_params)
gradient_direction_image = cv2.putText(normal_gradient_direction, "Gradient Direction", **shared_params)
sobel_x_image = cv2.putText(cv2.convertScaleAbs(sobel_x.copy()), "Sobel X", **shared_params)
sobel_y_image = cv2.putText(cv2.convertScaleAbs(sobel_y.copy()), "Sobel Y", **shared_params)
sobel_xy_image = cv2.putText(cv2.convertScaleAbs(sobel_x + sobel_y), "Sobel X+Y", **shared_params)

# 水平拼接
row1 = cv2.hconcat([original_image, gradient_magnitude_image, gradient_direction_image])
row2 = cv2.hconcat([sobel_x_image, sobel_y_image, sobel_xy_image])

# 垂直拼接
sobel_image = cv2.vconcat([row1, row2])

# 显示合并后的图像
cv2.imshow("Sobel Images", sobel_image)
cv2.waitKey(0)
cv2.destroyAllWindows()

常用边缘检测函数对比

作业

使用OpenCV读取一张图像,并将其缩放到原来的30%大小,读取一张图像,并将其绕中心旋转45度,将图像向右移动80个像素,向下移动160个像素,读取一张图像,并对其进行水平翻转

import cv2
import numpy as np

# 公共参数设置
image_path = "./01_cat.jpg"  


def resize_image():
    # 读取原始图像
    image = cv2.imread(image_path)
    if image is None:
        print("错误:无法加载图像")
        return
    
    # 计算新尺寸(宽高的30%)
    height, width = image.shape[:2]
    new_size = (int(width * 0.3), int(height * 0.3))
    
    # 使用INTER_AREA插值法缩小图像
    resized = cv2.resize(image, new_size, interpolation=cv2.INTER_AREA)
    
    # 显示结果对比
    cv2.imshow("Original", image)
    cv2.imshow("Resized 30%", resized)
    cv2.waitKey(0)
    cv2.destroyAllWindows()


def rotate_image():
    image = cv2.imread(image_path)
    if image is None:
        print("错误:无法加载图像")
        return
    
    # 获取图像尺寸
    (h, w) = image.shape[:2]
    
    # 计算旋转中心
    center = (w // 2, h // 2)
    
    # 构建旋转矩阵(逆时针45度)
    M = cv2.getRotationMatrix2D(center, 45, 1.0)
    
    # 执行仿射变换
    rotated = cv2.warpAffine(image, M, (w, h))
    
    # 显示结果
    cv2.imshow("Rotated 45 degrees", rotated)
    cv2.waitKey(0)
    cv2.destroyAllWindows()


def translate_image():
    image = cv2.imread(image_path)
    if image is None:
        print("错误:无法加载图像")
        return
    
    # 定义平移矩阵
    # [1, 0, tx] : tx控制水平平移(正数右移)
    # [0, 1, ty] : ty控制垂直平移(正数下移)
    M = np.float32([[1, 0, 80], [0, 1, 160]])
    
    # 执行平移操作
    translated = cv2.warpAffine(image, M, (image.shape[1], image.shape[0]))
    
    # 显示结果
    cv2.imshow("Translated Image", translated)
    cv2.waitKey(0)
    cv2.destroyAllWindows()


def flip_image():
    image = cv2.imread(image_path)
    if image is None:
        print("错误:无法加载图像")
        return
    
    # 参数1表示水平翻转
    # 参数0表示垂直翻转
    # 负数表示同时水平垂直翻转
    flipped = cv2.flip(image, 1)
    
    # 显示结果对比
    cv2.imshow("Original", image)
    cv2.imshow("Horizontally Flipped", flipped)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

# 执行所有操作(可单独调用)
if __name__ == "__main__":
    resize_image()    # 缩放演示
    rotate_image()    # 旋转演示
    translate_image() # 平移演示
    flip_image()      # 翻转演示

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值