Skip to content

Commit

Permalink
Merge pull request #222 from zhujun98/gui
Browse files Browse the repository at this point in the history
Redesign slice and volume control GUI and enable disable volume reconstruction
  • Loading branch information
zhujun98 authored Oct 5, 2023
2 parents 47d6ab8 + e548fcc commit 06e2436
Show file tree
Hide file tree
Showing 26 changed files with 281 additions and 131 deletions.
6 changes: 3 additions & 3 deletions docs/docs/tutorial/plastic_beads.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,17 @@ foamstream-tomo --datafile <Your/folder/2_plastic_beeds_RGB.h5> --pdata tomo --p

Open another terminal and run:
```sh
recastx-recon --rows 400 --cols 130 --angles 200 --minx -256 --maxx 256 --miny -256 --maxy 256 --preview-size 512
recastx-recon --rows 400 --cols 130 --angles 200 --minx -256 --maxx 256 --miny -256 --maxy 256 --volume-size 512
```

You can find the shapes of the DARK, FLAT and PROJECTION data from the output of foamstream.

!!! note
The `preview-size`, which defines the resolution of the "low-resolution"
The `volume-size`, which defines the resolution of the "low-resolution"
volume, is set to 512 in this case. As a result, the resolution of the
reconstructed volume is indeed high. It should be noted that it thus takes
longer time to perform the reconstruction and send the reconstructed volume
from the server to the client. Therefore, the default value of `preview-size`
from the server to the client. Therefore, the default value of `volume-size`
is set to 128 and is recommended to use in [dynamic tomography](./dynamic_tomography.md).

### Starting the GUI client
Expand Down
17 changes: 11 additions & 6 deletions docs/docs/user_guide/gui.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,17 @@
- *Auto Levels*: Check to enable automatically setting color levels of the displayed objects.
- *Min*: Minimum colormap value.
- *Max*: Maximum colormap value.
- *Slices*
- *Y-Z*: Toggle the visibility of the slice in the y-z plane.
- *X-Z*: Toggle the visibility of the slice in the x-z plane.
- *X-Y*: Toggle the visibility of the slice in the x-y plane.
- *Reset*: Click to reset the positions and orientations of all the slices.
- *Show volume*: Check to display the low-resolution 3D volume.
- *Slice 1/2/3*
- *2D*: Check to display the 2D high-resolution slice.
- *3D*: Check to display the 3D high-resolution slab (TBD).
- *Disable*: Check to hide the slice.
- *Reset all slices*: Click to reset the positions and orientations of all the slices.
- *Show slice histograms*: Check to display the pixel value histogram for each slice.
- *Volume*
- *Preview*: Check to use the 3D reconstructed volume as preview.
- *Show*: Check to display the 3D reconstructed volume.
- *Disable*: Check to disable the reconstruction of the 3D volume. As a result,
there will be no preview when moving a slice.
- *Alpha*: Opacity of the low-resolution 3D volume.

