Posts Tagged “opencv”

Well, I just finished adding support for a Bumblebee2 camera to OpenCV. I wish I could give the code away, but it depends on Triclops, Point Grey’s proprietary library and I don’t really know how to submit a patch to OpenCV anyway. For those of you who are interested in accessing stereo vision capabilities for this type of camera through OpenCV, let me know and I can send you some patches or point you in the right direction.

The main useful source of information turned out to be this wiki on how to setup the Triclops library and the more important libpgrlibdcstereo. The latter is distributed with examples for reading right and left stereo channels using the library and computing disparities, which formed the basis for my OpenCV code. I followed the structure of cvcap*.cpp code and used calls to pgrstereolib to actually perform the capture.

[I noticed that support for Videre stereo cameras was already included. I suppose that must be what they use at Willow Garage. I was able to read from my Bumblebee2 camera without any code changes, but could not figure out how to access the channels separately or compute disparities.]

The tricky part is getting everything into OpenCV. This required adding a small number of carefully placed lines of code to the CMake files and a small number of careful #defines in the highgui source. The project is mature enough, and the patterns consistent enough, that doing so really just meant looking for how other’s did it for other, similar features.

ASIDE: For some weird reason libpgrlibstereo comes with an LGPL license, which might be compatible with OpenCV, but makes calls to Triclops, which doesn’t seem to have any license other than “you bought our very expensive camera so you get this library.” That, as I understand things, sort of nullifies the use of libpgrlibstereo in any setting where we would normally like to use LGPL library code.

Comments 8 Comments »

I got the following error when trying to compile the latest svn version of opencv:

error: invalid controlling predicate

A quick Google search yielded this gem of a compiler bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=38650.

The offending loop:

#ifdef _OPENMP
#pragma omp for schedule(static, 1)
#endif /* _OPENMP */
for( i = first; (i < first + count) && next; i++ )

That is all.

UPDATE: Turns out I was using a stale configuration file from svn for this build. It seems like OpenCV has entirely too many build systems. They should ditch autoconf and go with cmake exclusively.

Comments No Comments »

You may have come across the following issue with OpenCV Python bindings:

image = cv.cvCreateImage(size, cv.IPL_DEPTH_8U, 3)
image.imageData = data # set some data

Trying to set the “data” of an OpenCV image directly fails. The problem is in the underlying SWIG code that attempts to make the imageData field available for writing at the python level. You can see in CVS that the code gets fixed immediately after the 1.0 release.

But wait! Doesn’t OpenCV come with an adaptors.py that is supposed to provide methods for translating between various Python data types (NumPy < => PIL < => IplImage) ?

A quick look at the code:

def PIL2Ipl(input):
    """Converts a PIL image to the OpenCV/IPL CvMat data format.
 
    Supported input image formats are:
        RGB
        L
        F
    """
 
    if not isinstance(input, PIL.Image.Image):
       raise TypeError, 'must be called with PIL.Image.Image!'
 
    size = cv.cvSize(input.size[0], input.size[1])
 
    # mode dictionary:
    # (pil_mode : (ipl_depth, ipl_channels, color model, channel Seq)
    mode_list = {
        "RGB" : (cv.IPL_DEPTH_8U, 3),
        "L"   : (cv.IPL_DEPTH_8U, 1),
        "F"   : (cv.IPL_DEPTH_32F, 1)
        }
 
    if not mode_list.has_key(input.mode):
        raise ValueError, 'unknown or unsupported input mode'
 
    modes = mode_list[input.mode]    
 
    result = cv.cvCreateImage(
        size,
        modes[0], # depth
        modes[1]  # channels
        )
 
    # set imageData
    result.imageData=input.tostring() #FAIL!
 
    return result

As you can see, adaptors.py tries to set imageData as well, and so fails to convert from any format into IplImage. Your options are to work from the repository version of OpenCV or to back port the change from the repository to your local installation. Both require compiling from source and so as you may imagine, neither case is convenient when working with libcv as installed from your favorite package manager of choice.

A third option is to back port the changes from the repository to your own custom swig module whose only goal is to implement a function that sets the imageData field properly. That’s the approach I took, and though it took a considerable amount of time to implement (because I don’t really understand SWIG), the end result did not require many lines of code. Here’s my iplimage.i file:

%module iplimage
%{
#include "cv.h"
void set(CvMat *self, char *string);
%}
 
void set(CvMat *self, char *string);

And here’s iplimage.c copied with minor changes directly out of the repository for OpenCV:

#include "cv.h"
 
