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

图像认知与OpenCV——图像预处理2

目录

一、仿射变换

图像旋转

 图像平移

图像缩放

二、插值方法

最近邻插值

双线性插值

像素区域插值

双三次插值

lanczos插值

三、边缘填充

边界复制

边界反射

边界反射101 

边界常数

边界包裹

四、透明变换

五、图像掩膜

掩膜

水印 

六、噪点消除

 均值滤波

方框滤波

高斯滤波

中值滤波

双边滤波

总结


一、仿射变换

仿射变换是一种线性变换,保持了点之间的相对距离不变。

  • 二维空间中,图像点坐标为(x,y),仿射变换的目标是将这些点映射到新的位置 (x', y')。

  • 为了实现这种映射,通常会使用一个矩阵乘法的形式:

cv2.warpAffine(img,M,dsize)

  • img:输入图像。

  • M:2x3的变换矩阵,类型为np.float32

  • dsize:输出图像的尺寸,形式为(width,height)

图像旋转

旋转图像可以将图像绕着某个点旋转一定的角度。

cv2.getRotationMatrix2D()函数

  • 获取旋转矩阵

    cv2.getRotationMatrix2D(center,angle,scale)
    • center:旋转中心点的坐标,格式为(x,y)

    • angle:旋转角度,单位为度,正值表示逆时针旋转负值表示顺时针旋转。

    • scale:缩放比例,若设为1,则不缩放。

    • 返回值M,2x3的旋转矩阵。

示例

import cv2 as cv# 读取图片
cat = cv.imread('../images/1.jpg')
cv.imshow('cat',cat)
# 获取旋转矩阵 cv2.getRotationMatrix2D(旋转中心坐标,旋转角度,缩放比例)
M = cv.getRotationMatrix2D((cat.shape[1]/2, cat.shape[0]/2), -45, 1)
# 放射变换函数 cv2.warpAffine(src, M, dsize)   dsize 输出图片大小,可以为任意大小,会自动缩放
dst = cv.warpAffine(cat, M, (cat.shape[1], cat.shape[0]))
cv.imshow('dst',dst)# 显示图片
cv.waitKey(0)
cv.destroyAllWindows()

 图像平移

移操作可以将图像中的每个点沿着某个方向移动一定的距离。

  • 假设我们有一个点 P(x,y),希望将其沿x轴方向平移t_x*个单位,沿y轴方向平移t_y个单位到新的位置P′(x′,y′),那么平移公式如下:

    x′=x+tx

    y′=y+ty

    在矩阵形式下,该变换可以表示为:

  • 这里的t_x和t_y分别代表在x轴和y轴上的平移量。

示例

import cv2 as cv
import numpy as np# 读取图片
cat = cv.imread('../images/1.jpg')# 定义平移量
tx,ty = 100,100
# 定义变换矩阵
M = np.float32([[1,0,tx],[0,1,ty]])
# 仿射变换
dst = cv.warpAffine(cat,M,(cat.shape[1],cat.shape[0]))# 显示图片
cv.imshow('cat',cat)
cv.imshow('dst',dst)
cv.waitKey(0)
cv.destroyAllWindows()

图像缩放

 缩放操作可以改变图片的大小。

  • 假设要把图像的宽高分别缩放为0.5和0.8,那么对应的缩放因子sx=0.5,sy=0.8。

  • 点P(x,y)对应到新的位置P'(x',y'),缩放公式为:

    x′=s_x*x

    y′=s_y*y

    在矩阵形式下,该变换可以表示为:

 示例

import cv2 as cv
import numpy as np# 读取图片
cat = cv.imread('../images/1.jpg')# 定义平移量
sx,sy = 0.6,0.5
# 定义变换矩阵
M = np.float32([[sx,0,0],[0,sy,0]])
# 仿射变换
dst = cv.warpAffine(cat,M,(cat.shape[1],cat.shape[0]))# 显示图片
cv.imshow('cat',cat)
cv.imshow('dst',dst)
cv.waitKey(0)
cv.destroyAllWindows()

二、插值方法

图像插值算法是为了解决图像缩放或者旋转等操作时,由于像素之间的间隔不一致而导致的信息丢失和图像质量下降的问题。当我们对图像进行缩放或旋转等操作时,需要在新的像素位置上计算出对应的像素值,而插值算法的作用就是根据已知的像素值来推测未知位置的像素值。

最近邻插值

放大前用点表示像素值,扩展后用方格表示像素点

