Login | Register 
Products Applications Downloads Features Wiki forum Store
 

Using open CV in touch.

General discussion about anything TouchDesigner

Using open CV in touch.

Postby xpat1024 » Tue May 03, 2011 6:46 am

Hi All,
I've started looking at getting openCV into touch as one of my little side projects. I scanned though the forum to see if see if this was possible. I was pleased to find Malcolm saying it was possible but only though the CUDA TOP. Is this still true, has anyone find other ways? If CUDA TOP is still the only way, has anyone got this working successfully? CUDA is not something I've had much experience with... it's on my 'will get to at some point list.' :P Does anyone have a very simple example using the code that Malcolm suggested?
Code: Select all
cudaMemcpy(output->data, yourData, yourDataSize, cudaMemcpyHostToDevice)


Basically all I want to start with is; take TOP input, do use openCV on the input, Output as TOP.

Thanks
xpat1024
 
Posts: 5
Joined: Tue Aug 03, 2010 11:46 am

Re: Using open CV in touch.

Postby Achim » Tue May 03, 2011 7:33 am

I guess malcolm posted that before the c++ TOP was added, so these days you can do it via the c++ TOP. Unfortunately there isn't too much of documentation/examples out there. Some bits on the wiki, and some info in the forum...
User avatar
Achim
 
Posts: 1505
Joined: Wed Nov 14, 2007 12:52 pm

Re: Using open CV in touch.

Postby malcolm » Tue May 03, 2011 10:51 am

Ya, the CPlusPlus TOP would be faster in the long run since it requires less GPU->GPU memory copies, but a bit more work.

To get started with the CPlusPlus TOP you'd first need to get your image data from the input texture into CPU memory. Then you'd run your OpenCV code, and finally upload the resulting image to the output. To do this you'd run this code in the execute() function

Code: Select all

// Allocate pace for width*height*3channels,
// you'll want to cache this as a member of your class to avoid allocating it
// every frame
unsigned char *imageData = new char[arrays->TOPInputs[0].width * arrays->TOPInputs[0].height * 3];

// Bind the texture
::glBindTexture(GL_TEXTURE_2D, arrays->TOPInputs[0].textureIndex);

// Download the texture into imageData
// GL_BGR is far faster than GL_RGB, use a Reorder TOP before the CPlusPlus TOP
// if your OpenCV usage requires proper channel ordering.
::glGetTexImage(GL_TEXTURE_2D, 0, GL_BGR, GL_UNSIGNED_BYTE, imageData);

// Run your openCV code here on image data

// Upload back to the output framebuffer.
// This assumes your input resolution is the same as your output.
::glDrawPixels(arrays->TOPInputs[0].width, arrays->TOPInputs[0].height, GL_BGR, GL_UNSIGNED_BYTE, openCVOutputImageData);


This is the basic code that will get you started. It won't be fast since downloading from the GPU will stall the rendering pipeline. Once you have this working post again and we can go into using pixel_buffer_objects to do asynchronous uploads/downloads.

It's also important to note that your resolution width should be a multiple of 4. If it's not then you'll need deal with byte-alignment issues using glPixelStorei(), which I can get into if needed also (since OpenCV requires pixel rows to be a multiple of 4 bytes in size )

This seems like a common enough issue that I should add the ability to do the download for you manually. I'll add an RFE for that for our next major release.
User avatar
malcolm
Staff
 
Posts: 2184
Joined: Tue Nov 13, 2007 12:11 am

Re: Using open CV in touch.

Postby xpat1024 » Tue May 03, 2011 2:18 pm

Thanks Malcolm, I will get playing with that. I'll be back when I have more questions. :)
xpat1024
 
Posts: 5
Joined: Tue Aug 03, 2010 11:46 am

Re: Using open CV in touch.

Postby malcolm » Tue May 03, 2011 2:20 pm

Just fixed a typo also, it should have said "glGetTexImage"
User avatar
malcolm
Staff
 
Posts: 2184
Joined: Tue Nov 13, 2007 12:11 am

Re: Using open CV in touch.

Postby Mary » Fri Sep 02, 2011 8:48 pm

Here's an example of openCV in a c++ TOP that runs corner detection-- generally a good algorithm for finding points of interest. Thanks Malcom and Barry for assistance.

CPlusPlusTopExample.h
Code: Select all
#include "TOP_CPlusPlusBase.h"
#include "cv.h"
#include "cxcore.h"
#include "cxtypes.h"
#include <gl/gl.h>

#define RES_X 640
#define RES_Y 480
#define MAX_CORNERS 60

class CPlusPlusTOPExample : public TOP_CPlusPlusBase
{
public:
   CPlusPlusTOPExample(const TOP_NodeInfo *info);
   CvSize topInSize;
   IplImage *cvImageData;
   IplImage *grayData;
   IplImage *grayData1;
   IplImage* harrisImg;
   IplImage *eigImg;
    char *glImageData;
   CvScalar target_color;
   CvPoint2D32f corners[MAX_CORNERS];
   int corner_count;

