libvips / pyvips

python binding for libvips using cffi
MIT License
630 stars 49 forks source link

How to can stitch multiple .tiff file as single file tiff file. #365

Open kuldeep203 opened 1 year ago

kuldeep203 commented 1 year ago

I am working on whole slide imaging of blood smear slide. i am having a thousands of picture which i want to stitch together to make a single tiff file. Please suggest me how to achieve it as i new on image processing.

jcupitt commented 1 year ago

Hello @kuldeep203,

This is a difficult problem, and how much work you need to do depends on how accurate your translation stage is, the level of pixel access you have to the camera, how good your lens is, how good your lighting system is, and the level of error you can tolerate. You'll need to do a lot of testing and experimentation.

The simplest would be to use arrayjoin to put the images together into a regular grid. This will only give good results if everything is perfect. The most complex would be to flatfield and use the mosaic functions.

I wrote an SO answer here with some background:

https://stackoverflow.com/questions/50168292/stitching-images-using-graphicsmagick-with-blending/50190264#50190264

kuldeep203 commented 1 year ago

Can you tell how i can use vips_arrayjoin in good way. suppose i am having a 100 image per row and i am having total 100 row and there is 100 pixcels overlap in the between the two picture. i was reading the documentation of arrayjoin, there are multiple arguements need to pass to the function as follow. across : gint, number of images per row

shim : gint, space between images, in pixels

background : VipsArrayDouble, background ink colour

halign : VipsAlign, low, centre or high alignment

valign : VipsAlign, low, centre or high alignment

hspacing : gint, horizontal distance between images

vspacing : gint, vertical distance between images

so i just want to ask how i use this parameter in my case.

jcupitt commented 1 year ago

Set hspacing and vspascing to the step between tiles. If each frame is 500x500 pixels, for example, set these to 400 and you'll have 100 pixels of overlap. Set across to the number of tiles across your grid. You need to sort the input images into row-major order.

This will make an ugly mosaic unless you have corrected all of your input images very carefully.

Here's a tiny demo prog to untile google maps pyramid:

#!/usr/bin/python3

# untile a google maps pyramid

import sys
import os
import pyvips

if len(sys.argv) != 3:
    print("usage: untile-google.py ~/pics/somepyramid out.jpg")
    sys.exit(1)

indir = sys.argv[1]
outfile = sys.argv[2]

# open the blank tile
blank = pyvips.Image.new_from_file(f"{indir}/blank.png")

# find number of pyramid layers
n_layers = 0
for layer in range(1000):
    if not os.path.isdir(f"{indir}/{layer}"):
        n_layers = layer
        break
print(f"{n_layers} layers detected")
if n_layers < 1:
    print("no layers found!")
    sys.exit(1)

# find size of largest layer
max_y = 0
for filename in os.listdir(f"{indir}/{n_layers - 1}"):
    max_y = max(max_y, int(filename))
max_x = 0
for filename in os.listdir(f"{indir}/{n_layers - 1}/0"):
    noext = os.path.splitext(filename)[0]
    max_x = max(max_x, int(noext))
print(f"{max_x + 1} tiles across, {max_y + 1} tiles down")

tiles = []
for y in range(max_y + 1):
    for x in range(max_x + 1):
        tile_name = f"{indir}/{n_layers - 1}/{y}/{x}.jpg"
        if os.path.isfile(tile_name):
            tile = pyvips.Image.new_from_file(tile_name,
                                              access="sequential")
        else:
            tile = blank
        tiles.append(tile)

image = pyvips.Image.arrayjoin(tiles,
                               across=max_x + 1, background=255)

image.write_to_file(outfile)

You can run it with eg.:

$ ./untile-google.py ~/pics/somepyramid out.tif[tile,pyramid,compression=jpeg]