opencv函数cv2.warpAffine 和 cv2.warpPerspective 的理解和复现

news2024/9/22 9:48:13

文章目录

  • opencv函数cv2.warpAffine 和 cv2.warpPerspective 的理解和复现
    • 1. warpAffine 函数处理仿射变换
    • 2. warp_perspective
    • 3, 实验

opencv函数cv2.warpAffine 和 cv2.warpPerspective 的理解和复现

1. warpAffine 函数处理仿射变换

仿射矩阵是2 * 3的矩阵。

首先进行坐标转换,然后应用插值

具体代码如下, 与opencv一致:

def warp_affine_forward(image, rot_mat, dst_h, dst_w):
    M = rot_mat.reshape([2, 3])
    hs, ws, cs = image.shape
    hh, ww = np.arange(hs), np.arange(ws)
    xx, yy = np.meshgrid(ww, hh)

    sx, sy = xx, yy # 不缩放图像
    tx, ty = M[0, 0] * sx + M[0, 1] * sy + M[0, 2], M[1, 0] * sx + M[1, 1] * sy + M[1, 2]
    # tx = np.sum(M[0, :].reshape([1, 1, 3]) * np.dstack((sx, sy, np.ones_like(sx))), axis=-1)
    # ty = np.sum(M[1, :].reshape([1, 1, 3]) * np.dstack((sx, sy, np.ones_like(sx))), axis=-1)

    dhh, dww = np.arange(dst_h), np.arange(dst_w)
    dxx, dyy = np.meshgrid(dww, dhh)
    grid_x, grid_y = dxx, dyy
    points = np.dstack((tx, ty))
    # print(points.shape, image.shape, grid_x.shape)
    out = griddata(points.reshape(-1, 2), image.reshape(-1, 3), (grid_x, grid_y), method='linear')
    out[np.isnan(out)] = 0

    return out

逆变换代码:

def warp_affine(image, rot_mat, dst_h, dst_w):
    M = rot_mat.reshape([2, 3])
    hs, ws, cs = image.shape
    hh, ww = np.arange(dst_h), np.arange(dst_w)
    xx, yy = np.meshgrid(ww, hh)

    sx, sy = (xx + 0.5) * (ws / ws) - 0.5, (yy + 0.5) * (hs / hs) - 0.5 # 不缩放图像。
    # sx, sy = (xx + 0.5) * (ws / dst_w) - 0.5, (yy + 0.5) * (hs / dst_h) - 0.5 # 缩放图像
    tx, ty = M[0, 0] * sx + M[0, 1] * sy + M[0, 2], M[1, 0] * sx + M[1, 1] * sy + M[1, 2]
    # tx = np.sum(M[0, :].reshape([1, 1, 3]) * np.dstack((sx, sy, np.ones_like(sx))), axis=-1)
    # ty = np.sum(M[1, :].reshape([1, 1, 3]) * np.dstack((sx, sy, np.ones_like(sx))), axis=-1)

    mask = ((tx < 0) + (ty < 0) + (tx > ws - 1) + (ty > hs - 1)) > 0
    # print(mask.shape, mask.dtype, np.sum(mask))
    out = interp_linear(image, tx, ty)
    out[mask] = 0
    return out

也可以求解转换矩阵的逆后,再正变换,结果相同。

其中用到重查找函数:根据tx,ty坐标位置,获取值
和cv2.remap函数相同。

def interp_linear(image, tx, ty):
    '''
    类似 cv2.remap 函数
    :param image: h,w,c image  np.float
    :param tx:  dst_h * dst_w, float , 目标位置x方向
    :param ty:  dst_h * dst_w, float , 目标位置y方向
    :return:
    '''
    h, w, c = image.shape
    hv, wv = ty, tx
    hh = np.floor(hv).astype(np.int32)
    ww = np.floor(wv).astype(np.int32)
    u = hv - hh
    v = wv - ww

    # special case
    u[hh < 0] = 0
    hh[hh < 0] = 0
    u[hh >= h - 1] = 1.0
    hh[hh >= h - 1] = h - 2

    v[ww < 0] = 0
    ww[ww < 0] = 0
    v[ww >= w - 1] = 1.0
    ww[ww >= w - 1] = w - 2
    # v = v.reshape(-1)

    w00 = (1-u)*(1-v)
    w01 = u * (1-v)
    w10 = (1-u) * v
    w11 = u*v
    out = w00[..., None] * image[hh, ww] + w10[..., None]  * image[hh, ww + 1] + w01[..., None]  * image[(hh + 1), ww] + w11[..., None]  * image[hh + 1, ww + 1]
    return out

