GithubHelp home page GithubHelp logo

stitch2d's Introduction

stitch2D

stitch2D is a Python script that stitches a two-dimensional grid of tiles into a mosaic. It was originally developed for stitching together images collected on various microscopes in the Department of Mineral Sciences at the Smithsonian National Museum of Natural History.

When tiles are stitched together by stitch2d, they are translated, not rotated, resized, or warped. As a result, stitch2d requires all images to be the same size and orientation. Images must overlap, although they don’t necessarily need to be arranged in a grid.

In addition to the instructions below, a guide and API reference are available in the documentation.

Install

Install stitch2d with pip:

pip install stitch2d

Or install from the GitHub repository using git and pip:

git clone https://github.com/adamancer/stitch2d
cd stitch2d
pip install .

Quick start

The following code can be used to create and save a mosaic:

from stitch2d import create_mosaic


mosaic = create_mosaic("/path/to/tiles")

try:
    mosaic.load_params()
except FileNotFoundError:
    mosaic.downsample(0.6)
    mosaic.align()
    mosaic.reset_tiles()
    mosaic.save_params()

mosaic.smooth_seams()
mosaic.save("mosaic.jpg")

A simple stitching workflow is also available from the command line. To create a smoothed mosaic and save it as a JPEG, run:

stitch2d path/to/tiles --smooth -output mosaic.jpg

For more information about using this command, including available parameters, run:

stitch2d --help

Overview

stitch2d includes two classes that can be used to create mosaics from a list of tiles:

  • Mosaic, which incorporates no information about how the tiles in the mosaic are arranged
  • StructuredMosaic, which arranges the tiles into a grid based on parameters supplied by the user

You can also use create_mosaic(), as above, which accepts the same arguments as StructuredMosaic. This function returns a StructuredMosaic if grid parameters are provided or can be inferred from the filenames of the tiles or a Mosaic if not.

Mosaic

Since Mosaic doesn’t know anything about the tile structure, it can be slow, especially for large grids where lots of tiles need to be compared. It’s almost always faster to use StructuredMosaic where possible.

Initialize a Mosaic by pointing it to the directory where the tiles of interest live:

from stitch2d import Mosaic

mosaic = Mosaic("/path/to/tiles")

Mosaic also includes a class attribute, num_cores, to specify how many cores it should use when aligning and stitching a mosaic. By default, it uses one core. Modify this value with:

Mosaic.num_cores = 2

Even when using multiple cores, detecting and extracting features can be time consuming. One way to speed up the process is to reduce the resolution of the tiles being analyzed:

mosaic.downsample(0.6)  # downsamples all tiles larger than 0.6 mp

Alternatively you can resize the tiles without the size check:

mosaic.resize(0.6)      # resizes all tiles to 0.6 mp

You can then align the smaller tiles:

mosaic.align()

In either case, you can restore the full-size images prior to stitching the mosaic together:

mosaic.reset_tiles()

Sometimes brightness and contrast can vary significantly between adjacent tiles, producing a checkerboard effect when the mosaic is stitched together. This can be mitigated in many cases using smooth_seams(), which aligns brightness/contrast between neighboring tiles by comparing areas of overlap:

mosaic.smooth_seams()

Once the tiles have been positioned, the mosaic can be viewed:

mosaic.show()

Or saved to a file:

mosaic.save("mosaic.tif")

Or returned as a numpy array if you need more control over the final mosaic:

arr = mosaic.stitch()

The default backend, opencv, orders color channels as BGR. You may want to reorder the color channels before working with the image in a different program. To get an RGB image from a BGR image, use:

arr = arr[...,::-1].copy()

New in 1.1: Or specify the desired channel order when stitching:

arr = mosaic.stitch("RGB")

Once the tiles are positioned, their locations are stored in the params attribute, which can be saved as JSON:

mosaic.save_params("params.json")

Those parameters can then be loaded into a new mosaic if needed:

mosaic.load_params("params.json")

StructuredMosaic

StructuredMosaic allows the user to specify how the tiles in the mosaic should be arranged. For tilesets of known structure, it is generally faster but otherwise works the same as Mosaic. Initialize a structured mosaic with:

from stitch2d import StructuredMosaic

mosaic = StructuredMosaic(
    "/path/to/tiles",
    dim=15,                  # number of tiles in primary axis
    origin="upper left",     # position of first tile
    direction="horizontal",  # primary axis (i.e., the direction to traverse first)
    pattern="snake"          # snake or raster
  )

For large tilesets where adequate-but-imperfect tile placement is acceptable, StructuredMosaic can use its knowledge of the tile grid to quickly build a mosaic based on the positions of only a handful of tiles:

# Stop aligning once 5 tiles have been successfully placed
mosaic.align(limit=5)

# Build the rest of the mosaic based on the positioned tiles. If from_placed
# is True, missing tiles are appended to the already positioned tiles. If
# False, a new mosaic is calculated from scratch.
mosaic.build_out(from_placed=True)

