fast conversion of IplImage to Numpy array - opencv

The newer OpenCV documentation here says you can convert an IplImage to a Numpy array just like this:
arr = numpy.asarray( im )
but that doesn't work for my needs, because it apparently doesn't support math:
x = arr/0.01
TypeError: unsupported operand type(s) for /: 'cv2.cv.iplimage' and 'float'
If I try to specify data type, I can't even get that far:
arr = numpy.asarray( im, dtype=num.float32 )
TypeError: float() argument must be a string or a number
So I'm using the code provided in the older documentation here. Basically, it does this:
arr = numpy.fromstring( im.tostring(), dtype=numpy.float32 )
But the tostring call is really slow, perhaps because it's copying the data? I need this conversion to be really fast and not copy any buffers it doesn't need to. I don't think the data are inherently incompatible; I'm creating my IplImage with cv.fromarray in the first place, which is extremely fast and accepted by the OpenCV functions.
Is there a way I can make the newer asarray method work for me, or else can I get direct access to the data pointer in the IplImage in a way that numpy.fromstring will accept it? I'm using OpenCV 2.3.1 prepackaged for Ubuntu Precise.

Fun Fact:
Say you call:
import cv2.cv as cv #Just a formality!
Capture = cv.CaptureFromCAM(0)
Img = cv.QueryFrame(Capture)
The object Img is an ipimage, and numpy.asarray(Img) is erratic at best. However! Img[:,:] is a cvmat type, and numpy.asarray(Img[:,:]) works fantastically, and more important: quickly!
This is by far the fastest way I've found to grab a frame and make it an ndarray for numpy processing.

That page does not say about IplImage. It says about CvMat which is different.
Anyway you'd better use wrappers from newer cv2 namespace. It natively uses numpy arrays instead of own image containers. Also the whole cv module is considered deprecated and will be completely dropped in the nearest major release.

Related

EmguCV 3.0.0 - CvInvoke.cvConvert equivalent

