#region usingusing System.Collections.Generic;using System.Drawing;using Emgu.CV;using Emgu.CV.CvEnum;using Emgu.CV.Structure;using VVVV.PluginInterfaces.V2;using VVVV.Utils.VMath;using System;using VVVV.Utils.VColor;#endregionnamespace VVVV.Nodes.EmguCV
{publicclass TemplateInstance : IFilterInstance
{//example of a propertyprivatebyte[] FColorAdd =newbyte[3];public RGBAColor ColorAdd
{//we don't expose the raw value, in case//we need to do some error checking//OpenCV loves throwing exceptions if its arguments aren't perfect :(//(in this instance we're not passing arguments to OpenCv)set{
FColorAdd[0]=(byte)(value.R *255.0);
FColorAdd[1]=(byte)(value.G *255.0);
FColorAdd[2]=(byte)(value.B *255.0);}//if changing these properties means we need to change the output image//size or colour type, then we need to call//Allocate();}protectedoverridevoid InitialiseOutput(){//This function gets called whenever the output image needs to be initialised//Initialising = setting the attributes (i.e. setting the image header and allocating the memory)
Size FHalfSize = FInput.ImageAttributes.Size;
FHalfSize.Width /=2;
FHalfSize.Height /=2;
FOutput.Image.Initialise(FHalfSize, FInput.ImageAttributes.ColourFormat);}publicoverridevoid Process(){//If we want to pull out an image in a specific format//then we must have a local instance of a CVImage initialised to that format//and use//FInput.Image.GetImage(TColourFormat.L8, FInputL8);//in that example, we expect to have a FInputL8 locally which has been intialised//with the correct size and colour format
CvInvoke.cvPyrDown(FInput.CvMat, FOutput.CvMat, FILTER_TYPE.CV_GAUSSIAN_5x5);if(FInput.ImageAttributes.ColourFormat==TColourFormat.RGB8)
PixelWiseAdd();
FOutput.Send();}privateunsafevoid PixelWiseAdd(){//here's an example of accessing the pixels one by one//note the 'unsafe' in the function header//we've also presumed that the image is of the format RGB8 in order for//this example to workbyte* rgb =(byte*)FOutput.Data.ToPointer();int width = FOutput.Image.Width;int height = FOutput.Image.Height;//for simplicity, i haven't clamped the colour values herefor(int i =0; i < width * height;++i){*rgb+++= FColorAdd[0];*rgb+++= FColorAdd[1];*rgb+++= FColorAdd[2];}}}#region PluginInfo[PluginInfo(Name ="Template", Category ="EmguCV", Version ="Filter", Help ="Template node for a threaded filter", Author ="", Credits ="", Tags ="")]#endregion PluginInfopublicclass TemplateNode : IFilterNode<TemplateInstance>{[Input("Add")]
IDiffSpread<RGBAColor> FColorAdd;protectedoverridevoid Update(int SpreadMax){if(FColorAdd.IsChanged)for(int i =0; i < SpreadMax; i++)
FProcessor[i].ColorAdd = FColorAdd[i];}}}
You define 2 classes:
The filter instance (inherits IFilterInstance)
The node (inherits IFilterNode<your filter instance class>)
In the node, you use
protectedoverridevoid Update(int SpreadMax){..}
rather than the usual Evaluate
The instance is managed by a ProcessInputOutputThreaded<T>
There's still likely to be some changes here but i'm trying to approach the point where the code within filters can be standardised
there's still a couple of bugs of course.
Note that if you change the spread count on the images, then FColorAdd inside the instance will just take the default value rather than the one from the pin
You define 2 classes:
In the node, you use
rather than the usual Evaluate
The instance is managed by a ProcessInputOutputThreaded<T>
There's still likely to be some changes here but i'm trying to approach the point where the code within filters can be standardised
there's still a couple of bugs of course.
Note that if you change the spread count on the images, then FColorAdd inside the instance will just take the default value rather than the one from the pin