title: How to find boundary voxels (pixels) using a binary mask, to get only the segment surface
body: <p>His is my first question here, so please direct me if anything. I briefly describe the situation: there is a voxel set of sizes 512x512xN (N is the number of tomography slices) (new BitArray (512x512xN)). As a result of one of the segmentation algorithms, the indices of the filled voxels in this set are obtained; the BitArray array is used to indicate the required voxels, where indices with the value true are the segment and false is the background. So I would like to know how to find boundary voxels (pixels) using a binary mask, which stores their coordinates (x, y, z) and background information or not (true - false)), to get only the segment envelope. Here is the code for defining the bounding indices, but it is not correct:</p>
  <pre><code>private static async Task&lt;BitArray&gt; EdgeArray(Vector3Int size, BitArray data)
      {
          return await Task.Run(() =&gt;
          {
              var edges = new BitArray(data.Length);
              var mask3d = new Dictionary&lt;Vector3Int,bool&gt;();
  
              Parallel.For(0, data.Count, i =&gt;
              {
                  lock (mask3d)
                  {
                      mask3d.Add(size.GetIndex3D(i),data[i]);
                  }
              });
  
              var voxels = mask3d.Keys.ToList();
  
              Parallel.For(0, voxels.Count, i =&gt;
              {
                  if (voxels[i].x == 0 || voxels[i].x == size.x - 1 || voxels[i].y == 0 ||
                      voxels[i].y == size.y - 1 || voxels[i].z == 0 || voxels[i].z == size.z - 1)
                  {
                      if (mask3d[voxels[i]])
                      {
                          var index = voxels[i].ToIndex3D(size.x, size.y, size.z);
                          edges[index] = true;
                          Debug.Log(index);
                      }
                  }
                  else
                  {
                      if (mask3d[voxels[i]] &amp;&amp; (!mask3d[voxels[i-1]] || !mask3d[voxels[i+1]]))
                      {
                          var index = voxels[i].ToIndex3D(size.x, size.y, size.z);
                          edges[index] = true;
                          Debug.Log(index);
                      }
                  }
              });
              return edges;
          });
      }
  </code></pre>
  <p>Secondary functions:</p>
  <pre><code>/// &lt;summary&gt;
      /// returns the index in the 3d representation
      /// &lt;/summary&gt;
      /// &lt;param name=&quot;vector3Int&quot;&gt; array size in 3d representation &lt;/param&gt;
      /// &lt;param name=&quot;index&quot;&gt; 1d index &lt;/param&gt;
      /// &lt;returns&gt;index in the 3d representation&lt;/returns&gt;
      public static Vector3Int GetIndex3D(this Vector3Int vector3Int, int index)
      {
          return new Vector3Int
          {
              z = index / (vector3Int.x * vector3Int.y),
              y = index % (vector3Int.x * vector3Int.y) / vector3Int.x,
              x = index % (vector3Int.x * vector3Int.y) % vector3Int.x
          };
      }
      
  public static int ToIndex3D(this Vector3Int vector3Int, int width, int height, int depth)
      {
          return vector3Int.z * width * height + vector3Int.y * width + vector3Int.x*depth;
      }
  </code></pre>