计算机视觉OpenCv学习系列:第八部分、图像操作-4

news/2024/11/29 4:41:54/

第八部分、图像操作-4

    • 第一节、图像卷积操作
      • 1.图像卷积定义
      • 2.卷积函数
      • 3.代码练习与测试
    • 第二节、高斯模糊
      • 1.高斯模糊
      • 2.函数解释
      • 3.代码练习与测试
    • 第三节、像素重映射
      • 1.像素重映射定义
      • 2.重映射函数
      • 3.代码练习与测试
    • 学习参考

第一节、图像卷积操作

1.图像卷积定义


卷积的基本原理:

  • 输入图像
  • 输出图像
  • 卷积核(窗口大小),卷积核里的数叫卷积核系数/权重/卷积核

左图所示是原值填充边缘,中间的部分是点乘求和之后取平均值。

卷积的本质:线性组合(矩阵乘法)

所有卷积核系数都相同如下图都是1,实验证明可以抑制噪声。并且最后求平均值的方法叫做均值卷积,可以用来做图像模糊。

在这里插入图片描述

卷积定义示例:

在这里插入图片描述

2.卷积函数


最常见的边缘填充函数:

# 边缘处理,边缘填充的方式
1. cv.BORDER_DEFAULT # 边框将是边框元素的镜像gfedcb|abcdefgh|gfedcba
2. cv.BORDER_WRAP # 用另一边(对边)的像素来补偿填充 cdefgh|abcdefgh|abcdefg
3. cv.BORDER_CONSTANT # 填充边缘用指定像素值 iiiiii|abcdefgh|iiiiiii

卷积模糊函数:

cv.blur(src, ksize[, dst[, anchor[, borderType]]]) --> dst
# src表示输入图像 CV_8U, CV_32F or CV_64F
# Ksize卷积核大小
# Anchor锚定位置,默认是赋值在锚点中心位置(-1, -1)
# borderType边缘处理方式

在这里插入图片描述

3.代码练习与测试


# 图像卷积操作
def conv_demo():image = cv.imread(r"F:\python\opencv-4.x\samples\data\lena.jpg")dst = np.copy(image)cv.imshow("input", image)h, w, c = image.shape# 自定义方法实现卷积# 从上到下,从左到右,从1开始说明边缘有一个没有绑定会有缝隙,从2开始就可以边缘填满for row in range(2, h-2, 1):for col in range(2, w-2, 1):# 求均值的区域范围是(0, 4)就是0, 1, 2, 3, 4,也就是一个5*5的卷积核m = cv.mean(image[row-2:row+2, col-2:col+2])# 把卷积后的均值结果赋值给中心位置dst[row, col] = (int(m[0]), int(m[1]), int(m[2]))cv.imshow("convolution-demo", dst)# 用官方自带的卷积api函数blured = cv.blur(image, (5, 5), anchor=(-1, -1))cv.imshow("blur-demo", blured)cv.waitKey(0)cv.destroyAllWindows()

结果示例:

在这里插入图片描述

# 窗口大小不是正方形的图像卷积
def conv_demo_2():image = cv.imread(r"F:\python\opencv-4.x\samples\data\lena.jpg")cv.imshow("input", image)# 用官方自带的卷积api函数# 水平抖动blured1 = cv.blur(image, (15, 1), anchor=(-1, -1))cv.imshow("blur-demo1", blured1)# 垂直抖动blured2 = cv.blur(image, (1, 15), anchor=(-1, -1))cv.imshow("blur-demo2", blured2)cv.waitKey(0)cv.destroyAllWindows()

结果示例:

在这里插入图片描述

# 模糊操作:系数相同,均值卷积
# 窗口大小不是正方形的图像卷积
def conv_demo_2():image = cv.imread(r"F:\python\opencv-4.x\samples\data\lena.jpg")cv.imshow("input", image)# 用官方自带的卷积api函数# 模糊操作,系数相同,均值卷积blured3 = cv.blur(image, (25, 25), anchor=(-1, -1))cv.imshow("blur-demo3", blured3)cv.waitKey(0)cv.destroyAllWindows()

在这里插入图片描述

第二节、高斯模糊

1.高斯模糊


卷积核系数相同叫做均值模糊,卷积核系数不同可以做高斯模糊

