Skip to content

Commit ec10396

Browse files
authored
Merge pull request #3264 from ControlSystemStudio/image_profiles
Image profiles
2 parents ebca0ec + 6ee1bb1 commit ec10396

File tree

8 files changed

+500
-2
lines changed

8 files changed

+500
-2
lines changed

core/formula/doc/index.rst

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ This includes the average, min, max, and element count
150150

151151
**arrayMin(VNumberArray array)** - Returns a VDouble with the smallest value of the given array
152152

153+
**arraySampleWithStride(VNumberArray array, VNumber stride, VNumber offset)** - Returns a VNumberArray where each element is defined as array\[x \* stride + offset\].
153154

154155
String
155156
------
@@ -212,4 +213,12 @@ i.e. [Int8, UInt8, Int16, UInt16, Int32, UInt32, Float32, Float64].
212213

213214
**imageYOffset(VImage image)** - Fetch vertical offset of image.
214215

215-
**imageYReversed(VImage image)** - Fetch vertical reversal of image.
216+
**imageYReversed(VImage image)** - Fetch vertical reversal of image.
217+
218+
**imageDataHorizontalProfile(VNumberArray image, VNumber imageWidth, VNumber yPosition)** - Fetch the horizontal profile data for the given Image data at a specific y position.
219+
220+
**imageDataVerticalProfile(VNumberArray image, VNumber imageWidth, VNumber xPosition)** - Fetch the vertical profile data for the given Image data at a specific x position.
221+
222+
**imageHorizontalProfile(VImage image, VNumber yPosition)** - Fetch the horizontal profile of the given Image at a specific y position.
223+
224+
**imageVerticalProfile(VImage image, VNumber xPosition)** - Fetch the vertical profile of the given Image at a specific x position.

core/formula/src/main/java/org/csstudio/apputil/formula/areadetector/ADDataTypeMappingFunction.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package org.csstudio.apputil.formula.areadetector;
22

