Skip to content

Commit 840edd6

Browse files
authored
BUG: Strip out the Alpha channel when creating the Image Geometry. (#827)
Signed-off-by: Michael Jackson <[email protected]>
1 parent c83e9f2 commit 840edd6

File tree

3 files changed

+94
-26
lines changed

3 files changed

+94
-26
lines changed

src/Plugins/OrientationAnalysis/docs/WritePoleFigureFilter.md

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,20 @@ IO (Output)
66

77
## Description
88

9-
This **Filter** creates a standard pole figure image for each **Ensemble** in a selected **Data Container** with an **Image Geometry**. The **Filter** uses Euler angles in radians and requires the crystal structures for each **Ensemble** array and the corresponding **Ensemble** Ids on the **Cells**. The **Filter** also optionally can use a *mask* array to determine which **Cells** are valid for the pole figure computation.
9+
This **Filter** creates a standard crystallographic pole figure image for each **Ensemble** (phase)in a selected **Data Container**. The **Filter** uses Euler angles in radians and requires the crystal structures and material names for each **Ensemble** array and the corresponding **Ensemble** Ids on the **Cells**. The **Filter** also optionally can use a *mask* array to determine which **Cells** are valid for the pole figure computation.
10+
11+
In a practicale sense, this means that the following information is available to the filter:
12+
13+
- Cell Level
14+
15+
- Euler Angles (Float 32) ordered as sets of (phi1, Phi, phi2).
16+
- Phases (Int32) This is the phase that each Euler angle belongs to
17+
- Optional Mask(boolean or uint8) True/1 if the Euler angle should be included in the pole figure.
18+
19+
- Ensemble Level (Phase Information)
20+
21+
- Laue Class (UInt32)
22+
- Material Names (String)
1023

1124
### Algorithm Choice
1225

@@ -18,7 +31,7 @@ This **Filter** creates a standard pole figure image for each **Ensemble** in a
1831

1932
### Layout
2033

21-
The 3 pole figures can be laid out in a Square, Horizontal row or vertical column. Supporting informatio (including the color bar legend for color pole figures) will also be printed on the image.
34+
The 3 pole figures can be laid out in a Square, Horizontal row or vertical column. Supporting information (including the color bar legend for color pole figures) will also be printed on the image.
2235

2336
| Lambert Projection | Discrete |
2437
|--------------------|----------|
@@ -28,8 +41,8 @@ The 3 pole figures can be laid out in a Square, Horizontal row or vertical colum
2841

2942
## Example Pipelines
3043

31-
+ TxCopper_Exposed
32-
+ TxCopper_Unexposed
44+
- TxCopper_Exposed
45+
- TxCopper_Unexposed
3346

3447
## License & Copyright
3548

src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/WritePoleFigure.cpp

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -362,21 +362,14 @@ Result<> WritePoleFigure::operator()()
362362
// Find how many phases we have by getting the number of Crystal Structures
363363
const size_t numPhases = crystalStructures.getNumberOfTuples();
364364

365-
// Loop over all the voxels gathering the Eulers for a specific phase into an array
365+
// Create the Image Geometry that will serve as the final storage location for each
366+
// pole figure. We are just giving it a default size for now, it will be resized
367+
// further down the algorithm.
366368
std::vector<usize> tupleShape = {1, static_cast<usize>(m_InputValues->ImageSize), static_cast<usize>(m_InputValues->ImageSize)};
367369
auto& imageGeom = m_DataStructure.getDataRefAs<ImageGeom>(m_InputValues->OutputImageGeometryPath);
368370
auto cellAttrMatPath = imageGeom.getCellDataPath();
369371
imageGeom.setDimensions({static_cast<usize>(m_InputValues->ImageSize), static_cast<usize>(m_InputValues->ImageSize), 1});
370372
imageGeom.getCellData()->resizeTuples(tupleShape);
371-
for(size_t phase = 1; phase < numPhases; ++phase)
372-
{
373-
auto imageArrayPath = cellAttrMatPath.createChildPath(fmt::format("{}Phase_{}", m_InputValues->ImagePrefix, phase));
374-
auto arrayCreationResult = nx::core::CreateArray<uint8>(m_DataStructure, tupleShape, {4ULL}, imageArrayPath, IDataAction::Mode::Execute);
375-
if(arrayCreationResult.invalid())
376-
{
377-
return arrayCreationResult;
378-
}
379-
}
380373

381374
// Loop over all the voxels gathering the Eulers for a specific phase into an array
382375
for(size_t phase = 1; phase < numPhases; ++phase)
@@ -666,22 +659,43 @@ Result<> WritePoleFigure::operator()()
666659
}
667660