2. warp_perspective

warpPerspective 和 warpAffine 是类似的。
但是warpPerspective的转换矩阵是3*3的透视变换矩阵,经过变换后平行线可能不在平行

一个逆变换 和 两个正变换的代码如下:

# 逆变换函数
def warp_perspective(image, pers_mat, dst_h, dst_w):
    M = pers_mat.reshape([3, 3])
    hs, ws, cs = image.shape
    hh, ww = np.arange(dst_h), np.arange(dst_w)
    xx, yy = np.meshgrid(ww, hh)
    sx, sy = (xx + 0.5) * (ws / ws) - 0.5, (yy + 0.5)* (hs / hs) - 0.5
    # sx, sy = (xx + 0.5) * (ws / dst_w) - 0.5, (yy + 0.5) * (hs / dst_h) - 0.5  # 缩放图像

    t = M[2, 0] * sx + M[2, 1] * sy + M[2, 2]
    tx, ty = M[0, 0] * sx + M[0, 1] * sy + M[0, 2] , M[1, 0] * sx + M[1, 1] * sy + M[1, 2]
    tx, ty = tx / t, ty / t
    # out = np.zeros_like(image)
    mask = ((tx < 0 ) + (ty < 0) + (tx > ws - 1) + (ty > hs - 1)) > 0
    print(mask.shape, mask.dtype, np.sum(mask))
    # out = interp_linear(image, tx, ty)
    out = cv2.remap(image, tx.astype(np.float32), ty.astype(np.float32), interpolation=cv2.INTER_LINEAR)
    out[mask] = 0
    return out
# 正变化函数
def warp_perspective_forward(image, pers_mat, dst_h, dst_w):
    M = pers_mat.reshape([3, 3])
    hs, ws, cs = image.shape
    hh, ww = np.arange(hs), np.arange(ws)
    xx, yy = np.meshgrid(ww, hh)

    sx, sy = xx, yy  # 不缩放图像

    t = M[2, 0] * sx + M[2, 1] * sy + M[2, 2]
    tx, ty = M[0, 0] * sx + M[0, 1] * sy + M[0, 2] , M[1, 0] * sx + M[1, 1] * sy + M[1, 2]
    tx, ty = tx / t, ty / t

    # interp
    dhh, dww = np.arange(dst_h), np.arange(dst_w)
    dxx, dyy = np.meshgrid(dww, dhh)
    grid_x, grid_y = dxx, dyy
    points = np.dstack((tx, ty))
    # print(points.shape, image.shape, grid_x.shape)
    out = griddata(points.reshape(-1, 2), image.reshape(-1, 3), (grid_x, grid_y), method='linear')
    out[np.isnan(out)] = 0
    return out

# 正变换函数:这里利用np.linalg.inv 求逆矩阵,然后按照warp_perspective的方式进行
def warp_perspective_forward2(image, pers_mat, dst_h, dst_w):
    M = pers_mat.reshape([3, 3])
    M_inv = np.linalg.inv(M)
    M = M_inv
    hs, ws, cs = image.shape
    hh, ww = np.arange(dst_h), np.arange(dst_w)
    xx, yy = np.meshgrid(ww, hh)
    sx, sy = (xx + 0.5) * (ws / ws) - 0.5, (yy + 0.5) * (hs / hs) - 0.5
    # sx, sy = (xx + 0.5) * (ws / dst_w) - 0.5, (yy + 0.5) * (hs / dst_h) - 0.5  # 缩放图像

    t = M[2, 0] * sx + M[2, 1] * sy + M[2, 2]
    tx, ty = M[0, 0] * sx + M[0, 1] * sy + M[0, 2], M[1, 0] * sx + M[1, 1] * sy + M[1, 2]
    tx, ty = tx / t, ty / t
    # out = np.zeros_like(image)
    mask = ((tx < 0) + (ty < 0) + (tx > ws - 1) + (ty > hs - 1)) > 0
    print(mask.shape, mask.dtype, np.sum(mask))
    # out = interp_linear(image, tx, ty)
    out = cv2.remap(image, tx.astype(np.float32), ty.astype(np.float32), interpolation=cv2.INTER_LINEAR)
    out[mask] = 0
    return out

