What I want to do:
Convert a ROI of the Nao Robot camera image on the OpenCV::Mat format. Later I will make use of this OpenCV::Mat
The situation:
Nao SDK provide the image in a format called ALImage. It is possible to convert the ALImage to OpenCV::Mat format, but I do not need all the image, only a small ROI. Despite ALImage provides its own ROI, the methods to use it are not really helpful:
int getNumOfROIs () const
const ROI* getROI (int index) const
void addROI (const ROI &rect)
void cleanROIs ()
void setEnableROIs (bool enable)
bool isROIEnabled () const
The question:
How can I use these ROIs?
Assuming you already have the coordinates of your ROI, you can crop your cv::Mat like this:
// your source image
cv::Mat image(imagesource);
// a rectangle with your ROI coordinates
cv::Rect myROI(10, 10, 100, 100);
// a "reference" to the image data within the rectangle
cv::Mat croppedImage = image(myROI);
Note that this does not copy the image data. Both, image and croppedImage share the same underlying raw data (a detailed example can be found in the opencv documentation). When you're done with the big source image, you can do image.release() and croppedImage = croppedImage.clone(); to deallocate all unnecessary data (outside of your ROI).
EDIT:
I didn't work with AL::ALImage::ROI yet, but the definition in alimage/alimage.h looks familiar to cv::Rect. So you can probably do the following:
// let's pretend you already got your image ...
AL::ALImage yourImage;
// ... and a ROI ...
AL::ALImage::ROI yourROI;
// ... as well as a Mat header with the dimensions and type of yourImage
cv::Mat header;
// then you can convert the ROI, ...
cv::Rect cvROI(yourROI.x, yourROI.y, yourROI.w, yourROI.h);
// ... wrap ALImage to a Mat (which should not copy anything) ...
header.data = yourImage.getData();
// ... and then proceed with the steps mentioned above to crop your Mat
cv::Mat cropped = header(cvROI);
header.release();
cropped = cropped.clone();
// ...
// your image processing using cropped
// ...
I hope this helps.
Related
I am programming in Qt environment and I have a Mat image with size 2592x2048 and I want to resize it to the size of a "label" that I have. But when I want to show the image, I have to multiply the width by 3, so the image is shown in its correct size. Is there any explanation for that?
This is my code:
//Here I get image from the a buffer and save it into a Mat image.
//img_width is 2592 and img_height is 2048
Mat image = Mat(cv::Size(img_width, img_height), CV_8UC3, (uchar*)img, Mat::AUTO_STEP);
Mat cimg;
double r; int n_width, n_height;
//Get the width of label (lbl) into which I want to show the image
n_width = ui->lbl->width();
r = (double)(n_width)/img_width;
n_height = r*(img_height);
cv::resize(image, cimg, Size(n_width*3, n_height), INTER_AREA);
Thanks.
The resize function works well, because if you save the resized image as a file is displayed correctly. Since you want to display it on QLabel, I assume you have to transform your image to QImage first and then to QPixmap. I believe the problem lies either in the step or the image format.
If we ensure the image data passed in
Mat image = Mat(cv::Size(img_width, img_height), CV_8UC3, (uchar*)img, Mat::AUTO_STEP);
are indeed an RGB image, then below code should work:
ui->lbl->setPixmap(QPixmap::fromImage(QImage(cimg.data, cimg.cols, cimg.rows, *cimg.step.p, QImage::Format_RGB888 )));
Finally, instead of using OpenCV, you could construct a QImage object using the constructor
QImage((uchar*)img, img_width, img_height, QImage::Format_RGB888)
and then use the scaledToWidth method to do the resize. (beware thought that this method returns the scaled image, and does not performs the resize operation to the image per se)
I would like to ask which is the most efficient way to set a region of a grayscale Mat image to zeros (or any other constant value, for that matter).
Should I create a zeros image and then use copyTo() or is there a better way?
I would use setTo(), for example:
// load an image
cv::Mat pImage = cv::imread("someimage.jpg", CV_LOAD_IMAGE_COLOR);
// select a region of interest
cv::Mat pRoi = pImage(cv::Rect(10, 10, 20, 20));
// set roi to some rgb colour
pRoi.setTo(cv::Scalar(blue, green, red));
Let's say we paint a black rectangle in a white canvas:
cv::Mat img(100,100,CV_8U,cv::Scalar(255));
img(cv::Rect(15,15,20,40))=0;
cv::imshow("Img",img);
cv::waitKey();
Try the following code
Mat image;
image = imread("images/lena.jpg");
int x=100;int y=100; int w=100; int h=100;
Rect roi = Rect(x,y,w,h);
image(roi).setTo(cv::Scalar(0,0,0));
imshow("display",image);
cvSetImageROI(dst, cvRect(0, 0,img1->width,img1->height) );
cvCopy(img1,dst,NULL);
cvResetImageROI(dst);
I was using these commands to set image ROI but now i m using MAT object and these functions take only Iplimage as a parameter. Is there any similar command for Mat object?
thanks for any help
You can use the cv::Mat::operator() to get a reference to the selected image ROI.
Consider the following example where you want to perform Bitwise NOT operation on a specific image ROI. You would do something like this:
img = imread("image.jpg", CV_LOAD_IMAGE_COLOR);
int x = 20, y = 20, width = 50, height = 50;
cv::Rect roi_rect(x,y,width,height);
cv::Mat roi = img(roi_rect);
/* ROI data pointer points to a location in the same memory as img. i.e.
No separate memory is created for roi data */
cv::Mat complement;
cv::bitwise_not(roi,complement);
complement.copyTo(roi);
cv::imshow("Image",img);
cv::waitKey();
The example you provided can be done as follows:
cv::Mat roi = dst(cv::Rect(0, 0,img1.cols,img1.rows));
img1.copyTo(roi);
Yes, you have a few options, see the docs.
The easiest way is usually to use a cv::Rect to specifiy the ROI:
cv::Mat img1(...);
cv::Mat dst(...);
...
cv::Rect roi(0, 0, img1.cols, img1.rows);
img1.copyTo(dst(roi));
The problem is solved....I used cvGet2D,below is the sample code
CvScalar s;
s=cvGet2D(src_Image,pixel[i].x,pixel[i].y);
cvSet2D(dst_Image,pixel[i].x,pixel[i].y,s);
Where src_Iamge and dst_Image is the source and destination image correspondingly and pixel[i] is the selected pixel i wanted to draw in the dst image. I have include the real out image below.
have an source Ipl image, I want to copy some of the part of the image to a new destination image pixel by pixel. can any body tell me how can do it? I use c,c++ in opencv. For example if the below image is source image,
The real output image
EDIT:
I can see the comments suggesting cvGet2d. I think, if you just want to show "points", it is best to show them with a small neighbourhood so they can be seen where they are. For that you can draw white filled circles with origins at (x,y), on a mask, then you do the copyTo.
using namespace cv;
Mat m(input_iplimage);
Mat mask=Mat::zeros(m.size(), CV_8UC1);
p1 = Point(x,y);
r = 3;
circle(mask,p1,r, 1); // draws the circle around your point.
floodFill(mask, p1, 1); // fills the circle.
//p2, p3, ...
Mat output = Mat::zeros(m.size(),m.type()); // output starts with a black background.
m.copyTo(output, mask); // copies the selected parts of m to output
OLD post:
Create a mask and copy those pixels:
#include<opencv2/opencv.hpp>
using namespace cv;
Mat m(input_iplimage);
Mat mask=Mat::zeros(m.size(), CV_8UC1); // set mask 1 for every pixel you wanna copy.
Rect roi=Rect(x,y,width,height); // create a rectangle
mask(roi) = 1; // set it to 0.
roi = Rect(x2,y2,w2,h2);
mask(roi)=1; // set the second rectangular area for copying...
Mat output = 100*Mat::ones(m.size(),m.type()); // output with a gray background.
m.copyTo(output, mask); // copy selected areas of m to output
Alternatively you can copy Rect-by-Rect:
Mat m(input_iplimage);
Mat output = 100*Mat::ones(m.size(),m.type()); // output with a gray background.
Rect roi=Rect(x,y,width,height);
Mat m_temp, out_temp;
m_temp=m(roi);
out_temp = output(roi);
m_temp.copyTo(out_temp);
roi=Rect(x2,y2,w2,h2);
Mat m_temp, out_temp;
m_temp=m(roi);
out_temp = output(roi);
m_temp.copyTo(out_temp);
The answer to your question only requires to have look at the OpenCV documentation or just to search in your favourite search engine.
Here you've an answer for Ipl images and for newer Mat data.
For having an output as I see in your images, I'd do it setting ROI's, it's more efficient.
I want to apply a binary mask to a color image.
Please provide a basic code example with proper explanation of how the code works.
Also, is there some option to apply a mask permanently so all functions operate only within the mask?
While #perrejba s answer is correct, it uses the legacy C-style functions. As the question is tagged C++, you may want to use a method instead:
inputMat.copyTo(outputMat, maskMat);
All objects are of type cv::Mat.
Please be aware that the masking is binary. Any non-zero value in the mask is interpreted as 'do copy'. Even if the mask is a greyscale image.
Also be aware that the .copyTo() function does not clear the output before copying.
If you want to permanently alter the original Image, you have to do an additional copy/clone/assignment. The copyTo() function is not defined for overlapping input/output images. So you can't use the same image as both input and output.
You don't apply a binary mask to an image. You (optionally) use a binary mask in a processing function call to tell the function which pixels of the image you want to process. If I'm completely misinterpreting your question, you should add more detail to clarify.
Well, this question appears on top of search results, so I believe we need code example here. Here's the Python code:
import cv2
def apply_mask(frame, mask):
"""Apply binary mask to frame, return in-place masked image."""
return cv2.bitwise_and(frame, frame, mask=mask)
Mask and frame must be the same size, so pixels remain as-is where mask is 1 and are set to zero where mask pixel is 0.
And for C++ it's a little bit different:
cv::Mat inFrame; // Original (non-empty) image
cv::Mat mask; // Original (non-empty) mask
// ...
cv::Mat outFrame; // Result output
inFrame.copyTo(outFrame, mask);
You can use the mask to copy only the region of interest of an original image to a destination one:
cvCopy(origImage,destImage,mask);
where mask should be an 8-bit single channel array.
See more at the OpenCV docs
Here is some code to apply binary mask on a video frame sequence acquired from a webcam.
comment and uncomment the "bitwise_not(Mon_mask,Mon_mask);"line and see the effect.
bests,
Ahmed.
#include "cv.h" // include it to used Main OpenCV functions.
#include "highgui.h" //include it to use GUI functions.
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
int c;
int radius=100;
CvPoint2D32f center;
//IplImage* color_img;
Mat image, image0,image1;
IplImage *tmp;
CvCapture* cv_cap = cvCaptureFromCAM(0);
while(1) {
tmp = cvQueryFrame(cv_cap); // get frame
// IplImage to Mat
Mat imgMat(tmp);
image =tmp;
center.x = tmp->width/2;
center.y = tmp->height/2;
Mat Mon_mask(image.size(), CV_8UC1, Scalar(0,0,0));
circle(Mon_mask, center, radius, Scalar(255,255,255), -1, 8, 0 ); //-1 means filled
bitwise_not(Mon_mask,Mon_mask);// commenté ou pas = RP ou DMLA
if(tmp != 0)
imshow("Glaucom", image); // show frame
c = cvWaitKey(10); // wait 10 ms or for key stroke
if(c == 27)
break; // if ESC, break and quit
}
/* clean up */
cvReleaseCapture( &cv_cap );
cvDestroyWindow("Glaucom");
}
Use copy with a mask.
Code sample:
Mat img1 = imread(path); // Load your image
Mat mask(img1 .size(),img1 .type()); // Create your mask
mask.setTo(0);
Point center(img1.cols/2, img1.rows / 2);
const int radius = img1.cols / 5; // Circle radio
circle(mask, center, radius, 255, FILLED);// Draw a circle in the image center
Mat img2(img1 .size(),img1 .type()); // Outimage
img2.setTo(0); // Clear data
img1.copyTo(img2, mask); // Only values at mask > 0 will be copied.