Skip to content

Commit

Permalink
Update DummyLoader after API upgrade
Browse files Browse the repository at this point in the history
Only an API update so far. Actual color-flow support will be added in a later PR.
  • Loading branch information
Fredrik Orderud committed Feb 20, 2020
1 parent f3000de commit 99d48be
Show file tree
Hide file tree
Showing 8 changed files with 270 additions and 147 deletions.
10 changes: 10 additions & 0 deletions DummyLoader/DummyLoader.idl
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,16 @@ library DummyLoader
{
importlib("stdole2.tlb");

[
version(1.2),
uuid(78317A0E-56BF-4735-AB5B-FE0751219FE8),
helpstring("3D image stream")
]
coclass Image3dStream
{
[default] interface IImage3dStream;
};

[
version(1.2),
uuid(6FA82ED5-6332-4344-8417-DEA55E72098C),
Expand Down
Binary file modified DummyLoader/DummyLoader.rc
Binary file not shown.
160 changes: 24 additions & 136 deletions DummyLoader/Image3dSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
#include "LinAlg.hpp"


static const uint8_t OUTSIDE_VAL = 0; // black outside image volume
static const uint8_t PROBE_PLANE = 127; // gray value for plane closest to probe


Image3dSource::Image3dSource() {
Expand Down Expand Up @@ -45,173 +43,63 @@ Image3dSource::Image3dSource() {
0.20f,0, 0, // dir1 (width)
0, 0.10f, 0, // dir2 (depth)
0, 0, 0.15f};// dir3 (elevation)
m_img_geom = geom;
}
{
// checker board image data
unsigned short dims[] = { 20, 15, 10 }; // matches length of dir1, dir2 & dir3, so that the image squares become quadratic
std::vector<byte> img_buf(dims[0] * dims[1] * dims[2]);
for (size_t frameNumber = 0; frameNumber < numFrames; ++frameNumber) {
for (unsigned int z = 0; z < dims[2]; ++z) {
for (unsigned int y = 0; y < dims[1]; ++y) {
for (unsigned int x = 0; x < dims[0]; ++x) {
bool even_f = (frameNumber / 2 % 2) == 0;
bool even_x = (x / 2 % 2) == 0;
bool even_y = (y / 2 % 2) == 0;
bool even_z = (z / 2 % 2) == 0;
byte & out_sample = img_buf[x + y*dims[0] + z*dims[0] * dims[1]];
if (even_f ^ even_x ^ even_y ^ even_z)
out_sample = 255;
else
out_sample = 0;
}
}
}

// special grayscale value for plane closest to probe
for (unsigned int z = 0; z < dims[2]; ++z) {
for (unsigned int x = 0; x < dims[0]; ++x) {
unsigned int y = 0;
byte & out_sample = img_buf[x + y*dims[0] + z*dims[0] * dims[1]];
out_sample = PROBE_PLANE;
}
}

m_frames.push_back(CreateImage3d(frameNumber*(duration/numFrames) + startTime, IMAGE_FORMAT_U8, dims, img_buf));
}
m_bbox = geom;
}

// a single tissue stream
m_stream_types.push_back(IMAGE_TYPE_TISSUE);
}

Image3dSource::~Image3dSource() {
}


HRESULT Image3dSource::GetFrameCount(/*out*/unsigned int *size) {
HRESULT Image3dSource::GetStreamCount(/*out*/unsigned int *size) {
if (!size)
return E_INVALIDARG;

*size = static_cast<unsigned int>(m_frames.size());
return S_OK;
}

HRESULT Image3dSource::GetFrameTimes(/*out*/SAFEARRAY * *frame_times) {
if (!frame_times)
return E_INVALIDARG;

const unsigned int N = static_cast<unsigned int>(m_frames.size());
CComSafeArray<double> result(N);
if (N > 0) {
double * time_arr = &result.GetAt(0);
for (unsigned int i = 0; i < N; ++i)
time_arr[i] = m_frames[i].time;
}

*frame_times = result.Detach();
*size = static_cast<unsigned int>(m_stream_types.size());
return S_OK;
}


/** Convert from normalized voxel pos in [0,1) to (x,y,z) coordinate. */
static vec3f PosToCoord (vec3f origin, vec3f dir1, vec3f dir2, vec3f dir3, const vec3f pos) {
mat33f M;
col_assign(M, 0, dir1);
col_assign(M, 1, dir2);
col_assign(M, 2, dir3);

return prod(M, pos) + origin;
}


/** Convert from (x,y,z) coordinate to normalized voxel pos in [0,1). */
static vec3f CoordToPos (Cart3dGeom geom, const vec3f xyz) {
const vec3f origin(geom.origin_x, geom.origin_y, geom.origin_z);
const vec3f dir1(geom.dir1_x, geom.dir1_y, geom.dir1_z);
const vec3f dir2(geom.dir2_x, geom.dir2_y, geom.dir2_z);
const vec3f dir3(geom.dir3_x, geom.dir3_y, geom.dir3_z);

mat33f M;
col_assign(M, 0, dir1);
col_assign(M, 1, dir2);
col_assign(M, 2, dir3);

return prod(inv(M), xyz - origin);
}


static unsigned char SampleVoxel (const Image3d & frame, const vec3f pos) {
// out-of-bounds checking
if ((pos.x < 0) || (pos.y < 0) || (pos.z < 0))
return OUTSIDE_VAL;

auto x = static_cast<unsigned int>(frame.dims[0] * pos.x);
auto y = static_cast<unsigned int>(frame.dims[1] * pos.y);
auto z = static_cast<unsigned int>(frame.dims[2] * pos.z);

// out-of-bounds checking
if ((x >= frame.dims[0]) || (y >= frame.dims[1]) || (z >= frame.dims[2]))
return OUTSIDE_VAL;

return static_cast<unsigned char*>(frame.data->pvData)[x + y*frame.stride0 + z*frame.stride1];
}


Image3d Image3dSource::SampleFrame (const Image3d & frame, Cart3dGeom out_geom, unsigned short max_res[3]) {
if (max_res[2] == 0)
max_res[2] = 1; // require at least one plane to to retrieved

vec3f out_origin(out_geom.origin_x, out_geom.origin_y, out_geom.origin_z);
vec3f out_dir1(out_geom.dir1_x, out_geom.dir1_y, out_geom.dir1_z);
vec3f out_dir2(out_geom.dir2_x, out_geom.dir2_y, out_geom.dir2_z);
vec3f out_dir3(out_geom.dir3_x, out_geom.dir3_y, out_geom.dir3_z);

// allow 3rd axis to be empty if only retrieving a single slice
if ((out_dir3 == vec3f(0, 0, 0)) && (max_res[2] < 2))
out_dir3 = cross_prod(out_dir1, out_dir2);

// sample image buffer
std::vector<unsigned char> img_buf(max_res[0] * max_res[1] * max_res[2], 127);
for (unsigned short z = 0; z < max_res[2]; ++z) {
for (unsigned short y = 0; y < max_res[1]; ++y) {
for (unsigned short x = 0; x < max_res[0]; ++x) {
// convert from input texture coordinate to output texture coordinate
vec3f pos_in(x*1.0f/max_res[0], y*1.0f/max_res[1], z*1.0f/max_res[2]);
vec3f xyz = PosToCoord(out_origin, out_dir1, out_dir2, out_dir3, pos_in);
vec3f pos_out = CoordToPos(m_img_geom, xyz);

unsigned char val = SampleVoxel(frame, pos_out);
img_buf[x + y*max_res[0] + z*max_res[0] * max_res[1]] = val;
}
}
}

return CreateImage3d(frame.time, IMAGE_FORMAT_U8, max_res, img_buf);
}

HRESULT Image3dSource::GetFrame(unsigned int index, Cart3dGeom out_geom, unsigned short max_res[3], /*out*/Image3d *data) {
if (!data)
HRESULT Image3dSource::GetStream(int index, Cart3dGeom out_geom, unsigned short max_resolution[3], /*out*/IImage3dStream ** stream) {
if (!stream)
return E_INVALIDARG;
if (index >= m_frames.size())
if (index >= m_stream_types.size())
return E_BOUNDS;

Image3d result = SampleFrame(m_frames[index], out_geom, max_res);
*data = std::move(result);
CComPtr<IImage3dStream> stream_obj;
{
// on-demand stream creation
auto stream_cls = CreateLocalInstance<Image3dStream>();
stream_cls->Initialize(m_stream_types[index], m_bbox, out_geom, max_resolution);
stream_obj = stream_cls; // cast class pointer to interface
}

*stream = stream_obj.Detach();
return S_OK;
}

HRESULT Image3dSource::GetBoundingBox(/*out*/Cart3dGeom *geom) {
if (!geom)
return E_INVALIDARG;

*geom = m_img_geom;
*geom = m_bbox;
return S_OK;
}

HRESULT Image3dSource::GetColorMap(/*out*/SAFEARRAY ** map) {
HRESULT Image3dSource::GetColorMap(ColorMapType type, /*out*/ImageFormat * format, /*out*/SAFEARRAY ** map) {
if (!map)
return E_INVALIDARG;
if (*map)
return E_INVALIDARG;

if (type != TYPE_TISSUE_COLOR)
return E_NOT_SET;

*format = IMAGE_FORMAT_R8G8B8A8;
// copy to new buffer
CComSafeArray<unsigned int> color_map(static_cast<unsigned int>(m_color_map.size()));
memcpy(&color_map.GetAt(0), m_color_map.data(), sizeof(m_color_map));
Expand Down
14 changes: 6 additions & 8 deletions DummyLoader/Image3dSource.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,21 @@ class ATL_NO_VTABLE Image3dSource :

/*NOT virtual*/ ~Image3dSource();

HRESULT STDMETHODCALLTYPE GetFrameCount(/*out*/unsigned int *size) override;

HRESULT STDMETHODCALLTYPE GetFrameTimes(/*out*/SAFEARRAY * *frame_times) override;
HRESULT STDMETHODCALLTYPE GetStreamCount (/*out*/unsigned int * size) override;

HRESULT STDMETHODCALLTYPE GetFrame(unsigned int index, Cart3dGeom out_geom, unsigned short max_res[3], /*out*/Image3d *data) override;
HRESULT STDMETHODCALLTYPE GetStream (int index, Cart3dGeom out_geom, unsigned short max_resolution[3], /*out*/IImage3dStream ** stream) override;

HRESULT STDMETHODCALLTYPE GetBoundingBox(/*out*/Cart3dGeom *geom) override;

HRESULT STDMETHODCALLTYPE GetColorMap(/*out*/SAFEARRAY ** map) override;
HRESULT STDMETHODCALLTYPE GetColorMap(ColorMapType type, /*out*/ImageFormat * format, /*out*/SAFEARRAY ** map) override;

HRESULT STDMETHODCALLTYPE GetECG(/*out*/EcgSeries *ecg) override;

HRESULT STDMETHODCALLTYPE GetProbeInfo(/*out*/ProbeInfo *probe) override;

HRESULT STDMETHODCALLTYPE GetSopInstanceUID(/*out*/BSTR *uid_str) override;

Image3d SampleFrame (const Image3d & frame, Cart3dGeom out_geom, unsigned short max_res[3]);

DECLARE_REGISTRY_RESOURCEID(IDR_Image3dSource)

BEGIN_COM_MAP(Image3dSource)
Expand All @@ -44,8 +41,9 @@ class ATL_NO_VTABLE Image3dSource :
ProbeInfo m_probe;
EcgSeries m_ecg;
std::array<R8G8B8A8,256> m_color_map;
Cart3dGeom m_img_geom = {};
std::vector<Image3d> m_frames;

Cart3dGeom m_bbox = {};
std::vector<ImageType> m_stream_types;
};

OBJECT_ENTRY_AUTO(__uuidof(Image3dSource), Image3dSource)
Loading

0 comments on commit 99d48be

Please sign in to comment.