浏览代码

scheme based auto labeling in progress

/main
Mohsen Kamalzadeh 4 年前
当前提交
eff25511
共有 3 个文件被更改,包括 455 次插入46 次删除
  1. 340
      com.unity.perception/Editor/GroundTruth/LabelingEditor.cs
  2. 18
      com.unity.perception/Editor/GroundTruth/Uxml/Labeling_Main.uxml
  3. 143
      com.unity.perception/Runtime/GroundTruth/Labeling/Labeling.cs

340
com.unity.perception/Editor/GroundTruth/LabelingEditor.cs


using UnityEngine.UI;
using UnityEngine.UIElements;
using Button = UnityEngine.UIElements.Button;
using Object = UnityEngine.Object;
using Toggle = UnityEngine.UIElements.Toggle;
namespace UnityEditor.Perception.GroundTruth
{

private Labeling m_Labeling;
private SerializedProperty m_SerializedLabelsArray;
//private SerializedProperty m_AutoLabelingBoolProperty;
private VisualElement m_ManualLabelingContainer;
private VisualElement m_AutoLabelingContainer;
private PopupField<string> m_LabelingSchemesPopup;
private Label m_CurrentAutoLabel;
private Label m_CurrentAutoLabelTitle;
private Toggle m_AutoLabelingToggle;
private string[] m_NameSeparators = {".","-", "_"};
private string[] m_PathSeparators = {"/"};
private List<AssetLabelingScheme> m_LabelingSchemes = new List<AssetLabelingScheme>();
private void OnEnable()
{
m_LabelConfigTypes = AddToConfigWindow.FindAllSubTypes(typeof(LabelConfig<>));

//m_AutoLabelingBoolProperty = serializedObject.FindProperty(nameof(Labeling.useAutoLabeling));
m_Labeling = mySerializedObject.targetObject as Labeling;
m_UxmlPath = m_UxmlDir + "Labeling_Main.uxml";

m_SuggestLabelsListView_FromName = m_Root.Q<ListView>("suggested-labels-name-listview");
m_SuggestLabelsListView_FromPath = m_Root.Q<ListView>("suggested-labels-path-listview");
m_LabelConfigsScrollView = m_Root.Q<ScrollView>("label-configs-scrollview");
m_AddButton = m_Root.Q<Button>("add-label");
m_CurrentAutoLabel = m_Root.Q<Label>("current-auto-label");
m_CurrentAutoLabelTitle = m_Root.Q<Label>("current-auto-label-title");
m_AutoLabelingToggle = m_Root.Q<Toggle>("auto-or-manual-toggle");
m_ManualLabelingContainer = m_Root.Q<VisualElement>("manual-labeling");
m_AutoLabelingContainer = m_Root.Q<VisualElement>("automatic-labeling");
m_AddButton = m_Root.Q<Button>("add-label");
var dropdownParent = m_Root.Q<VisualElement>("drop-down-parent");
InitializeLabelingSchemes(dropdownParent);
AssesAutoLabelingStatus();
if (serializedObject.targetObjects.Length > 1)
{

if (targetObject is Labeling labeling)
{
var serializedLabelingObject2 = new SerializedObject(labeling);
var serializedLabelArray2 = serializedLabelingObject2.FindProperty("labels");
var serializedLabelArray2 = serializedLabelingObject2.FindProperty(nameof(Labeling.labels));
serializedLabelArray2.InsertArrayElementAtIndex(serializedLabelArray2.arraySize);
serializedLabelArray2.GetArrayElementAtIndex(serializedLabelArray2.arraySize-1).stringValue = newLabel;
serializedLabelingObject2.ApplyModifiedProperties();

}
RefreshData();
RefreshManualLabelingData();
m_AutoLabelingToggle.RegisterValueChangedCallback<bool>(evt =>
{
AutoLabelToggleChanged();
});
}
void UpdateActivenessOfUiElements()
{
m_ManualLabelingContainer.SetEnabled(!m_AutoLabelingToggle.value);
m_AutoLabelingContainer.SetEnabled(m_AutoLabelingToggle.value);
if (serializedObject.targetObjects.Length > 1)
{
m_CurrentAutoLabelTitle.text = "Select assets individually to inspect their automatic labels.";
m_CurrentAutoLabel.style.display = DisplayStyle.None;
}
// if (m_LabelingSchemesPopup.index == 0)
// {
// m_CurrentAutoLabel.style.display = DisplayStyle.None;
//
// }
}
void InitializeLabelingSchemes(VisualElement parent)
{
//this function should be called only once during the lifecycle of the editor element
m_LabelingSchemes.Add(new AssetNameLabelingScheme());
m_LabelingSchemes.Add(new AssetFileNameLabelingScheme());
m_LabelingSchemes.Add(new CurrentOrParentsFolderNameLabelingScheme());
var descriptions = m_LabelingSchemes.Select(scheme => scheme.Description).ToList();
descriptions.Insert(0, "<Select Scheme>");
m_LabelingSchemesPopup = new PopupField<string>(descriptions, 0) {label = "Labeling Scheme"};
m_LabelingSchemesPopup.style.marginLeft = 0;
parent.Add(m_LabelingSchemesPopup);
m_LabelingSchemesPopup.RegisterValueChangedCallback<string>(evt => AssignAutomaticLabelToSelectedAssets());
}
void AutoLabelToggleChanged()
{
UpdateActivenessOfUiElements();
if (m_AutoLabelingToggle.value)
{
if (serializedObject.targetObjects.Length == 1)
{
SyncAutoLabelWithSchemeSingleTarget(true);
}
}
else
{
foreach (var targetObj in serializedObject.targetObjects)
{
var serObj = new SerializedObject(targetObj);
serObj.FindProperty(nameof(Labeling.useAutoLabeling)).boolValue = false;
var schemeName = serObj.FindProperty(nameof(Labeling.autoLabelingSchemeType)).stringValue;
if (schemeName != String.Empty)
{
//asset already had a labeling scheme before auto labeling was disabled, which means it has auto label(s) attached. these should be cleared now.
serObj.FindProperty(nameof(Labeling.labels)).ClearArray();
}
serObj.ApplyModifiedProperties();
serObj.SetIsDifferentCacheDirty();
}
}
RefreshManualLabelingData();
}
void AssignAutomaticLabelToSelectedAssets()
{
UpdateActivenessOfUiElements();
//the 0th index of this popup is "<Select Scheme>" and should not do anything
if (m_LabelingSchemesPopup.index == 0)
{
return;
}
var labelingScheme = m_LabelingSchemes[m_LabelingSchemesPopup.index - 1];
string topAssetAutoLabel = String.Empty;
foreach (var targetObj in serializedObject.targetObjects)
{
var serObj = new SerializedObject(targetObj);
serObj.FindProperty(nameof(Labeling.useAutoLabeling)).boolValue = true; //only set this flag once the user has actually chosen a scheme, otherwise, we will not touch the flag
serObj.FindProperty(nameof(Labeling.autoLabelingSchemeType)).stringValue = labelingScheme.GetType().Name;
BackupManualLabels(serObj);
var serLabelsArray = serObj.FindProperty(nameof(Labeling.labels));
serLabelsArray.ClearArray();
serLabelsArray.InsertArrayElementAtIndex(0);
var label = labelingScheme.GenerateLabel(targetObj);
serLabelsArray.GetArrayElementAtIndex(0).stringValue = label;
if (targetObj == serializedObject.targetObjects[0] && serializedObject.targetObjects.Length == 1)
{
topAssetAutoLabel = label;
}
serObj.ApplyModifiedProperties();
serObj.SetIsDifferentCacheDirty();
}
m_CurrentAutoLabel.text = topAssetAutoLabel;
}
void AssignAutomaticLabelToSerializedObject(SerializedObject serObj, string labelingSchemeName)
{
var labelingScheme = m_LabelingSchemes.Find(scheme => scheme.GetType().Name == labelingSchemeName);
AssignAutomaticLabelToSerializedObject(serObj, labelingScheme);
}
void AssignAutomaticLabelToSerializedObject(SerializedObject serObj, AssetLabelingScheme labelingScheme)
{
var serLabelsArray = serObj.FindProperty(nameof(Labeling.labels));
var label = labelingScheme.GenerateLabel(serObj.targetObject);
BackupManualLabels(serObj);
serLabelsArray.ClearArray();
serLabelsArray.InsertArrayElementAtIndex(0);
serLabelsArray.GetArrayElementAtIndex(0).stringValue = label;
serObj.ApplyModifiedProperties();
serObj.SetIsDifferentCacheDirty();
}
void BackupManualLabels(SerializedObject serObj)
{
// var serLabelsArray = serObj.FindProperty(nameof(Labeling.labels));
// var backupLabelsArray = serObj.FindProperty(nameof(Labeling.manualLabelsBackup));
// backupLabelsArray.ClearArray();
// for (int i = 0; i < serLabelsArray.arraySize; i++)
// {
// backupLabelsArray.InsertArrayElementAtIndex(i);
// backupLabelsArray.GetArrayElementAtIndex(i).stringValue =
// serLabelsArray.GetArrayElementAtIndex(i).stringValue;
// }
}
void RetrieveFromManualLabelsBackupArray(SerializedObject serObj)
{
// var serLabelsArray = serObj.FindProperty(nameof(Labeling.labels));
// var backupLabelsArray = serObj.FindProperty(nameof(Labeling.manualLabelsBackup));
// serLabelsArray.ClearArray();
// for (int i = 0; i < backupLabelsArray.arraySize; i++)
// {
// serLabelsArray.InsertArrayElementAtIndex(i);
// serLabelsArray.GetArrayElementAtIndex(i).stringValue =
// backupLabelsArray.GetArrayElementAtIndex(i).stringValue;
// }
}
void SyncAutoLabelWithSchemeSingleTarget(bool enableAutoLabeling = false)
{
var serObj = new SerializedObject(serializedObject.targetObjects[0]);
var currentLabelingSchemeName = serObj.FindProperty(nameof(Labeling.autoLabelingSchemeType)).stringValue;
if (currentLabelingSchemeName != String.Empty)
{
if (enableAutoLabeling)
{
//the useAutoLabeling flag is only turned on for an asset if a valid scheme for auto labeling has also been chosen, that is why it is deferred to here instead of immediately on toggle click
serObj.FindProperty(nameof(Labeling.useAutoLabeling)).boolValue = true;
}
AssignAutomaticLabelToSerializedObject(serObj, currentLabelingSchemeName);
var labelsArray = serObj.FindProperty(nameof(Labeling.labels));
if (labelsArray.arraySize > 0)
{
var autoLabel = labelsArray.GetArrayElementAtIndex(0).stringValue;
m_CurrentAutoLabel.text = autoLabel;
}
m_LabelingSchemesPopup.index =
m_LabelingSchemes.FindIndex(scheme => scheme.GetType().Name.ToString() == currentLabelingSchemeName) + 1;
}
else
{
}
}
void AssesAutoLabelingStatus()
{
var enabledOrNot = true;
if (serializedObject.targetObjects.Length == 1)
{
m_AutoLabelingToggle.text = "Use Automatic Labeling";
m_CurrentAutoLabel.style.display = DisplayStyle.Flex;
var serObj = new SerializedObject(serializedObject.targetObjects[0]);
var enabled = serObj.FindProperty(nameof(Labeling.useAutoLabeling)).boolValue;
SyncAutoLabelWithSchemeSingleTarget();
m_AutoLabelingToggle.value = enabled;
}
else
{
string unifiedLabelingScheme = null;
bool allAssetsUseSameLabelingScheme = true;
m_AutoLabelingToggle.text = "Use Automatic Labeling for All Selected Items";
m_CurrentAutoLabel.style.display = DisplayStyle.None;
foreach (var targetObj in serializedObject.targetObjects)
{
var serObj = new SerializedObject(targetObj);
var enabled = serObj.FindProperty(nameof(Labeling.useAutoLabeling)).boolValue;
enabledOrNot &= enabled;
// if (enabled)
// {
var schemeName = serObj.FindProperty(nameof(Labeling.autoLabelingSchemeType)).stringValue;
if (schemeName == string.Empty)
{
//if any of the selected assets does not have a labeling scheme, they can't all have the same valid scheme
allAssetsUseSameLabelingScheme = false;
}
if (allAssetsUseSameLabelingScheme)
{
if (unifiedLabelingScheme == null)
{
unifiedLabelingScheme = schemeName;
}
else if (unifiedLabelingScheme != schemeName)
{
allAssetsUseSameLabelingScheme = false;
}
}
if (targetObj == serializedObject.targetObjects[0])
{
var labelsArray = serObj.FindProperty(nameof(Labeling.labels));
if (labelsArray.arraySize > 0)
{
var autoLabelOfTopSelectedItem = labelsArray.GetArrayElementAtIndex(0).stringValue;
m_CurrentAutoLabel.text = autoLabelOfTopSelectedItem;
}
}
//}
}
m_AutoLabelingToggle.value = enabledOrNot;
if (allAssetsUseSameLabelingScheme)
{
//all selected assets are using auto labeling, all using the same scheme
m_LabelingSchemesPopup.index =
m_LabelingSchemes.FindIndex(scheme => scheme.GetType().Name.ToString() == unifiedLabelingScheme) + 1;
}
else
{
//the selected assets are all using auto labeling, but not using the same scheme
m_LabelingSchemesPopup.index = 0;
}
}
if (!enabledOrNot)
m_CurrentAutoLabel.text = String.Empty;
UpdateActivenessOfUiElements();
}
HashSet<string> CreateUnionOfAllLabels()

{
string assetName = serializedObject.targetObject.name;
m_SuggestedLabelsBasedOnName.Add(assetName);
m_SuggestedLabelsBasedOnName.AddRange(assetName.Split(m_NameSeparators, StringSplitOptions.RemoveEmptyEntries).ToList());
m_SuggestedLabelsBasedOnName.AddRange(assetName.Split(Labeling.NameSeparators, StringSplitOptions.RemoveEmptyEntries).ToList());
var prefabObject = PrefabUtility.GetCorrespondingObjectFromSource(m_Labeling.gameObject);
if (prefabObject)
string assetPath = Labeling.GetAssetOrPrefabPath(m_Labeling.gameObject);
//var prefabObject = PrefabUtility.GetCorrespondingObjectFromSource(m_Labeling.gameObject);
if (assetPath != null)
string assetPath = AssetDatabase.GetAssetPath(prefabObject);
var stringList = assetPath.Split(m_PathSeparators, StringSplitOptions.RemoveEmptyEntries).ToList();
var stringList = assetPath.Split(Labeling.PathSeparators, StringSplitOptions.RemoveEmptyEntries).ToList();
stringList.Reverse();
m_SuggestedLabelsBasedOnPath.AddRange(stringList);
}

if (targetObject == target)
continue; //we have already taken care of this one above
prefabObject = PrefabUtility.GetCorrespondingObjectFromSource(((Labeling)targetObject).gameObject);
if (prefabObject)
assetPath = Labeling.GetAssetOrPrefabPath(((Labeling)targetObject).gameObject);
//prefabObject = PrefabUtility.GetCorrespondingObjectFromSource(((Labeling)targetObject).gameObject);
if (assetPath != null)
string assetPath = AssetDatabase.GetAssetPath(prefabObject);
var stringList = assetPath.Split(m_PathSeparators, StringSplitOptions.RemoveEmptyEntries).ToList();
var stringList = assetPath.Split(Labeling.PathSeparators, StringSplitOptions.RemoveEmptyEntries).ToList();
m_SuggestedLabelsBasedOnPath = m_SuggestedLabelsBasedOnPath.Intersect(stringList).ToList();
}
}

}
public void RefreshData()
public void RefreshManualLabelingData()
m_SerializedLabelsArray = mySerializedObject.FindProperty("labels");
m_SerializedLabelsArray = mySerializedObject.FindProperty(nameof(Labeling.labels));
RefreshCommonLabels();
RefreshSuggestedLabelLists();
SetupSuggestedLabelsListViews();

