Skip to content

Commit

Permalink
Merge pull request #1578 from danforthcenter/1575-image-tiling
Browse files Browse the repository at this point in the history
1575 image tiling
  • Loading branch information
nfahlgren authored Aug 16, 2024
2 parents 248f983 + cf74ff1 commit b1a14e9
Show file tree
Hide file tree
Showing 12 changed files with 158 additions and 1 deletion.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions docs/updating.md
Original file line number Diff line number Diff line change
Expand Up @@ -1344,6 +1344,11 @@ pages for more details on the input and output variable types.
* pre v4.0: NA
* post v4.0: fig, ax = **pcv.visualize.pixel_scatter_plot**(*paths_to_imgs, x_channel, y_channel*)

#### plantcv.visualize.tile

* pre v4.4: NA
* post v4.4: tile_img = **pcv.visualize.tile**(*img_list, ncol*)

#### plantcv.visualize.time_lapse_video

* pre v4.0: NA
Expand Down
46 changes: 46 additions & 0 deletions docs/visualize_tile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
## Visualize composite of image tiles

This is a plotting method used to examine several output versions, such as from different model fits with varying parameters, all at once.

**plantcv.visualize.tile**(*images, ncol*)

**returns** comp_img

- **Parameters:**
- images - A list of numpy arrays to tile into a composite.
- ncol - Number of columns in composite output. Number of rows is calculated from the number of input images.

- **Example use:**
- Below


```python

from plantcv import plantcv as pcv
import os

# Read in a list of images
images = []
for i in os.listdir("./test_images/"):
images.append(pcv.readimage("./test_images/"+i)[0])

# Examine all images at once
composite = pcv.visualize.tile(images=images, ncol=2)

```

**Input images**

![Screenshot](img/documentation_images/visualize_tile/Tile_1.jpg)

![Screenshot](img/documentation_images/visualize_tile/Tile_2.jpg)

![Screenshot](img/documentation_images/visualize_tile/Tile_3.jpg)

![Screenshot](img/documentation_images/visualize_tile/Tile_4.jpg)

**Output**

![Screenshot](img/documentation_images/visualize_tile/Tile_output.jpg)

**Source Code:** [Here](https://github.com/danforthcenter/plantcv/blob/main/plantcv/plantcv/visualize/tile.py)
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ nav:
- 'Object Sizes': visualize_obj_sizes.md
- 'Pixel Scatter Plot': 'visualize_pixel_scatter_vis.md'
- 'Pseudocolor': visualize_pseudocolor.md
- 'Tile': visualize_tile.md
- 'Time Lapse Video': visualize_time_lapse_video.md
- 'Watershed Segmentation': watershed.md
- 'White balance': white_balance.md
Expand Down
3 changes: 2 additions & 1 deletion plantcv/plantcv/visualize/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
from plantcv.plantcv.visualize.hyper_histogram import hyper_histogram
from plantcv.plantcv.visualize.pixel_scatter_vis import pixel_scatter_plot
from plantcv.plantcv.visualize.chlorophyll_fluorescence import chlorophyll_fluorescence
from plantcv.plantcv.visualize.tile import tile

__all__ = ["pseudocolor", "colorize_masks", "histogram", "colorspaces", "auto_threshold_methods",
"overlay_two_imgs", "colorize_label_img", "obj_size_ecdf", "obj_sizes", "hyper_histogram",
"pixel_scatter_plot", "time_lapse_video", "chlorophyll_fluorescence"]
"pixel_scatter_plot", "time_lapse_video", "chlorophyll_fluorescence", "tile"]
88 changes: 88 additions & 0 deletions plantcv/plantcv/visualize/tile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Tile output images in a plot to visualize all at once

import cv2
import numpy as np
import os
from plantcv.plantcv import params
from plantcv.plantcv._debug import _debug


def _row_resize(row, ncol):
"""Resizes and concatenates objects in a row.
Parameters
----------
row : list of numpy.ndarray
List of images to concatenate.
ncol : int
Number of columns in desired composite image.
Returns
-------
numpy.ndarray
Image concatenated horizontally.
"""
h_min = min(img.shape[0] for img in row)
# Resizing each image so they're the same
row_resize = [cv2.resize(img, (int(img.shape[1] * h_min / img.shape[0]), h_min),
interpolation=cv2.INTER_CUBIC) for img in row]
# Add empty images to the end of the row so things still stay the same size
while len(row_resize) < ncol:
row_resize.append(np.zeros(row_resize[0].shape, dtype=np.uint8))
# Concatenate horizontally
return cv2.hconcat(row_resize)


# Same as _row_resize but for columns
def _col_resize(col):
"""Resized and concatenates objects in a column.
Parameters
----------
col : list of numpy.ndarray
List of images to concatenate vertically.
Returns
-------
numpy.ndarray
Image concatenated vertically.
"""
w_min = min(img.shape[1] for img in col)
col_resize = [cv2.resize(img, (w_min, int(img.shape[0] * w_min / img.shape[1])),
interpolation=cv2.INTER_CUBIC) for img in col]
return cv2.vconcat(col_resize)


# The function that does the tiling
def tile(images, ncol):
"""Tile a list of images into a composite with given dimensions.
Parameters
----------
images : list of numpy.ndarray
List of images to tile.
ncol : int
Number of columns in desired composite image.
Returns
-------
numpy.ndarray
Tiled composite image.
"""
# Increment the device counter
params.device += 1

# Calculate number of rows - always rounds up
nrow = int(len(images) / ncol) + (len(images) % ncol > 0)
tracker = 0
mat = []
for _ in range(nrow):
row = []
for _ in range(ncol):
if tracker <= (len(images) - 1):
row.append(images[tracker])
tracker += 1
mat.append(_row_resize(row, ncol))
comp_img = _col_resize(mat)
_debug(visual=comp_img, filename=os.path.join(params.debug_outdir, f"{params.device}_tile.png"))
return comp_img
4 changes: 4 additions & 0 deletions tests/plantcv/visualize/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ def __init__(self):
self.small_composed_contours_file = os.path.join(self.datadir, "setaria_small_plant_composed_contours.npz")
# PlantCV hyperspectral image object
self.hsi_file = os.path.join(self.datadir, "hsi.pkl")
# Tile image directory
self.tile_dir = os.path.join(self.datadir, "visualize_tile/")
# Tile image output
self.tile_out = os.path.join(self.datadir, "Tile_output.jpg")

@staticmethod
def load_hsi(pkl_file):
Expand Down
12 changes: 12 additions & 0 deletions tests/plantcv/visualize/test_tile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import cv2
from plantcv.plantcv.visualize import tile


def test_tile(visualize_test_data):
"""Test for PlantCV."""
# Read in image list
images = []
for _ in range(4):
images.append(cv2.imread(visualize_test_data.small_rgb_img))
composite = tile(images=images, ncol=3)
assert composite.shape == (670, 1200, 3)

0 comments on commit b1a14e9

Please sign in to comment.