def process_simulation(_simulation, _overwrite=False):
    _start_time = time.time()

    _simulation_structured_path = paths.structured(_simulation)
    os.makedirs(_simulation_structured_path
                ) if not os.path.isdir(_simulation_structured_path) else None

    # properties
    _properties_pickle_path = os.path.join(_simulation_structured_path,
                                           'properties.pkl')
    if not _overwrite and not os.path.isfile(_properties_pickle_path):
        _properties = create_properties(_simulation)
        print(_simulation, 'Pickling properties')
        to_pickle(_properties, _properties_pickle_path)

    # elements
    _elements_pickle_path = os.path.join(_simulation_structured_path,
                                         'elements.pkl')
    if not _overwrite and not os.path.isfile(_elements_pickle_path):
        _elements = create_elements(_simulation)
        print(_simulation, 'Pickling elements')
        to_pickle(_elements, _elements_pickle_path)

    # time points
    for _time_point in load.time_points(_simulation):
        _time_point_pickle_path = os.path.join(_simulation_structured_path,
                                               str(_time_point) + '.pkl')
        if not _overwrite and not os.path.isfile(_time_point_pickle_path):
            _time_point_data = create_time_point(_simulation, _time_point)
            print(_simulation, 'Pickling time-point:', _time_point)
            to_pickle(_time_point_data, _time_point_pickle_path)

    # fiber lengths
    _simulation_fiber_lengths_path = paths.fiber_lengths(_simulation)
    os.makedirs(_simulation_fiber_lengths_path) if not os.path.isdir(
        _simulation_fiber_lengths_path) else None
    _elements = None
    for _time_point in load.time_points(_simulation):
        _fiber_lengths_pickle_path = os.path.join(
            _simulation_fiber_lengths_path,
            str(_time_point) + '.pkl')
        if not _overwrite and not os.path.isfile(_fiber_lengths_pickle_path):
            _elements = load.elements(
                _simulation) if _elements is None else _elements
            _intersections = load.intersections(_simulation, _time_point)
            _time_point_fiber_lengths = create_fiber_lengths(
                _elements, _intersections)
            print(_simulation, 'Pickling fiber lengths time-point:',
                  _time_point)
            to_pickle(_time_point_fiber_lengths, _fiber_lengths_pickle_path)

    print(_simulation, 'Finished!',
          'Total ' + str(round(time.time() - _start_time, 2)) + ' seconds')
