Code Walkthrough: Unity CV Image Gallery Package
Introduction
The Unity CV Image Gallery package provides an interactive image gallery and Scroll View
prefab to facilitate the testing of computer vision applications, such as image classification, object detection, and pose estimation in Unity.
Many of my tutorials involve using computer vision models in Unity applications. This package makes that shared functionality more modular and reusable, allowing me to streamline my tutorial content. Check out the demo video below to see this package in action.
In this post, I’ll walk through the package code, providing a solid understanding of its components and their roles.
Package Overview
The package contains two C# scripts and a Scroll View
prefab. It is designed to be easily integrated into your existing Unity projects and can be customized to suit your needs.
C# Scripts
ImageGallery.cs
: This script creates and manages the interactive image gallery. It attaches to aScroll View -> Viewport -> Content
object in a Unity scene.PackageInstaller.cs
: An Editor utility script for automatically installing a list of dependency packages defined in a JSON file.
Scroll View Prefab
The Scroll View prefab helps simplify adding an image gallery to a Unity scene. The prefab contains an ImagePrefab
object and already has the ImageGallery.cs
script attached to the Scroll View -> Viewport -> Content
object. This prefab can be easily added to your Unity project, allowing you to quickly set up an interactive image gallery for testing computer vision applications. You can customize the prefab by modifying the serialized fields in the ImageGallery.cs
script.
Dependencies
The package depends on the Unity Media Display package. This package simplifies creating and managing demo screens for displaying test images, videos, and webcam streams in Unity projects.
Code Explanation
In this section, we will delve deeper into the Unity CV Image Gallery package by examining the purpose and functionality of each C# script.
ImageGallery.cs
In this section, we will go through the ImageGallery.cs
script and explain how each part of the code works to create and manage the interactive image gallery. The complete code is available on GitHub at the link below.
Class Variables
The ImageGallery
class contains several serialized fields to configure the gallery.
[Header("Scene")]
[Tooltip("The screen GameObject where the selected image will be displayed")]
[SerializeField] private GameObject screenObject;
[Tooltip("The camera GameObject used to display the selected image")]
[SerializeField] private GameObject cameraObject;
[Tooltip("The content panel GameObject where the image gallery is located")]
[SerializeField] private GameObject contentPanel;
[Tooltip("The image prefab used to create each image in the gallery")]
[SerializeField] private GameObject imagePrefab;
[Tooltip("A list of sprites to populate the image gallery.")]
[SerializeField] private List<Sprite> imageSprites;
[Tooltip(" The spacing between images in the gallery.")]
[SerializeField] private float spacing = 5f;
[Tooltip("The specified width for each image in the gallery.")]
[SerializeField] private float specifiedWidth = 100f;
Start
Start() runs when the script first executes. It calls several methods to initialize the gallery.
private void Start()
{
// Configures the content panel with a VerticalLayoutGroup component.
SetupContentPanel();
// Populates the gallery with images using the provided sprites.
PopulateImageGallery();
// Adjusts the content panel height by summing the vertical dimensions of all gallery images and spacing.
AdjustContentHeight();
// Assigns click events to the images in the gallery to update the screen texture.
AssignButtonClickEvents();
}
SetupContentPanel
This method sets up the content panel with a VerticalLayoutGroup
component. It configures the component’s properties, such as spacing
, childAlignment
, and childControlHeight
, to arrange the images in the gallery with proper spacing and alignment.
/// <summary>
/// Set up the content panel with a VerticalLayoutGroup component.
/// </summary>
private void SetupContentPanel()
{
= contentPanel.AddComponent<VerticalLayoutGroup>();
VerticalLayoutGroup verticalLayoutGroup .spacing = spacing;
verticalLayoutGroup.childAlignment = TextAnchor.UpperCenter;
verticalLayoutGroup.childControlHeight = false;
verticalLayoutGroup.childControlWidth = false;
verticalLayoutGroup.childForceExpandHeight = false;
verticalLayoutGroup.childForceExpandWidth = false;
verticalLayoutGroup}
PopulateImageGallery
This method populates the image gallery with the sprites in the imageSprites
list.
/// <summary>
/// Populate the image gallery with the sprites provided in imageSprites.
/// </summary>
private void PopulateImageGallery()
{
foreach (Sprite sprite in imageSprites)
{
// Instantiates a new GameObject using the imagePrefab
= Instantiate(imagePrefab, contentPanel.transform);
GameObject newImageObject = newImageObject.GetComponent<Image>();
Image newImage .SetActive(true);
newImageObject// Assign the curent sprite
.sprite = sprite;
newImage// Preserves the aspect ratio
.preserveAspect = true;
newImage// Use the sprite's name for easier identification
.name = sprite.name;
newImageObject
// Adjust the image size based on the specified width
= newImageObject.GetComponent<RectTransform>();
RectTransform rectTransform float aspectRatio = sprite.rect.height / sprite.rect.width;
.sizeDelta = new Vector2(specifiedWidth, specifiedWidth * aspectRatio);
rectTransform}
}
AdjustContentHeight
This method adjusts the content panel’s height based on the total vertical size of the images and spacing.
/// <summary>
/// Adjust the content panel height based on the total height of the images and spacing.
/// </summary>
private void AdjustContentHeight()
{
= contentPanel.GetComponent<RectTransform>();
RectTransform contentPanelRectTransform float totalHeight = 0f;
// Calculate the total height of all the images in the gallery
for (int i = 0; i < contentPanelRectTransform.childCount; i++)
{
= contentPanelRectTransform.GetChild(i).GetComponent<RectTransform>();
RectTransform childRect += childRect.sizeDelta.y;
totalHeight }
// Add the spacing between the images to the total height
+= spacing * (contentPanelRectTransform.childCount - 1);
totalHeight // Updates the content panel to accommodate the total height
.sizeDelta = new Vector2(contentPanelRectTransform.sizeDelta.x, totalHeight);
contentPanelRectTransform}
PackageInstaller.cs
In this section, we will go through the PackageInstaller.cs
script and explain how each part of the code works to install the required packages. The complete code is available on GitHub at the link below.
Serializable Classes
The script defines two serializable classes to hold package data.
// Serializable class to hold package data
[System.Serializable]
public class PackageData
{
public string packageName;
public string packageUrl;
}
// Serializable class to hold a list of PackageData objects
[System.Serializable]
public class PackageList
{
public List<PackageData> packages;
}
These classes are for deserializing the JSON file containing the list of packages to install.
PackageInstaller Class Variables
The PackageInstaller class contains several private static fields.
// Stores the AddRequest object for the current package to install.
private static AddRequest addRequest;
// A list of PackageData objects to install.
private static List<PackageData> packagesToInstall;
// The index of the current package to install.
private static int currentPackageIndex;
// GUID of the JSON file containing the list of packages to install
private const string PackagesJSONGUID = "f0b282a4fbb4473584f52e3fd0ab3087";
InstallDependencies
The InstallDependencies()
method executes when Unity loads without action from the user. It reads the package JSON file and calls the InstallNextPackage()
method to install the packages.
// Method called on load to install packages from the JSON file
[InitializeOnLoadMethod]
public static void InstallDependencies()
{
// Read the package JSON file
= ReadPackageJson().packages;
packagesToInstall // Initialize the current package index
= 0;
currentPackageIndex // Start installing the packages
InstallNextPackage();
}
InstallNextPackage
This method installs the next package in the list.
// Method to install the next package in the list
private static void InstallNextPackage()
{
// Iterate through package list
if (currentPackageIndex < packagesToInstall.Count)
{
= packagesToInstall[currentPackageIndex];
PackageData packageData
// Check if the package is already installed
if (!IsPackageInstalled(packageData.packageName))
{
// Attempt to install package
= Client.Add(packageData.packageUrl);
addRequest .update += PackageInstallationProgress;
EditorApplication}
else
{
// Increment the current package index
++;
currentPackageIndex// Recursively call InstallNextPackage
InstallNextPackage();
}
}
}
PackageInstallationProgress
This method monitors the progress of the package installation and logs whether it was successful. It then triggers the installation process for the next package in the list.
// Method to monitor the progress of package installation
private static void PackageInstallationProgress()
{
if (addRequest.IsCompleted)
{
// Log whether the package installation was successful
if (addRequest.Status == StatusCode.Success)
{
.Debug.Log($"Successfully installed: {addRequest.Result.packageId}");
UnityEngine}
else if (addRequest.Status >= StatusCode.Failure)
{
.Debug.LogError($"Failed to install package: {addRequest.Error.message}");
UnityEngine}
// Unregister the method from the EditorApplication.update
.update -= PackageInstallationProgress;
EditorApplication// Increment the current package index
++;
currentPackageIndex// Install the next package in the list
InstallNextPackage();
}
}
IsPackageInstalled
This method verifies whether a package has already been installed or not.
// Method to check if a package is already installed
private static bool IsPackageInstalled(string packageName)
{
// List the installed packages
var listRequest = Client.List(true, false);
while (!listRequest.IsCompleted) { }
if (listRequest.Status == StatusCode.Success)
{
// Check if the package is already installed
return listRequest.Result.Any(package => package.name == packageName);
}
else
{
.Debug.LogError($"Failed to list packages: {listRequest.Error.message}");
UnityEngine}
return false;
}
ReadPackageJson
This method reads the JSON file containing the list of packages to install and returns a PackageList
object.
// Method to read the JSON file and return a PackageList object
private static PackageList ReadPackageJson()
{
// Convert the PackagesJSONGUID to an asset path
string assetPath = AssetDatabase.GUIDToAssetPath(PackagesJSONGUID);
// Read the JSON file content as a string
string jsonString = File.ReadAllText(assetPath);
// Deserialize the JSON string into a PackageList object
return JsonUtility.FromJson<PackageList>(jsonString);
}
Conclusion
This post provided an in-depth walkthrough of the code for the Unity CV Image Gallery package. The package helps facilitate testing computer vision applications in Unity projects by providing an interactive image gallery.
You can continue to explore the package by going to its GitHub repository linked below, where you will also find instructions for installing it using the Unity Package Manager.
- GitHub Repository: unity-cv-image-gallery
You can find the code for the demo project shown in the video at the beginning of this post linked below, along with links for other demo projects that use the Unity CV Image Gallery package.
- Unity Media Display Demo: A simple demo project demonstrating how to use
the unity-media-display
andunity-cv-image-gallery
packages in Unity. - Barracuda Image Classification Demo: A simple Unity project demonstrating how to perform image classification with the
barracuda-inference-image-classification
package. - Barracuda Inference PoseNet Demo: A simple Unity project demonstrating how to perform 2D human pose estimation with the
barracuda-inference-posenet
package. - Barracuda Inference YOLOX Demo: A simple Unity project demonstrating how to perform object detection with the
barracuda-inference-yolox
package.
- I’m Christian Mills, a deep learning consultant specializing in computer vision and practical AI implementations.
- I help clients leverage cutting-edge AI technologies to solve real-world problems.
- Learn more about me or reach out via email at [email protected] to discuss your project.