HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
COP2_SampleFilter.C
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018
3  * Side Effects Software Inc. All rights reserved.
4  *
5  * Redistribution and use of Houdini Development Kit samples in source and
6  * binary forms, with or without modification, are permitted provided that the
7  * following conditions are met:
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  * 2. The name of Side Effects Software may not be used to endorse or
11  * promote products derived from this software without specific prior
12  * written permission.
13  *
14  * THIS SOFTWARE IS PROVIDED BY SIDE EFFECTS SOFTWARE `AS IS' AND ANY EXPRESS
15  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
17  * NO EVENT SHALL SIDE EFFECTS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
19  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
20  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
21  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
22  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
23  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  *----------------------------------------------------------------------------
26  */
27 #include <UT/UT_DSOVersion.h>
28 #include <OP/OP_OperatorTable.h>
29 
30 #include <PRM/PRM_Include.h>
31 #include <PRM/PRM_Parm.h>
32 
33 #include <SYS/SYS_Math.h>
34 
35 #include <TIL/TIL_Region.h>
36 #include <TIL/TIL_Tile.h>
37 #include <TIL/TIL_TileList.h>
38 
39 #include <PXL/PXL_Pixel.h>
40 #include <RU/RU_Algorithm.h>
41 #include <COP2/COP2_CookAreaInfo.h>
42 
43 #include "COP2_SampleFilter.h"
44 
45 using namespace HDK_Sample;
46 
47 COP_MASK_SWITCHER(4, "HDK Sample Filter");
48 
49 static PRM_Name names[] =
50 {
51  PRM_Name("left", "Left Enhance"),
52  PRM_Name("right", "Right Enhance"),
53  PRM_Name("top", "Top Enhance"),
54  PRM_Name("bottom", "Bottom Enhance"),
55 };
56 
57 
60 {
62 
67 
68  PRM_Template(),
69 };
70 
73 
75 
76 const char * COP2_SampleFilter::myInputLabels[] =
77 {
78  "Image to Enhance",
79  "Mask Input",
80  0
81 };
82 
83 
84 OP_Node *
86  const char *name,
87  OP_Operator *op)
88 {
89  return new COP2_SampleFilter(net, name, op);
90 }
91 
92 COP2_SampleFilter::COP2_SampleFilter(OP_Network *parent,
93  const char *name,
94  OP_Operator *entry)
95  : COP2_MaskOp(parent, name, entry)
96 {}
97 
99 {}
100 
101 // -----------------------------------------------------------------------
102 
103 // No cookSequenceInfo override - we'll let COP2_MaskOp do our work for us.
104 // This node doesn't alter any of the sequence parms - res, range or planes.
105 
106 
107 
108 // Stash some of our data in our shiny new context data.
111  float t, int xres, int yres,
112  int , int)
113 {
114  // Necessary since parameters cannot be evaluated in doCookMyTile
115 
117  float scx, scy;
118 
119  // The frame/scope effect allows the user to dial down the entire operation.
120  int index = mySequence.getImageIndex(t);
121  float effect = getFrameScopeEffect(index);
122 
123  // If cooking at a reduced res, scale down the effect for a closer
124  // approximation.
125  getScaleFactors(xres,yres, scx, scy);
126  effect *= SYSmin(scx,scy);
127 
128  data->myLeft = LEFT(t) * effect;
129  data->myRight = RIGHT(t) * effect;
130  data->myTop = TOP(t) * effect;
131  data->myBottom = BOTTOM(t) * effect;
132 
133  data->myKernel = new float[9];
134  // Kernel positions:
135  // 0 1 2
136  // 3 4 5
137  // 6 7 8
138 
139  data->myKernel[0] = -data->myLeft -data->myTop;
140  data->myKernel[1] = -data->myTop;
141  data->myKernel[2] = -data->myRight -data->myTop;
142 
143  data->myKernel[3] = -data->myLeft;
144  data->myKernel[5] = -data->myRight;
145 
146  data->myKernel[6] = -data->myLeft -data->myBottom;
147  data->myKernel[7] = -data->myBottom;
148  data->myKernel[8] = -data->myRight -data->myBottom;
149 
150  // center
151  data->myKernel[4] = 1.0f + 3.0f * (data->myLeft + data->myRight +
152  data->myTop + data->myBottom);
153  return data;
154 };
155 
156 // Our filter expands the image bounds by 1 in each direction.
157 void
159 {
160  int x1,y1,x2,y2;
161 
162  // Grab the bounds from the mask op, which combines the mask with the input
163  // bounds.
165 
166  // Now enlarge the bounds by 1 in each direction to account for the 3x3
167  // kernel.
168  context.getImageBounds(x1,y1,x2,y2);
169  context.setImageBounds(x1-1, y1-1, x2+1, y2+1);
170 }
171 
172 // Tell the scheduler which part of the inputs' image data we require.
173 void
175  COP2_CookAreaInfo &output_area,
176  const COP2_CookAreaList &input_areas,
177  COP2_CookAreaList &needed_areas)
178 {
179  // Add dependencies on the first input and the mask plane.
180  COP2_MaskOp::getInputDependenciesForOutputArea(output_area, input_areas,
181  needed_areas);
182 
183  // If bypassed, don't do anything else.
184  if (getBypass())
185  return;
186 
187  // Enlarge the needed area of the first input by 1 pixel in all directions.
188  COP2_CookAreaInfo *inarea =
189  makeOutputAreaDependOnMyPlane(0, output_area,input_areas,needed_areas);
190 
191  // It may not exist if the input node has an error.
192  if(inarea)
193  inarea->expandNeededArea(1, 1, 1, 1);
194 }
195 
196 
197 
198 // Some friendly node-info help. You can evaluate parms here and present even
199 // more specific help, like "Apply [Box/Gaussian]" blur (see Blur COP info)
200 const char *
202 {
203  return "This operation enhances individual edges.";
204 }
205 
206 namespace HDK_Sample {
207 
208 // This class allows the various data types to be abstracted out.
210 {
211 public:
212  cop2_EdgeEnhance(const float *kernel) : myKernel(kernel) {}
213  virtual ~cop2_EdgeEnhance() {}
214 
216 
217  const float *myKernel;
218 };
219 
220 // This is the template class which defines the image operation
221 template<class Type,int fast> class cop2_EdgeEnhanceOp
222  : public RU_FilterOp<Type,fast>
223 {
224 public:
226  : RU_FilterOp<Type,fast>(alg)
227  { ; }
228  virtual ~cop2_EdgeEnhanceOp() {;}
229 
230  virtual int filter(TIL_TileList *output,
231  const TIL_Region *input, float t,
232  int thread=-1, void *data=0);
233 
234  virtual int filter(TIL_Region *output,
235  const TIL_Region *input, float t,
236  int thread, void *data)
238  output, input, t, thread, data); }
239 };
240 
242 
243 
244 template<class Type,int fast> int
246  const TIL_Region *input, float t,
247  int thread, void *data)
248 {
249  PXL_Pixel<Type,fast> pixel(output->myBlack, output->myWhite);
250  cop2_EdgeEnhance *parm =
252  const float *kernel = parm->myKernel;
253  TIL_Tile *itr=0;
254  const Type *source_data, *iscan1, *iscan2, *iscan3;
255  Type *dest_data, *scan;
256  int ti;
257  int stride, istride;
258  float sum;
259  int x,y;
260  int w,h;
261 
262  w = output->myX2 - output->myX1 + 1;
263  h = output->myY2 - output->myY1 + 1;
264  stride = w;
265  istride = w + 2;
266 
267  FOR_EACH_UNCOOKED_TILE(output, itr, ti)
268  {
269  dest_data = (Type *) itr->getImageData();
270  source_data = (Type *) input->getImageData(ti);
271 
272  // 3 scanlines for a 3x3 kernel
273  iscan1 = source_data + 1;
274  iscan2 = iscan1 + istride;
275  iscan3 = iscan2 + istride;
276 
277  scan = dest_data;
278 
279  for(y=0; y<h; y++)
280  {
281  for(x=0; x<w; x++)
282  {
283  pixel.set(iscan1[x-1]);
284  sum = (float)pixel * kernel[0];
285 
286  pixel.set(iscan1[x]);
287  sum += (float)pixel * kernel[1];
288 
289  pixel.set(iscan1[x+1]);
290  sum += (float)pixel * kernel[2];
291 
292  pixel.set(iscan2[x-1]);
293  sum += (float)pixel * kernel[3];
294 
295  pixel.set(iscan2[x]);
296  sum += (float)pixel * kernel[4];
297 
298  pixel.set(iscan2[x+1]);
299  sum += (float)pixel * kernel[5];
300 
301  pixel.set(iscan3[x-1]);
302  sum += (float)pixel * kernel[6];
303 
304  pixel.set(iscan3[x]);
305  sum += (float)pixel * kernel[7];
306 
307  pixel.set(iscan3[x+1]);
308  sum += (float)pixel * kernel[8];
309 
310  // Assign to the output array
311  pixel = sum;
312  scan[x] = pixel.getValue();
313  }
314 
315  scan += stride;
316  iscan1 += istride;
317  iscan2 += istride;
318  iscan3 += istride;
319  }
320  }
321  return 1;
322 }
323 
324 } // namespace HDK_Sample
325 
326 
327 
328 OP_ERROR
330 {
331  // Grab our context data.
333  static_cast<cop2_SampleFilterContext *>(context.data());
334 
335  // Grab the input image data that we need for our tile area.
336  TIL_Region *in = inputRegion(0, context,
337  tiles->myX1 -1,
338  tiles->myY1 -1,
339  tiles->myX2 +1,
340  tiles->myY2 +1,
341  TIL_HOLD); // streak edges when outside canvas
342  if(!in)
343  {
344  tiles->clearToBlack();
345  return error();
346  }
347 
348  // call the templated operation
349  cop2_EdgeEnhance op(data->myKernel);
350  op.filter(tiles, in, context.getTime(), NULL, context.myThreadIndex);
351 
352  releaseRegion(in);
353 
354  // done - return any errors.
355  return error();
356 }
357 
358 
359 void
361 {
362  table->addOperator(new OP_Operator("hdksamplefilt",
363  "HDK Sample Filter",
366  1,
367  2, // optional mask input.
369  0, // not generator
371 }
372 
373 
Simple example of a kernel filter.
Storage class for our parameters and the kernel.
PRM_API PRM_Default PRMzeroDefaults[]
float * myKernel
Kernel filter derived from parameters.
static OP_Node * myConstructor(OP_Network *, const char *, OP_Operator *)
All nodes are instantiated via a myConstructor method.
unsigned int myWhite
Definition: TIL_TileList.h:80
virtual void getInputDependenciesForOutputArea(COP2_CookAreaInfo &output_area, const COP2_CookAreaList &input_areas, COP2_CookAreaList &needed_areas)
TIL_Sequence mySequence
Definition: COP2_Node.h:1304
virtual float getFrameScopeEffect(int image_index)
virtual void getInputDependenciesForOutputArea(COP2_CookAreaInfo &output_area, const COP2_CookAreaList &input_areas, COP2_CookAreaList &needed_areas)
int filter(TIL_TileList *output, const TIL_Region *input, float t, void *ndata=0, int thread=-1, void *data=0)
#define FOR_EACH_UNCOOKED_TILE(list, tile, i)
Definition: TIL_Defines.h:181
fpreal getTime() const
Definition: COP2_Context.h:77
virtual int filter(TIL_TileList *output, const TIL_Region *input, float t, int thread=-1, void *data=0)
static OP_TemplatePair myTemplatePair
Definition: COP2_MaskOp.h:29
UT_ErrorSeverity
Definition: UT_Error.h:25
void setImageBounds(int x1, int y1, int x2, int y2)
GLint y
Definition: glcorearb.h:102
bool addOperator(OP_Operator *op, std::ostream *err=nullptr)
static OP_VariablePair myVariablePair
Definition: COP2_Node.h:628
virtual void computeImageBounds(COP2_Context &context)
void * getImageData(int index)
DECLARE_FILTER_OP(cop2_EdgeEnhanceOp)
bool expandNeededArea(int pixels_left, int pixels_down, int pixels_right, int pixels_up)
COP_MASK_SWITCHER(4,"HDK Sample Filter")
int getBypass() const
Definition: OP_Node.h:1287
GLint GLenum GLboolean GLsizei stride
Definition: glcorearb.h:871
virtual COP2_ContextData * newContextData(const TIL_Plane *p, int array_index, float t, int xres, int yres, int thread, int max_threads)
COP2_ContextData * data()
GLboolean * data
Definition: glcorearb.h:130
void getScaleFactors(int xres, int yres, float &sx, float &sy) const
PRM_API PRM_Name PRMswitcherName
GLuint const GLchar * name
Definition: glcorearb.h:785
PRM_API const PRM_Type PRM_FLT_J
PRM_API const PRM_Type PRM_SWITCHER
COP2_CookAreaInfo * makeOutputAreaDependOnMyPlane(int input, COP2_CookAreaInfo &output_area, const COP2_CookAreaList &input_areas, COP2_CookAreaList &needed_areas)
virtual OP_ERROR doCookMyTile(COP2_Context &context, TIL_TileList *tilelist)
void releaseRegion(TIL_Region *, int output=0)
virtual OP_ERROR error()
Definition: COP2_Node.h:453
cop2_EdgeEnhanceOp(RU_Algorithm *alg)
#define TOOL_PARM
Definition: COP2_Common.h:26
cop2_EdgeEnhance(const float *kernel)
Type getValue() const
Definition: PXL_Pixel.h:80
GLfloat GLfloat GLfloat GLfloat h
Definition: glcorearb.h:2001
TIL_Region * inputRegion(int input_index, COP2_Context &context, const TIL_Plane *plane, int array_index, float t, int xstart, int ystart, int xend, int yend, TIL_RegionExtend hold=TIL_BLACK, int share=1, void *regionmem[PLANE_MAX_VECTOR_SIZE]=0, bool correct_aspect=true, bool correct_bounds=true, int scan_alignment=0)
unsigned int myBlack
Definition: TIL_TileList.h:80
void newCop2Operator(OP_OperatorTable *table)
static const char * myInputLabels[]
static OP_TemplatePair myTemplatePair
static OP_VariablePair myVariablePair
GLuint index
Definition: glcorearb.h:785
GLint GLenum GLint x
Definition: glcorearb.h:408
virtual const char * getOperationInfo()
Returns a description of the operation for the node info popup.
bool getImageBounds(int &x1, int &y1, int &x2, int &y2)
void getImageData(const unsigned char *&data) const
Type set(Type)
void clearToBlack(bool markconstant=true)
GLubyte GLubyte GLubyte GLubyte w
Definition: glcorearb.h:856
static PRM_Template myTemplateList[]
exint getImageIndex(double t, int clamp_range=1, int round_off=SEQUENCE_NEAREST) const
#define SYSmin(a, b)
Definition: SYS_Math.h:1368
virtual int filter(TIL_TileList *, const TIL_Region *, float, int, void *)
virtual int filter(TIL_Region *output, const TIL_Region *input, float t, int thread, void *data)
virtual void computeImageBounds(COP2_Context &context)
IMPLEMENT_FILTER_OP(cop2_EdgeEnhance, cop2_EdgeEnhanceOp)