docstr: Make a table that captures the graph relationship of the skeleton
  
  skeleton - binary skeleton image + outline of seed objects
  skeleton_labels - labels matrix of skeleton
  trunks - binary image with trunk points as 1
  branchpoints - binary image with branchpoints as 1
  endpoints - binary image with endpoints as 1
  image - image for intensity measurement
  
  returns two tables.
  Table 1: edge table
  The edge table is a numpy record array with the following named
  columns in the following order:
  v1: index into vertex table of first vertex of edge
  v2: index into vertex table of second vertex of edge
  length: # of intermediate pixels + 2 (for two vertices)
  total_intensity: sum of intensities along the edge
  
  Table 2: vertex table
  The vertex table is a numpy record array:
  i: I coordinate of the vertex
  j: J coordinate of the vertex
  label: the vertex's label
  kind: kind of vertex = "T" for trunk, "B" for branchpoint or "E" for endpoint.
docstr_tok: ["Make","a","table","that","captures","the","graph","relationship","of","the","skeleton","skeleton","-","binary","skeleton","image","+","outline","of","seed","objects","skeleton_labels","-","labels","matrix","of","skeleton","trunks","-","binary","image","with","trunk","points","as","1","branchpoints","-","binary","image","with","branchpoints","as","1","endpoints","-","binary","image","with","endpoints","as","1","image","-","image","for","intensity","measurement","returns","two","tables",".","Table","1",":","edge","table","The","edge","table","is","a","numpy","record","array","with","the","following","named","columns","in","the","following","order",":","v1",":","index","into","vertex","table","of","first","vertex","of","edge","v2",":","index","into","vertex","table","of","second","vertex","of","edge","length",":","#","of","intermediate","pixels","+","2","(","for","two","vertices",")","total_intensity",":","sum","of","intensities","along","the","edge","Table","2",":","vertex","table","The","vertex","table","is","a","numpy","record","array",":","i",":","I","coordinate","of","the","vertex","j",":","J","coordinate","of","the","vertex","label",":","the","vertex","'s","label","kind",":","kind","of","vertex","=","``","T","''","for","trunk",",","``","B","''","for","branchpoint","or","``","E","''","for","endpoint","."]
code: def make_objskeleton_graph(
      self,
      skeleton,
      skeleton_labels,
      trunks,
      branchpoints,
      endpoints,
      image,
  ):
      """Make a table that captures the graph relationship of the skeleton
  
      skeleton - binary skeleton image + outline of seed objects
      skeleton_labels - labels matrix of skeleton
      trunks - binary image with trunk points as 1
      branchpoints - binary image with branchpoints as 1
      endpoints - binary image with endpoints as 1
      image - image for intensity measurement
  
      returns two tables.
      Table 1: edge table
      The edge table is a numpy record array with the following named
      columns in the following order:
      v1: index into vertex table of first vertex of edge
      v2: index into vertex table of second vertex of edge
      length: # of intermediate pixels + 2 (for two vertices)
      total_intensity: sum of intensities along the edge
  
      Table 2: vertex table
      The vertex table is a numpy record array:
      i: I coordinate of the vertex
      j: J coordinate of the vertex
      label: the vertex's label
      kind: kind of vertex = "T" for trunk, "B" for branchpoint or "E" for endpoint.
      """
      i, j = numpy.mgrid[0 : skeleton.shape[0], 0 : skeleton.shape[1]]
      #
      # Give each point of interest a unique number
      #
      points_of_interest = trunks | branchpoints | endpoints
      number_of_points = numpy.sum(points_of_interest)
      #
      # Make up the vertex table
      #
      tbe = numpy.zeros(points_of_interest.shape, "|S1")
      tbe[trunks] = "T"
      tbe[branchpoints] = "B"
      tbe[endpoints] = "E"
      i_idx = i[points_of_interest]
      j_idx = j[points_of_interest]
      poe_labels = skeleton_labels[points_of_interest]
      tbe = tbe[points_of_interest]
      vertex_table = {
          self.VF_I: i_idx,
          self.VF_J: j_idx,
          self.VF_LABELS: poe_labels,
          self.VF_KIND: tbe,
      }
      #
      # First, break the skeleton by removing the branchpoints, endpoints
      # and trunks
      #
      broken_skeleton = skeleton & (~points_of_interest)
      #
      # Label the broken skeleton: this labels each edge differently
      #
      edge_labels, nlabels = centrosome.cpmorphology.label_skeleton(
          skeleton
      )
      #
      # Reindex after removing the points of interest
      #
      edge_labels[points_of_interest] = 0
      if nlabels > 0:
          indexer = numpy.arange(nlabels + 1)
          unique_labels = numpy.sort(numpy.unique(edge_labels))
          nlabels = len(unique_labels) - 1
          indexer[unique_labels] = numpy.arange(len(unique_labels))
          edge_labels = indexer[edge_labels]
          #
          # find magnitudes and lengths for all edges
          #
          magnitudes = fix(
              scipy.ndimage.sum(
                  image,
                  edge_labels,
                  numpy.arange(1, nlabels + 1, dtype=numpy.int32),
              )
          )
          lengths = fix(
              scipy.ndimage.sum(
                  numpy.ones(edge_labels.shape),
                  edge_labels,
                  numpy.arange(1, nlabels + 1, dtype=numpy.int32),
              )
          ).astype(int)
      else:
          magnitudes = numpy.zeros(0)
          lengths = numpy.zeros(0, int)
      #
      # combine the edge labels and indexes of points of interest with padding
      #
      edge_mask = edge_labels != 0
      all_labels = numpy.zeros(numpy.array(edge_labels.shape) + 2, int)
      all_labels[1:-1, 1:-1][edge_mask] = (
          edge_labels[edge_mask] + number_of_points
      )
      all_labels[i_idx + 1, j_idx + 1] = numpy.arange(
          1, number_of_points + 1
      )
      #
      # Collect all 8 neighbors for each point of interest
      #
      p1 = numpy.zeros(0, int)
      p2 = numpy.zeros(0, int)
      for i_off, j_off in (
          (0, 0),
          (0, 1),
          (0, 2),
          (1, 0),
          (1, 2),
          (2, 0),
          (2, 1),
          (2, 2),
      ):
          p1 = numpy.hstack((p1, numpy.arange(1, number_of_points + 1)))
          p2 = numpy.hstack(
              (p2, all_labels[i_idx + i_off, j_idx + j_off])
          )
      #
      # Get rid of zeros which are background
      #
      p1 = p1[p2 != 0]
      p2 = p2[p2 != 0]
      #
      # Find point_of_interest -> point_of_interest connections.
      #
      p1_poi = p1[(p2 <= number_of_points) & (p1 < p2)]
      p2_poi = p2[(p2 <= number_of_points) & (p1 < p2)]
      #
      # Make sure matches are labeled the same
      #
      same_labels = (
          skeleton_labels[i_idx[p1_poi - 1], j_idx[p1_poi - 1]]
          == skeleton_labels[i_idx[p2_poi - 1], j_idx[p2_poi - 1]]
      )
      p1_poi = p1_poi[same_labels]
      p2_poi = p2_poi[same_labels]
      #
      # Find point_of_interest -> edge
      #
      p1_edge = p1[p2 > number_of_points]
      edge = p2[p2 > number_of_points]
      #
      # Now, each value that p2_edge takes forms a group and all
      # p1_edge whose p2_edge are connected together by the edge.
      # Possibly they touch each other without the edge, but we will
      # take the minimum distance connecting each pair to throw out
      # the edge.
      #
      (
          edge,
          p1_edge,
          p2_edge,
      ) = centrosome.cpmorphology.pairwise_permutations(edge, p1_edge)
      indexer = edge - number_of_points - 1
      lengths = lengths[indexer]
      magnitudes = magnitudes[indexer]
      #
      # OK, now we make the edge table. First poi<->poi. Length = 2,
      # magnitude = magnitude at each point
      #
      poi_length = numpy.ones(len(p1_poi)) * 2
      poi_magnitude = (
          image[i_idx[p1_poi - 1], j_idx[p1_poi - 1]]
          + image[i_idx[p2_poi - 1], j_idx[p2_poi - 1]]
      )
      #
      # Now the edges...
      #
      poi_edge_length = lengths + 2
      poi_edge_magnitude = (
          image[i_idx[p1_edge - 1], j_idx[p1_edge - 1]]
          + image[i_idx[p2_edge - 1], j_idx[p2_edge - 1]]
          + magnitudes
      )
      #
      # Put together the columns
      #
      v1 = numpy.hstack((p1_poi, p1_edge))
      v2 = numpy.hstack((p2_poi, p2_edge))
      lengths = numpy.hstack((poi_length, poi_edge_length))
      magnitudes = numpy.hstack((poi_magnitude, poi_edge_magnitude))
      #
      # Sort by p1, p2 and length in order to pick the shortest length
      #
      indexer = numpy.lexsort((lengths, v1, v2))
      v1 = v1[indexer]
      v2 = v2[indexer]
      lengths = lengths[indexer]
      magnitudes = magnitudes[indexer]
      if len(v1) > 0:
          to_keep = numpy.hstack(
              ([True], (v1[1:] != v1[:-1]) | (v2[1:] != v2[:-1]))
          )
          v1 = v1[to_keep]
          v2 = v2[to_keep]
          lengths = lengths[to_keep]
          magnitudes = magnitudes[to_keep]
      #
      # Put it all together into a table
      #
      edge_table = {
          self.EF_V1: v1,
          self.EF_V2: v2,
          self.EF_LENGTH: lengths,
          self.EF_TOTAL_INTENSITY: magnitudes,
      }
      return edge_table, vertex_table
  