def process_group(_experiment, _series_id, _cells_coordinates, _cell_1_id, _cell_2_id, _series_image_by_time_frames,
                  _resolutions, _real_cells=True, _fake_cell_1_id=None, _fake_cell_2_id=None,
                  _x_change=0, _y_change=0, _z_change=0, _overwrite=False):
    _time_frames_data = []
    _left_cell_id = None
    _right_cell_id = None
    _time_frames_amount = min(
        len([_value for _value in _cells_coordinates[_cell_1_id] if _value is not None]),
        len([_value for _value in _cells_coordinates[_cell_2_id] if _value is not None])
    )

    # smooth coordinates
    _cells_coordinates_cell_1_smoothed = compute.smooth_coordinates_in_time(
        [_value for _value in _cells_coordinates[_cell_1_id] if _value is not None], _n=SMOOTH_AMOUNT
    )
    _cells_coordinates_cell_2_smoothed = compute.smooth_coordinates_in_time(
        [_value for _value in _cells_coordinates[_cell_2_id] if _value is not None], _n=SMOOTH_AMOUNT
    )

    if _real_cells:
        _group = 'cells_' + str(_cell_1_id) + '_' + str(_cell_2_id)
    elif _fake_cell_1_id is None:
        _group = 'fake_' + str(_cell_1_id) + '_' + str(_cell_2_id)
    else:
        _group = 'static_' + str(_fake_cell_1_id) + '_' + str(_fake_cell_2_id)

    # check if needed (missing time-point / properties file)
    if not _overwrite:
        _missing = False
        for _time_frame in range(_time_frames_amount):
            _time_frame_pickle_path = paths.structured(_experiment, _series_id, _group, _time_frame)
            if not os.path.isfile(_time_frame_pickle_path):
                _missing = True
                break
        _group_structured_path = paths.structured(_experiment, _series_id, _group)
        _properties_json_path = os.path.join(_group_structured_path, 'properties.json')
        if not os.path.isfile(_properties_json_path):
            _missing = True
        if not _missing:
            return

    # running for each time point
    for _time_frame in range(_time_frames_amount):
        _time_frame_image = _series_image_by_time_frames[_time_frame]
        _cell_1_coordinates = [_value for _value in _cells_coordinates_cell_1_smoothed[_time_frame]]
        _cell_2_coordinates = [_value for _value in _cells_coordinates_cell_2_smoothed[_time_frame]]

        # update coordinates if needed
        if any([_x_change != 0, _y_change != 0, _z_change != 0]):
            _cell_1_coordinates = [
                _cell_1_coordinates[0] + _x_change,
                _cell_1_coordinates[1] + _y_change,
                _cell_1_coordinates[2] + _z_change
            ]
            _cell_2_coordinates = [
                _cell_2_coordinates[0] + _x_change,
                _cell_2_coordinates[1] + _y_change,
                _cell_2_coordinates[2] + _z_change
            ]

        # choose left and right cells
        if _time_frame == 0:
            if _cell_1_coordinates[0] <= _cell_2_coordinates[0]:
                _left_cell_id, _right_cell_id = _cell_1_id, _cell_2_id
            else:
                _right_cell_id, _left_cell_id = _cell_1_id, _cell_2_id

        print(_experiment, 'Series ' + str(_series_id), 'Cell 1 #:', _cell_1_id, 'Cell 2 #:', _cell_2_id, 'Time point:',
              _time_frame, sep='\t')

        # set coordinates
        if _left_cell_id == _cell_1_id:
            _left_cell_coordinates, _right_cell_coordinates = _cell_1_coordinates, _cell_2_coordinates
        else:
            _right_cell_coordinates, _left_cell_coordinates = _cell_1_coordinates, _cell_2_coordinates

        # compute padding
        _helper_coordinates = (_left_cell_coordinates[0] + 1, _left_cell_coordinates[1])
        _angle = compute.angle_between_three_points(
            _right_cell_coordinates, _left_cell_coordinates, _helper_coordinates
        )
        _padding_x, _padding_y = compute.axes_padding(_2d_image_shape=_time_frame_image[0].shape, _angle=_angle)
        _left_cell_coordinates[0] += _padding_x
        _left_cell_coordinates[1] += _padding_y
        _right_cell_coordinates[0] += _padding_x
        _right_cell_coordinates[1] += _padding_y

        # rotate image and change axes
        _time_frame_image_rotated = np.array([rotate(_z, _angle) for _z in _time_frame_image])
        _time_frame_image_swapped = np.swapaxes(_time_frame_image_rotated, 0, 1)

        if SHOW_PLOTS:
            plt.imshow(_time_frame_image_rotated[int(round(_left_cell_coordinates[2]))])
            plt.show()
            plt.imshow(_time_frame_image_rotated[int(round(_right_cell_coordinates[2]))])
            plt.show()

        # update coordinates
        _image_center = compute.image_center_coordinates(_image_shape=reversed(_time_frame_image_rotated[0].shape))
        _left_cell_coordinates = compute.rotate_point_around_another_point(
            _point=_left_cell_coordinates,
            _angle_in_radians=math.radians(_angle),
            _around_point=_image_center
        )
        _right_cell_coordinates = compute.rotate_point_around_another_point(
            _point=_right_cell_coordinates,
            _angle_in_radians=math.radians(_angle),
            _around_point=_image_center
        )
        _fixed_y = (_left_cell_coordinates[1] + _right_cell_coordinates[1]) / 2
        # y is now z
        _left_cell_coordinates[1] = _left_cell_coordinates[2]
        _right_cell_coordinates[1] = _right_cell_coordinates[2]
        # z is now y
        _left_cell_coordinates[2] = _fixed_y
        _right_cell_coordinates[2] = _fixed_y

        if SHOW_PLOTS:
            plt.imshow(_time_frame_image_swapped[int(round(_left_cell_coordinates[2]))])
            plt.show()

        # swap resolutions
        _new_resolutions = {
            'x': _resolutions['x'],
            'y': _resolutions['z'],
            'z': _resolutions['y']
        }

        # second rotate, compute padding
        _helper_coordinates = (_left_cell_coordinates[0] + 1, _left_cell_coordinates[1])
        _angle = compute.angle_between_three_points(
            _right_cell_coordinates, _left_cell_coordinates, _helper_coordinates
        )
        _padding_x, _padding_y = compute.axes_padding(_2d_image_shape=_time_frame_image_swapped[0].shape, _angle=_angle)
        _left_cell_coordinates[0] += _padding_x
        _left_cell_coordinates[1] += _padding_y
        _right_cell_coordinates[0] += _padding_x
        _right_cell_coordinates[1] += _padding_y

        # rotate image
        _time_frame_image_swapped_rotated = np.array([rotate(_z, _angle) for _z in _time_frame_image_swapped])

        # convert to 8 bit color depth
        if CONVERT_TO_COLOR_DEPTH_8_BIT:
            _time_frame_image_swapped_rotated = \
                np.rint(_time_frame_image_swapped_rotated / (math.pow(2, 16) - 1) * (math.pow(2, 8) - 1)).astype(np.uint8)

        # update coordinates
        _image_center = compute.image_center_coordinates(
            _image_shape=reversed(_time_frame_image_swapped_rotated[0].shape))
        _left_cell_coordinates = compute.rotate_point_around_another_point(
            _point=_left_cell_coordinates,
            _angle_in_radians=math.radians(_angle),
            _around_point=_image_center
        )
        _right_cell_coordinates = compute.rotate_point_around_another_point(
            _point=_right_cell_coordinates,
            _angle_in_radians=math.radians(_angle),
            _around_point=_image_center
        )
        _fixed_y = (_left_cell_coordinates[1] + _right_cell_coordinates[1]) / 2
        _left_cell_coordinates[1] = _fixed_y
        _right_cell_coordinates[1] = _fixed_y

        if SHOW_PLOTS:
            if _time_frame == 0 or _time_frame == 50 or _time_frame == 150:
                plt.imshow(_time_frame_image_swapped_rotated[int(round(_left_cell_coordinates[2]))])
                plt.show()

        # update resolutions
        _angle = abs(_angle)
        _new_resolution_x = (_angle / 90) * _new_resolutions['y'] + ((90 - _angle) / 90) * _new_resolutions['x']
        _new_resolution_y = (_angle / 90) * _new_resolutions['x'] + ((90 - _angle) / 90) * _new_resolutions['y']
        _new_resolutions['x'] = _new_resolution_x
        _new_resolutions['y'] = _new_resolution_y

        _image_z, _image_y, _image_x = _time_frame_image_swapped_rotated.shape
        if not 0 <= _left_cell_coordinates[0] < _image_x or not \
                0 <= _left_cell_coordinates[1] < _image_y or not \
                0 <= _left_cell_coordinates[2] < _image_z:
            break
        if not 0 <= _right_cell_coordinates[0] < _image_x or not \
                0 <= _right_cell_coordinates[1] < _image_y or not \
                0 <= _right_cell_coordinates[2] < _image_z:
            break

        # add to array
        _time_frames_data.append({
            'left_cell': {
                'coordinates': {
                    'x': _left_cell_coordinates[0],
                    'y': _left_cell_coordinates[1],
                    'z': _left_cell_coordinates[2]
                }
            },
            'right_cell': {
                'coordinates': {
                    'x': _right_cell_coordinates[0],
                    'y': _right_cell_coordinates[1],
                    'z': _right_cell_coordinates[2]
                }
            },
            'resolutions': _new_resolutions
        })

        # save to pickle
        _time_frame_pickle_path = paths.structured(_experiment, _series_id, _group, _time_frame)
        save_lib.to_pickle(_time_frame_image_swapped_rotated, _time_frame_pickle_path)

    # save properties
    if _real_cells:
        _band = None
        _fake = False
        _static = False
    elif _fake_cell_1_id is None:
        _based_on_properties = load.group_properties(_experiment, _series_id, 'cells_' + _group.split('fake_')[1])
        _band = _based_on_properties['band']
        _fake = True
        _static = False
    else:
        _band = False
        _fake = True
        _static = True
    _properties_data = {
        'experiment': _experiment,
        'series_id': _series_id,
        'cells_ids': {
            'left_cell': _left_cell_id,
            'right_cell': _right_cell_id
        },
        'time_points': _time_frames_data,
        'band': _band,
        'fake': _fake,
        'static': _static
    }
    _group_structured_path = paths.structured(_experiment, _series_id, _group)
    _properties_json_path = os.path.join(_group_structured_path, 'properties.json')
    save_lib.to_json(_properties_data, _properties_json_path)
