Skip to content

Commit acb2b30

Browse files
authored
Merge pull request #216 from mianalysis/develop
Develop
2 parents 8ca2eaf + 2f836ad commit acb2b30

File tree

31 files changed

+680
-184
lines changed

31 files changed

+680
-184
lines changed

mia-algorithms/pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66
<parent>
77
<groupId>io.github.mianalysis</groupId>
88
<artifactId>pom-mia</artifactId>
9-
<version>1.7.4</version>
9+
<version>1.7.5</version>
1010
</parent>
1111

1212
<groupId>io.github.mianalysis</groupId>
1313
<artifactId>mia-algorithms</artifactId>
14-
<version>1.7.4</version>
14+
<version>1.7.5</version>
1515
<packaging>jar</packaging>
1616
<name>mia-algorithms</name>
1717
<url>https://github.com/mianalysis/mia</url>

mia-algorithms/src/main/java/io/github/mianalysis/mia/process/houghtransform/accumulators/AbstractAccumulator.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ public int[][] getParameters() {
6666
return parameters;
6767
}
6868

69+
public Indexer getIndexer() {
70+
return indexer;
71+
}
72+
6973

7074
// ABSTRACT METHODS
7175

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
package io.github.mianalysis.mia.process.houghtransform.accumulators;
2+
3+
import java.util.ArrayList;
4+
5+
import ij.IJ;
6+
import ij.ImagePlus;
7+
import ij.gui.Line;
8+
import ij.gui.Overlay;
9+
import io.github.mianalysis.mia.process.voxel.MidpointCircle;
10+
11+
public class LineAccumulator extends AbstractAccumulator {
12+
13+
public LineAccumulator(int[][] parameters) {
14+
super(parameters);
15+
}
16+
17+
@Override
18+
public void addDetectedObjectsOverlay(ImagePlus ipl, ArrayList<double[]> objects) {
19+
// Adding overlay showing detected circles
20+
Overlay overlay = ipl.getOverlay();
21+
if (overlay == null)
22+
overlay = new Overlay();
23+
24+
for (int i = 0; i < objects.size(); i++) {
25+
double R = objects.get(i)[0];
26+
double thetaD = objects.get(i)[1];
27+
double thetaR = Math.toRadians(thetaD);
28+
int y0 = (int) Math.round(R / (Math.sin(thetaR)));
29+
int y1 = (int) Math.round((R - ipl.getWidth() * Math.cos(thetaR)) / (Math.sin(thetaR)));
30+
31+
Line roi = new Line(0, y0, ipl.getWidth(), y1);
32+
33+
overlay.add(roi);
34+
35+
}
36+
37+
ipl.setOverlay(overlay);
38+
39+
}
40+
41+
@Override
42+
public void addPoints(int[] indices, double value, int[][] points) {
43+
for (int i = 0; i < points.length; i++) {
44+
int iR = parameters[0][indices[0]] + points[i][0] - parameters[0][0];
45+
int iThetaD = parameters[1][indices[1]] + points[i][1] - parameters[1][0];
46+
47+
int idx = indexer.getIndex(new int[] { iR, iThetaD });
48+
49+
if (idx == -1)
50+
continue;
51+
52+
// Adding the current value and incrementing the count
53+
accumulator[idx] = accumulator[idx] + value;
54+
counts[idx]++;
55+
56+
}
57+
}
58+
59+
@Override
60+
public ArrayList<double[]> getObjects(double minScore, int exclusionR) {
61+
// Creating an ArrayList to store the points
62+
ArrayList<double[]> objects = new ArrayList<>();
63+
64+
// Getting relative coordinates for exclusion zone
65+
MidpointCircle midpointCircle = new MidpointCircle(exclusionR);
66+
int[] x = midpointCircle.getXCircleFill();
67+
int[] y = midpointCircle.getYCircleFill();
68+
69+
// Identifying the brightest point in the accumulator
70+
int maxIdx = getLargestScorePixelIndex();
71+
if (maxIdx == -1)
72+
return objects;
73+
74+
double maxVal = accumulator[maxIdx];
75+
76+
// Extracting all points
77+
while (maxVal >= minScore) {
78+
addBrightestObject(maxIdx, maxVal, objects, x, y);
79+
80+
// Updating the brightest point
81+
maxIdx = getLargestScorePixelIndex();
82+
if (maxIdx == -1)
83+
break;
84+
85+
maxVal = accumulator[maxIdx];
86+
87+
}
88+
89+
return objects;
90+
91+
}
92+
93+
@Override
94+
public ArrayList<double[]> getNObjects(int nObjects, int exclusionR) {
95+
// Creating an ArrayList to store the points
96+
ArrayList<double[]> objects = new ArrayList<>();
97+
98+
// Getting relative coordinates for exclusion zone
99+
MidpointCircle midpointCircle = new MidpointCircle(exclusionR);
100+
int[] x = midpointCircle.getXCircleFill();
101+
int[] y = midpointCircle.getYCircleFill();
102+
103+
// Extracting all points
104+
for (int count = 0; count < nObjects; count++) {
105+
// Identifying the brightest point in the accumulator
106+
int maxIdx = getLargestScorePixelIndex();
107+
if (maxIdx == -1)
108+
return objects;
109+
110+
double maxVal = accumulator[maxIdx];
111+
112+
addBrightestObject(maxIdx, maxVal, objects, x, y);
113+
114+
}
115+
116+
return objects;
117+
118+
}
119+
120+
void addBrightestObject(int maxIdx, double maxVal, ArrayList<double[]> objects, int[] x, int[] y) {
121+
// Getting parameters for brightest current spot and adding to ArrayList
122+
int[] currIndices = indexer.getCoord(maxIdx);
123+
int RR = parameters[0][currIndices[0]];
124+
int thetaTheta = parameters[1][currIndices[1]];
125+
126+
objects.add(new double[] { RR, thetaTheta, maxVal });
127+
128+
// Setting all pixels within exclusion radius to zero. This is repeated for all
129+
// slices.
130+
for (int i = 0; i < x.length; i++) {
131+
int iR = RR + x[i] - parameters[0][0];
132+
int iTheta = thetaTheta + y[i] - parameters[1][0];
133+
int idx = indexer.getIndex(new int[] { iR, iTheta });
134+
135+
if (idx == -1)
136+
continue;
137+
138+
accumulator[idx] = 0;
139+
140+
}
141+
}
142+
143+
@Override
144+
public ImagePlus getAccumulatorAsImage() {
145+
int[] dim = indexer.getDim();
146+
ImagePlus ipl = IJ.createHyperStack("Line_Accumulator", dim[0], dim[1], 1, 1, 1, 32);
147+
148+
for (int idx = 0; idx < indexer.getLength(); idx++) {
149+
int[] coord = indexer.getCoord(idx);
150+
151+
double value = accumulator[idx];
152+
153+
ipl.getProcessor().putPixelValue(coord[0], coord[1], value);
154+
155+
}
156+
157+
return ipl;
158+
159+
}
160+
161+
/**
162+
* Returns the Indexer index for the pixel in the Accumulator with the largest
163+
* score.
164+
*
165+
* @return
166+
*/
167+
public int getLargestScorePixelIndex() {
168+
double maxVal = Double.MIN_VALUE;
169+
int maxIdx = -1;
170+
171+
// Iterating over all pixels in the Accumulator. Identifying the brightest.
172+
for (int i = 0; i < accumulator.length; i++) {
173+
if (accumulator[i] > maxVal) {
174+
maxVal = accumulator[i];
175+
maxIdx = i;
176+
}
177+
}
178+
179+
return maxIdx;
180+
181+
}
182+
183+
}

