def test_warp_img():
    base = (300, 200)
    top = (100, 200)
    warped_path, warped_base, warped_top = warp_img(IMG_PATH, base, top)

    expected_warped_path = os.path.join(TEMP_FOLDER, 'platane-1_warped.jpeg')
    assert_equals(warped_path, expected_warped_path)
    assert_equals(warped_base, (450, 250))
    assert_equals(warped_top, (25, 250))
    assert_true(os.path.exists(warped_path))

    # The resulting image has a fixed size
    assert_equals(get_img_size(warped_path), (500, 500))
Esempio n. 2
0
def snapshot(request):
    """Index page."""
    filename = request.matchdict['file']
    settings = dict(request.registry.settings)
    pic_dir = settings['thumbs.document_root']
    file_path = os.path.join(pic_dir, filename)

    try:
        height, width = get_img_size(file_path)
    except IOError:
        logger.error("Failed to open file with path: %s", file_path,
                     exc_info=True)
        raise HTTPNotFound("Could not load image for snap %s" % filename)

    # security loop
    elmts = filename.split(os.sep)
    for unsecure in ('.', '..'):
        if unsecure in elmts:
            return HTTPNotFound()

    file_uuid = os.path.splitext(filename)[0]

    if request.method == 'POST':
        base = _toint(request.POST['bottom_y']), _toint(request.POST['bottom_x'])
        top = _toint(request.POST['top_y']), _toint(request.POST['top_x'])
        warped_img_path, new_base, new_top = warp_img(file_path, base, top)
        # There should be only one
        snap_idx, snap_type = 'snaps', 'snaptype'
        snap = request.db.get(snap_idx, snap_type, file_uuid)
        warped_filename = os.path.basename(warped_img_path)
        if snap is not None:
            snap['warped_filename'] = warped_filename
            snap['warped'] = True
            snap['base_x'] = base[0]
            snap['base_y'] = base[1]
            snap['top_x'] = top[0]
            snap['top_y'] = top[1]
            logger.debug("Warping snap %s", file_uuid)
            request.db.index(snap, snap_idx, snap_type, file_uuid)
            request.db.refresh()
            # Precompute the cached features incrementally
            compute_features_collection([snap], pic_dir, cache=FEATURES_CACHE)
        else:
            logger.warning("Could not find snap for %s", file_uuid)
        return HTTPFound(location='/warped/%s' % warped_filename)

    data = {'snapshot': filename,
            'width': width,
            'height': height}

    return _basic(request, data)
Esempio n. 3
0
def warped(request):
    """Index page."""
    filename = request.matchdict['file']
    settings = dict(request.registry.settings)
    pic_dir = settings['thumbs.document_root']
    orig_img = os.path.join(pic_dir, filename)
    res = get_img_size(orig_img)

    warped_stemname = os.path.splitext(filename)[0]
    snap_idx, snap_type = 'snaps', 'snaptype'

    if warped_stemname.endswith('_warped'):
        file_uuid = warped_stemname[:-len('_warped')]
    else:
        logger.warning(
            'Warped stemname is expected to end with "_warped", got: %s',
            warped_stemname
        )
        file_uuid = warped_stemname

    try:
        current_snap = request.db.get(snap_idx, snap_type, file_uuid)
    except NotFoundException:
        raise HTTPNotFound("Could not find snapshot for %s" % file_uuid)

    next_snap = None
    unwarped_count = ""

    if not current_snap.plant:
        query = FieldQuery(FieldParameter('warped', True))
        candidates = request.db.search(query, size=200, indices=['snaps'],
                                       sort='timestamp:desc')

        # TODO: filter out non-plant snaps in the query directly
        candidates = [c for c in candidates if c.plant != None]

        logger.debug('Computing suggestion for %s', current_snap.filename)
        best_snaps, scores = suggest_snaps(current_snap, candidates, pic_dir,
                                           FEATURES_CACHE)
        suggestions = OrderedDict()
        for i, (snap, score) in enumerate(zip(best_snaps, scores)):
            name = snap.plant
            logger.debug("#%02d: %s with score = %f - %s",
                         i, name, score, snap.filename)
            suggestion = suggestions.get(name)
            if suggestion is None:
                query = FieldQuery(FieldParameter('name', name))
                plants = list(request.db.search(query, indices=['plants']))
                if not plants:
                    raise HTTPNotFound("No plant registered under %s"
                                       % name)
                plant = plants[0]
                suggestions[name] = (plant, [snap])
            else:
                suggestion[1].append(snap)
    else:
        suggestions = None

        # Suggest to warp the next unwarped snapshot from the same plant
        query = FieldQuery(fieldparameters=(
            FieldParameter('warped', None),
            FieldParameter('filename', '-' + current_snap.filename),
            FieldParameter('plant', current_snap.plant)))
        max_count = 100
        next_snaps = request.db.search({
            "bool" : {
                "must" : [
                    {'field': {'filename': '-' + current_snap.filename}},
                    {'field': {'plant': current_snap.plant}},
                ],
                "must_not" : [
                    {'field': {'warped': True}},
                ],
            },
        }, size=max_count, indices=['snaps'], sort='timestamp:desc')
        logger.debug(len(next_snaps))
        if len(next_snaps) > 0:
            next_snap = next_snaps[0]

        unwarped_count = "%d" % len(next_snaps)
        if len(next_snaps) == max_count:
            unwarped_count += "+"

    if len(res) == 2:
        height, width = res
    else:
        height, width = 500, 500

    # security loop
    elmts = filename.split(os.sep)
    for unsecure in ('.', '..'):
        if unsecure in elmts:
            return HTTPNotFound()

    data = {'snapshot': filename,
            'original': get_original_path(filename),
            'width': width,
            'height': height,
            'snap': current_snap,
            'uuid': file_uuid,
            'suggestions': suggestions,
            'next_snap': next_snap,
            'unwarped_count': unwarped_count}

    return _basic(request, data)