如放大一倍时,一个点周围四个格会的像素值都会变为该点的像素值

CV2.INTER_NEAREST

双线性插值

当需要对图像进行变换时,特别是尺寸变化时,原始图像的某些像素坐标可能不再是新图像中的整数位置,这时就需要使用插值算法来确定这些非整数坐标的像素值。

CV2.INTER_LINEAR

 

像素区域插值

像素区域插值主要分两种情况,缩小图像和放大图像的工作原理并不相同。

缩小图像时:它就会变成一个均值滤波器,对一个区域内的像素值取平均值

放大图像时:

  • 如果图像放大的比例是整数倍,那么其工作原理与最近邻插值类似;

  • 如果放大的比例不是整数倍,那么就会调用双线性插值进行放大。

cv2.INTER_AREA

双三次插值

与双线性插值法相同,该方法也是通过映射,在映射点的邻域内通过加权来得到放大图像中的像素值。不同的是,双三次插值法需要原图像中近邻的16个点来加权,也就是4x4的网格。

cv2.INTER_CUBIC

lanczos插值

Lanczos插值方法与双三次插值的思想是一样的,不同的就是其需要的原图像周围的像素点的范围变成了8*8,并且不再使用BiCubic函数来计算权重,而是换了一个公式计算权重。

cv2.INTER_LANCZOS4

示例

