//---------------------------------------------------------------------------- int BspTree2::CoPointLocation (const BspPolygon2& polygon, const Vector2d& vertex) const { // For numerical round-off error handling. const double epsilon = 0.00001; const int numEdges = (int)mCoincident.size(); for (int i = 0; i < numEdges; ++i) { Vector2d end0 = polygon.mVArray[mCoincident[i].I0]; Vector2d end1 = polygon.mVArray[mCoincident[i].I1]; Vector2d dir = end1 - end0; Vector2d diff = vertex - end0; double tmax = dir.Dot(dir); double t = dir.Dot(diff); if (-epsilon <= t && t <= tmax + epsilon) { return 0; } } // Does not matter which subtree you use. if (mPosChild) { return mPosChild->PointLocation(polygon, vertex); } if (mNegChild) { return mNegChild->PointLocation(polygon, vertex); } return 0; }
IShape* CreateLine(Vector2d p1, Vector2d p2, int r, int g, int b, int size) { sf::RectangleShape* rect = new sf::RectangleShape(sf::Vector2f(p1.x, p1.y)); rect->setPosition(sf::Vector2f(p1.x, p1.y)); float len = (p1-p2).Len(); rect->setSize(sf::Vector2f(len, size)); Vector2d target = p2-p1; Vector2d orig = p1; orig.x = int(len); orig.y = 0; orig = orig.GetNormalized(); target = target.GetNormalized(); float dot = target.Dot(orig); //float angle = atan2f(target.y-orig.y, target.x-orig.x) * 57.2957795; float angle = acos(dot) * 57.2957795; if(p1.y > p2.y) angle = -angle; rect->rotate(angle); SFMLShape * shape = new SFMLShape(rect); rect->setFillColor(sf::Color(r,g,b)); return shape; }
//---------------------------------------------------------------------------- int BspTree2::Classify (const Vector2d& end0, const Vector2d& end1, const Vector2d& vertex) const { // For numerical round-off error handling. const double epsilon = 0.00001; Vector2d dir = end1 - end0; Vector2d nor = dir.Perp(); Vector2d diff = vertex - end0; double c = nor.Dot(diff); if (c > epsilon) { return ALL_POSITIVE; } if (c < -epsilon) { return ALL_NEGATIVE; } return COINCIDENT; }
//---------------------------------------------------------------------------- void BspTree2::GetCoPartition (const BspPolygon2& polygon, const Vector2d& v0, const Vector2d& v1, BspPolygon2& pos, BspPolygon2& neg, BspPolygon2& coSame, BspPolygon2& coDiff) const { const double epsilon = 0.00001; // Segment the line containing V0 and V1 by the coincident intervals that // intersect <V0,V1>. Vector2d dir = v1 - v0; double tmax = dir.Dot(dir); Vector2d end0, end1; double t0, t1; bool sameDir; std::list<Interval> intervalList; std::list<Interval>::iterator iter; const int numEdges = (int)mCoincident.size(); for (int i = 0; i < numEdges; ++i) { end0 = polygon.mVArray[mCoincident[i].I0]; end1 = polygon.mVArray[mCoincident[i].I1]; t0 = dir.Dot(end0 - v0); if (Mathd::FAbs(t0) <= epsilon) { t0 = 0.0; } else if (Mathd::FAbs(t0 - tmax) <= epsilon) { t0 = tmax; } t1 = dir.Dot(end1 - v0); if (Mathd::FAbs(t1) <= epsilon) { t1 = 0.0; } else if (Mathd::FAbs(t1 - tmax) <= epsilon) { t1 = tmax; } sameDir = (t1 > t0); if (!sameDir) { double save = t0; t0 = t1; t1 = save; } if (t1 > 0.0 && t0 < tmax) { if (intervalList.empty()) { intervalList.push_front(Interval(t0, t1, sameDir, true)); } else { iter = intervalList.begin(); for (/**/; iter != intervalList.end(); ++iter) { if (Mathd::FAbs(t1 - iter->T0) <= epsilon) { t1 = iter->T0; } if (t1 <= iter->T0) { // [t0,t1] is on the left of [I.t0,I.t1] intervalList.insert(iter, Interval(t0, t1, sameDir, true)); break; } // Theoretically, the intervals are disjoint or intersect // only at an end point. The assert makes sure that // [t0,t1] is to the right of [I.t0,I.t1]. if (Mathd::FAbs(t0 - iter->T1) <= epsilon) { t0 = iter->T1; } assertion(t0 >= iter->T1, "Invalid ordering.\n"); std::list<Interval>::iterator last = intervalList.end(); --last; if (iter == last) { intervalList.push_back(Interval(t0, t1, sameDir, true)); break; } } } } } if (intervalList.empty()) { GetPosPartition(polygon, v0, v1, pos, neg, coSame, coDiff); GetNegPartition(polygon, v0, v1, pos, neg, coSame, coDiff); return; } // Insert outside intervals between the touching intervals. It is // possible that two touching intervals are adjacent, so this is not just // a simple alternation of touching and outside intervals. Interval& front = intervalList.front(); if (front.T0 > 0.0) { intervalList.push_front(Interval(0.0, front.T0, front.SameDir, false)); } else { front.T0 = 0.0; } Interval& back = intervalList.back(); if (back.T1 < tmax) { intervalList.push_back(Interval(back.T1, tmax, back.SameDir, false)); } else { back.T1 = tmax; } std::list<Interval>::iterator iter0 = intervalList.begin(); std::list<Interval>::iterator iter1 = intervalList.begin(); for (++iter1; iter1 != intervalList.end(); ++iter0, ++iter1) { t0 = iter0->T1; t1 = iter1->T0; if (t1 - t0 > epsilon) { iter0 = intervalList.insert(iter1, Interval(t0, t1, true, false)); } } // Process the segmentation. double invTMax = 1.0/tmax; t0 = intervalList.front().T0*invTMax; end1 = v0 + (intervalList.front().T0*invTMax)*dir; iter = intervalList.begin(); for (/**/; iter != intervalList.end(); ++iter) { end0 = end1; t1 = iter->T1*invTMax; end1 = v0 + (iter->T1*invTMax)*dir; if (iter->Touching) { Edge2 edge; if (iter->SameDir) { edge.I0 = coSame.InsertVertex(end0); edge.I1 = coSame.InsertVertex(end1); if (edge.I0 != edge.I1) { coSame.InsertEdge(edge); } } else { edge.I0 = coDiff.InsertVertex(end1); edge.I1 = coDiff.InsertVertex(end0); if (edge.I0 != edge.I1) { coDiff.InsertEdge(edge); } } } else { GetPosPartition(polygon, end0, end1, pos, neg, coSame, coDiff); GetNegPartition(polygon, end0, end1, pos, neg, coSame, coDiff); } } }
//---------------------------------------------------------------------------- int BspTree2::Classify (const Vector2d& end0, const Vector2d& end1, const Vector2d& v0, const Vector2d& v1, Vector2d& intr) const { // For numerical round-off error handling. const double epsilon0 = 0.00001; const double epsilon1 = 0.99999; Vector2d dir = end1 - end0; Vector2d nor = dir.Perp(); Vector2d diff0 = v0 - end0; Vector2d diff1 = v1 - end0; double d0 = nor.Dot(diff0); double d1 = nor.Dot(diff1); if (d0*d1 < 0.0) { // Edge <V0,V1> transversely crosses line. Compute point of // intersection I = V0 + t*(V1 - V0). double t = d0/(d0 - d1); if (t > epsilon0) { if (t < epsilon1) { intr = v0 + t*(v1 - v0); if (d1 > 0.0) { return TRANSVERSE_POSITIVE; } else { return TRANSVERSE_NEGATIVE; } } else { // T is effectively 1 (numerical round-off issue), so // set d1 = 0 and go on to other cases. d1 = 0.0; } } else { // T is effectively 0 (numerical round-off issue), so // set d0 = 0 and go on to other cases. d0 = 0.0; } } if (d0 > 0.0 || d1 > 0.0) { // edge on positive side of line return ALL_POSITIVE; } if (d0 < 0.0 || d1 < 0.0) { // edge on negative side of line return ALL_NEGATIVE; } return COINCIDENT; }
//---------------------------------------------------------------------------- int ExtractRidges::Main (int, char**) { std::string imageName = Environment::GetPathR("Head.im"); ImageDouble2D image(imageName.c_str()); // Normalize the image values to be in [0,1]. int quantity = image.GetQuantity(); double minValue = image[0], maxValue = minValue; int i; for (i = 1; i < quantity; ++i) { if (image[i] < minValue) { minValue = image[i]; } else if (image[i] > maxValue) { maxValue = image[i]; } } double invRange = 1.0/(maxValue - minValue); for (i = 0; i < quantity; ++i) { image[i] = (image[i] - minValue)*invRange; } // Use first-order centered finite differences to estimate the image // derivatives. The gradient is DF = (df/dx, df/dy) and the Hessian // is D^2F = {{d^2f/dx^2, d^2f/dxdy}, {d^2f/dydx, d^2f/dy^2}}. int xBound = image.GetBound(0); int yBound = image.GetBound(1); int xBoundM1 = xBound - 1; int yBoundM1 = yBound - 1; ImageDouble2D dx(xBound, yBound); ImageDouble2D dy(xBound, yBound); ImageDouble2D dxx(xBound, yBound); ImageDouble2D dxy(xBound, yBound); ImageDouble2D dyy(xBound, yBound); int x, y; for (y = 1; y < yBoundM1; ++y) { for (x = 1; x < xBoundM1; ++x) { dx(x, y) = 0.5*(image(x+1, y) - image(x-1, y)); dy(x, y) = 0.5*(image(x, y+1) - image(x, y-1)); dxx(x, y) = image(x+1, y) - 2.0*image(x, y) + image(x-1, y); dxy(x, y) = 0.25*(image(x+1, y+1) + image(x-1, y-1) - image(x+1, y-1) - image(x-1, y+1)); dyy(x, y) = image(x, y+1) - 2.0*image(x, y) + image(x, y+1); } } dx.Save("dx.im"); dy.Save("dy.im"); dxx.Save("dxx.im"); dxy.Save("dxy.im"); dyy.Save("dyy.im"); // The eigensolver produces eigenvalues a and b and corresponding // eigenvectors U and V: D^2F*U = a*U, D^2F*V = b*V. Define // P = Dot(U,DF) and Q = Dot(V,DF). The classification is as follows. // ridge: P = 0 with a < 0 // valley: Q = 0 with b > 0 ImageDouble2D aImage(xBound, yBound); ImageDouble2D bImage(xBound, yBound); ImageDouble2D pImage(xBound, yBound); ImageDouble2D qImage(xBound, yBound); for (y = 1; y < yBoundM1; ++y) { for (x = 1; x < xBoundM1; ++x) { Vector2d gradient(dx(x, y), dy(x, y)); Matrix2d hessian(dxx(x, y), dxy(x, y), dxy(x, y), dyy(x, y)); EigenDecompositiond decomposer(hessian); decomposer.Solve(true); aImage(x,y) = decomposer.GetEigenvalue(0); bImage(x,y) = decomposer.GetEigenvalue(1); Vector2d u = decomposer.GetEigenvector2(0); Vector2d v = decomposer.GetEigenvector2(1); pImage(x,y) = u.Dot(gradient); qImage(x,y) = v.Dot(gradient); } } aImage.Save("a.im"); bImage.Save("b.im"); pImage.Save("p.im"); qImage.Save("q.im"); // Use a cheap classification of the pixels by testing for sign changes // between neighboring pixels. ImageRGB82D result(xBound, yBound); for (y = 1; y < yBoundM1; ++y) { for (x = 1; x < xBoundM1; ++x) { unsigned char gray = (unsigned char)(255.0f*image(x, y)); double pValue = pImage(x, y); bool isRidge = false; if (pValue*pImage(x-1 ,y) < 0.0 || pValue*pImage(x+1, y) < 0.0 || pValue*pImage(x, y-1) < 0.0 || pValue*pImage(x, y+1) < 0.0) { if (aImage(x, y) < 0.0) { isRidge = true; } } double qValue = qImage(x,y); bool isValley = false; if (qValue*qImage(x-1, y) < 0.0 || qValue*qImage(x+1, y) < 0.0 || qValue*qImage(x, y-1) < 0.0 || qValue*qImage(x, y+1) < 0.0) { if (bImage(x,y) > 0.0) { isValley = true; } } if (isRidge) { if (isValley) { result(x, y) = GetColor24(gray, 0, gray); } else { result(x, y) = GetColor24(gray, 0, 0); } } else if (isValley) { result(x, y) = GetColor24(0, 0, gray); } else { result(x, y) = GetColor24(gray, gray, gray); } } } result.Save("result.im"); return 0; }