def test_contour_data_sizes(new_rtstruct: RTStruct):
    mask = get_empty_mask(new_rtstruct)
    mask[50:100, 50:100, 0] = 1
    mask[60:150, 40:120, 0] = 1

    # Given we've added the same mask with and without contour approximation
    new_rtstruct.add_roi(mask)
    new_rtstruct.add_roi(mask, approximate_contours=False)

    # Then using approximation leads to less data within the contour data
    assert get_data_len_by_index(new_rtstruct, 0) < get_data_len_by_index(
        new_rtstruct, 1)
def run_mask_iou_test(rtstruct:RTStruct, mask, IOU_threshold, use_pin_hole=False):
    # Save and load mask
    mask_name = "test"
    rtstruct.add_roi(mask, name=mask_name, use_pin_hole=use_pin_hole)
    loaded_mask = rtstruct.get_roi_mask_by_name(mask_name)

    # Use IOU to test accuracy of loaded mask
    print(np.sum(mask))
    print(np.sum(loaded_mask))
    numerator = np.logical_and(mask, loaded_mask)
    denominator = np.logical_or(mask, loaded_mask)
    IOU =  np.sum(numerator) / np.sum(denominator) 
    assert IOU >= IOU_threshold
def test_add_valid_roi(new_rtstruct: RTStruct):
    assert new_rtstruct.get_roi_names() == []
    assert len(new_rtstruct.ds.ROIContourSequence) == 0
    assert len(new_rtstruct.ds.StructureSetROISequence) == 0
    assert len(new_rtstruct.ds.RTROIObservationsSequence) == 0

    NAME = "Test ROI"
    COLOR = [123, 321, 456]
    mask = get_empty_mask(new_rtstruct)
    mask[50:100, 50:100, 0] = 1
    
    new_rtstruct.add_roi(mask, color=COLOR, name=NAME)

    assert len(new_rtstruct.ds.ROIContourSequence) == 1
    assert len(new_rtstruct.ds.ROIContourSequence[0].ContourSequence) == 1 # Only 1 slice was added to
    assert len(new_rtstruct.ds.StructureSetROISequence) == 1
    assert len(new_rtstruct.ds.RTROIObservationsSequence) == 1
    assert new_rtstruct.ds.ROIContourSequence[0].ROIDisplayColor == COLOR
    assert new_rtstruct.get_roi_names() == [NAME]
def run_mask_iou_test(
    rtstruct: RTStruct,
    mask,
    IOU_threshold,
    use_pin_hole=False,
    approximate_contours=True,
):
    # Save and load mask
    mask_name = "test"
    rtstruct.add_roi(
        mask,
        name=mask_name,
        use_pin_hole=use_pin_hole,
        approximate_contours=approximate_contours,
    )
    loaded_mask = rtstruct.get_roi_mask_by_name(mask_name)

    # Use IOU to test accuracy of loaded mask
    numerator = np.logical_and(mask, loaded_mask)
    denominator = np.logical_or(mask, loaded_mask)
    IOU = np.sum(numerator) / np.sum(denominator)
    assert IOU >= IOU_threshold
def test_get_invalid_roi_mask_by_name(new_rtstruct: RTStruct):
    assert new_rtstruct.get_roi_names() == []
    with pytest.raises(RTStruct.ROIException):
        new_rtstruct.get_roi_mask_by_name("FAKE_NAME")
def test_add_invalid_sized_roi(new_rtstruct: RTStruct):
    mask = get_empty_mask(new_rtstruct)
    with pytest.raises(RTStruct.ROIException):
        new_rtstruct.add_roi(mask)
def test_add_empty_roi(new_rtstruct: RTStruct):
    mask = get_empty_mask(new_rtstruct)
    mask = mask[:, :, 1:]  # One less slice than expected
    with pytest.raises(RTStruct.ROIException):
        new_rtstruct.add_roi(mask)
def test_add_non_binary_roi(new_rtstruct: RTStruct):
    mask = get_empty_mask(new_rtstruct)
    mask.astype(float)
    with pytest.raises(RTStruct.ROIException):
        new_rtstruct.add_roi(mask)