在 Unity 中使用另一个 Rect 裁剪图像

Crop an image using another Rect in Unity

我有一个 Texture2D,应用于 RawImage,取自网络摄像头,我称之为“originalImage”。我只想在另一个称为“cropArea”的矩形位置的基础上裁剪这个 originalImage 的一个块。基本上 cropArea 是我的 originalImage 的“指南”,我希望用户将他的手放在那里,这样我就可以得到另一张手的图像。

问题是我无法获得 originalImage 相对于 cropArea 位置的正确像素。实际裁剪区域相对于 cropArea 的位置有一个我无法理解的偏移量。这是一张显示我的问题的图片(我使用从 google 拍摄的随机图像作为 originalImage Texuter2D 而不是我的网络摄像头)

Crop Issue Screenshot

我的层次结构中有 cropArea 作为 originalImage 的子项,下面是我截取上面的屏幕截图时它们在我的检查器上的设置方式。

Images in Inspector

这是我的代码(这是我为重现我的问题而编写的代码,因此函数中没有涉及其他代码):

[SerializeField] private RawImage originalImage;
[SerializeField] private RawImage cropArea;
[SerializeField] private RawImage croppedImage;

void Update() {
    if (Input.GetKeyDown(KeyCode.S))
    {
        Texture2D croppedTexture = new Texture2D((int)cropArea.rectTransform.rect.width, (int)cropArea.rectTransform.rect.height);
        Texture2D originalTexture = (Texture2D)originalImage.mainTexture;

        croppedTexture.SetPixels(originalTexture.GetPixels((int)cropArea.rectTransform.anchoredPosition.x, (int)cropArea.rectTransform.anchoredPosition.y, (int)cropArea.rectTransform.rect.width, (int)cropArea.rectTransform.rect.height));
        croppedTexture.Apply();
        croppedImage.texture = croppedTexture;
    }
}

同样,我在我的代码中尝试了很多组合,尝试使用 localPositionrect 而不是 anchoredPosition 获取cropArea的位置,得到不同的结果,但永远不会是正确的。

我想我可能遗漏了 cropArea 的位置与从 originalImage 获取的像素之间的一些关系,但我真的无法理解它是什么。 每次我必须在运行时处理 Unity UI 这让我很头疼,它是如此的混乱和反直觉。

您的脚本运行良好。您只需要调整层次结构和支点。 我将裁剪区域放置在主图像下方,并将裁剪区域的枢轴设置为 0,0,将最小-最大锚点设置为 0,0,0,0。

查看图片。 (有问题可以在评论里提问)

好的,正如我在@obywan 的回答下写的那样,我的问题是我的原始图像被拉伸以填充 canvas,但要裁剪的源不是 RawImage,而是 RawImage 的纹理,它不会被拉伸。 我感谢 obywan 让我意识到我的代码实际上工作正常并让我认为可能存在维度问题。

我找到了一个可行的解决方案,它编写了一个调整纹理大小的函数,这样我就可以在纹理像素位置和我的眼睛在 UI 中实际看到的内容之间建立对应关系。 调整纹理大小后,我可以使用 cropArea position 从调整大小的纹理中获取像素,得到想要的结果。

所以,这是调整纹理大小的函数:

Texture2D ResizeTexture2D(Texture2D originalTexture, int resizedWidth, int resizedHeight)
{
    RenderTexture renderTexture = new RenderTexture(resizedWidth, resizedHeight, 32);
    RenderTexture.active = renderTexture;
    Graphics.Blit(originalTexture, renderTexture);
    Texture2D resizedTexture = new Texture2D(resizedWidth, resizedHeight);
    resizedTexture.ReadPixels(new Rect(0, 0, resizedWidth, resizedHeight), 0, 0);
    resizedTexture.Apply();
    return resizedTexture;
}

这是我的 Update 方法,实现了 ResizeTexture2D 函数可以正常工作:

void Update()
{
    if (Input.GetKeyDown(KeyCode.S))
    {
        Texture2D croppedTexture = new Texture2D((int)cropArea.rectTransform.rect.width, (int)cropArea.rectTransform.rect.height);
        Texture2D originalTexture = (Texture2D)originalImage.mainTexture;
        Texture2D originalTextureResized = ResizeTexture2D(originalTexture, (int)originalImage.rectTransform.rect.width, (int)originalImage.rectTransform.rect.height);
        croppedTexture.SetPixels(originalTextureResized.GetPixels((int)cropArea.rectTransform.anchoredPosition.x, (int)cropArea.rectTransform.anchoredPosition.y, (int)cropArea.rectTransform.rect.width, (int)cropArea.rectTransform.rect.height));
        croppedTexture.Apply();
        croppedImage.texture = croppedTexture;
    }
}

ResizeTexture2D 中的第 4 行应该是: Texture2D resizedTexture = new Texture2D(resizedWidth, resizedHeight);