参见作者原研究论文

本实验方案简略版
Dec 2017

本文章节


 

Simple Time-lapse Imaging for Quantifying the Hydrostatic Production of Oxygenic Photogranules
用于定量含氧光颗粒静水压力的简单时差成像   

引用 收藏 提问与回复 分享您的反馈 Cited by

Abstract

Oxygenic photogranules (OPGs) are dense, three-dimensional aggregates containing a syntrophic, light-driven microbial community. Their temporal and spatial development interests microbial ecologists working at the bioprocess engineering interface, as this knowledge can be used to optimize biotechnological applications, such as wastewater treatment and biomass valorization. The method presented here enables the high-throughput quantification of photogranulation. OPGs are produced from a loose sludge-like microbial matrix in hydrostatic batch cultures exposed to light. This matrix transforms into a consolidated, roughly spherical aggregate over time. Photogranulation is quantified by time-lapse imaging coupled to automated image analysis. This allows studying the development of many OPGs simultaneously and in a fully automated way to systematically test what factors drive photogranulation. The protocol can also be used to quantify other types of (a)biotic aggregation.

Keywords: Oxygenic photogranules (含氧感光颗粒), Microbial mats (微生物席), Biofilms (生物膜), Aggregation (聚合), Spatialization (空间化), Photogranulation (光粒化), Dynamics (动力学), Time-lapse imaging (时差成像技术)

Background

OPGs are dense, roughly spherical aggregates with diameters of several millimeters containing a syntrophic community of heterotrophic and phototrophic microorganisms (Milferstedt et al., 2017). Microbial ecologists study photogranulation to understand what factors drive the formation of the three-dimensional (3D) structure. This knowledge can be applied to steer ecosystem function towards a desired function for biotechnological processes, such as wastewater treatment and the production of value-added products (Abouhend et al., 2018; Quijano et al., 2017). OPGs can be produced from a sludge-like microbial matrix, i.e., activated sludge from the aeration basin of a wastewater treatment plant (Milferstedt et al., 2017; Park and Dolan, 2015). The transformation of this sludge takes place in closed, unagitated vials exposed to light. Over the course of several weeks, the sludge bed compacts (i.e., reduces in height) and contracts (i.e., reduces in diameter) and transforms into one consolidated, 3D aggregate per vial (Figure 1A). Experimental images are automatically acquired through the bottom of vials at a pre-set interval (Figure 1B) of multiple replicates simultaneously. Images are treated in ImageJ (Schneider et al., 2012), extending a macro developed for the quantification of naturally occurring OPGs called cryoconite granules (Irvine-Fynn et al., 2010). Dynamics of biomass contraction is calculated and plotted in the software environment R (R Core Team, 2019). This protocol enables testing photogranulation in a large number of repetitions, e.g., using different sludge sources or environmental conditions to advance the understanding of photogranulation. The protocol can also be used to quantify other types of (a)biotic aggregation.


Figure 1. Typical course of photogranulation, including compaction and contraction. Note the displayed images are for illustration purposes and were not obtained with the protocol presented here. A. Temporal progression of the transformation of loose activated sludge into a consolidated OPG in a 10 ml serum bottle with an outer diameter of 24 mm (adapted from Milferstedt et al., 2017). Arrows illustrate the terms compaction and contraction; B. Temporal progression of biomass contraction seen through the bottom of one well of a 24-well microplate with an outer diameter of 16 mm.

Materials and Reagents

  1. Fresh activated sludge from the aeration basin of a wastewater treatment plant
  2. 0.5-5 ml pipette with tips (Thermo Fisher Scientific, FinnpipetteTM F1, catalog number: 4641110N ; 5 ml FinntipTM, catalog number: 9402030 )
  3. Grid for aligning and spacing vials on scanner surface. Custom-made dark gray metal grid measuring 30.4 × 22.2 × 0.2 cm (L × W × thickness) (Figures 2A-2B)
    The grid should be sufficiently low so that it does not shadow the biomass from the side, e.g., it should not be much higher than the thickness of the vial bottom (Figure 3A-3B). The required cut-out where to place the vials can be produced using computer numerical control (CNC) metal milling or 3D printing. You can also make the grid out of other materials, such as paper.
  4. Light-impermeable box for covering distance between vials and light source to prevent loss of light and uncontrolled illumination. Home-made cardboard box of the approximate dimensions of 65 × 35 × 65 cm (L × W × H), enclosing the scanner and the lighting device.


    Figure 2. Grid. A. Grid design; B. Custom-made dark gray metal grid positioned on top of the scanner.

Equipment

  1. 1 L break resistant bottle with a wide neck for sampling (Fisher Scientific, Gosselin, catalog number: 11728643 )
  2. 2 L polypropylene beaker for mixing (Thermo Fisher Scientific, Nalgene, catalog number: 1201-2000 )
  3. 4 ml clear glass vials measuring 15 mm × 45 mm × 8 mm (outer diameter × height × inner diameter) with a screw top for cultivations (Sigma-Aldrich, Supelco, catalog number: 27111) (Figure 3A)
    A clear, smooth and flat bottom is critical for the success of this experiment (Figure 3C). We used glass vials here, and successfully used polystyrene vials previously.
  4. Screw caps with a contrasting color to the biomass for image treatment (Agilent Technologies, catalog number: 5183-4305 )
  5. Magnetic stirrer and stir bar (Bioblock Scientific, AM AMC BBS 3000 ) to homogenize activated sludge so that differences in sample composition between vials are minimized
  6. Holding device for mounting a light source, e.g., copy stand with camera arm (Kaiser, RS1, RA1, catalog number: 205510 )
  7. Flat light source, e.g., light emitting diode (LED) panel measuring 59.5 × 59.5 (cropped to 30) × 1.06 cm (L × W × H) (Rexel, LEDVANCE, PANEL LED 600, 40W, 6500K, 4000 lm, catalog number: 4058075000582 )
    We used cool white light (6,500 K) for this experiment, but other light temperatures were also successfully tested (e.g., 5,600 and 6,000 K)
  8. Photoactive synthetically radiation (PAR) quantum light sensor and display meter system (Skye Instruments Ltd, SKP 215/S 39520 , SKP 200 39521 )
  9. Desktop scanner (Epson, Perfection V500 Photo, model: J251A)


    Figure 3. Vials. A. Glass vial with screw cap; B. Vial bottom thickness; C. Clear, smooth and flat vial bottom.

