使用“VNImageHomographAlignmentObservation”类合并图像

2023-12-14

我正在尝试使用合并两个图像VNImageHomographicAlignmentObservation,我目前得到的 3d 矩阵如下所示:

simd_float3x3([ [0.99229, -0.00451023, -4.32607e-07)],  
                [0.00431724,0.993118, 2.38839e-07)],   
                [-72.2425, -67.9966, 0.999288)]], )

但我不知道如何使用这些值合并成一张图像。似乎没有任何文档说明这些值的含义。我在这里找到了一些关于变换矩阵的信息:使用矩阵.

但到目前为止,没有其他任何东西可以帮助我......有什么建议吗?

我的代码:

func setup() {

    let floatingImage = UIImage(named:"DJI_0333")!
    let referenceImage = UIImage(named: "DJI_0327")!

    let request = VNHomographicImageRegistrationRequest(targetedCGImage: floatingImage.cgImage!, options: [:])

    let handler = VNSequenceRequestHandler()
    try! handler.perform([request], on: referenceImage.cgImage!)

    if let results = request.results as? [VNImageHomographicAlignmentObservation] {
        print("Perspective warp found: \(results.count)")
        results.forEach { observation in
        // A matrix with 3 rows and 3 columns.                         
        let matrix = observation.warpTransform
        print(matrix) }
    }
}

这个单应性矩阵H描述如何将一个图像投影到另一图像的图像平面上。要将每个像素变换到其投影位置,您可以计算其投影位置x' = H * x using 齐次坐标(基本上采用 2D 图像坐标,添加 1.0 作为第三个分量,应用矩阵H,然后除以结果的第三个分量返回二维)。

对每个像素执行此操作的最有效方法是使用以下命令在均匀空间中编写此矩阵乘法核心图像. 核心图像提供多种着色器内核类型:CIColorKernel, CIWarpKernel and CIKernel。对于这个任务,我们只想变换每个像素的位置,所以CIWarpKernel就是你所需要的。使用核心图像着色语言,如下所示:

import CoreImage
let warpKernel = CIWarpKernel(source:
    """
    kernel vec2 warp(mat3 homography)
    {
        vec3 homogen_in = vec3(destCoord().x, destCoord().y, 1.0); // create homogeneous coord
        vec3 homogen_out = homography * homogen_in; // transform by homography
        return homogen_out.xy / homogen_out.z; // back to normal 2D coordinate
    }
    """
)

请注意,着色器需要一个mat3 called homography,这相当于着色语言simd_float3x3 matrix H。调用着色器时,矩阵应存储在 CIVector 中,要对其进行转换,请使用:

let (col0, col1, col2) = yourHomography.columns
let homographyCIVector = CIVector(values:[CGFloat(col0.x), CGFloat(col0.y), CGFloat(col0.z),
                                             CGFloat(col1.x), CGFloat(col1.y), CGFloat(col1.z),
                                             CGFloat(col2.x), CGFloat(col2.y), CGFloat(col2.z)], count: 9)

当您应用CIWarpKernel对于图像,你必须告诉核心图像输出应该有多大。要合并扭曲图像和参考图像,输出应该足够大以覆盖整个投影and原始图像。我们可以通过将单应性应用到图像矩形的每个角来计算投影图像的大小(这次在 Swift 中,CoreImage 将此矩形称为extent):

/**
 * Convert a 2D point to a homogeneous coordinate, transform by the provided homography,
 * and convert back to a non-homogeneous 2D point.
 */
func transform(_ point:CGPoint, by homography:matrix_float3x3) -> CGPoint
{
  let inputPoint = float3(Float(point.x), Float(point.y), 1.0)
  var outputPoint = homography * inputPoint
  outputPoint /= outputPoint.z
  return CGPoint(x:CGFloat(outputPoint.x), y:CGFloat(outputPoint.y))
}

