Converting cv::Mat to IplImage* - c++

The documentation on this seems incredibly spotty.
I've basically got an empty array of IplImage*s (IplImage** imageArray) and I'm calling a function to import an array of cv::Mats - I want to convert my cv::Mat into an IplImage* so I can copy it into the array.
Currently I'm trying this:
while(loop over cv::Mat array)
{
IplImage* xyz = &(IplImage(array[i]));
cvCopy(iplimagearray[i], xyz);
}
Which generates a segfault.
Also trying:
while(loop over cv::Mat array)
{
IplImage* xyz;
xyz = &array[i];
cvCopy(iplimagearray[i], xyz);
}
Which gives me a compile time error of:
error: cannot convert ‘cv::Mat*’ to ‘IplImage*’ in assignment
Stuck as to how I can go further and would appreciate some advice :)

cv::Mat is the new type introduce in OpenCV2.X while the IplImage* is the "legacy" image structure.
Although, cv::Mat does support the usage of IplImage in the constructor parameters, the default library does not provide function for the other way. You will need to extract the image header information manually. (Do remember that you need to allocate the IplImage structure, which is lack in your example).

Mat image1;
IplImage* image2=cvCloneImage(&(IplImage)image1);
Guess this will do the job.
Edit: If you face compilation errors, try this way:
cv::Mat image1;
IplImage* image2;
image2 = cvCreateImage(cvSize(image1.cols,image1.rows),8,3);
IplImage ipltemp=image1;
cvCopy(&ipltemp,image2);

(you have cv::Mat old)
IplImage copy = old;
IplImage* new_image = ©
you work with new as an originally declared IplImage*.

Here is the recent fix for dlib users link
cv::Mat img = ...
IplImage iplImage = cvIplImage(img);

Personaly I think it's not the problem caused by type casting but a buffer overflow problem; it is this line
cvCopy(iplimagearray[i], xyz);
that I think will cause segment fault, I suggest that you confirm the array iplimagearray[i] have enough size of buffer to receive copyed data

According to OpenCV cheat-sheet this can be done as follows:
IplImage* oldC0 = cvCreateImage(cvSize(320,240),16,1);
Mat newC = cvarrToMat(oldC0);
The cv::cvarrToMat function takes care of the conversion issues.

In case of gray image, I am using this function and it works fine! however you must take care about the function features ;)
CvMat * src= cvCreateMat(300,300,CV_32FC1);
IplImage *dist= cvCreateImage(cvGetSize(dist),IPL_DEPTH_32F,3);
cvConvertScale(src, dist, 1, 0);

One problem might be: when using external ipl and defining HAVE_IPL in your project, the ctor
_IplImage::_IplImage(const cv::Mat& m)
{
CV_Assert( m.dims <= 2 );
cvInitImageHeader(this, m.size(), cvIplDepth(m.flags), m.channels());
cvSetData(this, m.data, (int)m.step[0]);
}
found in ../OpenCV/modules/core/src/matrix.cpp is not used/instanciated and conversion fails.
You may reimplement it in a way similar to :
IplImage& FromMat(IplImage& img, const cv::Mat& m)
{
CV_Assert(m.dims <= 2);
cvInitImageHeader(&img, m.size(), cvIplDepth(m.flags), m.channels());
cvSetData(&img, m.data, (int)m.step[0]);
return img;
}
IplImage img;
FromMat(img,myMat);

Related

How to clone an mat array by pointer c++

I new in opencv, and I have a program where IplImage is used but I want to update to Mat, so there are things where I don't know exactly how to modify the program, for example this line :
void setDataToWork(Mat* sources)/* Before it was IplImage* sources*/
{
src = sources ;
...
...
{
/*segm = cvCloneImage( sources ) ;*/
/*ch_h = cvCloneImage( segMsk )*/;
sources->clone();
}
}
I need to clone the sources and ch_h, but I don't know how to do it correctly.
Thanks in advance
You can't replace all occurrences of IplImage to cv::Mat because the API has been totally changed, some methods does not exist, some has been renamed, etc.
The only thing you can do is to create a wrapper cv::Mat object to your old IplImage by the constructor below
cv::Mat(const IplImage* img, bool copyData=false);
In practice:
IplImage* iplImage = ...
cv::Mat matFromIpl(iplImage);
// use matFromIpl from here

Unsupported depth in Opencv

I am trying to learn some basics, but I keep getting errors.
I am trying to resize a cv::Mat
Edit to clarify why I am not loading an image: I am trying to test without having access to external files.
Inside the code, though, I put int x = M.depth(); and it read 0
cv::Mat M(2,2, CV_8UC3, cv::Scalar(0,0,255));
scale = 2;
cv::Size myImageSize;
myImageSize.height = M.rows;
myImageSize.width = M.cols;
cv::Mat ImgCopy = cvCreateImage(myImageSize, M.depth(), M.channels());
..
cv::resize(M, ImgCopy, myImageSize, 0, 0, CV_INTER_LINEAR);
I am getting an error on the line cvCreateImage
Input image depth is not supported by function (Unsupported format) in unknown functio, file... \modules\core\src\array.cpp...
I have tried with other values (CV_32F...) and I get the same error.
Please help !
cvCreateImage() is for use with the C API and returns an IplImage*. To initialize a cv::Mat, use the appropriate constructor.
cv::Mat ImgCopy(M.size(), M.type());
is the most succinct way to create and allocate memory for a new cv::Mat.
However, cv::resize() makes it even easier. You just have to declare your image
cv::Mat ImgCopy
and the arguments to cv::resize() allow automatic calculation of the correct dimensions and type. The last three parameters do not need to be specified because you don't change them from the defaults.
cv::resize(M, ImgCopy, myImageSize);
Try this code :
using namespace cv;
using namespace std;
int main( int argc, char** argv )
{
IplImage *src,*dst;
src=cvLoadImage("img.png");
cvNamedWindow("SRC", CV_WINDOW_AUTOSIZE);
cvNamedWindow("DST", CV_WINDOW_AUTOSIZE);
dst = cvCreateImage(cvSize(500,500),src->depth,src->nChannels);
cvResize(src,dst);
cvShowImage("SRC",src);
cvShowImage("DST",dst);
cvWaitKey(0);
cvDestroyWindow("SRC");
cvDestroyWindow("DST");
cvReleaseImage(&dst);
cvReleaseImage(&src);
return 0;
}

How to resize an image to a specific size in OpenCV?

IplImage* img = cvLoadImage("something.jpg");
IplImage* src = cvLoadImage("src.jpg");
cvSub(src, img, img);
But the size of the source image is different from img.
Is there any opencv function to resize it to the img size?
You can use cvResize. Or better use c++ interface (eg cv::Mat instead of IplImage and cv::imread instead of cvLoadImage) and then use cv::resize which handles memory allocation and deallocation itself.
The two functions you need are documented here:
imread: read an image from disk.
Image resizing: resize to just any size.
In short:
// Load images in the C++ format
cv::Mat img = cv::imread("something.jpg");
cv::Mat src = cv::imread("src.jpg");
// Resize src so that is has the same size as img
cv::resize(src, src, img.size());
And please, please, stop using the old and completely deprecated IplImage* classes
For your information, the python equivalent is:
imageBuffer = cv.LoadImage( strSrc )
nW = new X size
nH = new Y size
smallerImage = cv.CreateImage( (nH, nW), imageBuffer.depth, imageBuffer.nChannels )
cv.Resize( imageBuffer, smallerImage , interpolation=cv.CV_INTER_CUBIC )
cv.SaveImage( strDst, smallerImage )
Make a useful function like this:
IplImage* img_resize(IplImage* src_img, int new_width,int new_height)
{
IplImage* des_img;
des_img=cvCreateImage(cvSize(new_width,new_height),src_img->depth,src_img->nChannels);
cvResize(src_img,des_img,CV_INTER_LINEAR);
return des_img;
}
You can use CvInvoke.Resize for Emgu.CV 3.0
e.g
CvInvoke.Resize(inputImage, outputImage, new System.Drawing.Size(100, 100), 0, 0, Inter.Cubic);
Details are here

convert cv::Mat to const CvMat* or CvMat*

I know only C language, so I am getting confusion/not understanding the syntax of the openCV data types particularly in cv::Mat, CvMat*, Mat.
My question is How can I convert cv::Mat to const CvMat* or CvMat*, and can any one provide documentation link for difference between CvMat *mat and cv::Mat and Mat in opencv2.4.
and How can I convert my int data to float data in CvMat ?
Thank you
cv::Mat has a operator CvMat() so simple assignment works:
cv::Mat mat = ....;
CvMat cvMat = mat;
This uses the same underlying data so you have to be careful that the cv::Mat doesn't go out of scope before the CvMat.
If you need to use the CvMat in an API that takes a CvMat*, then pass the address of the object:
functionTakingCmMatptr(&cvMat);
As for the difference between cv::Mat and Mat, they are the same. In OpenCV examples, it is often assumed (and I don't think this is a good idea) that using namespace cv is used.
To answer especially surya's second question:
TBH, the documentation on OpenCV is not the best.
Here the link to the newest type: cv::Mat. The newer types are more modern c++ like than c style.
Here is more OpenCV forum answer with a similar topic and here is an archived page.
Especially for the conversion problem (as juanchopanza mentioned):
cv::Mat mat = cv::Mat(10, 10, CV_32FC1); //CV_32FC1 equals float
//(reads 32bit floating-point 1 channel)
CvMat cvMat = mat;
or with
using namespace cv; //this should be in the beginning where you include
Mat mat = Mat(10, 10, CV_32FC1);
CvMat cvMat = mat;
Note: Usually you would probably work with CvMat* - but you should think about switching to the newer types completely. Example (taken from my second link):
CvMat* A = cvCreateMat(10, 10, CV_32F); //guess this works fine with no channels too
Changing int to float:
CvMat* A = cvCreateMat(10, 10, CV_16SC1);
//Feed A with data
CvMat* B = cvCreateMat(10, 10, CV_32FC1);
for( int i=0; i<10; ++i)
for( int i=0; i<10; ++i)
CV_MAT_ELEM(*A, float, i, j) = (float) cvmGet(B, i, j);
//Don't forget this unless you want to produce a memory leak.
cvReleaseMat(&A);
cvReleaseMat(&B);
The first two examples (without the pointer) are fine like that as the CvMat is held on the heap then. cvCreateMat(...) allocates memory you have to free on your own later. Another reason to use cv::Mat.

(Adaptive) thresholding in opencv error (Bad argument (Unknown array type) in cvarrToMat)

I'm trying to use thresholding on my video stream but it is not working.
My video stream:
Mat *depthImage = new Mat(480, 640, CV_8UC1, Scalar::all(0));
Then i try to do the adaptive thresholding, (also doesn't work with regular thresholding)
for(;;){
if( wrapper->update()){
wrapper->getDisplayDepth(depthImage);
cvAdaptiveThreshold(depthImage, depthImage,255,CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY,75,10);
imshow("Depth", *depthImage);
}
int k = waitKey(25);
if(k == 27 ) exit(0);
}
I get this error :
OpenCV Error: Bad argument (Unknown array type) in cvarrToMat, file /Users/olivierjanssens/source/OpenCV-2.3.1/modules/core/src/matrix.cpp, line 646
terminate called throwing an exception
What am i doing wrong, i can get display and see the stream perfectly.But when i add this thresholding i get the error previously mentioned. (i'm rather new to opencv btw).
Thx in advance !
Your depthImage is a pointer to a cv::Mat, which to me seems strange...
...but, if you're using the C++ syntax then you'll want to use the C++ version of adaptiveThreshold, which deals with cv::Mat, with the following definition:
void adaptiveThreshold(InputArray src, OutputArray dst, double maxValue,
int adaptiveMethod, int thresholdType, int blockSize, double C);
which will need prefixed by cv:: if you're not using that namespace already.
For example:
Mat *depthImage; // Obtain this using your method
Mat image = *depthImage; // Obtain a regular Mat to use (doesn't copy data, just headers)
adaptiveThreshold(image, image,255,CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY,75,10);
imshow("Depth Image", *depthImage);
// OR
imshow("Depth Image", image);