分享缩略图

分享到:
链接已复制
首页> 新闻中心>

OpenCV的入门实验

2025-06-24 12:18:34

来源:新华网

字体:

写在前面:

这是我第一次进行python环境下的人工智能项目,采用OpenCV结合一些基础函数进行一些基础的图像处理。整个过程中我给了代码丰富的注释,希望能帮助到这方面,尤其是代码方面的初学者,我认为阅读注释和思考代码并产出自己的一些代码有助于任何一种编程语言的学习。

此外,我认为这项实验中比较有趣的并且我尝试解决的点是中文路径的读取和同一变化效果的不同实现,如果有需要的小伙伴和学习者可以尝试我的实验报告中提到的方式。

共勉!

一、实验目的及要求

1.实验目的

巩固图像处理基础;

了解OpenCV中用于图像处理的部分函数及其用法;

了解Python语法。

2.实验要求

使用OpenCV实现对一张图片的读取,并且在命令行窗口中输出其尺寸和数据类型;

使用for循环的方式,一次性读取指定路径下的多张图片,之后输出所有图片的平均像素值和像素值标准差;

理解二维图像自然缩放的原理,并且将一副未知大小的图像缩放到指定大小(区别于比例尺放缩);

分析给出的示例图像变换,选择合适的方式复现该变换。

二、实验方法步骤

1.图片读取与基本信息获取

解OpenCV中用于读取图像的函数(imread, imdecode等);

基于调试选择imdecode以解决中文路径对读取进程的影响,并且配套调整图像读取方式;

获取图像基本信息(shape, dtype等)。

2.多张图片的读取与信息获取、处理

·吸取第一次实验的教训,选择的目标文件夹路径为全英文;

·for循环的设计,基于不同文件名对文件夹内容进行遍历;

·遍历过程中使用链表存储像素值,遍历结束后将链表通过numpy中的函数实现转化为数组,并进行后续计算。

3.二维自然图像的放缩

·了解放缩函数resize的用法,包括了“放缩到指定尺寸”和“放缩到指定比例”两种放缩方式;

·resize函数不涉及图像通道数的改变,可以尝试其他放缩方式,观察其对图像通道数的影响。

4.示例图像变换的分析与复现

·分析图像变换,初步认为包括以下步骤:切分、部分变换、重组;

·理解和运用图像的切分,即将原图像的矩阵进行提取;

·部分变换的方式,认为可以通过中心对称或者直接旋转180°来实现;

·图像的重组,可以理解为矩阵的堆叠,了解vstack和hstack两中国堆叠函数的使用

三、实验代码

1.图片读取与基本信息获取

1)单独实现版本

import cv2import numpy as np# 使用cv2.imread()函数读取图片,图片路径根据你的实际路径来填写# 确保图片路径正确,否则img变量将会是None# 由于这里我的图片路径包含中文,所以不能直接使用imread读取# 使用 cv2.imdecode() 和 numpy 可以解决问题,这通常是因为你通过 numpy.fromfile() 读取了文件的原始字节数据# 并且这个过程中可能间接地处理了文件路径的编码问题# 但更可能的原因是,当你使用 numpy.fromfile() 读取文件时,你实际上绕过了任何可能由 cv2.imread() 触发的路径解析或文件系统调用问题。# 然而,这并不是 cv2.imdecode() 的功劳,而是因为你将文件内容作为字节流读取到内存中,并随后使用 cv2.imdecode() 来解码这些字节。# 但是,请注意,numpy.fromfile() 并不适合直接用于读取图片文件,因为它只是简单地按字节读取文件,而不会考虑图片文件的格式或结构。# 因此,你应该确保在调用 cv2.imdecode() 之前,文件内容确实是有效的图片数据,并且是以适当的格式存储的。imgPATH ="D:\\file\\College\\大三\\第一学期\\人工智能理论与实践\\作业\\Week1\\作业要求与素材\\作业素材\\WhiteDog.jpg"img = cv2.imdecode(np.fromfile(imgPATH, dtype=np.uint8), cv2.IMREAD_COLOR)# 检查图片是否成功读取if img is not None:    # 展示图片    cv2.imshow('Image', img)    # 输出图片尺寸    print("图片尺寸:", img.shape)  # shape将返回一个元组:(高度, 宽度, 通道数)    # 输出数据类型    print("数据类型:", img.dtype)  # 这将显示numpy.uint8或其他数据类型    # 指定目标尺寸(宽度和高度)    target_width = 512    target_height = 512    # 使用cv2.resize函数进行缩放,直接指定目标尺寸    resized_img = cv2.resize(img, (target_width, target_height), interpolation=cv2.INTER_LINEAR)    # 显示或保存缩放后的图像    cv2.imshow('Resized Image', resized_img)    # 等待任意键盘按键被按下    cv2.waitKey(0)    # 销毁所有OpenCV创建的窗口    cv2.destroyAllWindows()else:    print("Error: Image could not be read.")

