2using System.Collections.Generic;
6using System.Runtime.InteropServices;
10using System.Threading.Tasks;
50 Log m_log =
new Log(
"MyCaffePythonGym");
51 Tuple<SimpleDatum, double, bool> m_state =
null;
52 List<SimpleDatum> m_rgData =
new List<SimpleDatum>();
53 double[][] m_rgrgActionDistributions =
null;
54 bool m_bNormalizeOverlay =
true;
56 Dictionary<Color, Tuple<Brush, Brush, Pen, Brush>> m_rgStyle =
new Dictionary<Color, Tuple<Brush, Brush, Pen, Brush>>();
76 foreach (KeyValuePair<Color, Tuple<Brush, Brush, Pen, Brush>> kv
in m_rgStyle)
78 kv.Value.Item1.Dispose();
79 kv.Value.Item2.Dispose();
80 kv.Value.Item3.Dispose();
81 kv.Value.Item4.Dispose();
103 m_igym = col.
Find(strGym);
105 throw new Exception(
"Could not find the gym '" + strGym +
"'!");
120 throw new Exception(
"You must call 'Initialize' first!");
122 return "MyCaffe " + m_igym.
Name;
132 m_rgrgActionDistributions = rgrg;
143 throw new Exception(
"You must call 'Initialize' first!");
145 List<int> rg =
new List<int>();
149 foreach (KeyValuePair<string, int> kv
in rgActions)
167 throw new Exception(
"You must call 'Initialize' first!");
169 List<string> rg =
new List<string>();
172 foreach (KeyValuePair<string, int> kv
in rgActions)
186 get {
return (m_state ==
null) ? true : m_state.Item3; }
194 get {
return (m_state ==
null) ? 0 : m_state.Item2; }
202 get {
return (m_state ==
null) ? null : m_state.Item1.GetData<
double>().ToList(); }
214 double[] rgData1 = (sd ==
null) ?
Data.ToArray() : sd.GetData<
double>();
215 int nChannels = (sd ==
null) ? m_state.Item1.Channels : sd.Channels;
216 int nHeight = (sd ==
null) ? m_state.Item1.Height : sd.Height;
217 int nWidth = (sd ==
null) ? m_state.Item1.Width : sd.Width;
218 List<List<List<double>>> rgrgrgData =
new List<List<List<double>>>();
220 for (
int h = 0; h < nHeight; h++)
222 List<List<double>> rgrgData =
new List<List<double>>();
224 for (
int w = 0; w < nWidth; w++)
226 List<double> rgData =
new List<double>();
232 for (
int c = 0; c < nChannels; c++)
234 int nIdx = (c * nHeight * nWidth) + (h * nWidth) + w;
235 dfSum += rgData1[nIdx];
238 rgData.Add((dfSum / nChannels) * dfScale);
242 for (
int c = 0; c < nChannels; c++)
244 int nIdx = (c * nHeight * nWidth) + (h * nWidth) + w;
245 double dfVal = rgData1[nIdx];
247 rgData.Add(dfVal * dfScale);
251 rgrgData.Add(rgData);
254 rgrgrgData.Add(rgrgData);
262 if (!bGrayscale && dfScale == 1)
265 double[] rgData = sd.GetData<
double>();
269 byte[] rgByteData =
null;
270 double[] rgRealData =
null;
272 if (bIsReal && !bGrayscale)
275 rgRealData =
new double[nCount];
281 rgByteData =
new byte[nCount];
284 for (
int h = 0; h < sd.
Height; h++)
286 for (
int w = 0; w < sd.
Width; w++)
288 int nIdx = (h * sd.
Width) + w;
291 if (rgRealData !=
null)
293 for (
int c = 0; c < sd.
Channels; c++)
295 double dfVal = rgData[nIdxSrc + c] * dfScale;
296 rgRealData[nIdxSrc + c] = dfVal;
303 for (
int c = 0; c < sd.
Channels; c++)
305 dfSum += rgData[nIdxSrc + c];
308 double dfVal = ((dfSum / sd.
Channels) * dfScale);
315 rgByteData[nIdx] = (byte)dfVal;
322 if (rgRealData !=
null)
341 public List<List<List<double>>>
GetDataAsStacked3D(
bool bReset,
int nFrames = 4,
int nStacks = 4,
bool bGrayscale =
true,
double dfScale = 1)
343 SimpleDatum sd = preprocess(m_state.Item1, bGrayscale, dfScale);
349 for (
int i = 0; i < nFrames * nStacks; i++)
357 m_rgData.RemoveAt(0);
362 for (
int i = 0; i < nStacks; i++)
364 int nIdx = ((nStacks - i) * nFrames) - 1;
365 rgSd[i] = m_rgData[nIdx];
381 throw new Exception(
"You must call 'Initialize' first!");
383 Tuple<State, double, bool> state = m_igym.
Reset(
false, props);
385 bool bIsOpen = (m_nUiId >= 0) ?
true :
false;
386 Tuple<Bitmap, SimpleDatum> data = m_igym.
Render(bIsOpen, 512, 512,
true);
388 SimpleDatum sd = state.Item1.GetData(
false, out nDataLen);
390 if (data.Item1 !=
null || data.Item2 !=
null)
396 if (m_rgrgActionDistributions !=
null)
399 m_gymui.
Render(m_nUiId, obs);
406 sd.
Clip(nDataLen,
null, nDataLen,
null);
409 m_state =
new Tuple<SimpleDatum, double, bool>(sd, state.Item2, state.Item3);
411 return new CurrentState(m_state.Item1.GetData<
double>(), m_state.Item2, m_state.Item3);
424 throw new Exception(
"You must call 'Initialize' first!");
426 for (
int i = 0; i < nSteps-1; i++)
428 m_igym.
Step(nAction);
431 Tuple<State, double, bool> state = m_igym.
Step(nAction,
false, props);
433 bool bIsOpen = (m_nUiId >= 0) ?
true :
false;
434 Tuple<Bitmap, SimpleDatum> data = m_igym.
Render(bIsOpen, 512, 512,
true);
436 SimpleDatum sd = state.Item1.GetData(
false, out nDataLen);
438 if (data.Item1 !=
null || data.Item2 !=
null)
444 if (m_rgrgActionDistributions !=
null)
447 m_gymui.
Render(m_nUiId, obs);
454 sd.
Clip(nDataLen,
null, nDataLen,
null);
457 m_state =
new Tuple<SimpleDatum, double, bool>(sd, state.Item2, state.Item3);
459 return new CurrentState(m_state.Item1.GetData<
double>(), m_state.Item2, m_state.Item3, state.Item1);
462 private void overlay(Bitmap bmp,
double[][] rgData)
467 using (Graphics g = Graphics.FromImage(bmp))
470 int nWid = bmp.Width - (nBorder * 2);
471 int nWid1 = nWid / rgData.Length;
472 int nHt1 = (int)(bmp.Height * 0.3);
474 int nY = bmp.Height - nHt1;
476 float[] rgfMin =
new float[rgData.Length];
477 float[] rgfMax =
new float[rgData.Length];
478 float fMax = -
float.MaxValue;
479 float fMaxMax = -
float.MaxValue;
482 for (
int i = 0; i < rgData.Length; i++)
484 rgfMin[i] = (float)rgData[i].Min(p => p);
485 rgfMax[i] = (float)rgData[i].Max(p => p);
487 if (rgfMax[i] > fMax)
493 fMaxMax = Math.Max(fMax, fMaxMax);
497 m_bNormalizeOverlay =
false;
499 for (
int i = 0; i < rgData.Length; i++)
501 drawProbabilities(g, nX, nY, nWid1, nHt1, i, rgData[i], clrMap.
GetColor(i + 1), rgfMin.Min(p => p), rgfMax.Max(p => p), (i == nMaxIdx) ?
true :
false, m_bNormalizeOverlay);
507 private void drawProbabilities(Graphics g,
int nX,
int nY,
int nWid,
int nHt,
int nAction,
double[] rgProb, Color clr,
float fMin,
float fMax,
bool bMax,
bool bNormalize)
512 m_font =
new Font(
"Century Gothic", 9.0f);
514 if (!m_rgStyle.ContainsKey(clr))
516 Color clr1 = Color.FromArgb(128, clr);
517 Brush br1 =
new SolidBrush(clr1);
518 Color clr2 = Color.FromArgb(64, clr);
519 Pen pen =
new Pen(clr2, 1.0f);
520 Brush br2 =
new SolidBrush(clr2);
521 Brush brBright =
new SolidBrush(clr);
522 m_rgStyle.Add(clr,
new Tuple<Brush, Brush, Pen, Brush>(br1, br2, pen, brBright));
525 Brush brBack = m_rgStyle[clr].Item1;
526 Brush brFront = m_rgStyle[clr].Item2;
527 Brush brTop = m_rgStyle[clr].Item4;
528 Pen penLine = m_rgStyle[clr].Item3;
530 if (fMin != 0 || fMax != 0)
532 str =
"Action " + nAction.ToString() +
" (" + (fMax - fMin).ToString(
"N7") +
")";
536 str =
"Action " + nAction.ToString() +
" - No Probabilities";
539 SizeF sz = g.MeasureString(str, m_font);
541 int nY1 = (int)(nY + (nHt - sz.Height));
542 int nX1 = (int)(nX + (nWid / 2) - (sz.Width / 2));
543 g.DrawString(str, m_font, (bMax) ? brTop : brFront,
new Point(nX1, nY1));
545 if (fMin != 0 || fMax != 0)
548 float fWid = nWid / (float)rgProb.Length;
549 nHt -= (
int)sz.Height;
551 for (
int i = 0; i < rgProb.Length; i++)
553 float fProb = (float)rgProb[i];
556 fProb = (fProb - fMin) / (fMax - fMin);
558 float fHt = nHt * fProb;
559 float fHt1 = nHt - fHt;
560 RectangleF rc1 =
new RectangleF(fX, nY + fHt1, fWid, fHt);
561 g.FillRectangle(brBack, rc1);
562 g.DrawRectangle(penLine, rc1.X, rc1.Y, rc1.Width, rc1.Height);
576 throw new Exception(
"You must first Initialize the MyCaffePythonGym!");
585 public void OpenUi(
bool bStartRecording =
false)
594 m_nUiId = m_gymui.
OpenUi(
Name, m_nUiId, bStartRecording);
596 catch (Exception excpt)
598 throw new Exception(
"You need to run the MyCaffe Test Application which supports the gym user interface host.", excpt);
629 State m_gymState =
null;
643 m_rgData =
new SimpleDatum(rgData.Length, 1, 1, rgData.Select(p => (
float)p).ToArray(), 0, rgData.Length);
644 m_dfReward = dfReward;
645 m_bTerminal = bTerminal;
646 m_gymState = gymState;
654 get {
return m_rgData; }
662 get {
return m_dfReward; }
670 get {
return m_bTerminal; }
678 get {
return m_gymState; }
The ColorMapper maps a value within a number range, to a Color within a color scheme.
Color GetColor(double dfVal)
Find the color using a binary search algorithm.
The ImageData class is a helper class used to convert between Datum, other raw data,...
static Bitmap GetImage(SimpleDatum d, ColorMapper clrMap=null, List< int > rgClrOrder=null)
Converts a SimplDatum (or Datum) into an image, optionally using a ColorMapper.
The Log class provides general output in text form.
bool EnableTrace
Enables/disables the Trace. When enabled, the .Net Trace.WriteLine is called in addition to the norma...
Specifies a key-value pair of properties.
The SimpleDatum class holds a data input within host memory.
DateTime TimeStamp
Get/set the Timestamp.
object Tag
Specifies user data associated with the SimpleDatum.
int Channels
Return the number of channels of the data.
bool IsRealData
Returns whether or not the data contains real numbers or byte data.
int Boost
Get/set the boost for this data.
void Clip(int nDataLen, int? nNewChannel, int? nNewHeight, int? nNewWidth)
Clip the data length down to a smaller size and copies the clipped data.
int Width
Return the width of the data.
bool AutoLabeled
Get/set whether or not the label was auto generated.
int Index
Returns the index of the SimpleDatum.
int Height
Return the height of the data.
int Label
Return the known label of the data.
The DatasetDescriptor class describes a dataset which contains both a training data source and testin...
The GymCollection contains the available Gyms.
List< Exception > Load()
Loads the default and dynamic gyms.
IXMyCaffeGym Find(string strName)
Search for a given Gym by its name.
The MyCaffeGymUiProxy is used to interact with the MyCaffeGymUiService.
int OpenUi(string strName, int nId, bool bStartRecording=false)
Open the Gym user interface.
void Render(int nId, Observation obs)
Render the observation of the Gym.
void CloseUi(int nId)
Closes the Gym user interface.
The Observation contains data describing the Gym as it runs.
Bitmap ImageDisplay
Get/set the image to display.
The State class defines an abstract base class for the state information and gym data.
The State contains the current state of the gym.
CurrentState(double[] rgData, double dfReward, bool bTerminal, State gymState=null)
The constructor.
State GymState
Returns the GymState if provided.
SimpleDatum Data
Returns the data.
double Reward
Returns the reward.
bool Terminal
Returns whether or not the state is terminal or not.
The MyCaffePythonGym class provides a simple interface that can easily be used from within Python.
bool? IsTerminal
Returns the terminal state from the last state.
double? Reward
Returns the reward from the last state.
void CloseUi()
The CloseUi method closes the user interface if it is open.
void Dispose()
Release resources used.
void OpenUi(bool bStartRecording=false)
The OpenUi method opens the user interface to visualize the gym as it progresses.
List< List< List< double > > > GetDataAs3D(bool bGrayscale=false, double dfScale=1, SimpleDatum sd=null)
Returns the data int a 3D form compatible with CV2.
int Initialize(string strGym, string strParam)
The Initialize method loads the gym specified.
int[] Actions
Returns the action values
void SetActionDistributions(double[][] rgrg)
Set the action distribution for display.
CurrentState Reset(PropertySet props=null)
Resets the gym to its initial state.
string[] ActionNames
Returns the action names
DatasetDescriptor GetDataset(DATA_TYPE type)
Returns the dataset descriptor of the Gym.
List< List< List< double > > > GetDataAsStacked3D(bool bReset, int nFrames=4, int nStacks=4, bool bGrayscale=true, double dfScale=1)
Returns stacked data in a 3D form compatible with CV2.
MyCaffePythonGym()
The constructor.
string Name
Returns the name of the gym.
List< double >? Data
Returns the data from the last state.
CurrentState Step(int nAction, int nSteps=1, PropertySet props=null)
Steps the gym one or more steps with a given action.
void Closing()
The Closing method is a call-back method called when the gym closes.
The IXMyCaffeGym interface is used to interact with each Gym.
DatasetDescriptor GetDataset(DATA_TYPE dt, Log log=null)
Returns the dataset of the gym.
string Name
Returns the name of the gym.
Tuple< Bitmap, SimpleDatum > Render(bool bShowUi, int nWidth, int nHeight, bool bGetAction)
Render the gym on a bitmap.
Tuple< State, double, bool > Step(int nAction, bool bGetLabel=false, PropertySet extraProp=null)
Run an action on the gym.
int UiDelay
Returns the user-interface delay to use (if any).
Tuple< State, double, bool > Reset(bool bGetLabel=false, PropertySet props=null)
Resets the state of they gym.
DATA_TYPE SelectedDataType
Returns the selected data-type.
Dictionary< string, int > GetActionSpace()
Returns a dictionary containing the action space where each entry contains the action name and action...
void Initialize(Log log, PropertySet properties)
Initialize the gym using the properties in the PropertySet.
bool RequiresDisplayImage
Returns whether or not the gym requires the display image.
The IXMyCaffeGymUiCallback is used to interact with the user of the IXMyCaffeGymUiService interface.
The descriptors namespace contains all descriptor used to describe various items stored within the da...
The MyCaffe.basecode contains all generic types used throughout MyCaffe.
DATA_TYPE
Defines the gym data type.
The MyCaffe namespace contains the main body of MyCaffe code that closesly tracks the C++ Caffe open-...