优化图像处理:从旋转与缩放到水印添加

embedded/2024/9/19 0:49:20/ 标签: opencv, 计算机视觉, 人工智能

1. 旋转与缩放的仿射变换

在 OpenCV 中,cv2.getRotationMatrix2D() 函数可以生成旋转矩阵,该矩阵用于对图像进行旋转和缩放变换。旋转矩阵的主要参数是:

  • Center:旋转中心点的坐标 (x, y)。

  • Angle:旋转角度,单位是度。

  • Scale:缩放因子,调整图像的大小。

    import cv2
    img=cv2.imread("./src/tu.png")
    h,w,_=img.shape
    M=cv2.getRotationMatrix2D((w/2,h/2),45,1)
    m=cv2.warpAffine(img, M, (w, h))
    cv2.imshow("img",img)
    cv2.imshow("m",m)
    cv2.waitKey(0)

2. 旋转中的像素信息丢失

旋转图像时,由于三角函数计算出的坐标通常是浮点数,因此旋转后的像素点可能不会落在原始像素的整数坐标上。这导致以下问题:

  • 像素信息丢失:旋转过程中,某些像素点的坐标可能会落在图像边界之外,或多个像素点的旋转后坐标重合。

  • 插值问题:旋转后的坐标可能不是整数,这会导致需要计算这些非整数坐标对应的像素值。

3. 插值法的作用

为了处理这些问题,我们使用插值法来计算旋转后图像中每个像素点的值。常见的插值方法有:

  • 最近邻插值:cv2.INTER_NEAREST:简单且速度快,适合对图像进行小幅度的变换,但可能会导致锯齿效应。

  • 双线性插值:cv2.INTER_LINEAR:适用于大多数缩放操作,提供平滑的结果,尤其是在放大时。

  • 像素区域插值:cv2.INTER_AREA:用于图像缩小时表现良好,能避免模糊,并保留更多细节。

  • 双三次插值:cv2.INTER_CUBIC:提供比双线性更平滑的结果,适用于高质量的图像放大。

  • Lanczos插值:cv2.INTER_LANCZOS4:高质量插值方法,适合对图像进行大幅度变换,但计算开销较大。

import cv2
img = cv2.imread("./src/tu.png")
h, w, _ = img.shape
# 最近邻插值:CV2.INTER_NEAREST
img1 = cv2.resize(img, dsize=None, fx=0.5, fy=0.5, interpolation=cv2.INTER_NEAREST)
# 双线性插值:CV2.INTER_LINEAR
img2 = cv2.resize(img, dsize=None, fx=0.5, fy=0.5, interpolation=cv2.INTER_LINEAR)
# 像素区域插值:cv2.INTER_AREA
img3 = cv2.resize(img, dsize=None, fx=0.5, fy=0.5, interpolation=cv2.INTER_AREA)
# 双三次插值:cv2.INTER_CUBIC
img4 = cv2.resize(img, dsize=None, fx=0.5, fy=0.5, interpolation=cv2.INTER_CUBIC)
# Lanczos插值:cv2.INTER_LANCZOS4
img5 = cv2.resize(img, dsize=None, fx=0.5, fy=0.5, interpolation=cv2.INTER_LANCZOS4)
cv2.imshow("img", img)
cv2.imshow("img1", img1)
cv2.imshow("img2", img2)
cv2.imshow("img3", img3)
cv2.imshow("img4", img4)
cv2.imshow("img5", img5)
cv2.waitKey(0)
cv2.destroyAllWindows()

4.边缘填充方式

边缘填充方式用于处理图像在变换(如旋转、缩放)时的边界问题。常见的填充方式包括:

  • 边界复制:cv2.BORDER_REPLICATE:复制边缘像素填充,适用于保持图像的一致性。

  • 边界反射:cv2.BORDER_REFLECT:用边缘的镜像反射部分填充,使得填充区域与边缘平滑过渡。

  • 边界反射101:cv2.BORDER_REFLECT_101:类似于 BORDER_REFLECT,但不包含边缘的第一个像素,填充效果更加平滑。

  • 边界常数:cv2.BORDER_CONSTANT:用常量值填充边缘,常用于保持边缘的整洁。

  • 边界包裹:cv2.BORDER_WRAP:用图像的对面部分进行填充,适合周期性图像。

