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

问题描述 投票:0回答:5

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

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

裁剪问题截图

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

检查器中的图像

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

[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 时,这都会让我头疼,它是如此令人困惑和反直觉。

unity-game-engine user-interface texture2d
5个回答
2
投票

好的,正如我在 @obywan 答案下所写的那样,我的问题是我的原始图像被拉伸以填充画布,但裁剪的源不是 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;
}

这是我的 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;
    }
}

0
投票

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

查看图像。 (有问题可以在评论里提问) enter image description here

enter image description here

enter image description here


0
投票

ResizeTexture2D 中的第四行应该是:

Texture2D resizedTexture = new Texture2D(resizedWidth, resizedHeight);


0
投票

如果您可以将纹理装箱为精灵。然后 Sprite.Create 可以使用其 rect 参数为您处理裁剪:

void Update()
{
    if (Input.GetKeyDown(KeyCode.S))
    {
        Texture2D originalTexture = (Texture2D)originalImage.mainTexture;
        var textureCropArea = Rect.MinMaxRect(cropArea.rectTransform.anchoredPosition.x, cropArea.rectTransform.anchoredPosition.y, cropArea.rectTransform.rect.width, cropArea.rectTransform.rect.height);
        croppedImage.texture = Sprite.Create(originalTexture, textureCropArea, Vector2.one / 2, 100).texture;
    }
}

0
投票

为什么它只适用于作物区域(00)的左下锚点而不适用于中间(0.5)

    Texture2D originalTexture = originalImage.texture as Texture2D;

    if (originalTexture == null)
    {
        Debug.LogError("Original image does not have a valid Texture2D.");
        return;
    }

    Vector2 cropSize = cropArea.rect.size;
    Vector2 cropPosition = cropArea.anchoredPosition;

    // Adjust for the pivot (0.5, 0.5)
    cropPosition -= cropSize / 2;

    float widthRatio = originalTexture.width / originalImage.rectTransform.rect.width;
    float heightRatio = originalTexture.height / originalImage.rectTransform.rect.height;

    int x = Mathf.Clamp((int)(cropPosition.x * widthRatio), 0, originalTexture.width);
    int y = Mathf.Clamp((int)(cropPosition.y * heightRatio), 0, originalTexture.height);
    int width = Mathf.Clamp((int)(cropSize.x * widthRatio), 0, originalTexture.width - x);
    int height = Mathf.Clamp((int)(cropSize.y * heightRatio), 0, originalTexture.height - y);

    // Create a new texture for the cropped area
    Texture2D croppedTexture = new Texture2D(width, height);

    // Set pixels in the cropped texture
    croppedTexture.SetPixels(originalTexture.GetPixels(x, y, width, height));
    croppedTexture.Apply();

    // Update the cropped image with the new texture
    croppedImage.texture = croppedTexture;
© www.soinside.com 2019 - 2024. All rights reserved.