how to draw a rectangle in an image using open cv? - c++

I want to draw a rectangle in an image using open cv c++?I read a function called CV::rectangle,can anyone explain how this function works?Or is there any other method which can be used to draw rectangle?

You are right, you can use cv::rectangle.
You should be able to draw something using this code
cv::rectangle( img, cv::Point2f( 10, 10 ), cv::Point2f(100, 100), cv::Scalar( 255, 0, 0 ) );
This will draw a red rectangle starting with top left at (10, 10) and bottom right at (100,100).
This also assumes that img has 3 channels of usigned int type, if the type is different, then you need to change the values in the Scalar.

Related

Pixels at arrow tip missing when using antialiasing

I am trying to draw an arrow with OpenCV 3.2:
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
using namespace cv;
int main()
{
Mat image(480, 640, CV_8UC3, Scalar(255, 255, 255)); //White background
Point from(320, 240); //Middle
Point to(639, 240); //Right border
arrowedLine(image, from, to, Vec3b(0, 0, 0), 1, LINE_AA, 0, 0.1);
imshow("Arrow", image);
waitKey(0);
return 0;
}
An arrow is drawn, but at the tip some pixels are missing:
To be more precise, two columns of pixels are not colored correctly (zoomed):
If I disable antialiasing, i.e., if I use
arrowedLine(image, from, to, Vec3b(0, 0, 0), 1, LINE_8, 0, 0.1);
instead (note the LINE_8 instead of LINE_AA), the pixels are there, albeit without antialiasing:
I am aware that antialiasing might rely on neighboring pixels, but it seems strange that pixels are not drawn at all at the borders instead of being drawn without antialiasing. Is there a workaround for this issue?
Increasing the X coordinate, e.g. to 640 or 641) makes the problem worse, i.e., more of the arrow head pixels disappear, while the tip still lacks nearly two complete pixel columns.
Extending and cropping the image would solve the neighboring pixels issue, but in my original use case, where the problem appeared, I cannot enlarge my image, i.e., its size must remain constant.
After a quick review, I've found that OpenCV draws AA lines using a Gaussian filter, which contracts the final image.
As I've suggested in comments, you can implement your own function for the AA mode (you can call the original one if AA is disabled) extending the points manually (see code below to have an idea).
Other option may be to increase the line width when using AA.
You may also simulate the AA effect of OpenCV but on the final image (may be slower but helpful if you have many arrows). I'm not an OpenCV expert so I'll write a general scheme:
// Filter radius, the higher the stronger
const int kRadius = 3;
// Image is extended to fit pixels that are not going to be blurred
Mat blurred(480 + kRadius * 2, 640 + kRadius * 2, CV_8UC3, Scalar(255, 255, 255));
// Points moved a according to filter radius (need testing, but the idea is that)
Point from(320, 240 + kRadius);
Point to(639 + kRadius * 2, 240 + kRadius);
// Extended non-AA arrow
arrowedLine(blurred, ..., LINE_8, ...);
// Simulate AA
GaussianBlur(blurred, blurred, Size(kRadius, kRadius), ...);
// Crop image (be careful, it doesn't copy data)
Mat image = blurred(Rect(kRadius, kRadius, 640, 480));
Another option may be to draw the arrow in an image twice as large and the scale it down with a good smoothing filter.
Obviously, last two options will work only if you don't have any previous data on the image. If so, then use a transparent image for temporal drawing and overlay it at the end.

How can I show circle points in a separate window using OpenCV and C++?

If I draw some circles "in a sequence of frames" in OpenCV by using this function:
void circle(Mat& img, Point center, int radius, const Scalar& color,
int thickness = 1, int lineType = 8, int shift = 0);
...is there any way to show these circle points in a separate window?
You can create as many windows as you like using the imshow function. The first argument of imshow is the window name, the second one is the image you are going to display on it.
So, a simple way to show these circles in a separated window is to create a brand new Mat (with the desired dimensions), draw the points on it and display it using imshow. To draw the points you may use the circle function with radius=1.
More info: docs.opencv.org

OpenCV rotate, distort and translate ROI in new image