左图所示是均值模糊,右图是高斯模糊,中间的是高斯函数(中间部分是最高的,离中间越远值越小)

高斯模糊下针对不同位置使用高斯公式生成的卷积核叫做**高斯核**。

在这里插入图片描述

中心对称,不同权重,线性组合

在这里插入图片描述

高斯模糊和均值模糊的差异就是,高斯模糊考虑了中心位置对权重的影响

2.函数解释


# 高斯函数
1. cv.GaussianBlur(src, ksize, sigmaX[, dst[, sigmaY[, borderType]]]) -->dst
# ksize窗口大小,必须是正数而且是奇数
# sigmaX高斯核函数X方向标准方差
# sigmaY高斯核函数Y方向标准方差,默认0(表示跟sigmaX相同)
# ksize为0表示从sigmaX计算生成ksize
# ksize大于0表示从ksize计算生成sigmaX
# 所以ksize和sigmaX设一个就行
# 计算方式:σ = 0.3*((size - 1)*0.5 - 1) + 0.8
# ksize取值越大模糊程度越高,sigmaX取值越大模糊程度越高
  • 均值模糊 – 卷积核权重系数相同
  • 高斯模糊 – 卷积核根据高斯函数生成,权重系数不同

3.代码练习与测试


# 高斯模糊
def gaussian_blur_demo():image = cv.imread(r"F:\python\opencv-4.x\samples\data\lena.jpg")cv.imshow("input", image)# 用官方自带的卷积api函数# 窗口大小ksize为0表示从sigmaX计算生成ksize# ksize窗口大小,必须是正数而且是奇数g1 = cv.GaussianBlur(image, (0, 0), 15)# ksize大于0表示从ksize计算生成sigmaX# 此时的sigmaX由计算式子σ = 0.3*((size - 1)*0.5 - 1) + 0.8 计算为:2.6# ksize窗口大小,必须是正数而且是奇数g2 = cv.GaussianBlur(image, (15, 15), 15)cv.imshow("GaussianBlur-demo1", g1)cv.imshow("GaussianBlur-demo2", g2)cv.waitKey(0)cv.destroyAllWindows()

结果示例:

由于窗口大小ksize不为0时sigmaX由计算得出,所以会出现两种模糊不一致的情况。

在这里插入图片描述

第三节、像素重映射

1.像素重映射定义


把某个位置(x, y)的像素值赋值到另一个位置。例如(50, 50) -> (100, 100)

在这里插入图片描述

2.重映射函数


1. cv.remap(src, map1, map2, interpolation[, dst[, borderMode[, borderValue]]] ) -> dst
# src表示图像
# map1表示x,y方向映射规则,或者x方向映射
# Map2如果map1表示x,y映射时为空,否则表示y
# 表示映射时候的像素插值方法 支持:INTER_NEAREST 、NTER_LINEAR 、NTER_CUBIC 

3.代码练习与测试


# 滚动条实现像素重定向
def trackbar_remap_callback(pos):print(pos)def remap_demo():cv.namedWindow("remap-demo", cv.WINDOW_AUTOSIZE)# 注意使用cv.createTrackbar滚动条之前线要定义注册响应trackbar_remap_callbackcv.createTrackbar("remap-type", "remap-demo", 0, 3, trackbar_remap_callback)image = cv.imread(r"F:\python\opencv-4.x\samples\data\lena.jpg")cv.imshow("lena", image)h, w, c = image.shape# map_x和map_y只存储映射规则的坐标map_x = np.zeros((h, w), dtype=np.float32)map_y = np.zeros((h, w), dtype=np.float32)# 完成map_x和map_y的定义while True:pos = cv.getTrackbarPos("remap-type", "remap-demo")# 倒立,x方向不变,修改y方向if pos == 0:# map_x.shape[0]对应h# 一行一行的操作xfor i in range(map_x.shape[0]):map_x[i, :] = [x for x in range(map_x.shape[1])]# map_y.shape[1]对应w# 一列一列的操作yfor j in range(map_y.shape[1]):map_y[:, j] = [map_y.shape[0] - y for y in range(map_y.shape[0])]# 镜像,x方向修改,y方向不变elif pos == 1:# map_x.shape[0]对应h# 一行一行的操作xfor i in range(map_x.shape[0]):map_x[i, :] = [map_x.shape[1] - x for x in range(map_x.shape[1])]# map_y.shape[1]对应w# 一列一列的操作yfor j in range(map_y.shape[1]):map_y[:, j] = [y for y in range(map_y.shape[0])]# 对角线对称,x方向修改,y方向也修改elif pos == 2:# map_x.shape[0]对应h# 一行一行的操作xfor i in range(map_x.shape[0]):map_x[i, :] = [map_x.shape[1] - x for x in range(map_x.shape[1])]# map_y.shape[1]对应w# 一列一列的操作yfor j in range(map_y.shape[1]):map_y[:, j] = [map_y.shape[0] - y for y in range(map_y.shape[0])]# 放大两倍,x方向修改,y方向也修改elif pos == 3:# map_x.shape[0]对应h# 一行一行的操作xfor i in range(map_x.shape[0]):map_x[i, :] = [int(x/2) for x in range(map_x.shape[1])]# map_y.shape[1]对应w# 一列一列的操作yfor j in range(map_y.shape[1]):map_y[:, j] = [int(y/2) for y in range(map_y.shape[0])]# 像素重映射remap函数dst = cv.remap(image, map_x, map_y, cv.INTER_LINEAR)cv.imshow("remap-demo", dst)# 每50ms获取一次键值,ESC键值为27c = cv.waitKey(50)if c == 27:breakcv.destroyAllWindows()