3-
43
import java.util.Arrays;
54
import java.util.List;
65

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package org.csstudio.apputil.formula.areadetector;
2+
3+
import org.csstudio.apputil.formula.spi.FormulaFunction;
4+
import org.epics.vtype.Alarm;
5+
import org.epics.vtype.Display;
6+
import org.epics.vtype.VNumberArray;
7+
import org.epics.vtype.VType;
8+
import org.phoebus.core.vtypes.VTypeHelper;
9+
10+
import java.util.Arrays;
11+
import java.util.List;
12+
13+
/**
14+
* A formula function for fetching the horizontal profile from image data.
15+
* This function extracts the horizontal profile along a given y position.
16+
*
17+
* @author Kunal Shroff
18+
*/
19+
public class ImageDataHorizontalProfileFunction implements FormulaFunction {
20+
21+
@Override
22+
public String getCategory() {
23+
return "areaDetector";
24+
}
25+
26+
@Override
27+
public String getName() {
28+
return "imageDataHorizontalProfile";
29+
}
30+
31+
@Override
32+
public String getDescription() {
33+
return "Fetch the horizontal profile data for the given Image data at a specific y position.";
34+
}
35+
36+
@Override
37+
public List<String> getArguments() {
38+
return List.of("image", "image width", "y position");
39+
}
40+
41+
/**
42+
* Computes the horizontal profile of the given image data at the specified y position.
43+
*
44+
* @param imageData The image data.
45+
* @param imageWidth The width of the image.
46+
* @param yPosition The y position in the image data from which to extract the horizontal profile.
47+
* @return A VNumberArray representing the extracted horizontal profile.
48+
*/
49+
protected VType getHorizontalProfile(final VNumberArray imageData, final int imageWidth, final int yPosition) {
50+
int start = yPosition * imageWidth;
51+
int end = start + imageWidth;
52+
return VNumberArray.of(imageData.getData().subList(start, end),
53+
Alarm.none(),
54+
imageData.getTime(),
55+
Display.none());
56+
}
57+
58+
/**
59+
* Computes the horizontal profile based on the provided arguments.
60+
*
61+
* @param args The arguments, where:
62+
* - args[0] must be a numeric array
63+
* - args[1] must be the image width
64+
* - args[2] must be the y position
65+
* @return The computed horizontal profile as a VType.
66+
* @throws Exception If invalid arguments are provided.
67+
*/
68+
@Override
69+
public VType compute(final VType... args) throws Exception {
70+
if (args.length != 3) {
71+
throw new Exception("Function " + getName() +
72+
" requires 3 arguments but received " + Arrays.toString(args));
73+
}
74+
if (!(VTypeHelper.isNumericArray(args[0])))
75+
throw new Exception("Function " + getName() +
76+
" takes Numeric Array but received " + Arrays.toString(args));
77+
78+
int width = (int) Math.round(VTypeHelper.toDouble(args[1]));
79+
int yPosition = (int) Math.round(VTypeHelper.toDouble(args[2]));
80+
return getHorizontalProfile((VNumberArray) args[0], width, yPosition);
81+
}
82+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
package org.csstudio.apputil.formula.areadetector;
2+
3+
import org.csstudio.apputil.formula.spi.FormulaFunction;
4+
import org.epics.util.array.ListDouble;
5+
import org.epics.util.array.ListNumber;
6+
import org.epics.vtype.Alarm;
7+
import org.epics.vtype.Display;
8+
import org.epics.vtype.VImage;
9+
import org.epics.vtype.VNumberArray;
10+
import org.epics.vtype.VType;
11+
import org.phoebus.core.vtypes.VTypeHelper;
12+
13+
import java.util.Arrays;
14+
import java.util.List;
15+
16+
/**
17+
* A formula function for fetching the vertical profile for an Image.
18+
* The vertical profile is extracted along a given x position.
19+
* This is useful for analyzing the intensity distribution along a column in the image.
20+
*
21+
* @author Kunal Shroff
22+
*/
23+
public class ImageDataVerticalProfileFunction implements FormulaFunction
24+
{
25+
26+
@Override
27+
public String getCategory()
28+
{
29+
return "areaDetector";
30+
}
31+
32+
@Override
33+
public String getName()
34+
{
35+
return "imageDataVerticalProfile";
36+
}
37+
38+
@Override
39+
public String getDescription()
40+
{
41+
return "Fetch the vertical profile data for the given Image data and x position.";
42+
}
43+
44+
@Override
45+
public List<String> getArguments()
46+
{
47+
return List.of("image", "image width", "x position");
48+
}
49+
50+
/**
51+
* Computes the vertical profile of the given VImage at the specified x position.
52+
*
53+
* @param imageData The image data.
54+
* @param width The width of the image.
55+
* @param xPosition The x position in the image data from which to extract the vertical profile.
56+
* @return A VNumberArray representing the extracted vertical profile.
57+
*/
58+
protected VType getVerticalProfile(final VNumberArray imageData, final int width, final int xPosition) {
59+
return VNumberArray.of(sampleWithStride(imageData.getData(), width, xPosition), Alarm.none(), imageData.getTime(), Display.none());
60+
}
61+
62+
private static ListDouble sampleWithStride(final ListNumber data, final double stride, final double offset) {
63+
64+
return new ListDouble() {
65+
66+
@Override
67+
public double getDouble(int index) {
68+
int computedIndex = (int) Math.round(offset + index * stride);
69+
if (computedIndex < 0 || computedIndex >= data.size()) {
70+
throw new IndexOutOfBoundsException("Computed index " + computedIndex + " is out of range.");
71+
}
72+
return data.getDouble(computedIndex);
73+
}
74+
75+
@Override
76+
public int size() {
77+
int size = (int) Math.ceil((data.size() - offset) / stride);
78+
return Math.max(size, 0);
79+
}
80+
};
81+
}
82+
83+
/**
84+
* Computes the vertical profile based on the provided arguments.
85+
*
86+
* @param args The arguments, where:
87+
* - args[0] must be a numeric array representing the image data
88+
* - args[1] must be the image width
89+
* - args[2] must be the x position
90+
* @return The computed vertical profile as a VType.
91+
* @throws Exception If invalid arguments are provided.
92+
*/
93+
@Override
94+
public VType compute(final VType... args) throws Exception
95+
{
96+
if (args.length != 3) {
97+
throw new Exception("Function " + getName() +
98+
" requires 3 arguments but received " + Arrays.toString(args));
99+
}
100+
if (!(VTypeHelper.isNumericArray(args[0])))
101+
throw new Exception("Function " + getName() +
102+
" takes a Numeric Array but received " + Arrays.toString(args));
103+
104+
int width = (int) Math.round(VTypeHelper.toDouble(args[1]));
105+
int xPosition = (int) Math.round(VTypeHelper.toDouble(args[2]));
106+
return getVerticalProfile((VNumberArray) args[0], width, xPosition);
107+
}
108+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package org.csstudio.apputil.formula.areadetector;
2+
3+
import org.csstudio.apputil.formula.spi.FormulaFunction;
4+
import org.epics.vtype.Alarm;
5+
import org.epics.vtype.Display;
6+
import org.epics.vtype.VImage;
7+
import org.epics.vtype.VNumberArray;
8+
import org.epics.vtype.VType;
9+
import org.phoebus.core.vtypes.VTypeHelper;
10+
11+
import java.util.Arrays;
12+
import java.util.List;
13+
14+
/** A formula function for fetching the horizontal profile for a VImage.
15+
* @author Kunal Shroff
16+
*/
17+
public class ImageHorizontalProfileFunction implements FormulaFunction
18+
{
19+
20+
@Override
21+
public String getCategory()
22+
{
23+
return "areaDetector";
24+
}
25+
26+
@Override
27+
public String getName()
28+
{
29+
return "imageHorizontalProfile";
30+
}
31+
32+
@Override
33+
public String getDescription()
34+
{
35+
return "Fetch the horizontal profile data for the given Image and y position.";
36+
}
37+
38+
@Override
39+
public List<String> getArguments()
40+
{
41+
return List.of("image", "y position");
42+
}
43+
44+
protected VType getHorizontalProfile(final VImage image, final int yPosition)
45+
{
46+
int start = yPosition * image.getWidth();
47+
int end = start + image.getWidth();
48+
return VNumberArray.of(image.getData().subList(start, end), Alarm.none(), image.getTime(), Display.none());
49+
}
50+
51+
/**
52+
* Computes the horizontal profile based on the provided arguments.
53+
*
54+
* @param args The arguments, where:
55+
* - args[0] must be a VImage
56+
* - args[1] must be the y position
57+
* @return The computed horizontal profile as a VType.
58+
* @throws Exception If invalid arguments are provided.
59+
*/
60+
@Override
61+
public VType compute(final VType... args) throws Exception
62+
{
63+
if (args.length != 2) {
64+
throw new Exception("Function " + getName() +
65+
" requires 2 arguments but received " + Arrays.toString(args));
66+
}
67+
if (!(args[0] instanceof VImage))
68+
throw new Exception("Function " + getName() +
69+
" takes VImage but received " + Arrays.toString(args));
70+
71+
int yPosition = (int) Math.round(VTypeHelper.toDouble(args[1]));
72+
return getHorizontalProfile((VImage) args[0], yPosition);
73+
}
74+
}

0 commit comments

Comments
 (0)