The build_out() method can also be used to ensure that all tiles (including those that could not be placed using feature matching) appear in the final mosaic. The primary disadvantage of this method is that the placement of those tiles is less precise.

Beyond 8-bit images

New in 1.2: The Tile class now includes a prep_imdata() method that can be used to tweak the image data being used to align the mosaic. When using the default OpenCVTile class, this method creates an 8-bit copy of the image data to use for feature detection and matching while retaining the original data to use when building the mosaic.

The default behavior of prep_imdata() is simplistic. To customize it, use a subclass. For example, the default method scales the intensities of the original data based on the maximum intensity found in the array. For images with a small number of extremely bright pixels, this can yield unusably dim images. A better approach may be to use np.percentile():

import numpy as np

class MyTile(OpenCVTile):

    def prep_imdata(self):
        imdata = self.imdata - self.imdata.min()
        return  np.uint8(255 * imdata / np.percentile(imdata, 99))

mosaic = create_mosaic("path/to/tiles", tile_class=MyTile)

Similar tools

The opencv package includes powerful tools for stitching 2D and 3D images. Much of that functionality has been ported to Python as the stitching package, which streamlines the opencv API and includes a useful tutorial. I didn’t have any luck getting it to work consistently with microscope tilesets, but it includes advanced features missing from this package (lens corrections, affine transformations beyond simple translation, etc.) and can be configured to work with 2D images. It’s definitely worth a look for tilesets more complex than the simple case handled here.

Fiji also includes a 2D/3D stitching tool.

stitch2d's People

Contributors

adamancer avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

stitch2d's Issues

Live Stitch

Hello,

Thanks for this nice and usefull stitching project

I am able to stitch my microscopic images, but I have a question:

Is it possible to stitch the images when scanning the tissue ? Because my images are high resolution (5Mp) and there are a lot of them(Sometimes 2000 - 3000 tiles). Stitching these tiles after scanning takes much time

Thanks again

issue in installing stitch2d

i'm getting following error in installation

OS:- Ubantu 17.10
I also updated the supertool still no mluck

Collecting stitch2d
Using cached https://files.pythonhosted.org/packages/92/98/27704653b0243eebb1c08ef9e82475edda58ee841a0e768bed40e2d470fa/stitch2d-0.31.tar.gz
Complete output from command python setup.py egg_info:
running egg_info
creating pip-egg-info/stitch2d.egg-info
writing top-level names to pip-egg-info/stitch2d.egg-info/top_level.txt
writing pip-egg-info/stitch2d.egg-info/PKG-INFO
Traceback (most recent call last):
File "", line 1, in
File "/tmp/pip-install-7fo41qxe/stitch2d/setup.py", line 35, in
zip_safe=False)
File "/home/gulve/anaconda3/lib/python3.5/site-packages/setuptools/init.py", line 140, in setup
return distutils.core.setup(**attrs)
File "/home/gulve/anaconda3/lib/python3.5/distutils/core.py", line 148, in setup
dist.run_commands()
File "/home/gulve/anaconda3/lib/python3.5/distutils/dist.py", line 955, in run_commands
self.run_command(cmd)
File "/home/gulve/anaconda3/lib/python3.5/distutils/dist.py", line 974, in run_command
cmd_obj.run()
File "/home/gulve/anaconda3/lib/python3.5/site-packages/setuptools/command/egg_info.py", line 288, in run
writer(self, ep.name, os.path.join(self.egg_info, ep.name))
File "/home/gulve/anaconda3/lib/python3.5/site-packages/setuptools/command/egg_info.py", line 613, in write_pkg_info
metadata.write_pkg_info(cmd.egg_info)
File "/home/gulve/anaconda3/lib/python3.5/distutils/dist.py", line 1107, in write_pkg_info
self.write_pkg_file(pkg_info)
File "/home/gulve/anaconda3/lib/python3.5/site-packages/setuptools/dist.py", line 91, in write_pkg_file
long_desc = rfc822_escape(self.get_long_description())
File "/home/gulve/anaconda3/lib/python3.5/distutils/util.py", line 471, in rfc822_escape
lines = header.split('\n')
TypeError: a bytes-like object is required, not 'str'

----------------------------------------

Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-install-7fo41qxe/stitch2d/

>8bit depth support

This library is super useful but it doesn't support stitching images that have a bit depth other than 8bit. Also, would it be possible to add an option to load image arrays directly rather than loading them from a file?

Structured Mosaic - 101st Column

When creating a structured mosaic, the output omits the 101st column of tiles, replacing it with the final column (in my case the 123rd column). Columns 102 through 122 are placed correctly. My file numbering appears to be correct for both alpha and numeric sorting. The fact that is occurs on the 101st & final column leads me to believe it is an arbitrary limit applied in a while loop which is only being ignored for one cycle ("while count <= 100") then picks up again.
Capture

Memory Management and Clustering in Mosaic Construction