import cv2
import numpy as np
​
# 读取图像
img = cv2.imread("./src/face.png")
h, w, _ = img.shape
​
# 定义仿射变换矩阵
M = np.array([[0, 1, 50], [-1, 0, 100]], dtype=np.float32)
​
# 设置目标图像尺寸
dsize = (w * 2, h * 2)
# 使用不同的边界填充模式
border_modes = [cv2.BORDER_REPLICATE, cv2.BORDER_REFLECT, cv2.BORDER_REFLECT_101,cv2.BORDER_CONSTANT,cv2.BORDER_WRAP]
​
for mode in border_modes:img2 = cv2.warpAffine(img, M,dsize=dsize, flags=cv2.INTER_LINEAR, borderMode=mode, borderValue=[213,102,201])cv2.imshow(f"Border Mode: {mode}", img2)
​
cv2.waitKey(0)
cv2.destroyAllWindows()

图片镜像旋转

镜像旋转的翻转方式在 OpenCV 中通过 cv2.flip() 函数实现,flipCode 参数定义了翻转方式:

  • 0:垂直翻转,沿 x 轴对称。

  • 大于 0:水平翻转,沿 y 轴对称。

  • 小于 0:水平和垂直翻转,沿 x 轴和 y 轴对称。

    import cv2
    img = cv2.imread('./src/e.png')
    img1=cv2.flip(img,0)
    img2=img[::-1,::-1] #水平垂直翻转
    cv2.imshow("img",img)
    cv2.imshow("img1",img1)
    cv2.imshow("img2",img2)
    cv2.waitKey(0)

图像缩放

在图像缩放实验中,你可以独立调整图像在 x 轴和 y 轴的缩放比例,类似于图像旋转中的缩放,但允许不同方向上的不同缩放比例。使用 cv2.resize() 函数时,你可以设置 fxfy 进行缩放,插值方法如最近邻、双线性、像素区域、立方和 Lanczos 等,用于计算新像素值。双线性插值(cv2.INTER_LINEAR)是一种常用的方法,能够平滑地处理图像细节。

import cv2
img=cv2.imread('./src/c.png')
img1 = cv2.resize(img, dsize=None, fx=0.5, fy=0.5, interpolation=cv2.INTER_LINEAR)
cv2.imshow("img",img)
cv2.imshow("img1",img1)
cv2.waitKey(0)

图像矫正

图像矫正的原理是透视变换

透视变换的核心在于将图像从一个视角投影到另一个视角,从而修正图像中的透视畸变。相比于仿射变换,透视变换更复杂,它通过透视变换矩阵来处理三维到二维的投影过程。具体来说,透视变换矩阵是一个3x3的矩阵,其中每个元素影响着图像中点的变换关系。OpenCV中的getPerspectiveTransform(src, dst)函数用于计算这个矩阵,warpPerspective(src, M, dsize)函数则用来应用这个矩阵进行实际的透视变换。

import cv2
import numpy as np
​
# 读取图像
img = cv2.imread('./src/3.png')
​
# 定义源点
src1 = np.float32([[178, 102], [518, 154], [113, 300], [503, 346]])
​
# 绘制线条
img_line = img.copy()
cv2.line(img_line, tuple(src1[0].astype(np.int64)), tuple(src1[1].astype(np.int64)), (0, 0, 255), 2, cv2.LINE_AA)
cv2.line(img_line, tuple(src1[0].astype(np.int64)), tuple(src1[2].astype(np.int64)), (0, 0, 255), 2, cv2.LINE_AA)
cv2.line(img_line, tuple(src1[1].astype(np.int64)), tuple(src1[3].astype(np.int64)), (0, 0, 255), 2, cv2.LINE_AA)
cv2.line(img_line, tuple(src1[2].astype(np.int64)), tuple(src1[3].astype(np.int64)), (0, 0, 255), 2, cv2.LINE_AA)
​
# 定义目标点
h, w = img.shape[:2]
src2 = np.float32([[0, 0], [w, 0], [0, h], [w, h]])
​
# 计算透视变换矩阵
src = cv2.getPerspectiveTransform(src1, src2)
​
# 应用透视变换
img1 = cv2.warpPerspective(img, src, (w, h), flags=cv2.INTER_LINEAR, borderMode=cv2.BORDER_REFLECT_101)
cv2.imshow("img", img_line)
cv2.imshow("img1", img1)
cv2.waitKey(0)
cv2.destroyAllWindows()

图像添加水印

添加水印的过程可以理解为将一张图片中的图案叠加到另一张图片上。具体步骤如下:

1. 模板输入

模板输入用于获取水印图案。首先,将水印图像转换为灰度图,然后进行二值化处理。这一步的目的是创建一个掩膜图像,其中水印图案是白色(255),背景是黑色(0)。

2. 与运算

得到掩膜图像后,在目标图像中定义一个区域(ROI,感兴趣区域)作为水印的添加区域。使用掩膜图像与该ROI区域进行“与”运算。通过这种运算,只有掩膜图像中白色部分的区域会在目标图像的ROI区域中保留下来,其余部分将被遮盖。

