【问题标题】:Crop an image using another Rect in Unity在 Unity 中使用另一个 Rect 裁剪图像
【发布时间】:2021-03-28 02:00:42
【问题描述】:

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

问题是我无法获得 originalImage 相对于cropArea 位置的正确像素。实际裁剪的区域相对于cropArea 的位置有一个偏移量,我无法理解。这是一张显示我的问题的图片(我使用从谷歌获取的随机图像作为 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 时都会让我头疼,它是如此的混乱和反直觉。

【问题讨论】:

  • 你说的是UI.Mask吗?
  • 据我所知 UI.Mask 仅用于显示/隐藏图像的一部分。我要做的是获取由cropArea突出显示的原始图像部分并将其保存在全新的纹理中

标签: unity3d user-interface texture2d


【解决方案1】:

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

查看图片。 (有问题可以在cmets提问)

【讨论】:

  • 我昨天已经尝试过了...这个锚点和枢轴设置让我遇到了这个错误:Texture rectangle is out of bounds (504 + 100 > 512)我的层次结构和你的一样。
  • 我刚刚发现了问题,但还没有解决方案。我在 originalImage 中使用的纹理小于 originalImage 矩形大小,因为 originalImage 设置为拉伸以填充整个画布。因此,当我使用originalTexture.GetPixels 时,我实际上指的是具有 512x512 固定尺寸的纹理,而不是具有可变尺寸的 originalImage。事实上,将 originalImage 设置为固定尺寸 512x512 效果很好,因为它对您有用。我想我必须想办法将拉伸图像上的位置与纹理的像素联系起来
【解决方案2】:

好的,正如我在@obywan 回答下所写的那样,我的问题是我的 originalImage 被拉伸以填充画布,但裁剪的源不是 RawImage,而是 RawImage 的纹理,它没有得到反而被拉长了。 感谢 obywan 让我意识到我的代码实际上运行良好,并让我想到可能存在维度问题。

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

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

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;
}

这是我的更新方法,实现了 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;
    }
}

【讨论】:

    【解决方案3】:

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

    【讨论】:

    • 你说得对,谢谢。但是您应该将此作为对答案的评论发布,而不是作为答案本身!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-02-02
    • 2019-03-25
    • 2017-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-25
    相关资源
    最近更新 更多