Pad an image with zeros - c++

I am coding in C++ and am trying to resize image 2 to the same dimensions as image 1, however I don't want to stretch the image. I am trying to copy image2 to the padded matrix (at the point 0,0). Am getting the error:
OpenCV Error: Assertion failed (0 <= roi.x && 0 <= roi.width && roi.x + roi.width <= m.cols && 0 <= roi.y && 0 <= roi.height && roi.y + roi.height <= m.rows) in Mat, file C:\opencv\opencv\modules\core\src\matrix.cpp, line 323
Code is below. Thanks in advance
Mat padded;
padded.setTo(cv::Scalar::all(0));
padded.create(image1.rows,image1.cols, image2.type());
image2.copyTo(padded(Rect(0, 0, image2.rows, image2.cols)));

You can use the OpenCV function copyMakeBorder to pad an image:
To achieve what you want, you can try the following:
cv::Mat padded;
//Assuming that dimensions of image1 are larger than that of image2
//Calculate padding amount so that total size after padding is equal to image1's size
int rowPadding = image1.rows - image2.rows;
int colPadding = image1.cols - image2.cols;
cv::copyMakeBorder(image2, padded, 0, rowPadding, 0, colPadding, cv::BORDER_CONSTANT, cv::Scalar::all(0));

It is almost the same as I asked before. As for you exmple, you just swap cols and rows in function call as berak already mentioned above.
Method copyMakeBorder(...) exists both for Mat and oclMat, so it could be usefull if you will try openCL-extension of openCV for better perfomance.

I don't know the syntax, but here's a pseudo-code
float width1, height1; //size of image1
float width2, height2; //original size of image2
float scale;
bool portrait = width2 < height2;
if(portrait) scale = height1 / height2;
else scale = width1 / width2;
float scaled_width2 = width2 * scale;
float scaled_height2 = height2 * scale;
When the image is portrait, we fill height, otherwise we fill the width.
By doing it this way, the image will get to its maximum size without being stretched

Related

I'm getting an error from the implementation of my region of interest

Error message:
(-215) 0 <= roi.x && 0 <= roi.width && roi.x + roi.width <= m.cols &&
0 <= roi.y && 0 <= roi.height && roi.y + roi.height <= m.rows in
function cv::Mat::Mat
This is my code
Rect eye_rec(200, 300, 168, 168);
Point hand_pos(100, 100);
Mat des, mask = (cv::Mat::zeros(hand.size(), CV_8UC1));
mask(eye_rec).setTo(255);
seamlessClone(eye,hand, mask,hand_pos,des,NORMAL_CLONE);
imshow("clone", des);
waitKey(0);
i cant really understand the error message though..
Your error code generally means, that ROI you want to crop is out of the bounds of the source matrix - e.g. source matrix is of size 480x480 and you want to crop out ROI of size 300x300 from position (200, 200), where 300+200 > 480.
According to docs
src – Input 8-bit 3-channel image.
dst – Input 8-bit 3-channel image.
mask – Input 8-bit 1 or 3-channel image.
result – Output image with the same size and type as dst.
src, dst and result should be of type CV_8UC3 - three channel images, while you are passing just one channel images CV_8UC1, which most likely cause the error here.
The solution is to use 3-channel (color) images or different operation accepting 1-channel images.
hand.convertTo(hand, CV_8UC3);
eye.convertTo(eye, CV_8UC3);
Point hand_pos(hand.cols/2,hand.rows/2); //this code should put the eye image in the middle of the hand image
Mat des, mask = (cv::Mat::zeros(eye.size(), CV_8UC3));
des.convertTo(des, CV_8UC3);
mask = 255 * Mat::ones(eye.rows, eye.cols, eye.depth()); // creating a mask of all white from the eye image
seamlessClone(eye,hand, mask,hand_pos,des,NORMAL_CLONE);
imshow("normalclone", des); waitKey(0);
seamlessClone(eye,hand,mask,hand_pos,des, MIXED_CLONE);
imshow("mixclone",des); waitKey(0)
waitKey(0);
This change helped me, hope it helps others too, thanks #Filip Kočica

OpenCV Perspective corrention and cropping

