当前位置: 首页 > news >正文

OpenCV图像处理实战全解析:镜像、缩放、矫正、水印与降噪技术详解

目录

  • 前言
  • 一、图像镜像反转 
  • 1.1 代码
  • 二、图像缩放 
  • 2.1代码
  • 三、图像矫正 
  • 3.1仿射变换与透视变换
  • 3.2 透视变换矩阵 
  • 3.3 代码 
  • 四、图像添加水印 
  • 4.1 模板输入
  • 4.2 与运算
  • 4.3 图像融合
  • 5. 代码
  • 五、图像噪点消除
  • 5.1 噪声
  • 5.2 均值滤波
  • 5.3 方框滤波
  • 5.4 高斯滤波 
  • 5.5 中值滤波
  • 总结

前言

书接上文

OpenCV图像处理实战指南:ROI精准切割与旋转仿射变换核心技术解析-CSDN博客文章浏览阅读701次,点赞21次,收藏19次。本文系统讲解OpenCV图像处理两大核心技术——ROI区域切割与仿射变换旋转,通过坤坤篮球案例详解Numpy数组切片操作,从单点旋转推导出仿射变换矩阵的数学原理,对比分析最近邻/双线性/Lanczos等插值算法差异,演示边界反射/常数填充等边缘处理方案,配套可运行的Python代码实现旋转角度控制与效果可视化,帮助开发者掌握工业级图像预处理的关键技术。 https://blog.csdn.net/qq_58364361/article/details/146937711?fromshare=blogdetail&sharetype=blogdetail&sharerId=146937711&sharerefer=PC&sharesource=qq_58364361&sharefrom=from_link


一、图像镜像反转 

图像的镜像旋转分为三种,分别使用filpcode的参数表示:

  • flipcode=0,垂直翻转

垂直翻转可以把src沿着x轴翻转,坐标从(x,y)翻转为(x,-y)。

  • flipcode>0,水平翻转

水平翻转可以把src沿着y轴翻转,坐标从(x,y)翻转为(-x,y)。

  • flipcode<0,水平垂直翻转

相当与图像旋转,x轴和y周都翻转,坐标从(x,y)翻转为(-x,-y)。


1.1 代码

import cv2
import matplotlib.pyplot as plt

def show_image(image, name):
    """显示图像

    Args:
        image: 输入图像(numpy数组)
        name: 图像标题(str)
    """
    plt.rcParams['font.sans-serif'] = ['SimHei']  # 设置中文字体
    plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题
    if len(image.shape) == 3:  # 彩色图像
        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)  # BGR转RGB
    else:  # 灰度图像
        image = cv2.cvtColor(image, cv2.COLOR_GRAY2RGB)  # 灰度转RGB
    plt.imshow(image)  # 显示图像
    plt.title(name)  # 设置标题
    plt.axis('off')  # 关闭坐标轴


# 图像路径
path = "nvren.png"
# 读取图像
img = cv2.imread(path)
# 创建画布,设置DPI为300
plt.figure(dpi=300)
# 创建1行2列的子图,当前为第1个
plt.subplot(121)
# 显示原始图像
show_image(img, "原始图像")
# 图像翻转(-1表示水平和垂直同时翻转)
f_img = cv2.flip(img, -1)
# 切换到第2个子图
plt.subplot(122)
# 显示翻转后的图像
show_image(f_img, "翻转图像")
# 显示所有图像
plt.show()


二、图像缩放 

图像缩放相比之前图像旋转实验中,可以单独针对x轴和y轴进行独立的倍率缩放,另外插值方法节点与图像缩放实验完全相同。


2.1代码

import cv2
import matplotlib.pyplot as plt

def show_image(image, name):
    """显示图像

    Args:
        image: 输入图像(numpy数组)
        name: 图像标题(str)
    """
    plt.rcParams['font.sans-serif'] = ['SimHei']  # 设置中文字体
    plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题
    if len(image.shape) == 3:  # 彩色图像
        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)  # BGR转RGB
    else:  # 灰度图像
        image = cv2.cvtColor(image, cv2.COLOR_GRAY2RGB)  # 灰度转RGB
    plt.imshow(image)  # 显示图像
    plt.title(name)  # 设置标题
    plt.axis('off')  # 关闭坐标轴

