Skip to content

Commit

Permalink
Merge pull request #286 from danforthcenter/fvfm_8_or_16bit
Browse files Browse the repository at this point in the history
Update the Fv/Fm function to allow 8- or 16-bit images
  • Loading branch information
nfahlgren committed Dec 14, 2018
2 parents 3794a57 + eda538b commit 75d17ad
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 30 deletions.
8 changes: 4 additions & 4 deletions docs/fluor_fvfm.md
@@ -1,10 +1,10 @@
## Analyze FLU Signal
## Analyze PSII Signal

Extract Fv/Fm data of objects and produce pseudocolored images.

**plantcv.fluor_fvfm**(*fdark, fmin, fmax, mask, filename, bins=1000*)
**plantcv.fluor_fvfm**(*fdark, fmin, fmax, mask, filename, bins=256*)

**returns** FLU channel histogram headers, FLU channel histogram data
**returns** Fv/Fm histogram headers, Fv/Fm histogram data, PSII analysis images list

- **Parameters:**
- fdark - image object, grayscale
Expand Down Expand Up @@ -47,7 +47,7 @@ from plantcv import plantcv as pcv
pcv.params.debug = "print"

# Analyze Fv/Fm
fvfm_header, fvfm_data = pcv.fluor_fvfm(fdark, fmin, fmax, kept_mask, filename, 1000)
fvfm_header, fvfm_data, fvfm_images = pcv.fluor_fvfm(fdark, fmin, fmax, kept_mask, filename, 1000)
```

**Histogram of Fv/Fm values**
Expand Down
2 changes: 1 addition & 1 deletion docs/psII_tutorial.md
Expand Up @@ -224,7 +224,7 @@ along with the generated mask to calculate Fv/Fm.
fmin = cv2.imread(args.fmin, -1)
fmax = cv2.imread(args.fmax, -1)

fvfm_header, fvfm_data = pcv.fluor_fvfm(fdark,fmin,fmax,kept_mask, args.outdir+'/'+filename, 1000)
fvfm_header, fvfm_data, fvfm_images = pcv.fluor_fvfm(fdark,fmin,fmax,kept_mask, args.outdir+'/'+filename, 1000)

# Write shape and nir data to results file
result=open(args.result,"a")
Expand Down
2 changes: 1 addition & 1 deletion docs/updating.md
Expand Up @@ -246,7 +246,7 @@ pages for more details on the input and output variable types.
#### plantcv.fluor_fvfm

* pre v3.0dev2: device, hist_header, hist_data = **plantcv.fluor_fvfm**(*fdark, fmin, fmax, mask, device, filename, bins=1000, debug=None*)
* post v3.0dev2: hist_header, hist_data = **plantcv.fluor_fvfm**(*fdark, fmin, fmax, mask, filename, bins=1000*)
* post v3.0dev2: hist_header, hist_data, hist_images = **plantcv.fluor_fvfm**(*fdark, fmin, fmax, mask, filename, bins=256*)

#### plantcv.gaussian_blur

Expand Down
51 changes: 30 additions & 21 deletions plantcv/plantcv/fluor_fvfm.py
Expand Up @@ -10,16 +10,16 @@
from plantcv.plantcv import params


def fluor_fvfm(fdark, fmin, fmax, mask, filename, bins=1000):
def fluor_fvfm(fdark, fmin, fmax, mask, filename, bins=256):
"""Analyze PSII camera images.
Inputs:
fdark = 16-bit grayscale fdark image
fmin = 16-bit grayscale fmin image
fmax = 16-bit grayscale fmax image
mask = mask of plant (binary,single channel)
fdark = grayscale fdark image
fmin = grayscale fmin image
fmax = grayscale fmax image
mask = mask of plant (binary, single channel)
filename = name of file
bins = number of bins from 0 to 65,536 (default is 1000)
bins = number of bins (1 to 256 for 8-bit; 1 to 65,536 for 16-bit; default is 256)
Returns:
hist_header = fvfm data table headers
Expand All @@ -40,9 +40,13 @@ def fluor_fvfm(fdark, fmin, fmax, mask, filename, bins=1000):
# Check that fdark, fmin, and fmax are grayscale (single channel)
if not all(len(np.shape(i)) == 2 for i in [fdark, fmin, fmax]):
fatal_error("The fdark, fmin, and fmax images must be grayscale images.")
# # Check that fdark, fmin, and fmax are the same bit
# if not (all(i.dtype == "uint16" for i in [fdark, fmin, fmax]) or
# (all(i.dtype == "uint8" for i in [fdark, fmin, fmax]))):
# fatal_error("The fdark, fmin, and fmax images must all be the same bit depth.")
# Check that fdark, fmin, and fmax are 16-bit images
if not all(i.dtype == "uint16" for i in [fdark, fmin, fmax]):
fatal_error("The fdark, fmin, and fmax images must be 16-bit images.")
# if not all(i.dtype == "uint16" for i in [fdark, fmin, fmax]):
# fatal_error("The fdark, fmin, and fmax images must be 16-bit images.")

# QC Fdark Image
fdark_mask = cv2.bitwise_and(fdark, fdark, mask=mask)
Expand Down Expand Up @@ -104,6 +108,8 @@ def fluor_fvfm(fdark, fmin, fmax, mask, filename, bins=1000):
qc_fdark
)

analysis_images = []

if filename:
import matplotlib
matplotlib.use('Agg', warn=False)
Expand All @@ -112,7 +118,7 @@ def fluor_fvfm(fdark, fmin, fmax, mask, filename, bins=1000):

# Print F-variable image
print_image(fv, (os.path.splitext(filename)[0] + '_fv_img.png'))
print('\t'.join(map(str, ('IMAGE', 'fv', os.path.splitext(filename)[0] + '_fv_img.png'))))
analysis_images.append(['IMAGE', 'fv', os.path.splitext(filename)[0] + '_fv_img.png'])

# Create Histogram Plot, if you change the bin number you might need to change binx so that it prints
# an appropriate number of labels
Expand All @@ -128,26 +134,28 @@ def fluor_fvfm(fdark, fmin, fmax, mask, filename, bins=1000):
fig_name = (os.path.splitext(filename)[0] + '_fvfm_hist.svg')
plt.savefig(fig_name)
plt.clf()
print('\t'.join(map(str, ('IMAGE', 'hist', fig_name))))
analysis_images.append(['IMAGE', 'fvfm_hist', fig_name])

# Pseudocolored Fv/Fm image
fvfm_8bit = fvfm * 255
fvfm_8bit = fvfm_8bit.astype(np.uint8)
plt.imshow(fvfm_8bit, vmin=0, vmax=1, cmap=cm.jet_r)
plt.subplot(111)
mask_inv = cv2.bitwise_not(mask)
background = np.dstack((mask, mask, mask, mask_inv))
my_cmap = plt.get_cmap('binary_r')
plt.imshow(background, cmap=my_cmap)
plt.imshow(fvfm, vmin=0, vmax=1, cmap="viridis")
plt.colorbar()
# fvfm_8bit = fvfm * 255
# fvfm_8bit = fvfm_8bit.astype(np.uint8)
# plt.imshow(fvfm_8bit, vmin=0, vmax=1, cmap=cm.jet_r)
# plt.subplot(111)
# mask_inv = cv2.bitwise_not(mask)
# background = np.dstack((mask, mask, mask, mask_inv))
# my_cmap = plt.get_cmap('binary_r')
# plt.imshow(background, cmap=my_cmap)
plt.axis('off')
fig_name = (os.path.splitext(filename)[0] + '_pseudo_fvfm.png')
plt.savefig(fig_name, dpi=600, bbox_inches='tight')
plt.clf()
print('\t'.join(map(str, ('IMAGE', 'pseudo', fig_name))))
analysis_images.append(['IMAGE', 'fvfm_pseudo', fig_name])

path = os.path.dirname(filename)
fig_name = 'FvFm_pseudocolor_colorbar.svg'
if not os.path.isfile(path + '/' + fig_name):
if not os.path.isfile(os.path.join(path, fig_name)):
plot_colorbar(path, fig_name, 2)

if params.debug == 'print':
Expand All @@ -158,5 +166,6 @@ def fluor_fvfm(fdark, fmin, fmax, mask, filename, bins=1000):
plot_image(fmin_mask, cmap='gray')
plot_image(fmax_mask, cmap='gray')
plot_image(fv, cmap='gray')
plot_image(fvfm, cmap="jet")

return hist_header, hist_data
return hist_header, hist_data, analysis_images
5 changes: 3 additions & 2 deletions plantcv/plantcv/plot_colorbar.py
@@ -1,5 +1,6 @@
# Plot colorbar for pseudocolored images

import os

def plot_colorbar(outdir, filename, bins):
"""Plot colorbar for pseudocolored images
Expand All @@ -20,12 +21,12 @@ def plot_colorbar(outdir, filename, bins):
from matplotlib import colors as colors
from matplotlib import colorbar as colorbar

fig_name = outdir + '/' + filename
fig_name = os.path.join(outdir, filename)
fig = plt.figure()
ax1 = fig.add_axes([0.05, 0.80, 0.9, 0.15])
valmin = -0
valmax = (bins - 1)
norm = colors.Normalize(vmin=valmin, vmax=valmax)
colorbar.ColorbarBase(ax1, cmap="jet", norm=norm, orientation='horizontal')
colorbar.ColorbarBase(ax1, cmap="viridis", norm=norm, orientation='horizontal')
fig.savefig(fig_name, bbox_inches='tight')
fig.clf()
3 changes: 2 additions & 1 deletion tests/tests.py
Expand Up @@ -855,7 +855,8 @@ def test_plantcv_fluor_fvfm():
_ = pcv.fluor_fvfm(fdark=fdark, fmin=fmin, fmax=fmax, mask=fmask, filename=False, bins=1000)
# Test with debug = None
pcv.params.debug = None
fvfm_header, fvfm_data = pcv.fluor_fvfm(fdark=fdark, fmin=fmin, fmax=fmax, mask=fmask, filename=False, bins=1000)
fvfm_header, fvfm_data, fvfm_images = pcv.fluor_fvfm(fdark=fdark, fmin=fmin, fmax=fmax, mask=fmask, filename=False,
bins=1000)
assert fvfm_data[4] > 0.66


Expand Down

0 comments on commit 75d17ad

Please sign in to comment.