m_CurrentLabelsListView.itemsSource = m_CommonLabels;
m_CurrentLabelsListView.selectionType = SelectionType.None;
// #if UNITY_2020_1_OR_NEWER
// m_CurrentLabelsListView.selectionType = SelectionType.Single;
// m_CurrentLabelsListView.reorderable = true;
// m_CurrentLabelsListView.RegisterCallback<DragPerformEvent>(evt =>
// {
//
// });
// #endif
}
void SetupSuggestedLabelsListViews()

}
class AddedLabelEditor : VisualElement
internal class AddedLabelEditor : VisualElement
{
private string m_UxmlDir = "Packages/com.unity.perception/Editor/GroundTruth/Uxml/";
private string m_UxmlPath;

//The editor.CommonLabels.IndexOf(cEvent.newValue) != m_IndexInList check is for this purpose.
Debug.LogError("A label with the string " + cEvent.newValue + " has already been added to selected objects.");
editor.RefreshData();
editor.RefreshManualLabelingData();
return;
}

var serializedLabelingObject2 = new SerializedObject(labeling);
var serializedLabelArray2 = serializedLabelingObject2.FindProperty("labels");
var serializedLabelArray2 = serializedLabelingObject2.FindProperty(nameof(Labeling.labels));
serializedLabelArray2.GetArrayElementAtIndex(indexToModifyInTargetLabelList).stringValue = cEvent.newValue;
shouldRefresh = shouldRefresh || serializedLabelArray2.serializedObject.hasModifiedProperties;
serializedLabelingObject2.ApplyModifiedProperties();

