helpers.py 5.19 KB
Newer Older
Josef Brandt's avatar
Josef Brandt committed
1 2
from PyQt5 import QtCore, QtGui
import numpy as np
3 4 5
import sys
sys.path.append("C://Users//xbrjos//Desktop//Python")
from gepard import dataset
Josef Brandt's avatar
Josef Brandt committed
6

7 8 9 10 11 12 13 14 15 16 17 18 19 20 21

class ParticleBinSorter(object):
    def __init__(self):
        super(ParticleBinSorter, self).__init__()
        self.bins = [5, 10, 20, 50, 100, 200, 500]
        
    def sort_particles_into_bins(self, particleList):
        particlesInBins = self._get_empty_bins()
        
        for particle in particleList:
            binIndex = self._get_binIndex_of_particle(particle)
            particlesInBins[binIndex].append(particle)
        return particlesInBins
    
    def _get_empty_bins(self):
Josef Brandt's avatar
Josef Brandt committed
22
        return [[] for _ in range(len(self.bins)+1)]
23 24 25 26 27 28 29 30 31
    
    def _get_binIndex_of_particle(self, particle):
        size = particle.getParticleSize()
        binIndex = 0
        for upperLimit in self.bins:
            if size <= upperLimit:
                break
            else:
                binIndex += 1
Josef Brandt's avatar
Josef Brandt committed
32 33 34
        return binIndex


35 36 37 38 39 40 41 42 43 44
def box_overlaps_contour(boxTopLeftXY: tuple, boxWidthHeight: tuple, contour, offset: tuple = (0, 0)) -> bool:
    """
    Calculates, if a contour is overlapping a box.
    :param boxTopLeftXY: topLeft of Box
    :param boxWidthHeight: Width and height of box
    :param contour: np.ndarrayof contour data
    :param offset: optional offset (x, y) of the box (i.e., the (0, 0) of the contours coord system does not match
    the (0, 0) of the box coord system.
    :return:
    """
Josef Brandt's avatar
Josef Brandt committed
45
    contourPolygon = QtGui.QPolygonF()
46 47 48 49 50 51 52
    if type(contour) == np.ndarray:
        for point in contour:
            contourPolygon.append(QtCore.QPointF(point[0, 0], point[0, 1]))
    elif type(contour) == QtGui.QPolygonF:
        contourPolygon = contour
    else:
        raise TypeError
Josef Brandt's avatar
Josef Brandt committed
53 54

    boxPolygon = QtGui.QPolygonF()
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
    boxPolygon.append(QtCore.QPointF(boxTopLeftXY[0]+offset[0], boxTopLeftXY[1]+offset[1]))
    boxPolygon.append(QtCore.QPointF(boxTopLeftXY[0]+offset[0], boxTopLeftXY[1] + boxWidthHeight[1]+offset[1]))
    boxPolygon.append(QtCore.QPointF(boxTopLeftXY[0]+offset[0] + boxWidthHeight[0], boxTopLeftXY[1]+offset[1]))
    boxPolygon.append(QtCore.QPointF(boxTopLeftXY[0]+offset[0] + boxWidthHeight[0],
                                     boxTopLeftXY[1] + boxWidthHeight[1]+offset[1]))

    isOverlapping: bool = boxPolygon.intersects(contourPolygon)
    if not isOverlapping:
        # sometimes, the polygon.intersects method does not capture everything... We test the brects therefore..
        polygonBrect: QtCore.QRectF = contourPolygon.boundingRect()
        boxBrect: QtCore.QRectF = boxPolygon.boundingRect()
        if boxBrect.contains(polygonBrect) or boxBrect.intersects(polygonBrect):
            isOverlapping = True

    return isOverlapping


def get_overlapping_fraction(polygon1: QtGui.QPolygonF, polygon2: QtGui.QPolygonF) -> float:
    """
    Takes two polygons and returns the overlapping fraction (in terms of area)
    :param polygon1: The polygon that the fraction shall be calculated of.
    :param polygon2: The overlapping polygon, which's size is not of interest
    :return:
    """
    overlap: float = 0
    overlapPoly: QtGui.QPolygonF = polygon1.intersected(polygon2)
    if overlapPoly.size() > 0:
        origSize: float = get_polygon_area(polygon1)
        overlapSize: float = get_polygon_area(overlapPoly)
        overlap = overlapSize/origSize

    return overlap


def get_polygon_area(polygon: QtGui.QPolygonF) -> float:
    """
    Calculates the area of a polygon, adapted from:
    https://stackoverflow.com/questions/24467972/calculate-area-of-polygon-given-x-y-coordinates
    :param polygon:
    :return: area
    """
    x: list = []
    y: list = []
    for index in range(polygon.size()):
        point: QtCore.QPointF = polygon.at(index)
        x.append(point.x())
        y.append(point.y())

    x: np.ndarray = np.array(x)
    y: np.ndarray = np.array(y)
    area = 0.5 * np.abs(np.dot(x, np.roll(y, 1)) - np.dot(y, np.roll(x, 1)))
    return area


def get_filterDimensions_from_dataset(dataset) -> tuple:
    """
    Processes the datasets boundary items to calculate diameter and offset (coord system offset of circular filter
    with respect to actual dataset). This is used to set circular filter dimensions to use in the geometric
    subsampling approaches.
    The return values are in micrometer dimensions.
    :param dataset: The dataset to read.
    :return: (radius, offset, widthHeight) in µm
    """
    maxDim = dataset.maxdim
    imgDim = dataset.imagedim_df if dataset.imagescanMode == 'df' else dataset.imagedim_bf
    minX, maxY, = maxDim[0] - imgDim[0] / 2, maxDim[1] + imgDim[1] / 2
    maxX, minY = maxDim[2] + imgDim[0] / 2, maxDim[3] - imgDim[1] / 2
    width = maxX - minX
    height = maxY - minY

    diameter: float = min([width, height])
    offset: tuple = (width - diameter)/2, (height-diameter)/2
    return offset, diameter, [width, height]

Josef Brandt's avatar
Josef Brandt committed
129

130 131 132 133 134 135 136 137 138 139
def convert_length_to_pixels(dataset: dataset.DataSet, length: float) -> float:
    """
    :param dataset: dataset to use for conversion
    :param length: length in µm
    :return: length in px
    """
    imgMode: str = dataset.imagescanMode
    pixelScale: float = (dataset.pixelscale_df if imgMode == 'df' else dataset.pixelscale_bf)
    length /= pixelScale
    return length