Software

  1. Scanner driver allowing time-lapse acquisition of images using a desktop scanner, e.g., VueScan version 9.5.51 (Hamrick Software, https://www.hamrick.com/)
  2. Tool to read, write and edit meta information in batches of images, e.g., ExifTool version 11.78 (Phil Harvey, https://exiftool.org/)
  3. ImageJ version 1.52a (image processing program) (National Insitutes of Health (NIH), https://imagej.nih.gov/ij/) (Schneider et al., 2012)
    MorphoLibJ plugin to ImageJ version 1.4.0 (collection of mathematical morphology methods and plugins) (INRA-IJPB Modeling and Digital Imaging lab, https://imagej.net/MorphoLibJ) (Legland et al., 2016).
  4. R version 3.6.0 (software environment for statistical computing and graphics) (R Core Team, https://www.r-project.org/) (R Core Team, 2019)
    exiftoolr package version 0.1.3 (O’Brien, 2020)
    ggplot2 package version 3.2.0 (Wickham, 2016)
    plyr package version 1.8.4 (Wickham, 2011)
    readr package version 1.3.1 (Wickham et al., 2018)

Procedure

The steps below describe the production of OPGs in hydrostatic batch cultivations and the automated time-lapse acquisition of experimental images. The image analysis follows at “Data analysis”.

  1. Scanner setup (Figures 4A-4B)
    1. Connect a scanner to a computer and install scanner driver, e.g., VueScan.
    2. Set scanner settings and save program.
      1. 24-bit RGB image.
      2. 800 dots per inch (dpi) resolution yielding a pixel size of 32 µm. This resolution is sufficient to resolve the biological process and prevents the generation of excessively large files.
      3. Make sure there is no automatic color correction because this will complicate subsequent data analysis.
      4. Select the uncompressed Tagged Image File Format (TIFF) for saving images.
      5. Assign TIFF file names, e.g., YY-MM-DD_01+.tif and directory to save acquired scans.
      6. Set acquisition interval. Eight hours were sufficient to capture the dynamics of photogranulation. The interval can be increased as the experiment progresses.
    3. Take scanner image with a plain white sheet on top of the grid. This will be the background image for data analysis (Figure 5A).


      Figure 4. Experimental setup. A. Light source and scanner setup (Note the cardboard box is not shown); B. Close-up of scanner setup with vials positioned on the grid.

  2. Light source setup (Figures 4A-4B)
    1. Install a flat light source above a scanner, preferably using a device that allows adjusting the distance between the light source and vials, for example by connecting it to the camera arm of a copy stand. A flexible distance makes it possible to adjust the light intensity that vials receive and allows easy placement and removal of vials.
    2. Light intensity is typically not homogeneously distributed over a LED panel. To ensure that the local light conditions are known, you can map local PAR at different points on the scanner surface, draw a contour map and decide where to place the vials, e.g., along contour lines of similar light intensities. You can design a grid with circles that indicate where to place the vials (Figure 2A). You can print the grid on paper, cut out the circles and place it on top of the desktop scanner for positioning the vials. If you want to use the grid regularly, you can make it out of a more solid material, e.g., metal (Figure 2B) using CNC metal milling or 3D printing.
    3. Adjust the distance between the vials and light source such that the light intensity at the vial positions corresponds to approximately 60 µmol·m2·s-1 PAR. This can be measured using a PAR quantum light sensor.

  3. Activated sludge sampling and characterization
    1. Sample 200 ml of activated sludge from the aeration basin of a wastewater treatment plant. This volume is largely sufficient for an experiment using 72 vials inoculated with 1.5 ml of activated sludge each, as described in the following. The sample volume needs to be adapted if you are interested in characterizing the activated sludge, e.g., total and volatile solids, chemical oxygen demand, nitrogen, phosphorus, pH, chlorophyll, microbial community.
    2. It is useful to have available the measurement of total solids. This can be used to adjust the sludge concentration to a value comparable between experiments. We typically run an experiment with a concentration between 4 and 5 g/L of activated sludge.

  4. Vial preparation and placement
    1. Keep activated sludge in suspension upon arrival at the lab, e.g., using a magnetic stirrer.
      Note: Sludge can be stored at 4 °C when it cannot be used directly, but we recommend to use fresh activated sludge.
    2. Pipette 1.5 ml well-mixed activated sludge into 4 ml vials. Close vials with a screw cap. Our typical incubation set contains 72 vials.
    3. Place vials unagitated at the assigned areas on top of desktop scanner under constant light illumination at ambient room temperature (22-26 °C) (Figures 4A-4B).
    4. Place a light-impermeable box around the scanner and light source to limit loss of light and uncontrolled illumination of your samples.

  5. Vial incubation and time-lapse imaging
    1. Start scanner software to take an image of the bottom of the vials at the desired interval. Make sure the scanner takes an image at time 0 and that images are taken at indicated intervals.
    2. The unconsolidated sludge transforms into one OPG per vial that is typically situated at the bottom of the vial, unless it starts floating due to attached gas bubbles. Run the experiment until mature OPGs have been formed. A mature OPG is roughly spherical and remains its shape after vigorous shaking. Under the given experimental conditions, photogranulation can be expected to occur between three to six weeks. The experimental conditions, e.g., light intensity and sludge characteristics, may influence the time needed for photogranulation.
    3. Take a final scan before removing the vials from the scanner.

  6. Photogranulation success
    1. Note down whether OPGs are sitting on the bottom or floating for image analysis.
    2. Take camera images of OPGs to remember later what they looked like.
    3. Shake vials vigorously and note down in which vials a successful OPG has been formed. Photogranulation success is the percentage of successful OPGs among the total incubated vials.
    4. Characterize OPGs depending on the factors you are interested in, e.g., physicochemical parameters, microbial community.

Data analysis

For data analysis, we show the results of an experiment performed with 72 vials of a volume of 4 ml using two sludge sources, therefore having 36 replicates per condition. Some files are created as preparation for automatic data treatment (Procedures A-B). Experimental time-lapse images are treated in ImageJ (Schneider et al., 2012) using particle size analysis to measure particle characteristics including surface area (Procedures C-D). The surface area is subsequently transformed to equivalent diameters in the software environment R (R Core Team, 2019) and plotted over time. The decrease in equivalent diameter per sample is a measure for proceeding photogranulation (Procedure E). Text in green are comments from the authors, text in red require user input, text in blue show files that will be imported into R (Procedure E).

  1. Experimental conditions
    1. Create a text file (experimental_conditions.txt) containing the vial positions and their respective experimental conditions in three columns, i.e., Location, ExpCondition, ExpID. You can find an example of this file at https://doi.org/10.5281/zenodo.3938457.

  2. Extract acquisition date/ time and remove scan resolution
    1. The Exchangeable Image File (EXIF) data of the scanner images contains the filename and the creation date of the image. Both need to be available in a separate file for subsequent plotting of the data. You can automatically extract filename (e.g., 2018-03-14-01.tif) and creation date/ time (e.g., 2018:03:14 16:47:36) from EXIF data using the R script below. 
    2. The EXIF data may also contain the scan resolution. This resolution in dpi interferes with the particle size quantification using ImageJ. Remove scan resolution from EXIF data running ExifTool from within R so that ImageJ does not use dpi as a scaling factor. You can later assign a measurement unit to the images in ImageJ.
      1. Install ExifTool.
      2. Open a new R script in an R editor, for example RStudio, by clicking on ‘file’, ‘new file’, ‘R script’.
      3. Copy the following script into the source window. Text in red require user input and adaptations.

      ##Packages --------------------------------------
      require(exiftoolr) #(O’Brien, 2020)

      ##Working directory --------------------------------------
      rm(list=ls())
      directory <- ("/path-to-directory/")
      setwd(directory)

      ##Extract acquisition date/ time and remove scan resolution --------------------------------------
      image.vec <- list.files(directory, pattern = ".tif") #Generates a list of all *.tif files in the directory
      exif.images <- exif_read(path = image.vec) #Reads the EXIF data from the specified *.tif images
      image.data <- cbind(exif.images$FileName, exif.images$CreateDate)
      colnames(image.data) <- c("Name", "DateTime")
      write.csv(image.data, file = "image_acquisition.csv", quote = F, row.names = F) #Writes the tags file name and creation date to a separate file to be used later. You can find an example of this file at https://doi.org/10.5281/zenodo.3938457.
      exiftool_cmd <- paste("exiftool -ResolutionUnit= -XResolution= -YResolution= ", "*.tif",sep='') #Defines the ExifTool command to erase the Resolution data in the EXIF data of all images with the *.tif extension
      system(exiftool_cmd) #Executes ExifTool from within R. You can also run ExifTool outside R. Original scanner images are automatically saved as *.tif_original by ExifTool. Created images without scan resolution (*.tif) will be used for subsequent data analysis in this protocol.


The method presented below shows an example of how to define and measure regions of interest. ImageJ macros are adapted from Irvine-Fynn et al. (2010) who quantified granule geometry of cryoconite, microbial aggregates that share similarities with OPGs, under laboratory conditions. Extracting information from experimental time-lapse images is a means to an end and not the main interest of this protocol. Other methods may be used equally well to obtain particle characteristics, including area and X-, Y-coordinates.

  1. Marker image
    1. Here we convert the background image (Figure 5A) into a marker image (Figure 5B). The marker image will be used to determine the X-, Y-coordinates of areas that could possibly contain particles, i.e., the circles that vials occupy. These data are used to assign measured particle characteristics to unique samples and their respective experimental conditions (Procedure E).
      1. Open an empty macro in ImageJ by clicking on ‘plugins’, ‘new’, ‘macro’.
      2. Copy the following script into the macro.txt window.

        jobdirectory = getDirectory("Please choose a directory for saving result files and the marker image.");
        waitForUser("Please open the background image. Then click ok.");
        backgroundimage = getTitle();
        run("Split Channels");
        selectImage(backgroundimage + " (red)");
        close();
        selectImage(backgroundimage + " (green)");
        close();
        selectImage(backgroundimage + " (blue)");
        //Converts RGB to grayscale image. Retains only the channel which presents most contrast between the areas on which vials are placed (white) and the grid (black).
        run("Invert");
        //Vial areas now appear black and the grid white.
        setAutoThreshold("Default");
        run("Threshold...");
        waitForUser("Please set the threshold manually. Then press OK.");
        setOption("BlackBackground", false);
        run("Convert to Mask");
        run("Close");
        //Creates binary image from grayscale image: choose and apply cut-off value to divide image into foreground, i.e., vial areas, and background, i.e., grid. This works well when the grid is darker than the biomass. Otherwise you will have to setOption (“Black background”, true).
        run("Fill Holes (Binary/Gray)");
        //Fills holes in areas occupied by vials to achieve a solid area (Legland et al., 2016).
        run("Morphological Filters", "operation=Opening element=Disk radius=10");
        //Removes isolated pixels and breaks connections between areas occupied by vials and the grid so that it becomes less likely that the grid is accidentally considered part of the vial area.
        run("Morphological Filters", "operation=Erosion element=Disk radius=35");
        //Decreases the size of detected particles to exclude areas that are not part of the biomass, e.g., a ring corresponding to a vial that connects the biomass to the grid, resulting in a larger biomass particle than it actually is.
        //Note: You may adjust the parameter disk radius depending on your images and experiment.
        saveAs("Tiff", jobdirectory + "marker.tif");
        run("Set Measurements...", "area centroid fit shape display redirect=None decimal=3");
        //Specifies which measurements are recorded.
        run("Analyze Particles...", " show=Overlay display exclude");
        //Generates a result table containing information about each particle in the image, including a running number to label detected particles (i.e., the area that a vial occupies), the particle area and the centroid X-, Y-coordinates of the particles (Figure 6). It furthermore overlays the particle labels with the marker image to visually relate the particle characteristics in the table to the detected particles on the image.
        saveAs("Results", jobdirectory + "results_marker.csv");
        //You can find an example of this file at https://doi.org/10.5281/zenodo.3938457.

      3. Run the macro by clicking on ‘macros’, ‘run macro’. During execution of the macro, manually select the output directory to save the created marker image and open the background image. You can use your own background image or run a demo with the image that can be downloaded from https://doi.org/10.5281/zenodo.3938457.
      4. Take a screenshot of the resulting marker image with particle labels overlaid that is not automatically saved running the macro (Figure 5B). We numbered vial locations 1 to 72 from top left to bottom right. The order in which ImageJ detected the areas occupied by vials on the marker image does not necessarily correspond to this numbering as the particle analyzer in ImageJ scans the image until it finds an edge of an object, which becomes particle 1 (see number 1 in Figure 5B), which in this case also corresponds to location 1 according to our numbering. In the R script (Procedure E1b), we use the screenshot to relate ImageJ particle numbers (lines in result table) to our vial locations.


        Figure 5. Marker image created from background image. Screenshots of A. the background image, that is converted into B. the marker image, here displayed with the particle label overlay. The images that are saved in the macro do not have the headers and overlay as displayed in this figure. Columns are indicated in blue and rows in green.


        Figure 6. Result table of marker image. Screenshot of the result table showing characteristics of the first 15 out of 72 particles of the marker. This is not the result table that is saved in the macro, which is a comma-separated value (csv) file.

  2. Experimental time-lapse images
    1. Here we convert scanner color images to black and white binary images, displaying biomass particles in black and the grid in white. Characteristics of each particle will be saved in a corresponding result table. The grid for positioning the vials will be automatically removed from the images. Possible erratic particles that are not part of the OPGs are equally removed during the process. The macro includes a manual thresholding step which is relatively time-consuming, but automatic thresholding may not always result in particles that reflect well the visual impression on the scanner images. In theory, we obtain 72 biomass particles per image for an incubation set of 72 vials. We acquired experimental images over a period of six weeks, resulting in 110 color images, each of a size of 182 MB. An image that is taken halfway through the experiment is shown as an example in Figure 7A.
      1. An image containing the background (i.e., areas that cannot possibly contain biomass, for example the grid) is required. This image needs to be a grayscale image in which the grid is white and the areas potentially containing particles during the experiment are black. In the simplest case, the image could be the marker image generated in Procedure C, or, for improved particle detection, a manually curated image based on either the background or an experimental image. During manual curation, the area available for photogranulation may be redrawn as disks with the inner diameter of the vials. A foreground limited to the potential areas where particles can be detected avoids artefacts interfering with image detection that can be caused by reflections of the vial walls or shadowing effects of the grid during scanning.
      2. Open an empty macro in ImageJ by clicking on ‘plugins’, ‘new’, ‘macro’.
      3. Copy the following script into the macro.txt window.

        setBatchMode(false);
        //Enters or remains in batch mode and hide active images during macro execution.
        function action(input, output, filename){
        open(input + filename);
        jobname = getTitle();
        jobnamemod = indexOf(jobname, ".");
        jobname = substring(jobname, 0, jobnamemod);
        //The file paths and filenames entered when starting the macro are converted to variables that become useable to the commands where they are used.
        run("Split Channels");
        selectImage(jobname + ".tif (blue)");
        close();
        selectImage(jobname + ".tif (green)");
        close();
        selectImage(jobname + ".tif (red)");
        red_image = getTitle();
        //Converts RGB to grayscale image. Retains only the channel which presents most contrast between the areas on which vials are placed (white) and the grid (black).
        open(path);
        //Opens the grid image (e.g., the marker image) selected in Procedure D1a using the file specified below.
        //Vial areas now appear blackish and the grid whitish.
        grid = getTitle();
        imageCalculator("Add create", red_image, grid);
        close("\\Others");
        //Making grid appear as true white so that it will be detected as background in the subsequent binarization step.
        run("Set Scale...", "distance=0 known=0 pixel=1 unit=pixel");
        //Removes spatial scale of active image so that measurement results (e.g., area measurements) have the unit pixel.
        run("Threshold...");
        waitForUser("Please set the threshold manually. Then press OK, or cancel to exit macro");
        setOption("BlackBackground", false);
        run("Convert to Mask");
        selectWindow("Threshold");
        run("Close");
        //Creates binary image from grayscale image: choose and apply cut-off value to divide image into foreground, i.e., vial areas, and background, i.e., grid. Define your own criteria and try to treat each image of your dataset in the same way.
        //Note: This can be tricky because we normally do not find a threshold that works ideally for every particle on an image. We recommend testing a small subset (e.g., first, middle and last images) to get an idea of what works well.
        run("Fill Holes (Binary/Gray)");
        //Fills holes in the areas occupied by vials to achieve a solid area (Legland et al., 2016).
        //Note: This may fill up entire vial area when a biomass particle is surrounded by a ring corresponding to a vial. If this happens, you can reduce the size of the respective particle on the marker image using for example image editor Gimp and run the macro again (see also Procedure D1a).
        run("Morphological Filters", "operation=Opening element=Disk radius=10");
        close("\\Others");
        //Removes isolated pixels and breaks connections between areas occupied by vials and the grid so that it becomes less likely that the grid is accidentally considered part of the vial area.
        mask_image = getTitle();
        //Created image becomes mask image.
        run("Morphological Filters", "operation=Erosion element=Disk radius=40");
        marker_image = getTitle();
        //Drastically decreases the size of detected particles on the mask image to create an image that will be used for morphological reconstruction.
        //Note: Images of small granules may be removed when the disk radius is too large, you may adjust the parameter disk radius depending on your images and experiment.

        print("The marker image name is " + marker_image);
        print("The mask image name is " + mask_image);
        //Prints active marker and mask images.
        run("Morphological Reconstruction", "marker=["+marker_image+"] mask=["+mask_image+"] type=[By Dilation] connectivity=4");
        //Keeps particles from the mask image that overlap with at least one pixel on the marker image and remove other pixels. This step assures that only particles are retained that overlap with vial areas and that possible erratic particles that are not part of OPGs are removed.
        run("Set Measurements...", "area centroid fit shape display redirect=None decimal=3");
        rename(jobname);
        //Specifies which measurements are recorded.
        run("Analyze Particles...", "size=0-Infinity circularity=0.00-1.00 show=[Overlay Outlines] display exclude");
        //Generates result table (see explanation at Procedure C).
        save(output + jobname + ".final.tif");
        close();
        saveAs("Results", output+ jobname + "_results.csv" );
        run("Clear Results");
        selectWindow("Log");
        run("Close All");
        }
        //Erases any previous measurement results.
        input = getDirectory("Choose an input directory with the raw images, please.");
        output = getDirectory("Choose an output directory for result images and tables, please.");
        waitForUser("Please open the grid image. Then click ok.");
        //Selects the grid image (e.g., the marker image) selected in Procedure D1a. This image allows the removal of the grid from the scanner images.
        grid = getTitle();
        dir = getDirectory("image");
        path = dir+grid;
        close();
        //Define input directory with experimental images and output directory to save created images. Open the grid image selected in Procedure D1a. In the chronology of the script, results from these commands will be displayed once when starting the macro.
        list = getFileList(input);
        for (i = 0; i < list.length; i++)
        action(input, output, list[i]);
        setBatchMode(false);
        //Definition of a loop structure that will execute the macro function as many times as there are images found in the input directory.

      4. Run the macro by clicking on ‘macros’, ‘run macro’. During execution of the macro, manually select the input directory with experimental images, output directory to save created images and open the grid image selected in Procedure D1a. You can use your own experimental images and grid image or run a demo with exemplary images that can be downloaded from https://doi.org/10.5281/zenodo.3938457. Actions are automatically repeated for all images in the input directory.
        Note: Make sure to not have unrelated files in the folder as otherwise ImageJ attempts to treat them as images.
      5. Manually check whether the particles on the obtained images (Figure 7B) correspond to what you visually detect on the raw images.
        Note: This sanity check is important because the automated analysis is supposed to mimic and automate the visual inspection but is not infallible. You can create a series of thumbnails by rescaling the original scanner images to a reduced size to browse more easily through the images.
      6. Concatenate (combine) result tables into one csv file to simplify the analysis.
        1. Open a new R script in an R editor, for example RStudio (R Core Team, 2019), by clicking on ‘file’, ‘new file’, ‘R script’.
        2. Copy the following script into the source window. Text in red require user input and adaptations.

          ##Packages --------------------------------------
          require(plyr) #(Wickham, 2011)
          require(readr) #(Wickham et al., 2018)

          ##Working directory --------------------------------------
          rm(list=ls())
          directory <- ("/path-to-directory/")
          setwd(directory)

          ##Concatenate result tables --------------------------------------
          results.df <- list.files(path = directory, pattern = "*.csv", full.names = T) #Generates a list of all *.csv files in the directory
          results.df <- ldply(results.df, read_csv) #Combines result tables of all images into a single data frame
          colnames(results.df)[1] <- "ObjNum" #Assigns name ObjNum to first column
          write.csv(results.df, file = "results_scanner_images.csv", quote = F, row.names = F) #Writes result tables of all images to a separate file to be used later. You can find an example of this file at https://doi.org/10.5281/zenodo.3938457.


        Figure 7. Result image created from scanner image. Screenshots of A. a scanner image taken halfway through the experiment, that is converted into B. the result image for which the particle characteristics are determined. The images show particles contracted to varying degrees for the two sludge sources. The images that are saved in the macro do not have the headers as displayed in this figure.

  3. Quantification of photogranulation
    1. The experimental results are now imported into the software environment R (R Core Team, 2019). The challenge is to automatically convert the particle characterizations done per image into one time series per vial. The steps of the R script are as follows:
      • Calculate average X-, Y-coordinates of vial areas identified on the marker image (Figure 5B);
      • Assign experimental time to all experimentally measured particles per image by adding a column with experimental time to the particle data obtained with ImageJ. This facilitates the plotting to temporal dynamics;
      • Identify particles from a vial at a specific physical location on each image using the X-, Y-coordinates of vial areas. Relate particles to their location by assigning a location number and match them to the appropriate experimental conditions;
      • Transform the detected surface area of particles into equivalent diameters;
      • Plot the average decrease in particle diameter per experimental condition over time.
      1. Open a new R script in an R editor, for example RStudio, by clicking on ‘file, ‘new file’, ‘R script’.
      2. Copy the following script into the source window. Text in red require user input and adaptations.

        ##Packages --------------------------------------
        require(plyr) #(Wickham, 2011)
        require(ggplot2) #(Wickham, 2016)

        ##Working directory --------------------------------------
        rm(list=ls())
        directory <- ("/path-to-directory/")
        setwd(directory)

        ##Start time --------------------------------------
        start.time <- c("2018:03:14 17:51:19")
        #Manually enter start date/ time of the first image of the experiment. Experimental time will be calculated based on this time point, using the acquisition time of the scanner images.

        ##Scaling factor --------------------------------------
        scaling.factor <- 475.417/1.5 #pixels/cm
        #Manually enter the scale of the images, i.e., number of pixels to cover the diameter of a vial. This value can be easily measured in ImageJ.

        ##Margin --------------------------------------
        margin.vial <- 212
        #Manually enter average number of pixels between the center and edges of a particle as measured in ImageJ, typically the inner radius of the vials in pixel.

        ##Files to be imported --------------------------------------
        #You can run a demo with the files presented at https://doi.org/10.5281/zenodo.3938457.
        coordinates.name <- "results_marker.csv" #Information about each particle on marker image (generated using ImageJ).
        raw.data.name <- "results_scanner_images.csv" #Joined result tables of scanner images (generated using ImageJ).
        acquisition.time.name <- "image_acquisition.csv" #Filename and creation date of scanner images (generated using ExifTool from within R).
        experimental.condition.name <- "experimental_conditions.txt" #Experimental conditions per sample (manually generated).

        ##Loading files --------------------------------------
        coordinates <- read.csv(coordinates.name, header=T, as.is =T)
        raw.data <- read.csv(raw.data.name, header = T, as.is = T)
        acquisition.time <- read.csv(acquisition.time.name, header = T, as.is = T)
        experimental.condition <- read.delim(experimental.condition.name, header = T, as.is = T)

        ####Calculate average X-, Y-coordinates of vial areas identified on the marker image (Figure 5B).

        ##Average X-, Y-coordinates of vial areas --------------------------------------
        column.1 <- c(1,14,27,40,53,66) #Manually enter which particle label on the marker screenshot corresponds to which column, as indicated in blue (Figure 5B). The grid consists of columns alternating in starting position and size, e.g., the first particle detected corresponds to the first particle in the first column of the scanner grid, the fourteenth particle detected is situated on the grid in column 1, row 3, etc.
        column.2 <- c(8,21,34,47,60)
        column.3 <- c(2,15,28,41,54,67)
        column.4 <- c(9,22,35,48,61)
        column.5 <- c(3,16,29,42,55,68)
        column.6 <- c(10,23,36,49,62)
        column.7 <- c(4,17,30,43,56,69)
        column.8 <- c(11,24,37,50,63)
        column.9 <- c(5,18,31,44,57,70)
        column.10 <- c(12,25,38,51,64)
        column.11 <- c(6,19,32,45,58,71)
        column.12 <- c(13,26,39,52,65)
        column.13 <- c(7,20,33,46,59,72)

        row.1 <- c(1,2,3,4,5,6,7) #Manually enter which particle label on the marker screenshot corresponds to which row, as indicated in green (Figure 5B). The grid consists of rows alternating in starting position and size, e.g., the first particle detected corresponds to the most left particle in the first row of the grid, etc.
        row.2 <- c(8,9,10,11,12,13)
        row.3 <- c(14,15,16,17,18,19,20)
        row.4 <- c(21,22,23,24,25,26)
        row.5 <- c(27,28,29,30,31,32,33)
        row.6 <- c(34,35,36,37,38,39)
        row.7 <- c(40,41,42,43,44,45,46)
        row.8 <- c(47,48,49,50,51,52)
        row.9 <- c(53,54,55,56,57,58,59)
        row.10 <- c(60,61,62,63,64,65)
        row.11 <- c(66,67,68,69,70,71,72)

        pos.names <- c(row.1, row.2, row.3, row.4, row.5, row.6, row.7, row.8, row.9, row.10, row.11)
        #Order of particle numbers from top left to bottom right.

        average.x.1 <- mean(coordinates$X[coordinates$X.1 %in% column.1])
        average.x.2 <- mean(coordinates$X[coordinates$X.1 %in% column.2])
        average.x.3 <- mean(coordinates$X[coordinates$X.1 %in% column.3])
        average.x.4 <- mean(coordinates$X[coordinates$X.1 %in% column.4])
        average.x.5 <- mean(coordinates$X[coordinates$X.1 %in% column.5])
        average.x.6 <- mean(coordinates$X[coordinates$X.1 %in% column.6])
        average.x.7 <- mean(coordinates$X[coordinates$X.1 %in% column.7])
        average.x.8 <- mean(coordinates$X[coordinates$X.1 %in% column.8])
        average.x.9 <- mean(coordinates$X[coordinates$X.1 %in% column.9])
        average.x.10 <- mean(coordinates$X[coordinates$X.1 %in% column.10])
        average.x.11 <- mean(coordinates$X[coordinates$X.1 %in% column.11])
        average.x.12 <- mean(coordinates$X[coordinates$X.1 %in% column.12])
        average.x.13 <- mean(coordinates$X[coordinates$X.1 %in% column.13])
        #Calculates average X-coordinates.

        average.y.1 <- mean(coordinates$Y[coordinates$X.1 %in% row.1])
        average.y.2 <- mean(coordinates$Y[coordinates$X.1 %in% row.2])
        average.y.3 <- mean(coordinates$Y[coordinates$X.1 %in% row.3])
        average.y.4 <- mean(coordinates$Y[coordinates$X.1 %in% row.4])
        average.y.5 <- mean(coordinates$Y[coordinates$X.1 %in% row.5])
        average.y.6 <- mean(coordinates$Y[coordinates$X.1 %in% row.6])
        average.y.7 <- mean(coordinates$Y[coordinates$X.1 %in% row.7])
        average.y.8 <- mean(coordinates$Y[coordinates$X.1 %in% row.8])
        average.y.9 <- mean(coordinates$Y[coordinates$X.1 %in% row.9])
        average.y.10 <- mean(coordinates$Y[coordinates$X.1 %in% row.10])
        average.y.11 <- mean(coordinates$Y[coordinates$X.1 %in% row.11])
        #Calculates average Y-coordinates.

        average.x.a <-c(average.x.1, average.x.3, average.x.5, average.x.7, average.x.9, average.x.11, average.x.13)
        average.x.b <- c(average.x.2, average.x.4, average.x.6, average.x.8, average.x.10, average.x.12)
        #Calculates average Y-coordinates of rows having the same X-coordinate.
        average.y.a <- c(average.y.1, average.y.3, average.y.5, average.y.7, average.y.9, average.y.11)
        average.y.b <- c(average.y.2, average.y.4, average.y.6, average.y.8, average.y.10)
        #Calculates average X-coordinates of rows having the same Y-coordinate.
        first.half <- expand.grid(average.x.a, average.y.a)
        second.half <- expand.grid(average.x.b, average.y.b)
        #Couples X-, Y-coordinates for both a and b.
        average.coordinates <- rbind(first.half, second.half)
        colnames(average.coordinates) <- c("X","Y")
        #Combines first.half and second.half by rows.
        average.coordinates <- average.coordinates[order(average.coordinates$Y, average.coordinates$X),]
        #Arranges coordinates to be in the same order as the particle numbers that can be found on the marker screenshot.
        average.coordinates <- cbind(average.coordinates, pos.names, 1:72)
        colnames(average.coordinates) <- c("X","Y", "ParticleLabel", "Location")
        #Adds columns with order of particles numbers that can be found on the marker screenshot and experimental vial locations (1 to 72 from top left to bottom right).

        ####Assign experimental time to all experimentally measured particles per image by adding a column with experimental time to the particle data obtained with ImageJ. This facilitates the plotting to temporal dynamics.

        ##Experimental time --------------------------------------
        start.time <- strptime(start.time, "%Y:%m:%d %H:%M:%S")
        #Converts start time to date/ time representation.
        date.time <- strptime(acquisition.time$DateTime, "%Y:%m:%d %H:%M:%S")
        #Acquires acquisition time per image and converts it to a date/ time representation.
        exp.time <- round(-1*(as.numeric(start.time - date.time, units="hours")),3)
        #Converts date/ time to experimental time.
        acquisition.time <- cbind(acquisition.time, exp.time)
        #Adds experimental time to acquisition time file.
        colnames(acquisition.time) <- c("Name", "Date", "ExpTime")
        acquisition.time$Name <- gsub(".tif", "", acquisition.time$Name)
        #Removes *.tif from file names.
        unique.images <- unique(raw.data$Label)
        #Checks number of unique images.
        ExpTime.vec <- rep(0, nrow(raw.data))
        #Creates vector with as many zeros as there are rows in the raw data file (equals number of particles per image times number of images).
        for(i in 1:length(unique.images))
        {time.i <- acquisition.time$ExpTime[which(acquisition.time$Name == unique.images[i])]
        indices.1 <- which(raw.data$Label == unique.images[i])
        ExpTime.vec[indices.1] <- time.i}
        raw.data <- cbind(raw.data, ExpTime.vec, rep(NA, nrow(raw.data)), rep(NA,
        nrow(raw.data)), rep(NA, nrow(raw.data)))
        colnames(raw.data)[(ncol(raw.data)-3):ncol(raw.data)] <- c("ExpTime", "Location",
        "ExpCondition", "ExpID")
        raw.data <- raw.data[order(raw.data$ExpTime),]
        #Loops over number of scanner images (i.e., 110 images), gives experimental time of image in acquisition.time file that corresponds to image i. Gives rows that correspond to image raw.data file that corresponds to image i (each image typically has 72 particles). Replaces zeros in vector belonging to these rows by experimental time belonging to image i.

        ####Identify particles from a vial at a specific physical location on each image using the X-, Y-coordinates of vial areas. Relate particles to their location by assigning a location number and match them to the appropriate experimental conditions.

        ##Identify particles per location and add experimental conditions --------------------------------------
        for(j in 1:nrow(average.coordinates) ){indices.2 <- which(
        sqrt(((raw.data$X- average.coordinates$X[j])^2) + ((raw.data$Y-average.coordinates$Y[j])^2)) < margin.vial)
        if(length(indices.2) == length(unique.images)){print(paste(c("All looks fine for Location ", j, "."), sep = "", collapse = ""))}else{print(paste(c("Warning: there is an issue for Location ", j, "."), sep = "", collapse = ""))}
        #If there is an issue for Location j, go manually through the images and make sure the issue is corrected. It may happen that a particle was not detected on all images, e.g., because it started to float, or more than one particle has been detected in the same well on one image, e.g., because there was a small piece of loose biomass. In the latter case, you can manually remove the data from the erroneous particle that is not a granule from the dataset.
        raw.data$Location[indices.2] <- average.coordinates$Location[j]
        indices.1 <- which(experimental.condition$Location == average.coordinates$Location[j])
        raw.data$Location[indices.2] <- experimental.condition$Location[indices.1]
        raw.data$ExpCondition[indices.2] <- experimental.condition$ExpCondition[indices.1]
        raw.data$ExpID[indices.2] <- experimental.condition$ExpID[indices.1]}
        if (length(which(raw.data$Location == 0)) == 0) {print("No 0s left and all coordinates are assigned a location")} else {"Watch out! There are unidentified particles left in the data."}
        #Loops over number of rows in average.coordinates file (i.e., 72 rows for 72 particles). Returns the particle that falls within the X- , Y-coordinates for a specific position, i.e., 110 particles for each location because there are 110 images. Note: small and not-centered particles may not be detected. Relates the location number (i.e., 1 to 72) to the X, Y position so that the particle has the same label on every image. Couples experimental conditions to locations.

        ####Transform the detected surface area of particles into equivalent diameters.

        ##Calculation of equivalent diameter from area --------------------------------------
        raw.data <- cbind(raw.data, 2*sqrt(raw.data$Area/pi), rep(NA, nrow(raw.data)))
        colnames(raw.data)[(ncol(raw.data)-1):ncol(raw.data)] <- c("EquivDiam_pix",
        "EquivDiam_cm")
        #Calculates diameter of particle area assuming that it represents a circle.
        raw.data$EquivDiam_cm <- raw.data$EquivDiam_pix/scaling.factor
        #Converts pixels to centimeters.

        ####Plot the average decrease in particle diameter per experimental condition over time.

        ##Plot diameter over experimental time per experimental condition --------------------------------------
        treated.final.data <- ddply(raw.data, c("ExpTime", "ExpID"), summarise,
        average.diameter = mean(EquivDiam_cm), sd.diameter = sd(EquivDiam_cm),sem.diameter= sd(EquivDiam_cm)/sqrt(length(EquivDiam_cm)))

        treated.final.data$ExpID <- as.character(treated.final.data$ExpID)
        average.diameter <- treated.final.data$ average.diameter
        sd <- treated.final.data$sd.diameter

        p <- ggplot(treated.final.data, mapping = aes(x=ExpTime, y= average.diameter, shape=ExpID, color=ExpID))
        p <- p + geom_point()
        p <- p + scale_shape_discrete(name = "ExpID", breaks=c("1", "2"), labels=c("sludge1", "sludge2"))
        p <- p + scale_color_discrete(name = "ExpID", breaks=c("1", "2"), labels=c("sludge1", "sludge2"))
        p <- p + geom_errorbar(aes(ymin= average.diameter-sd, ymax= average.diameter+sd))
        p <- p + labs(x = "Experimental time [h]", y = "Biomass diameter [cm]")
        p #This is Figure 8.

      3. You can use your own generated files or you can run a demo with the files presented at https://doi.org/10.5281/zenodo.3938457.
      4. Run the script by clicking on ‘Run’.
      5. Verify whether the generated plot (Figure 8) matches with what you would expect based on the experimental time-lapse images.


        Figure 8. Progression of photogranulation shown as biomass contraction, i.e., decrease in diameter. Hydrotatic batch cultivations were started with two different sludge sources, each containing 36 replicates. Error bars present standard deviations.

    Progression of photogranulation as quantified by biomass contraction, i.e., the decrease in diameter over time, is presented in Figure 8 for two different sludge sources. Initially, the sludge bed covers the entire bottom and corresponds to the inner diameter of the vial, i.e., 1.27 cm. During successful photogranulation, a final diameter of about half the initial value or less can be expected. Here the biomass did not granulate well in all 36 replicates per sludge source, and the formation of microbial mats was observed. This large variation in degree of contraction, i.e., the formation of two very different phenotypes, is reflected by the large standard deviations around the average diameters. Despite this heterogeneity, sludge source 2 resulted in more compact OPGs with a smaller average diameter than sludge source 1. Data was not obtained between 354 and 472 hours due to a technical issue.

  4. Data exclusion
    1. Failed experiments (e.g., overgrown vial bottoms, floating biomass, tipped vials) can be excluded manually from the analysis by removing the corresponding lines in the raw data or using a file specifying data points to be removed within the script (not described here).

  5. Statistical analysis 
    1. Standard deviations around the average diameters of replicates are caculated at the end of the R script in Step E1b.

Notes

The biological phenomenon of photogranulation is not always reproducible: success rates greatly vary and may depend on the inoculum (i.e., the activated sludge) or experimental conditions, e.g., temperature, light intensity or light quality. This variability is subject of ongoing research using this protocol.

Acknowledgments

This work was funded by Graduate School GAIA of Montpellier University of Excellence (100% PhD fellowship for Esmee Joosten) and the ANR project PSST ANR- 16-CE04-0001.
  Production of OPGs under hydrostatic batch conditions was earlier presented by Park & Dolan (2015) and Milferstedt et al. (2017).

Competing interests

The authors declare not to have any (non-)financial competing interests.

References

  1. Abouhend, A. S., McNair, A., Kuo-Dahab, W. C., Watt, C., Butler, C. S., Milferstedt, K., Hamelin, J., Seo, J., Gikonyo, G. J., El-Moselhy, K. M. and Park, C. (2018). The oxygenic photogranule process for aeration-free wastewater treatment. Environ Sci Technol 52(6): 3503-3511.
  2. Irvine-Fynn, T. D. L., Bridge, J. W. and Hodson, A. J. (2010). Rapid quantification of cryoconite: granule geometry and in situ supraglacial extents, using examples from Svalbard and Greenland. J Glaciol 56(196): 297-308.
  3. Legland, D., Arganda-Carreras, I. and Andrey, P. (2016). MorphoLibJ: Integrated library and plugins for mathematical morphology with ImageJ. Bioinformatics 32(22): btw413.
  4. Milferstedt, K., Kuo-Dahab, W. C., Butler, C. S., Hamelin, J., Abouhend, A. S., Stauch-White, K., McNair, A., Watt, C., Carbajal-González, B. I., Dolan, S. and Park, C. (2017). The importance of filamentous cyanobacteria in the development of oxygenic photogranules. Sci Rep 7(1): 17944.
  5. O’Brien, J. (2020). exiftoolr: ExifTool Functionality from R. https://cran.r-project.org/package=exiftoolr
  6. Park, C. and Dolan, S. (2015). Algal-sludge granule for wastewater treatment and bioenergy feedstock generation. Pat Appl WO 2015112654 A2, Appl. number PCT/US2015/012332.
  7. Quijano, G., Arcila, J. S. and Buitrón, G. (2017). Microalgal-bacterial aggregates: Applications and perspectives for wastewater treatment. Biotechnol Adv 35(6): 772-781.
  8. R Core Team (2019). R: A language and environment for statistical computing. R Found. Stat. Comput. Vienna, Austria.
  9. Schneider, C. A., Rasband, W. S. and Eliceiri, K. W. (2012). ImageJ. Fundam Digit Imaging Med 9(7): 185-188.
  10. Wickham, H. (2016). ggplot2: Elegant Graphics for Data Analysis. Springer-Verlag New York.
  11. Wickham, H. (2011). The split-apply-combine strategy for data analysis. J Stat Software 40(1): 1-29.
  12. Wickham, H., Hester, J., Francois, R. (2018) readr: Read Rectangular Text Data. https://cran.r-project.org/package=readr

简介

[摘要]氧气颗粒(OPG)是致密的三维聚集体,包含一个光合的营养菌,由微生物驱动。他们的时间和空间发展引起了微生物生态学家在生物过程工程界面上的兴趣,因为这些知识可用于优化生物技术应用,例如废水处理和生物质平衡。此处介绍的方法可实现光颗粒化的高通量定量。OPGs是从松散污泥状微生物矩阵产生水电静态分批培养暴露于光下。随着时间的推移,此矩阵将转换为合并的大致球形的聚合体。光粒化通过延时成像与自动图像分析相结合进行量化。这允许以全自动方式同时研究许多OPG的开发,以系统地测试哪些因素驱动了光颗粒化。该协议还可用于量化其他类型的(a)生物聚集。


[背景] OPG是致密的,大致球形的聚集体,直径为几毫米,包含异养和光养微生物的共生群落(Milferstedt等人,2017)。微生物生态学家研究光粒化以了解哪些因素驱动了三维(3D)结构的形成。这种知识可以被施加到转向生态系统功能向期望的功能,用于生物技术工艺,例如作为污水处理和生产增值产品(Abouhend等人,2018;基哈诺等人,2017) 。OPG可以由类似污泥的微生物基质生产,即废水处理厂曝气池中的活性污泥(Milferstedt等人,2017; Park and Dolan,2015)。该污泥的转化发生在暴露于光下的封闭,未搅动的小瓶中。在数周的过程中,污泥床会压缩(即减小高度)并收缩(即减小直径),并转换为一个合并的3D /小瓶聚集体(图1A)。通过预先设定的时间间隔(图1 B)通过多次重复从小瓶底部自动获取实验图像。图像在ImageJ中处理(Schneider等,2012),扩展了为量化天然存在的OPG而开发的宏,称为冰晶石颗粒(Irvine-Fynn等,2010)。在软件环境R (R Core Team,2019)中计算并绘制生物质收缩的动力学。该协议可以进行大量重复的光粒化测试,例如,使用不同的污泥源或环境条件来促进对光粒化的理解。该协议还可用于量化其他类型的(a)生物聚集。

图1 。光粒化的典型过程,包括压实和收缩。请注意,显示的图像仅用于说明目的,并非通过此处介绍的协议获得。A.在外径为24 mm的10 ml血清瓶中,松散的活性污泥转化为固结OPG的时间进程(改编自Milferstedt等人,2017年)。箭头表示压实和收缩。B.通过外径为16mm的24孔微板的一个孔的底部看到的生物质收缩的时间进程。

关键字:含氧感光颗粒, 微生物席, 生物膜, 聚合, 空间化, 光粒化, 动力学, 时差成像技术

材料和试剂
 
1.来自废水处理厂曝气池的新鲜活性污泥      
2. 0.5-5毫升带吸头的吸管(Thermo Fisher Scientific,Finnpipette TM F1,目录号:4641110N; 5毫升Finntip TM ,目录号:9402030)      
3.网格,用于在扫描仪表面上对齐和隔开样品瓶。定制的深灰色金属网格尺寸为30.4×22.2 ×0.2厘米(长×宽×厚)(图2 A-2B)      
网格应足够低,以使它不会从侧面遮挡生物质,例如,网格不应高出样品瓶底部的厚度(图3 A-3B)。可以使用计算机数控(CNC)金属铣削或3D打印来生产所需的小瓶放置位置。您也可以使用其他材料(例如纸)制作网格。
4.不透光的盒子,用于覆盖样品瓶和光源之间的距离,以防止光线损失和照明失控。的65×35×65的近似尺寸的自制纸板盒厘米(大号×W×H ),包围扫描仪和照明装置。    ;

图2 。格。A.网格设计;B.定制的深灰色金属网格位于扫描仪顶部。
 
设备
 
1 L宽口防摔瓶,用于采样(Fisher Scientific,Gosselin,货号:1 1728643)
2升用于混合的聚丙烯烧杯(Thermo Fisher Scientific,Nalgene,目录号:1201-2000)
4毫升尺寸为15毫米×45毫米×8毫米(外径×高度×内径)的透明玻璃小瓶,带螺旋盖,用于培养(Sigma-Aldrich,Supelco ,目录号:27111)(图3 A)
底部的光滑,平整对于该实验的成功至关重要(图3 C)。我们在这里使用玻璃小瓶,并且在以前成功使用了聚苯乙烯小瓶。
与生物质形成对比颜色的旋盖用于图像处理(Agilent Technologies,目录号:5183-4305)
磁力搅拌器和搅拌棒(Bioblock Scientific,AM AMC BBS 3000)均质化活性污泥,从而使样品瓶之间的样品成分差异最小化
用于安装光源的固定装置,例如带摄像机臂的复印架(Kaiser,RS1,RA1,目录号:205510)
平面光源,例如,发光二极管(LED)面板测量59.5 ×59.5 (裁剪〜30)×1.06厘米(大号×W×H )(再XEL,LEDVANCE,面板LED 600,40W,6500K,4000流明,目录编号:4058075000582)
我们使用冷白光(6 ,500 K)用于本实验中,但其它的光的温度也被成功测试(例如,5 ,600 6和,000 K)
光敏合成辐射(PAR)量子光传感器和显示仪表系统(Skye Instruments Ltd,SKP 215 / S 39520,SKP 200 39521)
桌面扫描仪(Epson,Perfection V500 Photo,型号:J251A)


图3 。小瓶。A.带螺帽的玻璃小瓶;小瓶底部厚度;C.透明,光滑且平坦的样品瓶底部。
 
软件
 
扫描仪驱动程序允许时间推移采集使用的是台式扫描仪图像,例如,VueScan的版本51年9月5日(哈姆里克软件,https://www.hamrick.com/)
工具来读,在图像的批次写和编辑元数据信息例如,ExifTool版本11.78 (菲尔·哈维,https://exiftool.org/)
ImageJ的版本1.52a(图像处理程序)(国家Insitutes卫生研究院(NIH)的https://imagej.nih.gov/ij/)(施耐德等,2012)
I mageJ版本1.4.0的MorphoLibJ插件(数学形态学方法和插件的集合)(INRA-IJPB建模和数字成像实验室,https://imagej.net/MorphoLibJ )(Legland等,2016)。
R版本3.6.0(用于统计计算和图形的软件环境)(R核心团队,https://www.r-project.org/)(R核心团队,2019)
exiftoolr软件包0.1.3版(O'Brien,2020)
ggplot2软件包版本3.2.0 (Wickham,2016)
plyr软件包版本1.8.4 (Wickham,2011)
阅读器软件包1.3.1版(Wickham等,2018)
 
程序
 
下面的步骤描述在生产OPGs的水力静态分批培养和自动时间推移采集试验图像。图像分析在“数据分析”中进行。
 
扫描仪设置(图4 A-4B)
扫描仪连接至计算机并安装扫描仪驱动程序,例如,VueScan的。
设置扫描仪设置并保存程序。
24位RGB图像。
每英寸800点(dpi)的分辨率,像素大小为32 µm。此分辨率足以解决生物过程并防止生成过大的文件。
确保没有自动色彩校正,因为这会使后续的数据分析复杂化。
选择未压缩的标签图像文件格式(TIFF)以保存图像。
分配TIFF文件名,例如YY-MM-DD_01 + .tif和目录以保存获取的扫描。
设置采集间隔。八个小时足以捕获光颗粒化的动力学。的间隔可以增加作为所述实验的进行。
用网格顶部的纯白纸拍摄扫描仪图像。这将是数据分析的背景图像(图5 A)。
 


图4 。实验装置。A.光源和扫描仪的设置(注吨他纸板盒中未示出); B.将样品瓶放在网格上的扫描仪设置特写。
 
光源设置(图4 A-4B)
安装的平坦光源的上述扫描仪,优选地使用装置,其允许调整之间的距离的通过将其连接到一个拷贝支架的照相机臂光源和小瓶,例如。灵活的距离使调节小瓶接收到的光强度成为可能,并允许轻松放置和取出小瓶。
光强度通常不会均匀分布在LED面板上。为了确保了解局部光照条件,您可以在扫描仪表面上的不同点绘制局部PAR,绘制等高线图,并确定将小瓶放在何处,例如,沿类似光强度的轮廓线放置。您可以设计一个带有圆圈的网格,以指示小瓶的放置位置(图2 A)。您可以将网格打印在纸上,切出圆圈,然后将其放在台式扫描仪上以放置小瓶。如果要定期使用网格,则可以使用CNC金属铣削或3D打印由更坚固的材料(例如金属(图2 B))制成。
调整样品瓶和光源之间的距离,以使样品瓶位置的光强度约等于60 µmol·m 2 ·s -1 PAR。可以使用PAR量子光传感器进行测量。
 
活性污泥采样和表征
从废水处理厂的曝气池中取样200毫升活性污泥。该体积是对于使用72小瓶用1.5M接种实验很大程度上足够升活性污泥中的每个,如在下文中描述。牛逼以适应他的样品量的需求,如果你有兴趣的表征活性污泥,如,总和挥发性固体,化学需氧量,nitrog恩,磷,PH,叶绿素,微生物群落。
它是有益的 可以测量总固体。这可用于将污泥浓度调整为实验之间可比较的值。我们通常以4至5 g / L的活性污泥浓度进行实验。
 
样品瓶准备和放置
到达实验室后,使活性污泥保持悬浮状态,例如,使用磁力搅拌器。
注意:无法直接使用的污泥可以在4°C下存储,但我们建议使用新鲜的活性污泥。
吸取1.5 ml混合均匀的活性污泥到4 ml小瓶中。用螺帽封闭小瓶。我们的典型孵育套件包含72个样品瓶。
将未搅动的样品瓶放置在台式扫描仪顶部指定的区域,并在环境温度(22-26°C)下持续光照下(图4 A-4B)。
在扫描仪和光源周围放置一个不透光的盒子,以限制光的损失和样品的不受控制的照明。
 
样品瓶孵育和延时成像
启动扫描仪软件,以所需的时间间隔拍摄样品瓶底部的图像。确保扫描仪在时间0拍摄图像并且以指定的间隔拍摄图像。
未合并的污泥每个小瓶会转化为一个OPG,通常位于小瓶的底部,除非它由于附着的气泡而开始漂浮。运行实验,直到形成成熟的OPG。成熟的OPG大致呈球形,剧烈摇动后仍保持其形状。在给定的实验条件下,可以预期在三到六周内发生光粒化。实验条件下,例如,光强度和污泥特性,可能会影响所需要的时间photogranulation 。
从扫描仪中取出小瓶之前,请进行最终扫描。
 
光粒化成功
记下OPG是坐在底部还是漂浮在底部以进行图像分析。
拍摄OPG的相机图像,以便以后记住它们的外观。
剧烈摇动小瓶,并记下在其中成功形成OPG的小瓶。光粒化成功是指成功孵育的小瓶中OPG的百分比。
根据您感兴趣的因素(例如,理化参数,微生物群落)对OPG进行表征。
 
数据分析
 
对于数据分析,我们显示了使用两个污泥源对72个容量为4 ml的小瓶进行实验的结果,因此每个条件下可重复36次。创建一些文件作为自动数据处理的准备(过程A - B )。实验延时图像在ImageJ中处理(Schneider等,2012),使用粒度分析来测量包括表面积在内的颗粒特征(程序C - D )。随后在软件环境R中将表面积转换为等效直径(R Core Team,2019),并随时间进行绘制。在每个样品等效直径的减小是用于程序的量度photogranulation (程序ë )。绿色文本是作者的评论,红色文本需要用户输入,蓝色显示文件的文本将被导入R(过程E )。
 
实验条件
创建一个文本文件(experimental_conditions.txt ),该文件在三列(即位置,ExpCondition,ExpID )中包含样品瓶位置及其各自的实验条件。您可以在https://doi.org/10.5281/zenodo.3938457上找到此文件的示例。
 
提取采集日期/时间并删除扫描分辨率
扫描仪图像的可交换图像文件(EXIF)数据包含图像的文件名和创建日期。两者都需要在单独的文件中可用,以用于后续数据绘制。您可以使用以下R脚本从EXIF数据中自动提取文件名(例如2018-03-14-01.tif)和创建日期/时间(例如2018:03:14 16:47:36)。
EXIF数据也可能包含扫描分辨率。以dpi为单位的分辨率会干扰使用ImageJ进行的粒度定量。从R中从运行ExifTool的EXIF数据中删除扫描分辨率,以使ImageJ不使用dpi作为缩放因子。您以后可以在ImageJ中为图像分配度量单位。
安装ExifTool
通过单击“文件”,“新文件”,“ R脚本”,在R编辑器(例如RStudio)中打开新的R脚本。
将以下脚本复制到源代码窗口中。红色文本需要用户输入和修改。
 
## Packages --------------------------------------
require(exiftoolr )#(奥布莱恩,2020)
 
##工作目录--------------------------------------
rm(列表= ls())
目录<-(“ /目录路径/ ”)
setwd (目录)
 
##提取采集日期/时间并删除扫描分辨率--------------------------------------
image.vec < -list.files (目录,模式=“。tif ”)#生成所有*的列表。目录中的tif文件
exif.images < - exif_read (路径= image.vec )#Reads从指定* EXIF数据。tif图片
image.data < -cbind (exif.images $ FileName ,exif.images $ CreateDate )
列名(image.data )<- c(“ Name”,“ DateTime ”)
write.csv(image.data ,file =“ image_acquisition.csv ”,quote = F,row.names = F)#将标签的文件名和创建日期写入一个单独的文件中,以备后用。您可以在https://doi.org/10.5281/zenodo.3938457上找到此文件的示例。
exiftool_cmd < -粘贴( “ exiftool - ResolutionUnit = - XResolution = - YResolution =”, “* TIF ”,月= '') #定义的ExifTool命令以擦除带有*的所有图像的EXIF数据的分辨率的数据。tif扩展
系统(exiftool_cmd )#Executes ExifTool从内R.你也可以运行ExifTool R.原始图像扫描仪外自动保存为*。tif_original由ExifTool提供。创建的没有扫描分辨率(* 。tif )的图像将用于此协议中的后续数据分析。
 
下面介绍的方法显示了如何定义和测量关注区域的示例。ImageJ宏改编自Irvine-Fynn等人。(2010年),他们量化了在实验室条件下,低温凝胶的颗粒几何形状,即与OPG相似的微生物聚集体。从实验延时图像中提取信息是达到目的的一种手段,而不是该协议的主要目的。同样可以很好地使用其他方法来获得粒子特征,包括面积和X,Y坐标。
 
标记图片
在这里,我们将背景图像(图5 A)转换为标记图像(图5 B)。标记图像将被用于确定X轴,Y COO的那些可能含有颗粒,区域rdinates即,圆圈该小瓶占据。这些数据用于将测得的颗粒特征分配给唯一的样品及其各自的实验条件(过程E )。
通过单击“插件”,“新”,“宏”在ImageJ中打开一个空宏。
将以下脚本复制到macro.txt窗口中。
 
jobdirectory = getDirectory (“请选择用于保存结果文件和标记图像的目录。”);
waitForUser (“请打开背景图像。然后单击确定。”);
backgroundimage = getTitle ();
运行(“分割通道”);
selectImage (backgroundimage +“(红色)”);
close();
selectImage (backgroundimage +“(绿色)”);
close();
selectImage (backgroundimage +“(blue)”);
//将s RGB转换为灰度图像。保留小号仅呈现在其上小瓶置于(白色)的区域之间的对比度最通道和电网(黑色)。
run(“ Invert”);
//小样区域现在显示为黑色,网格显示为白色。
setAutoThreshold (“默认”);
运行(“阈值...”);
waitForUser (“请手动设置阈值。然后按OK。”);
setOption (“ BlackBackground ”,false);
运行(“转换为蒙版”);
run(“ Close”);
//创建小号从灰度图像二值图像:选择和应用截止值来划分图像为前景,即,小瓶领域和背景,即,电网。当网格比生物质暗时,这种方法效果很好。否则,您将必须设置setOption (“黑色背景”,是)。
运行(“填充孔(二进制/灰色)”);
//填充小号领域孔所占的小瓶,以实现固体区域(Legland等人,2016) 。
运行(“形态过滤器”,“操作=打开元素=磁盘半径= 10”);
//删除小号隔离像素和断裂小号区之间的连接所占据由小瓶和网格,以便它变得不太可能,网格被意外认为小瓶区域的一部分。
运行(“形态过滤器”,“操作=侵蚀元素=磁盘半径= 35”);
              //减少š检测到的颗粒的大小以排除区域不生物质的一部分,例如,相应于生物质连接到电网,从而导致更大的生物质颗粒比它实际上是一个小瓶中的环。 
              //注意:您可以根据图像和实验来调整参数磁盘半径。
saveAs (“ Tiff”,作业目录+“ marker.tif ”);
                            run(“ Set Measurements ...”,“区域形心拟合形状显示重定向=无小数= 3”);
//特异性IES其中记录测量结果。
运行(“分析粒子...”,“显示=覆盖显示排除”);
//生成小号关于图像中的每个粒子含有结果表的信息,包括一个运行编号,以标记进行检测的粒子(即,该小瓶占据的面积),则颗粒面积和质心X-,颗粒的Y坐标(图6 )。此外,它还用标记图像覆盖了粒子标签,以可视地将表格中的粒子特性与图像上检测到的粒子相关联。
的saveAs (“结果”,jobdirectory + “ results_marker.csv ”);
//您可以在https://doi.org/10.5281/zenodo.3938457上找到此文件的示例。
 
通过单击“宏”,“运行宏”来运行宏。在执行宏的过程中,手动选择输出目录以保存创建的标记图像并打开背景图像。您可以使用自己的背景图像或使用可从https://doi.org/10.5281/zenodo.3938457下载的图像进行演示。
拍摄结果标记图像的屏幕截图,该图像带有叠加的粒子标签,运行宏不会自动保存该图像(图5 B)。我们从左上角到右下角编号了小瓶位置1到72。其中ImageJ的检测出的区域所占据由小瓶标记图像上不一定对应于该编号作为ImageJ中的粒子分析仪的顺序扫描图像直到它找到一个对象,这成为颗粒1的边缘(见编号1图5 B),在这种情况下,根据我们的编号,它也对应于位置1。在R脚本(过程E 1 b )中,使用屏幕截图将ImageJ颗粒编号(结果表中的行)与我们的样品瓶位置相关联。
 


图5 。从背景图像创建的标记图像。A.背景图像的屏幕截图,该背景图像被转换为B.标记图像,此处与粒子标签叠加一起显示。宏中保存的图像没有标题和覆盖图,如图所示。列以蓝色表示,行以绿色表示。
 


图6 。标记图像的结果表。结果表的屏幕截图显示了72个标记颗粒中前15个的特征。这不是保存在宏中的结果表,该宏是一个逗号分隔的值(csv)文件。
 
实验性延时影像
在这里,我们将扫描仪彩色图像转换为黑白二进制图像,以黑色显示生物质颗粒,以白色显示网格。每个粒子的特性将保存在相应的结果表中。用于放置样品瓶的网格将自动从图像中删除。在此过程中,将不属于OPG的可能出现的不规则颗粒平均去除。宏包括一个手动阈值化步骤,该步骤比较耗时,但是自动阈值化可能并不总是导致粒子很好地反映扫描仪图像上的视觉印象。理论上,对于72个样品瓶的孵育组,每个图像可获得72个生物量颗粒。我们在六周的时间内获取了实验图像,生成了110幅彩色图像,每幅图像的大小为182 MB。即取中途通过实验的图像被示出为为例在电子图7 A.
需要包含背景的图像(即,可能不包含生物质的区域,例如网格)。该图像必须是灰度图像,其中网格为白色,实验过程中可能包含颗粒的区域为黑色。在最简单的情况下,图像可以是在过程C中生成的标记图像,或者,对于改进的粒子检测,可以是基于背景图像或实验图像的手动精选图像。在手动固化过程中,可以将可光化颗粒的区域重新绘制为具有小瓶内径的圆盘。前景仅限于可以检测到颗粒的潜在区域,可以避免干扰图像的检测,这些图像可能是由于样品瓶壁的反射或扫描过程中网格的阴影效应所引起的。
通过单击“插件”,“新”,“宏”在ImageJ中打开一个空宏。
将以下脚本复制到macro.txt窗口中。
 
setBatchMode (false);
//在批处理模式下输入s或将其保持为s ,并在宏执行期间隐藏活动图像。
功能动作(输入,输出,文件名){
                                                                                                                                            打开(输入+文件名);
                            工作名称= getTitle ();
jobnamemod = indexOf (jobname,“。”);
                            jobname = substring(jobname,0,jobnamemod );
//启动宏时输入的文件路径和文件名将转换为对使用它们的命令可用的变量。
              运行(“分割通道”);
                            selectImage (作业名+“。tif (蓝色)”);
close();
                            selectImage (作业名+“。tif (绿色)”);
                            close();
                            selectImage (作业名+“。tif (红色)”);
                            red_image = getTitle ();
//将s RGB转换为灰度图像。保留小号只有其中沟道呈现在其上小瓶置于(白色)的区域之间的对比度最和电网(黑色)。
                            打开(路径);
//打开小号格栅图像(例如在过程选择,标记图像)d 1一个使用以下指定的文件。
//小瓶区域现在显示为黑色,而网格为白色。
网格= getTitle ();
              imageCalculator (“添加创建”,red_image ,网格);
close(“ \\ Others ” );
//使网格显示为纯白色,以便在随后的二值化步骤中将其检测为背景。
              运行(“设置比例...”,“距离= 0已知= 0像素= 1单位=像素”);
//删除活动图像的空间比例,以使测量结果(例如,面积测量)具有单位像素。
              运行(“阈值...”);
                            waitForUser (“请手动设置阈值。然后按OK,或取消以退出宏”);
setOption (“ BlackBackground ”,false);
                            运行(“转换为蒙版”);
selectWindow (“ Threshold”);
                            run(“ Close”);
//创建小号从灰度图像二值图像:选择和应用截止值来划分图像为前景,即,小瓶领域和背景,即,电网。定义自己的条件,并尝试以相同的方式处理数据集的每个图像。
//注意:这可能很棘手,因为我们通常找不到适合图像上每个粒子的理想阈值。我们建议测试一个较小的子集(例如,第一张,中间和最后一张图像),以了解什么效果很好。
运行(“填充孔(二进制/灰色)”);
//填充小号中的区域的孔所占的小瓶,以实现固体区域(Legland等人,2016) 。
//注意:当生物质颗粒被对应于小瓶的环包围时,这可能会填满整个小瓶区域。如果发生这种情况,可以使用例如图像编辑器Gimp减小标记图像上各个粒子的大小,然后再次运行宏(另请参见过程D 1 a )。
              运行(“形态过滤器”,“操作=打开元素=磁盘半径= 10”);
close(“ \\ Others ” );
//删除小号隔离像素和断裂小号区之间的连接所占据由小瓶和网格,以便它变得不太可能,网格被意外认为小瓶区域的一部分。
                            mask_image = getTitle ();             
//创建的图像成为蒙版图像。
                            运行(“形态过滤器”,“操作=侵蚀元素=磁盘半径= 40”);
                            marker_image = getTitle ();
              //大幅减少š掩模图像上检测到的颗粒来创建将被用于形态重构的图像的大小。
              //注意:如果圆盘半径太大,则可能会删除小颗粒的图像,您可以根据图像和实验来调整参数圆盘半径。
              print(“标记图像名称为” + marker_image);
                            print(“遮罩图像名称为” + mask_image );
//打印s活动标记和蒙版图像。
运行(“形态重构”,“标记= [“ + marker_image +”] mask = [“ + mask_image +”] type = [按扩张]连通性= 4“);
//从蒙版图像中保留与标记图像上至少一个像素重叠的s个粒子,并移除其他像素。此步骤可确保仅保留与样品瓶区域重叠的颗粒,并去除不属于OPG的可能不稳定的颗粒。
              run(“ Set Measurements ...”,“区域形心拟合形状显示重定向=无小数= 3”);
              重命名(jobname);
//特异性IES其中记录测量结果。
              运行(“分析粒子...”,“尺寸= 0-无限圆度= 0.00-1.00 show = [叠加轮廓]显示排除”);
//生成的结果表(请参见过程C的说明)。
                            保存(输出+作业名称+“。final.tif ”);
                            close();
              saveAs (“结果”,输出+作业名+“ _ results.csv”);
运行(“清除结果”);                           
              selectWindow (“ Log”);
                            运行(“全部关闭”);
}
//清除以前的任何测量结果。
input = getDirectory (“请选择一个包含原始图像的输入目录。”);
output = getDirectory (“请为结果图像和表格选择输出目录。”);
waitForUser (“请打开网格图像。然后单击确定。”);
//选择在步骤D 1 a中选择的网格图像(例如标记图像)。此图像允许从扫描仪图像中删除网格。
网格= getTitle ();
dir = getDirectory (“ image”);
路径= dir +网格;
close();
//使用实验图像定义输入目录,并使用输出目录保存创建的图像。打开在步骤D 1 a中选择的网格图像。按照脚本的时间顺序,启动宏时,这些命令的结果将仅显示一次。
list = getFileList (输入);
对于(i = 0; i < list.length ; i ++)
                            动作(输入,输出,列表[ i ]);
setBatchMode (false);
//定义一个循环结构,该循环结构将执行宏功能的次数与在输入目录中找到图像的次数相同。
 
通过单击“宏”,“运行宏”来运行宏。在执行宏的过程中,手动选择带有实验图像的输入目录,选择输出目录以保存创建的图像并打开在步骤D 1 a中选择的网格图像。Ÿ欧可以使用自己的实验图像和网格图像或运行与可被下载示范图像演示https://doi.org/10.5281/zenodo.3938457。输入目录中所有图像的操作都会自动重复。
注意:确保文件夹中没有不相关的文件,否则ImageJ会尝试将它们视为图像。
手动检查获取的图像(图7 B )上的粒子是否与您在原始图像上视觉检测到的粒子相对应。
注意:此健全性检查非常重要,因为自动分析应该模拟并自动执行外观检查,但并非绝对可靠。您可以通过将原始扫描仪图像重新缩放为缩小的尺寸来创建一系列缩略图,以更轻松地浏览图像。
将结果表串联(合并)到一个csv文件中以简化分析。
在R编辑器中打开新的R脚本,例如RStudio (R Core Team,2019),方法是单击``文件'',``新文件'',``R脚本''。
将以下脚本复制到源代码窗口中。红色文字需要用户输入和修改。
 
## Packages --------------------------------------
require(plyr )#(Wickham,2011年)
require(readr )#(Wickham et al。,2018)
 
##工作目录--------------------------------------
rm(列表= ls())
目录<-(“ / path-to-directory / ”)
setwd (目录)
 
##连接结果表--------------------------------------
results.df < -list.files (路径=目录,模式=“ * .csv”,full.names = T)#生成目录中所有* .csv文件的列表
results.df < -ldply (results.df ,read_csv )#将所有图像的结果表合并为一个数据帧
colnames (。结果DF )[ 1] < - “ ObjNum ” #Assigns名称ObjNum到第一列
write.csv(results.df ,file =“ results_scanner_images.csv ”,quote = F,row.names = F)#将所有图像的结果表写入单独的文件中,以备后用。您可以在https://doi.org/10.5281/zenodo.3938457上找到此文件的示例。




图7 。从扫描仪图像创建的结果图像。A.在实验中途拍摄的扫描仪图像的屏幕截图,将其转换为B.确定了粒子特性的结果图像。图像显示两种污泥源的颗粒收缩程度不同。宏中保存的图像没有该图所示的标题。
 
光粒化的量化
现在将实验结果导入到软件环境R中(R Core Team,2019)。挑战在于将每个图像完成的颗粒特征自动转换为每个样品瓶一个时间序列。R脚本的步骤如下:
              计算在标记图像上确定的样品瓶区域的平均X,Y坐标(图5B);
              通过将带有实验时间的列添加到使用ImageJ获得的粒子数据中,为每个图像的所有实验测量的粒子分配实验时间。这有助于绘制时间动态图。
              使用样品瓶区域的X,Y坐标,在每个图像上特定物理位置识别样品瓶中的颗粒。通过分配位置编号将粒子关联到其位置,并使它们与适当的实验条件匹配;
              将检测到的颗粒表面积转化为相等的直径;
              绘制每个实验条件下随时间变化的平均粒径减小图。
单击“文件”,“新文件”,“ R脚本”,在R编辑器(例如RStudio)中打开新的R脚本。
将以下脚本复制到源窗口中。红色文本需要用户输入和修改。
 
## Packages --------------------------------------
require(plyr )#(Wickham,2011年)
require(ggplot2)#(威克姆,2016)
 
##工作目录--------------------------------------
rm(列表= ls())
目录<-(“ / path-to-directory / ”)
setwd (目录)
 
##开始时间 - - - - - - - - - - - - - - - - - - -
start.time <-c(“ 2018:03:14 17:51:19 ”)
#Manually输入开始日期/时间的的实验的第一张图像。实验时间将基于该时间点,使用扫描仪图像的采集时间来计算。
 
##比例系数--------------------------------------
比例因子< -475.417 / 1.5 #pixels / cm
#手动输入图像的比例,即覆盖小瓶直径的像素数。该值可以在ImageJ中轻松测量。
 
##保证金--------------------------------------
margin.vial < -212
#手动输入在ImageJ中测量的粒子的中心和边缘之间的平均像素数,通常为像素的小瓶的内半径。
 
##要导入的文件--------------------------------------
#您可以使用https://doi.org/10.5281/zenodo.3938457中显示的文件运行演示。
coordinates.name < - “ results_marker.csv ” #Information关于标记图像的每个粒子(使用ImageJ生成)。
raw.data.name < - “ results_scanner_images.csv ”扫描器图像#加入日期结果表(使用ImageJ生成)。
acquisition.time.name <-“ image_acquisition.csv ” #扫描仪图像的文件名和创建日期(使用R中的ExifTool生成)。
experimental.condition.name <-“ experimental_conditions.txt ” #每个样本的实验条件(手动生成)。
 
##加载文件--------------------------------------
坐标<-read.csv(coordinates.name,header = T,as.is = T)
raw.data <-read.csv(raw.data.name,标头= T,as.is = T)
Acquisition.time <-read.csv(acquisition.time.name,标头= T,as.is = T)
experimental.condition < - read.delim (experimental.condition.name,标题= T,as.is = T)
 
####计算在标记图像上识别出的样品瓶区域的平均X,Y坐标(图5B)。
 
##样品瓶区域的平均X,Y坐标--------------------------------------
column.1 <-c(1,14,27,40,53,66 )#手动输入标记屏幕快照上的哪个粒子标签与哪一列相对应,如蓝色所示(图5 B)。网格由在起始位置和大小上交替的列组成,例如,检测到的第一个粒子对应于扫描仪网格的第一列中的第一粒子,检测到的第十四个粒子位于第1列,第3行等的网格上。
column.2 < -c(8,21,34,47,60 )
column.3 < -c(2,15,28,41,54,67 )
column.4 < -c(9,22,35,48,61 )
column.5 < -c(3,16,29,42,55,68 )
column.6 < -c(10,23,36,49,62 )
column.7 < -c(4,17,30,43,56,69 )
column.8 < -c(11,24,37,50,63 )
column.9 < -c(5,18,31,44,57,70 )
column.10 < -c(12,25,38,51,64 )
column.11 < -c(6,19,32,45,58,71 )
column.12 < -c(13,26,39,52,65 )
column.13 < -c(7,20,33,46,59,72 )
 
row.1 <-c(1,2,3,4,5,6,7 )#手动输入标记屏幕快照上的哪个粒子标签与哪一行相对应,如绿色所示(图5 B)。网格由开始位置和大小交替的行组成,例如,检测到的第一个粒子对应于网格的第一行中最左边的粒子,依此类推。
row.2 < -c(8,9,10,11,12,13 )
row.3 < -c(14,15,16,17,18,19,20 )
row.4 < -c(21,22,23,24,25,26 )
row.5 < -c(27,28,29,30,31,32,33 )
row.6 < -c(34,35,36,37,38,39 )
row.7 < -c(40,41,42,43,44,45,46 )
row.8 < -c(47,48,49,50,51,52 )
row.9 < -c(53,54,55,56,57,58,59 )
row.10 < -c(60,61,62,63,64,65 )
row.11 < -c(66,67,68,69,70,71,72 )
 
位置名称<-c(第1行,第2行,第3行,第4行,第5行,第6行,第7行,第8行,第9行,第10行,第11行)
#粒子编号从左上到右下的顺序。
 
平均.x.1 <-平均值(坐标$ X [coordinates $ X.1%in%column.1])
average.x.2 <-平均值(坐标$ X [coordinates $ X.1%in%column.2])
average.x.3 <-平均值(坐标$ X [coordinates $ X.1%in%column.3])
average.x.4 <-平均值(坐标$ X [coordinates $ X.1%in%column.4])
平均。x.5 <-平均值(坐标$ X [坐标$ X.1%in%column.5])
average.x.6 <-平均值(坐标$ X [coordinates $ X.1%in%column.6])
average.x.7 <-平均值(坐标$ X [coordinates $ X.1%in%column.7])
average.x.8 <-平均值(坐标$ X [coordinates $ X.1%in%column.8])
average.x.9 <-平均值(坐标$ X [coordinates $ X.1%in%column.9])
average.x.10 <-平均值(坐标$ X [coordinates $ X.1%in%column.10])
average.x.11 <-平均值(坐标$ X [coordinates $ X.1%in%column.11])
average.x.12 <-平均值(坐标$ X [coordinates $ X.1%in%column.12])
average.x .13 <-平均值(坐标$ X [coordinates $ X.1%in%column.13])
#计算平均X坐标。
 
平均值.y.1 <-平均值(坐标$ Y [坐标$ X.1%in%row.1])
平均值.y.2 <-平均值(坐标$ Y [坐标$ X.1%in%row.2])
平均值.y.3 <-平均值(坐标$ Y [坐标$ X.1%in%row.3])
平均值.y.4 <-平均值(坐标$ Y [坐标$ X.1%in%row.4])
平均值.y.5 <-平均值(坐标$ Y [坐标$ X.1%in%row.5])
平均值.y.6 <-平均值(坐标$ Y [坐标$ X.1%in%row.6])
平均值.y.7 <-平均值(坐标$ Y [坐标$ X.1%in%row.7])
平均值.y.8 <-平均值(坐标$ Y [坐标$ X.1%in%row.8])
平均值.y.9 <-平均值(坐标$ Y [坐标$ X.1%in%row.9])
平均.y.10 <-平均值(坐标$ Y [坐标$ X.1%in%row.10])
平均。y.11 <-平均值(坐标$ Y [坐标$ X.1%in%row.11])
#计算平均Y坐标。
 
平均。xa <-c(平均值x.1,平均值x.3,平均值x.5,平均值x.7,平均值x.9,平均值x.11,平均值x.13)
平均。xb <-c(平均值x.2,平均值x.4,平均值x.6,平均值x.8,平均值x.10,平均值x.12)
#计算平均具有行的Y坐标的相同的X坐标。
平均。ya <-c(平均值y.1,平均值y.3,平均值y.5,平均值y.7,平均值y.9,平均值y.11)
平均。yb <-c(平均值y.2,平均值y.4,平均值y.6,平均值y.8,平均值y.10)
#Calculates平均X-COO具有行的rdinates的相同的Y坐标。
first.half < - expand.grid (average.xa ,average.ya )
second.half < - expand.grid (average.xb ,。平均YB )
#耦合a和b的X,Y坐标。
average.coordinates < - rbind (first.half ,second.half )
列名(平均坐标)<-c(“ X”,“ Y”)
#Combines ˚F irst.half和second.half由行。
平均.coordinates < - average.coordinates [顺序(average.coordinates $ Y ,average.coordinates $ X ),]
#将坐标设置为与可在标记屏幕快照上找到的粒子编号相同的顺序。
average.coordinates < - cbind (average.coordinates ,pos.names ,1:72)
colnames (average.coordinates )< - C( “X”, “Y”, “ ParticleLabel ”, “位置”)
#添加在标记屏幕快照和实验样品瓶位置(从左上方到右下方为1到72)中可以找到的带有颗粒编号顺序的列。
 
通过将带有实验时间的列添加到使用ImageJ获得的粒子数据中,为每个图像的所有实验测量的粒子分配实验时间。这有利于绘制时间动态。
 
##实验时间--------------------------------------
start.time < -strptime (start.time ,“%Y:%m:%d%H:%M:%S”)
#将开始时间转换为日期/时间表示。
date.time < -strptime (acquisition.time $ DateTime ,“%Y:%m:%d%H:%M:%S”)
#Acquires每IMAG采集时间e和其转换吨ö一个日期/时间表示。
exp.time < -round (-1 *(as.numeric (start.time - date.time ,units =“ hours”)),3)
#将日期/时间转换为实验时间。
采集时间<-cbind(采集时间,实验时间)
#将实验时间添加到采集时间文件中。
colnames (acquisition.time )< - C( “姓名”, “日期”, “ ExpTime ”)
acquisition.time $ Name < -gsub (“。tif ”,“”,Acquisition.time $ Name )
#删除*。文件名中的tif 。
unique.images <-unique(raw.data $ Label)
#检查大量唯一图像。
ExpTime.vec < -rep (0,nrow (raw.data ))
#创建与原始数据文件中的行一样多的零(矢量等于每个图像中的粒子数乘以图像数)。
for(i in 1:length(unique.images ))
{ time.i < -acquisition.time $ ExpTime [which(acquisition.time $ Name == unique.images [ i ])]
indexs.1 <-其中(raw.data $ Label == unique.images [ i ])
ExpTime.vec [ indices.1 ] < -time.i }
raw.data < -cbind (raw.data ,ExpTime.vec ,rep(NA,nrow (raw.data )),rep(NA,
nrow (raw.data )),rep(NA,nrow (raw.data )) )
colnames (raw.data )[(NcoI位(raw.data )-3):NcoI位(raw.data )] < - C( “ ExpTime ”, “位置”, 
“ ExpCondition ”, “ ExpID ”)
raw.data < -raw.data [order(raw.data $ ExpTime ),]
在扫描器的图像(数#Loops即,110倍的图像),图像给出的实验时间在acquisition.time文件对应于图像我。给出与对应于图像i的图像raw.data文件相对应的行(每个图像通常具有72个粒子)。将属于这些行的向量中的零替换为属于图像i的实验时间。
 
####使用样品瓶区域的X,Y坐标在每个图像的特定物理位置识别样品瓶中的颗粒。通过分配位置编号将粒子关联到其位置,并将其与适当的实验条件匹配。
 
##识别每个位置的粒子并添加实验条件--------------------------------------
为(J用1:NRO瓦特(average.coordinates )){indices.2 < -其中(
SQRT( ((raw.data $ X - average.coordinates $ X [j])^ 2)+((raw.data $ Y-average.coordinates $ Y [j]的)^ 2))< margin.vial )
if(length(indices.2 )== length(unique.images )){print(paste(c(“对于“位置”,“ j”,“。”看起来都不错,sep =”“,折叠= ”“)) } else {print(paste(c(“警告:“位置j,j,”。“),sep =”“,崩溃=”“))}}#
如果位置j存在问题,请转到手动浏览图像,并确保问题已得到纠正。可能会发生以下情况:在所有图像上均未检测到颗粒,例如,因为它开始漂浮,或者在一个图像的同一孔中已检测到一个以上的颗粒,例如,由于有一小块松散的生物质。在后一种情况下,您可以从数据集中不是颗粒的错误颗粒中手动删除数据。
raw.data $位置[indices.2 ] < - average.c oordinates $位置[J]。
indexs.1 <-which (experimental.condition $ Location == average.coordinates $ Location [j])
raw.data $ L ocation [indices.2] < - experimental.condition $位置[indices.1]
raw.data $ ExpCondition [ indices.2 ] <-实验条件$ ExpCondition [ indices.1 ]
raw.data $ ExpID [ indices.2 ] <-实验性条件$ ExpID [ indices.1 ]}
if(length(which(raw.data $ Location == 0))== 0){print(“不剩0,并且为所有坐标分配了位置”)} else {“当心!数据。”}
#Loops超过行数在average.coordinates文件(即,72行72个颗粒)。返回落在特定位置的X- ,Y坐标内的粒子,即,每个位置有110个粒子,因为有110张图像。注意:可能无法检测到小的且不居中的颗粒。将位置编号(即1到72)关联到X,Y位置,以便粒子在每个图像上具有相同的标签。将环境条件耦合到位置。
 
####将检测到的粒子表面积转换为等效直径。
 
##从面积计算等效直径--------------------------------------
raw.data < -cbind (raw.data ,2 * sqrt(raw.data $ Area / pi),rep(NA,nrow (raw.data )))
colnames (raw.data )[(NcoI位(raw.data )-1):NcoI位(raw.data )] < - C( “ EquivDiam_pix ”, 
“ EquivDiam_cm ”)
#假设它代表一个圆,计算颗粒区域的直径。
raw.data $ EquivDiam_cm < - raw.data $ EquivDiam_pix / scaling.factor
#Convert小号PI xels到厘米。
 
####绘制每个实验条件下随时间变化的平均粒径降低。
 
##根据每种实验条件在整个实验时间内的直径--------------------------------------
treated.final 。数据< - ddply (raw.data ,C( “ ExpTime ”, “ ExpID ”),综述,
average.diameter =平均值(EquivDiam_cm ),sd.diameter = SD (EquivDiam_cm ),sem.diameter = SD (EquivDiam_cm )/ SQRT(长度(EquivDiam_cm )))
 
处理后的最终数据$ ExpID <-作为字符(处理后的最终数据$ ExpID )
平均直径<-处理后的最终数据$平均直径
SD < - treated.final 。数据$ sd.diameter
 
P < - ggplot (treated.final.data ,映射= AES (X = ExpTime ,Y = average.diameter ,S HAPE = ExpID ,颜色= ExpID ))
p <-p + geom_ point ()
p <-p + scale_shape_离散(名称=“ ExpID ”,breaks = c(“ 1”,“ 2”),labels = c(“ sludge1”,“ sludge2”))
p <-p + scale_color_离散(名称=“ ExpID ”,breaks = c(“ 1”,“ 2”),标签= c(“ sludge1”,“ sludge2”))
P < - P + geom_ errorbar (AES (YMIN = average.diameter-SD ,YMAX = average.d iameter + SD ))
p <-p + labs(x =“实验时间[h]”,y =“生物质直径[cm]”)
p #这是图8 。
 
您可以使用自己生成的文件,也可以使用https://doi.org/10.5281/zenodo.3938457上显示的文件运行演示。
通过单击“运行”运行脚本。
验证生成的绘图(图8 )是否与基于实验延时图像的预期相匹配。
 


图8 。光粒化的进展显示为生物质收缩,即直径减小。水电tatic分批培养物开始具有两个不同的污泥源,每个含有36个重复。误差线表示标准偏差。
 
辐透的进展,通过生物质的收缩,定量ogranulation即,随着时间的推移在直径的减小,在呈现图8为两个不同的污泥源。最初,污泥床覆盖整个底部,并对应于内管形瓶的直径,即,1.27厘米 在成功的光粒化过程中,可以预期最终直径约为初始值的一半或更小。在此,每个污泥源的所有36个重复样本中的生物量均不能很好地造粒,并且观察到了微生物垫的形成。收缩程度的这种大变化,即形成两个非常不同的表型,反映在平均直径附近的大标准偏差上。尽管存在这种异质性,但污泥源2仍导致了比污泥源1更紧凑的OPG,且平均直径更小。
 
数据排除
通过删除原始数据中的相应行或使用指定脚本中要删除的数据点的文件(此处未描述),可以手动将失败的实验(例如,生长过度的小瓶底部,漂浮的生物质,带尖头的小瓶)从分析中排除。
 
统计分析
标准deviat围绕离子平均重复的直径在将R脚本的中底都计算值步骤ë 1 b 。
 
笔记
 
光粒化的生物学现象并不总是可再现的:成功率差异很大,并且可能取决于接种物(即活性污泥)或实验条件,例如温度,光强度或光质量。使用此协议,这种可变性是正在进行的研究的主题。
 
致谢
 
这项工作由蒙彼利埃卓越大学的研究生院GAIA (埃斯米·乔斯汀(Esmee Joosten)的100%博士奖学金)和ANR项目PSST ANR-16-CE04-0001资助。
  下OPGs生产液压静批量条件下早些时候提出的公园和多兰(2015年)和Milferstedt等。(2017年)。
 
利益争夺
 
作者声明不具有任何(非)金融竞争利益。
 
参考文献
 
Abouhend ,AS,McNair,A.,Kuo- Dahab,WC,Watt,C.,Butler,CS,Milferstedt ,K.,Hamelin,J.,Seo ,J.,Gikonyo ,GJ,El- Moselhy ,KM和Park ,C.(2018)。氧气光粒工艺用于无曝气废水处理。环境科学技术52(6):3503-3511。
Irvine-Fynn,TDL,Bridge,JW和Hodson,AJ(20 1 0 )。快速定量冰晶岩:使用斯瓦尔巴特群岛和格陵兰岛的实例对颗粒的几何形状和原位超冰砾度进行定量。J Glaciol 56(196):297-308。
Legland ,D.,阿尔甘-Carreras,I。和安德烈,P.(2016)。MorphoLibJ:集成的库和用于ImageJ的数学形态学的插件。生物信息学32(22):btw413。
Milferstedt ,K.,Kuo- Dahab,WC,Butler,CS,Hamelin,J.,Abouhend ,AS,Stauch -White ,K.,McNair,A.,Watt,C.,Carbajal-González,BI,Dolan,S和Park,C.(2017)。丝状蓝细菌在含氧光颗粒发育中的重要性。科学代表7(1):17944。
O'Brien,J.(2020年)。exiftoolr:ExifTool功能从R. https://cran.r-project.org/package=exiftoolr
Park,C.和Dolan,S.(2015年)。用于废水处理和生物能源原料生产的藻泥颗粒。专利申请号WO 2015112654 A2,Appl。PCT / US2015 / 012332。
基哈诺,G.,阿西拉,JS和Buitrón ,G。(2017)。微藻-细菌聚集体:废水处理的应用和前景。生物技术进阶35(6):772-781。
R核心团队(2019)。R:用于统计计算的语言和环境。R找到了。统计 COMPUT 。维也纳,奥地利。
Schneider,CA,Rasband ,WS和Eliceiri ,KW(2012)。ImageJ。Fundam数字成像医学9(7) :185 - 188。
Wickham,H.(2016年)。ggplot2:用于数据分析的精美图形。纽约Springer-Verlag。
Wickham,H.(2011年)。用于数据分析的拆分应用组合策略。J Stat软件40(1):1-29。
Wickham,H.,Hester,J.,Francois,R.(2018)阅读器:读取矩形文本数据。https://cran.r-project.org/package=readr
登录/注册账号可免费阅读全文
  • English
  • 中文翻译
免责声明 × 为了向广大用户提供经翻译的内容,www.bio-protocol.org 采用人工翻译与计算机翻译结合的技术翻译了本文章。基于计算机的翻译质量再高,也不及 100% 的人工翻译的质量。为此,我们始终建议用户参考原始英文版本。 Bio-protocol., LLC对翻译版本的准确性不承担任何责任。
Copyright: © 2020 The Authors; exclusive licensee Bio-protocol LLC.
引用:Joosten, E. D., Hamelin, J. and Milferstedt, K. (2020). Simple Time-lapse Imaging for Quantifying the Hydrostatic Production of Oxygenic Photogranules. Bio-protocol 10(19): e3784. DOI: 10.21769/BioProtoc.3784.
提问与回复
提交问题/评论即表示您同意遵守我们的服务条款。如果您发现恶意或不符合我们的条款的言论,请联系我们:eb@bio-protocol.org。

如果您对本实验方案有任何疑问/意见, 强烈建议您发布在此处。我们将邀请本文作者以及部分用户回答您的问题/意见。为了作者与用户间沟通流畅(作者能准确理解您所遇到的问题并给与正确的建议),我们鼓励用户用图片的形式来说明遇到的问题。

如果您对本实验方案有任何疑问/意见, 强烈建议您发布在此处。我们将邀请本文作者以及部分用户回答您的问题/意见。为了作者与用户间沟通流畅(作者能准确理解您所遇到的问题并给与正确的建议),我们鼓励用户用图片的形式来说明遇到的问题。