## Manipulating 3D model with mouse and keyboard
Expand Down
24 changes: 15 additions & 9 deletions gui/include/graphics/items/recon_item.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,10 @@ class Wireframe;
class ReconItem : public GraphicsItem, public GraphicsGLItem, public GraphicsDataItem {

enum class DragType : int { none, rotator, translator};

enum SlicePolicy { SHOW2D_SLI = 0, SHOW3D_SLI = 1, DISABLE_SLI = 2};

enum {
Slice_YZ = 0,
Slice_XZ = 1,
Slice_XY = 2
};
enum VolumePolicy { PREVIEW_VOL = 0, SHOW_VOL = 1, DISABLE_VOL = 2};

class DragMachine {

Expand Down Expand Up @@ -86,9 +84,7 @@ class ReconItem : public GraphicsItem, public GraphicsGLItem, public GraphicsDat
friend class SliceRotator;

std::vector<std::pair<uint64_t, std::unique_ptr<Slice>>> slices_;
std::unique_ptr<Volume> volume_;

std::unique_ptr<Wireframe> wireframe_;
std::array<int, MAX_NUM_SLICES> slice_policies_ { SHOW2D_SLI, SHOW2D_SLI, SHOW2D_SLI };

GLuint rotation_axis_vao_;
GLuint rotation_axis_vbo_;
Expand All @@ -103,9 +99,12 @@ class ReconItem : public GraphicsItem, public GraphicsGLItem, public GraphicsDat
float min_val_;
float max_val_;

bool show_volume_ = false;
std::unique_ptr<Volume> volume_;
int volume_policy_ = PREVIEW_VOL;
float volume_alpha_ = 1.f;

std::unique_ptr<Wireframe> wireframe_;

glm::mat4 matrix_;

bool show_statistics_ = true;
Expand All @@ -119,8 +118,15 @@ class ReconItem : public GraphicsItem, public GraphicsGLItem, public GraphicsDat

void initSlices();

template<size_t index>
void renderImSliceControl(const char* header);

void renderImVolumeControl();

bool updateServerSliceParams();

bool updateServerVolumeParams();

void updateHoveringSlice(float x, float y);

std::vector<Slice*> sortedSlices() const;
Expand Down
4 changes: 1 addition & 3 deletions gui/include/graphics/slice.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ class Slice {
using SizeType = std::array<size_t, 2>;
using Orient4Type = glm::mat4;

friend class ReconItem;

private:

int id_ = -1;
Expand Down Expand Up @@ -73,7 +71,7 @@ class Slice {

[[nodiscard]] bool visible() const { return visible_; }

void show(bool visible) { visible_ = visible; }
void setVisible(bool visible) { visible_ = visible; }

[[nodiscard]] bool transparent() const;

Expand Down
3 changes: 2 additions & 1 deletion gui/include/graphics/style.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,13 @@ struct Style {
colors[ImGuiCol_WindowBg] = ImVec4(0.06f, 0.06f, 0.06f, 0.05f);
colors[ImGuiCol_Border] = ImVec4(0.43f, 0.43f, 0.50f, 0.00f);
colors[ImGuiCol_FrameBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.60f);
colors[ImGuiCol_Header] = ImVec4(0.00f, 0.00f, 0.00f, 0.20f);
colors[ImGuiCol_TitleBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.40f);
colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.00f, 0.00f, 0.00f, 0.30f);
colors[ImGuiCol_CheckMark] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
colors[ImGuiCol_Button] = ImVec4(0.00f, 0.00f, 0.00f, 0.30f);
colors[ImGuiCol_Separator] = ImVec4(0.90f, 0.90f, 0.90f, 0.60f);

colors[ImGuiCol_SliderGrab] = ImVec4(0.40f, 0.40f, 0.40f, 0.80f);
}

};
Expand Down
2 changes: 2 additions & 0 deletions gui/include/graphics/volume.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ class Volume {

void setData(DataType&& data, const SizeType& size);

void clearData();

void render(const glm::mat4& view,
const glm::mat4& projection,
float min_v,
Expand Down
2 changes: 2 additions & 0 deletions gui/include/rpc_client.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ class RpcClient {

bool setSlice(uint64_t timestamp, const Orientation& orientation);

bool setVolume(bool required);

void start();
};

Expand Down
18 changes: 12 additions & 6 deletions gui/include/utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,21 +40,27 @@ std::tuple<bool, float, glm::vec3> intersectionPoint(const glm::mat4& inv_matrix

class FpsCounter {

int frames_ = 0;
double prev_;
double threshold_;
double fps_ = 0.;
int v_frames_ = 0;
double v_prev_;
double v_fps_ = 0.;

int s_frames_ = 0;
double s_prev_;
double s_fps_ = 0.;

double threshold_;
static constexpr double reset_interval_ = 5.;

public:

FpsCounter();
~FpsCounter();

void update();
void countVolume();
void countSlice();

[[nodiscard]] double frameRate();
[[nodiscard]] double volumeFrameRate();
[[nodiscard]] double sliceFrameRate();
};

inline std::ostream& operator<<(std::ostream& stream, const glm::vec3& v) {
Expand Down
111 changes: 78 additions & 33 deletions gui/src/graphics/items/recon_item.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ void ReconItem::renderIm() {
ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "RECONSTRUCTION");

auto& cmd = Colormap::data();
if (ImGui::BeginCombo("Colormap##Widget", cmd.GetName(cm_.get()))) {
if (ImGui::BeginCombo("Colormap##RECON", cmd.GetName(cm_.get()))) {
for (auto idx : Colormap::options()) {
const char* name = cmd.GetName(idx);
if (ImGui::Selectable(name, cm_.get() == idx)) {
Expand All @@ -88,28 +88,16 @@ void ReconItem::renderIm() {
ImGui::DragFloatRange2("Min / Max", &min_val_, &max_val_, step_size,
std::numeric_limits<float>::lowest(), // min() does not work
std::numeric_limits<float>::max());
ImGui::AlignTextToFramePadding();
ImGui::Text("Slices: ");
ImGui::SameLine();
ImGui::Checkbox("Y-Z##RECON", &slices_[Slice_YZ].second->visible_);
ImGui::SameLine();
ImGui::Checkbox("X-Z##RECON", &slices_[Slice_XZ].second->visible_);
ImGui::SameLine();
ImGui::Checkbox("X-Y##RECON", &slices_[Slice_XY].second->visible_);
ImGui::SameLine();
if(ImGui::Button("Reset")) {

renderImSliceControl<0>("Slice 1##RECON");
renderImSliceControl<1>("Slice 2##RECON");
renderImSliceControl<2>("Slice 3##RECON");

if (ImGui::Button("Reset all slices")) {
initSlices();
updateServerSliceParams();
}

ImGui::Checkbox("Show volume", &show_volume_);
ImGui::SameLine();
ImGui::BeginDisabled(!show_volume_);
ImGui::PushItemWidth(-40);
ImGui::SliderFloat("Alpha", &volume_alpha_, 0.0f, 1.0f);
ImGui::PopItemWidth();
ImGui::EndDisabled();

ImGui::Checkbox("Show slice histograms", &show_statistics_);
if (show_statistics_) {
ImGui::SetNextWindowPos(st_win_pos_);
Expand All @@ -136,9 +124,12 @@ void ReconItem::renderIm() {
ImGui::End();
}

renderImVolumeControl();

ImGui::Separator();

scene_.setStatus("tomoUpdateFrameRate", fps_counter_.frameRate());
scene_.setStatus("volumeUpdateFrameRate", fps_counter_.volumeFrameRate());
scene_.setStatus("sliceUpdateFrameRate", fps_counter_.sliceFrameRate());
}

void ReconItem::onFramebufferSizeChanged(int /* width */, int /* height */) {}
Expand All @@ -164,7 +155,7 @@ void ReconItem::renderGl() {
}
volume_->unbind();

if (show_volume_) {
if (volume_policy_ == SHOW_VOL) {
volume_->render(view, projection, min_val, max_val_, volume_alpha_);
}

Expand All @@ -189,7 +180,7 @@ void ReconItem::renderGl() {
}

bool ReconItem::updateServerParams() {
return updateServerSliceParams();
return updateServerSliceParams() || updateServerVolumeParams();
}

void ReconItem::setSliceData(const std::string& data,
Expand Down Expand Up @@ -228,13 +219,14 @@ bool ReconItem::consume(const DataType& packet) {
if (data.has_slice()) {
auto& slice = data.slice();
setSliceData(slice.data(), {slice.row_count(), slice.col_count()}, slice.timestamp());
fps_counter_.countSlice();
return true;
}

if (data.has_volume()) {
if (volume_policy_ != DISABLE_VOL && data.has_volume()) {
auto& volume = data.volume();
setVolumeData(volume.data(), {volume.row_count(), volume.col_count(), volume.slice_count()});
fps_counter_.update();
fps_counter_.countVolume();
return true;
}
}
Expand Down Expand Up @@ -315,19 +307,68 @@ void ReconItem::initSlices() {
assert(slices_.size() == MAX_NUM_SLICES);

// slice along axis 0 = x
slices_[Slice_YZ].second->setOrientation(glm::vec3(0.0f, -1.0f, -1.0f),
glm::vec3(0.0f, 2.0f, 0.0f),
glm::vec3(0.0f, 0.0f, 2.0f));
slices_[0].second->setOrientation(glm::vec3( 0.0f, -1.0f, -1.0f),
glm::vec3( 0.0f, 2.0f, 0.0f),
glm::vec3( 0.0f, 0.0f, 2.0f));

// slice along axis 1 = y
slices_[Slice_XZ].second->setOrientation(glm::vec3(-1.0f, 0.0f, -1.0f),
glm::vec3(2.0f, 0.0f, 0.0f),
glm::vec3(0.0f, 0.0f, 2.0f));
slices_[1].second->setOrientation(glm::vec3(-1.0f, 0.0f, -1.0f),
glm::vec3( 2.0f, 0.0f, 0.0f),
glm::vec3( 0.0f, 0.0f, 2.0f));

// slice along axis 2 = z
slices_[Slice_XY].second->setOrientation(glm::vec3(-1.0f, -1.0f, 0.0f),
glm::vec3(2.0f, 0.0f, 0.0f),
glm::vec3(0.0f, 2.0f, 0.0f));
slices_[2].second->setOrientation(glm::vec3(-1.0f, -1.0f, 0.0f),
glm::vec3( 2.0f, 0.0f, 0.0f),
glm::vec3( 0.0f, 2.0f, 0.0f));
}

template<size_t index>
void ReconItem::renderImSliceControl(const char* header) {

static const char* BTN_2D[] = {"2D##RECON_SLI_0", "2D##RECON_SLI_1", "2D##RECON_SLI_2"};
static const char* BTN_3D[] = {"3D##RECON_SLI_0", "3D##RECON_SLI_1", "3D##RECON_SLI_2"};
static const char* BTN_DISABLE[] = {"Disable##RECON_SLI_0", "Disable##RECON_SLI_1", "Disable##RECON_SLI_2"};

static const ImVec4 K_HEADER_COLOR = (ImVec4)ImColor(65, 145, 151);
ImGui::PushStyleColor(ImGuiCol_Header, K_HEADER_COLOR);
bool expand = ImGui::CollapsingHeader(header, ImGuiTreeNodeFlags_DefaultOpen);
ImGui::PopStyleColor();
if (expand) {
bool cd = false;

cd |= ImGui::RadioButton(BTN_2D[index], &slice_policies_[index], SHOW2D_SLI);
ImGui::SameLine();
cd |= ImGui::RadioButton(BTN_3D[index], &slice_policies_[index], SHOW3D_SLI);
ImGui::SameLine();
cd |= ImGui::RadioButton(BTN_DISABLE[index], &slice_policies_[index], DISABLE_SLI);

if (cd) slices_[index].second->setVisible(slice_policies_[index] != DISABLE_SLI);
}
}

void ReconItem::renderImVolumeControl() {
static const ImVec4 K_HEADER_COLOR = (ImVec4)ImColor(65, 145, 151);
ImGui::PushStyleColor(ImGuiCol_Header, K_HEADER_COLOR);
bool expand = ImGui::CollapsingHeader("Volume##RECON", ImGuiTreeNodeFlags_DefaultOpen);
ImGui::PopStyleColor();

if (expand) {
bool cd = false;
cd |= ImGui::RadioButton("Preview##RECON_VOL", &volume_policy_, PREVIEW_VOL);
ImGui::SameLine();
cd |= ImGui::RadioButton("Show##RECON_VOL", &volume_policy_, SHOW_VOL);
ImGui::SameLine();
bool disabled = ImGui::RadioButton("Disable##RECON_VOL", &volume_policy_, DISABLE_VOL);
cd |= disabled;

if (cd) updateServerVolumeParams();
if (disabled) {
volume_->clearData();
maybeUpdateMinMaxValues();
}

ImGui::SliderFloat("Alpha##RECON_VOL", &volume_alpha_, 0.0f, 1.0f);
}
}

bool ReconItem::updateServerSliceParams() {
Expand All @@ -339,6 +380,10 @@ bool ReconItem::updateServerSliceParams() {
return false;
}

bool ReconItem::updateServerVolumeParams() {
return scene_.client()->setVolume(volume_policy_ != DISABLE_VOL);
}

void ReconItem::updateHoveringSlice(float x, float y) {
auto inv_matrix = glm::inverse(matrix_);
int slice_id = -1;
Expand Down
7 changes: 4 additions & 3 deletions gui/src/graphics/items/statusbar_item.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,10 @@ void StatusbarItem::renderIm() {

auto& io = ImGui::GetIO();
ImGui::Text("GUI FPS: %.1f", io.Framerate);
ImGui::Text("Tomogram (update) FPS: %.1f",
std::any_cast<double>(scene_.getStatus("tomoUpdateFrameRate")));

ImGui::Text("Volume (update) FPS: %.1f",
std::any_cast<double>(scene_.getStatus("volumeUpdateFrameRate")));
ImGui::Text("Slice (update) FPS: %.1f",
std::any_cast<double>(scene_.getStatus("sliceUpdateFrameRate")));
ImGui::End();
}

Expand Down
10 changes: 10 additions & 0 deletions gui/src/graphics/volume.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,16 @@ void Volume::setData(DataType&& data, const SizeType& size) {
static_cast<int>(size_[2]));
}

void Volume::clearData() {
std::fill(data_.begin(), data_.end(), 0.f);
min_max_vals_ = {0.f, 0.f};

texture_.setData(data_,
static_cast<int>(size_[0]),
static_cast<int>(size_[1]),
static_cast<int>(size_[2]));
}

void Volume::render(const glm::mat4& view,
const glm::mat4& projection,
float min_v,
Expand Down
Loading

0 comments on commit 06e2436

Please sign in to comment.