2)函数封装版本

import cv2import numpy as np# 原定使用使用cv2.imread()函数读取图片,图片路径根据实际路径来填# 由于这里我的图片路径包含中文,所以不能直接使用imread读取# 使用 cv2.imdecode() 和 numpy 可以解决问题,这是因为可以通过 numpy.fromfile() 读取了文件的原始字节数据# 使用 numpy.fromfile() 读取文件时,你实际上绕过了任何可能由 cv2.imread() 触发的路径解析或文件系统调用问题。# 我将文件内容作为字节流读取到内存中,并随后使用 cv2.imdecode() 来解码这些字节。# 不过numpy.fromfile() 实际上并不适合直接用于读取图片文件,因为它只是简单地按字节读取文件,而不会考虑图片文件的格式或结构。# 所以在调用 cv2.imdecode() 之前,需要确认文件内容确实是有效的图片数据,并且是以适当的格式存储的。def SIR(img_path):    # 使用cv2.imdecode()加载图像    # imread是从文件(磁盘)中直接读取图像数据,imdecode是从内存缓冲区中读取数据,并解码成图像格式。    # 使用imdecode的优点在于可以从内存中直接解码图像数据,而不需要将数据保存到磁盘再进行读取。    # 在某些场景中是有用的,如网络传输的数据源,摄像头捕获的图像数据。    # imdecode与image的使用有一点要注意:    # imread是传入图片路径,转为图片格式;imdecode传入的内存数据(数组形式),转为图片    # 另外,需要考虑imdecode传入的内存数据可能需要释放掉    img = cv2.imdecode(np.fromfile(img_path, dtype=np.uint8), cv2.IMREAD_COLOR)    # np.fromfile部分代码使用NumPy的fromfile函数从指定的文件路径(img_path)读取数据。    # dtype = np.uint8指定了读取的数据类型是无符号8位整型(即每个数据点占用1个字节),这是图像数据(尤其是灰度图和彩色图的单通道)常用的数据类型。    # np.fromfile函数会将文件内容作为一维数组返回,数组中的每个元素都是文件中相应位置的字节值。    # cv2.imdecode(..., cv2.IMREAD_COLOR):    # 这部分代码使用OpenCV的imdecode函数来解码前面通过np.fromfile读取的原始图像数据。    # imdecode函数的第一个参数是一个字节对象或NumPy数组,这里传入的是np.fromfile返回的NumPy数组。    # 第二个参数是解码标志,这里使用的是cv2.IMREAD_COLOR,它告诉imdecode函数以彩色模式(即BGR格式)来解码图像。    # 如果图像实际上是灰度图,应该使用cv2.IMREAD_GRAYSCALE作为解码标志。    # imdecode函数返回解码后的图像,它是一个三维的NumPy数组,形状为(高度, 宽度, 通道数),其中通道数对于彩色图是3(BGR)。    # 检查图像是否有效    if img is not None and img.shape[0] > 0 and img.shape[1] > 0: # image.shape[]中的0和1表示该numpy数组中的第一个和第二个元素        # 输出图片尺寸        print("获取到的图片尺寸:", img.shape)  # shape将返回一个元组:(高度, 宽度, 通道数)        # 输出数据类型        print("获取到的图片所属数据类型:", img.dtype)  # 这将显示numpy.uint8或其他数据类型        return img    else:        print("Error: Image could not be read or is invalid.")        return None# 测试用调用函数# imgPATH = "D:\\file\\College\\大三\\第一学期\\人工智能理论与实践\\作业\\Week1\\作业要求与素材\\作业素材\\WhiteDog.jpg"# img = SIR(imgPATH)# # 展示图片# cv2.imshow('Image', img)# # 等待任意键盘按键被按下# cv2.waitKey(0)# # 销毁所有OpenCV创建的窗口# cv2.destroyAllWindows()

