Train own classifier IBM Watson Visual Recognition Unity3d - c#

I already followed the steps from installing the SDK and configuring the service credentials. The problem is I cant train my own classifier. I'm getting this error: No overload for method 'TrainClassifier' takes 5 arguments.
void Start()
{
string m_positiveExamplesPath = Application.dataPath + "/testData/cpu_positive_examples.zip";
string m_negativeExamplesPath = Application.dataPath + "/testData/negative_examples.zip";
if(!m_VisualRecognition.TrainClassifier("components", "cpu", m_positiveExamplesPath, m_negativeExamplesPath, OnTrainClassifier))
Log.Debug("ExampleVisualRecognition", "Train classifier failed!");
}
private void OnTrainClassifier(GetClassifiersPerClassifierVerbose classifier)
{
if(classifier != null)
{
Log.Debug("ExampleVisualRecognition", "Classifier is training! " + classifier);
}
else
{
Log.Debug("ExampleVisualRecognition", "Failed to train classifier!");
}
}
Here's the link of the SDK in GitHub. Thanks!

You copied that code from the example page but looks like that everything on that page is outdated. It needs to be updated by IBM.
The VisualRecognition class has 2 overloads of TrainClassifier:
public bool TrainClassifier(OnTrainClassifier callback, string classifierName, Dictionary<string, string> positiveExamples, string negativeExamplesPath = default(string), string mimeType = "application/zip", string customData = default(string))
and
public bool TrainClassifier(OnTrainClassifier callback, string classifierName, Dictionary<string, byte[]> positiveExamplesData, byte[] negativeExamplesData = null, string mimeType = "application/zip", string customData = default(string))
You have the SDK right in front of you. Next time you get an error like this, select the function, right click Go To Definition. It will show you the overload of the function then you will be able to pass the right parameter inside it.
Your code should be something like this:
private VisualRecognition m_VisualRecognition = new VisualRecognition();
void Start()
{
string m_positiveExamplesPath = Application.dataPath + "/testData/cpu_positive_examples.zip";
string m_negativeExamplesPath = Application.dataPath + "/testData/negative_examples.zip";
Dictionary<string, string> positiveExamples = new Dictionary<string, string>();
positiveExamples.Add("giraffe", m_positiveExamplesPath);
if (!m_VisualRecognition.TrainClassifier(OnTrainClassifier, "unity-test-classifier-example", positiveExamples, m_negativeExamplesPath))
Log.Debug("ExampleVisualRecognition", "Train classifier failed!");
}
private void OnTrainClassifier(GetClassifiersPerClassifierVerbose classifier, string data)
{
if (classifier != null)
{
Log.Debug("ExampleVisualRecognition", "Classifier is training! " + classifier);
}
else
{
Log.Debug("ExampleVisualRecognition", "Failed to train classifier!");
}
}
If you need any other example, don't get it from the example page. Get it from the Example folder that comes with the plugin.

Related

Reading the file only once for every method call

