Comparing Textures without using getPixels ??

Hey, I am making very very simple game but I am stuck on the following problem which happens only in certain situation

Game : A image is cut into 6 to 9 tiles(square or rectangle) using uv rect and jumbled. Then the player has to drag the correct piece on correct positon.

Problem: If all the tiles are distinct then there is no problem but if two 2 or 3 tiles are same (for example in a flag of italy, india etc) then the problem arises. Because while dividing the image in tiles I assign a position id to each tile and when the tile is dropped at correct id I permanently fix it there.But in situations when two tiles are of same colour then user might drop the other tile and it should still be correct.

Solutions tried :

  1. GetPixels function : The color array length is in lakhs and my system hangs if I try to compare pixle by pixel.
  2. Assigning multiple id manually : This worked but I want the levels to be auto generated.

Any suggestion?

Thanks,

Let me see if I have this proper… you have a few images you want to cut into pieces and then assign each piece to a random spot on the board. You want to see if where the user has put them is the original position.

My solution would be to create a class to contain each image piece and check if the users assignment of each image class instance is the same as it was when you split the image. Its dead simple for a moderately experienced coder.

There’s no reason get pixel will not work, if your system crashes because an array is a few 100k in size then then you have something wrong with your code or your system :s

Still you can always read part of the image rather than the whole image:
public Color[ ] GetPixels(int x, int y, int blockWidth, int blockHeight, int miplevel);

That said … you could always solve this by using images where no two pieces are the same (e.g. border around the flag).

Can’t you just use shaders and UV offsets for this? It doesn’t sound like you’re doing anything the CPU needs to be heavily involved in.

  1. I will try again the getPixel method.
  2. Border Around the flag. Great idea.

Thanks.

If the GetPixel perfomance is to low for you (I can imagine that totally being the case - especially when you decide to one up it a bit and use 4k-8k textures) I suggest trying to resizing the texture and comparing the resized ones.
That would probably be a lot faster then comparing hundreds of thousands of values (but you should test this of course - I never had that case before)

(user could see the full resolution texture, but in the background it works with the rescaled ones for example).

Be aware however that by resizing the image of course information is going to be lost - for images that are not just single-colored it should be accurate enough though.
If you use this on a VERY equal looking, but still not quite the same kind of image (think of a starry sky) you would probably have to up the desiredSize a bit - for simple flags 8px to 32px width/height is probably enough.

Here is what I use to resize my textures. With a bit of thinking you could probably change this up to work with parts of images too.

    /// <summary>
    /// Resizes <paramref name="textureToResize"/> to match either the width or height given in <paramref name="desiredSize"/> (depending on <paramref name="scaleByWidth"/>)
    /// </summary>
    /// <param name="textureToResize"></param>
    /// <param name="desiredSize"></param>
    /// <param name="scaleByWidth"></param>
    /// <returns>resized Texture2D</returns>
    public static Texture2D ResizeTexture(Texture2D textureToResize, int desiredSize, bool scaleByWidth = true) {
        //get the desired width and height depending on scaleByWidth
        var desiredWidth = scaleByWidth ? desiredSize : (int)(((float)desiredSize / textureToResize.height) * textureToResize.width);
        var desiredHeight = !scaleByWidth ? desiredSize : (int)(((float)desiredSize / textureToResize.width) * textureToResize.height);

        //Get a temporary RenderTexture with the desired width and height and set it's (and the original textures) filterMode to point so we use the non aliased images
        var tempRenderTexture = RenderTexture.GetTemporary(desiredWidth, desiredHeight);
        tempRenderTexture.filterMode = FilterMode.Point;
        textureToResize.filterMode = FilterMode.Point;

        //set the temporary RenderTexture as the active RenderTexture, so we can render onto it
        RenderTexture.active = tempRenderTexture;

        //Blit the texture onto the RenderTexture
        Graphics.Blit(textureToResize, tempRenderTexture);

        //Read the pixels of the rendered image onto a texture of the desired size
        var resizedTexture = new Texture2D(desiredWidth, desiredHeight);
        resizedTexture.ReadPixels(new Rect(0, 0, desiredWidth, desiredWidth), 0, 0);
        resizedTexture.Apply();

        //set the active RenderTexture to null so we can render normally again
        RenderTexture.active = null;
        return resizedTexture;
    }

Greetings
Roy

1 Like

No, they want to see if the user has created an image which matches the original. If there are tiles which are identical to each other then there are permutations where the image is correct but some tiles are not in their original positions.

If you know that the contents of so-called “identical” tiles will be exactly the same, then you could create a hash of the contents of each tile when you split them up. Tiles which are identical will have matching hashes. Then, instead of recording which tile should go in each place, you record what the hash should be and check against those.

As is, this approach would mean that tiles could be identified as not matching even if the difference is genuinely invisible to the human eye. However, it may be that you could do some kind of pre-processing on them to work around that (untested idea: convert to 8 bit colour before hashing).

That said, I agree that using GetPixels() should be fine in this case since you only have to check pairs of tiles when they’re moved, and it would give you the most direct control over what you will and won’t accept as matching.

Thanks a lot, I will give it a try.