aboutsummaryrefslogtreecommitdiff
path: root/externals/gridflow/optional
diff options
context:
space:
mode:
Diffstat (limited to 'externals/gridflow/optional')
-rw-r--r--externals/gridflow/optional/fftw.c114
-rw-r--r--externals/gridflow/optional/gem.c171
-rw-r--r--externals/gridflow/optional/opencv.c380
3 files changed, 665 insertions, 0 deletions
diff --git a/externals/gridflow/optional/fftw.c b/externals/gridflow/optional/fftw.c
new file mode 100644
index 00000000..e35bc9b9
--- /dev/null
+++ b/externals/gridflow/optional/fftw.c
@@ -0,0 +1,114 @@
+/*
+ GridFlow
+ Copyright (c) 2001-2008 by Mathieu Bouchard
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ See file ../COPYING for further informations on licensing terms.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "../gridflow.h.fcs"
+#include <fftw3.h>
+
+#define C(x) ((fftwf_complex *)x)
+
+\class GridFFT : FObject {
+ fftwf_plan plan;
+ P<Dim> lastdim; /* of last input (for plan cache) */
+ long lastchans; /* of last input (for plan cache) */
+ \attr int sign; /* -1 or +1 */
+ \attr int skip; /* 0 (y and x) or 1 (x only) */
+ \attr bool real;
+ bool lastreal;
+ \constructor () {sign=-1; plan=0; lastdim=0; lastchans=0; skip=0; real=false;}
+ \grin 0 float32
+};
+\def 0 sign (int sign) {
+ if (sign!=-1 && sign!=1) RAISE("sign should be -1 or +1");
+ this->sign=sign;
+ fftwf_destroy_plan(plan);
+}
+\def 0 skip (int skip) {
+ if (skip<0 || skip>1) RAISE("skip should be 0 or 1");
+ this->skip=skip;
+ if (plan) {fftwf_destroy_plan(plan); plan=0;}
+}
+GRID_INLET(GridFFT,0) {
+ if (in->nt != float32_e) RAISE("expecting float32");
+ if (real && sign==-1) {
+ if (in->dim->n != 2 && in->dim->n != 3) RAISE("expecting 2 or 3 dimensions: rows,columns,channels?");
+ } else {
+ if (in->dim->n != 3 && in->dim->n != 4) RAISE("expecting 3 or 4 dimensions: rows,columns,channels?,complex");
+ if (in->dim->get(in->dim->n-1)!=2) RAISE("expecting Dim(...,2): real,imaginary (got %d)",in->dim->get(2));
+ }
+ in->set_chunk(0);
+} GRID_FLOW {
+ if (skip==1 && !real) RAISE("can't do 1-D FFT in real mode, sorry");
+ Dim *dim;
+ if (!real) dim = in->dim;
+ else if (sign==-1) {
+ int v[Dim::MAX_DIM];
+ for (int i=0; i<in->dim->n; i++) v[i]=in->dim->v[i];
+ v[in->dim->n] = 2;
+ dim = new Dim(in->dim->n+1,v);
+ } else dim = new Dim(in->dim->n-1,in->dim->v);
+ GridOutlet out(this,0,dim,in->nt);
+ float32 *tada = (float32 *)memalign(16,dim->prod()*sizeof(float32));
+ long chans = in->dim->n>=3 ? in->dim->get(2) : 1;
+ CHECK_ALIGN16(data,in->nt)
+ CHECK_ALIGN16(tada,in->nt)
+ if (plan && lastdim && lastdim!=in->dim && chans!=lastchans && real==lastreal) {fftwf_destroy_plan(plan); plan=0;}
+ int v[] = {in->dim->v[0],in->dim->v[1],in->dim->n>2?in->dim->v[2]:1};
+// if (chans==1) {
+// if (skip==0) plan = fftwf_plan_dft_2d(v[0],v[1],data,tada,sign,0);
+// if (skip==1) plan = fftwf_plan_many_dft(1,&v[1],v[0],data,0,1,v[1],tada,0,1,v[1],sign,0);
+// }
+ if (skip==0) {
+ //plan = fftwf_plan_dft_2d(v[0],v[1],data,tada,sign,0);
+ if (!plan) {
+ int embed[] = {dim->v[0],dim->v[1]};
+ if (!real) {plan=fftwf_plan_many_dft( 2,&v[0],chans,C(data),0 ,chans,1,C(tada),0 ,chans,1,sign,0);}
+ else if (sign==-1) {plan=fftwf_plan_many_dft_r2c(2,&v[0],chans, data ,embed,chans,1,C(tada),embed,chans,1,0);}
+ else {plan=fftwf_plan_many_dft_c2r(2,&v[0],chans,C(data),embed,chans,1, tada ,embed,chans,1,0);}
+ }
+ if (!real) fftwf_execute_dft( plan,C(data),C(tada));
+ else if (sign==-1) fftwf_execute_dft_r2c(plan, data ,C(tada));
+ else fftwf_execute_dft_c2r(plan,C(data), tada );
+ }
+ if (skip==1) {
+ if (!plan) plan=fftwf_plan_many_dft(1,&v[1],chans,C(data),0,chans,1,C(tada),0,chans,1,sign,0);
+ //plan = fftwf_plan_many_dft(1,&v[1],v[0],C(data),0,1,v[1],C(tada),0,1,v[1],sign,0);
+ long incr = v[1]*chans;
+ for (int i=0; i<v[0]; i++) fftwf_execute_dft(plan,C(data)+i*incr,C(tada)+i*incr);
+ }
+ if (real && sign==-1) {
+ for (int i=0; i<v[0]; i++) {
+ int h = mod(-i,v[0]);
+ T *tada2 = tada + (h*v[1]+v[1]/2)*v[2]*2;
+ T *tada3 = tada + (i*v[1]+v[1]/2)*v[2]*2;
+ for (int j=1+v[1]/2; j<v[1]; j++) {
+ tada2-=v[2]*2; tada3+=v[2]*2;
+ for (int k=0; k<v[2]; k++) {tada3[k+k]=tada2[k+k]; tada3[k+k+1]=-tada2[k+k+1];}
+ }
+ }
+ }
+ out.send(out.dim->prod(),tada);
+ free(tada);
+ lastdim=in->dim; lastchans=chans; lastreal=real;
+} GRID_END
+\end class {install("#fft",1,1);}
+void startup_fftw () {
+ \startall
+}
diff --git a/externals/gridflow/optional/gem.c b/externals/gridflow/optional/gem.c
new file mode 100644
index 00000000..4280855f
--- /dev/null
+++ b/externals/gridflow/optional/gem.c
@@ -0,0 +1,171 @@
+/*
+ $Id: gem.c 3865 2008-06-11 21:13:58Z matju $
+
+ GridFlow
+ Copyright (c) 2001-2008 by Mathieu Bouchard
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ See file ../COPYING for further informations on licensing terms.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "../gridflow.h.fcs"
+#include "Base/GemPixDualObj.h"
+
+struct GridToPix;
+struct GridToPixHelper : GemPixObj {
+ GridToPix *boss;
+ CPPEXTERN_HEADER(GridToPixHelper,GemPixObj)
+public:
+ GridToPixHelper () {}
+ virtual void startRendering();
+ virtual void render(GemState *state);
+ virtual bool isRunnable () {return true;} // required to keep GEM 0.9.1 (the real 0.9.1) happy
+};
+CPPEXTERN_NEW(GridToPixHelper)
+
+// in 0: gem
+// in 1: grid
+// out 0: gem
+\class GridToPix : FObject {
+ GridToPixHelper *helper;
+ P<BitPacking> bit_packing;
+ pixBlock m_pixBlock;
+ \attr bool yflip;
+ GridToPix (BFObject *bself, MESSAGE) : FObject(bself,MESSAGE2) {
+ yflip = false;
+ imageStruct &im = m_pixBlock.image = imageStruct();
+ im.ysize = 1;
+ im.xsize = 1;
+ im.csize = 4;
+ im.format = GL_RGBA;
+ im.type = GL_UNSIGNED_BYTE;
+ im.allocate();
+ *(int*)im.data = 0x0000ff;
+ uint32 mask[4] = {0x0000ff,0x00ff00,0xff0000,0x000000};
+ bit_packing = new BitPacking(is_le(),4,4,mask);
+ helper = new GridToPixHelper;
+ helper->boss = this;
+ bself->gemself = helper;
+ }
+ ~GridToPix () {}
+ \grin 1 int
+};
+GRID_INLET(GridToPix,1) {
+ if (in->dim->n != 3) RAISE("expecting 3 dimensions: rows,columns,channels");
+ if (in->dim->get(2) != 4) RAISE("expecting 4 channels (got %d)",in->dim->get(2));
+ in->set_chunk(1);
+ imageStruct &im = m_pixBlock.image;
+ im.clear();
+ im.ysize = in->dim->get(0);
+ im.xsize = in->dim->get(1);
+ im.csize = in->dim->get(2);
+ im.type = GL_UNSIGNED_BYTE;
+ im.allocate();
+ im.format = GL_RGBA;
+ /*
+ switch (in->dim->get(2)) {
+ case 4: im.format = GL_RGBA; break;
+ default: RAISE("you shouldn't see this error message.");
+ }
+ */
+} GRID_FLOW {
+ uint8 *buf = (uint8 *)m_pixBlock.image.data;
+ /*!@#$ it would be nice to skip the bitpacking when we can */
+ long sxc = in->dim->prod(1);
+ long sx = in->dim->v[1];
+ long sy = in->dim->v[0];
+ if (yflip) {for (long y= in->dex/sxc; n; data+=sxc, n-=sxc, y++) bit_packing->pack(sx,data,buf+y*sxc);}
+ else {for (long y=sy-1-in->dex/sxc; n; data+=sxc, n-=sxc, y--) bit_packing->pack(sx,data,buf+y*sxc);}
+} GRID_END
+\end class {
+ install("#to_pix",2,0); // outlets are 0 because GEM makes its own outlet instead
+ add_creator("#export_pix");
+ GridToPixHelper::real_obj_setupCallback(fclass->bfclass);
+}
+void GridToPixHelper::obj_setupCallback(t_class *) {}
+void GridToPixHelper::startRendering() {boss->m_pixBlock.newimage = 1;}
+void GridToPixHelper::render(GemState *state) {state->image = &boss->m_pixBlock;}
+
+//------------------------------------------------------------------------
+
+struct GridFromPix;
+struct GridFromPixHelper : GemPixObj {
+ GridFromPix *boss;
+ CPPEXTERN_HEADER(GridFromPixHelper,GemPixObj)
+public:
+ GridFromPixHelper () {}
+ virtual void render(GemState *state);
+ virtual bool isRunnable () {return true;} // required to keep GEM 0.9.1 (the real 0.9.1) happy
+};
+CPPEXTERN_NEW(GridFromPixHelper)
+
+// in 0: gem (todo: auto 0 = manual mode; bang = send next frame; type = number type attr)
+// out 0: grid
+\class GridFromPix : FObject {
+ GridFromPixHelper *helper;
+ P<BitPacking> bit_packing;
+ \attr bool yflip;
+ GridFromPix () : FObject(0,0,0,0) {RAISE("don't call this. this exists only to make GEM happy.");}
+ GridFromPix (BFObject *bself, MESSAGE) : FObject(bself,MESSAGE2) {
+ uint32 mask[4] = {0x0000ff,0x00ff00,0xff0000,0x000000};
+ bit_packing = new BitPacking(is_le(),4,4,mask);
+ yflip = false;
+ bself->gemself = (GemPixObj *)this;
+ helper = new GridFromPixHelper;
+ helper->boss = this;
+ bself->gemself = helper;
+ }
+ virtual ~GridFromPix () {}
+ void render(GemState *state) {
+ if (!state->image) {::post("gemstate has no pix"); return;}
+ imageStruct &im = state->image->image;
+ if (im.format != GL_RGBA ) {::post("can't produce grid from pix format %d",im.format); return;}
+ if (im.type != GL_UNSIGNED_BYTE) {::post("can't produce grid from pix type %d", im.type ); return;}
+ int32 v[] = { im.ysize, im.xsize, im.csize };
+ GridOutlet out(this,0,new Dim(3,v));
+ long sxc = im.xsize*im.csize;
+ long sy = v[0];
+ uint8 buf[sxc];
+ for (int y=0; y<v[0]; y++) {
+ uint8 *data = (uint8 *)im.data+sxc*(yflip?y:sy-1-y);
+ bit_packing->pack(im.xsize,data,buf);
+ out.send(sxc,buf);
+ }
+ }
+};
+
+void GridFromPixHelper::obj_setupCallback(t_class *) {}
+
+\end class {
+ install("#from_pix",2,1);
+ add_creator("#import_pix");
+ GridFromPixHelper::real_obj_setupCallback(fclass->bfclass);
+}
+void GridFromPixHelper::render(GemState *state) {boss->render(state);}
+
+//------------------------------------------------------------------------
+
+void startup_gem () {
+ \startall
+}
+
+/*
+virtual void processRGBAImage(imageStruct &image) {}
+virtual void processRGBImage (imageStruct &image) {}
+virtual void processGrayImage(imageStruct &image) {}
+virtual void processYUVImage (imageStruct &image) {}
+*/
+
diff --git a/externals/gridflow/optional/opencv.c b/externals/gridflow/optional/opencv.c
new file mode 100644
index 00000000..e9393afc
--- /dev/null
+++ b/externals/gridflow/optional/opencv.c
@@ -0,0 +1,380 @@
+/*
+ $Id: opencv.c 3977 2008-07-04 20:15:08Z matju $
+
+ GridFlow
+ Copyright (c) 2001-2008 by Mathieu Bouchard
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ See file ../COPYING for further informations on licensing terms.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "../gridflow.h.fcs"
+#include <opencv/cv.h>
+#include <errno.h>
+
+int ipl_eltype(NumberTypeE e) {
+ switch (e) {
+ case uint8_e: return IPL_DEPTH_8U;
+ // IPL_DEPTH_8S not supported
+ // IPL_DEPTH_16U not supported
+ case int16_e: return IPL_DEPTH_16S;
+ case int32_e: return IPL_DEPTH_32S;
+ case float32_e: return IPL_DEPTH_32F;
+ case float64_e: return IPL_DEPTH_64F;
+ default: RAISE("unsupported type %s",number_type_table[e].name);
+ }
+}
+
+NumberTypeE gf_ipltype(int e) {
+ switch (e) {
+ case IPL_DEPTH_8U: return uint8_e;
+ // IPL_DEPTH_8S not supported
+ // IPL_DEPTH_16U not supported
+ case IPL_DEPTH_16S: return int16_e;
+ case IPL_DEPTH_32S: return int32_e;
+ case IPL_DEPTH_32F: return float32_e;
+ case IPL_DEPTH_64F: return float64_e;
+ default: RAISE("unsupported IPL type %d",e);
+ }
+}
+
+int cv_eltype(NumberTypeE e) {
+ switch (e) {
+ case uint8_e: return CV_8U;
+ // CV_8S not supported
+ // CV_16U not supported
+ case int16_e: return CV_16S;
+ case int32_e: return CV_32S;
+ case float32_e: return CV_32F;
+ case float64_e: return CV_64F;
+ default: RAISE("unsupported type %s",number_type_table[e].name);
+ }
+}
+
+NumberTypeE gf_cveltype(int e) {
+ switch (e) {
+ case CV_8U: return uint8_e;
+ // CV_8S not supported
+ // CV_16U not supported
+ case CV_16S: return int16_e;
+ case CV_32S: return int32_e;
+ case CV_32F: return float32_e;
+ case CV_64F: return float64_e;
+ default: RAISE("unsupported CV type %d",e);
+ }
+}
+
+enum CvMode {
+ cv_mode_auto,
+ cv_mode_channels,
+ cv_mode_nochannels,
+};
+
+CvMode convert (const t_atom2 &x, CvMode *foo) {
+ if (x==gensym("auto")) return cv_mode_auto;
+ if (x==gensym("channels")) return cv_mode_channels;
+ if (x==gensym("nochannels")) return cv_mode_nochannels;
+ RAISE("invalid CvMode");
+}
+
+CvArr *cvGrid(PtrGrid g, CvMode mode, int reqdims=-1) {
+ P<Dim> d = g->dim;
+ int channels=1;
+ int dims=g->dim->n;
+ //post("mode=%d",(int)mode);
+ if (mode==cv_mode_channels && g->dim->n==0) RAISE("CV: channels dimension required for 'mode channels'");
+ if ((mode==cv_mode_auto && g->dim->n>=3) || mode==cv_mode_channels) channels=g->dim->v[--dims];
+ if (channels>64) RAISE("CV: too many channels. max 64, got %d",channels);
+ //post("channels=%d dims=%d nt=%d",channels,dims,g->nt);
+ //post("bits=%d",number_type_table[g->nt].size);
+ //if (dims==2) return cvMat(g->dim->v[0],g->dim->v[1],cv_eltype(g->nt),g->data);
+ if (reqdims>=0 && reqdims!=dims) RAISE("CV: wrong number of dimensions. expected %d, got %d", reqdims, dims);
+ if (dims==2) {
+ CvMat *a = cvCreateMatHeader(g->dim->v[0],g->dim->v[1],CV_MAKETYPE(cv_eltype(g->nt),channels));
+ cvSetData(a,g->data,g->dim->prod(1)*(number_type_table[g->nt].size/8));
+ return a;
+ }
+ RAISE("unsupported number of dimensions (got %d)",g->dim->n);
+ //return 0;
+}
+
+IplImage *cvImageGrid(PtrGrid g /*, CvMode mode */) {
+ P<Dim> d = g->dim;
+ if (d->n!=3) RAISE("expected 3 dimensions, got %s",d->to_s());
+ int channels=g->dim->v[2];
+ if (channels>64) RAISE("too many channels. max 64, got %d",channels);
+ CvSize size = {d->v[1],d->v[0]};
+ IplImage *a = cvCreateImageHeader(size,ipl_eltype(g->nt),channels);
+ cvSetData(a,g->data,g->dim->prod(1)*(number_type_table[g->nt].size/8));
+ return a;
+}
+
+\class CvOp1 : FObject {
+ \attr CvMode mode;
+ \constructor () {mode = cv_mode_auto;}
+ /* has no default \grin 0 handler so far. */
+};
+\end class {}
+
+\class CvOp2 : CvOp1 {
+ PtrGrid r;
+ \constructor (Grid *r=0) {this->r = r?r:new Grid(new Dim(),int32_e,true);}
+ virtual void func(CvArr *l, CvArr *r, CvArr *o) {/* rien */}
+ \grin 0
+ \grin 1
+};
+GRID_INLET(CvOp2,0) {
+ SAME_TYPE(in,r);
+ if (!in->dim->equal(r->dim)) RAISE("dimension mismatch: left:%s right:%s",in->dim->to_s(),r->dim->to_s());
+ in->set_chunk(0);
+} GRID_FLOW {
+ PtrGrid l = new Grid(in->dim,(T *)data);
+ PtrGrid o = new Grid(in->dim,in->nt);
+ CvArr *a = cvGrid(l,mode);
+ CvArr *b = cvGrid(r,mode);
+ CvArr *c = cvGrid(o,mode);
+ func(a,b,c);
+ cvReleaseMat((CvMat **)&a);
+ cvReleaseMat((CvMat **)&b);
+ cvReleaseMat((CvMat **)&c);
+ out = new GridOutlet(this,0,in->dim,in->nt);
+ out->send(o->dim->prod(),(T *)o->data);
+} GRID_END
+GRID_INPUT2(CvOp2,1,r) {} GRID_END
+\end class {}
+
+#define FUNC(CLASS) CLASS(BFObject *bself, MESSAGE):CvOp2(bself,MESSAGE2) {} virtual void func(CvArr *l, CvArr *r, CvArr *o)
+
+\class CvAdd : CvOp2 {FUNC(CvAdd) {cvAdd(l,r,o,0);}};
+\end class {install("cv.Add",2,1);}
+\class CvSub : CvOp2 {FUNC(CvSub) {cvSub(l,r,o,0);}};
+\end class {install("cv.Sub",2,1);}
+\class CvMul : CvOp2 {FUNC(CvMul) {cvMul(l,r,o,1);}};
+\end class {install("cv.Mul",2,1);}
+\class CvDiv : CvOp2 {FUNC(CvDiv) {cvDiv(l,r,o,1);}};
+\end class {install("cv.Div",2,1);}
+\class CvAnd : CvOp2 {FUNC(CvAnd) {cvAnd(l,r,o,0);}};
+\end class {install("cv.And",2,1);}
+\class CvOr : CvOp2 {FUNC(CvOr ) {cvOr( l,r,o,0);}};
+\end class {install("cv.Or" ,2,1);}
+\class CvXor : CvOp2 {FUNC(CvXor) {cvXor(l,r,o,0);}};
+\end class {install("cv.Xor",2,1);}
+
+\class CvInvert : CvOp1 {
+ \constructor () {}
+ \grin 0
+};
+GRID_INLET(CvInvert,0) {
+ if (in->dim->n!=2) RAISE("should have 2 dimensions");
+ if (in->dim->v[0] != in->dim->v[1]) RAISE("matrix should be square");
+ in->set_chunk(0);
+} GRID_FLOW {
+ //post("l=%p, r=%p", &*l, &*r);
+ PtrGrid l = new Grid(in->dim,(T *)data);
+ PtrGrid o = new Grid(in->dim,in->nt);
+ CvArr *a = cvGrid(l,mode);
+ CvArr *c = cvGrid(o,mode);
+ //post("a=%p, b=%p", a, b);
+ cvInvert(a,c);
+ cvReleaseMat((CvMat **)&a);
+ cvReleaseMat((CvMat **)&c);
+ out = new GridOutlet(this,0,in->dim,in->nt);
+ out->send(o->dim->prod(),(T *)o->data);
+} GRID_END
+\end class {install("cv.Invert",1,1);}
+
+\class CvSVD : CvOp1 {
+ \grin 0
+ \constructor () {}
+};
+GRID_INLET(CvSVD,0) {
+ if (in->dim->n!=2) RAISE("should have 2 dimensions");
+ if (in->dim->v[0] != in->dim->v[1]) RAISE("matrix should be square");
+ in->set_chunk(0);
+} GRID_FLOW {
+ PtrGrid l = new Grid(in->dim,(T *)data);
+ PtrGrid o0 = new Grid(in->dim,in->nt);
+ PtrGrid o1 = new Grid(in->dim,in->nt);
+ PtrGrid o2 = new Grid(in->dim,in->nt);
+ CvArr *a = cvGrid(l,mode);
+ CvArr *c0 = cvGrid(o0,mode);
+ CvArr *c1 = cvGrid(o1,mode);
+ CvArr *c2 = cvGrid(o2,mode);
+ cvSVD(a,c0,c1,c2);
+ cvReleaseMat((CvMat **)&a);
+ cvReleaseMat((CvMat **)&c0);
+ cvReleaseMat((CvMat **)&c1);
+ cvReleaseMat((CvMat **)&c2);
+ out = new GridOutlet(this,2,in->dim,in->nt); out->send(o2->dim->prod(),(T *)o2->data);
+ out = new GridOutlet(this,1,in->dim,in->nt); out->send(o1->dim->prod(),(T *)o1->data);
+ out = new GridOutlet(this,0,in->dim,in->nt); out->send(o0->dim->prod(),(T *)o0->data);
+} GRID_END
+\end class {install("cv.SVD",1,3);}
+
+\class CvSplit : CvOp1 {
+ int channels;
+ \constructor (int channels) {
+ if (channels<0 || channels>64) RAISE("channels=%d is not in 1..64",channels);
+ this->channels = channels;
+ bself->noutlets_set(channels);
+ }
+};
+\end class {}
+
+\class CvHaarDetectObjects : FObject {
+ \attr double scale_factor; /*=1.1*/
+ \attr int min_neighbors; /*=3*/
+ \attr int flags; /*=0*/
+ \constructor () {
+ scale_factor=1.1;
+ min_neighbors=3;
+ flags=0;
+ //cascade = cvLoadHaarClassifierCascade("<default_face_cascade>",cvSize(24,24));
+ const char *filename = OPENCV_SHARE_PATH "/haarcascades/haarcascade_frontalface_alt2.xml";
+ FILE *f = fopen(filename,"r");
+ if (!f) RAISE("error opening %s: %s",filename,strerror(errno));
+ fclose(f);
+ cascade = (CvHaarClassifierCascade *)cvLoad(filename,0,0,0);
+ int s = cvGetErrStatus();
+ post("cascade=%p, cvGetErrStatus=%d cvErrorStr=%s",cascade,s,cvErrorStr(s));
+ //cascade = cvLoadHaarClassifierCascade(OPENCV_SHARE_PATH "/data/haarcascades/haarcascade_frontalface_alt2.xml",cvSize(24,24));
+ storage = cvCreateMemStorage(0);
+ }
+ CvHaarClassifierCascade *cascade;
+ CvMemStorage *storage;
+ \grin 0
+};
+GRID_INLET(CvHaarDetectObjects,0) {
+ in->set_chunk(0);
+} GRID_FLOW {
+ PtrGrid l = new Grid(in->dim,(T *)data);
+ IplImage *img = cvImageGrid(l);
+ CvSeq *ret = cvHaarDetectObjects(img,cascade,storage,scale_factor,min_neighbors,flags);
+ int n = ret ? ret->total : 0;
+ out = new GridOutlet(this,0,new Dim(n,2,2));
+ for (int i=0; i<n; i++) {
+ CvRect *r = (CvRect *)cvGetSeqElem(ret,i);
+ int32 duh[] = {r->y,r->x,r->y+r->height,r->x+r->width};
+ out->send(4,duh);
+ }
+} GRID_END
+\end class {install("cv.HaarDetectObjects",2,1);}
+
+\class CvKalmanWrapper : CvOp1 {
+ CvKalman *kal;
+ \constructor (int dynam_params, int measure_params, int control_params=0) {
+ kal = cvCreateKalman(dynam_params,measure_params,control_params);
+ }
+ ~CvKalmanWrapper () {if (kal) cvReleaseKalman(&kal);}
+ \decl void _0_bang ();
+ \grin 0
+ \grin 1
+};
+
+void cvMatSend(const CvMat *self, FObject *obj, int outno) {
+ int m = self->rows;
+ int n = self->cols;
+ int e = CV_MAT_TYPE(cvGetElemType(self));
+ int c = CV_MAT_CN( cvGetElemType(self));
+ GridOutlet *out = new GridOutlet(obj,0,new Dim(m,n));
+ for (int i=0; i<m; i++) {
+ uchar *meuh = cvPtr2D(self,i,0,0);
+ switch (e) {
+ case CV_8U: out->send(c*n, (uint8 *)meuh); break;
+ case CV_16S: out->send(c*n, (int16 *)meuh); break;
+ case CV_32S: out->send(c*n, (int32 *)meuh); break;
+ case CV_32F: out->send(c*n,(float32 *)meuh); break;
+ case CV_64F: out->send(c*n,(float64 *)meuh); break;
+ }
+ }
+}
+
+\def void _0_bang () {
+ const CvMat *r = cvKalmanPredict(kal,0);
+ cvMatSend(r,this,0);
+}
+
+GRID_INLET(CvKalmanWrapper,0) {
+ in->set_chunk(0);
+} GRID_FLOW {
+ PtrGrid l = new Grid(in->dim,(T *)data);
+ CvMat *a = (CvMat *)cvGrid(l,mode,2);
+ const CvMat *r = cvKalmanPredict(kal,a);
+ cvMatSend(r,this,0);
+} GRID_END
+
+GRID_INLET(CvKalmanWrapper,1) {
+ in->set_chunk(0);
+} GRID_FLOW {
+ PtrGrid l = new Grid(in->dim,(T *)data);
+ CvMat *a = (CvMat *)cvGrid(l,mode,2);
+ const CvMat* r = cvKalmanCorrect(kal,a);
+ cvMatSend(r,this,0);
+} GRID_END
+\end class {install("cv.Kalman",2,1);}
+
+//\class CvEllipse : FObject {
+// \grin 0
+//};
+//GRID_INLET(CvEllipse,0) {
+// in->set_chunk(0);
+//} GRID_FLOW {
+//} GRID_END
+//\end class {install("cv.Ellipse",1,1);}
+
+/*
+void cvEllipse( CvArr* img, CvPoint center, CvSize axes, double angle,
+ double start_angle, double end_angle, CvScalar color,
+ int thickness=1, int line_type=8, int shift=0 );
+CvSeq* cvApproxPoly( const void* src_seq, int header_size, CvMemStorage* storage,
+ int method, double parameter, int parameter2=0 );
+void cvCalcOpticalFlowHS( const CvArr* prev, const CvArr* curr, int use_previous,
+ CvArr* velx, CvArr* vely, double lambda,
+ CvTermCriteria criteria );
+void cvCalcOpticalFlowLK( const CvArr* prev, const CvArr* curr, CvSize win_size,
+ CvArr* velx, CvArr* vely );
+void cvCalcOpticalFlowBM( const CvArr* prev, const CvArr* curr, CvSize block_size,
+ CvSize shift_size, CvSize max_range, int use_previous,
+ CvArr* velx, CvArr* vely );
+void cvCalcOpticalFlowPyrLK( const CvArr* prev, const CvArr* curr, CvArr* prev_pyr, CvArr* curr_pyr,
+ const CvPoint2D32f* prev_features, CvPoint2D32f* curr_features,
+ int count, CvSize win_size, int level, char* status,
+ float* track_error, CvTermCriteria criteria, int flags );
+void cvCalcBackProject( IplImage** image, CvArr* back_project, const CvHistogram* hist );
+void cvCalcHist( IplImage** image, CvHistogram* hist, int accumulate=0, const CvArr* mask=NULL );
+CvHistogram* cvCreateHist( int dims, int* sizes, int type, float** ranges=NULL, int uniform=1 );
+void cvSnakeImage( const IplImage* image, CvPoint* points, int length,
+ float* alpha, float* beta, float* gamma, int coeff_usage,
+ CvSize win, CvTermCriteria criteria, int calc_gradient=1 );
+int cvMeanShift( const CvArr* prob_image, CvRect window, CvTermCriteria criteria, CvConnectedComp* comp );
+int cvCamShift( const CvArr* prob_image, CvRect window, CvTermCriteria criteria, CvConnectedComp* comp, CvBox2D* box=NULL );
+*/
+
+/* **************************************************************** */
+
+static int erreur_handleur (int status, const char* func_name, const char* err_msg, const char* file_name, int line, void *userdata) {
+ cvSetErrStatus(CV_StsOk);
+ // we might be looking for trouble because we don't know whether OpenCV is throw-proof.
+ RAISE("OpenCV error: status='%s' func_name=%s err_msg=\"%s\" file_name=%s line=%d",cvErrorStr(status),func_name,err_msg,file_name,line);
+ // if this breaks OpenCV, then we will have to use post() or a custom hybrid of post() and RAISE() that does not cause a
+ // longjmp when any OpenCV functions are on the stack.
+ return 0;
+}
+
+void startup_opencv() {
+ /* CvErrorCallback z = */ cvRedirectError(erreur_handleur);
+ \startall
+}