# 图像路径
path = "nvren.png"
# 读取图像
img = cv2.imread(path)
# 创建画布,设置DPI为300
plt.figure(dpi=300)
# 创建1行2列的子图,当前为第1个
plt.subplot(121)
# 显示原始图像
show_image(img, "原始图像")
#图像缩放
s_img = cv2.resize(img, (100, 150))  # 缩放图像到100x150像素
plt.subplot(122)  # 切换到第2个子图
show_image(s_img, "缩放图像")  # 显示缩放后的图像
plt.show()  # 显示所有图像


三、图像矫正 

3.1仿射变换与透视变换

  • 仿射变换

之前在图像旋转实验中已经接触过仿射变换,仿射变换是一个二维坐标系到另一个二维坐标系的过程,在仿射变换中符合直线的平直性和平行性。

  • 透视变换

透视变换是把一个图像投影到一个新的视平面的过程。在现实世界中,观察到的物体在人类视觉中都会受到透视效果的影响:近大远小。

透视变换可以把上面人眼看到的三维空间重新投影到二维平面,且消除出现的形变和透视畸变等问题。通俗的讲,透视变换的作用是改变物体被观察的视角。

上图就是一个透视变换的例子,很明显不符合平行性,但是并不是所有的不符合平直性和平行性的变换都是透视变换,透视变换需要满足中心投影关系:

实际开发中判断是否是透视变换的方法非常简单:只要是摄像头拍摄出的画面都是符合透视变换


3.2 透视变换矩阵 

与仿射变换相同,透视变换也有对应的透视变换矩阵,在这个过程原始图像src中的点(x,y)通过透视变换被转换到到dst图像中的新坐标点(x',y')

变换过程如下

它将原始图像的齐次坐标(x,y,1)变换为目标图像齐次坐标的(X,Y,Z),可以推导出:

Z是三维坐标,但是dst是二维图像此需要把三维的Z消除(除以Z),可以得到新的表达式

a11,a12,...,a33表示一些旋转量和平移量,涉及到三维图像学的变换,因此不去详细研究,只要理解过程就行。

使用上面的透视变换矩阵需要给算法提供输入的数据,通过输入数据计算a11,a12,...,a33的值,此处提供的输入数据必须满足以下条件:

  • 在源图像src中选择四个点
  • 不能共线
  • 四个符合透视变换关系(来自于摄像头)


3.3 代码 

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

def show_image(image, name):
    """显示图像

    Args:
        image: 输入图像(numpy数组)
        name: 图像标题(str)
    """
    plt.rcParams['font.sans-serif'] = ['SimHei']  # 设置中文字体
    plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题
    if len(image.shape) == 3:  # 彩色图像
        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)  # BGR转RGB
    else:  # 灰度图像
        image = cv2.cvtColor(image, cv2.COLOR_GRAY2RGB)  # 灰度转RGB
    plt.imshow(image)  # 显示图像
    plt.title(name)  # 设置标题
    plt.axis('off')  # 关闭坐标轴
    
# 图像路径
path = "vipka.jpg"
# 读取图像
img = cv2.imread(path)
# 创建画布,设置DPI为300
plt.figure(dpi=300)
# 创建1行2列的子图,当前为第1个
plt.subplot(131)
# 显示原始图像
show_image(img, "原始图像")

# 定义透视变换的4个顶点坐标
points = [[110,60],[330,88],[72,185],[320,220]]
# 转换为浮点型numpy数组
pts = np.float32(points)

# 复制原图用于绘制ROI标记
img_fz = img.copy()
# 在图像上绘制ROI区域的四条边线
cv2.line(
        img_fz,
        pts[0].astype(np.int32).tolist(),
        pts[1].astype(np.int32).tolist(),
        (0,0,255),  # 红色
        2,  # 线宽
        cv2.LINE_AA  # 抗锯齿
        )
cv2.line(
        img_fz,
        pts[1].astype(np.int32).tolist(),
        pts[3].astype(np.int32).tolist(),
        (0,0,255),
        2,
        cv2.LINE_AA
        )