I'm currently trying to correct the perspective of a random taken image showing a rectangle.
The perspective correction is working fine, but i want to crop the image to the target, too. Si I've tried to transform the given contour of my target by the perspective matrix (cv::Mat) and crop it with the results.
My method is currently crashing at the marked line with the following error.
OpenCV Error: Assertion failed (mtype == type0 || (CV_MAT_CN(mtype) == CV_MAT_CN(type0) && ((1 << type0) & fixedDepthMask) != 0)) in create, file /Volumes/build-storage/build/master_iOS-mac/opencv/modules/core/src/matrix.cpp, line 2430
libc++abi.dylib: terminating with uncaught exception of type cv::Exception: /Volumes/build-storage/build/master_iOS-mac/opencv/modules/core/src/matrix.cpp:2430: error: (-215) mtype == type0 || (CV_MAT_CN(mtype) == CV_MAT_CN(type0) && ((1 << type0) & fixedDepthMask) != 0) in function create
Code
cv::Mat correctMat(cv::Mat mat, std::vector<cv::Point> contour) {
double minObjectSize = 100.0;
if (contour.size() == 4) {
cv::Rect rect = cv::boundingRect(contour);
if (rect.height < minObjectSize || rect.width < minObjectSize) {
NSLog(#"Objects size was too small: %d * %d", rect.width, rect.height);
}
else {
std::vector<Point2f> quad_pts;
std::vector<Point2f> squre_pts;
quad_pts.push_back(Point2f(contour[0].x, contour[0].y));
quad_pts.push_back(Point2f(contour[1].x, contour[1].y));
quad_pts.push_back(Point2f(contour[3].x, contour[3].y));
quad_pts.push_back(Point2f(contour[2].x, contour[2].y));
squre_pts.push_back(Point2f(rect.x, rect.y));
squre_pts.push_back(Point2f(rect.x, rect.y + rect.height));
squre_pts.push_back(Point2f(rect.x + rect.width, rect.y));
squre_pts.push_back(Point2f(rect.x + rect.width, rect.y + rect.height));
Mat transmtx = getPerspectiveTransform(quad_pts, squre_pts);
Mat transformed = Mat::zeros(mat.rows, mat.cols, CV_8UC3);
cv::line(mat, quad_pts[0], quad_pts[1], Scalar(0,0,255), 5, CV_AA, 0);
cv::line(mat, quad_pts[1], quad_pts[2], Scalar(0,0,255), 5, CV_AA, 0);
cv::line(mat, quad_pts[2], quad_pts[3], Scalar(0,0,255), 5, CV_AA, 0);
cv::line(mat, quad_pts[3], quad_pts[0], Scalar(0,0,255), 5, CV_AA, 0);
warpPerspective(mat, transformed, transmtx, mat.size());
std::vector<cv::Point2f> transformedPoints;
cv::Matx23f matrix = *transmtx.clone().ptr();
cv::transform(quad_pts, transformedPoints, matrix);
cv::Mat cropped = transformed(cv::boundingRect(transformedPoints));
fixColorOfMat(cropped);
return cropped;
}
}
return mat;
}
I do not really know what the error message is telling me so i hope somebody here could help me solving this crash.
Next Problem
I've changed the code a bit, the transform action on the point vector works now, but i'm unabled to crop the Mat by these transformed points.
std::vector<cv::Point2f> transformedPoints;
cv::Matx23f matrix = *transmtx.clone().ptr();
cv::transform(quad_pts, transformedPoints, matrix);
// Crash
cv::Mat cropped = transformed(cv::boundingRect(transformedPoints));
The error message says
OpenCV Error: Assertion failed (0 <= roi.x && 0 <= roi.width && roi.x + roi.width <= m.cols && 0 <= roi.y && 0 <= roi.height && roi.y + roi.height <= m.rows) in Mat, file /Volumes/build-storage/build/master_iOS-mac/opencv/modules/core/src/matrix.cpp, line 522
libc++abi.dylib: terminating with uncaught exception of type cv::Exception: /Volumes/build-storage/build/master_iOS-mac/opencv/modules/core/src/matrix.cpp:522: error: (-215) 0 <= roi.x && 0 <= roi.width && roi.x + roi.width <= m.cols && 0 <= roi.y && 0 <= roi.height && roi.y + roi.height <= m.rows in function Mat
Hmm, I used memcpy() convert vector to Mat directly. Maybe you can try that on the transform part.
memcpy(Mat.data, vector.data(), vector.size()*sizeof(Point));
As long as you got the mask matrix of contour, I think you can use bitwise() to corp your target result.
Btw, I cannot explain opencv's error statement, as I have never understood it.

Setting RGB values of pixels in a certain image in openCV

I am trying to set RGB values of some pixels in a binary image. But whenever the coordinate is more than (89, 89) its giving me an assertion error! My image resolution is okay because I am accessing RGB values from (150, 150) coordinate. If the coordinate is (89, 89) or less it works fine. My Code:
cv::Mat img_gray, img_bw;
//read an image
cv::Mat3b img_bgr = cv::imread("test.jpg");
cv::imshow("Original Image", img_bgr);
//conversion to binary from color
cv::cvtColor(img_bgr, img_gray,CV_RGB2GRAY);
cv::threshold(img_gray, img_bw, 75.0, 255.0, THRESH_BINARY);
//accessing BGR of position (150, 150) from a color image
std::cout<<"Pixel at position (x, y) : ("<<150<<", "<<150<<") ="<<img_bgr(150,150)<<std::endl;
//Setting BGR of position (150, 150) in binary image
img_bw.at<Vec3b>(150, 150)[0] = 255;
img_bw.at<Vec3b>(150, 150)[1] = 255;
img_bw.at<Vec3b>(150, 150)[2] = 255;
std::cout<<"Pixel at position (x, y) : ("<<150<<", "<<150<<") ="<<img_bw.at<Vec3b>(150, 150)<<std::endl;
Here if I put 89 instead of 150 in the "Setting BGR" section then it works. Otherwise the full error is:
OpenCV Error: Assertion failed (dims <= 2 && data && (unsigned)i0 < (unsigned)size.p[0] && (unsigned)(i1*DataType<_Tp>::channels) < (unsigned)(size.p1*channels()) && ((((sizeof(size_t)<<28)|0x8442211) >> ((DataType<_Tp>::depth) & ((1 << 3) - 1))*4) & 15) == elemSize1()) in cv::Mat::at, file e:\opencv\opencv\build\include\opencv2\core\mat.hpp, line 538
So is this any type of memory space error?
Thanks in advance for the helps! :)
UPDATE: I've tried it this way! But the output is blank now.
cv::Mat img_gray, img_bw;
//read an image
cv::Mat3b img_bgr = cv::imread("test.jpg");
cv::imshow("Original Image", img_bgr);
//conversion to binary from color
cv::cvtColor(img_bgr, img_gray,CV_RGB2GRAY);
cv::threshold(img_gray, img_bw, 75.0, 255.0, THRESH_BINARY);
//accessing BGR of position (150, 150) from a color image
std::cout<<"Pixel at position (x, y) : ("<<150<<", "<<150<<") ="<<img_bgr(150,150)<<std::endl;
//Setting BGR of position (150, 150) in binary image
img_bw.at<uchar>(150, 150) = 255;
std::cout<<"Pixel at position (x, y) : ("<<150<<", "<<150<<") ="<<img_bw.at<uchar>(150, 150)<<std::endl;
My test image is here
And the output is here
Okay I have the answer now thanks to beaker's hint in the comment :) I'm putting the solution for others help!
I just need to define the output as an integer. So the last cout will be like
std::cout<<"Pixel at position (x, y) : ("<<150<<", "<<150<<") ="<<(int)img_bw.at<uchar>(150, 150)<<std::endl;

