61 |
61 |
|
62 |
62 |
#include "precomp.hpp"
|
63 |
63 |
#include <stdarg.h>
|
|
64 |
#include <limits.h>
|
64 |
65 |
|
65 |
66 |
//#define ENABLE_TRIM_COL_ROW
|
66 |
67 |
|
67 |
68 |
//#pragma comment(lib, "highgui200d.lib")
|
68 |
69 |
//#define DEBUG_CHESSBOARD
|
|
70 |
//#define DEBUG_CHESSBOARD_EVERY_CORNER
|
69 |
71 |
#ifdef DEBUG_CHESSBOARD
|
70 |
72 |
static int PRINTF( const char* fmt, ... )
|
71 |
73 |
{
|
... | ... | |
151 |
153 |
icvGenerateQuadsEx( CvCBQuad **out_quads, CvCBCorner **out_corners,
|
152 |
154 |
CvMemStorage *storage, CvMat *image, CvMat *thresh_img, int dilation, int flags );*/
|
153 |
155 |
|
154 |
|
static void icvFindQuadNeighbors( CvCBQuad *quads, int quad_count );
|
|
156 |
static void icvFindQuadNeighbors( CvCBQuad *quads, int quad_count, cv::Ptr<IplImage> );
|
155 |
157 |
|
156 |
158 |
static int icvFindConnectedQuads( CvCBQuad *quads, int quad_count,
|
157 |
159 |
CvCBQuad **quad_group, int group_idx,
|
... | ... | |
234 |
236 |
cv::Ptr<IplImage> dbg_img;
|
235 |
237 |
cv::Ptr<IplImage> dbg1_img;
|
236 |
238 |
cv::Ptr<IplImage> dbg2_img;
|
|
239 |
cv::Ptr<IplImage> dbg3_img;
|
237 |
240 |
#endif
|
238 |
241 |
cv::Ptr<CvMemStorage> storage;
|
239 |
242 |
|
240 |
243 |
CvMat stub, *img = (CvMat*)arr;
|
241 |
244 |
|
242 |
|
int expected_corners_num = (pattern_size.width/2+1)*(pattern_size.height/2+1);
|
|
245 |
int expected_quad_num = ((pattern_size.width+1)*(pattern_size.height+1)+1)/2;
|
243 |
246 |
|
244 |
247 |
int prev_sqr_size = 0;
|
245 |
248 |
|
... | ... | |
269 |
272 |
dbg_img = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 3 );
|
270 |
273 |
dbg1_img = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 3 );
|
271 |
274 |
dbg2_img = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 3 );
|
|
275 |
dbg3_img = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 3 );
|
272 |
276 |
#endif
|
273 |
277 |
|
274 |
278 |
if( CV_MAT_CN(img->type) != 1 || (flags & CV_CALIB_CB_NORMALIZE_IMAGE) )
|
... | ... | |
320 |
324 |
// Run multi-level quads extraction
|
321 |
325 |
// In case one-level binarization did not give enough number of quads
|
322 |
326 |
CV_CALL( quad_count = icvGenerateQuadsEx( &quads, &corners, storage, img, thresh_img, dilations, flags ));
|
323 |
|
PRINTF("EX quad count: %d/%d\n", quad_count, expected_corners_num);
|
|
327 |
PRINTF("EX quad count: %d/%d\n", quad_count, expected_quad_num);
|
324 |
328 |
}
|
325 |
329 |
else*/
|
326 |
330 |
{
|
... | ... | |
363 |
367 |
|
364 |
368 |
quad_count = icvGenerateQuads( &quads, &corners, storage, thresh_img, flags );
|
365 |
369 |
|
366 |
|
PRINTF("Quad count: %d/%d\n", quad_count, expected_corners_num);
|
|
370 |
PRINTF("Quad count: %d/%d\n", quad_count, expected_quad_num);
|
367 |
371 |
}
|
368 |
372 |
|
369 |
373 |
|
... | ... | |
396 |
400 |
continue;
|
397 |
401 |
|
398 |
402 |
// Find quad's neighbors
|
399 |
|
icvFindQuadNeighbors( quads, quad_count );
|
|
403 |
#ifdef DEBUG_CHESSBOARD
|
|
404 |
icvFindQuadNeighbors( quads, quad_count, dbg_img );
|
|
405 |
#else
|
|
406 |
icvFindQuadNeighbors( quads, quad_count, NULL );
|
|
407 |
#endif
|
|
408 |
|
|
409 |
#ifdef DEBUG_CHESSBOARD
|
|
410 |
cvCopy(dbg_img, dbg3_img);
|
|
411 |
cvNamedWindow("quads_neighbors", 1);
|
|
412 |
for (i = 0; i < quad_count; i++) {
|
|
413 |
for (int k=0; k<4; k++)
|
|
414 |
{
|
|
415 |
CvPoint2D32f pt1, pt2;
|
|
416 |
CvScalar color = CV_RGB(30,255,30);
|
|
417 |
pt1 = quads[i].corners[k]->pt;
|
|
418 |
pt2 = quads[i].corners[(k+1)%4]->pt;
|
|
419 |
if (k>0)
|
|
420 |
color = CV_RGB(200,200,0);
|
|
421 |
cvLine( dbg3_img, cvPointFrom32f(pt1), cvPointFrom32f(pt2), color, 2, 8);
|
|
422 |
if (quads[i].neighbors[k] != NULL) {
|
|
423 |
cvCircle(dbg3_img, cvPointFrom32f(pt1), 4, CV_RGB(255,0,0), 1, 8, 0);
|
|
424 |
}
|
|
425 |
}
|
|
426 |
}
|
|
427 |
cvShowImage("quads_neighbors", (IplImage*)dbg3_img);
|
|
428 |
cvWaitKey();
|
|
429 |
#endif
|
400 |
430 |
|
401 |
431 |
// allocate extra for adding in icvOrderFoundQuads
|
402 |
432 |
cvFree(&quad_group);
|
... | ... | |
1498 |
1542 |
|
1499 |
1543 |
//=====================================================================================
|
1500 |
1544 |
|
1501 |
|
static void icvFindQuadNeighbors( CvCBQuad *quads, int quad_count )
|
1502 |
|
{
|
1503 |
|
const float thresh_scale = 1.f;
|
1504 |
|
int idx, i, k, j;
|
1505 |
|
float dx, dy, dist;
|
1506 |
|
|
1507 |
|
// find quad neighbors
|
1508 |
|
for( idx = 0; idx < quad_count; idx++ )
|
1509 |
|
{
|
1510 |
|
CvCBQuad* cur_quad = &quads[idx];
|
1511 |
|
|
1512 |
|
// choose the points of the current quadrangle that are close to
|
1513 |
|
// some points of the other quadrangles
|
1514 |
|
// (it can happen for split corners (due to dilation) of the
|
1515 |
|
// checker board). Search only in other quadrangles!
|
1516 |
|
|
1517 |
|
// for each corner of this quadrangle
|
1518 |
|
for( i = 0; i < 4; i++ )
|
1519 |
|
{
|
1520 |
|
CvPoint2D32f pt;
|
1521 |
|
float min_dist = FLT_MAX;
|
1522 |
|
int closest_corner_idx = -1;
|
1523 |
|
CvCBQuad *closest_quad = 0;
|
1524 |
|
CvCBCorner *closest_corner = 0;
|
|
1545 |
typedef struct quadList {
|
|
1546 |
CvCBQuad *quad;
|
|
1547 |
struct quadList *next;
|
|
1548 |
int length;
|
|
1549 |
} quadList;
|
|
1550 |
|
|
1551 |
static quadList *newQuadList(CvCBQuad *quad) {
|
|
1552 |
quadList *list = (quadList *)cvAlloc(sizeof(quadList));
|
|
1553 |
list->quad = quad;
|
|
1554 |
list->next = NULL;
|
|
1555 |
list->length = 1;
|
|
1556 |
return list;
|
|
1557 |
}
|
1525 |
1558 |
|
1526 |
|
if( cur_quad->neighbors[i] )
|
1527 |
|
continue;
|
|
1559 |
static void deleteQuadList(quadList *list) {
|
|
1560 |
quadList *next;
|
|
1561 |
while (list != NULL) {
|
|
1562 |
next = list->next;
|
|
1563 |
cvFree(&list);
|
|
1564 |
list = next;
|
|
1565 |
}
|
|
1566 |
}
|
1528 |
1567 |
|
1529 |
|
pt = cur_quad->corners[i]->pt;
|
|
1568 |
static void addToQuadList(quadList **list, CvCBQuad *quad) {
|
|
1569 |
quadList *newList = newQuadList(quad);
|
|
1570 |
if (*list != NULL) {
|
|
1571 |
newList->next = *list;
|
|
1572 |
newList->length += (*list)->length;
|
|
1573 |
}
|
|
1574 |
*list = newList;
|
|
1575 |
}
|
1530 |
1576 |
|
1531 |
|
// find the closest corner in all other quadrangles
|
1532 |
|
for( k = 0; k < quad_count; k++ )
|
1533 |
|
{
|
1534 |
|
if( k == idx )
|
1535 |
|
continue;
|
|
1577 |
static bool inQuadList(quadList *list, CvCBQuad *quad) {
|
|
1578 |
while (list != NULL) {
|
|
1579 |
if (list->quad == quad) {
|
|
1580 |
return true;
|
|
1581 |
}
|
|
1582 |
list = list->next;
|
|
1583 |
}
|
|
1584 |
return false;
|
|
1585 |
}
|
1536 |
1586 |
|
1537 |
|
for( j = 0; j < 4; j++ )
|
1538 |
|
{
|
1539 |
|
if( quads[k].neighbors[j] )
|
1540 |
|
continue;
|
|
1587 |
static double itMean(double oldValue, double newValue, int it) {
|
|
1588 |
// it is zero-based
|
|
1589 |
if (it == 0) {
|
|
1590 |
return newValue;
|
|
1591 |
}
|
|
1592 |
else {
|
|
1593 |
return oldValue + (newValue - oldValue) / (it + 1);
|
|
1594 |
}
|
|
1595 |
}
|
1541 |
1596 |
|
1542 |
|
dx = pt.x - quads[k].corners[j]->pt.x;
|
1543 |
|
dy = pt.y - quads[k].corners[j]->pt.y;
|
1544 |
|
dist = dx * dx + dy * dy;
|
|
1597 |
static double edgeMeanRec(double mean, CvCBQuad *quad, quadList **list) {
|
|
1598 |
if (inQuadList(*list, quad)) {
|
|
1599 |
return mean;
|
|
1600 |
}
|
1545 |
1601 |
|
1546 |
|
if( dist < min_dist &&
|
1547 |
|
dist <= cur_quad->edge_len*thresh_scale &&
|
1548 |
|
dist <= quads[k].edge_len*thresh_scale )
|
1549 |
|
{
|
1550 |
|
// check edge lengths, make sure they're compatible
|
1551 |
|
// edges that are different by more than 1:4 are rejected
|
1552 |
|
float ediff = cur_quad->edge_len - quads[k].edge_len;
|
1553 |
|
if (ediff > 32*cur_quad->edge_len ||
|
1554 |
|
ediff > 32*quads[k].edge_len)
|
1555 |
|
{
|
1556 |
|
PRINTF("Incompatible edge lengths\n");
|
1557 |
|
continue;
|
1558 |
|
}
|
1559 |
|
closest_corner_idx = j;
|
1560 |
|
closest_quad = &quads[k];
|
1561 |
|
min_dist = dist;
|
1562 |
|
}
|
1563 |
|
}
|
1564 |
|
}
|
|
1602 |
int i;
|
|
1603 |
double dx, dy;
|
1565 |
1604 |
|
1566 |
|
// we found a matching corner point?
|
1567 |
|
if( closest_corner_idx >= 0 && min_dist < FLT_MAX )
|
1568 |
|
{
|
1569 |
|
// If another point from our current quad is closer to the found corner
|
1570 |
|
// than the current one, then we don't count this one after all.
|
1571 |
|
// This is necessary to support small squares where otherwise the wrong
|
1572 |
|
// corner will get matched to closest_quad;
|
1573 |
|
closest_corner = closest_quad->corners[closest_corner_idx];
|
|
1605 |
int length = *list == NULL ? 0 : (*list)->length;
|
|
1606 |
for (i = 0; i < 4; i++) {
|
|
1607 |
dx = quad->corners[i]->pt.x - quad->corners[(i+1)%4]->pt.x;
|
|
1608 |
dy = quad->corners[i]->pt.y - quad->corners[(i+1)%4]->pt.y;
|
|
1609 |
mean = itMean(mean, dx * dx + dy * dy, 4 * length + i);
|
|
1610 |
}
|
|
1611 |
addToQuadList(list, quad);
|
|
1612 |
|
|
1613 |
for (i = 0; i < 4; i++) {
|
|
1614 |
if (quad->neighbors[i] != NULL) {
|
|
1615 |
mean = edgeMeanRec(mean, quad->neighbors[i], list);
|
|
1616 |
}
|
|
1617 |
}
|
|
1618 |
|
|
1619 |
return mean;
|
|
1620 |
}
|
1574 |
1621 |
|
1575 |
|
for( j = 0; j < 4; j++ )
|
1576 |
|
{
|
1577 |
|
if( cur_quad->neighbors[j] == closest_quad )
|
1578 |
|
break;
|
|
1622 |
static double edgeMean(CvCBQuad *cur_quad, CvCBQuad *other_quad) {
|
|
1623 |
double mean = 0.0;
|
|
1624 |
quadList *list = NULL;
|
|
1625 |
mean = edgeMeanRec(mean, cur_quad, &list);
|
|
1626 |
mean = edgeMeanRec(mean, other_quad, &list);
|
|
1627 |
deleteQuadList(list);
|
|
1628 |
return mean;
|
|
1629 |
}
|
1579 |
1630 |
|
1580 |
|
dx = closest_corner->pt.x - cur_quad->corners[j]->pt.x;
|
1581 |
|
dy = closest_corner->pt.y - cur_quad->corners[j]->pt.y;
|
|
1631 |
static int minNumerOfEdgesBetweenCorners(CvCBQuad *cur_quad, int cur_corner, CvCBCorner *target_corner, int max_limit) {
|
|
1632 |
if (cur_quad->corners[cur_corner] == target_corner) {
|
|
1633 |
return 0;
|
|
1634 |
}
|
|
1635 |
|
|
1636 |
if (max_limit == 0) {
|
|
1637 |
return INT_MAX - 1; // Infinity, not reachable in zero edges, -1 to not overflow later on
|
|
1638 |
}
|
|
1639 |
|
|
1640 |
int cur_edges;
|
|
1641 |
int min_edges = max_limit;
|
|
1642 |
|
|
1643 |
cur_edges = minNumerOfEdgesBetweenCorners(cur_quad, (cur_corner+1)%4, target_corner, max_limit-1) + 1;
|
|
1644 |
if (cur_edges < min_edges)
|
|
1645 |
min_edges = cur_edges;
|
|
1646 |
|
|
1647 |
cur_edges = minNumerOfEdgesBetweenCorners(cur_quad, (cur_corner-1+4)%4, target_corner, max_limit-1) + 1;
|
|
1648 |
if (cur_edges < min_edges)
|
|
1649 |
min_edges = cur_edges;
|
|
1650 |
|
|
1651 |
CvCBQuad *neighbor_quad = cur_quad->neighbors[cur_corner];
|
|
1652 |
if (neighbor_quad != NULL) {
|
|
1653 |
int i;
|
|
1654 |
for (i = 0; i < 4; i++) {
|
|
1655 |
if (neighbor_quad->neighbors[i] == cur_quad)
|
|
1656 |
break;
|
|
1657 |
}
|
|
1658 |
CV_Assert( i < 4 );
|
|
1659 |
|
|
1660 |
cur_edges = minNumerOfEdgesBetweenCorners(neighbor_quad, (i+1)%4, target_corner, max_limit-1) + 1;
|
|
1661 |
if (cur_edges < min_edges)
|
|
1662 |
min_edges = cur_edges;
|
|
1663 |
|
|
1664 |
cur_edges = minNumerOfEdgesBetweenCorners(neighbor_quad, (i-1+4)%4, target_corner, max_limit-1) + 1;
|
|
1665 |
if (cur_edges < min_edges)
|
|
1666 |
min_edges = cur_edges;
|
|
1667 |
}
|
|
1668 |
|
|
1669 |
return min_edges;
|
|
1670 |
}
|
1582 |
1671 |
|
1583 |
|
if( dx * dx + dy * dy < min_dist )
|
1584 |
|
break;
|
1585 |
|
}
|
|
1672 |
static void icvFindQuadNeighbors( CvCBQuad *quads, int quad_count, cv::Ptr<IplImage> img )
|
|
1673 |
{
|
|
1674 |
const double max_thresh_scale = 2.0; // Ratio of max diagonal in a x 2a quad, squared (max for all quads is 4.0, 2.0^2)
|
|
1675 |
const double thresh_scale_step = 0.1;
|
|
1676 |
double thresh_scale;
|
|
1677 |
int idx, i, k, j;
|
|
1678 |
float dx, dy, dist;
|
|
1679 |
bool quad_added;
|
|
1680 |
int check_other_closest;
|
1586 |
1681 |
|
1587 |
|
if( j < 4 || cur_quad->count >= 4 || closest_quad->count >= 4 )
|
1588 |
|
continue;
|
|
1682 |
#ifdef DEBUG_CHESSBOARD
|
|
1683 |
cv::Ptr<IplImage> dbg_img = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 3 );
|
|
1684 |
#endif
|
1589 |
1685 |
|
1590 |
|
// Check that each corner is a neighbor of different quads
|
1591 |
|
for( j = 0; j < closest_quad->count; j++ )
|
|
1686 |
check_other_closest = 1;
|
|
1687 |
do {
|
|
1688 |
for (thresh_scale = thresh_scale_step; thresh_scale <= max_thresh_scale; thresh_scale += thresh_scale_step) {
|
|
1689 |
do {
|
|
1690 |
quad_added = false;
|
|
1691 |
|
|
1692 |
// find quad neighbors
|
|
1693 |
for( idx = 0; idx < quad_count; idx++ )
|
1592 |
1694 |
{
|
1593 |
|
if( closest_quad->neighbors[j] == cur_quad )
|
1594 |
|
break;
|
1595 |
|
}
|
1596 |
|
if( j < closest_quad->count )
|
1597 |
|
continue;
|
1598 |
|
|
1599 |
|
// check whether the closest corner to closest_corner
|
1600 |
|
// is different from cur_quad->corners[i]->pt
|
1601 |
|
for( k = 0; k < quad_count; k++ )
|
1602 |
|
{
|
1603 |
|
CvCBQuad* q = &quads[k];
|
1604 |
|
if( k == idx || q == closest_quad )
|
1605 |
|
continue;
|
1606 |
|
|
1607 |
|
for( j = 0; j < 4; j++ )
|
1608 |
|
if( !q->neighbors[j] )
|
|
1695 |
CvCBQuad* cur_quad = &quads[idx];
|
|
1696 |
|
|
1697 |
// choose the points of the current quadrangle that are close to
|
|
1698 |
// some points of the other quadrangles
|
|
1699 |
// (it can happen for split corners (due to dilation) of the
|
|
1700 |
// checker board). Search only in other quadrangles!
|
|
1701 |
|
|
1702 |
// for each corner of this quadrangle
|
|
1703 |
for( i = 0; i < 4; i++ )
|
|
1704 |
{
|
|
1705 |
CvPoint2D32f pt;
|
|
1706 |
float min_dist = FLT_MAX;
|
|
1707 |
int closest_corner_idx = -1;
|
|
1708 |
CvCBQuad *closest_quad = 0;
|
|
1709 |
CvCBCorner *closest_corner = 0;
|
|
1710 |
|
|
1711 |
if( cur_quad->neighbors[i] )
|
|
1712 |
continue;
|
|
1713 |
|
|
1714 |
pt = cur_quad->corners[i]->pt;
|
|
1715 |
|
|
1716 |
// find the closest corner in all other quadrangles
|
|
1717 |
for( k = 0; k < quad_count; k++ )
|
1609 |
1718 |
{
|
1610 |
|
dx = closest_corner->pt.x - q->corners[j]->pt.x;
|
1611 |
|
dy = closest_corner->pt.y - q->corners[j]->pt.y;
|
1612 |
|
dist = dx*dx + dy*dy;
|
1613 |
|
if( dist < min_dist )
|
1614 |
|
break;
|
|
1719 |
if( k == idx )
|
|
1720 |
continue;
|
|
1721 |
|
|
1722 |
for( j = 0; j < 4; j++ )
|
|
1723 |
{
|
|
1724 |
if( quads[k].neighbors[j] )
|
|
1725 |
continue;
|
|
1726 |
|
|
1727 |
dx = pt.x - quads[k].corners[j]->pt.x;
|
|
1728 |
dy = pt.y - quads[k].corners[j]->pt.y;
|
|
1729 |
dist = dx * dx + dy * dy;
|
|
1730 |
|
|
1731 |
if( dist < min_dist &&
|
|
1732 |
dist <= edgeMean(cur_quad, &(quads[k]))*thresh_scale )
|
|
1733 |
{
|
|
1734 |
// check edge lengths, make sure they're compatible
|
|
1735 |
// edges that are different by more than 1:4 are rejected
|
|
1736 |
float ediff = cur_quad->edge_len - quads[k].edge_len;
|
|
1737 |
if (ediff > 32*cur_quad->edge_len ||
|
|
1738 |
ediff > 32*quads[k].edge_len)
|
|
1739 |
{
|
|
1740 |
PRINTF("Incompatible edge lengths\n");
|
|
1741 |
continue;
|
|
1742 |
}
|
|
1743 |
closest_corner_idx = j;
|
|
1744 |
closest_quad = &quads[k];
|
|
1745 |
min_dist = dist;
|
|
1746 |
}
|
|
1747 |
}
|
1615 |
1748 |
}
|
1616 |
|
if( j < 4 )
|
1617 |
|
break;
|
|
1749 |
|
|
1750 |
// we found a matching corner point?
|
|
1751 |
if( closest_corner_idx >= 0 && min_dist < FLT_MAX )
|
|
1752 |
{
|
|
1753 |
// If another point from our current quad is closer to the found corner
|
|
1754 |
// than the current one, then we don't count this one after all.
|
|
1755 |
// This is necessary to support small squares where otherwise the wrong
|
|
1756 |
// corner will get matched to closest_quad;
|
|
1757 |
closest_corner = closest_quad->corners[closest_corner_idx];
|
|
1758 |
|
|
1759 |
#ifdef DEBUG_CHESSBOARD
|
|
1760 |
#ifdef DEBUG_CHESSBOARD_EVERY_CORNER
|
|
1761 |
cvCopy(img,dbg_img);
|
|
1762 |
cvNamedWindow("closest_corner", 1);
|
|
1763 |
cvCircle(dbg_img, cvPointFrom32f(cur_quad->corners[i]->pt), 4, CV_RGB(0,255,0), 1, 8, 0);
|
|
1764 |
cvCircle(dbg_img, cvPointFrom32f(closest_corner->pt), 4, CV_RGB(255,0,0), 1, 8, 0);
|
|
1765 |
cvShowImage("closest_corner", (IplImage*)dbg_img);
|
|
1766 |
cvWaitKey();
|
|
1767 |
#endif
|
|
1768 |
#endif
|
|
1769 |
|
|
1770 |
for( j = 0; j < 4; j++ )
|
|
1771 |
{
|
|
1772 |
if( cur_quad->neighbors[j] == closest_quad )
|
|
1773 |
break;
|
|
1774 |
|
|
1775 |
dx = closest_corner->pt.x - cur_quad->corners[j]->pt.x;
|
|
1776 |
dy = closest_corner->pt.y - cur_quad->corners[j]->pt.y;
|
|
1777 |
|
|
1778 |
if( dx * dx + dy * dy < min_dist )
|
|
1779 |
break;
|
|
1780 |
}
|
|
1781 |
|
|
1782 |
if( j < 4 || cur_quad->count >= 4 || closest_quad->count >= 4 ) {
|
|
1783 |
PRINTF("Another corner of the current quad is closer.\n");
|
|
1784 |
continue;
|
|
1785 |
}
|
|
1786 |
|
|
1787 |
// Check that each corner is a neighbor of different quads
|
|
1788 |
for( j = 0; j < closest_quad->count; j++ )
|
|
1789 |
{
|
|
1790 |
if( closest_quad->neighbors[j] == cur_quad )
|
|
1791 |
break;
|
|
1792 |
}
|
|
1793 |
if( j < closest_quad->count ) {
|
|
1794 |
PRINTF("Closest quad has already for neighbor current quad.\n");
|
|
1795 |
continue;
|
|
1796 |
}
|
|
1797 |
|
|
1798 |
// Check if merging corners will make a triangle
|
|
1799 |
// This happens if two edges from opposite quads are merged together, then space (white quad) between
|
|
1800 |
// them becomes a triangle
|
|
1801 |
// As we increase thresh_scale incrementally we can be sure that better (closer) corners were already
|
|
1802 |
// merged if this was possible, so this one is probably not the right one to merge
|
|
1803 |
if (minNumerOfEdgesBetweenCorners(cur_quad, i, closest_corner, 4) < 4) {
|
|
1804 |
PRINTF("Merging corners would make a triangle.\n");
|
|
1805 |
continue;
|
|
1806 |
}
|
|
1807 |
|
|
1808 |
// First time we check if there is some other quad which is closer to selected closest corner
|
|
1809 |
// Second time all useful corners in other quads are already used so we can use selected closest corner
|
|
1810 |
// even if there is some possible (but obviously not really useful) other quad closer
|
|
1811 |
if (check_other_closest > 0) {
|
|
1812 |
// check whether the closest corner to closest_corner
|
|
1813 |
// is different from cur_quad->corners[i]->pt
|
|
1814 |
for( k = 0; k < quad_count; k++ )
|
|
1815 |
{
|
|
1816 |
CvCBQuad* q = &quads[k];
|
|
1817 |
if( k == idx || q == closest_quad )
|
|
1818 |
continue;
|
|
1819 |
|
|
1820 |
for( j = 0; j < 4; j++ )
|
|
1821 |
if( !q->neighbors[j] )
|
|
1822 |
{
|
|
1823 |
dx = closest_corner->pt.x - q->corners[j]->pt.x;
|
|
1824 |
dy = closest_corner->pt.y - q->corners[j]->pt.y;
|
|
1825 |
dist = dx*dx + dy*dy;
|
|
1826 |
if( dist < min_dist )
|
|
1827 |
break;
|
|
1828 |
}
|
|
1829 |
if( j < 4 )
|
|
1830 |
break;
|
|
1831 |
}
|
|
1832 |
|
|
1833 |
if( k < quad_count ) {
|
|
1834 |
PRINTF("Another corner is closer than our closest one.\n");
|
|
1835 |
continue;
|
|
1836 |
}
|
|
1837 |
}
|
|
1838 |
|
|
1839 |
PRINTF("Found closest corner.\n");
|
|
1840 |
|
|
1841 |
closest_corner->pt.x = (pt.x + closest_corner->pt.x) * 0.5f;
|
|
1842 |
closest_corner->pt.y = (pt.y + closest_corner->pt.y) * 0.5f;
|
|
1843 |
|
|
1844 |
// We've found one more corner - remember it
|
|
1845 |
cur_quad->count++;
|
|
1846 |
cur_quad->neighbors[i] = closest_quad;
|
|
1847 |
cur_quad->corners[i] = closest_corner;
|
|
1848 |
|
|
1849 |
closest_quad->count++;
|
|
1850 |
closest_quad->neighbors[closest_corner_idx] = cur_quad;
|
|
1851 |
|
|
1852 |
quad_added = true;
|
|
1853 |
}
|
|
1854 |
}
|
1618 |
1855 |
}
|
1619 |
|
|
1620 |
|
if( k < quad_count )
|
1621 |
|
continue;
|
1622 |
|
|
1623 |
|
closest_corner->pt.x = (pt.x + closest_corner->pt.x) * 0.5f;
|
1624 |
|
closest_corner->pt.y = (pt.y + closest_corner->pt.y) * 0.5f;
|
1625 |
|
|
1626 |
|
// We've found one more corner - remember it
|
1627 |
|
cur_quad->count++;
|
1628 |
|
cur_quad->neighbors[i] = closest_quad;
|
1629 |
|
cur_quad->corners[i] = closest_corner;
|
1630 |
|
|
1631 |
|
closest_quad->count++;
|
1632 |
|
closest_quad->neighbors[closest_corner_idx] = cur_quad;
|
1633 |
|
}
|
|
1856 |
} while (quad_added);
|
1634 |
1857 |
}
|
1635 |
|
}
|
|
1858 |
check_other_closest--;
|
|
1859 |
} while (check_other_closest >= 0);
|
1636 |
1860 |
}
|
1637 |
1861 |
|
1638 |
1862 |
//=====================================================================================
|