3. 图像融合

最后,将经过与运算得到的目标区域与原始水印图像进行融合。图像融合步骤是将水印图像与目标图像中的对应区域进行逐像素的相加操作,注意两者的尺寸必须一致。这样,水印图案就会被成功叠加到目标图像中,从而实现水印的效果。

import cv2
import numpy as np
img=cv2.imread("./src/cat.png")
logo=cv2.imread("./src/logohq.png")
​
# 获取 logo 的尺寸
h, w, _ = logo.shape
# 将 logo 转换到 HSV 颜色空间
hsvlogo = cv2.cvtColor(logo, cv2.COLOR_BGR2HSV)
#提取红色范围
lower1 = np.array([0, 43, 46])
upper1 = np.array([10, 255, 255])
#提取灰色范围
lower2 = np.array([0, 0, 46])
upper2= np.array([180, 43, 220])
# 创建掩膜
mask1 = cv2.inRange(hsvlogo, lower1, upper1)
mask2 = cv2.inRange(hsvlogo, lower2, upper2)
mask=mask1+mask2
# 显示掩膜
cv2.imshow("mask", mask)
# 提取与 logo 大小相同的背景区域
img2 = img[:h, :w]
# 使用掩膜提取文字区域
text_bool = (mask == 255)
# 将文字部分融合到背景图像中
img2[text_bool] = logo[text_bool]
cv2.imshow("img", img)
cv2.imshow("logo", logo)
cv2.waitKey(0)
cv2.destroyAllWindows()

总结

整个过程包括:

  • 从模板图像中创建掩膜。

  • 在目标图像中定位水印区域,并用掩膜图像来提取水印形状。

  • 将提取出的水印图像与目标图像的相应区域融合


http://www.ppmy.cn/embedded/95699.html

相关文章

Nginx 优化与防盗链

目录 一、隐藏版本号 方法一:修改配置文件 方法二:修改源码文件,重新编译安装 二、修改用户和组 三、缓存时间 四、日志切割(脚本) 五、连接超时 六、更改进程数 七、配置网页压缩 八、配置防盗链 一、隐藏版…

类Unix环境在Windows上的演进史

自从以Unix为基础的操作系统被发明以来,尝试在Windows环境中模仿Unix操作的工具就一直存在。这种需求源于许多原因,包括Unix对脚本和命令行工具的强大支持,以及Unix和Linux系统在科学、工程和其他技术领域的广泛使用。下面就让我们一起探讨下…

智慧节能节水设备远程监控解决方案

智慧节能节水设备远程监控解决方案,作为现代物联网技术与环保理念深度融合的产物,旨在通过高度集成的传感器网络、大数据分析及云计算平台,实现对各类节能节水设施的精细化管理和实时监控,从而大幅度提升资源利用效率,…

英特尔新独显曝光,或于今年底发布

原文转载修改自(更多互联网新闻/搞机小技巧): 英特尔Arc Battlemage显卡参数规格曝光,或于年底发布 (不定时更新) Arc Battlemage显卡曝光 最近有报道称,英特尔计划将在今年晚些时候推出基于X…

springboot有关事务的实现

一、事务 1.事务的概念 事务是指一组操作,这些操作要么全部成功,要么全部失败。如果在一组操作中有一个操作失败了,那么整个事务都应该回滚,即撤销已经执行的操作,从而保证数据的一致性和完整性。 2.事务的四个特性…

Effective Java学习笔记--第29、30条优先考虑泛型和泛型方法

目录 类的构建优先考虑泛型 如何解决泛型数组的问题 创建Object数组然后进行强制转换 将Object数组中的元素进行强制转换 方法的构建优先考虑泛型 这两条主要讲述了泛型对于类与方法的构建能起到很多积极的作用。 类的构建优先考虑泛型 如果某一个类需要支持特定的数据类…

javaer快速入门 goweb框架 gin

gin 入门 前置条件 安装环境 配置代理 # 配置 GOPROXY 环境变量,以下三选一# 1. 七牛 CDN go env -w GOPROXYhttps://goproxy.cn,direct# 2. 阿里云 go env -w GOPROXYhttps://mirrors.aliyun.com/goproxy/,direct# 3. 官方 go env -w GOPROXYhttps://goproxy.…

时间记录内核模块

好的&#xff0c;下面是一个示例内核模块的代码&#xff0c;它每隔一秒打印一次当前时间&#xff0c;并在 /proc 文件系统中提供一个接口来查看这些时间记录。 内核模块代码 #include <linux/module.h> #include <linux/kernel.h> #include <linux/timer.h>…

上瘾模型与产品激励系统