Execution breaks at C++ opencv copyTo() function

My goal is to pad my segmented image with zeros along the border as I needed to close it (for filling in small holes in my foreground). Here tmp is an CV_8UC3 segmented image Mat obtained from my image frame, in which all my background pixels have been blacked out. I have manually created a binary mask from tmp and stored it in Mat bM, which is the same size and type as my image Mat frame.
Mat bM = Mat::zeros(frame.rows, frame.cols, CV_8UC1);
for(i=0;i<frame.rows;i++)
{
for(j=0;j<frame.cols;j++)
{
if(tmp.at<Vec3b>(i,j)[0] != 0 && tmp.at<Vec3b>(i,j)[1] != 0 && tmp.at<Vec3b>(i,j)[0] != 0)
bM.at<uchar>(i,j) = 255;
}
}
Mat padded;
int padding = 6;
padded.create(bM.rows + 2*padding, bM.cols + 2*padding, bM.type());
padded.setTo(Scalar::all(0));
bM.copyTo(padded(Rect(padding, padding, bM.rows, bM.cols)));
My execution breaks at the last line in Visual Studio giving the following error:
Assertion failed <0 <= roi.x && 0 <= roi.width && roi.x + roi.width <= m.cols && 0<=roi.height && roi.y+roi.height <=m.rows>
While I understand what that means, I cant figure out why it would throw this error as my source image is within bounds of my target image. I've stepped through my code and am sure it breaks at that specific line. From what I've read, the cv::Rect constructor can be given offsets the way I've passed the offsets padding and padding, and these offsets are taken from the top left corner of the image. Can the copyTo function be used this way? Or is my error elsewhere?
The CV::Rect constructor is different from the CV::Mat constructor.
Rect_(_Tp _x, _Tp _y, _Tp _width, _Tp _height);
The cv::Rect parameters are offset in x, offset in y and then width first and height at last.
So when you do this:
bM.copyTo(padded(Rect(padding, padding, bM.rows, bM.cols)));
You create a cv::Rect with width bM.rows and heigth bM.cols. Which is the oposite of what you need.
Change it to:
bM.copyTo(padded(Rect(padding, padding, bM.cols, bM.rows)));