cv2.line(
        img_fz,
        pts[2].astype(np.int32).tolist(),
        pts[3].astype(np.int32).tolist(),
        (0,0,255),
        2,
        cv2.LINE_AA
        )
cv2.line(
        img_fz,
        pts[0].astype(np.int32).tolist(),
        pts[2].astype(np.int32).tolist(),
        (0,0,255),
        2,
        cv2.LINE_AA
        )
plt.subplot(132)
show_image(img_fz, "标记roi区域")

# 获取图像尺寸
img_shape = img.shape
# 定义目标透视变换的4个顶点坐标(对应图像四个角)
pts2 = np.float32([[0,0],[img_shape[1],0],[0,img_shape[0]],[img_shape[1],img_shape[0]]])

# 生成透视变换矩阵
m = cv2.getPerspectiveTransform(pts, pts2)

# 应用透视变换
dst = cv2.warpPerspective(img,
                          m,
                          (img.shape[1], img.shape[0]),  # 输出图像尺寸
                          cv2.INTER_LANCZOS4,  # 插值方法
                          cv2.BORDER_WRAP  # 边界处理方式
                          )
plt.subplot(133)
show_image(dst, "透视变换")
plt.show()  # 显示所有图像


四、图像添加水印 

4.1 模板输入

此组件的功能是输入一个水印图片需要进行灰度化二值化还需要制作掩膜

模板图建议使用包含透明图层png格式png格式支持Alpha通道(透明度),jpg不支持通道但是OpenCV默认读取图片BGR三通道因此减少pngAlpha通道结果就是黑色

建议使用透明png图片作为水印

在一些软件中会谁用灰白格表示透明区域,例如PS。


4.2 与运算

有了二值化之后的模板输入图,就可以在原始图像中根据模板大小切割出一个ROI区域,即要添加水印的区域,让二值化之后的模板与原图切割出的ROI区域进行与运算。

进行与运算,得到


4.3 图像融合

该组件的目的是将图像对应的位置像素进行叠加,需要注意的是两个像素数组的大小应该是相同的,另外还需要通道数相同。

把上面的原理图改为实际的图片,相加的结果如下所示:

5. 代码

 

import cv2

if __name__ == '__main__':
    # 1. 图片输入: 读取原始图片文件
    image_np = cv2.imread('kunkun.jpg')
    # 2. 模板输入: 读取logo模板图片文件
    logo = cv2.imread('tubiao.png')
    # 3. 灰度化: 将logo转换为灰度图像
    gray_logo = cv2.cvtColor(logo, cv2.COLOR_BGR2GRAY)
    # 4. 二值化: 使用OTSU算法自动计算阈值并进行反二值化处理
    #    参数说明:
    #    - gray_logo: 输入灰度图像
    #    - 100: 初始阈值(实际使用OTSU自动计算)
    #    - 255: 最大值
    #    - cv2.THRESH_OTSU + cv2.THRESH_BINARY_INV: 使用OTSU算法+反二值化
    ret, mask_logo = cv2.threshold(gray_logo, 100, 255, cv2.THRESH_OTSU + cv2.THRESH_BINARY_INV)
    # 5. 与运算: 在原图上提取与logo相同大小的ROI区域
    #    获取logo的尺寸(高度和宽度)
    rows, cols = logo.shape[:2]
    #    从原图中截取ROI区域(左上角开始)
    roi = image_np[:rows, :cols]
    #    使用按位与运算进行掩膜处理
    #    参数说明:
    #    - roi: 输入图像1
    #    - roi: 输入图像2
    #    - mask_logo: 掩膜图像
    image_np_bg = cv2.bitwise_and(
            roi,
            roi,
            mask=mask_logo
            )
    # 6. 图像融合: 将处理后的背景与原始logo进行叠加
    dst = cv2.add(image_np_bg, logo)
    #    将融合结果放回原图对应位置
    image_np[:rows, :cols] = dst
    # 7. 图片输出: 显示最终结果图像
    cv2.imshow('image_np', image_np)
    cv2.waitKey(0)


五、图像噪点消除

5.1 噪声

