Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

5 basic image handling #7

Merged
merged 48 commits into from
Oct 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
1cba38e
Opening N5 Image
AvocadoMoon Aug 3, 2023
a76ef19
Added a basic GUI to N5 reader
AvocadoMoon Aug 3, 2023
008deb1
Open General N5 Files
AvocadoMoon Aug 3, 2023
ed6146a
Added Basic Test Case
AvocadoMoon Aug 3, 2023
7c3db2e
Test Resources
AvocadoMoon Aug 5, 2023
a902c22
Dynamic GUI and Refactored code
AvocadoMoon Aug 7, 2023
8316eb0
Changed Test Case
AvocadoMoon Aug 7, 2023
5b5c794
Make N5 files open any type of dataset
AvocadoMoon Aug 8, 2023
98b0136
Normal GUI
AvocadoMoon Aug 8, 2023
060e74e
GUI, Image Handling, and S3 Testing
AvocadoMoon Aug 10, 2023
292bcb7
Basic Remote Files GUI
AvocadoMoon Aug 10, 2023
d916d95
Remove N5-IJ Library
AvocadoMoon Aug 10, 2023
38acf26
Added Remote File Access GUI
AvocadoMoon Aug 15, 2023
a9bb25f
Added Test Case and Made Virtual Stack Available
AvocadoMoon Aug 15, 2023
6bf09f6
Ricky Wants Jar File
AvocadoMoon Aug 15, 2023
2c1524e
JAR File Test
paulricky Aug 15, 2023
ac18335
JAR File Test
paulricky Aug 15, 2023
98175b2
Ricky Jar Again
AvocadoMoon Aug 15, 2023
3af70d4
List and Read Remote Datasets
AvocadoMoon Aug 15, 2023
990bfa1
Switching to Linux
AvocadoMoon Aug 17, 2023
2b53b62
Improve GUI and outline some S3 Test Cases
AvocadoMoon Sep 6, 2023
e4aab0c
New S3 Tests
AvocadoMoon Sep 7, 2023
a66f0d5
Removed Unused Dependencies
AvocadoMoon Sep 11, 2023
1dd5c64
More Dependencies removed
AvocadoMoon Sep 11, 2023
f55265c
Changed scope of S3 Dependency
AvocadoMoon Sep 11, 2023
0a09bef
Refactored Test Class to no Longer Extend TestClass
AvocadoMoon Sep 12, 2023
5f2b996
Move S3 Proxy Service to Github Actions
AvocadoMoon Sep 18, 2023
ef24230
Changed Destination of Volume Mount S3Proxy
AvocadoMoon Sep 18, 2023
bad3032
Copy Workplace Data to Containers Storage
AvocadoMoon Sep 18, 2023
e3d6c11
Its WorkSpace not WorkPlace for Github Actions
AvocadoMoon Sep 18, 2023
016443d
Forgot to Make the Copy Recursive
AvocadoMoon Sep 18, 2023
50ffb8f
Permission Denied for Copying Files so Added Sudo
AvocadoMoon Sep 18, 2023
bdb100d
Remove S3 Proxy Dependencies
AvocadoMoon Sep 18, 2023
579110c
Better Errors Thrown
AvocadoMoon Sep 18, 2023
70dff35
Check if N5 Bucket is Available
AvocadoMoon Sep 18, 2023
6ba1d19
Everything has Sudo
AvocadoMoon Sep 18, 2023
551305a
Curl After the Files have Been Copied
AvocadoMoon Sep 18, 2023
2715742
Using AWS CLI to Put Resource Objects
AvocadoMoon Sep 18, 2023
674c873
Verbose Docker Env Variables
AvocadoMoon Sep 19, 2023
2922c4d
All Similar Format Env Variables
AvocadoMoon Sep 19, 2023
72ca6ba
No Sign Request AWS CLI
AvocadoMoon Sep 19, 2023
9202cfa
Foo credentials set
AvocadoMoon Sep 19, 2023
a91ad3f
Forgot to Remove No-Sign-Request
AvocadoMoon Sep 19, 2023
d851d18
None For Authorization S3Proxy
AvocadoMoon Sep 19, 2023
97ee3b0
S3 Connect
AvocadoMoon Oct 3, 2023
4f24388
Git Actions S3Proxy
AvocadoMoon Oct 3, 2023
b336363
Endpoint Specified
AvocadoMoon Oct 3, 2023
0b4cd4e
Light Refactor
AvocadoMoon Oct 3, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
60 changes: 59 additions & 1 deletion .github/workflows/maven.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,77 @@ on:
release:
types: [published, edited]



jobs:
build:

build:
runs-on: ubuntu-latest
env:
AWS_ACCESS_KEY_ID: jj
AWS_SECRET_ACCESS_KEY: jj
AWS_DEFAULT_REGION: 'site2-low'
AWS_ENDPOINT_URL: "http://127.0.0.1:4000"



# https://docs.github.com/en/actions/using-containerized-services/about-service-containers
services:
s3proxy:
image: andrewgaul/s3proxy
ports:
- 4000:80
env:
JCLOUDS_FILESYSTEM_BASEDIR: /data
JCLOUDS_PROVIDER: filesystem
JCLOUDS_REGIONS: site2-low
S3PROXY_IDENTITY: jj
S3PROXY_CREDENTIAL: jj

LOG_LEVEL: info
S3PROXY_ENDPOINT: http://0.0.0.0:80
S3PROXY_AUTHORIZATION: "aws-v2-or-v4"
S3PROXY_VIRTUALHOST: ""
S3PROXY_KEYSTORE_PATH: keystore.jks
S3PROXY_KEYSTORE_PASSWORD: password
S3PROXY_CORS_ALLOW_ALL: false
S3PROXY_CORS_ALLOW_ORIGINS: ""
S3PROXY_CORS_ALLOW_METHODS: ""
S3PROXY_CORS_ALLOW_HEADERS: ""
S3PROXY_IGNORE_UNKNOWN_HEADERS: false
S3PROXY_ENCRYPTED_BLOBSTORE: ""
S3PROXY_ENCRYPTED_BLOBSTORE_PASSWORD: ""
S3PROXY_ENCRYPTED_BLOBSTORE_SALT: ""

JCLOUDS_ENDPOINT: ""
JCLOUDS_REGION: ""
JCLOUDS_IDENTITY: remote-identity
JCLOUDS_CREDENTIAL: remote-credential
JCLOUDS_KEYSTONE_VERSION: ""
JCLOUDS_KEYSTONE_SCOPE: ""
JCLOUDS_KEYSTONE_PROJECT_DOMAIN_NAME: ""
volumes:
- /dockerImage/data:/data

steps:
- uses: actions/checkout@v3

- name: Put test resources in S3Proxy Container
run: |
aws s3 mb s3://nfive
aws s3 cp ${{ github.workspace }}/src/test/resources/nfive s3://nfive --recursive

- name: Set up JDK 8
uses: actions/setup-java@v3
with:
java-version: '8'
distribution: 'temurin'
cache: maven

#Before building the Repo a docker container needs to intialized such that the test cases can work properly
# https://github.com/addnab/docker-run-action


- name: Build with Maven
run: mvn -B package --file pom.xml

Expand Down
Binary file not shown.
Binary file added out/artifacts/BuildVCellManager/PluginImageJ.jar
Binary file not shown.
63 changes: 54 additions & 9 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,10 @@
<artifactId>scijava-ui-swing</artifactId>
</dependency>

<dependency>
<groupId>org.scijava</groupId>
<artifactId>scijava-ui-awt</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.scijava</groupId>-->
<!-- <artifactId>scijava-ui-awt</artifactId>-->
<!-- </dependency>-->

<dependency>
<groupId>net.imagej</groupId>
Expand All @@ -131,22 +131,67 @@
<groupId>org.scijava</groupId>
<artifactId>scijava-plugins-commands</artifactId>
<scope>runtime</scope>
<version>0.2.4</version>
</dependency>

<!-- <dependency>-->
<!-- <groupId>org.apache.httpcomponents</groupId>-->
<!-- <artifactId>httpclient</artifactId>-->
<!-- </dependency>-->

<!-- <dependency>-->
<!-- <groupId>org.scijava</groupId>-->
<!-- <artifactId>scijava-listeners</artifactId>-->
<!-- </dependency>-->

<!-- https://mvnrepository.com/artifact/org.janelia.saalfeldlab/n5 -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<groupId>org.janelia.saalfeldlab</groupId>
<artifactId>n5</artifactId>
<version>2.5.1</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.janelia.saalfeldlab/n5-imglib2 -->
<dependency>
<groupId>org.scijava</groupId>
<artifactId>scijava-listeners</artifactId>
<groupId>org.janelia.saalfeldlab</groupId>
<artifactId>n5-imglib2</artifactId>
<version>5.0.0</version>
</dependency>

<!-- https://mvnrepository.com/artifact/net.imglib2/imglib2 -->
<dependency>
<groupId>net.imglib2</groupId>
<artifactId>imglib2</artifactId>
<version>6.1.0</version>
</dependency>

