Related
i want to draw the canni result on the original image. How can i do this? i tried like this, but an error comes out
Mat image;
image = imread("C:\\test.jpg",1);
Mat gray, edqes, out;
cvtColor(image, gray, COLOR_BGR2GRAY);
Canny(gray, edqes, 100, 200, 3);
out.copyTo(image,edqes);
cvNamedWindow("original",CV_WINDOW_NORMAL);
cvNamedWindow("binary",CV_WINDOW_NORMAL);
cvNamedWindow("canny",CV_WINDOW_NORMAL);
cvNamedWindow("out",CV_WINDOW_NORMAL);
imshow("original",image);
imshow("binary", gray);
imshow("canny", edqes);
imshow("out", out);
cvWaitKey(0);
cvDestroyAllWindows();
Try:
cvtColor(edqes, edqes, COLOR_GRAY2BGR);
bitwise_or(edqes,image,out);
How to make my video not delay, in the beginning of the code it's not delay, but if I use the GaussianBlur, morphology operation, and SimpleBlobDetector, the video gets delayed, please someone help me..
Thanks in advance
using namespace cv;
using namespace std;
int _tmain(int argc, _TCHAR* argv[]){
VideoCapture cap(0);
cap.open("file.mp4"); //read the video
if (!cap.isOpened())
{
cout << "Cannot open the video cam" << endl;
return -1;
}
double Width = cap.get(CV_CAP_PROP_FRAME_WIDTH);
double Height = cap.get(CV_CAP_PROP_FRAME_HEIGHT);
cvNamedWindow("MyVideo", CV_WINDOW_AUTOSIZE);
while (1)
{
Mat frame;
bool bSuccess = cap.read(frame);
SimpleBlobDetector::Params params;
// Change thresholds
params.minThreshold = 0;
params.maxThreshold = 255;
params.filterByColor = true;
params.blobColor = 255;
// Filter by Area.
params.filterByArea = true;
params.minArea = 5 ;
// Filter by Circularity
params.filterByCircularity = true;
params.minCircularity = 0.1;
// Filter by Convexity
params.filterByConvexity = true;
params.minConvexity = 0.87;
// Filter by Inertia
params.filterByInertia = true;
params.minInertiaRatio = 0.01;
//crop the image with the pixel i want
Mat blur, crop;
GaussianBlur(frame, blur, Size(15, 15), 0); //blur the image
Point corners[1][4];
corners[0][0] = Point(550, 30); //top left
corners[0][1] = Point(250, 700); //bottom left
corners[0][2] = Point(1100, 700); //bottom right
corners[0][3] = Point(600, 30); //top right
const Point* corner_list[1] = { corners[0] };
int num_points = 4;
int num_polygons = 1;
int line_type = 8;
Mat mask(720, 1280, CV_8UC3, cv::Scalar(0, 0, 0));
fillPoly(mask, corner_list, &num_points, num_polygons, cv::Scalar(255, 255, 255), line_type);
bitwise_and(blur, mask, crop);//combine the image
Mat gray, changeToBlack;
cvtColor(crop, gray, COLOR_BGR2GRAY); //grayscale citra
inRange(gray, Scalar(0), Scalar(0), changeToBlack);
Mat black_image(gray.size(), CV_8U, Scalar(255));
black_image.copyTo(gray, changeToBlack);
Mat thres, tes;
threshold(gray, tes, 51, 255, THRESH_BINARY_INV); //threshold citra and 51 set value
Mat erosi, dilasi, open, close, tophat;
Mat kernel = Mat(3, 3, CV_8UC1, Scalar(1));
morphologyEx(tes, erosi, MORPH_ERODE, kernel, Point(-1, -1), 3);
morphologyEx(erosi, dilasi, MORPH_DILATE, kernel, Point(-1, -1), 20);
vector<KeyPoint> keypoints;
Ptr<SimpleBlobDetector> detector = SimpleBlobDetector::create(params);
detector->detect(dilasi, keypoints);
Mat im_with_keypoints;
drawKeypoints(dilasi, keypoints, im_with_keypoints, Scalar(205, 0, 0), DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
imshow("gray", frame);
imshow("MyVideo", im_with_keypoints);
if (waitKey(30) == 27)
{
cout << "esc key is pressed by user" << endl;
break;
}
}
return 0;
}
Anyone please help me
Oh! All actions and memory allocation inside loop. Try this:
int _tmain(int argc, _TCHAR* argv[]){
VideoCapture cap(0);
cap.open("file.mp4"); //read the video
if (!cap.isOpened())
{
cout << "Cannot open the video cam" << endl;
return -1;
}
double Width = cap.get(CV_CAP_PROP_FRAME_WIDTH);
double Height = cap.get(CV_CAP_PROP_FRAME_HEIGHT);
cvNamedWindow("MyVideo", CV_WINDOW_AUTOSIZE);
Mat frame;
Mat blur, crop;
Mat mask(720, 1280, CV_8UC3, cv::Scalar(0, 0, 0));
Mat gray, changeToBlack;
Mat black_image(gray.size(), CV_8U, Scalar(255));
Mat thres, tes;
Mat erosi, dilasi, open, close, tophat;
Mat kernel = Mat(3, 3, CV_8UC1, Scalar(1));
Mat im_with_keypoints;
SimpleBlobDetector::Params params;
// Change thresholds
params.minThreshold = 0;
params.maxThreshold = 255;
params.filterByColor = true;
params.blobColor = 255;
// Filter by Area.
params.filterByArea = true;
params.minArea = 5 ;
// Filter by Circularity
params.filterByCircularity = true;
params.minCircularity = 0.1;
// Filter by Convexity
params.filterByConvexity = true;
params.minConvexity = 0.87;
// Filter by Inertia
params.filterByInertia = true;
params.minInertiaRatio = 0.01;
vector<KeyPoint> keypoints;
Ptr<SimpleBlobDetector> detector = SimpleBlobDetector::create(params);
while (cap.read(frame))
{
//crop the image with the pixel i want
GaussianBlur(frame, blur, Size(15, 15), 0); //blur the image
Point corners[1][4];
corners[0][0] = Point(550, 30); //top left
corners[0][1] = Point(250, 700); //bottom left
corners[0][2] = Point(1100, 700); //bottom right
corners[0][3] = Point(600, 30); //top right
const Point* corner_list[1] = { corners[0] };
int num_points = 4;
int num_polygons = 1;
int line_type = 8;
fillPoly(mask, corner_list, &num_points, num_polygons, cv::Scalar(255, 255, 255), line_type);
bitwise_and(blur, mask, crop);//combine the image
cvtColor(crop, gray, COLOR_BGR2GRAY); //grayscale citra
inRange(gray, Scalar(0), Scalar(0), changeToBlack);
black_image.copyTo(gray, changeToBlack);
threshold(gray, tes, 51, 255, THRESH_BINARY_INV); //threshold citra and 51 set value
morphologyEx(tes, erosi, MORPH_ERODE, kernel, Point(-1, -1), 3);
morphologyEx(erosi, dilasi, MORPH_DILATE, kernel, Point(-1, -1), 20);
detector->detect(dilasi, keypoints);
drawKeypoints(dilasi, keypoints, im_with_keypoints, Scalar(205, 0, 0), DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
imshow("gray", frame);
imshow("MyVideo", im_with_keypoints);
if (waitKey(1) == 27)
{
cout << "esc key is pressed by user" << endl;
break;
}
}
return 0;
}
I want to draw a rectangle in a video capture that I converted to gray.
This is my code:
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, char* argv[])
{
VideoCapture cap(0);
if (!cap.isOpened())
{
// print error msg
return -1;
}
namedWindow("gray", CV_WINDOW_AUTOSIZE);
int pointf[8][4] = {
{100,100 , 150,50},
{100,250 , 150,200},
{100,430 , 150,380},
{295,200 , 345,150},
{295,400 , 345,350},
{490,100 , 540,50},
{490,250 , 540,200},
{490,430 , 540,380}
};
int i;
int j;
Mat frame;
Mat gray;
for (;;)
{
cap >> frame;
cvtColor(frame, gray, CV_BGR2GRAY);
for (i = 0; i < 8; i++) {
rectangle(frame, Point(pointf[i][0],pointf[i][1]), Point(pointf[i][2], pointf[i][3]), Scalar(0, 0, 255), 3);
}
imshow("gray", gray);
imshow("gray",frame);
if (waitKey(30) >= 0)
break;
}
return 0;
}
In the result, I succeed to draw eight of rectangle, but the video is not in a gray scale. If i reorder the imshow (make video gray first, then draw the rectangle), it will make a video in grayscale, but the rectangle didn't show.
So, any suggestion what I suppose to do?
I'm new in using OpenCV.
I use OpenCV 3.1.0 and C++ in Visual Studio 2015
Thanks.
Look at your code closely. Here's what you're doing:
imshow("gray", gray);
imshow("gray",frame);
What this does is that first it displays your greyscale image in a window called grey, and then immediately displays your color image frame in the same window. Which means that you don't get to see your gray image at all. That's your first error.
Your second error is in the statement:
rectangle(frame, Point(pointf[i][0],pointf[i][1]), Point(pointf[i][2], pointf[i][3]), Scalar(0, 0, 255), 3);
frame is your RGB image, not your gray image, so you're not drawing a rectangle on your grey image at all.
If you need to convert your original image to greyscale and then draw a rectangle on it, here's what your do:
for (;;)
{
cap >> frame;
cvtColor(frame, gray, CV_BGR2GRAY);
for (i = 0; i < 8; i++) {
//draw rect on gray, not frame
rectangle(gray, Point(pointf[i][0],pointf[i][1]), Point(pointf[i][2], pointf[i][3]), Scalar(0, 0, 255), 3);
}
//display the Mat objects in different windows
imshow("gray", gray);
imshow("original",frame);
if (waitKey(30) >= 0)
break;
}
I’m trying to detect some rectangles (white colored) which is drawn on an image. (say using paint or some other image editing tool).
As I’m very much beginner to image processing I searched through net and OpenCV sample program to accomplish the job, but could not get it to working perfectly. I’m using OpenCV C++ library.
Algorithm that I’ve tried
cv::Mat src = cv::imread(argv[1]);
cv::Mat gray;
cv::cvtColor(src, gray, CV_BGR2GRAY);
meanStdDev(gray, mu, sigma);
cv::Mat bw;
cv::Canny(gray, bw, mu.val[0] - sigma.val[0], mu.val[0] + sigma.val[0]);
std::vector<std::vector<cv::Point> > contours;
cv::findContours(bw.clone(), contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
std::vector<cv::Point> approx;
for (int i = 0; i < contours.size(); i++){
cv::approxPolyDP(cv::Mat(contours[i]), approx, cv::arcLength(cv::Mat(contours[i]), true)*0.02, true);
if (approx.size() >= 4 && approx.size() <= 6)
Rect boundRect = boundingRect( Mat(approx) );
rectangle( dst, boundRect.tl(), boundRect.br(), Scalar(255,255,255), 1, 8, 0 );}
Only one rectangle is detected. Can you please guide me or some link for the same.
Input image:
Output image:
I could not compile your code sample because there boundRect is declared within the if-block but rectangle drawing (trying to access boundRect) is outside of the if-block, so I adjusted your code:
int main(int argc, char* argv[])
{
cv::Mat src = cv::imread("C:/StackOverflow/Input/rectangles.png");
cv::Mat dst = src.clone();
cv::Mat gray;
cv::cvtColor(src, gray, CV_BGR2GRAY);
// ADDED: missing declaration of mu and sigma
cv::Scalar mu, sigma;
meanStdDev(gray, mu, sigma);
cv::Mat bw;
cv::Canny(gray, bw, mu.val[0] - sigma.val[0], mu.val[0] + sigma.val[0]);
// ADDED: displaying the canny output
cv::imshow("canny", bw);
std::vector<std::vector<cv::Point> > contours;
cv::findContours(bw.clone(), contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
std::vector<cv::Point> approx;
for (int i = 0; i < contours.size(); i++){
cv::approxPolyDP(cv::Mat(contours[i]), approx, cv::arcLength(cv::Mat(contours[i]), true)*0.02, true);
if (approx.size() >= 4 && approx.size() <= 6)
{
// ADDED: brackets around both lines belonging to the if-block
cv::Rect boundRect = cv::boundingRect(cv::Mat(approx));
cv::rectangle(dst, boundRect.tl(), boundRect.br(), cv::Scalar(255, 255, 255), 3, 8, 0);
}
}
// ADDED: displaying input and results
cv::imshow("input", src);
cv::imshow("dst", dst);
cv::imwrite("C:/StackOverflow/Output/rectangles.png", dst);
cv::waitKey(0);
return 0;
}
with your input image I do get this output:
which is probably not what you expected. See the canny output image (it is always good to have a look at intermediate results for visual debugging!), there are just too many structures in the image and contours will cover all of these, so there are some that will be approximated to polynomes with 4 to 6 elements.
Instead you'll have to become a bit smarter. You could try to extract straight lines with cv::HoughLinesP and connect those lines. Or you could try to segment the image first by finding white areas (if your rectangles are always white).
int main(int argc, char* argv[])
{
cv::Mat src = cv::imread("C:/StackOverflow/Input/rectangles.png");
cv::Mat dst = src.clone();
cv::Mat gray;
cv::cvtColor(src, gray, CV_BGR2GRAY);
cv::Mat mask;
// find "white" pixel
cv::inRange(src, cv::Scalar(230, 230, 230), cv::Scalar(255, 255, 255), mask);
cv::imshow("mask", mask);
std::vector<std::vector<cv::Point> > contours;
cv::findContours(mask, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
std::vector<cv::Point> approx;
for (int i = 0; i < contours.size(); i++){
cv::approxPolyDP(cv::Mat(contours[i]), approx, cv::arcLength(cv::Mat(contours[i]), true)*0.02, true);
if (approx.size() >= 4 && approx.size() <= 6)
{
cv::Rect boundRect = cv::boundingRect(cv::Mat(approx));
cv::rectangle(dst, boundRect.tl(), boundRect.br(), cv::Scalar(255, 255, 255), 1, 8, 0);
}
}
cv::imshow("input", src);
cv::imshow("dst", dst);
cv::imwrite("C:/StackOverflow/Output/rectangles2.png", dst);
cv::waitKey(0);
return 0;
}
gives this result:
As you can see, there are other bright regions near white, too. The polynom approximation does not help much, too.
In general, it's easier to segment a color (even white) in HSV space. With appropriate thresholds:
inRange(hsv, Scalar(0, 0, 220), Scalar(180, 30, 255), mask);
where we don't care about the Hue, and keep only low Saturation and high Value, I get:
Then you can easily find connected components, and discard blobs smaller than a threshold th_blob_size. Resulting rectangles are (in green):
You can eventually apply other filtering stage to account for more difficult situations, but for this image removing small blobs is enough. Please post other images if you need something more robust in general.
Code:
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
Mat3b img = imread("path_to_image");
int th_blob_size = 100;
Mat3b hsv;
cvtColor(img, hsv, COLOR_BGR2HSV);
Mat1b mask;
inRange(hsv, Scalar(0, 0, 220), Scalar(180, 30, 255), mask);
vector<vector<Point>> contours;
findContours(mask.clone(), contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);
Mat3b res = img.clone();
for (int i = 0; i < contours.size(); ++i)
{
// Remove small blobs
if (contours[i].size() < th_blob_size)
{
continue;
}
Rect box = boundingRect(contours[i]);
rectangle(res, box, Scalar(0,255,0), 1);
}
imshow("Result", res);
waitKey();
return 0;
}
Are you sure you are only finding one contour or are you only drawing one contour? It doesn't look like you are looping in the drawing routine so you will only ever draw the first one that is found.
I have a blog, long since dead, that may provide you some good direction on this: http://workingwithcomputervision.blogspot.co.uk/2012/09/game-player-step-2-finding-game-board.html
Should the link die I believe this is the most relevant part of the article which relates to drawing contours:
//Draw contours
for (int i = 0; i < contours.size(); i++) {
Scalar color = Scalar(0, 255, 0);
drawContours(drawing, contours, i, color, 2, 8, hierarchy, 0, Point());
}
I notice you are using bounding rectangles for the drawing. Here is an alternative drawing routine, again from the above link, that does this:
Rect bounds;
Mat drawing = Mat::zeros(purpleOnly.size(), CV_8UC3);
int j = 0;
for (int i = 0; i < contours.size(); i++) {
if (arcLength(contours[i], true) > 500){
Rect temp = boundingRect(contours[i]);
rectangle(drawing, temp, Scalar(255, 0, 0), 2, 8);
if (j == 0) {
bounds = temp;
} else {
bounds = bounds | temp;
}
j++;
}
}
Note that I also do some checks on the size of the contour to filter out noise.
I've written a code for face and eye detection that worked fine previously but now due to unknwon reasons, the program is having problems and a message is displayed that Your Project has stopped working... Please have a look at the following code and the commented line number has the problem and the program stops there
#include <opencv2/core/core.hpp>
#include "opencv2/objdetect/objdetect.hpp"
#include <opencv2/highgui/highgui.hpp>
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;
int main()
{
/*Mat image=imread("im.jpg");
namedWindow( "Display window", WINDOW_AUTOSIZE );// Create a window for display.
imshow( "Display window", image ); // Show our image inside it.
//imwrite("im2.jpg",image);// write the image stored in object image as im2.jpg
waitKey(0); // Wait for a keystroke in the window
return 0;*/
/*VideoCapture capture;
Mat frame;
capture.open(0);
if(capture.isOpened())
{
cout<<"success"<<endl;
while(1)
{
bool flag=capture.read(frame);
namedWindow( "Display window", WINDOW_AUTOSIZE );
if(flag)
imshow( "Display window", frame );
else
cout<<"failed";
waitKey(300);
}
}*/
//face detection
cout<<"i'm here";
CascadeClassifier face_cascade("C:\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt.xml");
CascadeClassifier eye_cascade("C:\\opencv\\sources\\data\\haarcascades\\haarcascade_eye.xml");
Mat image=imread("subject3.jpg");
cout<<"i'm here";
Mat res;
resize(image, res, Size(800, 600), 0, 0, INTER_LINEAR);
Mat gray;
cvtColor(res,gray,COLOR_BGR2GRAY);
equalizeHist(gray, gray);
std::vector<Rect> faces;
std::vector<Rect> eyes;
face_cascade.detectMultiScale(gray,faces, 1.1, 2,0 | CASCADE_SCALE_IMAGE, Size(30, 30));//problem
Rect roi;
cout<<faces.size();
Mat crop;
Mat grayEye;
for(int i=0;i<faces.size();i++)
{
cout<<"flag2";
roi.x=faces[i].x;
roi.y=faces[i].y;
roi.width=faces[i].width;
roi.height=faces[i].height;
Point pt1(faces[i].x, faces[i].y);
Point pt2((faces[i].x + faces[i].height), (faces[i].y + faces[i].width));
crop=res(roi);
resize(crop, crop, Size(300, 300), 0, 0, INTER_LINEAR);
cvtColor(crop, grayEye, CV_BGR2GRAY);
equalizeHist(grayEye, grayEye);
eye_cascade.detectMultiScale(grayEye,eyes, 1.1, 2,0 | CASCADE_SCALE_IMAGE, Size(30, 30));
cout<<endl<<eyes.size();
for(int j=0;j<eyes.size();j++)
{
Point pnt1(eyes[j].x, eyes[j].y);
Point pnt2((eyes[j].x + eyes[j].height), (eyes[j].y + eyes[j].width));
rectangle(crop, pnt1, pnt2, Scalar(0, 255, 0), 2);
}
rectangle(res, pt1, pt2, Scalar(0, 255, 0), 2);
}
namedWindow( "detected", WINDOW_AUTOSIZE );
imshow("detected",res);
waitKey(300);
imshow("detected",crop);
waitKey(0);
}
The following modifications made the program to work correctly (strange)
Previous Code :
CascadeClassifier face_cascade("C:\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt.xml");
Replaced with :
CascadeClassifier face_cascade;
face_cascade.load("C:\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt.xml");
I was loading the xml file in constructor previously (still don't know why it happened) but it is working now.