I am trying to rotate four points(rectangle) around the middle point of them.
But the result looks strange.
I use the formula found here and on wikipedia
p.x'=p.x*cos(alpha) + p.y*sin(alpha);
p.y'=(-1)p.x*sin(alpha) + p.y*cos(alpha);
Is this formula applicable for my purpose (rotating rectangle)?
Here is the source, I try to rotate 33 degrees counter clockwise
Thank You, very much
Mat img(480, 800, CV_8UC4, Scalar(255,255,255,255));
Mat dst(480, 800, CV_8UC4, Scalar(255,255,255,255));
Point p1, p2, p3, p4;
Point center;
p1.x=501; p1.y=247;
p2.x=429; p2.y=291;
p3.x=388; p3.y=222;
p4.x=451; p4.y=186;
circle(img, p1, 3, Scalar(255, 0, 0, 255), 3, 8, 0 );
circle(img, p2, 3, Scalar(0, 255, 0, 255), 3, 8, 0 );
circle(img, p3, 3, Scalar(0, 0, 255, 255), 3, 8, 0 );
circle(img, p4, 3, Scalar(255, 255, 0, 255), 3, 8, 0 );
center.x = (p1.x+p2.x+p3.x+p4.x)/4;
center.y = (p1.y+p2.y+p3.y+p4.y)/4;
double alpha = -33 * 0.0174532925;
double s = sin(alpha);
double c = cos(alpha);
p1.x = (+c*(p1.x-center.x)* + s*(p1.y-center.y)) + center.x;
p1.y = (-s*(p1.x-center.x) + c*(p1.y-center.y)) + center.y;
p2.x = (+c*(p2.x-center.x)* + s*(p2.y-center.y)) + center.x;
p2.y = (-s*(p2.x-center.x) + c*(p2.y-center.y)) + center.y;
p3.x = (+c*(p3.x-center.x)* + s*(p3.y-center.y)) + center.x;
p3.y = (-s*(p3.x-center.x) + c*(p3.y-center.y)) + center.y;
p4.x = (+c*(p4.x-center.x)* + s*(p4.y-center.y)) + center.x;
p4.y = (-s*(p4.x-center.x) + c*(p4.y-center.y)) + center.y;
circle(dst, p1, 3, Scalar(255, 0, 0, 255), 3, 8, 0 );
circle(dst, p2, 3, Scalar(0, 255, 0, 255), 3, 8, 0 );
circle(dst, p3, 3, Scalar(0, 0, 255, 255), 3, 8, 0 );
circle(dst, p4, 3, Scalar(255, 255, 0, 255), 3, 8, 0 );
imshow("src", img);
imshow("dst", dst);
cvMoveWindow("dst", 0, img.cols+50);
waitKey(0);
return 0;
Your formula is correct. Your math looks fine. Your problem is probably just the extra * symbol:
p1.x = (+c*(p1.x-center.x)* + s*(p1.y-center.y)) + center.x;
^
This gets evaluated as:
p1.x = ((+c*(p1.x-center.x))* (+ s*(p1.y-center.y))) + center.x;
Just remove the *
So, i find the solution.
I noob overwrite previous x value with new computed values
This is the solution
for(int i = 0; i<360; i++)
{
Mat img(480, 800, CV_8UC4, Scalar(255,255,255,255));
Mat dst(480, 800, CV_8UC4, Scalar(255,255,255,255));
Point p1, p2, p3, p4;
Point center;
p1.x=501; p1.y=247;
p2.x=429; p2.y=291;
p3.x=388; p3.y=222;
p4.x=451; p4.y=186;
circle(img, p1, 3, Scalar(255, 0, 0, 255), 3, 8, 0 );
circle(img, p2, 3, Scalar(0, 255, 0, 255), 3, 8, 0 );
circle(img, p3, 3, Scalar(0, 0, 255, 255), 3, 8, 0 );
circle(img, p4, 3, Scalar(255, 255, 0, 255), 3, 8, 0 );
center.x = (p1.x+p2.x+p3.x+p4.x)/4;
center.y = (p1.y+p2.y+p3.y+p4.y)/4;
double alpha = -i * 0.0174532925;
double s = sin(alpha);
double c = cos(alpha);
int x = 0, y = 0;
x=p1.x; y=p1.y;
p1.x = (c*(x-center.x) - s*(y-center.y)) + center.x;
p1.y = (s*(x-center.x) + c*(y-center.y)) + center.y;
x=p2.x; y=p2.y;
p2.x = (c*(x-center.x) - s*(y-center.y)) + center.x;
p2.y = (s*(x-center.x) + c*(y-center.y)) + center.y;
x=p3.x; y=p3.y;
p3.x = (c*(x-center.x) - s*(y-center.y)) + center.x;
p3.y = (s*(x-center.x) + c*(y-center.y)) + center.y;
x=p4.x; y=p4.y;
p4.x = (c*(x-center.x) - s*(y-center.y)) + center.x;
p4.y = (s*(x-center.x) + c*(y-center.y)) + center.y;
circle(dst, p1, 3, Scalar(255, 0, 0, 255), 3, 8, 0 );
circle(dst, p2, 3, Scalar(0, 255, 0, 255), 3, 8, 0 );
circle(dst, p3, 3, Scalar(0, 0, 255, 255), 3, 8, 0 );
circle(dst, p4, 3, Scalar(255, 255, 0, 255), 3, 8, 0 );
imshow("src", img);
imshow("dst", dst);
cvMoveWindow("dst", 0, img.cols+50);
waitKey(20);
Related
So, the first problem I ran into was that OpenCV defines its origin about the top left corner rather than the center of the window. This was a problem because I want to just apply a transformation matrix to an image (say a reflection about the x-axis for example) and see it applied "in place", so it stays in the same spot, but is still reflected.
My solution to fix this was to first translate the image to OpenCV's origin, apply my transformation matrix to the image, then translate it back to its original location.
This works fine, however, any part of the image that goes off screen at any point is permanently deleted/cropped. I cannot figure out how to prevent this, I figured there was maybe a flag or something and I tried utilizing BORDER_WRAP rather than BORDER_CONSTANT which almost fixed my problem, but not quite and now I am completely stuck on where to go next.
Here is what I have so far:
int main()
{
// Read in and display input image
Mat src = imread("myImage.png");
imshow("Input Image", src);
// Translate the image to the origin
Mat M = (Mat_<double>(2, 3) << 1, 0, -(src.rows / 2), 0, 1, -(src.cols / 2));
Size dsize = Size(src.rows, src.cols);
warpAffine(src, src, M, dsize, INTER_LINEAR, BORDER_CONSTANT, Scalar());
// Apply the affine transformation
Mat M2 = (Mat_<double>(2, 3) << 1, 0, 0, 0, -1, 0);
dsize = Size(src.rows, src.cols);
warpAffine(src, src, M2, dsize, INTER_LINEAR, BORDER_CONSTANT, Scalar());
// Translate the resulting image back to its original location and display
Mat M3 = (Mat_<double>(2, 3) << 1, 0, (src.rows / 2), 0, 1, (src.cols / 2));
dsize = Size(src.rows, src.cols);
warpAffine(src, src, M3, dsize, INTER_LINEAR, BORDER_CONSTANT, Scalar());
// This is an extremely cropped version of the input image because
// it gets cropped when translated to the origin
imshow("Output Image", src);
waitKey();
return 0;
}
NEW CODE:
// Read in and display input image
Mat src = imread("umichLogo.png");
imshow("Input Image", src);
Mat M = (Mat_<double>(3, 3) << 1, 0, -(src.rows / 2), 0, 1, -(src.cols / 2), 0, 0, 1);
Mat M2 = (Mat_<double>(3, 3) << 1, 0, 0, 0, -1, 0, 0, 0, 1);
Mat M3 = (Mat_<double>(3, 3) << 1, 0, (src.rows / 2), 0, 1, (src.cols / 2), 0, 0, 1);
Mat Composition = M3 * (M2 * M);
Size dsize = Size(src.rows, src.cols);
warpPerspective(src, src, Composition, dsize, INTER_LINEAR, BORDER_CONSTANT, Scalar());
imshow("Output Image", src);
waitKey();
return 0;
To avoid undesired cropping, transform once only (simultaneously).
Mat M = (Mat_<double>(3, 3) << 1, 0, -(src.rows / 2), 0, 1, -(src.cols / 2), 0,0,1);
Mat M2 = (Mat_<double>(3, 3) << 1, 0, 0, 0, -1, 0, 0,0,1);
Mat M3 = (Mat_<double>(3, 3) << 1, 0, (src.rows / 2), 0, 1, (src.cols / 2), 0,0,1);
Mat Composition = M3 * (M2 * M);
Size dsize = Size(src.rows, src.cols);
warpPerspective(src, src, Composition, dsize, INTER_LINEAR, BORDER_CONSTANT, Scalar());
I found that, rows and cols are mistaken (not only for size but also M and M3).
Fixed code is :
Mat M = (Mat_<double>(3, 3) << 1, 0, -(src.cols / 2), 0, 1, -(src.rows / 2), 0,0,1);
Mat M2 = (Mat_<double>(3, 3) << 1, 0, 0, 0, -1, 0, 0,0,1);
Mat M3 = (Mat_<double>(3, 3) << 1, 0, (src.cols / 2), 0, 1, (src.rows / 2), 0,0,1);
Mat Comp = M3 * (M2 * M);
warpPerspective(src, src, Comp, src.size(), INTER_LINEAR, BORDER_CONSTANT, Scalar());
I figure a way to draw a rounded rectangle using OpenCV C++. My function is:
void RoundedRectangle(cv::Mat& src,
cv::Point topLeft,
cv::Size rectSz,
const cv::Scalar lineColor,
const int thickness,
const int lineType,
const float cornerCurvatureRatio)
{
// corners:
// p1 - p2
// | |
// p4 - p3
//
cv::Point p1 = topLeft;
cv::Point p2 = cv::Point (p1.x + rectSz.width, p1.y);
cv::Point p3 = cv::Point (p1.x + rectSz.width, p1.y + rectSz.height);
cv::Point p4 = cv::Point (p1.x, p1.y + rectSz.height);
float cornerRadius = rectSz.height*cornerCurvatureRatio;
// draw straight lines
cv::line(src, cv::Point (p1.x + cornerRadius, p1.y), cv::Point (p2.x - cornerRadius, p2.y), lineColor, thickness, lineType);
cv::line(src, cv::Point (p2.x, p2.y + cornerRadius), cv::Point (p3.x, p3.y - cornerRadius), lineColor, thickness, lineType);
cv::line(src, cv::Point (p4.x + cornerRadius, p4.y), cv::Point (p3.x - cornerRadius, p3.y), lineColor, thickness, lineType);
cv::line(src, cv::Point (p1.x, p1.y + cornerRadius), cv::Point (p4.x, p4.y - cornerRadius), lineColor, thickness, lineType);
// draw arcs
cv::Size rad = cv::Size(cornerRadius, cornerRadius);
cv::ellipse(src, p1 + cv::Point(cornerRadius, cornerRadius), rad, 180.0, 0, 90, lineColor, thickness, lineType);
cv::ellipse(src, p2 + cv::Point(-cornerRadius, cornerRadius), rad, 270.0, 0, 90, lineColor, thickness, lineType);
cv::ellipse(src, p3 + cv::Point(-cornerRadius, -cornerRadius), rad, 0.0, 0, 90, lineColor, thickness, lineType);
cv::ellipse(src, p4 + cv::Point(cornerRadius, -cornerRadius), rad, 90.0, 0, 90, lineColor, thickness, lineType);
}
Now I want to fill the rectangle. I found some fill functions such as cv::fillPoly() and cv::fillConvexPoly however, I need a vector with points. How I can get the list of points from my construction?
Nuzhny was correct, floodFill() is the easiest and potentially the fastest way to fill that rounded rectangle. (Tested with CV 4.1.1)
One line of code will do it, but here is the entire example.
void rounded_rectangle( Mat& src, Point topLeft, Point bottomRight, const Scalar lineColor, int thickness, const int lineType , const int cornerRadius)
{
Point p1 = topLeft;
Point p2 = Point (bottomRight.x, topLeft.y);
Point p3 = bottomRight;
Point p4 = Point (topLeft.x, bottomRight.y);
line(src, Point (p1.x+cornerRadius,p1.y), Point (p2.x-cornerRadius,p2.y), lineColor, thickness, lineType);
line(src, Point (p2.x,p2.y+cornerRadius), Point (p3.x,p3.y-cornerRadius), lineColor, thickness, lineType);
line(src, Point (p4.x+cornerRadius,p4.y), Point (p3.x-cornerRadius,p3.y), lineColor, thickness, lineType);
line(src, Point (p1.x,p1.y+cornerRadius), Point (p4.x,p4.y-cornerRadius), lineColor, thickness, lineType);
ellipse( src, p1+Point(cornerRadius, cornerRadius), Size( cornerRadius, cornerRadius ), 180.0, 0, 90, lineColor, thickness, lineType );
ellipse( src, p2+Point(-cornerRadius, cornerRadius), Size( cornerRadius, cornerRadius ), 270.0, 0, 90, lineColor, thickness, lineType );
ellipse( src, p3+Point(-cornerRadius, -cornerRadius), Size( cornerRadius, cornerRadius ), 0.0, 0, 90, lineColor, thickness, lineType );
ellipse( src, p4+Point(cornerRadius, -cornerRadius), Size( cornerRadius, cornerRadius ), 90.0, 0, 90, lineColor, thickness, lineType );
// choose arbitrary starting point for fill => Top left plus 10,10
Point fillFrom(topLeft.x+10, topLeft.y+10);
Scalar fillColor(199, 120, 0);
// You may want to use `lineColor` instead of `fillColor`
floodFill(src, fillFrom, fillColor);
}
To get the points from the shape that you constructed with cv::line and cv::ellipse , you could draw the shape on a black background and then find the contours of that image.
Another approach that doesn't use line and ellipse commands is to compute the contour of the shape directly using trig.
import cv2, numpy as np, math
# Define the rectangle parameters
directions, ro, next_corner, radius, increment, angle, leg, corners = [(-1,0),(0,-1),(1,0),(0,1)],[(-1,-1),(1,-1),(1,1),(-1,1)],[3,0,1,2],56, 100, 0, 321, [(500,500)]
# Create list of corners
for side in range(4): corners.append((corners[side][0]+leg*directions[side][0], corners[side][1]+leg*directions[side][1]))
# Distance function
def distance(a,b): return math.sqrt((a[0]-b[0])**2+(a[1]-b[1])**2)
# Compute the contour points for each side and corner
contour_points = []
for i in range(4):
# Do the corner
center = corners[i][0] + radius*ro[i][0], corners[i][1] + radius*ro[i][1]
for angle_increment in range(increment):
contour_points.append((int(center[0] + math.cos(angle) * radius), int(center[1] + math.sin(angle) * radius)))
angle += .5*math.pi/increment
# Do the line
start = corners[i][0]+radius*directions[i][0], corners[i][1] + radius*directions[i][1]
while distance(start, (corners[i][0]+radius*directions[i][0], corners[i][1] + radius*directions[i][1])) < leg-2*radius:
contour_points.append(start)
start = start[0]+directions[i][0], start[1]+directions[i][1]
# Draw the contour and show the image
img = np.zeros((600,600), np.uint8)
cv2.drawContours(img, [np.array(contour_points, dtype=np.int32)], 0, 255, -1)
cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
Use cv::floodFill with start point inside your rectangle.
Here is my solution in case id of help to anybody.
void FilledRoundedRectangle(cv::Mat& src, //Image where rect is drawn
cv::Point topLeft, //top left corner
cv::Size rectSz, //rectangle size
const cv::Scalar fillColor, //fill color
const int lineType, //type of line
const int delta, //angle between points on the ellipse
const float cornerCurvatureRatio) //curvature of the corner
{
// corners:
// p1 - p2
// | |
// p4 - p3
//
cv::Point p1 = topLeft;
cv::Point p2 = cv::Point (p1.x + rectSz.width, p1.y);
cv::Point p3 = cv::Point (p1.x + rectSz.width, p1.y + rectSz.height);
cv::Point p4 = cv::Point (p1.x, p1.y + rectSz.height);
int cornerRadius = static_cast<int>(rectSz.height*cornerCurvatureRatio);
std::vector<cv::Point> points;
std::vector<cv::Point> pts;
// Add arcs points
cv::Size rad = cv::Size(cornerRadius, cornerRadius);
// segments:
// s2____s3
// s1 s4
// | |
// s8 s5
// s7_____s6
//
//Add arc s1 to s2
cv::ellipse2Poly(p1 + cv::Point(cornerRadius, cornerRadius) , rad, 180.0, 0, 90, delta , pts);
points.insert(points.end(), pts.begin(), pts.end());
pts.clear();
//Add line s2-s3
points.push_back(cv::Point (p1.x + cornerRadius, p1.y)); points.push_back(cv::Point (p2.x - cornerRadius, p2.y));
//Add arc s3 to s4
cv::ellipse2Poly(p2 + cv::Point(-cornerRadius, cornerRadius) , rad, 270.0, 0, 90, delta, pts);
points.insert(points.end(), pts.begin(), pts.end());
pts.clear();
//Add line s4 to s5
points.push_back(cv::Point (p2.x, p2.y + cornerRadius)); points.push_back(cv::Point (p3.x, p3.y - cornerRadius));
//Add arc s5 to s6
cv::ellipse2Poly(p3 + cv::Point(-cornerRadius, -cornerRadius), rad, 0.0, 0, 90, delta, pts);
points.insert(points.end(), pts.begin(), pts.end());
pts.clear();
//Add line s7 to s8
points.push_back(cv::Point (p4.x + cornerRadius, p4.y)); points.push_back(cv::Point (p3.x - cornerRadius, p3.y));
//Add arc s7 to s8
cv::ellipse2Poly(p4 + cv::Point(cornerRadius, -cornerRadius) , rad, 90.0, 0, 90, delta, pts);
points.insert(points.end(), pts.begin(), pts.end());
//Add line s1 to s8
points.push_back(cv::Point (p1.x, p1.y + cornerRadius)); points.push_back(cv::Point (p4.x, p4.y - cornerRadius));
//fill polygon
cv::fillConvexPoly(src, points, fillColor, lineType);
}
int main(int argc, char** argv)
{
try
{
cv::Mat img = cv::Mat(600, 600,CV_8UC1,cv::Scalar(0));
cv::Point topLeft(179, 179);
cv::Size rectSz(321, 321);
cv::Scalar fillColor(255, 255, 255);
int delta = 1; //every 1 degree
int lineType = cv::LINE_AA;
float cornerCurvatureRatio = 0.1;
FilledRoundedRectangle(img,
topLeft,
rectSz,
fillColor,
lineType,
delta,
cornerCurvatureRatio);
cv::imshow("", img);
cv::waitKey(0);
return 0;
std::cin.get();
} //end try
catch ( std::exception const & ex )
{
std::string errMsg = ex.what();
printf( "%s\n", errMsg.c_str() );
}
catch ( ... )
{
printf( "Error: unknown exception\n" );
}
}
This answer is a generalization of the answer submitted by #Stephen Meschke in case anyone is interested
import cv2
import numpy as np
# Distance function
def distance(a,b):
return np.sqrt((a[0]-b[0])**2+(a[1]-b[1])**2)
def RoundedRectPoints(topLeft,rectSz,cornerCurvature):
# Define the rectangle parameters
directions = [(-1,0),(0,-1),(1,0),(0,1)]
ro = [(-1,-1),(1,-1),(1,1),(-1,1)]
radius = cornerCurvature*(rectSz[0]+rectSz[1]);
increment = 100
angle = 0
corners = [(topLeft[0]+rectSz[0],topLeft[1]+rectSz[1])]
# Create list of corners
for side in range(4):
corners.append((corners[side][0]+rectSz[side%2]*directions[side][0], corners[side][1]+rectSz[side%2]*directions[side][1]))
# Compute the contour points for each side and corner
contour_points = []
for i in range(4):
# Do the corner
center = corners[i][0] + radius*ro[i][0], corners[i][1] + radius*ro[i][1]
for angle_increment in range(increment):
contour_points.append((int(center[0] + np.cos(angle) * radius), int(center[1] + np.sin(angle) * radius)))
angle += .5*np.pi/increment
# Do the line
start = corners[i][0]+radius*directions[i][0], corners[i][1] + radius*directions[i][1]
while distance(start, (corners[i][0]+radius*directions[i][0], corners[i][1] + radius*directions[i][1])) < np.min(rectSz)-2*radius:
contour_points.append(start)
start = start[0]+directions[i][0], start[1]+directions[i][1]
return contour_points
# Draw the contour and show the image
img = np.zeros((600,600), np.uint8)
topLeft = (179,179)
rectSz = (321,321)
cornerCurvature = 0.09
contour_points = RoundedRectPoints(topLeft,rectSz,cornerCurvature)
cv2.drawContours(img, [np.array(contour_points, dtype=np.int32)], 0, 255, -1)
cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
I am using visual studio 15 and working in opencv 3.0 ,i am getting access violation error in my code and even this function is not working with sample code given in opencv.
#include"stdafx.h"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <math.h>
#include <iostream>
using namespace cv;
using namespace std;
static void help()
{
cout
<< "\nThis program illustrates the use of findContours and drawContours\n"
<< "The original image is put up along with the image of drawn contours\n"
<< "Usage:\n"
<< "./contours2\n"
<< "\nA trackbar is put up which controls the contour level from -3 to 3\n"
<< endl;
}
const int w = 500;
int levels = 3;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
static void on_trackbar(int, void*)
{
Mat cnt_img = Mat::zeros(w, w, CV_8UC3);
int _levels = levels - 3;
drawContours(cnt_img, contours, _levels <= 0 ? 3 : -1, Scalar(128, 255, 255),
3, LINE_AA, hierarchy, std::abs(_levels));
imshow("contours", cnt_img);
}
int main(int argc, char**)
{
Mat img = Mat::zeros(w, w, CV_8UC1);
if (argc > 1)
{
help();
return -1;
}
//Draw 6 faces
for (int i = 0; i < 6; i++)
{
int dx = (i % 2) * 250 - 30;
int dy = (i / 2) * 150;
const Scalar white = Scalar(255);
const Scalar black = Scalar(0);
if (i == 0)
{
for (int j = 0; j <= 10; j++)
{
double angle = (j + 5)*CV_PI / 21;
line(img, Point(cvRound(dx + 100 + j * 10 - 80 * cos(angle)),
cvRound(dy + 100 - 90 * sin(angle))),
Point(cvRound(dx + 100 + j * 10 - 30 * cos(angle)),
cvRound(dy + 100 - 30 * sin(angle))), white, 1, 8, 0);
}
}
ellipse(img, Point(dx + 150, dy + 100), Size(100, 70), 0, 0, 360, white, -1, 8, 0);
ellipse(img, Point(dx + 115, dy + 70), Size(30, 20), 0, 0, 360, black, -1, 8, 0);
ellipse(img, Point(dx + 185, dy + 70), Size(30, 20), 0, 0, 360, black, -1, 8, 0);
ellipse(img, Point(dx + 115, dy + 70), Size(15, 15), 0, 0, 360, white, -1, 8, 0);
ellipse(img, Point(dx + 185, dy + 70), Size(15, 15), 0, 0, 360, white, -1, 8, 0);
ellipse(img, Point(dx + 115, dy + 70), Size(5, 5), 0, 0, 360, black, -1, 8, 0);
ellipse(img, Point(dx + 185, dy + 70), Size(5, 5), 0, 0, 360, black, -1, 8, 0);
ellipse(img, Point(dx + 150, dy + 100), Size(10, 5), 0, 0, 360, black, -1, 8, 0);
ellipse(img, Point(dx + 150, dy + 150), Size(40, 10), 0, 0, 360, black, -1, 8, 0);
ellipse(img, Point(dx + 27, dy + 100), Size(20, 35), 0, 0, 360, white, -1, 8, 0);
ellipse(img, Point(dx + 273, dy + 100), Size(20, 35), 0, 0, 360, white, -1, 8, 0);
}
//show the faces
namedWindow("image", 1);
imshow("image", img);
//Extract the contours so that
//vector<vector<Point> > contours0;
vector<cv::Mat> coutours;
findContours(img, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);
contours.resize(contours.size());
for (size_t k = 0; k < contours.size(); k++)
approxPolyDP(Mat(contours[k]), contours[k], 3, true);
namedWindow("contours", 1);
createTrackbar("levels+3", "contours", &levels, 7, on_trackbar);
on_trackbar(0, 0);
waitKey();
return 0;
}
I am using x64 architecture and linked all the library .lib along with d.lib(debug library).
I think the problem comes from your "contours" variable. You're declaring it as a vector<cv::Mat>, but the contours are not represented as a matrix, but rather as a series of points.
Look at this example : http://docs.opencv.org/2.4/doc/tutorials/imgproc/shapedescriptors/find_contours/find_contours.html
They declare the contours as vector<vector<Point> > contours;
Look also at the declaration of the function (http://docs.opencv.org/2.4/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=findcontours#findcontours), the paramater contour is defined as : contours – Detected contours. Each contour is stored as a vector of points.
I want to use convexity defects of a human hand as input to a classifier. I want to do this to detect hand gestures (sign language alphabet). Can someone please help me.
The code below is available on the opencv documentation. I want to know how to use this for my the purpose stated above.
// Data for visual representation
int width = 512, height = 512;
Mat image = Mat::zeros(height, width, CV_8UC3);
// Set up training data
float labels[4] = { 1.0, -1.0, -1.0, -1.0 };
Mat labelsMat(4, 1, CV_32FC1, labels);
// Storing as Mat objects of floats
float trainingData[4][2] = { { 501, 10 }, { 255, 10 }, { 501, 255 }, { 10, 501 } };
Mat trainingDataMat(4, 2, CV_32FC1, trainingData);
// Set up SVM's parameters
CvSVMParams params;
params.svm_type = CvSVM::C_SVC;
params.kernel_type = CvSVM::LINEAR;
params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER, 100, 1e-6);
// Train the SVM
CvSVM SVM;
SVM.train(trainingDataMat, labelsMat, Mat(), Mat(), params);
Vec3b green(0, 255, 0), blue(255, 0, 0);
// Show the decision regions given by the SVM
for (int i = 0; i < image.rows; ++i)
for (int j = 0; j < image.cols; ++j)
{
Mat sampleMat = (Mat_<float>(1, 2) << j, i);
float response = SVM.predict(sampleMat);
if (response == 1)
image.at<Vec3b>(i, j) = green;
else if (response == -1)
image.at<Vec3b>(i, j) = blue;
}
// Show the training data
int thickness = -1;
int lineType = 8;
circle(image, Point(501, 10), 5, Scalar(0, 0, 0), thickness, lineType);
circle(image, Point(255, 10), 5, Scalar(255, 255, 255), thickness, lineType);
circle(image, Point(501, 255), 5, Scalar(255, 255, 255), thickness, lineType);
circle(image, Point(10, 501), 5, Scalar(255, 255, 255), thickness, lineType);
// Show support vectors
thickness = 2;
lineType = 8;
int c = SVM.get_support_vector_count();
for (int i = 0; i < c; ++i)
{
const float* v = SVM.get_support_vector(i);
circle(image, Point((int)v[0], (int)v[1]), 6, Scalar(128, 128, 128), thickness, lineType);
}
imwrite("result.png", image); // save the image
imshow("SVM Simple Example", image); // show it to the user
waitKey(0);
}
How can I draw a rectangle with rounded corners in OpenCV? I know that the functions ellipse() and line() can be simply put together to draw it. I just wonder if someone has done it before and has put it in a proper function so I can use it? Ideally the corner radius is to calibrate in a parameter.
I searched a lot for that, but it seems no one had that problem before. If no one has such I function I will probably post my own solution here in a few days.
I realized, this is much easier that I thought. Here is my function. I hope it is helpful for someone.
/**
* Draws a rectangle with rounded corners, the parameters are the same as in the OpenCV function #see rectangle();
* #param cornerRadius A positive int value defining the radius of the round corners.
* #author K
*/
void rounded_rectangle( Mat& src, Point topLeft, Point bottomRight, const Scalar lineColor, const int thickness, const int lineType , const int cornerRadius)
{
/* corners:
* p1 - p2
* | |
* p4 - p3
*/
Point p1 = topLeft;
Point p2 = Point (bottomRight.x, topLeft.y);
Point p3 = bottomRight;
Point p4 = Point (topLeft.x, bottomRight.y);
// draw straight lines
line(src, Point (p1.x + cornerRadius, p1.y), Point (p2.x - cornerRadius, p2.y), lineColor, thickness, lineType);
line(src, Point (p2.x, p2.y + cornerRadius), Point (p3.x, p3.y - cornerRadius), lineColor, thickness, lineType);
line(src, Point (p4.x + cornerRadius, p4.y), Point (p3.x-cornerRadius, p3.y), lineColor, thickness, lineType);
line(src, Point (p1.x, p1.y + cornerRadius), Point (p4.x, p4.y - cornerRadius), lineColor, thickness, lineType);
// draw arcs
ellipse( src, p1 + Point(cornerRadius, cornerRadius), Size( cornerRadius, cornerRadius ), 180.0, 0, 90, lineColor, thickness, lineType );
ellipse( src, p2 + Point(-cornerRadius, cornerRadius), Size( cornerRadius, cornerRadius ), 270.0, 0, 90, lineColor, thickness, lineType );
ellipse( src, p3 + Point(-cornerRadius, -cornerRadius), Size( cornerRadius, cornerRadius ), 0.0, 0, 90, lineColor, thickness, lineType );
ellipse( src, p4 + Point(cornerRadius, -cornerRadius), Size( cornerRadius, cornerRadius ), 90.0, 0, 90, lineColor, thickness, lineType );
}
Here is the python version with filled/not filled feature and corner_radius automatically calculated based on the image's height.
import cv2
import numpy as np
def rounded_rectangle(src, top_left, bottom_right, radius=1, color=255, thickness=1, line_type=cv2.LINE_AA):
# corners:
# p1 - p2
# | |
# p4 - p3
p1 = top_left
p2 = (bottom_right[1], top_left[1])
p3 = (bottom_right[1], bottom_right[0])
p4 = (top_left[0], bottom_right[0])
height = abs(bottom_right[0] - top_left[1])
if radius > 1:
radius = 1
corner_radius = int(radius * (height/2))
if thickness < 0:
#big rect
top_left_main_rect = (int(p1[0] + corner_radius), int(p1[1]))
bottom_right_main_rect = (int(p3[0] - corner_radius), int(p3[1]))
top_left_rect_left = (p1[0], p1[1] + corner_radius)
bottom_right_rect_left = (p4[0] + corner_radius, p4[1] - corner_radius)
top_left_rect_right = (p2[0] - corner_radius, p2[1] + corner_radius)
bottom_right_rect_right = (p3[0], p3[1] - corner_radius)
all_rects = [
[top_left_main_rect, bottom_right_main_rect],
[top_left_rect_left, bottom_right_rect_left],
[top_left_rect_right, bottom_right_rect_right]]
[cv2.rectangle(src, rect[0], rect[1], color, thickness) for rect in all_rects]
# draw straight lines
cv2.line(src, (p1[0] + corner_radius, p1[1]), (p2[0] - corner_radius, p2[1]), color, abs(thickness), line_type)
cv2.line(src, (p2[0], p2[1] + corner_radius), (p3[0], p3[1] - corner_radius), color, abs(thickness), line_type)
cv2.line(src, (p3[0] - corner_radius, p4[1]), (p4[0] + corner_radius, p3[1]), color, abs(thickness), line_type)
cv2.line(src, (p4[0], p4[1] - corner_radius), (p1[0], p1[1] + corner_radius), color, abs(thickness), line_type)
# draw arcs
cv2.ellipse(src, (p1[0] + corner_radius, p1[1] + corner_radius), (corner_radius, corner_radius), 180.0, 0, 90, color ,thickness, line_type)
cv2.ellipse(src, (p2[0] - corner_radius, p2[1] + corner_radius), (corner_radius, corner_radius), 270.0, 0, 90, color , thickness, line_type)
cv2.ellipse(src, (p3[0] - corner_radius, p3[1] - corner_radius), (corner_radius, corner_radius), 0.0, 0, 90, color , thickness, line_type)
cv2.ellipse(src, (p4[0] + corner_radius, p4[1] - corner_radius), (corner_radius, corner_radius), 90.0, 0, 90, color , thickness, line_type)
return src
Usage:
top_left = (0, 0)
bottom_right = (500, 800)
color = (255, 255, 255)
image_size = (500, 800, 3)
img = np.zeros(image_size)
img = rounded_rectangle(img, top_left, bottom_right, color=color, radius=0.5, thickness=-1)
cv2.imshow('rounded_rect', img)
cv2.waitKey(0)
Here's a Python implementation(in case anyone was looking for one): it draws a rounded corner (of random radius and line thickness --- change that if you want) border around an image:
def addRoundedRectangleBorder(img):
height, width, channels = img.shape
border_radius = int(width * random.randint(1, 10)/100.0)
line_thickness = int(max(width, height) * random.randint(1, 3)/100.0)
edge_shift = int(line_thickness/2.0)
red = random.randint(230,255)
green = random.randint(230,255)
blue = random.randint(230,255)
color = (blue, green, red)
#draw lines
#top
cv2.line(img, (border_radius, edge_shift),
(width - border_radius, edge_shift), (blue, green, red), line_thickness)
#bottom
cv2.line(img, (border_radius, height-line_thickness),
(width - border_radius, height-line_thickness), (blue, green, red), line_thickness)
#left
cv2.line(img, (edge_shift, border_radius),
(edge_shift, height - border_radius), (blue, green, red), line_thickness)
#right
cv2.line(img, (width - line_thickness, border_radius),
(width - line_thickness, height - border_radius), (blue, green, red), line_thickness)
#corners
cv2.ellipse(img, (border_radius+ edge_shift, border_radius+edge_shift),
(border_radius, border_radius), 180, 0, 90, color, line_thickness)
cv2.ellipse(img, (width-(border_radius+line_thickness), border_radius),
(border_radius, border_radius), 270, 0, 90, color, line_thickness)
cv2.ellipse(img, (width-(border_radius+line_thickness), height-(border_radius + line_thickness)),
(border_radius, border_radius), 10, 0, 90, color, line_thickness)
cv2.ellipse(img, (border_radius+edge_shift, height-(border_radius + line_thickness)),
(border_radius, border_radius), 90, 0, 90, color, line_thickness)
return img
based on the code from #author K. make the function have ability to draw filled rounded rectangle if pass -1 as thickness
python version
def DrawRoundedRectangle(img, topLeft, bottomRight, radius=1, color=255, thickness=1, line_type=cv.LINE_AA):
min_half = int(min((bottomRight[0] - topLeft[0]), (bottomRight[1] - topLeft[1])) * 0.5)
radius = min(radius, min_half)
# /* corners:
# * p1 - p2
# * | |
# * p4 - p3
# */
p1 = topLeft
p2 = (bottomRight[0], topLeft[1])
p3 = bottomRight
p4 = (topLeft[0], bottomRight[1])
if(thickness < 0):
# // draw rectangle
cv.rectangle(img, (p1[0] + radius, p1[1]), (p3[0] - radius, p3[1]), color, thickness, line_type)
cv.rectangle(img, (p1[0], p1[1] + radius), (p3[0], p3[1] - radius), color, thickness, line_type)
else:
# // draw straight lines
cv.line(img, (p1[0] + radius, p1[1]), (p2[0] - radius, p2[1]), color, thickness, line_type);
cv.line(img, (p2[0], p2[1] + radius), (p3[0], p3[1] - radius), color, thickness, line_type);
cv.line(img, (p4[0] + radius, p4[1]), (p3[0]-radius, p3[1]), color, thickness, line_type);
cv.line(img, (p1[0], p1[1] + radius), (p4[0], p4[1] - radius), color, thickness, line_type);
# // draw arcs
if(radius > 0):
cv.ellipse( img, (p1[0] + radius, p1[1] + radius), ( radius, radius ), 180.0, 0, 90, color, thickness, line_type );
cv.ellipse( img, (p2[0] - radius, p2[1] + radius), ( radius, radius ), 270.0, 0, 90, color, thickness, line_type );
cv.ellipse( img, (p3[0] - radius, p3[1] - radius), ( radius, radius ), 0.0, 0, 90, color, thickness, line_type );
cv.ellipse( img, (p4[0] + radius, p4[1] - radius), ( radius, radius ), 90.0, 0, 90, color, thickness, line_type );
javascript version
function DrawRoundedRectangle(img, topLeft, bottomRight, radius=1, color=255, thickness=1, line_type=cv.LINE_AA){
let min_half = Math.floor(Math.min((bottomRight.x - topLeft.x), (bottomRight.y - topLeft.y)) * 0.5)
radius = Math.min(radius, min_half)
/* corners:
# * p1 - p2
# * | |
# * p4 - p3
# */
let p1 = topLeft
let p2 = new cv.Point(bottomRight.x, topLeft.y)
let p3 = bottomRight
let p4 = new cv.Point(topLeft.x, bottomRight.y)
if(thickness < 0){
// draw rectangle
cv.rectangle(img, new cv.Point(p1.x + radius, p1.y), new cv.Point(p3.x - radius, p3.y), color, thickness, line_type)
cv.rectangle(img, new cv.Point(p1.x, p1.y + radius), new cv.Point(p3.x, p3.y - radius), color, thickness, line_type)
}
else{
// draw straight lines
cv.line(img, new cv.Point(p1.x + radius, p1.y), new cv.Point(p2.x - radius, p2.y), color, thickness, line_type);
cv.line(img, new cv.Point(p2.x, p2.y + radius), new cv.Point(p3.x, p3.y - radius), color, thickness, line_type);
cv.line(img, new cv.Point(p4.x + radius, p4.y), new cv.Point(p3.x-radius, p3.y), color, thickness, line_type);
cv.line(img, new cv.Point(p1.x, p1.y + radius), new cv.Point(p4.x, p4.y - radius), color, thickness, line_type);
}
// draw arcs
if(radius > 0){
cv.ellipse( img, new cv.Point(p1.x + radius, p1.y + radius), new cv.Size( radius, radius ), 180.0, 0, 90, color, thickness, line_type );
cv.ellipse( img, new cv.Point(p2.x - radius, p2.y + radius), new cv.Size( radius, radius ), 270.0, 0, 90, color, thickness, line_type );
cv.ellipse( img, new cv.Point(p3.x - radius, p3.y - radius), new cv.Size( radius, radius ), 0.0, 0, 90, color, thickness, line_type );
cv.ellipse( img, new cv.Point(p4.x + radius, p4.y - radius), new cv.Size( radius, radius ), 90.0, 0, 90, color, thickness, line_type );
}
}