import cv2 as cv# 读取图片
cat = cv.imread('../images/1.jpg')# 旋转
# 获取旋转矩阵
M= cv.getRotationMatrix2D((cat.shape[1]//2, cat.shape[0]//2), 45, 0.5)
# 仿射变换
dst = cv.warpAffine(cat,M,(cat.shape[1],cat.shape[0])) # 默认
# 最近邻插值
dst1 = cv.warpAffine(cat,M,(cat.shape[1],cat.shape[0]),cv.INTER_NEAREST)
# 双线性插值   单线性插值 插两次:水平,垂直
dst2 = cv.warpAffine(cat,M,(cat.shape[1],cat.shape[0]),cv.INTER_LINEAR)
# 像素区域插值   缩小:均值滤波  放大:整数 最近邻 不是整数 双线性 4点 2*2
dst3 = cv.warpAffine(cat,M,(cat.shape[1],cat.shape[0]),cv.INTER_AREA)
# 双三次插值  16个  4*4
dst4 = cv.warpAffine(cat,M,(cat.shape[1],cat.shape[0]),cv.INTER_CUBIC)
# lanczos  64个 8*8
dst5 = cv.warpAffine(cat,M,(cat.shape[1],cat.shape[0]),cv.INTER_LANCZOS4)cv.imshow('dst', dst)
cv.imshow('dst1', dst1)
cv.imshow('dst2', dst2)
cv.imshow('dst3', dst3)
cv.imshow('dst4', dst4)
cv.imshow('dst5', dst5)# 显示
cv.waitKey(0)
cv.destroyAllWindows()

三、边缘填充

边界复制

边界复制会将边界处的像素值进行复制,然后作为边界填充的像素值

cv.warpAffine(img,M,(w,h),cv.INTER_LANCZOS4,borderMode=cv.BORDER_REPLICATE)

 

边界反射

cv.warpAffine(img,M,(w,h),cv.INTER_LANCZOS4,borderMode=cv.BORDER_REFLECT)

 

边界反射101 

与边界反射不同的是,不反射边缘的像素点

cv.warpAffine(img,M,(w,h),cv.INTER_LANCZOS4,borderMode=cv.BORDER_REFLECT_101)

 

边界常数

统一填充常数

 当选择边界常数时,还要指定常数值是多少,默认的填充常数值为0

cv.warpAffine(img,M,(w,h), cv.INTER_LANCZOS4, borderMode=cv.BORDER_CONSTANT, borderValue=(0,0,255))

边界包裹

cv.warpAffine(img,M,(w,h),cv.INTER_LANCZOS4,borderMode=cv.BORDER_WRAP)

四、透明变换

视觉上的图像越远图像越小,通过图像矫正可以把图像变为实际的图像,类似于斜视变俯视

首先要获取要纠正区域图形的四个角的坐标

获得变换矩阵

进行纠正

cv2.warpPerspective(src, M, dsize, flags, borderMode)

示例

import cv2 as cv
import numpy as np# 读取图片
card = cv.imread('../images/3.png')
cv.imshow('card', card)
# 获取透视变换矩阵
# 原图卡片四个点 : [178,100],[487,134],[124,267],[473,308]
pt1 = np.float32([[178,100],[487,134],[124,267],[473,308]])
pt2 = np.float32([[0,0],[card.shape[1],0],[0,card.shape[0]],[card.shape[1],card.shape[0]]])
M = cv.getPerspectiveTransform(pt1, pt2)
dst = cv.warpPerspective(card, M, (card.shape[1], card.shape[0]),cv.INTER_LINEAR,borderMode=cv.BORDER_REFLECT)cv.imshow('dst', dst)cv.waitKey(0)
cv.destroyAllWindows()

效果

 

 

五、图像掩膜

掩膜

掩膜是一种在图像处理中常见的操作,它用于选择性地遮挡图像的某些部分,以实现特定任务的目标。掩膜通常是一个二值化图像,并且与原图像的大小相同,其中目标区域被设置为1(或白色),而其他区域被设置为0(或黑色),并且目标区域可以根据HSV的颜色范围进行修改

mask=cv.inRange(img,color_low,color_high)

首先转换为HSV颜色空间

定义颜色范围

制作掩膜  :在颜色范围内的替换为255,其他为0

与运算(融合,提取颜色): cv.bitwise_and(img1,img2[,mask])

 

import cv2 as cv
import numpy as np
# 读取图片
demo =  cv.imread('../images/demo.png')
demo = cv.resize(demo, (640, 640))
# 转为HSV颜色空间
hsv = cv.cvtColor(demo,cv.COLOR_BGR2HSV)
# 定义颜色范围
low = np.array([0,43,46])
high = np.array([10,255,255])
# 创建掩膜 cv.inRange(img,low,high)    传hsv空间下的图像
# 在范围内的替换为255,其他为0
mask = cv.inRange(hsv,low,high)
# 颜色提取  cv.bitwise_and(img1,img2[,mask])   传的原图
dst = cv.bitwise_and(demo,demo,mask=mask)cv.imshow('mask',mask)
cv.imshow('demo',demo)
cv.imshow('dst',dst)
cv.waitKey(0)
cv.destroyAllWindows()

 效果

水印 

图片需要灰度化

import cv2 as cv
# 读取图片
bg = cv.imread('../images/bg.png')
logo = cv.imread('../images/logohq.png')
h,w = logo.shape[0:2]  # 获取logo的宽高
roi = bg[0:h,0:w]# 转灰度
gray = cv.cvtColor(logo,cv.COLOR_BGR2GRAY)# 二值化
# 黑logo 白底   与上背景  == 黑logo的背景
_,mask1 = cv.threshold(gray,200,255,cv.THRESH_BINARY)
bg1 = cv.bitwise_and(roi,roi,mask=mask1)
cv.imshow("mask1",mask1)
cv.imshow("bg1",bg1)
# 白logo 黑底   与上logo == 黑底的logo
_,mask2 = cv.threshold(gray,200,255,cv.THRESH_BINARY_INV)
logo1 = cv.bitwise_and(logo,logo,mask=mask2)
cv.imshow("mask2",mask2)
cv.imshow("logo1",logo1)
# 融合
roi[:] = cv.add(bg1,logo1)
cv.imshow("roi",roi)
cv.imshow("bg",bg)# 显示
cv.waitKey(0)
cv.destroyAllWindows()

六、噪点消除

噪声:指图像中的一些干扰因素,通常是由图像采集设备、传输信道等因素造成的,表现为图像中随机的亮度。

常见的噪声类型包括高斯噪声和椒盐噪声。高斯噪声是一种分布符合正态分布的噪声,会使图像变得模糊或有噪点。椒盐噪声则是一些黑白色的像素值分布在原图像中。

滤波器:也可以叫做卷积核,与自适应二值化中的核一样,本身是一个小的区域,有着特定的核值,并且工作原理也是在原图上进行滑动并计算中心像素点的像素值。  

 均值滤波

均值滤波是一种最简单的滤波处理,它取的是卷积核区域内元素的均值

方框滤波

滤波的过程与均值滤波一模一样,都采用卷积核从图像左上角开始,逐个计算对应位置的像素值,并从左至右、从上至下滑动卷积核,直至到达图像右下角,唯一的区别就是核值可能会不同。

高斯滤波

高斯滤波是一种常用的图像处理技术,主要用于平滑图像、去除噪声。它通过使用高斯函数(正态分布)作为卷积核来对图像进行模糊处理。

中值滤波

中值又叫中位数,是所有数排序后取中间的值。中值滤波没有核值,而是在原图中从左上角开始,将卷积核区域内的像素值进行排序,并选取中值作为卷积核的中点的像素值

双边滤波

双边滤波的基本思路是同时考虑将要被滤波的像素点的空域信息(周围像素点的位置的权重)和值域信息(周围像素点的像素值的权重)。

双边滤波明显保留了更多边缘信息

示例

import cv2 as cv# 优先考虑高斯滤波,其次使用均值滤波
# 椒盐噪声和斑点噪声使用中值滤波# 读取图片
lvbo2 = cv.imread("../images/lvbo2.png")
cv.imshow("lvbo2", lvbo2)
lvbo3 = cv.imread("../images/lvbo3.png")
cv.imshow("lvbo3", lvbo3)
# 均值滤波
dst1 = cv.blur(lvbo2, (3,3))  # 参数为图片和核大小 : 3*3
cv.imshow("dst1", dst1)
# 方框滤波    normalize=True时,就是均值滤波
dst2 = cv.boxFilter(lvbo2, -1, (3,3),normalize=False)  # -1 表示输出图片通道数和输入图片一致
cv.imshow("dst2", dst2)
# 高斯滤波
dst3 = cv.GaussianBlur(lvbo2, (3,3), 1)
cv.imshow("dst3", dst3)
# 中值滤波  用于处理椒盐噪声和斑点噪声
dst4 = cv.medianBlur(lvbo3,5)
cv.imshow("dst4", dst4)
# 双边滤波
dst5 = cv.bilateralFilter(lvbo2,7,75,75)   # 7为空间窗口大小, 50为灰度窗口大小
cv.imshow("dst5", dst5)# 显示
cv.waitKey(0)
cv.destroyAllWindows()

总结

本文系统介绍了OpenCV中的图像变换与处理技术。主要内容包括:1)仿射变换(旋转、平移、缩放)的实现方法;2)五种图像插值算法(最近邻、双线性、区域、双三次、Lanczos)的原理与应用;3)五种边缘填充方式(复制、反射、反射101、常数、包裹)的特点;4)透视变换的矫正方法;5)图像掩膜技术的实现步骤;6)常见噪声消除方法(均值、方框、高斯、中值、双边滤波)的适用场景。通过Python代码示例详细演示了各项技术的具体实现过程,为图像处理提供了全面的技术参考。

