Image Sampler Node Update

Hi All,

I am testing out another workflow using some hand drawings, I have a thought of using the image sampler but my skills in Visual Studio are not great.

The old ImageSamplerNode visual studio code has some updates needed. I was wondering if anyone knew where I would start looking for information on what to change. 

There are "type or namespace" errors in lines

using Bentley.GenerativeComponents.Nodes;

[Replicatable, ParentNodeScope] int ArrPtsX,

I am making a guess but would this be a UtilityNode as it doesn't produce geometry, it sort of functions like the calculator node in the sample addin?

 

Any pointers would be appreciated.

Thanks

Wayne

The script in full is:

 

// Source adapted from Ralf Lindemann's imageUVSampler
// which had been based code by Marc Hoppermann (www.21cd.org)


using System;
using System.Drawing;
using System.Collections.Generic;
//using System.Windows.Forms;
//using Bentley.Geometry;
using Bentley.GenerativeComponents;
using Bentley.GenerativeComponents.Features;
using Bentley.GenerativeComponents.GCScript.NameScopes;
using Bentley.GenerativeComponents.GeneralPurpose;
using Bentley.GenerativeComponents.GCScript;
using Bentley.GenerativeComponents.MicroStation;
using Bentley.GenerativeComponents.View;
using Bentley.Interop.MicroStationDGN;
using Bentley.GenerativeComponents.GCScript.GCTypes;
using Bentley.GenerativeComponents.GCScript.ReflectedNativeTypeSupport;
using Bentley.GenerativeComponents.Nodes;