噪声指的是图像中的一些干扰因素,通常由于图像的采集设备或传输过程中导致的,表现为图像中部分像素点出现随机亮度,也可以理解为一些像素点与周围的像素点格格不入。

常见的噪声分为两类:

  • 高斯噪声

是一种符合正态分布的噪声,会使图像变得有明暗不均的噪点,如果是彩图可能还会出现颜色的分布不均。

  • 椒盐噪声

是一些黑色像素值分布在原图像中,可以把椒盐噪声理解为斑点,随机出现在画面中。

滤波器:实际上就是之前的卷积核,与自适应二值化中的核一样,本身是一个小区域,有这特定的核值,并且工作原理也实在原图上从左向右、从上到下进行滑动计算。

滤波器可以分为两类:

  • 线性滤波

对卷积核中的邻域像素进行线性计算,例如计算求和等,常见的线性滤波器有均值滤波、高斯滤波等。

  • 非线性滤波

利用原始图像与模板之间的一种逻辑关系得到结果,常见的非线性滤波器有中值滤波、双边滤波等。


5.2 均值滤波

均值滤波是一种最简单的滤波器,它直接计算卷积核区域内元素的平均值,例如3x3的卷积核:

一张高斯噪声图: 

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

if __name__ == '__main__':
    # 1. 读取图像
    path = "gaosi.jpg"  # 图像文件路径
    img = cv2.imread(path)  # 使用OpenCV读取图像文件
    cv2.imshow("img", img)  # 显示原始图像窗口

    # 均值滤波
    # 使用3x3的核进行均值滤波处理
    # 参数说明:
    #   img: 输入图像
    #   (3,3): 滤波核大小
    lb_img = cv2.blur(img, (3, 3))  # 对图像进行均值滤波处理
    cv2.imshow("lb_img", lb_img)  # 显示滤波后的图像窗口
    cv2.waitKey(0)  # 等待按键输入


5.3 方框滤波

方框滤波与均值滤波非常像,如3x3的滤波核如下:

参数均值滤波有相同不同讲解不同的(后文同),新参数

  • ddepth 输出图像的深度

-1表示使用原图的深度,即每个像素点占用的位数,最常用的位数是cv2.CV_8U,即8位无符号整数:0-255

  • normalize 控制a的数值

当此参数为True时,方框滤波就是均值滤波;

当此参数为False时,a=1,相当于在区域内求像素和。

import cv2

if __name__ == '__main__':
    # 1. 读取图像
    path = "gaosi.jpg"  # 图像文件路径
    img = cv2.imread(path)  # 使用OpenCV读取图像文件
    cv2.imshow("img", img)  # 显示原始图像窗口

    # 使用boxFilter进行方框滤波
    # 参数说明:
    #   img: 输入图像
    #   -1: 输出图像深度(-1表示与输入相同)
    #   (3,3): 滤波核大小
    #   normalize=False: 不进行归一化(若为True则执行均值滤波)
    lb_img = cv2.boxFilter(
            img,
            -1,
            (3, 3),
            normalize=False,
            )
    cv2.imshow("lb_img", lb_img)  # 显示滤波后的图像窗口
    cv2.waitKey(0)  # 等待按键输入(0表示无限等待)


5.4 高斯滤波 

高斯滤波的核权重计算与自适应二值化的《高斯加权求和》过程完全相同。

当时以3x3为例,计算出核为:

可以看到多了一个SigmaX参数,对应的是高斯函数里σ的值,对应的效果就是中心区域的权重是否更大:SigmaX越大,中心像素的权重越低。

import cv2

if __name__ == '__main__':
    # 1. 读取图像
    path = "gaosi.jpg"  # 图像文件路径
    img = cv2.imread(path)  # 使用OpenCV读取图像文件
    # cv2.imshow: 显示图像窗口
    # 参数1: 窗口名称字符串
    # 参数2: 要显示的图像矩阵
    cv2.imshow("img", img)  # 显示原始图像窗口

    # cv2.GaussianBlur: 高斯滤波
    # 参数1: 输入图像
    # 参数2: 高斯核大小(宽度,高度),必须是正奇数
    # 参数3: 标准差,控制模糊程度
    lb_img = cv2.GaussianBlur(img, (3, 3), 1)
    cv2.imshow("lb_img", lb_img)  # 显示滤波后的图像窗口

    # cv2.waitKey: 等待键盘输入
    # 参数: 延迟毫秒数(0表示无限等待)
    # 返回值: 按键的ASCII码值
    cv2.waitKey(0)  # 等待按键输入(0表示无限等待)