I am new to object-oriented programming and I am working on a small personal project with some SQL scripts.
I have a scenario where a SQL script calls a static method with a file path as input.
queries = Select Query from Table where Utils.ContainsKeyword(Query, #Path1) AND NOT Utils.ContainsKeyword(Query, #Path2);
I had initially created a static class that does the following:
public static class Utils
{
public static bool ContainsKeyword(string query, string path)
{
var isQueryInFile = false;
var stringFromFile = GetStringFromFile(path);
List<Regex>regexList = GetRegexList(stringFromFile);
if(regexList!= null)
{
isQueryInFile = regexList.Any(pattern => pattern.IsMatch(query));
}
return isQueryInFile;
}
private static string GetStringFromFile(string path)
{
var words = String.Empty;
if(!string.IsNullOrEmpty(path))
{
try
{
using (StreamReader sr = File.OpenText(path))
{
words = sr.ReadToEnd().Replace(Environment.Newline, "");
}
}
catch { return words; }
}
return words;
}
private static List<Regex> GetRegexList(string words)
{
if(string.IsNullOrEmpty(words)) { return null; }
return words.Split(',').Select(w=> new Regex(#"\b" + Regex.Escape(w) + #'\b', RegexOptions.Compiled | RegexOptions.IgnoreCase)).ToList();
}
}
My problem is that I neither want to read from the file every time the ContainsKeyword static method is called nor do I want to create a new RegexList every time. Also, I cannot change the SQL script and I have to send the path to the file as an input parameter for the method call in the SQL script since the path might change in the future.
Is there a way to make sure I only read the contents from the input path only once, store them in a string, and use the string for the match with different input queries?
To read the content only once, saving in memory will probaby be needed. Memory capacity could be an issue.
public Dictionary<string, string> FileContentCache { get; set; } // make sure that gets initialized
public string GetFileContentCache(string path)
{
if (FileContentCache == null) FileContentCache = new Dictionary<string, string>();
if (FileContentCache.ContainsKey(path))
return FileContentCache[path];
var fileData = GetStringFromFile(path);
FileContentCache.Add(path, fileData);
return fileData;
}

Programmatically setting and saving the icon associated with an imported asset

I have some auto-generated data being exported into my Unity project. To help me out I want to assign a custom icon to these assets to clearly identify them. This is of course simply possible via the editor itself, but ideally I'd like this to happen automatically on import.
To this effect I have written an AssetPostProcessor which should take care of this for me. In the example below (which applies to MonoScripts as an example but could apply to any kind of asset), all newly imported scripts will have the MyFancyIcon icon assigned to them. This update is both visible on the script assets themselves, as well as on the MonoBehaviours in the inspector.
using UnityEngine;
using UnityEditor;
using System.Reflection;
public class IconAssignmentPostProcessor : AssetPostprocessor
{
static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
{
Texture2D icon = AssetDatabase.LoadAssetAtPath<Texture2D>("Assets/Iconfolder/MyFancyIcon.png");
foreach (string asset in importedAssets)
{
MonoScript script = AssetDatabase.LoadAssetAtPath<MonoScript>(asset);
if(script != null)
{
PropertyInfo inspectorModeInfo = typeof(SerializedObject).GetProperty("inspectorMode", BindingFlags.NonPublic | BindingFlags.Instance);
SerializedObject serializedObject = new SerializedObject(script);
inspectorModeInfo.SetValue(serializedObject, InspectorMode.Debug, null);
SerializedProperty iconProperty = serializedObject.FindProperty("m_Icon");
iconProperty.objectReferenceValue = icon;
serializedObject.ApplyModifiedProperties();
serializedObject.Update();
EditorUtility.SetDirty(script);
}
}
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
}
And it works just fine, except for one problem. The updates aren't saved when closing the project and reopening it. To the best of my knowledge, either the EditorUtility.SetDirty(script); call should take care of this, or at the very least the AssetDatabase.SaveAssets(); call.
However, looking at the difference between manually assigning an icon (which works) and doing it programmatically, there is an icon field in the meta files associated with the assets which does get set when manually assigning an icon, but not in my scripted case. (In the scripted case the meta files aren't even updated)
So what gives? Do I have to do anything in particular when it's (apparently) only meta data I'm changing? Is there anything simple I'm overlooking?
Experimented with this code and concluded that this is a bug. Made contact with Unity and this is their reply:
Currently , it is a submitted bug and Our Developer Team is
investigating it. It seems that this bug seems to happen because of
AssetDatabes.SaveAssets() does not save changes.
The work around is to do this manually.
Processing and Saving Data when OnPostprocessAllAssets is called:
1.Create a Json file settings that will hold the settings if it does not exist.
2.When OnPostprocessAllAssets is called, load old Json file settings.
4.Apply fancy icon to the Asset.
5.Loop over the the loaded Json file settings and check if it contains the file from the importedAssets parameter.
If it contains the loaded file, modify that setting and save it. If it does not, add it to the List then save it.
6.Check if the asset importedAssets does not exist on the hard-drive with File.Exists. If it does not exist, remove it from the List of the loaded Json file settings then save it.
Auto re-apply the fancy icon when Unity loads:
1.Add a static constructor to the IconAssignmentPostProcessor class. This static constructor will automatically be called when Editor loads and also when OnPostprocessAllAssets is invoked.
2.When the constructor is called, create a Json file settings that will hold the settings if it does not exist.
3.Load the old Json file settings.
4.Re-apply the fancy icons by looping through the loaded Json file.
5.Check if the loaded Json file still have assets that is not on the drive. If so, remove that asset from the List then save it.
Below is what the new IconAssignmentPostProcessor script should look like:
using UnityEngine;
using UnityEditor;
using System.Reflection;
using System.IO;
using System.Collections.Generic;
using System.Text;
using System;
public class IconAssignmentPostProcessor : AssetPostprocessor
{
// Called when Editor Starts
static IconAssignmentPostProcessor()
{
prepareSettingsDir();
reloadAllFancyIcons();
}
private static string settingsPath = Application.dataPath + "/FancyIconSettings.text";
private static string fancyIconPath = "Assets/Iconfolder/MyFancyIcon.png";
private static bool firstRun = true;
static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
{
prepareSettingsDir();
//Load old settings
FancyIconSaver savedFancyIconSaver = LoadSettings();
Texture2D icon = AssetDatabase.LoadAssetAtPath<Texture2D>(fancyIconPath);
for (int j = 0; j < importedAssets.Length; j++)
{
string asset = importedAssets[j];
MonoScript script = AssetDatabase.LoadAssetAtPath<MonoScript>(asset);
if (script != null)
{
//Apply fancy Icon
ApplyIcon(script, icon);
//Process each asset
processFancyIcon(savedFancyIconSaver, fancyIconPath, asset, pathToGUID(asset));
}
}
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
public static string pathToGUID(string path)
{
return AssetDatabase.AssetPathToGUID(path);
}
public static string guidToPath(string guid)
{
return AssetDatabase.GUIDToAssetPath(guid);
}
public static void processFancyIcon(FancyIconSaver oldSettings, string fancyIconPath, string scriptPath, string scriptGUID)
{
int matchIndex = -1;
if (oldSettings == null)
{
oldSettings = new FancyIconSaver();
}
if (oldSettings.fancyIconData == null)
{
oldSettings.fancyIconData = new List<FancyIconData>();
}
FancyIconData fancyIconData = new FancyIconData();
fancyIconData.fancyIconPath = fancyIconPath;
fancyIconData.scriptPath = scriptPath;
fancyIconData.scriptGUID = scriptGUID;
//Check if this guid exist in the List already. If so, override it with the match index
if (containsGUID(oldSettings, scriptGUID, out matchIndex))
{
oldSettings.fancyIconData[matchIndex] = fancyIconData;
}
else
{
//Does not exist, add it to the existing one
oldSettings.fancyIconData.Add(fancyIconData);
}
//Save the data
SaveSettings(oldSettings);
//If asset does not exist, delete it from the json settings
for (int i = 0; i < oldSettings.fancyIconData.Count; i++)
{
if (!assetExist(scriptPath))
{
//Remove it from the List then save the modified List
oldSettings.fancyIconData.RemoveAt(i);
SaveSettings(oldSettings);
Debug.Log("Asset " + scriptPath + " no longer exist. Deleted it from JSON Settings");
continue; //Continue to the next Settings in the List
}
}
}
//Re-loads all the fancy icons
public static void reloadAllFancyIcons()
{
if (!firstRun)
{
firstRun = false;
return; //Exit if this is not first run
}
//Load old settings
FancyIconSaver savedFancyIconSaver = LoadSettings();
if (savedFancyIconSaver == null || savedFancyIconSaver.fancyIconData == null)
{
Debug.Log("No Previous Fancy Icon Settings Found!");
return;//Exit
}
//Apply Icon Changes
for (int i = 0; i < savedFancyIconSaver.fancyIconData.Count; i++)
{
string asset = savedFancyIconSaver.fancyIconData[i].scriptPath;
//If asset does not exist, delete it from the json settings
if (!assetExist(asset))
{
//Remove it from the List then save the modified List
savedFancyIconSaver.fancyIconData.RemoveAt(i);
SaveSettings(savedFancyIconSaver);
Debug.Log("Asset " + asset + " no longer exist. Deleted it from JSON Settings");
continue; //Continue to the next Settings in the List
}
string tempFancyIconPath = savedFancyIconSaver.fancyIconData[i].fancyIconPath;
Texture2D icon = AssetDatabase.LoadAssetAtPath<Texture2D>(tempFancyIconPath);
MonoScript script = AssetDatabase.LoadAssetAtPath<MonoScript>(asset);
if (script == null)
{
continue;
}
Debug.Log(asset);
ApplyIcon(script, icon);
}
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
private static void ApplyIcon(MonoScript script, Texture2D icon)
{
PropertyInfo inspectorModeInfo = typeof(SerializedObject).GetProperty("inspectorMode", BindingFlags.NonPublic | BindingFlags.Instance);
SerializedObject serializedObject = new SerializedObject(script);
inspectorModeInfo.SetValue(serializedObject, InspectorMode.Debug, null);
SerializedProperty iconProperty = serializedObject.FindProperty("m_Icon");
iconProperty.objectReferenceValue = icon;
serializedObject.ApplyModifiedProperties();
serializedObject.Update();
EditorUtility.SetDirty(script);
Debug.Log("Applied Fancy Icon to: " + script.name);
}
//Creates the Settings File if it does not exit yet
private static void prepareSettingsDir()
{
if (!File.Exists(settingsPath))
{
File.Create(settingsPath);
}
}
public static void SaveSettings(FancyIconSaver fancyIconSaver)
{
try
{
string jsonData = JsonUtility.ToJson(fancyIconSaver, true);
Debug.Log("Data: " + jsonData);
byte[] jsonByte = Encoding.ASCII.GetBytes(jsonData);
File.WriteAllBytes(settingsPath, jsonByte);
}
catch (Exception e)
{
Debug.Log("Settings not Saved: " + e.Message);
}
}
public static FancyIconSaver LoadSettings()
{
FancyIconSaver loadedData = null;
try
{
byte[] jsonByte = File.ReadAllBytes(settingsPath);
string jsonData = Encoding.ASCII.GetString(jsonByte);
loadedData = JsonUtility.FromJson<FancyIconSaver>(jsonData);
return loadedData;
}
catch (Exception e)
{
Debug.Log("No Settings Loaded: " + e.Message);
}
return loadedData;
}
public static bool containsGUID(FancyIconSaver fancyIconSaver, string guid, out int matchIndex)
{
matchIndex = -1;
if (fancyIconSaver == null || fancyIconSaver.fancyIconData == null)
{
Debug.Log("List is null");
return false;
}
for (int i = 0; i < fancyIconSaver.fancyIconData.Count; i++)
{
if (fancyIconSaver.fancyIconData[i].scriptGUID == guid)
{
matchIndex = i;
return true;
}
}
return false;
}
public static bool assetExist(string path)
{
return File.Exists(path);
}
[Serializable]
public class FancyIconSaver
{
public List<FancyIconData> fancyIconData;
}
[Serializable]
public class FancyIconData
{
public string fancyIconPath;
public string scriptPath;
public string scriptGUID;
}
}
This should hold the fancy icons when Unity is restarted.
I think you may find your answer here: http://answers.unity3d.com/questions/344153/save-game-using-scriptable-object-derived-custom-a.html
Unfortunately.

Parse input and build a Dictionary/HashMap while parsing

I am not sure if the title makes it clear what I want to do.
My input for my parser contains debug information about C source files. Some of the input looks e.g. like this:
L:C$main.c$41$1$10:C0C5
Which basically means that line 10 in the source file main.c corresponds with the memory address C0C5.
Here is an example what my AST looks like:
Which represents the input:
M:main
L:C$main.c$29$1$0:C09C
L:C$main.c$30$1$10:C0A2
M:divide
L:C$divice.c$31$1$10:C5A9
What I want are two Hash-Maps such that I can access these information quickly at runtime. But how can I now build such Hash-Maps and is it possible to do that at parsetime?
This is how I would like to use my parser:
public CDBFileParser getFileParser(String cdbFilePath)
{
Stream stream = File.OpenRead(cdbFilePath);
ANTLRInputStream inputStream = new ANTLRInputStream(stream);
CDBFileLexer lexer = new CDBFileLexer(inputStream);
CommonTokenStream tokens = new CommonTokenStream(lexer);
CDBFileParser parser = new CDBFileParser(tokens);
try
{
parser.TreeAdaptor = new CommonTreeAdaptor();
parser.parseCDBFile();
// All this works so far. Here comes the part I am looking for:
Modules[] modules = parser.getModules();
Dictionary<int, int> lineToAddress = modules[0].getLineToAddressMap();
Dictionary<int, int> addressToLine = modules[0].getAddressToLineMap();
int address = 0xC09C;
System.Out.WriteLine( "Address 0xC09C is at line " + addressToLine.get(address) + " in " + modules[0].getName() );
}
catch (Exception e)
{
printException(e);
}
return parser;
}
Expected Output:
Address 0xC09C is at line 29 in main
Can anybody help?
Best regards.
I was about to delete my question but maybe somebody else comes along to this post. I just made the transition to ANTLR4 and it really is much simpler (so far at least).
In ANTLR4 an interface (e.g. ICDBFileListener) is built for you which one can use to catch all information at parsetime:
namespace Parser
{
public class CDBFileParserListener : ICDBFileListener
{
public void ExitModule_name(CDBFileParser.Module_nameContext context)
{
Console.WriteLine("ModuleName: " + context.GetText());
// Add module to module-map and remember
// that current module is context.GetText()
}
public void ExitLine_number(CDBFileParser.Line_numberContext context)
{
Console.WriteLine("LineNumber: " + context.GetText());
// Remember line number
}
public void ExitMemory_address(CDBFileParser.Memory_addressContext context)
{
Console.WriteLine("MemoryAddress: " + context.GetText());
// Add linenumber <-> memoryaddress to maps
}
public Modules[] getModules()
{
return m_modules;
}
}
}
And this is how it can be used:
public CDBFileParser getFileParser(String cdbFilePath)
{
Stream stream = File.OpenRead(cdbFilePath);
AntlrInputStream inputStream = new AntlrInputStream(stream);
CDBFileLexer lexer = new CDBFileLexer(inputStream);
CommonTokenStream tokens = new CommonTokenStream(lexer);
CDBFileParser parser = new CDBFileParser(tokens);
try
{
CDBFileParserListener listener = new CDBFileParserListener();
parser.AddParseListener(listener);
System.Diagnostics.Debug.WriteLine(parser.parseCDBFile().ToStringTree());
Dictionary<String, Module> modules = listener.Modules;
Module main;
modules.TryGetValue("main", out main);
long line = main.getLineFromAddress(0xC09C);
Console.WriteLine("0xC09C maps to " + line + " in main.c");
}
catch (Exception e)
{
printException(e);
}
return parser;
}

How to create OneNote 2010 section

How can you create a new section in a OneNote 2010 notebook with c#? According to the API there is no method to do so. But there is a CreateNewPage Method so I wondering if there is something similiar for sections? If not, how can this be achieved except for manipulating the XML files (which is a task i'd like to avoid since I'm not experienced in it)?
Here is code snippet from my add on:
public bool AddNewSection(string SectionTitle, out string newSectionId)
{
try
{
string CurrParentId;
string CurrParentName;
string strPath;
CurrParentId = FindCurrentlyViewedSectionGroup(out CurrParentName);
if (string.IsNullOrWhiteSpace(CurrParentId) || string.IsNullOrWhiteSpace(CurrParentName))
{
CurrParentId = FindCurrentlyViewedNotebook(out CurrParentName);
if (string.IsNullOrWhiteSpace(CurrParentId) || string.IsNullOrWhiteSpace(CurrParentName))
{
newSectionId = string.Empty;
return false;
}
strPath = FindCurrentlyViewedItemPath("Notebook");
}
else
strPath = FindCurrentlyViewedItemPath("SectionGroup");
if (string.IsNullOrWhiteSpace(strPath))
{
newSectionId = string.Empty;
return false;
}
SectionTitle = SectionTitle.Replace(':', '\\');
SectionTitle = SectionTitle.Trim('\\');
strPath += "\\" + SectionTitle + ".one";
onApp.OpenHierarchy(strPath, null, out newSectionId, Microsoft.Office.Interop.OneNote.CreateFileType.cftSection);
onApp.NavigateTo(newSectionId, "", false);
}
catch
{
newSectionId = string.Empty;
return false;
}
return true;
}
Basically what I am doing here is to get the path of currently viewing Section Group or Notebook and then adding new section name to that path and then calling OpenHierarchy method. OpenHierarchy creates a new section with title provided and returns it's id.
Following is where I create a new section and Navigate to it:
onApp.OpenHierarchy(strPath, null, out newSectionId, Microsoft.Office.Interop.OneNote.CreateFileType.cftSection);
onApp.NavigateTo(newSectionId, "", false);
So can write something like:
static void CreateNewSectionMeetingsInWorkNotebook()
{
String strID;
OneNote.Application onApplication = new OneNote.Application();
onApplication.OpenHierarchy("C:\\Documents and Settings\\user\\My Documents\\OneNote Notebooks\\Work\\Meetings.one",
System.String.Empty, out strID, OneNote.CreateFileType.cftSection);
}

Parallel.ForEach Error when using WebClient

First, my disclaimer: I'm a parallel noob. I thought this would be an easy "embarrassingly parallel" problem to tackle, but it's thrown me for a loop.
I'm trying to download some photos in parallel from the web. The original photos are Hi-Res and take up quite a bit of space, so I'm going to compact them once they're downloaded.
Here's the code:
private static void DownloadPhotos(ISet<MyPhoto> photos)
{
List<MyPhoto> failed = new List<MyPhoto>();
DateTime now = DateTime.Now;
string folderDayOfYear = now.DayOfYear.ToString();
string folderYear = now.Year.ToString();
string imagesFolder = string.Format("{0}{1}\\{2}\\", ImagePath, folderYear, folderDayOfYear);
if (!Directory.Exists(imagesFolder))
{
Directory.CreateDirectory(imagesFolder);
}
Parallel.ForEach(photos, photo =>
{
if (!SavePhotoFile(photo.Url, photo.Duid + ".jpg", imagesFolder))
{
failed.Add(photo);
Console.WriteLine("adding to failed photos: {0} ", photo.Duid.ToString());
}
});
Console.WriteLine();
Console.WriteLine("failed photos count: {0}", failed.Count);
RemoveHiResPhotos(string.Format(#"{0}\{1}\{2}", ImagePath, folderYear, folderDayOfYear));
}
private static bool SavePhotoFile(string url, string fileName, string imagesFolder)
{
string fullFileName = imagesFolder + fileName;
string originalFileName = fileName.Replace(".jpg", "-original.jpg");
string fullOriginalFileName = imagesFolder + originalFileName;
if (!File.Exists(fullFileName))
{
using (WebClient webClient = new WebClient())
{
try
{
webClient.DownloadFile(url, fullOriginalFileName);
}
catch (Exception ex)
{
Console.WriteLine();
Console.WriteLine("failed to download photo: {0}", fileName);
return false;
}
}
CreateStandardResImage(fullOriginalFileName, fullOriginalFileName.Replace("-original.jpg", ".jpg"));
}
return true;
}
private static void CreateStandardResImage(string hiResFileName, string stdResFileName)
{
Image image = Image.FromFile(hiResFileName);
Image newImage = image.Resize(1024, 640);
newImage.SaveAs(hiResFileName, stdResFileName, 70, ImageFormat.Jpeg);
}
So here's where things confuse me: each of the photos hits the Catch{} block of the SavePhotoFile() method at the webClient.DownloadFile line. The error message is an exception occured during a WebClient request and the inner detail is "The process cannot access the file . . . -original.jpg because it is being used by another process."
If I wasn't confused enough by this error, I'm confused even more by what happens next. It turns out that if I just ignore the message and wait, the image will eventually download and be processed.
What's going on?
OK, so it appears in my focus on parallelism that I made a simple error: I assumed something about my data that wasn't true. Brianestey figured out the problem: Duid isn't unique. It's supposed to be unique, except for some missing code in the process to create the list.
The fix was to add this to the MyPhoto class
public override bool Equals(object obj)
{
if (obj is MyPhoto)
{
var objPhoto = obj as MyPhoto;
if (objPhoto.Duid == this.Duid)
return true;
}
return false;
}
public override int GetHashCode()
{
return this.Duid.GetHashCode();
}

Categories

Resources