namespace ImageSampler
{
[GCNamespace("User")] // This custom attribute specifies that, when this node type is loaded into GC, it will be put into
// the GC namespace "User". (So, within GC, this node type's full name will be "User.ImageSamplerNode".)

[NodeTypePaletteCategory("Utility")] // The NodeTypePaletteCategory attribute lets us specify where this
// Calculator node type will appear within GC's Node Types dialog.
// So, it will appear within a group named "Sample Add-In".

[NodeTypeIcon("Resources/ImageSamplerNode.png")] // The NodeTypeIcon attribute lets us specify the graphical image (icon)
// that will appear on the Calculator node type's button within GC's Node
// Types dialog.


public class ImageSampler: Feature
{
/// <summary>ImageSampler reading pixels</summary>
[Technique]
public NodeUpdateResult ReadPixels
(
NodeUpdateContext updateContext,
[Replicatable, ParentNodeScope] int ArrPtsX,
[Replicatable] int ArrPtsY,
[Replicatable] int GridH,
[Replicatable] int GridV,
string ImagePath,
[Out] ref int Width,
[Out] ref int Height,
[Out] ref int R,
[Out] ref int G,
[Out] ref int B,
[Out] ref double Grayscale
)
{
double x = ArrPtsX;
double y = ArrPtsY;
if(false == System.IO.File.Exists(ImagePath))
{
Width = 0;
Height = 0;
R = 0;
G = 0;
B = 0;
Grayscale = 0.0;
return new NodeUpdateResult.IncompleteInputs("ImagePath");
}

Bitmap myBitmap = new Bitmap(ImagePath);
Width = myBitmap.Width;
Height = myBitmap.Height;

// this logic needs review
double stepX = Width / GridH;
double stepY = Height / GridV;
double pixelPosX = stepX * x;
double pixelPosY = stepY * y;

// get pixel information
Color pixelValue = myBitmap.GetPixel(Convert.ToInt32(pixelPosX), Convert.ToInt32(pixelPosY));

R = pixelValue.R;
G = pixelValue.G;
B = pixelValue.B;

// calculate gray scale
Grayscale = (0.3 * R + 0.59 * G + 0.11 * B) / 255.0;

return NodeUpdateResult.Success;
}

}
}

  • Hello Wayne,

    I am also an absolute novice when it comes to Visual Studio. We have to take it to our development team for their comments.

    I know some of the namespaces are changed. I guess we can compare the C# Sample Solution provided here with the one provided with the present GC installation, in that way we may get an idea which namespace changed to what.

    Thanks,

    Anik

  • Anik is right, probably your best source of information is the latest version of GC's sample solution.

    Looking at your source code, I see the following two issues, which would prevent it from compiling under the latest released version:

    The namespace Bentley.GenerativeComponents.Nodes is now named Bentley.GenerativeComponents.UtilityNodes.

    The attribute ParentNodeScope is now named DgnModelProvider. But, you should just delete that attribute, anyway. Your input parameter, ArrPtsX, is just a basic 'int' type, so it would never carry any information about a parent node scope or a DGN model.

    HTH

    Answer Verified By: Wayne Dickerson 

  • Thanks Jeff,

    I suspected the namespace of UtilityNode. 

    Thanks for the tips on the ParentNodeScope.

    I had been looking at the Calculator script and trying to adapt that script as I thought it would be a similar node not generating any geometry in the file.

    What I was a bit confused about was in the Calculator script it lists

    public class Calculator: UtilityNode

    which makes sense to me as it is creating a utilitynode.

    In the imagesampler code it uses:

    public class ImageSampler: Feature

    Which is more inline with the SimpleLine example. 

    I assume it is related to this comment.

    // One of the fundamental differences between the Feature-based node architecture and the Node-based node architecture
    // is that, in the former, reflection is used to extract the technique names, the documentation, and the names and types
    // of the inputs and outputs, directly from the compiled C# class. GC provides a number of custom attributes to provide
    // more information to the that reflection process.

    I need to do some more C# work.

    Is there any Bentley Documentation on things like the attributes or namespaces used in GC?

    But for now the Image Sampler is up and running, now to make some adjustments to suit the workflow I have in mind.

    Thanks

    Wayne

  • Hi Wayne,

    Good to know that ImageSampler is working for now.
    Can you please share the modified script? 

  • Yeah sure sorry I should have posted it here:

    I ended up creating a new C# file inside the Sample Solution and the code is:

    There are still some redundant references in the top part which could be removed. I also renamed it so I could identify my updates.

    using System;
    using System.Drawing;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Bentley.GenerativeComponents;
    using Bentley.GenerativeComponents.GCScript;
    using Bentley.GenerativeComponents.GCScript.GCTypes;
    using Bentley.GenerativeComponents.GCScript.NameScopes;
    using Bentley.GenerativeComponents.GCScript.ReflectedNativeTypeSupport;
    using Bentley.GenerativeComponents.GeneralPurpose;
    using Bentley.GenerativeComponents.UtilityNodes;
    using Bentley.GenerativeComponents.View;
    using Bentley.GenerativeComponents.Features;

    namespace SampleAddIn
    {
    [GCNamespace("User")] // This custom attribute specifies that, when this node type is loaded into GC, it will be put into
    // the GC namespace "User". (So, within GC, this node type's full name will be "User.ImageSamplerNode".)

    [NodeTypePaletteCategory("Sample Add-In")] // The NodeTypePaletteCategory attribute lets us specify where this
    // Calculator node type will appear within GC's Node Types dialog.
    // So, it will appear within a group named "Sample Add-In".

    [NodeTypeIcon("Resources/ImageSamplerNode.png")] // The NodeTypeIcon attribute lets us specify the graphical image (icon)
    // that will appear on the Calculator node type's button within GC's Node
    // Types dialog.


    public class WayneImageSampler: Feature
    {
    /// <summary>ImageSampler reading pixels</summary>
    [Technique]
    public NodeUpdateResult ReadPixels
    (
    NodeUpdateContext updateContext,
    [Replicatable] int ArrPtsX,
    [Replicatable] int ArrPtsY,
    [Replicatable] int GridH,
    [Replicatable] int GridV,
    string ImagePath,
    [Out] ref int Width,
    [Out] ref int Height,
    [Out] ref int R,
    [Out] ref int G,
    [Out] ref int B,
    [Out] ref double Grayscale
    )
    {
    double x = ArrPtsX;
    double y = ArrPtsY;
    if (false == System.IO.File.Exists(ImagePath))
    {
    Width = 0;
    Height = 0;
    R = 0;
    G = 0;
    B = 0;
    Grayscale = 0.0;
    return new NodeUpdateResult.IncompleteInputs("ImagePath");
    }

    Bitmap myBitmap = new Bitmap(ImagePath);
    Width = myBitmap.Width;
    Height = myBitmap.Height;

    // this logic needs review
    double stepX = Width / GridH;
    double stepY = Height / GridV;
    double pixelPosX = stepX * x;
    double pixelPosY = stepY * y;

    // get pixel information
    Color pixelValue = myBitmap.GetPixel(Convert.ToInt32(pixelPosX), Convert.ToInt32(pixelPosY));

    R = pixelValue.R;
    G = pixelValue.G;
    B = pixelValue.B;

    // calculate gray scale
    Grayscale = (0.3 * R + 0.59 * G + 0.11 * B) / 255.0;

    return NodeUpdateResult.Success;
    }

    }
    }