def process_group(_arguments):
    _time_frames_data = []
    _time_frames_amount = \
        len([_value for _value in _arguments['cell_coordinates'][_arguments['cell_id']] if _value is not None])

    # smooth coordinates
    _cells_coordinates_cell_smoothed = compute.smooth_coordinates_in_time(
        [
            _value
            for _value in _arguments['cell_coordinates'][_arguments['cell_id']]
            if _value is not None
        ],
        _n=SMOOTH_AMOUNT)

    if _arguments['cell_type'] == 'real':
        _group = 'cell_' + str(_arguments['cell_id']) + '_' + str(_arguments['degrees_xy']) + '_' + \
                 str(_arguments['degrees_z'])
    elif _arguments['cell_type'] == 'fake':
        _group = 'fake_' + str(_arguments['cell_id']) + '_' + str(_arguments['degrees_xy']) + '_' + \
                 str(_arguments['degrees_z'])
    elif _arguments['cell_type'] == 'static':
        _group = 'static_' + str(_arguments['cell_id']) + '_' + str(_arguments['degrees_xy']) + '_' + \
                 str(_arguments['degrees_z'])
    else:
        raise Exception('No such cell type')

    # check if needed (missing time-point / properties file)
    if not _arguments['overwrite']:
        _missing = False
        for _time_frame in range(_time_frames_amount):
            _time_frame_pickle_path = \
                paths.structured(_arguments['experiment'], _arguments['series_id'], _group, _time_frame)
            if not os.path.isfile(_time_frame_pickle_path):
                _missing = True
                break
        _group_structured_path = paths.structured(_arguments['experiment'],
                                                  _arguments['series_id'],
                                                  _group)
        _properties_json_path = os.path.join(_group_structured_path,
                                             'properties.json')
        if not os.path.isfile(_properties_json_path):
            _missing = True
        if not _missing:
            return

    # load image if needed
    if 'series_image_by_time_frames' not in _arguments:
        _series_image_path = \
            paths.serieses(_arguments['experiment'], _arguments['series_id'])
        _series_image = tifffile.imread(_series_image_path)
        _arguments['series_image_by_time_frames'] = [
            np.array([
                _z[IMAGE_FIBER_CHANNEL_INDEX]
                for _z in _series_image[_time_frame]
            ]) for _time_frame in range(_series_image.shape[0])
        ]

    # running for each time point
    for _time_frame in range(_time_frames_amount):
        _time_frame_image = _arguments['series_image_by_time_frames'][
            _time_frame]
        _cell_coordinates = [
            _value for _value in _cells_coordinates_cell_smoothed[_time_frame]
        ]

        # update coordinates if needed
        if 'x_change' in _arguments:
            _cell_coordinates[0] += _arguments['x_change']
        if 'y_change' in _arguments:
            _cell_coordinates[1] += _arguments['y_change']
        if 'z_change' in _arguments:
            _cell_coordinates[2] += _arguments['z_change']

        # compute padding xy
        _padding_x, _padding_y = \
            compute.axes_padding(_2d_image_shape=_time_frame_image[0].shape, _angle=_arguments['degrees_xy'])
        _cell_coordinates[0] += _padding_x
        _cell_coordinates[1] += _padding_y

        # rotate image and change axes
        _time_frame_image_rotated = np.array(
            [rotate(_z, _arguments['degrees_xy']) for _z in _time_frame_image])
        _time_frame_image_swapped = np.swapaxes(_time_frame_image_rotated, 0,
                                                1)

        if SHOW_PLOTS:
            plt.imshow(_time_frame_image_rotated[int(
                round(_cell_coordinates[2]))])
            plt.show()

        # update coordinates
        _image_center = compute.image_center_coordinates(
            _image_shape=reversed(_time_frame_image_rotated[0].shape))
        _cell_coordinates = compute.rotate_point_around_another_point(
            _point=_cell_coordinates,
            _angle_in_radians=math.radians(_arguments['degrees_xy']),
            _around_point=_image_center)
        # y is now z, z is now y
        _cell_coordinates[1], _cell_coordinates[2] = _cell_coordinates[
            2], _cell_coordinates[1]

        if SHOW_PLOTS:
            plt.imshow(_time_frame_image_swapped[int(
                round(_cell_coordinates[2]))])
            plt.show()

        # swap resolutions
        _new_resolutions = {
            'x': _arguments['resolutions']['x'],
            'y': _arguments['resolutions']['z'],
            'z': _arguments['resolutions']['y']
        }

        # second rotate, compute padding z
        _padding_x, _padding_y = \
            compute.axes_padding(_2d_image_shape=_time_frame_image_swapped[0].shape, _angle=_arguments['degrees_z'])
        _cell_coordinates[0] += _padding_x
        _cell_coordinates[1] += _padding_y

        # rotate image
        _time_frame_image_swapped_rotated = \
            np.array([rotate(_z, _arguments['degrees_z']) for _z in _time_frame_image_swapped])

        # update coordinates
        _image_center = compute.image_center_coordinates(
            _image_shape=reversed(_time_frame_image_swapped_rotated[0].shape))
        _cell_coordinates = compute.rotate_point_around_another_point(
            _point=_cell_coordinates,
            _angle_in_radians=math.radians(_arguments['degrees_z']),
            _around_point=_image_center)

        if SHOW_PLOTS:
            if _time_frame == 0 or _time_frame == 50 or _time_frame == 150:
                plt.imshow(_time_frame_image_swapped_rotated[int(
                    round(_cell_coordinates[2]))])
                plt.show()

        # update resolutions
        _angle = abs(_arguments['degrees_z'])
        _new_resolution_x = (_angle / 90) * _new_resolutions['y'] + (
            (90 - _angle) / 90) * _new_resolutions['x']
        _new_resolution_y = (_angle / 90) * _new_resolutions['x'] + (
            (90 - _angle) / 90) * _new_resolutions['y']
        _new_resolutions['x'] = _new_resolution_x
        _new_resolutions['y'] = _new_resolution_y

        _image_z, _image_y, _image_x = _time_frame_image_swapped_rotated.shape
        if not 0 <= _cell_coordinates[0] < _image_x or not \
                0 <= _cell_coordinates[1] < _image_y or not \
                0 <= _cell_coordinates[2] < _image_z:
            break

        # add to array
        _time_frames_data.append({
            'cell': {
                'coordinates': {
                    'x': _cell_coordinates[0],
                    'y': _cell_coordinates[1],
                    'z': _cell_coordinates[2]
                }
            },
            'resolutions': _new_resolutions
        })

        # save to pickle
        _time_frame_pickle_path = \
            paths.structured(_arguments['experiment'], _arguments['series_id'], _group, _time_frame)
        save_lib.to_pickle(_time_frame_image_swapped_rotated,
                           _time_frame_pickle_path)

    # save properties
    if _arguments['cell_type'] == 'real':
        _fake = False
        _static = False
    elif _arguments['cell_type'] == 'fake':
        _based_on_properties = \
            load.group_properties(_arguments['experiment'], _arguments['series_id'], 'cell_' + _group.split('fake_')[1])
        _fake = True
        _static = False
    elif _arguments['cell_type'] == 'static':
        _fake = True
        _static = True
    else:
        raise Exception('No such cell type')
    _properties_data = {
        'experiment': _arguments['experiment'],
        'series_id': _arguments['series_id'],
        'cell_id': _arguments['cell_id'],
        'time_points': _time_frames_data,
        'fake': _fake,
        'static': _static
    }
    _group_structured_path = paths.structured(_arguments['experiment'],
                                              _arguments['series_id'], _group)
    _properties_json_path = os.path.join(_group_structured_path,
                                         'properties.json')
    save_lib.to_json(_properties_data, _properties_json_path)
