Пример #1
0
vector<UIntSet> getExposureLayers(const PanoramaData & pano, UIntSet allImgs, PanoramaOptions opts)
{
    vector<UIntSet> result;

    // if no images are available, return empty result vector
    if ( allImgs.empty() )
    {
        return result;
    }

    UIntSet stack;

    do {
        unsigned srcImg = *(allImgs.begin());
        stack.insert(srcImg);
        allImgs.erase(srcImg);

        // find all images that have a suitable overlap.
        SrcPanoImage simg = pano.getSrcImage(srcImg);
        double maxEVDiff = opts.outputLayersExposureDiff;
        for (UIntSet::iterator it = allImgs.begin(); it !=  allImgs.end(); ) {
            unsigned srcImg2 = *it;
            ++it;
            SrcPanoImage simg2 = pano.getSrcImage(srcImg2);
            if ( fabs(simg.getExposureValue() - simg2.getExposureValue()) < maxEVDiff )
            {
                stack.insert(srcImg2);
                allImgs.erase(srcImg2);
            }
        }
        result.push_back(stack);
        stack.clear();
    } while (allImgs.size() > 0);

    return result;
}
Matrix3 StraightenPanorama::calcStraighteningRotation(const PanoramaData& panorama)
{
    // landscape/non rotated portrait detection is not working correctly
    // should use the exif rotation tag but thats not stored anywhere currently...
    // 1: use y axis (image x axis), for normal image
    // 0: use z axis (image y axis), for non rotated portrait images
    //    (usually rotation is just stored in EXIF tag)
    std::vector<int> coord_idx;

    for (unsigned int i = 0; i < panorama.getNrOfImages(); i++) {
        SrcPanoImage img = panorama.getSrcImage(i);
        // BUG: need to read exif data here, since exif orientation is not
        // stored in Panorama data model
        double fl=0;
        double crop=0;
        img.readEXIF(fl, crop, false, false);
        double roll = img.getExifOrientation();
        if (roll == 90 || roll == 270 ) {
            coord_idx.push_back(2);
        } else {
            coord_idx.push_back(1);
        }
    }

    // build covariance matrix of X
    Matrix3 cov;
    unsigned int nrOfVariableImages=0;

    for (unsigned int i = 0; i < panorama.getNrOfImages(); i++) 
    {
        const SrcPanoImage & img=panorama.getImage(i);
        if(img.YawisLinked())
        {
            //only consider images which are not linked with the previous ones
            bool consider=true;
            for(unsigned int j=0; j<i; j++)
            {
                if(img.YawisLinkedWith(panorama.getImage(j)))
                {
                    consider=false;
                    break;
                };
            };
            if(!consider)
                continue;
        };
        double y = const_map_get(panorama.getImageVariables(i), "y").getValue();
        double p = const_map_get(panorama.getImageVariables(i), "p").getValue();
        double r = const_map_get(panorama.getImageVariables(i), "r").getValue();
        Matrix3 mat;
        mat.SetRotationPT(DEG_TO_RAD(y), DEG_TO_RAD(p), DEG_TO_RAD(r));
        nrOfVariableImages++;
        DEBUG_DEBUG("mat = " << mat);
        for (int j=0; j<3; j++) {
            for (int k=0; k<3; k++) {
                cov.m[j][k] += mat.m[j][coord_idx[i]] * mat.m[k][coord_idx[i]];
            }
        }
    }
    cov /= nrOfVariableImages;
    DEBUG_DEBUG("cov = " << cov);

    // calculate eigenvalues and vectors
    Matrix3 eigvectors;
    double eigval[3];
    int eigvalIdx[3];
    int maxsweep = 100;
    int maxannil = 0;
    double eps = 1e-16;
    
    hugin_utils::eig_jacobi(3, cov.m, eigvectors.m, eigval, eigvalIdx, &maxsweep, &maxannil, &eps);
    
    DEBUG_DEBUG("Eigenvectors & eigenvalues:" << std::endl
                << "V = " << eigvectors << std::endl
                << "D = [" << eigval[0] << ", " << eigval[1] << ", " << eigval[2] << " ]"
                << "idx = [" << eigvalIdx[0] << ", " << eigvalIdx[1] << ", " << eigvalIdx[2] << " ]");
    
    // get up vector, eigenvector with smallest eigenvalue
    Vector3 up;
    up.x = eigvectors.m[eigvalIdx[2]][0];
    up.y = eigvectors.m[eigvalIdx[2]][1];
    up.z = eigvectors.m[eigvalIdx[2]][2];
    
    // normalize vector
    up.Normalize();
    DEBUG_DEBUG("Up vector: up = " << up );
    
    double rotAngle = acos(up.Dot(Vector3(0,0,1)));
    if (rotAngle > M_PI/2) {
        // turn in shorter direction
        up *= -1;
        rotAngle = acos(up.Dot(Vector3(0,0,1)));
    }
    DEBUG_DEBUG("rotation Angle: " << rotAngle);
    
    // get rotation axis
    Vector3 rotAxis = up.Cross(Vector3(0,0,1));
    DEBUG_DEBUG("rotAxis = " << rotAngle);
    
    // calculate rotation matrix
    Matrix3 rotMat = GetRotationAroundU(rotAxis, -rotAngle);
    DEBUG_DEBUG("rotMat = " << rotMat);

    return rotMat;
}
FDiff2D CalculateFOV::calcFOV(const PanoramaData& panorama)
{
    if (panorama.getNrOfImages() == 0) {
        // no change
        return FDiff2D(panorama.getOptions().getHFOV(), panorama.getOptions().getVFOV());
    }

    vigra::Size2D panoSize(360*2,180*2);

    // remap into minature pano.
    PanoramaOptions opts;
    opts.setHFOV(360);
    opts.setProjection(PanoramaOptions::EQUIRECTANGULAR);
    opts.setWidth(panoSize.x);
    opts.setHeight(panoSize.y);

    // remap image
    // DGSW - make sure the type is correct
    vigra::BImage panoAlpha(panoSize.x, panoSize.y,static_cast< unsigned char >(0));
    //    vigra::BImage panoAlpha(panoSize.x, panoSize.y,0);
    Nona::RemappedPanoImage<vigra::BImage, vigra::BImage> remapped;
    UIntSet activeImgs = panorama.getActiveImages();
    for (UIntSet::iterator it = activeImgs.begin(); it != activeImgs.end(); ++it) {
        //    for (unsigned int imgNr=0; imgNr < getNrOfImages(); imgNr++) {
        // DGSW FIXME - Unreferenced
        //	        const PanoImage & img = getImage(*it);
        remapped.setPanoImage(panorama.getSrcImage(*it), opts, vigra::Rect2D(0,0,panoSize.x,panoSize.y));
        //remapped.setPanoImage(*this, *it, vigra::Size2D(img.getWidth(), img.getHeight()), opts);
        // calculate alpha channel
        remapped.calcAlpha();
        // copy into global alpha channel.
        vigra::copyImageIf(vigra_ext::applyRect(remapped.boundingBox(),
                                                vigra_ext::srcMaskRange(remapped)),
                            vigra_ext::applyRect(remapped.boundingBox(),
                                                vigra_ext::srcMask(remapped)),
                            vigra_ext::applyRect(remapped.boundingBox(),
                                                destImage(panoAlpha)));
        //        vigra::ImageExportInfo imge2("c:/hugin_calcfov_alpha.png");
        //        exportImage(vigra::srcImageRange(panoAlpha), imge2);
        }

    // get field of view
    FDiff2D ul,lr;
    bool found = false;
    ul.x = DBL_MAX;
    ul.y = DBL_MAX;
    lr.x = -DBL_MAX;
    lr.y = -DBL_MAX;
    for (int v=0; v< panoSize.y; v++) {
        for (int h=0; h < panoSize.x; h++) {
            if (panoAlpha(h,v)) {
                // pixel is valid
                if ( ul.x > h ) {
                    found=true;
                    ul.x = h;
                }
                if ( ul.y > v ) {
                    found=true;
                    ul.y = v;
                }
                if ( lr.x < h) {
                    found=true;
                    lr.x = h;
                }
                if ( lr.y < v) {
                    found=true;
                    lr.y = v;
                }
            }
        }
    }
    if (!found) {
        // if nothing found, return current fov
        return FDiff2D(panorama.getOptions().getHFOV(), panorama.getOptions().getVFOV());
    }
    ul=ul/2.0;
    lr=lr/2.0;
    ul.x = ul.x - 180;
    ul.y = ul.y - 90;
    lr.x = lr.x - 180;
    lr.y = lr.y - 90;
    FDiff2D fov (2*std::max(fabs(ul.x), fabs(lr.x)), 2*std::max(fabs(ul.y), fabs(lr.y)));
    if(fov.x<40)
    {
        fov.x+=1;
    };
    return fov;
}
Пример #4
0
void CenterHorizontally::centerHorizontically(PanoramaData& panorama)
{
    vigra::Size2D panoSize(360,180);
    
    // remap into minature pano.
    PanoramaOptions opts;
    opts.setHFOV(360);
    opts.setProjection(PanoramaOptions::EQUIRECTANGULAR);
    opts.setWidth(360);
    opts.setHeight(180);
    
    // remap image
    vigra::BImage panoAlpha(panoSize);
    Nona::RemappedPanoImage<vigra::BImage, vigra::BImage> remapped;
    
    // use selected images.
    const UIntSet allActiveImgs(panorama.getActiveImages());

    if (allActiveImgs.empty())
    {
        // do nothing if there are no images
        return;
    }
    
    //only check unlinked images
    UIntSet activeImgs;
    for (UIntSet::const_iterator it = allActiveImgs.begin(); it!= allActiveImgs.end(); ++it)
    {
        const SrcPanoImage & img=panorama.getImage(*it);
        bool consider=true;
        if(img.YawisLinked())
        {
            for(UIntSet::const_iterator it2=activeImgs.begin(); it2!=activeImgs.end(); ++it2)
            {
                if(img.YawisLinkedWith(panorama.getSrcImage(*it2)))
                {
                    consider=false;
                    break;
                };
            };
        };
        if(consider)
            activeImgs.insert(*it);
    };

    for (UIntSet::iterator it = activeImgs.begin(); it != activeImgs.end(); ++it)
    {
        remapped.setPanoImage(panorama.getSrcImage(*it), opts, vigra::Rect2D(0,0,360,180));
        // calculate alpha channel
        remapped.calcAlpha();
        // copy into global alpha channel.
        vigra::copyImageIf(vigra_ext::applyRect(remapped.boundingBox(),
                                                vigra_ext::srcMaskRange(remapped)),
                           vigra_ext::applyRect(remapped.boundingBox(),
                                                vigra_ext::srcMask(remapped)),
                           vigra_ext::applyRect(remapped.boundingBox(),
                                                destImage(panoAlpha)));
        }
    
    // get field of view
    std::vector<int> borders;
    bool colOccupied = false;
    for (int h=0; h < 360; h++) {
        bool curColOccupied = false;
        for (int v=0; v< 180; v++) {
            if (panoAlpha(h,v)) {
                // pixel is valid
                curColOccupied = true;
            }
        }
        if ((colOccupied && !curColOccupied) ||
            (!colOccupied && curColOccupied))
        {
            // change in position, save point.
            borders.push_back(h-180);
            colOccupied = curColOccupied;
        }
    }
    
    
    int lastidx = borders.size() -1;
    if (lastidx == -1) {
        // empty pano
        return;
    }
    
    if (colOccupied) {
        // we have reached the right border, and the pano is still valid
        // shift right fragments by 360 deg
        // |11    2222|  -> |      222211     |
        std::vector<int> newBorders;
        newBorders.push_back(borders[lastidx]);
        for (int i = 0; i < lastidx; i++) {
            newBorders.push_back(borders[i]+360);
        }
        borders = newBorders;
    }
    
    const double dYaw=(borders[0] + borders[lastidx])/2;
    
    // apply yaw shift, takes also translation parameters into account
    RotatePanorama(panorama, -dYaw, 0, 0).run();
}