2.多张图片的读取与信息获取、处理

import osimport cv2import numpy as npdef calculate_image_stats(folder_path):    # 初始化一个列表来存储所有图片的像素值    all_pixels = []    # 遍历文件夹中的所有文件    for filename in os.listdir(folder_path):        # 构造完整的文件路径,使用join函数将文件名和文件夹地址连接起来        file_path = os.path.join(folder_path, filename)        # 检查文件是否是图片        if filename.endswith(('.png', '.jpg', '.jpeg')):            # 使用cv2读取图片            img = cv2.imread(file_path)            # 检查图片是否成功读取            if img is not None:                # 将图片数据转换为float32类型,方便后续计算                img_float = np.float32(img)                # 扁平化图片数组以获取所有像素值                flat_img = img_float.flatten()                # 将这些像素值添加到列表中                all_pixels.append(flat_img)            else:                print(f"Warning: Unable to read { file_path}")                # 检查是否至少有一张图片被读取    if not all_pixels:        print("没有读取到任何图片。")        return None, None  # 或者你可以抛出一个异常    # 将所有图片的像素值合并为一个大的numpy数组    all_pixels_combined = np.concatenate(all_pixels)    # 这行代码的意图是将all_pixels中的所有数组沿着某个轴连接起来,形成一个更大的数组all_pixels_combined。    # 关于轴的指定:在代码中,没有显式指定axis参数,因此np.concatenate将默认沿着第一个轴(axis=0)连接数组。    # 计算平均像素值    mean_pixel = np.mean(all_pixels_combined)    # 计算像素值的标准差    std_pixel = np.std(all_pixels_combined)    return mean_pixel, std_pixel# 使用函数folder_path = 'C:\\Users\\Wu\\Desktop\\TEMP\\material'mean_pixel, std_pixel = calculate_image_stats(folder_path)if mean_pixel is not None:    print(f"所有图片的平均像素值为: { mean_pixel}")    print(f"所有图片的像素值标准差为: { std_pixel}")

3.二维自然图像的放缩

单独实现版本

import cv2import numpy as np# 使用cv2.imread()函数读取图片,图片路径根据你的实际路径来填写# 确保图片路径正确,否则img变量将会是None# 由于这里我的图片路径包含中文,所以不能直接使用imread读取# 使用 cv2.imdecode() 和 numpy 可以解决问题,这通常是因为你通过 numpy.fromfile() 读取了文件的原始字节数据# 并且这个过程中可能间接地处理了文件路径的编码问题# 但更可能的原因是,当你使用 numpy.fromfile() 读取文件时,你实际上绕过了任何可能由 cv2.imread() 触发的路径解析或文件系统调用问题。# 然而,这并不是 cv2.imdecode() 的功劳,而是因为你将文件内容作为字节流读取到内存中,并随后使用 cv2.imdecode() 来解码这些字节。# 但是,请注意,numpy.fromfile() 并不适合直接用于读取图片文件,因为它只是简单地按字节读取文件,而不会考虑图片文件的格式或结构。# 因此,你应该确保在调用 cv2.imdecode() 之前,文件内容确实是有效的图片数据,并且是以适当的格式存储的。imgPATH ="D:\\file\\College\\大三\\第一学期\\人工智能理论与实践\\作业\\Week1\\作业要求与素材\\作业素材\\WhiteDog.jpg"img = cv2.imdecode(np.fromfile(imgPATH, dtype=np.uint8), cv2.IMREAD_COLOR)# 检查图片是否成功读取if img is not None:    # 指定目标尺寸(宽度和高度)    target_width = 512    target_height = 512    # 使用cv2.resize函数进行缩放,直接指定目标尺寸    resized_img = cv2.resize(img, (target_width, target_height), interpolation=cv2.INTER_LINEAR)    # 显示或保存缩放后的图像    cv2.imshow('Resized Image', resized_img)    # 等待任意键盘按键被按下    cv2.waitKey(0)    # 销毁所有OpenCV创建的窗口    cv2.destroyAllWindows()else:    print("Error: Image could not be read.")

