不同屏幕分辨率 坐标_IOS Metal 做滤波时取邻近像素的坐标问题备忘

本文会介绍以下内容:

  • 如何将相机画面映射到屏幕空间
  • 做滤波器时,如何取邻近像素

<1> 相机捕获到屏幕空间

根据我的实践,相机捕获的画面如果不做任何处理,总是向左侧旋转 90 度的状态,言语太难描述,请看下图:

849fa965b85833eba33274b0b6b3e656.png

所以,我们不得不将图像旋转一下放置在画面中。

在屏幕坐标和 Metal 之间,通过设置 viewport 来连接两个坐标空间。因为在 Metal 中,所有的坐标都是 normalized 坐标,只考虑 2D 的情况,左下角是 [-1, -1] ,右上角是 [1, 1],原点位于正中间。而屏幕坐标则是原点位于左上角,正方向向右,向下。

我们需要通过 viewport 来告诉系统,屏幕上的哪块区域对应着 Metal 中的坐标空间。根据文档,viewport 使用的单位是 pixel,而不是 point,因此这里需要注意要额外的乘以屏幕的 scale 才行。

<1.1> 纹理坐标

在我们得到相机捕获的 frame 后,要将它转换成一个 Metal 体系内的 Texture,而描述 Texture 的某个位置,使用的是纹理坐标系统,我以上面的图举例,应该是这样的,纹理坐标原点位于左上角,取值范围是 [0, 1]。

a58a99f10715b144e4a6eaac887b31af.png

<1.2> 顶点坐标与纹理坐标的对应

我们需要向 metal 提供 4 个顶点来摆放我们的纹理,显然这个 4 个顶点刚好就是位于坐标空间的 4 个顶点,为了能构成三角形展示矩形纹理,需要走一个 Z 字型。

为了能够将纹理正确的贴在对应的顶点上,也需要一一做一个对应,但是这个对应就可以完全按照我们的想法来了。

2a1b91282979e7cfdd3729f7dc04caf9.png

但对于前置摄像头,我们要映射的左右方向需要镜像一下,也只需要按需求改变映射端点即可。

<2> 滤波时邻近像素

在做滤波时,比如高斯滤波或者均值滤波,我们都需要得到邻近的像素点,由于在 metal 中所有的坐标都是浮点数,怎么知道邻近的像素点坐标呢?当时的我陷入思维盲区,后来请求别人才走出盲区。

想一想,如果要知道坐标 (0.5, 0.5) 相邻右边 1 个像素的坐标是多少,只需要再考虑一下当前的分辨率就可以了。假设分辨率是 100 * 100,那么 (0.5, 0.5) 就是点 (50, 50) ,那么 (51, 50) 呢?不就是 51 / 100 吗?

所以这个问题其实还简单的。

这时遇到了另一个问题,我发现我的画面的 y 轴方向,总是有一些残影,但是 x 方向就没有,显然是我的坐标出现了一些问题。经过我的排查和尝试,找到了问题,最后在与家人散步的路上,想明白了此问题。

一开始我的代码是这样的。

int width = 1080;
int height = 1920;
float newX = (textureCoordinate.x * width + 1) / width;
float newY = (textureCoordinate.y * height + 1) / height;

后来我通过调换 width 和 height 的值解决了此问题,原来还是坐标问题。参考上面的图,虽然在屏幕上,我是想向右读取下一个像素的位置,但是在纹理坐标上,是向。而这里采样也是在纹理坐标上采样的。

所以调换顺序得以解决此问题,希望踩到的坑能帮助到大家。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值