Skip to content

Is origin_offset_in_pixels correct? #17

@jonasteuwen

Description

@jonasteuwen

Following up here since #14 is about something else. Using @Falcury's tool and my function to create a read_region function:

Note: This does not happen in SlideScape! Not even a minor shift. Would this be due to the calculate of the shift in um? I will implement a non-integer shift using bilinear interpolation to check

isyntax_error_t libisyntax_read_region(isyntax_t* isyntax, isyntax_cache_t* isyntax_cache, int32_t level,
                                       int64_t x, int64_t y, int64_t width, int64_t height, uint32_t** out_pixels) {

    // Get the level
    assert(level < &isyntax->images[0].level_count);
    isyntax_level_t* current_level = &isyntax->images[0].levels[level];

    int32_t level_count = isyntax->images[0].level_count;
    // Setup the origin offset
    int32_t offset = current_level->origin_offset_in_pixels;
    int PER_LEVEL_PADDING = 3;

    // int32_t offset = ((PER_LEVEL_PADDING << level_count) - PER_LEVEL_PADDING) >> level;
    x += offset + level;
    y += offset + level;

    // Check bounds
//    assert(x + width - offset <= current_level->width_in_pixels);
//    assert(y + height - offset <= current_level->height_in_pixels);

    int32_t tile_width = isyntax->tile_width;
    int32_t tile_height = isyntax->tile_height;

    int64_t start_tile_x = x / tile_width;
    int64_t end_tile_x = (x + width - 1) / tile_width;
    int64_t start_tile_y = y / tile_height;
    int64_t end_tile_y = (y + height - 1) / tile_height;

    // Allocate memory for region
    *out_pixels = (uint32_t*)malloc(width * height * sizeof(uint32_t));

    // Read tiles and copy the relevant portion of each tile to the region
    for (int64_t tile_y = start_tile_y; tile_y <= end_tile_y; ++tile_y) {
        for (int64_t tile_x = start_tile_x; tile_x <= end_tile_x; ++tile_x) {
            // Calculate the portion of the tile to be copied
            int64_t src_x = (tile_x == start_tile_x) ? x % tile_width : 0;
            int64_t src_y = (tile_y == start_tile_y) ? y % tile_height : 0;
            int64_t dest_x = (tile_x == start_tile_x) ? 0 : (tile_x - start_tile_x) * tile_width - (x % tile_width);
            int64_t dest_y = (tile_y == start_tile_y) ? 0 : (tile_y - start_tile_y) * tile_height -
                                                            (y % tile_height);
            int64_t copy_width = (tile_x == end_tile_x) ? (x + width) % tile_width : tile_width - src_x;
            int64_t copy_height = (tile_y == end_tile_y) ? (y + height) % tile_height : tile_height - src_y;

            uint32_t *pixels = NULL;

            // Check if tile exists, if not, don't use the function to read the tile and immediately return an empty
            // tile.
            int64_t tile_index = tile_y * current_level->width_in_tiles + tile_x;
            bool tile_exists = (isyntax->images[0].levels[level].tiles + tile_index)->exists;
            if (tile_exists) {
                // Read tile
                assert(libisyntax_tile_read(isyntax, isyntax_cache, level, tile_x, tile_y, &pixels) == LIBISYNTAX_OK);
                // Copy the relevant portion of the tile to the region
                for (int64_t i = 0; i < copy_height; ++i) {
                    memcpy((*out_pixels) + (dest_y + i) * width + dest_x,
                           pixels + (src_y + i) * tile_width + src_x,
                           copy_width * sizeof(uint32_t));
                }
            } else {
                // Fill up with transparent white pixels (R=255, G=255, B=255, A=0)
                for (int64_t i = 0; i < copy_height; ++i) {
                    for (int64_t j = 0; j < copy_width; ++j) {
                        (*out_pixels)[(dest_y + i) * width + dest_x + j] = 0x00FFFFFFu;
                    }
                }
            }

            // Free the tile data
            free(pixels);
        }
    }

    return LIBISYNTAX_OK;
}

Using the origin_offset_in_pixels as defined in the header, I get a big shift between level 3 and 4 (and beyond, 0, 1, 2 are fine).

image

image

If I use ((PER_LEVEL_PADDING << level_count) - PER_LEVEL_PADDING) >> level it's rather stable, but there are very minor visual shifts. You also have these shifts in level 0, 1, 2.

This is the conversion tool. If --cache-size is too small it tends to segfault, which I couldn't locate yet (I will run Valgrind, but that doesn't work on M1, so needs to wait a bit), the conversion is here: https://github.com/NKI-AI/libisyntax/blob/add-read-region/src/isyntax_to_tiff.c

The absolute offset compared to the Philips SDK is slightly annoying, because we are annotating in a platform that uses the SDK and they output absolute coordinates in level 0.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions