How to clone an mat array by pointer c++ - 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

Related

Where does a Mat object store its data if it's not in data variable?

I need to transfer the image data from a Mat object (OpenCV) to a const unsigned char* within a ZXing::ImageView object; typically, I just use (assuming the object is named "object") object.data at my own risk and go from there if there are issues with the transfer. However, in this case, the data member variable is empty. This Mat object does produce an image with imshow though so I'm not sure where else to look. I have gone through the documentation but my limited experience and lack of knowledge keeps me from effectively going through it at a reasonable pace or in a relevant direction. Here is my code:
#include <opencv2/opencv.hpp>
#include <ZXing/ReadBarcode.h>
using namespace cv;
Mat applyThreshold(Mat gradient);
Mat erodeAnddilate(Mat threshold_applied);
void readBarCode(Mat dest);
int main() {
std::string file = "C:\\Users\\these\\Desktop\\cropped.JPG";
namedWindow("imageview", WINDOW_NORMAL);
Mat src = imread(file, IMREAD_COLOR);
Mat thresh_applied = applyThreshold(src);
Mat dest = erodeAnddilate(thresh_applied);
readBarCode(dest);
imshow("imageview", dest);
waitKey(0);
return 0;
}
Mat applyThreshold(Mat gradient) {
Mat dest, gray;
cvtColor(gradient, gray, COLOR_BGR2GRAY);
threshold(gray, dest, 0, 255, THRESH_BINARY + THRESH_OTSU);
return dest;
}
Mat erodeAnddilate(Mat threshold_applied) {
Mat dest;
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
morphologyEx(threshold_applied, dest, MORPH_CLOSE, kernel, Point(-1, -1), 2);
return dest;
}
void readBarCode(Mat dest) {
ZXing::ImageView test(dest.data, dest.size().width, dest.size().height, ZXing::ImageFormat::None);
ZXing::Result truth = ZXing::ReadBarcode(test);
int momentoftruth = 0;
}
The function readBarCode() is where the issue lies. And apologies for the probably terrible code everywhere else, I have a lot to learn. :)
EDIT: The accepted solution was the only one officially given, but all of the comments collectively helped me realize my error in thinking about the data variable in question. I see the data variable as a pointer now, and will take shallow vs deep copying into consideration as a potential solution. I have a better understanding of what's going on with my Mat object and consider my question answered. Thanks everyone.
Try to pass the reference to your Mat object to the functions, or if you want to copy the data for creating a new image, use explicitly the clone() method to get deep copy of your image.
Like either:
Mat applyThreshold(Mat& gradient) {
Mat dest, gray;
cvtColor(gradient, gray, COLOR_BGR2GRAY);
threshold(gray, dest, 0, 255, THRESH_BINARY + THRESH_OTSU);
return dest;
}
or:
// ...
Mat thresh_applied = applyThreshold(src.clone());
// ...

copyTo() vs clone() inside function?

I've just begun learning C++ and OpenCV. I'm trying to make my own function but I'm confused as to why copyTo(dst); works, but when I use dst = src.clone(); the displayed output is black?
void testFunc(InputArray _src, OutputArray _dst){
Mat src = _src.getMat();
_dst.create(src.size(), src.type());
Mat dst = _dst.getMat();
src.copyTo(dst);
// ^this works but
// dst = src.clone(); doesn't
}
I think one way to resolve this issue is to treat Mat as a pointer (not quite correct, but humour me for a moment).
In your example you create Mat src which points to the source matrix. You then create a matrix for the destination with create(...) and create a new pointer Mat dst to this new matrix. When you use src.copyTo(dst), OpenCV copies the data pointed to by src into the target pointed to by dst, however when you use the assignment dst = src.clone(), dst is replaced with a clone of src (that is, the pointer is changed to a new location).
With basic types, this could translate to something like:
struct Input { int* data; };
struct Output { int* data; };
void testFunc(Input _src, Output _dst)
{
int* src = _src.data;
_dst.data = new int;
int* dst = _dst.data;
// src.copyTo(dst)
*dst = *src;
// dst = src.clone()
dst = new int(*src);
}
This way of thinking about it is not entirely correct, but it might be useful for thinking about this behaviour.

Opencv C++ to C interface function conversion