函数封装版本

import cv2import numpy as np# 在另一个文件中from Single_ImgRead import SIRdef process_image_scaling(img):    # 对图像进行处理    # 指定目标尺寸(宽度和高度)    target_width = 512    target_height = 512    # 使用cv2.resize函数进行缩放,直接指定目标尺寸    resized_img = cv2.resize(img, (target_width, target_height), interpolation=cv2.INTER_LINEAR)    # interpolation:插值方法,决定了缩放过程中像素值的计算方法。    # cv2.INTER_LINEAR是常用的插值方法之一,它提供了较好的缩放效果和速度平衡。    # interpolation=cv2.INTER_LINEAR:这个参数指定了缩放时使用的插值算法为双线性插值。    # 双线性插值是一种在二维空间中进行的线性插值,它可以平滑地改变图像的大小,同时保持较好的图像质量    return resized_img# # 测试用调用函数# img_path = "D:\\file\\College\\大三\\第一学期\\人工智能理论与实践\\作业\\Week1\\作业要求与素材\\作业素材\\WhiteDog.jpg"# img = SIR(img_path)# if img is not None:#     # 显示初始图片#     cv2.imshow('Image', img)#     processed_img = process_image_scaling(img)#     # 显示或保存 processed_img#     cv2.imshow('Processed Image', processed_img)#     cv2.waitKey(0)#     cv2.destroyAllWindows()

4.示例图像变换的分析与复现

变换分析:中心对称版本

import cv2import numpy as np# 使用cv2.imread()函数读取图片,图片路径根据你的实际路径来填写# 确保图片路径正确,否则img变量将会是None# 由于这里我的图片路径包含中文,所以不能直接使用imread读取# 使用 cv2.imdecode() 和 numpy 可以解决问题,这通常是因为你通过 numpy.fromfile() 读取了文件的原始字节数据# 并且这个过程中可能间接地处理了文件路径的编码问题# 但更可能的原因是,当你使用 numpy.fromfile() 读取文件时,你实际上绕过了任何可能由 cv2.imread() 触发的路径解析或文件系统调用问题。# 然而,这并不是 cv2.imdecode() 的功劳,而是因为你将文件内容作为字节流读取到内存中,并随后使用 cv2.imdecode() 来解码这些字节。# 但是,请注意,numpy.fromfile() 并不适合直接用于读取图片文件,因为它只是简单地按字节读取文件,而不会考虑图片文件的格式或结构。# 因此,你应该确保在调用 cv2.imdecode() 之前,文件内容确实是有效的图片数据,并且是以适当的格式存储的。imgPATH ="D:\\file\\College\\大三\\第一学期\\人工智能理论与实践\\作业\\Week1\\作业要求与素材\\作业素材\\WhiteDog.jpg"img = cv2.imdecode(np.fromfile(imgPATH, dtype=np.uint8), cv2.IMREAD_COLOR)# 检查图片是否成功读取if img is not None:    # 展示图片    cv2.imshow('Image', img)    # 输出图片尺寸    print("图片尺寸:", img.shape)  # shape将返回一个元组:(高度, 宽度, 通道数)    # 输出数据类型    print("数据类型:", img.dtype)  # 这将显示numpy.uint8或其他数据类型    # 指定目标尺寸(宽度和高度)    target_width = 512    target_height = 512    # 使用cv2.resize函数进行缩放,直接指定目标尺寸    resized_img = cv2.resize(img, (target_width, target_height), interpolation=cv2.INTER_LINEAR)else:    print("Error: Image could not be read.")def center_symmetric_quarters(image_path):    # 加载图像    Useimg = resized_img    if Useimg is None:        raise FileNotFoundError("图像文件未找到")        # 获取图像尺寸    h, w = Useimg.shape[:2]    # 找到图像中心    center_x, center_y = w // 2, h // 2    # 分割图像为四部分    quarter_size = (w // 2, h // 2)    q1 = Useimg[:center_y, :center_x]    q2 = Useimg[:center_y, center_x:]    q3 = Useimg[center_y:, :center_x]    q4 = Useimg[center_y:, center_x:]    # 对每部分进行中心对称    def center_symmetric(quarter):        # 找到该部分的中心        q_h, q_w = quarter.shape[:2]        q_center_x, q_center_y = q_w // 2, q_h // 2        # 创建一个相同大小的空白图像用于存储结果        result = np.zeros_like(quarter)        # 对每个像素进行中心对称操作        for i in range(q_h):            for j in range(q_w):                # 计算对称点                sym_x, sym_y = q_center_x + (q_center_x - j), q_center_y + (q_center_y - i)                # 边界检查并赋值                if 0 <= sym_x < q_w and 0 <= sym_y < q_h:                    result[i, j] = quarter[sym_y, sym_x]        return result        # 应用中心对称    q1_sym = center_symmetric(q1)    q2_sym = center_symmetric(q2)    q3_sym = center_symmetric(q3)    q4_sym = center_symmetric(q4)    # 重新组合图像    result_img = np.vstack((np.hstack((q1_sym, q2_sym)), np.hstack((q3_sym, q4_sym))))    # 显示或保存结果    cv2.imshow('Result Image', result_img)    cv2.waitKey(0)    cv2.destroyAllWindows()# 使用函数center_symmetric_quarters('path_to_your_image.jpg')