//the value change event is called even when the listview recycles its child elements for re-use during scrolling, therefore, we should check to make sure there are modified properties, otherwise we would be doing the refresh for no reason (reduces scrolling performance)
if (shouldRefresh)
editor.RefreshData();
editor.RefreshManualLabelingData();
});
m_AddToConfigButton.clicked += () =>

}
}
editor.serializedObject.SetIsDifferentCacheDirty();
editor.RefreshData();
editor.RefreshManualLabelingData();
}
};
}

}
}
class SuggestedLabelElement : VisualElement
internal class SuggestedLabelElement : VisualElement
{
private string m_UxmlDir = "Packages/com.unity.perception/Editor/GroundTruth/Uxml/";
private string m_UxmlPath;

editor.serializedObject.SetIsDifferentCacheDirty();
}
}
editor.RefreshData();
editor.RefreshManualLabelingData();
class LabelConfigElement : VisualElement
internal class LabelConfigElement : VisualElement
{
private string m_UxmlDir = "Packages/com.unity.perception/Editor/GroundTruth/Uxml/";
private string m_UxmlPath;

}
}
}
}
#endif

18
com.unity.perception/Editor/GroundTruth/Uxml/Labeling_Main.uxml


<UXML xmlns="UnityEngine.UIElements">
<UXML xmlns="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements">
<VisualElement name="added-labels" class="inner-container" style="margin-top:0px">
<Toggle name = "auto-or-manual-toggle" text="Use Automatic Labeling" style="margin-top: 5px"/>
<VisualElement name="automatic-labeling" class="inner-container">
<VisualElement name = "drop-down-parent"/>
<VisualElement style="flex-direction:row; flex-shrink:1; width:auto">
<Label name ="current-auto-label-title" text="Automatic Label:"/>
<Label name ="current-auto-label" style="-unity-font-style: bold; margin-left: 54px;"/>
</VisualElement>
</VisualElement>
<VisualElement name="manual-labeling" class="inner-container" style="">
</VisualElement>
<VisualElement name="add-more-labels" class="inner-container">
<Label text="Add Labels" class="title-label"/>
<!--</VisualElement>
<VisualElement name="add-more-labels" class="inner-container"> -->
<Label text="Add Labels" class="title-label" style = "margin-top:10px"/>
<VisualElement name="from-label-configs" class="inner-container depth2">
<Label text="From Existing Label Configs" class="title-label"/>
<VisualElement name="add-from-label-configs" style="padding-top: 10px;">

