def pointOnPixel(self, location, zFilter=True): dotSize = self.uiState.parent().dotSize # TODO - share with below closestDist, closestPoint = None, None allPoints = self.uiState._tree.flattenPoints() for point in allPoints: if zFilter and round(point.location[2]) != round(location[2]): continue radius = dotSize resizeRadius = False if radius is None: radius = point.radius resizeRadius = (point.radius is not None) if radius is None: radius = DendritePainter.NODE_CIRCLE_DEFAULT_RADIUS if resizeRadius: radius, _ = self.imgView.fromSceneDist(radius, radius) # TODO - verify this always needs to happen, but not below? zLoc = self.zoomedLocation(location) zPLoc = self.zoomedLocation(point.location) dist = deltaSz(zLoc, zPLoc) if dist > radius: continue if closestDist is None or dist < closestDist: closestDist, closestPoint = dist, point return closestPoint
def spatialAndTreeDist(self, p1: Point, p2: Point) -> Tuple[float, float]: """Given two points in the tree, return both the 3D spatial distance, as well as how far to travel along the tree.""" path1, path2 = p1.pathFromRoot(), p2.pathFromRoot() lastMatch = 0 while lastMatch < len(path1) and lastMatch < len( path2) and path1[lastMatch].id == path2[lastMatch].id: lastMatch += 1 lastMatch -= 1 path1X, path1Y, path1Z = self.worldCoordPoints(path1[lastMatch:]) path2X, path2Y, path2Z = self.worldCoordPoints(path2[lastMatch:]) treeDist = 0.0 for i in range(len(path1X) - 1): pA = (path1X[i], path1Y[i], path1Z[i]) pB = (path1X[i + 1], path1Y[i + 1], path1Z[i + 1]) treeDist += util.deltaSz(pA, pB) for i in range(len(path2X) - 1): pA = (path2X[i], path2Y[i], path2Z[i]) pB = (path2X[i + 1], path2Y[i + 1], path2Z[i + 1]) treeDist += util.deltaSz(pA, pB) return self.spatialDist(p1, p2), treeDist
def cumulativeWorldLengths(self) -> List[float]: """Calculate the length to all points along the branch. :returns: List of cumulative lengths, how far along the branch to get to each point.""" pointsWithRoot = self.pointsWithParentIfExists() x, y, z = self._parentTree.worldCoordPoints(pointsWithRoot) cumulativeLength, lengths = 0.0, [] for i in range(len(x) - 1): edgeDistance = util.deltaSz((x[i], y[i], z[i]), (x[i + 1], y[i + 1], z[i + 1])) cumulativeLength += edgeDistance lengths.append(cumulativeLength) return lengths
def closestPointToWorldLocation( self, targetWorldLocation: Point3D) -> Optional[Point]: """Given a position in world space, find the point closest to it in world space. :param targetWorldLocation: (x, y, z) location tuple. :returns: Point object of point closest to the target location.""" closestDist, closestPoint = None, None allPoints = self.flattenPoints() allX, allY, allZ = self.worldCoordPoints(allPoints) for point, loc in zip(allPoints, zip(allX, allY, allZ)): dist = util.deltaSz(targetWorldLocation, loc) if closestDist is None or dist < closestDist: closestDist, closestPoint = dist, point return closestPoint
def punctaOnPixel(self, location, zFilter=True): # TODO - share with above closestDist, closestPoint = None, None if self.windowIndex < len(self.uiState._parent.puncta): allPoints = self.uiState._parent.puncta[self.windowIndex] for point in allPoints: if zFilter and round(point.location[2]) != round(location[2]): continue dist = deltaSz(location, point.location) if dist > point.radius: continue if closestDist is None or dist < closestDist: closestDist, closestPoint = dist, point return closestPoint
def closestPointTo(self, targetLocation: Point3D, zFilter: bool = False) -> Optional[Point]: """Given a position in the volume, find the point closest to it in image space. :param targetLocation: (x, y, z) location tuple. :param zFilter: If true, only items on the same zStack are considered. :returns: Point object of point closest to the target location.""" closestDist, closestPoint = None, None for point in self.flattenPoints(): if zFilter and round(point.location[2]) != round( targetLocation[2]): continue dist = util.deltaSz(targetLocation, point.location) if closestDist is None or dist < closestDist: closestDist, closestPoint = dist, point return closestPoint
def worldLengths(self, fromIdx: int = 0) -> Tuple[float, float]: """Returns world length of the branch, plus the length to the last branch point. :returns: (totalLength, totalLength to last branch) """ pointsWithRoot = self.pointsWithParentIfExists()[fromIdx:] parentRadius = 0 if pointsWithRoot[0].isRoot() == False: parentRadius = pointsWithRoot[0].returnWorldRadius( self._parentTree._fullState()) x, y, z = self._parentTree.worldCoordPoints(pointsWithRoot) lastBranchPoint = _lastPointWithChildren(pointsWithRoot) totalLength, totalLengthToLastBranch = 0.0, 0.0 for i in range(len(x) - 1): edgeDistance = util.deltaSz((x[i], y[i], z[i]), (x[i + 1], y[i + 1], z[i + 1])) totalLength += edgeDistance if i < lastBranchPoint: totalLengthToLastBranch += edgeDistance totalLength = totalLength - parentRadius return totalLength, totalLengthToLastBranch
def _averageIntensity(point: Point, image: np.ndarray, channel: int) -> float: x, y, z = point.location zAt = int(round(z)) plane = image[channel][zAt] r = point.radius if r is None: r = point.radiusFromAncestors() # HACK - find a better way to do this? intensitySum = 0.0 intensityCount = 0 for r in range(plane.shape[0]): for c in range(plane.shape[1]): d = util.deltaSz((c + 0.5, r + 0.5, 0), (x, y, 0)) if d <= r: intensitySum += 1.0 * plane[r, c] intensityCount += 1 if intensityCount == 0: return np.nan return intensitySum / intensityCount / 255.0
def _pointNear(locA, locB): return util.deltaSz(locA, locB) < 1e-9
def spatialDist(self, p1: Point, p2: Point) -> float: """Given two points in the tree, return the 3D spatial distance""" x, y, z = self.worldCoordPoints([p1, p2]) p1Location = (x[0], y[0], z[0]) p2Location = (x[1], y[1], z[1]) return util.deltaSz(p1Location, p2Location)
def movePointBoundary(self, index, location): localState = self._localState(index) current = localState.currentPuncta() if current is not None: self.history.pushState() current.radius = deltaSz(location, current.location)
def parseMatlabTree(fullState, saveState, removeOrphanBranches=True): tree = Tree() branchList = saveState['tree'][0] if branchList.shape == (1, ): branchList = branchList[0] for i in range(branchList.shape[1]): # HACK: Matlab uses branch index as ID: fullState._nextBranchID = i if len(branchList[0, i]) > 0: # Load in branch: branchData = branchList[0, i][0] branch = parseMatlabBranch( fullState, branchData[0].T, # XYZ position branchData[2][0], # Annotations ) # ... and remove first point as it is duplicated data from parent: rootPoint = branch.points[0] branch.removePointLocally(rootPoint) branch.setParentPoint(rootPoint) if i == 0: # First branch is special, as first node is tree root tree.rootPoint = rootPoint tree.rootPoint.parentBranch = None else: # No branch data? Not sure what caused this in matlab... branch = Branch(fullState.nextBranchID()) tree.addBranch(branch) # For each point, hook up its child branches to it: for i in range(branchList.shape[1]): if len(branchList[0, i]) > 0: childListForPoints = branchList[0, i][0][1][0] # Child index list for j, childListForPoint in enumerate(childListForPoints): for childIdx in np.nditer(childListForPoint, ['refs_ok', 'zerosize_ok']): if tree.branches[childIdx - 1].parentPoint is not None: oldParent = tree.branches[childIdx - 1].parentPoint newParent = tree.branches[i].points[j - 1] moved = deltaSz(oldParent.location, newParent.location) if moved > 0.01: print( "WARNING: Branch %d parent location has moved %f" % (childIdx - 1, moved)) print( "%s to %s" % (str(tree.branches[childIdx - 1].parentPoint.location), str(tree.branches[i].points[j - 1].location))) # HACK - add branch to children of parent, but keep old parent on branch tree.branches[i].points[j - 1].children.append( tree.branches[childIdx - 1]) tree.branches[ childIdx - 1].reparentTo = tree.branches[i].points[j - 1] continue tree.branches[childIdx - 1].setParentPoint( tree.branches[i].points[j - 1]) if removeOrphanBranches: tree.branches = [b for b in tree.branches if b.parentPoint is not None] tree.transform = parseTransform(saveState['info'][0]) return tree