4
$\begingroup$

I am trying to write a program to transform some XYZ coordinate data from a 3D scanner into a uniform grid. The goal is to be able to add or subtract future scans from the current scan. To do that, I group all coordinate sets that fall within a particular interval (x and y) and then average the value of z for that cell. Here is a synthetic example:

m = RandomInteger[{0, 10}, {50, 3}]

tablem = Table[
   Select[
    m, #[[2]] <= (i + 1)*1 && #[[2]] > i*1 && #[[1]] <= (j + 1)*1 && #[[1]] > j*1 &], {i, 0, 9}, {j, 0, 9}];

This gives me a 10x10 matrix containing all set of coordinates matching the coordinate rule.

My problem is that in some case, more than one coordinate set matches the rule (see example below). I want to replace these XYZ sets by one set, with the same x and y values but where the z value is the average of the z in all sets.

example

Any idea how to fix this? Also, any suggestions on other options to transform the XYZ data into a grid are welcome!

NB: Apologies for the poor image quality! This is my first post here.

Thank you for the help!

Rached

$\endgroup$
  • $\begingroup$ Something like ReplacePart[tablem, {i_, j_} /; Length[tablem[[i,j]]] > 1 :> {{j, i, Mean[tablem[[i, j]][[All, 3]]]}}] should work. There are probably more succinct way to write it. $\endgroup$ – Marius Ladegård Meyer Dec 5 '16 at 7:53
  • $\begingroup$ This works great! Thank you! $\endgroup$ – Rached Dec 5 '16 at 8:03
1
$\begingroup$

Try this:

m = RandomInteger[{0, 10}, {50, 3}];

Here I am not sure, if I am allowed to remove some extra curly braces. If yes,

tablem = Flatten[
  Table[Select[
    m, #[[2]] <= (i + 1)*1 && #[[2]] > 
       i*1 && #[[1]] <= (j + 1)*1 && #[[1]] > j*1 &], {i, 0, 9}, {j, 
    0, 9}], 1]

Let us define a function doing the job:

Clear[lst];
f[lst_] := 
 If[Length[lst] >= 2, 
   Transpose[
     lst] /. {x_List, y_List, z_List} -> {x // First, y // First, 
      Mean[z]}, If[Length[lst] > 0, First[lst], lst]] // Quiet

Now

tablem

returns this:

(*
{{{1, 1, 1}}, {}, {}, {}, {}, {{6, 1, 3}}, {}, {{8, 1, 5}}, {{9, 1, 
   8}}, {}, {{1, 2, 8}}, {}, {}, {}, {{5, 2, 9}}, {}, {{7, 2, 
   5}}, {}, {{9, 2, 10}}, {}, {}, {}, {{3, 3, 3}}, {{4, 3, 
   6}}, {}, {}, {}, {{8, 3, 6}}, {}, {{10, 3, 5}}, {}, {{2, 4, 
   6}}, {}, {}, {{5, 4, 4}, {5, 4, 0}}, {}, {}, {}, {{9, 4, 
   8}}, {}, {}, {}, {{3, 5, 7}}, {}, {}, {{6, 5, 2}}, {}, {}, {{9, 5, 
   5}, {9, 5, 1}}, {}, {}, {{2, 6, 0}}, {{3, 6, 10}}, {{4, 6, 
   7}}, {}, {}, {}, {{8, 6, 0}, {8, 6, 1}}, {{9, 6, 
   0}}, {}, {}, {}, {{3, 7, 3}, {3, 7, 2}}, {}, {}, {}, {{7, 7, 
   8}, {7, 7, 1}}, {}, {}, {}, {}, {{2, 8, 5}}, {{3, 8, 
   7}}, {}, {}, {}, {{7, 8, 7}}, {}, {}, {}, {}, {}, {{3, 9, 2}, {3, 
   9, 0}}, {}, {}, {}, {{7, 9, 
   10}}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {{7, 10, 3}}, {{8, 10, 
   5}, {8, 10, 10}}, {}, {}}
*)

and

Map[f, tablem]

returns this:

(*
{{}, {2, 1, 10}, {3, 1, 7}, {4, 1, 10}, {}, {6, 1, 
  5}, {}, {}, {}, {}, {}, {}, {3, 2, 
  3}, {}, {}, {}, {}, {}, {}, {}, {1, 3, 1}, {2, 3, 9}, {3, 3, 
  9}, {}, {}, {}, {}, {}, {9, 3, 6}, {}, {}, {2, 4, 3}, {3, 4, 9/
  2}, {}, {}, {6, 4, 5}, {}, {8, 4, 0}, {9, 4, 1}, {10, 4, 4}, {}, {2,
   5, 5}, {3, 5, 0}, {}, {5, 5, 5}, {}, {}, {}, {}, {10, 5, 
  2}, {}, {}, {}, {}, {}, {}, {7, 6, 5}, {}, {}, {10, 6, 
  2}, {}, {}, {3, 7, 6}, {}, {}, {}, {}, {8, 7, 5}, {9, 7, 10}, {10, 
  7, 9/2}, {}, {2, 8, 3}, {3, 8, 9/2}, {}, {}, {6, 8, 4}, {}, {}, {9, 
  8, 4}, {10, 8, 7}, {}, {}, {}, {4, 9, 10}, {}, {6, 9, 
  2}, {}, {}, {}, {10, 9, 8}, {}, {}, {}, {}, {}, {}, {}, {}, {9, 10, 
  3}, {10, 10, 5}}
*)

Hope it helps, have fun!

$\endgroup$
1
$\begingroup$

If you just want to add the values, then this gives you a matrix of the z-values:

mat = Mean /@ GroupBy[m, Most -> Last] // KeyMap[1 + # &] // Normal // SparseArray;
mat // MatrixForm

enter image description here

$\endgroup$
1
$\begingroup$

Perhaps

SeedRandom[1]
m = RandomInteger[{0, 5}, {20, 3}]

{{4, 2, 4}, {0, 1, 0}, {0, 2, 0}, {0, 3, 5}, {2, 0, 3}, {4, 4, 1}, {3, 3, 4}, {1, 4, 2}, {1, 1, 4}, {5, 4, 5}, {0, 3, 3}, {0, 0, 2}, {3, 1, 1}, {3, 2, 5}, {1, 1, 4}, {0, 1, 1}, {3, 5, 5}, {2, 3, 0}, {0, 2, 5}, {4, 5, 2}}

Join[#[[1, ;; 2]], {Mean[#[[All, 3]]]}] & /@ GatherBy[m , #[[;; 2]] &]

{{4, 2, 4}, {0, 1, 1/2}, {0, 2, 5/2}, {0, 3, 4}, {2, 0, 3}, {4, 4, 1},
{3, 3, 4}, {1, 4, 2}, {1, 1, 4}, {5, 4, 5}, {0, 0, 2}, {3, 1, 1},
{3, 2, 5}, {3, 5, 5}, {2, 3, 0}, {4, 5, 2}}

In version 10 and 11, you can use Merge:

Append @@@ Normal @ Merge[Mean][{#, #2} -> #3& @@@ m]

{{4, 2, 4}, {0, 1, 1/2}, {0, 2, 5/2}, {0, 3, 4}, {2, 0, 3}, {4, 4, 1},
{3, 3, 4}, {1, 4, 2}, {1, 1, 4}, {5, 4, 5}, {0, 0, 2}, {3, 1, 1},
{3, 2, 5}, {3, 5, 5}, {2, 3, 0}, {4, 5, 2}}

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.