http://www.xdnf.cn/news/16340.html

相关文章:

  • 【Unity开发】飞机大战项目实现总结
  • Python 程序设计讲义(15):Python 的数据运算——位运算
  • Unity VS Unreal Engine ,“电影像游戏的时代” 新手如何抉择引擎?(1)
  • 读书笔记(黄帝内经)
  • 使用Python采集招聘网站数据并智能分析求职信息
  • P1013 [NOIP 1998 提高组] 进制位
  • ESP32S3 Ubuntu vscode如何使用USB-JTAG调试
  • java中如何返回一个可以执行返回操作(return action)的函数或对象
  • 【自用】JavaSE--阶段测试
  • 基于深度学习的胸部 X 光图像肺炎分类系统(二)
  • 学习设计模式《十九》——享元模式
  • ICCV 2025 | CWNet: Causal Wavelet Network for Low-Light Image Enhancement
  • 主要分布在背侧海马体(dHPC)CA1区域(dCA1)的位置细胞对NLP中的深层语义分析的积极影响和启示
  • LeetCode|Day24|383. 赎金信|Python刷题笔记
  • 【Oracle】Oracle权限迷宫破解指南:2步定位视图依赖与授权关系
  • QML WorkerScript
  • 高版本Android跨应用广播通信实例
  • MBPO 算法:让智能体像人一样 “先模拟后实操”—强化学习(17)
  • Linux进程间通信:管道机制全方位解读
  • 卫星物联网:使用兼容 Arduino 的全新 Iridium Certus 9704 开发套件深入探索
  • 如何判断钱包的合约签名是否安全?
  • MySQL基础02
  • 常见半导体的介电常数
  • 【ROS1】09-ROS通信机制——参数服务器
  • 接口多态之我的误解
  • 高可用架构模式——异地多活设计步骤
  • k8s之ingress定义https访问方式
  • 精通Python PDF裁剪:从入门到专业的三重境界
  • Vue工程化 ElementPlus
  • 分布式推客系统开发全解:微服务拆分、佣金结算与风控设计