Does anyone know how to use the cvFindDominantPoints API of openCV? I basically have a 1 channel, binary image from which I get a set of contours. Judging from the image, I seem to be getting the correct contours. Now, I am selecting one of these contours to get dominant points of. This contour has about 60 vertices. However, the API call to cvFindDominantPoints is giving me a sequence of points (about 15) that does not even lie on the contour. It is quite far from it. Any insight?
my usage:
CvSeq *dominantpoints = cvFindDominantPoints(targetSeq, tristorage, CV_DOMINANT_IPAN, 7, 9, 9, 150);
#include "cv.h"
#include "highgui.h"
CvSeq* contours = 0;
CvSeq* dps = 0;
int main( int argc, char** argv )
{
int i, idx;
CvPoint p;
CvMemStorage* storage_ct = cvCreateMemStorage(0);
CvMemStorage* storage_dp = cvCreateMemStorage(0);
IplImage* img = cvLoadImage("contour.bmp", CV_LOAD_IMAGE_GRAYSCALE);
cvNamedWindow( "image" );
cvShowImage( "image", img );
cvFindContours( img, storage_ct, &contours, sizeof(CvContour),
CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE );
dps = cvFindDominantPoints( contours, storage_dp, CV_DOMINANT_IPAN, 7, 20, 9, 150 );
contours = cvApproxPoly( contours, sizeof(CvContour), storage_ct, CV_POLY_APPROX_DP, 3, 1 );
printf("found %d DPs and %d Contours \n", dps->total, contours->total );
for ( i = 0; i < dps->total; i++)
{
idx = *(int *) cvGetSeqElem(dps, i);
p = *(CvPoint *) cvGetSeqElem(contours, idx);
cvDrawCircle( img, p , 1, cvScalarAll(255) );
printf("%d %d %d\n", idx, p.x, p.y);
}
cvDrawContours(img, contours, cvScalarAll(100), cvScalarAll(200), 100 );
cvNamedWindow( "contours" );
cvShowImage( "contours", img );
cvWaitKey(0);
cvReleaseMemStorage( &storage_ct );
cvReleaseMemStorage( &storage_dp );
cvReleaseImage( &img );
return 0;
}
Related
[original image][1]
[1]: https://i.stack.imgur.com/j7brr.jpg
I am trying to detect the clusters of connected boundaries in this image. I need to find the length of these edges and also the radius of gyration of the individual clusters.
I am using opencv 2.4.13.
I used the following code to detect the mass clusters using contours.
#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 );
/// 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) );
/// Get the moments
vector<Moments> mu(contours.size() );
for( int i = 0; i < contours.size(); i++ )
{ mu[i] = moments( contours[i], false ); }
/// Get the mass centers:
vector<Point2f> mc( contours.size() );
for( int i = 0; i < contours.size(); i++ )
{ mc[i] = Point2f( mu[i].m10/mu[i].m00 , mu[i].m01/mu[i].m00 ); }
/// Draw contours
Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 );
Mat drawing2 = Mat::zeros( canny_output.size(), CV_8UC3 );
for( int i = 0; i< contours.size(); i++ )
{if(arcLength( contours[i], true )>900)
{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() );
circle( drawing, mc[i], 4, color, -1, 8, 0 );}
}
int length=0;
int j=0;
for( int i = 0; i< contours.size(); i++ )
{
if(arcLength( contours[i], true )>length)
{
length=arcLength( contours[i], true );
j=i;
}
}
Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
drawContours( drawing2, contours, j, color, 2, 8, hierarchy, 0, Point() );
circle( drawing2, mc[j], 4, color, -1, 8, 0 );
/// Show in a window
namedWindow( "Contours", CV_WINDOW_AUTOSIZE );
imshow( "Contours", drawing );
namedWindow( "Contours2", CV_WINDOW_AUTOSIZE );
imshow( "Contours_max", drawing2 );
/// Calculate the area with the moments 00 and compare with the result of the OpenCV function
printf("\t Info: Area and Contour Length \n");
for( int i = 0; i< contours.size(); i++ )
{
if(arcLength( contours[i], true )>900)
{printf(" * Contour[%d] - Area (M_00) = %.2f - Area OpenCV: %.2f - Length: %.2f \n", i, mu[i].m00, contourArea(contours[i]), arcLength( contours[i], true ) );
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() );
circle( drawing, mc[i], 4, color, -1, 8, 0 );}
}
}
The problem is the contours are getting different for common sharing edges and logically they should be of the same cluster. The following contour image I am giving.
We can see that many contours having same sharing edges are taken separately as different contours. I want them as a part of the same boundary clusters. Also suggest me how to detect the length of the boundaries and the radius of gyration.
Please help.
I am incredibly confused by your question (would ask for clarification in a comment, but I am too noob to comment)
My only advice based on what I see and understand is that you may not want to be using a canny filter. To be clear, your original image already has edges... running a canny filter on that gives you "double edges" which i do not think you want, but again, I am not even sure what you are trying to achieve.
I am currently working on extracting Contours path attributes from a particular image file. I am able to extract Contours using Open CV function findContours() the output look like this
[98, 81][97, 80][95, 80][94, 79][93, 79][92, 78][91, 78][88, 75][87, 75][85, 73][84, 73][83, 72][82, 72]
But my desired output is look like this
M 398.7,106.8 c -5.5,-2.7 -20.7,-4.7 -36.1,-4.6 -15.4,0.1
How can I get it
This is my code:
using namespace cv;
using namespace std;
Mat src_grays;
int threshs = 100;
int max_threshs = 255;
RNG rng(12345);
void thresh_callbacks(int, void* );
void main( )
{
Mat src = imread( "F:/academic/pro4/t/download.jpg" );
imshow("real Image", src);
Mat gray,edge,edges, draw,draws;
Mat samples(src.rows * src.cols, 3, CV_32F);
for( int y = 0; y < src.rows; y++ )
for( int x = 0; x < src.cols; x++ )
for( int z = 0; z < 3; z++)
samples.at<float>(y + x*src.rows, z) = src.at<Vec3b>(y,x)[z];
int clusterCount = 5;
Mat labels;
int attempts = 10;
Mat centers;
kmeans(samples, clusterCount, labels, TermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS, 10000, 0.0001), attempts, KMEANS_PP_CENTERS, centers );
Mat new_image( src.size(), src.type() );
for( int y = 0; y < src.rows; y++ )
for( int x = 0; x < src.cols; x++ )
{
int cluster_idx = labels.at<int>(y + x*src.rows,0);
new_image.at<Vec3b>(y,x)[0] = centers.at<float>(cluster_idx, 0);
new_image.at<Vec3b>(y,x)[1] = centers.at<float>(cluster_idx, 1);
new_image.at<Vec3b>(y,x)[2] = centers.at<float>(cluster_idx, 2);
}
imshow( "clustered image", new_image );
char filename[80];
sprintf(filename,"F:/academic/pro4/t/seg.png");
imwrite(filename, new_image);
cvtColor(src, gray, CV_BGR2GRAY);
Canny( new_image, edges, 50, 150, 3);
edges.convertTo(draws, CV_8U);
namedWindow("imageAfterSegmnetation", CV_WINDOW_AUTOSIZE);
imshow("imagesAfterCluster", draws);
cvtColor( new_image, src_grays, CV_BGR2GRAY );
blur( src_grays, src_grays, Size(3,3) );
char* source_window = "Source";
namedWindow( source_window, CV_WINDOW_AUTOSIZE );
imshow( source_window, src );
createTrackbar( " Canny thresh:", "Source", &threshs, max_threshs, thresh_callbacks );
thresh_callbacks( 0, 0 );
waitKey( 0 );
}
void thresh_callbacks(int, void* )
{
Mat canny_output;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
/// Detect edges using canny
Canny( src_grays, canny_output, threshs, threshs*2, 3 );
/// Find contours
findContours( canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
for(int i= 0; i < contours.size(); i++)
{
for(int j= 0; j < contours[i].size();j++) // run until j < contours[i].size();
{
int a= contours[i][j].x ;
int b =contours[i][j].y ;
// printf("Point(x,y)=" + a, b);
std::cout << contours[i][j] << std::endl;
}
printf ("%i", i + "\n");
}
/// Draw contours
int a=contours.size();
for( int i = 0; i<contours.size(); i++ )
{
Mat drawing_i = Mat::zeros( canny_output.size(), CV_8UC3 );
Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
drawContours( drawing_i, contours, i, color, 2, 8, hierarchy, 0, Point() );
namedWindow( "Contours_i", CV_WINDOW_AUTOSIZE );
imshow( "Contours_i", drawing_i );
}
}
Note:
I need Contours path, that mean how to contours connected for example it can be M = moveto L = lineto H = horizontal lineto V = vertical lineto C = curveto S = smooth curveto Q = quadratic Bézier curve T = smooth quadratic Bézier curveto A = elliptical Arc Z = closepath just like SVG path
I'm trying to find the contour area, but contour area only returns 0
whatever the contour is.
no error shows.
void CMFC_DEMODlg::OnBnClickedRun()
{
CString str;
IplImage* src1 = cvLoadImage("onlyone001.JPG",1);
IplImage* src2 = cvLoadImage("b004.JPG",1);
IplImage* grey = cvCreateImage( cvGetSize(src2), 8, 1 );
IplImage* dst = cvCreateImage( cvGetSize(src2), 8, 3 );
IplImage* F = cvCreateImage( cvGetSize(src2), 8, 1 );
IplImage* W = cvCreateImage( cvGetSize(src2), 8, 1 );
cvCvtColor( src2, grey, CV_BGR2GRAY);
cvThreshold( grey, W,200,255,CV_THRESH_BINARY);
CvSeq* c;
CvSeq* contour;
CvSeq* result;
CvMemStorage* storage = cvCreateMemStorage(0);
int Nc = cvFindContours(
W,
storage,
&contour,
sizeof(CvContour),
CV_RETR_LIST,
CV_CHAIN_APPROX_SIMPLE,
cvPoint(0,0));
double Area;
result = cvApproxPoly(contour, sizeof(CvContour), storage,
CV_POLY_APPROX_DP, cvContourPerimeter(contour)*0.02, 0);
Area = fabs(cvContourArea(result, CV_WHOLE_SEQ));
str.Format("Area: %d\n", Area);
GetDlgItem(IDC_STATIC02)->SetWindowText(str);
str.Format("Nc: %d\n", Nc);
GetDlgItem(IDC_STATIC01)->SetWindowText(str);
m_CvvImage.CopyOf(src2,1);
m_CvvImage.DrawToHDC(Disp_hDC1,Disp_Rect);
m_CvvImage.CopyOf(src1,1);
m_CvvImage.DrawToHDC(Disp_hDC2,Disp_Rect);
m_CvvImage.CopyOf(W,1);
m_CvvImage.DrawToHDC(Disp_hDC3,Disp_Rect);
}
I simply want to calculate the area of each contour in my image. What am I doing wrong?
The points should be placed in the vector in a clock-wise sequence.
Take a square for example:
corners2.push_back(Point(0,0));
corners2.push_back(Point(src.rows-1,0));
corners2.push_back(Point(src.rows-1,src.cols-1));
corners2.push_back(Point(1,src.cols-1));
I am using OpenCV 2.4.6 and Visual C++ 2010. I am trying to track RED color in the below code. I'm using cvInRangeS to get the RED object from the image and that image is a binary image. Then using cvFindContours(..) I want to find the contours of the object.But cvFindcontours(..) always returning 1. I am also using cvBoundingRect(..) to get the contour's position in the image. The rectangle position i am getting is always (1,1,638,478). Means the cvFindcontour(..) is taking whole image as a single contour. How can I get only the RED objects in contour?
int main()
{
IplImage* mCVImageColor = cvCreateImageHeader(cvSize(640,480), IPL_DEPTH_8U, 3);
IplImage* imgTracking;
CvCapture* capture = cvCaptureFromCAM( CV_CAP_ANY );
namedWindow( "Display image", CV_WINDOW_AUTOSIZE );
namedWindow( "Display window", CV_WINDOW_AUTOSIZE );
namedWindow( "Display tracking", CV_WINDOW_AUTOSIZE );
namedWindow( "Display thresh", CV_WINDOW_AUTOSIZE );
CvRect rect;
CvMemStorage *storage = cvCreateMemStorage(0);
CvSeq *contours=0;
while(1)
{
IplImage* mCVImageColor = cvQueryFrame( capture );
cvSmooth(mCVImageColor, mCVImageColor, CV_GAUSSIAN,3,3);
imgTracking=cvCreateImage(cvGetSize(mCVImageColor),IPL_DEPTH_8U, 1);
IplImage* imgHSV = cvCreateImage(cvGetSize(mCVImageColor), IPL_DEPTH_8U, 3);
IplImage* imgThresh=cvCreateImage(cvGetSize(mCVImageColor),8, 1);
cvCvtColor(mCVImageColor, imgHSV, CV_BGR2HSV);
cvInRangeS(imgHSV, cvScalar(170,160,60), cvScalar(180,255,256), imgThresh);
cvAdd(imgThresh, imgTracking, imgTracking);
cvConvertScale(imgTracking, imgTracking, 1.0, 0.0);
int x = cvFindContours(imgTracking,storage,&contours,sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(2, 2));
printf("%d\n",contours->total);
for (; contours != 0; contours = contours->h_next)
{
rect = cvBoundingRect(contours); //extract bounding box for current contour
//drawing rectangle
cvRectangle(mCVImageColor,cvPoint(rect.x, rect.y),cvPoint(rect.x+rect.width, rect.y+rect.height),cvScalar(0, 0, 255),2, 8, 0);
printf("%d %d %d %d\n",rect.x, rect.y,rect.width,rect.height);
if(rect.width*rect.height<1400)
{
CvPoint centroid[1];
centroid[0].x = cvRound((rect.x+rect.width)/2);
centroid[0].y = cvRound((rect.y+rect.height)/2);
cvCircle( mCVImageColor, centroid[0], 5, CV_RGB(255, 0, 0),10, -1);
}
}
cvShowImage("Display tracking",imgTracking);
cvShowImage("Display window",imgHSV);
cvShowImage("Display image",mCVImageColor);
cvShowImage("Display thresh",imgThresh);
cvClearMemStorage( storage );
contours = 0;
//cvReleaseImage(&imgHSV);
//cvReleaseImage(&imgThresh);
int c = waitKey(20);
if(c=='q')
break;
}
}
I have got this circle detection working but only detects 1 circle. How would I adjust code to detect multiple circles(max circles that will be detected is 22 as using it for snooker). I presume i would be editing the circle detectoin method but i am stuck:(
#include <stdio.h>
#include "cv.h"
#include "highgui.h"
#include <iostream>
#include <math.h>
#include <string.h>
#include <conio.h>
using namespace std;
IplImage* img = 0;
CvMemStorage * cstorage;
CvMemStorage * hstorage;
void detectCircle( IplImage *frame );
int main( int argc, char **argv )
{
CvCapture *capture = 0;
IplImage *frame = 0;
int key = 0;
hstorage = cvCreateMemStorage( 0 );
cstorage = cvCreateMemStorage( 0 );
//CvVideoWriter *writer = 0;
//int colour = 1;
//int fps = 25;
//int frameW = 640;
//int frameH = 480;
//writer = cvCreateVideoWriter("test.avi",CV_FOURCC('P', 'I', 'M', '1'),fps,cvSize(frameW,frameH),colour);
//initialise camera
capture = cvCaptureFromCAM( 0 );
//check if camera present
if ( !capture )
{
fprintf( stderr, "cannot open webcam\n");
return 1;
}
//create a window
cvNamedWindow( "Snooker", CV_WINDOW_AUTOSIZE );
while(key !='q')
{
//get frame
frame = cvQueryFrame(capture);
//int nFrames = 50;
//for (int i=0; i<nFrames;i++){
//cvGrabFrame(capture);
//frame = cvRetrieveFrame(capture);
//cvWriteFrame(writer, frame);
//}
//check for frame
if( !frame ) break;
detectCircle(frame);
//display current frame
//cvShowImage ("Snooker", frame );
//exit if Q pressed
key = cvWaitKey( 20 );
}
// free memory
cvDestroyWindow( "Snooker" );
cvReleaseCapture( &capture );
cvReleaseMemStorage( &cstorage);
cvReleaseMemStorage( &hstorage);
//cvReleaseVideoWriter(&writer);
return 0;
}
**void detectCircle( IplImage * img )
{
int px;
int py;
int edge_thresh = 1;
IplImage *gray = cvCreateImage( cvSize(img->width,img->height), 8, 1);
IplImage *edge = cvCreateImage( cvSize(img->width,img->height), 8, 1);
cvCvtColor(img, gray, CV_BGR2GRAY);
gray->origin = 1;
// color threshold
cvThreshold(gray,gray,100,255,CV_THRESH_BINARY);
// smooths out image
cvSmooth(gray, gray, CV_GAUSSIAN, 11, 11);
// get edges
cvCanny(gray, edge, (float)edge_thresh, (float)edge_thresh*3, 5);
// detects circle
CvSeq* circle = cvHoughCircles(gray, cstorage, CV_HOUGH_GRADIENT, 1, gray->height/50, 5, 35);
// draws circle and its centerpoint
float* p = (float*)cvGetSeqElem( circle, 0 );
if( p==null ){ return;}
cvCircle( img, cvPoint(cvRound(p[0]),cvRound(p[1])), 3, CV_RGB(255,0,0), -1, 8, 0 );
cvCircle( img, cvPoint(cvRound(p[0]),cvRound(p[1])), cvRound(p[2]), CV_RGB(200,0,0), 1, 8, 0 );
px=cvRound(p[0]);
py=cvRound(p[1]);**
cvShowImage ("Snooker", img );
}
Your code finds all circles - you just draw one:
// draws circle and its centerpoint
float* p = (float*)cvGetSeqElem( circle, 0 );
if( p==null ){ return;}
cvCircle( img, cvPoint(cvRound(p[0]),cvRound(p[1])), 3, CV_RGB(255,0,0), -1, 8, 0 );
cvCircle( img, cvPoint(cvRound(p[0]),cvRound(p[1])), cvRound(p[2]), CV_RGB(200,0,0), 1, 8, 0);
px=cvRound(p[0]);
py=cvRound(p[1]);
You should do it in cycle, something like:
for( int i=0; i < circles->total; i++ )
{
float* p = (float*) cvGetSeqElem( circles, i );
// ... d draw staff
}