3, 实验

验证以上代码和opencv中的一致性

import cv2
import numpy as np
from matplotlib import pyplot as plt
from scipy.interpolate import griddata
def cal_sobel(img):
    #分别求X,Y方向的梯度
    grad_X=cv2.Sobel(img,-1,1,0)
    grad_Y=cv2.Sobel(img,-1,0,1)
    #求梯度图像
    grad=cv2.addWeighted(grad_X,0.5,grad_Y,0.5,0)
    return grad
if __name__ == "__main__":
    file1 = r'test.jpg'
    image1 = cv2.imread(file1) / 255
    image1 = cv2.resize(image1, (0, 0), fx=0.5, fy=0.5)
    h, w, c = image1.shape
    print(h, w, c)

    center = (w // 2, h // 2)
    angle = -50
    scale = 0.6

    rot_mat = cv2.getRotationMatrix2D(center, angle, scale)
    print(rot_mat)

    dst_h, dst_w = int(image1.shape[0] * 0.7), int(image1.shape[1]* 0.7)
    image2 = cv2.warpAffine(image1, rot_mat, (dst_w, dst_h))

    center = (w // 2, h // 2)
    angle = 50
    scale = 1 / 0.6
    rot_mat2 = cv2.getRotationMatrix2D(center, angle, scale)
    print(rot_mat2)
    image3 = warp_affine(image1, rot_mat2, dst_h, dst_w)
    image4 = warp_affine_forward(image1, rot_mat, dst_h, dst_w)
    plt.figure()
    plt.subplot(221)
    plt.imshow(image1)
    plt.subplot(222)
    plt.imshow(image2)
    plt.subplot(223)
    plt.imshow(image3)
    plt.subplot(224)
    plt.imshow(image4)
    plt.show()

    # 根据4个点求透视转换
    pts1 = np.float32([[56, 65], [368, 52], [28, 387], [389, 390]])
    pts2 = np.float32([[0, 0], [300, 0], [0, 300], [300, 300]])
    M = cv2.getPerspectiveTransform(pts1, pts2)

    image2 = cv2.warpPerspective(image1, M, (dst_w, dst_h), flags=cv2.INTER_LINEAR + cv2.WARP_INVERSE_MAP)
    image3 = warp_perspective(image1, M, dst_h, dst_w)

    image4 = cv2.warpPerspective(image1, M, (dst_w, dst_h), flags=cv2.INTER_LINEAR)
    image5 = warp_perspective_forward(image1, M, dst_h, dst_w)
    image6 = warp_perspective_forward2(image1, M, dst_h, dst_w)

    plt.figure()
    plt.subplot(231)
    plt.imshow(image1)
    plt.subplot(232)
    plt.imshow(image2)
    plt.subplot(233)
    plt.imshow(image3)
    plt.subplot(234)
    plt.imshow(image4)
    plt.subplot(235)
    plt.imshow(image5)
    plt.subplot(236)
    plt.imshow(image6)
    plt.show()

运行上面的代码,实验结果如下:
warp affine实验结果:
在这里插入图片描述

warp perspective 实验结果
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

(深度学习快速入门)第三章第三节5:深度学习必备组件之欠拟合和过拟合

文章目录一&#xff1a;什么是欠拟合和过拟合二&#xff1a;正则化技术&#xff08;1&#xff09;加入正则项①&#xff1a;L1正则项②&#xff1a;L2正则项&#xff08;2&#xff09;Dropout&#xff08;暂退法&#xff09;我们训练模型的目的是为了让模型真正发现一种泛化模式…

个人流媒体服务搭建

简介 主要是个人的流媒体服务器的创建的方式分享 Centos7自建基于HLS的私人直播服务器 相关资源下载 链接&#xff1a;https://pan.baidu.com/s/1zhWFpFRy2v0_lyjA0-AfAg 提取码&#xff1a;yyds 入门操作 实现方法基于nginx和nginx的一个rtmp模块。因为epel源和nginx官…

来源于《高质量C/C++编程》的几道经典面试题

本文介绍几个非常经典的笔试题&#xff0c;原题详细解析&#xff0c;供参考题目1&#xff1a;非法访问内存泄漏题目2&#xff1a;返回栈空间地址问题--非法访问题目3&#xff1a;内存泄漏题目4&#xff1a;非法访问题目1&#xff1a;非法访问内存泄漏 void Getmemory(char* p)…

Apache Doris 系列: 基础篇-使用BitMap函数精准去重(2)

1. 背景 Apache Doris 原有的BitMap函数虽然比较通用&#xff0c; 但在亿级别的BitMap大基数并交计算性能较差&#xff0c;主要是由以下两个原因造成的&#xff1a; 当BitMap的基数过大&#xff0c;大小超过1GB时&#xff0c;网络或者磁盘的处理时间较长BE节点扫描完数据后传…

机器自动翻译古文拼音 - 十大宋词 - 念奴娇 赤壁怀古 苏轼

念奴娇 赤壁怀古 苏轼 大江东去&#xff0c;浪淘尽&#xff0c;千古风流人物。故垒西边&#xff0c;人道是&#xff0c;三国周郎赤壁。乱石穿空&#xff0c;惊涛拍岸&#xff0c;卷起千堆雪。江山如画&#xff0c;一时多少豪杰。 遥想公瑾当年&#xff0c;小乔初嫁了&#xf…

机器自动翻译古文拼音 - 十大宋词 - 扬州慢 淮左名都 姜夔

扬州慢淮左名都 南宋姜夔 淮左名都&#xff0c;竹西佳处&#xff0c;解鞍少驻初程。 过春风十里&#xff0c;尽荠麦青青。 自胡马窥江去后&#xff0c;废池乔木&#xff0c;犹厌言兵。 将黄昏&#xff0c;清角吹寒&#xff0c;都在空城。 杜郎俊赏&#xff0c;算而今重到须惊…

springmvc 整合 thymeleaf 模板引擎

springmvc 整合 thymeleaf 模板引擎 第一步&#xff1a;导入 web.xml 文件 -> <?xml version"1.0" encoding"UTF-8"?> <web-app xmlns"http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi"http://www.w3.org/2001/XMLSchema-ins…

代码随想录算法训练营第31天 二叉树 java :39. 组合总和 40.组合总和II 131.分割回文串

文章目录LeetCode 39. 组合总和本题题解思路LeetCode 40.组合总和II本题题解思路LeetCode 131.分割回文串本题题解思路那么在代码里什么是切割线呢&#xff1f;那么在代码里什么是切割线呢&#xff1f;总结LeetCode 39. 组合总和 本题题解 思路 根据递归三部曲来分析 递归函…

网站如何进行整站优化?

如果要做优化或者选择性优化&#xff0c;一定要区分关键词优化和全站优化&#xff0c;米贸搜整理如下&#xff0c;希望可以帮助到你&#xff1a;一、全站优化的概念:1.一般认为&#xff0c;全站点优化是指通过SEO技术&#xff0c;使其网站成为搜索引擎中的权威站点。当达到效果…

面试汇总-多线程

目录 1、Thread.sleep(0)的作用 2、Synchronized 2.1、特性 2.2、说一说自己对于 synchronized 关键字的了解&#xff1a; 2.3、synchronized关键字的底层原理(JVM如何实现重量级锁) 2.4、Jdk1.6之后对synchronized做的优化 2.4.1、锁粗化 2.4.2、锁消除 2.5、线程池的…

Scala运算符

算术运算符 关系运算符 Java 和 Scala 中关于“”的区别 逻辑运算符 赋值运算符 位运算符 Scala运算符总结 算术运算符 基本与Java一致 对于除号“/”&#xff0c;它的整数除和小数除是有区别的&#xff1a;整数之间做除法时&#xff0c;只保留整 数部分而舍弃小数部分…

JDBC学习笔记(黑马)

目录 一、JDBC快速入门 二、JDBC API详解 &#xff08;一&#xff09;DriverManager &#xff08;二&#xff09;Connection &#xff08;三&#xff09;Statement &#xff08;四&#xff09;ResultSet &#xff08;五&#xff09;PreparedStatement 三、数据库连接池…

前端实现水印的两种方式(DOM和Canvas)

&#x1f431; 个人主页&#xff1a;不叫猫先生 &#x1f64b;‍♂️ 作者简介&#xff1a;前端领域新星创作者、阿里云专家博主&#xff0c;专注于前端各领域技术&#xff0c;共同学习共同进步&#xff0c;一起加油呀&#xff01; &#x1f4ab;系列专栏&#xff1a;vue3从入门…

Python 海象运算符

✅作者简介&#xff1a;人工智能专业本科在读&#xff0c;喜欢计算机与编程&#xff0c;写博客记录自己的学习历程。 &#x1f34e;个人网站&#xff1a;小嗷犬的技术小站 &#x1f34a;个人信条&#xff1a;为天地立心&#xff0c;为生民立命&#xff0c;为往圣继绝学&#xf…

图纸版本混乱?BOM表管理困难?看SolidWorks PLM如何高效助力产品数据管理

“随着集团的日益壮大&#xff0c;我们越来越重视信息化系统的建设工作&#xff0c;但在研发生产的过程中我们经常会遇到图纸版本混乱、数据查找不便的问题&#xff1b;特别是在产品设计好后&#xff0c;还需要花费很多时间手动整理BOM表&#xff0c;整理期间由于数据量太大&am…

2023年,对人工智能的思考与展望

近些年来&#xff0c;人工智能的话题一次次的冲上热榜&#xff0c;而在前段时间内&#xff0c;chatgpt以及midjourney又一次冲上了热搜&#xff0c;在海内外引起广泛的讨论&#xff0c;我个人在研究了近一个多月的技术文档和文献资料后&#xff0c;也对人工智能的未来有了很多的…

STC32G 单片机通用串行通信接口及其编程

STC32G 系列单片机有4个全双工通用串行通信接口&#xff0c;串口1与串口2既有异步通信功能、又有同步通信功能&#xff0c;串口1与串口2都可进行SPI通信&#xff0c;SPI是一个全双工高速同步串行&#xff1b;通信总线串口3、串口4只有异步通信功能。本文将重点讨论其异步通信&a…

hexo个人博客搭建+butterfly主题配置(雏形版本)

前提&#xff1a; 1. 有一个属于自己的GitHub账号 2. 安装好了git 3. 安装好了node 一、安装hexo 1. 建立一个文件夹 Blog&#xff08;可以自己取名字&#xff09;&#xff0c;进入文件夹标右键打开 Git Bush Here&#xff0c;安装Hexo&#xff1a; npm install -g hexo-…

中智股份冲刺上交所上市:半年收入约87亿元,计划募资37亿元

近日&#xff0c;中智经济技术合作股份有限公司&#xff08;下称“中智股份”&#xff09;预披露招股书&#xff0c;准备在上海证券交易所主板上市&#xff0c;中信证券为其保荐机构。 本次冲刺上市&#xff0c;中智经济计划募资37.42亿元&#xff0c;将用于中智人力资源研发运…

函数的连续性和间断点——“高等数学”

各位CSDN的uu们你们好呀&#xff0c;今天小雅兰的内容是高等数学中的函数的连续性和间断点&#xff0c;好的&#xff0c;那现在就让我们进入函数的连续性和间断点的世界吧 一、函数的连续性 1.函数增量 2.连续的定义 3.单侧连续 二、例题&#xff08;函数的连续性&#xff09; …