   GLuint               tid1;

   virtual ~CPlusPlusTOPExample();

   virtual void      getGeneralInfo(TOP_GeneralInfo *);
   virtual bool      getOutputFormat(TOP_OutputFormat*);


   virtual void      execute(const TOP_OutputFormatSpecs*,
                        const TOP_InputArrays*,
                        void* reserved);


   virtual int         getNumInfoCHOPChans();
   virtual void      getInfoCHOPChan(int index,
                              TOP_InfoCHOPChan *chan);

   virtual bool      getInfoDATSize(TOP_InfoDATSize *infoSize);
   virtual void      getInfoDATEntries(int index,
                                 int nEntries,
                                 TOP_InfoDATEntries *entries);
private:

   const TOP_NodeInfo      *myNodeInfo;
   int                   myExecuteCount;


};




.cpp file: the goods are in CPlusPlusTOPExample::CPlusPlusTOPExample and CPlusPlusTOPExample::execute

Code: Select all
#include <windows.h>
#include "CPlusPlusTOPExample.h"
#include <stdio.h>
#include <string.h>
#include <gl/gl.h>
#include <math.h>
#include <iostream>

using namespace std;
using namespace cv;


extern "C"
{

DLLEXPORT
int
GetTOPAPIVersion(void)
{
   return TOP_CPLUSPLUS_API_VERSION;
}

DLLEXPORT
TOP_CPlusPlusBase*
CreateTOPInstance(const TOP_NodeInfo *info)
{
   return new CPlusPlusTOPExample(info);
}

DLLEXPORT
void
DestroyTOPInstance(TOP_CPlusPlusBase *instance)
{
   delete (CPlusPlusTOPExample*)instance;
}

};


CPlusPlusTOPExample::CPlusPlusTOPExample(const TOP_NodeInfo *info) : myNodeInfo(info)
{
   myExecuteCount = 0;
   target_color =cvScalar(255,0,0,0);
   topInSize= cvSize(RES_X,RES_Y);
        //make a header for the gl data
   cvImageData = cvCreateImageHeader(topInSize, IPL_DEPTH_8U,3);
   grayData = cvCreateImage(topInSize,IPL_DEPTH_8U,1);
   grayData1 = cvCreateImage(topInSize,IPL_DEPTH_8U,1);
   eigImg = cvCreateImage(topInSize,IPL_DEPTH_8U,1);
   harrisImg = cvCreateImage(topInSize, IPL_DEPTH_32F, 1);
    glImageData = new char[RES_X * RES_Y * 3];
   glGenTextures(1, &tid1);
   glBindTexture(GL_TEXTURE_2D, tid1);
   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, RES_X, RES_Y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}

CPlusPlusTOPExample::~CPlusPlusTOPExample()
{
   cvReleaseImage( &grayData);
    cvReleaseImage( &grayData1);
    cvReleaseImage( &cvImageData);
    cvReleaseImage( &eigImg);
    cvReleaseImage( &harrisImg);
}

void
CPlusPlusTOPExample::getGeneralInfo(TOP_GeneralInfo *ginfo)
{
   ginfo->cookEveryFrame = true;
}

bool
CPlusPlusTOPExample::getOutputFormat(TOP_OutputFormat *format)
{
   return false;
}


void
CPlusPlusTOPExample::execute(const TOP_OutputFormatSpecs* outputFormat ,
                        const TOP_InputArrays* arrays,
                        void* reserved)
{

    // Bind the texture
    ::glBindTexture(GL_TEXTURE_2D, arrays->TOPInputs[0].textureIndex);
    ::glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, glImageData);
   cvImageData->imageData = glImageData; //give gl data to an IplImage

    // <openCV> Run your openCV code on cvImageData
   int neighborhood= int(arrays->floatInputs->values[0]); //get TOP input floats
   int sobelAperture= int(arrays->floatInputs->values[1]);
   double harrisScalar= double(arrays->floatInputs->values[2]);
    cvCvtColor(cvImageData, grayData1, CV_RGB2GRAY); 
     //cvCanny( grayData1, grayData, 45, 60, 3 );  //edge detection
   //cornerHarris returns an image | harrisImg must be 32f
   cvCornerHarris(grayData1, harrisImg, neighborhood, sobelAperture,harrisScalar);
   cvConvertScale(harrisImg, grayData);  ///32 f -> 8 bit unsigned
       //overwrite the input img with the harris img for visual feedback
   cvCvtColor(grayData, cvImageData, CV_GRAY2RGB);

   //goodFeaturesToTrack returns location of corners
   corner_count = MAX_CORNERS;
   double quality_level = 0.1;
   double min_distance = 50;
   int eig_block_size = 4;
   int use_harris = false;
 
   cvGoodFeaturesToTrack(grayData, eigImg, grayData1, corners, &corner_count, quality_level, min_distance, NULL, eig_block_size,   use_harris);
   for( int i = 0; i < corner_count; i++) {
         int radius = RES_Y/25;
         cvCircle(cvImageData, cvPoint((int)(corners[i].x + 0.5f),(int)(corners[i].y + 0.5f)), radius, target_color);
      }
   // </openCV>

   //// DRAW IT

   glEnable(GL_TEXTURE_2D);
   glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
   glBindTexture(GL_TEXTURE_2D, tid1);
   glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, RES_X, RES_Y, GL_RGB, GL_UNSIGNED_BYTE, (BYTE *)cvImageData->imageData); 
   
   glBegin(GL_QUADS);
      glTexCoord2f(0, 1);
      glVertex2f(0, RES_Y);
      glTexCoord2f(1, 1);
      glVertex2f(RES_X, RES_Y);
      glTexCoord2f(1, 0);
      glVertex2f(RES_X, 0);
      glTexCoord2f(0, 0);
      glVertex2f(0, 0);
   glEnd();

   glDisable(GL_TEXTURE_2D);
   
}