​产品要增加客户粘性&#xff0c;使产品深入人心就需要让用户对产品上瘾。如何使用户对产品上瘾&#xff1f;对于产品来说&#xff0c;就需要建立产品的激励系统。 产品的激励系统要做的事就是对用户进行激励&#xff0c;就是让用户主动完成产品或服务想要他们做的事情。 那么…

MinIO DataPOD 目标锁定 GPU Direct 并行文件系统

MinIO 推出针对 AI 应用的 DataPOD 参考架构 MinIO 设计了一种旨在为 AI 训练提供数据的 exascale DataPOD 参考架构。这家开源对象存储软件供应商正将其可扩展至100 PiB&#xff08;即大约112.6 PB&#xff09;的单元定位为一种替代方案&#xff0c;以取代使用 GPU Direct 技…

JVM-内存结构

内存结构 内存结构是 JVM 中非常重要的一部分&#xff0c;是非常重要的系统资源&#xff0c;是硬盘和 CPU 的桥梁&#xff0c;承载着操作系统和应用程序的实时运行&#xff0c;又叫运行时数据区 JVM 内存结构规定了 Java 在运行过程中内存申请、分配、管理的策略&#xff0c;…

JavaScript 详解

第一章 JavaScript简介 为什么学习javascript &#xff1f; JavaScript 是全球最流行的编程语言。 JavaScript 是属于 Web 的编程语言。 JavaScript 是 web 开发者必学的三种语言之一&#xff1a; HTML 定义网页的内容 CSS 规定网页的布局 JavaScript 对网页行为进行编程 …

面对复杂订单统计,如何用这款工具化整为零?

最近制作报表时遇到了个问题&#xff0c;怎么把整合到一起的订单统计数据拆分成一个个单独的订单统计报表呢&#xff1f;经过一段时间的探索后&#xff0c;我找到了一款完全免费的报表软件&#xff0c;能够解决这个问题&#xff0c;这款软件叫作山海鲸可视化&#xff0c;我会在…

宝塔面板屏蔽 Censys,防止源站 IP 泄露

Censys 搜索引擎很强大。Censys 每天都会扫描 IPv4 地址空间&#xff0c;以搜索所有联网设备并收集相关的信息&#xff0c;并返回一份有关资源&#xff08;如设备、网站和证书&#xff09;配置和部署信息的总体报告。 在 IP 前加上 https 访问时&#xff0c;Nginx 会自动返回该…

几个常用脚本

系统初始化 #!/bin/bash # 定义颜色常量 RED\033[0;31m GREEN\033[0;32m NC\033[0m # No Color #功能菜单 menu() {clearecho "请选择要执行的操作:"echo "1. 检查网络"echo "2. 关闭防火墙和SELinux"echo "3. 替换YUM源"echo "…

Linux第六章---thrift

thrift开发笔记(4种由易到难的匹配系统) 准备工作 创建项目文件夹thrift_project 业务逻辑图 服务分为三部分&#xff1a;分别是game&#xff0c;match_system&#xff0c;save_servergame为match_client端&#xff0c;通过match.thrift接口向match_system完成添加用户和删…

【TiDB】09-修改tidb客户端访问密码

目录 1、修改配置文件 2、停止tidb-server 3、以root方式启动脚本 4、修改密码 5、停止脚本重启服务 1、修改配置文件 进入tidb-server默认部署位置 #切换tidb账号 su tidb# 进入tidb-server部署路径 cd /tidb-deploy/tidb-4000# 修改配置 vim ./conf/tidb.toml添加内容…

keepalived

实验环境布置 webserver1172.25.250.110webserver2172.25.250.120kail1172.25.250.10kail217225.250.20 在webserver1和webserver2下载httpd服务 [rootwebserver1 ~]# yum install httpd -y [rootwebserver1 ~]# echo webserver1 172.25.250.110 > /var/www/html/index.htm…

攻克面试:高频面试题与常见算法深度剖析

干货分享&#xff0c;感谢您的阅读&#xff01; &#xff08;暂存篇---后续会删除&#xff0c;完整版和持续更新见高频面试题基本总结回顾&#xff08;含笔试高频算法整理&#xff09;&#xff09; 备注&#xff1a;引用请标注出处&#xff0c;同时存在的问题请在相关博客留言…

Go语言基础--进制转换

二进制转十进制 从右向左开始&#xff0c;从右边第一个数开始&#xff0c;依次乘以2的n次幂 &#xff0c;n从0开始&#xff0c;每次递增1&#xff08;0&#xff0c;1&#xff0c;2&#xff0c;3 。。。。&#xff09;得出得数相加就是十进制得数 如&#xff1a;01011*2的0次幂0…