668661
// Fetch the rendered RGBA pixels from the entire canvas.
669-
std::vector<unsigned char> image(static_cast<size_t>(pageHeight * pageWidth * 4));
670-
context.get_image_data(image.data(), pageWidth, pageHeight, pageWidth * 4, 0, 0);
662+
std::vector<unsigned char> rgbaCanvasImage(static_cast<size_t>(pageHeight * pageWidth * 4));
663+
context.get_image_data(rgbaCanvasImage.data(), pageWidth, pageHeight, pageWidth * 4, 0, 0);
671664
if(m_InputValues->SaveAsImageGeometry)
672665
{
666+
// Ensure the final Image Geometry is sized correctly.
673667
imageGeom.setDimensions({static_cast<usize>(pageWidth), static_cast<usize>(pageHeight), 1});
674668
imageGeom.getCellData()->resizeTuples({1, static_cast<usize>(pageHeight), static_cast<usize>(pageWidth)});
669+
tupleShape[0] = 1;
670+
tupleShape[1] = pageHeight;
671+
tupleShape[2] = pageWidth;
672+
// Create an output array to hold the RGB formatted color image
673+
auto imageArrayPath = cellAttrMatPath.createChildPath(fmt::format("{}{}", m_InputValues->ImagePrefix, phase));
674+
auto arrayCreationResult = nx::core::CreateArray<uint8>(m_DataStructure, tupleShape, {3ULL}, imageArrayPath, IDataAction::Mode::Execute);
675+
if(arrayCreationResult.invalid())
676+
{
677+
return arrayCreationResult;
678+
}
675679

676-
auto imageArrayPath = cellAttrMatPath.createChildPath(fmt::format("{}Phase_{}", m_InputValues->ImagePrefix, phase));
680+
// Get a reference to the RGB final array and then copy ONLY the RGB pixels from the
681+
// canvas RGBA data.
677682
auto& imageData = m_DataStructure.getDataRefAs<UInt8Array>(imageArrayPath);
678-
std::copy(image.begin(), image.end(), imageData.begin());
683+
684+
imageData.fill(0);
685+
size_t tupleCount = pageHeight * pageWidth;
686+
for(size_t t = 0; t < tupleCount; t++)
687+
{
688+
imageData[t * 3 + 0] = rgbaCanvasImage[t * 4 + 0];
689+
imageData[t * 3 + 1] = rgbaCanvasImage[t * 4 + 1];
690+
imageData[t * 3 + 2] = rgbaCanvasImage[t * 4 + 2];
691+
}
679692
}
680693

