示例#1
0
void
Gui::debugImage(const Image* image,
                const RectI& roi,
                const QString & filename )
{
    if (image->getBitDepth() != eImageBitDepthFloat) {
        qDebug() << "Debug image only works on float images.";

        return;
    }
    RectI renderWindow;
    RectI bounds = image->getBounds();
    if ( roi.isNull() ) {
        renderWindow = bounds;
    } else {
        if ( !roi.intersect(bounds, &renderWindow) ) {
            qDebug() << "The RoI does not interesect the bounds of the image.";

            return;
        }
    }
    QImage output(renderWindow.width(), renderWindow.height(), QImage::Format_ARGB32);
    const Color::Lut* lut = Color::LutManager::sRGBLut();
    lut->validate();
    Image::ReadAccess acc = image->getReadRights();
    const float* from = (const float*)acc.pixelAt( renderWindow.left(), renderWindow.bottom() );
    assert(from);
    int srcNComps = (int)image->getComponentsCount();
    int srcRowElements = srcNComps * bounds.width();

    for ( int y = renderWindow.height() - 1; y >= 0; --y,
          from += ( srcRowElements - srcNComps * renderWindow.width() ) ) {
        QRgb* dstPixels = (QRgb*)output.scanLine(y);
        assert(dstPixels);

        unsigned error_r = 0x80;
        unsigned error_g = 0x80;
        unsigned error_b = 0x80;

        for (int x = 0; x < renderWindow.width(); ++x, from += srcNComps, ++dstPixels) {
            float r, g, b, a;
            switch (srcNComps) {
            case 1:
                r = g = b = *from;
                a = 1;
                break;
            case 2:
                r = *from;
                g = *(from + 1);
                b = 0;
                a = 1;
                break;
            case 3:
                r = *from;
                g = *(from + 1);
                b = *(from + 2);
                a = 1;
                break;
            case 4:
                r = *from;
                g = *(from + 1);
                b = *(from + 2);
                a = *(from + 3);
                break;
            default:
                assert(false);

                return;
            }
            error_r = (error_r & 0xff) + lut->toColorSpaceUint8xxFromLinearFloatFast(r);
            error_g = (error_g & 0xff) + lut->toColorSpaceUint8xxFromLinearFloatFast(g);
            error_b = (error_b & 0xff) + lut->toColorSpaceUint8xxFromLinearFloatFast(b);
            assert(error_r < 0x10000 && error_g < 0x10000 && error_b < 0x10000);
            *dstPixels = qRgba( U8(error_r >> 8),
                                U8(error_g >> 8),
                                U8(error_b >> 8),
                                U8(a * 255) );
        }
    }

    U64 hashKey = image->getHashKey();
    QString hashKeyStr = QString::number(hashKey);
    QString realFileName = filename.isEmpty() ? QString( hashKeyStr + QString::fromUtf8(".png") ) : filename;
#ifdef DEBUG
    qDebug() << "Writing image: " << realFileName;
    renderWindow.debug();
#endif
    output.save(realFileName);
} // Gui::debugImage
示例#2
0
RectI
ImageTilesState::getMinimalBboxToRenderFromTilesState(const RectI& roi, const TileStateHeader& stateMap)
{

    if (stateMap.state->tiles.empty()) {
        return RectI();
    }

    const RectI& imageBoundsRoundedToTileSize = stateMap.state->boundsRoundedToTileSize;
    const RectI& imageBoundsNotRounded = stateMap.state->bounds;

    assert(imageBoundsRoundedToTileSize.contains(roi));

    RectI roiRoundedToTileSize = roi;
    roiRoundedToTileSize.roundToTileSize(stateMap.tileSizeX, stateMap.tileSizeY);

    // Search for rendered lines from bottom to top
    for (int y = roiRoundedToTileSize.y1; y < roiRoundedToTileSize.y2; y += stateMap.tileSizeY) {

        bool hasTileUnrenderedOnLine = false;
        for (int x = roiRoundedToTileSize.x1; x < roiRoundedToTileSize.x2; x += stateMap.tileSizeX) {

            const TileState* tile = stateMap.getTileAt(x, y);
            if (tile->status == eTileStatusNotRendered) {
                hasTileUnrenderedOnLine = true;
                break;
            }
        }
        if (!hasTileUnrenderedOnLine) {
            roiRoundedToTileSize.y1 += stateMap.tileSizeY;
        } else {
            break;
        }
    }

    // Search for rendered lines from top to bottom
    for (int y = roiRoundedToTileSize.y2 - stateMap.tileSizeY; y >= roiRoundedToTileSize.y1; y -= stateMap.tileSizeY) {

        bool hasTileUnrenderedOnLine = false;
        for (int x = roiRoundedToTileSize.x1; x < roiRoundedToTileSize.x2; x += stateMap.tileSizeX) {

            const TileState* tile = stateMap.getTileAt(x, y);
            if (tile->status == eTileStatusNotRendered) {
                hasTileUnrenderedOnLine = true;
                break;
            }
        }
        if (!hasTileUnrenderedOnLine) {
            roiRoundedToTileSize.y2 -= stateMap.tileSizeY;
        } else {
            break;
        }
    }

    // Avoid making roiRoundedToTileSize.width() iterations for nothing
    if (roiRoundedToTileSize.isNull()) {
        return roiRoundedToTileSize;
    }


    // Search for rendered columns from left to right
    for (int x = roiRoundedToTileSize.x1; x < roiRoundedToTileSize.x2; x += stateMap.tileSizeX) {

        bool hasTileUnrenderedOnCol = false;
        for (int y = roiRoundedToTileSize.y1; y < roiRoundedToTileSize.y2; y += stateMap.tileSizeY) {

            const TileState* tile = stateMap.getTileAt(x, y);
            if (tile->status == eTileStatusNotRendered) {
                hasTileUnrenderedOnCol = true;
                break;
            }
        }
        if (!hasTileUnrenderedOnCol) {
            roiRoundedToTileSize.x1 += stateMap.tileSizeX;
        } else {
            break;
        }
    }

    // Avoid making roiRoundedToTileSize.width() iterations for nothing
    if (roiRoundedToTileSize.isNull()) {
        return roiRoundedToTileSize;
    }

    // Search for rendered columns from right to left
    for (int x = roiRoundedToTileSize.x2 - stateMap.tileSizeX; x >= roiRoundedToTileSize.x1; x -= stateMap.tileSizeX) {

        bool hasTileUnrenderedOnCol = false;
        for (int y = roiRoundedToTileSize.y1; y < roiRoundedToTileSize.y2; y += stateMap.tileSizeY) {

            const TileState* tile = stateMap.getTileAt(x, y);
            if (tile->status == eTileStatusNotRendered) {
                hasTileUnrenderedOnCol = true;
                break;
            }
        }
        if (!hasTileUnrenderedOnCol) {
            roiRoundedToTileSize.x2 -= stateMap.tileSizeX;
        } else {
            break;
        }
    }

    // Intersect the result to the actual image bounds (because the tiles are rounded to tile size)
    RectI ret;
    roiRoundedToTileSize.intersect(imageBoundsNotRounded, &ret);
    return ret;


} // getMinimalBboxToRenderFromTilesState
示例#3
0
void
ImageTilesState::getMinimalRectsToRenderFromTilesState(const RectI& roi, const TileStateHeader& stateMap, std::list<RectI>* rectsToRender)
{
    if (stateMap.state->tiles.empty()) {
        return;
    }

    RectI roiRoundedToTileSize = roi;
    roiRoundedToTileSize.roundToTileSize(stateMap.tileSizeX, stateMap.tileSizeY);

    RectI bboxM = getMinimalBboxToRenderFromTilesState(roi, stateMap);
    if (bboxM.isNull()) {
        return;
    }

    bboxM.roundToTileSize(stateMap.tileSizeX, stateMap.tileSizeY);

    // optimization by Fred, Jan 31, 2014
    //
    // Now that we have the smallest enclosing bounding box,
    // let's try to find rectangles for the bottom, the top,
    // the left and the right part.
    // This happens quite often, for example when zooming out
    // (in this case the area to compute is formed of A, B, C and D,
    // and X is already rendered), or when panning (in this case the area
    // is just two rectangles, e.g. A and C, and the rectangles B, D and
    // X are already rendered).
    // The rectangles A, B, C and D from the following drawing are just
    // zeroes, and X contains zeroes and ones.
    //
    // BBBBBBBBBBBBBB
    // BBBBBBBBBBBBBB
    // CXXXXXXXXXXDDD
    // CXXXXXXXXXXDDD
    // CXXXXXXXXXXDDD
    // CXXXXXXXXXXDDD
    // AAAAAAAAAAAAAA

    // First, find if there's an "A" rectangle, and push it to the result
    //find bottom
    RectI bboxX = bboxM;
    RectI bboxA = bboxX;
    bboxA.y2 = bboxA.y1;
    for (int y = bboxX.y1; y < bboxX.y2; y += stateMap.tileSizeY) {
        bool hasRenderedTileOnLine = false;
        for (int x = bboxX.x1; x < bboxX.x2; x += stateMap.tileSizeX) {
            const TileState* tile = stateMap.getTileAt(x, y);
            if (tile->status != eTileStatusNotRendered) {
                hasRenderedTileOnLine = true;
                break;
            }
        }
        if (hasRenderedTileOnLine) {
            break;
        } else {
            bboxX.y1 += stateMap.tileSizeY;
            bboxA.y2 = bboxX.y1;
        }
    }
    if ( !bboxA.isNull() ) { // empty boxes should not be pushed
        // Ensure the bbox lies in the RoI since we rounded to tile size earlier
        RectI bboxAIntersected;
        bboxA.intersect(roi, &bboxAIntersected);
        rectsToRender->push_back(bboxAIntersected);
    }

    // Now, find the "B" rectangle
    //find top
    RectI bboxB = bboxX;
    bboxB.y1 = bboxB.y2;

    for (int y = bboxX.y2 - stateMap.tileSizeY; y >= bboxX.y1; y -= stateMap.tileSizeY) {
        bool hasRenderedTileOnLine = false;
        for (int x = bboxX.x1; x < bboxX.x2; x += stateMap.tileSizeX) {
            const TileState* tile = stateMap.getTileAt(x, y);
            if (tile->status != eTileStatusNotRendered) {
                hasRenderedTileOnLine = true;
                break;
            }
        }
        if (hasRenderedTileOnLine) {
            break;
        } else {
            bboxX.y2 -= stateMap.tileSizeY;
            bboxB.y1 = bboxX.y2;
        }
    }

    if ( !bboxB.isNull() ) { // empty boxes should not be pushed
        // Ensure the bbox lies in the RoI since we rounded to tile size earlier
        RectI bboxBIntersected;
        bboxB.intersect(roi, &bboxBIntersected);
        rectsToRender->push_back(bboxBIntersected);
    }

    //find left
    RectI bboxC = bboxX;
    bboxC.x2 = bboxC.x1;
    if ( bboxX.y1 < bboxX.y2 ) {
        for (int x = bboxX.x1; x < bboxX.x2; x += stateMap.tileSizeX) {
            bool hasRenderedTileOnCol = false;
            for (int y = bboxX.y1; y < bboxX.y2; y += stateMap.tileSizeY) {
                const TileState* tile = stateMap.getTileAt(x, y);
                if (tile->status != eTileStatusNotRendered) {
                    hasRenderedTileOnCol = true;
                    break;
                }

            }
            if (hasRenderedTileOnCol) {
                break;
            } else {
                bboxX.x1 += stateMap.tileSizeX;
                bboxC.x2 = bboxX.x1;
            }
        }
    }
    if ( !bboxC.isNull() ) { // empty boxes should not be pushed
        // Ensure the bbox lies in the RoI since we rounded to tile size earlier
        RectI bboxCIntersected;
        bboxC.intersect(roi, &bboxCIntersected);
        rectsToRender->push_back(bboxCIntersected);
    }

    //find right
    RectI bboxD = bboxX;
    bboxD.x1 = bboxD.x2;
    if ( bboxX.y1 < bboxX.y2 ) {
        for (int x = bboxX.x2 - stateMap.tileSizeX; x >= bboxX.x1; x -= stateMap.tileSizeX) {
            bool hasRenderedTileOnCol = false;
            for (int y = bboxX.y1; y < bboxX.y2; y += stateMap.tileSizeY) {
                const TileState* tile = stateMap.getTileAt(x, y);
                if (tile->status != eTileStatusNotRendered) {
                    hasRenderedTileOnCol = true;
                    break;
                }
            }
            if (hasRenderedTileOnCol) {
                break;
            } else {
                bboxX.x2 -= stateMap.tileSizeX;
                bboxD.x1 = bboxX.x2;
            }
        }
    }
    if ( !bboxD.isNull() ) { // empty boxes should not be pushed
        // Ensure the bbox lies in the RoI since we rounded to tile size earlier
        RectI bboxDIntersected;
        bboxD.intersect(roi, &bboxDIntersected);
        rectsToRender->push_back(bboxDIntersected);
    }

    assert( bboxA.bottom() == bboxM.bottom() );
    assert( bboxA.left() == bboxM.left() );
    assert( bboxA.right() == bboxM.right() );
    assert( bboxA.top() == bboxX.bottom() );

    assert( bboxB.top() == bboxM.top() );
    assert( bboxB.left() == bboxM.left() );
    assert( bboxB.right() == bboxM.right() );
    assert( bboxB.bottom() == bboxX.top() );

    assert( bboxC.top() == bboxX.top() );
    assert( bboxC.left() == bboxM.left() );
    assert( bboxC.right() == bboxX.left() );
    assert( bboxC.bottom() == bboxX.bottom() );

    assert( bboxD.top() == bboxX.top() );
    assert( bboxD.left() == bboxX.right() );
    assert( bboxD.right() == bboxM.right() );
    assert( bboxD.bottom() == bboxX.bottom() );

    // get the bounding box of what's left (the X rectangle in the drawing above)
    bboxX = getMinimalBboxToRenderFromTilesState(bboxX, stateMap);

    if ( !bboxX.isNull() ) { // empty boxes should not be pushed
        // Ensure the bbox lies in the RoI since we rounded to tile size earlier
        RectI bboxXIntersected;
        bboxX.intersect(roi, &bboxXIntersected);
        rectsToRender->push_back(bboxXIntersected);
    }
    
} // getMinimalRectsToRenderFromTilesState
示例#4
0
std::pair<ImagePtr, RectI>
TrackMarker::getMarkerImage(int time,
                            const RectI& roi) const
{
    std::list<ImageComponents> components;

    components.push_back( ImageComponents::getRGBComponents() );

    const unsigned int mipmapLevel = 0;
    assert( !roi.isNull() );

    NodePtr node = getContext()->getNode();
    NodePtr input = node->getInput(0);
    if (!input) {
        return std::make_pair(ImagePtr(), roi);
    }

    AbortableRenderInfoPtr abortInfo = AbortableRenderInfo::create(false, 0);
    const bool isRenderUserInteraction = true;
    const bool isSequentialRender = false;
    AbortableThread* isAbortable = dynamic_cast<AbortableThread*>( QThread::currentThread() );
    if (isAbortable) {
        isAbortable->setAbortInfo( isRenderUserInteraction, abortInfo, node->getEffectInstance() );
    }

    ParallelRenderArgsSetter::CtorArgsPtr tlsArgs(new ParallelRenderArgsSetter::CtorArgs);
    tlsArgs->time = time;
    tlsArgs->view = ViewIdx(0);
    tlsArgs->isRenderUserInteraction = isRenderUserInteraction;
    tlsArgs->isSequential = isSequentialRender;
    tlsArgs->abortInfo = abortInfo;
    tlsArgs->treeRoot = getContext()->getNode();
    tlsArgs->textureIndex = 0;
    tlsArgs->timeline = node->getApp()->getTimeLine();
    tlsArgs->activeRotoPaintNode = NodePtr();
    tlsArgs->activeRotoDrawableItem = RotoDrawableItemPtr();
    tlsArgs->isDoingRotoNeatRender = false;
    tlsArgs->isAnalysis = true;
    tlsArgs->draftMode = true;
    tlsArgs->stats = RenderStatsPtr();
    ParallelRenderArgsSetter frameRenderArgs(tlsArgs);
    RenderScale scale;
    scale.x = scale.y = 1.;
    EffectInstance::RenderRoIArgs args( time,
                                        scale,
                                        mipmapLevel, //mipmaplevel
                                        ViewIdx(0),
                                        false,
                                        roi,
                                        RectD(),
                                        components,
                                        eImageBitDepthFloat,
                                        false,
                                        node->getEffectInstance(),
                                        eStorageModeRAM /*returnOpenGlTex*/,
                                        time);
    std::map<ImageComponents, ImagePtr> planes;
    EffectInstance::RenderRoIRetCode stat = input->getEffectInstance()->renderRoI(args, &planes);

    appPTR->getAppTLS()->cleanupTLSForThread();

    if ( (stat != EffectInstance::eRenderRoIRetCodeOk) || planes.empty() ) {
        return std::make_pair(ImagePtr(), roi);
    }

    return std::make_pair(planes.begin()->second, roi);
} // TrackMarker::getMarkerImage