变换分析:旋转180°版本

import cv2import numpy as np# 使用cv2.imread()函数读取图片,图片路径根据你的实际路径来填写# 确保图片路径正确,否则img变量将会是None# 由于这里我的图片路径包含中文,所以不能直接使用imread读取# 使用 cv2.imdecode() 和 numpy 可以解决问题,这通常是因为你通过 numpy.fromfile() 读取了文件的原始字节数据# 并且这个过程中可能间接地处理了文件路径的编码问题# 但更可能的原因是,当你使用 numpy.fromfile() 读取文件时,你实际上绕过了任何可能由 cv2.imread() 触发的路径解析或文件系统调用问题。# 然而,这并不是 cv2.imdecode() 的功劳,而是因为你将文件内容作为字节流读取到内存中,并随后使用 cv2.imdecode() 来解码这些字节。# 但是,请注意,numpy.fromfile() 并不适合直接用于读取图片文件,因为它只是简单地按字节读取文件,而不会考虑图片文件的格式或结构。# 因此,你应该确保在调用 cv2.imdecode() 之前,文件内容确实是有效的图片数据,并且是以适当的格式存储的。imgPATH ="D:\\file\\College\\大三\\第一学期\\人工智能理论与实践\\作业\\Week1\\作业要求与素材\\作业素材\\WhiteDog.jpg"img = cv2.imdecode(np.fromfile(imgPATH, dtype=np.uint8), cv2.IMREAD_COLOR)# 检查图片是否成功读取if img is not None:    # 展示图片    cv2.imshow('Image', img)    # 输出图片尺寸    print("图片尺寸:", img.shape)  # shape将返回一个元组:(高度, 宽度, 通道数)    # 输出数据类型    print("数据类型:", img.dtype)  # 这将显示numpy.uint8或其他数据类型    # 指定目标尺寸(宽度和高度)    target_width = 512    target_height = 512    # 使用cv2.resize函数进行缩放,直接指定目标尺寸    resized_img = cv2.resize(img, (target_width, target_height), interpolation=cv2.INTER_LINEAR)else:    print("Error: Image could not be read.")def center_symmetric_quarters(image_path):    # 加载图像    Useimg = resized_img    if Useimg is None:        raise FileNotFoundError("图像文件未找到")        # 获取图像尺寸    h, w = Useimg.shape[:2]    # 找到图像中心    center_x, center_y = w // 2, h // 2    # 分割图像为四部分    quarter_size = (w // 2, h // 2)    q1 = Useimg[:center_y, :center_x]    q2 = Useimg[:center_y, center_x:]    q3 = Useimg[center_y:, :center_x]    q4 = Useimg[center_y:, center_x:]    q1_sym = cv2.flip(q1, 0)  # 水平翻转    q1_sym = cv2.flip(q1_sym, 1)  # 垂直翻转    q2_sym = cv2.flip(q2, 1)  # 垂直翻转    q2_sym = cv2.flip(q2_sym, 0)  # 水平翻转    q3_sym = cv2.flip(q3, 0)  # 水平翻转    q3_sym = cv2.flip(q3_sym, 1)  # 垂直翻转    q4_sym = cv2.flip(q4, 1)  # 垂直翻转    q4_sym = cv2.flip(q4_sym, 0)  # 水平翻转    # 重新组合图像    result_img = np.vstack((np.hstack((q1_sym, q2_sym)), np.hstack((q3_sym, q4_sym))))    # 显示或保存结果    cv2.imshow('Result Image', result_img)    cv2.waitKey(0)    cv2.destroyAllWindows()# 使用函数center_symmetric_quarters('path_to_your_image.jpg')