5.5 中值滤波

中值就是中位数,是核中对应的像素排序后的中间值,因此核本身没有数值,也不需要新增的参数。需要注意的是,默认的边界填充算法是边界复制。

import cv2

if __name__ == '__main__':
    # 1. 读取图像
    path = "gaosi.jpg"  # 图像文件路径
    img = cv2.imread(path)  # 使用OpenCV读取图像文件
    """
    显示图像窗口
    @param winname: 窗口名称字符串
    @param mat: 要显示的图像矩阵
    """
    cv2.imshow("img", img)  # 显示原始图像窗口

    """
    中值滤波处理图像
    @param src: 输入图像矩阵
    @param ksize: 滤波器大小(必须为奇数)
    @return: 滤波后的图像矩阵
    """
    lb_img = cv2.medianBlur(img, 5)  # 中值滤波
    cv2.imshow("lb_img", lb_img)  # 显示滤波后的图像窗口

    """
    等待键盘输入
    @param delay: 延迟时间(毫秒),0表示无限等待
    @return: 按键的ASCII码值
    """
    cv2.waitKey(0)  # 等待按键输入(0表示无限等待)

中值滤波特别擅长去除椒盐噪声如下所示


总结

        本文全面探讨了OpenCV在图像处理中的五大核心技术:镜像反转通过flip函数实现垂直、水平及双轴翻转,揭示了坐标变换原理;缩放技术通过resize函数灵活调整图像尺寸,保留关键信息;图像矫正利用透视变换矩阵消除透视畸变,强调四点定位与坐标映射关系;水印添加结合二值化模板与像素运算实现精准融合,突显ROI区域处理逻辑;噪声消除部分对比均值滤波、高斯滤波、中值滤波的算法差异,解析线性与非线性滤波对高斯噪声、椒盐噪声的针对性解决方案。全文通过代码实例演示各技术实现路径,完整呈现从理论到实践的图像处理闭环。

 

 

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.dtcms.com/a/114452.html

相关文章:

  • 算法设计学习10
  • React编程高级主题:错误处理(Error Handling)
  • ts基础知识总结
  • Java后端开发流程
  • [ctfshow web入门]burpsuite的下载与使用
  • 每日c/c++题 备战蓝桥杯(小球反弹)[运动分解求解,最大公约数gcd]
  • Java进阶之旅-day05:网络编程
  • 1-SQL server 2022和SSMS的使用案例1
  • 从零构建大语言模型全栈开发指南:附录与资源-2.数据集大全-公开语料库、多模态数据集与领域专用数据源
  • 构建第一个ArkTS应用:Hello World之旅
  • 【百日精通JAVA | SQL篇 | 第三篇】 MYSQL增删改查
  • scala课后总结(5)
  • matlab 计算点云的形心
  • Flask学习笔记 - 项目结构 + 路由
  • C++11观察者模式示例
  • C语言单链表的增删改补
  • 从制造业历史来看,汽车兴,则制造业兴,则国兴,则机器视觉兴
  • 云原生与微服务的关系
  • Git 换行符警告(LF replaced by CRLF)的解决方案
  • 【无人机】PX4 飞控系统架构
  • 【Scratch编程系列】Scratch编程软件界面
  • b4a安卓开发技术和建议,VB6开发Android APK
  • AT_abc212_d [ABC212D] Querying Multiset
  • 搭建健康基石,畅享活力人生
  • 大模型 MCP:开启 AI 与现实世界的无缝交互革命
  • CSS语言的学习路线
  • Android DiaLog全屏设置,带有叉号的弹窗,这个弹窗分为两个部分,一个是主体,另一个是关闭部分。自定义布局弹窗
  • BN 层的作用, 为什么有这个作用?
  • 常见的HR面问题汇总
  • 知识图谱:知识图谱多模态推理技术详解