I'm trying to detect and extract playing cards from an image. The plan is to detect the contours of the cards and then extract them using the area of the contours. (Is there a more efficient way of doing it?)
The problem is that I was having trouble with non-closed contours:
With this contours I'm not able to calculate the area of the rectangles. Hence, I performed morphological transformations to close the contours, producing this:
And after edge extracting:
Leaving me with these "rectangles" with twisted corners in the edges. How can I approximate these pseudo-rectangles to perfect geometric rectangles?
Is there a more efficient way of doing this?
Here is my code so far:
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <stdlib.h>
#include <stdio.h>
using namespace cv;
using namespace std;
#define BKG_THRESH 60 // preProcessImg
Mat src;
void preProcessImg(Mat* _img){
Mat aux_gray;
cvtColor(*_img, aux_gray, CV_BGR2GRAY );
GaussianBlur(aux_gray, *_img, Size(5,5), 0);
}
int main( int argc, char** argv ){
vector<vector<Point>> contours;
/// Load an image
src = imread("img.jpg");
preProcessImg(&src);
Canny(src, src, 30, 200);
//Mostrar imagem
namedWindow( "canny_output", CV_WINDOW_NORMAL); // Create a window
imshow( "canny_output", src);
waitKey(0);
Mat structuringElement = getStructuringElement(MORPH_ELLIPSE, Size(7, 7));
morphologyEx(src, src, MORPH_CLOSE, structuringElement);
//Mostrar imagem
namedWindow( "morph_transf", CV_WINDOW_NORMAL); // Create a window
imshow( "morph_transf", src);
waitKey(0);
findContours(src, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
Mat drawing = Mat::zeros( src.size(), CV_8UC3 );
for( int i = 0; i< contours.size(); i++){
Scalar color( rand()&255, rand()&255, rand()&255 );
drawContours( drawing, contours, i, color );
}
//Mostrar imagem
namedWindow( "contours", CV_WINDOW_NORMAL); // Create a window
imshow( "contours", drawing);
waitKey(0);
return 0;
}
The more robust way is to find lines (Hough lines) afer Canny, intersect they and find rectangles. Contours are not robust for noise.
Related
I have a image
this image is output of threshold function.
I want to detect the specified object as above and measure their heights.
My idea is extracting contours and use convex hull but my result not correct.
Have anyone idea for this problem?
regards.
Sys : Win7(64bit),OpenCV 3.1,Visual Studio 2015
my output :
here is my code:
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace cv;
using namespace std;
Mat src; Mat src_gray;
int thresh = 100;
int max_thresh = 255;
RNG rng(12345);
/// Function header
void thresh_callback(int, void*);
/** #function main */
int main(int argc, char** argv)
{
/// Load source image and convert it to gray
src = imread("C:/Users/Amin/Desktop/binary.jpg", 1);
/// Convert image to gray and blur it
cvtColor(src, src_gray, CV_BGR2GRAY);
blur(src_gray, src_gray, Size(3, 3));
/// Create Window
char* source_window = "Source";
namedWindow(source_window, CV_WINDOW_AUTOSIZE);
imshow(source_window, src);
createTrackbar(" Threshold:", "Source", &thresh, max_thresh, thresh_callback);
thresh_callback(0, 0);
waitKey(0);
return(0);
}
/** #function thresh_callback */
void thresh_callback(int, void*)
{
Mat src_copy = src.clone();
Mat threshold_output;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
/// Detect edges using Threshold
threshold(src_gray, threshold_output, thresh, 255, THRESH_BINARY);
/// Find contours
findContours(threshold_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
/// Find the convex hull object for each contour
vector<vector<Point> >hull(contours.size());
for (int i = 0; i < contours.size(); i++)
{
convexHull(Mat(contours[i]), hull[i], false);
}
/// Draw contours + hull results
Mat drawing = Mat::zeros(threshold_output.size(), CV_8UC3);
for (int i = 0; i< contours.size(); i++)
{
Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
drawContours(drawing, contours, i, color, 1, 8, vector<Vec4i>(), 0, Point());
drawContours(drawing, hull, i, color, 1, 8, vector<Vec4i>(), 0, Point());
}
/// Show in a window
namedWindow("Hull demo", CV_WINDOW_AUTOSIZE);
imshow("Hull demo", drawing);
}
I achieved this result but don't know how to measure AB?
A is on the contour and B is known.
thanks
To measure heights (I think thats what you are asking?) there is little point in using Convex hull - considering this messy output. Instead, I would loop through each contour (1,2,3,4 and 5) and all their points, and detect the widths and heights separately by analysing the X,Y differences. so, while you loop through lets say contour 1, if Y is increasing but not X, you can assume it is the height .. so count each point. Then, when X starts to increase, assume the height has come to an end. You will want to set a tolerance as the lines are not perfectly straight. Hope this helps.
I'm just now starting to learn how to use the openCV libraries. I've downloaded and installed openCV 2.4.10 , and have run an example " in tutorial of Finding contours in your image " using visual studio 2010. The code compiles, but every time I run it, it crashes,and I get the showing error in this image link which is as the following message:
Windows has triggered a breakpoint in EdgeDetection.exe.
This may be due to a corruption of the heap, which indicates a bug in >EdgeDetection.exe or any of the DLLs it has loaded.
This may also be due to the user pressing F12 while EdgeDetection.exe has focus.
The output window may have more diagnostic information.
I don't know, what is the reason.Here's the offending code:
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace cv;
using namespace std;
Mat src; Mat src_gray;
int thresh = 100;
int max_thresh = 255;
RNG rng(12345);
/// Function header
void thresh_callback(int, void* );
/** #function main */
int main( int argc, char** argv )
{
/// Load source image and convert it to gray
// src = imread( argv[1], 1 );
src=cvLoadImage("fish.bmp");
/// Convert image to gray and blur it
cvtColor( src, src_gray, CV_BGR2GRAY );
blur( src_gray, src_gray, Size(3,3) );
/// Create Window
char* source_window = "Source";
namedWindow( source_window, CV_WINDOW_AUTOSIZE );
imshow( source_window, src );
createTrackbar( " Canny thresh:", "Source", &thresh, max_thresh, thresh_callback );
thresh_callback( 0, 0 );
waitKey(0);
return(0);
}
/** #function thresh_callback */
void thresh_callback(int, void* )
{
Mat canny_output;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
/// Detect edges using canny
Canny( src_gray, canny_output, thresh, thresh*2, 3 );
/// Find contours
findContours( canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
/// Draw contours
Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 );
for( int i = 0; i< contours.size(); i++ )
{
Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
drawContours( drawing, contours, i, color, 2, 8, hierarchy, 0, Point() );
}
/// Show in a window
namedWindow( "Contours", CV_WINDOW_AUTOSIZE );
imshow( "Contours", drawing );
}
the breaking appears at line :
findContours( canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
So,I would like you to help me.
I'm using OpenCV 2.4.9 on VisualStudio V10.0.30319.1 RTMRel trying to compile this sample code:
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace cv;
using namespace std;
Mat src; Mat src_gray;
int thresh = 100;
int max_thresh = 255;
RNG rng(12345);
/// Function header
void thresh_callback(int, void* );
/** #function main */
int main( int argc, char** argv )
{
/// Load source image and convert it to gray
VideoCapture capture;
capture.open(0);
capture.set(CV_CAP_PROP_FRAME_WIDTH,1280);
capture.set(CV_CAP_PROP_FRAME_HEIGHT,960);
char qq=0;
while(qq!=32)
{
qq = waitKey(30);
capture.read(src);
if(!src.empty())
imshow("Space",src);
}
/// Convert image to gray and blur it
cvtColor( src, src_gray, CV_BGR2GRAY );
blur( src_gray, src_gray, Size(3,3) );
/// Create Window
char* source_window = "Source";
namedWindow( source_window, CV_WINDOW_AUTOSIZE );
imshow( source_window, src );
createTrackbar( " Canny thresh:", "Source", &thresh, max_thresh, thresh_callback );
thresh_callback( 0, 0 );
waitKey(0);
return(0);
}
/** #function thresh_callback */
void thresh_callback(int, void* )
{
Mat canny_output;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
/// Detect edges using canny
Canny( src_gray, canny_output, thresh, thresh*2, 3 );
/// Find contours
findContours( canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
/// Draw contours
Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 );
for( int i = 0; i< contours.size(); i++ )
{
Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
drawContours( drawing, contours, i, color, 2, 8, hierarchy, 0, Point() );
}
/// Show in a window
namedWindow( "Contours", CV_WINDOW_AUTOSIZE );
imshow( "Contours", drawing );
}
It's a sample code and should work just find but when I try to run the code just after pressing Space to capture the image the program just crashes and says "Ashkan.exe has stopped working" without any error at all!
I know the problem is with the FindContours line because as i comment that line the program runs just fine.
In debug mode when passing findContours line it says: Unhandled exception at 0x76f2320e in Ashkan.exe: 0xC0000005: Access violation reading location 0xffffffffffffffff.
Does anyone know any possible cause for this problem?!
I am newbie in programming, so please help me. I want to retrieve only the outer contour of an object but the problem is I got another contour like a border. How can I get the only outer contour of object without any other contour?
An example image:
Here is the code I made:
// cvAutoHeight.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "opencv\cvaux.h"
#include "opencv\cxmisc.h"
#include "opencv\highgui.h"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdlib.h>
using namespace std;
using namespace cv;
int main(int, char**)
{
Mat threshold_output;
int thresh = 100;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
RNG rng(12345);
CvCapture* capture = cvCaptureFromCAM(0);
cv::Mat frame; cv::Mat src_gray;
while(1) {
frame = cvQueryFrame( capture );
cvtColor( frame,src_gray, CV_BGR2GRAY );
blur( src_gray, src_gray, Size(3,3) );
//Canny( src_gray, threshold_output, 128, 255, 3 );
threshold( src_gray, threshold_output, 100, 200, THRESH_BINARY );
findContours( threshold_output, contours, hierarchy,CV_RETR_TREE,
CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
/// Find the rotated rectangles and ellipses for each contour
vector<RotatedRect> minRect( contours.size() );
for( int i = 0; i < contours.size(); i++ )
{
minRect[i] = minAreaRect( Mat(contours[i]) );
}
/// Draw contours + rotated rects + ellipses
Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 );
for( int i = 0; i< contours.size(); i++ )
{
Scalar color = Scalar( rng.uniform(0,0), rng.uniform(0,0), rng.uniform(250,250) );
// contour
drawContours( drawing, contours, i, color, 1, 8, vector<Vec4i>(), 0,
Point() );
// rotated rectangle
Point2f rect_points[4]; minRect[i].points( rect_points );
for( int j = 0; j < 4; j++ )
line( frame, rect_points[j], rect_points[(j+1)%4], color, 1, 8 );
}
namedWindow( "Contours", CV_WINDOW_AUTOSIZE );
imshow( "Contours", frame );
cvWaitKey(33);
}
return 0;
}
`
by default, out of borders have 0 pixel value = black. after threshold, you get your black blob with white background. this why you have 2 contours. choose one of the solutions:
use binary threshold inverted.
apply canny after threshold.
I've been doing some skin detection but can't get a smooth one. The image below contains the input (left) and output (right) using the code also attached below. Now, the desired output should have been the bottom most image (the one that is smooth on the edges and doesn't have holes within). How do I achieve this output? A sample code on where to start would be of great help.
Input (left) and Incorrect output (right):
Desired output:
Code to generate the Incorect output:
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
int main(){
Mat src = imread("qq.jpg");
if (src.empty())
return -1;
blur( src, src, Size(3,3) );
Mat hsv;
cvtColor(src, hsv, CV_BGR2HSV);
Mat bw;
inRange(hsv, Scalar(0, 10, 60), Scalar(20, 150, 255), bw);
imshow("src", src);
imshow("dst", bw);
waitKey(0);
return 0;
}
Modified Code (after Astor's suggestion):
(the problem now is: how do you smoothen the output?)
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
int findBiggestContour(vector<vector<Point> >);
int main(){
Mat src = imread("qq.jpg");
if (src.empty())
return -1;
blur( src, src, Size(3,3) );
Mat hsv;
cvtColor(src, hsv, CV_BGR2HSV);
Mat bw;
inRange(hsv, Scalar(0, 10, 60), Scalar(20, 150, 255), bw);
imshow("src", src);
imshow("dst", bw);
Mat canny_output;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours( bw, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
int s = findBiggestContour(contours);
Mat drawing = Mat::zeros( src.size(), CV_8UC1 );
drawContours( drawing, contours, s, Scalar(255), -1, 8, hierarchy, 0, Point() );
imshow("drw", drawing);
waitKey(0);
return 0;
}
int findBiggestContour(vector<vector<Point> > contours){
int indexOfBiggestContour = -1;
int sizeOfBiggestContour = 0;
for (int i = 0; i < contours.size(); i++){
if(contours[i].size() > sizeOfBiggestContour){
sizeOfBiggestContour = contours[i].size();
indexOfBiggestContour = i;
}
}
return indexOfBiggestContour;
}
You should use findContours to detect the biggest contour and after this draw founded contour with fill parameter -1 using method drawContours. Here's useful link: http://docs.opencv.org/doc/tutorials/imgproc/shapedescriptors/find_contours/find_contours.html
To improve the smoothness of the output, or in other words to reduce the black holes in the detected area try performing morphological operations on the resulting image.
Following documentation explains the eroding and dilating functions in opencv.
http://docs.opencv.org/doc/tutorials/imgproc/erosion_dilatation/erosion_dilatation.html