OpenCv assertion failed

I am working on application for finding face in 2D image and later inside same image I want to find mouth, but I have some problem right now. This is my code so far:
for (int i = 0; i < faces.size(); i++)
{
Point pt1(faces[i].x, faces[i].y);
Point pt2((faces[i].x + faces[i].height), (faces[i].y + faces[i].width));
rectangle(frame, pt1, pt2, Scalar(255,0 , 0), 2, 8, 0);
//I WANT ROI(FOR MOUTH DETECTION) TO BE ONLY HALF OF THE RECTANGLE WITH FACE
Rect mouthROI;
mouthROI.x = (faces[i].x);
mouthROI.y = faces[i].y*(1.5);
mouthROI.width = (faces[i].x + faces[i].height);
mouthROI.height = (faces[i].y + faces[i].width);
//I CHECK IF NEW RECTANGLE IS EXACTLY BOTTOM HALF OF PREVIOUS ONE
Point ptAA(mouthROI.x, mouthROI.y);
Point ptBB(mouthROI.width, mouthROI.height);
rectangle(frame, ptBB, ptAA, Scalar(0,0 , 255), 2, 2, 0);
Mat image_roi = frame(mouthROI);
cvtColor(frame, frame_gray, COLOR_BGR2GRAY);
equalizeHist( frame_gray, frame_gray );
// DETECTING MOUTH INSIDE ROI OF EARLIER DETECTED FACE
mouth_cascade.detectMultiScale(image_roi, mouths, 1.1, 2, 0, Size(30, 30));
for(int i = 0; i < mouths.size(); i++)
{
Point pt1(mouths[i].x, mouths[i].y); // Display detected faces on main window - live stream from camera
Point pt2((mouths[i].x + mouths[i].height), (mouths[i].y + mouths[i].width));
rectangle(frame, pt1, pt2, Scalar(0, 255, 0), 2, 8, 0);
}
}
Unfortunately this code does not work. I get error like this:
OpenCV Error: Assertion failed (0 <= roi.x && 0 <= roi.width && roi.x + roi.width <= m.cols && 0 <= roi.y && 0 <= roi.height && roi.y + roi.height <= m.rows) in cv::Mat::Mat(const cv::Mat&, const cv::Rect&), file C:/build/2_4_PackSlave-win32-vc11-shared/opencv/modules/core/src/matrix.cpp, line 323
How can I fix this error. Thank You all for help!
The way you have initialized mouthROI is incorrect. It should be like this instead,
<previous code>
mouthROI.width = (faces[i].height);
mouthROI.height = (faces[i].width);
Point ptAA(mouthROI.x, mouthROI.y);
Point ptBB(mouthROI.x+mouthROI.width, mouthROI.y+mouthROI.height);
Remember that cv::Rect doesn't take the position of the rectangle, it takes the position of the upper left corner and the width and the height.. Refer to the documentation for further details.
HTH