Advertisement
JontePonte

Rearrange a picture into another (Unity C#)

Jul 18th, 2024
123
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 6.10 KB | None | 0 0
  1. using System.ComponentModel;
  2. using UnityEngine;
  3.  
  4. public class Main : MonoBehaviour
  5. {
  6.     //Based on this article: https://estebanhufstedler.com/2020/06/08/rearrange-a-picture-into-another/
  7.     public Texture2D sourceImage;
  8.     public Texture2D targetImage;
  9.  
  10.     public int segmentSize;
  11.  
  12.     public bool rotateTiles;
  13.  
  14.     public string executionTime;
  15.  
  16.     Texture2D[,,] sourceTiles;
  17.     Texture2D[,] targetTiles;
  18.     Texture2D[,] modifiedTiles;
  19.     Texture2D finishedImage;
  20.  
  21.     Color[,,][] sourceTilePixels;
  22.     Color[,][] targetTilePixels;
  23.  
  24.     int ySegments;
  25.     int xSegments;
  26.  
  27.     void Start()
  28.     {
  29.         float startTime = Time.realtimeSinceStartup;
  30.  
  31.         if (sourceImage.width != targetImage.width || sourceImage.height != targetImage.height)
  32.         {
  33.             Debug.LogError("Images must have the same dimensions!");
  34.             return;
  35.         }
  36.  
  37.         ySegments = sourceImage.height / segmentSize;
  38.         xSegments = sourceImage.width / segmentSize;
  39.  
  40.         sourceTiles = new Texture2D[xSegments, ySegments, 4];
  41.         targetTiles = new Texture2D[xSegments, ySegments];
  42.         modifiedTiles = new Texture2D[xSegments, ySegments];
  43.  
  44.         sourceTilePixels = new Color[xSegments, ySegments, 4][];
  45.         targetTilePixels = new Color[xSegments, ySegments][];
  46.  
  47.         for (int y = 0; y < ySegments; y++)
  48.         {
  49.             for (int x = 0; x < xSegments; x++)
  50.             {
  51.                 CreateTile(x, y);
  52.             }
  53.         }
  54.  
  55.         for (int y = 0; y < ySegments; y++)
  56.         {
  57.             for (int x = 0; x < xSegments; x++)
  58.             {
  59.                 MatchTileToTarget(x, y);
  60.             }
  61.         }
  62.  
  63.         finishedImage = new Texture2D(sourceImage.width, sourceImage.height);
  64.  
  65.         for (int y = 0; y < ySegments; y++)
  66.         {
  67.             for (int x = 0; x < xSegments; x++)
  68.             {
  69.                 Color[] tileColors = modifiedTiles[x, y].GetPixels();
  70.                 finishedImage.SetPixels(x * segmentSize, y * segmentSize, segmentSize, segmentSize, tileColors);
  71.             }
  72.         }
  73.  
  74.         finishedImage.Apply();
  75.         GameObject canvas = GameObject.CreatePrimitive(PrimitiveType.Quad);
  76.         canvas.transform.localScale = new Vector3(3, 4, 1);
  77.         canvas.GetComponent<MeshRenderer>().material = new Material(Shader.Find("Unlit/Texture"));
  78.         canvas.GetComponent<MeshRenderer>().material.mainTexture = finishedImage;
  79.  
  80.         executionTime = ((Time.realtimeSinceStartup - startTime) * 1000f) + "ms";
  81.     }
  82.  
  83.     void CreateTile(int x, int y)
  84.     {
  85.         Color[] sourceColors = sourceImage.GetPixels(x * segmentSize, y * segmentSize, segmentSize, segmentSize);
  86.         sourceTiles[x, y, 0] = new Texture2D(segmentSize, segmentSize);
  87.         sourceTiles[x, y, 0].SetPixels(sourceColors);
  88.         sourceTiles[x, y, 0].Apply();
  89.  
  90.         sourceTilePixels[x, y, 0] = sourceTiles[x, y, 0].GetPixels();
  91.  
  92.         //Create rotated version of tiles
  93.         for (int i = 1; i < 4; i++)
  94.         {
  95.             sourceTiles[x, y, i] = RotateTexture(sourceTiles[x, y, i - 1], true);
  96.             sourceTiles[x, y, i].Apply();
  97.             sourceTilePixels[x, y, i] = sourceTiles[x, y, i].GetPixels();
  98.         }
  99.  
  100.         targetTiles[x, y] = new Texture2D(segmentSize, segmentSize);
  101.  
  102.         Color[] targetColors = targetImage.GetPixels(x * segmentSize, y * segmentSize, segmentSize, segmentSize);
  103.  
  104.         targetTiles[x, y].SetPixels(targetColors);
  105.         targetTiles[x, y].Apply();
  106.         targetTilePixels[x, y] = targetTiles[x, y].GetPixels();
  107.     }
  108.  
  109.     void MatchTileToTarget(int xCoord, int yCoord)
  110.     {
  111.         int xOptimalCoord = 0;
  112.         int yOptimalCoord = 0;
  113.         int optimalRotation = 0;
  114.  
  115.         float minCost = float.MaxValue;
  116.  
  117.         for (int y = 0; y < ySegments; y++)
  118.         {
  119.             for (int x = 0; x < xSegments; x++)
  120.             {
  121.                 if (modifiedTiles[x, y] == null)
  122.                 {
  123.                     for (int i = 0; i < 4; i++)
  124.                     {
  125.                         float cost = CalculateCost(xCoord, yCoord, i, x, y);
  126.                         if (cost < minCost)
  127.                         {
  128.                             minCost = cost;
  129.                             xOptimalCoord = x;
  130.                             yOptimalCoord = y;
  131.                             optimalRotation = i;
  132.                         }
  133.                     }
  134.  
  135.                 }
  136.             }
  137.         }
  138.  
  139.         modifiedTiles[xOptimalCoord, yOptimalCoord] = sourceTiles[xCoord, yCoord, rotateTiles ? optimalRotation : 0];
  140.     }
  141.  
  142.     float CalculateCost(int x1, int y1, int rot, int x2, int y2)
  143.     {
  144.         Color[] pixels1 = sourceTilePixels[x1, y1, rot];
  145.         Color[] pixels2 = targetTilePixels[x2, y2];
  146.  
  147.         float totalDiff = 0;
  148.  
  149.         for (int i = 0; i < pixels1.Length; i++)
  150.         {
  151.             float r1 = pixels1[i].r;
  152.             float g1 = pixels1[i].g;
  153.             float b1 = pixels1[i].b;
  154.  
  155.             float r2 = pixels2[i].r;
  156.             float g2 = pixels2[i].g;
  157.             float b2 = pixels2[i].b;
  158.  
  159.             float redDiff = (r1 - r2) * (r1 - r2);
  160.             float greenDiff = (g1 - g2) * (g1 - g2);
  161.             float blueDiff = (b1 - b2) * (b1 - b2);
  162.  
  163.             totalDiff += redDiff + greenDiff + blueDiff;
  164.         }
  165.         return totalDiff;
  166.     }
  167.  
  168.     Texture2D RotateTexture(Texture2D originalTexture, bool clockwise)
  169.     {
  170.         Color32[] original = originalTexture.GetPixels32();
  171.         Color32[] rotated = new Color32[original.Length];
  172.         int w = originalTexture.width;
  173.         int h = originalTexture.height;
  174.  
  175.         int iRotated, iOriginal;
  176.  
  177.         for (int j = 0; j < h; ++j)
  178.         {
  179.             for (int i = 0; i < w; ++i)
  180.             {
  181.                 iRotated = (i + 1) * h - j - 1;
  182.                 iOriginal = clockwise ? original.Length - 1 - (j * w + i) : j * w + i;
  183.                 rotated[iRotated] = original[iOriginal];
  184.             }
  185.         }
  186.  
  187.         Texture2D rotatedTexture = new Texture2D(h, w);
  188.         rotatedTexture.SetPixels32(rotated);
  189.         rotatedTexture.Apply();
  190.         return rotatedTexture;
  191.     }
  192. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement