niessner / Opt

Opt DSL
Other
256 stars 68 forks source link

corrupt values of the unknowns after a call to copyImage() #121

Closed dgrzech closed 6 years ago

dgrzech commented 6 years ago

hi!

it's likely that i made a mistake somewhere with the indexing of arrays but i'm really struggling to find it, so here goes my question..

i'm running a simple program which uses opt where i try to find the parameters of translation that would transform one 3-d vertex into another using values stored in deformation nodes that are the nearest neighbours of a vertex.

the vertices are:

auto sourceVertex = pcl::PointXYZ(0, 0.05, 1);
auto sourceNormal = pcl::Normal(1, 1, 1);

auto targetVertex = pcl::PointXYZ(0.01, 0.06, 1);
auto targetNormal = pcl::Normal(1, 1, 1);

the obvious solution is that

translation.x = 0.01 translation.y = 0.01 translation.z = 0

this is my energy function:

local D,N = Dim("D",0), Dim("N",1)

local transformation = Unknown("transformation",float3,{D},0)

local canonicalVertices = Array("canonicalVertices",float3,{N},1)
local canonicalNormals = Array("canonicalNormals",float3,{N},2)

local liveVertices = Array("liveVertices",float3,{N},3)
local liveNormals = Array("liveNormals",float3,{N},4)

local G = Graph("dataGraph", 5,
                    "v", {N}, 6,
                    "n0", {D}, 7,
                    "n1", {D}, 8,
                    "n2", {D}, 9,
                    "n3", {D}, 10,
                    "n4", {D}, 11,
                    "n5", {D}, 12,
                    "n6", {D}, 13,
                    "n7", {D}, 14)

Energy(liveVertices(G.v) - canonicalVertices(G.v) - transformation(G.n0))

where D = 8 (no. of nearest neighbours, of which for now i'm only using 1) and N = 1.

the initial cost value is correctly 0.0002 and it is brought down to 0 as expected. however, after i copy the values of transformations back to the cpu via:

unsigned int D = 8;
std::vector<float3> h_transformation(D);

m_transformation->copyTo(h_transformation);

the values stored in the vector are:

0.01 0.01 0 0.01 0.01 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

which is clearly wrong because only one deformation node should be updated. m_transformation is initialised as follows:

std::vector<unsigned int> v = {D};
std::shared_ptr<OptImage> m_transformation = createEmptyOptImage(v, OptImage::Type::FLOAT, 3, OptImage::GPU, true);

where am i going wrong? why are 2 entries of the vector being set to (0.01, 0.01, 0) instead of just one?

when i change the energy term to:

local nodes = { 0, 1, 2, 3, 4, 5, 6, 7 }
local totalTransformation = 0

for _,i in ipairs(nodes) do
  totalTransformation = totalTransformation + transformation(G["n"..i])
end

Energy(liveVertices(G.v) - canonicalVertices(G.v) - totalTransformation)

the values are correct, but not if the nodes array stores any less than 8 indices.

thanks in advance for your help!

Mx7f commented 6 years ago

What does the graph you are passing in look like in terms of number of hyperedges and indices for each hyperedge?

dgrzech commented 6 years ago

hi!

the graph has 9 hyperedges. this is how i initialise it:

std::vector<std::vector<int>> indices(9, std::vector<int>(N));

    for (int count = 0; count < N; count++) {
        indices[0].push_back(count);

        auto vertexNeighboursIdx = m_warpfield.findNeighborsIndex(KNN, m_canonicalVerticesPCL[count]);

        for (int i = 1; i < indices.size(); i++) {
            indices[i].push_back(vertexNeighboursIdx[i - 1]);
        }
    }

    m_dataGraph = std::make_shared<OptGraph>(indices);

it's as simple as it gets i think. vertexNeighboursIdx does not contain double entries and the indices are in the range of 0 to 7 to correspond to the no. of deformation nodes

dgrzech commented 6 years ago

clearly the problem was with the index vector.. thanks for pointing my attention in that direction