Beispiel #4
0
def blacklist(_experiment, _series_id=None, _blacklist=None):
    if _blacklist is None:
        _blacklist = {}
    _path = paths.blacklist(_experiment, _series_id)
    to_pickle(_blacklist, _path)
Beispiel #5
0
def normalization(_simulation, _normalization):
    _normalization_path = os.path.join(paths.NORMALIZATION, _simulation + '.pkl')
    to_pickle(_normalization, _normalization_path)
Beispiel #6
0
def process_real_fake(_experiment,
                      _series_id,
                      _cells_coordinates,
                      _cell_1_id,
                      _cell_2_id,
                      _based_on_cell_id,
                      _fake_cell_x,
                      _fake_cell_y,
                      _series_image_by_time_frames,
                      _resolutions,
                      _overwrite=False):
    _time_frames_data = []
    _left_cell_id = None
    _right_cell_id = None
    _time_frames_amount = len([
        _value for _value in _cells_coordinates[_based_on_cell_id]
        if _value is not None
    ])

    # smooth coordinates
    _cells_coordinates_based_on_cell_smoothed = compute.smooth_coordinates_in_time(
        [
            _value for _value in _cells_coordinates[_based_on_cell_id]
            if _value is not None
        ],
        _n=SMOOTH_AMOUNT)
    _cells_coordinates_fake_cell_smoothed = compute.smooth_coordinates_in_time(
        [
            _value for _value in _cells_coordinates[_based_on_cell_id]
            if _value is not None
        ],
        _n=SMOOTH_AMOUNT)

    _group = 'cells_' + str(_cell_1_id) + '_' + str(_cell_2_id) + '_real_' + str(_based_on_cell_id) + \
             '_fake_' + str(_based_on_cell_id)

    # check if needed (missing time-point / properties file)
    if not _overwrite:
        _missing = False
        for _time_frame in range(_time_frames_amount):
            _time_frame_pickle_path = paths.structured(_experiment, _series_id,
                                                       _group, _time_frame)
            if not os.path.isfile(_time_frame_pickle_path):
                _missing = True
                break
        _group_structured_path = paths.structured(_experiment, _series_id,
                                                  _group)
        _properties_json_path = os.path.join(_group_structured_path,
                                             'properties.json')
        if not os.path.isfile(_properties_json_path):
            _missing = True
        if not _missing:
            return

    # compute change
    _x_change = _fake_cell_x - _cells_coordinates_based_on_cell_smoothed[0][0]
    _y_change = _fake_cell_y - _cells_coordinates_based_on_cell_smoothed[0][1]

    # running for each time point
    for _time_frame in range(_time_frames_amount):
        _time_frame_image = _series_image_by_time_frames[_time_frame]
        _based_on_cell_coordinates = [
            _value for _value in
            _cells_coordinates_based_on_cell_smoothed[_time_frame]
        ]
        _fake_cell_coordinates = [
            _value
            for _value in _cells_coordinates_fake_cell_smoothed[_time_frame]
        ]

        # update coordinates of fake
        _fake_cell_coordinates = [
            _based_on_cell_coordinates[0] + _x_change,
            _based_on_cell_coordinates[1] + _y_change,
            _based_on_cell_coordinates[2]
        ]

        # choose left and right cells
        if _time_frame == 0:
            if _based_on_cell_coordinates[0] <= _fake_cell_coordinates[0]:
                _left_cell_id, _right_cell_id = _cell_1_id, _cell_2_id
            else:
                _right_cell_id, _left_cell_id = _cell_1_id, _cell_2_id

        print(_experiment,
              'Series ' + str(_series_id),
              'Cell 1 #:',
              _cell_1_id,
              'Cell 2 #:',
              _cell_2_id,
              'Based on cell #:',
              _based_on_cell_id,
              'Time point:',
              _time_frame,
              sep='\t')

        # set coordinates
        if _left_cell_id == _cell_1_id:
            _left_cell_coordinates, _right_cell_coordinates = _based_on_cell_coordinates, _fake_cell_coordinates
        else:
            _right_cell_coordinates, _left_cell_coordinates = _based_on_cell_coordinates, _fake_cell_coordinates

        # compute padding
        _helper_coordinates = (_left_cell_coordinates[0] + 1,
                               _left_cell_coordinates[1])
        _angle = compute.angle_between_three_points(_right_cell_coordinates,
                                                    _left_cell_coordinates,
                                                    _helper_coordinates)
        _padding_x, _padding_y = compute.axes_padding(
            _2d_image_shape=_time_frame_image[0].shape, _angle=_angle)
        _left_cell_coordinates[0] += _padding_x
        _left_cell_coordinates[1] += _padding_y
        _right_cell_coordinates[0] += _padding_x
        _right_cell_coordinates[1] += _padding_y

        # rotate image and change axes
        _time_frame_image_rotated = np.array(
            [rotate(_z, _angle) for _z in _time_frame_image])
        _time_frame_image_swapped = np.swapaxes(_time_frame_image_rotated, 0,
                                                1)

        if SHOW_PLOTS:
            plt.imshow(_time_frame_image_rotated[int(
                round(_left_cell_coordinates[2]))])
            plt.show()
            plt.imshow(_time_frame_image_rotated[int(
                round(_right_cell_coordinates[2]))])
            plt.show()

        # update coordinates
        _image_center = compute.image_center_coordinates(
            _image_shape=reversed(_time_frame_image_rotated[0].shape))
        _left_cell_coordinates = compute.rotate_point_around_another_point(
            _point=_left_cell_coordinates,
            _angle_in_radians=math.radians(_angle),
            _around_point=_image_center)
        _right_cell_coordinates = compute.rotate_point_around_another_point(
            _point=_right_cell_coordinates,
            _angle_in_radians=math.radians(_angle),
            _around_point=_image_center)
        _fixed_y = (_left_cell_coordinates[1] + _right_cell_coordinates[1]) / 2
        # y is now z
        _left_cell_coordinates[1] = _left_cell_coordinates[2]
        _right_cell_coordinates[1] = _right_cell_coordinates[2]
        # z is now y
        _left_cell_coordinates[2] = _fixed_y
        _right_cell_coordinates[2] = _fixed_y

        if SHOW_PLOTS:
            plt.imshow(_time_frame_image_swapped[int(
                round(_left_cell_coordinates[2]))])
            plt.show()

        # swap resolutions
        _new_resolutions = {
            'x': _resolutions['x'],
            'y': _resolutions['z'],
            'z': _resolutions['y']
        }

        # second rotate, compute padding
        _helper_coordinates = (_left_cell_coordinates[0] + 1,
                               _left_cell_coordinates[1])
        _angle = compute.angle_between_three_points(_right_cell_coordinates,
                                                    _left_cell_coordinates,
                                                    _helper_coordinates)
        _padding_x, _padding_y = compute.axes_padding(
            _2d_image_shape=_time_frame_image_swapped[0].shape, _angle=_angle)
        _left_cell_coordinates[0] += _padding_x
        _left_cell_coordinates[1] += _padding_y
        _right_cell_coordinates[0] += _padding_x
        _right_cell_coordinates[1] += _padding_y

        # rotate image
        _time_frame_image_swapped_rotated = np.array(
            [rotate(_z, _angle) for _z in _time_frame_image_swapped])

        # update coordinates
        _image_center = compute.image_center_coordinates(
            _image_shape=reversed(_time_frame_image_swapped_rotated[0].shape))
        _left_cell_coordinates = compute.rotate_point_around_another_point(
            _point=_left_cell_coordinates,
            _angle_in_radians=math.radians(_angle),
            _around_point=_image_center)
        _right_cell_coordinates = compute.rotate_point_around_another_point(
            _point=_right_cell_coordinates,
            _angle_in_radians=math.radians(_angle),
            _around_point=_image_center)
        _fixed_y = (_left_cell_coordinates[1] + _right_cell_coordinates[1]) / 2
        _left_cell_coordinates[1] = _fixed_y
        _right_cell_coordinates[1] = _fixed_y

        if SHOW_PLOTS:
            if _time_frame == 0 or _time_frame == 50 or _time_frame == 150:
                plt.imshow(_time_frame_image_swapped_rotated[int(
                    round(_left_cell_coordinates[2]))])
                plt.show()

        # update resolutions
        _angle = abs(_angle)
        _new_resolution_x = (_angle / 90) * _new_resolutions['y'] + (
            (90 - _angle) / 90) * _new_resolutions['x']
        _new_resolution_y = (_angle / 90) * _new_resolutions['x'] + (
            (90 - _angle) / 90) * _new_resolutions['y']
        _new_resolutions['x'] = _new_resolution_x
        _new_resolutions['y'] = _new_resolution_y

        # TODO: if the cell coordinates are out of image write it somewhere, so when checking for "overwrite"
        #  it will know when to stop
        _image_z, _image_y, _image_x = _time_frame_image_swapped_rotated.shape
        if not 0 <= _left_cell_coordinates[0] < _image_x or not \
                0 <= _left_cell_coordinates[1] < _image_y or not \
                0 <= _left_cell_coordinates[2] < _image_z:
            break
        if not 0 <= _right_cell_coordinates[0] < _image_x or not \
                0 <= _right_cell_coordinates[1] < _image_y or not \
                0 <= _right_cell_coordinates[2] < _image_z:
            break

        # add to array
        _time_frames_data.append({
            'left_cell': {
                'coordinates': {
                    'x': _left_cell_coordinates[0],
                    'y': _left_cell_coordinates[1],
                    'z': _left_cell_coordinates[2]
                }
            },
            'right_cell': {
                'coordinates': {
                    'x': _right_cell_coordinates[0],
                    'y': _right_cell_coordinates[1],
                    'z': _right_cell_coordinates[2]
                }
            },
            'resolutions': _new_resolutions
        })

        # save to pickle
        _time_frame_pickle_path = paths.structured(_experiment, _series_id,
                                                   _group, _time_frame)
        save_lib.to_pickle(_time_frame_image_swapped_rotated,
                           _time_frame_pickle_path)

    # save properties
    _based_on_properties = \
        load.group_properties(_experiment, _series_id, 'cells_' + str(_cell_1_id) + '_' + str(_cell_2_id))
    _properties_data = {
        'experiment': _experiment,
        'series_id': _series_id,
        'cells_ids': {
            'left_cell': _left_cell_id,
            'right_cell': _right_cell_id
        },
        'time_points': _time_frames_data,
        'band': _based_on_properties['band'],
        'fake': False,
        'static': False,
        'real_fake': True
    }
    _group_structured_path = paths.structured(_experiment, _series_id, _group)
    _properties_json_path = os.path.join(_group_structured_path,
                                         'properties.json')
    save_lib.to_json(_properties_data, _properties_json_path)