int
CPlusPlusTOPExample::getNumInfoCHOPChans()
{
   return 1;
}

void
CPlusPlusTOPExample::getInfoCHOPChan(int index,
                              TOP_InfoCHOPChan *chan)
{

   if (index == 0)
   {
      chan->name = "executeCount";
      chan->value = myExecuteCount;
   }
}

bool      
CPlusPlusTOPExample::getInfoDATSize(TOP_InfoDATSize *infoSize)
{
   infoSize->rows = corner_count;
   infoSize->cols = 3;
   // Setting this to false means we'll be assigning values to the table
   // one row at a time. True means we'll do it one column at a time.
   infoSize->byColumn = false;
   return true;
}

void
CPlusPlusTOPExample::getInfoDATEntries(int index,
                              int nEntries,
                              TOP_InfoDATEntries *entries)
{
   if (index == 0)
   {
      // It's safe to use static buffers here because Touch will make it's own
      // copies of the strings immediately after this call returns
      // (so the buffers can be reuse for each column/row)
      static char tempBuffer1[4096];  //col1
      static char tempBuffer2[4096];  //2
      static char tempBuffer3[4096];  //3
      
      for( int i = 0; i < corner_count; i++) {
         // Set the value for the first column - ID
         sprintf(tempBuffer1, "%d", i);
         entries->values[0] = tempBuffer1;

         // Set the value for the second column -X
         sprintf(tempBuffer2, "%d", corners[1].x);
         entries->values[1] = tempBuffer2;
         // Set the value for the second column -Y
         sprintf(tempBuffer3, "%d", corners[1].y);
         entries->values[2] = tempBuffer3;
      }
   }
}



I'm still working on writing my corner data out to the info DAT properly.
Mary
 
Posts: 9
Joined: Fri May 21, 2010 3:22 pm

Re: Using open CV in touch.

Postby tcfr33 » Tue Apr 03, 2012 5:58 pm

I have compiled your OpenCV example against OpenCV 2.1. When I try to load it in the CPlusPlus TOP TD crashes. I've tried it on 16900 and the newest 17780 builds. I thought it might be because TD was trying to use the 2.0 libs so I copied cv210.dll etc. into the TD bin directory with no change. The CPlusPlus TOP demo dll runs just fine. Any ideas? I'd love to get OpenCV working.

Thanks,
Thadeus

Win7 64bit
Core i7
8GB RAM
NVIDIA Geforce 525m
tcfr33
 
Posts: 31
Joined: Mon Aug 22, 2011 6:28 pm

Re: Using open CV in touch.

Postby malcolm » Tue Apr 03, 2012 6:06 pm

I think the openCV .dlls you want to use should be next to the .dll you have created. Is there something in opencv 2.1 you need in particular? If not then I can post the openCV header/libs we use so you can link against those.
User avatar
malcolm
Staff
 
Posts: 2184
Joined: Tue Nov 13, 2007 12:11 am

Re: Using open CV in touch.

Postby tcfr33 » Tue Apr 03, 2012 7:00 pm

OpenCV 2.1 is just the version I happened to install to work with Visual C++. I didn't know TD was using 2.0 at the time. I tried copying the opencv dlls into the VC++ build folder with the new dll. No luck there either.
I've attached the crash dump file. I'll try building against OpenCV 2.0 next

Thanks
Attachments
TouchCrashFTE077.17780.3.dmp
(121.95 KiB) Downloaded 7 times
tcfr33
 
Posts: 31
Joined: Mon Aug 22, 2011 6:28 pm

Re: Using open CV in touch.

Postby tcfr33 » Wed Apr 04, 2012 4:50 am

It still doesn't work in OpenCV2.0. When compiled my ddls are a different size (1.34MB vs 1.56MB for cv200.dll) than the ones included with TD. If you get a chance to post the headers and libs that would be great Malcolm.

T
tcfr33
 
Posts: 31
Joined: Mon Aug 22, 2011 6:28 pm

Next

Return to General TouchDesigner Discussion

Who is online

Users browsing this forum: No registered users and 1 guest

cron