结果示例:

在这里插入图片描述

学习参考

本系列所有OpenCv相关的代码示例和内容均来自博主学习的网站:opencv_course


http://www.ppmy.cn/news/18985.html

相关文章

cmake 04 使用 python 管理 cmake 工程

本文目标 使用 python 写一个管理 cmake 工程的 cli 程序 参考 Python CLI python Click 官网 Click 中文文档 python多文件打包.exe执行文件 argparse 文档 使用说明 详细说明 思路 使用 click 制作单独的命令, 比如 mcmake_inti,mcmake_built , 每一个命令都打包为…

深入剖析JVM垃圾收集器

文章目录前言1、新生代垃圾收集器1.1、Serial1.2、ParNew1.3、Parallel Scavenge2、老年代垃圾收集器2.1、Serial Old2.2、Parallel Old2.3、CMS(Concurrent Mark Sweep)3、全堆垃圾收集器3.1、Garbage First(G1)前言 参考资料&am…

开发人员必备的 15 个备忘单

随着网络编程技术的快速发展,我们必须学习很多新东西。有些语言和框架非常复杂,您可能记不住所有的语法或方法。备忘单是易于访问的笔记。当有人在过去目睹任何有帮助或有价值的事情时,包括我自己,我们都会做笔记。但是&#xff0…

java枚举类2023028

一个类的对象是有限而且固定的,比如季节类, 它只有4个对象;再比如行星类,目前只有8个对象。这种实例有限而且固定的类,在Java里被称为枚举类。在早期代码中,可能会直接使用简单的静态常量来表示枚&#xff…

C语言之程序结构和常量

2.1.1 C语言的发展及标准 C语言:一种通用的、面向过程的计算机程序设计语言(第三代高级语言)1972年,为了移植与开发UNIX操作系统,丹尼斯里奇在贝尔电话实验室设计开发了C语言为了利于C语言的全面推广,许多…

SelectPdf for .NET 22.0 Crack

SelectPdf for .NET 是一个专业的 PDF 库,可用于创建、编写、编辑、处理和读取 PDF 文件,而无需在 .NET 应用程序中使用任何外部依赖项。使用此 .NET PDF 库,您可以实现丰富的功能,从头开始创建 PDF 文件或完全通过 C#/VB.NET 处理…

AtCoder Regular Contest 154 题解

A - Swap Digit 给2个长度均为n的十进制数&#xff0c;你可以任意次交换2个数相同位置的数字&#xff0c;要求使它们乘积最小 让其中一个数最小&#xff0c;另一个数最大。 #include<bits/stdc.h> using namespace std; #define For(i,n) for(int i1;i<n;i) #defi…

Kotlin中空安全操作符,异常处理和自定义异常,以及先决条件函数详解

博主前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住也分享一下给大家 &#x1f449;点击跳转到教程 一、Kotlin的可空性 null 在java中我们司空见惯的空指针异常NullPointerException,带给了我们很多麻烦。 Kotlin作为更强…