I am working on constructing a mosaic from photographs taken of a microscope slide. The total number of images is approximately 10,000, some of which are completely white, indicating areas with no tissue.

Running the script with either of the two options (Mosaic and StructuredMosaic) results in a memory management issue, causing the memory usage to reach 100% and freezing the computer.

I am looking for a way to work with the script using clusters to manage memory and recursively assemble the clusters until the entire mosaic is constructed. Additionally, I need to incorporate the white images (which do not have matching points) into the clusters based on their known positions.

Here is the detailed scenario:

  1. Image Acquisition: The complete set of images is captured by the hardware before running the script. Each image's position in the mosaic is identified in the file name, allowing the entire set to be mapped.
  2. Memory Management: Efficient memory and processing management is critical due to the large number of images.
  3. Clustering: Using a recursive approach to handle clusters would help manage memory and processing load.
  4. Incorporating White Images: The white images should be placed in the clusters and the final mosaic based on their known x and y coordinates in the grid.

Requirements

  • Mosaic Construction: Handle a large number of images (at least 10,000, potentially up to 500,000).
  • Efficient Memory Management: Ensure the script can run without exhausting system memory.
  • Recursive Clustering: Implement clustering in a recursive manner to assist with memory and processing load.
  • White Image Handling: Integrate white images into the clusters and mosaic based on their mapped positions.

Example

The script should be able to:

  1. Load a subset of images into memory, process them, and assemble them into clusters.
  2. Recursively combine clusters to form larger clusters until the full mosaic is assembled.
  3. Insert white images into their correct positions based on their coordinates without requiring matching points.

Is there a way to achieve this functionality with the current script or through modifications?

Stitching Tree Cookie Samples

Hi!

I am attempting to use this package to stitch together tree cookie image samples generated by a HQ raspberry pi camera. For each cookie, we have ~600 images.

On a "zoomed out" sample (15 images for the entire cookie), we are able to get pretty decent results using this package, but when we tried on our full dataset, it is unable to align our images. I have tried using a variety of values in the downsizing parameter, but am not sure if there is any other parameters to tune/ways to help improve performance.

Here is a zip of a few rows of our images (didn't include them all bc the file sizes are massive!)

Any help/guidance would be very appreciated!

from stitch2d import StructuredMosaic, create_mosaic
import os

mosaic = create_mosaic(
    tile_path,
    dim=16,                  # number of tiles in primary axis
    origin="upper left",     # position of first tile
    direction="horizontal",  # primary axis (i.e., the direction to traverse first)
    pattern="raster"          # snake or raster
  )


mosaic.downsample(0.9)
mosaic.align()
mosaic.reset_tiles()
mosaic.save_params()

mosaic.smooth_seams()
mosaic.save("mosaic.jpg")

Defining stitching positions

Hi Adam, I am a fellow geologist. I built this rig:

image

so i could take pictures of the drill core as it comes out of the ground. I am trying to stitch the resulting images with Stitch2D and hitting a wall. In the first case it is just putting the images next to each other, in the second case it cannot find any alignment.

image

These are the sample images I am trying to stitch:

Run2.zip

I am a python and programing newbie, many thanks in advance for you help.

Limit to Number of Image Params Saved?

Hi,

I am working on using your package in order to stitch High Resolution SEM microscopy images that are taken in a snake like grid pattern. I am having issue with the package only saving out the first 200 image coordinates while I have 240 images in a 80x3 grid array.
However, it does provide the filenames for all 240 images in the json file.

I have been using the structured mosaic aspect of the package to do this:

from stitch2d import StructuredMosaic

StructuredMosaic.num_cores = 1
mosaic= StructuredMosaic(
    Step0_SEM_Images_Folder,
    dim = 80, # number of tiles in primary axis
    origin="upper left", # position of first tile
    direction="horizontal",  # primary axis (i.e., the direction to traverse first)
    pattern="snake"  # snake or raster
    )

mosaic.align() 
mosaic.save_params(SEM_Params_Filename_Path)
mosaic.save(SEM_Stitched_Image_Path) 

Similarly, the images I am using are high resolution each small image is 6144 by 4096 pixels and the code takes a very long time to run (over 300 min), but if I scale the images down by a factor of 3 then it take only 20 seconds.

If helpful I can provide the images or the output json.

I'd appreciate any help you can offer as well as want to thank you for doing this development as this fits my application very well.

Thanks,
Chris

How to Maintain Color with Array

First, I would like to thank you for making this available, I have been using it for stitching the whole slide images our lab has been producing with wonderful results.

I recently upgraded from version 0.5 to version 1.0 and while I was updating the script I made I noticed that the correct color was not maintained when creating an array before saving. However, the correct color was maintained when saving the stitched image directly.

Unfortunately, I am not sure exactly how to troubleshoot the issue and I was wondering if someone might be able to provide some advice. I will attempt to upload my testing script as well as some “demo” images so someone can try to recreate what I am saying.

TestFiles.zip

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.