void PreviewColorPickerTool::CalcCorrection(hugin_utils::FDiff2D pos) { m_red=0; m_blue=0; m_count=0; HuginBase::Panorama* pano=helper->GetPanoramaPtr(); HuginBase::UIntSet activeImages=pano->getActiveImages(); if(activeImages.size()>0) { for(HuginBase::UIntSet::iterator it=activeImages.begin();it!=activeImages.end();++it) { //check if point is inside the image, check also all 4 corners of rectangle HuginBase::PTools::Transform trans; trans.createTransform(pano->getImage(*it),pano->getOptions()); double x; double y; if(trans.transformImgCoord(x,y,pos.x,pos.y)) { vigra::Point2D imagePos(x,y); if(pano->getImage(*it).isInside(imagePos) && pano->getImage(*it).isInside(imagePos + vigra::Point2D(-ColorPickerSize,-ColorPickerSize)) && pano->getImage(*it).isInside(imagePos + vigra::Point2D(-ColorPickerSize, ColorPickerSize)) && pano->getImage(*it).isInside(imagePos + vigra::Point2D( ColorPickerSize,-ColorPickerSize)) && pano->getImage(*it).isInside(imagePos + vigra::Point2D( ColorPickerSize, ColorPickerSize)) ) { CalcCorrectionForImage(*it,imagePos); }; }; }; }; if(m_count>0) { m_red=m_red/m_count; m_blue=m_blue/m_count; }; };
int main(int argc, char* argv[]) { // parse arguments const char* optstring = "hr"; int c; bool reverse = false; while ((c = getopt (argc, argv, optstring)) != -1) { switch (c) { case 'h': usage(hugin_utils::stripPath(argv[0]).c_str()); return 0; case 'r': reverse = true; break; case '?': break; default: abort (); } } if (argc - optind < 1 || argc - optind > 2) { usage(hugin_utils::stripPath(argv[0]).c_str()); return 1; } std::string input=argv[optind]; HuginBase::Panorama pano; std::ifstream prjfile(input.c_str()); if (!prjfile.good()) { std::cerr << "could not open script : " << input << std::endl; return 1; } pano.setFilePrefix(hugin_utils::getPathPrefix(input)); AppBase::DocumentData::ReadWriteError err = pano.readData(prjfile); if (err != AppBase::DocumentData::SUCCESSFUL) { std::cerr << "error while parsing panos tool script: " << input << std::endl; std::cerr << "AppBase::DocumentData::ReadWriteError code: " << err << std::endl; return 1; } // set up output format std::cout.setf ( std::ios::fixed ) ; std::cout.precision ( 6 ) ; // should be ample if ( argc - optind == 1 ) { // no image number was passed. This triggers the new // behaviour to accept triplets on cin work_on_triplets ( pano , reverse ) ; return 0; } // an image number was passed, so proceed // as in the original version int imageNumber = atoi(argv[optind+1]); if (imageNumber >= pano.getNrOfImages()) { std::cerr << "Not enough images in panorama" << std::endl; return 1; } // pano tools interface HuginBase::PTools::Transform trafo; if (reverse) { trafo.createTransform(pano.getSrcImage(imageNumber), pano.getOptions()); } else { trafo.createInvTransform(pano.getSrcImage(imageNumber), pano.getOptions()); } double xin , yin , xout , yout ; // here's where the old-style IO was, now it's all streams. // It's also format-free input, so newlines don't matter while ( std::cin >> xin >> yin ) { trafo.transformImgCoord(xout, yout, xin, yin); std::cout << xout << " " << yout << std::endl ; } }
void PreviewLayoutLinesTool::updateLineInformation() { m_lines.clear(); const HuginBase::Panorama & pano = *(helper->GetPanoramaPtr()); unsigned int numberOfImages = pano.getNrOfImages(); HuginBase::UIntSet active_images = pano.getActiveImages(); // make a line for every image pair, but set the unneeded ones as dud. // This is for constant look up times when we scan control points. m_lines.resize(numberOfImages * numberOfImages); unsigned int numberOfControlPoints = pano.getNrOfCtrlPoints(); // loop over all control points to count them and get error statistics. for (unsigned int cpi = 0 ; cpi < numberOfControlPoints ; cpi++) { const HuginBase::ControlPoint & cp = pano.getCtrlPoint(cpi); unsigned int low_index, high_index; if (cp.image1Nr < cp.image2Nr) { low_index = cp.image1Nr; high_index = cp.image2Nr; } else { low_index = cp.image2Nr; high_index = cp.image1Nr; } // find the line. // We use the formula in the line below to record image numbers to each // line later. LineDetails & line = m_lines[low_index * numberOfImages + high_index]; // update control point count. line.numberOfControlPoints++; // update error statistics line.totalError += cp.error; if (cp.error > line.worstError) { line.worstError = cp.error; } } /* Find some locations of the images. We will test if they overlap using * these locations. We don't need the last image as we can always take the * smallest numbered image as the source of points. */ /** @todo Check both ways around. * This only checks if points from the smallest numbered image are * within the largest numbered image. If the first image is huge compared to * the second, then it many points will miss and we might not reach the * target even if the second image is contained within the first. */ std::vector<PosMap> positions(pano.getNrOfImages() - 1); for (unsigned int i = 0; i < numberOfImages - 1; i++) { const HuginBase::SrcPanoImage & img = pano.getImage(i); for (unsigned int x = 0; x < SAMPLE_FREQUENCY; x++) { for (unsigned int y = 0; y < SAMPLE_FREQUENCY; y++) { // scale (x, y) so it is always within the cropped region of the // image. vigra::Rect2D c = img.getCropRect(); /** @todo Use only points inside the circle when circular crop * is used. */ double xc = double (x) / double (SAMPLE_FREQUENCY) * double(c.width()) + c.left(); double yc = double (y) / double (SAMPLE_FREQUENCY) * double(c.height()) + c.top(); // now look up (xc, yc) in the image, find where in the panorama // it ends up. m_transforms[i]->transformImgCoord ( positions[i][x][y].x, positions[i][x][y].y, xc, yc ); } } } // write other line data. for (unsigned int i = 0; i < numberOfImages; i++) { for (unsigned int j = 0; j < numberOfImages; j++) { LineDetails & line = m_lines[i * numberOfImages + j]; line.image1 = i; line.image2 = j; /// test if the line should be visible. if (!(set_contains(active_images, i) && set_contains(active_images, j))) { // At least one of the images is hidden, so don't show the line. line.dud = true; } else if (line.numberOfControlPoints > 0) { line.dud = false; } else if (i >= j) { // We only use lines where image1 is the lowest numbered image. // We don't bother with lines from one image to the same one. line.dud = true; } else { // test overlapping regions. HuginBase::PTools::Transform transform; ViewState & viewState = *helper->GetViewStatePtr(); HuginBase::SrcPanoImage & src = *viewState.GetSrcImage(j); transform.createTransform(src, *(viewState.GetOptions())); unsigned int overlapingSamples = 0; for (unsigned int x = 0; x < SAMPLE_FREQUENCY; x++) { for (unsigned int y = 0; y < SAMPLE_FREQUENCY; y++) { // check if mapping a point that was found earilier to // be inside an image in panorama space is inside the // other image when transformed from panorama to image. double dx, dy; transform.transformImgCoord ( dx, dy, positions[i][x][y].x, positions[i][x][y].y ); if (src.isInside(vigra::Point2D((int) dx, (int) dy))) { // they overlap overlapingSamples++; } } } // If the overlap isn't big enough, the line isn't used. line.dud = (overlapingSamples < MIN_SAMPLE_OVERLAPS); } if (!line.dud) { line.arc = GreatCircleArc(m_imageCentresSpherical[i].x, m_imageCentresSpherical[i].y, m_imageCentresSpherical[j].x, m_imageCentresSpherical[j].y, *(helper->GetVisualizationStatePtr())); } } } }
GreatCircleArc::GreatCircleArc(double startLat, double startLong, double endLat, double endLong, VisualizationState & visualizationState) { m_visualizationState = &visualizationState; // get the output projection const HuginBase::PanoramaOptions & options = *(visualizationState.GetOptions()); // make an image to transform spherical coordinates into the output projection HuginBase::SrcPanoImage equirectangularImage; equirectangularImage.setProjection(HuginBase::SrcPanoImage::EQUIRECTANGULAR); equirectangularImage.setHFOV(360.0); equirectangularImage.setSize(vigra::Size2D(360.0, 180.0)); // make a transformation from spherical coordinates to the output projection HuginBase::PTools::Transform transform; transform.createInvTransform(equirectangularImage, options); m_xscale = visualizationState.GetScale(); /**Handle case where the points are opposite sides of the sphere * (i.e. The angle startLat is -endLat and startLong is -endLong.) * There are infinetly many great circles in this case, we pick one going * through (180, 90), by splitting the problem in two. */ if (startLat == 360.0 - endLat && startLong == 180.0 - endLong) { // we should probably check to see if we already go through (180, 90). if (startLat == 180.0 && startLong == 90.0) { // foiled again: pick one going through (180, 0) instead. *this = GreatCircleArc(startLat, startLong, 180.0, 0.0, visualizationState); GreatCircleArc other(180.0, 0.0, endLat, endLong, visualizationState); m_lines.insert(m_lines.end(), other.m_lines.begin(), other.m_lines.end()); return; } *this = GreatCircleArc(startLat, startLong, 180.0, 90.0, visualizationState); GreatCircleArc other(180.0, 90.0, endLat, endLong, visualizationState); m_lines.insert(m_lines.end(), other.m_lines.begin(), other.m_lines.end()); return; } // convert start and end positions so that they don't go across the +/-180 // degree seam if (startLat < 90.0 && endLat > 270.0) { endLat -= 360.0; } // convert to radians startLat *= (M_PI / 180.0); startLong *= (M_PI / 180.0); endLat *= (M_PI / 180.0); endLong *= (M_PI / 180.0); // find sines and cosines, they are used multiple times. double sineStartLat = std::sin(startLat); double sineStartLong = std::sin(startLong); double sineEndLat = std::sin(endLat); double sineEndLong = std::sin(endLong); double cosineStartLat = std::cos(startLat); double cosineStartLong = std::cos(startLong); double cosineEndLat = std::cos(endLat); double cosineEndLong = std::cos(endLong); /* to get points on the great circle, we linearly interpolate between the * two 3D coordinates for the given spherical coordinates, then normalise * the vector to get back on the sphere. This works everywhere except exact * opposite points, where we'll get the original points repeated several * times (and if we are even more unlucky we will hit the origin where the * normal isn't defined.) */ // convert locations to 3d coordinates. double p1[3] = {cosineStartLat * sineStartLong, sineStartLat * sineStartLong, cosineStartLong}; double p2[3] = {cosineEndLat * sineEndLong, sineEndLat * sineEndLong, cosineEndLong}; ///@todo don't check the +/- 180 degree boundary when projection does not break there. bool hasSeam = true; // draw a line strip and transform the coordinates as we go. double b1 = 0.0; double b2 = 1.0; const double bDifference = 1.0 / double(segments); // for discontinuity detection. int lastSegment = 1; // The last processed vertex's position. hugin_utils::FDiff2D last_vertex; /* true if we shouldn't use last_vertex to make a line segment * i.e. We just crossed a discontinuity. */ bool skip = true; for (unsigned int segment_index = 0; segment_index < segments; segment_index++, b1 += bDifference, b2 -= bDifference) { // linearly interpolate positions double v[3] = {p1[0] * b1 + p2[0] * b2, p1[1] * b1 + p2[1] * b2, p1[2] * b1 + p2[2] * b2}; // normalise double length = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); v[0] /= length; v[1] /= length; v[2] /= length; /*double longitude = atan2(numerator, cosineStartLong * (c1 * std::sin(latitude) - c2 * std::cos(latitude)));*/ double longitude = std::acos(v[2]); // acos returns values between 0 and M_PI. The other // latitudes are on the back of the sphere, so check y coordinate (v1) double latitude = std::acos(v[0] / std::sin(longitude)); if (v[1] < 0.0) { // on the back. latitude = -latitude + 2 * M_PI; } double vx, vy; bool infront = transform.transformImgCoord(vx, vy, latitude * 180.0 / M_PI, longitude * 180.0 / M_PI); // don't draw across +/- 180 degree seems. if (hasSeam) { // we divide the width of the panorama into 3 segments. If we jump // across the middle section, we split the line into two. int newSegment = vx / (options.getWidth() / 3); if ((newSegment < 1 && lastSegment > 1) || (newSegment > 1 && lastSegment < 1)) { skip = true; } lastSegment = newSegment; } if (infront) { if (!skip) { LineSegment line; line.vertices[0] = last_vertex; line.vertices[1] = hugin_utils::FDiff2D(vx, vy); m_lines.push_back(line); } // The next line segment should be a valid one. last_vertex = hugin_utils::FDiff2D(vx, vy); skip = false; } else { skip = true; } } }