<!-- https://mvnrepository.com/artifact/net.imglib2/imglib2-ij -->
<dependency>
<groupId>net.imglib2</groupId>
<artifactId>imglib2-ij</artifactId>
<version>2.0.0</version>
</dependency>


<!-- https://mvnrepository.com/artifact/org.janelia.saalfeldlab/n5-aws-s3 -->
<dependency>
<groupId>org.janelia.saalfeldlab</groupId>
<artifactId>n5-aws-s3</artifactId>
<version>3.2.0</version>
</dependency>


<!-- https://mvnrepository.com/artifact/javax.xml.bind/jaxb-api Used for AWS library to properly parse XML files -->
<!-- <dependency>-->
<!-- <groupId>javax.xml.bind</groupId>-->
<!-- <artifactId>jaxb-api</artifactId>-->
<!-- <version>2.3.1</version>-->
<!-- </dependency>-->

<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.6.1</version>
<version>1.16.1</version>
</dependency>
</dependencies>

Expand Down
231 changes: 231 additions & 0 deletions src/main/java/org/vcell/vcellfiji/N5ImageHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
package org.vcell.vcellfiji;


import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.AnonymousAWSCredentials;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.AmazonS3URI;
import ij.ImagePlus;
import ij.plugin.Duplicator;
import net.imglib2.cache.img.CachedCellImg;
import net.imglib2.img.display.imagej.ImageJFunctions;
import net.imglib2.type.numeric.integer.*;
import net.imglib2.type.numeric.real.DoubleType;
import net.imglib2.type.numeric.real.FloatType;
import org.janelia.saalfeldlab.n5.imglib2.N5Utils;
import org.janelia.saalfeldlab.n5.s3.N5AmazonS3Reader;
import org.scijava.command.Command;
import org.scijava.plugin.Plugin;
import org.janelia.saalfeldlab.n5.*;
import org.vcell.vcellfiji.UI.VCellGUI;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;


/*
Able to open N5 files locally, display the datasets that can be chosen from it, and open the datasets within ImageJ.
Flow of operations is select an N5 file, get dataset list, select a dataset and then open it.
*/

@Plugin(type = Command.class, menuPath = "Plugins>VCell>N5 Dataset Viewer")
public class N5ImageHandler implements Command{
private VCellGUI vGui;
private File selectedLocalFile;
private AmazonS3 s3Client;
private String bucketName;

private String s3ObjectKey;

@Override
public void run() {
this.vGui = new VCellGUI();
this.vGui.localFileDialog.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
selectedLocalFile = vGui.localFileDialog.getSelectedFile();
displayN5Results(getN5DatasetList());
}
});

this.vGui.okayButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try{
loadN5Dataset(vGui.datasetList.getSelectedValue());
}
catch (IOException ex){
return;
}
}
});

this.vGui.remoteFileSelection.submitS3Info.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
createS3Client(vGui.remoteFileSelection.getS3URL(), vGui.remoteFileSelection.returnCredentials(), vGui.remoteFileSelection.returnEndpoint());
ArrayList<String> list = getS3N5DatasetList();
displayN5Results(list);
}
});
}

public ArrayList<String> getN5DatasetList(){
// auto closes reader
try (N5FSReader n5Reader = new N5FSReader(selectedLocalFile.getPath())) {
String[] metaList = n5Reader.deepList("/");
ArrayList<String> fList = new ArrayList<>();
for (String s : metaList) {
if (n5Reader.datasetExists(s)) {
fList.add(s);
};
}
return fList;
} catch (IOException e) {
throw new RuntimeException(e);
}
}

public void displayN5Results(ArrayList<String> datasetList){
SwingUtilities.invokeLater(() ->{
this.vGui.updateDatasetList(datasetList);
});
}