void set(CvMat * self, char *string)
{
	int depth = CV_MAT_DEPTH(self-&gt;type);
	int cn = CV_MAT_CN(self-&gt;type);
	int step = self-&gt;step ? self-&gt;step : CV_ELEM_SIZE(self-&gt;type) * self-&gt;cols;
	long line;
	long pixel;
 
	if (depth == CV_8U &amp;&amp; cn==3){
		// RGB case
		// The data is reordered beause OpenCV uses BGR instead of RGB
 
		for (line = 0; line &lt; self-&gt;rows; ++line)
			for (pixel = 0; pixel &lt; self-&gt;cols; ++pixel)
			{
				// In OpenCV the beginning of the lines are aligned
				// to 4 Bytes. So use step instead of cols.
				long position = line*step + pixel*3;
				long sourcepos = line*self-&gt;cols*3 + pixel*3;
				self-&gt;data.ptr[position  ] = string[sourcepos+2];
				self-&gt;data.ptr[position+1] = string[sourcepos+1];
				self-&gt;data.ptr[position+2] = string[sourcepos  ];
			}
	}
	else if (depth == CV_8U &amp;&amp; cn==1)
	{
		// Grayscale 8bit case
 
		for (line = 0; line &lt; self-&gt;rows; ++line)
		{
			// In OpenCV the beginning of the lines are aligned
			// to 4 Bytes. So use step instead of cols.
			memcpy
				(
				 self-&gt;data.ptr + line*step,
				 string + line*self-&gt;cols,
				 step
				);
		}
	}
	else if ( depth == CV_32F )
	{
		// float (32bit) case
		for (line = 0; line &lt; self-&gt;rows; ++line)
		{
			// here we don not have to care about alignment as the Floats are
			// as long as the alignment
			memcpy
				(
				 self-&gt;data.ptr + line*step,
				 string + line*self-&gt;cols*sizeof(float),
				 step
				);
		}
	}
	else if ( depth == CV_64F )
	{
		// double (64bit) case
		for (line = 0; line &lt; self-&gt;rows; ++line)
		{
			// here we don not have to care about alignment as the Floats are
			// as long as the alignment
			memcpy
				(
				 self-&gt;data.ptr + line*step,
				 string + line*self-&gt;cols*sizeof(double),
				 step
				);
		}
	}
	else
	{
	}
}

An example makefile that works on my system:

CFLAGS= `pkg-config --cflags opencv`
LDFLAGS= `pkg-config --libs opencv` -L.
CXX=g++
 
_iplimage.so: iplimage.c
	swig -python iplimage.i
	$(CXX) $(CFLAGS) -I/usr/include/python2.5 -c iplimage.c iplimage_wrap.c
	$(CXX) $(LDFLAGS) -shared iplimage.o iplimage_wrap.o -o _iplimage.so

If you manage to build the module, you can then invoke it from python using a call to iplimage.set(image,data) to set the imageData field for real. You can use the default OpenCV Python bindings that come with your package manager and simply install this small additional module. Hopefully, we’ll see a new release of OpenCV soon that negates the need for any of these acrobatics.

Comments 12 Comments »

A day of reading the SWIG manual and grokking the examples resulted in the following interface file. What does it do? It adds this to Python.

%module blobs
 
%exception
    {
    try { $action } 
    catch (...) 
        {
        return NULL;
        } 
    }
 
 
%include "exception.i"
 
%typemap(in) IplImage * (IplImage header){
	void * vptr;
	int res = SWIG_ConvertPtr($input, (&vptr), $descriptor( CvMat * ), 0);
	if ( res == -1 ){
		SWIG_exception( SWIG_TypeError, "%%typemap(in) IplImage * : could not convert to CvMat");
		SWIG_fail;
	}
	$1 = cvGetImage((CvMat *)vptr, &header);
}
 
%typemap(in) IplImage *mask{
	if ($input == Py_None){
	   $1 = NULL;
	}
	else {
		SWIG_exception( SWIG_TypeError, "%%typemap(in) IplImage *mask : masks not supported yet.");
		SWIG_fail;
	}
}
 
%typecheck(SWIG_TYPECHECK_POINTER) IplImage * {
  void *ptr;
  if (SWIG_ConvertPtr($input, (void **) &ptr, $descriptor( CvMat * ), 0) == -1) {
    $1 = 0;
    PyErr_Clear();
  } else {
    $1 = 1;
  }
}
 
%{
#include "BlobResult.h"
#include "Blob.h"
%}
%include "BlobResult.h"
%include "Blob.h"

Comments No Comments »