694+
// Write out the full RGBA data
681695
if(m_InputValues->WriteImageToDisk)
682696
{
683-
const std::string filename = fmt::format("{}/{}Phase_{}.tiff", m_InputValues->OutputPath.string(), m_InputValues->ImagePrefix, phase);
684-
auto result = TiffWriter::WriteImage(filename, pageWidth, pageHeight, 4, image.data());
697+
const std::string filename = fmt::format("{}/{}{}.tiff", m_InputValues->OutputPath.string(), m_InputValues->ImagePrefix, phase);
698+
auto result = TiffWriter::WriteImage(filename, pageWidth, pageHeight, 4, rgbaCanvasImage.data());
685699
if(result.first < 0)
686700
{
687701
return MakeErrorResult(-53900, fmt::format("Error writing pole figure image '{}' to disk.\n Error Code from Tiff Writer: {}\n Message: {}", filename, result.first, result.second));

src/Plugins/OrientationAnalysis/test/WritePoleFigureTest.cpp

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,43 @@ using namespace nx::core::UnitTest;
2121
namespace
2222
{
2323
const std::string k_ImagePrefix("fw-ar-IF1-aptr12-corr Discrete Pole Figure");
24+
25+
template <typename T>
26+
void CompareComponentsOfArrays(const DataStructure& dataStructure, const DataPath& exemplaryDataPath, const DataPath& computedPath, usize compIndex)
27+
{
28+
// DataPath exemplaryDataPath = featureGroup.createChildPath("SurfaceFeatures");
29+
REQUIRE_NOTHROW(dataStructure.getDataRefAs<DataArray<T>>(exemplaryDataPath));
30+
REQUIRE_NOTHROW(dataStructure.getDataRefAs<DataArray<T>>(computedPath));
31+
32+
const auto& exemplaryDataArray = dataStructure.getDataRefAs<DataArray<T>>(exemplaryDataPath);
33+
const auto& generatedDataArray = dataStructure.getDataRefAs<DataArray<T>>(computedPath);
34+
REQUIRE(generatedDataArray.getNumberOfTuples() == exemplaryDataArray.getNumberOfTuples());
35+
36+
usize exemplaryNumComp = exemplaryDataArray.getNumberOfComponents();
37+
usize generatedNumComp = generatedDataArray.getNumberOfComponents();
38+
39+
REQUIRE(exemplaryNumComp == 4);
40+
REQUIRE(generatedNumComp == 3);
41+
42+
REQUIRE(compIndex < exemplaryNumComp);
43+
REQUIRE(compIndex < generatedNumComp);
44+
45+
INFO(fmt::format("Bad Comparison\n Input Data Array:'{}'\n Output DataArray: '{}'", exemplaryDataPath.toString(), computedPath.toString()));
46+
47+
usize start = 0;
48+
usize numTuples = exemplaryDataArray.getNumberOfTuples();
49+
for(usize i = start; i < numTuples; i++)
50+
{
51+
auto oldVal = exemplaryDataArray[i * exemplaryNumComp + compIndex];
52+
auto newVal = generatedDataArray[i * generatedNumComp + compIndex];
53+
INFO(fmt::format("Index: {} Comp: {}", i, compIndex));
54+
55+
REQUIRE(oldVal == newVal);
56+
}
2457
}
2558

59+
} // namespace
60+
2661
TEST_CASE("OrientationAnalysis::WritePoleFigureFilter-1", "[OrientationAnalysis][WritePoleFigureFilter]")
2762
{
2863
Application::GetOrCreateInstance()->loadPlugins(unit_test::k_BuildDir.view(), true);
@@ -51,7 +86,7 @@ TEST_CASE("OrientationAnalysis::WritePoleFigureFilter-1", "[OrientationAnalysis]
5186
args.insertOrAssign(WritePoleFigureFilter::k_UseMask_Key, std::make_any<bool>(false));
5287
args.insertOrAssign(WritePoleFigureFilter::k_ImageGeometryPath_Key, std::make_any<DataPath>(DataPath({"fw-ar-IF1-aptr12-corr Discrete Pole Figure [CALCULATED]"})));
5388

54-
DataPath calculatedImageData({"fw-ar-IF1-aptr12-corr Discrete Pole Figure [CALCULATED]", "CellData", fmt::format("{}Phase_{}", k_ImagePrefix, 1)});
89+
DataPath calculatedImageData({"fw-ar-IF1-aptr12-corr Discrete Pole Figure [CALCULATED]", "CellData", fmt::format("{}{}", k_ImagePrefix, 1)});
5590
DataPath exemplarImageData({"fw-ar-IF1-aptr12-corr Discrete Pole Figure", "CellData", "Image"});
5691

5792
args.insertOrAssign(WritePoleFigureFilter::k_CellEulerAnglesArrayPath_Key, std::make_any<DataPath>(DataPath({"fw-ar-IF1-aptr12-corr", "Cell Data", "EulerAngles"})));
@@ -71,7 +106,9 @@ TEST_CASE("OrientationAnalysis::WritePoleFigureFilter-1", "[OrientationAnalysis]
71106
WriteTestDataStructure(dataStructure, fmt::format("{}/write_pole_figure-1.dream3d", unit_test::k_BinaryTestOutputDir));
72107
#endif
73108

74-
CompareArrays<uint8>(dataStructure, exemplarImageData, calculatedImageData);
109+
CompareComponentsOfArrays<uint8>(dataStructure, exemplarImageData, calculatedImageData, 0);
110+
CompareComponentsOfArrays<uint8>(dataStructure, exemplarImageData, calculatedImageData, 1);
111+
CompareComponentsOfArrays<uint8>(dataStructure, exemplarImageData, calculatedImageData, 2);
75112
}
76113

77114
TEST_CASE("OrientationAnalysis::WritePoleFigureFilter-2", "[OrientationAnalysis][WritePoleFigureFilter]")
@@ -102,7 +139,7 @@ TEST_CASE("OrientationAnalysis::WritePoleFigureFilter-2", "[OrientationAnalysis]
102139
args.insertOrAssign(WritePoleFigureFilter::k_UseMask_Key, std::make_any<bool>(true));
103140
args.insertOrAssign(WritePoleFigureFilter::k_ImageGeometryPath_Key, std::make_any<DataPath>(DataPath({"fw-ar-IF1-aptr12-corr Discrete Pole Figure Masked [CALCULATED]"})));
104141

105-
DataPath calculatedImageData({"fw-ar-IF1-aptr12-corr Discrete Pole Figure Masked [CALCULATED]", "CellData", fmt::format("{}Phase_{}", k_ImagePrefix, 1)});
142+
DataPath calculatedImageData({"fw-ar-IF1-aptr12-corr Discrete Pole Figure Masked [CALCULATED]", "CellData", fmt::format("{}{}", k_ImagePrefix, 1)});
106143
DataPath exemplarImageData({"fw-ar-IF1-aptr12-corr Discrete Pole Figure Masked", "CellData", "Image"});
107144

108145
args.insertOrAssign(WritePoleFigureFilter::k_CellEulerAnglesArrayPath_Key, std::make_any<DataPath>(DataPath({"fw-ar-IF1-aptr12-corr", "Cell Data", "EulerAngles"})));
@@ -123,7 +160,9 @@ TEST_CASE("OrientationAnalysis::WritePoleFigureFilter-2", "[OrientationAnalysis]
123160
WriteTestDataStructure(dataStructure, fmt::format("{}/write_pole_figure-2.dream3d", unit_test::k_BinaryTestOutputDir));
124161
#endif
125162

126-
CompareArrays<uint8>(dataStructure, exemplarImageData, calculatedImageData);
163+
CompareComponentsOfArrays<uint8>(dataStructure, exemplarImageData, calculatedImageData, 0);
164+
CompareComponentsOfArrays<uint8>(dataStructure, exemplarImageData, calculatedImageData, 1);
165+
CompareComponentsOfArrays<uint8>(dataStructure, exemplarImageData, calculatedImageData, 2);
127166
}
128167

129168
TEST_CASE("OrientationAnalysis::WritePoleFigureFilter-3", "[OrientationAnalysis][WritePoleFigureFilter]")
@@ -154,7 +193,7 @@ TEST_CASE("OrientationAnalysis::WritePoleFigureFilter-3", "[OrientationAnalysis]
154193
args.insertOrAssign(WritePoleFigureFilter::k_UseMask_Key, std::make_any<bool>(true));
155194
args.insertOrAssign(WritePoleFigureFilter::k_ImageGeometryPath_Key, std::make_any<DataPath>(DataPath({"fw-ar-IF1-aptr12-corr Discrete Pole Figure Masked Color [CALCULATED]"})));
156195

157-
DataPath calculatedImageData({"fw-ar-IF1-aptr12-corr Discrete Pole Figure Masked Color [CALCULATED]", "CellData", fmt::format("{}Phase_{}", k_ImagePrefix, 1)});
196+
DataPath calculatedImageData({"fw-ar-IF1-aptr12-corr Discrete Pole Figure Masked Color [CALCULATED]", "CellData", fmt::format("{}{}", k_ImagePrefix, 1)});
158197
DataPath exemplarImageData({"fw-ar-IF1-aptr12-corr Discrete Pole Figure Masked Color", "CellData", "Image"});
159198

160199
args.insertOrAssign(WritePoleFigureFilter::k_CellEulerAnglesArrayPath_Key, std::make_any<DataPath>(DataPath({"fw-ar-IF1-aptr12-corr", "Cell Data", "EulerAngles"})));
@@ -175,5 +214,7 @@ TEST_CASE("OrientationAnalysis::WritePoleFigureFilter-3", "[OrientationAnalysis]
175214
WriteTestDataStructure(dataStructure, fmt::format("{}/write_pole_figure-3.dream3d", unit_test::k_BinaryTestOutputDir));
176215
#endif
177216

178-
CompareArrays<uint8>(dataStructure, exemplarImageData, calculatedImageData);
217+
CompareComponentsOfArrays<uint8>(dataStructure, exemplarImageData, calculatedImageData, 0);
218+
CompareComponentsOfArrays<uint8>(dataStructure, exemplarImageData, calculatedImageData, 1);
219+
CompareComponentsOfArrays<uint8>(dataStructure, exemplarImageData, calculatedImageData, 2);
179220
}

0 commit comments

Comments
 (0)