Commit 0f5825f8 authored by Guillaume Blin's avatar Guillaume Blin

Initial commit

parents
bin/
target/
logs/
.*
!/.gitignore
This diff is collapsed.
# README #
PickCells is an image analysis platform. It has been designed with the following objectives in mind:
1. To be a flexible and powerful framework which allows developers to bring together generic image analysis algorithms, visualisation modules and data mining tasks.
2. To provide conventions and a rich API ensuring that modules remain as generic as possible (notably via use of Predicates) and have access to generic features of the application without direct dependencies to specific implementation (via inversion of control designs).
4. To be a user friendly solution for biologists with no programming knowledge to perform complex image analyses such as quantifying patterning and cell-cell interactions in complex tissues. A self descriptive property graph model resides at the core of the application. "Intelligent" graphical query builders allow the users to formulate hypothesis while exploring information contained in images and directly test ideas by querying and enriching the property graph data model.
### What is this repository for? ###
* This repository contains the PickCells Core modules.
### How do I get set up? ###
* The complete PickCells application is spread over several repositories. PickCells is mavenized, in order to create a PickCells distribution, one needs to obtain [the Assembly POM](https://framagit.org/pickcellslab/pickcells-assembly) and run the maven-assembly plugin.
\ No newline at end of file
This diff is collapsed.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.pickcellslab.pickcells</groupId>
<artifactId>pickcells-essentials</artifactId>
<version>0.7.0</version>
</parent>
<artifactId>pickcells-container</artifactId>
<version>0.7.0</version>
<packaging>jar</packaging>
<name>pickcells-container</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- Testing -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!-- Look and feel -->
<dependency>
<groupId>de.sciss</groupId>
<artifactId>weblaf</artifactId>
</dependency>
<!-- swingx -->
<dependency>
<groupId>org.swinglabs.swingx</groupId>
<artifactId>swingx-all</artifactId>
</dependency>
<!-- MetaInf helper -->
<dependency>
<groupId>org.kohsuke.metainf-services</groupId>
<artifactId>metainf-services</artifactId>
<optional>true</optional>
</dependency>
<!-- Vecmath -->
<dependency>
<groupId>java3d</groupId>
<artifactId>vecmath</artifactId>
</dependency>
<!-- pickcellslab dependencies -->
<dependency>
<groupId>org.pickcellslab.pickcells</groupId>
<artifactId>pickcells-img</artifactId>
</dependency>
<dependency>
<groupId>org.pickcellslab.pickcells</groupId>
<artifactId>pickcells-datamodel</artifactId>
</dependency>
<dependency>
<groupId>org.pickcellslab.pickcells</groupId>
<artifactId>pickcells-app</artifactId>
</dependency>
</dependencies>
<description>Module container interface, PickCells main</description>
</project>
package org.pickcellslab.pickcells.main;
/*-
* #%L
* Pickcells
* %%
* Copyright (C) 2016 - 2017 Guillaume Blin
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.stream.Collectors;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.LayoutStyle.ComponentPlacement;
import org.apache.log4j.Logger;
import org.pickcellslab.foundationj.datamodel.Direction;
import org.pickcellslab.foundationj.datamodel.tools.TraverserConstraints;
import org.pickcellslab.foundationj.datamodel.tools.Traversers;
import org.pickcellslab.foundationj.dbm.DataAccess;
import org.pickcellslab.foundationj.dbm.DataAccessException;
import org.pickcellslab.foundationj.dbm.queries.StorageBox.BoxBuilder;
import org.pickcellslab.pickcells.api.app.ui.AlphanumComparator;
import org.pickcellslab.pickcells.api.app.ui.UI;
import org.pickcellslab.pickcells.api.datamodel.conventions.Keys;
import org.pickcellslab.pickcells.api.datamodel.conventions.Links;
import org.pickcellslab.pickcells.api.datamodel.types.Experiment;
import org.pickcellslab.pickcells.api.datamodel.types.Image;
import org.pickcellslab.pickcells.api.datamodel.types.SegmentationResult;
import org.pickcellslab.pickcells.api.img.io.ImgIO;
import org.pickcellslab.pickcells.api.img.io.ImgWriter;
import com.alee.managers.tooltip.TooltipManager;
import net.imglib2.RandomAccessibleInterval;
import net.imglib2.type.numeric.integer.UnsignedByteType;
@SuppressWarnings("serial")
public class CanvasMaker extends JDialog{
private static Logger log = Logger.getLogger(CanvasMaker.class);
private DataAccess<?,?> session;
private File home;
private List<Image> images;
private boolean wasCancelled = true;
private boolean readImagesFailed;
private JTextField textField;
private final ImgIO io;
public CanvasMaker(DataAccess<?,?> session, ImgIO factory) {
this.session = session;
this.io = factory;
try {
if(home == null){
//Get the image folder
String f = session.queryFactory()
.read(Experiment.class)
.makeList(Experiment.dbPathKey)
.inOneSet().getAll().run().get(0);
home = new File(f);
}
//Build input dialog
//First get the image data
images =
session.queryFactory().regenerate(Image.class)
.toDepth(1)
.traverseLink(Links.COMPUTED_FROM, Direction.INCOMING)
.and(Image.RAW_FILE_LINK, Direction.OUTGOING)
.includeAllNodes()
.regenerateAllKeys()
.getAll()
.getTargets(Image.class).collect(Collectors.toList());
//Important sort the list based on the file names to maintain the same order as the one obtained from DiskImageandler
Collections.sort(images, new AlphanumComparator<Image>(I -> I.getAttribute(Keys.name).get()));
if(images.size() == 0)
return;
} catch (Exception e) {
readImagesFailed = true;
log.error("Unable to read images in the database", e);
return;
}
JLabel lblThisDialogAllows = new JLabel(
"<HTML><p align=\"justify\"> "
+ "This dialog allows you to generate \"blank\" segmentation results.<br>"
+ "<br>"+images.size()+" color images have been registered in the database, "
+ "therefore "+images.size()+" segmentation images will be created."
+ "</p> </HTML>");
JLabel lblSegmentedChannel = new JLabel("Segmentation Prefix");
TooltipManager.setTooltip(lblSegmentedChannel, "Define a prefix to name the generated images");
textField = new JTextField("canvas");
TooltipManager.setTooltip(textField, "Define a prefix to name the generated images");
JButton btnOk = new JButton("Ok");
btnOk.addActionListener(l->{
String text = textField.getText();
if(text.isEmpty()){
JOptionPane.showMessageDialog(null, "Define a prefix for the segmented images to be imported");
return;
}
images.get(0).segmentations().forEach(s->{
if(s.fileName().startsWith(text)){
JOptionPane.showMessageDialog(null, "This prefix is already taken");
return;
}
});
new Thread(()->{
try {
this.setVisible(false);
if(launchCanvasMaker()){
wasCancelled = false;
this.dispose();
}else
this.setVisible(true);
} catch (IOException e) {
log.error("An error occured while processing the image files",e);
this.dispose();
}
}).start();
});
JButton btnCancel = new JButton("Cancel");
btnCancel.addActionListener(l-> this.dispose());
//Layout
//-------------------------------------------------------------------------------------------------
GroupLayout groupLayout = new GroupLayout(getContentPane());
groupLayout.setHorizontalGroup(
groupLayout.createParallelGroup(Alignment.TRAILING)
.addGroup(groupLayout.createSequentialGroup()
.addGap(20)
.addComponent(lblThisDialogAllows, GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)
.addGap(11))
.addGroup(Alignment.LEADING, groupLayout.createSequentialGroup()
.addGap(71)
.addGroup(groupLayout.createParallelGroup(Alignment.TRAILING)
.addGroup(groupLayout.createSequentialGroup()
.addComponent(btnOk)
.addPreferredGap(ComponentPlacement.RELATED)
.addComponent(btnCancel))
.addGroup(groupLayout.createSequentialGroup()
.addComponent(lblSegmentedChannel)
.addPreferredGap(ComponentPlacement.UNRELATED)
.addComponent(textField, GroupLayout.PREFERRED_SIZE, 138, GroupLayout.PREFERRED_SIZE)))
.addContainerGap(58, Short.MAX_VALUE))
);
groupLayout.setVerticalGroup(
groupLayout.createParallelGroup(Alignment.LEADING)
.addGroup(groupLayout.createSequentialGroup()
.addContainerGap()
.addComponent(lblThisDialogAllows)
.addGap(18)
.addGroup(groupLayout.createParallelGroup(Alignment.BASELINE)
.addComponent(lblSegmentedChannel)
.addComponent(textField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
.addGap(18)
.addGroup(groupLayout.createParallelGroup(Alignment.BASELINE)
.addComponent(btnOk)
.addComponent(btnCancel))
.addGap(56))
);
getContentPane().setLayout(groupLayout);
}
@Override
public void setVisible(boolean visible){
if(readImagesFailed){
JOptionPane.showMessageDialog(null, "An error occured while reading the database", "Error", JOptionPane.ERROR_MESSAGE);
return;
}
else if(images.size() == 0){
JOptionPane.showMessageDialog(null,
"There are no image registered in the database, please register color images first.");
return;
}
else super.setVisible(visible);
}
public boolean wasCancelled(){
return wasCancelled;
}
private boolean launchCanvasMaker() throws IOException {
log.info("Started : Generating canvas...");
final String pfx = textField.getText();
int counter = -1;
for(Image img : images){
final long[] dims = img.getMinimalInfo().removeDimension(Image.c).imageDimensions();
final int bd = 1;
// Create the writer
final ImgWriter<UnsignedByteType> w = io.createWriter(img.getMinimalInfo().removeDimension(Image.c),
new UnsignedByteType(), home.getPath()+File.separator+pfx+"_"+ ++counter +io.standard(dims, bd));
// Write blank for each frame
for(int f = 0; f< img.frames(); f++){
RandomAccessibleInterval<UnsignedByteType> frame = w.createNewChannelFrame();
w.writeChannelFrame(frame, 0, f);
}
// Generate a Segmentation Result
new SegmentationResult(// Automatically creates a link to the parent image
img,
pfx+"_"+counter+io.standard(dims, bd),
pfx,
bd,
"Generated Canvas");
log.debug("Canvas generated!");
}
//Now save to the database
final TraverserConstraints tc =
Traversers.newConstraints()
.fromMinDepth().toDepth(1).traverseLink(Links.COMPUTED_FROM, Direction.INCOMING)
.includeAllNodes();
BoxBuilder b = session.queryFactory().store();
for(Image i : images)
b.add(i, tc);
try {
b.run();
} catch (DataAccessException e) {
UI.display("Error", "Could not update the database", e, Level.SEVERE);
return false;
}
return true;
}
}
package org.pickcellslab.pickcells.main;
/*-
* #%L
* Pickcells
* %%
* Copyright (C) 2016 - 2017 Guillaume Blin
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import org.jdesktop.swingx.border.DropShadowBorder;
/**
* Creates a Panel displaying a Component in the middle with a drop shadow border
*/
public class CenteredDropShadowPane {
private final JPanel main;
private final JPanel fixed;
public CenteredDropShadowPane(int borderWidth, int borderHeight, int prefWidth, int prefHeight) {
main = new JPanel();
GridBagLayout gridBagLayout = new GridBagLayout();
gridBagLayout.columnWidths = new int[]{borderWidth, prefWidth, borderWidth};
gridBagLayout.rowHeights = new int[]{borderHeight, prefHeight, borderHeight};
gridBagLayout.columnWeights = new double[]{0.0, 1.0, Double.MIN_VALUE};
gridBagLayout.rowWeights = new double[]{0.0, 1.0, Double.MIN_VALUE};
main.setLayout(gridBagLayout);
//Panel resizing with the parent container to place the fixed ratio in the middle
fixed = new JPanel();
DropShadowBorder b =new DropShadowBorder();
b.setShowLeftShadow(true);
b.setShowTopShadow(true);
b.setShowBottomShadow(true);
b.setShowRightShadow(true);
b.setShadowSize(10);
fixed.setBorder(b);
GridBagConstraints gbc_panel = new GridBagConstraints();
gbc_panel.fill = GridBagConstraints.BOTH;
gbc_panel.gridx = 1;
gbc_panel.gridy = 1;
main.add(fixed, gbc_panel);
}
public JPanel getHolderPanel(){
return main;
}
public JPanel getInsidePanel(){
return fixed;
}
public static void main(String[] args){
JFrame container = new JFrame();
container.setBackground(new Color(255,255,255));
container.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
container.getContentPane().add(new CenteredDropShadowPane(50, 50, 600, 400).getHolderPanel());
container.pack();
container.setVisible(true);
}
}
package org.pickcellslab.pickcells.main;
/*-
* #%L
* Pickcells
* %%
* Copyright (C) 2016 - 2017 Guillaume Blin
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.border.TitledBorder;
import org.pickcellslab.pickcells.api.img.view.ImgLut;
/**
* A simple dialog for the user to document the names of channels of imported images
*
* @author Guillaume Blin
*
*/
@SuppressWarnings("serial")
public class ChannelPane extends JPanel {
private JTextField textField;
private JComboBox<ImgLut<?>> comboBox;
/**
* Create the panel.
*/
public ChannelPane(int pos, ImgLut<?>[] luts) {
setBorder(new TitledBorder(null, "Channel "+pos, TitledBorder.LEADING, TitledBorder.TOP, null, null));
JLabel lblNewLabel = new JLabel("Name");
textField = new JTextField();
textField.setText("Channel "+pos);
textField.setColumns(10);
JLabel lblNewLabel_1 = new JLabel("LUT");
comboBox = new JComboBox<>(luts);
comboBox.setSelectedIndex(pos);
//Layout
//-----------------------------------------------------------------------------------------------------
GroupLayout groupLayout = new GroupLayout(this);
groupLayout.setHorizontalGroup(
groupLayout.createParallelGroup(Alignment.LEADING)
.addGroup(groupLayout.createSequentialGroup()
.addContainerGap()
.addGroup(groupLayout.createParallelGroup(Alignment.LEADING, false)
.addComponent(lblNewLabel, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(lblNewLabel_1, Alignment.TRAILING, GroupLayout.PREFERRED_SIZE, 59, GroupLayout.PREFERRED_SIZE))
.addPreferredGap(ComponentPlacement.RELATED)
.addGroup(groupLayout.createParallelGroup(Alignment.TRAILING)
.addComponent(comboBox, GroupLayout.PREFERRED_SIZE, 139, GroupLayout.PREFERRED_SIZE)
.addComponent(textField, GroupLayout.PREFERRED_SIZE, 139