143
com.unity.perception/Runtime/GroundTruth/Labeling/Labeling.cs


using System;
using System.Collections.Generic;
using System.Linq;
using Unity.Entities;
using UnityEditor;
using UnityEngine;

/// </summary>
public class Labeling : MonoBehaviour
{
public static readonly string[] NameSeparators = {".", "-", "_"};
public static readonly string[] PathSeparators = {"/"};
[FormerlySerializedAs("classes")]
public List<string> labels = new List<string>();
[FormerlySerializedAs("classes")] public List<string> labels = new List<string>();
// /// <summary>
// /// A list for backing up the asset's manually added labels, so that if the user switches to auto labeling and back, the previously added labels can be revived
// /// </summary>
// public List<string> manualLabelsBackup = new List<string>();
/// <summary>
/// Whether this labeling component is currently using an automatic labeling scheme. When this is enabled, the asset can have only one label (the automatic one) and the user cannot add more labels.
/// </summary>
public bool useAutoLabeling = false;
/// <summary>
/// The specific subtype of AssetLabelingScheme that this component is using, if useAutoLabeling is enabled.
/// </summary>
public string autoLabelingSchemeType = String.Empty;
/// <summary>
/// The unique id of this labeling component instance

{
this.instanceId = instanceId;
}
void Awake()
{
m_Entity = World.DefaultGameObjectInjectionWorld.EntityManager.CreateEntity();

void Reset()
{
labels.Clear();
labels.Add(gameObject.name);
useAutoLabeling = false;
autoLabelingSchemeType = String.Empty;
#if UNITY_EDITOR
EditorUtility.SetDirty(gameObject);
#endif

/// </summary>
public void RefreshLabeling()
{
World.DefaultGameObjectInjectionWorld.GetOrCreateSystem<GroundTruthLabelSetupSystem>().RefreshLabeling(m_Entity);
World.DefaultGameObjectInjectionWorld.GetOrCreateSystem<GroundTruthLabelSetupSystem>()
.RefreshLabeling(m_Entity);
}
public static string GetAssetOrPrefabPath(Object gObj)
{
string assetPath = AssetDatabase.GetAssetPath(gObj);
if (assetPath == String.Empty)
{
//this indicates that gObj is a scene object and not a prefab directly selected from the Project tab
var prefabObject = PrefabUtility.GetCorrespondingObjectFromSource(gObj);
if (prefabObject)
{
assetPath = AssetDatabase.GetAssetPath(prefabObject);
}
}
return assetPath;
}
}
public abstract class AssetLabelingScheme
{
protected Object m_TargetAsset;
//public abstract string Title { get; protected set; }
public abstract string Description { get; protected set; }
public abstract string GenerateLabel(Object asset);
public abstract bool IsCompatibleWithAsset(Object asset);
}
public class AssetNameLabelingScheme : AssetLabelingScheme
{
// public override string Title
// {
// get => "Use Asset Name";
// protected set { }
// }
public override string Description
{
get => "Use asset name";
protected set { }
}
public override bool IsCompatibleWithAsset(Object asset)
{
return true;
}
public override string GenerateLabel(Object asset)
{
return asset.name;
}
}
public class AssetFileNameLabelingScheme : AssetLabelingScheme
{
// public override string Title
// {
// get => "Use File Name with Extension";
// protected set { }
// }
public override string Description
{
//get => "Uses the full file name of the asset, including the extension.";
get => "Use file name with extension";
protected set { }
}
public override bool IsCompatibleWithAsset(Object asset)
{
string assetPath = Labeling.GetAssetOrPrefabPath(asset);
return assetPath != null;
}
public override string GenerateLabel(Object asset)
{
string assetPath = Labeling.GetAssetOrPrefabPath(asset);
var stringList = assetPath?.Split(Labeling.PathSeparators, StringSplitOptions.RemoveEmptyEntries)
.ToList();
return stringList?.Last();
}
}
public class CurrentOrParentsFolderNameLabelingScheme : AssetLabelingScheme
{
// public override string Title
// {
// get => "Use folder name of asset or its ancestors";
// protected set { }
// }
public override string Description
{
get => "Use folder name of asset or its ancestors";
protected set { }
}
public override bool IsCompatibleWithAsset(Object asset)
{
string assetPath = Labeling.GetAssetOrPrefabPath(asset);
return assetPath != null;
}
public override string GenerateLabel(Object asset)
{
string assetPath = Labeling.GetAssetOrPrefabPath(asset);
var stringList = assetPath?.Split(Labeling.PathSeparators, StringSplitOptions.RemoveEmptyEntries)
.ToList();
//if stringList is not null, it always has at least two members, the file's name and the parent folder
return stringList?[stringList.Count-2];
}
}
}
正在加载...
取消
保存