CvSeq* findSquares4(IplImage *img, CvMemStorage* storage) { CvSeq* contours; int i, c, l, N = 11; int thresh = 50; CvSize sz = cvSize(img->width & -2, img->height & -2); IplImage* timg = cvCloneImage(img); IplImage* gray = cvCreateImage(sz, 8, 1); IplImage* pyr = cvCreateImage(cvSize(sz.width / 2, sz.height / 2), 8, 3); IplImage* tgray; CvSeq* result; // 创建一个空序列用处储存轮廓角点 CvSeq* squares = cvCreateSeq(0, sizeof(CvSeq), sizeof(CvPoint), storage); cvSetImageROI(timg, cvRect(0, 0, sz.width, sz.height)); // 过滤噪音 //cvPyrDown(timg, pyr, 7); tgray = cvCreateImage(sz, 8, 1); //cvPyrUp(pyr, timg, 7); // 红绿蓝3色分别提取 for (int c = 0; c < 3; c++) { cvSetImageCOI(timg, c + 1); cvCopy(timg, tgray, 0); // 尝试各种阈值提取 for (int l = 0; l < N; l++) { if (l == 0) { cvCanny(tgray, gray, 0, thresh, 5); cvDilate(gray, gray, 0, 1); } else { cvThreshold(tgray, gray, (l + 1) * 255 / N, 255, CV_THRESH_BINARY); } // 找到轮廓并存储在队列中 cvFindContours(gray, storage, &contours, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0, 0)); // 遍历每一个轮廓 while (contours) { // 使用指定的精度逼近多边形曲线 result = cvApproxPoly(contours, sizeof(CvContour), storage, CV_POLY_APPROX_DP, cvContourPerimeter(contours) * 0.02, 0); if (result->total == 4 && fabs( cvContourArea( result, CV_WHOLE_SEQ)) > 500 && fabs( cvContourArea( result, CV_WHOLE_SEQ)) < 100000 && cvCheckContourConvexity( result)) { double s = 0, t; for (int i = 0; i < 5; i++) { if (i >= 2) { t = fabs( angle( (CvPoint*) cvGetSeqElem( result, i), (CvPoint *) cvGetSeqElem( result, i - 2), (CvPoint *) cvGetSeqElem( result, i - 1))); s = s > t ? s : t; } } // 如果余弦值足够小, 可以认定角度为90度, 是直角 if (s < 0.08) { for (int i = 0; i < 4; i++) { cvSeqPush(squares, (CvPoint *) cvGetSeqElem( result, i)); } } } contours = contours->h_next; } } } cvReleaseImage(&gray); cvReleaseImage (&pyr); cvReleaseImage(&tgray); cvReleaseImage(&timg); return squares; }
// returns sequence of squares detected on the image. // the sequence is stored in the specified memory storage CvSeq* findSquares4( IplImage* img, CvMemStorage* storage ) { CvSeq* contours; int i, c, l, N = 11; CvSize sz = cvSize( img->width & -2, img->height & -2 ); IplImage* timg = cvCloneImage( img ); // make a copy of input image IplImage* gray = cvCreateImage( sz, 8, 1 ); IplImage* pyr = cvCreateImage( cvSize(sz.width/2, sz.height/2), 8, 3 ); IplImage* tgray; CvSeq* result; double s, t; // create empty sequence that will contain points - // 4 points per square (the square's vertices) CvSeq* squares = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvPoint), storage ); // select the maximum ROI in the image // with the width and height divisible by 2 cvSetImageROI( timg, cvRect( 0, 0, sz.width, sz.height )); // down-scale and upscale the image to filter out the noise cvPyrDown( timg, pyr, 7 ); cvPyrUp( pyr, timg, 7 ); tgray = cvCreateImage( sz, 8, 1 ); // find squares in every color plane of the image for( c = 0; c < 3; c++ ) { // extract the c-th color plane cvSetImageCOI( timg, c+1 ); cvCopy( timg, tgray, 0 ); // try several threshold levels for( l = 0; l < N; l++ ) { // hack: use Canny instead of zero threshold level. // Canny helps to catch squares with gradient shading if( l == 0 ) { // apply Canny. Take the upper threshold from slider // and set the lower to 0 (which forces edges merging) cvCanny( tgray, gray, 0, thresh, 5 ); // dilate canny output to remove potential // holes between edge segments cvDilate( gray, gray, 0, 1 ); } else { // apply threshold if l!=0: // tgray(x,y) = gray(x,y) < (l+1)*255/N ? 255 : 0 cvThreshold( tgray, gray, (l+1)*255/N, 255, CV_THRESH_BINARY ); } // find contours and store them all as a list cvFindContours( gray, storage, &contours, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0) ); // test each contour while( contours ) { // approximate contour with accuracy proportional // to the contour perimeter result = cvApproxPoly( contours, sizeof(CvContour), storage, CV_POLY_APPROX_DP, cvContourPerimeter(contours)*0.02, 0 ); // square contours should have 4 vertices after approximation // relatively large area (to filter out noisy contours) // and be convex. // Note: absolute value of an area is used because // area may be positive or negative - in accordance with the // contour orientation if( result->total == 4 && cvContourArea(result,CV_WHOLE_SEQ,0) > 500 && cvCheckContourConvexity(result) ) { s = 0; for( i = 0; i < 5; i++ ) { // find minimum angle between joint // edges (maximum of cosine) if( i >= 2 ) { t = fabs(angle( (CvPoint*)cvGetSeqElem( result, i ), (CvPoint*)cvGetSeqElem( result, i-2 ), (CvPoint*)cvGetSeqElem( result, i-1 ))); s = s > t ? s : t; } } // if cosines of all angles are small // (all angles are ~90 degree) then write quandrange // vertices to resultant sequence if( s < 0.3 ) for( i = 0; i < 4; i++ ) cvSeqPush( squares, (CvPoint*)cvGetSeqElem( result, i )); } // take the next contour contours = contours->h_next; } } } // release all the temporary images cvReleaseImage( &gray ); cvReleaseImage( &pyr ); cvReleaseImage( &tgray ); cvReleaseImage( &timg ); return squares; }
CvSeq* CSquareDetection::FindSquares( IplImage* tgray ) { CvSeq* contours; int i, l, N = 11; double imgArea = tgray->width*tgray->height; CvSize sz = cvSize( tgray->width & -2, tgray->height & -2 ); IplImage* gray = cvCreateImage( sz, 8, 1 ); IplImage* pyr = cvCreateImage( cvSize(sz.width/2, sz.height/2), 8, 1 ); CvSeq* result; // create empty sequence that will contain points - // 4 points per square (the square's vertices) CvSeq* squares = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvPoint), storage ); // select the maximum ROI in the image // with the width and height divisible by 2 cvSetImageROI( tgray, cvRect( 0, 0, sz.width, sz.height )); // down-scale and upscale the image to filter out the noise //cvPyrDown( tgray, pyr, 7 ); //cvPyrUp( pyr, tgray, 7 ); // try several threshold levels cvCanny( tgray, gray, 0, _CannyThresh, 5 ); cvDilate( gray, gray, 0, 1 ); for( l = 1; l < N-4; l++ ) { cvThreshold( tgray, gray, (l+1)*255/N, 255, CV_THRESH_BINARY ); // find contours and store them all as a list cvFindContours( gray, storage, &contours, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0) ); // test each contour while( contours ) { // approximate contour with accuracy proportional // to the contour perimeter result = cvApproxPoly( contours, sizeof(CvContour), storage, CV_POLY_APPROX_DP, cvContourPerimeter(contours)*0.02, 0 ); // square contours should have 4 vertices after approximation // relatively large area (to filter out noisy contours) // and be convex. // Note: absolute value of an area is used because // area may be positive or negative - in accordance with the // contour orientation double area = fabs(cvContourArea(result,CV_WHOLE_SEQ)); if( result->total == 4 && area < _maxPropotionArea*imgArea && area > _minPropotionArea*imgArea && cvCheckContourConvexity(result) ) { // Kiem tra va sap xep lai vi tri dinh if (Check4Vertexes(result, _CosineThresh, _EdgeThresh)) { // Dau vao mang ket qua for( i = 0; i < 4; i++ ) cvSeqPush( squares,(CvPoint*)cvGetSeqElem( result, i )); } } // take the next contour contours = contours->h_next; } } // Loc lai int delta_thres = 30; int* flags = new int[squares->total/4]; for (int i = 0; i < squares->total/4; i++) flags[i] = 0; CvSeq* sqrSeq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvPoint), storage ); CvPoint* V[4], *Vp[4]; for (int i = 0; i < squares->total; i+=4) { if (!flags[i/4]) { V[0] = (CvPoint*)cvGetSeqElem( squares, i ); V[1] = (CvPoint*)cvGetSeqElem( squares, i+1 ); V[2] = (CvPoint*)cvGetSeqElem( squares, i+2 ); V[3] = (CvPoint*)cvGetSeqElem( squares, i+3 ); for (int j = i+4; j < squares->total; j+= 4) { if (!flags[j/4]) { Vp[0] = (CvPoint*)cvGetSeqElem( squares, j ); Vp[1] = (CvPoint*)cvGetSeqElem( squares, j+1 ); Vp[2] = (CvPoint*)cvGetSeqElem( squares, j+2 ); Vp[3] = (CvPoint*)cvGetSeqElem( squares, j+3 ); // xac dinh trung diem CvPoint M; M.x = (Vp[0]->x+Vp[2]->x)/2; M.y = (Vp[0]->y+Vp[2]->y)/2; if (MathHelper.ktNamTrong(V, 4, &M)) { int d1 = max(MathHelper.sqrDistance(V[0], V[1]), MathHelper.sqrDistance(V[1], V[2])); int d2 = max(MathHelper.sqrDistance(Vp[0], Vp[1]), MathHelper.sqrDistance(Vp[1], Vp[2])); if ( d1 > d2) { V[0]->x = Vp[0]->x; V[0]->y = Vp[0]->y; V[1]->x = Vp[1]->x; V[1]->y = Vp[1]->y; V[2]->x = Vp[2]->x; V[2]->y = Vp[2]->y; V[3]->x = Vp[3]->x; V[3]->y = Vp[3]->y; } flags[j/4] = 1; } } } } } for (int i = 0; i < squares->total; i+=4) { if (!flags[i/4]) { V[0] = (CvPoint*)cvGetSeqElem( squares, i ); V[1] = (CvPoint*)cvGetSeqElem( squares, i+1 ); V[2] = (CvPoint*)cvGetSeqElem( squares, i+2 ); V[3] = (CvPoint*)cvGetSeqElem( squares, i+3 ); // Kiem tra co nguoc chieu kim dong ho ko // Neu khong nguoc chieu kim dong ho thi hoan doi // Chinh lai huong cua la bai Line* l = MathHelper.ptDuongThang(V[0], V[1]); if (MathHelper.thePointLenLine(l, V[3]) > 0) { int temp = V[1]->x; V[1]->x = V[3]->x; V[3]->x = temp; temp = V[1]->y; V[1]->y = V[3]->y; V[3]->y = temp; } //MathHelper.SapDongHo(V); cvSeqPush(sqrSeq, V[0]); cvSeqPush(sqrSeq, V[1]); cvSeqPush(sqrSeq, V[2]); cvSeqPush(sqrSeq, V[3]); } } //cvClearSeq(squares); // release all the temporary images cvReleaseImage( &gray ); cvReleaseImage( &pyr ); //cvReleaseImage( &tgray ); cvClearMemStorage(storage); return sqrSeq; }
CvSeq* EyeTracker::findSquares() { CvSeq* contours; int i, N = 5; CvSize sz = cvSize( sceneImagePts->width, sceneImagePts->height); IplImage* gray = cvCreateImage( sz, 8, 1 ); IplImage* tgray = cvCreateImage( sz, 8, 1 ); CvSeq* result; double s, t; CvSeq* squares = cvCreateSeq(0, sizeof(CvSeq), sizeof(CvPoint), squareStorage); cvCvtColor(sceneImagePts, tgray, CV_RGB2GRAY); // apply threshold if l!=0: // tgray(x,y) = gray(x,y) < (l+1)*255/N ? 255 : 0 cvThreshold(tgray, gray, squareThreshold, 255, CV_THRESH_BINARY ); // find contours and store them all as a list cvFindContours(gray, squareStorage, &contours, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0)); // test each contour while(contours) { // approximate contour with accuracy proportional // to the contour perimeter result = cvApproxPoly(contours, sizeof(CvContour), squareStorage, CV_POLY_APPROX_DP, cvContourPerimeter(contours) * 0.02, 0); // square contours should have 4 vertices after approximation // relatively large area (to filter out noisy contours) // and be convex. // Note: absolute value of an area is used because // area may be positive or negative - in accordance with the // contour orientation if(result->total == 4 && fabs(cvContourArea(result, CV_WHOLE_SEQ)) > 1000 && cvCheckContourConvexity(result)) { s = 0; for(i = 0; i < 5; ++i) { // find minimum angle between joint // edges (maximum of cosine) if(i >= 2) { t = fabs(angle((CvPoint*)cvGetSeqElem(result, i), (CvPoint*)cvGetSeqElem(result, i-2), (CvPoint*)cvGetSeqElem(result, i-1))); s = s > t ? s : t; } } // if cosines of all angles are small // (all angles are ~90 degree) then write quandrange // vertices to resultant sequence if(s < 0.2) { CvSeqReader reader; // initialize reader of the sequence cvStartReadSeq(result, &reader, 0); CvPoint pt[4]; CV_READ_SEQ_ELEM( pt[0], reader ); CV_READ_SEQ_ELEM( pt[1], reader ); CV_READ_SEQ_ELEM( pt[2], reader ); CV_READ_SEQ_ELEM( pt[3], reader ); for(int i = 1; i < 4; ++i) { for(int j = 0; j < 4 - i; ++j) { if(pt[j].x > pt[j+1].x) { CvPoint temp = pt[j+1]; pt[j+1] = pt[j]; pt[j] = temp; } } } if(pt[0].y > pt[1].y) { CvPoint temp = pt[1]; pt[1] = pt[0]; pt[0] = temp; } if(pt[2].y > pt[3].y) { CvPoint temp = pt[3]; pt[3] = pt[2]; pt[2] = temp; } if(abs(pt[0].y - pt[1].y) > 240) { sceneCorner[0] = pt[0]; sceneCorner[1] = pt[1]; sceneCorner[2] = pt[2]; sceneCorner[3] = pt[3]; for(int i = 0; i < 4; ++i) cvSeqPush(squares, (CvPoint*) cvGetSeqElem(result, i)); break; } } } // take the next contour contours = contours->h_next; } // release all the temporary images cvReleaseImage(&gray); cvReleaseImage(&tgray); return squares; }
CvSeq * find_quad( CvSeq * src_contour, CvMemStorage *storage, int min_size) { // stolen from icvGenerateQuads CvMemStorage * temp_storage = cvCreateChildMemStorage( storage ); int flags = CV_CALIB_CB_FILTER_QUADS; CvSeq *dst_contour = 0; const int min_approx_level = 2, max_approx_level = MAX_CONTOUR_APPROX; int approx_level; for( approx_level = min_approx_level; approx_level <= max_approx_level; approx_level++ ) { dst_contour = cvApproxPoly( src_contour, sizeof(CvContour), temp_storage, CV_POLY_APPROX_DP, (float)approx_level ); // we call this again on its own output, because sometimes // cvApproxPoly() does not simplify as much as it should. dst_contour = cvApproxPoly( dst_contour, sizeof(CvContour), temp_storage, CV_POLY_APPROX_DP, (float)approx_level ); if( dst_contour->total == 4 ) break; } // reject non-quadrangles if( dst_contour->total == 4 && cvCheckContourConvexity(dst_contour) ) { CvPoint pt[4]; double d1, d2, p = cvContourPerimeter(dst_contour); double area = fabs(cvContourArea(dst_contour, CV_WHOLE_SEQ)); double dx, dy; for( int i = 0; i < 4; i++ ) pt[i] = *(CvPoint*)cvGetSeqElem(dst_contour, i); dx = pt[0].x - pt[2].x; dy = pt[0].y - pt[2].y; d1 = sqrt(dx*dx + dy*dy); dx = pt[1].x - pt[3].x; dy = pt[1].y - pt[3].y; d2 = sqrt(dx*dx + dy*dy); // philipg. Only accept those quadrangles which are more square // than rectangular and which are big enough double d3, d4; dx = pt[0].x - pt[1].x; dy = pt[0].y - pt[1].y; d3 = sqrt(dx*dx + dy*dy); dx = pt[1].x - pt[2].x; dy = pt[1].y - pt[2].y; d4 = sqrt(dx*dx + dy*dy); if( !(flags & CV_CALIB_CB_FILTER_QUADS) || (d3*1.1 > d4 && d4*1.1 > d3 && d3*d4 < area*1.5 && area > min_size && d1 >= 0.15 * p && d2 >= 0.15 * p) ) { // CvContourEx* parent = (CvContourEx*)(src_contour->v_prev); // parent->counter++; // if( !board || board->counter < parent->counter ) // board = parent; // dst_contour->v_prev = (CvSeq*)parent; //for( i = 0; i < 4; i++ ) cvLine( debug_img, pt[i], pt[(i+1)&3], cvScalar(200,255,255), 1, CV_AA, 0 ); // cvSeqPush( root, &dst_contour ); return dst_contour; } } return NULL; }
int RectDetector::FindShape(const IplImage* img,std::vector<RectShape>& shapes) { if( !img ) { return -1; } int thresh = 50; CvMemStorage* storage = cvCreateMemStorage(0); CvSeq* contours; int i, c, l, N = 11; CvSize sz = cvSize( img->width & -2, img->height & -2 ); IplImage* timg = cvCloneImage( img ); IplImage* gray = cvCreateImage( sz, 8, 1 ); IplImage* pyr = cvCreateImage( cvSize(sz.width/2, sz.height/2), 8, 3 ); IplImage* tgray; CvSeq* result; double s, t; // 创建一个空序列用于存储轮廓角点 //CvSeq* squares = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvPoint), storage ); cvSetImageROI( timg, cvRect( 0, 0, sz.width, sz.height )); // 过滤噪音 //cvPyrDown( timg, pyr, 5 ); //cvPyrUp( pyr, timg, 5 ); tgray = cvCreateImage( sz, 8, 1 ); //cvShowImage("test",timg); // 提取 the c-th color plane cvSetImageCOI( timg, 0 ); cvCopy( timg, tgray, 0 ); // 尝试各种阈值提取得到的(N=11) for( l = 0; l < N; l++ ) { // apply Canny. Take the upper threshold from slider // Canny helps to catch squares with gradient shading if( l == 0 ) { cvCanny( tgray, gray, 0, thresh, 5 ); //使用任意结构元素膨胀图像 cvDilate( gray, gray, 0, 2 ); //cvShowImage("test",gray); } else { // apply threshold if l!=0: cvThreshold( tgray, gray, (l+1)*255/N, 255, CV_THRESH_BINARY ); } // 找到所有轮廓并且存储在序列中 cvFindContours( gray, storage, &contours, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0) ); // 遍历找到的每个轮廓contours while( contours ) { //用指定精度逼近多边形曲线 result = cvApproxPoly( contours, sizeof(CvContour), storage, CV_POLY_APPROX_DP, cvContourPerimeter(contours)*0.02, 0 ); if( result->total == 4 && fabs(cvContourArea(result,CV_WHOLE_SEQ)) > 500 && fabs(cvContourArea(result,CV_WHOLE_SEQ)) < 100000 && cvCheckContourConvexity(result) ) { s = 0; for( i = 0; i < 5; i++ ) { // find minimum angle between joint edges (maximum of cosine) if( i >= 2 ) { t = fabs(this->CalcAngle((CvPoint*)cvGetSeqElem( result, i ), (CvPoint*)cvGetSeqElem( result, i-2 ), (CvPoint*)cvGetSeqElem( result, i-1 ))); s = s > t ? s : t; } } // if 余弦值 足够小,可以认定角度为90度直角 //cos0.1=83度,能较好的趋近直角 if( s < 0.1 ) { RectShape RectShape(*(CvPoint*)cvGetSeqElem( result, 0 ),*(CvPoint*)cvGetSeqElem( result, 1 ),*(CvPoint*)cvGetSeqElem( result, 2 ),*(CvPoint*)cvGetSeqElem( result, 3 )); bool isExist = false; //去重 for(int j = 0 ; j < shapes.size(); ++j) { if(RectShape == shapes[j] ) { isExist = true; continue; } //remove the rectangle which contains others if(RectShape.isNear(shapes[j])) { if(RectShape.ctPoint.x > shapes[j].ctPoint.x || RectShape.ctPoint.y > shapes[j].ctPoint.y) { isExist = true; continue; } else { shapes[j] = RectShape; } } } if(!isExist) { shapes.push_back(RectShape); } } } // 继续查找下一个轮廓 contours = contours->h_next; } } cvReleaseImage( &gray ); cvReleaseImage( &pyr ); cvReleaseImage( &tgray ); cvReleaseImage( &timg ); cvClearMemStorage( storage ); return shapes.size(); }
int main(int argc, char* argv[]) { IplImage* img_8uc1 = NULL; #ifdef IMAGE if( argc != 2 || !(img_8uc1 = cvLoadImage( argv[1], CV_LOAD_IMAGE_GRAYSCALE )) ){ printf("%s image\n",argv[0]); return -1; } #else CvCapture* capture = cvCreateFileCapture( argv[1] ); IplImage* frame; if( argc != 2 || !(frame = cvQueryFrame( capture )) ){ printf("%s image\n",argv[0]); return -1; } #endif const char* name = "Edge Detection Window"; cvNamedWindow( name, 0 ); cvCreateTrackbar( "Contour perimeter", name, &high_switch_value, 100, switch_callback_h ); cvCreateTrackbar( "Min area", name, &minimum_area, 100000, NULL); cvCreateTrackbar( "Max area", name, &maximum_area, 100000, NULL); while(1) { #ifndef IMAGE frame = cvQueryFrame( capture ); img_8uc1=cvCreateImage( cvGetSize(frame), 8, 1 ); cvCvtColor(frame,img_8uc1,CV_BGR2GRAY); #endif IplImage* img_edge = cvCreateImage( cvGetSize(img_8uc1), 8, 1 ); IplImage* img_8uc3 = cvCreateImage( cvGetSize(img_8uc1), 8, 3 ); cvThreshold( img_8uc1, img_edge, 128, 255, CV_THRESH_BINARY ); CvMemStorage* storage = cvCreateMemStorage(); CvSeq* first_contour = NULL; cvFindContours( img_edge, storage, &first_contour, sizeof(CvContour), CV_RETR_CCOMP ); int n=0; cvCvtColor( img_8uc1, img_8uc3, CV_GRAY2BGR ); CvSeq* contours=first_contour; while (contours) { double area=fabs(cvContourArea(contours, CV_WHOLE_SEQ)); if(area < minimum_area || area > maximum_area) { contours = contours->h_next; continue; } CvSeq *result; double s,t; result = cvApproxPoly(contours, sizeof(CvContour), storage, CV_POLY_APPROX_DP, cvContourPerimeter(contours) * perimeter_constant, 0); if (result->total == 4 && cvCheckContourConvexity(result)) { s = 0; int i; for (i = 0; i < 5; i++) { // find minimum angle between joint // edges (maximum of cosine) if (i >= 2) { t = fabs(angle( (CvPoint *) cvGetSeqElem(result, i), (CvPoint *) cvGetSeqElem(result, i - 2), (CvPoint *) cvGetSeqElem(result, i - 1))); s = s > t ? s : t; } } cvDrawContours(img_8uc3, contours, RED, BLUE, 0, 2, 8); // if cosines of all angles are small // (all angles are ~90 degree) then write quandrange // vertices to resultant sequence // printf("s=%f\n",s); if (s > 0.3) { /*for (i = 0; i < 4; i++) { cvSeqPush(squares,(CvPoint *) cvGetSeqElem(result, i)); }*/ } } contours = contours->h_next; n++; } cvShowImage( name, img_8uc3 ); cvWaitKey(200); cvReleaseImage( &img_8uc3 ); cvReleaseImage( &img_edge ); #ifndef IMAGE cvReleaseImage( &img_8uc1 ); #endif } cvDestroyWindow( argv[0] ); return 0; }
void FrameProcessor::DetectAndDrawQuads(IplImage* img, vector <Square>& cubes, CvCapture* capture) { float angle = 0.0f; CvSeq* contours; CvSeq* result; CvMemStorage *storage = cvCreateMemStorage(0); //IplImage* ret = cvCreateImage(cvGetSize(img), 8, 3); IplImage* temp = cvCreateImage(cvGetSize(img), 8, 1); cvCvtColor(img, temp, CV_BGR2GRAY); IplImage* Img = cvCreateImage (cvGetSize (img), 8, 1); cvThreshold(temp, Img, 0, 255, CV_THRESH_BINARY_INV | CV_THRESH_OTSU); cvFindContours(Img, storage, &contours, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0)); CvSeq* contours1 = contours; while(contours) { result = cvApproxPoly (contours, sizeof (CvContour), storage, CV_POLY_APPROX_DP, cvContourPerimeter (contours) * 0.02, 0); if((result->total==4) && (fabs(cvContourArea(result, CV_WHOLE_SEQ)) > 30) && cvCheckContourConvexity (result)) { int countTriang = 0; CvSeq* contours2 = contours1; while(contours2){ CvSeq* result2 = cvApproxPoly(contours2, sizeof(CvContour), storage, CV_POLY_APPROX_DP, cvContourPerimeter(contours2)*0.02, 0); if((result2->total==3) && (fabs(cvContourArea(result2, CV_WHOLE_SEQ)) > 50) && cvCheckContourConvexity(result2)) { CvPoint *pt[3]; for(int i=0;i<3;i++) pt[i] = (CvPoint*)cvGetSeqElem(result2, i); CvPoint ptCent[1]; ptCent[0].x = (pt[0]->x + pt[1]->x + pt[2]->x)/3; ptCent[0].y = (pt[0]->y + pt[1]->y + pt[2]->y)/3; //printf("(%d, %d) (%d,%d) (%d,%d)\n", pt[0]->x, pt[0]->y, pt[1]->x, pt[1]->y, pt[2]->x, pt[2]->y); //cvCircle(ret, ptCent[0], 5, cvScalar(255)); CvPoint2D32f triang; triang.x = ptCent[0].x; triang.y = ptCent[0].y; if(cvPointPolygonTest(result, triang, 0) > 0){ countTriang++; //cvLine(ret, *pt[0], *pt[1], cvScalar(30, 50, 50)); //cvLine(ret, *pt[1], *pt[2], cvScalar(30, 50, 50)); //cvLine(ret, *pt[2], *pt[0], cvScalar(30, 50, 50)); angle = GetAngle(pt); } } contours2 = contours2->h_next; } if(countTriang == 1){ CvPoint *pt[4]; for(int i=0;i<4;i++) pt[i] = (CvPoint*)cvGetSeqElem(result, i); //cvLine(ret, *pt[0], *pt[1], cvScalar(255)); //cvLine(ret, *pt[1], *pt[2], cvScalar(255)); //cvLine(ret, *pt[2], *pt[3], cvScalar(255)); //cvLine(ret, *pt[3], *pt[0], cvScalar(255)); CvSeq* contours3 = contours1; int countSquare = 0; while(contours3){ CvSeq* result3 = cvApproxPoly(contours3, sizeof(CvContour), storage, CV_POLY_APPROX_DP, cvContourPerimeter(contours3)*0.02, 0); if((result3->total==4) && (fabs(cvContourArea(result3, CV_WHOLE_SEQ)) > 50) && cvCheckContourConvexity(result3)) { CvPoint *pt[4]; for(int i=0;i<4;i++) pt[i] = (CvPoint*)cvGetSeqElem(result3, i); CvPoint ptCent[1]; ptCent[0].x = (pt[0]->x + pt[1]->x + pt[2]->x + pt[3]->x)/4; ptCent[0].y = (pt[0]->y + pt[1]->y + pt[2]->y + pt[3]->y)/4; //cvCircle(ret, ptCent[0], 5, cvScalar(255)); CvPoint2D32f square; square.x = ptCent[0].x; square.y = ptCent[0].y; //cout << cvPointPolygonTest(result, triang, 0); if(cvPointPolygonTest(result, square, 0) > 0){ countSquare++; //cvLine(ret, *pt[0], *pt[1], cvScalar(90, 50, 50)); //cvLine(ret, *pt[1], *pt[2], cvScalar(90, 50, 50)); //cvLine(ret, *pt[2], *pt[3], cvScalar(90, 50, 50)); //cvLine(ret, *pt[3], *pt[0], cvScalar(90, 50, 50)); } } contours3 = contours3->h_next; } countSquare--; CvPoint *pt1[4]; for(int i=0;i<4;i++) pt1[i] = (CvPoint*)cvGetSeqElem(result, i); CvPoint ptCent[1]; ptCent[0].x = (pt1[0]->x + pt1[1]->x + pt1[2]->x + pt1[3]->x)/4; ptCent[0].y = (pt1[0]->y + pt1[1]->y + pt1[2]->y + pt1[3]->y)/4; //printf("%d %d\n", ptCent[0].x, ptCent[0].y); //cvCircle(ret, ptCent[0], 5, cvScalar(255)); CvPoint pC[1]; pC[0].x = ptCent[0].x; pC[0].y = ptCent[0].y; int width = (int) cvGetCaptureProperty (capture, CV_CAP_PROP_FRAME_WIDTH); int height = (int) cvGetCaptureProperty (capture, CV_CAP_PROP_FRAME_HEIGHT); pC[0].x = width - ptCent[0].x; pC[0].x = (pC[0].x * 100) / width; pC[0].y = (ptCent[0].y * 100) / height; Square test3 (countSquare, pC [0], abs(pt1[0]->x - pC[0].x) * 1.5, abs(pt1[0]->x - pC[0].x) * 1.5, angle); cubes.push_back(test3); } } contours = contours->h_next; } cvReleaseImage(&temp); //cvReleaseImage(&ret); cvReleaseImage(&Img); cvReleaseMemStorage(&storage); }