void doCorrectIntensityVariation(Mat& image)
{
Mat kernel = getStructuringElement(MORPH_ELLIPSE, Size(19,19));
Mat closed;
morphologyEx(image, closed, MORPH_CLOSE, kernel);
image.convertTo(image, CV_32F); // divide requires floating-point
divide(image, closed, image, 1, CV_32F);
normalize(image, image, 0, 255, NORM_MINMAX);
image.convertTo(image, CV_8UC1); // convert back to unsigned int
}
inline void correctIntensityVariation(IplImage *img)
{
//Mat imgMat(img); copy the img
Mat imgMat;
imgMat = img; //no copy is done, imgMat is a header of img
doCorrectIntensityVariation(imgMat);
imshow("gamma corrected",imgMat); cvWaitKey(0);
}
When I call
cvShowImage ("normal", n_im); cvWaitKey (0);
correctIntensityVariation(n_im);//here n_im is IplImage*
cvShowImage ("After processed", n_im); cvWaitKey (0);
// here I require n_im for further processing
I wanted "After processed" to be same as that of "gamma corrected" but what I found "After processed" was not the same as that of "gamma corrected" but same as that of "normal" . Why?? What is going wrong??
A very simple wrapper should do the job
Cheetsheet of openCV
I rarely use the old api, because Mat are much more easier to deal with, and
they do not have performance penalty when compare with the old c api.Like the openCV
tutorial page say The main downside of the C++ interface is that many embedded development systems at the moment support only C. Therefore, unless you are targeting embedded platforms, there’s no point to using the old methods (unless you’re a masochist programmer and you’re asking for trouble).
openCV tutorial
cv::Mat to Ipl
Ipl to cv::Mat and Mat to Ipl
IplImage* pImg = cvLoadImage(“lena.jpg”);
cv::Mat img(pImg,0); //transform Ipl to Mat, 0 means do not copy
IplImage qImg; //not pointer, it is impossible to overload the operator of raw pointer
qImg = IplImage(img); //transform Mat to Ipl
Edit : I did a mistake earlier, if the Mat would be reallocated in the function, you need
to copy or try to steal the resource(I don't know how to do it yet) from the Mat.
Copy the data
void doCorrectIntensityVariation(cv::Mat& image)
{
cv::Mat kernel = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(19,19));
cv::Mat closed;
cv::morphologyEx(image, closed, cv::MORPH_CLOSE, kernel);
image.convertTo(image, CV_32F); // divide requires floating-point
cv::divide(image, closed, image, 1, CV_32F);
cv::normalize(image, image, 0, 255, cv::NORM_MINMAX);
image.convertTo(image, CV_8UC1); // convert back to unsigned int
}
//don't need to change the name of the function, the compiler treat
//these as different function in c++
void doCorrectIntensityVariation(IplImage **img)
{
cv::Mat imgMat;
imgMat = *img; //no copy is done, imgMat is a header of img
doCorrectIntensityVariation(imgMat);
IplImage* old = *img;
IplImage src = imgMat;
*img = cvCloneImage(&src);
cvReleaseImage(&old);
}
int main()
{
std::string const name = "onebit_31.png";
cv::Mat mat = cv::imread(name);
if(mat.data){
doCorrectIntensityVariation(mat);
cv::imshow("gamma corrected mat",mat);
cv::waitKey();
}
IplImage* templat = cvLoadImage(name.c_str(), 1);
if(templat){
doCorrectIntensityVariation(&templat);
cvShowImage("mainWin", templat);
// wait for a key
cvWaitKey(0);
cvReleaseImage(&templat);
}
return 0;
}
you could write a small function to alleviate the chores
void copy_mat_Ipl(cv::Mat const &src, IplImage **dst)
{
IplImage* old = *dst;
IplImage temp_src = src;
*dst = cvCloneImage(&temp_src);
cvReleaseImage(&old);
}
and call it in the function
void doCorrectIntensityVariation(IplImage **img)
{
cv::Mat imgMat;
imgMat = *img; //no copy is done, imgMat is a header of img
doCorrectIntensityVariation(imgMat);
copy_mat_to_Ipl(imgMat, img);
}
I will post how to "steal" the resource from Mat rather than copy after
I figure out a solid solution.Anyone know how to do it?

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

Converting cv::Mat to IplImage*

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);