public ImagePlus getImgPlusFromN5File(String selectedDataset, N5Reader n5Reader) throws IOException {
// Theres definitly a better way to do this, I trie using a variable to change the cached cells first parameter type but it didn't seem to work :/
switch (n5Reader.getDatasetAttributes(selectedDataset).getDataType()){
case UINT8:
return ImageJFunctions.wrap((CachedCellImg<UnsignedByteType, ?>)N5Utils.open(n5Reader, selectedDataset), "");
case UINT16:
return ImageJFunctions.wrap((CachedCellImg<UnsignedShortType, ?>)N5Utils.open(n5Reader, selectedDataset), "");
case UINT32:
return ImageJFunctions.wrap((CachedCellImg<UnsignedIntType, ?>)N5Utils.open(n5Reader, selectedDataset), "");
case INT8:
return ImageJFunctions.wrap((CachedCellImg<ByteType, ?>)N5Utils.open(n5Reader, selectedDataset), "");
case INT16:
return ImageJFunctions.wrap((CachedCellImg<ShortType, ?>)N5Utils.open(n5Reader, selectedDataset), "");
case INT32:
return ImageJFunctions.wrap((CachedCellImg<IntType, ?>)N5Utils.open(n5Reader, selectedDataset), "");
case FLOAT32:
return ImageJFunctions.wrap((CachedCellImg<FloatType, ?>)N5Utils.open(n5Reader, selectedDataset), "");
case FLOAT64:
return ImageJFunctions.wrap((CachedCellImg<DoubleType, ?>)N5Utils.open(n5Reader, selectedDataset), "");
// final ARGBARGBDoubleConverter<ARGBDoubleType> converters = new ARGBARGBDoubleConverter<>();
// final CachedCellImg<DoubleType, ?> cachedCellImg = N5Utils.open(n5Reader, selectedDataset);
// return ImageJFunctions.showRGB(cachedCellImg, converters, "");
}
return null;
}


private void displayN5Dataset(ImagePlus imagePlus){
if (this.vGui.openVirtualCheckBox.isSelected()){
imagePlus.show();
}
else{
ImagePlus memoryImagePlus = new Duplicator().run(imagePlus);
memoryImagePlus.show();
}
}

public N5AmazonS3Reader getN5AmazonS3Reader(){
try(N5AmazonS3Reader n5AmazonS3Reader = new N5AmazonS3Reader(this.s3Client, this.bucketName, this.s3ObjectKey)){
return n5AmazonS3Reader;
}
catch (IOException e){
throw new RuntimeException(e);
}
}

public N5FSReader getN5FSReader(){
try (N5FSReader n5FSReader = new N5FSReader(selectedLocalFile.getPath())) {
return n5FSReader;
} catch (IOException e) {
throw new RuntimeException(e);
}
}

public void loadN5Dataset(String selectedDataset) throws IOException {
if(selectedLocalFile != null) {
ImagePlus imagePlus = this.getImgPlusFromN5File(selectedDataset, this.getN5FSReader());
this.displayN5Dataset(imagePlus);
}
else {
ImagePlus imagePlus = this.getImgPlusFromN5File(selectedDataset, this.getN5AmazonS3Reader());
this.displayN5Dataset(imagePlus);
}
}

//When creating client's try to make one for an Amazon link, otherwise use our custom url scheme
public void createS3Client(String url, HashMap<String, String> credentials, HashMap<String, String> endpoint){
AmazonS3ClientBuilder s3ClientBuilder = AmazonS3ClientBuilder.standard();
URI uri = URI.create(url);
String defaultRegion = "site2-low";

// believe that it's a s3 URL
try{
AmazonS3URI s3URI = new AmazonS3URI(uri);
this.s3ObjectKey = s3URI.getKey();
this.bucketName = s3URI.getBucket();
defaultRegion = s3URI.getRegion();
}
// otherwise assume it is one of our URLs
catch (IllegalArgumentException e){
String[] pathSubStrings = uri.getPath().split("/", 3);
this.s3ObjectKey = pathSubStrings[2];
this.bucketName = pathSubStrings[1];
}

if(credentials != null){
s3ClientBuilder.withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials(credentials.get("AccessKey"), credentials.get("SecretKey"))));
}
if(endpoint != null){
s3ClientBuilder.withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endpoint.get("Endpoint"), endpoint.get("Region")));
this.s3Client = s3ClientBuilder.build();
return;
}
// if nothing is given, default user and return so that code after if statement does not execute
if(endpoint == null && credentials == null){
this.s3Client = AmazonS3ClientBuilder.standard().withRegion(defaultRegion).withCredentials(new AWSStaticCredentialsProvider(new AnonymousAWSCredentials())).build();
return;
}

//creds not null, but region is
this.s3Client = s3ClientBuilder.withRegion(defaultRegion).build();
}


public ArrayList<String> getS3N5DatasetList(){

// used as a flag to tell that remote access is occurring, and that there is no local files
selectedLocalFile = null;

try(N5AmazonS3Reader n5AmazonS3Reader = new N5AmazonS3Reader(this.s3Client, this.bucketName)) {
return new ArrayList<>(Arrays.asList(n5AmazonS3Reader.deepListDatasets(this.s3ObjectKey)));
}
catch (IOException e){
throw new RuntimeException(e);
}
}


public void setSelectedLocalFile(File selectedLocalFile){
this.selectedLocalFile = selectedLocalFile;
}
public File getSelectedLocalFile() {
return selectedLocalFile;
}

}
Loading
Loading