imports: import os
  import centrosome.cpmorphology
  import centrosome.propagate
  import numpy
  import scipy.ndimage
  from cellprofiler_core.constants.measurement import COLTYPE_FLOAT
  from cellprofiler_core.constants.measurement import COLTYPE_INTEGER
  from cellprofiler_core.image import Image
  from cellprofiler_core.measurement import Measurements
  from cellprofiler_core.module import Module
  from cellprofiler_core.preferences import ABSOLUTE_FOLDER_NAME
  from cellprofiler_core.preferences import DEFAULT_INPUT_FOLDER_NAME
  from cellprofiler_core.preferences import DEFAULT_INPUT_SUBFOLDER_NAME
  from cellprofiler_core.preferences import DEFAULT_OUTPUT_FOLDER_NAME
  from cellprofiler_core.preferences import DEFAULT_OUTPUT_SUBFOLDER_NAME
  from cellprofiler_core.preferences import get_default_colormap
  from cellprofiler_core.setting import Binary
  from cellprofiler_core.setting.subscriber import LabelSubscriber, ImageSubscriber
  from cellprofiler_core.setting.text import ImageName, Directory
  from cellprofiler_core.setting.text import Integer
  from cellprofiler_core.setting.text import Text
  from cellprofiler_core.utilities.core.object import size_similarly
  from centrosome.cpmorphology import fixup_scipy_ndimage_result
  from scipy.ndimage import grey_dilation, grey_erosion
label_desc: Use image node_id 14 for calling the MeasureObjectSkeleton obj's underlying member method code with example usage: obj.make_objskeleton_graph(skeleton, skeleton_labels, trunks, branchpoints, endpoints, image) and returns: edge_table,  vertex_table