I have an image from which I want to get a vertical ROI, apply some transformations and add to another image.
I read a lot of questions and answer on StackOverflow and other forums, but I'm still stuck with this problem. For the moment I'm using the C interface of OpenCV, but I could use the C++ one if needed (I would have to write a conversion function, since I'm working with CGImageRef in Cocoa).
To get from the top image (see below) to the bottom image, I guess I have to :
Get the ROI on the first image ;
Scale it down ;
Get the intersection points on the lines between the center and the 2 circles for my "width" angle (the angle is fixed) ;
Distort the image so the corners stick to my intersection points ;
Rotate around the center point and put it in the output image.
For the moment, I manage well to do this :
Getting the ROI ;
Scaling it with cvResize ;
Getting the intersection points shouldn't be too complicated, as it is pure geometry and I implemented it yet for another purpose.
But, I have no idea at all of how to distort the resulting image of my ROI, and I don't know if it is even possible in OpenCV. Would I have to use a kind of perspective correction ?
And, I've been trying the few good posts solutions I found by here to rotate with the rotated bounding box, but with no good results for the moment.
EDIT :
Well, I managed to do the first part of the work :
Getting a ROI in a basis image ;
Rotating and placing it at a fixed distance from the center.
I used the method explained and coded in this post : https://stackoverflow.com/a/16285286/1060921
I only added a variable to set the rotation point and get my inner circle.
NB : I set the ROI BEFORE to call the method, so the ROI in the post method is... the image size. Then I place it at the center of my final image with a cvAdd.
Here I get one pixel slices of my camera input. What I want to do now is to distort bigger slices, for example from 2 pixels on the inner circle to 5 pixels on the outer one.
See this tutorial which uses warpPerspective to correct perspective distortion.
EDIT: In your case warpAffine should be better and simpler solution.
So, you could do something like this, just use four points instead of three:
Point2f srcTri[3];
Point2f dstTri[3];
Mat rot_mat( 2, 3, CV_32FC1 );
Mat warp_mat( 2, 3, CV_32FC1 );
Mat src, warp_dst, warp_rotate_dst;
/// Load the image
src = imread( ... );
/// Set the dst image the same type and size as src
warp_dst = Mat::zeros( src.rows, src.cols, src.type() );
/// Set your 3 points to calculate the Affine Transform
srcTri[0] = Point2f( 0,0 );
srcTri[1] = Point2f( src.cols - 1, 0 );
srcTri[2] = Point2f( 0, src.rows - 1 );
dstTri[0] = Point2f( src.cols*0.0, src.rows*0.33 );
dstTri[1] = Point2f( src.cols*0.85, src.rows*0.25 );
dstTri[2] = Point2f( src.cols*0.15, src.rows*0.7 );
/// Get the Affine Transform
warp_mat = getAffineTransform( srcTri, dstTri );
/// Apply the Affine Transform just found to the src image
warpAffine( src, warp_dst, warp_mat, warp_dst.size() );

Detecting when a face enters ROI in opencv

I have a face tracking program that reads video from a camera and draws a rectangle around the persons face. What I want to do is have the program recognise when the face enters a particular region of the frame, and initialise some other action. What commands would I need to do this? (I am using C++ and openCV 2.4.3)
E.g
detect face;
if (face is in ROI)
{
close video feed;
}
So you have a rectangle enclosing your face and a rectangle defining the ROI of the image. To check if the face enters the ROI you just have to check if the two rects intersect. The easiest way to do this is to use the overloaded operator & of cv::Rect_ as described here ( http://docs.opencv.org/modules/core/doc/basic_structures.html#rect ) and then check if the area of the resulting rect is > 0.
An example code would look as follows:
cv::Rect r1(0, 0, 10, 10);
cv::Rect r2(5, 5, 10, 10);
if ( (r1&r2).area() )
{
// rects intersect
}
If you want the face to have entered the ROI with a certain percentage, you can compare the intersection area with the minimun of both input areas:
cv::Rect r1(0, 0, 10, 10);
cv::Rect r2(5, 5, 10, 10);
double minFraction( 0.1 );
if ( (r1&r2).area() > minFraction * std::min(r1.area(), r2.area() ) )
{
// rects intersect by at least minFraction
}

OpenCV: draw a white(!) circle in CV_16UC1 mat

I would like to draw a white circle in an matrix of type CV_16UC1.
That is basically what I do:
cv::Mat bla => Type CV_16UC1
cv::circle(bla, cv::Point(15, 15), 1, COLOR, 20);
I tried for Color:
cv::Scalar(0,0,0)
cv::Scalar(255,255,255)
UINT_MAX
but everything turns up black... any suggestions?
If I remember correctly that C1 means one channel image. Try to use a color with one demension: cv::Scalar(0xffff)
I use 0xffff because the 16U means 16 (unsigned) bits per channel.