23 | * The implementation uses the Graham-Scan convex hull algorithm. It runs in
24 | * O(N log N) time in the worst case and uses O(N)
25 | * extra memory.
26 | *
27 | * For additional documentation, see
28 | * Section 9.9 of
29 | * Algorithms, 4th Edition by Robert Sedgewick and Kevin Wayne.
30 | *
31 | * @author Robert Sedgewick
32 | * @author Kevin Wayne
33 | */
34 | public class GrahamScan {
35 |
36 | private Stack hull = new Stack();
37 |
38 | /**
39 | * Computes the convex hull of the specified array of points.
40 | *
41 | * @param pts the array of points
42 | * @throws NullPointerException if points is null or if
43 | * any entry in points[] is null
44 | */
45 | public GrahamScan(Point2D[] pts) {
46 |
47 | // defensive copy
48 | int N = pts.length;
49 | Point2D[] points = new Point2D[N];
50 | for (int i = 0; i < N; i++) {
51 | points[i] = pts[i];
52 | }
53 |
54 | // preprocess so that points[0] has lowest y-coordinate; break ties by x-coordinate
55 | // points[0] is an extreme point of the convex hull
56 | // (alternatively, could do easily in linear time)
57 | Arrays.sort(points);
58 |
59 | // sort by polar angle with respect to base point points[0],
60 | // breaking ties by distance to points[0]
61 | Arrays.sort(points, 1, N, points[0].polarOrder());
62 |
63 | hull.push(points[0]); // p[0] is first extreme point
64 |
65 | // find index k1 of first point not equal to points[0]
66 | int k1;
67 | for (k1 = 1; k1 < N; k1++) {
68 | if (!points[0].equals(points[k1])) {
69 | break;
70 | }
71 | }
72 | if (k1 == N) {
73 | return; // all points equal
74 | }
75 | // find index k2 of first point not collinear with points[0] and points[k1]
76 | int k2;
77 | for (k2 = k1 + 1; k2 < N; k2++) {
78 | if (Point2D.ccw(points[0], points[k1], points[k2]) != 0) {
79 | break;
80 | }
81 | }
82 | hull.push(points[k2 - 1]); // points[k2-1] is second extreme point
83 |
84 | // Graham scan; note that points[N-1] is extreme point different from points[0]
85 | for (int i = k2; i < N; i++) {
86 | Point2D top = hull.pop();
87 | while (Point2D.ccw(hull.peek(), top, points[i]) <= 0) {
88 | top = hull.pop();
89 | }
90 | hull.push(top);
91 | hull.push(points[i]);
92 | }
93 |
94 | assert isConvex();
95 | }
96 |
97 | /**
98 | * Returns the extreme points on the convex hull in counterclockwise order.
99 | *
100 | * @return the extreme points on the convex hull in counterclockwise order
101 | */
102 | public Iterable hull() {
103 | Stack s = new Stack();
104 | for (Point2D p : hull) {
105 | s.push(p);
106 | }
107 | return s;
108 | }
109 |
110 | // check that boundary of hull is strictly convex
111 | private boolean isConvex() {
112 | int N = hull.size();
113 | if (N <= 2) {
114 | return true;
115 | }
116 |
117 | Point2D[] points = new Point2D[N];
118 | int n = 0;
119 | for (Point2D p : hull()) {
120 | points[n++] = p;
121 | }
122 |
123 | for (int i = 0; i < N; i++) {
124 | if (Point2D.ccw(points[i], points[(i + 1) % N], points[(i + 2) % N]) <= 0) {
125 | return false;
126 | }
127 | }
128 | return true;
129 | }
130 |
131 | }
132 |
--------------------------------------------------------------------------------
/src/main/java/org/nolanlab/codex/segm/Kernel3D.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.nolanlab.codex.segm;
7 |
8 | import ij.ImageStack;
9 |
10 | /**
11 | *
12 | * @author Nikolay
13 | */
14 | public class Kernel3D {
15 |
16 | double[][][] weightMatrix;
17 | int[] center;
18 | int w, d, h;
19 |
20 | public Kernel3D(int w, int h, int d) {
21 | this.w = w;
22 | this.d = d;
23 | this.h = h;
24 | weightMatrix = new double[w][h][d];
25 |
26 | center = new int[]{w / 2, h / 2, d / 2};
27 | double[] sigmas = new double[]{w / 6.0, h / 6.0, d / 6.0};
28 | for (int z = 0; z < d; z++) {
29 | for (int x = 0; x < w; x++) {
30 | for (int y = 0; y < h; y++) {
31 | double sqdist = Math.pow((x - center[0]) / sigmas[0], 2) + Math.pow((y - center[1]) / sigmas[1], 2) + Math.pow((z - center[2]) / sigmas[2], 2);
32 | weightMatrix[x][y][z] = sqdist < 9 ? (Math.exp(-sqdist / 2.0)) : 0;// + (Math.exp(-Math.abs(sqdist) / 2.0))*0.3;
33 | }
34 | }
35 | }
36 | }
37 |
38 | public int[] getWeightedAverage(final ImageStack in, int pointX, int pointY, int pointZ) {
39 | double[] wAvg = new double[3];
40 | double sumWeights = 0;
41 |
42 | for (int kX = 0; kX < w; kX++) {
43 | for (int kY = 0; kY < h; kY++) {
44 | for (int kZ = 0; kZ < d; kZ++) {
45 |
46 | int xpos = (kX - center[0]) + pointX;
47 | int ypos = (kY - center[1]) + pointY;
48 | int zpos = (kZ - center[2]) + pointZ;
49 |
50 | if (0 <= xpos && xpos < in.getWidth() && 0 <= ypos && ypos < in.getHeight() && 0 <= zpos && zpos < in.size()) {
51 | double weight = in.getVoxel(xpos, ypos, zpos) * weightMatrix[kX][kY][kZ];
52 | wAvg[0] += kX * weight;
53 | wAvg[1] += kY * weight;
54 | wAvg[2] += kZ * weight;
55 | sumWeights += weight;
56 | }
57 | }
58 | }
59 | }
60 | int xpos = (((int) (wAvg[0] / sumWeights)) - center[0]) + pointX;
61 | int ypos = (((int) (wAvg[1] / sumWeights)) - center[1]) + pointY;
62 | int zpos = (((int) (wAvg[2] / sumWeights)) - center[2]) + pointZ;
63 |
64 | xpos = Math.max(0, Math.min(xpos, w - 1));
65 | ypos = Math.max(0, Math.min(ypos, w - 1));
66 | zpos = Math.max(0, Math.min(zpos, w - 1));
67 |
68 | return new int[]{xpos, ypos, zpos, (int) sumWeights};
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/src/main/java/org/nolanlab/codex/segm/MahalonobisDistance.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this template, choose Tools | Templates
3 | * and open the template in the editor.
4 | */
5 | package org.nolanlab.codex.segm;
6 |
7 |
8 | import cern.colt.matrix.DoubleMatrix2D;
9 | import cern.colt.matrix.impl.DenseDoubleMatrix1D;
10 | import cern.colt.matrix.impl.DenseDoubleMatrix2D;
11 | import cern.colt.matrix.linalg.Algebra;
12 |
13 | import java.util.Arrays;
14 |
15 | /**
16 | *
17 | * @author Zina
18 | */
19 | public class MahalonobisDistance {
20 |
21 | public DenseDoubleMatrix2D covMtx;
22 | public DenseDoubleMatrix1D center;
23 | private DoubleMatrix2D invCovMtx;
24 |
25 | public MahalonobisDistance(DenseDoubleMatrix1D center, DenseDoubleMatrix2D covMtx) {
26 | this.covMtx = covMtx;
27 | this.center = center;
28 | this.invCovMtx = Algebra.DEFAULT.inverse(covMtx);
29 | }
30 |
31 | @Override
32 | public String toString() {
33 | return "Center: " + center.toString() + "\nCovMtx\n"
34 | + covMtx.toString();
35 | }
36 |
37 | public MahalonobisDistance(SegmentedObject reg) {
38 |
39 | double[][] dataTable = new double[reg.getPoints().length][];
40 |
41 | for (int i = 0; i < reg.getPoints().length; i++) {
42 | dataTable[i] = new double[]{reg.getPoints()[i].x, reg.getPoints()[i].y, reg.getPoints()[i].z};
43 | }
44 |
45 | center = new DenseDoubleMatrix1D(new double[]{reg.getCenter().x, reg.getCenter().y, reg.getCenter().z});
46 | covMtx = new DenseDoubleMatrix2D(CovarianceMatrix.covarianceMatrix(dataTable));
47 |
48 | //Compute covariance matrix of the cluster
49 | //Take the inverse cov matrix
50 | try {
51 | invCovMtx = Algebra.DEFAULT.inverse(covMtx);
52 | } catch (IllegalArgumentException e) {
53 | System.out.println("Singular matrix. Using identity matrix instead");
54 | invCovMtx = new DenseDoubleMatrix2D(3, 3);
55 | for (int i = 0; i < 3; i++) {
56 | invCovMtx.setQuick(i, i, 1);
57 | }
58 | }
59 | }
60 |
61 | public MahalonobisDistance(double[][] dataTable) {
62 | // logger.print("init MD");
63 | //Compute the center of the cluster
64 |
65 | double[] vec = Arrays.copyOf(dataTable[0], dataTable[0].length);
66 | for (int i = 1; i < dataTable.length; i++) {
67 | double[] vec2 = dataTable[i];
68 | for (int dim = 0; dim < vec2.length; dim++) {
69 | vec[dim] += vec2[dim];
70 | }
71 | }
72 |
73 | for (int dim = 0; dim < vec.length; dim++) {
74 | vec[dim] /= (double) dataTable.length;
75 | }
76 | center = new DenseDoubleMatrix1D(vec);
77 |
78 | covMtx = new DenseDoubleMatrix2D(CovarianceMatrix.covarianceMatrix(dataTable));
79 |
80 | invCovMtx = Algebra.DEFAULT.inverse(covMtx);
81 | }
82 |
83 | public double distTo(double[] x) {
84 | DenseDoubleMatrix1D diff = new DenseDoubleMatrix1D(x.length);
85 | for (int i = 0; i < x.length; i++) {
86 | diff.setQuick(i, x[i] - center.getQuick(i));
87 | }
88 | double dist = Algebra.DEFAULT.mult(diff, Algebra.DEFAULT.mult(invCovMtx, diff));
89 | return Math.sqrt(dist);
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/main/java/org/nolanlab/codex/segm/MatrixOp.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this template, choose Tools | Templates
3 | * and open the template in the editor.
4 | */
5 | package org.nolanlab.codex.segm;
6 |
7 | import java.util.Arrays;
8 |
9 | /**
10 | *
11 | * @author Nikolay
12 | */
13 | public class MatrixOp {
14 |
15 | public static double mult(double[] vec1, double[] vec2) {
16 | if (vec1.length != vec2.length) {
17 | throw new IllegalArgumentException("Vectors differ in length");
18 | }
19 | double prod = 0;
20 | for (int x = 0; x < vec1.length; x++) {
21 | prod += vec1[x] * vec2[x];
22 | }
23 | return prod;
24 | }
25 |
26 | public static double[] subset(double[] source, int[] selectedIdx) {
27 | double[] res = new double[selectedIdx.length];
28 | for (int i = 0; i < res.length; i++) {
29 | res[i] = source[selectedIdx[i]];
30 | }
31 | return res;
32 | }
33 |
34 | public static double[] concat(double[] vec1, double[] vec2) {
35 | if (vec2 == null) {
36 | return vec1;
37 | }
38 | if (vec1 == null) {
39 | return vec2;
40 | }
41 | double[] res = Arrays.copyOf(vec1, vec1.length + vec2.length);
42 | for (int i = 0; i < vec2.length; i++) {
43 | res[i + vec1.length] = vec2[i];
44 | }
45 | return res;
46 | }
47 |
48 | public static double getEuclideanDistance(double[] vec1, double[] vec2) {
49 | if (vec1.length != vec2.length) {
50 | throw new IllegalArgumentException("Vectors differ in length");
51 | }
52 | double prod = 0;
53 | for (int x = 0; x < vec1.length; x++) {
54 | prod += (vec1[x] - vec2[x]) * (vec1[x] - vec2[x]);
55 | }
56 | return Math.sqrt(prod);
57 | }
58 |
59 | public static double getEuclideanCosine(double[] vec1, double[] vec2) {
60 | return Math.min(1.0, mult(vec1, vec2) / (lenght(vec1) * lenght(vec2)));
61 | }
62 |
63 | public static double[] copy(double[] vec) {
64 | if (vec == null) {
65 | return null;
66 | }
67 | return Arrays.copyOf(vec, vec.length);
68 | }
69 |
70 | public static void mult(double[] vec, double val) {
71 | for (int i = 0; i < vec.length; i++) {
72 | vec[i] *= val;
73 | }
74 | }
75 |
76 | public static void mult(double[][] mtx, double[] vec, double[] prod) {
77 | int col = vec.length;
78 | int row = mtx.length;
79 | for (int r = 0; r < row; r++) {
80 | prod[r] = 0;
81 | for (int c = 0; c < col; c++) {
82 | prod[r] += mtx[r][c] * vec[c];
83 | }
84 | }
85 | }
86 |
87 | public static double[] mult(double[][] mtx, double[] vec) {
88 | int col = vec.length;
89 | int row = mtx.length;
90 | double[] prod = new double[row];
91 | for (int r = 0; r < row; r++) {
92 | prod[r] = 0;
93 | for (int c = 0; c < col; c++) {
94 | prod[r] += mtx[r][c] * vec[c];
95 | }
96 | }
97 | return prod;
98 | }
99 |
100 | public static void mult(double[] vec, double val, double[] res) {
101 | for (int i = 0; i < vec.length; i++) {
102 | res[i] = vec[i] * val;
103 | }
104 | }
105 |
106 | public static double lenght(double vec[]) {
107 | return Math.sqrt(mult(vec, vec));
108 | }
109 |
110 | public static double[] toUnityLen(double[] vec) {
111 | double[] result = new double[vec.length];
112 | double len = lenght(vec);
113 | for (int i = 0; i < result.length; i++) {
114 | result[i] = vec[i] / len;
115 | }
116 | return result;
117 | }
118 |
119 | /**
120 | * @return x1+x2
121 | */
122 | public static double[] sum(double[] vec1, double[] vec2) {
123 | double[] result = copy(vec1);
124 | for (int x = 0; x < vec1.length; x++) {
125 | result[x] += vec2[x];
126 | }
127 | return result;
128 | }
129 |
130 | /**
131 | * @return x1-x2
132 | */
133 | public static double[] diff(double[] vec1, double[] vec2) {
134 | double[] result = copy(vec1);
135 | for (int x = 0; x < vec1.length; x++) {
136 | result[x] -= vec2[x];
137 | }
138 | return result;
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/src/main/java/org/nolanlab/codex/segm/Point3D.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.nolanlab.codex.segm;
7 |
8 | import java.awt.*;
9 |
10 | /**
11 | *
12 | * @author Nikolay
13 | */
14 | public class Point3D {
15 |
16 | final int x, y, z;
17 | double intensity;
18 | Color color;
19 |
20 | public Point3D(int x, int y, int z, double intensity, Color c) {
21 | this.x = x;
22 | this.y = y;
23 | this.z = z;
24 | this.intensity = intensity;
25 | this.color = c;
26 | }
27 |
28 | @Override
29 | public String toString() {
30 | return "{" + x + "," + y + "," + z + "}";
31 | }
32 |
33 | @Override
34 | public int hashCode() {
35 | return (String.valueOf(x) + String.valueOf(y) + String.valueOf(z)).hashCode();
36 | }
37 |
38 | public Point3D(int x, int y, int z) {
39 | this.x = x;
40 | this.y = y;
41 | this.z = z;
42 | this.intensity = 0;
43 | this.color = Color.BLACK;
44 | }
45 |
46 | @Override
47 | public boolean equals(Object obj) {
48 | return (obj instanceof Point3D) && ((Point3D) obj).x == this.x && ((Point3D) obj).y == this.y && ((Point3D) obj).z == this.z;
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/org/nolanlab/codex/segm/ProfileAverager.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this template, choose Tools | Templates
3 | * and open the template in the editor.
4 | */
5 | package org.nolanlab.codex.segm;
6 |
7 | import java.util.Arrays;
8 |
9 | /**
10 | *
11 | * @author Nikolay
12 | */
13 | public class ProfileAverager {
14 |
15 | double[] avg = null;
16 | double count = 0;
17 |
18 | public double getCount() {
19 | return count;
20 | }
21 |
22 |
23 |
24 |
25 | public ProfileAverager() {
26 | }
27 |
28 | public double[] getAverage() {
29 | if (count == 0) {
30 | throw new IllegalStateException("No profiles have been added to this averager");
31 | }
32 | double[] res = Arrays.copyOf(avg, avg.length);
33 | MatrixOp.mult(res, 1.0 / count);
34 | return res;
35 | }
36 |
37 | public double[] getAverageUnityLen() {
38 | if (count == 0) {
39 | throw new IllegalStateException("No profiles have been added to this averager");
40 | }
41 | double[] res = getAverage();
42 | return MatrixOp.toUnityLen(res);
43 | }
44 |
45 | public void addProfile(double[] vec) {
46 | if (vec == null) {
47 | return;
48 | }
49 | if (avg == null) {
50 | avg = Arrays.copyOf(vec, vec.length);
51 | } else {
52 | if (vec.length != avg.length) {
53 | throw new IllegalArgumentException("the vector size " + vec.length + " doesn't match the required size of " + vec.length);
54 | }
55 | avg = MatrixOp.sum(avg, vec);
56 | }
57 | count++;
58 | }
59 |
60 | public void addProfile(double[] vec, double weight) {
61 | if (vec == null) {
62 | return;
63 | }
64 | if (avg == null) {
65 | avg = Arrays.copyOf(vec, vec.length);
66 | MatrixOp.mult(avg, weight);
67 | } else {
68 | if (vec.length != avg.length) {
69 | throw new IllegalArgumentException("the vector size " + vec.length + " doesn't match the required size of " + vec.length);
70 | }
71 | double[] vec2 = Arrays.copyOf(vec, vec.length);
72 | MatrixOp.mult(vec2, weight);
73 | avg = MatrixOp.sum(avg, vec2);
74 | }
75 | count += weight;
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/main/java/org/nolanlab/codex/segm/RegionImageWriter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.nolanlab.codex.segm;
7 |
8 | import ij.ImagePlus;
9 |
10 | import javax.imageio.ImageIO;
11 | import java.awt.*;
12 | import java.awt.image.BufferedImage;
13 | import java.io.File;
14 | import java.io.IOException;
15 |
16 | /**
17 | *
18 | * @author Nikolay Samusik
19 | */
20 | public class RegionImageWriter {
21 |
22 | public static BufferedImage[] writeRegionImage(SegmentedObject[] reg, ImagePlus segmImage, String srcFileName, File outputDir) throws IOException {
23 | if (srcFileName.contains(".")) {
24 | srcFileName = srcFileName.substring(0, srcFileName.lastIndexOf("."));
25 | }
26 | int w = segmImage.getWidth();
27 | int h = segmImage.getHeight();
28 | int d = segmImage.getNSlices();
29 |
30 | BufferedImage[] bi = new BufferedImage[d];
31 | for (int z = 0; z < d; z++) {
32 | bi[z] = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
33 | }
34 |
35 | for (SegmentedObject segmentedObject : reg) {
36 | int r = (int) (Math.random() * 255);
37 | int g = (int) (Math.random() * 255);
38 | int b = (int) (Math.random() * 255);
39 | int a = 255;
40 | int col = (a << 24) | (r << 16) | (g << 8) | b;
41 | for (Point3D pt : segmentedObject.getPoints()) {
42 | bi[pt.z].setRGB(pt.x, pt.y, col);
43 | }
44 | }
45 |
46 | BufferedImage[] bi2 = new BufferedImage[d];
47 | for (int z = 0; z < d; z++) {
48 | bi2[z] = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
49 | bi[z].getGraphics().setColor(Color.black);
50 | bi2[z].getGraphics().fillRect(0,0,w,h);
51 | }
52 |
53 | for (int z = 0; z < d; z++) {
54 | BufferedImage img = bi[z];
55 | for (int x = 1; x < w - 1; x++) {
56 | for (int y = 1; y < h - 1; y++) {
57 | int col = img.getRGB(x, y);
58 |
59 | int a = (col >> 24) & 0xFF;
60 | if (a > 0) {
61 | boolean inner = true;
62 | for (int[] xy : new int[][]{{-1, 0}, {1, 0}, {0, -1}, {0, 1}}) {
63 | int col2 = img.getRGB(x + xy[0], y + xy[1]);
64 | inner &= col2 == col;
65 | }
66 | if (!inner) {
67 | bi2[z].setRGB(x, y, col);
68 | }else{
69 | bi2[z].setRGB(x, y, 0);
70 | }
71 | }else{
72 | bi2[z].setRGB(x, y, 0);
73 | }
74 | }
75 | }
76 | bi2[z].getGraphics().setColor(Color.black);
77 | bi2[z].getGraphics().drawRect(0,0,w-1,h-1);
78 | /*
79 | if (Main.printParams) {
80 | Graphics2D gr = bi2[z].createGraphics();
81 | gr.setPaint(Color.WHITE);
82 | String[] s = (Main.revision + "\n" + Main.params.toString().replace(',', '\n')).split("\n");
83 | int offset = 15;
84 | for (String string : s) {
85 | gr.drawString(string, 15, offset += 15);
86 | }
87 | }*/
88 | }
89 |
90 | for (int z = 0; z < d; z++) {
91 | String fileName = String.format(outputDir + File.separator + "regions_" + srcFileName + "_Z%02d", z+1);
92 | ImageIO.write(bi2[z], "PNG", new File(fileName + ".png"));
93 | }
94 | return bi2;
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/src/main/java/org/nolanlab/codex/segm/SegmentedObject.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.nolanlab.codex.segm;
7 |
8 | import java.awt.*;
9 |
10 | /**
11 | *
12 | * @author Nikolay
13 | */
14 | public class SegmentedObject {
15 |
16 | private final Point3D center;
17 | private final Point3D[] regionPts;
18 | private Point3D[] hull;
19 | private Color c;
20 | private double intensity;
21 |
22 | public void setIntensity(double intensity) {
23 | this.intensity = intensity;
24 | }
25 |
26 | public double getIntensity() {
27 | return intensity;
28 | }
29 |
30 | public void setC(Color c) {
31 | this.c = c;
32 | }
33 |
34 | public Point3D getCenter() {
35 | return center;
36 | }
37 |
38 | public Point3D[] getHull() {
39 | if (hull == null) {
40 | computeHull();
41 | }
42 | return hull;
43 | }
44 |
45 | private void computeHull() {
46 |
47 | }
48 |
49 | public Color getColor() {
50 | return c;
51 | }
52 |
53 | public Point3D[] getPoints() {
54 | return regionPts;
55 | }
56 |
57 | public SegmentedObject(Point3D center, Point3D[] regionPts) {
58 | this.center = center;
59 | this.regionPts = regionPts;
60 | c = new Color(100 + (int) (Math.random() * 155), 100 + (int) (Math.random() * 155), 100 + (int) (Math.random() * 155));
61 | }
62 |
63 | @Override
64 | public String toString() {
65 |
66 | StringBuilder sb = new StringBuilder();
67 |
68 | sb.append(center.toString());
69 | sb.append("\t");
70 |
71 | for (Point3D regionPt : regionPts) {
72 | sb.append(regionPt.toString());
73 | }
74 |
75 | return sb.toString(); //To change body of generated methods, choose Tools | Templates.
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/main/java/org/nolanlab/codex/segm/TIFFtoJPEG.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.nolanlab.codex.segm;
7 |
8 | import ij.IJ;
9 | import ij.ImagePlus;
10 | import ij.io.FileSaver;
11 | import ij.io.Opener;
12 | import ij.plugin.Duplicator;
13 |
14 | import java.io.File;
15 | import java.io.FileFilter;
16 | import java.io.IOException;
17 |
18 | /**
19 | *
20 | * @author Nikolay
21 | */
22 | public class TIFFtoJPEG {
23 |
24 | public static void main(String[] args) throws IOException {
25 |
26 | File inList = null;
27 | int quality = 90;
28 | try {
29 | if (args.length != 2) {
30 | throw new IllegalArgumentException("Invalid number of arguments, expected 2 arg");
31 | }
32 | inList = new File(args[0]);
33 | quality = Integer.parseInt(args[1]);
34 | } catch (Exception e) {
35 | e.printStackTrace();
36 | System.out.println("Provided arguments as seen by the application:");
37 | for (int i = 0; i < args.length; i++) {
38 | System.out.println("arg#" + i + "=" + args[i]);
39 | }
40 | System.out.println("Usage: java -jar CODEX.jar TIFFtoJPEG.class " + nNode.getFirstChild().getNodeValue()+ "");
57 | }
58 |
59 | printChildRecur(nNode.getChildNodes());
60 | }
61 | }
62 |
63 | }
64 |
65 |
--------------------------------------------------------------------------------
/src/main/java/org/nolanlab/codex/toolkit/GrahamScan.java:
--------------------------------------------------------------------------------
1 | /**
2 | * ****************************************************************************
3 | * Compilation: javac GrahamaScan.java
4 | * Execution: java GrahamScan < input.txt
5 | * Dependencies: Point2D.java
6 | *
7 | * Create points from standard input and compute the convex hull using
8 | * Graham scan algorithm.
9 | *
10 | * May be floating-point issues if x- and y-coordinates are not integers.
11 | *
12 | *****************************************************************************
13 | */
14 | package org.nolanlab.codex.toolkit;
15 |
16 | import java.util.Arrays;
17 | import java.util.Stack;
18 |
19 | /**
20 | * The GrahamScan data type provides methods for computing the convex
21 | * hull of a set of N points in the plane.
22 | *
23 | * The implementation uses the Graham-Scan convex hull algorithm. It runs in
24 | * O(N log N) time in the worst case and uses O(N)
25 | * extra memory.
26 | *
27 | * For additional documentation, see
28 | * Section 9.9 of
29 | * Algorithms, 4th Edition by Robert Sedgewick and Kevin Wayne.
30 | *
31 | * @author Robert Sedgewick
32 | * @author Kevin Wayne
33 | */
34 | public class GrahamScan {
35 |
36 | private Stack hull = new Stack();
37 |
38 | /**
39 | * Computes the convex hull of the specified array of points.
40 | *
41 | * @param pts the array of points
42 | * @throws NullPointerException if points is null or if
43 | * any entry in points[] is null
44 | */
45 | public GrahamScan(Point2D[] pts) {
46 |
47 | // defensive copy
48 | int N = pts.length;
49 | Point2D[] points = new Point2D[N];
50 | for (int i = 0; i < N; i++) {
51 | points[i] = pts[i];
52 | }
53 |
54 | // preprocess so that points[0] has lowest y-coordinate; break ties by x-coordinate
55 | // points[0] is an extreme point of the convex hull
56 | // (alternatively, could do easily in linear time)
57 | Arrays.sort(points);
58 |
59 | // sort by polar angle with respect to base point points[0],
60 | // breaking ties by distance to points[0]
61 | Arrays.sort(points, 1, N, points[0].polarOrder());
62 |
63 | hull.push(points[0]); // p[0] is first extreme point
64 |
65 | // find index k1 of first point not equal to points[0]
66 | int k1;
67 | for (k1 = 1; k1 < N; k1++) {
68 | if (!points[0].equals(points[k1])) {
69 | break;
70 | }
71 | }
72 | if (k1 == N) {
73 | return; // all points equal
74 | }
75 | // find index k2 of first point not collinear with points[0] and points[k1]
76 | int k2;
77 | for (k2 = k1 + 1; k2 < N; k2++) {
78 | if (Point2D.ccw(points[0], points[k1], points[k2]) != 0) {
79 | break;
80 | }
81 | }
82 | hull.push(points[k2 - 1]); // points[k2-1] is second extreme point
83 |
84 | // Graham scan; note that points[N-1] is extreme point different from points[0]
85 | for (int i = k2; i < N; i++) {
86 | Point2D top = hull.pop();
87 | while (Point2D.ccw(hull.peek(), top, points[i]) <= 0) {
88 | top = hull.pop();
89 | }
90 | hull.push(top);
91 | hull.push(points[i]);
92 | }
93 |
94 | assert isConvex();
95 | }
96 |
97 | /**
98 | * Returns the extreme points on the convex hull in counterclockwise order.
99 | *
100 | * @return the extreme points on the convex hull in counterclockwise order
101 | */
102 | public Iterable hull() {
103 | Stack s = new Stack();
104 | for (Point2D p : hull) {
105 | s.push(p);
106 | }
107 | return s;
108 | }
109 |
110 | // check that boundary of hull is strictly convex
111 | private boolean isConvex() {
112 | int N = hull.size();
113 | if (N <= 2) {
114 | return true;
115 | }
116 |
117 | Point2D[] points = new Point2D[N];
118 | int n = 0;
119 | for (Point2D p : hull()) {
120 | points[n++] = p;
121 | }
122 |
123 | for (int i = 0; i < N; i++) {
124 | if (Point2D.ccw(points[i], points[(i + 1) % N], points[(i + 2) % N]) <= 0) {
125 | return false;
126 | }
127 | }
128 | return true;
129 | }
130 |
131 | }
132 |
--------------------------------------------------------------------------------
/src/main/java/org/nolanlab/codex/toolkit/Matrix.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.nolanlab.codex.toolkit;
7 |
8 | import cern.colt.matrix.DoubleMatrix2D;
9 | import cern.colt.matrix.impl.DenseDoubleMatrix2D;
10 | import dataIO.DatasetStub;
11 |
12 | import java.io.BufferedWriter;
13 | import java.io.File;
14 | import java.io.FileWriter;
15 | import java.io.IOException;
16 | import java.util.Arrays;
17 | import java.util.List;
18 |
19 | /**
20 | *
21 | * @author Nikolay Samusik
22 | */
23 | public class Matrix {
24 |
25 | private String[] columnNames;
26 | private String[] rowNames;
27 | private DoubleMatrix2D mtx;
28 |
29 | private final String name;
30 |
31 | public Matrix(File f) {
32 | DatasetStub ds = DatasetStub.createFromTXT(f);
33 | columnNames = Arrays.copyOf(ds.getShortColumnNames(), ds.getShortColumnNames().length);
34 | rowNames = new String[(int) ds.getRowCount()];
35 | double[][] m = new double[rowNames.length][columnNames.length];
36 | for (int i = 0; i < rowNames.length; i++) {
37 | m[i] = ds.getRow(i);
38 | rowNames[i] = ds.getRowName(i);
39 | }
40 | mtx = new DenseDoubleMatrix2D(m);
41 | this.name = f.getName().split("\\.")[0];
42 | }
43 |
44 | public static Matrix sum(Matrix a, Matrix b) {
45 | Matrix ret = a.clone(a.name + " + " + b.name);
46 | for (int i = 0; i < a.rowNames.length; i++) {
47 | for (int j = 0; j < a.columnNames.length; j++) {
48 | ret.mtx().setQuick(i, j, a.mtx().getQuick(i, j) + b.mtx().getQuick(i, j));
49 | }
50 | }
51 | return ret;
52 | }
53 |
54 | public static Matrix avg(List list) {
55 | if (list.isEmpty()) {
56 | throw new IllegalArgumentException("List is empty");
57 | }
58 | Matrix avg = list.get(0).clone("avg of " + list.size() + " matrices");
59 | avg = list.stream().reduce(avg, Matrix::sum);
60 | avg.mtx().assign((double d) -> d / list.size());
61 | return avg;
62 | }
63 |
64 | public String getName() {
65 | return name;
66 | }
67 |
68 | public static Matrix SD(List list) {
69 | if (list.size() < 2) {
70 | throw new IllegalArgumentException("List size is less than 2");
71 | }
72 | Matrix avg = avg(list);
73 |
74 | Matrix res = avg.clone("SD of " + list.size() + " matrices");
75 |
76 | res.mtx().assign(0);
77 |
78 | for (Matrix m : list) {
79 | for (int i = 0; i < res.mtx().rows(); i++) {
80 | for (int j = 0; j < res.mtx().columns(); j++) {
81 | res.mtx().set(i, j, res.mtx().get(i, j) + Math.pow(m.mtx().getQuick(i, j) - avg.mtx().getQuick(i, j), 2));
82 | }
83 | }
84 | }
85 |
86 | for (int i = 0; i < res.mtx().rows(); i++) {
87 | for (int j = 0; j < res.mtx().columns(); j++) {
88 | res.mtx().set(i, j, Math.sqrt(res.mtx().get(i, j) / (list.size() - 1)));
89 | }
90 | }
91 |
92 | return res;
93 | }
94 |
95 | public DoubleMatrix2D mtx() {
96 | return mtx;
97 | }
98 |
99 | public String getColumnName(int i) {
100 | return columnNames[i];
101 | }
102 |
103 | public String getRowName(int i) {
104 | return rowNames[i];
105 | }
106 |
107 | public void writeToFile(File f) throws IOException {
108 | BufferedWriter br = new BufferedWriter(new FileWriter(f));
109 | br.write(this.toString());
110 | br.close();
111 | }
112 |
113 | @Override
114 | public String toString() {
115 | StringBuilder sb = new StringBuilder();
116 | sb.append("\t");
117 | sb.append(Arrays.toString(columnNames).replaceAll("[\\[\\]]", "").replaceAll(",", "\t"));
118 | sb.append("\n");
119 | for (int i = 0; i < rowNames.length; i++) {
120 | sb.append(rowNames[i]);
121 | for (int j = 0; j < columnNames.length; j++) {
122 | sb.append("\t").append(mtx.getQuick(i, j));
123 | }
124 | sb.append("\n");
125 | }
126 | return sb.toString();
127 | }
128 |
129 | public Matrix(String[] columnNames, String[] rowNames, DoubleMatrix2D mtx, String name) {
130 | this.columnNames = columnNames;
131 | this.rowNames = rowNames;
132 | if (columnNames.length != mtx.columns()) {
133 | throw new IllegalArgumentException("columnNames.size() != mtx.rows()");
134 | }
135 | if (rowNames.length != mtx.rows()) {
136 | throw new IllegalArgumentException("rowNames.size() != mtx.rows()");
137 | }
138 | this.mtx = mtx;
139 | this.name = name;
140 | }
141 |
142 | public Matrix clone(String newName) {
143 | return new Matrix(Arrays.copyOf(rowNames, rowNames.length), Arrays.copyOf(columnNames, columnNames.length), mtx.copy(), newName);
144 | }
145 |
146 | public String[] getColumnNames() {
147 | return columnNames;
148 | }
149 |
150 | public String[] getRowNames() {
151 | return rowNames;
152 | }
153 |
154 | }
155 |
--------------------------------------------------------------------------------
/src/main/java/org/nolanlab/codex/toolkit/VerifyDelaunayGraph.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.nolanlab.codex.toolkit;
7 |
8 | import java.io.File;
9 | import java.io.IOException;
10 |
11 | /**
12 | *
13 | * @author Nikolay Samusik
14 | */
15 | public class VerifyDelaunayGraph {
16 | public static void main(String[] args) throws IOException{
17 | File f = new File("D:\\CODEX paper revision");
18 | DelaunayGraph.verifyGraph(f);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/org/nolanlab/codex/toolkit/circularlayout/Bundle.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.nolanlab.codex.toolkit.circularlayout;
7 |
8 |
9 | import org.openide.util.NbBundle;
10 |
11 | class Bundle
12 | {
13 | static String Layout_NodePlacement_CCW()
14 | {
15 | return NbBundle.getMessage(Bundle.class, "Layout_NodePlacement_CCW");
16 | }
17 |
18 | static String Layout_NodePlacement_CW()
19 | {
20 | return NbBundle.getMessage(Bundle.class, "Layout_NodePlacement_CW");
21 | }
22 |
23 | static String Layout_NodePlacement_Degree_name()
24 | {
25 | return NbBundle.getMessage(Bundle.class, "Layout_NodePlacement_Degree_name");
26 | }
27 |
28 | static String Layout_NodePlacement_InDegree_name()
29 | {
30 | return NbBundle.getMessage(Bundle.class, "Layout_NodePlacement_InDegree_name");
31 | }
32 |
33 | static String Layout_NodePlacement_Mutual_name()
34 | {
35 | return NbBundle.getMessage(Bundle.class, "Layout_NodePlacement_Mutual_name");
36 | }
37 |
38 | static String Layout_NodePlacement_NodeID_name()
39 | {
40 | return NbBundle.getMessage(Bundle.class, "Layout_NodePlacement_NodeID_name");
41 | }
42 |
43 | static String Layout_NodePlacement_OutDegree_name()
44 | {
45 | return NbBundle.getMessage(Bundle.class, "Layout_NodePlacement_OutDegree_name");
46 | }
47 |
48 | static String Layout_NodePlacement_Random_name()
49 | {
50 | return NbBundle.getMessage(Bundle.class, "Layout_NodePlacement_Random_name");
51 | }
52 |
53 | static String Layout_name()
54 | {
55 | return NbBundle.getMessage(Bundle.class, "Layout_name");
56 | }
57 |
58 | private void Bundle() {}
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/java/org/nolanlab/codex/toolkit/circularlayout/CircleLayoutBuilder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package org.nolanlab.codex.toolkit.circularlayout;
7 |
8 | import org.gephi.graph.api.GraphModel;
9 | import org.gephi.layout.spi.Layout;
10 | import org.gephi.layout.spi.LayoutBuilder;
11 | import org.gephi.layout.spi.LayoutUI;
12 | import org.openide.util.NbBundle;
13 |
14 | import javax.swing.*;
15 |
16 | public class CircleLayoutBuilder
17 | implements LayoutBuilder
18 | {
19 | private CircleLayoutUI ui;
20 | GraphModel gm;
21 |
22 | public CircleLayoutBuilder(GraphModel gm)
23 | {
24 | this.gm = gm;
25 | }
26 |
27 | public String getName()
28 | {
29 | return NbBundle.getMessage(CircleLayoutBuilder.class, "CircleLayout.name");
30 | }
31 |
32 | @Override
33 | public Layout buildLayout()
34 | {
35 | return new CircleLayout(this, 500.0D, false);
36 | }
37 |
38 | public LayoutUI getUI()
39 | {
40 | return this.ui;
41 | }
42 |
43 | private static class CircleLayoutUI
44 | implements LayoutUI
45 | {
46 | public String getDescription()
47 | {
48 | return NbBundle.getMessage(CircleLayoutBuilder.class, "CircleLayout.description");
49 | }
50 |
51 | public Icon getIcon()
52 | {
53 | return null;
54 | }
55 |
56 | public JPanel getSimplePanel(Layout layout)
57 | {
58 | return null;
59 | }
60 |
61 | public int getQualityRank()
62 | {
63 | return -1;
64 | }
65 |
66 | public int getSpeedRank()
67 | {
68 | return -1;
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/main/java/org/nolanlab/codex/toolkit/circularlayout/NodeComparator.java:
--------------------------------------------------------------------------------
1 | package org.nolanlab.codex.toolkit.circularlayout;
2 |
3 | import org.gephi.graph.api.Graph;
4 | import org.gephi.graph.api.Node;
5 |
6 | import java.lang.reflect.Field;
7 | import java.lang.reflect.Method;
8 | import java.util.Comparator;
9 | import java.util.logging.Level;
10 | import java.util.logging.Logger;
11 |
12 | public class NodeComparator
13 | implements Comparator