mia-algorithms/src/main/java/io/github/mianalysis/mia/process/houghtransform/pixelarrays/PixelArray.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public PixelArray(int[] dim) {
1616

1717
public double getPixelValue(int[] coord) {
1818
int idx = getIndex(coord);
19+
1920
return getPixelValue(idx);
2021

2122
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package io.github.mianalysis.mia.process.houghtransform.transforms;
2+
3+
import ij.gui.Plot;
4+
import ij.process.ImageProcessor;
5+
import io.github.mianalysis.mia.process.houghtransform.accumulators.LineAccumulator;
6+
import io.github.mianalysis.mia.process.string.CommaSeparatedStringInterpreter;
7+
import io.github.mianalysis.mia.process.voxel.BresenhamLine;
8+
9+
/**
10+
* Created by sc13967 on 05/02/2025.
11+
*/
12+
public class LineTransform extends AbstractTransform {
13+
protected int width = 0;
14+
protected int height = 0;
15+
16+
public LineTransform(ImageProcessor ipr, String[] parameterRanges) {
17+
super(ipr);
18+
19+
String rRange = CommaSeparatedStringInterpreter.removeInterval(parameterRanges[0]);
20+
String thetaRange = CommaSeparatedStringInterpreter.removeInterval(parameterRanges[1]);
21+
22+
int[][] parameters = new int[parameterRanges.length][];
23+
24+
parameters[0] = CommaSeparatedStringInterpreter.interpretIntegers(rRange, true,
25+
(int) Math.ceil(Math.sqrt(ipr.getWidth() * ipr.getWidth() + ipr.getHeight() * ipr.getHeight())));
26+
parameters[1] = CommaSeparatedStringInterpreter.interpretIntegers(thetaRange, true, 179);
27+
28+
this.accumulator = new LineAccumulator(parameters);
29+
this.width = ipr.getWidth();
30+
this.height = ipr.getHeight();
31+
32+
}
33+
34+
@Override
35+
public void run() {
36+
int[][] parameters = accumulator.getParameters();
37+
38+
// Setting up the threading system
39+
// ThreadPoolExecutor pool = new ThreadPoolExecutor(nThreads, nThreads, 0L,
40+
// TimeUnit.MILLISECONDS,
41+
// new LinkedBlockingQueue<>());
42+
43+
// Iterating over all widths, heights and orientations
44+
int nR = parameters[0].length;
45+
int nTheta = parameters[1].length;
46+
47+
// Iterating over R and theta
48+
for (int iR = 0; iR < nR; iR++) {
49+
// int finalIR = iR;
50+
// Runnable task = () -> {
51+
for (int iTheta = 0; iTheta < nTheta; iTheta++) {
52+
// Getting current XY values
53+
int R = parameters[0][iR];
54+
int thetaD = parameters[1][iTheta];
55+
56+
// 180 degs causes the system to crash
57+
if (thetaD == 180)
58+
continue;
59+
60+
double thetaR = Math.toRadians(thetaD);
61+
62+
// Generating coordinates for the points on the line
63+
int y0 = (int) Math.round(R / (Math.sin(thetaR)));
64+
int y1 = (int) Math.round((R - (width-1) * Math.cos(thetaR)) / (Math.sin(thetaR)));
65+
int[][] line = BresenhamLine.getLine(0, width-1, y0, y1);
66+
67+
// double[] xx = new double[line.length];
68+
// double[] yy = new double[line.length];
69+
70+
// int i=0;
71+
for (int[] point : line) {
72+
// xx[i] = point[0];
73+
// yy[i] = point[1];
74+
if (point[1] >= 0 && point[1] < height) {
75+
// xx[i] = point[0];
76+
// yy[i] = point[1];
77+
double value = pixels.getPixelValue(point);
78+
accumulator.addPoints(new int[] { iR, iTheta }, value, new int[][]{new int[]{0,0}});
79+
}
80+
// i++;
81+
}
82+
// Plot pl = new Plot("T", "", "");
83+
// pl.setLimits(0, 512, 0, 512);
84+
// pl.add("Line", xx, yy);
85+
// pl.show();
86+
}
87+
}
88+
89+
// pool.shutdown();
90+
// try {
91+
// pool.awaitTermination(Integer.MAX_VALUE, TimeUnit.DAYS); // i.e. never
92+
// terminate early
93+
// } catch (InterruptedException e) {
94+
// e.printStackTrace();
95+
// }
96+
}
97+
}

mia-algorithms/src/main/java/io/github/mianalysis/mia/process/string/CommaSeparatedStringInterpreter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,11 @@ public static String removeEndRanges(String range, int endValue) {
4343
public static String removeInterval(String range) {
4444
// Removes anything after a potential second hyphen
4545
Pattern pattern = Pattern.compile("-");
46-
Matcher matcher = pattern.matcher(range);
46+
Matcher matcher = pattern.matcher(range.substring(1));
4747
int count = 0;
4848
while (matcher.find())
4949
if (count++ > 0)
50-
return range.substring(0, matcher.start());
50+
return range.substring(0, matcher.start()+1);
5151

5252
return range;
5353

mia-bonej/pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66
<parent>
77
<groupId>io.github.mianalysis</groupId>
88
<artifactId>pom-mia</artifactId>
9-
<version>1.7.4</version>
9+
<version>1.7.5</version>
1010
</parent>
1111

1212
<groupId>io.github.mianalysis</groupId>
1313
<artifactId>mia-bonej</artifactId>
14-
<version>1.7.4</version>
14+
<version>1.7.5</version>
1515
<packaging>jar</packaging>
1616
<name>mia-bonej</name>
1717
<url>https://github.com/mianalysis/mia</url>

mia-coordinates/pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66
<parent>
77
<groupId>io.github.mianalysis</groupId>
88
<artifactId>pom-mia</artifactId>
9-
<version>1.7.4</version>
9+
<version>1.7.5</version>
1010
</parent>
1111

1212
<groupId>io.github.mianalysis</groupId>
1313
<artifactId>mia-coordinates</artifactId>
14-
<version>1.7.4</version>
14+
<version>1.7.5</version>
1515
<packaging>jar</packaging>
1616
<name>mia-coordinates</name>
1717
<url>https://github.com/mianalysis/mia</url>

mia-core/pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66
<parent>
77
<groupId>io.github.mianalysis</groupId>
88
<artifactId>pom-mia</artifactId>
9-
<version>1.7.4</version>
9+
<version>1.7.5</version>
1010
</parent>
1111

1212
<groupId>io.github.mianalysis</groupId>
1313
<artifactId>mia-core</artifactId>
14-
<version>1.7.4</version>
14+
<version>1.7.5</version>
1515
<packaging>jar</packaging>
1616
<name>mia-core</name>
1717
<url>https://github.com/mianalysis/mia</url>

mia-core/src/main/java/io/github/mianalysis/mia/module/objects/detect/extensions/ManualExtension.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ public ManualExtension(Module module) {
2525

2626
public abstract Status initialiseAfterImageShown(@Nullable ImagePlus displayIpl);
2727

28+
public abstract Status onFinishAddingObjects();
29+
2830
protected abstract Parameters initialiseParameters();
2931

3032
public abstract Parameters updateAndGetParameters();

0 commit comments

Comments
 (0)