func computeExtentAfterTransforming(_ extent:CGRect, with homography:matrix_float3x3) -> CGRect
{
  let points = [transform(extent.origin, by: homography),
                transform(CGPoint(x: extent.origin.x + extent.width, y:extent.origin.y), by: homography),
                transform(CGPoint(x: extent.origin.x + extent.width, y:extent.origin.y + extent.height), by: homography),
                transform(CGPoint(x: extent.origin.x, y:extent.origin.y + extent.height), by: homography)]

  var (xmin, xmax, ymin, ymax) = (points[0].x, points[0].x, points[0].y, points[0].y)
  points.forEach { p in
    xmin = min(xmin, p.x)
    xmax = max(xmax, p.x)
    ymin = min(ymin, p.y)
    ymax = max(ymax, p.y)
  }
  let result = CGRect(x: xmin, y:ymin, width: xmax-xmin, height: ymax-ymin)
  return result
}

let warpedExtent = computeExtentAfterTransforming(ciFloatingImage.extent, with: homography.inverse)
let outputExtent = warpedExtent.union(ciFloatingImage.extent)

现在您可以创建浮动图像的扭曲版本:

let ciFloatingImage = CIImage(image: floatingImage)
let ciWarpedImage = warpKernel.apply(extent: outputExtent, roiCallback:
    {
        (index, rect) in
        return computeExtentAfterTransforming(rect, with: homography.inverse)
    },
    image: inputImage,
    arguments: [homographyCIVector])!

The roiCallback有什么可说的核心图像需要输入图像的哪一部分来计算输出的某一部分。 CoreImage 使用它来逐块地将着色器应用于图像的各个部分,以便它可以处理巨大的图像。 (看创建自定义过滤器在苹果的文档中)。一个快速的破解方法是始终return CGRect.infinite在这里,但是 CoreImage 无法执行任何块方面的魔法。

最后,创建参考图像和扭曲图像的合成图像:

let ciReferenceImage = CIImage(image: referenceImage)
let ciResultImage = ciWarpedImage.composited(over: ciReferenceImage)
let resultImage = UIImage(ciImage: ciResultImage)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用“VNImageHomographAlignmentObservation”类合并图像 的相关文章