封装集成版本(采用旋转180°方案)

import cv2import numpy as npfrom Single_ImgRead import SIRfrom Single_ImgScaling import process_image_scalingdef process_image_partiton(img):    # 加载图像    useimg = img    if useimg is None:        raise FileNotFoundError("图像文件未找到")        # 获取图像尺寸    h, w = useimg.shape[:2] # [:2]是切片操作,表示只取前两个变量,也就是长和宽    # 找到图像中心    center_x, center_y = w // 2, h // 2 # //表示整数除法    # 分割图像为四部分    quarter_size = (w // 2, h // 2)    q1 = useimg[:center_y, :center_x]    q2 = useimg[:center_y, center_x:]    q3 = useimg[center_y:, :center_x]    q4 = useimg[center_y:, center_x:]    # 其中:的意义是表示索引的取值范围。比如:center_y就表示[0,center_y)的范围    q1_sym = cv2.flip(q1, 0)  # 水平翻转    q1_sym = cv2.flip(q1_sym, 1)  # 垂直翻转    q2_sym = cv2.flip(q2, 1)  # 垂直翻转    q2_sym = cv2.flip(q2_sym, 0)  # 水平翻转    q3_sym = cv2.flip(q3, 0)  # 水平翻转    q3_sym = cv2.flip(q3_sym, 1)  # 垂直翻转    q4_sym = cv2.flip(q4, 1)  # 垂直翻转    q4_sym = cv2.flip(q4_sym, 0)  # 水平翻转    # 重新组合图像    result_img = np.vstack((np.hstack((q1_sym, q2_sym)), np.hstack((q3_sym, q4_sym))))    # hstack用于水平堆叠;vstack由于竖直堆叠,也就是说上面的代码还有一种写法    # result_img = np.hstack((np.vstack((q1_sym, q3_sym)), np.vstack((q2_sym, q4_sym))))    # 先竖直再水平也可以是一种堆叠方法    return  result_img# 调用函数img_path = "D:\\file\\College\\大三\\第一学期\\人工智能理论与实践\\作业\\Week1\\作业要求与素材\\作业素材\\WhiteDog.jpg"img = SIR(img_path)if img is not None:    # 显示初始图片    cv2.imshow('Image', img)    Scaled_img = process_image_scaling(img)    # 显示放缩图片    cv2.imshow('Scaled Image', Scaled_img)    Parted_img = process_image_partiton(Scaled_img)    # 显示分部处理图片    cv2.imshow('Parted Image', Parted_img)    cv2.waitKey(0)    cv2.destroyAllWindows()else:    print("Error: Unable to process image.")

四、实验结果

实验结果包含最终集成版本输出结果以及中心对称变换方案(未成功)结果。

单张图像的读取和信息获取

多张图片的获取与信息获取

单张图片的二维自然变换

单张图片的变换(中心对称版本)

单张图片的变换(旋转180°版本)

【责任编辑:新华网】
返回顶部