I want to convert between Matrix and Image in EmguCV 3.0.0.
I saw in this video (https://www.youtube.com/watch?v=DfTS5a9xmwo) that you can do this with the CvInvoke.cvConvert method. But it seems this method doesn't exist anymore in EmguCV 3.0.0. I did find the method CVInvoke.ConvertMaps , but this method requires two input and two output arrays. Is this method equivalent if I use empty arrays as the second arrays?
Try the (.ToImage) method. It operates to convert to a Matrix to an image. a working example in C# is:
Image<Bgr,Byte> img1 = imgMat.ToImage<Bgr, Byte>();
You can also change it to a grayscale by using (gray,byte)
You can also find an example in VB at (http://www.emgu.com/forum/viewtopic.php?t=5209).

How to get depth and channel for a cvMat?

I am convert a numpy array to a cvMat using fromArray() function. Now when I try to apply Threshold on it I get the below error
OpenCV Error: Unsupported format or combination of formats () in threshold
On checking on stackoverflow I see that it might be an issue with the channel or depth of my image. But I am not sure how can I check that for a cvMat. Could somebody tell me how to check the depth and number of channels for a cvMat in python.
Well, you can't directly get it from a cvMat because cvMats have types instead of depth/channels, so
print mymat.type
returns the type code.
If you want to get the depth and channel number, the easiest way I've found is to generate the IplImage header with cv.GetImage like
print cv.GetImage(mymat).depth,cv.GetImage(mymat).nChannels
I believe cv2 does away with all of that IplImage/cvMat stuff and rolls it all into Mat though.

How to determine the human-readable type of a cv::Mat?

My current problem is that I would like to know the type of the cv::Mat-frames grabbed by cv::VideoCapture from a video file. The documentation doesn't specify that (as is often the case, so even if I have overlooked it in this particular case, it would still be helpful to get an answer for dealing with the problem in general).
Of course, I could open the appropriate OpenCV header file and go through the CV_64FC2, ... macros to find a macro which matches the Mat's type(). But I'm kind of sick of that. There must be an easier way.
Isn't there any function that lets me translate a Mat's type() to a human-readable format ? Like this:
cv::Mat myMatWithUnknownType;
// Some code modifying myMatWithUnknownType.
// ...
std::string readableType = myMatWithUnknownType.typeString();
std::cout << readableType; // Prints "CV_64FC3".
How do you deal with that?
First, the format that come from cameras is only one: CV_8UC3. This is hardcoded in OpenCV, and any video format is converted to this before being sent to user. So
capture >> frame;
Will always return a RGB image, of 8 bits per channel.
Now, for other types you can write your function, keeping in mid that there are not so many types supported in OpenCV: A Mat can be of type char, uchar, short, ushort, int, uint, float, double, of 1 to 512 channels (according to the latest docs.) So writing your own type_to_string() is not difficult.

How to save CV_32F type CV::Mat to a file without loosing precision?

I'm using cv::PCA class for a face recognition project. I convert photos of faces to one row vectors, concatenate them to one big array and feed to pca, to acquire a new space in which I can try to use distance for recognition. Problem is, that calculating the pca from scratch each time I start the program is really time consuming (almost five minutes). I figured out that I need to save the calculated pca to hard drive, and load it when I start the program again. And here is the problem. As I can see, all cv::Mat objects in cv::PCA are of type CV_32F. When i try to save it as a normal picture, its converted to 8 bit image, and there is some data lost. When i use XML/YAML persistence, the generated file is really big, and data is also lost (I have saved it, loaded to another structure and ran cerr<<sum(pca_orginal.mean==pca_loaded.mean)[0]<<endl to check how big is the difference). Right now I'm trying to use std::ofstream::write with std::ofstream::binary flag, and istream::read, but there are some type issues (out.write(_pca.mean.data,_pca.mean.rows*_pca.mean.cols*4/*CV_32F->4*CV_8U*/\); generates error: no matching function for call to ‘std::basic_ofstream<char, std::char_traits<char> >::write(uchar*&, int). I've also heard about openexr library and it's file format, but I would rather avoid using additional libraries. I'm using OpenCV 2.3.1 and OpenCV 2.2.
edit:
I'm sorry for the confusion. I misread cv::Mat operator== description, and thought that it works the opposite way that it does, so sum(pca_orginal.mean==pca_loaded.mean)[0] giving 0 is the worse possible result, not the best. It means that XML/YML works fine apart from generating huge files. Also, after using c-style casting I was able to make the binary streams work, but the files generated are also big (over 150MB).
In the C interface, there are functions cvSave and cvLoad for saving arbitrary matrices. There are probably C++ interface counterparts, too.

How to read a bitmap in OCAML?

I want to read a bitmap file (from the file system) using OCAML and store the pixels (the colors) inside an array which have th dimension of the bitmap, each pixel will take one cell in the array.
I found the function Graphics.dump_image image -> color array array
but it doesn't read from a file.
CAMLIMAGE should do it. There is also a debian package (libcamlimage-ocmal-dev), as well as an installation through godi, if you use that to manage your ocaml packages.
As a useful example of reading and manipulating images in ocaml, I suggest looking over the code for a seam removal algorithm over at eigenclass.
You can also, as stated by jonathan --but not well-- call C functions from ocaml, such as ImageMagick. Although you're going to do a lot of manipulation of the image data to bring the image into ocaml, you can always write c for all your functions to manipulate the image as an abstract data type --this seems to be completely opposite of what you want though, writing most of the program in C not ocaml.
Since I recently wanted to play around with camlimages (and had some trouble installing it --I had to modify two of the ml files from compilation errors, very simple ones though). Here is a quick program, black_and_white.ml, and how to compile it. This should get someone painlessly started with the package (especially, dynamic image generation):
let () =
let width = int_of_string Sys.argv.(1)
and length = int_of_string Sys.argv.(2)
and name = Sys.argv.(3)
and black = {Color.Rgb.r = 0; g=0; b=0; }
and white = {Color.Rgb.r = 255; g=255; b=255; } in
let image = Rgb24.make width length black in
for i = 0 to width-1 do
for j = 0 to (length/2) - 1 do
Rgb24.set image i j white;
done;
done;
Png.save name [] (Images.Rgb24 image)
And to compile,
ocamlopt.opt -I /usr/local/lib/ocaml/camlimages/ ci_core.cmxa graphics.cmxa ci_graphics.cmxa ci_png.cmxa black_and_white.ml -o black_and_white
And to run,
./black_and_white 20 20 test1.png
I don't know of an out-of-the box way to do it. You could open the file with open_in and read it byte at a time with input_char, suck in the header and the data and build up the color array array that way for simple formats (e.g. BMPs) but for anything like JPGs or PNGs a roll your-own solution would probably be more work than you want to get into.
You could also use one of the numerous SDL bindings for OCaml, specifically the SDL_image ones, which let you load all kinds of images easily, and provides functions to access individual pixels and raw data as an array.
OCamlSDL is a popular one.
If you don't want to use CAMLIMAGE, usually raw RGB or PNM/PPM (which have an easy to create header format followed by RGB values) images are used. ImageMagick allows you to then view this formats or convert them into more usable formats.

Resources