随机推荐

  • 使用 CORS 的跨域 ajax 请求

    我正在尝试发布到我的跨域 休息服务 通过 javascript 并意识到除非我使用此规范 否则这是不可能的 http www w3 org wiki CORS Enabled 但是如何实现这一点的文档非常有限 我有几个问题 1 我用玻璃鱼
  • 如何检测由 CATransaction 触发的动画的完成情况

    我有一个 CALayer 我只需创建它并将其添加到控制器的 initWithNibName 中的视图控制器主视图的子视图中 然后 我执行以下动画 CATransaction begin CATransaction setAnimationD
  • 变量参数列表中定义的字符串长度是否有限制

    我对变量参数列表有疑问 定义为变量列表参数之一的字符字符串的长度是否有任何限制 例如 void ShowVar int a char szTypes int main ShowVar 4 Test string size 现在我的问题是 这
  • 使用 AngularFire 获取用户电子邮件地址列表

    我的 Web 应用程序使用 Firebase JS AngularFire 在应用程序中显示用户报告 仅管理员可见 如何使用 AngularFire 检索用户的电子邮件地址 查看 AngularFire API 参考 我没有看到可用的方法来
  • 我需要元素的完整 dom 节点路径

    我需要搜索 html 文档 p class content text here p 然后输出完整的节点路径 CSS或XPATH 例如 html gt body gt div class something gt table gt tr gt
  • gfortran 在 MinGW 下找不到 OpenMP 库 (omp_lib.mod)

    我正在尝试编译某人发给我的 Fortran 代码 它在我的 Linux 机器上编译得很好 现在我尝试在 Windows 上的 MinGW 下编译它 但是当我运行gfortran命令编译并链接它 它失败并出现以下错误 undumag main
  • 使用 JDBC 连接到 MS SQLServer 时出现 ClassNotFoundException

    我正在尝试使用 MS JDBC 驱动程序 Microsoft SQL Server JDBC 驱动程序 3 0 http www microsoft com download en details aspx id 21599 但是当我在 N
  • 两次事件之间的时间

    如果有一个跟踪用户某些事件的表 id user id action created at 5 1 create 2016 09 08 11 29 56 325691 6 1 clear 2016 09 08 11 30 00 08604 7
  • 正则表达式从字符串中去除纬度/经度

    有人有一个正则表达式来从字符串中去除纬度 经度吗 例如 号码 39 825 86 88333 匹配一个值 d d 对于这两个值 d d d d 如果字符串始终具有以下形式 ID 39 825 86 88333 match ID d d d
  • Spring Boot、JPA 和 Ignite

    原因 org springframework data mapping PropertyReferenceException 找不到类型为 Person 的属性保存 Entity Entity public class Person imp
  • 如何不对连续数据(INTS、FLOATS、DATETIME,...)进行标准化?

    根据我的理解 如果我错了 请纠正我 标准化 是从数据库设计中删除冗余数据的过程 然而 当我尝试学习数据库优化 调整性能时 我遇到了里克 詹姆斯先生推荐against标准化连续值 例如 INTS FLOATS DATETIME 正常化 但不要
  • 将 C++ DLL 与 VB6 结合使用

    我刚刚在 MSVC 2010 中为我的老板创建了一个 DLL 我选择了 New Win32 DLL 和 Export Symbols 选项 所以 一切都是完全标准的 新项目文件中有一些预定义的导出 一个类 它的构造函数 一个全局函数和具有虚
  • Inno Setup 脚本中的基本电子邮件验证

    我想在 Inno Setup 脚本中进行基本的字符串验证 以相对确定该字符串是电子邮件地址 我只想看到有一个 字符后跟一个 字符 并且在这些字符的两侧至少有一个字符 与此正则表达式类似的东西 object pascal 中缺少正则表达式和有
  • 最佳实践 - 只下载您需要的 CSS,还是使用缩小过程?

    在改善的背景下overall站点性能 下载和渲染速度 以下两个最佳实践之间似乎存在矛盾 仅降低正在查看的页面所需的 CSS 因为CSS规则过多导致渲染速度慢 始终缩小 CSS 并将其合并到一个文件中 因为更多的请求意味着更慢的页面加载 现在
  • 如何在 Selenium 中获得“nth-of-type”

    我正在使用 Selenium Webdriver 检查此特定段落的文本 此处以蓝色突出显示的段落 但我如何 查询 该段落呢 这就是我正在尝试的 不起作用 def test intro text self Test that intro te
  • 设置 jwplayer youtube 视频播放质量

    我正在使用 jw 播放器播放 youtube 视频 但我需要视频开始以高清 720p 播放 我使用以下代码 div div 但我收到以下错误 回调事件处
  • 基于身份列的 JPA 派生列值

    JPA 2 0 Hibernate 4 2 4 Final Spring 3 2 8 Release Mysql 5 6 对于具有自动生成主键的托管实体 E 例如 Id GeneratedValue private int id Colum
  • SAXParser '&' 连接问题

    我目前正在将 SAXParser 与 SAXParserFactory 一起使用 并且遇到了字符串在 符号处被截断的问题 例如 国家创造了我们的世界及其中的一切 变成 其中的一切 显然 我不希望这种情况发生 在 xml 输入中 字符被正确转
  • 这个类应该使用数据锁定进行多线程吗?

    我有一个包含一些数据的类 并且有很多线程使用它 class MyClass static Dictionary
  • 使用“VNImageHomographAlignmentObservation”类合并图像

    我正在尝试使用合并两个图像VNImageHomographicAlignmentObservation 我目前得到的 3d 矩阵如下所示 simd float3x3 0 99229 0 00451023 4 32607e 07 0 0043