diff --git a/.gitattributes b/.gitattributes index 9b576669ef40e81a9bc7065ba52b9197a14985e4..aefa7ebcbcc4cbd900edf15a407308cd4fcd1f9f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text *.zst filter=lfs diff=lfs merge=lfs -text *tfevents* filter=lfs diff=lfs merge=lfs -text *.pth.tar filter=lfs diff=lfs merge=lfs -text +*.o filter=lfs diff=lfs merge=lfs -text \ No newline at end of file diff --git a/FGT_codes/FGT/checkpoint/config.yaml b/FGT_codes/FGT/checkpoint/config.yaml new file mode 100644 index 0000000000000000000000000000000000000000..669b04db8a0163aa63caa41f6e3b16f7d1c740f8 --- /dev/null +++ b/FGT_codes/FGT/checkpoint/config.yaml @@ -0,0 +1,34 @@ +PASSMASK: 1 +alpha: 0.3 +ape: 1 +cnum: 64 +conv_type: vanilla +dist_cnum: 32 +drop: 0 +frame_hidden: 512 +gd: 4 +in_channel: 4 +init_weights: 1 +input_resolution: !!python/tuple +- 240 +- 432 +flow_inChannel: 2 +flow_cnum: 64 +flow_hidden: 256 +kernel_size: !!python/tuple +- 7 +- 7 +mlp_ratio: 40 +numBlocks: 8 +num_head: 4 +padding: !!python/tuple +- 3 +- 3 +stride: !!python/tuple +- 3 +- 3 +sw: 8 +tw: 2 +use_bias: 1 +norm: None +model: model \ No newline at end of file diff --git a/FGT_codes/FGT/checkpoint/fgt.pth.tar b/FGT_codes/FGT/checkpoint/fgt.pth.tar new file mode 100644 index 0000000000000000000000000000000000000000..e448da9f713f6831ea6196943d5be13b83fb0080 --- /dev/null +++ b/FGT_codes/FGT/checkpoint/fgt.pth.tar @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:41352263b2d14aec73f0dcf75c4bf5155ddb23404aba6f023a0300aadfd7672f +size 157341393 diff --git a/FGT_codes/FGT/config/data_info.yaml b/FGT_codes/FGT/config/data_info.yaml new file mode 100644 index 0000000000000000000000000000000000000000..5b4a01f695eba30eeaa05f7ec9c86e1999d79109 --- /dev/null +++ b/FGT_codes/FGT/config/data_info.yaml @@ -0,0 +1,11 @@ +# dataset general info +frame_path: youtubevos_frames +flow_path: youtubevos_flows +name2len: config/youtubevos_name2len.pkl + +flow: + flow_height: 240 + flow_width: 432 + augments: False + colors: RGB + ext: .jpg diff --git a/FGT_codes/FGT/config/davis_name2len.pkl b/FGT_codes/FGT/config/davis_name2len.pkl new file mode 100644 index 0000000000000000000000000000000000000000..2de0cbcd34dcf437851566f4aea51fd2bc4a7fe9 --- /dev/null +++ b/FGT_codes/FGT/config/davis_name2len.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6607939cc02910f5badaebff46242f299597e93c07d77b6d740a3004f179f50c +size 1621 diff --git a/FGT_codes/FGT/config/davis_name2len_train.pkl b/FGT_codes/FGT/config/davis_name2len_train.pkl new file mode 100644 index 0000000000000000000000000000000000000000..e5f588d776f661fec1e3342c3815f5b986120951 --- /dev/null +++ b/FGT_codes/FGT/config/davis_name2len_train.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1ad5e89d5486b38f74ac62d08924a4ff7caa445d34df827385457e8516d4763f +size 1073 diff --git a/FGT_codes/FGT/config/davis_name2len_val.pkl b/FGT_codes/FGT/config/davis_name2len_val.pkl new file mode 100644 index 0000000000000000000000000000000000000000..aea02ea711362cbe33ab21389211ecfe7c69eddc --- /dev/null +++ b/FGT_codes/FGT/config/davis_name2len_val.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:30b2a23f943f40f2a09e98b474b88b07271e46a1224cb415650432d491cc1896 +size 188 diff --git a/FGT_codes/FGT/config/train.yaml b/FGT_codes/FGT/config/train.yaml new file mode 100644 index 0000000000000000000000000000000000000000..ea849e53267463dce297abc6e4d95de81149bfb0 --- /dev/null +++ b/FGT_codes/FGT/config/train.yaml @@ -0,0 +1,93 @@ +### General settings +name: FGT_train +use_tb_logger: true +outputdir: /myData/ret/experiments +datadir: /myData +record_iter: 16 + +### Calling definition +model: model +datasetName_train: train_dataset +network: network + +### datasets +datasets: + train: + name: youtubevos + type: video + mode: train + dataInfo_config: ./config/data_info.yaml + use_shuffle: True + n_workers: 0 + batch_size: 2 + + val: + name: youtubevos + type: video + mode: val + use_shuffle: False + n_workers: 1 + batch_size: 1 + val_config: ./config/valid_config.yaml + +### train settings +train: + lr: 0.0001 + lr_decay: 0.1 + manual_seed: 10 + BETA1: 0.9 + BETA2: 0.999 + MAX_ITERS: 500000 + UPDATE_INTERVAL: 300000 # 400000 is also OK + WARMUP: ~ + val_freq: 1 # Set to 1 is for debug, you can enlarge it to 50 in regular training + TEMPORAL_GAN: ~ # without temporal GAN + +### logger +logger: + PRINT_FREQ: 16 + SAVE_CHECKPOINT_FREQ: 4000 # 100 is for debug consideration + +### Data related parameters +flow2rgb: 1 +flow_direction: for +num_frames: 5 +sample: random +max_val: 0.01 + +### Model related parameters +res_h: 240 +res_w: 432 +in_channel: 4 +cnum: 64 +flow_inChannel: 2 +flow_cnum: 64 +dist_cnum: 32 +frame_hidden: 512 +flow_hidden: 256 +PASSMASK: 1 +num_blocks: 8 +kernel_size_w: 7 +kernel_size_h: 7 +stride_h: 3 +stride_w: 3 +num_head: 4 +conv_type: vanilla +norm: None +use_bias: 1 +ape: 1 +pos_mode: single +mlp_ratio: 40 +drop: 0 +init_weights: 1 +tw: 2 +sw: 8 +gd: 4 + +### Loss weights +L1M: 1 +L1V: 1 +adv: 0.01 + +### inference parameters +ref_length: 10 diff --git a/FGT_codes/FGT/config/valid_config.yaml b/FGT_codes/FGT/config/valid_config.yaml new file mode 100644 index 0000000000000000000000000000000000000000..967135e9cc197b651fafa01f1c0dd457a0b9654c --- /dev/null +++ b/FGT_codes/FGT/config/valid_config.yaml @@ -0,0 +1,8 @@ +flow_height: 240 +flow_width: 432 +data_root: davis_valid_flows +mask_root: rectMask_96 +frame_root: JPEGImages/480p +flow_root: davis_test_flows +batch_size: 1 +name2len: config/davis_name2len_val.pkl diff --git a/FGT_codes/FGT/config/youtubevos_name2len.pkl b/FGT_codes/FGT/config/youtubevos_name2len.pkl new file mode 100644 index 0000000000000000000000000000000000000000..6b65a72c30037e03a772692e9597ed3beaf934ca --- /dev/null +++ b/FGT_codes/FGT/config/youtubevos_name2len.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:60410308d4a0e780a531290d8bddc7f204bc0e8a500eab7c01c563b8efce9753 +size 75501 diff --git a/FGT_codes/FGT/data/__init__.py b/FGT_codes/FGT/data/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..53a0ac88410c95930e2019dbbb2fcb5057eea12d --- /dev/null +++ b/FGT_codes/FGT/data/__init__.py @@ -0,0 +1,49 @@ +import logging +import torch +import torch.utils.data +from importlib import import_module + + +def create_dataloader(phase, dataset, dataset_opt, opt=None, sampler=None): + logger = logging.getLogger('base') + if phase == 'train': + num_workers = dataset_opt['n_workers'] * opt['world_size'] + batch_size = dataset_opt['batch_size'] + if sampler is not None: + logger.info('N_workers: {}, batch_size: {} DDP train dataloader has been established'.format(num_workers, + batch_size)) + return torch.utils.data.DataLoader(dataset, batch_size=batch_size, + num_workers=num_workers, sampler=sampler, + pin_memory=True) + else: + logger.info('N_workers: {}, batch_size: {} train dataloader has been established'.format(num_workers, + batch_size)) + return torch.utils.data.DataLoader(dataset, batch_size=batch_size, + num_workers=num_workers, shuffle=True, + pin_memory=True) + + else: + logger.info( + 'N_workers: {}, batch_size: {} validate/test dataloader has been established'.format( + dataset_opt['n_workers'], + dataset_opt['batch_size'])) + return torch.utils.data.DataLoader(dataset, batch_size=dataset_opt['batch_size'], shuffle=False, + num_workers=dataset_opt['n_workers'], + pin_memory=False) + + +def create_dataset(dataset_opt, dataInfo, phase, dataset_name): + if phase == 'train': + dataset_package = import_module('data.{}'.format(dataset_name)) + dataset = dataset_package.VideoBasedDataset(dataset_opt, dataInfo) + + mode = dataset_opt['mode'] + logger = logging.getLogger('base') + logger.info( + '{} train dataset [{:s} - {:s} - {:s}] is created.'.format(dataset_opt['type'].upper(), + dataset.__class__.__name__, + dataset_opt['name'], mode)) + else: # validate and test dataset + return ValueError('No dataset initialized for valdataset') + + return dataset diff --git a/FGT_codes/FGT/data/train_dataset.py b/FGT_codes/FGT/data/train_dataset.py new file mode 100644 index 0000000000000000000000000000000000000000..917af60bdfc094a7a1c68d97c608889b25a1379a --- /dev/null +++ b/FGT_codes/FGT/data/train_dataset.py @@ -0,0 +1,165 @@ +import random +import pickle + +import logging +import torch +import cv2 +import os + +from torch.utils.data.dataset import Dataset +import numpy as np +import cvbase +from .util.STTN_mask import create_random_shape_with_random_motion +import imageio +from .util.flow_utils import region_fill as rf + +logger = logging.getLogger('base') + + +class VideoBasedDataset(Dataset): + def __init__(self, opt, dataInfo): + self.opt = opt + self.sampleMethod = opt['sample'] + self.dataInfo = dataInfo + self.height, self.width = self.opt['input_resolution'] + self.frame_path = dataInfo['frame_path'] + self.flow_path = dataInfo['flow_path'] # The path of the optical flows + self.train_list = os.listdir(self.frame_path) + self.name2length = self.dataInfo['name2len'] + with open(self.name2length, 'rb') as f: + self.name2length = pickle.load(f) + self.sequenceLen = self.opt['num_frames'] + self.flow2rgb = opt['flow2rgb'] # whether to change flow to rgb domain + self.flow_direction = opt[ + 'flow_direction'] # The direction must be in ['for', 'back', 'bi'], indicating forward, backward and bidirectional flows + + def __len__(self): + return len(self.train_list) + + def __getitem__(self, idx): + try: + item = self.load_item(idx) + except: + print('Loading error: ' + self.train_list[idx]) + item = self.load_item(0) + return item + + def frameSample(self, frameLen, sequenceLen): + if self.sampleMethod == 'random': + indices = [i for i in range(frameLen)] + sampleIndices = random.sample(indices, sequenceLen) + elif self.sampleMethod == 'seq': + pivot = random.randint(0, sequenceLen - 1 - frameLen) + sampleIndices = [i for i in range(pivot, pivot + frameLen)] + else: + raise ValueError('Cannot determine the sample method {}'.format(self.sampleMethod)) + return sampleIndices + + def load_item(self, idx): + video = self.train_list[idx] + frame_dir = os.path.join(self.frame_path, video) + forward_flow_dir = os.path.join(self.flow_path, video, 'forward_flo') + backward_flow_dir = os.path.join(self.flow_path, video, 'backward_flo') + frameLen = self.name2length[video] + flowLen = frameLen - 1 + assert frameLen > self.sequenceLen, 'Frame length {} is less than sequence length'.format(frameLen) + sampledIndices = self.frameSample(frameLen, self.sequenceLen) + + # generate random masks for these sampled frames + candidateMasks = create_random_shape_with_random_motion(frameLen, 0.9, 1.1, 1, 10) + + # read the frames and masks + frames, masks, forward_flows, backward_flows = [], [], [], [] + for i in range(len(sampledIndices)): + frame = self.read_frame(os.path.join(frame_dir, '{:05d}.jpg'.format(sampledIndices[i])), self.height, + self.width) + mask = self.read_mask(candidateMasks[sampledIndices[i]], self.height, self.width) + frames.append(frame) + masks.append(mask) + if self.flow_direction == 'for': + forward_flow = self.read_forward_flow(forward_flow_dir, sampledIndices[i], flowLen) + forward_flow = self.diffusion_flow(forward_flow, mask) + forward_flows.append(forward_flow) + elif self.flow_direction == 'back': + backward_flow = self.read_backward_flow(backward_flow_dir, sampledIndices[i]) + backward_flow = self.diffusion_flow(backward_flow, mask) + backward_flows.append(backward_flow) + elif self.flow_direction == 'bi': + forward_flow = self.read_forward_flow(forward_flow_dir, sampledIndices[i], flowLen) + forward_flow = self.diffusion_flow(forward_flow, mask) + forward_flows.append(forward_flow) + backward_flow = self.read_backward_flow(backward_flow_dir, sampledIndices[i]) + backward_flow = self.diffusion_flow(backward_flow, mask) + backward_flows.append(backward_flow) + else: + raise ValueError('Unknown flow direction mode: {}'.format(self.flow_direction)) + inputs = {'frames': frames, 'masks': masks, 'forward_flo': forward_flows, 'backward_flo': backward_flows} + inputs = self.to_tensor(inputs) + inputs['frames'] = (inputs['frames'] / 255.) * 2 - 1 + return inputs + + def diffusion_flow(self, flow, mask): + flow_filled = np.zeros(flow.shape) + flow_filled[:, :, 0] = rf.regionfill(flow[:, :, 0] * (1 - mask), mask) + flow_filled[:, :, 1] = rf.regionfill(flow[:, :, 1] * (1 - mask), mask) + return flow_filled + + def read_frame(self, path, height, width): + frame = imageio.imread(path) + frame = cv2.resize(frame, (width, height), cv2.INTER_LINEAR) + return frame + + def read_mask(self, mask, height, width): + mask = np.array(mask) + mask = mask / 255. + raw_mask = (mask > 0.5).astype(np.uint8) + raw_mask = cv2.resize(raw_mask, dsize=(width, height), interpolation=cv2.INTER_NEAREST) + return raw_mask + + def read_forward_flow(self, forward_flow_dir, sampledIndex, flowLen): + if sampledIndex >= flowLen: + sampledIndex = flowLen - 1 + flow = cvbase.read_flow(os.path.join(forward_flow_dir, '{:05d}.flo'.format(sampledIndex))) + height, width = flow.shape[:2] + flow = cv2.resize(flow, (self.width, self.height), cv2.INTER_LINEAR) + flow[:, :, 0] = flow[:, :, 0] / width * self.width + flow[:, :, 1] = flow[:, :, 1] / height * self.height + return flow + + def read_backward_flow(self, backward_flow_dir, sampledIndex): + if sampledIndex == 0: + sampledIndex = 0 + else: + sampledIndex -= 1 + flow = cvbase.read_flow(os.path.join(backward_flow_dir, '{:05d}.flo'.format(sampledIndex))) + height, width = flow.shape[:2] + flow = cv2.resize(flow, (self.width, self.height), cv2.INTER_LINEAR) + flow[:, :, 0] = flow[:, :, 0] / width * self.width + flow[:, :, 1] = flow[:, :, 1] / height * self.height + return flow + + def to_tensor(self, data_list): + """ + + Args: + data_list: A list contains multiple numpy arrays + + Returns: The stacked tensor list + + """ + keys = list(data_list.keys()) + for key in keys: + if data_list[key] is None or data_list[key] == []: + data_list.pop(key) + else: + item = data_list[key] + if not isinstance(item, list): + item = torch.from_numpy(np.transpose(item, (2, 0, 1))).float() # [c, h, w] + else: + item = np.stack(item, axis=0) + if len(item.shape) == 3: # [t, h, w] + item = item[:, :, :, np.newaxis] + item = torch.from_numpy(np.transpose(item, (0, 3, 1, 2))).float() # [t, c, h, w] + data_list[key] = item + return data_list + diff --git a/FGT_codes/FGT/data/util/MaskModel.py b/FGT_codes/FGT/data/util/MaskModel.py new file mode 100644 index 0000000000000000000000000000000000000000..9cca4f962889e9b3fd30d0f92f19c8b3104bfd3a --- /dev/null +++ b/FGT_codes/FGT/data/util/MaskModel.py @@ -0,0 +1,123 @@ +import random +import numpy as np + +class RandomMask(): + def __init__(self, videoLength, dataInfo): + self.videoLength = videoLength + self.imageHeight, self.imageWidth = dataInfo['image']['image_height'], \ + dataInfo['image']['image_width'] + self.maskHeight, self.maskWidth = dataInfo['mask']['mask_height'], \ + dataInfo['mask']['mask_width'] + try: + self.maxDeltaHeight, self.maxDeltaWidth = dataInfo['mask']['max_delta_height'], \ + dataInfo['mask']['max_delta_width'] + except KeyError: + self.maxDeltaHeight, self.maxDeltaWidth = 0, 0 + + try: + self.verticalMargin, self.horizontalMargin = dataInfo['mask']['vertical_margin'], \ + dataInfo['mask']['horizontal_margin'] + except KeyError: + self.verticalMargin, self.horizontalMargin = 0, 0 + + def __call__(self): + from .utils import random_bbox + from .utils import bbox2mask + masks = [] + bbox = random_bbox(self.imageHeight, self.imageWidth, self.verticalMargin, self.horizontalMargin, + self.maskHeight, self.maskWidth) + if random.uniform(0, 1) > 0.5: + mask = bbox2mask(self.imageHeight, self.imageWidth, 0, 0, bbox) + for frame in range(self.videoLength): + masks.append(mask) + else: + for frame in range(self.videoLength): + delta_h, delta_w = random.randint(-3, 3), random.randint(-3, 3) # 每次向四个方向移动三个像素以内 + bbox = list(bbox) + bbox[0] = min(max(self.verticalMargin, bbox[0] + delta_h), self.imageHeight - self.verticalMargin - bbox[2]) + bbox[1] = min(max(self.horizontalMargin, bbox[1] + delta_w), self.imageWidth - self.horizontalMargin - bbox[3]) + mask = bbox2mask(self.imageHeight, self.imageWidth, 0, 0, bbox) + masks.append(mask) + masks = np.stack(masks, axis=0) + if len(masks.shape) == 3: + masks = masks[:, :, :, np.newaxis] + assert len(masks.shape) == 4, 'Wrong mask dimension {}'.format(len(masks.shape)) + return masks + + +class MidRandomMask(): + ### This mask is considered without random motion + def __init__(self, videoLength, dataInfo): + self.videoLength = videoLength + self.imageHeight, self.imageWidth = dataInfo['image']['image_height'], \ + dataInfo['image']['image_width'] + self.maskHeight, self.maskWidth = dataInfo['mask']['mask_height'], \ + dataInfo['mask']['mask_width'] + + def __call__(self): + from .utils import mid_bbox_mask + mask = mid_bbox_mask(self.imageHeight, self.imageWidth, self.maskHeight, self.maskWidth) + masks = [] + for _ in range(self.videoLength): + masks.append(mask) + return mask + + +class MatrixMask(): + ### This mask is considered without random motion + def __init__(self, videoLength, dataInfo): + self.videoLength = videoLength + self.imageHeight, self.imageWidth = dataInfo['image']['image_height'], \ + dataInfo['image']['image_width'] + self.maskHeight, self.maskWidth = dataInfo['mask']['mask_height'], \ + dataInfo['mask']['mask_width'] + try: + self.row, self.column = dataInfo['mask']['row'], \ + dataInfo['mask']['column'] + except KeyError: + self.row, self.column = 5, 4 + + def __call__(self): + from .utils import matrix2bbox + mask = matrix2bbox(self.imageHeight, self.imageWidth, self.maskHeight, + self.maskWidth, self.row, self.column) + masks = [] + for video in range(self.videoLength): + masks.append(mask) + return mask + + +class FreeFormMask(): + def __init__(self, videoLength, dataInfo): + self.videoLength = videoLength + self.imageHeight, self.imageWidth = dataInfo['image']['image_height'], \ + dataInfo['image']['image_width'] + self.maxVertex = dataInfo['mask']['max_vertex'] + self.maxLength = dataInfo['mask']['max_length'] + self.maxBrushWidth = dataInfo['mask']['max_brush_width'] + self.maxAngle = dataInfo['mask']['max_angle'] + + def __call__(self): + from .utils import freeFormMask + mask = freeFormMask(self.imageHeight, self.imageWidth, + self.maxVertex, self.maxLength, + self.maxBrushWidth, self.maxAngle) + return mask + + +class StationaryMask(): + def __init__(self, videoLength, dataInfo): + self.videoLength = videoLength + self.imageHeight, self.imageWidth = dataInfo['image']['image_height'], \ + dataInfo['image']['image_width'] + # self.maxPointNum = dataInfo['mask']['max_point_num'] + # self.maxLength = dataInfo['mask']['max_length'] + + def __call__(self): + from .STTN_mask import create_random_shape_with_random_motion + masks = create_random_shape_with_random_motion(self.videoLength, 0.9, 1.1, 1, 10, self.imageHeight, self.imageWidth) + masks = np.stack(masks, axis=0) + if len(masks.shape) == 3: + masks = masks[:, :, :, np.newaxis] + assert len(masks.shape) == 4, 'Your masks with a wrong shape {}'.format(len(masks.shape)) + return masks \ No newline at end of file diff --git a/FGT_codes/FGT/data/util/STTN_mask.py b/FGT_codes/FGT/data/util/STTN_mask.py new file mode 100644 index 0000000000000000000000000000000000000000..f7ee67e6eb3eb9a5ace90d92120dd9b018091e3f --- /dev/null +++ b/FGT_codes/FGT/data/util/STTN_mask.py @@ -0,0 +1,244 @@ +import matplotlib.patches as patches +from matplotlib.path import Path +import os +import sys +import io +import cv2 +import time +import math +import argparse +import shutil +import random +import zipfile +from glob import glob +import math +import numpy as np +import torch.nn.functional as F +import torchvision.transforms as transforms +from PIL import Image, ImageOps, ImageDraw, ImageFilter + +import torch +import torchvision +import torch.nn as nn +import torch.distributed as dist + +import matplotlib +from matplotlib import pyplot as plt +matplotlib.use('agg') + + +class GroupRandomHorizontalFlip(object): + """Randomly horizontally flips the given PIL.Image with a probability of 0.5 + """ + + def __init__(self, is_flow=False): + self.is_flow = is_flow + + def __call__(self, img_group, is_flow=False): + v = random.random() + if v < 0.5: + ret = [img.transpose(Image.FLIP_LEFT_RIGHT) for img in img_group] + if self.is_flow: + for i in range(0, len(ret), 2): + # invert flow pixel values when flipping + ret[i] = ImageOps.invert(ret[i]) + return ret + else: + return img_group + + +class Stack(object): + def __init__(self, roll=False): + self.roll = roll + + def __call__(self, img_group): + mode = img_group[0].mode + if mode == '1': + img_group = [img.convert('L') for img in img_group] + mode = 'L' + if mode == 'L': + return np.stack([np.expand_dims(x, 2) for x in img_group], axis=2) + elif mode == 'RGB': + if self.roll: + return np.stack([np.array(x)[:, :, ::-1] for x in img_group], axis=2) + else: + return np.stack(img_group, axis=2) + else: + raise NotImplementedError("Image mode {}".format(mode)) + + +class ToTorchFormatTensor(object): + """ Converts a PIL.Image (RGB) or numpy.ndarray (H x W x C) in the range [0, 255] + to a torch.FloatTensor of shape (C x H x W) in the range [0.0, 1.0] """ + + def __init__(self, div=True): + self.div = div + + def __call__(self, pic): + if isinstance(pic, np.ndarray): + # numpy img: [L, C, H, W] + img = torch.from_numpy(pic).permute(2, 3, 0, 1).contiguous() + else: + # handle PIL Image + img = torch.ByteTensor( + torch.ByteStorage.from_buffer(pic.tobytes())) + img = img.view(pic.size[1], pic.size[0], len(pic.mode)) + # put it from HWC to CHW format + # yikes, this transpose takes 80% of the loading time/CPU + img = img.transpose(0, 1).transpose(0, 2).contiguous() + img = img.float().div(255) if self.div else img.float() + return img + + +# ########################################## +# ########################################## + +def create_random_shape_with_random_motion(video_length, zoomin, zoomout, rotmin, rotmax, imageHeight=240, imageWidth=432): + # get a random shape + assert zoomin < 1, "Zoom-in parameter must be smaller than 1" + assert zoomout > 1, "Zoom-out parameter must be larger than 1" + assert rotmin < rotmax, "Minimum value of rotation must be smaller than maximun value !" + height = random.randint(imageHeight//3, imageHeight-1) + width = random.randint(imageWidth//3, imageWidth-1) + edge_num = random.randint(6, 8) + ratio = random.randint(6, 8)/10 + region = get_random_shape( + edge_num=edge_num, ratio=ratio, height=height, width=width) + region_width, region_height = region.size + # get random position + x, y = random.randint( + 0, imageHeight-region_height), random.randint(0, imageWidth-region_width) + velocity = get_random_velocity(max_speed=3) + m = Image.fromarray(np.zeros((imageHeight, imageWidth)).astype(np.uint8)) + m.paste(region, (y, x, y+region.size[0], x+region.size[1])) + masks = [m.convert('L')] + # return fixed masks + if random.uniform(0, 1) > 0.5: + return masks*video_length # -> directly copy all the base masks + # return moving masks + for _ in range(video_length-1): + x, y, velocity = random_move_control_points( + x, y, imageHeight, imageWidth, velocity, region.size, maxLineAcceleration=(3, 0.5), maxInitSpeed=3) + m = Image.fromarray( + np.zeros((imageHeight, imageWidth)).astype(np.uint8)) + ### add by kaidong, to simulate zoon-in, zoom-out and rotation + extra_transform = random.uniform(0, 1) + # zoom in and zoom out + if extra_transform > 0.75: + resize_coefficient = random.uniform(zoomin, zoomout) + region = region.resize((math.ceil(region_width * resize_coefficient), math.ceil(region_height * resize_coefficient)), Image.NEAREST) + m.paste(region, (y, x, y + region.size[0], x + region.size[1])) + region_width, region_height = region.size + # rotation + elif extra_transform > 0.5: + m.paste(region, (y, x, y + region.size[0], x + region.size[1])) + m = m.rotate(random.randint(rotmin, rotmax)) + # region_width, region_height = region.size + ### end + else: + m.paste(region, (y, x, y+region.size[0], x+region.size[1])) + masks.append(m.convert('L')) + return masks + + +def get_random_shape(edge_num=9, ratio=0.7, width=432, height=240): + ''' + There is the initial point and 3 points per cubic bezier curve. + Thus, the curve will only pass though n points, which will be the sharp edges. + The other 2 modify the shape of the bezier curve. + edge_num, Number of possibly sharp edges + points_num, number of points in the Path + ratio, (0, 1) magnitude of the perturbation from the unit circle, + ''' + points_num = edge_num*3 + 1 + angles = np.linspace(0, 2*np.pi, points_num) + codes = np.full(points_num, Path.CURVE4) + codes[0] = Path.MOVETO + # Using this instad of Path.CLOSEPOLY avoids an innecessary straight line + verts = np.stack((np.cos(angles), np.sin(angles))).T * \ + (2*ratio*np.random.random(points_num)+1-ratio)[:, None] + verts[-1, :] = verts[0, :] + path = Path(verts, codes) + # draw paths into images + fig = plt.figure() + ax = fig.add_subplot(111) + patch = patches.PathPatch(path, facecolor='black', lw=2) + ax.add_patch(patch) + ax.set_xlim(np.min(verts)*1.1, np.max(verts)*1.1) + ax.set_ylim(np.min(verts)*1.1, np.max(verts)*1.1) + ax.axis('off') # removes the axis to leave only the shape + fig.canvas.draw() + # convert plt images into numpy images + data = np.frombuffer(fig.canvas.tostring_rgb(), dtype=np.uint8) + data = data.reshape((fig.canvas.get_width_height()[::-1] + (3,))) + plt.close(fig) + # postprocess + data = cv2.resize(data, (width, height))[:, :, 0] + data = (1 - np.array(data > 0).astype(np.uint8))*255 + corrdinates = np.where(data > 0) + xmin, xmax, ymin, ymax = np.min(corrdinates[0]), np.max( + corrdinates[0]), np.min(corrdinates[1]), np.max(corrdinates[1]) + region = Image.fromarray(data).crop((ymin, xmin, ymax, xmax)) + return region + + +def random_accelerate(velocity, maxAcceleration, dist='uniform'): + speed, angle = velocity + d_speed, d_angle = maxAcceleration + if dist == 'uniform': + speed += np.random.uniform(-d_speed, d_speed) + angle += np.random.uniform(-d_angle, d_angle) + elif dist == 'guassian': + speed += np.random.normal(0, d_speed / 2) + angle += np.random.normal(0, d_angle / 2) + else: + raise NotImplementedError( + f'Distribution type {dist} is not supported.') + return (speed, angle) + + +def get_random_velocity(max_speed=3, dist='uniform'): + if dist == 'uniform': + speed = np.random.uniform(max_speed) + elif dist == 'guassian': + speed = np.abs(np.random.normal(0, max_speed / 2)) + else: + raise NotImplementedError( + 'Distribution type {} is not supported.'.format(dist)) + angle = np.random.uniform(0, 2 * np.pi) + return (speed, angle) + + +def random_move_control_points(X, Y, imageHeight, imageWidth, lineVelocity, region_size, maxLineAcceleration=(3, 0.5), maxInitSpeed=3): + region_width, region_height = region_size + speed, angle = lineVelocity + X += int(speed * np.cos(angle)) + Y += int(speed * np.sin(angle)) + lineVelocity = random_accelerate( + lineVelocity, maxLineAcceleration, dist='guassian') + if ((X > imageHeight - region_height) or (X < 0) or (Y > imageWidth - region_width) or (Y < 0)): + lineVelocity = get_random_velocity(maxInitSpeed, dist='guassian') + new_X = np.clip(X, 0, imageHeight - region_height) + new_Y = np.clip(Y, 0, imageWidth - region_width) + return new_X, new_Y, lineVelocity + + + +# ############################################## +# ############################################## + +if __name__ == '__main__': + import os + os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE" + trials = 10 + for _ in range(trials): + video_length = 10 + # The returned masks are either stationary (50%) or moving (50%) + masks = create_random_shape_with_random_motion(video_length, zoomin=0.9, zoomout=1.1, rotmin=1, rotmax=10, imageHeight=240, imageWidth=432) + i = 0 + + for m in masks: + cv2.imshow('mask', np.array(m)) + cv2.waitKey(500) + # m.save('mask_{}.png'.format(i)) + i += 1 \ No newline at end of file diff --git a/FGT_codes/FGT/data/util/__init__.py b/FGT_codes/FGT/data/util/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..35e29baa771a24d045de69a7259c08fb9ee86f4b --- /dev/null +++ b/FGT_codes/FGT/data/util/__init__.py @@ -0,0 +1,28 @@ +from .STTN_mask import create_random_shape_with_random_motion + +import logging +logger = logging.getLogger('base') + + +def initialize_mask(videoLength, dataInfo): + from .MaskModel import RandomMask + from .MaskModel import MidRandomMask + from .MaskModel import MatrixMask + from .MaskModel import FreeFormMask + from .MaskModel import StationaryMask + + return {'random': RandomMask(videoLength, dataInfo), + 'mid': MidRandomMask(videoLength, dataInfo), + 'matrix': MatrixMask(videoLength, dataInfo), + 'free': FreeFormMask(videoLength, dataInfo), + 'stationary': StationaryMask(videoLength, dataInfo) + } + + +def create_mask(maskClass, form): + if form == 'mix': + from random import randint + candidates = list(maskClass.keys()) + candidate_index = randint(0, len(candidates) - 1) + return maskClass[candidates[candidate_index]]() + return maskClass[form]() \ No newline at end of file diff --git a/FGT_codes/FGT/data/util/flow_utils/__init__.py b/FGT_codes/FGT/data/util/flow_utils/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/FGT_codes/FGT/data/util/flow_utils/flow_reversal.py b/FGT_codes/FGT/data/util/flow_utils/flow_reversal.py new file mode 100644 index 0000000000000000000000000000000000000000..328558100ed45dd191b81ea4704f67df13202dc8 --- /dev/null +++ b/FGT_codes/FGT/data/util/flow_utils/flow_reversal.py @@ -0,0 +1,77 @@ +import torch + + +def flow_reversal(flow): + """ + flow: shape [b, c, h, w] + return: backward flow in corresponding to the forward flow + The formula is borrowed from Quadratic Video Interpolation (4) + """ + b, c, h, w = flow.shape + y = flow[:, 0:1, :, :] + x = flow[:, 1:2, :, :] # [b, 1, h, w] + + x = x.repeat(1, c, 1, 1) + y = y.repeat(1, c, 1, 1) + + # get the four points of the square (x1, y1), (x1, y2), (x2, y1), (x2, y2) + x1 = torch.floor(x) + x2 = x1 + 1 + y1 = torch.floor(y) + y2 = y1 + 1 + + # get gaussian weights + w11, w12, w21, w22 = get_gaussian_weights(x, y, x1, x2, y1, y2) + + # calculate the weight maps for each optical flows + flow11, o11 = sample_one(flow, x1, y1, w11) + flow12, o12 = sample_one(flow, x1, y2, w12) + flow21, o21 = sample_one(flow, x2, y1, w21) + flow22, o22 = sample_one(flow, x2, y2, w22) + + # fuse all the reversed flows based on equation (4) + flow_o = flow11 + flow12 + flow21 + flow22 + o = o11 + o12 + o21 + o22 + + flow_o = -flow_o + flow_o[o > 0] = flow_o[o > 0] / o[o > 0] + + return flow_o + + +def get_gaussian_weights(x, y, x1, x2, y1, y2): + sigma = 1 + w11 = torch.exp(-((x - x1) ** 2 + (y - y1) ** 2) / (sigma ** 2)) + w12 = torch.exp(-((x - x1) ** 2 + (y - y2) ** 2) / (sigma ** 2)) + w21 = torch.exp(-((x - x2) ** 2 + (y - y1) ** 2) / (sigma ** 2)) + w22 = torch.exp(-((x - x2) ** 2 + (y - y2) ** 2) / (sigma ** 2)) + return w11, w12, w21, w22 + + +def sample_one(flow, shiftx, shifty, weight): + b, c, h, w = flow.shape + flat_shiftx = shiftx.view(-1) # [h * w] + flat_shifty = shifty.view(-1) # [h * w] + flat_basex = torch.arange(0, h, requires_grad=False).view(-1, 1).long().repeat(b, c, 1, w).view(-1) # [h * w] + flat_basey = torch.arange(0, w, requires_grad=False).view(-1, 1).long().repeat(b, c, h, 1).view(-1) # [h * w] + flat_weight = weight.reshape(-1) # [h * w] + flat_flow = flow.reshape(-1) + + idxn = torch.arange(0, b, requires_grad=False).view(b, 1, 1, 1).long().repeat(1, c, h, w).view(-1) + idxc = torch.arange(0, c, requires_grad=False).view(1, c, 1, 1).long().repeat(b, 1, h, w).view(-1) + idxx = flat_shiftx.long() + flat_basex # size [-1] + idxy = flat_shifty.long() + flat_basey # size [-1] + + # record the shifted pixels inside the image boundaries + mask = idxx.ge(0) & idxx.lt(h) & idxy.ge(0) & idxy.lt(w) + + # mask off points out of boundaries + ids = idxn * c * h * w + idxc * h * w + idxx * w + idxy + ids_mask = torch.masked_select(ids, mask).clone() + + # put the value into corresponding regions + flow_warp = torch.zeros([b * c * h * w]) + flow_warp.put_(ids_mask, torch.masked_select(flat_flow * flat_weight, mask), accumulate=True) + one_warp = torch.zeros([b * c * h * w]) + one_warp.put_(ids_mask, torch.masked_select(flat_weight, mask), accumulate=True) + return flow_warp.view(b, c, h, w), one_warp.view(b, c, h, w) diff --git a/FGT_codes/FGT/data/util/flow_utils/region_fill.py b/FGT_codes/FGT/data/util/flow_utils/region_fill.py new file mode 100644 index 0000000000000000000000000000000000000000..603c78aadc312b07a2eb7c99dc9439a2a47dfee7 --- /dev/null +++ b/FGT_codes/FGT/data/util/flow_utils/region_fill.py @@ -0,0 +1,142 @@ +import numpy as np +import cv2 +from scipy import sparse +from scipy.sparse.linalg import spsolve + + +# Laplacian filling +def regionfill(I, mask, factor=1.0): + if np.count_nonzero(mask) == 0: + return I.copy() + resize_mask = cv2.resize( + mask.astype(float), (0, 0), fx=factor, fy=factor) > 0 + resize_I = cv2.resize(I.astype(float), (0, 0), fx=factor, fy=factor) + maskPerimeter = findBoundaryPixels(resize_mask) + regionfillLaplace(resize_I, resize_mask, maskPerimeter) + resize_I = cv2.resize(resize_I, (I.shape[1], I.shape[0])) + resize_I[mask == 0] = I[mask == 0] + return resize_I + + +def findBoundaryPixels(mask): + kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (3, 3)) + maskDilated = cv2.dilate(mask.astype(float), kernel) + return (maskDilated > 0) & (mask == 0) + + +def regionfillLaplace(I, mask, maskPerimeter): + height, width = I.shape + rightSide = formRightSide(I, maskPerimeter) + + # Location of mask pixels + maskIdx = np.where(mask) + + # Only keep values for pixels that are in the mask + rightSide = rightSide[maskIdx] + + # Number the mask pixels in a grid matrix + grid = -np.ones((height, width)) + grid[maskIdx] = range(0, maskIdx[0].size) + # Pad with zeros to avoid "index out of bounds" errors in the for loop + grid = padMatrix(grid) + gridIdx = np.where(grid >= 0) + + # Form the connectivity matrix D=sparse(i,j,s) + # Connect each mask pixel to itself + i = np.arange(0, maskIdx[0].size) + j = np.arange(0, maskIdx[0].size) + # The coefficient is the number of neighbors over which we average + numNeighbors = computeNumberOfNeighbors(height, width) + s = numNeighbors[maskIdx] + # Now connect the N,E,S,W neighbors if they exist + for direction in ((-1, 0), (0, 1), (1, 0), (0, -1)): + # Possible neighbors in the current direction + neighbors = grid[gridIdx[0] + direction[0], gridIdx[1] + direction[1]] + # ConDnect mask points to neighbors with -1's + index = (neighbors >= 0) + i = np.concatenate((i, grid[gridIdx[0][index], gridIdx[1][index]])) + j = np.concatenate((j, neighbors[index])) + s = np.concatenate((s, -np.ones(np.count_nonzero(index)))) + + D = sparse.coo_matrix((s, (i.astype(int), j.astype(int)))).tocsr() + sol = spsolve(D, rightSide) + I[maskIdx] = sol + return I + + +def formRightSide(I, maskPerimeter): + height, width = I.shape + perimeterValues = np.zeros((height, width)) + perimeterValues[maskPerimeter] = I[maskPerimeter] + rightSide = np.zeros((height, width)) + + rightSide[1:height - 1, 1:width - 1] = ( + perimeterValues[0:height - 2, 1:width - 1] + + perimeterValues[2:height, 1:width - 1] + + perimeterValues[1:height - 1, 0:width - 2] + + perimeterValues[1:height - 1, 2:width]) + + rightSide[1:height - 1, 0] = ( + perimeterValues[0:height - 2, 0] + perimeterValues[2:height, 0] + + perimeterValues[1:height - 1, 1]) + + rightSide[1:height - 1, width - 1] = ( + perimeterValues[0:height - 2, width - 1] + + perimeterValues[2:height, width - 1] + + perimeterValues[1:height - 1, width - 2]) + + rightSide[0, 1:width - 1] = ( + perimeterValues[1, 1:width - 1] + perimeterValues[0, 0:width - 2] + + perimeterValues[0, 2:width]) + + rightSide[height - 1, 1:width - 1] = ( + perimeterValues[height - 2, 1:width - 1] + + perimeterValues[height - 1, 0:width - 2] + + perimeterValues[height - 1, 2:width]) + + rightSide[0, 0] = perimeterValues[0, 1] + perimeterValues[1, 0] + rightSide[0, width - 1] = ( + perimeterValues[0, width - 2] + perimeterValues[1, width - 1]) + rightSide[height - 1, 0] = ( + perimeterValues[height - 2, 0] + perimeterValues[height - 1, 1]) + rightSide[height - 1, width - 1] = (perimeterValues[height - 2, width - 1] + + perimeterValues[height - 1, width - 2]) + return rightSide + + +def computeNumberOfNeighbors(height, width): + # Initialize + numNeighbors = np.zeros((height, width)) + # Interior pixels have 4 neighbors + numNeighbors[1:height - 1, 1:width - 1] = 4 + # Border pixels have 3 neighbors + numNeighbors[1:height - 1, (0, width - 1)] = 3 + numNeighbors[(0, height - 1), 1:width - 1] = 3 + # Corner pixels have 2 neighbors + numNeighbors[(0, 0, height - 1, height - 1), (0, width - 1, 0, + width - 1)] = 2 + return numNeighbors + + +def padMatrix(grid): + height, width = grid.shape + gridPadded = -np.ones((height + 2, width + 2)) + gridPadded[1:height + 1, 1:width + 1] = grid + gridPadded = gridPadded.astype(grid.dtype) + return gridPadded + + +if __name__ == '__main__': + import time + x = np.linspace(0, 255, 500) + xv, _ = np.meshgrid(x, x) + image = ((xv + np.transpose(xv)) / 2.0).astype(int) + mask = np.zeros((500, 500)) + mask[100:259, 100:259] = 1 + mask = (mask > 0) + image[mask] = 0 + st = time.time() + inpaint = regionfill(image, mask, 0.5).astype(np.uint8) + print(time.time() - st) + cv2.imshow('img', np.concatenate((image.astype(np.uint8), inpaint))) + cv2.waitKey() diff --git a/FGT_codes/FGT/data/util/freeform_masks.py b/FGT_codes/FGT/data/util/freeform_masks.py new file mode 100644 index 0000000000000000000000000000000000000000..2ced45154b2cacb0b09d87134989501d07ccbb65 --- /dev/null +++ b/FGT_codes/FGT/data/util/freeform_masks.py @@ -0,0 +1,266 @@ +import os +import sys +import shutil +sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))) # NOQA + +import numpy as np +import argparse +from PIL import Image + +from .mask_generators import get_video_masks_by_moving_random_stroke, get_masked_ratio +from .util import make_dirs, make_dir_under_root, get_everything_under +from .readers import MaskReader + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument( + '-od', '--output_dir', + type=str, + help="Output directory name" + ) + parser.add_argument( + '-im', + '--image_masks', action='store_true', + help="Set this if you want to generate independent masks in one directory." + ) + parser.add_argument( + '-vl', '--video_len', + type=int, + help="Maximum video length (i.e. #mask)" + ) + parser.add_argument( + '-ns', '--num_stroke', + type=int, + help="Number of stroke in one mask" + ) + parser.add_argument( + '-nsb', '--num_stroke_bound', + type=int, + nargs=2, + help="Upper/lower bound of number of stroke in one mask" + ) + parser.add_argument( + '-n', + type=int, + help="Number of mask to generate" + ) + parser.add_argument( + '-sp', + '--stroke_preset', + type=str, + default='rand_curve', + help="Preset of the stroke parameters" + ) + parser.add_argument( + '-iw', + '--image_width', + type=int, + default=320 + ) + parser.add_argument( + '-ih', + '--image_height', + type=int, + default=180 + ) + parser.add_argument( + '--cluster_by_area', + action='store_true' + ) + parser.add_argument( + '--leave_boarder_unmasked', + type=int, + help='Set this to a number, then a copy of the mask where the mask of boarder is erased.' + ) + parser.add_argument( + '--redo_without_generation', + action='store_true', + help='Set this, and the script will skip the generation and redo the left tasks' + '(uncluster -> erase boarder -> re-cluster)' + ) + args = parser.parse_args() + return args + + +def get_stroke_preset(stroke_preset): + if stroke_preset == 'object_like': + return { + "nVertexBound": [5, 30], + "maxHeadSpeed": 15, + "maxHeadAcceleration": (10, 1.5), + "brushWidthBound": (20, 50), + "nMovePointRatio": 0.5, + "maxPiontMove": 10, + "maxLineAcceleration": (5, 0.5), + "boarderGap": None, + "maxInitSpeed": 10, + } + elif stroke_preset == 'object_like_middle': + return { + "nVertexBound": [5, 15], + "maxHeadSpeed": 8, + "maxHeadAcceleration": (4, 1.5), + "brushWidthBound": (20, 50), + "nMovePointRatio": 0.5, + "maxPiontMove": 5, + "maxLineAcceleration": (5, 0.5), + "boarderGap": None, + "maxInitSpeed": 10, + } + elif stroke_preset == 'object_like_small': + return { + "nVertexBound": [5, 20], + "maxHeadSpeed": 7, + "maxHeadAcceleration": (3.5, 1.5), + "brushWidthBound": (10, 30), + "nMovePointRatio": 0.5, + "maxPiontMove": 5, + "maxLineAcceleration": (3, 0.5), + "boarderGap": None, + "maxInitSpeed": 4, + } + elif stroke_preset == 'rand_curve': + return { + "nVertexBound": [10, 30], + "maxHeadSpeed": 20, + "maxHeadAcceleration": (15, 0.5), + "brushWidthBound": (3, 10), + "nMovePointRatio": 0.5, + "maxPiontMove": 3, + "maxLineAcceleration": (5, 0.5), + "boarderGap": None, + "maxInitSpeed": 6 + } + elif stroke_preset == 'rand_curve_small': + return { + "nVertexBound": [6, 22], + "maxHeadSpeed": 12, + "maxHeadAcceleration": (8, 0.5), + "brushWidthBound": (2.5, 5), + "nMovePointRatio": 0.5, + "maxPiontMove": 1.5, + "maxLineAcceleration": (3, 0.5), + "boarderGap": None, + "maxInitSpeed": 3 + } + else: + raise NotImplementedError(f'The stroke presetting "{stroke_preset}" does not exist.') + + +def copy_masks_without_boarder(root_dir, args): + def erase_mask_boarder(mask, gap): + pix = np.asarray(mask).astype('uint8') * 255 + pix[:gap, :] = 255 + pix[-gap:, :] = 255 + pix[:, :gap] = 255 + pix[:, -gap:] = 255 + return Image.fromarray(pix).convert('1') + + wo_boarder_dir = root_dir + '_noBoarder' + shutil.copytree(root_dir, wo_boarder_dir) + + for i, filename in enumerate(get_everything_under(wo_boarder_dir)): + if args.image_masks: + mask = Image.open(filename) + mask_wo_boarder = erase_mask_boarder(mask, args.leave_boarder_unmasked) + mask_wo_boarder.save(filename) + else: + # filename is a diretory containing multiple mask files + for f in get_everything_under(filename, pattern='*.png'): + mask = Image.open(f) + mask_wo_boarder = erase_mask_boarder(mask, args.leave_boarder_unmasked) + mask_wo_boarder.save(f) + + return wo_boarder_dir + + +def cluster_by_masked_area(root_dir, args): + clustered_dir = root_dir + '_clustered' + make_dirs(clustered_dir) + radius = 5 + + # all masks with ratio in x +- radius will be stored in sub-directory x + clustered_centors = np.arange(radius, 100, radius * 2) + clustered_subdirs = [] + for c in clustered_centors: + # make sub-directories for each ratio range + clustered_subdirs.append(make_dir_under_root(clustered_dir, str(c))) + + for i, filename in enumerate(get_everything_under(root_dir)): + if args.image_masks: + ratio = get_masked_ratio(Image.open(filename)) + else: + # filename is a diretory containing multiple mask files + ratio = np.mean([ + get_masked_ratio(Image.open(f)) + for f in get_everything_under(filename, pattern='*.png') + ]) + + # find the nearest centor + for i, c in enumerate(clustered_centors): + if c - radius <= ratio * 100 <= c + radius: + shutil.move(filename, clustered_subdirs[i]) + break + + shutil.rmtree(root_dir) + os.rename(clustered_dir, root_dir) + + +def decide_nStroke(args): + if args.num_stroke is not None: + return args.num_stroke + elif args.num_stroke_bound is not None: + return np.random.randint(args.num_stroke_bound[0], args.num_stroke_bound[1]) + else: + raise ValueError('One of "-ns" or "-nsb" is needed') + + +def main(args): + preset = get_stroke_preset(args.stroke_preset) + make_dirs(args.output_dir) + + if args.redo_without_generation: + assert(len(get_everything_under(args.output_dir)) > 0) + # put back clustered masks + for clustered_subdir in get_everything_under(args.output_dir): + if not os.path.isdir(clustered_subdir): + continue + for f in get_everything_under(clustered_subdir): + shutil.move(f, args.output_dir) + os.rmdir(clustered_subdir) + + else: + if args.image_masks: + for i in range(args.n): + nStroke = decide_nStroke(args) + mask = get_video_masks_by_moving_random_stroke( + video_len=1, imageWidth=args.image_width, imageHeight=args.image_height, + nStroke=nStroke, **preset + )[0] + mask.save(os.path.join(args.output_dir, f'{i:07d}.png')) + + else: + for i in range(args.n): + mask_dir = make_dir_under_root(args.output_dir, f'{i:05d}') + mask_reader = MaskReader(mask_dir, read=False) + + nStroke = decide_nStroke(args) + masks = get_video_masks_by_moving_random_stroke( + imageWidth=args.image_width, imageHeight=args.image_height, + video_len=args.video_len, nStroke=nStroke, **preset) + + mask_reader.set_files(masks) + mask_reader.save_files(output_dir=mask_reader.dir_name) + + if args.leave_boarder_unmasked is not None: + dir_leave_boarder = copy_masks_without_boarder(args.output_dir, args) + if args.cluster_by_area: + cluster_by_masked_area(dir_leave_boarder, args) + + if args.cluster_by_area: + cluster_by_masked_area(args.output_dir, args) + + +if __name__ == "__main__": + args = parse_args() + main(args) diff --git a/FGT_codes/FGT/data/util/mask_generators.py b/FGT_codes/FGT/data/util/mask_generators.py new file mode 100644 index 0000000000000000000000000000000000000000..541a898a6feee551ffda029a4dd9280f2beeb421 --- /dev/null +++ b/FGT_codes/FGT/data/util/mask_generators.py @@ -0,0 +1,217 @@ +import numpy as np +import random +from PIL import Image, ImageDraw + + +def get_video_masks_by_moving_random_stroke( + video_len, imageWidth=320, imageHeight=180, nStroke=5, + nVertexBound=[10, 30], maxHeadSpeed=15, maxHeadAcceleration=(15, 0.5), + brushWidthBound=(5, 20), boarderGap=None, nMovePointRatio=0.5, maxPiontMove=10, + maxLineAcceleration=5, maxInitSpeed=5 +): + ''' + Get video masks by random strokes which move randomly between each + frame, including the whole stroke and its control points + + Parameters + ---------- + imageWidth: Image width + imageHeight: Image height + nStroke: Number of drawed lines + nVertexBound: Lower/upper bound of number of control points for each line + maxHeadSpeed: Max head speed when creating control points + maxHeadAcceleration: Max acceleration applying on the current head point ( + a head point and its velosity decides the next point) + brushWidthBound (min, max): Bound of width for each stroke + boarderGap: The minimum gap between image boarder and drawed lines + nMovePointRatio: The ratio of control points to move for next frames + maxPiontMove: The magnitude of movement for control points for next frames + maxLineAcceleration: The magnitude of acceleration for the whole line + + Examples + ---------- + object_like_setting = { + "nVertexBound": [5, 20], + "maxHeadSpeed": 15, + "maxHeadAcceleration": (15, 3.14), + "brushWidthBound": (30, 50), + "nMovePointRatio": 0.5, + "maxPiontMove": 10, + "maxLineAcceleration": (5, 0.5), + "boarderGap": 20, + "maxInitSpeed": 10, + } + rand_curve_setting = { + "nVertexBound": [10, 30], + "maxHeadSpeed": 20, + "maxHeadAcceleration": (15, 0.5), + "brushWidthBound": (3, 10), + "nMovePointRatio": 0.5, + "maxPiontMove": 3, + "maxLineAcceleration": (5, 0.5), + "boarderGap": 20, + "maxInitSpeed": 6 + } + get_video_masks_by_moving_random_stroke(video_len=5, nStroke=3, **object_like_setting) + ''' + assert(video_len >= 1) + + # Initilize a set of control points to draw the first mask + mask = Image.new(mode='1', size=(imageWidth, imageHeight), color=1) + control_points_set = [] + for i in range(nStroke): + brushWidth = np.random.randint(brushWidthBound[0], brushWidthBound[1]) + Xs, Ys, velocity = get_random_stroke_control_points( + imageWidth=imageWidth, imageHeight=imageHeight, + nVertexBound=nVertexBound, maxHeadSpeed=maxHeadSpeed, + maxHeadAcceleration=maxHeadAcceleration, boarderGap=boarderGap, + maxInitSpeed=maxInitSpeed + ) + control_points_set.append((Xs, Ys, velocity, brushWidth)) + draw_mask_by_control_points(mask, Xs, Ys, brushWidth, fill=0) + + # Generate the following masks by randomly move strokes and their control points + masks = [mask] + for i in range(video_len - 1): + mask = Image.new(mode='1', size=(imageWidth, imageHeight), color=1) + for j in range(len(control_points_set)): + Xs, Ys, velocity, brushWidth = control_points_set[j] + new_Xs, new_Ys = random_move_control_points( + Xs, Ys, velocity, nMovePointRatio, maxPiontMove, + maxLineAcceleration, boarderGap + ) + control_points_set[j] = (new_Xs, new_Ys, velocity, brushWidth) + for Xs, Ys, velocity, brushWidth in control_points_set: + draw_mask_by_control_points(mask, Xs, Ys, brushWidth, fill=0) + masks.append(mask) + + return masks + + +def random_accelerate(velocity, maxAcceleration, dist='uniform'): + speed, angle = velocity + d_speed, d_angle = maxAcceleration + + if dist == 'uniform': + speed += np.random.uniform(-d_speed, d_speed) + angle += np.random.uniform(-d_angle, d_angle) + elif dist == 'guassian': + speed += np.random.normal(0, d_speed / 2) + angle += np.random.normal(0, d_angle / 2) + else: + raise NotImplementedError(f'Distribution type {dist} is not supported.') + + return (speed, angle) + + +def random_move_control_points(Xs, Ys, lineVelocity, nMovePointRatio, maxPiontMove, maxLineAcceleration, boarderGap=15): + new_Xs = Xs.copy() + new_Ys = Ys.copy() + + # move the whole line and accelerate + speed, angle = lineVelocity + new_Xs += int(speed * np.cos(angle)) + new_Ys += int(speed * np.sin(angle)) + lineVelocity = random_accelerate(lineVelocity, maxLineAcceleration, dist='guassian') + + # choose points to move + chosen = np.arange(len(Xs)) + np.random.shuffle(chosen) + chosen = chosen[:int(len(Xs) * nMovePointRatio)] + for i in chosen: + new_Xs[i] += np.random.randint(-maxPiontMove, maxPiontMove) + new_Ys[i] += np.random.randint(-maxPiontMove, maxPiontMove) + return new_Xs, new_Ys + + +def get_random_stroke_control_points( + imageWidth, imageHeight, + nVertexBound=(10, 30), maxHeadSpeed=10, maxHeadAcceleration=(5, 0.5), boarderGap=20, + maxInitSpeed=10 +): + ''' + Implementation the free-form training masks generating algorithm + proposed by JIAHUI YU et al. in "Free-Form Image Inpainting with Gated Convolution" + ''' + startX = np.random.randint(imageWidth) + startY = np.random.randint(imageHeight) + Xs = [startX] + Ys = [startY] + + numVertex = np.random.randint(nVertexBound[0], nVertexBound[1]) + + angle = np.random.uniform(0, 2 * np.pi) + speed = np.random.uniform(0, maxHeadSpeed) + + for i in range(numVertex): + speed, angle = random_accelerate((speed, angle), maxHeadAcceleration) + speed = np.clip(speed, 0, maxHeadSpeed) + + nextX = startX + speed * np.sin(angle) + nextY = startY + speed * np.cos(angle) + + if boarderGap is not None: + nextX = np.clip(nextX, boarderGap, imageWidth - boarderGap) + nextY = np.clip(nextY, boarderGap, imageHeight - boarderGap) + + startX, startY = nextX, nextY + Xs.append(nextX) + Ys.append(nextY) + + velocity = get_random_velocity(maxInitSpeed, dist='guassian') + + return np.array(Xs), np.array(Ys), velocity + + +def get_random_velocity(max_speed, dist='uniform'): + if dist == 'uniform': + speed = np.random.uniform(max_speed) + elif dist == 'guassian': + speed = np.abs(np.random.normal(0, max_speed / 2)) + else: + raise NotImplementedError(f'Distribution type {dist} is not supported.') + + angle = np.random.uniform(0, 2 * np.pi) + return (speed, angle) + + +def draw_mask_by_control_points(mask, Xs, Ys, brushWidth, fill=255): + radius = brushWidth // 2 - 1 + for i in range(1, len(Xs)): + draw = ImageDraw.Draw(mask) + startX, startY = Xs[i - 1], Ys[i - 1] + nextX, nextY = Xs[i], Ys[i] + draw.line((startX, startY) + (nextX, nextY), fill=fill, width=brushWidth) + for x, y in zip(Xs, Ys): + draw.ellipse((x - radius, y - radius, x + radius, y + radius), fill=fill) + return mask + + +# modified from https://github.com/naoto0804/pytorch-inpainting-with-partial-conv/blob/master/generate_data.py +def get_random_walk_mask(imageWidth=320, imageHeight=180, length=None): + action_list = [[0, 1], [0, -1], [1, 0], [-1, 0]] + canvas = np.zeros((imageHeight, imageWidth)).astype("i") + if length is None: + length = imageWidth * imageHeight + x = random.randint(0, imageHeight - 1) + y = random.randint(0, imageWidth - 1) + x_list = [] + y_list = [] + for i in range(length): + r = random.randint(0, len(action_list) - 1) + x = np.clip(x + action_list[r][0], a_min=0, a_max=imageHeight - 1) + y = np.clip(y + action_list[r][1], a_min=0, a_max=imageWidth - 1) + x_list.append(x) + y_list.append(y) + canvas[np.array(x_list), np.array(y_list)] = 1 + return Image.fromarray(canvas * 255).convert('1') + + +def get_masked_ratio(mask): + """ + Calculate the masked ratio. + mask: Expected a binary PIL image, where 0 and 1 represent + masked(invalid) and valid pixel values. + """ + hist = mask.histogram() + return hist[0] / np.prod(mask.size) diff --git a/FGT_codes/FGT/data/util/readers.py b/FGT_codes/FGT/data/util/readers.py new file mode 100644 index 0000000000000000000000000000000000000000..71bb1cd3840ff390d4ca186b42d920c1e65494a0 --- /dev/null +++ b/FGT_codes/FGT/data/util/readers.py @@ -0,0 +1,527 @@ +import os +import sys +sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) # NOQA +import argparse +from math import ceil +from glob import glob + +import numpy as np +import cv2 +from PIL import Image, ImageDraw, ImageOps, ImageFont + +from utils.logging_config import logger +from utils.util import make_dirs, bbox_offset + + +DEFAULT_FPS = 6 +MAX_LENGTH = 60 + + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument( + '-fps', '--fps', + type=int, default=DEFAULT_FPS, + help="Output video FPS" + ) + parser.add_argument( + '-v', '--video_dir', + type=str, + help="Video directory name" + ) + parser.add_argument( + '-vs', '--video_dirs', + nargs='+', + type=str, + help="Video directory names" + ) + parser.add_argument( + '-v2', '--video_dir2', + type=str, + help="Video directory name" + ) + parser.add_argument( + '-sd', '--segms_dir', + type=str, + help="Segmentation directory name" + ) + parser.add_argument( + '-fgd', '--fg_dir', + type=str, + help="Foreground directory name" + ) + parser.add_argument( + '-fgfd', '--fg_frames_dir', + type=str, + help="Foreground frames directory name" + ) + parser.add_argument( + '-fgsd', '--fg_segms_dir', + type=str, + help="Foreground segmentations directory name" + ) + parser.add_argument( + '-syfd', '--syn_frames_dir', + type=str, + help="Synthesized frames directory name" + ) + parser.add_argument( + '-bgfd', '--bg_frames_dir', + type=str, + help="Background frames directory name" + ) + parser.add_argument( + '-rt', '--reader_type', + type=str, + help="Type of reader" + ) + parser.add_argument( + '-od', '--output_dir', + type=str, + help="Output directory name" + ) + parser.add_argument( + '-o', '--output_filename', + type=str, required=True, + help="Output output filename" + ) + args = parser.parse_args() + return args + + +class Reader: + def __init__(self, dir_name, read=True, max_length=None, sample_period=1): + self.dir_name = dir_name + self.count = 0 + self.max_length = max_length + self.filenames = [] + self.sample_period = sample_period + if read: + if os.path.exists(dir_name): + # self.filenames = read_filenames_from_dir(dir_name, self.__class__.__name__) + # ^^^^^ yield None when reading some videos of face forensics data + # (related to 'Too many levels of symbolic links'?) + + self.filenames = sorted(glob(os.path.join(dir_name, '*'))) + self.filenames = [f for f in self.filenames if os.path.isfile(f)] + self.filenames = self.filenames[::sample_period][:max_length] + self.files = self.read_files(self.filenames) + else: + self.files = [] + logger.warning(f"Directory {dir_name} not exists!") + else: + self.files = [] + self.current_index = 0 + + def append(self, file_): + self.files.append(file_) + + def set_files(self, files): + self.files = files + + def read_files(self, filenames): + assert type(filenames) == list, f'filenames is not a list; dirname: {self.dir_name}' + filenames.sort() + frames = [] + for filename in filenames: + file_ = self.read_file(filename) + frames.append(file_) + return frames + + def save_files(self, output_dir=None): + make_dirs(output_dir) + logger.info(f"Saving {self.__class__.__name__} files to {output_dir}") + for i, file_ in enumerate(self.files): + self._save_file(output_dir, i, file_) + + def _save_file(self, output_dir, i, file_): + raise NotImplementedError("This is an abstract function") + + def read_file(self, filename): + raise NotImplementedError("This is an abstract function") + + def __iter__(self): + return self + + def __next__(self): + if self.current_index < len(self.files): + file_ = self.files[self.current_index] + self.current_index += 1 + return file_ + else: + self.current_index = 0 + raise StopIteration + + def __getitem__(self, key): + return self.files[key] + + def __len__(self): + return len(self.files) + + +class FrameReader(Reader): + def __init__( + self, dir_name, resize=None, read=True, max_length=MAX_LENGTH, + scale=1, sample_period=1 + ): + self.resize = resize + self.scale = scale + self.sample_period = sample_period + super().__init__(dir_name, read, max_length, sample_period) + + def read_file(self, filename): + origin_frame = Image.open(filename) + size = self.resize if self.resize is not None else origin_frame.size + origin_frame_resized = origin_frame.resize( + (int(size[0] * self.scale), int(size[1] * self.scale)) + ) + return origin_frame_resized + + def _save_file(self, output_dir, i, file_): + if len(self.filenames) == len(self.files): + name = sorted(self.filenames)[i].split('/')[-1] + else: + name = f"frame_{i:04}.png" + filename = os.path.join( + output_dir, name + ) + file_.save(filename, "PNG") + + def write_files_to_video(self, output_filename, fps=DEFAULT_FPS, frame_num_when_repeat_list=[1]): + logger.info( + f"Writeing frames to video {output_filename} with FPS={fps}") + video_writer = cv2.VideoWriter( + output_filename, + cv2.VideoWriter_fourcc(*"MJPG"), + fps, + self.files[0].size + ) + for frame_num_when_repeat in frame_num_when_repeat_list: + for frame in self.files: + frame = frame.convert("RGB") + frame_cv = np.array(frame) + frame_cv = cv2.cvtColor(frame_cv, cv2.COLOR_RGB2BGR) + for i in range(frame_num_when_repeat): + video_writer.write(frame_cv) + video_writer.release() + + +class SynthesizedFrameReader(FrameReader): + def __init__( + self, bg_frames_dir, fg_frames_dir, + fg_segms_dir, segm_bbox_mask_dir, fg_dir, dir_name, + bboxes_list_dir, + fg_scale=0.7, fg_location=(48, 27), mask_only=False + ): + self.bg_reader = FrameReader(bg_frames_dir) + self.size = self.bg_reader[0].size + # TODO: add different location and change scale to var + self.fg_reader = ForegroundReader( + fg_frames_dir, fg_segms_dir, fg_dir, + resize=self.size, + scale=fg_scale + ) + self.fg_location = fg_location + # self.masks = self.fg_reader.masks + # self.bbox_masks = self.fg_reader.bbox_masks + super().__init__(dir_name, read=False) + self.files = self.synthesize_frames( + self.bg_reader, self.fg_reader, mask_only) + self.bbox_masks = MaskGenerator( + segm_bbox_mask_dir, self.size, self.get_bboxeses() + ) + self.bboxes_list_dir = bboxes_list_dir + self.bboxes_list = self.get_bboxeses() + self.save_bboxes() + + def save_bboxes(self): + make_dirs(self.bboxes_list_dir) + logger.info(f"Saving bboxes to {self.bboxes_list_dir}") + for i, bboxes in enumerate(self.bboxes_list): + save_path = os.path.join(self.bboxes_list_dir, f"bboxes_{i:04}.txt") + if len(bboxes) > 0: + np.savetxt(save_path, bboxes[0], fmt='%4u') + + def get_bboxeses(self): + bboxeses = self.fg_reader.segms.bboxeses + new_bboxeses = [] + for bboxes in bboxeses: + new_bboxes = [] + for bbox in bboxes: + offset_bbox = bbox_offset(bbox, self.fg_location) + new_bboxes.append(offset_bbox) + new_bboxeses.append(new_bboxes) + return new_bboxeses + + def synthesize_frames(self, bg_reader, fg_reader, mask_only=False): + logger.info( + f"Synthesizing {bg_reader.dir_name} and {fg_reader.dir_name}" + ) + synthesized_frames = [] + for i, bg in enumerate(bg_reader): + if i == len(fg_reader): + break + fg = fg_reader[i] + mask = fg_reader.get_mask(i) + synthesized_frame = bg.copy() + if mask_only: + synthesized_frame.paste(mask, self.fg_location, mask) + else: + synthesized_frame.paste(fg, self.fg_location, mask) + synthesized_frames.append(synthesized_frame) + return synthesized_frames + + +class WarpedFrameReader(FrameReader): + def __init__(self, dir_name, i, ks): + self.i = i + self.ks = ks + super().__init__(dir_name) + + def _save_file(self, output_dir, i, file_): + filename = os.path.join( + output_dir, + f"warped_frame_{self.i:04}_k{self.ks[i]:02}.png" + ) + file_.save(filename) + + +class SegmentationReader(FrameReader): + def __init__( + self, dir_name, + resize=None, scale=1 + ): + super().__init__( + dir_name, resize=resize, scale=scale + ) + + def read_file(self, filename): + origin_frame = Image.open(filename) + mask = ImageOps.invert(origin_frame.convert("L")) + mask = mask.point(lambda x: 0 if x < 255 else 255, '1') + size = self.resize if self.resize is not None else origin_frame.size + mask_resized = mask.resize( + (int(size[0] * self.scale), int(size[1] * self.scale)) + ) + return mask_resized + + +class MaskReader(Reader): + def __init__(self, dir_name, read=True): + super().__init__(dir_name, read=read) + + def read_file(self, filename): + mask = Image.open(filename) + return mask + + def _save_file(self, output_dir, i, file_): + filename = os.path.join( + output_dir, + f"mask_{i:04}.png" + ) + file_.save(filename) + + def get_bboxes(self, i): + # TODO: save bbox instead of looking for one + mask = self.files[i] + mask = ImageOps.invert(mask.convert("L")).convert("1") + mask = np.array(mask) + image, contours, hier = cv2.findContours( + mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) + bboxes = [] + for c in contours: + # get the bounding rect + x, y, w, h = cv2.boundingRect(c) + bbox = ((x, y), (x + w - 1, y + h - 1)) + bboxes.append(bbox) + return bboxes + + def get_bbox(self, i): + # TODO: save bbox instead of looking for one + mask = self.files[i] + mask = ImageOps.invert(mask.convert("L")) + mask = np.array(mask) + image, contours, hier = cv2.findContours( + mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) + for c in contours: + # get the bounding rect + x, y, w, h = cv2.boundingRect(c) + bbox = ((x, y), (x + w - 1, y + h - 1)) + return bbox + + +class MaskGenerator(Reader): + def __init__( + self, mask_output_dir, size, bboxeses, save_masks=True + ): + self.bboxeses = bboxeses + self.size = size + super().__init__(mask_output_dir, read=False) + self.files = self.generate_masks() + if save_masks: + make_dirs(mask_output_dir) + self.save_files(mask_output_dir) + + def _save_file(self, output_dir, i, file_): + filename = os.path.join( + output_dir, + f"mask_{i:04}.png" + ) + file_.save(filename) + + def get_bboxes(self, i): + return self.bboxeses[i] + + def generate_masks(self): + masks = [] + for i in range(len(self.bboxeses)): + mask = self.generate_mask(i) + masks.append(mask) + return masks + + def generate_mask(self, i): + bboxes = self.bboxeses[i] + mask = Image.new("1", self.size, 1) + draw = ImageDraw.Draw(mask) + for bbox in bboxes: + draw.rectangle( + bbox, fill=0 + ) + return mask + + +class ForegroundReader(FrameReader): + def __init__( + self, frames_dir, segms_dir, dir_name, + resize=None, scale=1 + ): + self.frames_dir = frames_dir + self.segms_dir = segms_dir + self.frames = FrameReader( + frames_dir, + resize=resize, scale=scale + ) + self.segms = SegmentationReader( + segms_dir, resize=resize, scale=scale + ) + super().__init__(dir_name, read=False) + self.masks = self.segms.masks + # self.bbox_masks = self.segms.bbox_masks + self.files = self.generate_fg_frames(self.frames, self.segms) + + def get_mask(self, i): + return self.masks[i] + + def generate_fg_frames(self, frames, segms): + logger.info( + f"Generating fg frames from {self.frames_dir} and {self.segms_dir}" + ) + fg_frames = [] + for i, frame in enumerate(frames): + mask = self.masks[i] + fg_frame = Image.new("RGB", frame.size, (0, 0, 0)) + fg_frame.paste( + frame, (0, 0), + mask + ) + fg_frames.append(fg_frame) + return fg_frames + + +class CompareFramesReader(FrameReader): + def __init__(self, dir_names, col=2, names=[], mask_dir=None): + self.videos = [] + for dir_name in dir_names: + # If a method fails on this video, use None to indicate the situation + try: + self.videos.append(FrameReader(dir_name)) + except AssertionError: + self.videos.append(None) + if mask_dir is not None: + self.masks = MaskReader(mask_dir) + self.names = names + self.files = self.combine_videos(self.videos, col) + + def combine_videos(self, videos, col=2, edge_offset=35, h_start_offset=35): + combined_frames = [] + w, h = videos[0][0].size + # Prevent the first method fails and have a "None" as its video + i = 0 + while videos[i] is None: + i += 1 + length = len(videos[i]) + video_num = len(videos) + row = ceil(video_num / col) + for frame_idx in range(length): + width = col * w + (col - 1) * edge_offset + height = row * h + (row - 1) * edge_offset + h_start_offset + combined_frame = Image.new("RGBA", (width, height)) + draw = ImageDraw.Draw(combined_frame) + for i, video in enumerate(videos): + # Give the failed method a black output + if video is None or frame_idx >= len(video): + failed = True + frame = Image.new("RGBA", (w, h)) + else: + frame = video[frame_idx].convert("RGBA") + failed = False + + f_x = (i % col) * (w + edge_offset) + f_y = (i // col) * (h + edge_offset) + h_start_offset + combined_frame.paste(frame, (f_x, f_y)) + + # Draw name + font = ImageFont.truetype("DejaVuSans.ttf", 12) + # font = ImageFont.truetype("DejaVuSans-Bold.ttf", 13) + # font = ImageFont.truetype("timesbd.ttf", 14) + name = self.names[i] if not failed else f'{self.names[i]} (failed)' + draw.text( + (f_x + 10, f_y - 20), + name, (255, 255, 255), font=font + ) + + combined_frames.append(combined_frame) + return combined_frames + + +class BoundingBoxesListReader(Reader): + def __init__( + self, dir_name, resize=None, read=True, max_length=MAX_LENGTH, + scale=1 + ): + self.resize = resize + self.scale = scale + super().__init__(dir_name, read, max_length) + + def read_file(self, filename): + bboxes = np.loadtxt(filename, dtype=int) + bboxes = [bboxes.tolist()] + return bboxes + + +def save_frames_to_dir(frames, dirname): + reader = FrameReader(dirname, read=False) + reader.set_files(frames) + reader.save_files(dirname) + + +if __name__ == "__main__": + args = parse_args() + if args.reader_type is None: + reader = FrameReader(args.video_dir) + elif args.reader_type == 'fg': + reader = ForegroundReader( + args.video_dir, args.segms_dir, args.fg_dir) + elif args.reader_type == 'sy': + reader = SynthesizedFrameReader( + args.bg_frames_dir, args.fg_frames_dir, + args.fg_segms_dir, args.fg_dir, args.syn_frames_dir + ) + elif args.reader_type == 'com': + reader = CompareFramesReader( + args.video_dirs + ) + reader.write_files_to_video( + os.path.join(args.output_dir, args.output_filename), + fps=args.fps + ) diff --git a/FGT_codes/FGT/data/util/util.py b/FGT_codes/FGT/data/util/util.py new file mode 100644 index 0000000000000000000000000000000000000000..1170de3aa61b19eae12fb7ec45505e6e26a68b42 --- /dev/null +++ b/FGT_codes/FGT/data/util/util.py @@ -0,0 +1,259 @@ +import os +import argparse +import shutil +from glob import glob + +import numpy as np +from PIL import Image + +from utils.logging_config import logger + + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument( + '-v', '--video_dir', + type=str, + help="Video directory name" + ) + parser.add_argument( + '-fl', '--flow_dir', + type=str, + help="Optical flow ground truth directory name" + ) + parser.add_argument( + '-od', '--output_dir', + type=str, + help="Output directory name" + ) + parser.add_argument( + '-o', '--output_filename', + type=str, + help="Output output filename" + ) + args = parser.parse_args() + return args + + +def make_dirs(dir_name): + if not os.path.exists(dir_name): + os.makedirs(dir_name) + logger.info(f"Directory {dir_name} made") + + +ensure_dir = make_dirs + + +def make_dir_under_root(root_dir, name): + full_dir_name = os.path.join(root_dir, name) + make_dirs(full_dir_name) + return full_dir_name + + +def rm_dirs(dir_name, ignore_errors=False): + if os.path.exists(dir_name): + shutil.rmtree(dir_name, ignore_errors) + logger.info(f"Directory {dir_name} removed") + + +def read_dirnames_under_root(root_dir, skip_list=[]): + dirnames = [ + name for i, name in enumerate(sorted(os.listdir(root_dir))) + if (os.path.isdir(os.path.join(root_dir, name)) + and name not in skip_list + and i not in skip_list) + ] + logger.info(f"Reading directories under {root_dir}, exclude {skip_list}, num: {len(dirnames)}") + return dirnames + + +def bbox_offset(bbox, location): + x0, y0 = location + (x1, y1), (x2, y2) = bbox + return ((x1 + x0, y1 + y0), (x2 + x0, y2 + y0)) + + +def cover2_bbox(bbox1, bbox2): + x1 = min(bbox1[0][0], bbox2[0][0]) + y1 = min(bbox1[0][1], bbox2[0][1]) + x2 = max(bbox1[1][0], bbox2[1][0]) + y2 = max(bbox1[1][1], bbox2[1][1]) + return ((x1, y1), (x2, y2)) + + +def extend_r_bbox(bbox, w, h, r): + (x1, y1), (x2, y2) = bbox + x1 = max(x1 - r, 0) + x2 = min(x2 + r, w) + y1 = max(y1 - r, 0) + y2 = min(y2 + r, h) + return ((x1, y1), (x2, y2)) + + +def mean_squared_error(A, B): + return np.square(np.subtract(A, B)).mean() + + +def bboxes_to_mask(size, bboxes): + mask = Image.new("L", size, 255) + mask = np.array(mask) + for bbox in bboxes: + try: + (x1, y1), (x2, y2) = bbox + except Exception: + (x1, y1, x2, y2) = bbox + + mask[y1:y2, x1:x2] = 0 + mask = Image.fromarray(mask.astype("uint8")) + return mask + + +def get_extended_from_box(img_size, box, patch_size): + def _decide_patch_num(box_width, patch_size): + num = np.ceil(box_width / patch_size).astype(np.int) + if (num * patch_size - box_width) < (patch_size // 2): + num += 1 + return num + + x1, y1 = box[0] + x2, y2 = box[1] + new_box = (x1, y1, x2 - x1, y2 - y1) + box_x_start, box_y_start, box_x_size, box_y_size = new_box + + patchN_x = _decide_patch_num(box_x_size, patch_size) + patchN_y = _decide_patch_num(box_y_size, patch_size) + + extend_x = (patch_size * patchN_x - box_x_size) // 2 + extend_y = (patch_size * patchN_y - box_y_size) // 2 + img_x_size = img_size[0] + img_y_size = img_size[1] + + x_start = max(0, box_x_start - extend_x) + x_end = min(box_x_start - extend_x + patchN_x * patch_size, img_x_size) + + y_start = max(0, box_y_start - extend_y) + y_end = min(box_y_start - extend_y + patchN_y * patch_size, img_y_size) + x_start, y_start, x_end, y_end = int(x_start), int(y_start), int(x_end), int(y_end) + extented_box = ((x_start, y_start), (x_end, y_end)) + return extented_box + + +# code modified from https://github.com/WonwoongCho/Generative-Inpainting-pytorch/blob/master/util.py +def spatial_discounting_mask(mask_width, mask_height, discounting_gamma): + """Generate spatial discounting mask constant. + Spatial discounting mask is first introduced in publication: + Generative Image Inpainting with Contextual Attention, Yu et al. + Returns: + np.array: spatial discounting mask + """ + gamma = discounting_gamma + mask_values = np.ones((mask_width, mask_height), dtype=np.float32) + for i in range(mask_width): + for j in range(mask_height): + mask_values[i, j] = max( + gamma**min(i, mask_width - i), + gamma**min(j, mask_height - j)) + + return mask_values + + +def bboxes_to_discounting_loss_mask(img_size, bboxes, discounting_gamma=0.99): + mask = np.zeros(img_size, dtype=np.float32) + 0.5 + for bbox in bboxes: + try: + (x1, y1), (x2, y2) = bbox + except Exception: + (x1, y1, x2, y2) = bbox + mask_width, mask_height = y2 - y1, x2 - x1 + mask[y1:y2, x1:x2] = spatial_discounting_mask(mask_width, mask_height, discounting_gamma) + return mask + + +def find_proper_window(image_size, bbox_point): + ''' + parameters: + image_size(2-tuple): (height, width) + bbox_point(2-2-tuple): (first_point, last_point) + return values: + window left-up point, (2-tuple) + window right-bottom point, (2-tuple) + ''' + bbox_height = bbox_point[1][0] - bbox_point[0][0] + bbox_width = bbox_point[1][1] - bbox_point[0][1] + + window_size = min( + max(bbox_height, bbox_width) * 2, + image_size[0], image_size[1] + ) + # Limit min window size due to the requirement of VGG16 + window_size = max(window_size, 32) + + horizontal_span = window_size - (bbox_point[1][1] - bbox_point[0][1]) + vertical_span = window_size - (bbox_point[1][0] - bbox_point[0][0]) + + top_bound, bottom_bound = bbox_point[0][0] - \ + vertical_span // 2, bbox_point[1][0] + vertical_span // 2 + left_bound, right_bound = bbox_point[0][1] - \ + horizontal_span // 2, bbox_point[1][1] + horizontal_span // 2 + + if left_bound < 0: + right_bound += 0 - left_bound + left_bound += 0 - left_bound + elif right_bound > image_size[1]: + left_bound -= right_bound - image_size[1] + right_bound -= right_bound - image_size[1] + + if top_bound < 0: + bottom_bound += 0 - top_bound + top_bound += 0 - top_bound + elif bottom_bound > image_size[0]: + top_bound -= bottom_bound - image_size[0] + bottom_bound -= bottom_bound - image_size[0] + + return (top_bound, left_bound), (bottom_bound, right_bound) + + +def drawrect(drawcontext, xy, outline=None, width=0, partial=None): + (x1, y1), (x2, y2) = xy + if partial is None: + points = (x1, y1), (x2, y1), (x2, y2), (x1, y2), (x1, y1) + drawcontext.line(points, fill=outline, width=width) + else: + drawcontext.line([(x1, y1), (x1, y1 + partial)], fill=outline, width=width) + drawcontext.line([(x1 + partial, y1), (x1, y1)], fill=outline, width=width) + + drawcontext.line([(x2, y1), (x2, y1 + partial)], fill=outline, width=width) + drawcontext.line([(x2, y1), (x2 - partial, y1)], fill=outline, width=width) + + drawcontext.line([(x1, y2), (x1 + partial, y2)], fill=outline, width=width) + drawcontext.line([(x1, y2), (x1, y2 - partial)], fill=outline, width=width) + + drawcontext.line([(x2 - partial, y2), (x2, y2)], fill=outline, width=width) + drawcontext.line([(x2, y2), (x2, y2 - partial)], fill=outline, width=width) + + +def get_everything_under(root_dir, pattern='*', only_dirs=False, only_files=False): + assert not(only_dirs and only_files), 'You will get nothnig '\ + 'when "only_dirs" and "only_files" are both set to True' + everything = sorted(glob(os.path.join(root_dir, pattern))) + if only_dirs: + everything = [f for f in everything if os.path.isdir(f)] + if only_files: + everything = [f for f in everything if os.path.isfile(f)] + + return everything + + +def read_filenames_from_dir(dir_name, reader, max_length=None): + logger.debug( + f"{reader} reading files from {dir_name}") + filenames = [] + for root, dirs, files in os.walk(dir_name): + assert len(dirs) == 0, f"There are direcories: {dirs} in {root}" + assert len(files) != 0, f"There are no files in {root}" + filenames = [os.path.join(root, name) for name in sorted(files)] + for name in filenames: + logger.debug(name) + if max_length is not None: + return filenames[:max_length] + return filenames diff --git a/FGT_codes/FGT/data/util/utils.py b/FGT_codes/FGT/data/util/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..4d38b2df4e0c79dfcdbc9d1e57add64cfdbf9dcc --- /dev/null +++ b/FGT_codes/FGT/data/util/utils.py @@ -0,0 +1,158 @@ +import random +import numpy as np +import cv2 + +def random_bbox(img_height, img_width, vertical_margin, horizontal_margin, mask_height, mask_width): + maxt = img_height - vertical_margin - mask_height + maxl = img_width - horizontal_margin - mask_width + + t = random.randint(vertical_margin, maxt) + l = random.randint(horizontal_margin, maxl) + h = random.randint(mask_height // 2, mask_height) + w = random.randint(mask_width // 2, mask_width) + return (t, l, h, w) # 产生随机块状box,这个box后面会发展成为mask + + +def mid_bbox_mask(img_height, img_width, mask_height, mask_width): + def npmask(bbox, height, width): + mask = np.zeros((height, width, 1), np.float32) + mask[bbox[0]: bbox[0] + bbox[2], bbox[1]: bbox[1] + bbox[3], :] = 255. + return mask + + bbox = (img_height * 3 // 8, img_width * 3 // 8, mask_height, mask_width) + mask = npmask(bbox, img_height, img_width) + + return mask + + +def bbox2mask(img_height, img_width, max_delta_height, max_delta_width, bbox): + """Generate mask tensor from bbox. + + Args: + bbox: configuration tuple, (top, left, height, width) + config: Config should have configuration including IMG_SHAPES, + MAX_DELTA_HEIGHT, MAX_DELTA_WIDTH. + + Returns: + tf.Tensor: output with shape [B, 1, H, W] + + """ + + def npmask(bbox, height, width, delta_h, delta_w): + mask = np.zeros((height, width, 1), np.float32) + h = np.random.randint(delta_h // 2 + 1) # 防止有0产生 + w = np.random.randint(delta_w // 2 + 1) + mask[bbox[0] + h: bbox[0] + bbox[2] - h, bbox[1] + w: bbox[1] + bbox[3] - w, :] = 255. # height_true = height - 2 * h, width_true = width - 2 * w + return mask + + mask = npmask(bbox, img_height, img_width, + max_delta_height, + max_delta_width) + + return mask + + +def matrix2bbox(img_height, img_width, mask_height, mask_width, row, column): + """Generate masks with a matrix form + @param img_height + @param img_width + @param mask_height + @param mask_width + @param row: number of blocks in row + @param column: number of blocks in column + @return mbbox: multiple bboxes in (y, h, h, w) manner + """ + assert img_height - column * mask_height > img_height // 2, "Too many masks across a column" + assert img_width - row * mask_width > img_width // 2, "Too many masks across a row" + + interval_height = (img_height - column * mask_height) // (column + 1) + interval_width = (img_width - row * mask_width) // (row + 1) + + mbbox = [] + for i in range(row): + for j in range(column): + y = interval_height * (j+1) + j * mask_height + x = interval_width * (i+1) + i * mask_width + mbbox.append((y, x, mask_height, mask_width)) + return mbbox + + +def mbbox2masks(img_height, img_width, mbbox): + + def npmask(mbbox, height, width): + mask = np.zeros((height, width, 1), np.float32) + for bbox in mbbox: + mask[bbox[0]: bbox[0] + bbox[2], bbox[1]: bbox[1] + bbox[3], :] = 255. # height_true = height - 2 * h, width_true = width - 2 * w + return mask + + mask = npmask(mbbox, img_height, img_width) + + return mask + + +def draw_line(mask, startX, startY, angle, length, brushWidth): + """assume the size of mask is (H,W,1) + """ + assert len(mask.shape) == 2 or mask.shape[2] == 1, "The channel of mask doesn't fit the opencv format" + offsetX = int(np.round(length * np.cos(angle))) + offsetY = int(np.round(length * np.sin(angle))) + endX = startX + offsetX + endY = startY + offsetY + if endX > mask.shape[1]: + endX = mask.shape[1] + if endY > mask.shape[0]: + endY = mask.shape[0] + mask_processed = cv2.line(mask, (startX, startY), (endX, endY), 255, brushWidth) + return mask_processed, endX, endY + + +def draw_circle(mask, circle_x, circle_y, brushWidth): + radius = brushWidth // 2 + assert len(mask.shape) == 2 or mask.shape[2] == 1, "The channel of mask doesn't fit the opencv format" + mask_processed = cv2.circle(mask, (circle_x, circle_y), radius, 255) + return mask_processed + + +def freeFormMask(img_height, img_width, maxVertex, maxLength, maxBrushWidth, maxAngle): + mask = np.zeros((img_height, img_width)) + numVertex = random.randint(1, maxVertex) + startX = random.randint(10, img_width) + startY = random.randint(10, img_height) + brushWidth = random.randint(10, maxBrushWidth) + for i in range(numVertex): + angle = random.uniform(0, maxAngle) + if i % 2 == 0: + angle = 2 * np.pi - angle + length = random.randint(10, maxLength) + mask, endX, endY = draw_line(mask, startX, startY, angle, length, brushWidth) + startX = startX + int(length * np.sin(angle)) + startY = startY + int(length * np.cos(angle)) + mask = draw_circle(mask, endX, endY, brushWidth) + + if random.random() < 0.5: + mask = np.fliplr(mask) + if random.random() < 0.5: + mask = np.flipud(mask) + + if len(mask.shape) == 2: + mask = mask[:, :, np.newaxis] + + return mask + + +if __name__ == "__main__": + # for stationary mask generation + # stationary_mask_generator(240, 480, 50, 120) + + # for free-form mask generation + # mask = freeFormMask(240, 480, 30, 50, 20, np.pi) + # cv2.imwrite('mask.png', mask) + + # for matrix mask generation + # img_height, img_width = 240, 480 + # masks = matrix2bbox(240, 480, 20, 20, 5, 4) + # matrixMask = mbbox2masks(img_height, img_width, masks) + # cv2.imwrite('matrixMask.png', matrixMask) + pass + + diff --git a/FGT_codes/FGT/flowCheckPoint/config.yaml b/FGT_codes/FGT/flowCheckPoint/config.yaml new file mode 100644 index 0000000000000000000000000000000000000000..dc7ed566ff2427bee93bd1cd2e65f61a09432c12 --- /dev/null +++ b/FGT_codes/FGT/flowCheckPoint/config.yaml @@ -0,0 +1,11 @@ +PASSMASK: 1 +cnum: 48 +conv_type: vanilla +flow_interval: 1 +in_channel: 3 +init_weights: 1 +num_flows: 1 +resBlocks: 1 +use_bias: 1 +use_residual: 1 +model: lafc_single diff --git a/FGT_codes/FGT/flowCheckPoint/lafc_single.pth.tar b/FGT_codes/FGT/flowCheckPoint/lafc_single.pth.tar new file mode 100644 index 0000000000000000000000000000000000000000..682f2477bc3816888d4d6bba6eeaccaf221f00d2 --- /dev/null +++ b/FGT_codes/FGT/flowCheckPoint/lafc_single.pth.tar @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0fa168e8b711852c458594cddf4262afdb81e096253197a802a29b4dec9d6d12 +size 11547053 diff --git a/FGT_codes/FGT/inputs.py b/FGT_codes/FGT/inputs.py new file mode 100644 index 0000000000000000000000000000000000000000..363b9637947dbc63f3f404b2eff3a37a162ad66d --- /dev/null +++ b/FGT_codes/FGT/inputs.py @@ -0,0 +1,83 @@ +import argparse + + +def args_parser(): + parser = argparse.ArgumentParser(description="General top layer trainer") + parser.add_argument("--opt", type=str, default="config/train.yaml", help="Path to optional configuration file") + parser.add_argument('--model', type=str, default='model', + help='Model block name, in the `model` directory') + parser.add_argument('--name', type=str, default='FGT_train', help='Experiment name') + parser.add_argument('--outputdir', type=str, default='/myData/ret/experiments', help='Output dir to save results') + parser.add_argument('--datadir', type=str, default='/myData/', metavar='PATH') + parser.add_argument('--datasetName_train', type=str, default='train_dataset_frames_diffusedFlows', + help='The file name of the train dataset, in `data` directory') + parser.add_argument('--network', type=str, default='network', + help='The network file which defines the training process, in the `network` directory') + parser.add_argument('--finetune', type=int, default=0, help='Whether to fine tune trained models') + # parser.add_argument('--checkPoint', type=str, default='', help='checkpoint path for continue training') + parser.add_argument('--gen_state', type=str, default='', help='Checkpoint of the generator') + parser.add_argument('--dis_state', type=str, default='', help='Checkpoint of the discriminator') + parser.add_argument('--opt_state', type=str, default='', help='Checkpoint of the options') + parser.add_argument('--record_iter', type=int, default=16, help='How many iters to print an item of log') + parser.add_argument('--flow_checkPoint', type=str, default='flowCheckPoint/', + help='The path for flow model filling') + parser.add_argument('--dataMode', type=str, default='resize', choices=['resize', 'crop']) + + # data related parameters + parser.add_argument('--flow2rgb', type=int, default=1, help='Whether to transform flows from raw data to rgb') + parser.add_argument('--flow_direction', type=str, default='for', choices=['for', 'back', 'bi'], + help='Which GT flow should be chosen for guidance') + parser.add_argument('--num_frames', type=int, default=5, help='How many frames are chosen for frame completion') + parser.add_argument('--sample', type=str, default='random', choices=['random', 'seq'], + help='Choose the sample method for training in each iterations') + parser.add_argument('--max_val', type=float, default=0.01, help='The maximal value to quantize the optical flows') + + # model related parameters + parser.add_argument('--res_h', type=int, default=240, help='The height of the frame resolution') + parser.add_argument('--res_w', type=int, default=432, help='The width of the frame resolution') + parser.add_argument('--in_channel', type=int, default=4, help='The input channel of the frame branch') + parser.add_argument('--cnum', type=int, default=64, help='The initial channel number of the frame branch') + parser.add_argument('--flow_inChannel', type=int, default=2, help='The input channel of the flow branch') + parser.add_argument('--flow_cnum', type=int, default=64, help='The initial channel dimension of the flow branch') + parser.add_argument('--dist_cnum', type=int, default=32, help='The initial channel num in the discriminator') + parser.add_argument('--frame_hidden', type=int, default=512, + help='The channel / patch dimension in the frame branch') + parser.add_argument('--flow_hidden', type=int, default=256, help='The channel / patch dimension in the flow branch') + parser.add_argument('--PASSMASK', type=int, default=1, + help='1 -> concat the mask with the corrupted optical flows to fill the flow') + parser.add_argument('--numBlocks', type=int, default=8, help='How many transformer blocks do we need to stack') + parser.add_argument('--kernel_size_w', type=int, default=7, help='The width of the kernel for extracting patches') + parser.add_argument('--kernel_size_h', type=int, default=7, help='The height of the kernel for extracting patches') + parser.add_argument('--stride_h', type=int, default=3, help='The height of the stride') + parser.add_argument('--stride_w', type=int, default=3, help='The width of the stride') + parser.add_argument('--pad_h', type=int, default=3, help='The height of the padding') + parser.add_argument('--pad_w', type=int, default=3, help='The width of the padding') + parser.add_argument('--num_head', type=int, default=4, help='The head number for the multihead attention') + parser.add_argument('--conv_type', type=str, choices=['vanilla', 'gated', 'partial'], default='vanilla', + help='Which kind of conv to use') + parser.add_argument('--norm', type=str, default='None', choices=['None', 'BN', 'SN', 'IN'], + help='The normalization method for the conv blocks') + parser.add_argument('--use_bias', type=int, default=1, help='If 1, use bias in the convolution blocks') + parser.add_argument('--ape', type=int, default=1, help='If ape = 1, use absolute positional embedding') + parser.add_argument('--pos_mode', type=str, default='single', choices=['single', 'dual'], + help='If pos_mode = dual, add positional embedding to flow patches') + parser.add_argument('--mlp_ratio', type=int, default=40, help='The mlp dilation rate for the feed forward layers') + parser.add_argument('--drop', type=int, default=0, help='The dropout rate, 0 by default') + parser.add_argument('--init_weights', type=int, default=1, help='If 1, initialize the network, 1 by default') + + # loss related parameters + parser.add_argument('--L1M', type=float, default=1, help='The weight of L1 loss in the masked area') + parser.add_argument('--L1V', type=float, default=1, help='The weight of L1 loss in the valid area') + parser.add_argument('--adv', type=float, default=0.01, help='The weight of adversarial loss') + + # spatial and temporal related parameters + parser.add_argument('--tw', type=int, default=2, help='The number of temporal group in the temporal transformer') + parser.add_argument('--sw', type=int, default=8, + help='The number of spatial window size in the spatial transformer') + parser.add_argument('--gd', type=int, default=4, help='Global downsample rate for spatial transformer') + + parser.add_argument('--ref_length', type=int, default=10, help='The sample interval during inference') + parser.add_argument('--use_valid', action='store_true') + + args = parser.parse_args() + return args diff --git a/FGT_codes/FGT/metrics/__init__.py b/FGT_codes/FGT/metrics/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..46ea22fd70085ba3878587ddd252b04f24c67885 --- /dev/null +++ b/FGT_codes/FGT/metrics/__init__.py @@ -0,0 +1,31 @@ +import numpy as np +from skimage.metrics import peak_signal_noise_ratio as psnr +from skimage.metrics import structural_similarity as ssim +import os + +os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE" + + +def calculate_metrics(results, gts): + B, H, W, C = results.shape + psnr_values, ssim_values, L1errors, L2errors = [], [], [], [] + for i in range(B): + result = results[i] + gt = gts[i] + result_img = result + gt_img = gt + residual = result - gt + L1error = np.mean(np.abs(residual)) + L2error = np.sum(residual ** 2) ** 0.5 / (H * W * C) + psnr_value = psnr(result_img, gt_img) + ssim_value = ssim(result_img, gt_img, multichannel=True) + L1errors.append(L1error) + L2errors.append(L2error) + psnr_values.append(psnr_value) + ssim_values.append(ssim_value) + L1_value = np.mean(L1errors) + L2_value = np.mean(L2errors) + psnr_value = np.mean(psnr_values) + ssim_value = np.mean(ssim_values) + + return {'l1': L1_value, 'l2': L2_value, 'psnr': psnr_value, 'ssim': ssim_value} diff --git a/FGT_codes/FGT/metrics/psnr.py b/FGT_codes/FGT/metrics/psnr.py new file mode 100644 index 0000000000000000000000000000000000000000..52a12602a7de2403ce7c2baf32c1cfcb359d9f2a --- /dev/null +++ b/FGT_codes/FGT/metrics/psnr.py @@ -0,0 +1,10 @@ +import numpy +import math + + +def psnr(img1, img2): + mse = numpy.mean( (img1 - img2) ** 2 ) + if mse == 0: + return 100 + PIXEL_MAX = 255.0 + return 20 * math.log10(PIXEL_MAX / math.sqrt(mse)) \ No newline at end of file diff --git a/FGT_codes/FGT/metrics/ssim.py b/FGT_codes/FGT/metrics/ssim.py new file mode 100644 index 0000000000000000000000000000000000000000..2a3a431813678cf5d02f0d0b8185712be16f9e24 --- /dev/null +++ b/FGT_codes/FGT/metrics/ssim.py @@ -0,0 +1,46 @@ +import cv2 +import numpy as np + + +def calculate_ssim(img1, img2): + C1 = (0.01 * 255)**2 + C2 = (0.03 * 255)**2 + + img1 = img1.astype(np.float64) + img2 = img2.astype(np.float64) + kernel = cv2.getGaussianKernel(11, 1.5) + window = np.outer(kernel, kernel.transpose()) + + mu1 = cv2.filter2D(img1, -1, window)[5:-5, 5:-5] # valid + mu2 = cv2.filter2D(img2, -1, window)[5:-5, 5:-5] + mu1_sq = mu1**2 + mu2_sq = mu2**2 + mu1_mu2 = mu1 * mu2 + sigma1_sq = cv2.filter2D(img1**2, -1, window)[5:-5, 5:-5] - mu1_sq + sigma2_sq = cv2.filter2D(img2**2, -1, window)[5:-5, 5:-5] - mu2_sq + sigma12 = cv2.filter2D(img1 * img2, -1, window)[5:-5, 5:-5] - mu1_mu2 + + ssim_map = ((2 * mu1_mu2 + C1) * (2 * sigma12 + C2)) / ((mu1_sq + mu2_sq + C1) * + (sigma1_sq + sigma2_sq + C2)) + return ssim_map.mean() + + +def ssim(img1, img2): + '''calculate SSIM + the same outputs as MATLAB's + img1, img2: [0, 255] + ''' + if not img1.shape == img2.shape: + raise ValueError('Input images must have the same dimensions.') + if img1.ndim == 2: + return calculate_ssim(img1, img2) + elif img1.ndim == 3: + if img1.shape[2] == 3: + ssims = [] + for i in range(3): + ssims.append(calculate_ssim(img1[:, :, i], img2[:, :, i])) + return np.array(ssims).mean() + elif img1.shape[2] == 1: + return calculate_ssim(np.squeeze(img1), np.squeeze(img2)) + else: + raise ValueError('Wrong input image dimensions.') \ No newline at end of file diff --git a/FGT_codes/FGT/models/BaseNetwork.py b/FGT_codes/FGT/models/BaseNetwork.py new file mode 100644 index 0000000000000000000000000000000000000000..648147819039a0e31c1a2e8155e830ba2488ead1 --- /dev/null +++ b/FGT_codes/FGT/models/BaseNetwork.py @@ -0,0 +1,46 @@ +from .utils.network_blocks_2d import * + + +class BaseNetwork(nn.Module): + def __init__(self, conv_type): + super(BaseNetwork, self).__init__() + self.conv_type = conv_type + if conv_type == 'gated': + self.ConvBlock = GatedConv + self.DeconvBlock = GatedDeconv + if conv_type == 'partial': + self.ConvBlock = PartialConv + self.DeconvBlock = PartialDeconv + if conv_type == 'vanilla': + self.ConvBlock = VanillaConv + self.DeconvBlock = VanillaDeconv + self.ConvBlock2d = self.ConvBlock + self.DeconvBlock2d = self.DeconvBlock + + def init_weights(self, init_type='normal', gain=0.02): + ''' + initialize network's weights + init_type: normal | xavier | kaiming | orthogonal + https://github.com/junyanz/pytorch-CycleGAN-and-pix2pix/blob/9451e70673400885567d08a9e97ade2524c700d0/models/networks.py#L39 + ''' + + def init_func(m): + classname = m.__class__.__name__ + if hasattr(m, 'weight') and (classname.find('Conv') != -1 or classname.find('Linear') != -1): + if init_type == 'normal': + nn.init.normal_(m.weight.data, 0.0, gain) + elif init_type == 'xavier': + nn.init.xavier_normal_(m.weight.data, gain=gain) + elif init_type == 'kaiming': + nn.init.kaiming_normal_(m.weight.data, a=0, mode='fan_in') + elif init_type == 'orthogonal': + nn.init.orthogonal_(m.weight.data, gain=gain) + + if hasattr(m, 'bias') and m.bias is not None: + nn.init.constant_(m.bias.data, 0.0) + + elif classname.find('BatchNorm2d') != -1: + nn.init.normal_(m.weight.data, 1.0, gain) + nn.init.constant_(m.bias.data, 0.0) + + self.apply(init_func) diff --git a/FGT_codes/FGT/models/__init__.py b/FGT_codes/FGT/models/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/FGT_codes/FGT/models/__pycache__/BaseNetwork.cpython-39.pyc b/FGT_codes/FGT/models/__pycache__/BaseNetwork.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fd3cf1373454d4c1ac3b1fe29be189b005922d44 Binary files /dev/null and b/FGT_codes/FGT/models/__pycache__/BaseNetwork.cpython-39.pyc differ diff --git a/FGT_codes/FGT/models/__pycache__/__init__.cpython-39.pyc b/FGT_codes/FGT/models/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3a7f36d1c98ee325ac1609ebd807f248f6559d33 Binary files /dev/null and b/FGT_codes/FGT/models/__pycache__/__init__.cpython-39.pyc differ diff --git a/FGT_codes/FGT/models/__pycache__/model.cpython-39.pyc b/FGT_codes/FGT/models/__pycache__/model.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9dbc31ac7cea16431a673517afb6e432d49d6494 Binary files /dev/null and b/FGT_codes/FGT/models/__pycache__/model.cpython-39.pyc differ diff --git a/FGT_codes/FGT/models/lafc_single.py b/FGT_codes/FGT/models/lafc_single.py new file mode 100644 index 0000000000000000000000000000000000000000..50ec653d9e2ab306891f9520c2de46781827ccbc --- /dev/null +++ b/FGT_codes/FGT/models/lafc_single.py @@ -0,0 +1,114 @@ +import torch +import torch.nn.functional as F +import torch.nn as nn +import functools +from .BaseNetwork import BaseNetwork +from models.utils.reconstructionLayers import make_layer, ResidualBlock_noBN + + +class Model(nn.Module): + def __init__(self, config): + super(Model, self).__init__() + self.net = P3DNet(config['num_flows'], config['cnum'], config['in_channel'], config['PASSMASK'], + config['use_residual'], + config['resBlocks'], config['use_bias'], config['conv_type'], config['init_weights']) + + def forward(self, flows, masks, edges=None): + ret = self.net(flows, masks, edges) + return ret + + +class P3DNet(BaseNetwork): + def __init__(self, num_flows, num_feats, in_channels, passmask, use_residual, res_blocks, + use_bias, conv_type, init_weights): + super().__init__(conv_type) + self.passmask = passmask + self.encoder2 = nn.Sequential( + nn.ReplicationPad2d(2), + self.ConvBlock2d(in_channels, num_feats, kernel_size=5, stride=1, padding=0, bias=use_bias, norm=None), + self.ConvBlock2d(num_feats, num_feats * 2, kernel_size=3, stride=2, padding=1, bias=use_bias, norm=None) + ) + self.encoder4 = nn.Sequential( + self.ConvBlock2d(num_feats * 2, num_feats * 2, kernel_size=3, stride=1, padding=1, bias=use_bias, + norm=None), + self.ConvBlock2d(num_feats * 2, num_feats * 4, kernel_size=3, stride=2, padding=1, bias=use_bias, norm=None) + ) + residualBlock = functools.partial(ResidualBlock_noBN, nf=num_feats * 4) + self.res_blocks = make_layer(residualBlock, res_blocks) + self.resNums = res_blocks + # dilation convolution to enlarge the receptive field + self.middle = nn.Sequential( + self.ConvBlock2d(num_feats * 4, num_feats * 4, kernel_size=3, stride=1, padding=8, bias=use_bias, + dilation=8, norm=None), + self.ConvBlock2d(num_feats * 4, num_feats * 4, kernel_size=3, stride=1, padding=4, bias=use_bias, + dilation=4, norm=None), + self.ConvBlock2d(num_feats * 4, num_feats * 4, kernel_size=3, stride=1, padding=2, bias=use_bias, + dilation=2, norm=None), + self.ConvBlock2d(num_feats * 4, num_feats * 4, kernel_size=3, stride=1, padding=1, bias=use_bias, + dilation=1, norm=None), + ) + self.decoder2 = nn.Sequential( + self.DeconvBlock2d(num_feats * 8, num_feats * 2, kernel_size=3, stride=1, padding=1, bias=use_bias, + norm=None), + self.ConvBlock2d(num_feats * 2, num_feats * 2, kernel_size=3, stride=1, padding=1, bias=use_bias, + norm=None), + self.ConvBlock2d(num_feats * 2, num_feats * 2, kernel_size=3, stride=1, padding=1, bias=use_bias, + norm=None) + ) + self.decoder = nn.Sequential( + self.DeconvBlock2d(num_feats * 4, num_feats, kernel_size=3, stride=1, padding=1, bias=use_bias, + norm=None), + self.ConvBlock2d(num_feats, num_feats // 2, kernel_size=3, stride=1, padding=1, bias=use_bias, + norm=None), + self.ConvBlock2d(num_feats // 2, 2, kernel_size=3, stride=1, padding=1, bias=use_bias, + norm=None) + ) + self.edgeDetector = EdgeDetection(conv_type) + if init_weights: + self.init_weights() + + def forward(self, flows, masks, edges=None): + if self.passmask: + inputs = torch.cat((flows, masks), dim=1) + else: + inputs = flows + if edges is not None: + inputs = torch.cat((inputs, edges), dim=1) + e2 = self.encoder2(inputs) + e4 = self.encoder4(e2) + if self.resNums > 0: + e4_res = self.res_blocks(e4) + else: + e4_res = e4 + c_e4_filled = self.middle(e4_res) + c_e4 = torch.cat((c_e4_filled, e4), dim=1) + c_e2Post = self.decoder2(c_e4) + c_e2 = torch.cat((c_e2Post, e2), dim=1) + output = self.decoder(c_e2) + edge = self.edgeDetector(output) + return output, edge + + +class EdgeDetection(BaseNetwork): + def __init__(self, conv_type, in_channels=2, out_channels=1, mid_channels=16): + super(EdgeDetection, self).__init__(conv_type) + self.projection = self.ConvBlock2d(in_channels=in_channels, out_channels=mid_channels, kernel_size=3, stride=1, + padding=1, norm=None) + self.mid_layer_1 = self.ConvBlock2d(in_channels=mid_channels, out_channels=mid_channels, kernel_size=3, + stride=1, padding=1, norm=None) + self.mid_layer_2 = self.ConvBlock2d(in_channels=mid_channels, out_channels=mid_channels, kernel_size=3, + stride=1, padding=1, activation=None, norm=None) + self.l_relu = nn.LeakyReLU() + self.out_layer = self.ConvBlock2d(in_channels=mid_channels, out_channels=out_channels, kernel_size=1, + activation=None, norm=None) + + def forward(self, flow): + flow = self.projection(flow) + edge = self.mid_layer_1(flow) + edge = self.mid_layer_2(edge) + edge = self.l_relu(flow + edge) + edge = self.out_layer(edge) + edge = torch.sigmoid(edge) + return edge + + diff --git a/FGT_codes/FGT/models/model.py b/FGT_codes/FGT/models/model.py new file mode 100644 index 0000000000000000000000000000000000000000..fe3cef1f2d1fafdbea4ad2b504187ca701d927f8 --- /dev/null +++ b/FGT_codes/FGT/models/model.py @@ -0,0 +1,284 @@ +from models.BaseNetwork import BaseNetwork +from models.transformer_base.ffn_base import FusionFeedForward +from models.transformer_base.attention_flow import SWMHSA_depthGlobalWindowConcatLN_qkFlow_reweightFlow +from models.transformer_base.attention_base import TMHSA + +import torch +import torch.nn as nn +from functools import reduce +import torch.nn.functional as F + + +class Model(nn.Module): + def __init__(self, config): + super(Model, self).__init__() + self.net = FGT(config['tw'], config['sw'], config['gd'], config['input_resolution'], config['in_channel'], + config['cnum'], config['flow_inChannel'], config['flow_cnum'], config['frame_hidden'], + config['flow_hidden'], config['PASSMASK'], + config['numBlocks'], config['kernel_size'], config['stride'], config['padding'], + config['num_head'], config['conv_type'], config['norm'], + config['use_bias'], config['ape'], + config['mlp_ratio'], config['drop'], config['init_weights']) + + def forward(self, frames, flows, masks): + ret = self.net(frames, flows, masks) + return ret + + +class Encoder(nn.Module): + def __init__(self, in_channels): + super(Encoder, self).__init__() + self.group = [1, 2, 4, 8, 1] + self.layers = nn.ModuleList([ + nn.Conv2d(in_channels, 64, kernel_size=3, stride=2, padding=1), + nn.LeakyReLU(0.2, inplace=True), + nn.Conv2d(64, 64, kernel_size=3, stride=1, padding=1), + nn.LeakyReLU(0.2, inplace=True), + nn.Conv2d(64, 128, kernel_size=3, stride=2, padding=1), + nn.LeakyReLU(0.2, inplace=True), + nn.Conv2d(128, 256, kernel_size=3, stride=1, padding=1), + nn.LeakyReLU(0.2, inplace=True), + nn.Conv2d(256, 384, kernel_size=3, stride=1, padding=1, groups=1), + nn.LeakyReLU(0.2, inplace=True), + nn.Conv2d(640, 512, kernel_size=3, stride=1, padding=1, groups=2), + nn.LeakyReLU(0.2, inplace=True), + nn.Conv2d(768, 384, kernel_size=3, stride=1, padding=1, groups=4), + nn.LeakyReLU(0.2, inplace=True), + nn.Conv2d(640, 256, kernel_size=3, stride=1, padding=1, groups=8), + nn.LeakyReLU(0.2, inplace=True), + nn.Conv2d(512, 128, kernel_size=3, stride=1, padding=1, groups=1), + nn.LeakyReLU(0.2, inplace=True) + ]) + + def forward(self, x): + bt, c, h, w = x.size() + h, w = h // 4, w // 4 + out = x + for i, layer in enumerate(self.layers): + if i == 8: + x0 = out + if i > 8 and i % 2 == 0: + g = self.group[(i - 8) // 2] + x = x0.view(bt, g, -1, h, w) + o = out.view(bt, g, -1, h, w) + out = torch.cat([x, o], 2).view(bt, -1, h, w) + out = layer(out) + return out + + +class AddPosEmb(nn.Module): + def __init__(self, h, w, in_channels, out_channels): + super(AddPosEmb, self).__init__() + self.proj = nn.Conv2d(in_channels, out_channels, 3, 1, 1, bias=True, groups=out_channels) + self.h, self.w = h, w + + def forward(self, x, h=0, w=0): + B, N, C = x.shape + if h == 0 and w == 0: + assert N == self.h * self.w, 'Wrong input size' + else: + assert N == h * w, 'Wrong input size during inference' + feat_token = x + if h == 0 and w == 0: + cnn_feat = feat_token.transpose(1, 2).view(B, C, self.h, self.w) + else: + cnn_feat = feat_token.transpose(1, 2).view(B, C, h, w) + x = self.proj(cnn_feat) + cnn_feat + x = x.flatten(2).transpose(1, 2) + return x + + +class Vec2Patch(nn.Module): + def __init__(self, channel, hidden, output_size, kernel_size, stride, padding): + super(Vec2Patch, self).__init__() + self.relu = nn.LeakyReLU(0.2, inplace=True) + c_out = reduce((lambda x, y: x * y), kernel_size) * channel + self.embedding = nn.Linear(hidden, c_out) + self.restore = nn.Fold(output_size=output_size, kernel_size=kernel_size, stride=stride, padding=padding) + self.kernel_size = kernel_size + self.stride = stride + self.padding = padding + + def forward(self, x, output_h=0, output_w=0): + feat = self.embedding(x) + feat = feat.permute(0, 2, 1) + if output_h != 0 or output_w != 0: + feat = F.fold(feat, output_size=(output_h, output_w), kernel_size=self.kernel_size, stride=self.stride, + padding=self.padding) + else: + feat = self.restore(feat) + return feat + + +class TemporalTransformer(nn.Module): + def __init__(self, token_size, frame_hidden, num_heads, t_groupSize, mlp_ratio, dropout, n_vecs, + t2t_params): + super(TemporalTransformer, self).__init__() + self.attention = TMHSA(token_size=token_size, group_size=t_groupSize, d_model=frame_hidden, head=num_heads, + p=dropout) + self.ffn = FusionFeedForward(frame_hidden, mlp_ratio, n_vecs, t2t_params, p=dropout) + self.norm1 = nn.LayerNorm(frame_hidden) + self.norm2 = nn.LayerNorm(frame_hidden) + self.dropout = nn.Dropout(p=dropout) + + def forward(self, x, t, h, w, output_size): + token_size = h * w + s = self.norm1(x) + x = x + self.dropout(self.attention(s, t, h, w)) + y = self.norm2(x) + x = x + self.ffn(y, token_size, output_size[0], output_size[1]) + return x + + +class SpatialTransformer(nn.Module): + def __init__(self, token_size, frame_hidden, flow_hidden, num_heads, s_windowSize, g_downSize, mlp_ratio, + dropout, n_vecs, t2t_params): + super(SpatialTransformer, self).__init__() + self.attention = SWMHSA_depthGlobalWindowConcatLN_qkFlow_reweightFlow(token_size=token_size, window_size=s_windowSize, + kernel_size=g_downSize, d_model=frame_hidden, + flow_dModel=flow_hidden, head=num_heads, p=dropout) + self.ffn = FusionFeedForward(frame_hidden, mlp_ratio, n_vecs, t2t_params, p=dropout) + self.norm = nn.LayerNorm(frame_hidden) + self.dropout = nn.Dropout(p=dropout) + + def forward(self, x, f, t, h, w, output_size): + token_size = h * w + x = x + self.dropout(self.attention(x, f, t, h, w)) + y = self.norm(x) + x = x + self.ffn(y, token_size, output_size[0], output_size[1]) + return x + + +class TransformerBlock(nn.Module): + def __init__(self, token_size, frame_hidden, flow_hidden, num_heads, t_groupSize, s_windowSize, g_downSize, + mlp_ratio, + dropout, n_vecs, + t2t_params): + super(TransformerBlock, self).__init__() + self.t_transformer = TemporalTransformer(token_size=token_size, frame_hidden=frame_hidden, num_heads=num_heads, + t_groupSize=t_groupSize, mlp_ratio=mlp_ratio, + dropout=dropout, n_vecs=n_vecs, + t2t_params=t2t_params) # temporal multi-head self attention + self.s_transformer = SpatialTransformer(token_size=token_size, frame_hidden=frame_hidden, + flow_hidden=flow_hidden, num_heads=num_heads, s_windowSize=s_windowSize, + g_downSize=g_downSize, mlp_ratio=mlp_ratio, + dropout=dropout, n_vecs=n_vecs, t2t_params=t2t_params) + + def forward(self, inputs): + x, f, t = inputs['x'], inputs['f'], inputs['t'] + h, w = inputs['h'], inputs['w'] + output_size = inputs['output_size'] + x = self.t_transformer(x, t, h, w, output_size) + x = self.s_transformer(x, f, t, h, w, output_size) + return {'x': x, 'f': f, 't': t, 'h': h, 'w': w, 'output_size': output_size} + + +class Decoder(BaseNetwork): + def __init__(self, conv_type, in_channels, out_channels, use_bias, norm=None): + super(Decoder, self).__init__(conv_type) + self.layer1 = self.DeconvBlock(in_channels, in_channels, kernel_size=3, padding=1, norm=norm, + bias=use_bias) + self.layer2 = self.ConvBlock(in_channels, in_channels // 2, kernel_size=3, stride=1, padding=1, norm=norm, + bias=use_bias) + self.layer3 = self.DeconvBlock(in_channels // 2, in_channels // 2, kernel_size=3, padding=1, norm=norm, + bias=use_bias) + self.final = self.ConvBlock(in_channels // 2, out_channels, kernel_size=3, stride=1, padding=1, norm=norm, + bias=use_bias, activation=None) + + def forward(self, features): + feat1 = self.layer1(features) + feat2 = self.layer2(feat1) + feat3 = self.layer3(feat2) + output = self.final(feat3) + return output + + +class FGT(BaseNetwork): + def __init__(self, t_groupSize, s_windowSize, g_downSize, input_resolution, in_channels, cnum, flow_inChannel, + flow_cnum, + frame_hidden, flow_hidden, passmask, numBlocks, kernel_size, stride, padding, num_heads, conv_type, + norm, use_bias, ape, mlp_ratio=4, drop=0, init_weights=True): + super(FGT, self).__init__(conv_type) + self.in_channels = in_channels + self.passmask = passmask + self.ape = ape + self.frame_endoder = Encoder(in_channels) + self.flow_encoder = nn.Sequential( + nn.ReplicationPad2d(2), + self.ConvBlock(flow_inChannel, flow_cnum, kernel_size=5, stride=1, padding=0, bias=use_bias, norm=norm), + self.ConvBlock(flow_cnum, flow_cnum * 2, kernel_size=3, stride=2, padding=1, bias=use_bias, norm=norm), + self.ConvBlock(flow_cnum * 2, flow_cnum * 2, kernel_size=3, stride=1, padding=1, bias=use_bias, norm=norm), + self.ConvBlock(flow_cnum * 2, flow_cnum * 2, kernel_size=3, stride=2, padding=1, bias=use_bias, norm=norm) + ) + # patch to vector operation + self.patch2vec = nn.Conv2d(cnum * 2, frame_hidden, kernel_size=kernel_size, stride=stride, padding=padding) + self.f_patch2vec = nn.Conv2d(flow_cnum * 2, flow_hidden, kernel_size=kernel_size, stride=stride, + padding=padding) + # initialize transformer blocks for frame completion + n_vecs = 1 + token_size = [] + output_shape = (input_resolution[0] // 4, input_resolution[1] // 4) + for i, d in enumerate(kernel_size): + token_nums = int((output_shape[i] + 2 * padding[i] - kernel_size[i]) / stride[i] + 1) + n_vecs *= token_nums + token_size.append(token_nums) + # Add positional embedding to the encode features + if self.ape: + self.add_pos_emb = AddPosEmb(token_size[0], token_size[1], frame_hidden, frame_hidden) + self.token_size = token_size + # initialize transformer blocks + blocks = [] + t2t_params = {'kernel_size': kernel_size, 'stride': stride, 'padding': padding, 'output_size': output_shape} + for i in range(numBlocks // 2 - 1): + layer = TransformerBlock(token_size, frame_hidden, flow_hidden, num_heads, t_groupSize, s_windowSize, + g_downSize, mlp_ratio, drop, n_vecs, t2t_params) + blocks.append(layer) + self.first_t_transformer = TemporalTransformer(token_size, frame_hidden, num_heads, t_groupSize, mlp_ratio, + drop, n_vecs, t2t_params) + self.first_s_transformer = SpatialTransformer(token_size, frame_hidden, flow_hidden, num_heads, s_windowSize, + g_downSize, mlp_ratio, drop, n_vecs, t2t_params) + self.transformer = nn.Sequential(*blocks) + # vector to patch operation + self.vec2patch = Vec2Patch(cnum * 2, frame_hidden, output_shape, kernel_size, stride, padding) + # decoder + self.decoder = Decoder(conv_type, cnum * 2, 3, use_bias, norm) + + if init_weights: + self.init_weights() + + def forward(self, masked_frames, flows, masks): + b, t, c, h, w = masked_frames.shape + cf = flows.shape[2] + output_shape = (h // 4, w // 4) + if self.passmask: + inputs = torch.cat((masked_frames, masks), dim=2) + else: + inputs = masked_frames + inputs = inputs.view(b * t, self.in_channels, h, w) + flows = flows.view(b * t, cf, h, w) + enc_feats = self.frame_endoder(inputs) + flow_feats = self.flow_encoder(flows) + trans_feat = self.patch2vec(enc_feats) + flow_patches = self.f_patch2vec(flow_feats) + _, c, h, w = trans_feat.shape + cf = flow_patches.shape[1] + if h != self.token_size[0] or w != self.token_size[1]: + new_h, new_w = h, w + else: + new_h, new_w = 0, 0 + output_shape = (0, 0) + trans_feat = trans_feat.view(b * t, c, -1).permute(0, 2, 1) + flow_patches = flow_patches.view(b * t, cf, -1).permute(0, 2, 1) + trans_feat = self.first_t_transformer(trans_feat, t, new_h, new_w, output_shape) + trans_feat = self.add_pos_emb(trans_feat, new_h, new_w) + trans_feat = self.first_s_transformer(trans_feat, flow_patches, t, new_h, new_w, output_shape) + inputs_trans_feat = {'x': trans_feat, 'f': flow_patches, 't': t, 'h': new_h, 'w': new_w, + 'output_size': output_shape} + trans_feat = self.transformer(inputs_trans_feat)['x'] + trans_feat = self.vec2patch(trans_feat, output_shape[0], output_shape[1]) + enc_feats = enc_feats + trans_feat + + output = self.decoder(enc_feats) + output = torch.tanh(output) + return output + diff --git a/FGT_codes/FGT/models/temporal_patch_gan.py b/FGT_codes/FGT/models/temporal_patch_gan.py new file mode 100644 index 0000000000000000000000000000000000000000..726cf27244768857b7472412516fd4a9fb16eba6 --- /dev/null +++ b/FGT_codes/FGT/models/temporal_patch_gan.py @@ -0,0 +1,76 @@ +# temporal patch GAN to maintain the temporal consecutive of the flows +import torch +import torch.nn as nn +from .BaseNetwork import BaseNetwork + + +class Discriminator(BaseNetwork): + def __init__(self, in_channels, conv_type, dist_cnum, use_sigmoid=False, use_spectral_norm=True, init_weights=True): + """ + + Args: + in_channels: The input channels of the discriminator + use_sigmoid: Whether to use sigmoid for the base network (true for the nsgan) + use_spectral_norm: The usage of the spectral norm: always be true for the stability of GAN + init_weights: always be True + """ + super(Discriminator, self).__init__(conv_type) + self.use_sigmoid = use_sigmoid + nf = dist_cnum + + self.conv = nn.Sequential( + spectral_norm( + nn.Conv3d(in_channels=in_channels, out_channels=nf * 1, kernel_size=(3, 5, 5), stride=(1, 2, 2), + padding=(1, 2, 2), + bias=not use_spectral_norm), use_spectral_norm), + nn.LeakyReLU(0.2, inplace=True), + spectral_norm( + nn.Conv3d(in_channels=nf * 1, out_channels=nf * 2, kernel_size=(3, 5, 5), stride=(1, 2, 2), + padding=(1, 2, 2), + bias=not use_spectral_norm), use_spectral_norm), + nn.LeakyReLU(0.2, inplace=True), + spectral_norm( + nn.Conv3d(in_channels=nf * 2, out_channels=nf * 4, kernel_size=(3, 5, 5), stride=(1, 2, 2), + padding=(1, 2, 2), + bias=not use_spectral_norm), use_spectral_norm), + nn.LeakyReLU(0.2, inplace=True), + spectral_norm( + nn.Conv3d(in_channels=nf * 4, out_channels=nf * 4, kernel_size=(3, 5, 5), stride=(1, 2, 2), + padding=(1, 2, 2), + bias=not use_spectral_norm), use_spectral_norm), + nn.LeakyReLU(0.2, inplace=True), + spectral_norm( + nn.Conv3d(in_channels=nf * 4, out_channels=nf * 4, kernel_size=(3, 5, 5), stride=(1, 2, 2), + padding=(1, 2, 2), + bias=not use_spectral_norm), use_spectral_norm), + nn.LeakyReLU(0.2, inplace=True), + nn.Conv3d(in_channels=nf * 4, out_channels=nf * 4, kernel_size=(3, 5, 5), stride=(1, 2, 2), + padding=(1, 2, 2)) + ) + + if init_weights: + self.init_weights() + + def forward(self, xs, t): + """ + + Args: + xs: Input feature, with shape of [bt, c, h, w] + + Returns: The discriminative map from the GAN + + """ + bt, c, h, w = xs.shape + b = bt // t + xs = xs.view(b, t, c, h, w).permute(0, 2, 1, 3, 4).contiguous() + feat = self.conv(xs) + if self.use_sigmoid: + feat = torch.sigmoid(feat) + out = torch.transpose(feat, 1, 2) # [b, t, c, h, w] + return out + + +def spectral_norm(module, mode=True): + if mode: + return nn.utils.spectral_norm(module) + return module diff --git a/FGT_codes/FGT/models/transformer_base/__init__.py b/FGT_codes/FGT/models/transformer_base/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/FGT_codes/FGT/models/transformer_base/__pycache__/__init__.cpython-39.pyc b/FGT_codes/FGT/models/transformer_base/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8ba3e3d13792ee67be09cc47452712d2a164afca Binary files /dev/null and b/FGT_codes/FGT/models/transformer_base/__pycache__/__init__.cpython-39.pyc differ diff --git a/FGT_codes/FGT/models/transformer_base/__pycache__/attention_base.cpython-39.pyc b/FGT_codes/FGT/models/transformer_base/__pycache__/attention_base.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2f80e2a05dec8400175154cd30b67afb5ba778be Binary files /dev/null and b/FGT_codes/FGT/models/transformer_base/__pycache__/attention_base.cpython-39.pyc differ diff --git a/FGT_codes/FGT/models/transformer_base/__pycache__/attention_flow.cpython-39.pyc b/FGT_codes/FGT/models/transformer_base/__pycache__/attention_flow.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cb3c02c9d48fb5fd9ca8514b18b57cc01e28a85c Binary files /dev/null and b/FGT_codes/FGT/models/transformer_base/__pycache__/attention_flow.cpython-39.pyc differ diff --git a/FGT_codes/FGT/models/transformer_base/__pycache__/ffn_base.cpython-39.pyc b/FGT_codes/FGT/models/transformer_base/__pycache__/ffn_base.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..45ddb55c5d2060d040079df8287863b6fcddd8a3 Binary files /dev/null and b/FGT_codes/FGT/models/transformer_base/__pycache__/ffn_base.cpython-39.pyc differ diff --git a/FGT_codes/FGT/models/transformer_base/attention_base.py b/FGT_codes/FGT/models/transformer_base/attention_base.py new file mode 100644 index 0000000000000000000000000000000000000000..9cbd31902e01afb8f259f41bad032fe13568a572 --- /dev/null +++ b/FGT_codes/FGT/models/transformer_base/attention_base.py @@ -0,0 +1,106 @@ +import math +import torch +import torch.nn as nn +import torch.nn.functional as F + + +class Attention(nn.Module): + """ + Compute 'Scaled Dot Product Attention + """ + + def __init__(self, p=0.1): + super(Attention, self).__init__() + self.dropout = nn.Dropout(p=p) + + def forward(self, query, key, value): + scores = torch.matmul(query, key.transpose(-2, -1) + ) / math.sqrt(query.size(-1)) + p_attn = F.softmax(scores, dim=-1) + p_attn = self.dropout(p_attn) + p_val = torch.matmul(p_attn, value) + return p_val, p_attn + + +class TMHSA(nn.Module): + def __init__(self, token_size, group_size, d_model, head, p=0.1): + super(TMHSA, self).__init__() + self.h, self.w = token_size + self.group_size = group_size # 这里的group size表示可分的组 + self.wh, self.ww = math.ceil(self.h / self.group_size), math.ceil(self.w / self.group_size) + self.pad_r = (self.ww - self.w % self.ww) % self.ww + self.pad_b = (self.wh - self.h % self.wh) % self.wh + self.new_h, self.new_w = self.h + self.pad_b, self.w + self.pad_r # 只在右侧和下侧进行padding,另一侧不padding,实现起来更加容易 + self.window_h, self.window_w = self.new_h // self.group_size, self.new_w // self.group_size # 这里面的group表示的是窗口大小,而window_size表示的是group大小(与spatial的定义不同) + self.d_model = d_model + self.p = p + self.query_embedding = nn.Linear(d_model, d_model) + self.key_embedding = nn.Linear(d_model, d_model) + self.value_embedding = nn.Linear(d_model, d_model) + self.output_linear = nn.Linear(d_model, d_model) + self.attention = Attention(p=p) + self.head = head + + def inference(self, x, t, h, w): + # calculate the attention related parameters + wh, ww = math.ceil(h / self.group_size), math.ceil(w / self.group_size) + pad_r = (ww - w % ww) % ww + pad_b = (wh - h % wh) % wh + new_h, new_w = h + pad_b, w + pad_r + window_h, window_w = new_h // self.group_size, new_w // self.group_size + bt, n, c = x.shape + b = bt // t + c_h = c // self.head + x = x.view(bt, h, w, c) + if pad_r > 0 or pad_b > 0: + x = F.pad(x, + (0, 0, 0, pad_r, 0, pad_b)) # channel, channel, left, right, top, bottom -> [bt, new_h, new_w, c] + query = self.query_embedding(x) + key = self.key_embedding(x) + value = self.value_embedding(x) + query = query.view(b, t, self.group_size, window_h, self.group_size, window_w, self.head, c_h) + query = query.permute(0, 2, 4, 6, 1, 3, 5, 7).reshape(b, self.group_size * self.group_size, self.head, -1, c_h) + key = key.view(b, t, self.group_size, window_h, self.group_size, window_w, self.head, c_h) + key = key.permute(0, 2, 4, 6, 1, 3, 5, 7).reshape(b, self.group_size * self.group_size, self.head, -1, c_h) + value = value.view(b, t, self.group_size, window_h, self.group_size, window_w, self.head, c_h) + value = value.permute(0, 2, 4, 6, 1, 3, 5, 7).reshape(b, self.group_size * self.group_size, self.head, -1, c_h) + att, _ = self.attention(query, key, value) + att = att.view(b, self.group_size, self.group_size, self.head, t, window_h, window_w, c_h) + att = att.permute(0, 4, 1, 5, 2, 6, 3, 7).contiguous().view(bt, new_h, new_w, c) + if pad_b > 0 or pad_r > 0: + att = att[:, :h, :w, :] + att = att.reshape(bt, n, c) + output = self.output_linear(att) + return output + + def forward(self, x, t, h=0, w=0): + bt, n, c = x.shape + if h == 0 and w == 0: + assert n == self.h * self.w, 'Wrong input shape: {} with token: h->{}, w->{}'.format(x.shape, self.h, + self.w) + else: + assert n == h * w, 'Wrong input shape: {} with token: h->{}, w->{}'.format(x.shape, h, w) + return self.inference(x, t, h, w) + b = bt // t + c_h = c // self.head + x = x.view(bt, self.h, self.w, c) + if self.pad_r > 0 or self.pad_b > 0: + x = F.pad(x, ( + 0, 0, 0, self.pad_r, 0, self.pad_b)) # channel, channel, left, right, top, bottom -> [bt, new_h, new_w, c] + query = self.query_embedding(x) + key = self.key_embedding(x) + value = self.value_embedding(x) + query = query.view(b, t, self.group_size, self.window_h, self.group_size, self.window_w, self.head, c_h) + query = query.permute(0, 2, 4, 6, 1, 3, 5, 7).reshape(b, self.group_size * self.group_size, self.head, -1, c_h) + key = key.view(b, t, self.group_size, self.window_h, self.group_size, self.window_w, self.head, c_h) + key = key.permute(0, 2, 4, 6, 1, 3, 5, 7).reshape(b, self.group_size * self.group_size, self.head, -1, c_h) + value = value.view(b, t, self.group_size, self.window_h, self.group_size, self.window_w, self.head, c_h) + value = value.permute(0, 2, 4, 6, 1, 3, 5, 7).reshape(b, self.group_size * self.group_size, self.head, -1, c_h) + att, _ = self.attention(query, key, value) + att = att.view(b, self.group_size, self.group_size, self.head, t, self.window_h, self.window_w, c_h) + att = att.permute(0, 4, 1, 5, 2, 6, 3, 7).contiguous().view(bt, self.new_h, self.new_w, c) + if self.pad_b > 0 or self.pad_r > 0: + att = att[:, :self.h, :self.w, :] + att = att.reshape(bt, n, c) + output = self.output_linear(att) + return output diff --git a/FGT_codes/FGT/models/transformer_base/attention_flow.py b/FGT_codes/FGT/models/transformer_base/attention_flow.py new file mode 100644 index 0000000000000000000000000000000000000000..1e443fe92c5d0fc9b41f5090047565b36f3ac21e --- /dev/null +++ b/FGT_codes/FGT/models/transformer_base/attention_flow.py @@ -0,0 +1,171 @@ +import math +import torch +import torch.nn as nn +import torch.nn.functional as F + + +class Attention(nn.Module): + """ + Compute 'Scaled Dot Product Attention + """ + + def __init__(self, p=0.1): + super(Attention, self).__init__() + self.dropout = nn.Dropout(p=p) + + def forward(self, query, key, value): + scores = torch.matmul(query, key.transpose(-2, -1) + ) / math.sqrt(query.size(-1)) + p_attn = F.softmax(scores, dim=-1) + p_attn = self.dropout(p_attn) + p_val = torch.matmul(p_attn, value) + return p_val, p_attn + + +class SWMHSA_depthGlobalWindowConcatLN_qkFlow_reweightFlow(nn.Module): + def __init__(self, token_size, window_size, kernel_size, d_model, flow_dModel, head, p=0.1): + super(SWMHSA_depthGlobalWindowConcatLN_qkFlow_reweightFlow, self).__init__() + self.h, self.w = token_size + self.head = head + self.window_size = window_size + self.d_model = d_model + self.flow_dModel = flow_dModel + in_channels = d_model + flow_dModel + self.query_embedding = nn.Linear(in_channels, d_model) + self.key_embedding = nn.Linear(in_channels, d_model) + self.value_embedding = nn.Linear(d_model, d_model) + self.output_linear = nn.Linear(d_model, d_model) + self.attention = Attention(p) + self.pad_l = self.pad_t = 0 + self.pad_r = (self.window_size - self.w % self.window_size) % self.window_size + self.pad_b = (self.window_size - self.h % self.window_size) % self.window_size + self.new_h, self.new_w = self.h + self.pad_b, self.w + self.pad_r + self.group_h, self.group_w = self.new_h // self.window_size, self.new_w // self.window_size + self.global_extract_v = nn.Conv2d(d_model, d_model, kernel_size=kernel_size, stride=kernel_size, padding=0, + groups=d_model) + self.global_extract_k = nn.Conv2d(in_channels, in_channels, kernel_size=kernel_size, stride=kernel_size, + padding=0, + groups=in_channels) + self.q_norm = nn.LayerNorm(d_model + flow_dModel) + self.k_norm = nn.LayerNorm(d_model + flow_dModel) + self.v_norm = nn.LayerNorm(d_model) + self.reweightFlow = nn.Sequential( + nn.Linear(in_channels, flow_dModel), + nn.Sigmoid() + ) + + def inference(self, x, f, h, w): + pad_r = (self.window_size - w % self.window_size) % self.window_size + pad_b = (self.window_size - h % self.window_size) % self.window_size + new_h, new_w = h + pad_b, w + pad_r + group_h, group_w = new_h // self.window_size, new_w // self.window_size + bt, n, c = x.shape + cf = f.shape[2] + x = x.view(bt, h, w, c) + f = f.view(bt, h, w, cf) + if pad_r > 0 or pad_b > 0: + x = F.pad(x, (0, 0, self.pad_l, pad_r, self.pad_t, pad_b)) + f = F.pad(f, (0, 0, self.pad_l, pad_r, self.pad_t, pad_b)) + y = x.permute(0, 3, 1, 2) + xf = torch.cat((x, f), dim=-1) + flow_weights = self.reweightFlow(xf) + f = f * flow_weights + qk = torch.cat((x, f), dim=-1) # [b, h, w, c] + qk_c = qk.shape[-1] + # generate q + q = qk.reshape(bt, group_h, self.window_size, group_w, self.window_size, qk_c).transpose(2, 3) + q = q.reshape(bt, group_h * group_w, self.window_size * self.window_size, qk_c) + # generate k + ky = qk.permute(0, 3, 1, 2) # [b, c, h, w] + k_global = self.global_extract_k(ky) + k_global = k_global.permute(0, 2, 3, 1).reshape(bt, -1, qk_c).unsqueeze(1).repeat(1, group_h * group_w, 1, 1) + k = torch.cat((q, k_global), dim=2) + # norm q and k + q = self.q_norm(q) + k = self.k_norm(k) + # generate v + global_tokens = self.global_extract_v(y) # [bt, c, h', w'] + global_tokens = global_tokens.permute(0, 2, 3, 1).reshape(bt, -1, c).unsqueeze(1).repeat(1, + group_h * group_w, + 1, + 1) # [bt, gh * gw, h'*w', c] + x = x.reshape(bt, group_h, self.window_size, group_w, self.window_size, c).transpose(2, + 3) # [bt, gh, gw, ws, ws, c] + x = x.reshape(bt, group_h * group_w, self.window_size * self.window_size, c) # [bt, gh * gw, ws^2, c] + v = torch.cat((x, global_tokens), dim=2) + v = self.v_norm(v) + query = self.query_embedding(q) # [bt, self.group_h, self.group_w, self.window_size, self.window_size, c] + key = self.key_embedding(k) + value = self.value_embedding(v) + query = query.reshape(bt, group_h * group_w, self.window_size * self.window_size, self.head, + c // self.head).permute(0, 1, 3, 2, 4) + key = key.reshape(bt, group_h * group_w, -1, self.head, + c // self.head).permute(0, 1, 3, 2, 4) + value = value.reshape(bt, group_h * group_w, -1, self.head, + c // self.head).permute(0, 1, 3, 2, 4) + attn, _ = self.attention(query, key, value) + x = attn.transpose(2, 3).reshape(bt, group_h, group_w, self.window_size, self.window_size, c) + x = x.transpose(2, 3).reshape(bt, group_h * self.window_size, group_w * self.window_size, c) + if pad_r > 0 or pad_b > 0: + x = x[:, :h, :w, :].contiguous() + x = x.reshape(bt, n, c) + output = self.output_linear(x) + return output + + def forward(self, x, f, t, h=0, w=0): + if h != 0 or w != 0: + return self.inference(x, f, h, w) + bt, n, c = x.shape + cf = f.shape[2] + x = x.view(bt, self.h, self.w, c) + f = f.view(bt, self.h, self.w, cf) + if self.pad_r > 0 or self.pad_b > 0: + x = F.pad(x, (0, 0, self.pad_l, self.pad_r, self.pad_t, self.pad_b)) + f = F.pad(f, (0, 0, self.pad_l, self.pad_r, self.pad_t, self.pad_b)) # [bt, cf, h, w] + y = x.permute(0, 3, 1, 2) + xf = torch.cat((x, f), dim=-1) + weights = self.reweightFlow(xf) + f = f * weights + qk = torch.cat((x, f), dim=-1) # [b, h, w, c] + qk_c = qk.shape[-1] + # generate q + q = qk.reshape(bt, self.group_h, self.window_size, self.group_w, self.window_size, qk_c).transpose(2, 3) + q = q.reshape(bt, self.group_h * self.group_w, self.window_size * self.window_size, qk_c) + # generate k + ky = qk.permute(0, 3, 1, 2) # [b, c, h, w] + k_global = self.global_extract_k(ky) # [b, qk_c, h, w] + k_global = k_global.permute(0, 2, 3, 1).reshape(bt, -1, qk_c).unsqueeze(1).repeat(1, + self.group_h * self.group_w, + 1, 1) + k = torch.cat((q, k_global), dim=2) + # norm q and k + q = self.q_norm(q) + k = self.k_norm(k) + # generate v + global_tokens = self.global_extract_v(y) # [bt, c, h', w'] + global_tokens = global_tokens.permute(0, 2, 3, 1).reshape(bt, -1, c).unsqueeze(1).repeat(1, + self.group_h * self.group_w, + 1, + 1) # [bt, gh * gw, h'*w', c] + x = x.reshape(bt, self.group_h, self.window_size, self.group_w, self.window_size, c).transpose(2, + 3) # [bt, gh, gw, ws, ws, c] + x = x.reshape(bt, self.group_h * self.group_w, self.window_size * self.window_size, c) # [bt, gh * gw, ws^2, c] + v = torch.cat((x, global_tokens), dim=2) + v = self.v_norm(v) + query = self.query_embedding(q) # [bt, self.group_h, self.group_w, self.window_size, self.window_size, c] + key = self.key_embedding(k) + value = self.value_embedding(v) + query = query.reshape(bt, self.group_h * self.group_w, self.window_size * self.window_size, self.head, + c // self.head).permute(0, 1, 3, 2, 4) + key = key.reshape(bt, self.group_h * self.group_w, -1, self.head, + c // self.head).permute(0, 1, 3, 2, 4) + value = value.reshape(bt, self.group_h * self.group_w, -1, self.head, + c // self.head).permute(0, 1, 3, 2, 4) + attn, _ = self.attention(query, key, value) + x = attn.transpose(2, 3).reshape(bt, self.group_h, self.group_w, self.window_size, self.window_size, c) + x = x.transpose(2, 3).reshape(bt, self.group_h * self.window_size, self.group_w * self.window_size, c) + if self.pad_r > 0 or self.pad_b > 0: + x = x[:, :self.h, :self.w, :].contiguous() + x = x.reshape(bt, n, c) + output = self.output_linear(x) + return output diff --git a/FGT_codes/FGT/models/transformer_base/ffn_base.py b/FGT_codes/FGT/models/transformer_base/ffn_base.py new file mode 100644 index 0000000000000000000000000000000000000000..de3086620ef4dc52b9576424d6d1b4bb53cef63b --- /dev/null +++ b/FGT_codes/FGT/models/transformer_base/ffn_base.py @@ -0,0 +1,114 @@ +import torch +from functools import reduce +import torch.nn as nn +import torch.nn.functional as F +from functools import partial + + +class FeedForward(nn.Module): + def __init__(self, frame_hidden, mlp_ratio, n_vecs, t2t_params, p): + """ + + Args: + frame_hidden: hidden size of frame features + mlp_ratio: mlp ratio in the middle layer of the transformers + n_vecs: number of vectors in the transformer + t2t_params: dictionary -> {'kernel_size': kernel_size, 'stride': stride, 'padding': padding, 'output_size': output_shape} + p: dropout rate, 0 by default + """ + super(FeedForward, self).__init__() + self.conv = nn.Sequential( + nn.Linear(frame_hidden, frame_hidden * mlp_ratio), + nn.ReLU(inplace=True), + nn.Dropout(p), + nn.Linear(frame_hidden * mlp_ratio, frame_hidden), + nn.Dropout(p) + ) + + def forward(self, x, n_vecs=0, output_h=0, output_w=0): + x = self.conv(x) + return x + + +class FusionFeedForward(nn.Module): + def __init__(self, frame_hidden, mlp_ratio, n_vecs, t2t_params, p): + super(FusionFeedForward, self).__init__() + self.kernel_shape = reduce((lambda x, y: x * y), t2t_params['kernel_size']) + self.t2t_params = t2t_params + hidden_size = self.kernel_shape * mlp_ratio + self.conv1 = nn.Linear(frame_hidden, hidden_size) + self.conv2 = nn.Sequential( + nn.ReLU(inplace=True), + nn.Dropout(p), + nn.Linear(hidden_size, frame_hidden), + nn.Dropout(p) + ) + assert t2t_params is not None and n_vecs is not None + tp = t2t_params.copy() + self.fold = nn.Fold(**tp) + del tp['output_size'] + self.unfold = nn.Unfold(**tp) + self.n_vecs = n_vecs + + def forward(self, x, n_vecs=0, output_h=0, output_w=0): + x = self.conv1(x) + b, n, c = x.size() + if n_vecs != 0: + normalizer = x.new_ones(b, n, self.kernel_shape).view(-1, n_vecs, self.kernel_shape).permute(0, 2, 1) + x = self.unfold(F.fold(x.view(-1, n_vecs, c).permute(0, 2, 1), output_size=(output_h, output_w), + kernel_size=self.t2t_params['kernel_size'], stride=self.t2t_params['stride'], + padding=self.t2t_params['padding']) / F.fold(normalizer, + output_size=(output_h, output_w), + kernel_size=self.t2t_params[ + 'kernel_size'], + stride=self.t2t_params['stride'], + padding=self.t2t_params[ + 'padding'])).permute(0, + 2, + 1).contiguous().view( + b, n, c) + else: + normalizer = x.new_ones(b, n, self.kernel_shape).view(-1, self.n_vecs, self.kernel_shape).permute(0, 2, 1) + x = self.unfold(self.fold(x.view(-1, self.n_vecs, c).permute(0, 2, 1)) / self.fold(normalizer)).permute(0, + 2, + 1).contiguous().view( + b, n, c) + x = self.conv2(x) + return x + + +class ResidualBlock_noBN(nn.Module): + """Residual block w/o BN + ---Conv-ReLU-Conv-+- + |________________| + """ + + def __init__(self, nf=64): + super(ResidualBlock_noBN, self).__init__() + self.conv1 = nn.Conv2d(nf, nf, kernel_size=3, stride=1, padding=1, bias=True) + self.conv2 = nn.Conv2d(nf, nf, kernel_size=3, stride=1, padding=1, bias=True) + self.lrelu = nn.LeakyReLU(negative_slope=0.2, inplace=True) + + def forward(self, x): + """ + + Args: + x: with shape of [b, c, t, h, w] + + Returns: processed features with shape [b, c, t, h, w] + + """ + identity = x + out = self.lrelu(self.conv1(x)) + out = self.conv2(out) + out = identity + out + # Remove ReLU at the end of the residual block + # http://torch.ch/blog/2016/02/04/resnets.html + return out + + +def make_layer(block, n_layers): + layers = [] + for _ in range(n_layers): + layers.append(block()) + return nn.Sequential(*layers) diff --git a/FGT_codes/FGT/models/utils/RAFT/utils/__init__.py b/FGT_codes/FGT/models/utils/RAFT/utils/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/FGT_codes/FGT/models/utils/RAFT/utils/utils.py b/FGT_codes/FGT/models/utils/RAFT/utils/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..5f32d281c1c46353a0a2bf36b0550adb74125c65 --- /dev/null +++ b/FGT_codes/FGT/models/utils/RAFT/utils/utils.py @@ -0,0 +1,82 @@ +import torch +import torch.nn.functional as F +import numpy as np +from scipy import interpolate + + +class InputPadder: + """ Pads images such that dimensions are divisible by 8 """ + def __init__(self, dims, mode='sintel'): + self.ht, self.wd = dims[-2:] + pad_ht = (((self.ht // 8) + 1) * 8 - self.ht) % 8 + pad_wd = (((self.wd // 8) + 1) * 8 - self.wd) % 8 + if mode == 'sintel': + self._pad = [pad_wd//2, pad_wd - pad_wd//2, pad_ht//2, pad_ht - pad_ht//2] + else: + self._pad = [pad_wd//2, pad_wd - pad_wd//2, 0, pad_ht] + + def pad(self, *inputs): + return [F.pad(x, self._pad, mode='replicate') for x in inputs] + + def unpad(self,x): + ht, wd = x.shape[-2:] + c = [self._pad[2], ht-self._pad[3], self._pad[0], wd-self._pad[1]] + return x[..., c[0]:c[1], c[2]:c[3]] + +def forward_interpolate(flow): + flow = flow.detach().cpu().numpy() + dx, dy = flow[0], flow[1] + + ht, wd = dx.shape + x0, y0 = np.meshgrid(np.arange(wd), np.arange(ht)) + + x1 = x0 + dx + y1 = y0 + dy + + x1 = x1.reshape(-1) + y1 = y1.reshape(-1) + dx = dx.reshape(-1) + dy = dy.reshape(-1) + + valid = (x1 > 0) & (x1 < wd) & (y1 > 0) & (y1 < ht) + x1 = x1[valid] + y1 = y1[valid] + dx = dx[valid] + dy = dy[valid] + + flow_x = interpolate.griddata( + (x1, y1), dx, (x0, y0), method='nearest', fill_value=0) + + flow_y = interpolate.griddata( + (x1, y1), dy, (x0, y0), method='nearest', fill_value=0) + + flow = np.stack([flow_x, flow_y], axis=0) + return torch.from_numpy(flow).float() + + +def bilinear_sampler(img, coords, mode='bilinear', mask=False): + """ Wrapper for grid_sample, uses pixel coordinates """ + H, W = img.shape[-2:] + xgrid, ygrid = coords.split([1,1], dim=-1) + xgrid = 2*xgrid/(W-1) - 1 + ygrid = 2*ygrid/(H-1) - 1 + + grid = torch.cat([xgrid, ygrid], dim=-1) + img = F.grid_sample(img, grid, align_corners=True) + + if mask: + mask = (xgrid > -1) & (ygrid > -1) & (xgrid < 1) & (ygrid < 1) + return img, mask.float() + + return img + + +def coords_grid(batch, ht, wd): + coords = torch.meshgrid(torch.arange(ht), torch.arange(wd)) + coords = torch.stack(coords[::-1], dim=0).float() + return coords[None].repeat(batch, 1, 1, 1) + + +def upflow8(flow, mode='bilinear'): + new_size = (8 * flow.shape[2], 8 * flow.shape[3]) + return 8 * F.interpolate(flow, size=new_size, mode=mode, align_corners=True) diff --git a/FGT_codes/FGT/models/utils/__init__.py b/FGT_codes/FGT/models/utils/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/FGT_codes/FGT/models/utils/__pycache__/__init__.cpython-39.pyc b/FGT_codes/FGT/models/utils/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..64e654f4189e04715b91aa293e8eadbac94c6b16 Binary files /dev/null and b/FGT_codes/FGT/models/utils/__pycache__/__init__.cpython-39.pyc differ diff --git a/FGT_codes/FGT/models/utils/__pycache__/network_blocks_2d.cpython-39.pyc b/FGT_codes/FGT/models/utils/__pycache__/network_blocks_2d.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..343ade2852732918f3b7dd2e83002351459e5379 Binary files /dev/null and b/FGT_codes/FGT/models/utils/__pycache__/network_blocks_2d.cpython-39.pyc differ diff --git a/FGT_codes/FGT/models/utils/fbConsistencyCheck.py b/FGT_codes/FGT/models/utils/fbConsistencyCheck.py new file mode 100644 index 0000000000000000000000000000000000000000..7d5b546c6124c8380e13f985199cf079350a8d2d --- /dev/null +++ b/FGT_codes/FGT/models/utils/fbConsistencyCheck.py @@ -0,0 +1,127 @@ +import torch +import numpy as np +from .sobel2 import SobelLayer, SeperateSobelLayer +import torch.nn as nn +import torch.nn.functional as F + + +def image_warp(image, flow): + ''' + image: 上一帧的图片,torch.Size([1, 3, 256, 256]) + flow: 光流, torch.Size([1, 2, 256, 256]) + final_grid: torch.Size([1, 2, 256, 256]) + ''' + b, c, h, w = image.size() + device = image.device + flow = torch.cat([flow[:, 0:1, :, :] / ((w - 1.0) / 2.0), flow[:, 1:2, :, :] / ((h - 1.0) / 2.0)], + dim=1) # normalize to [-1~1](from upper left to lower right + flow = flow.permute(0, 2, 3, + 1) # if you wanna use grid_sample function, the channel(band) shape of show must be in the last dimension + x = np.linspace(-1, 1, w) + y = np.linspace(-1, 1, h) + X, Y = np.meshgrid(x, y) + grid = torch.cat((torch.from_numpy(X.astype('float32')).unsqueeze(0).unsqueeze(3), + torch.from_numpy(Y.astype('float32')).unsqueeze(0).unsqueeze(3)), 3).to(device) + output = torch.nn.functional.grid_sample(image, grid + flow, mode='bilinear', padding_mode='zeros') + return output + + +def length_sq(x): + return torch.sum(torch.square(x), dim=1, keepdim=True) + + +def fbConsistencyCheck(flow_fw, flow_bw, alpha1=0.01, alpha2=0.5): + flow_bw_warped = image_warp(flow_bw, flow_fw) # wb(wf(x)) + flow_fw_warped = image_warp(flow_fw, flow_bw) # wf(wb(x)) + flow_diff_fw = flow_fw + flow_bw_warped # wf + wb(wf(x)) + flow_diff_bw = flow_bw + flow_fw_warped # wb + wf(wb(x)) + + mag_sq_fw = length_sq(flow_fw) + length_sq(flow_bw_warped) # |wf| + |wb(wf(x))| + mag_sq_bw = length_sq(flow_bw) + length_sq(flow_fw_warped) # |wb| + |wf(wb(x))| + occ_thresh_fw = alpha1 * mag_sq_fw + alpha2 + occ_thresh_bw = alpha1 * mag_sq_bw + alpha2 + + fb_occ_fw = (length_sq(flow_diff_fw) > occ_thresh_fw).float() + fb_occ_bw = (length_sq(flow_diff_bw) > occ_thresh_bw).float() + + return fb_occ_fw, fb_occ_bw # fb_occ_fw -> frame2 area occluded by frame1, fb_occ_bw -> frame1 area occluded by frame2 + + +def rgb2gray(image): + gray_image = image[:, 0] * 0.299 + image[:, 1] * 0.587 + 0.110 * image[:, 2] + gray_image = gray_image.unsqueeze(1) + return gray_image + + +def ternary_transform(image, max_distance=1): + device = image.device + patch_size = 2 * max_distance + 1 + intensities = rgb2gray(image) * 255 + out_channels = patch_size * patch_size + w = np.eye(out_channels).reshape(out_channels, 1, patch_size, patch_size) + weights = torch.from_numpy(w).float().to(device) + patches = F.conv2d(intensities, weights, stride=1, padding=1) + transf = patches - intensities + transf_norm = transf / torch.sqrt(0.81 + torch.square(transf)) + return transf_norm + + +def hamming_distance(t1, t2): + dist = torch.square(t1 - t2) + dist_norm = dist / (0.1 + dist) + dist_sum = torch.sum(dist_norm, dim=1, keepdim=True) + return dist_sum + + +def create_mask(mask, paddings): + """ + padding: [[top, bottom], [left, right]] + """ + shape = mask.shape + inner_height = shape[2] - (paddings[0][0] + paddings[0][1]) + inner_width = shape[3] - (paddings[1][0] + paddings[1][1]) + inner = torch.ones([inner_height, inner_width]) + + mask2d = F.pad(inner, pad=[paddings[1][0], paddings[1][1], paddings[0][0], paddings[0][1]]) # mask最外边一圈都pad成0了 + mask3d = mask2d.unsqueeze(0) + mask4d = mask3d.unsqueeze(0).repeat(shape[0], 1, 1, 1) + return mask4d.detach() + + +def ternary_loss2(frame1, warp_frame21, confMask, masks, max_distance=1): + """ + + Args: + frame1: torch tensor, with shape [b * t, c, h, w] + warp_frame21: torch tensor, with shape [b * t, c, h, w] + confMask: confidence mask, with shape [b * t, c, h, w] + masks: torch tensor, with shape [b * t, c, h, w] + max_distance: maximum distance. + + Returns: ternary loss + + """ + t1 = ternary_transform(frame1) + t21 = ternary_transform(warp_frame21) + dist = hamming_distance(t1, t21) # 近似求解,其实利用了mask区域和外界边缘交叉的那一部分像素 + loss = torch.mean(dist * confMask * masks) / torch.mean(masks) + return loss + + +def gradient_loss(frame1, frame2, confMask): + device = frame1.device + frame1_edge = SobelLayer(device)(frame1) + frame2_edge = SobelLayer(device)(frame2) + loss = torch.sum(torch.abs(frame1_edge * confMask - frame2_edge * confMask)) / (torch.sum(confMask) + 1) # escape divide 0 + return loss + + +def seperate_gradient_loss(frame1, warp_frame21, confMask): + device = frame1.device + mask_x = create_mask(frame1, [[0, 0], [1, 1]]).to(device) + mask_y = create_mask(frame1, [[1, 1], [0, 0]]).to(device) + gradient_mask = torch.cat([mask_x, mask_y], dim=1).repeat(1, 3, 1, 1) + frame1_edge = SeperateSobelLayer(device)(frame1) + warp_frame21_edge = SeperateSobelLayer(device)(warp_frame21) + loss = nn.L1Loss()(frame1_edge * confMask * gradient_mask, warp_frame21_edge * confMask * gradient_mask) + return loss diff --git a/FGT_codes/FGT/models/utils/flow_losses.py b/FGT_codes/FGT/models/utils/flow_losses.py new file mode 100644 index 0000000000000000000000000000000000000000..d1a266bdd6d85fcd0aeb6574ee62bda6b6a242b5 --- /dev/null +++ b/FGT_codes/FGT/models/utils/flow_losses.py @@ -0,0 +1,517 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +import torchvision.models as models +import numpy as np +from .fbConsistencyCheck import image_warp + + +class FlowWarpingLoss(nn.Module): + def __init__(self, metric): + super(FlowWarpingLoss, self).__init__() + self.metric = metric + + def warp(self, x, flow): + """ + + Args: + x: torch tensor with shape [b, c, h, w], the x can be 3 (for rgb frame) or 2 (for optical flow) + flow: torch tensor with shape [b, 2, h, w] + + Returns: the warped x (can be an image or an optical flow) + + """ + h, w = x.shape[2:] + device = x.device + # normalize the flow to [-1~1] + flow = torch.cat([flow[:, 0:1, :, :] / ((w - 1) / 2), flow[:, 1:2, :, :] / ((h - 1) / 2)], dim=1) + flow = flow.permute(0, 2, 3, 1) # change to [b, h, w, c] + # generate meshgrid + x_idx = np.linspace(-1, 1, w) + y_idx = np.linspace(-1, 1, h) + X_idx, Y_idx = np.meshgrid(x_idx, y_idx) + grid = torch.cat((torch.from_numpy(X_idx.astype('float32')).unsqueeze(0).unsqueeze(3), + torch.from_numpy(Y_idx.astype('float32')).unsqueeze(0).unsqueeze(3)), 3).to(device) + output = torch.nn.functional.grid_sample(x, grid + flow, mode='bilinear', padding_mode='zeros') + return output + + def __call__(self, x, y, flow, mask): + """ + image/flow warping, only support the single image/flow warping + Args: + x: Can be optical flow or image with shape [b, c, h, w], c can be 2 or 3 + y: The ground truth of x (can be the extracted optical flow or image) + flow: The flow used to warp x, whose shape is [b, 2, h, w] + mask: The mask which indicates the hole of x, which must be [b, 1, h, w] + + Returns: the warped image/optical flow + + """ + warped_x = self.warp(x, flow) + loss = self.metric(warped_x * mask, y * mask) + return loss + + +class TVLoss(): + # shift one pixel to get difference ( for both x and y direction) + def __init__(self): + super(TVLoss, self).__init__() + + def __call__(self, x): + loss = torch.mean(torch.abs(x[:, :, :, :-1] - x[:, :, :, 1:])) + torch.mean( + torch.abs(x[:, :, :-1, :] - x[:, :, 1:, :])) + return loss + + +class WarpLoss(nn.Module): + def __init__(self): + super(WarpLoss, self).__init__() + self.metric = nn.L1Loss() + + def forward(self, flow, mask, img1, img2): + """ + + Args: + flow: flow indicates the motion from img1 to img2 + mask: mask corresponds to img1 + img1: frame 1 + img2: frame t+1 + + Returns: warp loss from img2 to img1 + + """ + img2_warped = image_warp(img2, flow) + loss = self.metric(img2_warped * mask, img1 * mask) + return loss + + +class AdversarialLoss(nn.Module): + r""" + Adversarial loss + https://arxiv.org/abs/1711.10337 + """ + + def __init__(self, type='nsgan', target_real_label=1.0, target_fake_label=0.0): + r""" + type = nsgan | lsgan | hinge + """ + super(AdversarialLoss, self).__init__() + + self.type = type + self.register_buffer('real_label', torch.tensor(target_real_label)) + self.register_buffer('fake_label', torch.tensor(target_fake_label)) + + if type == 'nsgan': + self.criterion = nn.BCELoss() + + elif type == 'lsgan': + self.criterion = nn.MSELoss() + + elif type == 'hinge': + self.criterion = nn.ReLU() + + def __call__(self, outputs, is_real, is_disc=None): + if self.type == 'hinge': + if is_disc: + if is_real: + outputs = -outputs + return self.criterion(1 + outputs).mean() + else: + return (-outputs).mean() + + else: + labels = (self.real_label if is_real else self.fake_label).expand_as(outputs) + loss = self.criterion(outputs, labels) + return loss + + +class StyleLoss(nn.Module): + r""" + Perceptual loss, VGG-based + https://arxiv.org/abs/1603.08155 + https://github.com/dxyang/StyleTransfer/blob/master/utils.py + """ + + def __init__(self): + super(StyleLoss, self).__init__() + self.add_module('vgg', VGG19()) + self.criterion = torch.nn.L1Loss() + + def compute_gram(self, x): + b, ch, h, w = x.size() + f = x.view(b, ch, w * h) + f_T = f.transpose(1, 2) + G = f.bmm(f_T) / (h * w * ch) + + return G + + def __call__(self, x, y): + # Compute features + x_vgg, y_vgg = self.vgg(x), self.vgg(y) + + # Compute loss + style_loss = 0.0 + style_loss += self.criterion(self.compute_gram(x_vgg['relu2_2']), self.compute_gram(y_vgg['relu2_2'])) + style_loss += self.criterion(self.compute_gram(x_vgg['relu3_4']), self.compute_gram(y_vgg['relu3_4'])) + style_loss += self.criterion(self.compute_gram(x_vgg['relu4_4']), self.compute_gram(y_vgg['relu4_4'])) + style_loss += self.criterion(self.compute_gram(x_vgg['relu5_2']), self.compute_gram(y_vgg['relu5_2'])) + + return style_loss + + +class PerceptualLoss(nn.Module): + r""" + Perceptual loss, VGG-based + https://arxiv.org/abs/1603.08155 + https://github.com/dxyang/StyleTransfer/blob/master/utils.py + """ + + def __init__(self, weights=[1.0, 1.0, 1.0, 1.0, 1.0]): + super(PerceptualLoss, self).__init__() + self.add_module('vgg', VGG19()) + self.criterion = torch.nn.L1Loss() + self.weights = weights + + def __call__(self, x, y): + # Compute features + x_vgg, y_vgg = self.vgg(x), self.vgg(y) + + content_loss = 0.0 + content_loss += self.weights[0] * self.criterion(x_vgg['relu1_1'], y_vgg['relu1_1']) + content_loss += self.weights[1] * self.criterion(x_vgg['relu2_1'], y_vgg['relu2_1']) + content_loss += self.weights[2] * self.criterion(x_vgg['relu3_1'], y_vgg['relu3_1']) + content_loss += self.weights[3] * self.criterion(x_vgg['relu4_1'], y_vgg['relu4_1']) + content_loss += self.weights[4] * self.criterion(x_vgg['relu5_1'], y_vgg['relu5_1']) + + return content_loss + + +class VGG19(torch.nn.Module): + def __init__(self): + super(VGG19, self).__init__() + features = models.vgg19(pretrained=True).features + self.relu1_1 = torch.nn.Sequential() + self.relu1_2 = torch.nn.Sequential() + + self.relu2_1 = torch.nn.Sequential() + self.relu2_2 = torch.nn.Sequential() + + self.relu3_1 = torch.nn.Sequential() + self.relu3_2 = torch.nn.Sequential() + self.relu3_3 = torch.nn.Sequential() + self.relu3_4 = torch.nn.Sequential() + + self.relu4_1 = torch.nn.Sequential() + self.relu4_2 = torch.nn.Sequential() + self.relu4_3 = torch.nn.Sequential() + self.relu4_4 = torch.nn.Sequential() + + self.relu5_1 = torch.nn.Sequential() + self.relu5_2 = torch.nn.Sequential() + self.relu5_3 = torch.nn.Sequential() + self.relu5_4 = torch.nn.Sequential() + + for x in range(2): + self.relu1_1.add_module(str(x), features[x]) + + for x in range(2, 4): + self.relu1_2.add_module(str(x), features[x]) + + for x in range(4, 7): + self.relu2_1.add_module(str(x), features[x]) + + for x in range(7, 9): + self.relu2_2.add_module(str(x), features[x]) + + for x in range(9, 12): + self.relu3_1.add_module(str(x), features[x]) + + for x in range(12, 14): + self.relu3_2.add_module(str(x), features[x]) + + for x in range(14, 16): + self.relu3_3.add_module(str(x), features[x]) + + for x in range(16, 18): + self.relu3_4.add_module(str(x), features[x]) + + for x in range(18, 21): + self.relu4_1.add_module(str(x), features[x]) + + for x in range(21, 23): + self.relu4_2.add_module(str(x), features[x]) + + for x in range(23, 25): + self.relu4_3.add_module(str(x), features[x]) + + for x in range(25, 27): + self.relu4_4.add_module(str(x), features[x]) + + for x in range(27, 30): + self.relu5_1.add_module(str(x), features[x]) + + for x in range(30, 32): + self.relu5_2.add_module(str(x), features[x]) + + for x in range(32, 34): + self.relu5_3.add_module(str(x), features[x]) + + for x in range(34, 36): + self.relu5_4.add_module(str(x), features[x]) + + # don't need the gradients, just want the features + for param in self.parameters(): + param.requires_grad = False + + def forward(self, x): + relu1_1 = self.relu1_1(x) + relu1_2 = self.relu1_2(relu1_1) + + relu2_1 = self.relu2_1(relu1_2) + relu2_2 = self.relu2_2(relu2_1) + + relu3_1 = self.relu3_1(relu2_2) + relu3_2 = self.relu3_2(relu3_1) + relu3_3 = self.relu3_3(relu3_2) + relu3_4 = self.relu3_4(relu3_3) + + relu4_1 = self.relu4_1(relu3_4) + relu4_2 = self.relu4_2(relu4_1) + relu4_3 = self.relu4_3(relu4_2) + relu4_4 = self.relu4_4(relu4_3) + + relu5_1 = self.relu5_1(relu4_4) + relu5_2 = self.relu5_2(relu5_1) + relu5_3 = self.relu5_3(relu5_2) + relu5_4 = self.relu5_4(relu5_3) + + out = { + 'relu1_1': relu1_1, + 'relu1_2': relu1_2, + + 'relu2_1': relu2_1, + 'relu2_2': relu2_2, + + 'relu3_1': relu3_1, + 'relu3_2': relu3_2, + 'relu3_3': relu3_3, + 'relu3_4': relu3_4, + + 'relu4_1': relu4_1, + 'relu4_2': relu4_2, + 'relu4_3': relu4_3, + 'relu4_4': relu4_4, + + 'relu5_1': relu5_1, + 'relu5_2': relu5_2, + 'relu5_3': relu5_3, + 'relu5_4': relu5_4, + } + return out + + +# Some losses related to optical flows +# From Unflow: https://github.com/simonmeister/UnFlow +def fbLoss(forward_flow, backward_flow, forward_gt_flow, backward_gt_flow, fb_loss_weight, image_warp_loss_weight=0, + occ_weight=0, beta=255, first_image=None, second_image=None): + """ + calculate the forward-backward consistency loss and the related image warp loss + Args: + forward_flow: torch tensor, with shape [b, c, h, w] + backward_flow: torch tensor, with shape [b, c, h, w] + forward_gt_flow: the ground truth of the forward flow (used for occlusion calculation) + backward_gt_flow: the ground truth of the backward flow (used for occlusion calculation) + fb_loss_weight: loss weight for forward-backward consistency check between two frames + image_warp_loss_weight: loss weight for image warping + occ_weight: loss weight for occlusion area (serve as a punishment for image warp loss) + beta: 255 by default, according to the original loss codes in unflow + first_image: the previous image (extraction for the optical flows) + second_image: the later image (extraction for the optical flows) + Note: forward and backward flow should be extracted from the same image pair + Returns: forward backward consistency loss between forward and backward flow + + """ + mask_fw = create_outgoing_mask(forward_flow).float() + mask_bw = create_outgoing_mask(backward_flow).float() + + # forward warp backward flow and backward forward flow to calculate the cycle consistency + forward_flow_warped = image_warp(forward_flow, backward_gt_flow) + forward_flow_warped_gt = image_warp(forward_gt_flow, backward_gt_flow) + backward_flow_warped = image_warp(backward_flow, forward_gt_flow) + backward_flow_warped_gt = image_warp(backward_gt_flow, forward_gt_flow) + flow_diff_fw = backward_flow_warped + forward_flow + flow_diff_fw_gt = backward_flow_warped_gt + forward_gt_flow + flow_diff_bw = backward_flow + forward_flow_warped + flow_diff_bw_gt = backward_gt_flow + forward_flow_warped_gt + + # occlusion calculation + mag_sq_fw = length_sq(forward_gt_flow) + length_sq(backward_flow_warped_gt) + mag_sq_bw = length_sq(backward_gt_flow) + length_sq(forward_flow_warped_gt) + occ_thresh_fw = 0.01 * mag_sq_fw + 0.5 + occ_thresh_bw = 0.01 * mag_sq_bw + 0.5 + + fb_occ_fw = (length_sq(flow_diff_fw_gt) > occ_thresh_fw).float() + fb_occ_bw = (length_sq(flow_diff_bw_gt) > occ_thresh_bw).float() + + mask_fw *= (1 - fb_occ_fw) + mask_bw *= (1 - fb_occ_bw) + + occ_fw = 1 - mask_fw + occ_bw = 1 - mask_bw + + if image_warp_loss_weight != 0: + # warp images + second_image_warped = image_warp(second_image, forward_flow) # frame 2 -> 1 + first_image_warped = image_warp(first_image, backward_flow) # frame 1 -> 2 + im_diff_fw = first_image - second_image_warped + im_diff_bw = second_image - first_image_warped + # calculate the image warp loss based on the occlusion regions calculated by forward and backward flows (gt) + occ_loss = occ_weight * (charbonnier_loss(occ_fw) + charbonnier_loss(occ_bw)) + image_warp_loss = image_warp_loss_weight * ( + charbonnier_loss(im_diff_fw, mask_fw, beta=beta) + charbonnier_loss(im_diff_bw, mask_bw, + beta=beta)) + occ_loss + else: + image_warp_loss = 0 + fb_loss = fb_loss_weight * (charbonnier_loss(flow_diff_fw, mask_fw) + charbonnier_loss(flow_diff_bw, mask_bw)) + return fb_loss + image_warp_loss + + +def length_sq(x): + return torch.sum(torch.square(x), 1, keepdim=True) + + +def smoothness_loss(flow, cmask): + delta_u, delta_v, mask = smoothness_deltas(flow) + loss_u = charbonnier_loss(delta_u, cmask) + loss_v = charbonnier_loss(delta_v, cmask) + return loss_u + loss_v + + +def smoothness_deltas(flow): + """ + flow: [b, c, h, w] + """ + mask_x = create_mask(flow, [[0, 0], [0, 1]]) + mask_y = create_mask(flow, [[0, 1], [0, 0]]) + mask = torch.cat((mask_x, mask_y), dim=1) + mask = mask.to(flow.device) + filter_x = torch.tensor([[0, 0, 0.], [0, 1, -1], [0, 0, 0]]) + filter_y = torch.tensor([[0, 0, 0.], [0, 1, 0], [0, -1, 0]]) + weights = torch.ones([2, 1, 3, 3]) + weights[0, 0] = filter_x + weights[1, 0] = filter_y + weights = weights.to(flow.device) + + flow_u, flow_v = torch.split(flow, split_size_or_sections=1, dim=1) + delta_u = F.conv2d(flow_u, weights, stride=1, padding=1) + delta_v = F.conv2d(flow_v, weights, stride=1, padding=1) + return delta_u, delta_v, mask + + +def second_order_loss(flow, cmask): + delta_u, delta_v, mask = second_order_deltas(flow) + loss_u = charbonnier_loss(delta_u, cmask) + loss_v = charbonnier_loss(delta_v, cmask) + return loss_u + loss_v + + +def charbonnier_loss(x, mask=None, truncate=None, alpha=0.45, beta=1.0, epsilon=0.001): + """ + Compute the generalized charbonnier loss of the difference tensor x + All positions where mask == 0 are not taken into account + x: a tensor of shape [b, c, h, w] + mask: a mask of shape [b, mc, h, w], where mask channels must be either 1 or the same as + the number of channels of x. Entries should be 0 or 1 + return: loss + """ + b, c, h, w = x.shape + norm = b * c * h * w + error = torch.pow(torch.square(x * beta) + torch.square(torch.tensor(epsilon)), alpha) + if mask is not None: + error = mask * error + if truncate is not None: + error = torch.min(error, truncate) + return torch.sum(error) / norm + + +def second_order_deltas(flow): + """ + consider the single flow first + flow shape: [b, c, h, w] + """ + # create mask + mask_x = create_mask(flow, [[0, 0], [1, 1]]) + mask_y = create_mask(flow, [[1, 1], [0, 0]]) + mask_diag = create_mask(flow, [[1, 1], [1, 1]]) + mask = torch.cat((mask_x, mask_y, mask_diag, mask_diag), dim=1) + mask = mask.to(flow.device) + + filter_x = torch.tensor([[0, 0, 0.], [1, -2, 1], [0, 0, 0]]) + filter_y = torch.tensor([[0, 1, 0.], [0, -2, 0], [0, 1, 0]]) + filter_diag1 = torch.tensor([[1, 0, 0.], [0, -2, 0], [0, 0, 1]]) + filter_diag2 = torch.tensor([[0, 0, 1.], [0, -2, 0], [1, 0, 0]]) + weights = torch.ones([4, 1, 3, 3]) + weights[0] = filter_x + weights[1] = filter_y + weights[2] = filter_diag1 + weights[3] = filter_diag2 + weights = weights.to(flow.device) + + # split the flow into flow_u and flow_v, conv them with the weights + flow_u, flow_v = torch.split(flow, split_size_or_sections=1, dim=1) + delta_u = F.conv2d(flow_u, weights, stride=1, padding=1) + delta_v = F.conv2d(flow_v, weights, stride=1, padding=1) + return delta_u, delta_v, mask + + +def create_mask(tensor, paddings): + """ + tensor shape: [b, c, h, w] + paddings: [2 x 2] shape list, the first row indicates up and down paddings + the second row indicates left and right paddings + | | + | x | + | x * x | + | x | + | | + """ + shape = tensor.shape + inner_height = shape[2] - (paddings[0][0] + paddings[0][1]) + inner_width = shape[3] - (paddings[1][0] + paddings[1][1]) + inner = torch.ones([inner_height, inner_width]) + torch_paddings = [paddings[1][0], paddings[1][1], paddings[0][0], paddings[0][1]] # left, right, up and down + mask2d = F.pad(inner, pad=torch_paddings) + mask3d = mask2d.unsqueeze(0).repeat(shape[0], 1, 1) + mask4d = mask3d.unsqueeze(1) + return mask4d.detach() + + +def create_outgoing_mask(flow): + """ + Computes a mask that is zero at all positions where the flow would carry a pixel over the image boundary + For such pixels, it's invalid to calculate the flow losses + Args: + flow: torch tensor: with shape [b, 2, h, w] + + Returns: a mask, 1 indicates in-boundary pixels, with shape [b, 1, h, w] + + """ + b, c, h, w = flow.shape + + grid_x = torch.reshape(torch.arange(0, w), [1, 1, w]) + grid_x = grid_x.repeat(b, h, 1).float() + grid_y = torch.reshape(torch.arange(0, h), [1, h, 1]) + grid_y = grid_y.repeat(b, 1, w).float() + + grid_x = grid_x.to(flow.device) + grid_y = grid_y.to(flow.device) + + flow_u, flow_v = torch.split(flow, split_size_or_sections=1, dim=1) # [b, h, w] + pos_x = grid_x + flow_u + pos_y = grid_y + flow_v + inside_x = torch.logical_and(pos_x <= w - 1, pos_x >= 0) + inside_y = torch.logical_and(pos_y <= h - 1, pos_y >= 0) + inside = torch.logical_and(inside_x, inside_y) + if len(inside.shape) == 3: + inside = inside.unsqueeze(1) + return inside diff --git a/FGT_codes/FGT/models/utils/loss.py b/FGT_codes/FGT/models/utils/loss.py new file mode 100644 index 0000000000000000000000000000000000000000..fd2586d7cfd5e1dbc07dc9c0136f5499cb0dc7f0 --- /dev/null +++ b/FGT_codes/FGT/models/utils/loss.py @@ -0,0 +1,474 @@ +import os +import sys + +import torch +import torch.nn as nn +import numpy as np + + +class AlignLoss(nn.Module): + def __init__(self, reduction='mean'): + super().__init__() + self.loss_fn = nn.L1Loss(reduction=reduction) + + def forward(self, frames, masks, aligned_vs, aligned_rs): + """ + + :param frames: The original frames(GT) + :param masks: Original masks + :param aligned_vs: aligned visibility map from reference frame(List: B, C, T, H, W) + :param aligned_rs: aligned reference frames(List: B, C, T, H, W) + :return: + """ + try: + B, C, T, H, W = frames.shape + except ValueError: + frames = frames.unsqueeze(2) + masks = masks.unsqueeze(2) + B, C, T, H, W = frames.shape + loss = 0 + for i in range(T): + frame = frames[:, :, i] + mask = masks[:, :, i] + aligned_v = aligned_vs[i] + aligned_r = aligned_rs[i] + loss += self._singleFrameAlignLoss(frame, mask, aligned_v, aligned_r) + return loss + + def _singleFrameAlignLoss(self, targetFrame, targetMask, aligned_v, aligned_r): + """ + + :param targetFrame: targetFrame to be aligned-> B, C, H, W + :param targetMask: the mask of target frames + :param aligned_v: aligned visibility map from reference frame + :param aligned_r: aligned reference frame-> B, C, T, H, W + :return: + """ + targetVisibility = 1. - targetMask + targetVisibility = targetVisibility.unsqueeze(2) + targetFrame = targetFrame.unsqueeze(2) + visibility_map = targetVisibility * aligned_v + target_visibility = visibility_map * targetFrame + reference_visibility = visibility_map * aligned_r + loss = 0 + for i in range(aligned_r.shape[2]): + loss += self.loss_fn(target_visibility[:, :, i], reference_visibility[:, :, i]) + return loss + + +class HoleVisibleLoss(nn.Module): + def __init__(self, reduction='mean'): + super().__init__() + self.loss_fn = nn.L1Loss(reduction=reduction) + + def forward(self, outputs, masks, GTs, c_masks): + try: + B, C, T, H, W = outputs.shape + except ValueError: + outputs = outputs.unsqueeze(2) + masks = masks.unsqueeze(2) + GTs = GTs.unsqueeze(2) + c_masks = c_masks.unsqueeze(2) + B, C, T, H, W = outputs.shape + loss = 0 + for i in range(T): + loss += self._singleFrameHoleVisibleLoss(outputs[:, :, i], masks[:, :, i], c_masks[:, :, i], GTs[:, :, i]) + return loss + + def _singleFrameHoleVisibleLoss(self, targetFrame, targetMask, c_mask, GT): + return self.loss_fn(targetMask * c_mask * targetFrame, targetMask * c_mask * GT) + + +class HoleInvisibleLoss(nn.Module): + def __init__(self, reduction='mean'): + super().__init__() + self.loss_fn = nn.L1Loss(reduction=reduction) + + def forward(self, outputs, masks, GTs, c_masks): + try: + B, C, T, H, W = outputs.shape + except ValueError: + outputs = outputs.unsqueeze(2) + masks = masks.unsqueeze(2) + GTs = GTs.unsqueeze(2) + c_masks = c_masks.unsqueeze(2) + B, C, T, H, W = outputs.shape + loss = 0 + for i in range(T): + loss += self._singleFrameHoleInvisibleLoss(outputs[:, :, i], masks[:, :, i], c_masks[:, :, i], GTs[:, :, i]) + return loss + + def _singleFrameHoleInvisibleLoss(self, targetFrame, targetMask, c_mask, GT): + return self.loss_fn(targetMask * (1. - c_mask) * targetFrame, targetMask * (1. - c_mask) * GT) + + +class NonHoleLoss(nn.Module): + def __init__(self, reduction='mean'): + super().__init__() + self.loss_fn = nn.L1Loss(reduction=reduction) + + def forward(self, outputs, masks, GTs): + try: + B, C, T, H, W = outputs.shape + except ValueError: + outputs = outputs.unsqueeze(2) + masks = masks.unsqueeze(2) + GTs = GTs.unsqueeze(2) + B, C, T, H, W = outputs.shape + loss = 0 + for i in range(T): + loss += self._singleNonHoleLoss(outputs[:, :, i], masks[:, :, i], GTs[:, :, i]) + return loss + + def _singleNonHoleLoss(self, targetFrame, targetMask, GT): + return self.loss_fn((1. - targetMask) * targetFrame, (1. - targetMask) * GT) + + +class ReconLoss(nn.Module): + def __init__(self, reduction='mean', masked=False): + super().__init__() + self.loss_fn = nn.L1Loss(reduction=reduction) + self.masked = masked + + def forward(self, model_output, target, mask): + outputs = model_output + targets = target + if self.masked: + masks = mask + return self.loss_fn(outputs * masks, targets * masks) # L1 loss in masked region + else: + return self.loss_fn(outputs, targets) # L1 loss in the whole region + + +class VGGLoss(nn.Module): + def __init__(self, vgg): + super().__init__() + self.l1_loss = nn.L1Loss() + self.vgg = vgg + + def vgg_loss(self, output, target): + output_feature = self.vgg(output) + target_feature = self.vgg(target) + loss = ( + self.l1_loss(output_feature.relu2_2, target_feature.relu2_2) + + self.l1_loss(output_feature.relu3_3, target_feature.relu3_3) + + self.l1_loss(output_feature.relu4_3, target_feature.relu4_3) + ) + return loss + + def forward(self, data_input, model_output): + targets = data_input + outputs = model_output + mean_image_loss = self.vgg_loss(outputs, targets) + return mean_image_loss + + +class StyleLoss(nn.Module): + def __init__(self, vgg, original_channel_norm=True): + super().__init__() + self.l1_loss = nn.L1Loss() + self.vgg = vgg + self.original_channel_norm = original_channel_norm + + # From https://github.com/pytorch/tutorials/blob/master/advanced_source/neural_style_tutorial.py + def gram_matrix(self, input): + a, b, c, d = input.size() # a=batch size(=1) + # b=number of feature maps + # (c,d)=dimensions of a f. map (N=c*d) + + features = input.view(a * b, c * d) # resise F_XL into \hat F_XL + + G = torch.mm(features, features.t()) # compute the gram product + + # we 'normalize' the values of the gram matrix + # by dividing by the number of element in each feature maps. + return G.div(a * b * c * d) + + # Implement "Image Inpainting for Irregular Holes Using Partial Convolutions", Liu et al., 2018 + def style_loss(self, output, target): + output_features = self.vgg(output) + target_features = self.vgg(target) + layers = ['relu2_2', 'relu3_3', 'relu4_3'] # n_channel: 128 (=2 ** 7), 256 (=2 ** 8), 512 (=2 ** 9) + loss = 0 + for i, layer in enumerate(layers): + output_feature = getattr(output_features, layer) + target_feature = getattr(target_features, layer) + B, C_P, H, W = output_feature.shape + output_gram_matrix = self.gram_matrix(output_feature) + target_gram_matrix = self.gram_matrix(target_feature) + if self.original_channel_norm: + C_P_square_divider = 2 ** (i + 1) # original design (avoid too small loss) + else: + C_P_square_divider = C_P ** 2 + assert C_P == 128 * 2 ** i + loss += self.l1_loss(output_gram_matrix, target_gram_matrix) / C_P_square_divider + return loss + + def forward(self, data_input, model_output): + targets = data_input + outputs = model_output + mean_image_loss = self.style_loss(outputs, targets) + return mean_image_loss + + +class L1LossMaskedMean(nn.Module): + def __init__(self): + super().__init__() + self.l1 = nn.L1Loss(reduction='sum') + + def forward(self, x, y, mask): + masked = 1 - mask # 默认missing region的mask值为0,原有区域为1 + l1_sum = self.l1(x * masked, y * masked) + return l1_sum / torch.sum(masked) + + +class L2LossMaskedMean(nn.Module): + def __init__(self, reduction='sum'): + super().__init__() + self.l2 = nn.MSELoss(reduction=reduction) + + def forward(self, x, y, mask): + masked = 1 - mask + l2_sum = self.l2(x * masked, y * masked) + return l2_sum / torch.sum(masked) + + +class ImcompleteVideoReconLoss(nn.Module): + def __init__(self): + super().__init__() + self.loss_fn = L1LossMaskedMean() + + def forward(self, data_input, model_output): + imcomplete_video = model_output['imcomplete_video'] + targets = data_input['targets'] + down_sampled_targets = nn.functional.interpolate( + targets.transpose(1, 2), scale_factor=[1, 0.5, 0.5]) + + masks = data_input['masks'] + down_sampled_masks = nn.functional.interpolate( + masks.transpose(1, 2), scale_factor=[1, 0.5, 0.5]) + return self.loss_fn( + imcomplete_video, down_sampled_targets, + down_sampled_masks + ) + + +class CompleteFramesReconLoss(nn.Module): + def __init__(self): + super().__init__() + self.loss_fn = L1LossMaskedMean() + + def forward(self, data_input, model_output): + outputs = model_output['outputs'] + targets = data_input['targets'] + masks = data_input['masks'] + return self.loss_fn(outputs, targets, masks) + + +class AdversarialLoss(nn.Module): + r""" + Adversarial loss + https://arxiv.org/abs/1711.10337 + """ + + def __init__(self, type='nsgan', target_real_label=1.0, target_fake_label=0.0): + r""" + type = nsgan | lsgan | hinge + """ + super(AdversarialLoss, self).__init__() + self.type = type + self.register_buffer('real_label', torch.tensor(target_real_label)) + self.register_buffer('fake_label', torch.tensor(target_fake_label)) + + if type == 'nsgan': + self.criterion = nn.BCELoss() + elif type == 'lsgan': + self.criterion = nn.MSELoss() + elif type == 'hinge': + self.criterion = nn.ReLU() + + def __call__(self, outputs, is_real, is_disc=None): + if self.type == 'hinge': + if is_disc: + if is_real: + outputs = -outputs + return self.criterion(1 + outputs).mean() + else: + return (-outputs).mean() + else: + labels = (self.real_label if is_real else self.fake_label).expand_as( + outputs) + loss = self.criterion(outputs, labels) + return loss + + +# # From https://github.com/phoenix104104/fast_blind_video_consistency +# class TemporalWarpingLoss(nn.Module): +# def __init__(self, opts, flownet_checkpoint_path=None, alpha=50): +# super().__init__() +# self.loss_fn = L1LossMaskedMean() +# self.alpha = alpha +# self.opts = opts +# +# assert flownet_checkpoint_path is not None, "Flownet2 pretrained models must be provided" +# +# self.flownet_checkpoint_path = flownet_checkpoint_path +# raise NotImplementedError +# +# def get_flownet_checkpoint_path(self): +# return self.flownet_checkpoint_path +# +# def _flownetwrapper(self): +# Flownet = FlowNet2(self.opts, requires_grad=False) +# Flownet2_ckpt = torch.load(self.flownet_checkpoint_path) +# Flownet.load_state_dict(Flownet2_ckpt['state_dict']) +# Flownet.to(device) +# Flownet.exal() +# return Flownet +# +# def _setup(self): +# self.flownet = self._flownetwrapper() +# +# def _get_non_occlusuib_mask(self, targets, warped_targets): +# non_occlusion_masks = torch.exp( +# -self.alpha * torch.sum(targets[:, 1:] - warped_targets, dim=2).pow(2) +# ).unsqueeze(2) +# return non_occlusion_masks +# +# def _get_loss(self, outputs, warped_outputs, non_occlusion_masks, masks): +# return self.loss_fn( +# outputs[:, 1:] * non_occlusion_masks, +# warped_outputs * non_occlusion_masks, +# masks[:, 1:] +# ) +# +# def forward(self, data_input, model_output): +# if self.flownet is None: +# self._setup() +# +# targets = data_input['targets'].to(device) +# outputs = model_output['outputs'].to(device) +# flows = self.flownet.infer_video(targets).to(device) +# +# from utils.flow_utils import warp_optical_flow +# warped_targets = warp_optical_flow(targets[:, :-1], -flows).detach() +# warped_outputs = warp_optical_flow(outputs[:, :-1], -flows).detach() +# non_occlusion_masks = self._get_non_occlusion_mask(targets, warped_targets) +# +# # model_output is passed by name and dictionary is mutable +# # These values are sent to trainer for visualization +# model_output['warped_outputs'] = warped_outputs[0] +# model_output['warped_targets'] = warped_targets[0] +# model_output['non_occlusion_masks'] = non_occlusion_masks[0] +# from utils.flow_utils import flow_to_image +# flow_imgs = [] +# for flow in flows[0]: +# flow_img = flow_to_image(flow.cpu().permute(1, 2, 0).detach().numpy()).transpose(2, 0, 1) +# flow_imgs.append(torch.Tensor(flow_img)) +# model_output['flow_imgs'] = flow_imgs +# +# masks = data_input['masks'].to(device) +# return self._get_loss(outputs, warped_outputs, non_occlusion_masks, masks) +# +# +# class TemporalWarpingError(TemporalWarpingLoss): +# def __init__(self, flownet_checkpoint_path, alpha=50): +# super().__init__(flownet_checkpoint_path, alpha) +# self.loss_fn = L2LossMaskedMean(reduction='none') +# +# def _get_loss(self, outputs, warped_outputs, non_occlusion_masks, masks): +# # See https://arxiv.org/pdf/1808.00449.pdf 4.3 +# # The sum of non_occlusion_masks is different for each video, +# # So the batch dim is kept +# loss = self.loss_fn( +# outputs[:, 1:] * non_occlusion_masks, +# warped_outputs * non_occlusion_masks, +# masks[:, 1:] +# ).sum(1).sum(1).sum(1).sum(1) +# +# loss = loss / non_occlusion_masks.sum(1).sum(1).sum(1).sum(1) +# return loss.sum() + + +class ValidLoss(nn.Module): + def __init__(self): + super(ValidLoss, self).__init__() + self.loss_fn = nn.L1Loss(reduction='mean') + + def forward(self, model_output, target, mk): + outputs = model_output + targets = target + return self.loss_fn(outputs * (1 - mk), targets * (1 - mk)) # L1 loss in masked region + + + +class TVLoss(nn.Module): + def __init__(self): + super(TVLoss, self).__init__() + + def forward(self, mask_input, model_output): + # View 3D data as 2D + outputs = model_output + + if len(mask_input.shape) == 4: + mask_input = mask_input.unsqueeze(2) + if len(outputs.shape) == 4: + outputs = outputs.unsqueeze(2) + + outputs = outputs.permute((0, 2, 1, 3, 4)).contiguous() + masks = mask_input.permute((0, 2, 1, 3, 4)).contiguous() + + B, L, C, H, W = outputs.shape + x = outputs.view([B * L, C, H, W]) + + masks = masks.view([B * L, -1]) + mask_areas = masks.sum(dim=1) + + h_x = x.size()[2] + w_x = x.size()[3] + h_tv = torch.pow((x[:, :, 1:, :] - x[:, :, :h_x - 1, :]), 2).sum(1).sum(1).sum(1) # 差分是为了求梯度,本质上还是梯度平方和 + w_tv = torch.pow((x[:, :, :, 1:] - x[:, :, :, :w_x - 1]), 2).sum(1).sum(1).sum(1) + return ((h_tv + w_tv) / mask_areas).mean() + + +# for debug +def show_images(image, name): + import cv2 + import numpy as np + image = np.array(image) + image[image > 0.5] = 255. + image = image.transpose((1, 2, 0)) + cv2.imwrite(name, image) + + +if __name__ == '__main__': + # test align loss, + targetFrame = torch.ones(1, 3, 32, 32) + GT = torch.ones(1, 3, 32, 32) + GT += 1 + mask = torch.zeros(1, 1, 32, 32) + mask[:, :, 8:24, 8:24] = 1. + + # referenceFrames = torch.ones(1, 3, 4, 32, 32) + # referenceMasks = torch.zeros(1, 1, 4, 32, 32) + # referenceMasks[:, :, 0, 4:12, 4:12] = 1. + # referenceFrames[:, :, 0, 4:12, 4:12] = 2. + # referenceMasks[:, :, 1, 4:12, 20:28] = 1. + # referenceFrames[:, :, 1, 4:12, 20:28] = 2. + # referenceMasks[:, :, 2, 20:28, 4:12] = 1. + # referenceFrames[:, :, 2, 20:28, 4:12] = 2. + # referenceMasks[:, :, 3, 20:28, 20:28] = 1. + # referenceFrames[:, :, 3, 20:28, 20:28] = 2. + # + # aligned_v = referenceMasks + # aligned_v, referenceFrames = [aligned_v], [referenceFrames] + # + # result = AlignLoss()(targetFrame, mask, aligned_v, referenceFrames) + # print(result) + + c_mask = torch.zeros(1, 1, 32, 32) + c_mask[:, :, 8:16, 16:24] = 1. + result1 = HoleVisibleLoss()(targetFrame, mask, GT, c_mask) + result2 = HoleInvisibleLoss()(targetFrame, mask, GT, c_mask) + result3 = NonHoleLoss()(targetFrame, mask, GT) + print('vis: {}, invis: {}, gt: {}'.format(result1, result2, result3)) diff --git a/FGT_codes/FGT/models/utils/network_blocks_2d.py b/FGT_codes/FGT/models/utils/network_blocks_2d.py new file mode 100644 index 0000000000000000000000000000000000000000..937e4c76fae71dcd4d8345ce1ad0f8f3019c7167 --- /dev/null +++ b/FGT_codes/FGT/models/utils/network_blocks_2d.py @@ -0,0 +1,186 @@ +import torch +import torch.nn as nn +import numpy as np +import torch.nn.functional as F + + +class VanillaConv(nn.Module): + def __init__( + self, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, + groups=1, bias=True, norm="SN", activation=nn.LeakyReLU(0.2, inplace=True) + ): + + super().__init__() + if padding == -1: + if isinstance(kernel_size, int): + kernel_size = (kernel_size, kernel_size) + if isinstance(dilation, int): + dilation = (dilation, dilation) + self.padding = tuple(((np.array(kernel_size) - 1) * np.array(dilation)) // 2) if padding == -1 else padding + self.featureConv = nn.Conv2d( + in_channels, out_channels, kernel_size, + stride, self.padding, dilation, groups, bias) + + self.norm = norm + if norm == "BN": + self.norm_layer = nn.BatchNorm2d(out_channels) + elif norm == "IN": + self.norm_layer = nn.InstanceNorm2d(out_channels, track_running_stats=True) + elif norm == "SN": + self.norm = None + self.featureConv = nn.utils.spectral_norm(self.featureConv) + else: + self.norm = None + + self.activation = activation + + def forward(self, xs): + out = self.featureConv(xs) + if self.activation: + out = self.activation(out) + if self.norm is not None: + out = self.norm_layer(out) + return out + + +class VanillaDeconv(nn.Module): + def __init__( + self, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, + groups=1, bias=True, norm="SN", activation=nn.LeakyReLU(0.2, inplace=True), + scale_factor=2 + ): + super().__init__() + self.conv = VanillaConv( + in_channels, out_channels, kernel_size, stride, padding, dilation, + groups, bias, norm, activation) + self.scale_factor = scale_factor + + def forward(self, xs): + xs_resized = F.interpolate(xs, scale_factor=self.scale_factor) + return self.conv(xs_resized) + + +class GatedConv(VanillaConv): + def __init__( + self, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, + groups=1, bias=True, norm="SN", activation=nn.LeakyReLU(0.2, inplace=True) + ): + super().__init__( + in_channels, out_channels, kernel_size, stride, padding, dilation, + groups, bias, norm, activation + ) + self.gatingConv = nn.Conv2d( + in_channels, out_channels, kernel_size, + stride, self.padding, dilation, groups, bias) + if norm == 'SN': + self.gatingConv = nn.utils.spectral_norm(self.gatingConv) + self.sigmoid = nn.Sigmoid() + self.store_gated_values = False + + def gated(self, mask): + # return torch.clamp(mask, -1, 1) + out = self.sigmoid(mask) + if self.store_gated_values: + self.gated_values = out.detach().cpu() + return out + + def forward(self, xs): + gating = self.gatingConv(xs) + feature = self.featureConv(xs) + if self.activation: + feature = self.activation(feature) + out = self.gated(gating) * feature + if self.norm is not None: + out = self.norm_layer(out) + return out + + +class GatedDeconv(VanillaDeconv): + def __init__( + self, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, + groups=1, bias=True, norm="SN", activation=nn.LeakyReLU(0.2, inplace=True), + scale_factor=2 + ): + super().__init__( + in_channels, out_channels, kernel_size, stride, padding, dilation, + groups, bias, norm, activation, scale_factor + ) + self.conv = GatedConv( + in_channels, out_channels, kernel_size, stride, padding, dilation, + groups, bias, norm, activation) + + +class PartialConv(VanillaConv): + def __init__(self, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, + groups=1, bias=True, norm="SN", activation=nn.LeakyReLU(0.2, inplace=True)): + super().__init__( + in_channels, out_channels, kernel_size, stride, padding, dilation, + groups, bias, norm, activation + ) + self.mask_sum_conv = nn.Conv2d(1, 1, kernel_size, + stride, self.padding, dilation, groups, False) + nn.init.constant_(self.mask_sum_conv.weight, 1.0) + + # mask conv needs not update + for param in self.mask_sum_conv.parameters(): + param.requires_grad = False + + def forward(self, input_tuple): + # http://masc.cs.gmu.edu/wiki/partialconv + # C(X) = W^T * X + b, C(0) = b, D(M) = 1 * M + 0 = sum(M) + # output = W^T* (M .* X) / sum(M) + b = [C(M .* X) – C(0)] / D(M) + C(0), if sum(M) != 0 + # = 0, if sum(M) == 0 + inp, mask = input_tuple + # print(inp.shape, mask.shape) + + # C(M .* X) + output = self.featureConv(mask * inp) + + # C(0) = b + if self.featureConv.bias is not None: + output_bias = self.featureConv.bias.view(1, -1, 1, 1) + else: + output_bias = torch.zeros([1, 1, 1, 1]).to(inp.device) + + # D(M) = sum(M) + with torch.no_grad(): + mask_sum = self.mask_sum_conv(mask) + + # find those sum(M) == 0 + no_update_holes = (mask_sum == 0) + + # Just to prevent devided by 0 + mask_sum_no_zero = mask_sum.masked_fill_(no_update_holes, 1.0) + + # output = [C(M .* X) – C(0)] / D(M) + C(0), if sum(M) != 0 + # = 0, if sum (M) == 0 + output = (output - output_bias) / mask_sum_no_zero + output_bias + output = output.masked_fill_(no_update_holes, 0.0) + + # create a new mask with only 1 or 0 + new_mask = torch.ones_like(mask_sum) + new_mask = new_mask.masked_fill_(no_update_holes, 0.0) + + if self.activation is not None: + output = self.activation(output) + if self.norm is not None: + output = self.norm_layer(output) + return output, new_mask + + +class PartialDeconv(nn.Module): + def __init__(self, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, + groups=1, bias=True, norm="SN", activation=nn.LeakyReLU(0.2, inplace=True), + scale_factor=2): + super().__init__() + self.conv = PartialConv( + in_channels, out_channels, kernel_size, stride, padding, dilation, + groups, bias, norm, activation) + self.scale_factor = scale_factor + + def forward(self, input_tuple): + inp, mask = input_tuple + inp_resized = F.interpolate(inp, scale_factor=self.scale_factor) + with torch.no_grad(): + mask_resized = F.interpolate(mask, scale_factor=self.scale_factor) + return self.conv((inp_resized, mask_resized)) diff --git a/FGT_codes/FGT/models/utils/reconstructionLayers.py b/FGT_codes/FGT/models/utils/reconstructionLayers.py new file mode 100644 index 0000000000000000000000000000000000000000..37302c52f8aa65292ab722d73d6ff6af910bca52 --- /dev/null +++ b/FGT_codes/FGT/models/utils/reconstructionLayers.py @@ -0,0 +1,143 @@ +# Two types of reconstructionl layers: 1. original residual layers, 2. residual layers with contrast and adaptive attention(CCA layer) +import torch +import torch.nn as nn +import torch.nn.init as init + + +def initialize_weights(net_l, scale=1): + if not isinstance(net_l, list): + net_l = [net_l] + for net in net_l: + for m in net.modules(): + if isinstance(m, nn.Conv2d): + init.kaiming_normal_(m.weight, a=0, mode='fan_in') + m.weight.data *= scale # for residual block + if m.bias is not None: + m.bias.data.zero_() + elif isinstance(m, nn.Linear): + init.kaiming_normal_(m.weight, a=0, mode='fan_in') + m.weight.data *= scale + if m.bias is not None: + m.bias.data.zero_() + elif isinstance(m, nn.BatchNorm2d): + init.constant_(m.weight, 1) + init.constant_(m.bias.data, 0.0) + + +def make_layer(block, n_layers): + layers = [] + for _ in range(n_layers): + layers.append(block()) + return nn.Sequential(*layers) + + +class ResidualBlock_noBN(nn.Module): + """Residual block w/o BN + ---Conv-ReLU-Conv-+- + |________________| + """ + + def __init__(self, nf=64): + super(ResidualBlock_noBN, self).__init__() + self.conv1 = nn.Conv2d(nf, nf, kernel_size=3, stride=1, padding=1, bias=True) + self.conv2 = nn.Conv2d(nf, nf, kernel_size=3, stride=1, padding=1, bias=True) + self.lrelu = nn.LeakyReLU(negative_slope=0.2, inplace=True) + + def forward(self, x): + """ + + Args: + x: with shape of [b, c, t, h, w] + + Returns: processed features with shape [b, c, t, h, w] + + """ + identity = x + out = self.lrelu(self.conv1(x)) + out = self.conv2(out) + out = identity + out + # Remove ReLU at the end of the residual block + # http://torch.ch/blog/2016/02/04/resnets.html + return out + + +class ResBlock_noBN_new(nn.Module): + def __init__(self, nf): + super(ResBlock_noBN_new, self).__init__() + self.c1 = nn.Conv3d(nf, nf // 4, kernel_size=(1, 3, 3), stride=1, padding=(0, 1, 1), bias=True) + self.d1 = nn.Conv3d(nf // 4, nf // 4, kernel_size=(1, 3, 3), stride=1, padding=(0, 1, 1), + bias=True) # dilation rate=1 + self.d2 = nn.Conv3d(nf // 4, nf // 4, kernel_size=(1, 3, 3), stride=1, padding=(0, 2, 2), dilation=(1, 2, 2), + bias=True) # dilation rate=2 + self.d3 = nn.Conv3d(nf // 4, nf // 4, kernel_size=(1, 3, 3), stride=1, padding=(0, 4, 4), dilation=(1, 4, 4), + bias=True) # dilation rate=4 + self.d4 = nn.Conv3d(nf // 4, nf // 4, kernel_size=(1, 3, 3), stride=1, padding=(0, 8, 8), dilation=(1, 8, 8), + bias=True) # dilation rate=8 + self.act = nn.LeakyReLU(negative_slope=0.2, inplace=True) + self.c2 = nn.Conv3d(nf, nf, kernel_size=(1, 3, 3), stride=1, padding=(0, 1, 1), bias=True) + + def forward(self, x): + output1 = self.act(self.c1(x)) + d1 = self.d1(output1) + d2 = self.d2(output1) + d3 = self.d3(output1) + d4 = self.d4(output1) + + add1 = d1 + d2 + add2 = add1 + d3 + add3 = add2 + d4 + combine = torch.cat([d1, add1, add2, add3], dim=1) + output2 = self.c2(self.act(combine)) + output = x + output2 + # remove ReLU at the end of the residual block + # http://torch.ch/blog/2016/02/04/resnets.html + return output + + +class CCALayer(nn.Module): #############################################3 new + '''Residual block w/o BN + --conv--contrast-conv--x--- + | \--mean--| | + |___________________| + + ''' + + def __init__(self, nf=64): + super(CCALayer, self).__init__() + self.conv1 = nn.Conv2d(nf, nf, 3, 1, 1, bias=True) + self.conv2 = nn.Conv2d(nf, nf, 3, 1, 1, bias=True) + self.lrelu = nn.LeakyReLU(negative_slope=0.2, inplace=True) + self.conv_du = nn.Sequential( + nn.Conv2d(nf, 4, 1, padding=0, bias=True), + nn.ReLU(inplace=True), + nn.Conv2d(4, nf, 1, padding=0, bias=True), + nn.Tanh() # change from `Sigmoid` to `Tanh` to make the output between -1 and 1 + ) + self.contrast = stdv_channels + self.avg_pool = nn.AdaptiveAvgPool2d(1) + # initialization + initialize_weights([self.conv1, self.conv_du], 0.1) + + def forward(self, x): + identity = x + out = self.lrelu(self.conv1(x)) + out = self.conv2(out) + out = self.contrast(out) + self.avg_pool(out) + out_channel = self.conv_du(out) + out_channel = out_channel * out + out_last = out_channel + identity + + return out_last + + +def mean_channels(F): + assert (F.dim() == 4), 'Your dim is {} bit not 4'.format(F.dim()) + spatial_sum = F.sum(3, keepdim=True).sum(2, keepdim=True) + return spatial_sum / (F.size(2) * F.size(3)) # 对每一个channel都求其特征图的高和宽的平均值 + + +def stdv_channels(F): + assert F.dim() == 4, 'Your dim is {} bit not 4'.format(F.dim()) + F_mean = mean_channels(F) + F_variance = (F - F_mean).pow(2).sum(3, keepdim=True).sum(2, keepdim=True) / (F.size(2) * F.size(3)) + return F_variance.pow(0.5) diff --git a/FGT_codes/FGT/models/utils/sobel2.py b/FGT_codes/FGT/models/utils/sobel2.py new file mode 100644 index 0000000000000000000000000000000000000000..7a4ec74aff4cf187a738f717bac94bbb87dc0b60 --- /dev/null +++ b/FGT_codes/FGT/models/utils/sobel2.py @@ -0,0 +1,68 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F + + +class SobelLayer(nn.Module): + def __init__(self, device): + super(SobelLayer, self).__init__() + self.kernel_x = torch.tensor([[-1., 0, 1], [-2, 0, 2], [-1, 0, 1]]).unsqueeze(0).unsqueeze(0) / 4. + self.kernel_y = torch.tensor([[-1, -2, -1], [0, 0, 0], [1, 2, 1.]]).unsqueeze(0).unsqueeze(0) / 4. + self.kernel_x = self.kernel_x.to(device) + self.kernel_y = self.kernel_y.to(device) + self.pad = nn.ReplicationPad2d(padding=1) + self.absLayer = nn.ReLU() + + def forward(self, images): + """ + + Args: + images: images with shape [b, c, h, w] + + Returns: + + """ + images = self.pad(images) + gray_images = self._convertGrey(images) + + edge_x = F.conv2d(gray_images, self.kernel_x, stride=1) + edge_y = F.conv2d(gray_images, self.kernel_y, stride=1) + edge = (self.absLayer(edge_x) + self.absLayer(edge_y)) / 2 + return edge + + def _convertGrey(self, image): + """ + grey = 0.299 * r + 0.587 * g + 0.110 * b + Args: + image: RGB image + + Returns: Grey scale image + + """ + grey_image = image[:, 0] * 0.299 + image[:, 1] * 0.587 + 0.110 * image[:, 2] + output = grey_image.unsqueeze(1) + return output + + +class SeperateSobelLayer(nn.Module): + def __init__(self, device): + super(SeperateSobelLayer, self).__init__() + self.kernel_x = torch.tensor([[-1., 0, 1], [-2, 0, 2], [-1, 0, 1]]).unsqueeze(0).unsqueeze(0) + self.kernel_y = torch.tensor([[-1, -2, -1], [0, 0, 0], [1, 2, 1.]]).unsqueeze(0).unsqueeze(0) + self.weight = torch.zeros([6, 3, 3, 3]) + for c in range(3): + self.weight[2 * c, c] = self.kernel_x + self.weight[2 * c + 1, c] = self.kernel_y + self.weight = self.weight.to(device) + + def forward(self, images): + """ + + Args: + images: with shape [b, c, h, w] + + Returns: sobel gradient image with shape [b, c, h, w] (same padding) + + """ + gradientMap = F.conv2d(images, self.weight, stride=1, padding=1) + return gradientMap diff --git a/FGT_codes/FGT/models/utils/util.py b/FGT_codes/FGT/models/utils/util.py new file mode 100644 index 0000000000000000000000000000000000000000..4c0a7a6314fbcd6bd4adbc4c51595d6c75d48579 --- /dev/null +++ b/FGT_codes/FGT/models/utils/util.py @@ -0,0 +1,329 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +import math + +networks = ['BaseNetwork', 'Discriminator', 'ASPP'] + + +# Base model borrows from PEN-NET +# https://github.com/researchmm/PEN-Net-for-Inpainting +class BaseNetwork(nn.Module): + def __init__(self): + super(BaseNetwork, self).__init__() + + def print_network(self): + if isinstance(self, list): + self = self[0] + num_params = 0 + for param in self.parameters(): + num_params += param.numel() + print('Network [%s] was created. Total number of parameters: %.1f million. ' + 'To see the architecture, do print(network).' % (type(self).__name__, num_params / 1000000)) + + def init_weights(self, init_type='normal', gain=0.02): + ''' + initialize network's weights + init_type: normal | xavier | kaiming | orthogonal + https://github.com/junyanz/pytorch-CycleGAN-and-pix2pix/blob/9451e70673400885567d08a9e97ade2524c700d0/models/networks.py#L39 + ''' + + def init_func(m): + classname = m.__class__.__name__ + if classname.find('InstanceNorm2d') != -1: + if hasattr(m, 'weight') and m.weight is not None: + nn.init.constant_(m.weight.data, 1.0) + if hasattr(m, 'bias') and m.bias is not None: + nn.init.constant_(m.bias.data, 0.0) + elif hasattr(m, 'weight') and (classname.find('Conv') != -1 or classname.find('Linear') != -1): + if init_type == 'normal': + nn.init.normal_(m.weight.data, 0.0, gain) + elif init_type == 'xavier': + nn.init.xavier_normal_(m.weight.data, gain=gain) + elif init_type == 'xavier_uniform': + nn.init.xavier_uniform_(m.weight.data, gain=1.0) + elif init_type == 'kaiming': + nn.init.kaiming_normal_(m.weight.data, a=0, mode='fan_in') + elif init_type == 'orthogonal': + nn.init.orthogonal_(m.weight.data, gain=gain) + elif init_type == 'none': # uses pytorch's default init method + m.reset_parameters() + else: + raise NotImplementedError('initialization method [%s] is not implemented' % init_type) + if hasattr(m, 'bias') and m.bias is not None: + nn.init.constant_(m.bias.data, 0.0) + + self.apply(init_func) + + # propagate to children + for m in self.children(): + if hasattr(m, 'init_weights'): + m.init_weights(init_type, gain) + + +# temporal patch gan: from Free-form Video Inpainting with 3D Gated Convolution and Temporal PatchGAN in 2019 ICCV +# todo: debug this model +class Discriminator(BaseNetwork): + def __init__(self, in_channels=3, use_sigmoid=False, use_spectral_norm=True, init_weights=True): + super(Discriminator, self).__init__() + self.use_sigmoid = use_sigmoid + nf = 64 + + self.conv = nn.Sequential( + DisBuildingBlock(in_channel=in_channels, out_channel=nf * 1, kernel_size=(3, 5, 5), stride=(1, 2, 2), + padding=1, use_spectral_norm=use_spectral_norm), + # nn.InstanceNorm2d(64, track_running_stats=False), + nn.LeakyReLU(0.2, inplace=True), + DisBuildingBlock(in_channel=nf * 1, out_channel=nf * 2, kernel_size=(3, 5, 5), stride=(1, 2, 2), + padding=(1, 2, 2), use_spectral_norm=use_spectral_norm), + # nn.InstanceNorm2d(128, track_running_stats=False), + nn.LeakyReLU(0.2, inplace=True), + DisBuildingBlock(in_channel=nf * 2, out_channel=nf * 4, kernel_size=(3, 5, 5), stride=(1, 2, 2), + padding=(1, 2, 2), use_spectral_norm=use_spectral_norm), + # nn.InstanceNorm2d(256, track_running_stats=False), + nn.LeakyReLU(0.2, inplace=True), + DisBuildingBlock(in_channel=nf * 4, out_channel=nf * 4, kernel_size=(3, 5, 5), stride=(1, 2, 2), + padding=(1, 2, 2), use_spectral_norm=use_spectral_norm), + # nn.InstanceNorm2d(256, track_running_stats=False), + nn.LeakyReLU(0.2, inplace=True), + DisBuildingBlock(in_channel=nf * 4, out_channel=nf * 4, kernel_size=(3, 5, 5), stride=(1, 2, 2), + padding=(1, 2, 2), use_spectral_norm=use_spectral_norm), + # nn.InstanceNorm2d(256, track_running_stats=False), + nn.LeakyReLU(0.2, inplace=True), + nn.Conv3d(nf * 4, nf * 4, kernel_size=(3, 5, 5), + stride=(1, 2, 2), padding=(1, 2, 2)) + ) + + if init_weights: + self.init_weights() + + def forward(self, xs): + # B, C, T, H, W = xs.shape + feat = self.conv(xs) + if self.use_sigmoid: + feat = torch.sigmoid(feat) + return feat + + +class DisBuildingBlock(nn.Module): + def __init__(self, in_channel, out_channel, kernel_size, stride, padding, use_spectral_norm): + super(DisBuildingBlock, self).__init__() + self.block = self._getBlock(in_channel, out_channel, kernel_size, stride, padding, use_spectral_norm) + + def _getBlock(self, in_channel, out_channel, kernel_size, stride, padding, use_spectral_norm): + feature_conv = nn.Conv3d(in_channels=in_channel, out_channels=out_channel, kernel_size=kernel_size, + stride=stride, padding=padding, bias=not use_spectral_norm) + if use_spectral_norm: + feature_conv = nn.utils.spectral_norm(feature_conv) + return feature_conv + + def forward(self, inputs): + out = self.block(inputs) + return out + + +class ASPP(nn.Module): + def __init__(self, input_channels, output_channels, rate=[1, 2, 4, 8]): + super(ASPP, self).__init__() + self.input_channels = input_channels + self.output_channels = output_channels + self.rate = rate + for i in range(len(rate)): + self.__setattr__('conv{}'.format(str(i).zfill(2)), nn.Sequential( + nn.Conv2d(input_channels, output_channels // len(rate), kernel_size=3, dilation=rate[i], + padding=rate[i]), + nn.LeakyReLU(negative_slope=0.2, inplace=True) + )) + + def forward(self, inputs): + inputs = inputs / len(self.rate) + tmp = [] + for i in range(len(self.rate)): + tmp.append(self.__getattr__('conv{}'.format(str(i).zfill(2)))(inputs)) + output = torch.cat(tmp, dim=1) + return output + + +class GatedConv2dWithActivation(torch.nn.Module): + """ + Gated Convlution layer with activation (default activation:LeakyReLU) + Params: same as conv2d + Input: The feature from last layer "I" + Output:\phi(f(I))*\sigmoid(g(I)) + """ + + def __init__(self, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, + batch_norm=False, activation=torch.nn.LeakyReLU(0.2, inplace=True)): + super(GatedConv2dWithActivation, self).__init__() + self.batch_norm = batch_norm + self.activation = activation + self.conv2d = torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride, padding, dilation, groups, bias) + self.mask_conv2d = torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride, padding, dilation, groups, + bias) + self.batch_norm2d = torch.nn.BatchNorm2d(out_channels) + self.sigmoid = torch.nn.Sigmoid() + + for m in self.modules(): + if isinstance(m, nn.Conv2d): + nn.init.kaiming_normal_(m.weight) + + def gated(self, mask): + return self.sigmoid(mask) + + def forward(self, inputs): + x = self.conv2d(inputs) + mask = self.mask_conv2d(inputs) + if self.activation is not None: + x = self.activation(x) * self.gated(mask) + else: + x = x * self.gated(mask) + if self.batch_norm: + return self.batch_norm2d(x) + else: + return x + + +class GatedDeConv2dWithActivation(torch.nn.Module): + """ + Gated DeConvlution layer with activation (default activation:LeakyReLU) + resize + conv + Params: same as conv2d + Input: The feature from last layer "I" + Output:\phi(f(I))*\sigmoid(g(I)) + """ + + def __init__(self, scale_factor, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, + bias=True, batch_norm=False, activation=torch.nn.LeakyReLU(0.2, inplace=True)): + super(GatedDeConv2dWithActivation, self).__init__() + self.conv2d = GatedConv2dWithActivation(in_channels, out_channels, kernel_size, stride, padding, dilation, + groups, bias, batch_norm, activation) + self.scale_factor = scale_factor + + def forward(self, inputs): + # print(input.size()) + x = F.interpolate(inputs, scale_factor=self.scale_factor) + return self.conv2d(x) + + +class SNGatedConv2dWithActivation(torch.nn.Module): + """ + Gated Convolution with spetral normalization + """ + + def __init__(self, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, + batch_norm=False, activation=torch.nn.LeakyReLU(0.2, inplace=True)): + super(SNGatedConv2dWithActivation, self).__init__() + self.conv2d = torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride, padding, dilation, groups, bias) + self.mask_conv2d = torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride, padding, dilation, groups, + bias) + self.activation = activation + self.batch_norm = batch_norm + self.batch_norm2d = torch.nn.BatchNorm2d(out_channels) + self.sigmoid = torch.nn.Sigmoid() + self.conv2d = torch.nn.utils.spectral_norm(self.conv2d) + self.mask_conv2d = torch.nn.utils.spectral_norm(self.mask_conv2d) + for m in self.modules(): + if isinstance(m, nn.Conv2d): + nn.init.kaiming_normal_(m.weight) + + def gated(self, mask): + return self.sigmoid(mask) + + def forward(self, inputs): + x = self.conv2d(inputs) + mask = self.mask_conv2d(inputs) + if self.activation is not None: + x = self.activation(x) * self.gated(mask) + else: + x = x * self.gated(mask) + if self.batch_norm: + return self.batch_norm2d(x) + else: + return x + + +class SNGatedDeConv2dWithActivation(torch.nn.Module): + """ + Gated DeConvlution layer with activation (default activation:LeakyReLU) + resize + conv + Params: same as conv2d + Input: The feature from last layer "I" + Output:\phi(f(I))*\sigmoid(g(I)) + """ + + def __init__(self, scale_factor, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, + bias=True, batch_norm=False, activation=torch.nn.LeakyReLU(0.2, inplace=True)): + super(SNGatedDeConv2dWithActivation, self).__init__() + self.conv2d = SNGatedConv2dWithActivation(in_channels, out_channels, kernel_size, stride, padding, dilation, + groups, bias, batch_norm, activation) + self.scale_factor = scale_factor + + def forward(self, inputs): + x = F.interpolate(inputs, scale_factor=2) + return self.conv2d(x) + + +class GatedConv3d(nn.Module): + def __init__(self, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, + activation=nn.LeakyReLU(0.2, inplace=True)): + super(GatedConv3d, self).__init__() + self.input_conv = nn.Conv3d(in_channels, out_channels, kernel_size, + stride, padding, dilation, groups, bias) + self.gating_conv = nn.Conv3d(in_channels, out_channels, kernel_size, + stride, padding, dilation, groups, bias) + self.activation = activation + + def forward(self, inputs): + feature = self.input_conv(inputs) + if self.activation: + feature = self.activation(feature) + gating = torch.sigmoid(self.gating_conv(inputs)) + return feature * gating + + +class GatedDeconv3d(nn.Module): + def __init__(self, in_channels, out_channels, kernel_size, stride, padding, scale_factor, dilation=1, groups=1, + bias=True, activation=nn.LeakyReLU(0.2, inplace=True)): + super().__init__() + self.scale_factor = scale_factor + self.deconv = GatedConv3d(in_channels, out_channels, kernel_size, stride, padding, dilation, groups, bias, + activation) + + def forward(self, inputs): + inputs = F.interpolate(inputs, scale_factor=(1, self.scale_factor, self.scale_factor)) + return self.deconv(inputs) + + +def trunc_normal_(tensor, mean=0., std=1., a=-2., b=2.): + return _no_grad_trunc_normal_(tensor, mean, std, a, b) + + +def _no_grad_trunc_normal_(tensor, mean, std, a, b): + # Cut & paste from PyTorch official master until it's in a few official releases - RW + # Method based on https://people.sc.fsu.edu/~jburkardt/presentations/truncated_normal.pdf + def norm_cdf(x): + # Computes standard normal cumulative distribution function + return (1. + math.erf(x / math.sqrt(2.))) / 2. + + with torch.no_grad(): + # Values are generated by using a truncated uniform distribution and + # then using the inverse CDF for the normal distribution. + # Get upper and lower cdf values + l = norm_cdf((a - mean) / std) + u = norm_cdf((b - mean) / std) + + # Uniformly fill tensor with values from [l, u], then translate to + # [2l-1, 2u-1]. + tensor.uniform_(2 * l - 1, 2 * u - 1) + + # Use inverse cdf transform for normal distribution to get truncated + # standard normal + tensor.erfinv_() + + # Transform to proper mean, std + tensor.mul_(std * math.sqrt(2.)) + tensor.add_(mean) + + # Clamp to ensure it's in the proper range + tensor.clamp_(min=a, max=b) + return tensor diff --git a/FGT_codes/FGT/networks/__init__.py b/FGT_codes/FGT/networks/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/FGT_codes/FGT/networks/network.py b/FGT_codes/FGT/networks/network.py new file mode 100644 index 0000000000000000000000000000000000000000..ff8998d48933c5d471f1ec011061a16d45982617 --- /dev/null +++ b/FGT_codes/FGT/networks/network.py @@ -0,0 +1,491 @@ +from trainer import Trainer +from importlib import import_module +import math +import torch +from torch import optim +from torch.optim import lr_scheduler +import numpy as np +from metrics import calculate_metrics +import os +import glob +import torch.nn.functional as F +from models.temporal_patch_gan import Discriminator +import cv2 +import cvbase +import imageio +from skimage.feature import canny +from models.lafc_single import Model +from data.util.flow_utils import region_fill as rf + + +class Network(Trainer): + def init_model(self): + model_package = import_module('models.{}'.format(self.opt['model'])) + model = model_package.Model(self.opt) + dist_in = 3 + discriminator = Discriminator(in_channels=dist_in, conv_type=self.opt['conv_type'], + dist_cnum=self.opt['dist_cnum']) + optimizer = optim.Adam(model.parameters(), lr=float(self.opt['train']['lr']), + betas=(float(self.opt['train']['BETA1']), float(float(self.opt['train']['BETA2'])))) + dist_optim = optim.Adam(discriminator.parameters(), lr=float(self.opt['train']['lr']), + betas=(float(self.opt['train']['BETA1']), float(float(self.opt['train']['BETA2'])))) + if self.rank <= 0: + self.logger.info( + 'Optimizer is Adam, BETA1: {}, BETA2: {}'.format(float(self.opt['train']['BETA1']), + float(self.opt['train']['BETA2']))) + step_size = int(math.ceil(self.opt['train']['UPDATE_INTERVAL'] / self.trainSize)) + if self.rank <= 0: + self.logger.info('Step size for optimizer is {} epoch'.format(step_size)) + scheduler = lr_scheduler.StepLR(optimizer, step_size=step_size, gamma=self.opt['train']['lr_decay']) + dist_scheduler = lr_scheduler.StepLR(dist_optim, step_size=step_size, gamma=self.opt['train']['lr_decay']) + return model, discriminator, optimizer, dist_optim, scheduler, dist_scheduler + + def init_flow_model(self): + flow_model = Model(self.opt['flow_config']) + state = torch.load(self.opt['flow_checkPoint'], + map_location=lambda storage, loc: storage.cuda(self.opt['device'])) + flow_model.load_state_dict(state['model_state_dict']) + flow_model = flow_model.to(self.opt['device']) + return flow_model + + def resume_training(self): + gen_state = torch.load(self.opt['path']['gen_state'], + map_location=lambda storage, loc: storage.cuda(self.opt['device'])) + dis_state = torch.load(self.opt['path']['dis_state'], + map_location=lambda storage, loc: storage.cuda(self.opt['device'])) + opt_state = torch.load(self.opt['path']['opt_state'], + map_location=lambda storage, loc: storage.cuda(self.opt['device'])) + + if self.rank <= 0: + self.logger.info('Resume state is activated') + self.logger.info('Resume training from epoch: {}, iter: {}'.format( + opt_state['epoch'], opt_state['iteration'] + )) + if self.opt['finetune'] == False: + start_epoch = opt_state['epoch'] + current_step = opt_state['iteration'] + self.optimizer.load_state_dict(opt_state['optimizer_state_dict']) + self.dist_optim.load_state_dict(opt_state['dist_optim_state_dict']) + self.scheduler.load_state_dict(opt_state['scheduler_state_dict']) + self.dist_scheduler.load_state_dict(opt_state['dist_scheduler_state_dict']) + else: + start_epoch = 0 + current_step = 0 + self.model.load_state_dict(gen_state['model_state_dict']) + self.dist.load_state_dict(dis_state['dist_state_dict']) + if self.rank <= 0: + self.logger.info('Resume training mode, optimizer, scheduler and model have been uploaded') + return start_epoch, current_step + + def norm_flows(self, flows): + flattened_flows = flows.flatten(3) + flow_max = torch.max(flattened_flows, dim=-1, keepdim=True)[0] + flows = flows / flow_max.unsqueeze(-1) + return flows + + def _trainEpoch(self, epoch): + for idx, train_data in enumerate(self.trainLoader): + self.currentStep += 1 + + if self.currentStep > self.totalIterations: + if self.rank <= 0: + self.logger.info('Train process has been finished') + break + if self.opt['train']['WARMUP'] is not None and self.currentStep <= self.opt['train']['WARMUP'] // self.opt[ + 'world_size']: + target_lr = self.opt['train']['lr'] * self.currentStep / ( + self.opt['train']['WARMUP']) + self.adjust_learning_rate(self.optimizer, target_lr) + + frames = train_data['frames'] # tensor, [b, t, c, h, w] + masks = train_data['masks'] # tensor, [b, t, c, h, w] + if self.opt['flow_direction'] == 'for': + flows = train_data['forward_flo'] + elif self.opt['flow_direction'] == 'back': + flows = train_data['backward_flo'] + elif self.opt['flow_direction'] == 'bi': + raise NotImplementedError('Bidirectory flow mode is not implemented') + else: + raise ValueError('Unknown flow mode: {}'.format(self.opt['flow_direction'])) + frames = frames.to(self.opt['device']) # [b, t, c(3), h, w] + masks = masks.to(self.opt['device']) # [b, t, 1, h, w] + flows = flows.to(self.opt['device']) # [b, t, c(2), h, w] + + b, t, c, h, w = flows.shape + flows = flows.reshape(b * t, c, h, w) + compressed_masks = masks.reshape(b * t, 1, h, w) + with torch.no_grad(): + flows = self.flow_model(flows, compressed_masks)[0] # filled flows + flows = flows.reshape(b, t, c, h, w) + + flows = self.norm_flows(flows) + + b, t, c, h, w = frames.shape + cm, cf = masks.shape[2], flows.shape[2] + + masked_frames = frames * (1 - masks) + + filled_frames = self.model(masked_frames, flows, masks) # filled_frames shape: [b, t, c, h, w] + frames = frames.view(b * t, c, h, w) + masks = masks.view(b * t, cm, h, w) + comp_img = filled_frames * masks + frames * (1 - masks) + + real_vid_feat = self.dist(frames, t) + fake_vid_feat = self.dist(comp_img.detach(), t) + dis_real_loss = self.adversarial_loss(real_vid_feat, True, True) + dis_fake_loss = self.adversarial_loss(fake_vid_feat, False, True) + dis_loss = (dis_real_loss + dis_fake_loss) / 2 + self.dist_optim.zero_grad() + dis_loss.backward() + self.dist_optim.step() + + # calculate generator loss + gen_vid_feat = self.dist(comp_img, t) + gan_loss = self.adversarial_loss(gen_vid_feat, True, False) + gen_loss = gan_loss * self.opt['adv'] + L1Loss_valid = self.validLoss(filled_frames * (1 - masks), + frames * (1 - masks)) / torch.mean(1 - masks) + L1Loss_masked = self.validLoss(filled_frames * masks, + frames * masks) / torch.mean(masks) + m_loss_valid = L1Loss_valid * self.opt['L1M'] + m_loss_masked = L1Loss_masked * self.opt['L1V'] + + loss = m_loss_valid + m_loss_masked + gen_loss + + self.optimizer.zero_grad() + loss.backward() + self.optimizer.step() + + if self.opt['use_tb_logger'] and self.rank <= 0 and self.currentStep % 8 == 0: + print('Mask: {:.03f}, valid: {:.03f}, dis_fake: {:.03f}, dis_real: {:.03f}, adv: {:.03f}'.format( + m_loss_masked.item(), + m_loss_valid.item(), + dis_fake_loss.item(), + dis_real_loss.item(), + gen_loss.item() + )) + if self.opt['use_tb_logger'] and self.rank <= 0 and self.currentStep % 64 == 0: + self.tb_logger.add_scalar('{}/recon_mask'.format('train'), m_loss_masked.item(), + self.currentStep) + self.tb_logger.add_scalar('{}/recon_valid'.format('train'), m_loss_valid.item(), + self.currentStep) + self.tb_logger.add_scalar('{}/adv'.format('train'), gen_loss.item(), + self.currentStep) + self.tb_logger.add_scalar('train/dist', dis_loss.item(), self.currentStep) + + if self.currentStep % self.opt['logger']['PRINT_FREQ'] == 0 and self.rank <= 0: + c_frames = comp_img.detach().permute(0, 2, 3, 1).cpu() + f_frames = frames.detach().permute(0, 2, 3, 1).cpu() + compLog = np.clip(np.array((c_frames + 1) / 2 * 255), 0, 255).astype(np.uint8) + framesLog = np.clip(np.array((f_frames + 1) / 2 * 255), 0, 255).astype(np.uint8) + logs = calculate_metrics(compLog, framesLog) + self._printLog(logs, epoch, loss) + + def _printLog(self, logs, epoch, loss): + if self.countDown % self.opt['record_iter'] == 0: + self.total_psnr = 0 + self.total_ssim = 0 + self.total_l1 = 0 + self.total_l2 = 0 + self.total_loss = 0 + self.countDown = 0 + self.countDown += 1 + message = '[epoch:{:3d}, iter:{:7d}, lr:('.format(epoch, self.currentStep) + for v in self.get_lr(): + message += '{:.3e}, '.format(v) + message += ')] ' + self.total_psnr += logs['psnr'] + self.total_ssim += logs['ssim'] + self.total_l1 += logs['l1'] + self.total_l2 += logs['l2'] + self.total_loss += loss.item() + mean_psnr = self.total_psnr / self.countDown + mean_ssim = self.total_ssim / self.countDown + mean_l1 = self.total_l1 / self.countDown + mean_l2 = self.total_l2 / self.countDown + mean_loss = self.total_loss / self.countDown + + message += '{:s}: {:.4e} '.format('mean_loss', mean_loss) + message += '{:s}: {:} '.format('mean_psnr', mean_psnr) + message += '{:s}: {:} '.format('mean_ssim', mean_ssim) + message += '{:s}: {:} '.format('mean_l1', mean_l1) + message += '{:s}: {:} '.format('mean_l2', mean_l2) + + if self.opt['use_tb_logger']: + self.tb_logger.add_scalar('train/mean_psnr', mean_psnr, self.currentStep) + self.tb_logger.add_scalar('train/mean_ssim', mean_ssim, self.currentStep) + self.tb_logger.add_scalar('train/mean_l1', mean_l1, self.currentStep) + self.tb_logger.add_scalar('train/mean_l2', mean_l2, self.currentStep) + self.tb_logger.add_scalar('train/mean_loss', mean_loss, self.currentStep) + self.logger.info(message) + + if self.currentStep % self.opt['logger']['SAVE_CHECKPOINT_FREQ'] == 0: + self.save_checkpoint(epoch) + + def save_checkpoint(self, epoch): + if isinstance(self.model, torch.nn.DataParallel) or isinstance(self.model, + torch.nn.parallel.DistributedDataParallel): + model_state = self.model.module.state_dict() + dist_state = self.dist.module.state_dict() + else: + model_state = self.model.state_dict() + dist_state = self.dist.state_dict() + gen_state = { + 'model_state_dict': model_state + } + dis_state = { + 'dist_state_dict': dist_state + } + opt_state = { + 'epoch': epoch, + 'iteration': self.currentStep, + 'optimizer_state_dict': self.optimizer.state_dict(), + 'dist_optim_state_dict': self.dist_optim.state_dict(), + 'scheduler_state_dict': self.scheduler.state_dict(), + 'dist_scheduler_state_dict': self.dist_scheduler.state_dict() + } + + gen_name = os.path.join(self.opt['path']['TRAINING_STATE'], + 'gen_{}_{}.pth.tar'.format(epoch, self.currentStep)) + dist_name = os.path.join(self.opt['path']['TRAINING_STATE'], + 'dist_{}_{}.pth.tar'.format(epoch, self.currentStep)) + opt_name = os.path.join(self.opt['path']['TRAINING_STATE'], + 'opt_{}_{}.pth.tar'.format(epoch, self.currentStep)) + torch.save(gen_state, gen_name) + torch.save(dis_state, dist_name) + torch.save(opt_state, opt_name) + + def _validate(self, epoch): + frame_path = self.valInfo['frame_root'] + mask_path = self.valInfo['mask_root'] + flow_path = self.valInfo['flow_root'] + self.model.eval() + test_list = os.listdir(flow_path) + if len(test_list) > 10: + test_list = test_list[:10] # only valid 10 videos to save test time + width, height = self.valInfo['flow_width'], self.valInfo['flow_height'] + psnr, ssim, l1, l2 = {}, {}, {}, {} + pivot, sequenceLen, ref_length = 20, self.opt['num_frames'], self.opt['ref_length'] + for i in range(len(test_list)): + videoName = test_list[i] + if self.rank <= 0: + self.logger.info('Video {} is been processed'.format(videoName)) + frame_dir = os.path.join(frame_path, videoName) + mask_dir = os.path.join(mask_path, videoName) + flow_dir = os.path.join(flow_path, videoName) + videoLen = len(glob.glob(os.path.join(mask_dir, '*.png'))) + neighbor_ids = [i for i in range(max(0, pivot - sequenceLen // 2), min(videoLen, pivot + sequenceLen // 2))] + ref_ids = self.get_ref_index(neighbor_ids, videoLen, ref_length) + ref_ids.extend(neighbor_ids) + frames = self.read_frames(frame_dir, width, height, ref_ids) + masks = self.read_masks(mask_dir, width, height, ref_ids) + flows = self.read_flows(flow_dir, width, height, ref_ids, videoLen - 1) + if frames == [] or masks == []: + if self.rank <= 0: + print('Video {} doesn\'t have enough frames'.format(videoName)) + continue + flows = self.diffusion_flows(flows, masks) + if self.rank <= 0: + self.logger.info('Frames, masks, and flows have been read') + frames = np.stack(frames, axis=0) # [t, h, w, c] + masks = np.stack(masks, axis=0) + flows = np.stack(flows, axis=0) + frames = torch.from_numpy(np.transpose(frames, (0, 3, 1, 2))).unsqueeze(0).float() + flows = torch.from_numpy(np.transpose(flows, (0, 3, 1, 2))).unsqueeze(0).float() + masks = torch.from_numpy(np.transpose(masks, (0, 3, 1, 2))).unsqueeze(0).float() + frames = frames / 127.5 - 1 + frames = frames.to(self.opt['device']) + masks = masks.to(self.opt['device']) + flows = flows.to(self.opt['device']) + b, t, c, h, w = flows.shape + flows = flows.reshape(b * t, c, h, w) + compressed_masks = masks.reshape(b * t, 1, h, w) + with torch.no_grad(): + flows = self.flow_model(flows, compressed_masks)[0] + flows = flows.reshape(b, t, c, h, w) + flows = self.norm_flows(flows) + + b, t, c, h, w = frames.shape + cm, cf = masks.shape[2], flows.shape[2] + masked_frames = frames * (1 - masks) + with torch.no_grad(): + filled_frames = self.model(masked_frames, flows, masks) + frames = frames.view(b * t, c, h, w) + masks = masks.view(b * t, cm, h, w) + comp_img = filled_frames * masks + frames * (1 - masks) # [t, c, h, w] + + # calculate metrics + psnr_avg, ssim_avg, l1_avg, l2_avg = self.metrics_calc(comp_img, frames) + psnr[videoName] = psnr_avg + ssim[videoName] = ssim_avg + l1[videoName] = l1_avg + l2[videoName] = l2_avg + + # visualize frames and report the phase performance + if self.rank <= 0: + if self.opt['use_tb_logger']: + self.tb_logger.add_scalar('test/{}/l1'.format(videoName), l1_avg, + self.currentStep) + self.tb_logger.add_scalar('test/{}/l2'.format(videoName), l2_avg, self.currentStep) + self.tb_logger.add_scalar('test/{}/psnr'.format(videoName), psnr_avg, self.currentStep) + self.tb_logger.add_scalar('test/{}/ssim'.format(videoName), ssim_avg, self.currentStep) + masked_frames = masked_frames.view(b * t, c, h, w) + self.vis_frames(comp_img, masked_frames, frames, videoName, + epoch) # view the difference between diffused flows and the completed flows + mean_psnr = np.mean([psnr[k] for k in psnr.keys()]) + mean_ssim = np.mean([ssim[k] for k in ssim.keys()]) + mean_l1 = np.mean([l1[k] for k in l1.keys()]) + mean_l2 = np.mean([l2[k] for k in l2.keys()]) + self.logger.info( + '[epoch:{:3d}, vid:{}/{}], mean_l1: {:.4e}, mean_l2: {:.4e}, mean_psnr: {:}, mean_ssim: {:}'.format( + epoch, i, len(test_list), mean_l1, mean_l2, mean_psnr, mean_ssim)) + + # give the overall performance + if self.rank <= 0: + mean_psnr = np.mean([psnr[k] for k in psnr.keys()]) + mean_ssim = np.mean([ssim[k] for k in ssim.keys()]) + mean_l1 = np.mean([l1[k] for k in l1.keys()]) + mean_l2 = np.mean([l2[k] for k in l2.keys()]) + self.logger.info( + '[epoch:{:3d}], mean_l1: {:.4e} mean_l2: {:.4e} mean_psnr: {:} mean_ssim: {:}'.format( + epoch, mean_l1, mean_l2, mean_psnr, mean_ssim)) + self.save_checkpoint(epoch) + + self.model.train() + + def get_ref_index(self, neighbor_ids, videoLen, ref_length): + ref_indices = [] + for i in range(0, videoLen, ref_length): + if not i in neighbor_ids: + ref_indices.append(i) + return ref_indices + + def metrics_calc(self, results, frames): + psnr_avg, ssim_avg, l1_avg, l2_avg = 0, 0, 0, 0 + results = np.array(results.permute(0, 2, 3, 1).cpu()) + frames = np.array(frames.permute(0, 2, 3, 1).cpu()) + result = np.clip((results + 1) / 2 * 255, 0, 255).astype(np.uint8) + frames = np.clip((frames + 1) / 2 * 255, 0, 255).astype(np.uint8) + logs = calculate_metrics(result, frames) + psnr_avg += logs['psnr'] + ssim_avg += logs['ssim'] + l1_avg += logs['l1'] + l2_avg += logs['l2'] + return psnr_avg, ssim_avg, l1_avg, l2_avg + + def read_frames(self, frame_dir, width, height, ref_indices): + frame_paths = sorted(glob.glob(os.path.join(frame_dir, '*.jpg'))) + frames = [] + if len(frame_paths) <= 30: + return frames + for i in ref_indices: + frame_path = os.path.join(frame_dir, '{:05d}.jpg'.format(i)) + frame = imageio.imread(frame_path) + frame = cv2.resize(frame, (width, height), cv2.INTER_LINEAR) + frames.append(frame) + return frames + + def diffusion_flows(self, flows, masks): + assert len(flows) == len(masks), 'Length of flow: {}, length of mask: {}'.format(len(flows), len(masks)) + ret_flows = [] + for i in range(len(flows)): + flow, mask = flows[i], masks[i] + flow = self.diffusion_flow(flow, mask) + ret_flows.append(flow) + return ret_flows + + def diffusion_flow(self, flow, mask): + mask = mask[:, :, 0] + flow_filled = np.zeros(flow.shape) + flow_filled[:, :, 0] = rf.regionfill(flow[:, :, 0] * (1 - mask), mask) + flow_filled[:, :, 1] = rf.regionfill(flow[:, :, 1] * (1 - mask), mask) + return flow_filled + + def read_flows(self, flow_dir, width, height, ref_ids, frameMaxIndex): + if self.opt['flow_direction'] == 'for': + direction = 'forward_flo' + shift = 0 + elif self.opt['flow_direction'] == 'back': + direction = 'backward_flo' + shift = -1 + elif self.opt['flow_direction'] == 'bi': + raise NotImplementedError('Bidirectional flows processing are not implemented') + else: + raise ValueError('Unknown flow direction: {}'.format(self.opt['flow_direction'])) + flows = [] + flow_path = os.path.join(flow_dir, direction) + for i in ref_ids: + i += shift + if i >= frameMaxIndex: + i = frameMaxIndex - 1 + if i < 0: + i = 0 + flow_p = os.path.join(flow_path, '{:05d}.flo'.format(i)) + flow = cvbase.read_flow(flow_p) + pre_height, pre_width = flow.shape[:2] + flow = cv2.resize(flow, (width, height), cv2.INTER_LINEAR) + flow[:, :, 0] = flow[:, :, 0] / pre_width * width + flow[:, :, 1] = flow[:, :, 1] / pre_height * height + flows.append(flow) + return flows + + def load_edges(self, frames, width, height): + edges = [] + for i in range(len(frames)): + frame = frames[i] + frame_gray = cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY) + edge = canny(frame_gray, sigma=self.valInfo['sigma'], mask=None, + low_threshold=self.valInfo['low_threshold'], + high_threshold=self.valInfo['high_threshold']).astype(np.float) # [h, w, 1] + edge_t = self.to_tensor(edge, width, height, mode='nearest') + edges.append(edge_t) + return edges + + def to_tensor(self, frame, width, height, mode='bilinear'): + if len(frame.shape) == 2: + frame = frame[:, :, np.newaxis] + frame_t = torch.from_numpy(frame).unsqueeze(0).permute(0, 3, 1, 2).float() # [b, c, h, w] + if width != 0 and height != 0: + frame_t = F.interpolate(frame_t, size=(height, width), mode=mode) + return frame_t + + def to_numpy(self, tensor): + array = np.array(tensor.permute(1, 2, 0)) + return array + + def read_masks(self, mask_dir, width, height, ref_indices): + mask_path = sorted(glob.glob(os.path.join(mask_dir, '*.png'))) + masks = [] + if len(mask_path) < 30: + return masks + for i in ref_indices: + mask = cv2.imread(mask_path[i], 0) + mask = mask / 255. + mask = cv2.resize(mask, (width, height), cv2.INTER_NEAREST) + mask[mask > 0] = 1 + mask = mask[:, :, np.newaxis] + masks.append(mask) + return masks + + def vis_frames(self, results, masked_frames, frames, video_name, epoch): + out_root = self.opt['path']['VAL_IMAGES'] + out_dir = os.path.join(out_root, str(epoch), video_name) + if not os.path.exists(out_dir): + os.makedirs(out_dir) + black_column_pixels = 20 + results, masked_frames, frames = results.cpu(), masked_frames.cpu(), frames.cpu() + T = results.shape[0] + for t in range(T): + result, masked_frame, frame = results[t], masked_frames[t], frames[t] + result = self.to_numpy(result) + masked_frame = self.to_numpy(masked_frame) + frame = self.to_numpy(frame) + result = np.clip(((result + 1) / 2) * 255, 0, 255) + frame = np.clip(((frame + 1) / 2) * 255, 0, 255) + masked_frame = np.clip(((masked_frame + 1) / 2) * 255, 0, 255) # normalize to [0~255] + height, width = result.shape[:2] + canvas = np.zeros((height, width * 3 + black_column_pixels * 2, 3)) + canvas[:, 0:width, :] = result + canvas[:, width + black_column_pixels: 2 * width + black_column_pixels, :] = frame + canvas[:, 2 * (width + black_column_pixels):, :] = masked_frame + imageio.imwrite(os.path.join(out_dir, 'result_compare_{:05d}.png'.format(t)), canvas) diff --git a/FGT_codes/FGT/parse.py b/FGT_codes/FGT/parse.py new file mode 100644 index 0000000000000000000000000000000000000000..72dfa32c0d985bb903ab074cedb7513c867d2ee8 --- /dev/null +++ b/FGT_codes/FGT/parse.py @@ -0,0 +1,77 @@ +import yaml +import os +import os.path as osp + + +def path_correction(dataInfo, workdir): + for key in dataInfo.keys(): + if 'path' in key: + dataInfo[key] = os.path.join(workdir, dataInfo[key]) + return dataInfo + + +def val_path_correction(valInfo, workdir): + for key in valInfo.keys(): + if 'root' in key: + valInfo[key] = os.path.join(workdir, valInfo[key]) + return valInfo + + +def parse(args_setting, is_train=True): + opt_path = args_setting['opt'] + print('Current working dir is: {}'.format(os.getcwd())) + print('There are {} sub directories here'.format(os.listdir(os.getcwd()))) + with open(opt_path, 'r', encoding='utf-8') as f: + opt = yaml.safe_load(f) + + opt['is_train'] = is_train + opt = {**args_setting, **opt} + + name = opt['name'] + datadir, outputdir = opt['datadir'], opt['outputdir'] + + datasets = {} + for phase, args in opt['datasets'].items(): + # phase is `train`, `val` or `test` + datasets[phase] = args + if phase == 'train': + with open(args['dataInfo_config'], 'r', encoding='utf-8') as f: + dataInfo = yaml.safe_load(f) + dataInfo = path_correction(dataInfo, datadir) + datasets['dataInfo'] = dataInfo + if phase == 'val': + with open(args['val_config'], 'r', encoding='utf-8') as f: + valInfo = yaml.safe_load(f) + valInfo = val_path_correction(valInfo, datadir) + datasets['valInfo'] = valInfo + opt['datasets'] = datasets + + # path + opt['path'] = {} + + # training settings + if is_train: + output_root = osp.join(outputdir, opt['name'], 'experiments') + opt['path']['OUTPUT_ROOT'] = output_root + opt['path']['TRAINING_STATE'] = osp.join(output_root, 'training_state') + opt['path']['LOG'] = osp.join(output_root, 'log') + opt['path']['VAL_IMAGES'] = osp.join(output_root, 'val_images') + else: # for test + result_root = osp.join(datadir, opt['path']['OUTPUT_ROOT'], 'results', opt['name']) + opt['path']['RESULT_ROOT'] = osp.join(result_root, 'RESULT_ROOT') + opt['path']['LOG'] = result_root + + return opt + + +def toString(opt, indent_l=1): + msg = '' + for k, v in opt.items(): + if isinstance(v, dict): + msg += ' ' * (indent_l * 2) + k + ':[\n' + msg += toString(v, indent_l=1) + msg += ' ' * (indent_l * 2) + ']\n' + else: + msg += ' ' * (indent_l * 2) + k + ': ' + str(v) + '\n' + return msg + diff --git a/FGT_codes/FGT/train.py b/FGT_codes/FGT/train.py new file mode 100644 index 0000000000000000000000000000000000000000..ef88d3bc27385bdc3e44bdff3823f12eb44cc19e --- /dev/null +++ b/FGT_codes/FGT/train.py @@ -0,0 +1,83 @@ +from utils.dist import * +from parse import * +from utils.util import find_free_port +import torch.multiprocessing as mp +import torch.distributed +from importlib import import_module +import os +import glob +from inputs import args_parser + + +def main_worker(rank, opt): + if 'local_rank' not in opt: + opt['local_rank'] = opt['global_rank'] = rank + if opt['distributed']: + torch.cuda.set_device(int(opt['local_rank'])) + torch.distributed.init_process_group(backend='nccl', + init_method=opt['init_method'], + world_size=opt['world_size'], + rank=opt['global_rank'], + group_name='mtorch') + print('using GPU {}-{} for training'.format( + int(opt['global_rank']), int(opt['local_rank']))) + + if torch.cuda.is_available(): + opt['device'] = torch.device("cuda:{}".format(opt['local_rank'])) + else: + opt['device'] = 'cpu' + + pkg = import_module('networks.{}'.format(opt['network'])) + trainer = pkg.Network(opt, rank) + trainer.train() + + +def main(args_obj): + opt = parse(args_obj) + opt['world_size'] = get_world_size() + free_port = find_free_port() + master_ip = get_master_ip() + opt['init_method'] = "tcp://{}:{}".format(master_ip, free_port) + opt['distributed'] = True if opt['world_size'] > 1 else False + print(f'World size is: {opt["world_size"]}, and init_method is: {opt["init_method"]}') + print('Import network module: ', opt['network']) + + checkpoint, config = glob.glob(os.path.join(opt['flow_checkPoint'], '*.tar'))[0], \ + glob.glob(os.path.join(opt['flow_checkPoint'], '*.yaml'))[0] + with open(config, 'r') as f: + configs = yaml.full_load(f) + opt['flow_config'] = configs + opt['flow_checkPoint'] = checkpoint + + if args.finetune == 1: + opt['finetune'] = True + else: + opt['finetune'] = False + if opt['gen_state'] != '': + opt['path']['gen_state'] = opt['gen_state'] + if opt['dis_state'] != '': + opt['path']['dis_state'] = opt['dis_state'] + if opt['opt_state'] != '': + opt['path']['opt_state'] = opt['opt_state'] + + opt['input_resolution'] = (opt['res_h'], opt['res_w']) + opt['kernel_size'] = (opt['kernel_size_h'], opt['kernel_size_w']) + opt['stride'] = (opt['stride_h'], opt['stride_w']) + opt['padding'] = (opt['pad_h'], opt['pad_w']) + + print('model is: {}'.format(opt['model'])) + + if get_master_ip() == "127.0.0.1": + # localhost + mp.spawn(main_worker, nprocs=opt['world_size'], args=(opt,)) + else: + # multiple processes should be launched by openmpi + opt['local_rank'] = get_local_rank() + opt['global_rank'] = get_global_rank() + main_worker(-1, opt) + + +if __name__ == '__main__': + args = args_parser() + args_obj = vars(args) + main(args_obj) diff --git a/FGT_codes/FGT/trainer.py b/FGT_codes/FGT/trainer.py new file mode 100644 index 0000000000000000000000000000000000000000..08d0644b9e464a1fda954de38ebd524089a79c26 --- /dev/null +++ b/FGT_codes/FGT/trainer.py @@ -0,0 +1,200 @@ +import math +import parse +import logging +from utils import util +from torch.utils.data.distributed import DistributedSampler +from torch.nn.parallel import DistributedDataParallel as DDP +from data import create_dataset, create_dataloader +from models.utils.loss import * +import yaml +from abc import abstractmethod, ABCMeta +from models.utils.flow_losses import AdversarialLoss + + +class Trainer(metaclass=ABCMeta): + def __init__(self, opt, rank): + self.opt = opt + self.rank = rank + + # make directory and set logger + if rank <= 0: + self.mkdir() + self.logger, self.tb_logger = self.setLogger() + self.setSeed() + self.dataInfo, self.valInfo, self.trainSet, self.trainSize, self.totalIterations, self.totalEpochs, self.trainLoader, self.trainSampler = self.prepareDataset() + self.model, self.dist, self.optimizer, self.dist_optim, self.scheduler, self.dist_scheduler = self.init_model() + self.flow_model = self.init_flow_model() + self.model = self.model.to(self.opt['device']) + self.dist = self.dist.to(self.opt['device']) + if opt['path'].get('gen_state', None): + self.startEpoch, self.currentStep = self.resume_training() + else: + self.startEpoch, self.currentStep = 0, 0 + if opt['distributed']: + self.model = DDP( + self.model, + device_ids=[self.opt['local_rank']], + output_device=self.opt['local_rank'], + find_unused_parameters=True + ) + self.dist = DDP( + self.dist, + device_ids=[self.opt['local_rank']], + output_device=self.opt['local_rank'], + find_unused_parameters=True + ) + if self.rank <= 0: + self.logger.info('Start training from epoch: {}, iter: {}'.format( + self.startEpoch, self.currentStep)) + self.best_psnr = 0 + self.valid_best_psnr = 0 + + self.maskedLoss = nn.L1Loss() + self.validLoss = nn.L1Loss() + self.adversarial_loss = AdversarialLoss(type='hinge') + self.adversarial_loss = self.adversarial_loss.to(self.opt['device']) + self.countDown = 0 + + # metrics recorder + self.total_loss = 0 + self.total_psnr = 0 + self.total_ssim = 0 + self.total_l1 = 0 + self.total_l2 = 0 + + def get_lr(self): + lr = [] + for param_group in self.optimizer.param_groups: + lr += [param_group['lr']] + for param_group in self.dist_optim.param_groups: + lr += [param_group['lr']] + return lr + + def adjust_learning_rate(self, optimizer, target_lr): + for param_group in optimizer.param_groups: + param_group['lr'] = target_lr + for param_group in self.dist_optim.param_groups: + param_group['lr'] = target_lr + + def mkdir(self): + new_name = util.mkdir_and_rename(self.opt['path']['OUTPUT_ROOT']) + if new_name: + self.opt['path']['TRAINING_STATE'] = os.path.join(new_name, 'training_state') + self.opt['path']['LOG'] = os.path.join(new_name, 'log') + self.opt['path']['VAL_IMAGES'] = os.path.join(new_name, 'val_images') + if not os.path.exists(self.opt['path']['TRAINING_STATE']): + os.makedirs(self.opt['path']['TRAINING_STATE']) + if not os.path.exists(self.opt['path']['LOG']): + os.makedirs(self.opt['path']['LOG']) + if not os.path.exists(self.opt['path']['VAL_IMAGES']): + os.makedirs(self.opt['path']['VAL_IMAGES']) + # save config file for output + with open(os.path.join(self.opt['path']['LOG'], 'config.yaml'), 'w') as f: + yaml.dump(self.opt, f) + + def setLogger(self): + util.setup_logger('base', self.opt['path']['LOG'], 'train_' + self.opt['name'], level=logging.INFO, + screen=True, tofile=True) + logger = logging.getLogger('base') + logger.info(parse.toString(self.opt)) + logger.info('OUTPUT DIR IS: {}'.format(self.opt['path']['OUTPUT_ROOT'])) + if self.opt['use_tb_logger']: + version = float(torch.__version__[0:3]) + if version >= 1.1: + from torch.utils.tensorboard import SummaryWriter + else: + logger.info('You are using PyTorch {}, Tensorboard will use [tensorboardX)'.format(version)) + from tensorboardX import SummaryWriter + tb_logger = SummaryWriter(os.path.join(self.opt['path']['OUTPUT_ROOT'], 'log')) + else: + tb_logger = None + return logger, tb_logger + + def setSeed(self): + seed = self.opt['train']['manual_seed'] + if self.rank <= 0: + self.logger.info('Random seed: {}'.format(seed)) + util.set_random_seed(seed) + torch.backends.cudnn.benchmark = True + if seed == 0: + torch.backends.cudnn.deterministic = True + + def prepareDataset(self): + dataInfo = self.opt['datasets']['dataInfo'] + valInfo = self.opt['datasets']['valInfo'] + valInfo['norm'] = self.opt['norm'] + if self.rank <= 0: + self.logger.debug('Val info is: {}'.format(valInfo)) + train_set, train_size, total_iterations, total_epochs = 0, 0, 0, 0 + train_loader, train_sampler = None, None + for phase, dataset in self.opt['datasets'].items(): + dataset['norm'] = self.opt['norm'] + dataset['dataMode'] = self.opt['dataMode'] + dataset['num_frames'] = self.opt['num_frames'] + dataset['sample'] = self.opt['sample'] + dataset['flow2rgb'] = self.opt['flow2rgb'] + dataset['flow_direction'] = self.opt['flow_direction'] + dataset['max_val'] = self.opt['max_val'] + dataset['input_resolution'] = self.opt['input_resolution'] + if phase.lower() == 'train': + train_set = create_dataset(dataset, dataInfo, phase, self.opt['datasetName_train']) + train_size = math.ceil( + len(train_set) / (dataset['batch_size'] * self.opt['world_size'])) + total_iterations = self.opt['train']['MAX_ITERS'] + total_epochs = int(math.ceil(total_iterations / train_size)) + if self.opt['distributed']: + train_sampler = DistributedSampler( + train_set, + num_replicas=self.opt['world_size'], + rank=self.opt['global_rank']) + else: + train_sampler = None + train_loader = create_dataloader(phase, train_set, dataset, self.opt, train_sampler) + if self.rank <= 0: + self.logger.info('Number of training batches: {}, iters: {}'.format(len(train_set), + total_iterations)) + self.logger.info('Total epoch needed: {} for iters {}'.format(total_epochs, total_iterations)) + assert train_set != 0 and train_size != 0, "Train size cannot be zero" + assert train_loader is not None, "Cannot find train set, val set can be None" + return dataInfo, valInfo, train_set, train_size, total_iterations, total_epochs, train_loader, train_sampler + + @abstractmethod + def init_model(self): + pass + + @abstractmethod + def init_flow_model(self): + pass + + @abstractmethod + def resume_training(self): + pass + + def train(self): + for epoch in range(self.startEpoch, self.totalEpochs + 1): + if self.opt['distributed']: + self.trainSampler.set_epoch(epoch) + self._trainEpoch(epoch) + if self.currentStep > self.totalIterations: + break + if self.opt['use_valid'] and (epoch + 1) % self.opt['train']['val_freq'] == 0: + self._validate(epoch) + self.scheduler.step(epoch) + self.dist_scheduler.step(epoch) + + @abstractmethod + def _trainEpoch(self, epoch): + pass + + @abstractmethod + def _printLog(self, logs, epoch, loss): + pass + + @abstractmethod + def save_checkpoint(self, epoch, is_best, metric, number): + pass + + @abstractmethod + def _validate(self, epoch): + pass + diff --git a/FGT_codes/FGT/utils/__init__.py b/FGT_codes/FGT/utils/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/FGT_codes/FGT/utils/dist.py b/FGT_codes/FGT/utils/dist.py new file mode 100644 index 0000000000000000000000000000000000000000..f07940ada074a687debbfe730e5df9ccd34651cf --- /dev/null +++ b/FGT_codes/FGT/utils/dist.py @@ -0,0 +1,55 @@ +import os +import io +import re +import subprocess +import logging +import random +import torch +import numpy as np + + +## This code is borrowed from +# https://github.com/researchmm/STTN/blob/master/core/dist.py +def get_world_size(): + """Find OMPI world size without calling mpi functions + :rtype: int + """ + if os.environ.get('PMI_SIZE') is not None: + return int(os.environ.get('PMI_SIZE') or 1) + elif os.environ.get('OMPI_COMM_WORLD_SIZE') is not None: + return int(os.environ.get('OMPI_COMM_WORLD_SIZE') or 1) + else: + return torch.cuda.device_count() + + +def get_global_rank(): + """Find OMPI world rank without calling mpi functions + :rtype: int + """ + if os.environ.get('PMI_RANK') is not None: + return int(os.environ.get('PMI_RANK') or 0) + elif os.environ.get('OMPI_COMM_WORLD_RANK') is not None: + return int(os.environ.get('OMPI_COMM_WORLD_RANK') or 0) + else: + return 0 + + +def get_local_rank(): + """Find OMPI local rank without calling mpi functions + :rtype: int + """ + if os.environ.get('MPI_LOCALRANKID') is not None: + return int(os.environ.get('MPI_LOCALRANKID') or 0) + elif os.environ.get('OMPI_COMM_WORLD_LOCAL_RANK') is not None: + return int(os.environ.get('OMPI_COMM_WORLD_LOCAL_RANK') or 0) + else: + return 0 + + +def get_master_ip(): + if os.environ.get('AZ_BATCH_MASTER_NODE') is not None: + return os.environ.get('AZ_BATCH_MASTER_NODE').split(':')[0] + elif os.environ.get('AZ_BATCHAI_MPI_MASTER_NODE') is not None: + return os.environ.get('AZ_BATCHAI_MPI_MASTER_NODE') + else: + return "127.0.0.1" diff --git a/FGT_codes/FGT/utils/flow_utils.py b/FGT_codes/FGT/utils/flow_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..65d5be9fdf4454dc2c18506289bbdb0298b3c5d7 --- /dev/null +++ b/FGT_codes/FGT/utils/flow_utils.py @@ -0,0 +1,176 @@ +import numpy as np +import torch +import torch.nn as nn + +# https://zhuanlan.zhihu.com/p/112030273 +def warp_optical_flow(batch_x, batch_flow): + """ + Modified from https://github.com/NVlabs/PWC-Net/blob/fc6ebf9a70a7387164df09a3a2070ba16f9c1ede/PyTorch/models/PWCNet.py # NOQA + warp an im2 back to im1, according to the optical flow + x: [B, L, C, H, W] (im2) + flo: [B, L, 2, H, W] flow + """ + B, L, C, H, W = batch_x.shape + B = B * L + x = batch_x.contiguous().view(-1, C, H, W) + flo = batch_flow.view(-1, 2, H, W) + # mesh grid + xx = torch.arange(0, W).view(1, -1).repeat(H, 1) + yy = torch.arange(0, H).view(-1, 1).repeat(1, W) + xx = xx.view(1, 1, H, W).repeat(B, 1, 1, 1) + yy = yy.view(1, 1, H, W).repeat(B, 1, 1, 1) + grid = torch.cat((xx, yy), 1).float() + + if x.is_cuda: + grid = grid.cuda() + vgrid = grid + flo + + # scale grid to [-1, 1] + vgrid[:, 0, :, :] = 2.0 * vgrid[:, 0, :, :] / max(W - 1, 1) - 1.0 + vgrid[:, 1, :, :] = 2.0 * vgrid[:, 1, :, :] / max(H - 1, 1) - 1.0 + + vgrid = vgrid.permute(0, 2, 3, 1) # B, H, W, 2(compatible with API) + output = nn.functional.grid_sample(x, vgrid) # 按照vgrid将x warp到output张量上 + mask = torch.autograd.Variable(torch.ones(x.size())).cuda() + mask = nn.functional.grid_sample(mask, vgrid) # 这个我觉得没有太大意义,因为warp之后还是1(mask默认全是1) + + mask[mask < 0.9999] = 0 + mask[mask > 0] = 1 # 仍然全是1 + + result = output * mask + return result.view(-1, L, C, H, W) + + +UNKNOWN_FLOW_THRESH = 1e7 + + +def flow_to_image(flow): + """ + Convert flow into middlebury color code image + :param flow: optical flow map + :return: optical flow image in middlebury color + """ + u = flow[:, :, 0] + v = flow[:, :, 1] + + maxu = -999. + maxv = -999. + minu = 999. + minv = 999. + + idxUnknow = (abs(u) > UNKNOWN_FLOW_THRESH) | (abs(v) > UNKNOWN_FLOW_THRESH) + u[idxUnknow] = 0 + v[idxUnknow] = 0 + + maxu = max(maxu, np.max(u)) + minu = min(minu, np.min(u)) + + maxv = max(maxv, np.max(v)) + minv = min(minv, np.min(v)) + + rad = np.sqrt(u ** 2 + v ** 2) + maxrad = max(-1, np.max(rad)) + + u = u / (maxrad + np.finfo(float).eps) + v = v / (maxrad + np.finfo(float).eps) + + img = compute_color(u, v) + + idx = np.repeat(idxUnknow[:, :, np.newaxis], 3, axis=2) + img[idx] = 0 + + return np.uint8(img) + + +def compute_color(u, v): + """ + compute optical flow color map + :param u: optical flow horizontal map + :param v: optical flow vertical map + :return: optical flow in color code + """ + [h, w] = u.shape + img = np.zeros([h, w, 3]) + nanIdx = np.isnan(u) | np.isnan(v) + u[nanIdx] = 0 + v[nanIdx] = 0 + + colorwheel = make_color_wheel() + ncols = np.size(colorwheel, 0) + + rad = np.sqrt(u ** 2 + v ** 2) + + a = np.arctan2(-v, -u) / np.pi + + fk = (a + 1) / 2 * (ncols - 1) + 1 + + k0 = np.floor(fk).astype(int) + + k1 = k0 + 1 + k1[k1 == ncols + 1] = 1 + f = fk - k0 + + for i in range(0, np.size(colorwheel, 1)): + tmp = colorwheel[:, i] + col0 = tmp[k0 - 1] / 255 + col1 = tmp[k1 - 1] / 255 + col = (1 - f) * col0 + f * col1 + + idx = rad <= 1 + col[idx] = 1 - rad[idx] * (1 - col[idx]) + notidx = np.logical_not(idx) + + col[notidx] *= 0.75 + img[:, :, i] = np.uint8(np.floor(255 * col * (1 - nanIdx))) + + return img + + +def make_color_wheel(): + """ + Generate color wheel according Middlebury color code + :return: Color wheel + """ + RY = 15 + YG = 6 + GC = 4 + CB = 11 + BM = 13 + MR = 6 + + ncols = RY + YG + GC + CB + BM + MR + + colorwheel = np.zeros([ncols, 3]) + + col = 0 + + # RY + colorwheel[0:RY, 0] = 255 + colorwheel[0:RY, 1] = np.transpose(np.floor(255 * np.arange(0, RY) / RY)) + col += RY + + # YG + colorwheel[col:col + YG, 0] = 255 - np.transpose(np.floor(255 * np.arange(0, YG) / YG)) + colorwheel[col:col + YG, 1] = 255 + col += YG + + # GC + colorwheel[col:col + GC, 1] = 255 + colorwheel[col:col + GC, 2] = np.transpose(np.floor(255 * np.arange(0, GC) / GC)) + col += GC + + # CB + colorwheel[col:col + CB, 1] = 255 - np.transpose(np.floor(255 * np.arange(0, CB) / CB)) + colorwheel[col:col + CB, 2] = 255 + col += CB + + # BM + colorwheel[col:col + BM, 2] = 255 + colorwheel[col:col + BM, 0] = np.transpose(np.floor(255 * np.arange(0, BM) / BM)) + col += + BM + + # MR + colorwheel[col:col + MR, 2] = 255 - np.transpose(np.floor(255 * np.arange(0, MR) / MR)) + colorwheel[col:col + MR, 0] = 255 + + return colorwheel diff --git a/FGT_codes/FGT/utils/util.py b/FGT_codes/FGT/utils/util.py new file mode 100644 index 0000000000000000000000000000000000000000..e494f1cecb0c872eeffb8b626e26077b5ce621c2 --- /dev/null +++ b/FGT_codes/FGT/utils/util.py @@ -0,0 +1,432 @@ +import os +import sys +import time +import math +import torch.nn.functional as F +from datetime import datetime +import random +import logging +from collections import OrderedDict +import numpy as np +import cv2 +import torch +from torchvision.utils import make_grid +from shutil import get_terminal_size +import torchvision.utils as vutils +from shutil import copyfile +import torchvision.transforms as transforms + +import yaml + +try: + from yaml import CLoader as Loader, CDumper as Dumper +except ImportError: + from yaml import Loader, Dumper + + +def OrderedYaml(): + '''yaml orderedDict support''' + _mapping_tag = yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG + + def dict_representer(dumper, data): + return dumper.represent_dict(data.items()) + + def dict_constructor(loader, node): + return OrderedDict(loader.construct_pairs(node)) + + Dumper.add_representer(OrderedDict, dict_representer) + Loader.add_constructor(_mapping_tag, dict_constructor) + return Loader, Dumper + + +#################### +# miscellaneous +#################### + + +def get_timestamp(): + return datetime.now().strftime('%y%m%d-%H%M%S') + + +def mkdir(path): + if not os.path.exists(path): + os.makedirs(path) + + +def mkdirs(paths): + if isinstance(paths, str): + print('path is : ', paths) + mkdir(paths) + else: + for path in paths: + print('path is : {}'.format(path)) + mkdir(path) + + +def mkdir_and_rename(path): + new_name = None + if os.path.exists(path): + new_name = path + '_archived_' + get_timestamp() + logger = logging.getLogger('base') + logger.info('Path already exists. Rename it to [{:s}]'.format(new_name)) + os.rename(path, new_name) + os.makedirs(path) + return new_name + + +def set_random_seed(seed): + random.seed(seed) + np.random.seed(seed) + torch.manual_seed(seed) + torch.cuda.manual_seed_all(seed) + + +def setup_logger(logger_name, root, phase, level=logging.INFO, screen=False, tofile=False): + '''set up logger''' + lg = logging.getLogger(logger_name) + formatter = logging.Formatter('%(asctime)s.%(msecs)03d - %(levelname)s: %(message)s', + datefmt='%y-%m-%d %H:%M:%S') + lg.setLevel(level) + if tofile: + log_file = os.path.join(root, phase + '_{}.log'.format(get_timestamp())) + fh = logging.FileHandler(log_file, mode='w') + fh.setFormatter(formatter) + lg.addHandler(fh) + if screen: + sh = logging.StreamHandler() + sh.setFormatter(formatter) + lg.addHandler(sh) + + +#################### +# image convert +#################### +def crop_border(img_list, crop_border): + """Crop borders of images + Args: + img_list (list [Numpy]): HWC + crop_border (int): crop border for each end of height and weight + + Returns: + (list [Numpy]): cropped image list + """ + if crop_border == 0: + return img_list + else: + return [v[crop_border:-crop_border, crop_border:-crop_border] for v in img_list] + + +def tensor2img(tensor, out_type=np.uint8, min_max=(0, 1)): + ''' + Converts a torch Tensor into an image Numpy array + Input: 4D(B,(3/1),H,W), 3D(C,H,W), or 2D(H,W), any range, RGB channel order + Output: 3D(H,W,C) or 2D(H,W), [0,255], np.uint8 (default) + ''' + tensor = tensor.squeeze().float().cpu().clamp_(*min_max) # clamp + tensor = (tensor - min_max[0]) / (min_max[1] - min_max[0]) # to range [0,1] + n_dim = tensor.dim() + if n_dim == 4: + n_img = len(tensor) + img_np = make_grid(tensor, nrow=int(math.sqrt(n_img)), normalize=False).numpy() + img_np = np.transpose(img_np[[2, 1, 0], :, :], (1, 2, 0)) # HWC, BGR + elif n_dim == 3: + img_np = tensor.numpy() + img_np = np.transpose(img_np[[2, 1, 0], :, :], (1, 2, 0)) # HWC, BGR + elif n_dim == 2: + img_np = tensor.numpy() + else: + raise TypeError( + 'Only support 4D, 3D and 2D tensor. But received with dimension: {:d}'.format(n_dim)) + if out_type == np.uint8: + img_np = (img_np * 255.0).round() + # Important. Unlike matlab, numpy.unit8() WILL NOT round by default. + return img_np.astype(out_type) + + +def save_img(img, img_path, mode='RGB'): + cv2.imwrite(img_path, img) + + +def DUF_downsample(x, scale=4): + """Downsamping with Gaussian kernel used in the DUF official code + + Args: + x (Tensor, [B, T, C, H, W]): frames to be downsampled. + scale (int): downsampling factor: 2 | 3 | 4. + """ + + assert scale in [2, 3, 4], 'Scale [{}] is not supported'.format(scale) + + def gkern(kernlen=13, nsig=1.6): + import scipy.ndimage.filters as fi + inp = np.zeros((kernlen, kernlen)) + # set element at the middle to one, a dirac delta + inp[kernlen // 2, kernlen // 2] = 1 + # gaussian-smooth the dirac, resulting in a gaussian filter mask + return fi.gaussian_filter(inp, nsig) + + B, T, C, H, W = x.size() + x = x.view(-1, 1, H, W) + pad_w, pad_h = 6 + scale * 2, 6 + scale * 2 # 6 is the pad of the gaussian filter + r_h, r_w = 0, 0 + if scale == 3: + r_h = 3 - (H % 3) + r_w = 3 - (W % 3) + x = F.pad(x, [pad_w, pad_w + r_w, pad_h, pad_h + r_h], 'reflect') + + gaussian_filter = torch.from_numpy(gkern(13, 0.4 * scale)).type_as(x).unsqueeze(0).unsqueeze(0) + x = F.conv2d(x, gaussian_filter, stride=scale) + x = x[:, :, 2:-2, 2:-2] + x = x.view(B, T, C, x.size(2), x.size(3)) + return x + + +def single_forward(model, inp): + """PyTorch model forward (single test), it is just a simple warpper + Args: + model (PyTorch model) + inp (Tensor): inputs defined by the model + + Returns: + output (Tensor): outputs of the model. float, in CPU + """ + with torch.no_grad(): + model_output = model(inp) + if isinstance(model_output, list) or isinstance(model_output, tuple): + output = model_output[0] + else: + output = model_output + output = output.data.float().cpu() + return output + + +def flipx4_forward(model, inp): + """Flip testing with X4 self ensemble, i.e., normal, flip H, flip W, flip H and W + Args: + model (PyTorch model) + inp (Tensor): inputs defined by the model + + Returns: + output (Tensor): outputs of the model. float, in CPU + """ + # normal + output_f = single_forward(model, inp) + + # flip W + output = single_forward(model, torch.flip(inp, (-1,))) + output_f = output_f + torch.flip(output, (-1,)) + # flip H + output = single_forward(model, torch.flip(inp, (-2,))) + output_f = output_f + torch.flip(output, (-2,)) + # flip both H and W + output = single_forward(model, torch.flip(inp, (-2, -1))) + output_f = output_f + torch.flip(output, (-2, -1)) + + return output_f / 4 + + +#################### +# metric +#################### + + +class ProgressBar(object): + '''A progress bar which can print the progress + modified from https://github.com/hellock/cvbase/blob/master/cvbase/progress.py + ''' + + def __init__(self, task_num=0, bar_width=50, start=True): + self.task_num = task_num + max_bar_width = self._get_max_bar_width() + self.bar_width = (bar_width if bar_width <= max_bar_width else max_bar_width) + self.completed = 0 + if start: + self.start() + + def _get_max_bar_width(self): + terminal_width, _ = get_terminal_size() + max_bar_width = min(int(terminal_width * 0.6), terminal_width - 50) + if max_bar_width < 10: + print('terminal width is too small ({}), please consider widen the terminal for better ' + 'progressbar visualization'.format(terminal_width)) + max_bar_width = 10 + return max_bar_width + + def start(self): + if self.task_num > 0: + sys.stdout.write('[{}] 0/{}, elapsed: 0s, ETA:\n{}\n'.format( + ' ' * self.bar_width, self.task_num, 'Start...')) + else: + sys.stdout.write('completed: 0, elapsed: 0s') + sys.stdout.flush() + self.start_time = time.time() + + def update(self, msg='In progress...'): + self.completed += 1 + elapsed = time.time() - self.start_time + fps = self.completed / elapsed + if self.task_num > 0: + percentage = self.completed / float(self.task_num) + eta = int(elapsed * (1 - percentage) / percentage + 0.5) + mark_width = int(self.bar_width * percentage) + bar_chars = '>' * mark_width + '-' * (self.bar_width - mark_width) + sys.stdout.write('\033[2F') # cursor up 2 lines + sys.stdout.write('\033[J') # clean the output (remove extra chars since last display) + sys.stdout.write('[{}] {}/{}, {:.1f} task/s, elapsed: {}s, ETA: {:5}s\n{}\n'.format( + bar_chars, self.completed, self.task_num, fps, int(elapsed + 0.5), eta, msg)) + else: + sys.stdout.write('completed: {}, elapsed: {}s, {:.1f} tasks/s'.format( + self.completed, int(elapsed + 0.5), fps)) + sys.stdout.flush() + + +### communication +def find_free_port(): + import socket + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.bind(("", 0)) + port = sock.getsockname()[1] + sock.close() + return port + + +# for debug +def visualize_image(result, outputDir, epoch, mode, video_name, minData=0): + ### Only visualize one frame + targetDir = os.path.join(outputDir, str(epoch), video_name) + if not os.path.exists(targetDir): + os.makedirs(targetDir) + if minData == -1: + result = (result + 1) / 2 + vutils.save_image(result, os.path.join(targetDir, '{}.png'.format(mode))) + elif minData == 0: + vutils.save_image(result, os.path.join(targetDir, '{}.png'.format(mode))) + else: + raise ValueError('minValue {} is not supported'.format(minData)) + + +def get_learning_rate(optimizer): + lr = [] + for param_group in optimizer.param_groups: + lr += [param_group['lr']] + return lr + + +def adjust_learning_rate(optimizer, target_lr): + for param_group in optimizer.param_groups: + param_group['lr'] = target_lr + + +def save_checkpoint(epoch, model, discriminator, current_step, schedulers, dist_scheduler, optimizers, dist_optimizer, save_path, is_best, monitor, monitor_value, + config): + # for entriely resuming state, you need to save the state dict of model, optimizer and learning scheduler + if isinstance(model, torch.nn.DataParallel) or isinstance(model, torch.nn.parallel.DistributedDataParallel): + model_state = model.module.state_dict() + discriminator_state = discriminator.module.state_dict() + else: + model_state = model.state_dict() + discriminator_state = discriminator.state_dict() + state = { + 'epoch': epoch, + 'iteration': current_step, + 'model_state_dict': model_state, + 'discriminator_state_dict': discriminator_state, + 'optimizer_state_dict': optimizers.state_dict(), + 'dist_optim_state_dict': dist_optimizer.state_dict(), + 'scheduler_state_dict': schedulers.state_dict(), + 'dist_scheduler_state_dict': dist_scheduler.state_dict(), + 'is_best': is_best, + 'config': config, + } + + best_str = '-best-so-far' if is_best else '' + monitor_str = '-{}:{}'.format(monitor, monitor_value) if monitor_value else '' + if not os.path.exists(os.path.join(save_path, 'best')): + os.makedirs(os.path.join(save_path, 'best')) + file_name = os.path.join(save_path, 'checkpoint-epoch:{}{}{}.pth.tar'.format(epoch, monitor_str, best_str)) + torch.save(state, file_name) + if is_best: + copyfile(src=file_name, dst=os.path.join(save_path, 'best', + 'checkpoint-epoch:{}{}{}.pth.tar'.format(epoch, monitor_str, + best_str))) + + +def save_dist_checkpoint(epoch, model, dist, current_step, schedulers, schedulersD, optimizers, optimizersD, save_path, + is_best, monitor, monitor_value, + config): + # for entriely resuming state, you need to save the state dict of model, optimizer and learning scheduler + if isinstance(model, torch.nn.DataParallel) or isinstance(model, torch.nn.parallel.DistributedDataParallel): + model_state = model.module.state_dict() + dist_state = dist.module.state_dict() + else: + model_state = model.state_dict() + dist_state = dist.state_dict() + state = { + 'epoch': epoch, + 'iteration': current_step, + 'model_state_dict': model_state, + 'dist_state_dict': dist_state, + 'optimizer_state_dict': optimizers.state_dict(), + 'optimizerD_state_dict': optimizersD.state_dict(), + 'scheduler_state_dict': schedulers.state_dict(), + 'schedulerD_state_dict': schedulersD.state_dict(), + 'is_best': is_best, + 'config': config + } + + best_str = '-best-so-far' if is_best else '' + monitor_str = '-{}:{}'.format(monitor, monitor_value) if monitor_value else '' + if not os.path.exists(os.path.join(save_path, 'best')): + os.makedirs(os.path.join(save_path, 'best')) + file_name = os.path.join(save_path, 'checkpoint-epoch:{}{}{}.pth.tar'.format(epoch, monitor_str, best_str)) + torch.save(state, file_name) + if is_best: + copyfile(src=file_name, dst=os.path.join(save_path, 'best', + 'checkpoint-epoch:{}{}{}.pth.tar'.format(epoch, monitor_str, + best_str))) + + +def poisson_blend(input, output, mask): + """ + * inputs: + - input (torch.Tensor, required) + Input tensor of Completion Network, whose shape = (N, 3, H, W). + - output (torch.Tensor, required) + Output tensor of Completion Network, whose shape = (N, 3, H, W). + - mask (torch.Tensor, required) + Input mask tensor of Completion Network, whose shape = (N, 1, H, W). + * returns: + Output image tensor of shape (N, 3, H, W) inpainted with poisson image editing method. + from lizuka et al: https://github.com/otenim/GLCIC-PyTorch/blob/caf9bebe667fba0aebbd041918f2d8128f59ec62/utils.py + """ + input = input.clone().cpu() + output = output.clone().cpu() + mask = mask.clone().cpu() + mask = torch.cat((mask, mask, mask), dim=1) # convert to 3-channel format + num_samples = input.shape[0] + ret = [] + for i in range(num_samples): + dstimg = transforms.functional.to_pil_image(input[i]) + dstimg = np.array(dstimg)[:, :, [2, 1, 0]] + srcimg = transforms.functional.to_pil_image(output[i]) + srcimg = np.array(srcimg)[:, :, [2, 1, 0]] + msk = transforms.functional.to_pil_image(mask[i]) + msk = np.array(msk)[:, :, [2, 1, 0]] + # compute mask's center + xs, ys = [], [] + for j in range(msk.shape[0]): + for k in range(msk.shape[1]): + if msk[j, k, 0] == 255: + ys.append(j) + xs.append(k) + xmin, xmax = min(xs), max(xs) + ymin, ymax = min(ys), max(ys) + center = ((xmax + xmin) // 2, (ymax + ymin) // 2) + dstimg = cv2.inpaint(dstimg, msk[:, :, 0], 1, cv2.INPAINT_TELEA) + out = cv2.seamlessClone(srcimg, dstimg, msk, center, cv2.NORMAL_CLONE) + out = out[:, :, [2, 1, 0]] + out = transforms.functional.to_tensor(out) + out = torch.unsqueeze(out, dim=0) + ret.append(out) + ret = torch.cat(ret, dim=0) + return ret diff --git a/FGT_codes/LAFC/checkpoint/config.yaml b/FGT_codes/LAFC/checkpoint/config.yaml new file mode 100644 index 0000000000000000000000000000000000000000..aecd1affca6a842d861f269278412f2a0d181d2c --- /dev/null +++ b/FGT_codes/LAFC/checkpoint/config.yaml @@ -0,0 +1,11 @@ +PASSMASK: 1 +cnum: 48 +conv_type: vanilla +flow_interval: 3 +in_channel: 3 +init_weights: 1 +num_flows: 3 +resBlocks: 1 +use_bias: 1 +use_residual: 1 +model: lafc \ No newline at end of file diff --git a/FGT_codes/LAFC/checkpoint/lafc.pth.tar b/FGT_codes/LAFC/checkpoint/lafc.pth.tar new file mode 100644 index 0000000000000000000000000000000000000000..f08213937d943a661be3a913603555d7615d5e4a --- /dev/null +++ b/FGT_codes/LAFC/checkpoint/lafc.pth.tar @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:71d502d6bcd877f46cc08c4f2f80c48c95759c523de022f90295533125bcd65f +size 12360405 diff --git a/FGT_codes/LAFC/config/data_info.yaml b/FGT_codes/LAFC/config/data_info.yaml new file mode 100644 index 0000000000000000000000000000000000000000..4cb80a383d17693a361fe93df465968d0da076c1 --- /dev/null +++ b/FGT_codes/LAFC/config/data_info.yaml @@ -0,0 +1,16 @@ +# dataset general info +flow_path: youtubevos_flows +frame_path: youtubevos_frames +name2len: config/youtubevos_name2len.pkl + +flow: + flow_height: 256 + flow_width: 256 + augments: False + colors: RGB + ext: .jpg + +edge: + sigma: 1 + low_threshold: 0.1 + high_threshold: 0.2 diff --git a/FGT_codes/LAFC/config/davis_name2len.pkl b/FGT_codes/LAFC/config/davis_name2len.pkl new file mode 100644 index 0000000000000000000000000000000000000000..2de0cbcd34dcf437851566f4aea51fd2bc4a7fe9 --- /dev/null +++ b/FGT_codes/LAFC/config/davis_name2len.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6607939cc02910f5badaebff46242f299597e93c07d77b6d740a3004f179f50c +size 1621 diff --git a/FGT_codes/LAFC/config/davis_name2len_train.pkl b/FGT_codes/LAFC/config/davis_name2len_train.pkl new file mode 100644 index 0000000000000000000000000000000000000000..e5f588d776f661fec1e3342c3815f5b986120951 --- /dev/null +++ b/FGT_codes/LAFC/config/davis_name2len_train.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1ad5e89d5486b38f74ac62d08924a4ff7caa445d34df827385457e8516d4763f +size 1073 diff --git a/FGT_codes/LAFC/config/davis_name2len_val.pkl b/FGT_codes/LAFC/config/davis_name2len_val.pkl new file mode 100644 index 0000000000000000000000000000000000000000..aea02ea711362cbe33ab21389211ecfe7c69eddc --- /dev/null +++ b/FGT_codes/LAFC/config/davis_name2len_val.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:30b2a23f943f40f2a09e98b474b88b07271e46a1224cb415650432d491cc1896 +size 188 diff --git a/FGT_codes/LAFC/config/train.yaml b/FGT_codes/LAFC/config/train.yaml new file mode 100644 index 0000000000000000000000000000000000000000..e0f5c11c2bcbdebea5a830fbe082ec85c9d312b2 --- /dev/null +++ b/FGT_codes/LAFC/config/train.yaml @@ -0,0 +1,74 @@ +### General settings +name: LAFC_train +use_tb_logger: True +outputdir: /myData/ret/experiments/ +datadir: /myData/ +record_iter: 16 + +### Calling definition +model: lafc +datasetName_train: train_dataset_edge +network: network + +### Datasets +datasets: + train: + name: youtubevos + type: video + mode: train + dataInfo_config: ./config/data_info.yaml + use_shuffle: True + n_workers: 0 + batch_size: 4 + + val: + name: youtubevos + type: video + mode: val + use_shuffle: False + n_workers: 1 + batch_size: 1 + val_config: ./config/valid_config.yaml + +### train settings +train: + lr: 0.0001 + lr_decay: 0.1 + manual_seed: 10 + BETA1: 0.9 + BETA2: 0.999 + MAX_ITERS: 280000 + UPDATE_INTERVAL: 120000 + WARMUP: ~ + val_freq: 1 # epoch为~M~U~M, set to 1 is for debug + +### logger +logger: + PRINT_FREQ: 16 + SAVE_CHECKPOINT_FREQ: 1 # 100 is for debug consideration + +### Data related parameters +num_flows: 3 +flow_interval: 3 +sample: seq +use_edges: 0 + +### Model related parameters +PASSMASK: 1 +use_bias: 1 +init_weights: 1 +cnum: 48 +resBlocks: 1 +edge_residuals: 4 +conv_type: vanilla +in_channel: 3 +use_residual: 1 +gc: 0 +rescale: 1 + +### Loss weights +L1M: 1 +sm: 1 +sm2: 1 +edge_loss: 1 +ternary: 0.01 diff --git a/FGT_codes/LAFC/config/train_single.yaml b/FGT_codes/LAFC/config/train_single.yaml new file mode 100644 index 0000000000000000000000000000000000000000..1a6a3682eae43f413a4568a0e4025f157c29de03 --- /dev/null +++ b/FGT_codes/LAFC/config/train_single.yaml @@ -0,0 +1,74 @@ +### General settings +name: LAFC_single +use_tb_logger: True +outputdir: /myData/ret/experiments/ +datadir: /myData/ +record_iter: 16 + +### Calling definition +model: lafc_single +datasetName_train: train_dataset_single_edge +network: network + +### Datasets +datasets: + train: + name: youtubevos + type: video + mode: train + dataInfo_config: ./config/data_info.yaml + use_shuffle: True + n_workers: 0 + batch_size: 4 + + val: + name: youtubevos + type: video + mode: val + use_shuffle: False + n_workers: 1 + batch_size: 1 + val_config: ./config/valid_config.yaml + +### train settings +train: + lr: 0.0001 + lr_decay: 0.1 + manual_seed: 10 + BETA1: 0.9 + BETA2: 0.999 + MAX_ITERS: 280000 + UPDATE_INTERVAL: 120000 + WARMUP: ~ + val_freq: 1 # epoch为~M~U~M, set to 1 is for debug + +### logger +logger: + PRINT_FREQ: 16 + SAVE_CHECKPOINT_FREQ: 1 # 100 is for debug consideration + +### Data related parameters +num_flows: 1 +flow_interval: 1 +sample: seq +use_edges: 0 + +### Model related parameters +PASSMASK: 1 +use_bias: 1 +init_weights: 1 +cnum: 48 +resBlocks: 1 +edge_residuals: 4 +conv_type: vanilla +in_channel: 3 +use_residual: 1 +gc: 0 +rescale: 1 + +### Loss weights +L1M: 1 +sm: 1 +sm2: 1 +edge_loss: 1 +ternary: 0.01 diff --git a/FGT_codes/LAFC/config/valid_config.yaml b/FGT_codes/LAFC/config/valid_config.yaml new file mode 100644 index 0000000000000000000000000000000000000000..ca2445ccd0a75e6413a787635748bbf769de3a5b --- /dev/null +++ b/FGT_codes/LAFC/config/valid_config.yaml @@ -0,0 +1,7 @@ +flow_height: 256 +flow_width: 432 +data_root: davis_valid_flows +mask_root: rectMask_96 +frame_root: JPEGImages/480p +batch_size: 1 +name2len: config/davis_name2len_val.pkl diff --git a/FGT_codes/LAFC/config/youtubevos_name2len.pkl b/FGT_codes/LAFC/config/youtubevos_name2len.pkl new file mode 100644 index 0000000000000000000000000000000000000000..6b65a72c30037e03a772692e9597ed3beaf934ca --- /dev/null +++ b/FGT_codes/LAFC/config/youtubevos_name2len.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:60410308d4a0e780a531290d8bddc7f204bc0e8a500eab7c01c563b8efce9753 +size 75501 diff --git a/FGT_codes/LAFC/data/__init__.py b/FGT_codes/LAFC/data/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..53a0ac88410c95930e2019dbbb2fcb5057eea12d --- /dev/null +++ b/FGT_codes/LAFC/data/__init__.py @@ -0,0 +1,49 @@ +import logging +import torch +import torch.utils.data +from importlib import import_module + + +def create_dataloader(phase, dataset, dataset_opt, opt=None, sampler=None): + logger = logging.getLogger('base') + if phase == 'train': + num_workers = dataset_opt['n_workers'] * opt['world_size'] + batch_size = dataset_opt['batch_size'] + if sampler is not None: + logger.info('N_workers: {}, batch_size: {} DDP train dataloader has been established'.format(num_workers, + batch_size)) + return torch.utils.data.DataLoader(dataset, batch_size=batch_size, + num_workers=num_workers, sampler=sampler, + pin_memory=True) + else: + logger.info('N_workers: {}, batch_size: {} train dataloader has been established'.format(num_workers, + batch_size)) + return torch.utils.data.DataLoader(dataset, batch_size=batch_size, + num_workers=num_workers, shuffle=True, + pin_memory=True) + + else: + logger.info( + 'N_workers: {}, batch_size: {} validate/test dataloader has been established'.format( + dataset_opt['n_workers'], + dataset_opt['batch_size'])) + return torch.utils.data.DataLoader(dataset, batch_size=dataset_opt['batch_size'], shuffle=False, + num_workers=dataset_opt['n_workers'], + pin_memory=False) + + +def create_dataset(dataset_opt, dataInfo, phase, dataset_name): + if phase == 'train': + dataset_package = import_module('data.{}'.format(dataset_name)) + dataset = dataset_package.VideoBasedDataset(dataset_opt, dataInfo) + + mode = dataset_opt['mode'] + logger = logging.getLogger('base') + logger.info( + '{} train dataset [{:s} - {:s} - {:s}] is created.'.format(dataset_opt['type'].upper(), + dataset.__class__.__name__, + dataset_opt['name'], mode)) + else: # validate and test dataset + return ValueError('No dataset initialized for valdataset') + + return dataset diff --git a/FGT_codes/LAFC/data/train_dataset_edge.py b/FGT_codes/LAFC/data/train_dataset_edge.py new file mode 100644 index 0000000000000000000000000000000000000000..465e316bb5b7df105d0240401ce1ce4d8b9b9fe6 --- /dev/null +++ b/FGT_codes/LAFC/data/train_dataset_edge.py @@ -0,0 +1,174 @@ +import random + +import pickle +import logging +import torch +import cv2 +import os + +from torch.utils.data.dataset import Dataset +import numpy as np +from skimage.feature import canny +from .util.STTN_mask import create_random_shape_with_random_motion +from cvbase import read_flow, flow2rgb +from .util.flow_utils import region_fill as rf +import imageio + +logger = logging.getLogger('base') + + +class VideoBasedDataset(Dataset): + def __init__(self, opt, dataInfo): + self.opt = opt + self.mode = opt['mode'] + self.sampleMethod = opt['sample'] + self.dataInfo = dataInfo + self.flow_height, self.flow_width = dataInfo['flow']['flow_height'], dataInfo['flow']['flow_width'] + self.data_path = dataInfo['flow_path'] + self.frame_path = dataInfo['frame_path'] + self.train_list = os.listdir(self.data_path) + self.name2length = self.dataInfo['name2len'] + self.require_edge = opt['use_edges'] + self.sigma = dataInfo['edge']['sigma'] + self.low_threshold = dataInfo['edge']['low_threshold'] + self.high_threshold = dataInfo['edge']['high_threshold'] + with open(self.name2length, 'rb') as f: + self.name2len = pickle.load(f) + self.norm = opt['norm'] + self.sequenceLen = self.opt['num_flows'] + self.flow_interval = self.opt['flow_interval'] + self.halfLen = self.sequenceLen // 2 + + def __len__(self): + return len(self.train_list) + + def __getitem__(self, idx): + try: + item = self.load_item(idx) + except: + print('Loading error: ' + self.train_list[idx]) + item = self.load_item(0) + return item + + def frameSample(self, flowLen): + if self.sampleMethod == 'random': + indices = [i for i in range(flowLen)] + sampledIndices = random.sample(indices, self.sequenceLen) + else: + sampledIndices = [] + pivot = random.randint(0, flowLen - 1) + for i in range(-self.halfLen, self.halfLen + 1): + index = pivot + i * self.flow_interval + if index < 0: + index = 0 + if index >= flowLen: + index = flowLen - 1 + sampledIndices.append(index) + return sampledIndices + + def load_item(self, idx): + info = {} + video = self.train_list[idx] + info['name'] = video + if np.random.uniform(0, 1) > 0.5: + direction = 'forward_flo' + else: + direction = 'backward_flo' + flow_dir = os.path.join(self.data_path, video, direction) + frame_dir = os.path.join(self.frame_path, video) + flowLen = self.name2len[video] - 1 + assert flowLen > self.sequenceLen, 'Flow length {} is not enough'.format(flowLen) + sampledIndices = self.frameSample(flowLen) + candidateMasks = create_random_shape_with_random_motion(self.sequenceLen, 0.9, 1.1, 1, + 10) + flows, diffused_flows, masks = [], [], [] + current_frames, shift_frames = None, None + mask_counter = 0 + for i in sampledIndices: + flow = read_flow(os.path.join(flow_dir, '{:05d}.flo'.format(i))) + mask = self.read_mask(candidateMasks[mask_counter], self.flow_height, self.flow_width) + mask_counter += 1 + flow = self.flow_tf(flow, self.flow_height, self.flow_width) + diffused_flow = self.diffusion_fill(flow, mask) + flows.append(flow) + masks.append(mask) + diffused_flows.append(diffused_flow) + targetIndex = sampledIndices[self.sequenceLen // 2] + current_frames, shift_frames = self.read_frames(frame_dir, targetIndex, direction, self.flow_width, + self.flow_height) + flow_gray, edge = self.load_edge(flows[self.halfLen]) + inputs = {'flows': flows, 'diffused_flows': diffused_flows, 'current_frame': current_frames, + 'shift_frame': shift_frames, 'edges': edge, 'masks': masks, 'flow_gray': flow_gray} + return self.to_tensor(inputs) + + def read_frames(self, frame_dir, index, direction, width, height): + if direction == 'forward_flo': + current_frame = os.path.join(frame_dir, '{:05d}.jpg'.format(index)) + shift_frame = os.path.join(frame_dir, '{:05d}.jpg'.format(index + 1)) + else: + current_frame = os.path.join(frame_dir, '{:05d}.jpg'.format(index + 1)) + shift_frame = os.path.join(frame_dir, '{:05d}.jpg'.format(index)) + current_frame = imageio.imread(current_frame) + shift_frame = imageio.imread(shift_frame) + current_frame = cv2.resize(current_frame, (width, height), cv2.INTER_LINEAR) + shift_frame = cv2.resize(shift_frame, (width, height), cv2.INTER_LINEAR) + current_frame = current_frame / 255. + shift_frame = shift_frame / 255. + return current_frame, shift_frame + + def diffusion_fill(self, flow, mask): + flow_filled = np.zeros(flow.shape) + flow_filled[:, :, 0] = rf.regionfill(flow[:, :, 0] * (1 - mask), mask) + flow_filled[:, :, 1] = rf.regionfill(flow[:, :, 1] * (1 - mask), mask) + return flow_filled + + def flow_tf(self, flow, height, width): + flow_shape = flow.shape + flow_resized = cv2.resize(flow, (width, height), cv2.INTER_LINEAR) + flow_resized[:, :, 0] *= (float(width) / float(flow_shape[1])) + flow_resized[:, :, 1] *= (float(height) / float(flow_shape[0])) + return flow_resized + + def read_mask(self, mask, height, width): + mask = np.array(mask) + mask = mask / 255. + raw_mask = (mask > 0.5).astype(np.uint8) + raw_mask = cv2.resize(raw_mask, dsize=(width, height), interpolation=cv2.INTER_NEAREST) + return raw_mask + + def load_edge(self, flow): + gray_flow = (flow[:, :, 0] ** 2 + flow[:, :, 1] ** 2) ** 0.5 + factor = gray_flow.max() + gray_flow = gray_flow / factor + flow_rgb = flow2rgb(flow) + flow_gray = cv2.cvtColor(flow_rgb, cv2.COLOR_RGB2GRAY) + return gray_flow, canny(flow_gray, sigma=self.sigma, mask=None, low_threshold=self.low_threshold, + high_threshold=self.high_threshold).astype(np.float) + + def to_tensor(self, data_list): + """ + + Args: + data_list: a numpy.array list + + Returns: a torch.tensor list with the None entries removed + + """ + keys = list(data_list.keys()) + for key in keys: + if data_list[key] is None or data_list[key] == []: + data_list.pop(key) + else: + item = data_list[key] + if not isinstance(item, list): + if len(item.shape) == 2: + item = item[:, :, np.newaxis] + item = torch.from_numpy(np.transpose(item, (2, 0, 1))).float() + else: + item = np.stack(item, axis=0) + if len(item.shape) == 3: + item = item[:, :, :, np.newaxis] + item = torch.from_numpy(np.transpose(item, (3, 0, 1, 2))).float() + data_list[key] = item + return data_list + diff --git a/FGT_codes/LAFC/data/train_dataset_single_edge.py b/FGT_codes/LAFC/data/train_dataset_single_edge.py new file mode 100644 index 0000000000000000000000000000000000000000..37674ff0e00be8911568fb96fba108f2c43b6500 --- /dev/null +++ b/FGT_codes/LAFC/data/train_dataset_single_edge.py @@ -0,0 +1,151 @@ +import random + +import pickle +import logging +import torch +import cv2 +import os + +from torch.utils.data.dataset import Dataset +import numpy as np +from skimage.feature import canny +from .util.STTN_mask import create_random_shape_with_random_motion +from cvbase import read_flow, flow2rgb +from .util.flow_utils import region_fill as rf +import imageio + +logger = logging.getLogger('base') + + +class VideoBasedDataset(Dataset): + def __init__(self, opt, dataInfo): + self.opt = opt + self.mode = opt['mode'] + self.dataInfo = dataInfo + self.flow_height, self.flow_width = dataInfo['flow']['flow_height'], dataInfo['flow']['flow_width'] + self.data_path = dataInfo['flow_path'] + self.frame_path = dataInfo['frame_path'] + self.train_list = os.listdir(self.data_path) + self.name2length = self.dataInfo['name2len'] + self.require_edge = opt['use_edges'] + self.sigma = dataInfo['edge']['sigma'] + self.low_threshold = dataInfo['edge']['low_threshold'] + self.high_threshold = dataInfo['edge']['high_threshold'] + with open(self.name2length, 'rb') as f: + self.name2len = pickle.load(f) + self.norm = opt['norm'] + self.ternary_loss = opt.get('ternary', 0) + + def __len__(self): + return len(self.train_list) + + def __getitem__(self, idx): + try: + item = self.load_item(idx) + except: + print('Loading error: ' + self.train_list[idx]) + item = self.load_item(0) + return item + + def frameSample(self, flowLen): + pivot = random.randint(0, flowLen - 1) + return pivot + + def load_item(self, idx): + info = {} + video = self.train_list[idx] + info['name'] = video + if np.random.uniform(0, 1) > 0.5: + direction = 'forward_flo' + else: + direction = 'backward_flo' + flow_dir = os.path.join(self.data_path, video, direction) + frame_dir = os.path.join(self.frame_path, video) + flowLen = self.name2len[video] - 1 + pivot = self.frameSample(flowLen) + # generate random masks + candidateMasks = create_random_shape_with_random_motion(1, 0.9, 1.1, 1, + 10) + # read the flows and masks + flow = read_flow(os.path.join(flow_dir, '{:05d}.flo'.format(pivot))) + mask = self.read_mask(candidateMasks[0], self.flow_height, self.flow_width) + flow = self.flow_tf(flow, self.flow_height, self.flow_width) + diffused_flow = self.diffusion_fill(flow, mask) + current_frame, shift_frame = self.read_frames(frame_dir, pivot, direction, self.flow_width, + self.flow_height) + edge = self.load_edge(flow) + inputs = {'flows': flow, 'diffused_flows': diffused_flow, 'current_frame': current_frame, + 'shift_frame': shift_frame, 'edges': edge, 'masks': mask} + return self.to_tensor(inputs) + + def read_frames(self, frame_dir, index, direction, width, height): + if direction == 'forward_flo': + current_frame = os.path.join(frame_dir, '{:05d}.jpg'.format(index)) + shift_frame = os.path.join(frame_dir, '{:05d}.jpg'.format(index + 1)) + else: + current_frame = os.path.join(frame_dir, '{:05d}.jpg'.format(index + 1)) + shift_frame = os.path.join(frame_dir, '{:05d}.jpg'.format(index)) + current_frame = imageio.imread(current_frame) + shift_frame = imageio.imread(shift_frame) + current_frame = cv2.resize(current_frame, (width, height), cv2.INTER_LINEAR) + shift_frame = cv2.resize(shift_frame, (width, height), cv2.INTER_LINEAR) + current_frame = current_frame / 255. + shift_frame = shift_frame / 255. + return current_frame, shift_frame + + def diffusion_fill(self, flow, mask): + flow_filled = np.zeros(flow.shape) + flow_filled[:, :, 0] = rf.regionfill(flow[:, :, 0] * (1 - mask), mask) + flow_filled[:, :, 1] = rf.regionfill(flow[:, :, 1] * (1 - mask), mask) + return flow_filled + + def flow_tf(self, flow, height, width): + flow_shape = flow.shape + flow_resized = cv2.resize(flow, (width, height), cv2.INTER_LINEAR) + flow_resized[:, :, 0] *= (float(width) / float(flow_shape[1])) + flow_resized[:, :, 1] *= (float(height) / float(flow_shape[0])) + return flow_resized + + def read_mask(self, mask, height, width): + mask = np.array(mask) + mask = mask / 255. + raw_mask = (mask > 0.5).astype(np.uint8) + raw_mask = cv2.resize(raw_mask, dsize=(width, height), interpolation=cv2.INTER_NEAREST) + return raw_mask + + def load_edge(self, flow): + gray_flow = (flow[:, :, 0] ** 2 + flow[:, :, 1] ** 2) ** 0.5 + factor = gray_flow.max() + gray_flow = gray_flow / factor + flow_rgb = flow2rgb(flow) + flow_gray = cv2.cvtColor(flow_rgb, cv2.COLOR_RGB2GRAY) + return canny(flow_gray, sigma=self.sigma, mask=None, low_threshold=self.low_threshold, + high_threshold=self.high_threshold).astype(np.float) + + def to_tensor(self, data_list): + """ + + Args: + data_list: a numpy.array list + + Returns: a torch.tensor list with the None entries removed + + """ + keys = list(data_list.keys()) + for key in keys: + if data_list[key] is None or data_list[key] == []: + data_list.pop(key) + else: + item = data_list[key] + if not isinstance(item, list): + if len(item.shape) == 2: + item = item[:, :, np.newaxis] + item = torch.from_numpy(np.transpose(item, (2, 0, 1))).float() + else: + item = np.stack(item, axis=0) + if len(item.shape) == 3: + item = item[:, :, :, np.newaxis] + item = torch.from_numpy(np.transpose(item, (3, 0, 1, 2))).float() + data_list[key] = item + return data_list + diff --git a/FGT_codes/LAFC/data/util/MaskModel.py b/FGT_codes/LAFC/data/util/MaskModel.py new file mode 100644 index 0000000000000000000000000000000000000000..9cca4f962889e9b3fd30d0f92f19c8b3104bfd3a --- /dev/null +++ b/FGT_codes/LAFC/data/util/MaskModel.py @@ -0,0 +1,123 @@ +import random +import numpy as np + +class RandomMask(): + def __init__(self, videoLength, dataInfo): + self.videoLength = videoLength + self.imageHeight, self.imageWidth = dataInfo['image']['image_height'], \ + dataInfo['image']['image_width'] + self.maskHeight, self.maskWidth = dataInfo['mask']['mask_height'], \ + dataInfo['mask']['mask_width'] + try: + self.maxDeltaHeight, self.maxDeltaWidth = dataInfo['mask']['max_delta_height'], \ + dataInfo['mask']['max_delta_width'] + except KeyError: + self.maxDeltaHeight, self.maxDeltaWidth = 0, 0 + + try: + self.verticalMargin, self.horizontalMargin = dataInfo['mask']['vertical_margin'], \ + dataInfo['mask']['horizontal_margin'] + except KeyError: + self.verticalMargin, self.horizontalMargin = 0, 0 + + def __call__(self): + from .utils import random_bbox + from .utils import bbox2mask + masks = [] + bbox = random_bbox(self.imageHeight, self.imageWidth, self.verticalMargin, self.horizontalMargin, + self.maskHeight, self.maskWidth) + if random.uniform(0, 1) > 0.5: + mask = bbox2mask(self.imageHeight, self.imageWidth, 0, 0, bbox) + for frame in range(self.videoLength): + masks.append(mask) + else: + for frame in range(self.videoLength): + delta_h, delta_w = random.randint(-3, 3), random.randint(-3, 3) # 每次向四个方向移动三个像素以内 + bbox = list(bbox) + bbox[0] = min(max(self.verticalMargin, bbox[0] + delta_h), self.imageHeight - self.verticalMargin - bbox[2]) + bbox[1] = min(max(self.horizontalMargin, bbox[1] + delta_w), self.imageWidth - self.horizontalMargin - bbox[3]) + mask = bbox2mask(self.imageHeight, self.imageWidth, 0, 0, bbox) + masks.append(mask) + masks = np.stack(masks, axis=0) + if len(masks.shape) == 3: + masks = masks[:, :, :, np.newaxis] + assert len(masks.shape) == 4, 'Wrong mask dimension {}'.format(len(masks.shape)) + return masks + + +class MidRandomMask(): + ### This mask is considered without random motion + def __init__(self, videoLength, dataInfo): + self.videoLength = videoLength + self.imageHeight, self.imageWidth = dataInfo['image']['image_height'], \ + dataInfo['image']['image_width'] + self.maskHeight, self.maskWidth = dataInfo['mask']['mask_height'], \ + dataInfo['mask']['mask_width'] + + def __call__(self): + from .utils import mid_bbox_mask + mask = mid_bbox_mask(self.imageHeight, self.imageWidth, self.maskHeight, self.maskWidth) + masks = [] + for _ in range(self.videoLength): + masks.append(mask) + return mask + + +class MatrixMask(): + ### This mask is considered without random motion + def __init__(self, videoLength, dataInfo): + self.videoLength = videoLength + self.imageHeight, self.imageWidth = dataInfo['image']['image_height'], \ + dataInfo['image']['image_width'] + self.maskHeight, self.maskWidth = dataInfo['mask']['mask_height'], \ + dataInfo['mask']['mask_width'] + try: + self.row, self.column = dataInfo['mask']['row'], \ + dataInfo['mask']['column'] + except KeyError: + self.row, self.column = 5, 4 + + def __call__(self): + from .utils import matrix2bbox + mask = matrix2bbox(self.imageHeight, self.imageWidth, self.maskHeight, + self.maskWidth, self.row, self.column) + masks = [] + for video in range(self.videoLength): + masks.append(mask) + return mask + + +class FreeFormMask(): + def __init__(self, videoLength, dataInfo): + self.videoLength = videoLength + self.imageHeight, self.imageWidth = dataInfo['image']['image_height'], \ + dataInfo['image']['image_width'] + self.maxVertex = dataInfo['mask']['max_vertex'] + self.maxLength = dataInfo['mask']['max_length'] + self.maxBrushWidth = dataInfo['mask']['max_brush_width'] + self.maxAngle = dataInfo['mask']['max_angle'] + + def __call__(self): + from .utils import freeFormMask + mask = freeFormMask(self.imageHeight, self.imageWidth, + self.maxVertex, self.maxLength, + self.maxBrushWidth, self.maxAngle) + return mask + + +class StationaryMask(): + def __init__(self, videoLength, dataInfo): + self.videoLength = videoLength + self.imageHeight, self.imageWidth = dataInfo['image']['image_height'], \ + dataInfo['image']['image_width'] + # self.maxPointNum = dataInfo['mask']['max_point_num'] + # self.maxLength = dataInfo['mask']['max_length'] + + def __call__(self): + from .STTN_mask import create_random_shape_with_random_motion + masks = create_random_shape_with_random_motion(self.videoLength, 0.9, 1.1, 1, 10, self.imageHeight, self.imageWidth) + masks = np.stack(masks, axis=0) + if len(masks.shape) == 3: + masks = masks[:, :, :, np.newaxis] + assert len(masks.shape) == 4, 'Your masks with a wrong shape {}'.format(len(masks.shape)) + return masks \ No newline at end of file diff --git a/FGT_codes/LAFC/data/util/STTN_mask.py b/FGT_codes/LAFC/data/util/STTN_mask.py new file mode 100644 index 0000000000000000000000000000000000000000..f7ee67e6eb3eb9a5ace90d92120dd9b018091e3f --- /dev/null +++ b/FGT_codes/LAFC/data/util/STTN_mask.py @@ -0,0 +1,244 @@ +import matplotlib.patches as patches +from matplotlib.path import Path +import os +import sys +import io +import cv2 +import time +import math +import argparse +import shutil +import random +import zipfile +from glob import glob +import math +import numpy as np +import torch.nn.functional as F +import torchvision.transforms as transforms +from PIL import Image, ImageOps, ImageDraw, ImageFilter + +import torch +import torchvision +import torch.nn as nn +import torch.distributed as dist + +import matplotlib +from matplotlib import pyplot as plt +matplotlib.use('agg') + + +class GroupRandomHorizontalFlip(object): + """Randomly horizontally flips the given PIL.Image with a probability of 0.5 + """ + + def __init__(self, is_flow=False): + self.is_flow = is_flow + + def __call__(self, img_group, is_flow=False): + v = random.random() + if v < 0.5: + ret = [img.transpose(Image.FLIP_LEFT_RIGHT) for img in img_group] + if self.is_flow: + for i in range(0, len(ret), 2): + # invert flow pixel values when flipping + ret[i] = ImageOps.invert(ret[i]) + return ret + else: + return img_group + + +class Stack(object): + def __init__(self, roll=False): + self.roll = roll + + def __call__(self, img_group): + mode = img_group[0].mode + if mode == '1': + img_group = [img.convert('L') for img in img_group] + mode = 'L' + if mode == 'L': + return np.stack([np.expand_dims(x, 2) for x in img_group], axis=2) + elif mode == 'RGB': + if self.roll: + return np.stack([np.array(x)[:, :, ::-1] for x in img_group], axis=2) + else: + return np.stack(img_group, axis=2) + else: + raise NotImplementedError("Image mode {}".format(mode)) + + +class ToTorchFormatTensor(object): + """ Converts a PIL.Image (RGB) or numpy.ndarray (H x W x C) in the range [0, 255] + to a torch.FloatTensor of shape (C x H x W) in the range [0.0, 1.0] """ + + def __init__(self, div=True): + self.div = div + + def __call__(self, pic): + if isinstance(pic, np.ndarray): + # numpy img: [L, C, H, W] + img = torch.from_numpy(pic).permute(2, 3, 0, 1).contiguous() + else: + # handle PIL Image + img = torch.ByteTensor( + torch.ByteStorage.from_buffer(pic.tobytes())) + img = img.view(pic.size[1], pic.size[0], len(pic.mode)) + # put it from HWC to CHW format + # yikes, this transpose takes 80% of the loading time/CPU + img = img.transpose(0, 1).transpose(0, 2).contiguous() + img = img.float().div(255) if self.div else img.float() + return img + + +# ########################################## +# ########################################## + +def create_random_shape_with_random_motion(video_length, zoomin, zoomout, rotmin, rotmax, imageHeight=240, imageWidth=432): + # get a random shape + assert zoomin < 1, "Zoom-in parameter must be smaller than 1" + assert zoomout > 1, "Zoom-out parameter must be larger than 1" + assert rotmin < rotmax, "Minimum value of rotation must be smaller than maximun value !" + height = random.randint(imageHeight//3, imageHeight-1) + width = random.randint(imageWidth//3, imageWidth-1) + edge_num = random.randint(6, 8) + ratio = random.randint(6, 8)/10 + region = get_random_shape( + edge_num=edge_num, ratio=ratio, height=height, width=width) + region_width, region_height = region.size + # get random position + x, y = random.randint( + 0, imageHeight-region_height), random.randint(0, imageWidth-region_width) + velocity = get_random_velocity(max_speed=3) + m = Image.fromarray(np.zeros((imageHeight, imageWidth)).astype(np.uint8)) + m.paste(region, (y, x, y+region.size[0], x+region.size[1])) + masks = [m.convert('L')] + # return fixed masks + if random.uniform(0, 1) > 0.5: + return masks*video_length # -> directly copy all the base masks + # return moving masks + for _ in range(video_length-1): + x, y, velocity = random_move_control_points( + x, y, imageHeight, imageWidth, velocity, region.size, maxLineAcceleration=(3, 0.5), maxInitSpeed=3) + m = Image.fromarray( + np.zeros((imageHeight, imageWidth)).astype(np.uint8)) + ### add by kaidong, to simulate zoon-in, zoom-out and rotation + extra_transform = random.uniform(0, 1) + # zoom in and zoom out + if extra_transform > 0.75: + resize_coefficient = random.uniform(zoomin, zoomout) + region = region.resize((math.ceil(region_width * resize_coefficient), math.ceil(region_height * resize_coefficient)), Image.NEAREST) + m.paste(region, (y, x, y + region.size[0], x + region.size[1])) + region_width, region_height = region.size + # rotation + elif extra_transform > 0.5: + m.paste(region, (y, x, y + region.size[0], x + region.size[1])) + m = m.rotate(random.randint(rotmin, rotmax)) + # region_width, region_height = region.size + ### end + else: + m.paste(region, (y, x, y+region.size[0], x+region.size[1])) + masks.append(m.convert('L')) + return masks + + +def get_random_shape(edge_num=9, ratio=0.7, width=432, height=240): + ''' + There is the initial point and 3 points per cubic bezier curve. + Thus, the curve will only pass though n points, which will be the sharp edges. + The other 2 modify the shape of the bezier curve. + edge_num, Number of possibly sharp edges + points_num, number of points in the Path + ratio, (0, 1) magnitude of the perturbation from the unit circle, + ''' + points_num = edge_num*3 + 1 + angles = np.linspace(0, 2*np.pi, points_num) + codes = np.full(points_num, Path.CURVE4) + codes[0] = Path.MOVETO + # Using this instad of Path.CLOSEPOLY avoids an innecessary straight line + verts = np.stack((np.cos(angles), np.sin(angles))).T * \ + (2*ratio*np.random.random(points_num)+1-ratio)[:, None] + verts[-1, :] = verts[0, :] + path = Path(verts, codes) + # draw paths into images + fig = plt.figure() + ax = fig.add_subplot(111) + patch = patches.PathPatch(path, facecolor='black', lw=2) + ax.add_patch(patch) + ax.set_xlim(np.min(verts)*1.1, np.max(verts)*1.1) + ax.set_ylim(np.min(verts)*1.1, np.max(verts)*1.1) + ax.axis('off') # removes the axis to leave only the shape + fig.canvas.draw() + # convert plt images into numpy images + data = np.frombuffer(fig.canvas.tostring_rgb(), dtype=np.uint8) + data = data.reshape((fig.canvas.get_width_height()[::-1] + (3,))) + plt.close(fig) + # postprocess + data = cv2.resize(data, (width, height))[:, :, 0] + data = (1 - np.array(data > 0).astype(np.uint8))*255 + corrdinates = np.where(data > 0) + xmin, xmax, ymin, ymax = np.min(corrdinates[0]), np.max( + corrdinates[0]), np.min(corrdinates[1]), np.max(corrdinates[1]) + region = Image.fromarray(data).crop((ymin, xmin, ymax, xmax)) + return region + + +def random_accelerate(velocity, maxAcceleration, dist='uniform'): + speed, angle = velocity + d_speed, d_angle = maxAcceleration + if dist == 'uniform': + speed += np.random.uniform(-d_speed, d_speed) + angle += np.random.uniform(-d_angle, d_angle) + elif dist == 'guassian': + speed += np.random.normal(0, d_speed / 2) + angle += np.random.normal(0, d_angle / 2) + else: + raise NotImplementedError( + f'Distribution type {dist} is not supported.') + return (speed, angle) + + +def get_random_velocity(max_speed=3, dist='uniform'): + if dist == 'uniform': + speed = np.random.uniform(max_speed) + elif dist == 'guassian': + speed = np.abs(np.random.normal(0, max_speed / 2)) + else: + raise NotImplementedError( + 'Distribution type {} is not supported.'.format(dist)) + angle = np.random.uniform(0, 2 * np.pi) + return (speed, angle) + + +def random_move_control_points(X, Y, imageHeight, imageWidth, lineVelocity, region_size, maxLineAcceleration=(3, 0.5), maxInitSpeed=3): + region_width, region_height = region_size + speed, angle = lineVelocity + X += int(speed * np.cos(angle)) + Y += int(speed * np.sin(angle)) + lineVelocity = random_accelerate( + lineVelocity, maxLineAcceleration, dist='guassian') + if ((X > imageHeight - region_height) or (X < 0) or (Y > imageWidth - region_width) or (Y < 0)): + lineVelocity = get_random_velocity(maxInitSpeed, dist='guassian') + new_X = np.clip(X, 0, imageHeight - region_height) + new_Y = np.clip(Y, 0, imageWidth - region_width) + return new_X, new_Y, lineVelocity + + + +# ############################################## +# ############################################## + +if __name__ == '__main__': + import os + os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE" + trials = 10 + for _ in range(trials): + video_length = 10 + # The returned masks are either stationary (50%) or moving (50%) + masks = create_random_shape_with_random_motion(video_length, zoomin=0.9, zoomout=1.1, rotmin=1, rotmax=10, imageHeight=240, imageWidth=432) + i = 0 + + for m in masks: + cv2.imshow('mask', np.array(m)) + cv2.waitKey(500) + # m.save('mask_{}.png'.format(i)) + i += 1 \ No newline at end of file diff --git a/FGT_codes/LAFC/data/util/__init__.py b/FGT_codes/LAFC/data/util/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..35e29baa771a24d045de69a7259c08fb9ee86f4b --- /dev/null +++ b/FGT_codes/LAFC/data/util/__init__.py @@ -0,0 +1,28 @@ +from .STTN_mask import create_random_shape_with_random_motion + +import logging +logger = logging.getLogger('base') + + +def initialize_mask(videoLength, dataInfo): + from .MaskModel import RandomMask + from .MaskModel import MidRandomMask + from .MaskModel import MatrixMask + from .MaskModel import FreeFormMask + from .MaskModel import StationaryMask + + return {'random': RandomMask(videoLength, dataInfo), + 'mid': MidRandomMask(videoLength, dataInfo), + 'matrix': MatrixMask(videoLength, dataInfo), + 'free': FreeFormMask(videoLength, dataInfo), + 'stationary': StationaryMask(videoLength, dataInfo) + } + + +def create_mask(maskClass, form): + if form == 'mix': + from random import randint + candidates = list(maskClass.keys()) + candidate_index = randint(0, len(candidates) - 1) + return maskClass[candidates[candidate_index]]() + return maskClass[form]() \ No newline at end of file diff --git a/FGT_codes/LAFC/data/util/flow_utils/__init__.py b/FGT_codes/LAFC/data/util/flow_utils/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/FGT_codes/LAFC/data/util/flow_utils/flow_reversal.py b/FGT_codes/LAFC/data/util/flow_utils/flow_reversal.py new file mode 100644 index 0000000000000000000000000000000000000000..328558100ed45dd191b81ea4704f67df13202dc8 --- /dev/null +++ b/FGT_codes/LAFC/data/util/flow_utils/flow_reversal.py @@ -0,0 +1,77 @@ +import torch + + +def flow_reversal(flow): + """ + flow: shape [b, c, h, w] + return: backward flow in corresponding to the forward flow + The formula is borrowed from Quadratic Video Interpolation (4) + """ + b, c, h, w = flow.shape + y = flow[:, 0:1, :, :] + x = flow[:, 1:2, :, :] # [b, 1, h, w] + + x = x.repeat(1, c, 1, 1) + y = y.repeat(1, c, 1, 1) + + # get the four points of the square (x1, y1), (x1, y2), (x2, y1), (x2, y2) + x1 = torch.floor(x) + x2 = x1 + 1 + y1 = torch.floor(y) + y2 = y1 + 1 + + # get gaussian weights + w11, w12, w21, w22 = get_gaussian_weights(x, y, x1, x2, y1, y2) + + # calculate the weight maps for each optical flows + flow11, o11 = sample_one(flow, x1, y1, w11) + flow12, o12 = sample_one(flow, x1, y2, w12) + flow21, o21 = sample_one(flow, x2, y1, w21) + flow22, o22 = sample_one(flow, x2, y2, w22) + + # fuse all the reversed flows based on equation (4) + flow_o = flow11 + flow12 + flow21 + flow22 + o = o11 + o12 + o21 + o22 + + flow_o = -flow_o + flow_o[o > 0] = flow_o[o > 0] / o[o > 0] + + return flow_o + + +def get_gaussian_weights(x, y, x1, x2, y1, y2): + sigma = 1 + w11 = torch.exp(-((x - x1) ** 2 + (y - y1) ** 2) / (sigma ** 2)) + w12 = torch.exp(-((x - x1) ** 2 + (y - y2) ** 2) / (sigma ** 2)) + w21 = torch.exp(-((x - x2) ** 2 + (y - y1) ** 2) / (sigma ** 2)) + w22 = torch.exp(-((x - x2) ** 2 + (y - y2) ** 2) / (sigma ** 2)) + return w11, w12, w21, w22 + + +def sample_one(flow, shiftx, shifty, weight): + b, c, h, w = flow.shape + flat_shiftx = shiftx.view(-1) # [h * w] + flat_shifty = shifty.view(-1) # [h * w] + flat_basex = torch.arange(0, h, requires_grad=False).view(-1, 1).long().repeat(b, c, 1, w).view(-1) # [h * w] + flat_basey = torch.arange(0, w, requires_grad=False).view(-1, 1).long().repeat(b, c, h, 1).view(-1) # [h * w] + flat_weight = weight.reshape(-1) # [h * w] + flat_flow = flow.reshape(-1) + + idxn = torch.arange(0, b, requires_grad=False).view(b, 1, 1, 1).long().repeat(1, c, h, w).view(-1) + idxc = torch.arange(0, c, requires_grad=False).view(1, c, 1, 1).long().repeat(b, 1, h, w).view(-1) + idxx = flat_shiftx.long() + flat_basex # size [-1] + idxy = flat_shifty.long() + flat_basey # size [-1] + + # record the shifted pixels inside the image boundaries + mask = idxx.ge(0) & idxx.lt(h) & idxy.ge(0) & idxy.lt(w) + + # mask off points out of boundaries + ids = idxn * c * h * w + idxc * h * w + idxx * w + idxy + ids_mask = torch.masked_select(ids, mask).clone() + + # put the value into corresponding regions + flow_warp = torch.zeros([b * c * h * w]) + flow_warp.put_(ids_mask, torch.masked_select(flat_flow * flat_weight, mask), accumulate=True) + one_warp = torch.zeros([b * c * h * w]) + one_warp.put_(ids_mask, torch.masked_select(flat_weight, mask), accumulate=True) + return flow_warp.view(b, c, h, w), one_warp.view(b, c, h, w) diff --git a/FGT_codes/LAFC/data/util/flow_utils/region_fill.py b/FGT_codes/LAFC/data/util/flow_utils/region_fill.py new file mode 100644 index 0000000000000000000000000000000000000000..603c78aadc312b07a2eb7c99dc9439a2a47dfee7 --- /dev/null +++ b/FGT_codes/LAFC/data/util/flow_utils/region_fill.py @@ -0,0 +1,142 @@ +import numpy as np +import cv2 +from scipy import sparse +from scipy.sparse.linalg import spsolve + + +# Laplacian filling +def regionfill(I, mask, factor=1.0): + if np.count_nonzero(mask) == 0: + return I.copy() + resize_mask = cv2.resize( + mask.astype(float), (0, 0), fx=factor, fy=factor) > 0 + resize_I = cv2.resize(I.astype(float), (0, 0), fx=factor, fy=factor) + maskPerimeter = findBoundaryPixels(resize_mask) + regionfillLaplace(resize_I, resize_mask, maskPerimeter) + resize_I = cv2.resize(resize_I, (I.shape[1], I.shape[0])) + resize_I[mask == 0] = I[mask == 0] + return resize_I + + +def findBoundaryPixels(mask): + kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (3, 3)) + maskDilated = cv2.dilate(mask.astype(float), kernel) + return (maskDilated > 0) & (mask == 0) + + +def regionfillLaplace(I, mask, maskPerimeter): + height, width = I.shape + rightSide = formRightSide(I, maskPerimeter) + + # Location of mask pixels + maskIdx = np.where(mask) + + # Only keep values for pixels that are in the mask + rightSide = rightSide[maskIdx] + + # Number the mask pixels in a grid matrix + grid = -np.ones((height, width)) + grid[maskIdx] = range(0, maskIdx[0].size) + # Pad with zeros to avoid "index out of bounds" errors in the for loop + grid = padMatrix(grid) + gridIdx = np.where(grid >= 0) + + # Form the connectivity matrix D=sparse(i,j,s) + # Connect each mask pixel to itself + i = np.arange(0, maskIdx[0].size) + j = np.arange(0, maskIdx[0].size) + # The coefficient is the number of neighbors over which we average + numNeighbors = computeNumberOfNeighbors(height, width) + s = numNeighbors[maskIdx] + # Now connect the N,E,S,W neighbors if they exist + for direction in ((-1, 0), (0, 1), (1, 0), (0, -1)): + # Possible neighbors in the current direction + neighbors = grid[gridIdx[0] + direction[0], gridIdx[1] + direction[1]] + # ConDnect mask points to neighbors with -1's + index = (neighbors >= 0) + i = np.concatenate((i, grid[gridIdx[0][index], gridIdx[1][index]])) + j = np.concatenate((j, neighbors[index])) + s = np.concatenate((s, -np.ones(np.count_nonzero(index)))) + + D = sparse.coo_matrix((s, (i.astype(int), j.astype(int)))).tocsr() + sol = spsolve(D, rightSide) + I[maskIdx] = sol + return I + + +def formRightSide(I, maskPerimeter): + height, width = I.shape + perimeterValues = np.zeros((height, width)) + perimeterValues[maskPerimeter] = I[maskPerimeter] + rightSide = np.zeros((height, width)) + + rightSide[1:height - 1, 1:width - 1] = ( + perimeterValues[0:height - 2, 1:width - 1] + + perimeterValues[2:height, 1:width - 1] + + perimeterValues[1:height - 1, 0:width - 2] + + perimeterValues[1:height - 1, 2:width]) + + rightSide[1:height - 1, 0] = ( + perimeterValues[0:height - 2, 0] + perimeterValues[2:height, 0] + + perimeterValues[1:height - 1, 1]) + + rightSide[1:height - 1, width - 1] = ( + perimeterValues[0:height - 2, width - 1] + + perimeterValues[2:height, width - 1] + + perimeterValues[1:height - 1, width - 2]) + + rightSide[0, 1:width - 1] = ( + perimeterValues[1, 1:width - 1] + perimeterValues[0, 0:width - 2] + + perimeterValues[0, 2:width]) + + rightSide[height - 1, 1:width - 1] = ( + perimeterValues[height - 2, 1:width - 1] + + perimeterValues[height - 1, 0:width - 2] + + perimeterValues[height - 1, 2:width]) + + rightSide[0, 0] = perimeterValues[0, 1] + perimeterValues[1, 0] + rightSide[0, width - 1] = ( + perimeterValues[0, width - 2] + perimeterValues[1, width - 1]) + rightSide[height - 1, 0] = ( + perimeterValues[height - 2, 0] + perimeterValues[height - 1, 1]) + rightSide[height - 1, width - 1] = (perimeterValues[height - 2, width - 1] + + perimeterValues[height - 1, width - 2]) + return rightSide + + +def computeNumberOfNeighbors(height, width): + # Initialize + numNeighbors = np.zeros((height, width)) + # Interior pixels have 4 neighbors + numNeighbors[1:height - 1, 1:width - 1] = 4 + # Border pixels have 3 neighbors + numNeighbors[1:height - 1, (0, width - 1)] = 3 + numNeighbors[(0, height - 1), 1:width - 1] = 3 + # Corner pixels have 2 neighbors + numNeighbors[(0, 0, height - 1, height - 1), (0, width - 1, 0, + width - 1)] = 2 + return numNeighbors + + +def padMatrix(grid): + height, width = grid.shape + gridPadded = -np.ones((height + 2, width + 2)) + gridPadded[1:height + 1, 1:width + 1] = grid + gridPadded = gridPadded.astype(grid.dtype) + return gridPadded + + +if __name__ == '__main__': + import time + x = np.linspace(0, 255, 500) + xv, _ = np.meshgrid(x, x) + image = ((xv + np.transpose(xv)) / 2.0).astype(int) + mask = np.zeros((500, 500)) + mask[100:259, 100:259] = 1 + mask = (mask > 0) + image[mask] = 0 + st = time.time() + inpaint = regionfill(image, mask, 0.5).astype(np.uint8) + print(time.time() - st) + cv2.imshow('img', np.concatenate((image.astype(np.uint8), inpaint))) + cv2.waitKey() diff --git a/FGT_codes/LAFC/data/util/freeform_masks.py b/FGT_codes/LAFC/data/util/freeform_masks.py new file mode 100644 index 0000000000000000000000000000000000000000..2ced45154b2cacb0b09d87134989501d07ccbb65 --- /dev/null +++ b/FGT_codes/LAFC/data/util/freeform_masks.py @@ -0,0 +1,266 @@ +import os +import sys +import shutil +sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))) # NOQA + +import numpy as np +import argparse +from PIL import Image + +from .mask_generators import get_video_masks_by_moving_random_stroke, get_masked_ratio +from .util import make_dirs, make_dir_under_root, get_everything_under +from .readers import MaskReader + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument( + '-od', '--output_dir', + type=str, + help="Output directory name" + ) + parser.add_argument( + '-im', + '--image_masks', action='store_true', + help="Set this if you want to generate independent masks in one directory." + ) + parser.add_argument( + '-vl', '--video_len', + type=int, + help="Maximum video length (i.e. #mask)" + ) + parser.add_argument( + '-ns', '--num_stroke', + type=int, + help="Number of stroke in one mask" + ) + parser.add_argument( + '-nsb', '--num_stroke_bound', + type=int, + nargs=2, + help="Upper/lower bound of number of stroke in one mask" + ) + parser.add_argument( + '-n', + type=int, + help="Number of mask to generate" + ) + parser.add_argument( + '-sp', + '--stroke_preset', + type=str, + default='rand_curve', + help="Preset of the stroke parameters" + ) + parser.add_argument( + '-iw', + '--image_width', + type=int, + default=320 + ) + parser.add_argument( + '-ih', + '--image_height', + type=int, + default=180 + ) + parser.add_argument( + '--cluster_by_area', + action='store_true' + ) + parser.add_argument( + '--leave_boarder_unmasked', + type=int, + help='Set this to a number, then a copy of the mask where the mask of boarder is erased.' + ) + parser.add_argument( + '--redo_without_generation', + action='store_true', + help='Set this, and the script will skip the generation and redo the left tasks' + '(uncluster -> erase boarder -> re-cluster)' + ) + args = parser.parse_args() + return args + + +def get_stroke_preset(stroke_preset): + if stroke_preset == 'object_like': + return { + "nVertexBound": [5, 30], + "maxHeadSpeed": 15, + "maxHeadAcceleration": (10, 1.5), + "brushWidthBound": (20, 50), + "nMovePointRatio": 0.5, + "maxPiontMove": 10, + "maxLineAcceleration": (5, 0.5), + "boarderGap": None, + "maxInitSpeed": 10, + } + elif stroke_preset == 'object_like_middle': + return { + "nVertexBound": [5, 15], + "maxHeadSpeed": 8, + "maxHeadAcceleration": (4, 1.5), + "brushWidthBound": (20, 50), + "nMovePointRatio": 0.5, + "maxPiontMove": 5, + "maxLineAcceleration": (5, 0.5), + "boarderGap": None, + "maxInitSpeed": 10, + } + elif stroke_preset == 'object_like_small': + return { + "nVertexBound": [5, 20], + "maxHeadSpeed": 7, + "maxHeadAcceleration": (3.5, 1.5), + "brushWidthBound": (10, 30), + "nMovePointRatio": 0.5, + "maxPiontMove": 5, + "maxLineAcceleration": (3, 0.5), + "boarderGap": None, + "maxInitSpeed": 4, + } + elif stroke_preset == 'rand_curve': + return { + "nVertexBound": [10, 30], + "maxHeadSpeed": 20, + "maxHeadAcceleration": (15, 0.5), + "brushWidthBound": (3, 10), + "nMovePointRatio": 0.5, + "maxPiontMove": 3, + "maxLineAcceleration": (5, 0.5), + "boarderGap": None, + "maxInitSpeed": 6 + } + elif stroke_preset == 'rand_curve_small': + return { + "nVertexBound": [6, 22], + "maxHeadSpeed": 12, + "maxHeadAcceleration": (8, 0.5), + "brushWidthBound": (2.5, 5), + "nMovePointRatio": 0.5, + "maxPiontMove": 1.5, + "maxLineAcceleration": (3, 0.5), + "boarderGap": None, + "maxInitSpeed": 3 + } + else: + raise NotImplementedError(f'The stroke presetting "{stroke_preset}" does not exist.') + + +def copy_masks_without_boarder(root_dir, args): + def erase_mask_boarder(mask, gap): + pix = np.asarray(mask).astype('uint8') * 255 + pix[:gap, :] = 255 + pix[-gap:, :] = 255 + pix[:, :gap] = 255 + pix[:, -gap:] = 255 + return Image.fromarray(pix).convert('1') + + wo_boarder_dir = root_dir + '_noBoarder' + shutil.copytree(root_dir, wo_boarder_dir) + + for i, filename in enumerate(get_everything_under(wo_boarder_dir)): + if args.image_masks: + mask = Image.open(filename) + mask_wo_boarder = erase_mask_boarder(mask, args.leave_boarder_unmasked) + mask_wo_boarder.save(filename) + else: + # filename is a diretory containing multiple mask files + for f in get_everything_under(filename, pattern='*.png'): + mask = Image.open(f) + mask_wo_boarder = erase_mask_boarder(mask, args.leave_boarder_unmasked) + mask_wo_boarder.save(f) + + return wo_boarder_dir + + +def cluster_by_masked_area(root_dir, args): + clustered_dir = root_dir + '_clustered' + make_dirs(clustered_dir) + radius = 5 + + # all masks with ratio in x +- radius will be stored in sub-directory x + clustered_centors = np.arange(radius, 100, radius * 2) + clustered_subdirs = [] + for c in clustered_centors: + # make sub-directories for each ratio range + clustered_subdirs.append(make_dir_under_root(clustered_dir, str(c))) + + for i, filename in enumerate(get_everything_under(root_dir)): + if args.image_masks: + ratio = get_masked_ratio(Image.open(filename)) + else: + # filename is a diretory containing multiple mask files + ratio = np.mean([ + get_masked_ratio(Image.open(f)) + for f in get_everything_under(filename, pattern='*.png') + ]) + + # find the nearest centor + for i, c in enumerate(clustered_centors): + if c - radius <= ratio * 100 <= c + radius: + shutil.move(filename, clustered_subdirs[i]) + break + + shutil.rmtree(root_dir) + os.rename(clustered_dir, root_dir) + + +def decide_nStroke(args): + if args.num_stroke is not None: + return args.num_stroke + elif args.num_stroke_bound is not None: + return np.random.randint(args.num_stroke_bound[0], args.num_stroke_bound[1]) + else: + raise ValueError('One of "-ns" or "-nsb" is needed') + + +def main(args): + preset = get_stroke_preset(args.stroke_preset) + make_dirs(args.output_dir) + + if args.redo_without_generation: + assert(len(get_everything_under(args.output_dir)) > 0) + # put back clustered masks + for clustered_subdir in get_everything_under(args.output_dir): + if not os.path.isdir(clustered_subdir): + continue + for f in get_everything_under(clustered_subdir): + shutil.move(f, args.output_dir) + os.rmdir(clustered_subdir) + + else: + if args.image_masks: + for i in range(args.n): + nStroke = decide_nStroke(args) + mask = get_video_masks_by_moving_random_stroke( + video_len=1, imageWidth=args.image_width, imageHeight=args.image_height, + nStroke=nStroke, **preset + )[0] + mask.save(os.path.join(args.output_dir, f'{i:07d}.png')) + + else: + for i in range(args.n): + mask_dir = make_dir_under_root(args.output_dir, f'{i:05d}') + mask_reader = MaskReader(mask_dir, read=False) + + nStroke = decide_nStroke(args) + masks = get_video_masks_by_moving_random_stroke( + imageWidth=args.image_width, imageHeight=args.image_height, + video_len=args.video_len, nStroke=nStroke, **preset) + + mask_reader.set_files(masks) + mask_reader.save_files(output_dir=mask_reader.dir_name) + + if args.leave_boarder_unmasked is not None: + dir_leave_boarder = copy_masks_without_boarder(args.output_dir, args) + if args.cluster_by_area: + cluster_by_masked_area(dir_leave_boarder, args) + + if args.cluster_by_area: + cluster_by_masked_area(args.output_dir, args) + + +if __name__ == "__main__": + args = parse_args() + main(args) diff --git a/FGT_codes/LAFC/data/util/mask_generators.py b/FGT_codes/LAFC/data/util/mask_generators.py new file mode 100644 index 0000000000000000000000000000000000000000..541a898a6feee551ffda029a4dd9280f2beeb421 --- /dev/null +++ b/FGT_codes/LAFC/data/util/mask_generators.py @@ -0,0 +1,217 @@ +import numpy as np +import random +from PIL import Image, ImageDraw + + +def get_video_masks_by_moving_random_stroke( + video_len, imageWidth=320, imageHeight=180, nStroke=5, + nVertexBound=[10, 30], maxHeadSpeed=15, maxHeadAcceleration=(15, 0.5), + brushWidthBound=(5, 20), boarderGap=None, nMovePointRatio=0.5, maxPiontMove=10, + maxLineAcceleration=5, maxInitSpeed=5 +): + ''' + Get video masks by random strokes which move randomly between each + frame, including the whole stroke and its control points + + Parameters + ---------- + imageWidth: Image width + imageHeight: Image height + nStroke: Number of drawed lines + nVertexBound: Lower/upper bound of number of control points for each line + maxHeadSpeed: Max head speed when creating control points + maxHeadAcceleration: Max acceleration applying on the current head point ( + a head point and its velosity decides the next point) + brushWidthBound (min, max): Bound of width for each stroke + boarderGap: The minimum gap between image boarder and drawed lines + nMovePointRatio: The ratio of control points to move for next frames + maxPiontMove: The magnitude of movement for control points for next frames + maxLineAcceleration: The magnitude of acceleration for the whole line + + Examples + ---------- + object_like_setting = { + "nVertexBound": [5, 20], + "maxHeadSpeed": 15, + "maxHeadAcceleration": (15, 3.14), + "brushWidthBound": (30, 50), + "nMovePointRatio": 0.5, + "maxPiontMove": 10, + "maxLineAcceleration": (5, 0.5), + "boarderGap": 20, + "maxInitSpeed": 10, + } + rand_curve_setting = { + "nVertexBound": [10, 30], + "maxHeadSpeed": 20, + "maxHeadAcceleration": (15, 0.5), + "brushWidthBound": (3, 10), + "nMovePointRatio": 0.5, + "maxPiontMove": 3, + "maxLineAcceleration": (5, 0.5), + "boarderGap": 20, + "maxInitSpeed": 6 + } + get_video_masks_by_moving_random_stroke(video_len=5, nStroke=3, **object_like_setting) + ''' + assert(video_len >= 1) + + # Initilize a set of control points to draw the first mask + mask = Image.new(mode='1', size=(imageWidth, imageHeight), color=1) + control_points_set = [] + for i in range(nStroke): + brushWidth = np.random.randint(brushWidthBound[0], brushWidthBound[1]) + Xs, Ys, velocity = get_random_stroke_control_points( + imageWidth=imageWidth, imageHeight=imageHeight, + nVertexBound=nVertexBound, maxHeadSpeed=maxHeadSpeed, + maxHeadAcceleration=maxHeadAcceleration, boarderGap=boarderGap, + maxInitSpeed=maxInitSpeed + ) + control_points_set.append((Xs, Ys, velocity, brushWidth)) + draw_mask_by_control_points(mask, Xs, Ys, brushWidth, fill=0) + + # Generate the following masks by randomly move strokes and their control points + masks = [mask] + for i in range(video_len - 1): + mask = Image.new(mode='1', size=(imageWidth, imageHeight), color=1) + for j in range(len(control_points_set)): + Xs, Ys, velocity, brushWidth = control_points_set[j] + new_Xs, new_Ys = random_move_control_points( + Xs, Ys, velocity, nMovePointRatio, maxPiontMove, + maxLineAcceleration, boarderGap + ) + control_points_set[j] = (new_Xs, new_Ys, velocity, brushWidth) + for Xs, Ys, velocity, brushWidth in control_points_set: + draw_mask_by_control_points(mask, Xs, Ys, brushWidth, fill=0) + masks.append(mask) + + return masks + + +def random_accelerate(velocity, maxAcceleration, dist='uniform'): + speed, angle = velocity + d_speed, d_angle = maxAcceleration + + if dist == 'uniform': + speed += np.random.uniform(-d_speed, d_speed) + angle += np.random.uniform(-d_angle, d_angle) + elif dist == 'guassian': + speed += np.random.normal(0, d_speed / 2) + angle += np.random.normal(0, d_angle / 2) + else: + raise NotImplementedError(f'Distribution type {dist} is not supported.') + + return (speed, angle) + + +def random_move_control_points(Xs, Ys, lineVelocity, nMovePointRatio, maxPiontMove, maxLineAcceleration, boarderGap=15): + new_Xs = Xs.copy() + new_Ys = Ys.copy() + + # move the whole line and accelerate + speed, angle = lineVelocity + new_Xs += int(speed * np.cos(angle)) + new_Ys += int(speed * np.sin(angle)) + lineVelocity = random_accelerate(lineVelocity, maxLineAcceleration, dist='guassian') + + # choose points to move + chosen = np.arange(len(Xs)) + np.random.shuffle(chosen) + chosen = chosen[:int(len(Xs) * nMovePointRatio)] + for i in chosen: + new_Xs[i] += np.random.randint(-maxPiontMove, maxPiontMove) + new_Ys[i] += np.random.randint(-maxPiontMove, maxPiontMove) + return new_Xs, new_Ys + + +def get_random_stroke_control_points( + imageWidth, imageHeight, + nVertexBound=(10, 30), maxHeadSpeed=10, maxHeadAcceleration=(5, 0.5), boarderGap=20, + maxInitSpeed=10 +): + ''' + Implementation the free-form training masks generating algorithm + proposed by JIAHUI YU et al. in "Free-Form Image Inpainting with Gated Convolution" + ''' + startX = np.random.randint(imageWidth) + startY = np.random.randint(imageHeight) + Xs = [startX] + Ys = [startY] + + numVertex = np.random.randint(nVertexBound[0], nVertexBound[1]) + + angle = np.random.uniform(0, 2 * np.pi) + speed = np.random.uniform(0, maxHeadSpeed) + + for i in range(numVertex): + speed, angle = random_accelerate((speed, angle), maxHeadAcceleration) + speed = np.clip(speed, 0, maxHeadSpeed) + + nextX = startX + speed * np.sin(angle) + nextY = startY + speed * np.cos(angle) + + if boarderGap is not None: + nextX = np.clip(nextX, boarderGap, imageWidth - boarderGap) + nextY = np.clip(nextY, boarderGap, imageHeight - boarderGap) + + startX, startY = nextX, nextY + Xs.append(nextX) + Ys.append(nextY) + + velocity = get_random_velocity(maxInitSpeed, dist='guassian') + + return np.array(Xs), np.array(Ys), velocity + + +def get_random_velocity(max_speed, dist='uniform'): + if dist == 'uniform': + speed = np.random.uniform(max_speed) + elif dist == 'guassian': + speed = np.abs(np.random.normal(0, max_speed / 2)) + else: + raise NotImplementedError(f'Distribution type {dist} is not supported.') + + angle = np.random.uniform(0, 2 * np.pi) + return (speed, angle) + + +def draw_mask_by_control_points(mask, Xs, Ys, brushWidth, fill=255): + radius = brushWidth // 2 - 1 + for i in range(1, len(Xs)): + draw = ImageDraw.Draw(mask) + startX, startY = Xs[i - 1], Ys[i - 1] + nextX, nextY = Xs[i], Ys[i] + draw.line((startX, startY) + (nextX, nextY), fill=fill, width=brushWidth) + for x, y in zip(Xs, Ys): + draw.ellipse((x - radius, y - radius, x + radius, y + radius), fill=fill) + return mask + + +# modified from https://github.com/naoto0804/pytorch-inpainting-with-partial-conv/blob/master/generate_data.py +def get_random_walk_mask(imageWidth=320, imageHeight=180, length=None): + action_list = [[0, 1], [0, -1], [1, 0], [-1, 0]] + canvas = np.zeros((imageHeight, imageWidth)).astype("i") + if length is None: + length = imageWidth * imageHeight + x = random.randint(0, imageHeight - 1) + y = random.randint(0, imageWidth - 1) + x_list = [] + y_list = [] + for i in range(length): + r = random.randint(0, len(action_list) - 1) + x = np.clip(x + action_list[r][0], a_min=0, a_max=imageHeight - 1) + y = np.clip(y + action_list[r][1], a_min=0, a_max=imageWidth - 1) + x_list.append(x) + y_list.append(y) + canvas[np.array(x_list), np.array(y_list)] = 1 + return Image.fromarray(canvas * 255).convert('1') + + +def get_masked_ratio(mask): + """ + Calculate the masked ratio. + mask: Expected a binary PIL image, where 0 and 1 represent + masked(invalid) and valid pixel values. + """ + hist = mask.histogram() + return hist[0] / np.prod(mask.size) diff --git a/FGT_codes/LAFC/data/util/readers.py b/FGT_codes/LAFC/data/util/readers.py new file mode 100644 index 0000000000000000000000000000000000000000..71bb1cd3840ff390d4ca186b42d920c1e65494a0 --- /dev/null +++ b/FGT_codes/LAFC/data/util/readers.py @@ -0,0 +1,527 @@ +import os +import sys +sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) # NOQA +import argparse +from math import ceil +from glob import glob + +import numpy as np +import cv2 +from PIL import Image, ImageDraw, ImageOps, ImageFont + +from utils.logging_config import logger +from utils.util import make_dirs, bbox_offset + + +DEFAULT_FPS = 6 +MAX_LENGTH = 60 + + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument( + '-fps', '--fps', + type=int, default=DEFAULT_FPS, + help="Output video FPS" + ) + parser.add_argument( + '-v', '--video_dir', + type=str, + help="Video directory name" + ) + parser.add_argument( + '-vs', '--video_dirs', + nargs='+', + type=str, + help="Video directory names" + ) + parser.add_argument( + '-v2', '--video_dir2', + type=str, + help="Video directory name" + ) + parser.add_argument( + '-sd', '--segms_dir', + type=str, + help="Segmentation directory name" + ) + parser.add_argument( + '-fgd', '--fg_dir', + type=str, + help="Foreground directory name" + ) + parser.add_argument( + '-fgfd', '--fg_frames_dir', + type=str, + help="Foreground frames directory name" + ) + parser.add_argument( + '-fgsd', '--fg_segms_dir', + type=str, + help="Foreground segmentations directory name" + ) + parser.add_argument( + '-syfd', '--syn_frames_dir', + type=str, + help="Synthesized frames directory name" + ) + parser.add_argument( + '-bgfd', '--bg_frames_dir', + type=str, + help="Background frames directory name" + ) + parser.add_argument( + '-rt', '--reader_type', + type=str, + help="Type of reader" + ) + parser.add_argument( + '-od', '--output_dir', + type=str, + help="Output directory name" + ) + parser.add_argument( + '-o', '--output_filename', + type=str, required=True, + help="Output output filename" + ) + args = parser.parse_args() + return args + + +class Reader: + def __init__(self, dir_name, read=True, max_length=None, sample_period=1): + self.dir_name = dir_name + self.count = 0 + self.max_length = max_length + self.filenames = [] + self.sample_period = sample_period + if read: + if os.path.exists(dir_name): + # self.filenames = read_filenames_from_dir(dir_name, self.__class__.__name__) + # ^^^^^ yield None when reading some videos of face forensics data + # (related to 'Too many levels of symbolic links'?) + + self.filenames = sorted(glob(os.path.join(dir_name, '*'))) + self.filenames = [f for f in self.filenames if os.path.isfile(f)] + self.filenames = self.filenames[::sample_period][:max_length] + self.files = self.read_files(self.filenames) + else: + self.files = [] + logger.warning(f"Directory {dir_name} not exists!") + else: + self.files = [] + self.current_index = 0 + + def append(self, file_): + self.files.append(file_) + + def set_files(self, files): + self.files = files + + def read_files(self, filenames): + assert type(filenames) == list, f'filenames is not a list; dirname: {self.dir_name}' + filenames.sort() + frames = [] + for filename in filenames: + file_ = self.read_file(filename) + frames.append(file_) + return frames + + def save_files(self, output_dir=None): + make_dirs(output_dir) + logger.info(f"Saving {self.__class__.__name__} files to {output_dir}") + for i, file_ in enumerate(self.files): + self._save_file(output_dir, i, file_) + + def _save_file(self, output_dir, i, file_): + raise NotImplementedError("This is an abstract function") + + def read_file(self, filename): + raise NotImplementedError("This is an abstract function") + + def __iter__(self): + return self + + def __next__(self): + if self.current_index < len(self.files): + file_ = self.files[self.current_index] + self.current_index += 1 + return file_ + else: + self.current_index = 0 + raise StopIteration + + def __getitem__(self, key): + return self.files[key] + + def __len__(self): + return len(self.files) + + +class FrameReader(Reader): + def __init__( + self, dir_name, resize=None, read=True, max_length=MAX_LENGTH, + scale=1, sample_period=1 + ): + self.resize = resize + self.scale = scale + self.sample_period = sample_period + super().__init__(dir_name, read, max_length, sample_period) + + def read_file(self, filename): + origin_frame = Image.open(filename) + size = self.resize if self.resize is not None else origin_frame.size + origin_frame_resized = origin_frame.resize( + (int(size[0] * self.scale), int(size[1] * self.scale)) + ) + return origin_frame_resized + + def _save_file(self, output_dir, i, file_): + if len(self.filenames) == len(self.files): + name = sorted(self.filenames)[i].split('/')[-1] + else: + name = f"frame_{i:04}.png" + filename = os.path.join( + output_dir, name + ) + file_.save(filename, "PNG") + + def write_files_to_video(self, output_filename, fps=DEFAULT_FPS, frame_num_when_repeat_list=[1]): + logger.info( + f"Writeing frames to video {output_filename} with FPS={fps}") + video_writer = cv2.VideoWriter( + output_filename, + cv2.VideoWriter_fourcc(*"MJPG"), + fps, + self.files[0].size + ) + for frame_num_when_repeat in frame_num_when_repeat_list: + for frame in self.files: + frame = frame.convert("RGB") + frame_cv = np.array(frame) + frame_cv = cv2.cvtColor(frame_cv, cv2.COLOR_RGB2BGR) + for i in range(frame_num_when_repeat): + video_writer.write(frame_cv) + video_writer.release() + + +class SynthesizedFrameReader(FrameReader): + def __init__( + self, bg_frames_dir, fg_frames_dir, + fg_segms_dir, segm_bbox_mask_dir, fg_dir, dir_name, + bboxes_list_dir, + fg_scale=0.7, fg_location=(48, 27), mask_only=False + ): + self.bg_reader = FrameReader(bg_frames_dir) + self.size = self.bg_reader[0].size + # TODO: add different location and change scale to var + self.fg_reader = ForegroundReader( + fg_frames_dir, fg_segms_dir, fg_dir, + resize=self.size, + scale=fg_scale + ) + self.fg_location = fg_location + # self.masks = self.fg_reader.masks + # self.bbox_masks = self.fg_reader.bbox_masks + super().__init__(dir_name, read=False) + self.files = self.synthesize_frames( + self.bg_reader, self.fg_reader, mask_only) + self.bbox_masks = MaskGenerator( + segm_bbox_mask_dir, self.size, self.get_bboxeses() + ) + self.bboxes_list_dir = bboxes_list_dir + self.bboxes_list = self.get_bboxeses() + self.save_bboxes() + + def save_bboxes(self): + make_dirs(self.bboxes_list_dir) + logger.info(f"Saving bboxes to {self.bboxes_list_dir}") + for i, bboxes in enumerate(self.bboxes_list): + save_path = os.path.join(self.bboxes_list_dir, f"bboxes_{i:04}.txt") + if len(bboxes) > 0: + np.savetxt(save_path, bboxes[0], fmt='%4u') + + def get_bboxeses(self): + bboxeses = self.fg_reader.segms.bboxeses + new_bboxeses = [] + for bboxes in bboxeses: + new_bboxes = [] + for bbox in bboxes: + offset_bbox = bbox_offset(bbox, self.fg_location) + new_bboxes.append(offset_bbox) + new_bboxeses.append(new_bboxes) + return new_bboxeses + + def synthesize_frames(self, bg_reader, fg_reader, mask_only=False): + logger.info( + f"Synthesizing {bg_reader.dir_name} and {fg_reader.dir_name}" + ) + synthesized_frames = [] + for i, bg in enumerate(bg_reader): + if i == len(fg_reader): + break + fg = fg_reader[i] + mask = fg_reader.get_mask(i) + synthesized_frame = bg.copy() + if mask_only: + synthesized_frame.paste(mask, self.fg_location, mask) + else: + synthesized_frame.paste(fg, self.fg_location, mask) + synthesized_frames.append(synthesized_frame) + return synthesized_frames + + +class WarpedFrameReader(FrameReader): + def __init__(self, dir_name, i, ks): + self.i = i + self.ks = ks + super().__init__(dir_name) + + def _save_file(self, output_dir, i, file_): + filename = os.path.join( + output_dir, + f"warped_frame_{self.i:04}_k{self.ks[i]:02}.png" + ) + file_.save(filename) + + +class SegmentationReader(FrameReader): + def __init__( + self, dir_name, + resize=None, scale=1 + ): + super().__init__( + dir_name, resize=resize, scale=scale + ) + + def read_file(self, filename): + origin_frame = Image.open(filename) + mask = ImageOps.invert(origin_frame.convert("L")) + mask = mask.point(lambda x: 0 if x < 255 else 255, '1') + size = self.resize if self.resize is not None else origin_frame.size + mask_resized = mask.resize( + (int(size[0] * self.scale), int(size[1] * self.scale)) + ) + return mask_resized + + +class MaskReader(Reader): + def __init__(self, dir_name, read=True): + super().__init__(dir_name, read=read) + + def read_file(self, filename): + mask = Image.open(filename) + return mask + + def _save_file(self, output_dir, i, file_): + filename = os.path.join( + output_dir, + f"mask_{i:04}.png" + ) + file_.save(filename) + + def get_bboxes(self, i): + # TODO: save bbox instead of looking for one + mask = self.files[i] + mask = ImageOps.invert(mask.convert("L")).convert("1") + mask = np.array(mask) + image, contours, hier = cv2.findContours( + mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) + bboxes = [] + for c in contours: + # get the bounding rect + x, y, w, h = cv2.boundingRect(c) + bbox = ((x, y), (x + w - 1, y + h - 1)) + bboxes.append(bbox) + return bboxes + + def get_bbox(self, i): + # TODO: save bbox instead of looking for one + mask = self.files[i] + mask = ImageOps.invert(mask.convert("L")) + mask = np.array(mask) + image, contours, hier = cv2.findContours( + mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) + for c in contours: + # get the bounding rect + x, y, w, h = cv2.boundingRect(c) + bbox = ((x, y), (x + w - 1, y + h - 1)) + return bbox + + +class MaskGenerator(Reader): + def __init__( + self, mask_output_dir, size, bboxeses, save_masks=True + ): + self.bboxeses = bboxeses + self.size = size + super().__init__(mask_output_dir, read=False) + self.files = self.generate_masks() + if save_masks: + make_dirs(mask_output_dir) + self.save_files(mask_output_dir) + + def _save_file(self, output_dir, i, file_): + filename = os.path.join( + output_dir, + f"mask_{i:04}.png" + ) + file_.save(filename) + + def get_bboxes(self, i): + return self.bboxeses[i] + + def generate_masks(self): + masks = [] + for i in range(len(self.bboxeses)): + mask = self.generate_mask(i) + masks.append(mask) + return masks + + def generate_mask(self, i): + bboxes = self.bboxeses[i] + mask = Image.new("1", self.size, 1) + draw = ImageDraw.Draw(mask) + for bbox in bboxes: + draw.rectangle( + bbox, fill=0 + ) + return mask + + +class ForegroundReader(FrameReader): + def __init__( + self, frames_dir, segms_dir, dir_name, + resize=None, scale=1 + ): + self.frames_dir = frames_dir + self.segms_dir = segms_dir + self.frames = FrameReader( + frames_dir, + resize=resize, scale=scale + ) + self.segms = SegmentationReader( + segms_dir, resize=resize, scale=scale + ) + super().__init__(dir_name, read=False) + self.masks = self.segms.masks + # self.bbox_masks = self.segms.bbox_masks + self.files = self.generate_fg_frames(self.frames, self.segms) + + def get_mask(self, i): + return self.masks[i] + + def generate_fg_frames(self, frames, segms): + logger.info( + f"Generating fg frames from {self.frames_dir} and {self.segms_dir}" + ) + fg_frames = [] + for i, frame in enumerate(frames): + mask = self.masks[i] + fg_frame = Image.new("RGB", frame.size, (0, 0, 0)) + fg_frame.paste( + frame, (0, 0), + mask + ) + fg_frames.append(fg_frame) + return fg_frames + + +class CompareFramesReader(FrameReader): + def __init__(self, dir_names, col=2, names=[], mask_dir=None): + self.videos = [] + for dir_name in dir_names: + # If a method fails on this video, use None to indicate the situation + try: + self.videos.append(FrameReader(dir_name)) + except AssertionError: + self.videos.append(None) + if mask_dir is not None: + self.masks = MaskReader(mask_dir) + self.names = names + self.files = self.combine_videos(self.videos, col) + + def combine_videos(self, videos, col=2, edge_offset=35, h_start_offset=35): + combined_frames = [] + w, h = videos[0][0].size + # Prevent the first method fails and have a "None" as its video + i = 0 + while videos[i] is None: + i += 1 + length = len(videos[i]) + video_num = len(videos) + row = ceil(video_num / col) + for frame_idx in range(length): + width = col * w + (col - 1) * edge_offset + height = row * h + (row - 1) * edge_offset + h_start_offset + combined_frame = Image.new("RGBA", (width, height)) + draw = ImageDraw.Draw(combined_frame) + for i, video in enumerate(videos): + # Give the failed method a black output + if video is None or frame_idx >= len(video): + failed = True + frame = Image.new("RGBA", (w, h)) + else: + frame = video[frame_idx].convert("RGBA") + failed = False + + f_x = (i % col) * (w + edge_offset) + f_y = (i // col) * (h + edge_offset) + h_start_offset + combined_frame.paste(frame, (f_x, f_y)) + + # Draw name + font = ImageFont.truetype("DejaVuSans.ttf", 12) + # font = ImageFont.truetype("DejaVuSans-Bold.ttf", 13) + # font = ImageFont.truetype("timesbd.ttf", 14) + name = self.names[i] if not failed else f'{self.names[i]} (failed)' + draw.text( + (f_x + 10, f_y - 20), + name, (255, 255, 255), font=font + ) + + combined_frames.append(combined_frame) + return combined_frames + + +class BoundingBoxesListReader(Reader): + def __init__( + self, dir_name, resize=None, read=True, max_length=MAX_LENGTH, + scale=1 + ): + self.resize = resize + self.scale = scale + super().__init__(dir_name, read, max_length) + + def read_file(self, filename): + bboxes = np.loadtxt(filename, dtype=int) + bboxes = [bboxes.tolist()] + return bboxes + + +def save_frames_to_dir(frames, dirname): + reader = FrameReader(dirname, read=False) + reader.set_files(frames) + reader.save_files(dirname) + + +if __name__ == "__main__": + args = parse_args() + if args.reader_type is None: + reader = FrameReader(args.video_dir) + elif args.reader_type == 'fg': + reader = ForegroundReader( + args.video_dir, args.segms_dir, args.fg_dir) + elif args.reader_type == 'sy': + reader = SynthesizedFrameReader( + args.bg_frames_dir, args.fg_frames_dir, + args.fg_segms_dir, args.fg_dir, args.syn_frames_dir + ) + elif args.reader_type == 'com': + reader = CompareFramesReader( + args.video_dirs + ) + reader.write_files_to_video( + os.path.join(args.output_dir, args.output_filename), + fps=args.fps + ) diff --git a/FGT_codes/LAFC/data/util/util.py b/FGT_codes/LAFC/data/util/util.py new file mode 100644 index 0000000000000000000000000000000000000000..1170de3aa61b19eae12fb7ec45505e6e26a68b42 --- /dev/null +++ b/FGT_codes/LAFC/data/util/util.py @@ -0,0 +1,259 @@ +import os +import argparse +import shutil +from glob import glob + +import numpy as np +from PIL import Image + +from utils.logging_config import logger + + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument( + '-v', '--video_dir', + type=str, + help="Video directory name" + ) + parser.add_argument( + '-fl', '--flow_dir', + type=str, + help="Optical flow ground truth directory name" + ) + parser.add_argument( + '-od', '--output_dir', + type=str, + help="Output directory name" + ) + parser.add_argument( + '-o', '--output_filename', + type=str, + help="Output output filename" + ) + args = parser.parse_args() + return args + + +def make_dirs(dir_name): + if not os.path.exists(dir_name): + os.makedirs(dir_name) + logger.info(f"Directory {dir_name} made") + + +ensure_dir = make_dirs + + +def make_dir_under_root(root_dir, name): + full_dir_name = os.path.join(root_dir, name) + make_dirs(full_dir_name) + return full_dir_name + + +def rm_dirs(dir_name, ignore_errors=False): + if os.path.exists(dir_name): + shutil.rmtree(dir_name, ignore_errors) + logger.info(f"Directory {dir_name} removed") + + +def read_dirnames_under_root(root_dir, skip_list=[]): + dirnames = [ + name for i, name in enumerate(sorted(os.listdir(root_dir))) + if (os.path.isdir(os.path.join(root_dir, name)) + and name not in skip_list + and i not in skip_list) + ] + logger.info(f"Reading directories under {root_dir}, exclude {skip_list}, num: {len(dirnames)}") + return dirnames + + +def bbox_offset(bbox, location): + x0, y0 = location + (x1, y1), (x2, y2) = bbox + return ((x1 + x0, y1 + y0), (x2 + x0, y2 + y0)) + + +def cover2_bbox(bbox1, bbox2): + x1 = min(bbox1[0][0], bbox2[0][0]) + y1 = min(bbox1[0][1], bbox2[0][1]) + x2 = max(bbox1[1][0], bbox2[1][0]) + y2 = max(bbox1[1][1], bbox2[1][1]) + return ((x1, y1), (x2, y2)) + + +def extend_r_bbox(bbox, w, h, r): + (x1, y1), (x2, y2) = bbox + x1 = max(x1 - r, 0) + x2 = min(x2 + r, w) + y1 = max(y1 - r, 0) + y2 = min(y2 + r, h) + return ((x1, y1), (x2, y2)) + + +def mean_squared_error(A, B): + return np.square(np.subtract(A, B)).mean() + + +def bboxes_to_mask(size, bboxes): + mask = Image.new("L", size, 255) + mask = np.array(mask) + for bbox in bboxes: + try: + (x1, y1), (x2, y2) = bbox + except Exception: + (x1, y1, x2, y2) = bbox + + mask[y1:y2, x1:x2] = 0 + mask = Image.fromarray(mask.astype("uint8")) + return mask + + +def get_extended_from_box(img_size, box, patch_size): + def _decide_patch_num(box_width, patch_size): + num = np.ceil(box_width / patch_size).astype(np.int) + if (num * patch_size - box_width) < (patch_size // 2): + num += 1 + return num + + x1, y1 = box[0] + x2, y2 = box[1] + new_box = (x1, y1, x2 - x1, y2 - y1) + box_x_start, box_y_start, box_x_size, box_y_size = new_box + + patchN_x = _decide_patch_num(box_x_size, patch_size) + patchN_y = _decide_patch_num(box_y_size, patch_size) + + extend_x = (patch_size * patchN_x - box_x_size) // 2 + extend_y = (patch_size * patchN_y - box_y_size) // 2 + img_x_size = img_size[0] + img_y_size = img_size[1] + + x_start = max(0, box_x_start - extend_x) + x_end = min(box_x_start - extend_x + patchN_x * patch_size, img_x_size) + + y_start = max(0, box_y_start - extend_y) + y_end = min(box_y_start - extend_y + patchN_y * patch_size, img_y_size) + x_start, y_start, x_end, y_end = int(x_start), int(y_start), int(x_end), int(y_end) + extented_box = ((x_start, y_start), (x_end, y_end)) + return extented_box + + +# code modified from https://github.com/WonwoongCho/Generative-Inpainting-pytorch/blob/master/util.py +def spatial_discounting_mask(mask_width, mask_height, discounting_gamma): + """Generate spatial discounting mask constant. + Spatial discounting mask is first introduced in publication: + Generative Image Inpainting with Contextual Attention, Yu et al. + Returns: + np.array: spatial discounting mask + """ + gamma = discounting_gamma + mask_values = np.ones((mask_width, mask_height), dtype=np.float32) + for i in range(mask_width): + for j in range(mask_height): + mask_values[i, j] = max( + gamma**min(i, mask_width - i), + gamma**min(j, mask_height - j)) + + return mask_values + + +def bboxes_to_discounting_loss_mask(img_size, bboxes, discounting_gamma=0.99): + mask = np.zeros(img_size, dtype=np.float32) + 0.5 + for bbox in bboxes: + try: + (x1, y1), (x2, y2) = bbox + except Exception: + (x1, y1, x2, y2) = bbox + mask_width, mask_height = y2 - y1, x2 - x1 + mask[y1:y2, x1:x2] = spatial_discounting_mask(mask_width, mask_height, discounting_gamma) + return mask + + +def find_proper_window(image_size, bbox_point): + ''' + parameters: + image_size(2-tuple): (height, width) + bbox_point(2-2-tuple): (first_point, last_point) + return values: + window left-up point, (2-tuple) + window right-bottom point, (2-tuple) + ''' + bbox_height = bbox_point[1][0] - bbox_point[0][0] + bbox_width = bbox_point[1][1] - bbox_point[0][1] + + window_size = min( + max(bbox_height, bbox_width) * 2, + image_size[0], image_size[1] + ) + # Limit min window size due to the requirement of VGG16 + window_size = max(window_size, 32) + + horizontal_span = window_size - (bbox_point[1][1] - bbox_point[0][1]) + vertical_span = window_size - (bbox_point[1][0] - bbox_point[0][0]) + + top_bound, bottom_bound = bbox_point[0][0] - \ + vertical_span // 2, bbox_point[1][0] + vertical_span // 2 + left_bound, right_bound = bbox_point[0][1] - \ + horizontal_span // 2, bbox_point[1][1] + horizontal_span // 2 + + if left_bound < 0: + right_bound += 0 - left_bound + left_bound += 0 - left_bound + elif right_bound > image_size[1]: + left_bound -= right_bound - image_size[1] + right_bound -= right_bound - image_size[1] + + if top_bound < 0: + bottom_bound += 0 - top_bound + top_bound += 0 - top_bound + elif bottom_bound > image_size[0]: + top_bound -= bottom_bound - image_size[0] + bottom_bound -= bottom_bound - image_size[0] + + return (top_bound, left_bound), (bottom_bound, right_bound) + + +def drawrect(drawcontext, xy, outline=None, width=0, partial=None): + (x1, y1), (x2, y2) = xy + if partial is None: + points = (x1, y1), (x2, y1), (x2, y2), (x1, y2), (x1, y1) + drawcontext.line(points, fill=outline, width=width) + else: + drawcontext.line([(x1, y1), (x1, y1 + partial)], fill=outline, width=width) + drawcontext.line([(x1 + partial, y1), (x1, y1)], fill=outline, width=width) + + drawcontext.line([(x2, y1), (x2, y1 + partial)], fill=outline, width=width) + drawcontext.line([(x2, y1), (x2 - partial, y1)], fill=outline, width=width) + + drawcontext.line([(x1, y2), (x1 + partial, y2)], fill=outline, width=width) + drawcontext.line([(x1, y2), (x1, y2 - partial)], fill=outline, width=width) + + drawcontext.line([(x2 - partial, y2), (x2, y2)], fill=outline, width=width) + drawcontext.line([(x2, y2), (x2, y2 - partial)], fill=outline, width=width) + + +def get_everything_under(root_dir, pattern='*', only_dirs=False, only_files=False): + assert not(only_dirs and only_files), 'You will get nothnig '\ + 'when "only_dirs" and "only_files" are both set to True' + everything = sorted(glob(os.path.join(root_dir, pattern))) + if only_dirs: + everything = [f for f in everything if os.path.isdir(f)] + if only_files: + everything = [f for f in everything if os.path.isfile(f)] + + return everything + + +def read_filenames_from_dir(dir_name, reader, max_length=None): + logger.debug( + f"{reader} reading files from {dir_name}") + filenames = [] + for root, dirs, files in os.walk(dir_name): + assert len(dirs) == 0, f"There are direcories: {dirs} in {root}" + assert len(files) != 0, f"There are no files in {root}" + filenames = [os.path.join(root, name) for name in sorted(files)] + for name in filenames: + logger.debug(name) + if max_length is not None: + return filenames[:max_length] + return filenames diff --git a/FGT_codes/LAFC/data/util/utils.py b/FGT_codes/LAFC/data/util/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..4d38b2df4e0c79dfcdbc9d1e57add64cfdbf9dcc --- /dev/null +++ b/FGT_codes/LAFC/data/util/utils.py @@ -0,0 +1,158 @@ +import random +import numpy as np +import cv2 + +def random_bbox(img_height, img_width, vertical_margin, horizontal_margin, mask_height, mask_width): + maxt = img_height - vertical_margin - mask_height + maxl = img_width - horizontal_margin - mask_width + + t = random.randint(vertical_margin, maxt) + l = random.randint(horizontal_margin, maxl) + h = random.randint(mask_height // 2, mask_height) + w = random.randint(mask_width // 2, mask_width) + return (t, l, h, w) # 产生随机块状box,这个box后面会发展成为mask + + +def mid_bbox_mask(img_height, img_width, mask_height, mask_width): + def npmask(bbox, height, width): + mask = np.zeros((height, width, 1), np.float32) + mask[bbox[0]: bbox[0] + bbox[2], bbox[1]: bbox[1] + bbox[3], :] = 255. + return mask + + bbox = (img_height * 3 // 8, img_width * 3 // 8, mask_height, mask_width) + mask = npmask(bbox, img_height, img_width) + + return mask + + +def bbox2mask(img_height, img_width, max_delta_height, max_delta_width, bbox): + """Generate mask tensor from bbox. + + Args: + bbox: configuration tuple, (top, left, height, width) + config: Config should have configuration including IMG_SHAPES, + MAX_DELTA_HEIGHT, MAX_DELTA_WIDTH. + + Returns: + tf.Tensor: output with shape [B, 1, H, W] + + """ + + def npmask(bbox, height, width, delta_h, delta_w): + mask = np.zeros((height, width, 1), np.float32) + h = np.random.randint(delta_h // 2 + 1) # 防止有0产生 + w = np.random.randint(delta_w // 2 + 1) + mask[bbox[0] + h: bbox[0] + bbox[2] - h, bbox[1] + w: bbox[1] + bbox[3] - w, :] = 255. # height_true = height - 2 * h, width_true = width - 2 * w + return mask + + mask = npmask(bbox, img_height, img_width, + max_delta_height, + max_delta_width) + + return mask + + +def matrix2bbox(img_height, img_width, mask_height, mask_width, row, column): + """Generate masks with a matrix form + @param img_height + @param img_width + @param mask_height + @param mask_width + @param row: number of blocks in row + @param column: number of blocks in column + @return mbbox: multiple bboxes in (y, h, h, w) manner + """ + assert img_height - column * mask_height > img_height // 2, "Too many masks across a column" + assert img_width - row * mask_width > img_width // 2, "Too many masks across a row" + + interval_height = (img_height - column * mask_height) // (column + 1) + interval_width = (img_width - row * mask_width) // (row + 1) + + mbbox = [] + for i in range(row): + for j in range(column): + y = interval_height * (j+1) + j * mask_height + x = interval_width * (i+1) + i * mask_width + mbbox.append((y, x, mask_height, mask_width)) + return mbbox + + +def mbbox2masks(img_height, img_width, mbbox): + + def npmask(mbbox, height, width): + mask = np.zeros((height, width, 1), np.float32) + for bbox in mbbox: + mask[bbox[0]: bbox[0] + bbox[2], bbox[1]: bbox[1] + bbox[3], :] = 255. # height_true = height - 2 * h, width_true = width - 2 * w + return mask + + mask = npmask(mbbox, img_height, img_width) + + return mask + + +def draw_line(mask, startX, startY, angle, length, brushWidth): + """assume the size of mask is (H,W,1) + """ + assert len(mask.shape) == 2 or mask.shape[2] == 1, "The channel of mask doesn't fit the opencv format" + offsetX = int(np.round(length * np.cos(angle))) + offsetY = int(np.round(length * np.sin(angle))) + endX = startX + offsetX + endY = startY + offsetY + if endX > mask.shape[1]: + endX = mask.shape[1] + if endY > mask.shape[0]: + endY = mask.shape[0] + mask_processed = cv2.line(mask, (startX, startY), (endX, endY), 255, brushWidth) + return mask_processed, endX, endY + + +def draw_circle(mask, circle_x, circle_y, brushWidth): + radius = brushWidth // 2 + assert len(mask.shape) == 2 or mask.shape[2] == 1, "The channel of mask doesn't fit the opencv format" + mask_processed = cv2.circle(mask, (circle_x, circle_y), radius, 255) + return mask_processed + + +def freeFormMask(img_height, img_width, maxVertex, maxLength, maxBrushWidth, maxAngle): + mask = np.zeros((img_height, img_width)) + numVertex = random.randint(1, maxVertex) + startX = random.randint(10, img_width) + startY = random.randint(10, img_height) + brushWidth = random.randint(10, maxBrushWidth) + for i in range(numVertex): + angle = random.uniform(0, maxAngle) + if i % 2 == 0: + angle = 2 * np.pi - angle + length = random.randint(10, maxLength) + mask, endX, endY = draw_line(mask, startX, startY, angle, length, brushWidth) + startX = startX + int(length * np.sin(angle)) + startY = startY + int(length * np.cos(angle)) + mask = draw_circle(mask, endX, endY, brushWidth) + + if random.random() < 0.5: + mask = np.fliplr(mask) + if random.random() < 0.5: + mask = np.flipud(mask) + + if len(mask.shape) == 2: + mask = mask[:, :, np.newaxis] + + return mask + + +if __name__ == "__main__": + # for stationary mask generation + # stationary_mask_generator(240, 480, 50, 120) + + # for free-form mask generation + # mask = freeFormMask(240, 480, 30, 50, 20, np.pi) + # cv2.imwrite('mask.png', mask) + + # for matrix mask generation + # img_height, img_width = 240, 480 + # masks = matrix2bbox(240, 480, 20, 20, 5, 4) + # matrixMask = mbbox2masks(img_height, img_width, masks) + # cv2.imwrite('matrixMask.png', matrixMask) + pass + + diff --git a/FGT_codes/LAFC/flowCheckPoint/raft-things.pth b/FGT_codes/LAFC/flowCheckPoint/raft-things.pth new file mode 100644 index 0000000000000000000000000000000000000000..1e206ac8a2f660bc7620b0806a9278ddb3fc594d --- /dev/null +++ b/FGT_codes/LAFC/flowCheckPoint/raft-things.pth @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fcfa4125d6418f4de95d84aec20a3c5f4e205101715a79f193243c186ac9a7e1 +size 21108000 diff --git a/FGT_codes/LAFC/flow_inputs.py b/FGT_codes/LAFC/flow_inputs.py new file mode 100644 index 0000000000000000000000000000000000000000..8c0284c7bee293f3bb750d06e134ac96d6f78bee --- /dev/null +++ b/FGT_codes/LAFC/flow_inputs.py @@ -0,0 +1,50 @@ +import argparse + + +def args_parser(): + parser = argparse.ArgumentParser(description="General top layer trainer") + parser.add_argument("--opt", type=str, default="config/train.yaml", help="Path to optional configuration file") + parser.add_argument('--model', type=str, default='2d_net_appendEdges', + help='Model block name, in the `model` directory') + parser.add_argument('--name', type=str, default='flowFusion', help='Experiment name') + parser.add_argument('--outputdir', type=str, default='/myData/ret/experiments', help='Output dir to save results') + parser.add_argument('--datadir', type=str, default='/myData/', metavar='PATH') + parser.add_argument('--datasetName_train', type=str, default='train_dataset_single_edge', + help='The file name of the train dataset, in `data` directory') + parser.add_argument('--dataMode', type=str, default='resize', choices=['resize', 'crop']) + parser.add_argument('--network', type=str, default='flow_single_appendEdges', + help='The network file which defines the training process, in the `network` directory') + parser.add_argument('--PASSMASK', type=int, default=1, + help='1 -> concat the mask with the corrupted optical flows to fill the flow') + parser.add_argument('--L1M', type=float, default=1, help='The weight of L1 loss in masked area') + parser.add_argument('--sm', type=float, default=1, help='The loss weight of smooth loss') + parser.add_argument('--sm2', type=float, default=1, help='The loss weight of second order smooth loss') + # model related parameters + parser.add_argument('--use_bias', type=int, default=1, help='If 1, use bias in the convolution blocks') + parser.add_argument('--norm', type=int, default=0, help='If 1, normalize the weights of layers (SN by deault)') + parser.add_argument('--init_weights', type=int, default=1, + help='If 1, initialize the network with kaiming parameter set.') + parser.add_argument('--cnum', type=int, default=48, help='Initial channel of encoder') + parser.add_argument('--finetune', type=int, default=0, help='Whether to fine tune trained models') + # parser.add_argument('--checkPoint', type=str, default='', help='checkpoint path for continue training') + parser.add_argument('--gen_state', type=str, default='', help='checkpoint of the gen state for continuous training') + parser.add_argument('--opt_state', type=str, default='', help='checkpoint of the opt state for continuous training') + parser.add_argument('--resBlocks', type=int, default=1, help='The number of resblocks in the modulation subnetwork') + parser.add_argument('--edge_residuals', type=int, default=4, help='The number of resblocks in edge branch') + parser.add_argument('--conv_type', type=str, choices=['vanilla', 'gated', 'partial'], default='vanilla', + help='Which kind of conv to use') + parser.add_argument('--edge_loss', type=float, default=1, help='Loss weight for edge loss') + parser.add_argument('--in_channel', type=int, default=3, help='The input channel of the defined network') + parser.add_argument('--record_iter', type=int, default=16, help='How many iters to print an item of log') + parser.add_argument('--num_flows', type=int, default=1) + parser.add_argument('--sample', type=str, default='seq', choices=['random', 'seq']) + parser.add_argument('--use_edges', type=int, default=0) + parser.add_argument('--flow_interval', type=int, default=1) + parser.add_argument('--use_residual', type=int, default=1, help='Whether to use residual for the P3D network') + parser.add_argument('--gc', type=int, default=0, help='Use gradient clip to stabilize training') + parser.add_argument('--rescale', type=int, default=1, + help='Whether to rescale the results to the original flow range for calculating losses?') + parser.add_argument('--ternary', type=float, default=0.01) + parser.add_argument('--use_valid', action='store_true') + args = parser.parse_args() + return args diff --git a/FGT_codes/LAFC/metrics/__init__.py b/FGT_codes/LAFC/metrics/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..c608be9615c145466c14d93e93c77e1a4cce9c5d --- /dev/null +++ b/FGT_codes/LAFC/metrics/__init__.py @@ -0,0 +1,41 @@ +import numpy as np +from skimage.metrics import peak_signal_noise_ratio as psnr +from skimage.metrics import structural_similarity as ssim +import cvbase +import os + +os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE" + + +def calculate_metrics(results_flow, gts_flow): + """ + + Args: + results_flow: inpainted optical flow with shape [b, h, w, c], numpy array + gts_flow: ground truth optical flow with shape [b, h, w, c], numpy array + + Returns: PSNR, SSIM for flow images, and L1/L2 error for flow map + + """ + B, H, W, C = results_flow.shape + psnr_values, ssim_values, L1errors, L2errors = [], [], [], [] + for i in range(B): + result = results_flow[i] + gt = gts_flow[i] + result_img = cvbase.flow2rgb(result) + gt_img = cvbase.flow2rgb(gt) + residual = result - gt + L1error = np.mean(np.abs(residual)) + L2error = np.sum(residual ** 2) ** 0.5 / (H * W * C) + psnr_value = psnr(result_img, gt_img) + ssim_value = ssim(result_img, gt_img, multichannel=True) + L1errors.append(L1error) + L2errors.append(L2error) + psnr_values.append(psnr_value) + ssim_values.append(ssim_value) + L1_value = np.mean(L1errors) + L2_value = np.mean(L2errors) + psnr_value = np.mean(psnr_values) + ssim_value = np.mean(ssim_values) + + return {'l1': L1_value, 'l2': L2_value, 'psnr': psnr_value, 'ssim': ssim_value} diff --git a/FGT_codes/LAFC/metrics/psnr.py b/FGT_codes/LAFC/metrics/psnr.py new file mode 100644 index 0000000000000000000000000000000000000000..52a12602a7de2403ce7c2baf32c1cfcb359d9f2a --- /dev/null +++ b/FGT_codes/LAFC/metrics/psnr.py @@ -0,0 +1,10 @@ +import numpy +import math + + +def psnr(img1, img2): + mse = numpy.mean( (img1 - img2) ** 2 ) + if mse == 0: + return 100 + PIXEL_MAX = 255.0 + return 20 * math.log10(PIXEL_MAX / math.sqrt(mse)) \ No newline at end of file diff --git a/FGT_codes/LAFC/metrics/ssim.py b/FGT_codes/LAFC/metrics/ssim.py new file mode 100644 index 0000000000000000000000000000000000000000..2a3a431813678cf5d02f0d0b8185712be16f9e24 --- /dev/null +++ b/FGT_codes/LAFC/metrics/ssim.py @@ -0,0 +1,46 @@ +import cv2 +import numpy as np + + +def calculate_ssim(img1, img2): + C1 = (0.01 * 255)**2 + C2 = (0.03 * 255)**2 + + img1 = img1.astype(np.float64) + img2 = img2.astype(np.float64) + kernel = cv2.getGaussianKernel(11, 1.5) + window = np.outer(kernel, kernel.transpose()) + + mu1 = cv2.filter2D(img1, -1, window)[5:-5, 5:-5] # valid + mu2 = cv2.filter2D(img2, -1, window)[5:-5, 5:-5] + mu1_sq = mu1**2 + mu2_sq = mu2**2 + mu1_mu2 = mu1 * mu2 + sigma1_sq = cv2.filter2D(img1**2, -1, window)[5:-5, 5:-5] - mu1_sq + sigma2_sq = cv2.filter2D(img2**2, -1, window)[5:-5, 5:-5] - mu2_sq + sigma12 = cv2.filter2D(img1 * img2, -1, window)[5:-5, 5:-5] - mu1_mu2 + + ssim_map = ((2 * mu1_mu2 + C1) * (2 * sigma12 + C2)) / ((mu1_sq + mu2_sq + C1) * + (sigma1_sq + sigma2_sq + C2)) + return ssim_map.mean() + + +def ssim(img1, img2): + '''calculate SSIM + the same outputs as MATLAB's + img1, img2: [0, 255] + ''' + if not img1.shape == img2.shape: + raise ValueError('Input images must have the same dimensions.') + if img1.ndim == 2: + return calculate_ssim(img1, img2) + elif img1.ndim == 3: + if img1.shape[2] == 3: + ssims = [] + for i in range(3): + ssims.append(calculate_ssim(img1[:, :, i], img2[:, :, i])) + return np.array(ssims).mean() + elif img1.shape[2] == 1: + return calculate_ssim(np.squeeze(img1), np.squeeze(img2)) + else: + raise ValueError('Wrong input image dimensions.') \ No newline at end of file diff --git a/FGT_codes/LAFC/models/BaseNetwork.py b/FGT_codes/LAFC/models/BaseNetwork.py new file mode 100644 index 0000000000000000000000000000000000000000..b916da739d190b1cf3e9f8e8708abb50cc652c29 --- /dev/null +++ b/FGT_codes/LAFC/models/BaseNetwork.py @@ -0,0 +1,51 @@ +from .utils.network_blocks import * +from .utils.network_blocks_2d import * + + +class BaseNetwork(nn.Module): + def __init__(self, conv_type): + super(BaseNetwork, self).__init__() + self.conv_type = conv_type + if conv_type == 'gated': + self.ConvBlock = GatedConv + self.DeconvBlock = GatedDeconv + self.ConvBlock2d = GatedConv2d + self.DeconvBlock2d = GatedDeconv2d + if conv_type == 'partial': + self.ConvBlock = PartialConv + self.DeconvBlock = PartialDeconv + self.ConvBlock2d = PartialConv2d + self.DeconvBlock2d = PartialDeconv2d + if conv_type == 'vanilla': + self.ConvBlock = VanillaConv + self.DeconvBlock = VanillaDeconv + self.ConvBlock2d = VanillaConv2d + self.DeconvBlock2d = VanillaDeconv2d + + def init_weights(self, init_type='kaiming', gain=0.02): + ''' + initialize network's weights + init_type: normal | xavier | kaiming | orthogonal + https://github.com/junyanz/pytorch-CycleGAN-and-pix2pix/blob/9451e70673400885567d08a9e97ade2524c700d0/models/networks.py#L39 + ''' + + def init_func(m): + classname = m.__class__.__name__ + if hasattr(m, 'weight') and (classname.find('Conv') != -1 or classname.find('Linear') != -1): + if init_type == 'normal': + nn.init.normal_(m.weight.data, 0.0, gain) + elif init_type == 'xavier': + nn.init.xavier_normal_(m.weight.data, gain=gain) + elif init_type == 'kaiming': + nn.init.kaiming_normal_(m.weight.data, a=0, mode='fan_in') + elif init_type == 'orthogonal': + nn.init.orthogonal_(m.weight.data, gain=gain) + + if hasattr(m, 'bias') and m.bias is not None: + nn.init.constant_(m.bias.data, 0.0) + + elif classname.find('BatchNorm2d') != -1: + nn.init.normal_(m.weight.data, 1.0, gain) + nn.init.constant_(m.bias.data, 0.0) + + self.apply(init_func) diff --git a/FGT_codes/LAFC/models/__init__.py b/FGT_codes/LAFC/models/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/FGT_codes/LAFC/models/__pycache__/BaseNetwork.cpython-39.pyc b/FGT_codes/LAFC/models/__pycache__/BaseNetwork.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3fb4e79149bbd6252eb650931f4ed5ac3e9037bf Binary files /dev/null and b/FGT_codes/LAFC/models/__pycache__/BaseNetwork.cpython-39.pyc differ diff --git a/FGT_codes/LAFC/models/__pycache__/__init__.cpython-39.pyc b/FGT_codes/LAFC/models/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6bd8b58eca9b3a456a9d6572f8e99f1996ed6bcf Binary files /dev/null and b/FGT_codes/LAFC/models/__pycache__/__init__.cpython-39.pyc differ diff --git a/FGT_codes/LAFC/models/__pycache__/lafc.cpython-39.pyc b/FGT_codes/LAFC/models/__pycache__/lafc.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ac7bf33b894785738461e0014c2c93272dc8d45c Binary files /dev/null and b/FGT_codes/LAFC/models/__pycache__/lafc.cpython-39.pyc differ diff --git a/FGT_codes/LAFC/models/lafc.py b/FGT_codes/LAFC/models/lafc.py new file mode 100644 index 0000000000000000000000000000000000000000..a3b5ef03ace91c13aac526cb3e7db66096dcd26e --- /dev/null +++ b/FGT_codes/LAFC/models/lafc.py @@ -0,0 +1,148 @@ +import torch +import torch.nn as nn +from .BaseNetwork import BaseNetwork + + +class Model(nn.Module): + def __init__(self, config): + super(Model, self).__init__() + self.net = P3DNet(config['num_flows'], config['cnum'], config['in_channel'], config['PASSMASK'], + config['use_residual'], + config['resBlocks'], config['use_bias'], config['conv_type'], config['init_weights']) + + def forward(self, flows, masks, edges=None): + ret = self.net(flows, masks, edges) + return ret + + +class P3DNet(BaseNetwork): + def __init__(self, num_flows, num_feats, in_channels, passmask, use_residual, res_blocks, + use_bias, conv_type, init_weights): + super().__init__(conv_type) + self.passmask = passmask + self.encoder2 = nn.Sequential( + nn.ReplicationPad3d((2, 2, 2, 2, 0, 0)), + P3DBlock(in_channels, num_feats, kernel_size=5, stride=1, padding=0, bias=use_bias, conv_type=conv_type, + norm=None, use_residual=0), + P3DBlock(num_feats, num_feats * 2, kernel_size=3, stride=2, padding=1, bias=use_bias, conv_type=conv_type, + norm=None, use_residual=0) + ) + self.encoder4 = nn.Sequential( + P3DBlock(num_feats * 2, num_feats * 2, kernel_size=3, stride=1, padding=1, bias=use_bias, + conv_type=conv_type, norm=None, use_residual=use_residual), + P3DBlock(num_feats * 2, num_feats * 4, kernel_size=3, stride=2, padding=1, bias=use_bias, + conv_type=conv_type, norm=None, use_residual=0) + ) + residual_blocks = [] + self.resNums = res_blocks + base_residual_block = P3DBlock(num_feats * 4, num_feats * 4, kernel_size=3, stride=1, padding=1, bias=use_bias, + conv_type=conv_type, + norm=None, use_residual=1) + for _ in range(res_blocks): + residual_blocks.append(base_residual_block) + self.res_blocks = nn.Sequential(*residual_blocks) + self.condense2 = self.ConvBlock(num_feats * 2, num_feats * 2, kernel_size=(num_flows, 1, 1), stride=1, + padding=0, + bias=use_bias, norm=None) + self.condense4_pre = self.ConvBlock(num_feats * 4, num_feats * 4, kernel_size=(num_flows, 1, 1), stride=1, + padding=0, + bias=use_bias, norm=None) + self.condense4_post = self.ConvBlock(num_feats * 4, num_feats * 4, kernel_size=(num_flows, 1, 1), stride=1, + padding=0, + bias=use_bias, norm=None) + # dilation convolution to enlarge the receptive field + self.middle = nn.Sequential( + self.ConvBlock2d(num_feats * 4, num_feats * 4, kernel_size=3, stride=1, padding=8, bias=use_bias, + dilation=8, norm=None), + self.ConvBlock2d(num_feats * 4, num_feats * 4, kernel_size=3, stride=1, padding=4, bias=use_bias, + dilation=4, norm=None), + self.ConvBlock2d(num_feats * 4, num_feats * 4, kernel_size=3, stride=1, padding=2, bias=use_bias, + dilation=2, norm=None), + self.ConvBlock2d(num_feats * 4, num_feats * 4, kernel_size=3, stride=1, padding=1, bias=use_bias, + dilation=1, norm=None), + ) + self.decoder2 = nn.Sequential( + self.DeconvBlock2d(num_feats * 8, num_feats * 2, kernel_size=3, stride=1, padding=1, bias=use_bias, + norm=None), + self.ConvBlock2d(num_feats * 2, num_feats * 2, kernel_size=3, stride=1, padding=1, bias=use_bias, + norm=None), + self.ConvBlock2d(num_feats * 2, num_feats * 2, kernel_size=3, stride=1, padding=1, bias=use_bias, + norm=None) + ) + self.decoder = nn.Sequential( + self.DeconvBlock2d(num_feats * 4, num_feats, kernel_size=3, stride=1, padding=1, bias=use_bias, + norm=None), + self.ConvBlock2d(num_feats, num_feats // 2, kernel_size=3, stride=1, padding=1, bias=use_bias, + norm=None), + self.ConvBlock2d(num_feats // 2, 2, kernel_size=3, stride=1, padding=1, bias=use_bias, + norm=None, activation=None) + ) + self.edgeDetector = EdgeDetection(conv_type) + if init_weights: + self.init_weights() + + def forward(self, flows, masks, edges=None): + if self.passmask: + inputs = torch.cat((flows, masks), dim=1) + else: + inputs = flows + if edges is not None: + inputs = torch.cat((inputs, edges), dim=1) + e2 = self.encoder2(inputs) + c_e2Pre = self.condense2(e2).squeeze(2) + e4 = self.encoder4(e2) + c_e4Pre = self.condense4_pre(e4).squeeze(2) + if self.resNums > 0: + e4 = self.res_blocks(e4) + c_e4Post = self.condense4_post(e4).squeeze(2) + assert len(c_e4Post.shape) == 4, 'Wrong with the c_e4 shape: {}'.format(len(c_e4Post.shape)) + c_e4_filled = self.middle(c_e4Post) + c_e4 = torch.cat((c_e4_filled, c_e4Pre), dim=1) + c_e2Post = self.decoder2(c_e4) + c_e2 = torch.cat((c_e2Post, c_e2Pre), dim=1) + output = self.decoder(c_e2) + edge = self.edgeDetector(output) + return output, edge + + +class P3DBlock(BaseNetwork): + def __init__(self, in_channels, out_channels, kernel_size, stride, padding, bias, conv_type, norm, use_residual): + super().__init__(conv_type) + self.conv1 = self.ConvBlock(in_channels, out_channels, kernel_size=(1, kernel_size, kernel_size), + stride=(1, stride, stride), padding=(0, padding, padding), + bias=bias, norm=norm) + self.conv2 = self.ConvBlock(out_channels, out_channels, kernel_size=(3, 1, 1), stride=1, + padding=(1, 0, 0), bias=bias, norm=norm) + self.use_residual = use_residual + + def forward(self, feats): + feat1 = self.conv1(feats) + feat2 = self.conv2(feat1) + if self.use_residual: + output = feats + feat2 + else: + output = feat2 + return output + + +class EdgeDetection(BaseNetwork): + def __init__(self, conv_type, in_channels=2, out_channels=1, mid_channels=16): + super(EdgeDetection, self).__init__(conv_type) + self.projection = self.ConvBlock2d(in_channels=in_channels, out_channels=mid_channels, kernel_size=3, stride=1, + padding=1, norm=None) + self.mid_layer_1 = self.ConvBlock2d(in_channels=mid_channels, out_channels=mid_channels, kernel_size=3, + stride=1, padding=1, norm=None) + self.mid_layer_2 = self.ConvBlock2d(in_channels=mid_channels, out_channels=mid_channels, kernel_size=3, + stride=1, padding=1, activation=None, norm=None) + self.l_relu = nn.LeakyReLU() + self.out_layer = self.ConvBlock2d(in_channels=mid_channels, out_channels=out_channels, kernel_size=1, + activation=None, norm=None) + + def forward(self, flow): + flow = self.projection(flow) + edge = self.mid_layer_1(flow) + edge = self.mid_layer_2(edge) + edge = self.l_relu(flow + edge) + edge = self.out_layer(edge) + edge = torch.sigmoid(edge) + return edge diff --git a/FGT_codes/LAFC/models/lafc_single.py b/FGT_codes/LAFC/models/lafc_single.py new file mode 100644 index 0000000000000000000000000000000000000000..0a6a8b2d323e36e323db5960db265bb9f773f4a6 --- /dev/null +++ b/FGT_codes/LAFC/models/lafc_single.py @@ -0,0 +1,112 @@ +import torch +import torch.nn.functional as F +import torch.nn as nn +import functools +from .BaseNetwork import BaseNetwork +from models.utils.reconstructionLayers import make_layer, ResidualBlock_noBN + + +class Model(nn.Module): + def __init__(self, config): + super(Model, self).__init__() + self.net = P3DNet(config['num_flows'], config['cnum'], config['in_channel'], config['PASSMASK'], + config['use_residual'], + config['resBlocks'], config['use_bias'], config['conv_type'], config['init_weights']) + + def forward(self, flows, masks, edges=None): + ret = self.net(flows, masks, edges) + return ret + + +class P3DNet(BaseNetwork): + def __init__(self, num_flows, num_feats, in_channels, passmask, use_residual, res_blocks, + use_bias, conv_type, init_weights): + super().__init__(conv_type) + self.passmask = passmask + self.encoder2 = nn.Sequential( + nn.ReplicationPad2d(2), + self.ConvBlock2d(in_channels, num_feats, kernel_size=5, stride=1, padding=0, bias=use_bias, norm=None), + self.ConvBlock2d(num_feats, num_feats * 2, kernel_size=3, stride=2, padding=1, bias=use_bias, norm=None) + ) + self.encoder4 = nn.Sequential( + self.ConvBlock2d(num_feats * 2, num_feats * 2, kernel_size=3, stride=1, padding=1, bias=use_bias, + norm=None), + self.ConvBlock2d(num_feats * 2, num_feats * 4, kernel_size=3, stride=2, padding=1, bias=use_bias, norm=None) + ) + residualBlock = functools.partial(ResidualBlock_noBN, nf=num_feats * 4) + self.res_blocks = make_layer(residualBlock, res_blocks) + self.resNums = res_blocks + # dilation convolution to enlarge the receptive field + self.middle = nn.Sequential( + self.ConvBlock2d(num_feats * 4, num_feats * 4, kernel_size=3, stride=1, padding=8, bias=use_bias, + dilation=8, norm=None), + self.ConvBlock2d(num_feats * 4, num_feats * 4, kernel_size=3, stride=1, padding=4, bias=use_bias, + dilation=4, norm=None), + self.ConvBlock2d(num_feats * 4, num_feats * 4, kernel_size=3, stride=1, padding=2, bias=use_bias, + dilation=2, norm=None), + self.ConvBlock2d(num_feats * 4, num_feats * 4, kernel_size=3, stride=1, padding=1, bias=use_bias, + dilation=1, norm=None), + ) + self.decoder2 = nn.Sequential( + self.DeconvBlock2d(num_feats * 8, num_feats * 2, kernel_size=3, stride=1, padding=1, bias=use_bias, + norm=None), + self.ConvBlock2d(num_feats * 2, num_feats * 2, kernel_size=3, stride=1, padding=1, bias=use_bias, + norm=None), + self.ConvBlock2d(num_feats * 2, num_feats * 2, kernel_size=3, stride=1, padding=1, bias=use_bias, + norm=None) + ) + self.decoder = nn.Sequential( + self.DeconvBlock2d(num_feats * 4, num_feats, kernel_size=3, stride=1, padding=1, bias=use_bias, + norm=None), + self.ConvBlock2d(num_feats, num_feats // 2, kernel_size=3, stride=1, padding=1, bias=use_bias, + norm=None), + self.ConvBlock2d(num_feats // 2, 2, kernel_size=3, stride=1, padding=1, bias=use_bias, + norm=None) + ) + self.edgeDetector = EdgeDetection(conv_type) + if init_weights: + self.init_weights() + + def forward(self, flows, masks, edges=None): + if self.passmask: + inputs = torch.cat((flows, masks), dim=1) + else: + inputs = flows + if edges is not None: + inputs = torch.cat((inputs, edges), dim=1) + e2 = self.encoder2(inputs) + e4 = self.encoder4(e2) + if self.resNums > 0: + e4_res = self.res_blocks(e4) + else: + e4_res = e4 + c_e4_filled = self.middle(e4_res) + c_e4 = torch.cat((c_e4_filled, e4), dim=1) + c_e2Post = self.decoder2(c_e4) + c_e2 = torch.cat((c_e2Post, e2), dim=1) + output = self.decoder(c_e2) + edge = self.edgeDetector(output) + return output, edge + + +class EdgeDetection(BaseNetwork): + def __init__(self, conv_type, in_channels=2, out_channels=1, mid_channels=16): + super(EdgeDetection, self).__init__(conv_type) + self.projection = self.ConvBlock2d(in_channels=in_channels, out_channels=mid_channels, kernel_size=3, stride=1, + padding=1, norm=None) + self.mid_layer_1 = self.ConvBlock2d(in_channels=mid_channels, out_channels=mid_channels, kernel_size=3, + stride=1, padding=1, norm=None) + self.mid_layer_2 = self.ConvBlock2d(in_channels=mid_channels, out_channels=mid_channels, kernel_size=3, + stride=1, padding=1, activation=None, norm=None) + self.l_relu = nn.LeakyReLU() + self.out_layer = self.ConvBlock2d(in_channels=mid_channels, out_channels=out_channels, kernel_size=1, + activation=None, norm=None) + + def forward(self, flow): + flow = self.projection(flow) + edge = self.mid_layer_1(flow) + edge = self.mid_layer_2(edge) + edge = self.l_relu(flow + edge) + edge = self.out_layer(edge) + edge = torch.sigmoid(edge) + return edge diff --git a/FGT_codes/LAFC/models/utils/RAFT/utils/__init__.py b/FGT_codes/LAFC/models/utils/RAFT/utils/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/FGT_codes/LAFC/models/utils/RAFT/utils/utils.py b/FGT_codes/LAFC/models/utils/RAFT/utils/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..5f32d281c1c46353a0a2bf36b0550adb74125c65 --- /dev/null +++ b/FGT_codes/LAFC/models/utils/RAFT/utils/utils.py @@ -0,0 +1,82 @@ +import torch +import torch.nn.functional as F +import numpy as np +from scipy import interpolate + + +class InputPadder: + """ Pads images such that dimensions are divisible by 8 """ + def __init__(self, dims, mode='sintel'): + self.ht, self.wd = dims[-2:] + pad_ht = (((self.ht // 8) + 1) * 8 - self.ht) % 8 + pad_wd = (((self.wd // 8) + 1) * 8 - self.wd) % 8 + if mode == 'sintel': + self._pad = [pad_wd//2, pad_wd - pad_wd//2, pad_ht//2, pad_ht - pad_ht//2] + else: + self._pad = [pad_wd//2, pad_wd - pad_wd//2, 0, pad_ht] + + def pad(self, *inputs): + return [F.pad(x, self._pad, mode='replicate') for x in inputs] + + def unpad(self,x): + ht, wd = x.shape[-2:] + c = [self._pad[2], ht-self._pad[3], self._pad[0], wd-self._pad[1]] + return x[..., c[0]:c[1], c[2]:c[3]] + +def forward_interpolate(flow): + flow = flow.detach().cpu().numpy() + dx, dy = flow[0], flow[1] + + ht, wd = dx.shape + x0, y0 = np.meshgrid(np.arange(wd), np.arange(ht)) + + x1 = x0 + dx + y1 = y0 + dy + + x1 = x1.reshape(-1) + y1 = y1.reshape(-1) + dx = dx.reshape(-1) + dy = dy.reshape(-1) + + valid = (x1 > 0) & (x1 < wd) & (y1 > 0) & (y1 < ht) + x1 = x1[valid] + y1 = y1[valid] + dx = dx[valid] + dy = dy[valid] + + flow_x = interpolate.griddata( + (x1, y1), dx, (x0, y0), method='nearest', fill_value=0) + + flow_y = interpolate.griddata( + (x1, y1), dy, (x0, y0), method='nearest', fill_value=0) + + flow = np.stack([flow_x, flow_y], axis=0) + return torch.from_numpy(flow).float() + + +def bilinear_sampler(img, coords, mode='bilinear', mask=False): + """ Wrapper for grid_sample, uses pixel coordinates """ + H, W = img.shape[-2:] + xgrid, ygrid = coords.split([1,1], dim=-1) + xgrid = 2*xgrid/(W-1) - 1 + ygrid = 2*ygrid/(H-1) - 1 + + grid = torch.cat([xgrid, ygrid], dim=-1) + img = F.grid_sample(img, grid, align_corners=True) + + if mask: + mask = (xgrid > -1) & (ygrid > -1) & (xgrid < 1) & (ygrid < 1) + return img, mask.float() + + return img + + +def coords_grid(batch, ht, wd): + coords = torch.meshgrid(torch.arange(ht), torch.arange(wd)) + coords = torch.stack(coords[::-1], dim=0).float() + return coords[None].repeat(batch, 1, 1, 1) + + +def upflow8(flow, mode='bilinear'): + new_size = (8 * flow.shape[2], 8 * flow.shape[3]) + return 8 * F.interpolate(flow, size=new_size, mode=mode, align_corners=True) diff --git a/FGT_codes/LAFC/models/utils/__init__.py b/FGT_codes/LAFC/models/utils/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/FGT_codes/LAFC/models/utils/__pycache__/__init__.cpython-39.pyc b/FGT_codes/LAFC/models/utils/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cf855b4d247ac64648bd372d93472f2dab27a6bf Binary files /dev/null and b/FGT_codes/LAFC/models/utils/__pycache__/__init__.cpython-39.pyc differ diff --git a/FGT_codes/LAFC/models/utils/__pycache__/network_blocks.cpython-39.pyc b/FGT_codes/LAFC/models/utils/__pycache__/network_blocks.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4d8f466f7a9a3669f4cdc5dc776606925a297af7 Binary files /dev/null and b/FGT_codes/LAFC/models/utils/__pycache__/network_blocks.cpython-39.pyc differ diff --git a/FGT_codes/LAFC/models/utils/__pycache__/network_blocks_2d.cpython-39.pyc b/FGT_codes/LAFC/models/utils/__pycache__/network_blocks_2d.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4040934e523cce047f7b8726aa0735f2a4154c08 Binary files /dev/null and b/FGT_codes/LAFC/models/utils/__pycache__/network_blocks_2d.cpython-39.pyc differ diff --git a/FGT_codes/LAFC/models/utils/bce_edge_loss.py b/FGT_codes/LAFC/models/utils/bce_edge_loss.py new file mode 100644 index 0000000000000000000000000000000000000000..d8ec534d445588f95d93ad6d379ef873d82c74b8 --- /dev/null +++ b/FGT_codes/LAFC/models/utils/bce_edge_loss.py @@ -0,0 +1,77 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F + + +def edgeLoss(preds_edges, edges): + """ + + Args: + preds_edges: with shape [b, c, h , w] + edges: with shape [b, c, h, w] + + Returns: Edge losses + + """ + mask = (edges > 0.5).float() + b, c, h, w = mask.shape + num_pos = torch.sum(mask, dim=[1, 2, 3]).float() + num_neg = c * h * w - num_pos + neg_weights = (num_neg / (num_pos + num_neg)).unsqueeze(1).unsqueeze(2).unsqueeze(3) + pos_weights = (num_pos / (num_pos + num_neg)).unsqueeze(1).unsqueeze(2).unsqueeze(3) + weight = neg_weights * mask + pos_weights * (1 - mask) # weight for debug + losses = F.binary_cross_entropy_with_logits(preds_edges.float(), edges.float(), weight=weight, reduction='none') + loss = torch.mean(losses) + return loss + + +class EdgeAcc(nn.Module): + """ + Measure the accuracy of the edge map + """ + + def __init__(self, threshold=0.5): + super(EdgeAcc, self).__init__() + self.threshold = threshold + + def __call__(self, pred_edge, gt_edge): + """ + + Args: + pred_edge: Predicted edges, with shape [b, c, h, w] + gt_edge: GT edges, with shape [b, c, h, w] + + Returns: The prediction accuracy and the recall of the edges + + """ + labels = gt_edge > self.threshold + preds = pred_edge > self.threshold + + relevant = torch.sum(labels.float()) + selected = torch.sum(preds.float()) + + if relevant == 0 and selected == 0: + return torch.tensor(1), torch.tensor(1) + + true_positive = ((preds == labels) * labels).float() + recall = torch.sum(true_positive) / (relevant + 1e-8) + precision = torch.sum(true_positive) / (selected + 1e-8) + return precision, recall + + +if __name__ == '__main__': + edge = torch.zeros([2, 1, 10, 10]) # [b, 1, h, w] -> the extracted edges + edge[0, :, 2:8, 2:8] = 1 + edge[1, :, 3:7, 3:7] = 1 + mask = (edge > 0.5).float() + b, c, h, w = mask.shape + num_pos = torch.sum(mask, dim=[1, 2, 3]).float() + num_neg = c * h * w - num_pos + print(num_pos, num_neg) + n = num_neg / (num_pos + num_neg) + p = num_pos / (num_pos + num_neg) + n = n.unsqueeze(1).unsqueeze(2).unsqueeze(3) + p = p.unsqueeze(1).unsqueeze(2).unsqueeze(3) + print(n * mask + p * (1 - mask)) + # weight = num_neg / (num_pos + num_neg) * mask + num_pos / (num_pos + num_neg) * (1 - mask) + # print(weight) diff --git a/FGT_codes/LAFC/models/utils/edgeLoss.py b/FGT_codes/LAFC/models/utils/edgeLoss.py new file mode 100644 index 0000000000000000000000000000000000000000..d0859dcc267adc6c39aaa91bc7266f9b7fcba1eb --- /dev/null +++ b/FGT_codes/LAFC/models/utils/edgeLoss.py @@ -0,0 +1,75 @@ +# under development +import cv2 +import torch +import torch.nn as nn +import numpy as np +import torch.nn.functional as F + + +class EdgeLoss(nn.Module): + def __init__(self, device, reduction='mean'): + super().__init__() + self.loss_fn = nn.L1Loss(reduction=reduction) + self.gaussianKernel = self._gaussianKernel2dOpencv(kernel_size=5, sigma=1) + self.gaussianKernel = np.reshape(self.gaussianKernel, (1, 1, 5, 5)) # 5 is kernel size + self.gaussianKernel = torch.from_numpy(self.gaussianKernel).float().to(device) + + def forward(self, outputs, GTs, masks, cannyEdges): + """ + Calculate the L1 loss in the edge regions + edges are detected by canny operator + Args: + outputs: torch tensor, shape [b, c, h, w] + GTs: torch tensor, shape [b, c, h, w] + masks: torch tensor, shape [b, 1, h, w] + cannyEdges: shape [b, c, h, w], 1 indicates edge regions, while 0 indicates nonedge regions + cannyEdges should be provided by the dataloader + + Returns: edge loss between outputs and GTs + + """ + cannyEdges = self.gaussianBlur(cannyEdges) + loss = self.loss_fn(outputs * cannyEdges * masks, GTs * cannyEdges * masks) / torch.mean(masks) + return loss + + def gaussianBlur(self, cannyEdges, iteration=2): + for i in range(iteration): + cannyEdges = F.conv2d(cannyEdges, self.gaussianKernel, stride=1, padding=2) + return cannyEdges + + def _gaussianKernel2dOpencv(self, kernel_size=5, sigma=1): + kx = cv2.getGaussianKernel(kernel_size, sigma) + ky = cv2.getGaussianKernel(kernel_size, sigma) + return np.multiply(kx, np.transpose(ky)) + + +if __name__ == '__main__': + from PIL import Image + from torchvision.transforms import ToTensor + from skimage.feature import canny + from torchvision.utils import save_image + from skimage.color import rgb2gray + + output = Image.open('images/00001_res.jpg') + GT = Image.open('images/img2.jpg') + # mask = Image.open('images/mask.png') + cannyMap = canny(rgb2gray(np.array(GT)), sigma=2).astype(np.float32) + + output = ToTensor()(output).unsqueeze(0) + GT = ToTensor()(GT).unsqueeze(0) + # mask = ToTensor()(mask).unsqueeze(0) + mask = torch.ones_like(GT) + cannyMap = ToTensor()(cannyMap).unsqueeze(0) + output = output * 2 - 1 + GT = GT * 2 - 1 + + EdgeLossLayer = EdgeLoss(2, 'cpu') + edgeLoss, cannyPriority, edgeMap_output, edgeMap_GT, errorMap, errorMap2 = EdgeLossLayer(output, GT, mask, cannyMap) + print(edgeLoss) + save_image(cannyPriority, 'images/cannyPriority.jpg') + save_image(edgeMap_output, 'images/edgeMap_output.jpg') + save_image(edgeMap_GT, 'images/edgeMap_GT.jpg') + save_image(edgeMap_output * cannyPriority, 'images/edgeMap_output_canny.jpg') + save_image(edgeMap_GT * cannyPriority, 'images/edgeMap_GT_canny.jpg') + save_image(errorMap, 'images/errorMap.jpg') + save_image(errorMap2, 'images/errorMap2.jpg') diff --git a/FGT_codes/LAFC/models/utils/fbConsistencyCheck.py b/FGT_codes/LAFC/models/utils/fbConsistencyCheck.py new file mode 100644 index 0000000000000000000000000000000000000000..7d5b546c6124c8380e13f985199cf079350a8d2d --- /dev/null +++ b/FGT_codes/LAFC/models/utils/fbConsistencyCheck.py @@ -0,0 +1,127 @@ +import torch +import numpy as np +from .sobel2 import SobelLayer, SeperateSobelLayer +import torch.nn as nn +import torch.nn.functional as F + + +def image_warp(image, flow): + ''' + image: 上一帧的图片,torch.Size([1, 3, 256, 256]) + flow: 光流, torch.Size([1, 2, 256, 256]) + final_grid: torch.Size([1, 2, 256, 256]) + ''' + b, c, h, w = image.size() + device = image.device + flow = torch.cat([flow[:, 0:1, :, :] / ((w - 1.0) / 2.0), flow[:, 1:2, :, :] / ((h - 1.0) / 2.0)], + dim=1) # normalize to [-1~1](from upper left to lower right + flow = flow.permute(0, 2, 3, + 1) # if you wanna use grid_sample function, the channel(band) shape of show must be in the last dimension + x = np.linspace(-1, 1, w) + y = np.linspace(-1, 1, h) + X, Y = np.meshgrid(x, y) + grid = torch.cat((torch.from_numpy(X.astype('float32')).unsqueeze(0).unsqueeze(3), + torch.from_numpy(Y.astype('float32')).unsqueeze(0).unsqueeze(3)), 3).to(device) + output = torch.nn.functional.grid_sample(image, grid + flow, mode='bilinear', padding_mode='zeros') + return output + + +def length_sq(x): + return torch.sum(torch.square(x), dim=1, keepdim=True) + + +def fbConsistencyCheck(flow_fw, flow_bw, alpha1=0.01, alpha2=0.5): + flow_bw_warped = image_warp(flow_bw, flow_fw) # wb(wf(x)) + flow_fw_warped = image_warp(flow_fw, flow_bw) # wf(wb(x)) + flow_diff_fw = flow_fw + flow_bw_warped # wf + wb(wf(x)) + flow_diff_bw = flow_bw + flow_fw_warped # wb + wf(wb(x)) + + mag_sq_fw = length_sq(flow_fw) + length_sq(flow_bw_warped) # |wf| + |wb(wf(x))| + mag_sq_bw = length_sq(flow_bw) + length_sq(flow_fw_warped) # |wb| + |wf(wb(x))| + occ_thresh_fw = alpha1 * mag_sq_fw + alpha2 + occ_thresh_bw = alpha1 * mag_sq_bw + alpha2 + + fb_occ_fw = (length_sq(flow_diff_fw) > occ_thresh_fw).float() + fb_occ_bw = (length_sq(flow_diff_bw) > occ_thresh_bw).float() + + return fb_occ_fw, fb_occ_bw # fb_occ_fw -> frame2 area occluded by frame1, fb_occ_bw -> frame1 area occluded by frame2 + + +def rgb2gray(image): + gray_image = image[:, 0] * 0.299 + image[:, 1] * 0.587 + 0.110 * image[:, 2] + gray_image = gray_image.unsqueeze(1) + return gray_image + + +def ternary_transform(image, max_distance=1): + device = image.device + patch_size = 2 * max_distance + 1 + intensities = rgb2gray(image) * 255 + out_channels = patch_size * patch_size + w = np.eye(out_channels).reshape(out_channels, 1, patch_size, patch_size) + weights = torch.from_numpy(w).float().to(device) + patches = F.conv2d(intensities, weights, stride=1, padding=1) + transf = patches - intensities + transf_norm = transf / torch.sqrt(0.81 + torch.square(transf)) + return transf_norm + + +def hamming_distance(t1, t2): + dist = torch.square(t1 - t2) + dist_norm = dist / (0.1 + dist) + dist_sum = torch.sum(dist_norm, dim=1, keepdim=True) + return dist_sum + + +def create_mask(mask, paddings): + """ + padding: [[top, bottom], [left, right]] + """ + shape = mask.shape + inner_height = shape[2] - (paddings[0][0] + paddings[0][1]) + inner_width = shape[3] - (paddings[1][0] + paddings[1][1]) + inner = torch.ones([inner_height, inner_width]) + + mask2d = F.pad(inner, pad=[paddings[1][0], paddings[1][1], paddings[0][0], paddings[0][1]]) # mask最外边一圈都pad成0了 + mask3d = mask2d.unsqueeze(0) + mask4d = mask3d.unsqueeze(0).repeat(shape[0], 1, 1, 1) + return mask4d.detach() + + +def ternary_loss2(frame1, warp_frame21, confMask, masks, max_distance=1): + """ + + Args: + frame1: torch tensor, with shape [b * t, c, h, w] + warp_frame21: torch tensor, with shape [b * t, c, h, w] + confMask: confidence mask, with shape [b * t, c, h, w] + masks: torch tensor, with shape [b * t, c, h, w] + max_distance: maximum distance. + + Returns: ternary loss + + """ + t1 = ternary_transform(frame1) + t21 = ternary_transform(warp_frame21) + dist = hamming_distance(t1, t21) # 近似求解,其实利用了mask区域和外界边缘交叉的那一部分像素 + loss = torch.mean(dist * confMask * masks) / torch.mean(masks) + return loss + + +def gradient_loss(frame1, frame2, confMask): + device = frame1.device + frame1_edge = SobelLayer(device)(frame1) + frame2_edge = SobelLayer(device)(frame2) + loss = torch.sum(torch.abs(frame1_edge * confMask - frame2_edge * confMask)) / (torch.sum(confMask) + 1) # escape divide 0 + return loss + + +def seperate_gradient_loss(frame1, warp_frame21, confMask): + device = frame1.device + mask_x = create_mask(frame1, [[0, 0], [1, 1]]).to(device) + mask_y = create_mask(frame1, [[1, 1], [0, 0]]).to(device) + gradient_mask = torch.cat([mask_x, mask_y], dim=1).repeat(1, 3, 1, 1) + frame1_edge = SeperateSobelLayer(device)(frame1) + warp_frame21_edge = SeperateSobelLayer(device)(warp_frame21) + loss = nn.L1Loss()(frame1_edge * confMask * gradient_mask, warp_frame21_edge * confMask * gradient_mask) + return loss diff --git a/FGT_codes/LAFC/models/utils/flow_losses.py b/FGT_codes/LAFC/models/utils/flow_losses.py new file mode 100644 index 0000000000000000000000000000000000000000..d1a266bdd6d85fcd0aeb6574ee62bda6b6a242b5 --- /dev/null +++ b/FGT_codes/LAFC/models/utils/flow_losses.py @@ -0,0 +1,517 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +import torchvision.models as models +import numpy as np +from .fbConsistencyCheck import image_warp + + +class FlowWarpingLoss(nn.Module): + def __init__(self, metric): + super(FlowWarpingLoss, self).__init__() + self.metric = metric + + def warp(self, x, flow): + """ + + Args: + x: torch tensor with shape [b, c, h, w], the x can be 3 (for rgb frame) or 2 (for optical flow) + flow: torch tensor with shape [b, 2, h, w] + + Returns: the warped x (can be an image or an optical flow) + + """ + h, w = x.shape[2:] + device = x.device + # normalize the flow to [-1~1] + flow = torch.cat([flow[:, 0:1, :, :] / ((w - 1) / 2), flow[:, 1:2, :, :] / ((h - 1) / 2)], dim=1) + flow = flow.permute(0, 2, 3, 1) # change to [b, h, w, c] + # generate meshgrid + x_idx = np.linspace(-1, 1, w) + y_idx = np.linspace(-1, 1, h) + X_idx, Y_idx = np.meshgrid(x_idx, y_idx) + grid = torch.cat((torch.from_numpy(X_idx.astype('float32')).unsqueeze(0).unsqueeze(3), + torch.from_numpy(Y_idx.astype('float32')).unsqueeze(0).unsqueeze(3)), 3).to(device) + output = torch.nn.functional.grid_sample(x, grid + flow, mode='bilinear', padding_mode='zeros') + return output + + def __call__(self, x, y, flow, mask): + """ + image/flow warping, only support the single image/flow warping + Args: + x: Can be optical flow or image with shape [b, c, h, w], c can be 2 or 3 + y: The ground truth of x (can be the extracted optical flow or image) + flow: The flow used to warp x, whose shape is [b, 2, h, w] + mask: The mask which indicates the hole of x, which must be [b, 1, h, w] + + Returns: the warped image/optical flow + + """ + warped_x = self.warp(x, flow) + loss = self.metric(warped_x * mask, y * mask) + return loss + + +class TVLoss(): + # shift one pixel to get difference ( for both x and y direction) + def __init__(self): + super(TVLoss, self).__init__() + + def __call__(self, x): + loss = torch.mean(torch.abs(x[:, :, :, :-1] - x[:, :, :, 1:])) + torch.mean( + torch.abs(x[:, :, :-1, :] - x[:, :, 1:, :])) + return loss + + +class WarpLoss(nn.Module): + def __init__(self): + super(WarpLoss, self).__init__() + self.metric = nn.L1Loss() + + def forward(self, flow, mask, img1, img2): + """ + + Args: + flow: flow indicates the motion from img1 to img2 + mask: mask corresponds to img1 + img1: frame 1 + img2: frame t+1 + + Returns: warp loss from img2 to img1 + + """ + img2_warped = image_warp(img2, flow) + loss = self.metric(img2_warped * mask, img1 * mask) + return loss + + +class AdversarialLoss(nn.Module): + r""" + Adversarial loss + https://arxiv.org/abs/1711.10337 + """ + + def __init__(self, type='nsgan', target_real_label=1.0, target_fake_label=0.0): + r""" + type = nsgan | lsgan | hinge + """ + super(AdversarialLoss, self).__init__() + + self.type = type + self.register_buffer('real_label', torch.tensor(target_real_label)) + self.register_buffer('fake_label', torch.tensor(target_fake_label)) + + if type == 'nsgan': + self.criterion = nn.BCELoss() + + elif type == 'lsgan': + self.criterion = nn.MSELoss() + + elif type == 'hinge': + self.criterion = nn.ReLU() + + def __call__(self, outputs, is_real, is_disc=None): + if self.type == 'hinge': + if is_disc: + if is_real: + outputs = -outputs + return self.criterion(1 + outputs).mean() + else: + return (-outputs).mean() + + else: + labels = (self.real_label if is_real else self.fake_label).expand_as(outputs) + loss = self.criterion(outputs, labels) + return loss + + +class StyleLoss(nn.Module): + r""" + Perceptual loss, VGG-based + https://arxiv.org/abs/1603.08155 + https://github.com/dxyang/StyleTransfer/blob/master/utils.py + """ + + def __init__(self): + super(StyleLoss, self).__init__() + self.add_module('vgg', VGG19()) + self.criterion = torch.nn.L1Loss() + + def compute_gram(self, x): + b, ch, h, w = x.size() + f = x.view(b, ch, w * h) + f_T = f.transpose(1, 2) + G = f.bmm(f_T) / (h * w * ch) + + return G + + def __call__(self, x, y): + # Compute features + x_vgg, y_vgg = self.vgg(x), self.vgg(y) + + # Compute loss + style_loss = 0.0 + style_loss += self.criterion(self.compute_gram(x_vgg['relu2_2']), self.compute_gram(y_vgg['relu2_2'])) + style_loss += self.criterion(self.compute_gram(x_vgg['relu3_4']), self.compute_gram(y_vgg['relu3_4'])) + style_loss += self.criterion(self.compute_gram(x_vgg['relu4_4']), self.compute_gram(y_vgg['relu4_4'])) + style_loss += self.criterion(self.compute_gram(x_vgg['relu5_2']), self.compute_gram(y_vgg['relu5_2'])) + + return style_loss + + +class PerceptualLoss(nn.Module): + r""" + Perceptual loss, VGG-based + https://arxiv.org/abs/1603.08155 + https://github.com/dxyang/StyleTransfer/blob/master/utils.py + """ + + def __init__(self, weights=[1.0, 1.0, 1.0, 1.0, 1.0]): + super(PerceptualLoss, self).__init__() + self.add_module('vgg', VGG19()) + self.criterion = torch.nn.L1Loss() + self.weights = weights + + def __call__(self, x, y): + # Compute features + x_vgg, y_vgg = self.vgg(x), self.vgg(y) + + content_loss = 0.0 + content_loss += self.weights[0] * self.criterion(x_vgg['relu1_1'], y_vgg['relu1_1']) + content_loss += self.weights[1] * self.criterion(x_vgg['relu2_1'], y_vgg['relu2_1']) + content_loss += self.weights[2] * self.criterion(x_vgg['relu3_1'], y_vgg['relu3_1']) + content_loss += self.weights[3] * self.criterion(x_vgg['relu4_1'], y_vgg['relu4_1']) + content_loss += self.weights[4] * self.criterion(x_vgg['relu5_1'], y_vgg['relu5_1']) + + return content_loss + + +class VGG19(torch.nn.Module): + def __init__(self): + super(VGG19, self).__init__() + features = models.vgg19(pretrained=True).features + self.relu1_1 = torch.nn.Sequential() + self.relu1_2 = torch.nn.Sequential() + + self.relu2_1 = torch.nn.Sequential() + self.relu2_2 = torch.nn.Sequential() + + self.relu3_1 = torch.nn.Sequential() + self.relu3_2 = torch.nn.Sequential() + self.relu3_3 = torch.nn.Sequential() + self.relu3_4 = torch.nn.Sequential() + + self.relu4_1 = torch.nn.Sequential() + self.relu4_2 = torch.nn.Sequential() + self.relu4_3 = torch.nn.Sequential() + self.relu4_4 = torch.nn.Sequential() + + self.relu5_1 = torch.nn.Sequential() + self.relu5_2 = torch.nn.Sequential() + self.relu5_3 = torch.nn.Sequential() + self.relu5_4 = torch.nn.Sequential() + + for x in range(2): + self.relu1_1.add_module(str(x), features[x]) + + for x in range(2, 4): + self.relu1_2.add_module(str(x), features[x]) + + for x in range(4, 7): + self.relu2_1.add_module(str(x), features[x]) + + for x in range(7, 9): + self.relu2_2.add_module(str(x), features[x]) + + for x in range(9, 12): + self.relu3_1.add_module(str(x), features[x]) + + for x in range(12, 14): + self.relu3_2.add_module(str(x), features[x]) + + for x in range(14, 16): + self.relu3_3.add_module(str(x), features[x]) + + for x in range(16, 18): + self.relu3_4.add_module(str(x), features[x]) + + for x in range(18, 21): + self.relu4_1.add_module(str(x), features[x]) + + for x in range(21, 23): + self.relu4_2.add_module(str(x), features[x]) + + for x in range(23, 25): + self.relu4_3.add_module(str(x), features[x]) + + for x in range(25, 27): + self.relu4_4.add_module(str(x), features[x]) + + for x in range(27, 30): + self.relu5_1.add_module(str(x), features[x]) + + for x in range(30, 32): + self.relu5_2.add_module(str(x), features[x]) + + for x in range(32, 34): + self.relu5_3.add_module(str(x), features[x]) + + for x in range(34, 36): + self.relu5_4.add_module(str(x), features[x]) + + # don't need the gradients, just want the features + for param in self.parameters(): + param.requires_grad = False + + def forward(self, x): + relu1_1 = self.relu1_1(x) + relu1_2 = self.relu1_2(relu1_1) + + relu2_1 = self.relu2_1(relu1_2) + relu2_2 = self.relu2_2(relu2_1) + + relu3_1 = self.relu3_1(relu2_2) + relu3_2 = self.relu3_2(relu3_1) + relu3_3 = self.relu3_3(relu3_2) + relu3_4 = self.relu3_4(relu3_3) + + relu4_1 = self.relu4_1(relu3_4) + relu4_2 = self.relu4_2(relu4_1) + relu4_3 = self.relu4_3(relu4_2) + relu4_4 = self.relu4_4(relu4_3) + + relu5_1 = self.relu5_1(relu4_4) + relu5_2 = self.relu5_2(relu5_1) + relu5_3 = self.relu5_3(relu5_2) + relu5_4 = self.relu5_4(relu5_3) + + out = { + 'relu1_1': relu1_1, + 'relu1_2': relu1_2, + + 'relu2_1': relu2_1, + 'relu2_2': relu2_2, + + 'relu3_1': relu3_1, + 'relu3_2': relu3_2, + 'relu3_3': relu3_3, + 'relu3_4': relu3_4, + + 'relu4_1': relu4_1, + 'relu4_2': relu4_2, + 'relu4_3': relu4_3, + 'relu4_4': relu4_4, + + 'relu5_1': relu5_1, + 'relu5_2': relu5_2, + 'relu5_3': relu5_3, + 'relu5_4': relu5_4, + } + return out + + +# Some losses related to optical flows +# From Unflow: https://github.com/simonmeister/UnFlow +def fbLoss(forward_flow, backward_flow, forward_gt_flow, backward_gt_flow, fb_loss_weight, image_warp_loss_weight=0, + occ_weight=0, beta=255, first_image=None, second_image=None): + """ + calculate the forward-backward consistency loss and the related image warp loss + Args: + forward_flow: torch tensor, with shape [b, c, h, w] + backward_flow: torch tensor, with shape [b, c, h, w] + forward_gt_flow: the ground truth of the forward flow (used for occlusion calculation) + backward_gt_flow: the ground truth of the backward flow (used for occlusion calculation) + fb_loss_weight: loss weight for forward-backward consistency check between two frames + image_warp_loss_weight: loss weight for image warping + occ_weight: loss weight for occlusion area (serve as a punishment for image warp loss) + beta: 255 by default, according to the original loss codes in unflow + first_image: the previous image (extraction for the optical flows) + second_image: the later image (extraction for the optical flows) + Note: forward and backward flow should be extracted from the same image pair + Returns: forward backward consistency loss between forward and backward flow + + """ + mask_fw = create_outgoing_mask(forward_flow).float() + mask_bw = create_outgoing_mask(backward_flow).float() + + # forward warp backward flow and backward forward flow to calculate the cycle consistency + forward_flow_warped = image_warp(forward_flow, backward_gt_flow) + forward_flow_warped_gt = image_warp(forward_gt_flow, backward_gt_flow) + backward_flow_warped = image_warp(backward_flow, forward_gt_flow) + backward_flow_warped_gt = image_warp(backward_gt_flow, forward_gt_flow) + flow_diff_fw = backward_flow_warped + forward_flow + flow_diff_fw_gt = backward_flow_warped_gt + forward_gt_flow + flow_diff_bw = backward_flow + forward_flow_warped + flow_diff_bw_gt = backward_gt_flow + forward_flow_warped_gt + + # occlusion calculation + mag_sq_fw = length_sq(forward_gt_flow) + length_sq(backward_flow_warped_gt) + mag_sq_bw = length_sq(backward_gt_flow) + length_sq(forward_flow_warped_gt) + occ_thresh_fw = 0.01 * mag_sq_fw + 0.5 + occ_thresh_bw = 0.01 * mag_sq_bw + 0.5 + + fb_occ_fw = (length_sq(flow_diff_fw_gt) > occ_thresh_fw).float() + fb_occ_bw = (length_sq(flow_diff_bw_gt) > occ_thresh_bw).float() + + mask_fw *= (1 - fb_occ_fw) + mask_bw *= (1 - fb_occ_bw) + + occ_fw = 1 - mask_fw + occ_bw = 1 - mask_bw + + if image_warp_loss_weight != 0: + # warp images + second_image_warped = image_warp(second_image, forward_flow) # frame 2 -> 1 + first_image_warped = image_warp(first_image, backward_flow) # frame 1 -> 2 + im_diff_fw = first_image - second_image_warped + im_diff_bw = second_image - first_image_warped + # calculate the image warp loss based on the occlusion regions calculated by forward and backward flows (gt) + occ_loss = occ_weight * (charbonnier_loss(occ_fw) + charbonnier_loss(occ_bw)) + image_warp_loss = image_warp_loss_weight * ( + charbonnier_loss(im_diff_fw, mask_fw, beta=beta) + charbonnier_loss(im_diff_bw, mask_bw, + beta=beta)) + occ_loss + else: + image_warp_loss = 0 + fb_loss = fb_loss_weight * (charbonnier_loss(flow_diff_fw, mask_fw) + charbonnier_loss(flow_diff_bw, mask_bw)) + return fb_loss + image_warp_loss + + +def length_sq(x): + return torch.sum(torch.square(x), 1, keepdim=True) + + +def smoothness_loss(flow, cmask): + delta_u, delta_v, mask = smoothness_deltas(flow) + loss_u = charbonnier_loss(delta_u, cmask) + loss_v = charbonnier_loss(delta_v, cmask) + return loss_u + loss_v + + +def smoothness_deltas(flow): + """ + flow: [b, c, h, w] + """ + mask_x = create_mask(flow, [[0, 0], [0, 1]]) + mask_y = create_mask(flow, [[0, 1], [0, 0]]) + mask = torch.cat((mask_x, mask_y), dim=1) + mask = mask.to(flow.device) + filter_x = torch.tensor([[0, 0, 0.], [0, 1, -1], [0, 0, 0]]) + filter_y = torch.tensor([[0, 0, 0.], [0, 1, 0], [0, -1, 0]]) + weights = torch.ones([2, 1, 3, 3]) + weights[0, 0] = filter_x + weights[1, 0] = filter_y + weights = weights.to(flow.device) + + flow_u, flow_v = torch.split(flow, split_size_or_sections=1, dim=1) + delta_u = F.conv2d(flow_u, weights, stride=1, padding=1) + delta_v = F.conv2d(flow_v, weights, stride=1, padding=1) + return delta_u, delta_v, mask + + +def second_order_loss(flow, cmask): + delta_u, delta_v, mask = second_order_deltas(flow) + loss_u = charbonnier_loss(delta_u, cmask) + loss_v = charbonnier_loss(delta_v, cmask) + return loss_u + loss_v + + +def charbonnier_loss(x, mask=None, truncate=None, alpha=0.45, beta=1.0, epsilon=0.001): + """ + Compute the generalized charbonnier loss of the difference tensor x + All positions where mask == 0 are not taken into account + x: a tensor of shape [b, c, h, w] + mask: a mask of shape [b, mc, h, w], where mask channels must be either 1 or the same as + the number of channels of x. Entries should be 0 or 1 + return: loss + """ + b, c, h, w = x.shape + norm = b * c * h * w + error = torch.pow(torch.square(x * beta) + torch.square(torch.tensor(epsilon)), alpha) + if mask is not None: + error = mask * error + if truncate is not None: + error = torch.min(error, truncate) + return torch.sum(error) / norm + + +def second_order_deltas(flow): + """ + consider the single flow first + flow shape: [b, c, h, w] + """ + # create mask + mask_x = create_mask(flow, [[0, 0], [1, 1]]) + mask_y = create_mask(flow, [[1, 1], [0, 0]]) + mask_diag = create_mask(flow, [[1, 1], [1, 1]]) + mask = torch.cat((mask_x, mask_y, mask_diag, mask_diag), dim=1) + mask = mask.to(flow.device) + + filter_x = torch.tensor([[0, 0, 0.], [1, -2, 1], [0, 0, 0]]) + filter_y = torch.tensor([[0, 1, 0.], [0, -2, 0], [0, 1, 0]]) + filter_diag1 = torch.tensor([[1, 0, 0.], [0, -2, 0], [0, 0, 1]]) + filter_diag2 = torch.tensor([[0, 0, 1.], [0, -2, 0], [1, 0, 0]]) + weights = torch.ones([4, 1, 3, 3]) + weights[0] = filter_x + weights[1] = filter_y + weights[2] = filter_diag1 + weights[3] = filter_diag2 + weights = weights.to(flow.device) + + # split the flow into flow_u and flow_v, conv them with the weights + flow_u, flow_v = torch.split(flow, split_size_or_sections=1, dim=1) + delta_u = F.conv2d(flow_u, weights, stride=1, padding=1) + delta_v = F.conv2d(flow_v, weights, stride=1, padding=1) + return delta_u, delta_v, mask + + +def create_mask(tensor, paddings): + """ + tensor shape: [b, c, h, w] + paddings: [2 x 2] shape list, the first row indicates up and down paddings + the second row indicates left and right paddings + | | + | x | + | x * x | + | x | + | | + """ + shape = tensor.shape + inner_height = shape[2] - (paddings[0][0] + paddings[0][1]) + inner_width = shape[3] - (paddings[1][0] + paddings[1][1]) + inner = torch.ones([inner_height, inner_width]) + torch_paddings = [paddings[1][0], paddings[1][1], paddings[0][0], paddings[0][1]] # left, right, up and down + mask2d = F.pad(inner, pad=torch_paddings) + mask3d = mask2d.unsqueeze(0).repeat(shape[0], 1, 1) + mask4d = mask3d.unsqueeze(1) + return mask4d.detach() + + +def create_outgoing_mask(flow): + """ + Computes a mask that is zero at all positions where the flow would carry a pixel over the image boundary + For such pixels, it's invalid to calculate the flow losses + Args: + flow: torch tensor: with shape [b, 2, h, w] + + Returns: a mask, 1 indicates in-boundary pixels, with shape [b, 1, h, w] + + """ + b, c, h, w = flow.shape + + grid_x = torch.reshape(torch.arange(0, w), [1, 1, w]) + grid_x = grid_x.repeat(b, h, 1).float() + grid_y = torch.reshape(torch.arange(0, h), [1, h, 1]) + grid_y = grid_y.repeat(b, 1, w).float() + + grid_x = grid_x.to(flow.device) + grid_y = grid_y.to(flow.device) + + flow_u, flow_v = torch.split(flow, split_size_or_sections=1, dim=1) # [b, h, w] + pos_x = grid_x + flow_u + pos_y = grid_y + flow_v + inside_x = torch.logical_and(pos_x <= w - 1, pos_x >= 0) + inside_y = torch.logical_and(pos_y <= h - 1, pos_y >= 0) + inside = torch.logical_and(inside_x, inside_y) + if len(inside.shape) == 3: + inside = inside.unsqueeze(1) + return inside diff --git a/FGT_codes/LAFC/models/utils/flow_warp.py b/FGT_codes/LAFC/models/utils/flow_warp.py new file mode 100644 index 0000000000000000000000000000000000000000..9e0de5524552420ee4ff69240c95641f621dac2d --- /dev/null +++ b/FGT_codes/LAFC/models/utils/flow_warp.py @@ -0,0 +1,94 @@ +import torch + + +def flow_prop(feat, flow, mode='forward'): + """ + + Args: + feat: features to be aligned + flow: the filled current flow + mode: `forward` or `backward`, indicates the propagation direction + + Returns: feature after warping + + """ + assert mode in ['forward', 'backward'], 'Invalid mode: {}'.format(mode) + feat = warp(feat, flow, mode) + + return feat + + +def warp(feat, flow, mode): + device = feat.device + c = feat.shape[1] + y = flow[:, 0:1, :, :] + x = flow[:, 1:2, :, :] + + x = x.repeat(1, c, 1, 1) # [b, c, h, w] + y = y.repeat(1, c, 1, 1) + + x1 = torch.floor(x) + x2 = x1 + 1 + y1 = torch.floor(y) + y2 = y1 + 1 + + w11, w12, w21, w22 = get_gaussian_weights(x, y, x1, y1, x2, y2) + + feat11, o11 = sample_one(feat, x1, y1, w11, mode) + feat12, o12 = sample_one(feat, x1, y2, w12, mode) + feat21, o21 = sample_one(feat, x2, y1, w21, mode) + feat22, o22 = sample_one(feat, x2, y2, w22, mode) + + feat_o = feat11 + feat12 + feat21 + feat22 + o = o11 + o12 + o21 + o22 + feat_o[o > 0] = feat_o[o > 0] / o[o > 0] + return feat_o + + +def sample_one(feat, shiftx, shifty, weight, mode): + device = feat.device + b, c, h, w = feat.shape + flat_shiftx = shiftx.view(-1) # [b * c * h * w] + flat_shifty = shifty.view(-1) + flat_basex = torch.arange(0, h, requires_grad=False).view(-1, 1).long().repeat(b, c, 1, w).view(-1) + flat_basey = torch.arange(0, w, requires_grad=False).view(-1, 1).long().repeat(b, c, h, 1).view(-1) + flat_basex = flat_basex.to(device) + flat_basey = flat_basey.to(device) + flat_weight = weight.reshape(-1) + flat_feat = feat.reshape(-1) + + idxn = torch.arange(0, b, requires_grad=False).view(b, 1, 1, 1).long().repeat(1, c, h, w).view(-1) + idxc = torch.arange(0, c, requires_grad=False).view(1, c, 1, 1).long().repeat(b, 1, h, w).view(-1) + idxn = idxn.to(device) + idxc = idxc.to(device) + if mode == 'forward': + idxx = flat_shiftx.long() + flat_basex # size [-1] + idxy = flat_shifty.long() + flat_basey # size [-1] + else: # backward propagation + idxx = -flat_shiftx.long() + flat_basex # size [-1] + idxy = -flat_shifty.long() + flat_basey # size [-1] + + # record the shifted pixels inside the image boundaries + mask = idxx.ge(0) & idxx.lt(h) & idxy.ge(0) & idxy.lt(w) + + # mask off points out of boundaries + ids = idxn * c * h * w + idxc * h * w + idxx * w + idxy + ids_mask = torch.masked_select(ids, mask).clone() + + # put the value into corresponding regions + feat_warp = torch.zeros([b * c * h * w]) + feat_warp = feat_warp.to(device) + feat_warp.put_(ids_mask, torch.masked_select(flat_feat * flat_weight, mask), accumulate=True) + one_warp = torch.zeros([b * c * h * w]) + one_warp = one_warp.to(device) + one_warp.put_(ids_mask, torch.masked_select(flat_weight, mask), accumulate=True) + return feat_warp.view(b, c, h, w), one_warp.view(b, c, h, w) + + +def get_gaussian_weights(x, y, x1, y1, x2, y2): + sigma = 1 + w11 = torch.exp(-((x - x1) ** 2 + (y - y1) ** 2) / (sigma ** 2)) + w12 = torch.exp(-((x - x1) ** 2 + (y - y2) ** 2) / (sigma ** 2)) + w21 = torch.exp(-((x - x2) ** 2 + (y - y1) ** 2) / (sigma ** 2)) + w22 = torch.exp(-((x - x2) ** 2 + (y - y2) ** 2) / (sigma ** 2)) + return w11, w12, w21, w22 diff --git a/FGT_codes/LAFC/models/utils/loss.py b/FGT_codes/LAFC/models/utils/loss.py new file mode 100644 index 0000000000000000000000000000000000000000..fd2586d7cfd5e1dbc07dc9c0136f5499cb0dc7f0 --- /dev/null +++ b/FGT_codes/LAFC/models/utils/loss.py @@ -0,0 +1,474 @@ +import os +import sys + +import torch +import torch.nn as nn +import numpy as np + + +class AlignLoss(nn.Module): + def __init__(self, reduction='mean'): + super().__init__() + self.loss_fn = nn.L1Loss(reduction=reduction) + + def forward(self, frames, masks, aligned_vs, aligned_rs): + """ + + :param frames: The original frames(GT) + :param masks: Original masks + :param aligned_vs: aligned visibility map from reference frame(List: B, C, T, H, W) + :param aligned_rs: aligned reference frames(List: B, C, T, H, W) + :return: + """ + try: + B, C, T, H, W = frames.shape + except ValueError: + frames = frames.unsqueeze(2) + masks = masks.unsqueeze(2) + B, C, T, H, W = frames.shape + loss = 0 + for i in range(T): + frame = frames[:, :, i] + mask = masks[:, :, i] + aligned_v = aligned_vs[i] + aligned_r = aligned_rs[i] + loss += self._singleFrameAlignLoss(frame, mask, aligned_v, aligned_r) + return loss + + def _singleFrameAlignLoss(self, targetFrame, targetMask, aligned_v, aligned_r): + """ + + :param targetFrame: targetFrame to be aligned-> B, C, H, W + :param targetMask: the mask of target frames + :param aligned_v: aligned visibility map from reference frame + :param aligned_r: aligned reference frame-> B, C, T, H, W + :return: + """ + targetVisibility = 1. - targetMask + targetVisibility = targetVisibility.unsqueeze(2) + targetFrame = targetFrame.unsqueeze(2) + visibility_map = targetVisibility * aligned_v + target_visibility = visibility_map * targetFrame + reference_visibility = visibility_map * aligned_r + loss = 0 + for i in range(aligned_r.shape[2]): + loss += self.loss_fn(target_visibility[:, :, i], reference_visibility[:, :, i]) + return loss + + +class HoleVisibleLoss(nn.Module): + def __init__(self, reduction='mean'): + super().__init__() + self.loss_fn = nn.L1Loss(reduction=reduction) + + def forward(self, outputs, masks, GTs, c_masks): + try: + B, C, T, H, W = outputs.shape + except ValueError: + outputs = outputs.unsqueeze(2) + masks = masks.unsqueeze(2) + GTs = GTs.unsqueeze(2) + c_masks = c_masks.unsqueeze(2) + B, C, T, H, W = outputs.shape + loss = 0 + for i in range(T): + loss += self._singleFrameHoleVisibleLoss(outputs[:, :, i], masks[:, :, i], c_masks[:, :, i], GTs[:, :, i]) + return loss + + def _singleFrameHoleVisibleLoss(self, targetFrame, targetMask, c_mask, GT): + return self.loss_fn(targetMask * c_mask * targetFrame, targetMask * c_mask * GT) + + +class HoleInvisibleLoss(nn.Module): + def __init__(self, reduction='mean'): + super().__init__() + self.loss_fn = nn.L1Loss(reduction=reduction) + + def forward(self, outputs, masks, GTs, c_masks): + try: + B, C, T, H, W = outputs.shape + except ValueError: + outputs = outputs.unsqueeze(2) + masks = masks.unsqueeze(2) + GTs = GTs.unsqueeze(2) + c_masks = c_masks.unsqueeze(2) + B, C, T, H, W = outputs.shape + loss = 0 + for i in range(T): + loss += self._singleFrameHoleInvisibleLoss(outputs[:, :, i], masks[:, :, i], c_masks[:, :, i], GTs[:, :, i]) + return loss + + def _singleFrameHoleInvisibleLoss(self, targetFrame, targetMask, c_mask, GT): + return self.loss_fn(targetMask * (1. - c_mask) * targetFrame, targetMask * (1. - c_mask) * GT) + + +class NonHoleLoss(nn.Module): + def __init__(self, reduction='mean'): + super().__init__() + self.loss_fn = nn.L1Loss(reduction=reduction) + + def forward(self, outputs, masks, GTs): + try: + B, C, T, H, W = outputs.shape + except ValueError: + outputs = outputs.unsqueeze(2) + masks = masks.unsqueeze(2) + GTs = GTs.unsqueeze(2) + B, C, T, H, W = outputs.shape + loss = 0 + for i in range(T): + loss += self._singleNonHoleLoss(outputs[:, :, i], masks[:, :, i], GTs[:, :, i]) + return loss + + def _singleNonHoleLoss(self, targetFrame, targetMask, GT): + return self.loss_fn((1. - targetMask) * targetFrame, (1. - targetMask) * GT) + + +class ReconLoss(nn.Module): + def __init__(self, reduction='mean', masked=False): + super().__init__() + self.loss_fn = nn.L1Loss(reduction=reduction) + self.masked = masked + + def forward(self, model_output, target, mask): + outputs = model_output + targets = target + if self.masked: + masks = mask + return self.loss_fn(outputs * masks, targets * masks) # L1 loss in masked region + else: + return self.loss_fn(outputs, targets) # L1 loss in the whole region + + +class VGGLoss(nn.Module): + def __init__(self, vgg): + super().__init__() + self.l1_loss = nn.L1Loss() + self.vgg = vgg + + def vgg_loss(self, output, target): + output_feature = self.vgg(output) + target_feature = self.vgg(target) + loss = ( + self.l1_loss(output_feature.relu2_2, target_feature.relu2_2) + + self.l1_loss(output_feature.relu3_3, target_feature.relu3_3) + + self.l1_loss(output_feature.relu4_3, target_feature.relu4_3) + ) + return loss + + def forward(self, data_input, model_output): + targets = data_input + outputs = model_output + mean_image_loss = self.vgg_loss(outputs, targets) + return mean_image_loss + + +class StyleLoss(nn.Module): + def __init__(self, vgg, original_channel_norm=True): + super().__init__() + self.l1_loss = nn.L1Loss() + self.vgg = vgg + self.original_channel_norm = original_channel_norm + + # From https://github.com/pytorch/tutorials/blob/master/advanced_source/neural_style_tutorial.py + def gram_matrix(self, input): + a, b, c, d = input.size() # a=batch size(=1) + # b=number of feature maps + # (c,d)=dimensions of a f. map (N=c*d) + + features = input.view(a * b, c * d) # resise F_XL into \hat F_XL + + G = torch.mm(features, features.t()) # compute the gram product + + # we 'normalize' the values of the gram matrix + # by dividing by the number of element in each feature maps. + return G.div(a * b * c * d) + + # Implement "Image Inpainting for Irregular Holes Using Partial Convolutions", Liu et al., 2018 + def style_loss(self, output, target): + output_features = self.vgg(output) + target_features = self.vgg(target) + layers = ['relu2_2', 'relu3_3', 'relu4_3'] # n_channel: 128 (=2 ** 7), 256 (=2 ** 8), 512 (=2 ** 9) + loss = 0 + for i, layer in enumerate(layers): + output_feature = getattr(output_features, layer) + target_feature = getattr(target_features, layer) + B, C_P, H, W = output_feature.shape + output_gram_matrix = self.gram_matrix(output_feature) + target_gram_matrix = self.gram_matrix(target_feature) + if self.original_channel_norm: + C_P_square_divider = 2 ** (i + 1) # original design (avoid too small loss) + else: + C_P_square_divider = C_P ** 2 + assert C_P == 128 * 2 ** i + loss += self.l1_loss(output_gram_matrix, target_gram_matrix) / C_P_square_divider + return loss + + def forward(self, data_input, model_output): + targets = data_input + outputs = model_output + mean_image_loss = self.style_loss(outputs, targets) + return mean_image_loss + + +class L1LossMaskedMean(nn.Module): + def __init__(self): + super().__init__() + self.l1 = nn.L1Loss(reduction='sum') + + def forward(self, x, y, mask): + masked = 1 - mask # 默认missing region的mask值为0,原有区域为1 + l1_sum = self.l1(x * masked, y * masked) + return l1_sum / torch.sum(masked) + + +class L2LossMaskedMean(nn.Module): + def __init__(self, reduction='sum'): + super().__init__() + self.l2 = nn.MSELoss(reduction=reduction) + + def forward(self, x, y, mask): + masked = 1 - mask + l2_sum = self.l2(x * masked, y * masked) + return l2_sum / torch.sum(masked) + + +class ImcompleteVideoReconLoss(nn.Module): + def __init__(self): + super().__init__() + self.loss_fn = L1LossMaskedMean() + + def forward(self, data_input, model_output): + imcomplete_video = model_output['imcomplete_video'] + targets = data_input['targets'] + down_sampled_targets = nn.functional.interpolate( + targets.transpose(1, 2), scale_factor=[1, 0.5, 0.5]) + + masks = data_input['masks'] + down_sampled_masks = nn.functional.interpolate( + masks.transpose(1, 2), scale_factor=[1, 0.5, 0.5]) + return self.loss_fn( + imcomplete_video, down_sampled_targets, + down_sampled_masks + ) + + +class CompleteFramesReconLoss(nn.Module): + def __init__(self): + super().__init__() + self.loss_fn = L1LossMaskedMean() + + def forward(self, data_input, model_output): + outputs = model_output['outputs'] + targets = data_input['targets'] + masks = data_input['masks'] + return self.loss_fn(outputs, targets, masks) + + +class AdversarialLoss(nn.Module): + r""" + Adversarial loss + https://arxiv.org/abs/1711.10337 + """ + + def __init__(self, type='nsgan', target_real_label=1.0, target_fake_label=0.0): + r""" + type = nsgan | lsgan | hinge + """ + super(AdversarialLoss, self).__init__() + self.type = type + self.register_buffer('real_label', torch.tensor(target_real_label)) + self.register_buffer('fake_label', torch.tensor(target_fake_label)) + + if type == 'nsgan': + self.criterion = nn.BCELoss() + elif type == 'lsgan': + self.criterion = nn.MSELoss() + elif type == 'hinge': + self.criterion = nn.ReLU() + + def __call__(self, outputs, is_real, is_disc=None): + if self.type == 'hinge': + if is_disc: + if is_real: + outputs = -outputs + return self.criterion(1 + outputs).mean() + else: + return (-outputs).mean() + else: + labels = (self.real_label if is_real else self.fake_label).expand_as( + outputs) + loss = self.criterion(outputs, labels) + return loss + + +# # From https://github.com/phoenix104104/fast_blind_video_consistency +# class TemporalWarpingLoss(nn.Module): +# def __init__(self, opts, flownet_checkpoint_path=None, alpha=50): +# super().__init__() +# self.loss_fn = L1LossMaskedMean() +# self.alpha = alpha +# self.opts = opts +# +# assert flownet_checkpoint_path is not None, "Flownet2 pretrained models must be provided" +# +# self.flownet_checkpoint_path = flownet_checkpoint_path +# raise NotImplementedError +# +# def get_flownet_checkpoint_path(self): +# return self.flownet_checkpoint_path +# +# def _flownetwrapper(self): +# Flownet = FlowNet2(self.opts, requires_grad=False) +# Flownet2_ckpt = torch.load(self.flownet_checkpoint_path) +# Flownet.load_state_dict(Flownet2_ckpt['state_dict']) +# Flownet.to(device) +# Flownet.exal() +# return Flownet +# +# def _setup(self): +# self.flownet = self._flownetwrapper() +# +# def _get_non_occlusuib_mask(self, targets, warped_targets): +# non_occlusion_masks = torch.exp( +# -self.alpha * torch.sum(targets[:, 1:] - warped_targets, dim=2).pow(2) +# ).unsqueeze(2) +# return non_occlusion_masks +# +# def _get_loss(self, outputs, warped_outputs, non_occlusion_masks, masks): +# return self.loss_fn( +# outputs[:, 1:] * non_occlusion_masks, +# warped_outputs * non_occlusion_masks, +# masks[:, 1:] +# ) +# +# def forward(self, data_input, model_output): +# if self.flownet is None: +# self._setup() +# +# targets = data_input['targets'].to(device) +# outputs = model_output['outputs'].to(device) +# flows = self.flownet.infer_video(targets).to(device) +# +# from utils.flow_utils import warp_optical_flow +# warped_targets = warp_optical_flow(targets[:, :-1], -flows).detach() +# warped_outputs = warp_optical_flow(outputs[:, :-1], -flows).detach() +# non_occlusion_masks = self._get_non_occlusion_mask(targets, warped_targets) +# +# # model_output is passed by name and dictionary is mutable +# # These values are sent to trainer for visualization +# model_output['warped_outputs'] = warped_outputs[0] +# model_output['warped_targets'] = warped_targets[0] +# model_output['non_occlusion_masks'] = non_occlusion_masks[0] +# from utils.flow_utils import flow_to_image +# flow_imgs = [] +# for flow in flows[0]: +# flow_img = flow_to_image(flow.cpu().permute(1, 2, 0).detach().numpy()).transpose(2, 0, 1) +# flow_imgs.append(torch.Tensor(flow_img)) +# model_output['flow_imgs'] = flow_imgs +# +# masks = data_input['masks'].to(device) +# return self._get_loss(outputs, warped_outputs, non_occlusion_masks, masks) +# +# +# class TemporalWarpingError(TemporalWarpingLoss): +# def __init__(self, flownet_checkpoint_path, alpha=50): +# super().__init__(flownet_checkpoint_path, alpha) +# self.loss_fn = L2LossMaskedMean(reduction='none') +# +# def _get_loss(self, outputs, warped_outputs, non_occlusion_masks, masks): +# # See https://arxiv.org/pdf/1808.00449.pdf 4.3 +# # The sum of non_occlusion_masks is different for each video, +# # So the batch dim is kept +# loss = self.loss_fn( +# outputs[:, 1:] * non_occlusion_masks, +# warped_outputs * non_occlusion_masks, +# masks[:, 1:] +# ).sum(1).sum(1).sum(1).sum(1) +# +# loss = loss / non_occlusion_masks.sum(1).sum(1).sum(1).sum(1) +# return loss.sum() + + +class ValidLoss(nn.Module): + def __init__(self): + super(ValidLoss, self).__init__() + self.loss_fn = nn.L1Loss(reduction='mean') + + def forward(self, model_output, target, mk): + outputs = model_output + targets = target + return self.loss_fn(outputs * (1 - mk), targets * (1 - mk)) # L1 loss in masked region + + + +class TVLoss(nn.Module): + def __init__(self): + super(TVLoss, self).__init__() + + def forward(self, mask_input, model_output): + # View 3D data as 2D + outputs = model_output + + if len(mask_input.shape) == 4: + mask_input = mask_input.unsqueeze(2) + if len(outputs.shape) == 4: + outputs = outputs.unsqueeze(2) + + outputs = outputs.permute((0, 2, 1, 3, 4)).contiguous() + masks = mask_input.permute((0, 2, 1, 3, 4)).contiguous() + + B, L, C, H, W = outputs.shape + x = outputs.view([B * L, C, H, W]) + + masks = masks.view([B * L, -1]) + mask_areas = masks.sum(dim=1) + + h_x = x.size()[2] + w_x = x.size()[3] + h_tv = torch.pow((x[:, :, 1:, :] - x[:, :, :h_x - 1, :]), 2).sum(1).sum(1).sum(1) # 差分是为了求梯度,本质上还是梯度平方和 + w_tv = torch.pow((x[:, :, :, 1:] - x[:, :, :, :w_x - 1]), 2).sum(1).sum(1).sum(1) + return ((h_tv + w_tv) / mask_areas).mean() + + +# for debug +def show_images(image, name): + import cv2 + import numpy as np + image = np.array(image) + image[image > 0.5] = 255. + image = image.transpose((1, 2, 0)) + cv2.imwrite(name, image) + + +if __name__ == '__main__': + # test align loss, + targetFrame = torch.ones(1, 3, 32, 32) + GT = torch.ones(1, 3, 32, 32) + GT += 1 + mask = torch.zeros(1, 1, 32, 32) + mask[:, :, 8:24, 8:24] = 1. + + # referenceFrames = torch.ones(1, 3, 4, 32, 32) + # referenceMasks = torch.zeros(1, 1, 4, 32, 32) + # referenceMasks[:, :, 0, 4:12, 4:12] = 1. + # referenceFrames[:, :, 0, 4:12, 4:12] = 2. + # referenceMasks[:, :, 1, 4:12, 20:28] = 1. + # referenceFrames[:, :, 1, 4:12, 20:28] = 2. + # referenceMasks[:, :, 2, 20:28, 4:12] = 1. + # referenceFrames[:, :, 2, 20:28, 4:12] = 2. + # referenceMasks[:, :, 3, 20:28, 20:28] = 1. + # referenceFrames[:, :, 3, 20:28, 20:28] = 2. + # + # aligned_v = referenceMasks + # aligned_v, referenceFrames = [aligned_v], [referenceFrames] + # + # result = AlignLoss()(targetFrame, mask, aligned_v, referenceFrames) + # print(result) + + c_mask = torch.zeros(1, 1, 32, 32) + c_mask[:, :, 8:16, 16:24] = 1. + result1 = HoleVisibleLoss()(targetFrame, mask, GT, c_mask) + result2 = HoleInvisibleLoss()(targetFrame, mask, GT, c_mask) + result3 = NonHoleLoss()(targetFrame, mask, GT) + print('vis: {}, invis: {}, gt: {}'.format(result1, result2, result3)) diff --git a/FGT_codes/LAFC/models/utils/network_blocks.py b/FGT_codes/LAFC/models/utils/network_blocks.py new file mode 100644 index 0000000000000000000000000000000000000000..8e55b31714f7d109cccbb1527e96fe6b4e9d3ddb --- /dev/null +++ b/FGT_codes/LAFC/models/utils/network_blocks.py @@ -0,0 +1,185 @@ +import torch +import torch.nn as nn +import numpy as np +import torch.nn.functional as F + + +class VanillaConv(nn.Module): + def __init__( + self, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, + groups=1, bias=True, norm="SN", activation=nn.LeakyReLU(0.2, inplace=True) + ): + + super().__init__() + + self.padding = tuple(((np.array(kernel_size) - 1) * np.array(dilation)) // 2) if padding == -1 else padding + self.featureConv = nn.Conv3d( + in_channels, out_channels, kernel_size, + stride, self.padding, dilation, groups, bias) + + self.norm = norm + if norm == "BN": + self.norm_layer = nn.BatchNorm3d(out_channels) + elif norm == "IN": + self.norm_layer = nn.InstanceNorm3d(out_channels, track_running_stats=True) + elif norm == "SN": + self.norm = None + self.featureConv = nn.utils.spectral_norm(self.featureConv) + else: + self.norm = None + + self.activation = activation + + def forward(self, xs): + out = self.featureConv(xs) + if self.activation: + out = self.activation(out) + if self.norm is not None: + out = self.norm_layer(out) + return out + + +class VanillaDeconv(nn.Module): + def __init__( + self, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, + groups=1, bias=True, norm="SN", activation=nn.LeakyReLU(0.2, inplace=True), + scale_factor=2 + ): + super().__init__() + self.conv = VanillaConv( + in_channels, out_channels, kernel_size, stride, padding, dilation, + groups, bias, norm, activation) + self.scale_factor = scale_factor + + def forward(self, xs): + xs_resized = F.interpolate(xs, scale_factor=(1, self.scale_factor, self.scale_factor)) + return self.conv(xs_resized) + + +class GatedConv(VanillaConv): + def __init__( + self, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, + groups=1, bias=True, norm="SN", activation=nn.LeakyReLU(0.2, inplace=True) + ): + super().__init__( + in_channels, out_channels, kernel_size, stride, padding, dilation, + groups, bias, norm, activation + ) + self.gatingConv = nn.Conv3d( + in_channels, out_channels, kernel_size, + stride, self.padding, dilation, groups, bias) + if norm == 'SN': + self.gatingConv = nn.utils.spectral_norm(self.gatingConv) + self.sigmoid = nn.Sigmoid() + self.store_gated_values = False + + def gated(self, mask): + # return torch.clamp(mask, -1, 1) + out = self.sigmoid(mask) + if self.store_gated_values: + self.gated_values = out.detach().cpu() + return out + + def forward(self, xs): + gating = self.gatingConv(xs) + feature = self.featureConv(xs) + if self.activation: + feature = self.activation(feature) + out = self.gated(gating) * feature + if self.norm is not None: + out = self.norm_layer(out) + return out + + +class GatedDeconv(VanillaDeconv): + def __init__( + self, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, + groups=1, bias=True, norm="SN", activation=nn.LeakyReLU(0.2, inplace=True), + scale_factor=2 + ): + super().__init__( + in_channels, out_channels, kernel_size, stride, padding, dilation, + groups, bias, norm, activation, scale_factor + ) + self.conv = GatedConv( + in_channels, out_channels, kernel_size, stride, padding, dilation, + groups, bias, norm, activation) + + +class PartialConv(VanillaConv): + def __init__(self, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, + groups=1, bias=True, norm="SN", activation=nn.LeakyReLU(0.2, inplace=True)): + super().__init__( + in_channels, out_channels, kernel_size, stride, padding, dilation, + groups, bias, norm, activation + ) + self.mask_sum_conv = self.module.Conv3d(1, 1, kernel_size, + stride, padding, dilation, groups, False) + nn.init.constant_(self.mask_sum_conv.weight, 1.0) + + # mask conv needs not update + for param in self.mask_sum_conv.parameters(): + param.requires_grad = False + + if norm == "SN": + self.featureConv = nn.utils.spectral_norm(self.featureConv) + raise NotImplementedError(f"Norm type {norm} not implemented") + + def forward(self, input_tuple): + # http://masc.cs.gmu.edu/wiki/partialconv + # C(X) = W^T * X + b, C(0) = b, D(M) = 1 * M + 0 = sum(M) + # output = W^T* (M .* X) / sum(M) + b = [C(M .* X) – C(0)] / D(M) + C(0), if sum(M) != 0 + # = 0, if sum(M) == 0 + inp, mask = input_tuple + + # C(M .* X) + output = self.featureConv(mask * inp) + + # C(0) = b + if self.featureConv.bias is not None: + output_bias = self.featureConv.bias.view(1, -1, 1, 1, 1) + else: + output_bias = torch.zeros([1, 1, 1, 1, 1]).to(inp.device) + + # D(M) = sum(M) + with torch.no_grad(): + mask_sum = self.mask_sum_conv(mask) + + # find those sum(M) == 0 + no_update_holes = (mask_sum == 0) + + # Just to prevent devided by 0 + mask_sum_no_zero = mask_sum.masked_fill_(no_update_holes, 1.0) + + # output = [C(M .* X) – C(0)] / D(M) + C(0), if sum(M) != 0 + # = 0, if sum (M) == 0 + output = (output - output_bias) / mask_sum_no_zero + output_bias + output = output.masked_fill_(no_update_holes, 0.0) + + # create a new mask with only 1 or 0 + new_mask = torch.ones_like(mask_sum) + new_mask = new_mask.masked_fill_(no_update_holes, 0.0) + + if self.activation is not None: + output = self.activation(output) + if self.norm is not None: + output = self.norm_layer(output) + return output, new_mask + + +class PartialDeconv(nn.Module): + def __init__(self, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, + groups=1, bias=True, norm="SN", activation=nn.LeakyReLU(0.2, inplace=True), + scale_factor=2): + super().__init__() + self.conv = PartialConv( + in_channels, out_channels, kernel_size, stride, padding, dilation, + groups, bias, norm, activation) + self.scale_factor = scale_factor + + def forward(self, input_tuple): + inp, mask = input_tuple + inp_resized = F.interpolate(inp, scale_factor=(1, self.scale_factor, self.scale_factor)) + with torch.no_grad(): + mask_resized = F.interpolate(mask, scale_factor=(1, self.scale_factor, self.scale_factor)) + return self.conv((inp_resized, mask_resized)) \ No newline at end of file diff --git a/FGT_codes/LAFC/models/utils/network_blocks_2d.py b/FGT_codes/LAFC/models/utils/network_blocks_2d.py new file mode 100644 index 0000000000000000000000000000000000000000..c14b5cb1f47d16c930f395061a2ba3b4fc5a43fa --- /dev/null +++ b/FGT_codes/LAFC/models/utils/network_blocks_2d.py @@ -0,0 +1,186 @@ +import torch +import torch.nn as nn +import numpy as np +import torch.nn.functional as F + + +class VanillaConv2d(nn.Module): + def __init__( + self, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, + groups=1, bias=True, norm="SN", activation=nn.LeakyReLU(0.2, inplace=True) + ): + + super().__init__() + if padding == -1: + if isinstance(kernel_size, int): + kernel_size = (kernel_size, kernel_size) + if isinstance(dilation, int): + dilation = (dilation, dilation) + self.padding = tuple(((np.array(kernel_size) - 1) * np.array(dilation)) // 2) if padding == -1 else padding + self.featureConv = nn.Conv2d( + in_channels, out_channels, kernel_size, + stride, self.padding, dilation, groups, bias) + + self.norm = norm + if norm == "BN": + self.norm_layer = nn.BatchNorm2d(out_channels) + elif norm == "IN": + self.norm_layer = nn.InstanceNorm2d(out_channels, track_running_stats=True) + elif norm == "SN": + self.norm = None + self.featureConv = nn.utils.spectral_norm(self.featureConv) + else: + self.norm = None + + self.activation = activation + + def forward(self, xs): + out = self.featureConv(xs) + if self.activation: + out = self.activation(out) + if self.norm is not None: + out = self.norm_layer(out) + return out + + +class VanillaDeconv2d(nn.Module): + def __init__( + self, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, + groups=1, bias=True, norm="SN", activation=nn.LeakyReLU(0.2, inplace=True), + scale_factor=2 + ): + super().__init__() + self.conv = VanillaConv2d( + in_channels, out_channels, kernel_size, stride, padding, dilation, + groups, bias, norm, activation) + self.scale_factor = scale_factor + + def forward(self, xs): + xs_resized = F.interpolate(xs, scale_factor=self.scale_factor) + return self.conv(xs_resized) + + +class GatedConv2d(VanillaConv2d): + def __init__( + self, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, + groups=1, bias=True, norm="SN", activation=nn.LeakyReLU(0.2, inplace=True) + ): + super().__init__( + in_channels, out_channels, kernel_size, stride, padding, dilation, + groups, bias, norm, activation + ) + self.gatingConv = nn.Conv2d( + in_channels, out_channels, kernel_size, + stride, self.padding, dilation, groups, bias) + if norm == 'SN': + self.gatingConv = nn.utils.spectral_norm(self.gatingConv) + self.sigmoid = nn.Sigmoid() + self.store_gated_values = False + + def gated(self, mask): + # return torch.clamp(mask, -1, 1) + out = self.sigmoid(mask) + if self.store_gated_values: + self.gated_values = out.detach().cpu() + return out + + def forward(self, xs): + gating = self.gatingConv(xs) + feature = self.featureConv(xs) + if self.activation: + feature = self.activation(feature) + out = self.gated(gating) * feature + if self.norm is not None: + out = self.norm_layer(out) + return out + + +class GatedDeconv2d(VanillaDeconv2d): + def __init__( + self, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, + groups=1, bias=True, norm="SN", activation=nn.LeakyReLU(0.2, inplace=True), + scale_factor=2 + ): + super().__init__( + in_channels, out_channels, kernel_size, stride, padding, dilation, + groups, bias, norm, activation, scale_factor + ) + self.conv = GatedConv2d( + in_channels, out_channels, kernel_size, stride, padding, dilation, + groups, bias, norm, activation) + + +class PartialConv2d(VanillaConv2d): + def __init__(self, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, + groups=1, bias=True, norm="SN", activation=nn.LeakyReLU(0.2, inplace=True)): + super().__init__( + in_channels, out_channels, kernel_size, stride, padding, dilation, + groups, bias, norm, activation + ) + self.mask_sum_conv = nn.Conv2d(1, 1, kernel_size, + stride, self.padding, dilation, groups, False) + nn.init.constant_(self.mask_sum_conv.weight, 1.0) + + # mask conv needs not update + for param in self.mask_sum_conv.parameters(): + param.requires_grad = False + + def forward(self, input_tuple): + # http://masc.cs.gmu.edu/wiki/partialconv + # C(X) = W^T * X + b, C(0) = b, D(M) = 1 * M + 0 = sum(M) + # output = W^T* (M .* X) / sum(M) + b = [C(M .* X) – C(0)] / D(M) + C(0), if sum(M) != 0 + # = 0, if sum(M) == 0 + inp, mask = input_tuple + # print(inp.shape, mask.shape) + + # C(M .* X) + output = self.featureConv(mask * inp) + + # C(0) = b + if self.featureConv.bias is not None: + output_bias = self.featureConv.bias.view(1, -1, 1, 1) + else: + output_bias = torch.zeros([1, 1, 1, 1]).to(inp.device) + + # D(M) = sum(M) + with torch.no_grad(): + mask_sum = self.mask_sum_conv(mask) + + # find those sum(M) == 0 + no_update_holes = (mask_sum == 0) + + # Just to prevent devided by 0 + mask_sum_no_zero = mask_sum.masked_fill_(no_update_holes, 1.0) + + # output = [C(M .* X) – C(0)] / D(M) + C(0), if sum(M) != 0 + # = 0, if sum (M) == 0 + output = (output - output_bias) / mask_sum_no_zero + output_bias + output = output.masked_fill_(no_update_holes, 0.0) + + # create a new mask with only 1 or 0 + new_mask = torch.ones_like(mask_sum) + new_mask = new_mask.masked_fill_(no_update_holes, 0.0) + + if self.activation is not None: + output = self.activation(output) + if self.norm is not None: + output = self.norm_layer(output) + return output, new_mask + + +class PartialDeconv2d(nn.Module): + def __init__(self, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, + groups=1, bias=True, norm="SN", activation=nn.LeakyReLU(0.2, inplace=True), + scale_factor=2): + super().__init__() + self.conv = PartialConv2d( + in_channels, out_channels, kernel_size, stride, padding, dilation, + groups, bias, norm, activation) + self.scale_factor = scale_factor + + def forward(self, input_tuple): + inp, mask = input_tuple + inp_resized = F.interpolate(inp, scale_factor=self.scale_factor) + with torch.no_grad(): + mask_resized = F.interpolate(mask, scale_factor=self.scale_factor) + return self.conv((inp_resized, mask_resized)) diff --git a/FGT_codes/LAFC/models/utils/reconstructionLayers.py b/FGT_codes/LAFC/models/utils/reconstructionLayers.py new file mode 100644 index 0000000000000000000000000000000000000000..55ca5815e2248b29a49e491e514f4c359f7c3e9d --- /dev/null +++ b/FGT_codes/LAFC/models/utils/reconstructionLayers.py @@ -0,0 +1,57 @@ +import torch +import torch.nn as nn +import torch.nn.init as init + + +def initialize_weights(net_l, scale=1): + if not isinstance(net_l, list): + net_l = [net_l] + for net in net_l: + for m in net.modules(): + if isinstance(m, nn.Conv2d): + init.kaiming_normal_(m.weight, a=0, mode='fan_in') + m.weight.data *= scale # for residual block + if m.bias is not None: + m.bias.data.zero_() + elif isinstance(m, nn.Linear): + init.kaiming_normal_(m.weight, a=0, mode='fan_in') + m.weight.data *= scale + if m.bias is not None: + m.bias.data.zero_() + elif isinstance(m, nn.BatchNorm2d): + init.constant_(m.weight, 1) + init.constant_(m.bias.data, 0.0) + + +def make_layer(block, n_layers): + layers = [] + for _ in range(n_layers): + layers.append(block()) + return nn.Sequential(*layers) + + +class ResidualBlock_noBN(nn.Module): + """Residual block w/o BN + ---Conv-ReLU-Conv-+- + |________________| + """ + + def __init__(self, nf=64): + super(ResidualBlock_noBN, self).__init__() + self.conv1 = nn.Conv2d(nf, nf, kernel_size=3, stride=1, padding=1, bias=True) + self.conv2 = nn.Conv2d(nf, nf, kernel_size=3, stride=1, padding=1, bias=True) + self.lrelu = nn.LeakyReLU(negative_slope=0.2, inplace=True) + + def forward(self, x): + """ + Args: + x: with shape of [b, c, t, h, w] + Returns: processed features with shape [b, c, t, h, w] + """ + identity = x + out = self.lrelu(self.conv1(x)) + out = self.conv2(out) + out = identity + out + # Remove ReLU at the end of the residual block + # http://torch.ch/blog/2016/02/04/resnets.html + return out diff --git a/FGT_codes/LAFC/models/utils/sobel2.py b/FGT_codes/LAFC/models/utils/sobel2.py new file mode 100644 index 0000000000000000000000000000000000000000..7a4ec74aff4cf187a738f717bac94bbb87dc0b60 --- /dev/null +++ b/FGT_codes/LAFC/models/utils/sobel2.py @@ -0,0 +1,68 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F + + +class SobelLayer(nn.Module): + def __init__(self, device): + super(SobelLayer, self).__init__() + self.kernel_x = torch.tensor([[-1., 0, 1], [-2, 0, 2], [-1, 0, 1]]).unsqueeze(0).unsqueeze(0) / 4. + self.kernel_y = torch.tensor([[-1, -2, -1], [0, 0, 0], [1, 2, 1.]]).unsqueeze(0).unsqueeze(0) / 4. + self.kernel_x = self.kernel_x.to(device) + self.kernel_y = self.kernel_y.to(device) + self.pad = nn.ReplicationPad2d(padding=1) + self.absLayer = nn.ReLU() + + def forward(self, images): + """ + + Args: + images: images with shape [b, c, h, w] + + Returns: + + """ + images = self.pad(images) + gray_images = self._convertGrey(images) + + edge_x = F.conv2d(gray_images, self.kernel_x, stride=1) + edge_y = F.conv2d(gray_images, self.kernel_y, stride=1) + edge = (self.absLayer(edge_x) + self.absLayer(edge_y)) / 2 + return edge + + def _convertGrey(self, image): + """ + grey = 0.299 * r + 0.587 * g + 0.110 * b + Args: + image: RGB image + + Returns: Grey scale image + + """ + grey_image = image[:, 0] * 0.299 + image[:, 1] * 0.587 + 0.110 * image[:, 2] + output = grey_image.unsqueeze(1) + return output + + +class SeperateSobelLayer(nn.Module): + def __init__(self, device): + super(SeperateSobelLayer, self).__init__() + self.kernel_x = torch.tensor([[-1., 0, 1], [-2, 0, 2], [-1, 0, 1]]).unsqueeze(0).unsqueeze(0) + self.kernel_y = torch.tensor([[-1, -2, -1], [0, 0, 0], [1, 2, 1.]]).unsqueeze(0).unsqueeze(0) + self.weight = torch.zeros([6, 3, 3, 3]) + for c in range(3): + self.weight[2 * c, c] = self.kernel_x + self.weight[2 * c + 1, c] = self.kernel_y + self.weight = self.weight.to(device) + + def forward(self, images): + """ + + Args: + images: with shape [b, c, h, w] + + Returns: sobel gradient image with shape [b, c, h, w] (same padding) + + """ + gradientMap = F.conv2d(images, self.weight, stride=1, padding=1) + return gradientMap diff --git a/FGT_codes/LAFC/models/utils/util.py b/FGT_codes/LAFC/models/utils/util.py new file mode 100644 index 0000000000000000000000000000000000000000..d849e3cd9f320c43473092c534c5f4d6e154c114 --- /dev/null +++ b/FGT_codes/LAFC/models/utils/util.py @@ -0,0 +1,279 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F + +networks = ['BaseNetwork', 'Discriminator', 'ASPP'] + +# Base model borrows from PEN-NET +# https://github.com/researchmm/PEN-Net-for-Inpainting +class BaseNetwork(nn.Module): + def __init__(self): + super(BaseNetwork, self).__init__() + + def print_network(self): + if isinstance(self, list): + self = self[0] + num_params = 0 + for param in self.parameters(): + num_params += param.numel() + print('Network [%s] was created. Total number of parameters: %.1f million. ' + 'To see the architecture, do print(network).' % (type(self).__name__, num_params / 1000000)) + + def init_weights(self, init_type='normal', gain=0.02): + ''' + initialize network's weights + init_type: normal | xavier | kaiming | orthogonal + https://github.com/junyanz/pytorch-CycleGAN-and-pix2pix/blob/9451e70673400885567d08a9e97ade2524c700d0/models/networks.py#L39 + ''' + + def init_func(m): + classname = m.__class__.__name__ + if classname.find('InstanceNorm2d') != -1: + if hasattr(m, 'weight') and m.weight is not None: + nn.init.constant_(m.weight.data, 1.0) + if hasattr(m, 'bias') and m.bias is not None: + nn.init.constant_(m.bias.data, 0.0) + elif hasattr(m, 'weight') and (classname.find('Conv') != -1 or classname.find('Linear') != -1): + if init_type == 'normal': + nn.init.normal_(m.weight.data, 0.0, gain) + elif init_type == 'xavier': + nn.init.xavier_normal_(m.weight.data, gain=gain) + elif init_type == 'xavier_uniform': + nn.init.xavier_uniform_(m.weight.data, gain=1.0) + elif init_type == 'kaiming': + nn.init.kaiming_normal_(m.weight.data, a=0, mode='fan_in') + elif init_type == 'orthogonal': + nn.init.orthogonal_(m.weight.data, gain=gain) + elif init_type == 'none': # uses pytorch's default init method + m.reset_parameters() + else: + raise NotImplementedError('initialization method [%s] is not implemented' % init_type) + if hasattr(m, 'bias') and m.bias is not None: + nn.init.constant_(m.bias.data, 0.0) + + self.apply(init_func) + + # propagate to children + for m in self.children(): + if hasattr(m, 'init_weights'): + m.init_weights(init_type, gain) + + +# temporal patch gan: from Free-form Video Inpainting with 3D Gated Convolution and Temporal PatchGAN in 2019 ICCV +# todo: debug this model +class Discriminator(BaseNetwork): + def __init__(self, in_channels=3, use_sigmoid=False, use_spectral_norm=True, init_weights=True): + super(Discriminator, self).__init__() + self.use_sigmoid = use_sigmoid + nf = 64 + + self.conv = nn.Sequential( + DisBuildingBlock(in_channel=in_channels, out_channel=nf * 1, kernel_size=(3, 5, 5), stride=(1, 2, 2), + padding=1, use_spectral_norm=use_spectral_norm), + # nn.InstanceNorm2d(64, track_running_stats=False), + nn.LeakyReLU(0.2, inplace=True), + DisBuildingBlock(in_channel=nf * 1, out_channel=nf * 2, kernel_size=(3, 5, 5), stride=(1, 2, 2), + padding=(1, 2, 2), use_spectral_norm=use_spectral_norm), + # nn.InstanceNorm2d(128, track_running_stats=False), + nn.LeakyReLU(0.2, inplace=True), + DisBuildingBlock(in_channel=nf * 2, out_channel=nf * 4, kernel_size=(3, 5, 5), stride=(1, 2, 2), + padding=(1, 2, 2), use_spectral_norm=use_spectral_norm), + # nn.InstanceNorm2d(256, track_running_stats=False), + nn.LeakyReLU(0.2, inplace=True), + DisBuildingBlock(in_channel=nf * 4, out_channel=nf * 4, kernel_size=(3, 5, 5), stride=(1, 2, 2), + padding=(1, 2, 2), use_spectral_norm=use_spectral_norm), + # nn.InstanceNorm2d(256, track_running_stats=False), + nn.LeakyReLU(0.2, inplace=True), + DisBuildingBlock(in_channel=nf * 4, out_channel=nf * 4, kernel_size=(3, 5, 5), stride=(1, 2, 2), + padding=(1, 2, 2), use_spectral_norm=use_spectral_norm), + # nn.InstanceNorm2d(256, track_running_stats=False), + nn.LeakyReLU(0.2, inplace=True), + nn.Conv3d(nf * 4, nf * 4, kernel_size=(3, 5, 5), + stride=(1, 2, 2), padding=(1, 2, 2)) + ) + + if init_weights: + self.init_weights() + + def forward(self, xs): + # B, C, T, H, W = xs.shape + feat = self.conv(xs) + if self.use_sigmoid: + feat = torch.sigmoid(feat) + return feat + + +class DisBuildingBlock(nn.Module): + def __init__(self, in_channel, out_channel, kernel_size, stride, padding, use_spectral_norm): + super(DisBuildingBlock, self).__init__() + self.block = self._getBlock(in_channel, out_channel, kernel_size, stride, padding, use_spectral_norm) + + def _getBlock(self, in_channel, out_channel, kernel_size, stride, padding, use_spectral_norm): + feature_conv = nn.Conv3d(in_channels=in_channel, out_channels=out_channel, kernel_size=kernel_size, + stride=stride, padding=padding, bias=not use_spectral_norm) + if use_spectral_norm: + feature_conv = nn.utils.spectral_norm(feature_conv) + return feature_conv + + def forward(self, inputs): + out = self.block(inputs) + return out + + +class ASPP(nn.Module): + def __init__(self, input_channels, output_channels, rate=[1, 2, 4, 8]): + super(ASPP, self).__init__() + self.input_channels = input_channels + self.output_channels = output_channels + self.rate = rate + for i in range(len(rate)): + self.__setattr__('conv{}'.format(str(i).zfill(2)), nn.Sequential( + nn.Conv2d(input_channels, output_channels // len(rate), kernel_size=3, dilation=rate[i], + padding=rate[i]), + nn.LeakyReLU(negative_slope=0.2, inplace=True) + )) + + def forward(self, inputs): + inputs = inputs / len(self.rate) + tmp = [] + for i in range(len(self.rate)): + tmp.append(self.__getattr__('conv{}'.format(str(i).zfill(2)))(inputs)) + output = torch.cat(tmp, dim=1) + return output + + +class GatedConv2dWithActivation(torch.nn.Module): + """ + Gated Convlution layer with activation (default activation:LeakyReLU) + Params: same as conv2d + Input: The feature from last layer "I" + Output:\phi(f(I))*\sigmoid(g(I)) + """ + + def __init__(self, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, batch_norm=False, activation=torch.nn.LeakyReLU(0.2, inplace=True)): + super(GatedConv2dWithActivation, self).__init__() + self.batch_norm = batch_norm + self.activation = activation + self.conv2d = torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride, padding, dilation, groups, bias) + self.mask_conv2d = torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride, padding, dilation, groups, bias) + self.batch_norm2d = torch.nn.BatchNorm2d(out_channels) + self.sigmoid = torch.nn.Sigmoid() + + for m in self.modules(): + if isinstance(m, nn.Conv2d): + nn.init.kaiming_normal_(m.weight) + + def gated(self, mask): + return self.sigmoid(mask) + + def forward(self, inputs): + x = self.conv2d(inputs) + mask = self.mask_conv2d(inputs) + if self.activation is not None: + x = self.activation(x) * self.gated(mask) + else: + x = x * self.gated(mask) + if self.batch_norm: + return self.batch_norm2d(x) + else: + return x + + +class GatedDeConv2dWithActivation(torch.nn.Module): + """ + Gated DeConvlution layer with activation (default activation:LeakyReLU) + resize + conv + Params: same as conv2d + Input: The feature from last layer "I" + Output:\phi(f(I))*\sigmoid(g(I)) + """ + def __init__(self, scale_factor, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, batch_norm=False, activation=torch.nn.LeakyReLU(0.2, inplace=True)): + super(GatedDeConv2dWithActivation, self).__init__() + self.conv2d = GatedConv2dWithActivation(in_channels, out_channels, kernel_size, stride, padding, dilation, groups, bias, batch_norm, activation) + self.scale_factor = scale_factor + + def forward(self, inputs): + #print(input.size()) + x = F.interpolate(inputs, scale_factor=self.scale_factor) + return self.conv2d(x) + + +class SNGatedConv2dWithActivation(torch.nn.Module): + """ + Gated Convolution with spetral normalization + """ + def __init__(self, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, batch_norm=False, activation=torch.nn.LeakyReLU(0.2, inplace=True)): + super(SNGatedConv2dWithActivation, self).__init__() + self.conv2d = torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride, padding, dilation, groups, bias) + self.mask_conv2d = torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride, padding, dilation, groups, bias) + self.activation = activation + self.batch_norm = batch_norm + self.batch_norm2d = torch.nn.BatchNorm2d(out_channels) + self.sigmoid = torch.nn.Sigmoid() + self.conv2d = torch.nn.utils.spectral_norm(self.conv2d) + self.mask_conv2d = torch.nn.utils.spectral_norm(self.mask_conv2d) + for m in self.modules(): + if isinstance(m, nn.Conv2d): + nn.init.kaiming_normal_(m.weight) + + def gated(self, mask): + return self.sigmoid(mask) + + def forward(self, inputs): + x = self.conv2d(inputs) + mask = self.mask_conv2d(inputs) + if self.activation is not None: + x = self.activation(x) * self.gated(mask) + else: + x = x * self.gated(mask) + if self.batch_norm: + return self.batch_norm2d(x) + else: + return x + + +class SNGatedDeConv2dWithActivation(torch.nn.Module): + """ + Gated DeConvlution layer with activation (default activation:LeakyReLU) + resize + conv + Params: same as conv2d + Input: The feature from last layer "I" + Output:\phi(f(I))*\sigmoid(g(I)) + """ + def __init__(self, scale_factor, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, batch_norm=False, activation=torch.nn.LeakyReLU(0.2, inplace=True)): + super(SNGatedDeConv2dWithActivation, self).__init__() + self.conv2d = SNGatedConv2dWithActivation(in_channels, out_channels, kernel_size, stride, padding, dilation, groups, bias, batch_norm, activation) + self.scale_factor = scale_factor + + def forward(self, inputs): + x = F.interpolate(inputs, scale_factor=2) + return self.conv2d(x) + + +class GatedConv3d(nn.Module): + def __init__(self, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, activation=nn.LeakyReLU(0.2, inplace=True)): + super(GatedConv3d, self).__init__() + self.input_conv = nn.Conv3d(in_channels, out_channels, kernel_size, + stride, padding, dilation, groups, bias) + self.gating_conv = nn.Conv3d(in_channels, out_channels, kernel_size, + stride, padding, dilation, groups, bias) + self.activation = activation + + def forward(self, inputs): + feature = self.input_conv(inputs) + if self.activation: + feature = self.activation(feature) + gating = torch.sigmoid(self.gating_conv(inputs)) + return feature * gating + + +class GatedDeconv3d(nn.Module): + def __init__(self, in_channels, out_channels, kernel_size, stride, padding, scale_factor, dilation=1, groups=1, bias=True, activation=nn.LeakyReLU(0.2, inplace=True)): + super().__init__() + self.scale_factor = scale_factor + self.deconv = GatedConv3d(in_channels, out_channels, kernel_size, stride, padding, dilation, groups, bias, activation) + + def forward(self, inputs): + inputs = F.interpolate(inputs, scale_factor=(1, self.scale_factor, self.scale_factor)) + return self.deconv(inputs) + diff --git a/FGT_codes/LAFC/networks/__init__.py b/FGT_codes/LAFC/networks/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/FGT_codes/LAFC/networks/network.py b/FGT_codes/LAFC/networks/network.py new file mode 100644 index 0000000000000000000000000000000000000000..f0fd86c075195f95e96d4739d1aa497c1ff05898 --- /dev/null +++ b/FGT_codes/LAFC/networks/network.py @@ -0,0 +1,513 @@ +from trainer import Trainer +from importlib import import_module +import math +import torch +from torch import optim +from torch.optim import lr_scheduler +import numpy as np +import os +from shutil import copyfile +import glob +from models.utils.flow_losses import smoothness_loss, second_order_loss +from models.utils.fbConsistencyCheck import image_warp +from models.utils.fbConsistencyCheck import ternary_loss2 +import torch.nn.functional as F +import cv2 +import cvbase +from data.util.flow_utils import region_fill as rf +import imageio +import torch.nn as nn +from skimage.feature import canny +from skimage.metrics import peak_signal_noise_ratio as psnr +from skimage.metrics import structural_similarity as ssim +from models.utils.bce_edge_loss import edgeLoss, EdgeAcc + + +class Network(Trainer): + def init_model(self): + self.edgeMeasure = EdgeAcc() + model_package = import_module('models.{}'.format(self.opt['model'])) + model = model_package.Model(self.opt) + optimizer = optim.Adam(model.parameters(), lr=float(self.opt['train']['lr']), + betas=(float(self.opt['train']['BETA1']), float(float(self.opt['train']['BETA2'])))) + if self.rank <= 0: + self.logger.info( + 'Optimizer is Adam, BETA1: {}, BETA2: {}'.format(float(self.opt['train']['BETA1']), + float(self.opt['train']['BETA2']))) + step_size = int(math.ceil(self.opt['train']['UPDATE_INTERVAL'] / self.trainSize)) + if self.rank <= 0: + self.logger.info('Step size for optimizer is {} epoch'.format(step_size)) + scheduler = lr_scheduler.StepLR(optimizer, step_size=step_size, gamma=self.opt['train']['lr_decay']) + return model, optimizer, scheduler + + def resume_training(self): + gen_state = torch.load(self.opt['path']['gen_state'], + map_location=lambda storage, loc: storage.cuda(self.opt['device'])) + opt_state = torch.load(self.opt['path']['opt_state'], + map_location=lambda storage, loc: storage.cuda(self.opt['device'])) + if self.rank <= 0: + self.logger.info('Resume state is activated') + self.logger.info('Resume training from epoch: {}, iter: {}'.format( + opt_state['epoch'], opt_state['iteration'] + )) + if self.opt['finetune'] == False: + start_epoch = opt_state['epoch'] + current_step = opt_state['iteration'] + self.optimizer.load_state_dict(opt_state['optimizer_state_dict']) + self.scheduler.load_state_dict(opt_state['scheduler_state_dict']) + else: + start_epoch = 0 + current_step = 0 + self.model.load_state_dict(gen_state['model_state_dict']) + if self.rank <= 0: + self.logger.info('Resume training mode, optimizer, scheduler and model have been uploaded') + return start_epoch, current_step + + def _trainEpoch(self, epoch): + for idx, train_data in enumerate(self.trainLoader): + self.currentStep += 1 + + if self.currentStep > self.totalIterations: + if self.rank <= 0: + self.logger.info('Train process has been finished') + break + if self.opt['train']['WARMUP'] is not None and self.currentStep <= self.opt['train']['WARMUP'] // self.opt[ + 'world_size']: + target_lr = self.opt['train']['lr'] * self.currentStep / ( + self.opt['train']['WARMUP']) + self.adjust_learning_rate(self.optimizer, target_lr) + + flows = train_data['flows'] + diffused_flows = train_data['diffused_flows'] + target_edge = train_data['edges'] + current_frame = train_data['current_frame'] + current_frame = current_frame.to(self.opt['device']) + shift_frame = train_data['shift_frame'] + shift_frame = shift_frame.to(self.opt['device']) + masks = train_data['masks'] + flows = flows.to(self.opt['device']) + masks = masks.to(self.opt['device']) + diffused_flows = diffused_flows.to(self.opt['device']) + target_edge = target_edge.to(self.opt['device']) + + if len(masks.shape) == 5: + b, c, t, h, w = masks.shape + target_flow = flows[:, :, t // 2] + target_mask = masks[:, :, t // 2] + else: + assert len(masks.shape) == 4 and len(flows.shape) == 4 + target_flow = flows + target_mask = masks + + filled_flow = self.model(diffused_flows, masks) + + filled_flow, filled_edge = filled_flow + + combined_flow = target_flow * (1 - target_mask) + filled_flow * target_mask + combined_edge = target_edge * (1 - target_mask) + filled_edge * target_mask + edge_loss = (edgeLoss(filled_edge, target_edge) + 5 * edgeLoss(combined_edge, target_edge)) + + # loss calculations + L1Loss_masked = self.maskedLoss(combined_flow * target_mask, + target_flow * target_mask) / torch.mean(target_mask) + L1Loss_valid = self.validLoss(filled_flow * (1 - target_mask), + target_flow * (1 - target_mask)) / torch.mean(1 - target_mask) + + smoothLoss = smoothness_loss(combined_flow, target_mask) + smoothLoss2 = second_order_loss(combined_flow, target_mask) + ternary_loss = self.ternary_loss(combined_flow, target_flow, target_mask, current_frame, shift_frame, + scale_factor=1) + + m_losses = (L1Loss_masked + L1Loss_valid) * self.opt['L1M'] + sm1_loss = smoothLoss * self.opt['sm'] + sm2_loss = smoothLoss2 * self.opt['sm2'] + t_loss = self.opt['ternary'] * ternary_loss + e_loss = edge_loss * self.opt['edge_loss'] + + loss = m_losses + sm1_loss + sm2_loss + t_loss + e_loss + + self.optimizer.zero_grad() + loss.backward() + if self.opt['gc']: # gradient clip + nn.utils.clip_grad_norm_(self.model.parameters(), max_norm=10, + norm_type=2) + self.optimizer.step() + + if self.opt['use_tb_logger'] and self.rank <= 0 and self.currentStep % 8 == 0: + print('Mask: {:.03f}, sm: {:.03f}, sm2: {:.03f}, ternary: {:.03f}, edge: {:03f}'.format( + m_losses.item(), + sm1_loss.item(), + sm2_loss.item(), + t_loss.item(), + e_loss.item() + )) + self.tb_logger.add_scalar('{}/recon'.format('train'), m_losses.item(), + self.currentStep) + self.tb_logger.add_scalar('{}/sm'.format('train'), sm1_loss.item(), self.currentStep) + self.tb_logger.add_scalar('{}/sm2'.format('train'), sm2_loss.item(), + self.currentStep) + self.tb_logger.add_scalar('{}/ternary'.format('train'), + t_loss.item(), + self.currentStep) + self.tb_logger.add_scalar('{}/edge'.format('train'), e_loss.item(), + self.currentStep) + + if self.currentStep % self.opt['logger']['PRINT_FREQ'] == 0 and self.rank <= 0: + compLog = np.array(combined_flow.detach().permute(0, 2, 3, 1).cpu()) + flowsLog = np.array(target_flow.detach().permute(0, 2, 3, 1).cpu()) + logs = self.calculate_metrics(compLog, flowsLog) + prec, recall = self.edgeMeasure(filled_edge.detach(), target_edge.detach()) + logs['prec'] = prec + logs['recall'] = recall + self._printLog(logs, epoch, loss) + + def ternary_loss(self, comp, flow, mask, current_frame, shift_frame, scale_factor): + if scale_factor != 1: + current_frame = F.interpolate(current_frame, scale_factor=1 / scale_factor, mode='bilinear') + shift_frame = F.interpolate(shift_frame, scale_factor=1 / scale_factor, mode='bilinear') + warped_sc = image_warp(shift_frame, flow) + noc_mask = torch.exp(-50. * torch.sum(torch.abs(current_frame - warped_sc), dim=1).pow(2)).unsqueeze(1) + warped_comp_sc = image_warp(shift_frame, comp) + loss = ternary_loss2(current_frame, warped_comp_sc, noc_mask, mask) + return loss + + def calculate_metrics(self, results, gts): + B, H, W, C = results.shape + psnr_values, ssim_values, L1errors, L2errors = [], [], [], [] + for i in range(B): + result, gt = results[i], gts[i] + result_rgb = cvbase.flow2rgb(result) + gt_rgb = cvbase.flow2rgb(gt) + psnr_value = psnr(result_rgb, gt_rgb) + ssim_value = ssim(result_rgb, gt_rgb, multichannel=True) + residual = result - gt + L1error = np.mean(np.abs(residual)) + L2error = np.sum(residual ** 2) ** 0.5 / (H * W * C) + psnr_values.append(psnr_value) + ssim_values.append(ssim_value) + L1errors.append(L1error) + L2errors.append(L2error) + psnr_value = np.mean(psnr_values) + ssim_value = np.mean(ssim_values) + L1_value = np.mean(L1errors) + L2_value = np.mean(L2errors) + return {'l1': L1_value, 'l2': L2_value, 'psnr': psnr_value, 'ssim': ssim_value} + + def _printLog(self, logs, epoch, loss): + if self.countDown % self.opt['record_iter'] == 0: + self.total_psnr = 0 + self.total_ssim = 0 + self.total_l1 = 0 + self.total_l2 = 0 + self.total_loss = 0 + self.total_prec = 0 + self.total_recall = 0 + self.countDown = 0 + self.countDown += 1 + message = '[epoch:{:3d}, iter:{:7d}, lr:('.format(epoch, self.currentStep) + for v in self.get_lr(): + message += '{:.3e}, '.format(v) + message += ')] ' + self.total_psnr += logs['psnr'] + self.total_ssim += logs['ssim'] + self.total_l1 += logs['l1'] + self.total_l2 += logs['l2'] + self.total_prec += logs['prec'].item() + self.total_recall += logs['recall'].item() + self.total_loss += loss.item() + mean_psnr = self.total_psnr / self.countDown + mean_ssim = self.total_ssim / self.countDown + mean_l1 = self.total_l1 / self.countDown + mean_l2 = self.total_l2 / self.countDown + mean_prec = self.total_prec / self.countDown + mean_recall = self.total_recall / self.countDown + mean_loss = self.total_loss / self.countDown + + message += '{:s}: {:.4e} '.format('mean_loss', mean_loss) + message += '{:s}: {:} '.format('mean_psnr', mean_psnr) + message += '{:s}: {:} '.format('mean_ssim', mean_ssim) + message += '{:s}: {:} '.format('mean_l1', mean_l1) + message += '{:s}: {:} '.format('mean_l2', mean_l2) + message += '{:s}: {:} '.format('mean_prec', mean_prec) + message += '{:s}: {:} '.format('mean_recall', mean_recall) + + if self.opt['use_tb_logger']: + self.tb_logger.add_scalar('train/mean_psnr', mean_psnr, self.currentStep) + self.tb_logger.add_scalar('train/mean_ssim', mean_ssim, self.currentStep) + self.tb_logger.add_scalar('train/mean_l1', mean_l1, self.currentStep) + self.tb_logger.add_scalar('train/mean_l2', mean_l2, self.currentStep) + self.tb_logger.add_scalar('train/mean_loss', mean_loss, self.currentStep) + self.tb_logger.add_scalar('train/mean_prec', mean_prec, self.currentStep) + self.tb_logger.add_scalar('train/mean_recall', mean_recall, self.currentStep) + self.logger.info(message) + + if self.currentStep % self.opt['logger']['SAVE_CHECKPOINT_FREQ'] == 0: + self.save_checkpoint(epoch, 'l1', logs['l1']) + + def save_checkpoint(self, epoch, metric, number): + if isinstance(self.model, torch.nn.DataParallel) or isinstance(self.model, + torch.nn.parallel.DistributedDataParallel): + model_state = self.model.module.state_dict() + else: + model_state = self.model.state_dict() + gen_state = { + 'model_state_dict': model_state + } + + opt_state = { + 'epoch': epoch, + 'iteration': self.currentStep, + 'optimizer_state_dict': self.optimizer.state_dict(), + 'scheduler_state_dict': self.scheduler.state_dict(), + } + + gen_name = os.path.join(self.opt['path']['TRAINING_STATE'], + 'gen_{}_{}.pth.tar'.format(epoch, self.currentStep)) + opt_name = os.path.join(self.opt['path']['TRAINING_STATE'], + 'opt_{}_{}.pth.tar'.format(epoch, self.currentStep)) + torch.save(gen_state, gen_name) + torch.save(opt_state, opt_name) + + def _validate(self, epoch): + data_path = self.valInfo['data_root'] + mask_path = self.valInfo['mask_root'] + self.model.eval() + test_list = os.listdir(data_path) + test_list = test_list[:10] # only inference 10 videos + width, height = self.valInfo['flow_width'], self.valInfo['flow_height'] + flow_interval = self.opt['flow_interval'] # The sampling interval for flow completion + psnr, ssim, l1, l2, prec, recall = {}, {}, {}, {}, {}, {} + pivot, sequenceLen = 20, self.opt['num_flows'] + for i in range(len(test_list)): + videoName = test_list[i] + if self.rank <= 0: + self.logger.info(f'Video {videoName} is being processed') + for direction in ['forward_flo', 'backward_flo']: + flow_dir = os.path.join(data_path, videoName, direction) + mask_dir = os.path.join(mask_path, videoName) + flows = self.read_flows(flow_dir, width, height, pivot, sequenceLen, flow_interval) + masks = self.read_masks(mask_dir, width, height, pivot, sequenceLen, flow_interval) + if flows == [] or masks == []: + if self.rank <= 0: + print('Video {} doesn\'t have enough {} flows'.format(videoName, direction)) + continue + if self.rank <= 0: + self.logger.info('Flows have been read') + diffused_flows = self.diffusion_filling(flows, masks) + flows = np.stack(flows, axis=0) + masks = np.stack(masks, axis=0) + diffused_flows = np.stack(diffused_flows, axis=0) + target_flow = flows[self.opt['num_flows'] // 2] + target_edge = self.load_edge(target_flow) + target_edge = target_edge[:, :, np.newaxis] + diffused_flows = torch.from_numpy(np.transpose(diffused_flows, (3, 0, 1, 2))).unsqueeze( + 0).float() + masks = torch.from_numpy(np.transpose(masks, (3, 0, 1, 2))).unsqueeze(0).float() + target_flow = torch.from_numpy(np.transpose(target_flow, (2, 0, 1))).unsqueeze( + 0).float() + target_edge = torch.from_numpy(np.transpose(target_edge, (2, 0, 1))).unsqueeze(0).float() + diffused_flows = diffused_flows.to(self.opt['device']) + masks = masks.to(self.opt['device']) + target_flow = target_flow.to(self.opt['device']) + target_edge = target_edge.to(self.opt['device']) + target_mask = masks[:, :, sequenceLen // 2] + if diffused_flows.shape[2] == 1 and len(diffused_flows.shape) == 5: + assert masks.shape[2] == 1 + diffused_flows = diffused_flows.squeeze(2) + masks = masks.squeeze(2) + with torch.no_grad(): + filled_flow = self.model(diffused_flows, masks, None) + filled_flow, filled_edge = filled_flow + if len(diffused_flows.shape) == 5: + target_diffused_flow = diffused_flows[:, :, sequenceLen // 2] + else: + target_diffused_flow = diffused_flows + combined_flow = target_flow * (1 - target_mask) + filled_flow * target_mask + + # calculate metrics + psnr_avg, ssim_avg, l1_avg, l2_avg = self.metrics_calc(combined_flow, target_flow) + prec_avg, recall_avg = self.edgeMeasure(filled_edge, target_edge) + psnr[videoName] = psnr_avg + ssim[videoName] = ssim_avg + l1[videoName] = l1_avg + l2[videoName] = l2_avg + prec[videoName] = prec_avg.item() + recall[videoName] = recall_avg.item() + + # visualize frames and report the phase performance + if self.rank <= 0: + if self.opt['use_tb_logger']: + self.tb_logger.add_scalar('test/{}/l1'.format(videoName), l1_avg, + self.currentStep) + self.tb_logger.add_scalar('test/{}/l2'.format(videoName), l2_avg, self.currentStep) + self.tb_logger.add_scalar('test/{}/psnr'.format(videoName), psnr_avg, self.currentStep) + self.tb_logger.add_scalar('test/{}/ssim'.format(videoName), ssim_avg, self.currentStep) + self.tb_logger.add_scalar('test/{}/prec'.format(videoName), prec_avg, self.currentStep) + self.tb_logger.add_scalar('test/{}/recall'.format(videoName), recall_avg, self.currentStep) + self.vis_flows(combined_flow, target_flow, target_diffused_flow, videoName, + epoch) # view the difference between diffused flows and the completed flows + mean_psnr = np.mean([psnr[k] for k in psnr.keys()]) + mean_ssim = np.mean([ssim[k] for k in ssim.keys()]) + mean_l1 = np.mean([l1[k] for k in l1.keys()]) + mean_l2 = np.mean([l2[k] for k in l2.keys()]) + mean_prec = np.mean([prec[k] for k in prec.keys()]) + mean_recall = np.mean([recall[k] for k in recall.keys()]) + self.logger.info( + '[epoch:{:3d}, vid:{}/{}], mean_l1: {:.4e}, mean_l2: {:.4e}, mean_psnr: {:}, mean_ssim: {:}, prec: {:}, recall: {:}'.format( + epoch, i, len(test_list), mean_l1, mean_l2, mean_psnr, mean_ssim, mean_prec, mean_recall)) + + # give the overall performance + if self.rank <= 0: + mean_psnr = np.mean([psnr[k] for k in psnr.keys()]) + mean_ssim = np.mean([ssim[k] for k in ssim.keys()]) + mean_l1 = np.mean([l1[k] for k in l1.keys()]) + mean_l2 = np.mean([l2[k] for k in l2.keys()]) + mean_prec = np.mean([prec[k] for k in prec.keys()]) + mean_recall = np.mean([recall[k] for k in recall.keys()]) + self.logger.info( + '[epoch:{:3d}], mean_l1: {:.4e} mean_l2: {:.4e} mean_psnr: {:} mean_ssim: {:}, prec: {:}, recall: {:}'.format( + epoch, mean_l1, mean_l2, mean_psnr, mean_ssim, mean_prec, mean_recall)) + valid_l1 = mean_l1 + 100 + self.save_checkpoint(epoch, 'l1', valid_l1) + + self.model.train() + + def load_edge(self, flow): + flow_rgb = cvbase.flow2rgb(flow) + flow_gray = cv2.cvtColor(flow_rgb, cv2.COLOR_RGB2GRAY) + return canny(flow_gray, sigma=self.opt['datasets']['dataInfo']['edge']['sigma'], mask=None, + low_threshold=self.opt['datasets']['dataInfo']['edge']['low_threshold'], + high_threshold=self.opt['datasets']['dataInfo']['edge']['high_threshold']).astype( + np.float) + + def read_flows(self, flow_dir, width, height, pivot, sequenceLen, sample_interval): + flow_paths = glob.glob(os.path.join(flow_dir, '*.flo')) + flows = [] + half_seq = sequenceLen // 2 + for i in range(-half_seq, half_seq + 1): + index = pivot + sample_interval * i + if index < 0: + index = 0 + if index >= len(flow_paths): + index = len(flow_paths) - 1 + flow_path = os.path.join(flow_dir, '{:05d}.flo'.format(index)) + flow = cvbase.read_flow(flow_path) + pre_height, pre_width = flow.shape[:2] + flow = cv2.resize(flow, (width, height), cv2.INTER_LINEAR) + flow[:, :, 0] = flow[:, :, 0] / pre_width * width + flow[:, :, 1] = flow[:, :, 1] / pre_height * height + flows.append(flow) + return flows + + def metrics_calc(self, result, frames): + psnr_avg, ssim_avg, l1_avg, l2_avg = 0, 0, 0, 0 + result = np.array(result.permute(0, 2, 3, 1).cpu()) # [b, h, w, c] + gt = np.array(frames.permute(0, 2, 3, 1).cpu()) # [b, h, w, c] + logs = self.calculate_metrics(result, gt) + psnr_avg += logs['psnr'] + ssim_avg += logs['ssim'] + l1_avg += logs['l1'] + l2_avg += logs['l2'] + return psnr_avg, ssim_avg, l1_avg, l2_avg + + def read_frames(self, frame_dir, width, height, pivot, sequenceLen): + frame_paths = sorted(glob.glob(os.path.join(frame_dir, '*.jpg'))) + frames = [] + if len(frame_paths) <= 30: + return frames + for i in range(pivot, pivot + sequenceLen): + frame_path = os.path.join(frame_dir, '{:05d}.jpg'.format(i)) + frame = imageio.imread(frame_path) + frame = cv2.resize(frame, (width, height), cv2.INTER_LINEAR) + frames.append(frame) + return frames + + def load_edges(self, frames, width, height): + edges = [] + for i in range(len(frames)): + frame = frames[i] + frame_gray = cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY) + edge = canny(frame_gray, sigma=self.valInfo['sigma'], mask=None, + low_threshold=self.valInfo['low_threshold'], + high_threshold=self.valInfo['high_threshold']).astype(np.float) # [h, w, 1] + edge_t = self.to_tensor(edge, width, height, mode='nearest') + edges.append(edge_t) + return edges + + def to_tensor(self, frame, width, height, mode='bilinear'): + if len(frame.shape) == 2: + frame = frame[:, :, np.newaxis] + frame_t = torch.from_numpy(frame).unsqueeze(0).permute(0, 3, 1, 2).float() # [b, c, h, w] + if width != 0 and height != 0: + frame_t = F.interpolate(frame_t, size=(height, width), mode=mode) + return frame_t + + def to_numpy(self, tensor): + tensor = tensor.cpu() + tensor = tensor[0] + array = np.array(tensor.permute(1, 2, 0)) + return array + + def read_masks(self, mask_dir, width, height, pivot, sequenceLen, sample_interval): + mask_path = sorted(glob.glob(os.path.join(mask_dir, '*.png'))) + masks = [] + half_seq = sequenceLen // 2 + for i in range(-half_seq, half_seq + 1): + index = pivot + i * sample_interval + if index < 0: + index = 0 + if index >= len(mask_path): + index = len(mask_path) - 1 + mask = cv2.imread(mask_path[index], 0) + mask = mask / 255. + mask = cv2.resize(mask, (width, height), cv2.INTER_NEAREST) + mask[mask > 0] = 1 + if len(mask.shape) == 2: + mask = mask[:, :, np.newaxis] + assert len(mask.shape) == 3, 'Invalid mask shape: {}'.format(mask.shape) + masks.append(mask) + return masks + + def diffusion_filling(self, flows, masks): + filled_flows = [] + for i in range(len(flows)): + flow, mask = flows[i], masks[i][:, :, 0] + flow_filled = np.zeros(flow.shape) + flow_filled[:, :, 0] = rf.regionfill(flow[:, :, 0], mask) + flow_filled[:, :, 1] = rf.regionfill(flow[:, :, 1], mask) + filled_flows.append(flow_filled) + return filled_flows + + def vis_flows(self, result, target_flow, diffused_flow, video_name, epoch): + """ + Vis the filled frames, the GT and the masked frames with the following format + | | | | + | Ours | GT | diffused_flows | + | | | | + Args: + result: contains generated flow tensors with shape [1, 2, h, w] + target_flow: contains GT flow tensors with shape [1, 2, h, w] + diffused_flow: contains diffused flow tensor with shape [1, 2, h, w] + video_name: video name + epoch: epoch + + Returns: No returns, but will save the flows for every flow + + """ + out_root = self.opt['path']['VAL_IMAGES'] + out_dir = os.path.join(out_root, str(epoch), video_name) + if not os.path.exists(out_dir): + os.makedirs(out_dir) + black_column_pixels = 20 + result = self.to_numpy(result) + target_flow = self.to_numpy(target_flow) + diffused_flow = self.to_numpy(diffused_flow) + result = cvbase.flow2rgb(result) + target_flow = cvbase.flow2rgb(target_flow) + diffused_flow = cvbase.flow2rgb(diffused_flow) + height, width = result.shape[:2] + canvas = np.zeros((height, width * 3 + black_column_pixels * 2, 3)) + canvas[:, 0:width, :] = result + canvas[:, width + black_column_pixels: 2 * width + black_column_pixels, :] = target_flow + canvas[:, 2 * (width + black_column_pixels):, :] = diffused_flow + imageio.imwrite(os.path.join(out_dir, 'result_compare.png'), canvas) diff --git a/FGT_codes/LAFC/parse.py b/FGT_codes/LAFC/parse.py new file mode 100644 index 0000000000000000000000000000000000000000..72dfa32c0d985bb903ab074cedb7513c867d2ee8 --- /dev/null +++ b/FGT_codes/LAFC/parse.py @@ -0,0 +1,77 @@ +import yaml +import os +import os.path as osp + + +def path_correction(dataInfo, workdir): + for key in dataInfo.keys(): + if 'path' in key: + dataInfo[key] = os.path.join(workdir, dataInfo[key]) + return dataInfo + + +def val_path_correction(valInfo, workdir): + for key in valInfo.keys(): + if 'root' in key: + valInfo[key] = os.path.join(workdir, valInfo[key]) + return valInfo + + +def parse(args_setting, is_train=True): + opt_path = args_setting['opt'] + print('Current working dir is: {}'.format(os.getcwd())) + print('There are {} sub directories here'.format(os.listdir(os.getcwd()))) + with open(opt_path, 'r', encoding='utf-8') as f: + opt = yaml.safe_load(f) + + opt['is_train'] = is_train + opt = {**args_setting, **opt} + + name = opt['name'] + datadir, outputdir = opt['datadir'], opt['outputdir'] + + datasets = {} + for phase, args in opt['datasets'].items(): + # phase is `train`, `val` or `test` + datasets[phase] = args + if phase == 'train': + with open(args['dataInfo_config'], 'r', encoding='utf-8') as f: + dataInfo = yaml.safe_load(f) + dataInfo = path_correction(dataInfo, datadir) + datasets['dataInfo'] = dataInfo + if phase == 'val': + with open(args['val_config'], 'r', encoding='utf-8') as f: + valInfo = yaml.safe_load(f) + valInfo = val_path_correction(valInfo, datadir) + datasets['valInfo'] = valInfo + opt['datasets'] = datasets + + # path + opt['path'] = {} + + # training settings + if is_train: + output_root = osp.join(outputdir, opt['name'], 'experiments') + opt['path']['OUTPUT_ROOT'] = output_root + opt['path']['TRAINING_STATE'] = osp.join(output_root, 'training_state') + opt['path']['LOG'] = osp.join(output_root, 'log') + opt['path']['VAL_IMAGES'] = osp.join(output_root, 'val_images') + else: # for test + result_root = osp.join(datadir, opt['path']['OUTPUT_ROOT'], 'results', opt['name']) + opt['path']['RESULT_ROOT'] = osp.join(result_root, 'RESULT_ROOT') + opt['path']['LOG'] = result_root + + return opt + + +def toString(opt, indent_l=1): + msg = '' + for k, v in opt.items(): + if isinstance(v, dict): + msg += ' ' * (indent_l * 2) + k + ':[\n' + msg += toString(v, indent_l=1) + msg += ' ' * (indent_l * 2) + ']\n' + else: + msg += ' ' * (indent_l * 2) + k + ': ' + str(v) + '\n' + return msg + diff --git a/FGT_codes/LAFC/train.py b/FGT_codes/LAFC/train.py new file mode 100644 index 0000000000000000000000000000000000000000..67468dbb90daed76b8af4addb496bd3631fd8958 --- /dev/null +++ b/FGT_codes/LAFC/train.py @@ -0,0 +1,70 @@ +from utils.dist import * +from parse import * +from utils.util import find_free_port +import torch.multiprocessing as mp +import torch.distributed +from importlib import import_module + +from flow_inputs import args_parser + + +def main_worker(rank, opt): + if 'local_rank' not in opt: + opt['local_rank'] = opt['global_rank'] = rank + if opt['distributed']: + torch.cuda.set_device(int(opt['local_rank'])) + torch.distributed.init_process_group(backend='nccl', + init_method=opt['init_method'], + world_size=opt['world_size'], + rank=opt['global_rank'], + group_name='mtorch') + print('using GPU {}-{} for training'.format( + int(opt['global_rank']), int(opt['local_rank']))) + + if torch.cuda.is_available(): + opt['device'] = torch.device("cuda:{}".format(opt['local_rank'])) + else: + opt['device'] = 'cpu' + + pkg = import_module('networks.{}'.format(opt['network'])) + trainer = pkg.Network(opt, rank) + trainer.train() + + +def main(args_obj): + opt = parse(args_obj) + opt['world_size'] = get_world_size() + free_port = find_free_port() + master_ip = get_master_ip() + opt['init_method'] = "tcp://{}:{}".format(master_ip, free_port) + opt['distributed'] = True if opt['world_size'] > 1 else False + print(f'World size is: {opt["world_size"]}, and init_method is: {opt["init_method"]}') + print('Import network module: ', opt['network']) + + # dataset file names + if opt['gen_state'] != '': + opt['path']['gen_state'] = opt['gen_state'] + if opt['opt_state'] != '': + opt['path']['opt_state'] = opt['opt_state'] + + if args.finetune == 1: + opt['finetune'] = True + else: + opt['finetune'] = False + + print(f'model is: {opt["model"]}') + + if get_master_ip() == "127.0.0.1": + # localhost + mp.spawn(main_worker, nprocs=opt['world_size'], args=(opt,)) + else: + # multiple processes should be launched by openmpi + opt['local_rank'] = get_local_rank() + opt['global_rank'] = get_global_rank() + main_worker(-1, opt) + + +if __name__ == '__main__': + args = args_parser() + args_obj = vars(args) + main(args_obj) diff --git a/FGT_codes/LAFC/trainer.py b/FGT_codes/LAFC/trainer.py new file mode 100644 index 0000000000000000000000000000000000000000..43e7cd74cce4a4d080d71d609f2e001383682b18 --- /dev/null +++ b/FGT_codes/LAFC/trainer.py @@ -0,0 +1,182 @@ +import math +import parse +import logging +from utils import util +from torch.utils.data.distributed import DistributedSampler +from torch.nn.parallel import DistributedDataParallel as DDP +from data import create_dataset, create_dataloader +from models.utils.loss import * +import yaml +from models.utils.edgeLoss import EdgeLoss +from abc import abstractmethod, ABCMeta + + +class Trainer(metaclass=ABCMeta): + def __init__(self, opt, rank): + self.opt = opt + self.rank = rank + + # make directory and set logger + if rank <= 0: + self.mkdir() + self.logger, self.tb_logger = self.setLogger() + self.setSeed() + self.dataInfo, self.valInfo, self.trainSet, self.trainSize, self.totalIterations, self.totalEpochs, self.trainLoader, self.trainSampler = self.prepareDataset() + self.model, self.optimizer, self.scheduler = self.init_model() + self.model = self.model.to(self.opt['device']) + if opt['path'].get('opt_state', None): + self.startEpoch, self.currentStep = self.resume_training() + else: + self.startEpoch, self.currentStep = 0, 0 + if opt['distributed']: + self.model = DDP( + self.model, + device_ids=[self.opt['local_rank']], + output_device=self.opt['local_rank'], + # find_unused_parameters=True + ) + if self.rank <= 0: + self.logger.info('Start training from epoch: {}, iter: {}'.format( + self.startEpoch, self.currentStep)) + + self.maskedLoss = nn.L1Loss() + self.validLoss = nn.L1Loss() + self.edgeLoss = EdgeLoss(self.opt['device']) + self.countDown = 0 + + # metrics recorder + self.total_loss = 0 + self.total_psnr = 0 + self.total_ssim = 0 + self.total_l1 = 0 + self.total_l2 = 0 + + def get_lr(self): + lr = [] + for param_group in self.optimizer.param_groups: + lr += [param_group['lr']] + return lr + + def adjust_learning_rate(self, optimizer, target_lr): + for param_group in optimizer.param_groups: + param_group['lr'] = target_lr + + def mkdir(self): + new_name = util.mkdir_and_rename(self.opt['path']['OUTPUT_ROOT']) + if new_name: + self.opt['path']['TRAINING_STATE'] = os.path.join(new_name, 'training_state') + self.opt['path']['LOG'] = os.path.join(new_name, 'log') + self.opt['path']['VAL_IMAGES'] = os.path.join(new_name, 'val_images') + if not os.path.exists(self.opt['path']['TRAINING_STATE']): + os.makedirs(self.opt['path']['TRAINING_STATE']) + if not os.path.exists(self.opt['path']['LOG']): + os.makedirs(self.opt['path']['LOG']) + if not os.path.exists(self.opt['path']['VAL_IMAGES']): + os.makedirs(self.opt['path']['VAL_IMAGES']) + # save config file for output + with open(os.path.join(self.opt['path']['LOG'], 'config.yaml'), 'w') as f: + yaml.dump(self.opt, f) + + def setLogger(self): + util.setup_logger('base', self.opt['path']['LOG'], 'train_' + self.opt['name'], level=logging.INFO, + screen=True, tofile=True) + logger = logging.getLogger('base') + logger.info(parse.toString(self.opt)) + logger.info('OUTPUT DIR IS: {}'.format(self.opt['path']['OUTPUT_ROOT'])) + if self.opt['use_tb_logger']: + version = float(torch.__version__[0:3]) + if version >= 1.1: + from torch.utils.tensorboard import SummaryWriter + else: + logger.info('You are using PyTorch {}, Tensorboard will use [tensorboardX)'.format(version)) + from tensorboardX import SummaryWriter + tb_logger = SummaryWriter(os.path.join(self.opt['path']['OUTPUT_ROOT'], 'log')) + else: + tb_logger = None + return logger, tb_logger + + def setSeed(self): + seed = self.opt['train']['manual_seed'] + if self.rank <= 0: + self.logger.info('Random seed: {}'.format(seed)) + util.set_random_seed(seed) + torch.backends.cudnn.benchmark = True + if seed == 0: + torch.backends.cudnn.deterministic = True + + def prepareDataset(self): + dataInfo = self.opt['datasets']['dataInfo'] + valInfo = self.opt['datasets']['valInfo'] + valInfo['sigma'] = dataInfo['edge']['sigma'] + valInfo['low_threshold'] = dataInfo['edge']['low_threshold'] + valInfo['high_threshold'] = dataInfo['edge']['high_threshold'] + valInfo['norm'] = self.opt['norm'] + if self.rank <= 0: + self.logger.debug('Val info is: {}'.format(valInfo)) + train_set, train_size, total_iterations, total_epochs = 0, 0, 0, 0 + train_loader, train_sampler = None, None + for phase, dataset in self.opt['datasets'].items(): + dataset['norm'] = self.opt['norm'] + dataset['dataMode'] = self.opt['dataMode'] + dataset['edge_loss'] = self.opt['edge_loss'] + dataset['ternary'] = self.opt['ternary'] + dataset['num_flows'] = self.opt['num_flows'] + dataset['sample'] = self.opt['sample'] + dataset['use_edges'] = self.opt['use_edges'] + dataset['flow_interval'] = self.opt['flow_interval'] + if phase.lower() == 'train': + train_set = create_dataset(dataset, dataInfo, phase, self.opt['datasetName_train']) + train_size = math.ceil( + len(train_set) / (dataset['batch_size'] * self.opt['world_size'])) # 计算一个epoch有多少个iterations + total_iterations = self.opt['train']['MAX_ITERS'] + total_epochs = int(math.ceil(total_iterations / train_size)) + if self.opt['distributed']: + train_sampler = DistributedSampler( + train_set, + num_replicas=self.opt['world_size'], + rank=self.opt['global_rank']) + else: + train_sampler = None + train_loader = create_dataloader(phase, train_set, dataset, self.opt, train_sampler) + if self.rank <= 0: + self.logger.info('Number of training batches: {}, iters: {}'.format(len(train_set), + total_iterations)) + self.logger.info('Total epoch needed: {} for iters {}'.format(total_epochs, total_iterations)) + assert train_set != 0 and train_size != 0, "Train size cannot be zero" + assert train_loader is not None, "Cannot find train set, val set can be None" + return dataInfo, valInfo, train_set, train_size, total_iterations, total_epochs, train_loader, train_sampler + + @abstractmethod + def init_model(self): + pass + + @abstractmethod + def resume_training(self): + pass + + def train(self): + for epoch in range(self.startEpoch, self.totalEpochs + 1): + if self.opt['distributed']: + self.trainSampler.set_epoch(epoch) + self._trainEpoch(epoch) + if self.currentStep > self.totalIterations: + break + if self.opt['use_valid'] and (epoch + 1) % self.opt['train']['val_freq'] == 0: + self._validate(epoch) + self.scheduler.step(epoch) + + @abstractmethod + def _trainEpoch(self, epoch): + pass + + @abstractmethod + def _printLog(self, logs, epoch, loss): + pass + + @abstractmethod + def save_checkpoint(self, epoch, metric, number): + pass + + @abstractmethod + def _validate(self, epoch): + pass diff --git a/FGT_codes/LAFC/utils/__init__.py b/FGT_codes/LAFC/utils/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/FGT_codes/LAFC/utils/dist.py b/FGT_codes/LAFC/utils/dist.py new file mode 100644 index 0000000000000000000000000000000000000000..f07940ada074a687debbfe730e5df9ccd34651cf --- /dev/null +++ b/FGT_codes/LAFC/utils/dist.py @@ -0,0 +1,55 @@ +import os +import io +import re +import subprocess +import logging +import random +import torch +import numpy as np + + +## This code is borrowed from +# https://github.com/researchmm/STTN/blob/master/core/dist.py +def get_world_size(): + """Find OMPI world size without calling mpi functions + :rtype: int + """ + if os.environ.get('PMI_SIZE') is not None: + return int(os.environ.get('PMI_SIZE') or 1) + elif os.environ.get('OMPI_COMM_WORLD_SIZE') is not None: + return int(os.environ.get('OMPI_COMM_WORLD_SIZE') or 1) + else: + return torch.cuda.device_count() + + +def get_global_rank(): + """Find OMPI world rank without calling mpi functions + :rtype: int + """ + if os.environ.get('PMI_RANK') is not None: + return int(os.environ.get('PMI_RANK') or 0) + elif os.environ.get('OMPI_COMM_WORLD_RANK') is not None: + return int(os.environ.get('OMPI_COMM_WORLD_RANK') or 0) + else: + return 0 + + +def get_local_rank(): + """Find OMPI local rank without calling mpi functions + :rtype: int + """ + if os.environ.get('MPI_LOCALRANKID') is not None: + return int(os.environ.get('MPI_LOCALRANKID') or 0) + elif os.environ.get('OMPI_COMM_WORLD_LOCAL_RANK') is not None: + return int(os.environ.get('OMPI_COMM_WORLD_LOCAL_RANK') or 0) + else: + return 0 + + +def get_master_ip(): + if os.environ.get('AZ_BATCH_MASTER_NODE') is not None: + return os.environ.get('AZ_BATCH_MASTER_NODE').split(':')[0] + elif os.environ.get('AZ_BATCHAI_MPI_MASTER_NODE') is not None: + return os.environ.get('AZ_BATCHAI_MPI_MASTER_NODE') + else: + return "127.0.0.1" diff --git a/FGT_codes/LAFC/utils/util.py b/FGT_codes/LAFC/utils/util.py new file mode 100644 index 0000000000000000000000000000000000000000..e494f1cecb0c872eeffb8b626e26077b5ce621c2 --- /dev/null +++ b/FGT_codes/LAFC/utils/util.py @@ -0,0 +1,432 @@ +import os +import sys +import time +import math +import torch.nn.functional as F +from datetime import datetime +import random +import logging +from collections import OrderedDict +import numpy as np +import cv2 +import torch +from torchvision.utils import make_grid +from shutil import get_terminal_size +import torchvision.utils as vutils +from shutil import copyfile +import torchvision.transforms as transforms + +import yaml + +try: + from yaml import CLoader as Loader, CDumper as Dumper +except ImportError: + from yaml import Loader, Dumper + + +def OrderedYaml(): + '''yaml orderedDict support''' + _mapping_tag = yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG + + def dict_representer(dumper, data): + return dumper.represent_dict(data.items()) + + def dict_constructor(loader, node): + return OrderedDict(loader.construct_pairs(node)) + + Dumper.add_representer(OrderedDict, dict_representer) + Loader.add_constructor(_mapping_tag, dict_constructor) + return Loader, Dumper + + +#################### +# miscellaneous +#################### + + +def get_timestamp(): + return datetime.now().strftime('%y%m%d-%H%M%S') + + +def mkdir(path): + if not os.path.exists(path): + os.makedirs(path) + + +def mkdirs(paths): + if isinstance(paths, str): + print('path is : ', paths) + mkdir(paths) + else: + for path in paths: + print('path is : {}'.format(path)) + mkdir(path) + + +def mkdir_and_rename(path): + new_name = None + if os.path.exists(path): + new_name = path + '_archived_' + get_timestamp() + logger = logging.getLogger('base') + logger.info('Path already exists. Rename it to [{:s}]'.format(new_name)) + os.rename(path, new_name) + os.makedirs(path) + return new_name + + +def set_random_seed(seed): + random.seed(seed) + np.random.seed(seed) + torch.manual_seed(seed) + torch.cuda.manual_seed_all(seed) + + +def setup_logger(logger_name, root, phase, level=logging.INFO, screen=False, tofile=False): + '''set up logger''' + lg = logging.getLogger(logger_name) + formatter = logging.Formatter('%(asctime)s.%(msecs)03d - %(levelname)s: %(message)s', + datefmt='%y-%m-%d %H:%M:%S') + lg.setLevel(level) + if tofile: + log_file = os.path.join(root, phase + '_{}.log'.format(get_timestamp())) + fh = logging.FileHandler(log_file, mode='w') + fh.setFormatter(formatter) + lg.addHandler(fh) + if screen: + sh = logging.StreamHandler() + sh.setFormatter(formatter) + lg.addHandler(sh) + + +#################### +# image convert +#################### +def crop_border(img_list, crop_border): + """Crop borders of images + Args: + img_list (list [Numpy]): HWC + crop_border (int): crop border for each end of height and weight + + Returns: + (list [Numpy]): cropped image list + """ + if crop_border == 0: + return img_list + else: + return [v[crop_border:-crop_border, crop_border:-crop_border] for v in img_list] + + +def tensor2img(tensor, out_type=np.uint8, min_max=(0, 1)): + ''' + Converts a torch Tensor into an image Numpy array + Input: 4D(B,(3/1),H,W), 3D(C,H,W), or 2D(H,W), any range, RGB channel order + Output: 3D(H,W,C) or 2D(H,W), [0,255], np.uint8 (default) + ''' + tensor = tensor.squeeze().float().cpu().clamp_(*min_max) # clamp + tensor = (tensor - min_max[0]) / (min_max[1] - min_max[0]) # to range [0,1] + n_dim = tensor.dim() + if n_dim == 4: + n_img = len(tensor) + img_np = make_grid(tensor, nrow=int(math.sqrt(n_img)), normalize=False).numpy() + img_np = np.transpose(img_np[[2, 1, 0], :, :], (1, 2, 0)) # HWC, BGR + elif n_dim == 3: + img_np = tensor.numpy() + img_np = np.transpose(img_np[[2, 1, 0], :, :], (1, 2, 0)) # HWC, BGR + elif n_dim == 2: + img_np = tensor.numpy() + else: + raise TypeError( + 'Only support 4D, 3D and 2D tensor. But received with dimension: {:d}'.format(n_dim)) + if out_type == np.uint8: + img_np = (img_np * 255.0).round() + # Important. Unlike matlab, numpy.unit8() WILL NOT round by default. + return img_np.astype(out_type) + + +def save_img(img, img_path, mode='RGB'): + cv2.imwrite(img_path, img) + + +def DUF_downsample(x, scale=4): + """Downsamping with Gaussian kernel used in the DUF official code + + Args: + x (Tensor, [B, T, C, H, W]): frames to be downsampled. + scale (int): downsampling factor: 2 | 3 | 4. + """ + + assert scale in [2, 3, 4], 'Scale [{}] is not supported'.format(scale) + + def gkern(kernlen=13, nsig=1.6): + import scipy.ndimage.filters as fi + inp = np.zeros((kernlen, kernlen)) + # set element at the middle to one, a dirac delta + inp[kernlen // 2, kernlen // 2] = 1 + # gaussian-smooth the dirac, resulting in a gaussian filter mask + return fi.gaussian_filter(inp, nsig) + + B, T, C, H, W = x.size() + x = x.view(-1, 1, H, W) + pad_w, pad_h = 6 + scale * 2, 6 + scale * 2 # 6 is the pad of the gaussian filter + r_h, r_w = 0, 0 + if scale == 3: + r_h = 3 - (H % 3) + r_w = 3 - (W % 3) + x = F.pad(x, [pad_w, pad_w + r_w, pad_h, pad_h + r_h], 'reflect') + + gaussian_filter = torch.from_numpy(gkern(13, 0.4 * scale)).type_as(x).unsqueeze(0).unsqueeze(0) + x = F.conv2d(x, gaussian_filter, stride=scale) + x = x[:, :, 2:-2, 2:-2] + x = x.view(B, T, C, x.size(2), x.size(3)) + return x + + +def single_forward(model, inp): + """PyTorch model forward (single test), it is just a simple warpper + Args: + model (PyTorch model) + inp (Tensor): inputs defined by the model + + Returns: + output (Tensor): outputs of the model. float, in CPU + """ + with torch.no_grad(): + model_output = model(inp) + if isinstance(model_output, list) or isinstance(model_output, tuple): + output = model_output[0] + else: + output = model_output + output = output.data.float().cpu() + return output + + +def flipx4_forward(model, inp): + """Flip testing with X4 self ensemble, i.e., normal, flip H, flip W, flip H and W + Args: + model (PyTorch model) + inp (Tensor): inputs defined by the model + + Returns: + output (Tensor): outputs of the model. float, in CPU + """ + # normal + output_f = single_forward(model, inp) + + # flip W + output = single_forward(model, torch.flip(inp, (-1,))) + output_f = output_f + torch.flip(output, (-1,)) + # flip H + output = single_forward(model, torch.flip(inp, (-2,))) + output_f = output_f + torch.flip(output, (-2,)) + # flip both H and W + output = single_forward(model, torch.flip(inp, (-2, -1))) + output_f = output_f + torch.flip(output, (-2, -1)) + + return output_f / 4 + + +#################### +# metric +#################### + + +class ProgressBar(object): + '''A progress bar which can print the progress + modified from https://github.com/hellock/cvbase/blob/master/cvbase/progress.py + ''' + + def __init__(self, task_num=0, bar_width=50, start=True): + self.task_num = task_num + max_bar_width = self._get_max_bar_width() + self.bar_width = (bar_width if bar_width <= max_bar_width else max_bar_width) + self.completed = 0 + if start: + self.start() + + def _get_max_bar_width(self): + terminal_width, _ = get_terminal_size() + max_bar_width = min(int(terminal_width * 0.6), terminal_width - 50) + if max_bar_width < 10: + print('terminal width is too small ({}), please consider widen the terminal for better ' + 'progressbar visualization'.format(terminal_width)) + max_bar_width = 10 + return max_bar_width + + def start(self): + if self.task_num > 0: + sys.stdout.write('[{}] 0/{}, elapsed: 0s, ETA:\n{}\n'.format( + ' ' * self.bar_width, self.task_num, 'Start...')) + else: + sys.stdout.write('completed: 0, elapsed: 0s') + sys.stdout.flush() + self.start_time = time.time() + + def update(self, msg='In progress...'): + self.completed += 1 + elapsed = time.time() - self.start_time + fps = self.completed / elapsed + if self.task_num > 0: + percentage = self.completed / float(self.task_num) + eta = int(elapsed * (1 - percentage) / percentage + 0.5) + mark_width = int(self.bar_width * percentage) + bar_chars = '>' * mark_width + '-' * (self.bar_width - mark_width) + sys.stdout.write('\033[2F') # cursor up 2 lines + sys.stdout.write('\033[J') # clean the output (remove extra chars since last display) + sys.stdout.write('[{}] {}/{}, {:.1f} task/s, elapsed: {}s, ETA: {:5}s\n{}\n'.format( + bar_chars, self.completed, self.task_num, fps, int(elapsed + 0.5), eta, msg)) + else: + sys.stdout.write('completed: {}, elapsed: {}s, {:.1f} tasks/s'.format( + self.completed, int(elapsed + 0.5), fps)) + sys.stdout.flush() + + +### communication +def find_free_port(): + import socket + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.bind(("", 0)) + port = sock.getsockname()[1] + sock.close() + return port + + +# for debug +def visualize_image(result, outputDir, epoch, mode, video_name, minData=0): + ### Only visualize one frame + targetDir = os.path.join(outputDir, str(epoch), video_name) + if not os.path.exists(targetDir): + os.makedirs(targetDir) + if minData == -1: + result = (result + 1) / 2 + vutils.save_image(result, os.path.join(targetDir, '{}.png'.format(mode))) + elif minData == 0: + vutils.save_image(result, os.path.join(targetDir, '{}.png'.format(mode))) + else: + raise ValueError('minValue {} is not supported'.format(minData)) + + +def get_learning_rate(optimizer): + lr = [] + for param_group in optimizer.param_groups: + lr += [param_group['lr']] + return lr + + +def adjust_learning_rate(optimizer, target_lr): + for param_group in optimizer.param_groups: + param_group['lr'] = target_lr + + +def save_checkpoint(epoch, model, discriminator, current_step, schedulers, dist_scheduler, optimizers, dist_optimizer, save_path, is_best, monitor, monitor_value, + config): + # for entriely resuming state, you need to save the state dict of model, optimizer and learning scheduler + if isinstance(model, torch.nn.DataParallel) or isinstance(model, torch.nn.parallel.DistributedDataParallel): + model_state = model.module.state_dict() + discriminator_state = discriminator.module.state_dict() + else: + model_state = model.state_dict() + discriminator_state = discriminator.state_dict() + state = { + 'epoch': epoch, + 'iteration': current_step, + 'model_state_dict': model_state, + 'discriminator_state_dict': discriminator_state, + 'optimizer_state_dict': optimizers.state_dict(), + 'dist_optim_state_dict': dist_optimizer.state_dict(), + 'scheduler_state_dict': schedulers.state_dict(), + 'dist_scheduler_state_dict': dist_scheduler.state_dict(), + 'is_best': is_best, + 'config': config, + } + + best_str = '-best-so-far' if is_best else '' + monitor_str = '-{}:{}'.format(monitor, monitor_value) if monitor_value else '' + if not os.path.exists(os.path.join(save_path, 'best')): + os.makedirs(os.path.join(save_path, 'best')) + file_name = os.path.join(save_path, 'checkpoint-epoch:{}{}{}.pth.tar'.format(epoch, monitor_str, best_str)) + torch.save(state, file_name) + if is_best: + copyfile(src=file_name, dst=os.path.join(save_path, 'best', + 'checkpoint-epoch:{}{}{}.pth.tar'.format(epoch, monitor_str, + best_str))) + + +def save_dist_checkpoint(epoch, model, dist, current_step, schedulers, schedulersD, optimizers, optimizersD, save_path, + is_best, monitor, monitor_value, + config): + # for entriely resuming state, you need to save the state dict of model, optimizer and learning scheduler + if isinstance(model, torch.nn.DataParallel) or isinstance(model, torch.nn.parallel.DistributedDataParallel): + model_state = model.module.state_dict() + dist_state = dist.module.state_dict() + else: + model_state = model.state_dict() + dist_state = dist.state_dict() + state = { + 'epoch': epoch, + 'iteration': current_step, + 'model_state_dict': model_state, + 'dist_state_dict': dist_state, + 'optimizer_state_dict': optimizers.state_dict(), + 'optimizerD_state_dict': optimizersD.state_dict(), + 'scheduler_state_dict': schedulers.state_dict(), + 'schedulerD_state_dict': schedulersD.state_dict(), + 'is_best': is_best, + 'config': config + } + + best_str = '-best-so-far' if is_best else '' + monitor_str = '-{}:{}'.format(monitor, monitor_value) if monitor_value else '' + if not os.path.exists(os.path.join(save_path, 'best')): + os.makedirs(os.path.join(save_path, 'best')) + file_name = os.path.join(save_path, 'checkpoint-epoch:{}{}{}.pth.tar'.format(epoch, monitor_str, best_str)) + torch.save(state, file_name) + if is_best: + copyfile(src=file_name, dst=os.path.join(save_path, 'best', + 'checkpoint-epoch:{}{}{}.pth.tar'.format(epoch, monitor_str, + best_str))) + + +def poisson_blend(input, output, mask): + """ + * inputs: + - input (torch.Tensor, required) + Input tensor of Completion Network, whose shape = (N, 3, H, W). + - output (torch.Tensor, required) + Output tensor of Completion Network, whose shape = (N, 3, H, W). + - mask (torch.Tensor, required) + Input mask tensor of Completion Network, whose shape = (N, 1, H, W). + * returns: + Output image tensor of shape (N, 3, H, W) inpainted with poisson image editing method. + from lizuka et al: https://github.com/otenim/GLCIC-PyTorch/blob/caf9bebe667fba0aebbd041918f2d8128f59ec62/utils.py + """ + input = input.clone().cpu() + output = output.clone().cpu() + mask = mask.clone().cpu() + mask = torch.cat((mask, mask, mask), dim=1) # convert to 3-channel format + num_samples = input.shape[0] + ret = [] + for i in range(num_samples): + dstimg = transforms.functional.to_pil_image(input[i]) + dstimg = np.array(dstimg)[:, :, [2, 1, 0]] + srcimg = transforms.functional.to_pil_image(output[i]) + srcimg = np.array(srcimg)[:, :, [2, 1, 0]] + msk = transforms.functional.to_pil_image(mask[i]) + msk = np.array(msk)[:, :, [2, 1, 0]] + # compute mask's center + xs, ys = [], [] + for j in range(msk.shape[0]): + for k in range(msk.shape[1]): + if msk[j, k, 0] == 255: + ys.append(j) + xs.append(k) + xmin, xmax = min(xs), max(xs) + ymin, ymax = min(ys), max(ys) + center = ((xmax + xmin) // 2, (ymax + ymin) // 2) + dstimg = cv2.inpaint(dstimg, msk[:, :, 0], 1, cv2.INPAINT_TELEA) + out = cv2.seamlessClone(srcimg, dstimg, msk, center, cv2.NORMAL_CLONE) + out = out[:, :, [2, 1, 0]] + out = transforms.functional.to_tensor(out) + out = torch.unsqueeze(out, dim=0) + ret.append(out) + ret = torch.cat(ret, dim=0) + return ret diff --git a/FGT_codes/RAFT/__init__.py b/FGT_codes/RAFT/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e7179ea3ce4ad81425c619772d4bc47bc7ceea3a --- /dev/null +++ b/FGT_codes/RAFT/__init__.py @@ -0,0 +1,2 @@ +# from .demo import RAFT_infer +from .raft import RAFT diff --git a/FGT_codes/RAFT/__pycache__/__init__.cpython-39.pyc b/FGT_codes/RAFT/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3310c709821a7d77062149edd8beb3cfceff4567 Binary files /dev/null and b/FGT_codes/RAFT/__pycache__/__init__.cpython-39.pyc differ diff --git a/FGT_codes/RAFT/__pycache__/corr.cpython-39.pyc b/FGT_codes/RAFT/__pycache__/corr.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..042ecb53356a2172ddc8a5d54346df38baf5ecd9 Binary files /dev/null and b/FGT_codes/RAFT/__pycache__/corr.cpython-39.pyc differ diff --git a/FGT_codes/RAFT/__pycache__/extractor.cpython-39.pyc b/FGT_codes/RAFT/__pycache__/extractor.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1037d44e109ab850303cd651a57ff9126a244b0c Binary files /dev/null and b/FGT_codes/RAFT/__pycache__/extractor.cpython-39.pyc differ diff --git a/FGT_codes/RAFT/__pycache__/raft.cpython-39.pyc b/FGT_codes/RAFT/__pycache__/raft.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..598557c1268d621b99f0bd8548ca61ab9d357db7 Binary files /dev/null and b/FGT_codes/RAFT/__pycache__/raft.cpython-39.pyc differ diff --git a/FGT_codes/RAFT/__pycache__/update.cpython-39.pyc b/FGT_codes/RAFT/__pycache__/update.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9522526758a74995adebd135f5c3f14cbd36b63b Binary files /dev/null and b/FGT_codes/RAFT/__pycache__/update.cpython-39.pyc differ diff --git a/FGT_codes/RAFT/corr.py b/FGT_codes/RAFT/corr.py new file mode 100644 index 0000000000000000000000000000000000000000..449dbd963b8303eda242a65063ca857b95475721 --- /dev/null +++ b/FGT_codes/RAFT/corr.py @@ -0,0 +1,111 @@ +import torch +import torch.nn.functional as F +from .utils.utils import bilinear_sampler, coords_grid + +try: + import alt_cuda_corr +except: + # alt_cuda_corr is not compiled + pass + + +class CorrBlock: + def __init__(self, fmap1, fmap2, num_levels=4, radius=4): + self.num_levels = num_levels + self.radius = radius + self.corr_pyramid = [] + + # all pairs correlation + corr = CorrBlock.corr(fmap1, fmap2) + + batch, h1, w1, dim, h2, w2 = corr.shape + corr = corr.reshape(batch*h1*w1, dim, h2, w2) + + self.corr_pyramid.append(corr) + for i in range(self.num_levels-1): + corr = F.avg_pool2d(corr, 2, stride=2) + self.corr_pyramid.append(corr) + + def __call__(self, coords): + r = self.radius + coords = coords.permute(0, 2, 3, 1) + batch, h1, w1, _ = coords.shape + + out_pyramid = [] + for i in range(self.num_levels): + corr = self.corr_pyramid[i] + dx = torch.linspace(-r, r, 2*r+1) + dy = torch.linspace(-r, r, 2*r+1) + delta = torch.stack(torch.meshgrid(dy, dx), axis=-1).to(coords.device) + + centroid_lvl = coords.reshape(batch*h1*w1, 1, 1, 2) / 2**i + delta_lvl = delta.view(1, 2*r+1, 2*r+1, 2) + coords_lvl = centroid_lvl + delta_lvl + + corr = bilinear_sampler(corr, coords_lvl) + corr = corr.view(batch, h1, w1, -1) + out_pyramid.append(corr) + + out = torch.cat(out_pyramid, dim=-1) + return out.permute(0, 3, 1, 2).contiguous().float() + + @staticmethod + def corr(fmap1, fmap2): + batch, dim, ht, wd = fmap1.shape + fmap1 = fmap1.view(batch, dim, ht*wd) + fmap2 = fmap2.view(batch, dim, ht*wd) + + corr = torch.matmul(fmap1.transpose(1,2), fmap2) + corr = corr.view(batch, ht, wd, 1, ht, wd) + return corr / torch.sqrt(torch.tensor(dim).float()) + + +class CorrLayer(torch.autograd.Function): + @staticmethod + def forward(ctx, fmap1, fmap2, coords, r): + fmap1 = fmap1.contiguous() + fmap2 = fmap2.contiguous() + coords = coords.contiguous() + ctx.save_for_backward(fmap1, fmap2, coords) + ctx.r = r + corr, = correlation_cudaz.forward(fmap1, fmap2, coords, ctx.r) + return corr + + @staticmethod + def backward(ctx, grad_corr): + fmap1, fmap2, coords = ctx.saved_tensors + grad_corr = grad_corr.contiguous() + fmap1_grad, fmap2_grad, coords_grad = \ + correlation_cudaz.backward(fmap1, fmap2, coords, grad_corr, ctx.r) + return fmap1_grad, fmap2_grad, coords_grad, None + + +class AlternateCorrBlock: + def __init__(self, fmap1, fmap2, num_levels=4, radius=4): + self.num_levels = num_levels + self.radius = radius + + self.pyramid = [(fmap1, fmap2)] + for i in range(self.num_levels): + fmap1 = F.avg_pool2d(fmap1, 2, stride=2) + fmap2 = F.avg_pool2d(fmap2, 2, stride=2) + self.pyramid.append((fmap1, fmap2)) + + def __call__(self, coords): + + coords = coords.permute(0, 2, 3, 1) + B, H, W, _ = coords.shape + + corr_list = [] + for i in range(self.num_levels): + r = self.radius + fmap1_i = self.pyramid[0][0].permute(0, 2, 3, 1) + fmap2_i = self.pyramid[i][1].permute(0, 2, 3, 1) + + coords_i = (coords / 2**i).reshape(B, 1, H, W, 2).contiguous() + corr = alt_cuda_corr(fmap1_i, fmap2_i, coords_i, r) + corr_list.append(corr.squeeze(1)) + + corr = torch.stack(corr_list, dim=1) + corr = corr.reshape(B, -1, H, W) + return corr / 16.0 diff --git a/FGT_codes/RAFT/datasets.py b/FGT_codes/RAFT/datasets.py new file mode 100644 index 0000000000000000000000000000000000000000..3411fdacfb900024005e8997d07c600e963a95ca --- /dev/null +++ b/FGT_codes/RAFT/datasets.py @@ -0,0 +1,235 @@ +# Data loading based on https://github.com/NVIDIA/flownet2-pytorch + +import numpy as np +import torch +import torch.utils.data as data +import torch.nn.functional as F + +import os +import math +import random +from glob import glob +import os.path as osp + +from utils import frame_utils +from utils.augmentor import FlowAugmentor, SparseFlowAugmentor + + +class FlowDataset(data.Dataset): + def __init__(self, aug_params=None, sparse=False): + self.augmentor = None + self.sparse = sparse + if aug_params is not None: + if sparse: + self.augmentor = SparseFlowAugmentor(**aug_params) + else: + self.augmentor = FlowAugmentor(**aug_params) + + self.is_test = False + self.init_seed = False + self.flow_list = [] + self.image_list = [] + self.extra_info = [] + + def __getitem__(self, index): + + if self.is_test: + img1 = frame_utils.read_gen(self.image_list[index][0]) + img2 = frame_utils.read_gen(self.image_list[index][1]) + img1 = np.array(img1).astype(np.uint8)[..., :3] + img2 = np.array(img2).astype(np.uint8)[..., :3] + img1 = torch.from_numpy(img1).permute(2, 0, 1).float() + img2 = torch.from_numpy(img2).permute(2, 0, 1).float() + return img1, img2, self.extra_info[index] + + if not self.init_seed: + worker_info = torch.utils.data.get_worker_info() + if worker_info is not None: + torch.manual_seed(worker_info.id) + np.random.seed(worker_info.id) + random.seed(worker_info.id) + self.init_seed = True + + index = index % len(self.image_list) + valid = None + if self.sparse: + flow, valid = frame_utils.readFlowKITTI(self.flow_list[index]) + else: + flow = frame_utils.read_gen(self.flow_list[index]) + + img1 = frame_utils.read_gen(self.image_list[index][0]) + img2 = frame_utils.read_gen(self.image_list[index][1]) + + flow = np.array(flow).astype(np.float32) + img1 = np.array(img1).astype(np.uint8) + img2 = np.array(img2).astype(np.uint8) + + # grayscale images + if len(img1.shape) == 2: + img1 = np.tile(img1[...,None], (1, 1, 3)) + img2 = np.tile(img2[...,None], (1, 1, 3)) + else: + img1 = img1[..., :3] + img2 = img2[..., :3] + + if self.augmentor is not None: + if self.sparse: + img1, img2, flow, valid = self.augmentor(img1, img2, flow, valid) + else: + img1, img2, flow = self.augmentor(img1, img2, flow) + + img1 = torch.from_numpy(img1).permute(2, 0, 1).float() + img2 = torch.from_numpy(img2).permute(2, 0, 1).float() + flow = torch.from_numpy(flow).permute(2, 0, 1).float() + + if valid is not None: + valid = torch.from_numpy(valid) + else: + valid = (flow[0].abs() < 1000) & (flow[1].abs() < 1000) + + return img1, img2, flow, valid.float() + + + def __rmul__(self, v): + self.flow_list = v * self.flow_list + self.image_list = v * self.image_list + return self + + def __len__(self): + return len(self.image_list) + + +class MpiSintel(FlowDataset): + def __init__(self, aug_params=None, split='training', root='datasets/Sintel', dstype='clean'): + super(MpiSintel, self).__init__(aug_params) + flow_root = osp.join(root, split, 'flow') + image_root = osp.join(root, split, dstype) + + if split == 'test': + self.is_test = True + + for scene in os.listdir(image_root): + image_list = sorted(glob(osp.join(image_root, scene, '*.png'))) + for i in range(len(image_list)-1): + self.image_list += [ [image_list[i], image_list[i+1]] ] + self.extra_info += [ (scene, i) ] # scene and frame_id + + if split != 'test': + self.flow_list += sorted(glob(osp.join(flow_root, scene, '*.flo'))) + + +class FlyingChairs(FlowDataset): + def __init__(self, aug_params=None, split='train', root='datasets/FlyingChairs_release/data'): + super(FlyingChairs, self).__init__(aug_params) + + images = sorted(glob(osp.join(root, '*.ppm'))) + flows = sorted(glob(osp.join(root, '*.flo'))) + assert (len(images)//2 == len(flows)) + + split_list = np.loadtxt('chairs_split.txt', dtype=np.int32) + for i in range(len(flows)): + xid = split_list[i] + if (split=='training' and xid==1) or (split=='validation' and xid==2): + self.flow_list += [ flows[i] ] + self.image_list += [ [images[2*i], images[2*i+1]] ] + + +class FlyingThings3D(FlowDataset): + def __init__(self, aug_params=None, root='datasets/FlyingThings3D', dstype='frames_cleanpass'): + super(FlyingThings3D, self).__init__(aug_params) + + for cam in ['left']: + for direction in ['into_future', 'into_past']: + image_dirs = sorted(glob(osp.join(root, dstype, 'TRAIN/*/*'))) + image_dirs = sorted([osp.join(f, cam) for f in image_dirs]) + + flow_dirs = sorted(glob(osp.join(root, 'optical_flow/TRAIN/*/*'))) + flow_dirs = sorted([osp.join(f, direction, cam) for f in flow_dirs]) + + for idir, fdir in zip(image_dirs, flow_dirs): + images = sorted(glob(osp.join(idir, '*.png')) ) + flows = sorted(glob(osp.join(fdir, '*.pfm')) ) + for i in range(len(flows)-1): + if direction == 'into_future': + self.image_list += [ [images[i], images[i+1]] ] + self.flow_list += [ flows[i] ] + elif direction == 'into_past': + self.image_list += [ [images[i+1], images[i]] ] + self.flow_list += [ flows[i+1] ] + + +class KITTI(FlowDataset): + def __init__(self, aug_params=None, split='training', root='datasets/KITTI'): + super(KITTI, self).__init__(aug_params, sparse=True) + if split == 'testing': + self.is_test = True + + root = osp.join(root, split) + images1 = sorted(glob(osp.join(root, 'image_2/*_10.png'))) + images2 = sorted(glob(osp.join(root, 'image_2/*_11.png'))) + + for img1, img2 in zip(images1, images2): + frame_id = img1.split('/')[-1] + self.extra_info += [ [frame_id] ] + self.image_list += [ [img1, img2] ] + + if split == 'training': + self.flow_list = sorted(glob(osp.join(root, 'flow_occ/*_10.png'))) + + +class HD1K(FlowDataset): + def __init__(self, aug_params=None, root='datasets/HD1k'): + super(HD1K, self).__init__(aug_params, sparse=True) + + seq_ix = 0 + while 1: + flows = sorted(glob(os.path.join(root, 'hd1k_flow_gt', 'flow_occ/%06d_*.png' % seq_ix))) + images = sorted(glob(os.path.join(root, 'hd1k_input', 'image_2/%06d_*.png' % seq_ix))) + + if len(flows) == 0: + break + + for i in range(len(flows)-1): + self.flow_list += [flows[i]] + self.image_list += [ [images[i], images[i+1]] ] + + seq_ix += 1 + + +def fetch_dataloader(args, TRAIN_DS='C+T+K+S+H'): + """ Create the data loader for the corresponding trainign set """ + + if args.stage == 'chairs': + aug_params = {'crop_size': args.image_size, 'min_scale': -0.1, 'max_scale': 1.0, 'do_flip': True} + train_dataset = FlyingChairs(aug_params, split='training') + + elif args.stage == 'things': + aug_params = {'crop_size': args.image_size, 'min_scale': -0.4, 'max_scale': 0.8, 'do_flip': True} + clean_dataset = FlyingThings3D(aug_params, dstype='frames_cleanpass') + final_dataset = FlyingThings3D(aug_params, dstype='frames_finalpass') + train_dataset = clean_dataset + final_dataset + + elif args.stage == 'sintel': + aug_params = {'crop_size': args.image_size, 'min_scale': -0.2, 'max_scale': 0.6, 'do_flip': True} + things = FlyingThings3D(aug_params, dstype='frames_cleanpass') + sintel_clean = MpiSintel(aug_params, split='training', dstype='clean') + sintel_final = MpiSintel(aug_params, split='training', dstype='final') + + if TRAIN_DS == 'C+T+K+S+H': + kitti = KITTI({'crop_size': args.image_size, 'min_scale': -0.3, 'max_scale': 0.5, 'do_flip': True}) + hd1k = HD1K({'crop_size': args.image_size, 'min_scale': -0.5, 'max_scale': 0.2, 'do_flip': True}) + train_dataset = 100*sintel_clean + 100*sintel_final + 200*kitti + 5*hd1k + things + + elif TRAIN_DS == 'C+T+K/S': + train_dataset = 100*sintel_clean + 100*sintel_final + things + + elif args.stage == 'kitti': + aug_params = {'crop_size': args.image_size, 'min_scale': -0.2, 'max_scale': 0.4, 'do_flip': False} + train_dataset = KITTI(aug_params, split='training') + + train_loader = data.DataLoader(train_dataset, batch_size=args.batch_size, + pin_memory=False, shuffle=True, num_workers=4, drop_last=True) + + print('Training with %d image pairs' % len(train_dataset)) + return train_loader + diff --git a/FGT_codes/RAFT/demo.py b/FGT_codes/RAFT/demo.py new file mode 100644 index 0000000000000000000000000000000000000000..096963bdbb36aed3df673f131d6e044d8c6f95ea --- /dev/null +++ b/FGT_codes/RAFT/demo.py @@ -0,0 +1,79 @@ +import sys +import argparse +import os +import cv2 +import glob +import numpy as np +import torch +from PIL import Image + +from .raft import RAFT +from .utils import flow_viz +from .utils.utils import InputPadder + + + +DEVICE = 'cuda' + +def load_image(imfile): + img = np.array(Image.open(imfile)).astype(np.uint8) + img = torch.from_numpy(img).permute(2, 0, 1).float() + return img + + +def load_image_list(image_files): + images = [] + for imfile in sorted(image_files): + images.append(load_image(imfile)) + + images = torch.stack(images, dim=0) + images = images.to(DEVICE) + + padder = InputPadder(images.shape) + return padder.pad(images)[0] + + +def viz(img, flo): + img = img[0].permute(1,2,0).cpu().numpy() + flo = flo[0].permute(1,2,0).cpu().numpy() + + # map flow to rgb image + flo = flow_viz.flow_to_image(flo) + # img_flo = np.concatenate([img, flo], axis=0) + img_flo = flo + + cv2.imwrite('/home/chengao/test/flow.png', img_flo[:, :, [2,1,0]]) + # cv2.imshow('image', img_flo[:, :, [2,1,0]]/255.0) + # cv2.waitKey() + + +def demo(args): + model = torch.nn.DataParallel(RAFT(args)) + model.load_state_dict(torch.load(args.model)) + + model = model.module + model.to(DEVICE) + model.eval() + + with torch.no_grad(): + images = glob.glob(os.path.join(args.path, '*.png')) + \ + glob.glob(os.path.join(args.path, '*.jpg')) + + images = load_image_list(images) + for i in range(images.shape[0]-1): + image1 = images[i,None] + image2 = images[i+1,None] + + flow_low, flow_up = model(image1, image2, iters=20, test_mode=True) + viz(image1, flow_up) + + +def RAFT_infer(args): + model = torch.nn.DataParallel(RAFT(args)) + model.load_state_dict(torch.load(args.model)) + + model = model.module + model.to(DEVICE) + model.eval() + + return model diff --git a/FGT_codes/RAFT/extractor.py b/FGT_codes/RAFT/extractor.py new file mode 100644 index 0000000000000000000000000000000000000000..9a9c759d1243d4694e8656c2f6f8a37e53edd009 --- /dev/null +++ b/FGT_codes/RAFT/extractor.py @@ -0,0 +1,267 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F + + +class ResidualBlock(nn.Module): + def __init__(self, in_planes, planes, norm_fn='group', stride=1): + super(ResidualBlock, self).__init__() + + self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=3, padding=1, stride=stride) + self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, padding=1) + self.relu = nn.ReLU(inplace=True) + + num_groups = planes // 8 + + if norm_fn == 'group': + self.norm1 = nn.GroupNorm(num_groups=num_groups, num_channels=planes) + self.norm2 = nn.GroupNorm(num_groups=num_groups, num_channels=planes) + if not stride == 1: + self.norm3 = nn.GroupNorm(num_groups=num_groups, num_channels=planes) + + elif norm_fn == 'batch': + self.norm1 = nn.BatchNorm2d(planes) + self.norm2 = nn.BatchNorm2d(planes) + if not stride == 1: + self.norm3 = nn.BatchNorm2d(planes) + + elif norm_fn == 'instance': + self.norm1 = nn.InstanceNorm2d(planes) + self.norm2 = nn.InstanceNorm2d(planes) + if not stride == 1: + self.norm3 = nn.InstanceNorm2d(planes) + + elif norm_fn == 'none': + self.norm1 = nn.Sequential() + self.norm2 = nn.Sequential() + if not stride == 1: + self.norm3 = nn.Sequential() + + if stride == 1: + self.downsample = None + + else: + self.downsample = nn.Sequential( + nn.Conv2d(in_planes, planes, kernel_size=1, stride=stride), self.norm3) + + + def forward(self, x): + y = x + y = self.relu(self.norm1(self.conv1(y))) + y = self.relu(self.norm2(self.conv2(y))) + + if self.downsample is not None: + x = self.downsample(x) + + return self.relu(x+y) + + + +class BottleneckBlock(nn.Module): + def __init__(self, in_planes, planes, norm_fn='group', stride=1): + super(BottleneckBlock, self).__init__() + + self.conv1 = nn.Conv2d(in_planes, planes//4, kernel_size=1, padding=0) + self.conv2 = nn.Conv2d(planes//4, planes//4, kernel_size=3, padding=1, stride=stride) + self.conv3 = nn.Conv2d(planes//4, planes, kernel_size=1, padding=0) + self.relu = nn.ReLU(inplace=True) + + num_groups = planes // 8 + + if norm_fn == 'group': + self.norm1 = nn.GroupNorm(num_groups=num_groups, num_channels=planes//4) + self.norm2 = nn.GroupNorm(num_groups=num_groups, num_channels=planes//4) + self.norm3 = nn.GroupNorm(num_groups=num_groups, num_channels=planes) + if not stride == 1: + self.norm4 = nn.GroupNorm(num_groups=num_groups, num_channels=planes) + + elif norm_fn == 'batch': + self.norm1 = nn.BatchNorm2d(planes//4) + self.norm2 = nn.BatchNorm2d(planes//4) + self.norm3 = nn.BatchNorm2d(planes) + if not stride == 1: + self.norm4 = nn.BatchNorm2d(planes) + + elif norm_fn == 'instance': + self.norm1 = nn.InstanceNorm2d(planes//4) + self.norm2 = nn.InstanceNorm2d(planes//4) + self.norm3 = nn.InstanceNorm2d(planes) + if not stride == 1: + self.norm4 = nn.InstanceNorm2d(planes) + + elif norm_fn == 'none': + self.norm1 = nn.Sequential() + self.norm2 = nn.Sequential() + self.norm3 = nn.Sequential() + if not stride == 1: + self.norm4 = nn.Sequential() + + if stride == 1: + self.downsample = None + + else: + self.downsample = nn.Sequential( + nn.Conv2d(in_planes, planes, kernel_size=1, stride=stride), self.norm4) + + + def forward(self, x): + y = x + y = self.relu(self.norm1(self.conv1(y))) + y = self.relu(self.norm2(self.conv2(y))) + y = self.relu(self.norm3(self.conv3(y))) + + if self.downsample is not None: + x = self.downsample(x) + + return self.relu(x+y) + +class BasicEncoder(nn.Module): + def __init__(self, output_dim=128, norm_fn='batch', dropout=0.0): + super(BasicEncoder, self).__init__() + self.norm_fn = norm_fn + + if self.norm_fn == 'group': + self.norm1 = nn.GroupNorm(num_groups=8, num_channels=64) + + elif self.norm_fn == 'batch': + self.norm1 = nn.BatchNorm2d(64) + + elif self.norm_fn == 'instance': + self.norm1 = nn.InstanceNorm2d(64) + + elif self.norm_fn == 'none': + self.norm1 = nn.Sequential() + + self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3) + self.relu1 = nn.ReLU(inplace=True) + + self.in_planes = 64 + self.layer1 = self._make_layer(64, stride=1) + self.layer2 = self._make_layer(96, stride=2) + self.layer3 = self._make_layer(128, stride=2) + + # output convolution + self.conv2 = nn.Conv2d(128, output_dim, kernel_size=1) + + self.dropout = None + if dropout > 0: + self.dropout = nn.Dropout2d(p=dropout) + + for m in self.modules(): + if isinstance(m, nn.Conv2d): + nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu') + elif isinstance(m, (nn.BatchNorm2d, nn.InstanceNorm2d, nn.GroupNorm)): + if m.weight is not None: + nn.init.constant_(m.weight, 1) + if m.bias is not None: + nn.init.constant_(m.bias, 0) + + def _make_layer(self, dim, stride=1): + layer1 = ResidualBlock(self.in_planes, dim, self.norm_fn, stride=stride) + layer2 = ResidualBlock(dim, dim, self.norm_fn, stride=1) + layers = (layer1, layer2) + + self.in_planes = dim + return nn.Sequential(*layers) + + + def forward(self, x): + + # if input is list, combine batch dimension + is_list = isinstance(x, tuple) or isinstance(x, list) + if is_list: + batch_dim = x[0].shape[0] + x = torch.cat(x, dim=0) + + x = self.conv1(x) + x = self.norm1(x) + x = self.relu1(x) + + x = self.layer1(x) + x = self.layer2(x) + x = self.layer3(x) + + x = self.conv2(x) + + if self.training and self.dropout is not None: + x = self.dropout(x) + + if is_list: + x = torch.split(x, [batch_dim, batch_dim], dim=0) + + return x + + +class SmallEncoder(nn.Module): + def __init__(self, output_dim=128, norm_fn='batch', dropout=0.0): + super(SmallEncoder, self).__init__() + self.norm_fn = norm_fn + + if self.norm_fn == 'group': + self.norm1 = nn.GroupNorm(num_groups=8, num_channels=32) + + elif self.norm_fn == 'batch': + self.norm1 = nn.BatchNorm2d(32) + + elif self.norm_fn == 'instance': + self.norm1 = nn.InstanceNorm2d(32) + + elif self.norm_fn == 'none': + self.norm1 = nn.Sequential() + + self.conv1 = nn.Conv2d(3, 32, kernel_size=7, stride=2, padding=3) + self.relu1 = nn.ReLU(inplace=True) + + self.in_planes = 32 + self.layer1 = self._make_layer(32, stride=1) + self.layer2 = self._make_layer(64, stride=2) + self.layer3 = self._make_layer(96, stride=2) + + self.dropout = None + if dropout > 0: + self.dropout = nn.Dropout2d(p=dropout) + + self.conv2 = nn.Conv2d(96, output_dim, kernel_size=1) + + for m in self.modules(): + if isinstance(m, nn.Conv2d): + nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu') + elif isinstance(m, (nn.BatchNorm2d, nn.InstanceNorm2d, nn.GroupNorm)): + if m.weight is not None: + nn.init.constant_(m.weight, 1) + if m.bias is not None: + nn.init.constant_(m.bias, 0) + + def _make_layer(self, dim, stride=1): + layer1 = BottleneckBlock(self.in_planes, dim, self.norm_fn, stride=stride) + layer2 = BottleneckBlock(dim, dim, self.norm_fn, stride=1) + layers = (layer1, layer2) + + self.in_planes = dim + return nn.Sequential(*layers) + + + def forward(self, x): + + # if input is list, combine batch dimension + is_list = isinstance(x, tuple) or isinstance(x, list) + if is_list: + batch_dim = x[0].shape[0] + x = torch.cat(x, dim=0) + + x = self.conv1(x) + x = self.norm1(x) + x = self.relu1(x) + + x = self.layer1(x) + x = self.layer2(x) + x = self.layer3(x) + x = self.conv2(x) + + if self.training and self.dropout is not None: + x = self.dropout(x) + + if is_list: + x = torch.split(x, [batch_dim, batch_dim], dim=0) + + return x diff --git a/FGT_codes/RAFT/raft.py b/FGT_codes/RAFT/raft.py new file mode 100644 index 0000000000000000000000000000000000000000..81b0ee51fde2065165499c9496661ca1f771949d --- /dev/null +++ b/FGT_codes/RAFT/raft.py @@ -0,0 +1,147 @@ +import numpy as np +import torch +import torch.nn as nn +import torch.nn.functional as F + +from .update import BasicUpdateBlock, SmallUpdateBlock +from .extractor import BasicEncoder, SmallEncoder +from .corr import CorrBlock, AlternateCorrBlock +from .utils.utils import bilinear_sampler, coords_grid, upflow8 + +try: + autocast = torch.cuda.amp.autocast +except: + # dummy autocast for PyTorch < 1.6 + class autocast: + def __init__(self, enabled): + pass + def __enter__(self): + pass + def __exit__(self, *args): + pass + + +class RAFT(nn.Module): + def __init__(self, args): + super(RAFT, self).__init__() + self.args = args + + if args.small: + self.hidden_dim = hdim = 96 + self.context_dim = cdim = 64 + args.corr_levels = 4 + args.corr_radius = 3 + + else: + self.hidden_dim = hdim = 128 + self.context_dim = cdim = 128 + args.corr_levels = 4 + args.corr_radius = 4 + + '''if 'dropout' not in args._get_kwargs(): + args.dropout = 0 + + if 'alternate_corr' not in args._get_kwargs(): + args.alternate_corr = False''' + args.dropout = 0 + args.alternate_corr = False + + # feature network, context network, and update block + if args.small: + self.fnet = SmallEncoder(output_dim=128, norm_fn='instance', dropout=args.dropout) + self.cnet = SmallEncoder(output_dim=hdim+cdim, norm_fn='none', dropout=args.dropout) + self.update_block = SmallUpdateBlock(self.args, hidden_dim=hdim) + + else: + self.fnet = BasicEncoder(output_dim=256, norm_fn='instance', dropout=args.dropout) + self.cnet = BasicEncoder(output_dim=hdim+cdim, norm_fn='batch', dropout=args.dropout) + self.update_block = BasicUpdateBlock(self.args, hidden_dim=hdim) + + + def freeze_bn(self): + for m in self.modules(): + if isinstance(m, nn.BatchNorm2d): + m.eval() + + def initialize_flow(self, img): + """ Flow is represented as difference between two coordinate grids flow = coords1 - coords0""" + N, C, H, W = img.shape + coords0 = coords_grid(N, H//8, W//8).to(img.device) + coords1 = coords_grid(N, H//8, W//8).to(img.device) + + # optical flow computed as difference: flow = coords1 - coords0 + return coords0, coords1 + + def upsample_flow(self, flow, mask): + """ Upsample flow field [H/8, W/8, 2] -> [H, W, 2] using convex combination """ + N, _, H, W = flow.shape + mask = mask.view(N, 1, 9, 8, 8, H, W) + mask = torch.softmax(mask, dim=2) + + up_flow = F.unfold(8 * flow, [3,3], padding=1) + up_flow = up_flow.view(N, 2, 9, 1, 1, H, W) + + up_flow = torch.sum(mask * up_flow, dim=2) + up_flow = up_flow.permute(0, 1, 4, 2, 5, 3) + return up_flow.reshape(N, 2, 8*H, 8*W) + + + def forward(self, image1, image2, iters=12, flow_init=None, upsample=True, test_mode=False): + """ Estimate optical flow between pair of frames """ + + image1 = 2 * (image1 / 255.0) - 1.0 + image2 = 2 * (image2 / 255.0) - 1.0 + + image1 = image1.contiguous() + image2 = image2.contiguous() + + hdim = self.hidden_dim + cdim = self.context_dim + + # run the feature network + with autocast(enabled=self.args.mixed_precision): + fmap1, fmap2 = self.fnet([image1, image2]) + + fmap1 = fmap1.float() + fmap2 = fmap2.float() + if self.args.alternate_corr: + corr_fn = CorrBlockAlternate(fmap1, fmap2, radius=self.args.corr_radius) + else: + corr_fn = CorrBlock(fmap1, fmap2, radius=self.args.corr_radius) + + # run the context network + with autocast(enabled=self.args.mixed_precision): + cnet = self.cnet(image1) + net, inp = torch.split(cnet, [hdim, cdim], dim=1) + net = torch.tanh(net) + inp = torch.relu(inp) + + coords0, coords1 = self.initialize_flow(image1) + + if flow_init is not None: + coords1 = coords1 + flow_init + + flow_predictions = [] + for itr in range(iters): + coords1 = coords1.detach() + corr = corr_fn(coords1) # index correlation volume + + flow = coords1 - coords0 + with autocast(enabled=self.args.mixed_precision): + net, up_mask, delta_flow = self.update_block(net, inp, corr, flow) + + # F(t+1) = F(t) + \Delta(t) + coords1 = coords1 + delta_flow + + # upsample predictions + if up_mask is None: + flow_up = upflow8(coords1 - coords0) + else: + flow_up = self.upsample_flow(coords1 - coords0, up_mask) + + flow_predictions.append(flow_up) + + if test_mode: + return coords1 - coords0, flow_up + + return flow_predictions diff --git a/FGT_codes/RAFT/update.py b/FGT_codes/RAFT/update.py new file mode 100644 index 0000000000000000000000000000000000000000..f940497f9b5eb1c12091574fe9a0223a1b196d50 --- /dev/null +++ b/FGT_codes/RAFT/update.py @@ -0,0 +1,139 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F + + +class FlowHead(nn.Module): + def __init__(self, input_dim=128, hidden_dim=256): + super(FlowHead, self).__init__() + self.conv1 = nn.Conv2d(input_dim, hidden_dim, 3, padding=1) + self.conv2 = nn.Conv2d(hidden_dim, 2, 3, padding=1) + self.relu = nn.ReLU(inplace=True) + + def forward(self, x): + return self.conv2(self.relu(self.conv1(x))) + +class ConvGRU(nn.Module): + def __init__(self, hidden_dim=128, input_dim=192+128): + super(ConvGRU, self).__init__() + self.convz = nn.Conv2d(hidden_dim+input_dim, hidden_dim, 3, padding=1) + self.convr = nn.Conv2d(hidden_dim+input_dim, hidden_dim, 3, padding=1) + self.convq = nn.Conv2d(hidden_dim+input_dim, hidden_dim, 3, padding=1) + + def forward(self, h, x): + hx = torch.cat([h, x], dim=1) + + z = torch.sigmoid(self.convz(hx)) + r = torch.sigmoid(self.convr(hx)) + q = torch.tanh(self.convq(torch.cat([r*h, x], dim=1))) + + h = (1-z) * h + z * q + return h + +class SepConvGRU(nn.Module): + def __init__(self, hidden_dim=128, input_dim=192+128): + super(SepConvGRU, self).__init__() + self.convz1 = nn.Conv2d(hidden_dim+input_dim, hidden_dim, (1,5), padding=(0,2)) + self.convr1 = nn.Conv2d(hidden_dim+input_dim, hidden_dim, (1,5), padding=(0,2)) + self.convq1 = nn.Conv2d(hidden_dim+input_dim, hidden_dim, (1,5), padding=(0,2)) + + self.convz2 = nn.Conv2d(hidden_dim+input_dim, hidden_dim, (5,1), padding=(2,0)) + self.convr2 = nn.Conv2d(hidden_dim+input_dim, hidden_dim, (5,1), padding=(2,0)) + self.convq2 = nn.Conv2d(hidden_dim+input_dim, hidden_dim, (5,1), padding=(2,0)) + + + def forward(self, h, x): + # horizontal + hx = torch.cat([h, x], dim=1) + z = torch.sigmoid(self.convz1(hx)) + r = torch.sigmoid(self.convr1(hx)) + q = torch.tanh(self.convq1(torch.cat([r*h, x], dim=1))) + h = (1-z) * h + z * q + + # vertical + hx = torch.cat([h, x], dim=1) + z = torch.sigmoid(self.convz2(hx)) + r = torch.sigmoid(self.convr2(hx)) + q = torch.tanh(self.convq2(torch.cat([r*h, x], dim=1))) + h = (1-z) * h + z * q + + return h + +class SmallMotionEncoder(nn.Module): + def __init__(self, args): + super(SmallMotionEncoder, self).__init__() + cor_planes = args.corr_levels * (2*args.corr_radius + 1)**2 + self.convc1 = nn.Conv2d(cor_planes, 96, 1, padding=0) + self.convf1 = nn.Conv2d(2, 64, 7, padding=3) + self.convf2 = nn.Conv2d(64, 32, 3, padding=1) + self.conv = nn.Conv2d(128, 80, 3, padding=1) + + def forward(self, flow, corr): + cor = F.relu(self.convc1(corr)) + flo = F.relu(self.convf1(flow)) + flo = F.relu(self.convf2(flo)) + cor_flo = torch.cat([cor, flo], dim=1) + out = F.relu(self.conv(cor_flo)) + return torch.cat([out, flow], dim=1) + +class BasicMotionEncoder(nn.Module): + def __init__(self, args): + super(BasicMotionEncoder, self).__init__() + cor_planes = args.corr_levels * (2*args.corr_radius + 1)**2 + self.convc1 = nn.Conv2d(cor_planes, 256, 1, padding=0) + self.convc2 = nn.Conv2d(256, 192, 3, padding=1) + self.convf1 = nn.Conv2d(2, 128, 7, padding=3) + self.convf2 = nn.Conv2d(128, 64, 3, padding=1) + self.conv = nn.Conv2d(64+192, 128-2, 3, padding=1) + + def forward(self, flow, corr): + cor = F.relu(self.convc1(corr)) + cor = F.relu(self.convc2(cor)) + flo = F.relu(self.convf1(flow)) + flo = F.relu(self.convf2(flo)) + + cor_flo = torch.cat([cor, flo], dim=1) + out = F.relu(self.conv(cor_flo)) + return torch.cat([out, flow], dim=1) + +class SmallUpdateBlock(nn.Module): + def __init__(self, args, hidden_dim=96): + super(SmallUpdateBlock, self).__init__() + self.encoder = SmallMotionEncoder(args) + self.gru = ConvGRU(hidden_dim=hidden_dim, input_dim=82+64) + self.flow_head = FlowHead(hidden_dim, hidden_dim=128) + + def forward(self, net, inp, corr, flow): + motion_features = self.encoder(flow, corr) + inp = torch.cat([inp, motion_features], dim=1) + net = self.gru(net, inp) + delta_flow = self.flow_head(net) + + return net, None, delta_flow + +class BasicUpdateBlock(nn.Module): + def __init__(self, args, hidden_dim=128, input_dim=128): + super(BasicUpdateBlock, self).__init__() + self.args = args + self.encoder = BasicMotionEncoder(args) + self.gru = SepConvGRU(hidden_dim=hidden_dim, input_dim=128+hidden_dim) + self.flow_head = FlowHead(hidden_dim, hidden_dim=256) + + self.mask = nn.Sequential( + nn.Conv2d(128, 256, 3, padding=1), + nn.ReLU(inplace=True), + nn.Conv2d(256, 64*9, 1, padding=0)) + + def forward(self, net, inp, corr, flow, upsample=True): + motion_features = self.encoder(flow, corr) + inp = torch.cat([inp, motion_features], dim=1) + + net = self.gru(net, inp) + delta_flow = self.flow_head(net) + + # scale mask to balence gradients + mask = .25 * self.mask(net) + return net, mask, delta_flow + + + diff --git a/FGT_codes/RAFT/utils/__init__.py b/FGT_codes/RAFT/utils/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..0437149bfee42718973728158641020ccc1906ad --- /dev/null +++ b/FGT_codes/RAFT/utils/__init__.py @@ -0,0 +1,2 @@ +from .flow_viz import flow_to_image +from .frame_utils import writeFlow diff --git a/FGT_codes/RAFT/utils/__pycache__/__init__.cpython-39.pyc b/FGT_codes/RAFT/utils/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f9783d4ec685f3cfc894e84771473c8f36b4a62e Binary files /dev/null and b/FGT_codes/RAFT/utils/__pycache__/__init__.cpython-39.pyc differ diff --git a/FGT_codes/RAFT/utils/__pycache__/flow_viz.cpython-39.pyc b/FGT_codes/RAFT/utils/__pycache__/flow_viz.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a1b3558a6eb1e761c3b89a0c3adfaaa52f750c98 Binary files /dev/null and b/FGT_codes/RAFT/utils/__pycache__/flow_viz.cpython-39.pyc differ diff --git a/FGT_codes/RAFT/utils/__pycache__/frame_utils.cpython-39.pyc b/FGT_codes/RAFT/utils/__pycache__/frame_utils.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3d0aa28a910a1ce21b46010f386deb05aa0dcb07 Binary files /dev/null and b/FGT_codes/RAFT/utils/__pycache__/frame_utils.cpython-39.pyc differ diff --git a/FGT_codes/RAFT/utils/__pycache__/utils.cpython-39.pyc b/FGT_codes/RAFT/utils/__pycache__/utils.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dfee5192153036351dd3ba3fe48a3a609d152477 Binary files /dev/null and b/FGT_codes/RAFT/utils/__pycache__/utils.cpython-39.pyc differ diff --git a/FGT_codes/RAFT/utils/augmentor.py b/FGT_codes/RAFT/utils/augmentor.py new file mode 100644 index 0000000000000000000000000000000000000000..e81c4f2b5c16c31c0ae236d744f299d430228a04 --- /dev/null +++ b/FGT_codes/RAFT/utils/augmentor.py @@ -0,0 +1,246 @@ +import numpy as np +import random +import math +from PIL import Image + +import cv2 +cv2.setNumThreads(0) +cv2.ocl.setUseOpenCL(False) + +import torch +from torchvision.transforms import ColorJitter +import torch.nn.functional as F + + +class FlowAugmentor: + def __init__(self, crop_size, min_scale=-0.2, max_scale=0.5, do_flip=True): + + # spatial augmentation params + self.crop_size = crop_size + self.min_scale = min_scale + self.max_scale = max_scale + self.spatial_aug_prob = 0.8 + self.stretch_prob = 0.8 + self.max_stretch = 0.2 + + # flip augmentation params + self.do_flip = do_flip + self.h_flip_prob = 0.5 + self.v_flip_prob = 0.1 + + # photometric augmentation params + self.photo_aug = ColorJitter(brightness=0.4, contrast=0.4, saturation=0.4, hue=0.5/3.14) + self.asymmetric_color_aug_prob = 0.2 + self.eraser_aug_prob = 0.5 + + def color_transform(self, img1, img2): + """ Photometric augmentation """ + + # asymmetric + if np.random.rand() < self.asymmetric_color_aug_prob: + img1 = np.array(self.photo_aug(Image.fromarray(img1)), dtype=np.uint8) + img2 = np.array(self.photo_aug(Image.fromarray(img2)), dtype=np.uint8) + + # symmetric + else: + image_stack = np.concatenate([img1, img2], axis=0) + image_stack = np.array(self.photo_aug(Image.fromarray(image_stack)), dtype=np.uint8) + img1, img2 = np.split(image_stack, 2, axis=0) + + return img1, img2 + + def eraser_transform(self, img1, img2, bounds=[50, 100]): + """ Occlusion augmentation """ + + ht, wd = img1.shape[:2] + if np.random.rand() < self.eraser_aug_prob: + mean_color = np.mean(img2.reshape(-1, 3), axis=0) + for _ in range(np.random.randint(1, 3)): + x0 = np.random.randint(0, wd) + y0 = np.random.randint(0, ht) + dx = np.random.randint(bounds[0], bounds[1]) + dy = np.random.randint(bounds[0], bounds[1]) + img2[y0:y0+dy, x0:x0+dx, :] = mean_color + + return img1, img2 + + def spatial_transform(self, img1, img2, flow): + # randomly sample scale + ht, wd = img1.shape[:2] + min_scale = np.maximum( + (self.crop_size[0] + 8) / float(ht), + (self.crop_size[1] + 8) / float(wd)) + + scale = 2 ** np.random.uniform(self.min_scale, self.max_scale) + scale_x = scale + scale_y = scale + if np.random.rand() < self.stretch_prob: + scale_x *= 2 ** np.random.uniform(-self.max_stretch, self.max_stretch) + scale_y *= 2 ** np.random.uniform(-self.max_stretch, self.max_stretch) + + scale_x = np.clip(scale_x, min_scale, None) + scale_y = np.clip(scale_y, min_scale, None) + + if np.random.rand() < self.spatial_aug_prob: + # rescale the images + img1 = cv2.resize(img1, None, fx=scale_x, fy=scale_y, interpolation=cv2.INTER_LINEAR) + img2 = cv2.resize(img2, None, fx=scale_x, fy=scale_y, interpolation=cv2.INTER_LINEAR) + flow = cv2.resize(flow, None, fx=scale_x, fy=scale_y, interpolation=cv2.INTER_LINEAR) + flow = flow * [scale_x, scale_y] + + if self.do_flip: + if np.random.rand() < self.h_flip_prob: # h-flip + img1 = img1[:, ::-1] + img2 = img2[:, ::-1] + flow = flow[:, ::-1] * [-1.0, 1.0] + + if np.random.rand() < self.v_flip_prob: # v-flip + img1 = img1[::-1, :] + img2 = img2[::-1, :] + flow = flow[::-1, :] * [1.0, -1.0] + + y0 = np.random.randint(0, img1.shape[0] - self.crop_size[0]) + x0 = np.random.randint(0, img1.shape[1] - self.crop_size[1]) + + img1 = img1[y0:y0+self.crop_size[0], x0:x0+self.crop_size[1]] + img2 = img2[y0:y0+self.crop_size[0], x0:x0+self.crop_size[1]] + flow = flow[y0:y0+self.crop_size[0], x0:x0+self.crop_size[1]] + + return img1, img2, flow + + def __call__(self, img1, img2, flow): + img1, img2 = self.color_transform(img1, img2) + img1, img2 = self.eraser_transform(img1, img2) + img1, img2, flow = self.spatial_transform(img1, img2, flow) + + img1 = np.ascontiguousarray(img1) + img2 = np.ascontiguousarray(img2) + flow = np.ascontiguousarray(flow) + + return img1, img2, flow + +class SparseFlowAugmentor: + def __init__(self, crop_size, min_scale=-0.2, max_scale=0.5, do_flip=False): + # spatial augmentation params + self.crop_size = crop_size + self.min_scale = min_scale + self.max_scale = max_scale + self.spatial_aug_prob = 0.8 + self.stretch_prob = 0.8 + self.max_stretch = 0.2 + + # flip augmentation params + self.do_flip = do_flip + self.h_flip_prob = 0.5 + self.v_flip_prob = 0.1 + + # photometric augmentation params + self.photo_aug = ColorJitter(brightness=0.3, contrast=0.3, saturation=0.3, hue=0.3/3.14) + self.asymmetric_color_aug_prob = 0.2 + self.eraser_aug_prob = 0.5 + + def color_transform(self, img1, img2): + image_stack = np.concatenate([img1, img2], axis=0) + image_stack = np.array(self.photo_aug(Image.fromarray(image_stack)), dtype=np.uint8) + img1, img2 = np.split(image_stack, 2, axis=0) + return img1, img2 + + def eraser_transform(self, img1, img2): + ht, wd = img1.shape[:2] + if np.random.rand() < self.eraser_aug_prob: + mean_color = np.mean(img2.reshape(-1, 3), axis=0) + for _ in range(np.random.randint(1, 3)): + x0 = np.random.randint(0, wd) + y0 = np.random.randint(0, ht) + dx = np.random.randint(50, 100) + dy = np.random.randint(50, 100) + img2[y0:y0+dy, x0:x0+dx, :] = mean_color + + return img1, img2 + + def resize_sparse_flow_map(self, flow, valid, fx=1.0, fy=1.0): + ht, wd = flow.shape[:2] + coords = np.meshgrid(np.arange(wd), np.arange(ht)) + coords = np.stack(coords, axis=-1) + + coords = coords.reshape(-1, 2).astype(np.float32) + flow = flow.reshape(-1, 2).astype(np.float32) + valid = valid.reshape(-1).astype(np.float32) + + coords0 = coords[valid>=1] + flow0 = flow[valid>=1] + + ht1 = int(round(ht * fy)) + wd1 = int(round(wd * fx)) + + coords1 = coords0 * [fx, fy] + flow1 = flow0 * [fx, fy] + + xx = np.round(coords1[:,0]).astype(np.int32) + yy = np.round(coords1[:,1]).astype(np.int32) + + v = (xx > 0) & (xx < wd1) & (yy > 0) & (yy < ht1) + xx = xx[v] + yy = yy[v] + flow1 = flow1[v] + + flow_img = np.zeros([ht1, wd1, 2], dtype=np.float32) + valid_img = np.zeros([ht1, wd1], dtype=np.int32) + + flow_img[yy, xx] = flow1 + valid_img[yy, xx] = 1 + + return flow_img, valid_img + + def spatial_transform(self, img1, img2, flow, valid): + # randomly sample scale + + ht, wd = img1.shape[:2] + min_scale = np.maximum( + (self.crop_size[0] + 1) / float(ht), + (self.crop_size[1] + 1) / float(wd)) + + scale = 2 ** np.random.uniform(self.min_scale, self.max_scale) + scale_x = np.clip(scale, min_scale, None) + scale_y = np.clip(scale, min_scale, None) + + if np.random.rand() < self.spatial_aug_prob: + # rescale the images + img1 = cv2.resize(img1, None, fx=scale_x, fy=scale_y, interpolation=cv2.INTER_LINEAR) + img2 = cv2.resize(img2, None, fx=scale_x, fy=scale_y, interpolation=cv2.INTER_LINEAR) + flow, valid = self.resize_sparse_flow_map(flow, valid, fx=scale_x, fy=scale_y) + + if self.do_flip: + if np.random.rand() < 0.5: # h-flip + img1 = img1[:, ::-1] + img2 = img2[:, ::-1] + flow = flow[:, ::-1] * [-1.0, 1.0] + valid = valid[:, ::-1] + + margin_y = 20 + margin_x = 50 + + y0 = np.random.randint(0, img1.shape[0] - self.crop_size[0] + margin_y) + x0 = np.random.randint(-margin_x, img1.shape[1] - self.crop_size[1] + margin_x) + + y0 = np.clip(y0, 0, img1.shape[0] - self.crop_size[0]) + x0 = np.clip(x0, 0, img1.shape[1] - self.crop_size[1]) + + img1 = img1[y0:y0+self.crop_size[0], x0:x0+self.crop_size[1]] + img2 = img2[y0:y0+self.crop_size[0], x0:x0+self.crop_size[1]] + flow = flow[y0:y0+self.crop_size[0], x0:x0+self.crop_size[1]] + valid = valid[y0:y0+self.crop_size[0], x0:x0+self.crop_size[1]] + return img1, img2, flow, valid + + + def __call__(self, img1, img2, flow, valid): + img1, img2 = self.color_transform(img1, img2) + img1, img2 = self.eraser_transform(img1, img2) + img1, img2, flow, valid = self.spatial_transform(img1, img2, flow, valid) + + img1 = np.ascontiguousarray(img1) + img2 = np.ascontiguousarray(img2) + flow = np.ascontiguousarray(flow) + valid = np.ascontiguousarray(valid) + + return img1, img2, flow, valid diff --git a/FGT_codes/RAFT/utils/flow_viz.py b/FGT_codes/RAFT/utils/flow_viz.py new file mode 100644 index 0000000000000000000000000000000000000000..b5e8d79b1ae7ea9707dfa68fdf44691fa6b13108 --- /dev/null +++ b/FGT_codes/RAFT/utils/flow_viz.py @@ -0,0 +1,195 @@ +# Flow visualization code used from https://github.com/tomrunia/OpticalFlow_Visualization + + +# MIT License +# +# Copyright (c) 2018 Tom Runia +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to conditions. +# +# Author: Tom Runia +# Date Created: 2018-08-03 + +import numpy as np + +def make_colorwheel(): + """ + Generates a color wheel for optical flow visualization as presented in: + Baker et al. "A Database and Evaluation Methodology for Optical Flow" (ICCV, 2007) + URL: http://vision.middlebury.edu/flow/flowEval-iccv07.pdf + + Code follows the original C++ source code of Daniel Scharstein. + Code follows the the Matlab source code of Deqing Sun. + + Returns: + np.ndarray: Color wheel + """ + + RY = 15 + YG = 6 + GC = 4 + CB = 11 + BM = 13 + MR = 6 + + ncols = RY + YG + GC + CB + BM + MR + colorwheel = np.zeros((ncols, 3)) + col = 0 + + # RY + colorwheel[0:RY, 0] = 255 + colorwheel[0:RY, 1] = np.floor(255*np.arange(0,RY)/RY) + col = col+RY + # YG + colorwheel[col:col+YG, 0] = 255 - np.floor(255*np.arange(0,YG)/YG) + colorwheel[col:col+YG, 1] = 255 + col = col+YG + # GC + colorwheel[col:col+GC, 1] = 255 + colorwheel[col:col+GC, 2] = np.floor(255*np.arange(0,GC)/GC) + col = col+GC + # CB + colorwheel[col:col+CB, 1] = 255 - np.floor(255*np.arange(CB)/CB) + colorwheel[col:col+CB, 2] = 255 + col = col+CB + # BM + colorwheel[col:col+BM, 2] = 255 + colorwheel[col:col+BM, 0] = np.floor(255*np.arange(0,BM)/BM) + col = col+BM + # MR + colorwheel[col:col+MR, 2] = 255 - np.floor(255*np.arange(MR)/MR) + colorwheel[col:col+MR, 0] = 255 + return colorwheel + + +def flow_uv_to_colors(u, v, convert_to_bgr=False): + """ + Applies the flow color wheel to (possibly clipped) flow components u and v. + + According to the C++ source code of Daniel Scharstein + According to the Matlab source code of Deqing Sun + + Args: + u (np.ndarray): Input horizontal flow of shape [H,W] + v (np.ndarray): Input vertical flow of shape [H,W] + convert_to_bgr (bool, optional): Convert output image to BGR. Defaults to False. + + Returns: + np.ndarray: Flow visualization image of shape [H,W,3] + """ + flow_image = np.zeros((u.shape[0], u.shape[1], 3), np.uint8) + colorwheel = make_colorwheel() # shape [55x3] + ncols = colorwheel.shape[0] + rad = np.sqrt(np.square(u) + np.square(v)) + a = np.arctan2(-v, -u)/np.pi + fk = (a+1) / 2*(ncols-1) + k0 = np.floor(fk).astype(np.int32) + k1 = k0 + 1 + k1[k1 == ncols] = 0 + f = fk - k0 + for i in range(colorwheel.shape[1]): + tmp = colorwheel[:,i] + col0 = tmp[k0] / 255.0 + col1 = tmp[k1] / 255.0 + col = (1-f)*col0 + f*col1 + idx = (rad <= 1) + col[idx] = 1 - rad[idx] * (1-col[idx]) + col[~idx] = col[~idx] * 0.75 # out of range + # Note the 2-i => BGR instead of RGB + ch_idx = 2-i if convert_to_bgr else i + flow_image[:,:,ch_idx] = np.floor(255 * col) + return flow_image + + +def flow_to_image(flow_uv, clip_flow=None, convert_to_bgr=False): + """ + Expects a two dimensional flow image of shape. + + Args: + flow_uv (np.ndarray): Flow UV image of shape [H,W,2] + clip_flow (float, optional): Clip maximum of flow values. Defaults to None. + convert_to_bgr (bool, optional): Convert output image to BGR. Defaults to False. + + Returns: + np.ndarray: Flow visualization image of shape [H,W,3] + """ + assert flow_uv.ndim == 3, 'input flow must have three dimensions' + assert flow_uv.shape[2] == 2, 'input flow must have shape [H,W,2]' + if clip_flow is not None: + flow_uv = np.clip(flow_uv, 0, clip_flow) + u = flow_uv[:,:,0] + v = flow_uv[:,:,1] + rad = np.sqrt(np.square(u) + np.square(v)) + rad_max = np.max(rad) + epsilon = 1e-5 + u = u / (rad_max + epsilon) + v = v / (rad_max + epsilon) + return flow_uv_to_colors(u, v, convert_to_bgr) + + +def flow_to_image_noNorm(flow_uvs, clip_flow=None, convert_to_bgr=False): + """ + flow_uvs is a list that accomodates lots of flows + All the flows in flow_uvs are normalized by the maximum value of in all the flows of flow_uvs + """ + maximum_value = 0 + for flow_uv in flow_uvs: + u = flow_uv[:, :, 0] + v = flow_uv[:, :, 1] + rad = np.sqrt(np.square(u) + np.square(v)) + rad_max = np.max(rad) + maximum_value = max(maximum_value, rad_max) + assert maximum_value > 0, 'Maximum value must be greater than 0' + flow_colors = [] + for flow_uv in flow_uvs: + u = flow_uv[:, :, 0] + v = flow_uv[:, :, 1] + epsilon = 1e-5 + u = u / (maximum_value + epsilon) + v = v / (maximum_value + epsilon) + flow_color = flow_uv_to_colors(u, v, convert_to_bgr) + flow_colors.append(flow_color) + return flow_colors + + +if __name__ == '__main__': + # cvbase.read_flow test + import cvbase + import cv2 + import os + import glob + import argparse + parser = argparse.ArgumentParser() + parser.add_argument('--flow_path', type=str, default='.') + parser.add_argument('--out_path', type=str, default='.') + args = parser.parse_args() + flow_path = args.flow_path + out_path = args.out_path + videos = os.listdir(flow_path) + video_nums = len(videos) + v = 0 + for video in videos: + v += 1 + # forward flow visualization + forward_flows = sorted(glob.glob(os.path.join(flow_path, video, 'forward_flo', '*.flo'))) + backward_flows = sorted(glob.glob(os.path.join(flow_path, video, 'backward_flo', '*.flo'))) + assert len(forward_flows) == len(backward_flows), 'Unmatched number of flows, forward flow is {}, backward flow is {}'.format(len(forward_flows), len(backward_flows)) + forward_out_path = os.path.join(out_path, video, 'forward_flo') + backward_out_path = os.path.join(out_path, video, 'backward_flo') + if not os.path.exists(forward_out_path): + os.makedirs(forward_out_path) + if not os.path.exists(backward_out_path): + os.makedirs(backward_out_path) + for i in range(len(forward_flows)): + forward_flow_data = cvbase.read_flow(forward_flows[i]) + backward_flow_data = cvbase.read_flow(backward_flows[i]) + forward_flow_image = flow_to_image(forward_flow_data, convert_to_bgr=True) + backward_flow_image = flow_to_image(backward_flow_data, convert_to_bgr=True) + cv2.imwrite(os.path.join(forward_out_path, '{:05d}.png'.format(i)), forward_flow_image) + cv2.imwrite(os.path.join(backward_out_path, '{:05d}.png'.format(i)), backward_flow_image) + print('[{}]/[{}] video {} has been processed'.format(v, video_nums, video)) \ No newline at end of file diff --git a/FGT_codes/RAFT/utils/frame_utils.py b/FGT_codes/RAFT/utils/frame_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..6c491135efaffc25bd61ec3ecde99d236f5deb12 --- /dev/null +++ b/FGT_codes/RAFT/utils/frame_utils.py @@ -0,0 +1,137 @@ +import numpy as np +from PIL import Image +from os.path import * +import re + +import cv2 +cv2.setNumThreads(0) +cv2.ocl.setUseOpenCL(False) + +TAG_CHAR = np.array([202021.25], np.float32) + +def readFlow(fn): + """ Read .flo file in Middlebury format""" + # Code adapted from: + # http://stackoverflow.com/questions/28013200/reading-middlebury-flow-files-with-python-bytes-array-numpy + + # WARNING: this will work on little-endian architectures (eg Intel x86) only! + # print 'fn = %s'%(fn) + with open(fn, 'rb') as f: + magic = np.fromfile(f, np.float32, count=1) + if 202021.25 != magic: + print('Magic number incorrect. Invalid .flo file') + return None + else: + w = np.fromfile(f, np.int32, count=1) + h = np.fromfile(f, np.int32, count=1) + # print 'Reading %d x %d flo file\n' % (w, h) + data = np.fromfile(f, np.float32, count=2*int(w)*int(h)) + # Reshape data into 3D array (columns, rows, bands) + # The reshape here is for visualization, the original code is (w,h,2) + return np.resize(data, (int(h), int(w), 2)) + +def readPFM(file): + file = open(file, 'rb') + + color = None + width = None + height = None + scale = None + endian = None + + header = file.readline().rstrip() + if header == b'PF': + color = True + elif header == b'Pf': + color = False + else: + raise Exception('Not a PFM file.') + + dim_match = re.match(rb'^(\d+)\s(\d+)\s$', file.readline()) + if dim_match: + width, height = map(int, dim_match.groups()) + else: + raise Exception('Malformed PFM header.') + + scale = float(file.readline().rstrip()) + if scale < 0: # little-endian + endian = '<' + scale = -scale + else: + endian = '>' # big-endian + + data = np.fromfile(file, endian + 'f') + shape = (height, width, 3) if color else (height, width) + + data = np.reshape(data, shape) + data = np.flipud(data) + return data + +def writeFlow(filename,uv,v=None): + """ Write optical flow to file. + + If v is None, uv is assumed to contain both u and v channels, + stacked in depth. + Original code by Deqing Sun, adapted from Daniel Scharstein. + """ + nBands = 2 + + if v is None: + assert(uv.ndim == 3) + assert(uv.shape[2] == 2) + u = uv[:,:,0] + v = uv[:,:,1] + else: + u = uv + + assert(u.shape == v.shape) + height,width = u.shape + f = open(filename,'wb') + # write the header + f.write(TAG_CHAR) + np.array(width).astype(np.int32).tofile(f) + np.array(height).astype(np.int32).tofile(f) + # arrange into matrix form + tmp = np.zeros((height, width*nBands)) + tmp[:,np.arange(width)*2] = u + tmp[:,np.arange(width)*2 + 1] = v + tmp.astype(np.float32).tofile(f) + f.close() + + +def readFlowKITTI(filename): + flow = cv2.imread(filename, cv2.IMREAD_ANYDEPTH|cv2.IMREAD_COLOR) + flow = flow[:,:,::-1].astype(np.float32) + flow, valid = flow[:, :, :2], flow[:, :, 2] + flow = (flow - 2**15) / 64.0 + return flow, valid + +def readDispKITTI(filename): + disp = cv2.imread(filename, cv2.IMREAD_ANYDEPTH) / 256.0 + valid = disp > 0.0 + flow = np.stack([-disp, np.zeros_like(disp)], -1) + return flow, valid + + +def writeFlowKITTI(filename, uv): + uv = 64.0 * uv + 2**15 + valid = np.ones([uv.shape[0], uv.shape[1], 1]) + uv = np.concatenate([uv, valid], axis=-1).astype(np.uint16) + cv2.imwrite(filename, uv[..., ::-1]) + + +def read_gen(file_name, pil=False): + ext = splitext(file_name)[-1] + if ext == '.png' or ext == '.jpeg' or ext == '.ppm' or ext == '.jpg': + return Image.open(file_name) + elif ext == '.bin' or ext == '.raw': + return np.load(file_name) + elif ext == '.flo': + return readFlow(file_name).astype(np.float32) + elif ext == '.pfm': + flow = readPFM(file_name).astype(np.float32) + if len(flow.shape) == 2: + return flow + else: + return flow[:, :, :-1] + return [] \ No newline at end of file diff --git a/FGT_codes/RAFT/utils/utils.py b/FGT_codes/RAFT/utils/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..5f32d281c1c46353a0a2bf36b0550adb74125c65 --- /dev/null +++ b/FGT_codes/RAFT/utils/utils.py @@ -0,0 +1,82 @@ +import torch +import torch.nn.functional as F +import numpy as np +from scipy import interpolate + + +class InputPadder: + """ Pads images such that dimensions are divisible by 8 """ + def __init__(self, dims, mode='sintel'): + self.ht, self.wd = dims[-2:] + pad_ht = (((self.ht // 8) + 1) * 8 - self.ht) % 8 + pad_wd = (((self.wd // 8) + 1) * 8 - self.wd) % 8 + if mode == 'sintel': + self._pad = [pad_wd//2, pad_wd - pad_wd//2, pad_ht//2, pad_ht - pad_ht//2] + else: + self._pad = [pad_wd//2, pad_wd - pad_wd//2, 0, pad_ht] + + def pad(self, *inputs): + return [F.pad(x, self._pad, mode='replicate') for x in inputs] + + def unpad(self,x): + ht, wd = x.shape[-2:] + c = [self._pad[2], ht-self._pad[3], self._pad[0], wd-self._pad[1]] + return x[..., c[0]:c[1], c[2]:c[3]] + +def forward_interpolate(flow): + flow = flow.detach().cpu().numpy() + dx, dy = flow[0], flow[1] + + ht, wd = dx.shape + x0, y0 = np.meshgrid(np.arange(wd), np.arange(ht)) + + x1 = x0 + dx + y1 = y0 + dy + + x1 = x1.reshape(-1) + y1 = y1.reshape(-1) + dx = dx.reshape(-1) + dy = dy.reshape(-1) + + valid = (x1 > 0) & (x1 < wd) & (y1 > 0) & (y1 < ht) + x1 = x1[valid] + y1 = y1[valid] + dx = dx[valid] + dy = dy[valid] + + flow_x = interpolate.griddata( + (x1, y1), dx, (x0, y0), method='nearest', fill_value=0) + + flow_y = interpolate.griddata( + (x1, y1), dy, (x0, y0), method='nearest', fill_value=0) + + flow = np.stack([flow_x, flow_y], axis=0) + return torch.from_numpy(flow).float() + + +def bilinear_sampler(img, coords, mode='bilinear', mask=False): + """ Wrapper for grid_sample, uses pixel coordinates """ + H, W = img.shape[-2:] + xgrid, ygrid = coords.split([1,1], dim=-1) + xgrid = 2*xgrid/(W-1) - 1 + ygrid = 2*ygrid/(H-1) - 1 + + grid = torch.cat([xgrid, ygrid], dim=-1) + img = F.grid_sample(img, grid, align_corners=True) + + if mask: + mask = (xgrid > -1) & (ygrid > -1) & (xgrid < 1) & (ygrid < 1) + return img, mask.float() + + return img + + +def coords_grid(batch, ht, wd): + coords = torch.meshgrid(torch.arange(ht), torch.arange(wd)) + coords = torch.stack(coords[::-1], dim=0).float() + return coords[None].repeat(batch, 1, 1, 1) + + +def upflow8(flow, mode='bilinear'): + new_size = (8 * flow.shape[2], 8 * flow.shape[3]) + return 8 * F.interpolate(flow, size=new_size, mode=mode, align_corners=True) diff --git a/FGT_codes/prepare_data.sh b/FGT_codes/prepare_data.sh new file mode 100644 index 0000000000000000000000000000000000000000..8d069530692eff7f4888600545d4fc44aa2e2f2b --- /dev/null +++ b/FGT_codes/prepare_data.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +unzip FGT_data.zip +unzip weights.zip +mkdir FGT/checkpoint +mkdir FGT/flowCheckPoint +mkdir LAFC/checkpoint +mv weights/fgt/* FGT/checkpoint +mv weights/lafc/* LAFC/checkpoint +mv weights/lafc_single/* FGT/flowCheckPoint +rm -r weights +rm FGT_data.zip +rm weights.zip diff --git a/FGT_codes/requirements.txt b/FGT_codes/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..c1d05808d9ea360cb691427ee6783654f85b4f1d --- /dev/null +++ b/FGT_codes/requirements.txt @@ -0,0 +1,12 @@ +cvbase==0.5.5 +imageio==2.6.1 +matplotlib==3.1.1 +numpy==1.22.2 +opencv_python==4.1.1.26 +Pillow==9.2.0 +PyYAML==6.0 +scikit_image==0.17.2 +scipy==1.3.1 +tensorboardX==2.5.1 +torch==1.10.1 +torchvision==0.11.2 diff --git a/FGT_codes/tool/__pycache__/get_flowNN_gradient.cpython-39.pyc b/FGT_codes/tool/__pycache__/get_flowNN_gradient.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..18cac6cb66af69c6bf59374afb6a6ece961ffc73 Binary files /dev/null and b/FGT_codes/tool/__pycache__/get_flowNN_gradient.cpython-39.pyc differ diff --git a/FGT_codes/tool/__pycache__/video_inpainting.cpython-39.pyc b/FGT_codes/tool/__pycache__/video_inpainting.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6c79945794aa5ec6e3de21b48930bd250cff7863 Binary files /dev/null and b/FGT_codes/tool/__pycache__/video_inpainting.cpython-39.pyc differ diff --git a/FGT_codes/tool/configs/object_removal.yaml b/FGT_codes/tool/configs/object_removal.yaml new file mode 100644 index 0000000000000000000000000000000000000000..59099029dc43ebc55dfc857100adb008306c2e97 --- /dev/null +++ b/FGT_codes/tool/configs/object_removal.yaml @@ -0,0 +1,8 @@ +mode: object_removal +consistencyThres: 5 +alpha: 0.1 +lafc_ckpts: ../LAFC/checkpoint +fgt_ckpts: ../FGT/checkpoint +flow_mask_dilates: 12 +frame_dilates: 4 +gpu: 0 \ No newline at end of file diff --git a/FGT_codes/tool/configs/video_extrapolation.yaml b/FGT_codes/tool/configs/video_extrapolation.yaml new file mode 100644 index 0000000000000000000000000000000000000000..af0ec45e031482d96b69d8476a512862579cb78b --- /dev/null +++ b/FGT_codes/tool/configs/video_extrapolation.yaml @@ -0,0 +1,8 @@ +mode: video_extrapolation +consistencyThres: 5 +alpha: 0.1 +lafc_ckpts: ../LAFC/checkpoint +fgt_ckpts: ../FGT/checkpoint +H_scale: 1.2 +W_scale: 1.2 +gpu: 0 \ No newline at end of file diff --git a/FGT_codes/tool/configs/watermark_removal.yaml b/FGT_codes/tool/configs/watermark_removal.yaml new file mode 100644 index 0000000000000000000000000000000000000000..d5174bd9ca2889d0935feddc9b012cbbc3ee5099 --- /dev/null +++ b/FGT_codes/tool/configs/watermark_removal.yaml @@ -0,0 +1,8 @@ +mode: watermark_removal +consistencyThres: 1 +alpha: 0.1 +lafc_ckpts: ../LAFC/checkpoint +fgt_ckpts: ../FGT/checkpoint +flow_mask_dilates: 9 +frame_dilates: 0 +gpu: 0 \ No newline at end of file diff --git a/FGT_codes/tool/flow_extract.py b/FGT_codes/tool/flow_extract.py new file mode 100644 index 0000000000000000000000000000000000000000..63483f7918bbb88377bb3b48e803629f3a8efa4d --- /dev/null +++ b/FGT_codes/tool/flow_extract.py @@ -0,0 +1,169 @@ +# coding=utf-8 +import os +import sys + +sys.path.append(os.path.abspath(os.path.join(__file__, '..', '..'))) + +import argparse +import os +import cv2 +import glob +import copy +import numpy as np +import torch +from PIL import Image +import scipy.ndimage +import torchvision.transforms.functional as F +import torch.nn.functional as F2 +from RAFT import utils +from RAFT import RAFT + +import utils.region_fill as rf +from torchvision.transforms import ToTensor +import time + + +def to_tensor(img): + img = Image.fromarray(img) + img_t = F.to_tensor(img).float() + return img_t + + +def gradient_mask(mask): # 产生梯度的mask + + gradient_mask = np.logical_or.reduce((mask, + np.concatenate((mask[1:, :], np.zeros((1, mask.shape[1]), dtype=np.bool)), + axis=0), + np.concatenate((mask[:, 1:], np.zeros((mask.shape[0], 1), dtype=np.bool)), + axis=1))) + + return gradient_mask + + +def create_dir(dir): + """Creates a directory if not exist. + """ + if not os.path.exists(dir): + os.makedirs(dir) + + +def initialize_RAFT(args): + """Initializes the RAFT model. + """ + model = torch.nn.DataParallel(RAFT(args)) + model.load_state_dict(torch.load(args.model)) + + model = model.module + model.to('cuda') + model.eval() + + return model + + +def calculate_flow(args, model, vid, video, mode): + """Calculates optical flow. + """ + if mode not in ['forward', 'backward']: + raise NotImplementedError + + nFrame, _, imgH, imgW = video.shape + Flow = np.empty(((imgH, imgW, 2, 0)), dtype=np.float32) + + create_dir(os.path.join(args.outroot, vid, mode + '_flo')) + # create_dir(os.path.join(args.outroot, vid, 'flow', mode + '_png')) + + with torch.no_grad(): + for i in range(video.shape[0] - 1): + print("Calculating {0} flow {1:2d} <---> {2:2d}".format(mode, i, i + 1), '\r', end='') + if mode == 'forward': + # Flow i -> i + 1 + image1 = video[i, None] + image2 = video[i + 1, None] + elif mode == 'backward': + # Flow i + 1 -> i + image1 = video[i + 1, None] + image2 = video[i, None] + else: + raise NotImplementedError + + _, flow = model(image1, image2, iters=20, test_mode=True) + flow = flow[0].permute(1, 2, 0).cpu().numpy() + # Flow = np.concatenate((Flow, flow[..., None]), axis=-1) + + # Flow visualization. + # flow_img = utils.flow_viz.flow_to_image(flow) + # flow_img = Image.fromarray(flow_img) + + # Saves the flow and flow_img. + # flow_img.save(os.path.join(args.outroot, vid, 'flow', mode + '_png', '%05d.png'%i)) + utils.frame_utils.writeFlow(os.path.join(args.outroot, vid, mode + '_flo', '%05d.flo' % i), flow) + + +def main(args): + # Flow model. + RAFT_model = initialize_RAFT(args) + + videos = os.listdir(args.path) + videoLen = len(videos) + try: + exceptList = os.listdir(args.expdir) + except: + exceptList = [] + v = 0 + for vid in videos: + v += 1 + print('[{}]/[{}] Video {} is being processed'.format(v, len(videos), vid)) + if vid in exceptList: + print('Video: {} skipped'.format(vid)) + continue + # Loads frames. + filename_list = glob.glob(os.path.join(args.path, vid, '*.png')) + \ + glob.glob(os.path.join(args.path, vid, '*.jpg')) + + # Obtains imgH, imgW and nFrame. + imgH, imgW = np.array(Image.open(filename_list[0])).shape[:2] + nFrame = len(filename_list) + print('images are loaded') + + # Loads video. + video = [] + for filename in sorted(filename_list): + print(filename) + img = np.array(Image.open(filename)) + if args.width != 0 and args.height != 0: + img = cv2.resize(img, (args.width, args.height), cv2.INTER_LINEAR) + video.append(torch.from_numpy(img.astype(np.uint8)).permute(2, 0, 1).float()) + + video = torch.stack(video, dim=0) + video = video.to('cuda') + + # Calcutes the corrupted flow. + start = time.time() + calculate_flow(args, RAFT_model, vid, video, 'forward') + calculate_flow(args, RAFT_model, vid, video, 'backward') + end = time.time() + sumTime = end - start + print('{}/{}, video {} is finished. {} frames takes {}s, {}s/frame.'.format(v, videoLen, vid, nFrame, sumTime, + sumTime / (2 * nFrame))) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + + # flow basic setting + parser.add_argument('--path', required=True, type=str) + parser.add_argument('--expdir', type=str) + parser.add_argument('--outroot', required=True, type=str) + parser.add_argument('--width', type=int, default=432) + parser.add_argument('--height', type=int, default=256) + + # RAFT + parser.add_argument('--model', default='../weight/raft-things.pth', help="restore checkpoint") + parser.add_argument('--small', action='store_true', help='use small model') + parser.add_argument('--mixed_precision', action='store_true', help='use mixed precision') + parser.add_argument('--alternate_corr', action='store_true', help='use efficent correlation implementation') + + args = parser.parse_args() + + main(args) + diff --git a/FGT_codes/tool/get_flowNN_gradient.py b/FGT_codes/tool/get_flowNN_gradient.py new file mode 100644 index 0000000000000000000000000000000000000000..6f201fbc86387ca5a53828c542023eedcd343eba --- /dev/null +++ b/FGT_codes/tool/get_flowNN_gradient.py @@ -0,0 +1,534 @@ +from __future__ import absolute_import, division, print_function, unicode_literals +import os +import cv2 +import copy +import numpy as np +import scipy.io as sio +from common_utils import interp, BFconsistCheck, \ + FBconsistCheck, consistCheck, get_KeySourceFrame_flowNN_gradient + + +def get_flowNN_gradient(args, + gradient_x, + gradient_y, + mask_RGB, + mask, + videoFlowF, + videoFlowB, + videoNonLocalFlowF, + videoNonLocalFlowB): + + # gradient_x: imgH x (imgW - 1 + 1) x 3 x nFrame + # gradient_y: (imgH - 1 + 1) x imgW x 3 x nFrame + # mask_RGB: imgH x imgW x nFrame + # mask: imgH x imgW x nFrame + # videoFlowF: imgH x imgW x 2 x (nFrame - 1) | [u, v] + # videoFlowB: imgH x imgW x 2 x (nFrame - 1) | [u, v] + # videoNonLocalFlowF: imgH x imgW x 2 x 3 x nFrame + # videoNonLocalFlowB: imgH x imgW x 2 x 3 x nFrame + + if args.Nonlocal: + num_candidate = 5 + else: + num_candidate = 2 + imgH, imgW, nFrame = mask.shape + numPix = np.sum(mask) + + # |--------------------| |--------------------| + # | y | | v | + # | x * | | u * | + # | | | | + # |--------------------| |--------------------| + + # sub: numPix * 3 | [y, x, t] + # flowNN: numPix * 3 * 2 | [y, x, t], [BN, FN] + # HaveFlowNN: imgH * imgW * nFrame * 2 + # numPixInd: imgH * imgW * nFrame + # consistencyMap: imgH * imgW * 5 * nFrame | [BN, FN, NL2, NL3, NL4] + # consistency_uv: imgH * imgW * [BN, FN] * [u, v] * nFrame + + # sub: numPix * [y, x, t] | position of mising pixels + sub = np.concatenate((np.where(mask == 1)[0].reshape(-1, 1), + np.where(mask == 1)[1].reshape(-1, 1), + np.where(mask == 1)[2].reshape(-1, 1)), axis=1) + + # flowNN: numPix * [y, x, t] * [BN, FN] | flow neighbors + flowNN = np.ones((numPix, 3, 2)) * 99999 # * -1 + HaveFlowNN = np.ones((imgH, imgW, nFrame, 2)) * 99999 + HaveFlowNN[mask, :] = 0 + numPixInd = np.ones((imgH, imgW, nFrame)) * -1 + consistencyMap = np.zeros((imgH, imgW, num_candidate, nFrame)) + consistency_uv = np.zeros((imgH, imgW, 2, 2, nFrame)) + + # numPixInd[y, x, t] gives the index of the missing pixel@[y, x, t] in sub, + # i.e. which row. numPixInd[y, x, t] = idx; sub[idx, :] = [y, x, t] + for idx in range(len(sub)): + numPixInd[sub[idx, 0], sub[idx, 1], sub[idx, 2]] = idx + + # Initialization + frameIndSetF = range(1, nFrame) + frameIndSetB = range(nFrame - 2, -1, -1) + + # 1. Forward Pass (backward flow propagation) + print('Forward Pass......') + + NN_idx = 0 # BN:0 + for indFrame in frameIndSetF: + + # Bool indicator of missing pixels at frame t + holepixPosInd = (sub[:, 2] == indFrame) + + # Hole pixel location at frame t, i.e. [y, x, t] + holepixPos = sub[holepixPosInd, :] + + # Calculate the backward flow neighbor. Should be located at frame t-1 + flowB_neighbor = copy.deepcopy(holepixPos) + flowB_neighbor = flowB_neighbor.astype(np.float32) + + flowB_vertical = videoFlowB[:, :, 1, indFrame - 1] # t --> t-1 + flowB_horizont = videoFlowB[:, :, 0, indFrame - 1] + flowF_vertical = videoFlowF[:, :, 1, indFrame - 1] # t-1 --> t + flowF_horizont = videoFlowF[:, :, 0, indFrame - 1] + + flowB_neighbor[:, 0] += flowB_vertical[holepixPos[:, 0], holepixPos[:, 1]] + flowB_neighbor[:, 1] += flowB_horizont[holepixPos[:, 0], holepixPos[:, 1]] + flowB_neighbor[:, 2] -= 1 + + # Round the backward flow neighbor location + flow_neighbor_int = np.round(copy.deepcopy(flowB_neighbor)).astype(np.int32) + + # Chen: I should combine the following two operations together + # Check the backward/forward consistency + IsConsist, _ = BFconsistCheck(flowB_neighbor, + flowF_vertical, + flowF_horizont, + holepixPos, + args.consistencyThres) + + trueConsist = IsConsist[IsConsist == True] + + BFdiff, BF_uv = consistCheck(videoFlowF[:, :, :, indFrame - 1], + videoFlowB[:, :, :, indFrame - 1]) + + # Check out-of-boundary + # Last column and last row does not have valid gradient + ValidPos = np.logical_and( + np.logical_and(flow_neighbor_int[:, 0] >= 0, + flow_neighbor_int[:, 0] < imgH - 1), + np.logical_and(flow_neighbor_int[:, 1] >= 0, + flow_neighbor_int[:, 1] < imgW - 1)) + + # Only work with pixels that are not out-of-boundary + holepixPos = holepixPos[ValidPos, :] + flowB_neighbor = flowB_neighbor[ValidPos, :] + flow_neighbor_int = flow_neighbor_int[ValidPos, :] + IsConsist = IsConsist[ValidPos] + + # For each missing pixel in holepixPos|[y, x, t], + # we check its backward flow neighbor flowB_neighbor|[y', x', t-1]. + + # Case 1: If mask[round(y'), round(x'), t-1] == 0, + # the backward flow neighbor of [y, x, t] is known. + # [y', x', t-1] is the backward flow neighbor. + + # KnownInd: Among all backward flow neighbors, which pixel is known. + KnownInd = mask[flow_neighbor_int[:, 0], + flow_neighbor_int[:, 1], + indFrame - 1] == 0 + + KnownIsConsist = np.logical_and(KnownInd, IsConsist) + holepixPos_valid = holepixPos[KnownIsConsist] + + # We save backward flow neighbor flowB_neighbor in flowNN + flowNN[numPixInd[holepixPos[KnownIsConsist, 0], + holepixPos[KnownIsConsist, 1], + indFrame].astype(np.int32), :, NN_idx] = \ + flowB_neighbor[KnownIsConsist, :] + # flowNN[np.where(holepixPosInd == 1)[0][ValidPos][KnownIsConsist], :, 0] = \ + # flowB_neighbor[KnownIsConsist, :] + + # We mark [y, x, t] in HaveFlowNN as 1 + HaveFlowNN[holepixPos[KnownIsConsist, 0], + holepixPos[KnownIsConsist, 1], + indFrame, + NN_idx] = 1 + + # HaveFlowNN[:, :, :, 0] + # 0: Backward flow neighbor can not be reached + # 1: Backward flow neighbor can be reached + # -1: Pixels that do not need to be completed + + consistency_uv[holepixPos[KnownIsConsist, 0], holepixPos[KnownIsConsist, 1], NN_idx, 0, indFrame] = np.abs(BF_uv[holepixPos[KnownIsConsist, 0], holepixPos[KnownIsConsist, 1], 0]) + consistency_uv[holepixPos[KnownIsConsist, 0], holepixPos[KnownIsConsist, 1], NN_idx, 1, indFrame] = np.abs(BF_uv[holepixPos[KnownIsConsist, 0], holepixPos[KnownIsConsist, 1], 1]) + + # Case 2: If mask[round(y'), round(x'), t-1] == 1, + # the pixel@[round(y'), round(x'), t-1] is also occluded. + # We further check if we already assign a backward flow neighbor for the backward flow neighbor + # If HaveFlowNN[round(y'), round(x'), t-1] == 0, + # this is isolated pixel. Do nothing. + # If HaveFlowNN[round(y'), round(x'), t-1] == 1, + # we can borrow the value and refine it. + + UnknownInd = np.invert(KnownInd) + + # If we already assign a backward flow neighbor@[round(y'), round(x'), t-1] + HaveNNInd = HaveFlowNN[flow_neighbor_int[:, 0], + flow_neighbor_int[:, 1], + indFrame - 1, + NN_idx] == 1 + + # Unknown & IsConsist & HaveNNInd + Valid_ = np.logical_and.reduce((UnknownInd, HaveNNInd, IsConsist)) + + refineVec = np.concatenate(( + (flowB_neighbor[:, 0] - flow_neighbor_int[:, 0]).reshape(-1, 1), + (flowB_neighbor[:, 1] - flow_neighbor_int[:, 1]).reshape(-1, 1), + np.zeros((flowB_neighbor[:, 0].shape[0])).reshape(-1, 1)), 1) + + # Check if the transitive backward flow neighbor of [y, x, t] is known. + # Sometimes after refinement, it is no longer known. + flowNN_tmp = copy.deepcopy(flowNN[numPixInd[flow_neighbor_int[:, 0], + flow_neighbor_int[:, 1], + indFrame - 1].astype(np.int32), :, NN_idx] + refineVec[:, :]) + flowNN_tmp = np.round(flowNN_tmp).astype(np.int32) + + # Check out-of-boundary. flowNN_tmp may be out-of-boundary + ValidPos_ = np.logical_and( + np.logical_and(flowNN_tmp[:, 0] >= 0, + flowNN_tmp[:, 0] < imgH - 1), + np.logical_and(flowNN_tmp[:, 1] >= 0, + flowNN_tmp[:, 1] < imgW - 1)) + + # Change the out-of-boundary value to 0, in order to run mask[y,x,t] + # in the next line. It won't affect anything as ValidPos_ is saved already + flowNN_tmp[np.invert(ValidPos_), :] = 0 + ValidNN = mask[flowNN_tmp[:, 0], + flowNN_tmp[:, 1], + flowNN_tmp[:, 2]] == 0 + + # Valid = np.logical_and.reduce((Valid_, ValidNN, ValidPos_)) + Valid = np.logical_and.reduce((Valid_, ValidPos_)) + + # We save the transitive backward flow neighbor flowB_neighbor in flowNN + flowNN[numPixInd[holepixPos[Valid, 0], + holepixPos[Valid, 1], + indFrame].astype(np.int32), :, NN_idx] = \ + flowNN[numPixInd[flow_neighbor_int[Valid, 0], + flow_neighbor_int[Valid, 1], + indFrame - 1].astype(np.int32), :, NN_idx] + refineVec[Valid, :] + + # We mark [y, x, t] in HaveFlowNN as 1 + HaveFlowNN[holepixPos[Valid, 0], + holepixPos[Valid, 1], + indFrame, + NN_idx] = 1 + + consistency_uv[holepixPos[Valid, 0], holepixPos[Valid, 1], NN_idx, 0, indFrame] = np.maximum(np.abs(BF_uv[holepixPos[Valid, 0], holepixPos[Valid, 1], 0]), np.abs(consistency_uv[flow_neighbor_int[Valid, 0], flow_neighbor_int[Valid, 1], NN_idx, 0, indFrame - 1])) + consistency_uv[holepixPos[Valid, 0], holepixPos[Valid, 1], NN_idx, 1, indFrame] = np.maximum(np.abs(BF_uv[holepixPos[Valid, 0], holepixPos[Valid, 1], 1]), np.abs(consistency_uv[flow_neighbor_int[Valid, 0], flow_neighbor_int[Valid, 1], NN_idx, 1, indFrame - 1])) + + consistencyMap[:, :, NN_idx, indFrame] = (consistency_uv[:, :, NN_idx, 0, indFrame] ** 2 + consistency_uv[:, :, NN_idx, 1, indFrame] ** 2) ** 0.5 + + print("Frame {0:3d}: {1:8d} + {2:8d} = {3:8d}" + .format(indFrame, + np.sum(HaveFlowNN[:, :, indFrame, NN_idx] == 1), + np.sum(HaveFlowNN[:, :, indFrame, NN_idx] == 0), + np.sum(HaveFlowNN[:, :, indFrame, NN_idx] != 99999))) + + # 2. Backward Pass (forward flow propagation) + print('Backward Pass......') + + NN_idx = 1 # FN:1 + for indFrame in frameIndSetB: + + # Bool indicator of missing pixels at frame t + holepixPosInd = (sub[:, 2] == indFrame) + + # Hole pixel location at frame t, i.e. [y, x, t] + holepixPos = sub[holepixPosInd, :] + + # Calculate the forward flow neighbor. Should be located at frame t+1 + flowF_neighbor = copy.deepcopy(holepixPos) + flowF_neighbor = flowF_neighbor.astype(np.float32) + + flowF_vertical = videoFlowF[:, :, 1, indFrame] # t --> t+1 + flowF_horizont = videoFlowF[:, :, 0, indFrame] + flowB_vertical = videoFlowB[:, :, 1, indFrame] # t+1 --> t + flowB_horizont = videoFlowB[:, :, 0, indFrame] + + flowF_neighbor[:, 0] += flowF_vertical[holepixPos[:, 0], holepixPos[:, 1]] + flowF_neighbor[:, 1] += flowF_horizont[holepixPos[:, 0], holepixPos[:, 1]] + flowF_neighbor[:, 2] += 1 + + # Round the forward flow neighbor location + flow_neighbor_int = np.round(copy.deepcopy(flowF_neighbor)).astype(np.int32) + + # Check the forawrd/backward consistency + IsConsist, _ = FBconsistCheck(flowF_neighbor, + flowB_vertical, + flowB_horizont, + holepixPos, + args.consistencyThres) + + FBdiff, FB_uv = consistCheck(videoFlowB[:, :, :, indFrame], + videoFlowF[:, :, :, indFrame]) + + # Check out-of-boundary + # Last column and last row does not have valid gradient + ValidPos = np.logical_and( + np.logical_and(flow_neighbor_int[:, 0] >= 0, + flow_neighbor_int[:, 0] < imgH - 1), + np.logical_and(flow_neighbor_int[:, 1] >= 0, + flow_neighbor_int[:, 1] < imgW - 1)) + + # Only work with pixels that are not out-of-boundary + holepixPos = holepixPos[ValidPos, :] + flowF_neighbor = flowF_neighbor[ValidPos, :] + flow_neighbor_int = flow_neighbor_int[ValidPos, :] + IsConsist = IsConsist[ValidPos] + + # Case 1: + KnownInd = mask[flow_neighbor_int[:, 0], + flow_neighbor_int[:, 1], + indFrame + 1] == 0 + + KnownIsConsist = np.logical_and(KnownInd, IsConsist) + flowNN[numPixInd[holepixPos[KnownIsConsist, 0], + holepixPos[KnownIsConsist, 1], + indFrame].astype(np.int32), :, NN_idx] = \ + flowF_neighbor[KnownIsConsist, :] + + HaveFlowNN[holepixPos[KnownIsConsist, 0], + holepixPos[KnownIsConsist, 1], + indFrame, + NN_idx] = 1 + + consistency_uv[holepixPos[KnownIsConsist, 0], holepixPos[KnownIsConsist, 1], NN_idx, 0, indFrame] = np.abs(FB_uv[holepixPos[KnownIsConsist, 0], holepixPos[KnownIsConsist, 1], 0]) + consistency_uv[holepixPos[KnownIsConsist, 0], holepixPos[KnownIsConsist, 1], NN_idx, 1, indFrame] = np.abs(FB_uv[holepixPos[KnownIsConsist, 0], holepixPos[KnownIsConsist, 1], 1]) + + # Case 2: + UnknownInd = np.invert(KnownInd) + HaveNNInd = HaveFlowNN[flow_neighbor_int[:, 0], + flow_neighbor_int[:, 1], + indFrame + 1, + NN_idx] == 1 + + # Unknown & IsConsist & HaveNNInd + Valid_ = np.logical_and.reduce((UnknownInd, HaveNNInd, IsConsist)) + + refineVec = np.concatenate(( + (flowF_neighbor[:, 0] - flow_neighbor_int[:, 0]).reshape(-1, 1), + (flowF_neighbor[:, 1] - flow_neighbor_int[:, 1]).reshape(-1, 1), + np.zeros((flowF_neighbor[:, 0].shape[0])).reshape(-1, 1)), 1) + + # Check if the transitive backward flow neighbor of [y, x, t] is known. + # Sometimes after refinement, it is no longer known. + flowNN_tmp = copy.deepcopy(flowNN[numPixInd[flow_neighbor_int[:, 0], + flow_neighbor_int[:, 1], + indFrame + 1].astype(np.int32), :, NN_idx] + refineVec[:, :]) + flowNN_tmp = np.round(flowNN_tmp).astype(np.int32) + + # Check out-of-boundary. flowNN_tmp may be out-of-boundary + ValidPos_ = np.logical_and( + np.logical_and(flowNN_tmp[:, 0] >= 0, + flowNN_tmp[:, 0] < imgH - 1), + np.logical_and(flowNN_tmp[:, 1] >= 0, + flowNN_tmp[:, 1] < imgW - 1)) + + # Change the out-of-boundary value to 0, in order to run mask[y,x,t] + # in the next line. It won't affect anything as ValidPos_ is saved already + flowNN_tmp[np.invert(ValidPos_), :] = 0 + ValidNN = mask[flowNN_tmp[:, 0], + flowNN_tmp[:, 1], + flowNN_tmp[:, 2]] == 0 + + # Valid = np.logical_and.reduce((Valid_, ValidNN, ValidPos_)) + Valid = np.logical_and.reduce((Valid_, ValidPos_)) + + # We save the transitive backward flow neighbor flowB_neighbor in flowNN + flowNN[numPixInd[holepixPos[Valid, 0], + holepixPos[Valid, 1], + indFrame].astype(np.int32), :, NN_idx] = \ + flowNN[numPixInd[flow_neighbor_int[Valid, 0], + flow_neighbor_int[Valid, 1], + indFrame + 1].astype(np.int32), :, NN_idx] + refineVec[Valid, :] + + # We mark [y, x, t] in HaveFlowNN as 1 + HaveFlowNN[holepixPos[Valid, 0], + holepixPos[Valid, 1], + indFrame, + NN_idx] = 1 + + consistency_uv[holepixPos[Valid, 0], holepixPos[Valid, 1], NN_idx, 0, indFrame] = np.maximum(np.abs(FB_uv[holepixPos[Valid, 0], holepixPos[Valid, 1], 0]), np.abs(consistency_uv[flow_neighbor_int[Valid, 0], flow_neighbor_int[Valid, 1], NN_idx, 0, indFrame + 1])) + consistency_uv[holepixPos[Valid, 0], holepixPos[Valid, 1], NN_idx, 1, indFrame] = np.maximum(np.abs(FB_uv[holepixPos[Valid, 0], holepixPos[Valid, 1], 1]), np.abs(consistency_uv[flow_neighbor_int[Valid, 0], flow_neighbor_int[Valid, 1], NN_idx, 1, indFrame + 1])) + + consistencyMap[:, :, NN_idx, indFrame] = (consistency_uv[:, :, NN_idx, 0, indFrame] ** 2 + consistency_uv[:, :, NN_idx, 1, indFrame] ** 2) ** 0.5 + + print("Frame {0:3d}: {1:8d} + {2:8d} = {3:8d}" + .format(indFrame, + np.sum(HaveFlowNN[:, :, indFrame, NN_idx] == 1), + np.sum(HaveFlowNN[:, :, indFrame, NN_idx] == 0), + np.sum(HaveFlowNN[:, :, indFrame, NN_idx] != 99999))) + + # Interpolation + gradient_x_BN = copy.deepcopy(gradient_x) + gradient_y_BN = copy.deepcopy(gradient_y) + gradient_x_FN = copy.deepcopy(gradient_x) + gradient_y_FN = copy.deepcopy(gradient_y) + + for indFrame in range(nFrame): + # Index of missing pixel whose backward flow neighbor is from frame indFrame + SourceFmInd = np.where(flowNN[:, 2, 0] == indFrame) + + print("{0:8d} pixels are from source Frame {1:3d}" + .format(len(SourceFmInd[0]), indFrame)) + # The location of the missing pixel whose backward flow neighbor is + # from frame indFrame flowNN[SourceFmInd, 0, 0], flowNN[SourceFmInd, 1, 0] + + if len(SourceFmInd[0]) != 0: + + # |--------------------| + # | y | + # | x * | + # | | + # |--------------------| + # sub: numPix x 3 [y, x, t] + # img: [y, x] + # interp(img, x, y) + + gradient_x_BN[sub[SourceFmInd[0], :][:, 0], + sub[SourceFmInd[0], :][:, 1], + :, sub[SourceFmInd[0], :][:, 2]] = \ + interp(gradient_x_BN[:, :, :, indFrame], + flowNN[SourceFmInd, 1, 0].reshape(-1), + flowNN[SourceFmInd, 0, 0].reshape(-1)) + + gradient_y_BN[sub[SourceFmInd[0], :][:, 0], + sub[SourceFmInd[0], :][:, 1], + :, sub[SourceFmInd[0], :][:, 2]] = \ + interp(gradient_y_BN[:, :, :, indFrame], + flowNN[SourceFmInd, 1, 0].reshape(-1), + flowNN[SourceFmInd, 0, 0].reshape(-1)) + + assert(((sub[SourceFmInd[0], :][:, 2] - indFrame) <= 0).sum() == 0) + + for indFrame in range(nFrame - 1, -1, -1): + # Index of missing pixel whose forward flow neighbor is from frame indFrame + SourceFmInd = np.where(flowNN[:, 2, 1] == indFrame) + print("{0:8d} pixels are from source Frame {1:3d}" + .format(len(SourceFmInd[0]), indFrame)) + if len(SourceFmInd[0]) != 0: + + gradient_x_FN[sub[SourceFmInd[0], :][:, 0], + sub[SourceFmInd[0], :][:, 1], + :, sub[SourceFmInd[0], :][:, 2]] = \ + interp(gradient_x_FN[:, :, :, indFrame], + flowNN[SourceFmInd, 1, 1].reshape(-1), + flowNN[SourceFmInd, 0, 1].reshape(-1)) + + gradient_y_FN[sub[SourceFmInd[0], :][:, 0], + sub[SourceFmInd[0], :][:, 1], + :, sub[SourceFmInd[0], :][:, 2]] = \ + interp(gradient_y_FN[:, :, :, indFrame], + flowNN[SourceFmInd, 1, 1].reshape(-1), + flowNN[SourceFmInd, 0, 1].reshape(-1)) + + assert(((indFrame - sub[SourceFmInd[0], :][:, 2]) <= 0).sum() == 0) + + # New mask + mask_tofill = np.zeros((imgH, imgW, nFrame)).astype(np.bool) + + for indFrame in range(nFrame): + if args.Nonlocal: + consistencyMap[:, :, 2, indFrame], _ = consistCheck( + videoNonLocalFlowB[:, :, :, 0, indFrame], + videoNonLocalFlowF[:, :, :, 0, indFrame]) + consistencyMap[:, :, 3, indFrame], _ = consistCheck( + videoNonLocalFlowB[:, :, :, 1, indFrame], + videoNonLocalFlowF[:, :, :, 1, indFrame]) + consistencyMap[:, :, 4, indFrame], _ = consistCheck( + videoNonLocalFlowB[:, :, :, 2, indFrame], + videoNonLocalFlowF[:, :, :, 2, indFrame]) + + HaveNN = np.zeros((imgH, imgW, num_candidate)) + + if args.Nonlocal: + HaveKeySourceFrameFlowNN, gradient_x_KeySourceFrameFlowNN, gradient_y_KeySourceFrameFlowNN = \ + get_KeySourceFrame_flowNN_gradient(sub, + indFrame, + mask, + videoNonLocalFlowB, + videoNonLocalFlowF, + gradient_x, + gradient_y, + args.consistencyThres) + + HaveNN[:, :, 2] = HaveKeySourceFrameFlowNN[:, :, 0] == 1 + HaveNN[:, :, 3] = HaveKeySourceFrameFlowNN[:, :, 1] == 1 + HaveNN[:, :, 4] = HaveKeySourceFrameFlowNN[:, :, 2] == 1 + + HaveNN[:, :, 0] = HaveFlowNN[:, :, indFrame, 0] == 1 + HaveNN[:, :, 1] = HaveFlowNN[:, :, indFrame, 1] == 1 + + NotHaveNN = np.logical_and(np.invert(HaveNN.astype(np.bool)), + np.repeat(np.expand_dims((mask[:, :, indFrame]), 2), num_candidate, axis=2)) + + if args.Nonlocal: + HaveNN_sum = np.logical_or.reduce((HaveNN[:, :, 0], + HaveNN[:, :, 1], + HaveNN[:, :, 2], + HaveNN[:, :, 3], + HaveNN[:, :, 4])) + else: + HaveNN_sum = np.logical_or.reduce((HaveNN[:, :, 0], + HaveNN[:, :, 1])) + + gradient_x_Candidate = np.zeros((imgH, imgW, 3, num_candidate)) + gradient_y_Candidate = np.zeros((imgH, imgW, 3, num_candidate)) + + gradient_x_Candidate[:, :, :, 0] = gradient_x_BN[:, :, :, indFrame] + gradient_y_Candidate[:, :, :, 0] = gradient_y_BN[:, :, :, indFrame] + gradient_x_Candidate[:, :, :, 1] = gradient_x_FN[:, :, :, indFrame] + gradient_y_Candidate[:, :, :, 1] = gradient_y_FN[:, :, :, indFrame] + + if args.Nonlocal: + gradient_x_Candidate[:, :, :, 2] = gradient_x_KeySourceFrameFlowNN[:, :, :, 0] + gradient_y_Candidate[:, :, :, 2] = gradient_y_KeySourceFrameFlowNN[:, :, :, 0] + gradient_x_Candidate[:, :, :, 3] = gradient_x_KeySourceFrameFlowNN[:, :, :, 1] + gradient_y_Candidate[:, :, :, 3] = gradient_y_KeySourceFrameFlowNN[:, :, :, 1] + gradient_x_Candidate[:, :, :, 4] = gradient_x_KeySourceFrameFlowNN[:, :, :, 2] + gradient_y_Candidate[:, :, :, 4] = gradient_y_KeySourceFrameFlowNN[:, :, :, 2] + + consistencyMap[:, :, :, indFrame] = np.exp( - consistencyMap[:, :, :, indFrame] / args.alpha) + + consistencyMap[NotHaveNN[:, :, 0], 0, indFrame] = 0 + consistencyMap[NotHaveNN[:, :, 1], 1, indFrame] = 0 + + if args.Nonlocal: + consistencyMap[NotHaveNN[:, :, 2], 2, indFrame] = 0 + consistencyMap[NotHaveNN[:, :, 3], 3, indFrame] = 0 + consistencyMap[NotHaveNN[:, :, 4], 4, indFrame] = 0 + + weights = (consistencyMap[HaveNN_sum, :, indFrame] * HaveNN[HaveNN_sum, :]) / ((consistencyMap[HaveNN_sum, :, indFrame] * HaveNN[HaveNN_sum, :]).sum(axis=1, keepdims=True)) + + # Fix the numerical issue. 0 / 0 + fix = np.where((consistencyMap[HaveNN_sum, :, indFrame] * HaveNN[HaveNN_sum, :]).sum(axis=1, keepdims=True) == 0)[0] + weights[fix, :] = HaveNN[HaveNN_sum, :][fix, :] / HaveNN[HaveNN_sum, :][fix, :].sum(axis=1, keepdims=True) + + # Fuse RGB channel independently + gradient_x[HaveNN_sum, 0, indFrame] = \ + np.sum(np.multiply(gradient_x_Candidate[HaveNN_sum, 0, :], weights), axis=1) + gradient_x[HaveNN_sum, 1, indFrame] = \ + np.sum(np.multiply(gradient_x_Candidate[HaveNN_sum, 1, :], weights), axis=1) + gradient_x[HaveNN_sum, 2, indFrame] = \ + np.sum(np.multiply(gradient_x_Candidate[HaveNN_sum, 2, :], weights), axis=1) + + gradient_y[HaveNN_sum, 0, indFrame] = \ + np.sum(np.multiply(gradient_y_Candidate[HaveNN_sum, 0, :], weights), axis=1) + gradient_y[HaveNN_sum, 1, indFrame] = \ + np.sum(np.multiply(gradient_y_Candidate[HaveNN_sum, 1, :], weights), axis=1) + gradient_y[HaveNN_sum, 2, indFrame] = \ + np.sum(np.multiply(gradient_y_Candidate[HaveNN_sum, 2, :], weights), axis=1) + + mask_tofill[np.logical_and(np.invert(HaveNN_sum), mask[:, :, indFrame]), indFrame] = True + + return gradient_x, gradient_y, mask_tofill diff --git a/FGT_codes/tool/utils/Poisson_blend.py b/FGT_codes/tool/utils/Poisson_blend.py new file mode 100644 index 0000000000000000000000000000000000000000..9a32612f53ce8e5b0ef8b5f48aba46dd5f297c97 --- /dev/null +++ b/FGT_codes/tool/utils/Poisson_blend.py @@ -0,0 +1,287 @@ +from __future__ import absolute_import, division, print_function, unicode_literals + +import scipy.ndimage +from scipy.sparse.linalg import spsolve +from scipy import sparse +import scipy.io as sio +import numpy as np +from PIL import Image +import copy +import cv2 +import os +import argparse + + +def sub2ind(pi, pj, imgH, imgW): + return pj + pi * imgW + + +def Poisson_blend(imgTrg, imgSrc_gx, imgSrc_gy, holeMask, edge=None): + + imgH, imgW, nCh = imgTrg.shape + + if not isinstance(edge, np.ndarray): + edge = np.zeros((imgH, imgW), dtype=np.float32) + + # Initialize the reconstructed image + imgRecon = np.zeros((imgH, imgW, nCh), dtype=np.float32) + + # prepare discrete Poisson equation + A, b = solvePoisson(holeMask, imgSrc_gx, imgSrc_gy, imgTrg, edge) + + # Independently process each channel + for ch in range(nCh): + + # solve Poisson equation + x = scipy.sparse.linalg.lsqr(A, b[:, ch, None])[0] + imgRecon[:, :, ch] = x.reshape(imgH, imgW) + + # Combined with the known region in the target + holeMaskC = np.tile(np.expand_dims(holeMask, axis=2), (1, 1, nCh)) + imgBlend = holeMaskC * imgRecon + (1 - holeMaskC) * imgTrg + + # Fill in edge pixel + pi = np.expand_dims(np.where((holeMask * edge) == 1)[0], axis=1) # y, i + pj = np.expand_dims(np.where((holeMask * edge) == 1)[1], axis=1) # x, j + + for k in range(len(pi)): + if pi[k, 0] - 1 >= 0: + if edge[pi[k, 0] - 1, pj[k, 0]] == 0: + imgBlend[pi[k, 0], pj[k, 0], :] = imgBlend[pi[k, 0] - 1, pj[k, 0], :] + continue + if pi[k, 0] + 1 <= imgH - 1: + if edge[pi[k, 0] + 1, pj[k, 0]] == 0: + imgBlend[pi[k, 0], pj[k, 0], :] = imgBlend[pi[k, 0] + 1, pj[k, 0], :] + continue + if pj[k, 0] - 1 >= 0: + if edge[pi[k, 0], pj[k, 0] - 1] == 0: + imgBlend[pi[k, 0], pj[k, 0], :] = imgBlend[pi[k, 0], pj[k, 0] - 1, :] + continue + if pj[k, 0] + 1 <= imgW - 1: + if edge[pi[k, 0], pj[k, 0] + 1] == 0: + imgBlend[pi[k, 0], pj[k, 0], :] = imgBlend[pi[k, 0], pj[k, 0] + 1, :] + + return imgBlend + +def solvePoisson(holeMask, imgSrc_gx, imgSrc_gy, imgTrg, edge): + + # Prepare the linear system of equations for Poisson blending + imgH, imgW = holeMask.shape + N = imgH * imgW + + # Number of unknown variables + numUnknownPix = holeMask.sum() + + # 4-neighbors: dx and dy + dx = [1, 0, -1, 0] + dy = [0, 1, 0, -1] + + # 3 + # | + # 2 -- * -- 0 + # | + # 1 + # + + # Initialize (I, J, S), for sparse matrix A where A(I(k), J(k)) = S(k) + I = np.empty((0, 1), dtype=np.float32) + J = np.empty((0, 1), dtype=np.float32) + S = np.empty((0, 1), dtype=np.float32) + + # Initialize b + b = np.empty((0, 2), dtype=np.float32) + + # Precompute unkonwn pixel position + pi = np.expand_dims(np.where(holeMask == 1)[0], axis=1) # y, i + pj = np.expand_dims(np.where(holeMask == 1)[1], axis=1) # x, j + pind = sub2ind(pi, pj, imgH, imgW) + + # |--------------------| + # | y (i) | + # | x (j) * | + # | | + # |--------------------| + + qi = np.concatenate((pi + dy[0], + pi + dy[1], + pi + dy[2], + pi + dy[3]), axis=1) + + qj = np.concatenate((pj + dx[0], + pj + dx[1], + pj + dx[2], + pj + dx[3]), axis=1) + + # Handling cases at image borders + validN = (qi >= 0) & (qi <= imgH - 1) & (qj >= 0) & (qj <= imgW - 1) + qind = np.zeros((validN.shape), dtype=np.float32) + qind[validN] = sub2ind(qi[validN], qj[validN], imgH, imgW) + + e_start = 0 # equation counter start + e_stop = 0 # equation stop + + # 4 neighbors + I, J, S, b, e_start, e_stop = constructEquation(0, validN, holeMask, edge, imgSrc_gx, imgSrc_gy, imgTrg, pi, pj, pind, qi, qj, qind, I, J, S, b, e_start, e_stop) + I, J, S, b, e_start, e_stop = constructEquation(1, validN, holeMask, edge, imgSrc_gx, imgSrc_gy, imgTrg, pi, pj, pind, qi, qj, qind, I, J, S, b, e_start, e_stop) + I, J, S, b, e_start, e_stop = constructEquation(2, validN, holeMask, edge, imgSrc_gx, imgSrc_gy, imgTrg, pi, pj, pind, qi, qj, qind, I, J, S, b, e_start, e_stop) + I, J, S, b, e_start, e_stop = constructEquation(3, validN, holeMask, edge, imgSrc_gx, imgSrc_gy, imgTrg, pi, pj, pind, qi, qj, qind, I, J, S, b, e_start, e_stop) + + nEqn = len(b) + # Construct the sparse matrix A + A = sparse.csr_matrix((S[:, 0], (I[:, 0], J[:, 0])), shape=(nEqn, N)) + + return A, b + + +def constructEquation(n, validN, holeMask, edge, imgSrc_gx, imgSrc_gy, imgTrg, pi, pj, pind, qi, qj, qind, I, J, S, b, e_start, e_stop): + + # Pixel that has valid neighbors + validNeighbor = validN[:, n] + + # Change the out-of-boundary value to 0, in order to run edge[y,x] + # in the next line. It won't affect anything as validNeighbor is saved already + + qi_tmp = copy.deepcopy(qi) + qj_tmp = copy.deepcopy(qj) + qi_tmp[np.invert(validNeighbor), n] = 0 + qj_tmp[np.invert(validNeighbor), n] = 0 + + # Not edge + NotEdge = (edge[pi[:, 0], pj[:, 0]] == 0) * (edge[qi_tmp[:, n], qj_tmp[:, n]] == 0) + + # Boundary constraint + Boundary = holeMask[qi_tmp[:, n], qj_tmp[:, n]] == 0 + valid = validNeighbor * NotEdge * Boundary + J_tmp = pind[valid, :] + + # num of equations: len(J_tmp) + e_stop = e_start + len(J_tmp) + I_tmp = np.arange(e_start, e_stop, dtype=np.float32).reshape(-1, 1) + e_start = e_stop + + S_tmp = np.ones(J_tmp.shape, dtype=np.float32) + + if n == 0: + b_tmp = - imgSrc_gx[pi[valid, 0], pj[valid, 0], :] + imgTrg[qi[valid, n], qj[valid, n], :] + elif n == 2: + b_tmp = imgSrc_gx[pi[valid, 0], pj[valid, 0] - 1, :] + imgTrg[qi[valid, n], qj[valid, n], :] + elif n == 1: + b_tmp = - imgSrc_gy[pi[valid, 0], pj[valid, 0], :] + imgTrg[qi[valid, n], qj[valid, n], :] + elif n == 3: + b_tmp = imgSrc_gy[pi[valid, 0] - 1, pj[valid, 0], :] + imgTrg[qi[valid, n], qj[valid, n], :] + + I = np.concatenate((I, I_tmp)) + J = np.concatenate((J, J_tmp)) + S = np.concatenate((S, S_tmp)) + b = np.concatenate((b, b_tmp)) + + + # Non-boundary constraint + NonBoundary = holeMask[qi_tmp[:, n], qj_tmp[:, n]] == 1 + valid = validNeighbor * NotEdge * NonBoundary + + J_tmp = pind[valid, :] + + # num of equations: len(J_tmp) + e_stop = e_start + len(J_tmp) + I_tmp = np.arange(e_start, e_stop, dtype=np.float32).reshape(-1, 1) + e_start = e_stop + + S_tmp = np.ones(J_tmp.shape, dtype=np.float32) + + if n == 0: + b_tmp = - imgSrc_gx[pi[valid, 0], pj[valid, 0], :] + elif n == 2: + b_tmp = imgSrc_gx[pi[valid, 0], pj[valid, 0] - 1, :] + elif n == 1: + b_tmp = - imgSrc_gy[pi[valid, 0], pj[valid, 0], :] + elif n == 3: + b_tmp = imgSrc_gy[pi[valid, 0] - 1, pj[valid, 0], :] + + I = np.concatenate((I, I_tmp)) + J = np.concatenate((J, J_tmp)) + S = np.concatenate((S, S_tmp)) + b = np.concatenate((b, b_tmp)) + + S_tmp = - np.ones(J_tmp.shape, dtype=np.float32) + J_tmp = qind[valid, n, None] + + I = np.concatenate((I, I_tmp)) + J = np.concatenate((J, J_tmp)) + S = np.concatenate((S, S_tmp)) + + return I, J, S, b, e_start, e_stop + + +def gradient_mask(mask): #产生梯度的mask + + gradient_mask = np.logical_or.reduce((mask, + np.concatenate((mask[1:, :], np.zeros((1, mask.shape[1]), dtype=np.bool)), axis=0), + np.concatenate((mask[:, 1:], np.zeros((mask.shape[0], 1), dtype=np.bool)), axis=1))) + + return gradient_mask + + + +if __name__ == '__main__': + import cvbase + from skimage.feature import canny + import argparse + import imageio + + parser = argparse.ArgumentParser() + parser.add_argument('--flow', type=str, default='../../test_blending/flow/00000.flo') + parser.add_argument('--mask', type=str, default='../../test_blending/mask/00000.png') + parser.add_argument('--width', type=int, default=432) + parser.add_argument('--height', type=int, default=256) + parser.add_argument('--output', type=str, default='../../test_blending/ret') + args = parser.parse_args() + flow, mask = args.flow, args.mask + width, height = args.width, args.height + output = args.output + + if not os.path.exists(output): + os.makedirs(output) + + flow = cvbase.read_flow(flow) + mask = cv2.imread(mask, 0) + h, w, c = flow.shape + flow_resized = np.zeros((height, width, 2)) + flow_resized[:, :, 0] = cv2.resize(flow[:, :, 0], (width, height), cv2.INTER_LINEAR) * width / w + flow_resized[:, :, 1] = cv2.resize(flow[:, :, 1], (width, height), cv2.INTER_LINEAR) * height / h + flow = flow_resized + + mask = cv2.resize(mask, (width, height), cv2.INTER_NEAREST) + mask_gradient = gradient_mask(mask) + + flow_gray = (flow[:, :, 0] ** 2 + flow[:, :, 1] ** 2) ** 0.5 + flow_gray = flow_gray / flow_gray.max() + edge = canny(flow_gray, sigma=1, low_threshold=0.1, high_threshold=0.2) + edge = edge.astype(np.bool) + masked_edge = edge * mask + + # gradients + gradient_x = np.concatenate((np.diff(flow, axis=1), np.zeros((height, 1, 2), dtype=np.float32)), axis=1) + gradient_y = np.concatenate((np.diff(flow, axis=0), np.zeros((1, width, 2), dtype=np.float32)), axis=0) + gradient = np.concatenate((gradient_x, gradient_y), axis=2) + gradient[mask_gradient, :] = 0 # 把中间的梯度设置成了0 + + # complete flow + imgSrc_gy = gradient[:, :, 2: 4] + imgSrc_gy = imgSrc_gy[0: h - 1, :, :] + imgSrc_gx = gradient[:, :, 0: 2] + imgSrc_gx = imgSrc_gx[:, 0: w - 1, :] + compFlow = Poisson_blend(flow, imgSrc_gx, imgSrc_gy, mask, masked_edge) # todo: edge or masked_edge ? + + # save flow + flow_n = cvbase.flow2rgb(flow) + compFlow_n = cvbase.flow2rgb(compFlow) + imageio.imwrite(os.path.join(output, 'flow.png'), flow_n) + imageio.imwrite(os.path.join(output, 'compFlow.png'), compFlow_n) + imageio.imwrite(os.path.join(output, 'edge.png'), masked_edge) + # imageio.imwrite(os.path.join(output, 'gx.png'), imgSrc_gx) + # imageio.imwrite(os.path.join(output, 'gy.png'), imgSrc_gy) + imageio.imwrite(os.path.join(output, 'mask.png'), mask) + imageio.imwrite(os.path.join(output, 'grad0.png'), gradient[:, :, 0]) + imageio.imwrite(os.path.join(output, 'grad1.png'), gradient[:, :, 1]) + diff --git a/FGT_codes/tool/utils/Poisson_blend_img.py b/FGT_codes/tool/utils/Poisson_blend_img.py new file mode 100644 index 0000000000000000000000000000000000000000..5aa182e19d7c17c5136284ae390e478952217f38 --- /dev/null +++ b/FGT_codes/tool/utils/Poisson_blend_img.py @@ -0,0 +1,314 @@ +from __future__ import absolute_import, division, print_function, unicode_literals + +import scipy.ndimage +from scipy.sparse.linalg import spsolve +from scipy import sparse +import scipy.io as sio +import numpy as np +from PIL import Image +import copy +import cv2 +import os +import argparse + + +def sub2ind(pi, pj, imgH, imgW): + return pj + pi * imgW + + +def Poisson_blend_img(imgTrg, imgSrc_gx, imgSrc_gy, holeMask, gradientMask=None, edge=None): + + imgH, imgW, nCh = imgTrg.shape + + if not isinstance(gradientMask, np.ndarray): + gradientMask = np.zeros((imgH, imgW), dtype=np.float32) + + if not isinstance(edge, np.ndarray): + edge = np.zeros((imgH, imgW), dtype=np.float32) + + # Initialize the reconstructed image + imgRecon = np.zeros((imgH, imgW, nCh), dtype=np.float32) + + # prepare discrete Poisson equation + A, b, UnfilledMask = solvePoisson(holeMask, imgSrc_gx, imgSrc_gy, imgTrg, + gradientMask, edge) + + # Independently process each channel + for ch in range(nCh): + + # solve Poisson equation + x = scipy.sparse.linalg.lsqr(A, b[:, ch])[0] + + imgRecon[:, :, ch] = x.reshape(imgH, imgW) + + # Combined with the known region in the target + holeMaskC = np.tile(np.expand_dims(holeMask, axis=2), (1, 1, nCh)) + imgBlend = holeMaskC * imgRecon + (1 - holeMaskC) * imgTrg + + + # while((UnfilledMask * edge).sum() != 0): + # # Fill in edge pixel + # pi = np.expand_dims(np.where((UnfilledMask * edge) == 1)[0], axis=1) # y, i + # pj = np.expand_dims(np.where((UnfilledMask * edge) == 1)[1], axis=1) # x, j + # + # for k in range(len(pi)): + # if pi[k, 0] - 1 >= 0: + # if (UnfilledMask * edge)[pi[k, 0] - 1, pj[k, 0]] == 0: + # imgBlend[pi[k, 0], pj[k, 0], :] = imgBlend[pi[k, 0] - 1, pj[k, 0], :] + # UnfilledMask[pi[k, 0], pj[k, 0]] = 0 + # continue + # if pi[k, 0] + 1 <= imgH - 1: + # if (UnfilledMask * edge)[pi[k, 0] + 1, pj[k, 0]] == 0: + # imgBlend[pi[k, 0], pj[k, 0], :] = imgBlend[pi[k, 0] + 1, pj[k, 0], :] + # UnfilledMask[pi[k, 0], pj[k, 0]] = 0 + # continue + # if pj[k, 0] - 1 >= 0: + # if (UnfilledMask * edge)[pi[k, 0], pj[k, 0] - 1] == 0: + # imgBlend[pi[k, 0], pj[k, 0], :] = imgBlend[pi[k, 0], pj[k, 0] - 1, :] + # UnfilledMask[pi[k, 0], pj[k, 0]] = 0 + # continue + # if pj[k, 0] + 1 <= imgW - 1: + # if (UnfilledMask * edge)[pi[k, 0], pj[k, 0] + 1] == 0: + # imgBlend[pi[k, 0], pj[k, 0], :] = imgBlend[pi[k, 0], pj[k, 0] + 1, :] + # UnfilledMask[pi[k, 0], pj[k, 0]] = 0 + + return imgBlend, UnfilledMask + +def solvePoisson(holeMask, imgSrc_gx, imgSrc_gy, imgTrg, + gradientMask, edge): + + # UnfilledMask indicates the region that is not completed + UnfilledMask_topleft = copy.deepcopy(holeMask) + UnfilledMask_bottomright = copy.deepcopy(holeMask) + + # Prepare the linear system of equations for Poisson blending + imgH, imgW = holeMask.shape + N = imgH * imgW + + # Number of unknown variables + numUnknownPix = holeMask.sum() + + # 4-neighbors: dx and dy + dx = [1, 0, -1, 0] + dy = [0, 1, 0, -1] + + # 3 + # | + # 2 -- * -- 0 + # | + # 1 + # + + # Initialize (I, J, S), for sparse matrix A where A(I(k), J(k)) = S(k) + I = np.empty((0, 1), dtype=np.float32) + J = np.empty((0, 1), dtype=np.float32) + S = np.empty((0, 1), dtype=np.float32) + + # Initialize b + b = np.empty((0, 3), dtype=np.float32) + + # Precompute unkonwn pixel position + pi = np.expand_dims(np.where(holeMask == 1)[0], axis=1) # y, i + pj = np.expand_dims(np.where(holeMask == 1)[1], axis=1) # x, j + pind = sub2ind(pi, pj, imgH, imgW) + + # |--------------------| + # | y (i) | + # | x (j) * | + # | | + # |--------------------| + # p[y, x] + + qi = np.concatenate((pi + dy[0], + pi + dy[1], + pi + dy[2], + pi + dy[3]), axis=1) + + qj = np.concatenate((pj + dx[0], + pj + dx[1], + pj + dx[2], + pj + dx[3]), axis=1) + + # Handling cases at image borders + validN = (qi >= 0) & (qi <= imgH - 1) & (qj >= 0) & (qj <= imgW - 1) + qind = np.zeros((validN.shape), dtype=np.float32) + qind[validN] = sub2ind(qi[validN], qj[validN], imgH, imgW) + + e_start = 0 # equation counter start + e_stop = 0 # equation stop + + # 4 neighbors + I, J, S, b, e_start, e_stop = constructEquation(0, validN, holeMask, gradientMask, edge, imgSrc_gx, imgSrc_gy, imgTrg, pi, pj, pind, qi, qj, qind, I, J, S, b, e_start, e_stop) + I, J, S, b, e_start, e_stop = constructEquation(1, validN, holeMask, gradientMask, edge, imgSrc_gx, imgSrc_gy, imgTrg, pi, pj, pind, qi, qj, qind, I, J, S, b, e_start, e_stop) + I, J, S, b, e_start, e_stop = constructEquation(2, validN, holeMask, gradientMask, edge, imgSrc_gx, imgSrc_gy, imgTrg, pi, pj, pind, qi, qj, qind, I, J, S, b, e_start, e_stop) + I, J, S, b, e_start, e_stop = constructEquation(3, validN, holeMask, gradientMask, edge, imgSrc_gx, imgSrc_gy, imgTrg, pi, pj, pind, qi, qj, qind, I, J, S, b, e_start, e_stop) + + nEqn = len(b) + # Construct the sparse matrix A + A = sparse.csr_matrix((S[:, 0], (I[:, 0], J[:, 0])), shape=(nEqn, N)) + + # Check connected pixels + for ind in range(0, len(pi), 1): + ii = pi[ind, 0] + jj = pj[ind, 0] + + # check up (3) + if ii - 1 >= 0: + if UnfilledMask_topleft[ii - 1, jj] == 0 and gradientMask[ii - 1, jj] == 0: + UnfilledMask_topleft[ii, jj] = 0 + # check left (2) + if jj - 1 >= 0: + if UnfilledMask_topleft[ii, jj - 1] == 0 and gradientMask[ii, jj - 1] == 0: + UnfilledMask_topleft[ii, jj] = 0 + + + for ind in range(len(pi) - 1, -1, -1): + ii = pi[ind, 0] + jj = pj[ind, 0] + + # check bottom (1) + if ii + 1 <= imgH - 1: + if UnfilledMask_bottomright[ii + 1, jj] == 0 and gradientMask[ii, jj] == 0: + UnfilledMask_bottomright[ii, jj] = 0 + # check right (0) + if jj + 1 <= imgW - 1: + if UnfilledMask_bottomright[ii, jj + 1] == 0 and gradientMask[ii, jj] == 0: + UnfilledMask_bottomright[ii, jj] = 0 + + UnfilledMask = UnfilledMask_topleft * UnfilledMask_bottomright + + return A, b, UnfilledMask + + +def constructEquation(n, validN, holeMask, gradientMask, edge, imgSrc_gx, imgSrc_gy, imgTrg, pi, pj, pind, qi, qj, qind, I, J, S, b, e_start, e_stop): + + # Pixel that has valid neighbors + validNeighbor = validN[:, n] + + # Change the out-of-boundary value to 0, in order to run edge[y,x] + # in the next line. It won't affect anything as validNeighbor is saved already + + qi_tmp = copy.deepcopy(qi) + qj_tmp = copy.deepcopy(qj) + qi_tmp[np.invert(validNeighbor), n] = 0 + qj_tmp[np.invert(validNeighbor), n] = 0 + + NotEdge = (edge[pi[:, 0], pj[:, 0]] == 0) * (edge[qi_tmp[:, n], qj_tmp[:, n]] == 0) + + # Have gradient + if n == 0: + HaveGrad = gradientMask[pi[:, 0], pj[:, 0]] == 0 + elif n == 2: + HaveGrad = gradientMask[pi[:, 0], pj[:, 0] - 1] == 0 + elif n == 1: + HaveGrad = gradientMask[pi[:, 0], pj[:, 0]] == 0 + elif n == 3: + HaveGrad = gradientMask[pi[:, 0] - 1, pj[:, 0]] == 0 + + # Boundary constraint + Boundary = holeMask[qi_tmp[:, n], qj_tmp[:, n]] == 0 + + valid = validNeighbor * NotEdge * HaveGrad * Boundary + + J_tmp = pind[valid, :] + + # num of equations: len(J_tmp) + e_stop = e_start + len(J_tmp) + I_tmp = np.arange(e_start, e_stop, dtype=np.float32).reshape(-1, 1) + e_start = e_stop + + S_tmp = np.ones(J_tmp.shape, dtype=np.float32) + + if n == 0: + b_tmp = - imgSrc_gx[pi[valid, 0], pj[valid, 0], :] + imgTrg[qi[valid, n], qj[valid, n], :] + elif n == 2: + b_tmp = imgSrc_gx[pi[valid, 0], pj[valid, 0] - 1, :] + imgTrg[qi[valid, n], qj[valid, n], :] + elif n == 1: + b_tmp = - imgSrc_gy[pi[valid, 0], pj[valid, 0], :] + imgTrg[qi[valid, n], qj[valid, n], :] + elif n == 3: + b_tmp = imgSrc_gy[pi[valid, 0] - 1, pj[valid, 0], :] + imgTrg[qi[valid, n], qj[valid, n], :] + + I = np.concatenate((I, I_tmp)) + J = np.concatenate((J, J_tmp)) + S = np.concatenate((S, S_tmp)) + b = np.concatenate((b, b_tmp)) + + # Non-boundary constraint + NonBoundary = holeMask[qi_tmp[:, n], qj_tmp[:, n]] == 1 + valid = validNeighbor * NotEdge * HaveGrad * NonBoundary + + J_tmp = pind[valid, :] + + # num of equations: len(J_tmp) + e_stop = e_start + len(J_tmp) + I_tmp = np.arange(e_start, e_stop, dtype=np.float32).reshape(-1, 1) + e_start = e_stop + + S_tmp = np.ones(J_tmp.shape, dtype=np.float32) + + if n == 0: + b_tmp = - imgSrc_gx[pi[valid, 0], pj[valid, 0], :] + elif n == 2: + b_tmp = imgSrc_gx[pi[valid, 0], pj[valid, 0] - 1, :] + elif n == 1: + b_tmp = - imgSrc_gy[pi[valid, 0], pj[valid, 0], :] + elif n == 3: + b_tmp = imgSrc_gy[pi[valid, 0] - 1, pj[valid, 0], :] + + I = np.concatenate((I, I_tmp)) + J = np.concatenate((J, J_tmp)) + S = np.concatenate((S, S_tmp)) + b = np.concatenate((b, b_tmp)) + + S_tmp = - np.ones(J_tmp.shape, dtype=np.float32) + J_tmp = qind[valid, n, None] + + I = np.concatenate((I, I_tmp)) + J = np.concatenate((J, J_tmp)) + S = np.concatenate((S, S_tmp)) + + return I, J, S, b, e_start, e_stop + + +def getUnfilledMask(holeMask, gradientMask): + # UnfilledMask indicates the region that is not completed + UnfilledMask_topleft = copy.deepcopy(holeMask) + UnfilledMask_bottomright = copy.deepcopy(holeMask) + + # Get the shape information of the mask + imgH, imgW = holeMask.shape + + # Precompute the unknown pixel position + pi = np.expand_dims(np.where(holeMask == 1)[0], axis=1) + pj = np.expand_dims(np.where(holeMask == 1)[1], axis=1) + + # Check connected pixels + for ind in range(0, len(pi), 1): + ii = pi[ind, 0] + jj = pj[ind, 0] + + # check up (3) + if ii - 1 >= 0: + if UnfilledMask_topleft[ii - 1, jj] == 0 and gradientMask[ii - 1, jj] == 0: + UnfilledMask_topleft[ii, jj] = 0 + # check left (2) + if jj - 1 >= 0: + if UnfilledMask_topleft[ii, jj - 1] == 0 and gradientMask[ii, jj - 1] == 0: + UnfilledMask_topleft[ii, jj] = 0 + + for ind in range(len(pi) - 1, -1, -1): + ii = pi[ind, 0] + jj = pj[ind, 0] + + # check bottom (1) + if ii + 1 <= imgH - 1: + if UnfilledMask_bottomright[ii + 1, jj] == 0 and gradientMask[ii, jj] == 0: + UnfilledMask_bottomright[ii, jj] = 0 + # check right (0) + if jj + 1 <= imgW - 1: + if UnfilledMask_bottomright[ii, jj + 1] == 0 and gradientMask[ii, jj] == 0: + UnfilledMask_bottomright[ii, jj] = 0 + + UnfilledMask = UnfilledMask_topleft * UnfilledMask_bottomright + + return UnfilledMask diff --git a/FGT_codes/tool/utils/__init__.py b/FGT_codes/tool/utils/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..a91473dd975fc090e378aa11c6bc122e579605fc --- /dev/null +++ b/FGT_codes/tool/utils/__init__.py @@ -0,0 +1 @@ +from . import region_fill \ No newline at end of file diff --git a/FGT_codes/tool/utils/__pycache__/Poisson_blend_img.cpython-39.pyc b/FGT_codes/tool/utils/__pycache__/Poisson_blend_img.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ec976bbc7402fb0e6101f52c67671b64c961d924 Binary files /dev/null and b/FGT_codes/tool/utils/__pycache__/Poisson_blend_img.cpython-39.pyc differ diff --git a/FGT_codes/tool/utils/__pycache__/__init__.cpython-39.pyc b/FGT_codes/tool/utils/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e41042b44202066c5a0bcf30748658addc95debe Binary files /dev/null and b/FGT_codes/tool/utils/__pycache__/__init__.cpython-39.pyc differ diff --git a/FGT_codes/tool/utils/__pycache__/common_utils.cpython-39.pyc b/FGT_codes/tool/utils/__pycache__/common_utils.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..43b6b6ef911c143da82f6dd1fc16a0659e4e9def Binary files /dev/null and b/FGT_codes/tool/utils/__pycache__/common_utils.cpython-39.pyc differ diff --git a/FGT_codes/tool/utils/__pycache__/region_fill.cpython-39.pyc b/FGT_codes/tool/utils/__pycache__/region_fill.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5e590146e902425b5b161679f984e15da90cc69f Binary files /dev/null and b/FGT_codes/tool/utils/__pycache__/region_fill.cpython-39.pyc differ diff --git a/FGT_codes/tool/utils/common_utils.py b/FGT_codes/tool/utils/common_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..7836cf3ba31cca4ac131ad3e5b804bb6e6d420be --- /dev/null +++ b/FGT_codes/tool/utils/common_utils.py @@ -0,0 +1,613 @@ +from __future__ import absolute_import, division, print_function, unicode_literals +import torch +import torch.nn as nn +import cv2 +import copy +import numpy as np +import sys +import os +import time +from PIL import Image +import scipy.ndimage + + +def combine(img1, img2, slope=0.55, band_width=0.015, offset=0): + + imgH, imgW, _ = img1.shape + band_width = int(band_width * imgH) + + if img1.shape != img2.shape: + # img1 = cv2.resize(img1, (imgW, imgH)) + raise NameError('Shape does not match') + + center_point = (int(imgH / 2), int(imgW / 2 + offset)) + + b = (center_point[1] - 1) - slope * (center_point[0] - 1) + comp_img = np.zeros(img2.shape, dtype=np.float32) + + for x in range(imgH): + for y in range(imgW): + if y < (slope * x + b): + comp_img[x, y, :] = img1[x, y, :] + elif y > (slope * x + b): + comp_img[x, y, :] = img2[x, y, :] + + start_point = (int(b - 0.5 * band_width), 0) + end_point = (int(slope * (imgW - 1) + b - 0.5 * band_width), imgW - 1) + + color = (1, 1, 1) + comp_img = cv2.line(comp_img, start_point, end_point, color, band_width, lineType=cv2.LINE_AA) + + return comp_img + + +def save_video(in_dir, out_dir, optimize=False): + + _, ext = os.path.splitext(sorted(os.listdir(in_dir))[0]) + dir = '"' + os.path.join(in_dir, '*' + ext) + '"' + + if optimize: + os.system('ffmpeg -y -pattern_type glob -f image2 -i {} -pix_fmt yuv420p -preset veryslow -crf 27 {}'.format(dir, out_dir)) + else: + os.system('ffmpeg -y -pattern_type glob -f image2 -i {} -pix_fmt yuv420p {}'.format(dir, out_dir)) + +def create_dir(dir): + if not os.path.exists(dir): + os.makedirs(dir) + + +def bboxes_mask(imgH, imgW, type='ori'): + mask = np.zeros((imgH, imgW), dtype=np.float32) + factor = 1920 * 2 // imgW + + for indFrameH in range(int(imgH / (256 * 2 // factor))): + for indFrameW in range(int(imgW / (384 * 2 // factor))): + mask[indFrameH * (256 * 2 // factor) + (128 * 2 // factor) - (64 * 2 // factor) : + indFrameH * (256 * 2 // factor) + (128 * 2 // factor) + (64 * 2 // factor), + indFrameW * (384 * 2 // factor) + (192 * 2 // factor) - (64 * 2 // factor) : + indFrameW * (384 * 2 // factor) + (192 * 2 // factor) + (64 * 2 // factor)] = 1 + + if type == 'ori': + return mask + elif type == 'flow': + # Dilate 25 pixel so that all known pixel is trustworthy + return scipy.ndimage.binary_dilation(mask, iterations=15) + +def bboxes_mask_large(imgH, imgW, type='ori'): + mask = np.zeros((imgH, imgW), dtype=np.float32) + # mask[50 : 450, 280: 680] = 1 + mask[150 : 350, 350: 650] = 1 + + if type == 'ori': + return mask + elif type == 'flow': + # Dilate 35 pixel so that all known pixel is trustworthy + return scipy.ndimage.binary_dilation(mask, iterations=35) + +def gradient_mask(mask): + + gradient_mask = np.logical_or.reduce((mask, + np.concatenate((mask[1:, :], np.zeros((1, mask.shape[1]), dtype=np.bool)), axis=0), + np.concatenate((mask[:, 1:], np.zeros((mask.shape[0], 1), dtype=np.bool)), axis=1))) + + return gradient_mask + + +def flow_edge(flow, mask=None): + # mask: 1 indicates the missing region + if not isinstance(mask, np.ndarray): + mask = None + else: + # using 'mask' parameter prevents canny to detect edges for the masked regions + mask = (1 - mask).astype(np.bool) + + flow_mag = (flow[:, :, 0] ** 2 + flow[:, :, 1] ** 2) ** 0.5 + flow_mag = flow_mag / flow_mag.max() + + edge_canny_flow = canny_flow(flow_mag, flow, mask=mask) + edge_canny = canny(flow_mag, sigma=2, mask=mask) + + if edge_canny_flow.sum() > edge_canny.sum(): + return edge_canny_flow + else: + return edge_canny + + +def np_to_torch(img_np): + '''Converts image in numpy.array to torch.Tensor. + From C x W x H [0..1] to C x W x H [0..1] + ''' + return torch.from_numpy(img_np)[None, :] + + +def torch_to_np(img_var): + '''Converts an image in torch.Tensor format to np.array. + From 1 x C x W x H [0..1] to C x W x H [0..1] + ''' + return img_var.detach().cpu().numpy()[0] + + +def sigmoid_(x, thres): + return 1. / (1 + np.exp(-x + thres)) + + +# def softmax(x): +# e_x = np.exp(x - np.max(x)) +# return e_x / e_x.sum() + + +def softmax(x, axis=None, mask_=None): + + if mask_ is None: + mask_ = np.ones(x.shape) + x = (x - x.max(axis=axis, keepdims=True)) + y = np.multiply(np.exp(x), mask_) + return y / y.sum(axis=axis, keepdims=True) + + +# Bypass cv2's SHRT_MAX limitation +def interp(img, x, y): + + x = x.astype(np.float32).reshape(1, -1) + y = y.astype(np.float32).reshape(1, -1) + + assert(x.shape == y.shape) + + numPix = x.shape[1] + len_padding = (numPix // 1024 + 1) * 1024 - numPix + padding = np.zeros((1, len_padding)).astype(np.float32) + + map_x = np.concatenate((x, padding), axis=1).reshape(1024, numPix // 1024 + 1) + map_y = np.concatenate((y, padding), axis=1).reshape(1024, numPix // 1024 + 1) + + # Note that cv2 takes the input in opposite order, i.e. cv2.remap(img, x, y) + mapped_img = cv2.remap(img, map_x, map_y, cv2.INTER_LINEAR) + + if len(img.shape) == 2: + mapped_img = mapped_img.reshape(-1)[:numPix] + else: + mapped_img = mapped_img.reshape(-1, img.shape[2])[:numPix, :] + + return mapped_img + + +def imsave(img, path): + im = Image.fromarray(img.cpu().numpy().astype(np.uint8).squeeze()) + im.save(path) + + +def postprocess(img): + # [0, 1] => [0, 255] + img = img * 255.0 + img = img.permute(0, 2, 3, 1) + return img.int() + + +# Backward flow propagating and forward flow propagating consistency check +def BFconsistCheck(flowB_neighbor, flowF_vertical, flowF_horizont, + holepixPos, consistencyThres): + + flowBF_neighbor = copy.deepcopy(flowB_neighbor) + + # After the backward and forward propagation, the pixel should go back + # to the original location. + flowBF_neighbor[:, 0] += interp(flowF_vertical, + flowB_neighbor[:, 1], + flowB_neighbor[:, 0]) + flowBF_neighbor[:, 1] += interp(flowF_horizont, + flowB_neighbor[:, 1], + flowB_neighbor[:, 0]) + flowBF_neighbor[:, 2] += 1 + + # Check photometric consistency + BFdiff = ((flowBF_neighbor - holepixPos)[:, 0] ** 2 + + (flowBF_neighbor - holepixPos)[:, 1] ** 2) ** 0.5 + IsConsist = BFdiff < consistencyThres + + return IsConsist, BFdiff + + +# Forward flow propagating and backward flow propagating consistency check +def FBconsistCheck(flowF_neighbor, flowB_vertical, flowB_horizont, + holepixPos, consistencyThres): + + flowFB_neighbor = copy.deepcopy(flowF_neighbor) + + # After the forward and backward propagation, the pixel should go back + # to the original location. + flowFB_neighbor[:, 0] += interp(flowB_vertical, + flowF_neighbor[:, 1], + flowF_neighbor[:, 0]) + flowFB_neighbor[:, 1] += interp(flowB_horizont, + flowF_neighbor[:, 1], + flowF_neighbor[:, 0]) + flowFB_neighbor[:, 2] -= 1 + + # Check photometric consistency + FBdiff = ((flowFB_neighbor - holepixPos)[:, 0] ** 2 + + (flowFB_neighbor - holepixPos)[:, 1] ** 2) ** 0.5 + IsConsist = FBdiff < consistencyThres + + return IsConsist, FBdiff + + +def consistCheck(flowF, flowB): + + # |--------------------| |--------------------| + # | y | | v | + # | x * | | u * | + # | | | | + # |--------------------| |--------------------| + + # sub: numPix * [y x t] + + imgH, imgW, _ = flowF.shape + + (fy, fx) = np.mgrid[0 : imgH, 0 : imgW].astype(np.float32) + fxx = fx + flowB[:, :, 0] # horizontal + fyy = fy + flowB[:, :, 1] # vertical + + u = (fxx + cv2.remap(flowF[:, :, 0], fxx, fyy, cv2.INTER_LINEAR) - fx) + v = (fyy + cv2.remap(flowF[:, :, 1], fxx, fyy, cv2.INTER_LINEAR) - fy) + BFdiff = (u ** 2 + v ** 2) ** 0.5 + + return BFdiff, np.stack((u, v), axis=2) + + +def get_KeySourceFrame_flowNN(sub, + indFrame, + mask, + videoNonLocalFlowB, + videoNonLocalFlowF, + video, + consistencyThres): + + imgH, imgW, _, _, nFrame = videoNonLocalFlowF.shape + KeySourceFrame = [0, nFrame // 2, nFrame - 1] + + # Bool indicator of missing pixels at frame t + holepixPosInd = (sub[:, 2] == indFrame) + + # Hole pixel location at frame t, i.e. [x, y, t] + holepixPos = sub[holepixPosInd, :] + + HaveKeySourceFrameFlowNN = np.zeros((imgH, imgW, 3)) + imgKeySourceFrameFlowNN = np.zeros((imgH, imgW, 3, 3)) + + for KeySourceFrameIdx in range(3): + + # flowF_neighbor + flowF_neighbor = copy.deepcopy(holepixPos) + flowF_neighbor = flowF_neighbor.astype(np.float32) + flowF_vertical = videoNonLocalFlowF[:, :, 1, KeySourceFrameIdx, indFrame] + flowF_horizont = videoNonLocalFlowF[:, :, 0, KeySourceFrameIdx, indFrame] + flowB_vertical = videoNonLocalFlowB[:, :, 1, KeySourceFrameIdx, indFrame] + flowB_horizont = videoNonLocalFlowB[:, :, 0, KeySourceFrameIdx, indFrame] + + flowF_neighbor[:, 0] += flowF_vertical[holepixPos[:, 0], holepixPos[:, 1]] + flowF_neighbor[:, 1] += flowF_horizont[holepixPos[:, 0], holepixPos[:, 1]] + flowF_neighbor[:, 2] = KeySourceFrame[KeySourceFrameIdx] + + # Round the forward flow neighbor location + flow_neighbor_int = np.round(copy.deepcopy(flowF_neighbor)).astype(np.int32) + + # Check the forawrd/backward consistency + IsConsist, _ = FBconsistCheck(flowF_neighbor, flowB_vertical, + flowB_horizont, holepixPos, consistencyThres) + + # Check out-of-boundary + ValidPos = np.logical_and( + np.logical_and(flow_neighbor_int[:, 0] >= 0, + flow_neighbor_int[:, 0] < imgH), + np.logical_and(flow_neighbor_int[:, 1] >= 0, + flow_neighbor_int[:, 1] < imgW)) + + holepixPos_ = copy.deepcopy(holepixPos)[ValidPos, :] + flow_neighbor_int = flow_neighbor_int[ValidPos, :] + flowF_neighbor = flowF_neighbor[ValidPos, :] + IsConsist = IsConsist[ValidPos] + + KnownInd = mask[flow_neighbor_int[:, 0], + flow_neighbor_int[:, 1], + KeySourceFrame[KeySourceFrameIdx]] == 0 + + KnownInd = np.logical_and(KnownInd, IsConsist) + + imgKeySourceFrameFlowNN[:, :, :, KeySourceFrameIdx] = \ + copy.deepcopy(video[:, :, :, indFrame]) + + imgKeySourceFrameFlowNN[holepixPos_[KnownInd, 0], + holepixPos_[KnownInd, 1], + :, KeySourceFrameIdx] = \ + interp(video[:, :, :, KeySourceFrame[KeySourceFrameIdx]], + flowF_neighbor[KnownInd, 1].reshape(-1), + flowF_neighbor[KnownInd, 0].reshape(-1)) + + HaveKeySourceFrameFlowNN[holepixPos_[KnownInd, 0], + holepixPos_[KnownInd, 1], + KeySourceFrameIdx] = 1 + + return HaveKeySourceFrameFlowNN, imgKeySourceFrameFlowNN +# +def get_KeySourceFrame_flowNN_gradient(sub, + indFrame, + mask, + videoNonLocalFlowB, + videoNonLocalFlowF, + gradient_x, + gradient_y, + consistencyThres): + + imgH, imgW, _, _, nFrame = videoNonLocalFlowF.shape + KeySourceFrame = [0, nFrame // 2, nFrame - 1] + + # Bool indicator of missing pixels at frame t + holepixPosInd = (sub[:, 2] == indFrame) + + # Hole pixel location at frame t, i.e. [x, y, t] + holepixPos = sub[holepixPosInd, :] + + HaveKeySourceFrameFlowNN = np.zeros((imgH, imgW, 3)) + gradient_x_KeySourceFrameFlowNN = np.zeros((imgH, imgW, 3, 3)) + gradient_y_KeySourceFrameFlowNN = np.zeros((imgH, imgW, 3, 3)) + + for KeySourceFrameIdx in range(3): + + # flowF_neighbor + flowF_neighbor = copy.deepcopy(holepixPos) + flowF_neighbor = flowF_neighbor.astype(np.float32) + + flowF_vertical = videoNonLocalFlowF[:, :, 1, KeySourceFrameIdx, indFrame] + flowF_horizont = videoNonLocalFlowF[:, :, 0, KeySourceFrameIdx, indFrame] + flowB_vertical = videoNonLocalFlowB[:, :, 1, KeySourceFrameIdx, indFrame] + flowB_horizont = videoNonLocalFlowB[:, :, 0, KeySourceFrameIdx, indFrame] + + flowF_neighbor[:, 0] += flowF_vertical[holepixPos[:, 0], holepixPos[:, 1]] + flowF_neighbor[:, 1] += flowF_horizont[holepixPos[:, 0], holepixPos[:, 1]] + flowF_neighbor[:, 2] = KeySourceFrame[KeySourceFrameIdx] + + # Round the forward flow neighbor location + flow_neighbor_int = np.round(copy.deepcopy(flowF_neighbor)).astype(np.int32) + + # Check the forawrd/backward consistency + IsConsist, _ = FBconsistCheck(flowF_neighbor, flowB_vertical, + flowB_horizont, holepixPos, consistencyThres) + + # Check out-of-boundary + ValidPos = np.logical_and( + np.logical_and(flow_neighbor_int[:, 0] >= 0, + flow_neighbor_int[:, 0] < imgH - 1), + np.logical_and(flow_neighbor_int[:, 1] >= 0, + flow_neighbor_int[:, 1] < imgW - 1)) + + holepixPos_ = copy.deepcopy(holepixPos)[ValidPos, :] + flow_neighbor_int = flow_neighbor_int[ValidPos, :] + flowF_neighbor = flowF_neighbor[ValidPos, :] + IsConsist = IsConsist[ValidPos] + + KnownInd = mask[flow_neighbor_int[:, 0], + flow_neighbor_int[:, 1], + KeySourceFrame[KeySourceFrameIdx]] == 0 + + KnownInd = np.logical_and(KnownInd, IsConsist) + + gradient_x_KeySourceFrameFlowNN[:, :, :, KeySourceFrameIdx] = \ + copy.deepcopy(gradient_x[:, :, :, indFrame]) + gradient_y_KeySourceFrameFlowNN[:, :, :, KeySourceFrameIdx] = \ + copy.deepcopy(gradient_y[:, :, :, indFrame]) + + gradient_x_KeySourceFrameFlowNN[holepixPos_[KnownInd, 0], + holepixPos_[KnownInd, 1], + :, KeySourceFrameIdx] = \ + interp(gradient_x[:, :, :, KeySourceFrame[KeySourceFrameIdx]], + flowF_neighbor[KnownInd, 1].reshape(-1), + flowF_neighbor[KnownInd, 0].reshape(-1)) + + gradient_y_KeySourceFrameFlowNN[holepixPos_[KnownInd, 0], + holepixPos_[KnownInd, 1], + :, KeySourceFrameIdx] = \ + interp(gradient_y[:, :, :, KeySourceFrame[KeySourceFrameIdx]], + flowF_neighbor[KnownInd, 1].reshape(-1), + flowF_neighbor[KnownInd, 0].reshape(-1)) + + HaveKeySourceFrameFlowNN[holepixPos_[KnownInd, 0], + holepixPos_[KnownInd, 1], + KeySourceFrameIdx] = 1 + + return HaveKeySourceFrameFlowNN, gradient_x_KeySourceFrameFlowNN, gradient_y_KeySourceFrameFlowNN + +class Progbar(object): + """Displays a progress bar. + + Arguments: + target: Total number of steps expected, None if unknown. + width: Progress bar width on screen. + verbose: Verbosity mode, 0 (silent), 1 (verbose), 2 (semi-verbose) + stateful_metrics: Iterable of string names of metrics that + should *not* be averaged over time. Metrics in this list + will be displayed as-is. All others will be averaged + by the progbar before display. + interval: Minimum visual progress update interval (in seconds). + """ + + def __init__(self, target, width=25, verbose=1, interval=0.05, + stateful_metrics=None): + self.target = target + self.width = width + self.verbose = verbose + self.interval = interval + if stateful_metrics: + self.stateful_metrics = set(stateful_metrics) + else: + self.stateful_metrics = set() + + self._dynamic_display = ((hasattr(sys.stdout, 'isatty') and + sys.stdout.isatty()) or + 'ipykernel' in sys.modules or + 'posix' in sys.modules) + self._total_width = 0 + self._seen_so_far = 0 + # We use a dict + list to avoid garbage collection + # issues found in OrderedDict + self._values = {} + self._values_order = [] + self._start = time.time() + self._last_update = 0 + + def update(self, current, values=None): + """Updates the progress bar. + + Arguments: + current: Index of current step. + values: List of tuples: + `(name, value_for_last_step)`. + If `name` is in `stateful_metrics`, + `value_for_last_step` will be displayed as-is. + Else, an average of the metric over time will be displayed. + """ + values = values or [] + for k, v in values: + if k not in self._values_order: + self._values_order.append(k) + if k not in self.stateful_metrics: + if k not in self._values: + self._values[k] = [v * (current - self._seen_so_far), + current - self._seen_so_far] + else: + self._values[k][0] += v * (current - self._seen_so_far) + self._values[k][1] += (current - self._seen_so_far) + else: + self._values[k] = v + self._seen_so_far = current + + now = time.time() + info = ' - %.0fs' % (now - self._start) + if self.verbose == 1: + if (now - self._last_update < self.interval and + self.target is not None and current < self.target): + return + + prev_total_width = self._total_width + if self._dynamic_display: + sys.stdout.write('\b' * prev_total_width) + sys.stdout.write('\r') + else: + sys.stdout.write('\n') + + if self.target is not None: + numdigits = int(np.floor(np.log10(self.target))) + 1 + barstr = '%%%dd/%d [' % (numdigits, self.target) + bar = barstr % current + prog = float(current) / self.target + prog_width = int(self.width * prog) + if prog_width > 0: + bar += ('=' * (prog_width - 1)) + if current < self.target: + bar += '>' + else: + bar += '=' + bar += ('.' * (self.width - prog_width)) + bar += ']' + else: + bar = '%7d/Unknown' % current + + self._total_width = len(bar) + sys.stdout.write(bar) + + if current: + time_per_unit = (now - self._start) / current + else: + time_per_unit = 0 + if self.target is not None and current < self.target: + eta = time_per_unit * (self.target - current) + if eta > 3600: + eta_format = '%d:%02d:%02d' % (eta // 3600, + (eta % 3600) // 60, + eta % 60) + elif eta > 60: + eta_format = '%d:%02d' % (eta // 60, eta % 60) + else: + eta_format = '%ds' % eta + + info = ' - ETA: %s' % eta_format + else: + if time_per_unit >= 1: + info += ' %.0fs/step' % time_per_unit + elif time_per_unit >= 1e-3: + info += ' %.0fms/step' % (time_per_unit * 1e3) + else: + info += ' %.0fus/step' % (time_per_unit * 1e6) + + for k in self._values_order: + info += ' - %s:' % k + if isinstance(self._values[k], list): + avg = np.mean(self._values[k][0] / max(1, self._values[k][1])) + if abs(avg) > 1e-3: + info += ' %.4f' % avg + else: + info += ' %.4e' % avg + else: + info += ' %s' % self._values[k] + + self._total_width += len(info) + if prev_total_width > self._total_width: + info += (' ' * (prev_total_width - self._total_width)) + + if self.target is not None and current >= self.target: + info += '\n' + + sys.stdout.write(info) + sys.stdout.flush() + + elif self.verbose == 2: + if self.target is None or current >= self.target: + for k in self._values_order: + info += ' - %s:' % k + avg = np.mean(self._values[k][0] / max(1, self._values[k][1])) + if avg > 1e-3: + info += ' %.4f' % avg + else: + info += ' %.4e' % avg + info += '\n' + + sys.stdout.write(info) + sys.stdout.flush() + + self._last_update = now + + def add(self, n, values=None): + self.update(self._seen_so_far + n, values) + + +class PSNR(nn.Module): + def __init__(self, max_val): + super(PSNR, self).__init__() + + base10 = torch.log(torch.tensor(10.0)) + max_val = torch.tensor(max_val).float() + + self.register_buffer('base10', base10) + self.register_buffer('max_val', 20 * torch.log(max_val) / base10) + + def __call__(self, a, b): + mse = torch.mean((a.float() - b.float()) ** 2) + + if mse == 0: + return torch.tensor(0) + + return self.max_val - 10 * torch.log(mse) / self.base10 +# Get surrounding integer postiion +def IntPos(CurPos): + + x_floor = np.expand_dims(np.floor(CurPos[:, 0]).astype(np.int32), 1) + x_ceil = np.expand_dims(np.ceil(CurPos[:, 0]).astype(np.int32), 1) + y_floor = np.expand_dims(np.floor(CurPos[:, 1]).astype(np.int32), 1) + y_ceil = np.expand_dims(np.ceil(CurPos[:, 1]).astype(np.int32), 1) + Fm = np.expand_dims(np.floor(CurPos[:, 2]).astype(np.int32), 1) + + Pos_tl = np.concatenate((x_floor, y_floor, Fm), 1) + Pos_tr = np.concatenate((x_ceil, y_floor, Fm), 1) + Pos_bl = np.concatenate((x_floor, y_ceil, Fm), 1) + Pos_br = np.concatenate((x_ceil, y_ceil, Fm), 1) + + return Pos_tl, Pos_tr, Pos_bl, Pos_br diff --git a/FGT_codes/tool/utils/region_fill.py b/FGT_codes/tool/utils/region_fill.py new file mode 100644 index 0000000000000000000000000000000000000000..89ca0ddd3ea652cc31c149087799908387da822b --- /dev/null +++ b/FGT_codes/tool/utils/region_fill.py @@ -0,0 +1,126 @@ +import numpy as np +import cv2 +from scipy import sparse +from scipy.sparse.linalg import spsolve + + +def regionfill(I, mask, factor=1.0): # I -> flow, mask -> flow mask + if np.count_nonzero(mask) == 0: + return I.copy() # All of the regions in mask has been filled + resize_mask = cv2.resize( + mask.astype(float), (0, 0), fx=factor, fy=factor) > 0 + resize_I = cv2.resize(I.astype(float), (0, 0), fx=factor, fy=factor) + maskPerimeter = findBoundaryPixels(resize_mask) # boundary pixels in the resized mask + regionfillLaplace(resize_I, resize_mask, maskPerimeter) + resize_I = cv2.resize(resize_I, (I.shape[1], I.shape[0])) + resize_I[mask == 0] = I[mask == 0] + return resize_I + + +def findBoundaryPixels(mask): + kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (3, 3)) + maskDilated = cv2.dilate(mask.astype(float), kernel) + return (maskDilated > 0) & (mask == 0) + + +def regionfillLaplace(I, mask, maskPerimeter): + height, width = I.shape + rightSide = formRightSide(I, maskPerimeter) + + # Location of mask pixels + maskIdx = np.where(mask) + + # Only keep values for pixels that are in the mask + rightSide = rightSide[maskIdx] + + # Number the mask pixels in a grid matrix + grid = -np.ones((height, width)) + grid[maskIdx] = range(0, maskIdx[0].size) + # Pad with zeros to avoid "index out of bounds" errors in the for loop + grid = padMatrix(grid) + gridIdx = np.where(grid >= 0) + + # Form the connectivity matrix D=sparse(i,j,s) + # Connect each mask pixel to itself + i = np.arange(0, maskIdx[0].size) + j = np.arange(0, maskIdx[0].size) + # The coefficient is the number of neighbors over which we average + numNeighbors = computeNumberOfNeighbors(height, width) + s = numNeighbors[maskIdx] + # Now connect the N,E,S,W neighbors if they exist + for direction in ((-1, 0), (0, 1), (1, 0), (0, -1)): + # Possible neighbors in the current direction + neighbors = grid[gridIdx[0] + direction[0], gridIdx[1] + direction[1]] + # ConDnect mask points to neighbors with -1's + index = (neighbors >= 0) + i = np.concatenate((i, grid[gridIdx[0][index], gridIdx[1][index]])) + j = np.concatenate((j, neighbors[index])) + s = np.concatenate((s, -np.ones(np.count_nonzero(index)))) + + D = sparse.coo_matrix((s, (i.astype(int), j.astype(int)))).tocsr() + sol = spsolve(D, rightSide) + I[maskIdx] = sol + return I + + +def formRightSide(I, maskPerimeter): + height, width = I.shape + perimeterValues = np.zeros((height, width)) + assert perimeterValues.shape == I.shape, 'P shape: {}, I shape: {}'.format(perimeterValues.shape, I.shape) + perimeterValues[maskPerimeter] = I[maskPerimeter] + rightSide = np.zeros((height, width)) + + rightSide[1:height - 1, 1:width - 1] = ( + perimeterValues[0:height - 2, 1:width - 1] + + perimeterValues[2:height, 1:width - 1] + + perimeterValues[1:height - 1, 0:width - 2] + + perimeterValues[1:height - 1, 2:width]) + + rightSide[1:height - 1, 0] = ( + perimeterValues[0:height - 2, 0] + perimeterValues[2:height, 0] + + perimeterValues[1:height - 1, 1]) + + rightSide[1:height - 1, width - 1] = ( + perimeterValues[0:height - 2, width - 1] + + perimeterValues[2:height, width - 1] + + perimeterValues[1:height - 1, width - 2]) + + rightSide[0, 1:width - 1] = ( + perimeterValues[1, 1:width - 1] + perimeterValues[0, 0:width - 2] + + perimeterValues[0, 2:width]) + + rightSide[height - 1, 1:width - 1] = ( + perimeterValues[height - 2, 1:width - 1] + + perimeterValues[height - 1, 0:width - 2] + + perimeterValues[height - 1, 2:width]) + + rightSide[0, 0] = perimeterValues[0, 1] + perimeterValues[1, 0] + rightSide[0, width - 1] = ( + perimeterValues[0, width - 2] + perimeterValues[1, width - 1]) + rightSide[height - 1, 0] = ( + perimeterValues[height - 2, 0] + perimeterValues[height - 1, 1]) + rightSide[height - 1, width - 1] = (perimeterValues[height - 2, width - 1] + + perimeterValues[height - 1, width - 2]) + return rightSide + + +def computeNumberOfNeighbors(height, width): + # Initialize + numNeighbors = np.zeros((height, width)) + # Interior pixels have 4 neighbors + numNeighbors[1:height - 1, 1:width - 1] = 4 + # Border pixels have 3 neighbors + numNeighbors[1:height - 1, (0, width - 1)] = 3 + numNeighbors[(0, height - 1), 1:width - 1] = 3 + # Corner pixels have 2 neighbors + numNeighbors[(0, 0, height - 1, height - 1), (0, width - 1, 0, + width - 1)] = 2 + return numNeighbors + + +def padMatrix(grid): + height, width = grid.shape + gridPadded = -np.ones((height + 2, width + 2)) + gridPadded[1:height + 1, 1:width + 1] = grid + gridPadded = gridPadded.astype(grid.dtype) + return gridPadded diff --git a/FGT_codes/tool/video_inpainting.py b/FGT_codes/tool/video_inpainting.py new file mode 100644 index 0000000000000000000000000000000000000000..82b59023cf98951c56a3aa1fff052146e7b58bc5 --- /dev/null +++ b/FGT_codes/tool/video_inpainting.py @@ -0,0 +1,748 @@ +import cvbase +from torchvision.transforms import ToTensor +from get_flowNN_gradient import get_flowNN_gradient +from utils.Poisson_blend_img import Poisson_blend_img +from utils.region_fill import regionfill +from importlib import import_module +import yaml +from RAFT import RAFT +from RAFT import utils +import torch.nn.functional as F2 +import torchvision.transforms.functional as F +from skimage.feature import canny +import scipy.ndimage +from PIL import Image +import imageio +import torch +import numpy as np +import copy +import glob +import cv2 +import argparse +import warnings +import os +import sys + +sys.path.append(os.path.abspath(os.path.join(__file__, '..', '..'))) +sys.path.append(os.path.abspath(os.path.join(__file__, '..', '..', 'tool'))) +sys.path.append(os.path.abspath(os.path.join( + __file__, '..', '..', 'tool', 'utils'))) +sys.path.append(os.path.abspath(os.path.join( + __file__, '..', '..', 'tool', 'utils', 'region_fill.py'))) +sys.path.append(os.path.abspath(os.path.join( + __file__, '..', '..', 'tool', 'utils', 'Poisson_blend_img.py'))) +sys.path.append(os.path.abspath(os.path.join(__file__, '..', '..', 'FGT'))) +sys.path.append(os.path.abspath(os.path.join(__file__, '..', '..', 'LAFC'))) +sys.path.append(os.path.abspath( + os.path.join(os.path.dirname("__file__"), '..'))) +warnings.filterwarnings("ignore") + + +def to_tensor(img): + img = Image.fromarray(img) + img_t = F.to_tensor(img).float() + return img_t + + +def diffusion(flows, masks): + flows_filled = [] + for i in range(flows.shape[0]): + flow, mask = flows[i], masks[i] + flow_filled = np.zeros(flow.shape) + flow_filled[:, :, 0] = regionfill(flow[:, :, 0], mask[:, :, 0]) + flow_filled[:, :, 1] = regionfill(flow[:, :, 1], mask[:, :, 0]) + flows_filled.append(flow_filled) + return flows_filled + + +def np2tensor(array, near='c'): + if isinstance(array, list): + array = np.stack(array, axis=0) # [t, h, w, c] + if near == 'c': + array = torch.from_numpy(np.transpose(array, (3, 0, 1, 2))).unsqueeze( + 0).float() # [1, c, t, h, w] + elif near == 't': + array = torch.from_numpy(np.transpose( + array, (0, 3, 1, 2))).unsqueeze(0).float() + else: + raise ValueError(f'Unknown near type: {near}') + return array + + +def tensor2np(array): + array = torch.stack(array, dim=-1).squeeze(0).permute(1, + 2, 0, 3).cpu().numpy() + return array + + +def gradient_mask(mask): + gradient_mask = np.logical_or.reduce((mask, + np.concatenate((mask[1:, :], np.zeros((1, mask.shape[1]), dtype=np.bool)), + axis=0), + np.concatenate((mask[:, 1:], np.zeros((mask.shape[0], 1), dtype=np.bool)), + axis=1))) + + return gradient_mask + + +def indicesGen(pivot, interval, frames, t): + singleSide = frames // 2 + results = [] + for i in range(-singleSide, singleSide + 1): + index = pivot + interval * i + if index < 0: + index = abs(index) + if index > t - 1: + index = 2 * (t - 1) - index + results.append(index) + return results + + +def get_ref_index(f, neighbor_ids, length, ref_length, num_ref): + ref_index = [] + if num_ref == -1: + for i in range(0, length, ref_length): + if i not in neighbor_ids: + ref_index.append(i) + else: + start_idx = max(0, f - ref_length * (num_ref // 2)) + end_idx = min(length, f + ref_length * (num_ref // 2)) + for i in range(start_idx, end_idx + 1, ref_length): + if i not in neighbor_ids: + if len(ref_index) > num_ref: + break + ref_index.append(i) + return ref_index + + +def save_flows(output, videoFlowF, videoFlowB): + create_dir(os.path.join(output, 'completed_flow', 'forward_flo')) + create_dir(os.path.join(output, 'completed_flow', 'backward_flo')) + create_dir(os.path.join(output, 'completed_flow', 'forward_png')) + create_dir(os.path.join(output, 'completed_flow', 'backward_png')) + N = videoFlowF.shape[-1] + for i in range(N): + forward_flow = videoFlowF[..., i] + backward_flow = videoFlowB[..., i] + forward_flow_vis = cvbase.flow2rgb(forward_flow) + backward_flow_vis = cvbase.flow2rgb(backward_flow) + cvbase.write_flow(forward_flow, os.path.join( + output, 'completed_flow', 'forward_flo', '{:05d}.flo'.format(i))) + cvbase.write_flow(backward_flow, os.path.join( + output, 'completed_flow', 'backward_flo', '{:05d}.flo'.format(i))) + imageio.imwrite(os.path.join(output, 'completed_flow', + 'forward_png', '{:05d}.png'.format(i)), forward_flow_vis) + imageio.imwrite(os.path.join(output, 'completed_flow', + 'backward_png', '{:05d}.png'.format(i)), backward_flow_vis) + + +def save_fgcp(output, frames, masks): + create_dir(os.path.join(output, 'prop_frames')) + create_dir(os.path.join(output, 'masks_left')) + create_dir(os.path.join(output, 'prop_frames_npy')) + create_dir(os.path.join(output, 'masks_left_npy')) + + assert len(frames) == masks.shape[2] + for i in range(len(frames)): + cv2.imwrite(os.path.join(output, 'prop_frames', + '%05d.png' % i), frames[i] * 255.) + cv2.imwrite(os.path.join(output, 'masks_left', '%05d.png' % + i), masks[:, :, i] * 255.) + np.save(os.path.join(output, 'prop_frames_npy', + '%05d.npy' % i), frames[i] * 255.) + np.save(os.path.join(output, 'masks_left_npy', + '%05d.npy' % i), masks[:, :, i] * 255.) + + +def create_dir(dir): + """Creates a directory if not exist. + """ + if not os.path.exists(dir): + os.makedirs(dir) + + +def initialize_RAFT(args, device): + """Initializes the RAFT model. + """ + model = torch.nn.DataParallel(RAFT(args)) + model.load_state_dict(torch.load(args.raft_model)) + + model = model.module + model.to(device) + model.eval() + + return model + + +def initialize_LAFC(args, device): + print(args.lafc_ckpts) + assert len(os.listdir(args.lafc_ckpts)) == 2 + checkpoint, config_file = glob.glob(os.path.join(args.lafc_ckpts, '*.tar'))[0], \ + glob.glob(os.path.join(args.lafc_ckpts, '*.yaml'))[0] + with open(config_file, 'r') as f: + configs = yaml.full_load(f) + model = configs['model'] + pkg = import_module('LAFC.models.{}'.format(model)) + model = pkg.Model(configs) + state = torch.load(checkpoint, map_location=lambda storage, + loc: storage.cuda(device)) + model.load_state_dict(state['model_state_dict']) + model = model.to(device) + return model, configs + + +def initialize_FGT(args, device): + assert len(os.listdir(args.fgt_ckpts)) == 2 + checkpoint, config_file = glob.glob(os.path.join(args.fgt_ckpts, '*.tar'))[0], \ + glob.glob(os.path.join(args.fgt_ckpts, '*.yaml'))[0] + with open(config_file, 'r') as f: + configs = yaml.full_load(f) + model = configs['model'] + net = import_module('FGT.models.{}'.format(model)) + model = net.Model(configs).to(device) + state = torch.load(checkpoint, map_location=lambda storage, + loc: storage.cuda(device)) + model.load_state_dict(state['model_state_dict']) + return model, configs + + +def calculate_flow(args, model, video, mode): + """Calculates optical flow. + """ + if mode not in ['forward', 'backward']: + raise NotImplementedError + + imgH, imgW = args.imgH, args.imgW + Flow = np.empty(((imgH, imgW, 2, 0)), dtype=np.float32) + + if args.vis_flows: + create_dir(os.path.join(args.outroot, 'flow', mode + '_flo')) + create_dir(os.path.join(args.outroot, 'flow', mode + '_png')) + + with torch.no_grad(): + for i in range(video.shape[0] - 1): + print( + "Calculating {0} flow {1:2d} <---> {2:2d}".format(mode, i, i + 1), '\r', end='') + if mode == 'forward': + # Flow i -> i + 1 + image1 = video[i, None] + image2 = video[i + 1, None] + elif mode == 'backward': + # Flow i + 1 -> i + image1 = video[i + 1, None] + image2 = video[i, None] + else: + raise NotImplementedError + + _, flow = model(image1, image2, iters=20, test_mode=True) + flow = flow[0].permute(1, 2, 0).cpu().numpy() + # resize optical flows + h, w = flow.shape[:2] + if h != imgH or w != imgW: + flow = cv2.resize(flow, (imgW, imgH), cv2.INTER_LINEAR) + flow[:, :, 0] *= (float(imgW) / float(w)) + flow[:, :, 1] *= (float(imgH) / float(h)) + + Flow = np.concatenate((Flow, flow[..., None]), axis=-1) + + if args.vis_flows: + # Flow visualization. + flow_img = utils.flow_viz.flow_to_image(flow) + flow_img = Image.fromarray(flow_img) + + # Saves the flow and flow_img. + flow_img.save(os.path.join(args.outroot, 'flow', + mode + '_png', '%05d.png' % i)) + utils.frame_utils.writeFlow(os.path.join( + args.outroot, 'flow', mode + '_flo', '%05d.flo' % i), flow) + + return Flow + + +def extrapolation(args, video_ori, corrFlowF_ori, corrFlowB_ori): + """Prepares the data for video extrapolation. + """ + imgH, imgW, _, nFrame = video_ori.shape + + # Defines new FOV. + imgH_extr = int(args.H_scale * imgH) + imgW_extr = int(args.W_scale * imgW) + imgH_extr = imgH_extr - imgH_extr % 4 + imgW_extr = imgW_extr - imgW_extr % 4 + H_start = int((imgH_extr - imgH) / 2) + W_start = int((imgW_extr - imgW) / 2) + + # Generates the mask for missing region. + flow_mask = np.ones(((imgH_extr, imgW_extr)), dtype=np.bool) + flow_mask[H_start: H_start + imgH, W_start: W_start + imgW] = 0 + + mask_dilated = gradient_mask(flow_mask) + + # Extrapolates the FOV for video. + video = np.zeros(((imgH_extr, imgW_extr, 3, nFrame)), dtype=np.float32) + video[H_start: H_start + imgH, W_start: W_start + imgW, :, :] = video_ori + + for i in range(nFrame): + print("Preparing frame {0}".format(i), '\r', end='') + video[:, :, :, i] = cv2.inpaint((video[:, :, :, i] * 255).astype(np.uint8), flow_mask.astype(np.uint8), 3, + cv2.INPAINT_TELEA).astype(np.float32) / 255. + + # Extrapolates the FOV for flow. + corrFlowF = np.zeros( + ((imgH_extr, imgW_extr, 2, nFrame - 1)), dtype=np.float32) + corrFlowB = np.zeros( + ((imgH_extr, imgW_extr, 2, nFrame - 1)), dtype=np.float32) + corrFlowF[H_start: H_start + imgH, + W_start: W_start + imgW, :] = corrFlowF_ori + corrFlowB[H_start: H_start + imgH, + W_start: W_start + imgW, :] = corrFlowB_ori + + return video, corrFlowF, corrFlowB, flow_mask, mask_dilated, (W_start, H_start), (W_start + imgW, H_start + imgH) + + +def complete_flow(config, flow_model, flows, flow_masks, mode, device): + if mode not in ['forward', 'backward']: + raise NotImplementedError(f'Error flow mode {mode}') + flow_masks = np.moveaxis(flow_masks, -1, 0) # [N, H, W] + flows = np.moveaxis(flows, -1, 0) # [N, H, W, 2] + if len(flow_masks.shape) == 3: + flow_masks = flow_masks[:, :, :, np.newaxis] + if mode == 'forward': + flow_masks = flow_masks[0:-1] + else: + flow_masks = flow_masks[1:] + + num_flows, flow_interval = config['num_flows'], config['flow_interval'] + + diffused_flows = diffusion(flows, flow_masks) + + flows = np2tensor(flows) + flow_masks = np2tensor(flow_masks) + diffused_flows = np2tensor(diffused_flows) + + flows = flows.to(device) + flow_masks = flow_masks.to(device) + diffused_flows = diffused_flows.to(device) + + t = diffused_flows.shape[2] + filled_flows = [None] * t + pivot = num_flows // 2 + for i in range(t): + indices = indicesGen(i, flow_interval, num_flows, t) + print('Indices: ', indices, '\r', end='') + cand_flows = flows[:, :, indices] + cand_masks = flow_masks[:, :, indices] + inputs = diffused_flows[:, :, indices] + pivot_mask = cand_masks[:, :, pivot] + pivot_flow = cand_flows[:, :, pivot] + with torch.no_grad(): + output_flow = flow_model(inputs, cand_masks) + if isinstance(output_flow, tuple) or isinstance(output_flow, list): + output_flow = output_flow[0] + comp = output_flow * pivot_mask + pivot_flow * (1 - pivot_mask) + if filled_flows[i] is None: + filled_flows[i] = comp + assert None not in filled_flows + return filled_flows + + +def read_flow(flow_dir, video): + nFrame, _, imgH, imgW = video.shape + Flow = np.empty(((imgH, imgW, 2, 0)), dtype=np.float32) + flows = sorted(glob.glob(os.path.join(flow_dir, '*.flo'))) + for flow in flows: + flow_data = cvbase.read_flow(flow) + h, w = flow_data.shape[:2] + flow_data = cv2.resize(flow_data, (imgW, imgH), cv2.INTER_LINEAR) + flow_data[:, :, 0] *= (float(imgW) / float(w)) + flow_data[:, :, 1] *= (float(imgH) / float(h)) + Flow = np.concatenate((Flow, flow_data[..., None]), axis=-1) + return Flow + + +def norm_flows(flows): + assert len(flows.shape) == 5, 'FLow shape: {}'.format(flows.shape) + flattened_flows = flows.flatten(3) + flow_max = torch.max(flattened_flows, dim=-1, keepdim=True)[0] + flows = flows / flow_max.unsqueeze(-1) + return flows + + +def save_results(outdir, comp_frames): + out_dir = os.path.join(outdir, 'frames') + if not os.path.exists(out_dir): + os.makedirs(out_dir) + for i in range(len(comp_frames)): + out_path = os.path.join(out_dir, '{:05d}.png'.format(i)) + cv2.imwrite(out_path, comp_frames[i][:, :, ::-1]) + + +def video_inpainting(args, imgArr, imgMaskArr): + device = torch.device('cuda:{}'.format(args.gpu)) + print(args) + if args.opt is not None: + with open(args.opt, 'r') as f: + opts = yaml.full_load(f) + + for k in opts.keys(): + if k in args: + setattr(args, k, opts[k]) + + print(args) + # Flow model. + RAFT_model = initialize_RAFT(args, device) + # LAFC (flow completion) + LAFC_model, LAFC_config = initialize_LAFC(args, device) + # FGT + FGT_model, FGT_config = initialize_FGT(args, device) + + # Loads frames. + # filename_list = glob.glob(os.path.join(args.path, '*.png')) + \ + # glob.glob(os.path.join(args.path, '*.jpg')) + + # Obtains imgH, imgW and nFrame. + imgH, imgW = args.imgH, args.imgW + # nFrame = len(filename_list) + nFrame = len(imgArr) + + if imgH < 350: + flowH, flowW = imgH * 2, imgW * 2 + else: + flowH, flowW = imgH, imgW + + # Load video. + video, video_flow = [], [] + if args.mode == 'watermark_removal': + maskname_list = glob.glob(os.path.join(args.path_mask, '*.png')) + glob.glob( + os.path.join(args.path_mask, '*.jpg')) + assert len(filename_list) == len(maskname_list) + for filename, maskname in zip(sorted(filename_list), sorted(maskname_list)): + frame = torch.from_numpy(np.array(Image.open(filename)).astype(np.uint8)).permute(2, 0, + 1).float().unsqueeze(0) + mask = torch.from_numpy(np.array(Image.open(maskname)).astype(np.uint8)).permute(2, 0, + 1).float().unsqueeze(0) + mask[mask > 0] = 1 + frame = frame * (1 - mask) + frame = F2.upsample(frame, size=(imgH, imgW), + mode='bilinear', align_corners=False) + frame_flow = F2.upsample(frame, size=( + flowH, flowW), mode='bilinear', align_corners=False) + video.append(frame) + video_flow.append(frame_flow) + else: + '''for filename in sorted(filename_list): + frame = torch.from_numpy(np.array(Image.open(filename)).astype(np.uint8)).permute(2, 0, 1).float().unsqueeze(0) + frame = F2.upsample(frame, size=(imgH, imgW), mode='bilinear', align_corners=False) + frame_flow = F2.upsample(frame, size=(flowH, flowW), mode='bilinear', align_corners=False) + video.append(frame) + video_flow.append(frame_flow)''' + for im in imgArr: + frame = torch.from_numpy(np.array(im).astype( + np.uint8)).permute(2, 0, 1).float().unsqueeze(0) + frame = F2.upsample(frame, size=(imgH, imgW), + mode='bilinear', align_corners=False) + frame_flow = F2.upsample(frame, size=( + flowH, flowW), mode='bilinear', align_corners=False) + video.append(frame) + video_flow.append(frame_flow) + + video = torch.cat(video, dim=0) # [n, c, h, w] + video_flow = torch.cat(video_flow, dim=0) + gts = video.clone() + video = video.to(device) + video_flow = video_flow.to(device) + + # Calcutes the corrupted flow. + forward_flows = calculate_flow( + args, RAFT_model, video_flow, 'forward') # [B, C, 2, N] + backward_flows = calculate_flow(args, RAFT_model, video_flow, 'backward') + + # Makes sure video is in BGR (opencv) format. + video = video.permute(2, 3, 1, 0).cpu().numpy()[ + :, :, ::-1, :] / 255. # np array -> [h, w, c, N] (0~1) + + if args.mode == 'video_extrapolation': + + # Creates video and flow where the extrapolated region are missing. + video, forward_flows, backward_flows, flow_mask, mask_dilated, start_point, end_point = extrapolation(args, + video, + forward_flows, + backward_flows) + imgH, imgW = video.shape[:2] + + # mask indicating the missing region in the video. + mask = np.tile(flow_mask[..., None], (1, 1, nFrame)) + flow_mask = np.tile(flow_mask[..., None], (1, 1, nFrame)) + mask_dilated = np.tile(mask_dilated[..., None], (1, 1, nFrame)) + + else: + # Loads masks. + filename_list = glob.glob(os.path.join(args.path_mask, '*.png')) + \ + glob.glob(os.path.join(args.path_mask, '*.jpg')) + + mask = [] + mask_dilated = [] + flow_mask = [] + '''for filename in sorted(filename_list): + mask_img = np.array(Image.open(filename).convert('L')) + mask_img = cv2.resize(mask_img, dsize=(imgW, imgH), interpolation=cv2.INTER_NEAREST) + + if args.flow_mask_dilates > 0: + flow_mask_img = scipy.ndimage.binary_dilation(mask_img, iterations=args.flow_mask_dilates) + else: + flow_mask_img = mask_img + flow_mask.append(flow_mask_img) + + if args.frame_dilates > 0: + mask_img = scipy.ndimage.binary_dilation(mask_img, iterations=args.frame_dilates) + mask.append(mask_img) + mask_dilated.append(gradient_mask(mask_img))''' + + for f_mask in imgMaskArr: + mask_img = np.array(f_mask) + mask_img = cv2.resize(mask_img, dsize=( + imgW, imgH), interpolation=cv2.INTER_NEAREST) + + if args.flow_mask_dilates > 0: + flow_mask_img = scipy.ndimage.binary_dilation( + mask_img, iterations=args.flow_mask_dilates) + else: + flow_mask_img = mask_img + flow_mask.append(flow_mask_img) + + if args.frame_dilates > 0: + mask_img = scipy.ndimage.binary_dilation( + mask_img, iterations=args.frame_dilates) + mask.append(mask_img) + mask_dilated.append(gradient_mask(mask_img)) + + # mask indicating the missing region in the video. + mask = np.stack(mask, -1).astype(np.bool) # [H, W, C, N] + mask_dilated = np.stack(mask_dilated, -1).astype(np.bool) + flow_mask = np.stack(flow_mask, -1).astype(np.bool) + + # Completes the flow. + videoFlowF = complete_flow( + LAFC_config, LAFC_model, forward_flows, flow_mask, 'forward', device) + videoFlowB = complete_flow( + LAFC_config, LAFC_model, backward_flows, flow_mask, 'backward', device) + videoFlowF = tensor2np(videoFlowF) + videoFlowB = tensor2np(videoFlowB) + print('\nFinish flow completion.') + + if args.vis_completed_flows: + save_flows(args.outroot, videoFlowF, videoFlowB) + + # Prepare gradients + gradient_x = np.empty(((imgH, imgW, 3, 0)), dtype=np.float32) + gradient_y = np.empty(((imgH, imgW, 3, 0)), dtype=np.float32) + + for indFrame in range(nFrame): + img = video[:, :, :, indFrame] + img[mask[:, :, indFrame], :] = 0 + img = cv2.inpaint((img * 255).astype(np.uint8), mask[:, :, indFrame].astype(np.uint8), 3, + cv2.INPAINT_TELEA).astype(np.float32) / 255. + + gradient_x_ = np.concatenate((np.diff(img, axis=1), np.zeros((imgH, 1, 3), dtype=np.float32)), + axis=1) + gradient_y_ = np.concatenate( + (np.diff(img, axis=0), np.zeros((1, imgW, 3), dtype=np.float32)), axis=0) + gradient_x = np.concatenate( + (gradient_x, gradient_x_.reshape(imgH, imgW, 3, 1)), axis=-1) + gradient_y = np.concatenate( + (gradient_y, gradient_y_.reshape(imgH, imgW, 3, 1)), axis=-1) + + gradient_x[mask_dilated[:, :, indFrame], :, indFrame] = 0 + gradient_y[mask_dilated[:, :, indFrame], :, indFrame] = 0 + + gradient_x_filled = gradient_x + gradient_y_filled = gradient_y + mask_gradient = mask_dilated + video_comp = video + + # Gradient propagation. + gradient_x_filled, gradient_y_filled, mask_gradient = \ + get_flowNN_gradient(args, + gradient_x_filled, + gradient_y_filled, + mask, + mask_gradient, + videoFlowF, + videoFlowB, + None, + None) + + # if there exist holes in mask, Poisson blending will fail. So I did this trick. I sacrifice some value. Another solution is to modify Poisson blending. + for indFrame in range(nFrame): + mask_gradient[:, :, indFrame] = scipy.ndimage.binary_fill_holes(mask_gradient[:, :, indFrame]).astype( + np.bool) + + # After one gradient propagation iteration + # gradient --> RGB + frameBlends = [] + for indFrame in range(nFrame): + print("Poisson blending frame {0:3d}".format(indFrame)) + + if mask[:, :, indFrame].sum() > 0: + try: + frameBlend, UnfilledMask = Poisson_blend_img(video_comp[:, :, :, indFrame], + gradient_x_filled[:, + 0: imgW - 1, :, indFrame], + gradient_y_filled[0: imgH - + 1, :, :, indFrame], + mask[:, :, indFrame], mask_gradient[:, :, indFrame]) + except: + frameBlend, UnfilledMask = video_comp[:, + :, :, indFrame], mask[:, :, indFrame] + + frameBlend = np.clip(frameBlend, 0, 1.0) + tmp = cv2.inpaint((frameBlend * 255).astype(np.uint8), UnfilledMask.astype(np.uint8), 3, + cv2.INPAINT_TELEA).astype(np.float32) / 255. + frameBlend[UnfilledMask, :] = tmp[UnfilledMask, :] + + video_comp[:, :, :, indFrame] = frameBlend + mask[:, :, indFrame] = UnfilledMask + + frameBlend_ = copy.deepcopy(frameBlend) + # Green indicates the regions that are not filled yet. + frameBlend_[mask[:, :, indFrame], :] = [0, 1., 0] + else: + frameBlend_ = video_comp[:, :, :, indFrame] + frameBlends.append(frameBlend_) + + if args.vis_prop: + save_fgcp(args.outroot, frameBlends, mask) + + video_length = len(frameBlends) + + for i in range(len(frameBlends)): + frameBlends[i] = frameBlends[i][:, :, ::-1] + + frames_first = np2tensor(frameBlends, near='t').to(device) + mask = np.moveaxis(mask, -1, 0) + mask = mask[:, :, :, np.newaxis] + masks = np2tensor(mask, near='t').to(device) + normed_frames = frames_first * 2 - 1 + comp_frames = [None] * video_length + + ref_length = args.step + num_ref = args.num_ref + neighbor_stride = args.neighbor_stride + + videoFlowF = np.moveaxis(videoFlowF, -1, 0) + + videoFlowF = np.concatenate([videoFlowF, videoFlowF[-1:, ...]], axis=0) + + flows = np2tensor(videoFlowF, near='t') + flows = norm_flows(flows).to(device) + + for f in range(0, video_length, neighbor_stride): + neighbor_ids = [i for i in range( + max(0, f - neighbor_stride), min(video_length, f + neighbor_stride + 1))] + ref_ids = get_ref_index( + f, neighbor_ids, video_length, ref_length, num_ref) + print(f, len(neighbor_ids), len(ref_ids)) + selected_frames = normed_frames[:, neighbor_ids + ref_ids] + selected_masks = masks[:, neighbor_ids + ref_ids] + masked_frames = selected_frames * (1 - selected_masks) + selected_flows = flows[:, neighbor_ids + ref_ids] + with torch.no_grad(): + filled_frames = FGT_model( + masked_frames, selected_flows, selected_masks) + filled_frames = (filled_frames + 1) / 2 + filled_frames = filled_frames.cpu().permute(0, 2, 3, 1).numpy() * 255 + for i in range(len(neighbor_ids)): + idx = neighbor_ids[i] + valid_frame = frames_first[0, idx].cpu().permute( + 1, 2, 0).numpy() * 255. + valid_mask = masks[0, idx].cpu().permute(1, 2, 0).numpy() + comp = np.array(filled_frames[i]).astype(np.uint8) * valid_mask + \ + np.array(valid_frame).astype(np.uint8) * (1 - valid_mask) + if comp_frames[idx] is None: + comp_frames[idx] = comp + else: + comp_frames[idx] = comp_frames[idx].astype( + np.float32) * 0.5 + comp.astype(np.float32) * 0.5 + if args.vis_frame: + save_results(args.outroot, comp_frames) + create_dir(args.outroot) + for i in range(len(comp_frames)): + comp_frames[i] = comp_frames[i].astype(np.uint8) + imageio.mimwrite(os.path.join(args.outroot, 'result.mp4'), + comp_frames, fps=30, quality=8) + print(f'Done, please check your result in {args.outroot} ') + + +def main(args): + assert args.mode in ('object_removal', 'video_extrapolation', 'watermark_removal'), ( + "Accepted modes: 'object_removal', 'video_extrapolation', and 'watermark_removal', but input is %s" + ) % args.mode + video_inpainting(args) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--opt', default='configs/object_removal.yaml', + help='Please select your config file for inference') + # video completion + parser.add_argument('--mode', default='object_removal', choices=[ + 'object_removal', 'watermark_removal', 'video_extrapolation'], help="modes: object_removal / video_extrapolation") + parser.add_argument( + '--path', default='/myData/davis_resized/walking', help="dataset for evaluation") + parser.add_argument( + '--path_mask', default='/myData/dilateAnnotations_4/walking', help="mask for object removal") + parser.add_argument( + '--outroot', default='quick_start/walking3', help="output directory") + parser.add_argument('--consistencyThres', dest='consistencyThres', default=5, type=float, + help='flow consistency error threshold') + parser.add_argument('--alpha', dest='alpha', default=0.1, type=float) + parser.add_argument('--Nonlocal', dest='Nonlocal', + default=False, type=bool) + + # RAFT + parser.add_argument( + '--raft_model', default='../LAFC/flowCheckPoint/raft-things.pth', help="restore checkpoint") + parser.add_argument('--small', action='store_true', help='use small model') + parser.add_argument('--mixed_precision', + action='store_true', help='use mixed precision') + parser.add_argument('--alternate_corr', action='store_true', + help='use efficent correlation implementation') + + # LAFC + parser.add_argument('--lafc_ckpts', type=str, default='../LAFC/checkpoint') + + # FGT + parser.add_argument('--fgt_ckpts', type=str, default='../FGT/checkpoint') + + # extrapolation + parser.add_argument('--H_scale', dest='H_scale', default=2, + type=float, help='H extrapolation scale') + parser.add_argument('--W_scale', dest='W_scale', default=2, + type=float, help='W extrapolation scale') + + # Image basic information + parser.add_argument('--imgH', type=int, default=256) + parser.add_argument('--imgW', type=int, default=432) + parser.add_argument('--flow_mask_dilates', type=int, default=8) + parser.add_argument('--frame_dilates', type=int, default=0) + + parser.add_argument('--gpu', type=int, default=0) + + # FGT inference parameters + parser.add_argument('--step', type=int, default=10) + parser.add_argument('--num_ref', type=int, default=-1) + parser.add_argument('--neighbor_stride', type=int, default=5) + + # visualization + parser.add_argument('--vis_flows', action='store_true', + help='Visualize the initialized flows') + parser.add_argument('--vis_completed_flows', + action='store_true', help='Visualize the completed flows') + parser.add_argument('--vis_prop', action='store_true', + help='Visualize the frames after stage-I filling (flow guided content propagation)') + parser.add_argument('--vis_frame', action='store_true', + help='Visualize frames') + + args = parser.parse_args() + + main(args) diff --git a/SiamMask/data/coco/gen_json.py b/SiamMask/data/coco/gen_json.py new file mode 100644 index 0000000000000000000000000000000000000000..b9b8769e3a2e45122ffa05389932acc5c4138eb3 --- /dev/null +++ b/SiamMask/data/coco/gen_json.py @@ -0,0 +1,38 @@ +# -------------------------------------------------------- +# SiamMask +# Licensed under The MIT License +# Written by Qiang Wang (wangqiang2015 at ia.ac.cn) +# -------------------------------------------------------- +from pycocotools.coco import COCO +from os.path import join +import json + + +dataDir = '.' +for data_subset in ['val2017', 'train2017']: + dataset = dict() + annFile = '{}/annotations/instances_{}.json'.format(dataDir, data_subset) + coco = COCO(annFile) + n_imgs = len(coco.imgs) + for n, img_id in enumerate(coco.imgs): + print('subset: {} image id: {:04d} / {:04d}'.format(data_subset, n, n_imgs)) + img = coco.loadImgs(img_id)[0] + annIds = coco.getAnnIds(imgIds=img['id'], iscrowd=None) + anns = coco.loadAnns(annIds) + crop_base_path = join(data_subset, img['file_name'].split('/')[-1].split('.')[0]) + + if len(anns) > 0: + dataset[crop_base_path] = dict() + + for track_id, ann in enumerate(anns): + rect = ann['bbox'] + if rect[2] <= 0 or rect[3] <= 0: # lead nan error in cls. + continue + bbox = [rect[0], rect[1], rect[0]+rect[2]-1, rect[1]+rect[3]-1] # x1,y1,x2,y2 + + dataset[crop_base_path]['{:02d}'.format(track_id)] = {'000000': bbox} + + print('save json (dataset), please wait 20 seconds~') + json.dump(dataset, open('{}.json'.format(data_subset), 'w'), indent=4, sort_keys=True) + print('done!') + diff --git a/SiamMask/data/coco/par_crop.py b/SiamMask/data/coco/par_crop.py new file mode 100644 index 0000000000000000000000000000000000000000..67f662cb91d5d0e69e7ea191c7cd63832998b831 --- /dev/null +++ b/SiamMask/data/coco/par_crop.py @@ -0,0 +1,131 @@ +# -------------------------------------------------------- +# SiamMask +# Licensed under The MIT License +# Written by Qiang Wang (wangqiang2015 at ia.ac.cn) +# -------------------------------------------------------- +from pycocotools.coco import COCO +import cv2 +import numpy as np +from os.path import join, isdir +from os import mkdir, makedirs +from concurrent import futures +import sys +import time +import argparse + +parser = argparse.ArgumentParser(description='COCO Parallel Preprocessing for SiamMask') +parser.add_argument('--exemplar_size', type=int, default=127, help='size of exemplar') +parser.add_argument('--context_amount', type=float, default=0.5, help='context amount') +parser.add_argument('--search_size', type=int, default=511, help='size of cropped search region') +parser.add_argument('--enable_mask', action='store_true', help='whether crop mask') +parser.add_argument('--num_threads', type=int, default=24, help='number of threads') +args = parser.parse_args() + + +# Print iterations progress (thanks StackOverflow) +def printProgress(iteration, total, prefix='', suffix='', decimals=1, barLength=100): + """ + Call in a loop to create terminal progress bar + @params: + iteration - Required : current iteration (Int) + total - Required : total iterations (Int) + prefix - Optional : prefix string (Str) + suffix - Optional : suffix string (Str) + decimals - Optional : positive number of decimals in percent complete (Int) + barLength - Optional : character length of bar (Int) + """ + formatStr = "{0:." + str(decimals) + "f}" + percents = formatStr.format(100 * (iteration / float(total))) + filledLength = int(round(barLength * iteration / float(total))) + bar = '' * filledLength + '-' * (barLength - filledLength) + sys.stdout.write('\r%s |%s| %s%s %s' % (prefix, bar, percents, '%', suffix)), + if iteration == total: + sys.stdout.write('\x1b[2K\r') + sys.stdout.flush() + + +def crop_hwc(image, bbox, out_sz, padding=(0, 0, 0)): + a = (out_sz-1) / (bbox[2]-bbox[0]) + b = (out_sz-1) / (bbox[3]-bbox[1]) + c = -a * bbox[0] + d = -b * bbox[1] + mapping = np.array([[a, 0, c], + [0, b, d]]).astype(np.float) + crop = cv2.warpAffine(image, mapping, (out_sz, out_sz), + borderMode=cv2.BORDER_CONSTANT, borderValue=padding) + return crop + + +def pos_s_2_bbox(pos, s): + return [pos[0]-s/2, pos[1]-s/2, pos[0]+s/2, pos[1]+s/2] + + +def crop_like_SiamFCx(image, bbox, exemplar_size=127, context_amount=0.5, search_size=255, padding=(0, 0, 0)): + target_pos = [(bbox[2]+bbox[0])/2., (bbox[3]+bbox[1])/2.] + target_size = [bbox[2]-bbox[0]+1, bbox[3]-bbox[1]+1] + wc_z = target_size[1] + context_amount * sum(target_size) + hc_z = target_size[0] + context_amount * sum(target_size) + s_z = np.sqrt(wc_z * hc_z) + scale_z = exemplar_size / s_z + d_search = (search_size - exemplar_size) / 2 + pad = d_search / scale_z + s_x = s_z + 2 * pad + + x = crop_hwc(image, pos_s_2_bbox(target_pos, s_x), search_size, padding) + return x + + +def crop_img(img, anns, set_crop_base_path, set_img_base_path, + exemplar_size=127, context_amount=0.5, search_size=511, enable_mask=True): + frame_crop_base_path = join(set_crop_base_path, img['file_name'].split('/')[-1].split('.')[0]) + if not isdir(frame_crop_base_path): makedirs(frame_crop_base_path) + + im = cv2.imread('{}/{}'.format(set_img_base_path, img['file_name'])) + avg_chans = np.mean(im, axis=(0, 1)) + for track_id, ann in enumerate(anns): + rect = ann['bbox'] + if rect[2] <= 0 or rect[3] <= 0: + continue + bbox = [rect[0], rect[1], rect[0]+rect[2]-1, rect[1]+rect[3]-1] + + x = crop_like_SiamFCx(im, bbox, exemplar_size=exemplar_size, context_amount=context_amount, + search_size=search_size, padding=avg_chans) + cv2.imwrite(join(frame_crop_base_path, '{:06d}.{:02d}.x.jpg'.format(0, track_id)), x) + + if enable_mask: + im_mask = coco.annToMask(ann).astype(np.float32) + x = (crop_like_SiamFCx(im_mask, bbox, exemplar_size=exemplar_size, context_amount=context_amount, + search_size=search_size) > 0.5).astype(np.uint8) * 255 + cv2.imwrite(join(frame_crop_base_path, '{:06d}.{:02d}.m.png'.format(0, track_id)), x) + + +def main(exemplar_size=127, context_amount=0.5, search_size=511, enable_mask=True, num_threads=24): + global coco # will used for generate mask + data_dir = '.' + crop_path = './crop{:d}'.format(search_size) + if not isdir(crop_path): mkdir(crop_path) + + for data_subset in ['val2017', 'train2017']: + set_crop_base_path = join(crop_path, data_subset) + set_img_base_path = join(data_dir, data_subset) + + anno_file = '{}/annotations/instances_{}.json'.format(data_dir, data_subset) + coco = COCO(anno_file) + n_imgs = len(coco.imgs) + with futures.ProcessPoolExecutor(max_workers=num_threads) as executor: + fs = [executor.submit(crop_img, coco.loadImgs(id)[0], + coco.loadAnns(coco.getAnnIds(imgIds=id, iscrowd=None)), + set_crop_base_path, set_img_base_path, + exemplar_size, context_amount, search_size, + enable_mask) for id in coco.imgs] + for i, f in enumerate(futures.as_completed(fs)): + printProgress(i, n_imgs, prefix=data_subset, suffix='Done ', barLength=40) + print('done') + + +if __name__ == '__main__': + since = time.time() + main(args.exemplar_size, args.context_amount, args.search_size, args.enable_mask, args.num_threads) + time_elapsed = time.time() - since + print('Total complete in {:.0f}m {:.0f}s'.format( + time_elapsed // 60, time_elapsed % 60)) diff --git a/SiamMask/data/coco/pycocotools/Makefile b/SiamMask/data/coco/pycocotools/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..9717ed5e8ff4e48c3921ebe28252d62bd276a293 --- /dev/null +++ b/SiamMask/data/coco/pycocotools/Makefile @@ -0,0 +1,11 @@ +all: + # install pycocotools locally + python setup.py build_ext --inplace + rm -rf build + +install: + # install pycocotools to the Python site-packages + python setup.py build_ext install + rm -rf build +clean: + rm _mask.c _mask.cpython-36m-x86_64-linux-gnu.so diff --git a/SiamMask/data/coco/pycocotools/__init__.py b/SiamMask/data/coco/pycocotools/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..3f7d85bba884ea8f83fc6ab2a1e6ade80d98d4d9 --- /dev/null +++ b/SiamMask/data/coco/pycocotools/__init__.py @@ -0,0 +1 @@ +__author__ = 'tylin' diff --git a/SiamMask/data/coco/pycocotools/_mask.pyx b/SiamMask/data/coco/pycocotools/_mask.pyx new file mode 100644 index 0000000000000000000000000000000000000000..544bb1f0f17c3042cf8e6db212362bdd63da653d --- /dev/null +++ b/SiamMask/data/coco/pycocotools/_mask.pyx @@ -0,0 +1,308 @@ +# distutils: language = c +# distutils: sources = common/maskApi.c + +#************************************************************************** +# Microsoft COCO Toolbox. version 2.0 +# Data, paper, and tutorials available at: http://mscoco.org/ +# Code written by Piotr Dollar and Tsung-Yi Lin, 2015. +# Licensed under the Simplified BSD License [see coco/license.txt] +#************************************************************************** + +__author__ = 'tsungyi' + +import sys +PYTHON_VERSION = sys.version_info[0] + +# import both Python-level and C-level symbols of Numpy +# the API uses Numpy to interface C and Python +import numpy as np +cimport numpy as np +from libc.stdlib cimport malloc, free + +# intialized Numpy. must do. +np.import_array() + +# import numpy C function +# we use PyArray_ENABLEFLAGS to make Numpy ndarray responsible to memoery management +cdef extern from "numpy/arrayobject.h": + void PyArray_ENABLEFLAGS(np.ndarray arr, int flags) + +# Declare the prototype of the C functions in MaskApi.h +cdef extern from "maskApi.h": + ctypedef unsigned int uint + ctypedef unsigned long siz + ctypedef unsigned char byte + ctypedef double* BB + ctypedef struct RLE: + siz h, + siz w, + siz m, + uint* cnts, + void rlesInit( RLE **R, siz n ) + void rleEncode( RLE *R, const byte *M, siz h, siz w, siz n ) + void rleDecode( const RLE *R, byte *mask, siz n ) + void rleMerge( const RLE *R, RLE *M, siz n, int intersect ) + void rleArea( const RLE *R, siz n, uint *a ) + void rleIou( RLE *dt, RLE *gt, siz m, siz n, byte *iscrowd, double *o ) + void bbIou( BB dt, BB gt, siz m, siz n, byte *iscrowd, double *o ) + void rleToBbox( const RLE *R, BB bb, siz n ) + void rleFrBbox( RLE *R, const BB bb, siz h, siz w, siz n ) + void rleFrPoly( RLE *R, const double *xy, siz k, siz h, siz w ) + char* rleToString( const RLE *R ) + void rleFrString( RLE *R, char *s, siz h, siz w ) + +# python class to wrap RLE array in C +# the class handles the memory allocation and deallocation +cdef class RLEs: + cdef RLE *_R + cdef siz _n + + def __cinit__(self, siz n =0): + rlesInit(&self._R, n) + self._n = n + + # free the RLE array here + def __dealloc__(self): + if self._R is not NULL: + for i in range(self._n): + free(self._R[i].cnts) + free(self._R) + def __getattr__(self, key): + if key == 'n': + return self._n + raise AttributeError(key) + +# python class to wrap Mask array in C +# the class handles the memory allocation and deallocation +cdef class Masks: + cdef byte *_mask + cdef siz _h + cdef siz _w + cdef siz _n + + def __cinit__(self, h, w, n): + self._mask = malloc(h*w*n* sizeof(byte)) + self._h = h + self._w = w + self._n = n + # def __dealloc__(self): + # the memory management of _mask has been passed to np.ndarray + # it doesn't need to be freed here + + # called when passing into np.array() and return an np.ndarray in column-major order + def __array__(self): + cdef np.npy_intp shape[1] + shape[0] = self._h*self._w*self._n + # Create a 1D array, and reshape it to fortran/Matlab column-major array + ndarray = np.PyArray_SimpleNewFromData(1, shape, np.NPY_UINT8, self._mask).reshape((self._h, self._w, self._n), order='F') + # The _mask allocated by Masks is now handled by ndarray + PyArray_ENABLEFLAGS(ndarray, np.NPY_OWNDATA) + return ndarray + +# internal conversion from Python RLEs object to compressed RLE format +def _toString(RLEs Rs): + cdef siz n = Rs.n + cdef bytes py_string + cdef char* c_string + objs = [] + for i in range(n): + c_string = rleToString( &Rs._R[i] ) + py_string = c_string + objs.append({ + 'size': [Rs._R[i].h, Rs._R[i].w], + 'counts': py_string + }) + free(c_string) + return objs + +# internal conversion from compressed RLE format to Python RLEs object +def _frString(rleObjs): + cdef siz n = len(rleObjs) + Rs = RLEs(n) + cdef bytes py_string + cdef char* c_string + for i, obj in enumerate(rleObjs): + if PYTHON_VERSION == 2: + py_string = str(obj['counts']).encode('utf8') + elif PYTHON_VERSION == 3: + py_string = str.encode(obj['counts']) if type(obj['counts']) == str else obj['counts'] + else: + raise Exception('Python version must be 2 or 3') + c_string = py_string + rleFrString( &Rs._R[i], c_string, obj['size'][0], obj['size'][1] ) + return Rs + +# encode mask to RLEs objects +# list of RLE string can be generated by RLEs member function +def encode(np.ndarray[np.uint8_t, ndim=3, mode='fortran'] mask): + h, w, n = mask.shape[0], mask.shape[1], mask.shape[2] + cdef RLEs Rs = RLEs(n) + rleEncode(Rs._R,mask.data,h,w,n) + objs = _toString(Rs) + return objs + +# decode mask from compressed list of RLE string or RLEs object +def decode(rleObjs): + cdef RLEs Rs = _frString(rleObjs) + h, w, n = Rs._R[0].h, Rs._R[0].w, Rs._n + masks = Masks(h, w, n) + rleDecode(Rs._R, masks._mask, n); + return np.array(masks) + +def merge(rleObjs, intersect=0): + cdef RLEs Rs = _frString(rleObjs) + cdef RLEs R = RLEs(1) + rleMerge(Rs._R, R._R, Rs._n, intersect) + obj = _toString(R)[0] + return obj + +def area(rleObjs): + cdef RLEs Rs = _frString(rleObjs) + cdef uint* _a = malloc(Rs._n* sizeof(uint)) + rleArea(Rs._R, Rs._n, _a) + cdef np.npy_intp shape[1] + shape[0] = Rs._n + a = np.array((Rs._n, ), dtype=np.uint8) + a = np.PyArray_SimpleNewFromData(1, shape, np.NPY_UINT32, _a) + PyArray_ENABLEFLAGS(a, np.NPY_OWNDATA) + return a + +# iou computation. support function overload (RLEs-RLEs and bbox-bbox). +def iou( dt, gt, pyiscrowd ): + def _preproc(objs): + if len(objs) == 0: + return objs + if type(objs) == np.ndarray: + if len(objs.shape) == 1: + objs = objs.reshape((objs[0], 1)) + # check if it's Nx4 bbox + if not len(objs.shape) == 2 or not objs.shape[1] == 4: + raise Exception('numpy ndarray input is only for *bounding boxes* and should have Nx4 dimension') + objs = objs.astype(np.double) + elif type(objs) == list: + # check if list is in box format and convert it to np.ndarray + isbox = np.all(np.array([(len(obj)==4) and ((type(obj)==list) or (type(obj)==np.ndarray)) for obj in objs])) + isrle = np.all(np.array([type(obj) == dict for obj in objs])) + if isbox: + objs = np.array(objs, dtype=np.double) + if len(objs.shape) == 1: + objs = objs.reshape((1,objs.shape[0])) + elif isrle: + objs = _frString(objs) + else: + raise Exception('list input can be bounding box (Nx4) or RLEs ([RLE])') + else: + raise Exception('unrecognized type. The following type: RLEs (rle), np.ndarray (box), and list (box) are supported.') + return objs + def _rleIou(RLEs dt, RLEs gt, np.ndarray[np.uint8_t, ndim=1] iscrowd, siz m, siz n, np.ndarray[np.double_t, ndim=1] _iou): + rleIou( dt._R, gt._R, m, n, iscrowd.data, _iou.data ) + def _bbIou(np.ndarray[np.double_t, ndim=2] dt, np.ndarray[np.double_t, ndim=2] gt, np.ndarray[np.uint8_t, ndim=1] iscrowd, siz m, siz n, np.ndarray[np.double_t, ndim=1] _iou): + bbIou( dt.data, gt.data, m, n, iscrowd.data, _iou.data ) + def _len(obj): + cdef siz N = 0 + if type(obj) == RLEs: + N = obj.n + elif len(obj)==0: + pass + elif type(obj) == np.ndarray: + N = obj.shape[0] + return N + # convert iscrowd to numpy array + cdef np.ndarray[np.uint8_t, ndim=1] iscrowd = np.array(pyiscrowd, dtype=np.uint8) + # simple type checking + cdef siz m, n + dt = _preproc(dt) + gt = _preproc(gt) + m = _len(dt) + n = _len(gt) + if m == 0 or n == 0: + return [] + if not type(dt) == type(gt): + raise Exception('The dt and gt should have the same data type, either RLEs, list or np.ndarray') + + # define local variables + cdef double* _iou = 0 + cdef np.npy_intp shape[1] + # check type and assign iou function + if type(dt) == RLEs: + _iouFun = _rleIou + elif type(dt) == np.ndarray: + _iouFun = _bbIou + else: + raise Exception('input data type not allowed.') + _iou = malloc(m*n* sizeof(double)) + iou = np.zeros((m*n, ), dtype=np.double) + shape[0] = m*n + iou = np.PyArray_SimpleNewFromData(1, shape, np.NPY_DOUBLE, _iou) + PyArray_ENABLEFLAGS(iou, np.NPY_OWNDATA) + _iouFun(dt, gt, iscrowd, m, n, iou) + return iou.reshape((m,n), order='F') + +def toBbox( rleObjs ): + cdef RLEs Rs = _frString(rleObjs) + cdef siz n = Rs.n + cdef BB _bb = malloc(4*n* sizeof(double)) + rleToBbox( Rs._R, _bb, n ) + cdef np.npy_intp shape[1] + shape[0] = 4*n + bb = np.array((1,4*n), dtype=np.double) + bb = np.PyArray_SimpleNewFromData(1, shape, np.NPY_DOUBLE, _bb).reshape((n, 4)) + PyArray_ENABLEFLAGS(bb, np.NPY_OWNDATA) + return bb + +def frBbox(np.ndarray[np.double_t, ndim=2] bb, siz h, siz w ): + cdef siz n = bb.shape[0] + Rs = RLEs(n) + rleFrBbox( Rs._R, bb.data, h, w, n ) + objs = _toString(Rs) + return objs + +def frPoly( poly, siz h, siz w ): + cdef np.ndarray[np.double_t, ndim=1] np_poly + n = len(poly) + Rs = RLEs(n) + for i, p in enumerate(poly): + np_poly = np.array(p, dtype=np.double, order='F') + rleFrPoly( &Rs._R[i], np_poly.data, int(len(p)/2), h, w ) + objs = _toString(Rs) + return objs + +def frUncompressedRLE(ucRles, siz h, siz w): + cdef np.ndarray[np.uint32_t, ndim=1] cnts + cdef RLE R + cdef uint *data + n = len(ucRles) + objs = [] + for i in range(n): + Rs = RLEs(1) + cnts = np.array(ucRles[i]['counts'], dtype=np.uint32) + # time for malloc can be saved here but it's fine + data = malloc(len(cnts)* sizeof(uint)) + for j in range(len(cnts)): + data[j] = cnts[j] + R = RLE(ucRles[i]['size'][0], ucRles[i]['size'][1], len(cnts), data) + Rs._R[0] = R + objs.append(_toString(Rs)[0]) + return objs + +def frPyObjects(pyobj, h, w): + # encode rle from a list of python objects + if type(pyobj) == np.ndarray: + objs = frBbox(pyobj, h, w) + elif type(pyobj) == list and len(pyobj[0]) == 4: + objs = frBbox(pyobj, h, w) + elif type(pyobj) == list and len(pyobj[0]) > 4: + objs = frPoly(pyobj, h, w) + elif type(pyobj) == list and type(pyobj[0]) == dict \ + and 'counts' in pyobj[0] and 'size' in pyobj[0]: + objs = frUncompressedRLE(pyobj, h, w) + # encode rle from single python object + elif type(pyobj) == list and len(pyobj) == 4: + objs = frBbox([pyobj], h, w)[0] + elif type(pyobj) == list and len(pyobj) > 4: + objs = frPoly([pyobj], h, w)[0] + elif type(pyobj) == dict and 'counts' in pyobj and 'size' in pyobj: + objs = frUncompressedRLE([pyobj], h, w)[0] + else: + raise Exception('input type is not supported.') + return objs diff --git a/SiamMask/data/coco/pycocotools/coco.py b/SiamMask/data/coco/pycocotools/coco.py new file mode 100644 index 0000000000000000000000000000000000000000..3ef19b1e12a4ca58ee3a32630b1bf784fe93c5f4 --- /dev/null +++ b/SiamMask/data/coco/pycocotools/coco.py @@ -0,0 +1,439 @@ +__author__ = 'tylin' +__version__ = '2.0' +# Interface for accessing the Microsoft COCO dataset. + +# Microsoft COCO is a large image dataset designed for object detection, +# segmentation, and caption generation. pycocotools is a Python API that +# assists in loading, parsing and visualizing the annotations in COCO. +# Please visit http://mscoco.org/ for more information on COCO, including +# for the data, paper, and tutorials. The exact format of the annotations +# is also described on the COCO website. For example usage of the pycocotools +# please see pycocotools_demo.ipynb. In addition to this API, please download both +# the COCO images and annotations in order to run the demo. + +# An alternative to using the API is to load the annotations directly +# into Python dictionary +# Using the API provides additional utility functions. Note that this API +# supports both *instance* and *caption* annotations. In the case of +# captions not all functions are defined (e.g. categories are undefined). + +# The following API functions are defined: +# COCO - COCO api class that loads COCO annotation file and prepare data structures. +# decodeMask - Decode binary mask M encoded via run-length encoding. +# encodeMask - Encode binary mask M using run-length encoding. +# getAnnIds - Get ann ids that satisfy given filter conditions. +# getCatIds - Get cat ids that satisfy given filter conditions. +# getImgIds - Get img ids that satisfy given filter conditions. +# loadAnns - Load anns with the specified ids. +# loadCats - Load cats with the specified ids. +# loadImgs - Load imgs with the specified ids. +# annToMask - Convert segmentation in an annotation to binary mask. +# showAnns - Display the specified annotations. +# loadRes - Load algorithm results and create API for accessing them. +# download - Download COCO images from mscoco.org server. +# Throughout the API "ann"=annotation, "cat"=category, and "img"=image. +# Help on each functions can be accessed by: "help COCO>function". + +# See also COCO>decodeMask, +# COCO>encodeMask, COCO>getAnnIds, COCO>getCatIds, +# COCO>getImgIds, COCO>loadAnns, COCO>loadCats, +# COCO>loadImgs, COCO>annToMask, COCO>showAnns + +# Microsoft COCO Toolbox. version 2.0 +# Data, paper, and tutorials available at: http://mscoco.org/ +# Code written by Piotr Dollar and Tsung-Yi Lin, 2014. +# Licensed under the Simplified BSD License [see bsd.txt] + +import json +import time + +try: + import matplotlib.pyplot as plt + from matplotlib.collections import PatchCollection + from matplotlib.patches import Polygon +except Exception as e: + print(e) + +import numpy as np +import copy +import itertools +from . import mask as maskUtils +import os +from collections import defaultdict +import sys +PYTHON_VERSION = sys.version_info[0] +if PYTHON_VERSION == 2: + from urllib import urlretrieve +elif PYTHON_VERSION == 3: + from urllib.request import urlretrieve + + +def _isArrayLike(obj): + return hasattr(obj, '__iter__') and hasattr(obj, '__len__') + + +class COCO: + def __init__(self, annotation_file=None): + """ + Constructor of Microsoft COCO helper class for reading and visualizing annotations. + :param annotation_file (str): location of annotation file + :param image_folder (str): location to the folder that hosts images. + :return: + """ + # load dataset + self.dataset,self.anns,self.cats,self.imgs = dict(),dict(),dict(),dict() + self.imgToAnns, self.catToImgs = defaultdict(list), defaultdict(list) + if not annotation_file == None: + print('loading annotations into memory...') + tic = time.time() + dataset = json.load(open(annotation_file, 'r')) + assert type(dataset)==dict, 'annotation file format {} not supported'.format(type(dataset)) + print('Done (t={:0.2f}s)'.format(time.time()- tic)) + self.dataset = dataset + self.createIndex() + + def createIndex(self): + # create index + print('creating index...') + anns, cats, imgs = {}, {}, {} + imgToAnns,catToImgs = defaultdict(list),defaultdict(list) + if 'annotations' in self.dataset: + for ann in self.dataset['annotations']: + imgToAnns[ann['image_id']].append(ann) + anns[ann['id']] = ann + + if 'images' in self.dataset: + for img in self.dataset['images']: + imgs[img['id']] = img + + if 'categories' in self.dataset: + for cat in self.dataset['categories']: + cats[cat['id']] = cat + + if 'annotations' in self.dataset and 'categories' in self.dataset: + for ann in self.dataset['annotations']: + catToImgs[ann['category_id']].append(ann['image_id']) + + print('index created!') + + # create class members + self.anns = anns + self.imgToAnns = imgToAnns + self.catToImgs = catToImgs + self.imgs = imgs + self.cats = cats + + def info(self): + """ + Print information about the annotation file. + :return: + """ + for key, value in self.dataset['info'].items(): + print('{}: {}'.format(key, value)) + + def getAnnIds(self, imgIds=[], catIds=[], areaRng=[], iscrowd=None): + """ + Get ann ids that satisfy given filter conditions. default skips that filter + :param imgIds (int array) : get anns for given imgs + catIds (int array) : get anns for given cats + areaRng (float array) : get anns for given area range (e.g. [0 inf]) + iscrowd (boolean) : get anns for given crowd label (False or True) + :return: ids (int array) : integer array of ann ids + """ + imgIds = imgIds if _isArrayLike(imgIds) else [imgIds] + catIds = catIds if _isArrayLike(catIds) else [catIds] + + if len(imgIds) == len(catIds) == len(areaRng) == 0: + anns = self.dataset['annotations'] + else: + if not len(imgIds) == 0: + lists = [self.imgToAnns[imgId] for imgId in imgIds if imgId in self.imgToAnns] + anns = list(itertools.chain.from_iterable(lists)) + else: + anns = self.dataset['annotations'] + anns = anns if len(catIds) == 0 else [ann for ann in anns if ann['category_id'] in catIds] + anns = anns if len(areaRng) == 0 else [ann for ann in anns if ann['area'] > areaRng[0] and ann['area'] < areaRng[1]] + if not iscrowd == None: + ids = [ann['id'] for ann in anns if ann['iscrowd'] == iscrowd] + else: + ids = [ann['id'] for ann in anns] + return ids + + def getCatIds(self, catNms=[], supNms=[], catIds=[]): + """ + filtering parameters. default skips that filter. + :param catNms (str array) : get cats for given cat names + :param supNms (str array) : get cats for given supercategory names + :param catIds (int array) : get cats for given cat ids + :return: ids (int array) : integer array of cat ids + """ + catNms = catNms if _isArrayLike(catNms) else [catNms] + supNms = supNms if _isArrayLike(supNms) else [supNms] + catIds = catIds if _isArrayLike(catIds) else [catIds] + + if len(catNms) == len(supNms) == len(catIds) == 0: + cats = self.dataset['categories'] + else: + cats = self.dataset['categories'] + cats = cats if len(catNms) == 0 else [cat for cat in cats if cat['name'] in catNms] + cats = cats if len(supNms) == 0 else [cat for cat in cats if cat['supercategory'] in supNms] + cats = cats if len(catIds) == 0 else [cat for cat in cats if cat['id'] in catIds] + ids = [cat['id'] for cat in cats] + return ids + + def getImgIds(self, imgIds=[], catIds=[]): + ''' + Get img ids that satisfy given filter conditions. + :param imgIds (int array) : get imgs for given ids + :param catIds (int array) : get imgs with all given cats + :return: ids (int array) : integer array of img ids + ''' + imgIds = imgIds if _isArrayLike(imgIds) else [imgIds] + catIds = catIds if _isArrayLike(catIds) else [catIds] + + if len(imgIds) == len(catIds) == 0: + ids = self.imgs.keys() + else: + ids = set(imgIds) + for i, catId in enumerate(catIds): + if i == 0 and len(ids) == 0: + ids = set(self.catToImgs[catId]) + else: + ids &= set(self.catToImgs[catId]) + return list(ids) + + def loadAnns(self, ids=[]): + """ + Load anns with the specified ids. + :param ids (int array) : integer ids specifying anns + :return: anns (object array) : loaded ann objects + """ + if _isArrayLike(ids): + return [self.anns[id] for id in ids] + elif type(ids) == int: + return [self.anns[ids]] + + def loadCats(self, ids=[]): + """ + Load cats with the specified ids. + :param ids (int array) : integer ids specifying cats + :return: cats (object array) : loaded cat objects + """ + if _isArrayLike(ids): + return [self.cats[id] for id in ids] + elif type(ids) == int: + return [self.cats[ids]] + + def loadImgs(self, ids=[]): + """ + Load anns with the specified ids. + :param ids (int array) : integer ids specifying img + :return: imgs (object array) : loaded img objects + """ + if _isArrayLike(ids): + return [self.imgs[id] for id in ids] + elif type(ids) == int: + return [self.imgs[ids]] + + def showAnns(self, anns): + """ + Display the specified annotations. + :param anns (array of object): annotations to display + :return: None + """ + if len(anns) == 0: + return 0 + if 'segmentation' in anns[0] or 'keypoints' in anns[0]: + datasetType = 'instances' + elif 'caption' in anns[0]: + datasetType = 'captions' + else: + raise Exception('datasetType not supported') + if datasetType == 'instances': + ax = plt.gca() + ax.set_autoscale_on(False) + polygons = [] + color = [] + for ann in anns: + c = (np.random.random((1, 3))*0.6+0.4).tolist()[0] + if 'segmentation' in ann: + if type(ann['segmentation']) == list: + # polygon + for seg in ann['segmentation']: + poly = np.array(seg).reshape((int(len(seg)/2), 2)) + polygons.append(Polygon(poly)) + color.append(c) + else: + # mask + t = self.imgs[ann['image_id']] + if type(ann['segmentation']['counts']) == list: + rle = maskUtils.frPyObjects([ann['segmentation']], t['height'], t['width']) + else: + rle = [ann['segmentation']] + m = maskUtils.decode(rle) + img = np.ones( (m.shape[0], m.shape[1], 3) ) + if ann['iscrowd'] == 1: + color_mask = np.array([2.0,166.0,101.0])/255 + if ann['iscrowd'] == 0: + color_mask = np.random.random((1, 3)).tolist()[0] + for i in range(3): + img[:,:,i] = color_mask[i] + ax.imshow(np.dstack( (img, m*0.5) )) + if 'keypoints' in ann and type(ann['keypoints']) == list: + # turn skeleton into zero-based index + sks = np.array(self.loadCats(ann['category_id'])[0]['skeleton'])-1 + kp = np.array(ann['keypoints']) + x = kp[0::3] + y = kp[1::3] + v = kp[2::3] + for sk in sks: + if np.all(v[sk]>0): + plt.plot(x[sk],y[sk], linewidth=3, color=c) + plt.plot(x[v>0], y[v>0],'o',markersize=8, markerfacecolor=c, markeredgecolor='k',markeredgewidth=2) + plt.plot(x[v>1], y[v>1],'o',markersize=8, markerfacecolor=c, markeredgecolor=c, markeredgewidth=2) + p = PatchCollection(polygons, facecolor=color, linewidths=0, alpha=0.4) + ax.add_collection(p) + p = PatchCollection(polygons, facecolor='none', edgecolors=color, linewidths=2) + ax.add_collection(p) + elif datasetType == 'captions': + for ann in anns: + print(ann['caption']) + + def loadRes(self, resFile): + """ + Load result file and return a result api object. + :param resFile (str) : file name of result file + :return: res (obj) : result api object + """ + res = COCO() + res.dataset['images'] = [img for img in self.dataset['images']] + + print('Loading and preparing results...') + tic = time.time() + #if type(resFile) == str or type(resFile) == unicode: + if type(resFile) == str: + anns = json.load(open(resFile)) + elif type(resFile) == np.ndarray: + anns = self.loadNumpyAnnotations(resFile) + else: + anns = resFile + assert type(anns) == list, 'results in not an array of objects' + annsImgIds = [ann['image_id'] for ann in anns] + assert set(annsImgIds) == (set(annsImgIds) & set(self.getImgIds())), \ + 'Results do not correspond to current coco set' + if 'caption' in anns[0]: + imgIds = set([img['id'] for img in res.dataset['images']]) & set([ann['image_id'] for ann in anns]) + res.dataset['images'] = [img for img in res.dataset['images'] if img['id'] in imgIds] + for id, ann in enumerate(anns): + ann['id'] = id+1 + elif 'bbox' in anns[0] and not anns[0]['bbox'] == []: + res.dataset['categories'] = copy.deepcopy(self.dataset['categories']) + for id, ann in enumerate(anns): + bb = ann['bbox'] + x1, x2, y1, y2 = [bb[0], bb[0]+bb[2], bb[1], bb[1]+bb[3]] + if not 'segmentation' in ann: + ann['segmentation'] = [[x1, y1, x1, y2, x2, y2, x2, y1]] + ann['area'] = bb[2]*bb[3] + ann['id'] = id+1 + ann['iscrowd'] = 0 + elif 'segmentation' in anns[0]: + res.dataset['categories'] = copy.deepcopy(self.dataset['categories']) + for id, ann in enumerate(anns): + # now only support compressed RLE format as segmentation results + ann['area'] = maskUtils.area(ann['segmentation']) + if not 'bbox' in ann: + ann['bbox'] = maskUtils.toBbox(ann['segmentation']) + ann['id'] = id+1 + ann['iscrowd'] = 0 + elif 'keypoints' in anns[0]: + res.dataset['categories'] = copy.deepcopy(self.dataset['categories']) + for id, ann in enumerate(anns): + s = ann['keypoints'] + x = s[0::3] + y = s[1::3] + x0,x1,y0,y1 = np.min(x), np.max(x), np.min(y), np.max(y) + ann['area'] = (x1-x0)*(y1-y0) + ann['id'] = id + 1 + ann['bbox'] = [x0,y0,x1-x0,y1-y0] + print('DONE (t={:0.2f}s)'.format(time.time()- tic)) + + res.dataset['annotations'] = anns + res.createIndex() + return res + + def download(self, tarDir = None, imgIds = [] ): + ''' + Download COCO images from mscoco.org server. + :param tarDir (str): COCO results directory name + imgIds (list): images to be downloaded + :return: + ''' + if tarDir is None: + print('Please specify target directory') + return -1 + if len(imgIds) == 0: + imgs = self.imgs.values() + else: + imgs = self.loadImgs(imgIds) + N = len(imgs) + if not os.path.exists(tarDir): + os.makedirs(tarDir) + for i, img in enumerate(imgs): + tic = time.time() + fname = os.path.join(tarDir, img['file_name']) + if not os.path.exists(fname): + urlretrieve(img['coco_url'], fname) + print('downloaded {}/{} images (t={:0.1f}s)'.format(i, N, time.time()- tic)) + + def loadNumpyAnnotations(self, data): + """ + Convert result data from a numpy array [Nx7] where each row contains {imageID,x1,y1,w,h,score,class} + :param data (numpy.ndarray) + :return: annotations (python nested list) + """ + print('Converting ndarray to lists...') + assert(type(data) == np.ndarray) + print(data.shape) + assert(data.shape[1] == 7) + N = data.shape[0] + ann = [] + for i in range(N): + if i % 1000000 == 0: + print('{}/{}'.format(i,N)) + ann += [{ + 'image_id' : int(data[i, 0]), + 'bbox' : [ data[i, 1], data[i, 2], data[i, 3], data[i, 4] ], + 'score' : data[i, 5], + 'category_id': int(data[i, 6]), + }] + return ann + + def annToRLE(self, ann): + """ + Convert annotation which can be polygons, uncompressed RLE to RLE. + :return: binary mask (numpy 2D array) + """ + t = self.imgs[ann['image_id']] + h, w = t['height'], t['width'] + segm = ann['segmentation'] + if type(segm) == list: + # polygon -- a single object might consist of multiple parts + # we merge all parts into one mask rle code + rles = maskUtils.frPyObjects(segm, h, w) + rle = maskUtils.merge(rles) + elif type(segm['counts']) == list: + # uncompressed RLE + rle = maskUtils.frPyObjects(segm, h, w) + else: + # rle + rle = ann['segmentation'] + return rle + + def annToMask(self, ann): + """ + Convert annotation which can be polygons, uncompressed RLE, or RLE to binary mask. + :return: binary mask (numpy 2D array) + """ + rle = self.annToRLE(ann) + m = maskUtils.decode(rle) + return m diff --git a/SiamMask/data/coco/pycocotools/cocoeval.py b/SiamMask/data/coco/pycocotools/cocoeval.py new file mode 100644 index 0000000000000000000000000000000000000000..7a4b4adc3e5dd7c59d50ea0fd346805d6e4b0227 --- /dev/null +++ b/SiamMask/data/coco/pycocotools/cocoeval.py @@ -0,0 +1,534 @@ +__author__ = 'tsungyi' + +import numpy as np +import datetime +import time +from collections import defaultdict +from . import mask as maskUtils +import copy + +class COCOeval: + # Interface for evaluating detection on the Microsoft COCO dataset. + # + # The usage for CocoEval is as follows: + # cocoGt=..., cocoDt=... # load dataset and results + # E = CocoEval(cocoGt,cocoDt); # initialize CocoEval object + # E.params.recThrs = ...; # set parameters as desired + # E.evaluate(); # run per image evaluation + # E.accumulate(); # accumulate per image results + # E.summarize(); # display summary metrics of results + # For example usage see evalDemo.m and http://mscoco.org/. + # + # The evaluation parameters are as follows (defaults in brackets): + # imgIds - [all] N img ids to use for evaluation + # catIds - [all] K cat ids to use for evaluation + # iouThrs - [.5:.05:.95] T=10 IoU thresholds for evaluation + # recThrs - [0:.01:1] R=101 recall thresholds for evaluation + # areaRng - [...] A=4 object area ranges for evaluation + # maxDets - [1 10 100] M=3 thresholds on max detections per image + # iouType - ['segm'] set iouType to 'segm', 'bbox' or 'keypoints' + # iouType replaced the now DEPRECATED useSegm parameter. + # useCats - [1] if true use category labels for evaluation + # Note: if useCats=0 category labels are ignored as in proposal scoring. + # Note: multiple areaRngs [Ax2] and maxDets [Mx1] can be specified. + # + # evaluate(): evaluates detections on every image and every category and + # concats the results into the "evalImgs" with fields: + # dtIds - [1xD] id for each of the D detections (dt) + # gtIds - [1xG] id for each of the G ground truths (gt) + # dtMatches - [TxD] matching gt id at each IoU or 0 + # gtMatches - [TxG] matching dt id at each IoU or 0 + # dtScores - [1xD] confidence of each dt + # gtIgnore - [1xG] ignore flag for each gt + # dtIgnore - [TxD] ignore flag for each dt at each IoU + # + # accumulate(): accumulates the per-image, per-category evaluation + # results in "evalImgs" into the dictionary "eval" with fields: + # params - parameters used for evaluation + # date - date evaluation was performed + # counts - [T,R,K,A,M] parameter dimensions (see above) + # precision - [TxRxKxAxM] precision for every evaluation setting + # recall - [TxKxAxM] max recall for every evaluation setting + # Note: precision and recall==-1 for settings with no gt objects. + # + # See also coco, mask, pycocoDemo, pycocoEvalDemo + # + # Microsoft COCO Toolbox. version 2.0 + # Data, paper, and tutorials available at: http://mscoco.org/ + # Code written by Piotr Dollar and Tsung-Yi Lin, 2015. + # Licensed under the Simplified BSD License [see coco/license.txt] + def __init__(self, cocoGt=None, cocoDt=None, iouType='segm'): + ''' + Initialize CocoEval using coco APIs for gt and dt + :param cocoGt: coco object with ground truth annotations + :param cocoDt: coco object with detection results + :return: None + ''' + if not iouType: + print('iouType not specified. use default iouType segm') + self.cocoGt = cocoGt # ground truth COCO API + self.cocoDt = cocoDt # detections COCO API + self.params = {} # evaluation parameters + self.evalImgs = defaultdict(list) # per-image per-category evaluation results [KxAxI] elements + self.eval = {} # accumulated evaluation results + self._gts = defaultdict(list) # gt for evaluation + self._dts = defaultdict(list) # dt for evaluation + self.params = Params(iouType=iouType) # parameters + self._paramsEval = {} # parameters for evaluation + self.stats = [] # result summarization + self.ious = {} # ious between all gts and dts + if not cocoGt is None: + self.params.imgIds = sorted(cocoGt.getImgIds()) + self.params.catIds = sorted(cocoGt.getCatIds()) + + + def _prepare(self): + ''' + Prepare ._gts and ._dts for evaluation based on params + :return: None + ''' + def _toMask(anns, coco): + # modify ann['segmentation'] by reference + for ann in anns: + rle = coco.annToRLE(ann) + ann['segmentation'] = rle + p = self.params + if p.useCats: + gts=self.cocoGt.loadAnns(self.cocoGt.getAnnIds(imgIds=p.imgIds, catIds=p.catIds)) + dts=self.cocoDt.loadAnns(self.cocoDt.getAnnIds(imgIds=p.imgIds, catIds=p.catIds)) + else: + gts=self.cocoGt.loadAnns(self.cocoGt.getAnnIds(imgIds=p.imgIds)) + dts=self.cocoDt.loadAnns(self.cocoDt.getAnnIds(imgIds=p.imgIds)) + + # convert ground truth to mask if iouType == 'segm' + if p.iouType == 'segm': + _toMask(gts, self.cocoGt) + _toMask(dts, self.cocoDt) + # set ignore flag + for gt in gts: + gt['ignore'] = gt['ignore'] if 'ignore' in gt else 0 + gt['ignore'] = 'iscrowd' in gt and gt['iscrowd'] + if p.iouType == 'keypoints': + gt['ignore'] = (gt['num_keypoints'] == 0) or gt['ignore'] + self._gts = defaultdict(list) # gt for evaluation + self._dts = defaultdict(list) # dt for evaluation + for gt in gts: + self._gts[gt['image_id'], gt['category_id']].append(gt) + for dt in dts: + self._dts[dt['image_id'], dt['category_id']].append(dt) + self.evalImgs = defaultdict(list) # per-image per-category evaluation results + self.eval = {} # accumulated evaluation results + + def evaluate(self): + ''' + Run per image evaluation on given images and store results (a list of dict) in self.evalImgs + :return: None + ''' + tic = time.time() + print('Running per image evaluation...') + p = self.params + # add backward compatibility if useSegm is specified in params + if not p.useSegm is None: + p.iouType = 'segm' if p.useSegm == 1 else 'bbox' + print('useSegm (deprecated) is not None. Running {} evaluation'.format(p.iouType)) + print('Evaluate annotation type *{}*'.format(p.iouType)) + p.imgIds = list(np.unique(p.imgIds)) + if p.useCats: + p.catIds = list(np.unique(p.catIds)) + p.maxDets = sorted(p.maxDets) + self.params=p + + self._prepare() + # loop through images, area range, max detection number + catIds = p.catIds if p.useCats else [-1] + + if p.iouType == 'segm' or p.iouType == 'bbox': + computeIoU = self.computeIoU + elif p.iouType == 'keypoints': + computeIoU = self.computeOks + self.ious = {(imgId, catId): computeIoU(imgId, catId) \ + for imgId in p.imgIds + for catId in catIds} + + evaluateImg = self.evaluateImg + maxDet = p.maxDets[-1] + self.evalImgs = [evaluateImg(imgId, catId, areaRng, maxDet) + for catId in catIds + for areaRng in p.areaRng + for imgId in p.imgIds + ] + self._paramsEval = copy.deepcopy(self.params) + toc = time.time() + print('DONE (t={:0.2f}s).'.format(toc-tic)) + + def computeIoU(self, imgId, catId): + p = self.params + if p.useCats: + gt = self._gts[imgId,catId] + dt = self._dts[imgId,catId] + else: + gt = [_ for cId in p.catIds for _ in self._gts[imgId,cId]] + dt = [_ for cId in p.catIds for _ in self._dts[imgId,cId]] + if len(gt) == 0 and len(dt) ==0: + return [] + inds = np.argsort([-d['score'] for d in dt], kind='mergesort') + dt = [dt[i] for i in inds] + if len(dt) > p.maxDets[-1]: + dt=dt[0:p.maxDets[-1]] + + if p.iouType == 'segm': + g = [g['segmentation'] for g in gt] + d = [d['segmentation'] for d in dt] + elif p.iouType == 'bbox': + g = [g['bbox'] for g in gt] + d = [d['bbox'] for d in dt] + else: + raise Exception('unknown iouType for iou computation') + + # compute iou between each dt and gt region + iscrowd = [int(o['iscrowd']) for o in gt] + ious = maskUtils.iou(d,g,iscrowd) + return ious + + def computeOks(self, imgId, catId): + p = self.params + # dimention here should be Nxm + gts = self._gts[imgId, catId] + dts = self._dts[imgId, catId] + inds = np.argsort([-d['score'] for d in dts], kind='mergesort') + dts = [dts[i] for i in inds] + if len(dts) > p.maxDets[-1]: + dts = dts[0:p.maxDets[-1]] + # if len(gts) == 0 and len(dts) == 0: + if len(gts) == 0 or len(dts) == 0: + return [] + ious = np.zeros((len(dts), len(gts))) + sigmas = np.array([.26, .25, .25, .35, .35, .79, .79, .72, .72, .62,.62, 1.07, 1.07, .87, .87, .89, .89])/10.0 + vars = (sigmas * 2)**2 + k = len(sigmas) + # compute oks between each detection and ground truth object + for j, gt in enumerate(gts): + # create bounds for ignore regions(double the gt bbox) + g = np.array(gt['keypoints']) + xg = g[0::3]; yg = g[1::3]; vg = g[2::3] + k1 = np.count_nonzero(vg > 0) + bb = gt['bbox'] + x0 = bb[0] - bb[2]; x1 = bb[0] + bb[2] * 2 + y0 = bb[1] - bb[3]; y1 = bb[1] + bb[3] * 2 + for i, dt in enumerate(dts): + d = np.array(dt['keypoints']) + xd = d[0::3]; yd = d[1::3] + if k1>0: + # measure the per-keypoint distance if keypoints visible + dx = xd - xg + dy = yd - yg + else: + # measure minimum distance to keypoints in (x0,y0) & (x1,y1) + z = np.zeros((k)) + dx = np.max((z, x0-xd),axis=0)+np.max((z, xd-x1),axis=0) + dy = np.max((z, y0-yd),axis=0)+np.max((z, yd-y1),axis=0) + e = (dx**2 + dy**2) / vars / (gt['area']+np.spacing(1)) / 2 + if k1 > 0: + e=e[vg > 0] + ious[i, j] = np.sum(np.exp(-e)) / e.shape[0] + return ious + + def evaluateImg(self, imgId, catId, aRng, maxDet): + ''' + perform evaluation for single category and image + :return: dict (single image results) + ''' + p = self.params + if p.useCats: + gt = self._gts[imgId,catId] + dt = self._dts[imgId,catId] + else: + gt = [_ for cId in p.catIds for _ in self._gts[imgId,cId]] + dt = [_ for cId in p.catIds for _ in self._dts[imgId,cId]] + if len(gt) == 0 and len(dt) ==0: + return None + + for g in gt: + if g['ignore'] or (g['area']aRng[1]): + g['_ignore'] = 1 + else: + g['_ignore'] = 0 + + # sort dt highest score first, sort gt ignore last + gtind = np.argsort([g['_ignore'] for g in gt], kind='mergesort') + gt = [gt[i] for i in gtind] + dtind = np.argsort([-d['score'] for d in dt], kind='mergesort') + dt = [dt[i] for i in dtind[0:maxDet]] + iscrowd = [int(o['iscrowd']) for o in gt] + # load computed ious + ious = self.ious[imgId, catId][:, gtind] if len(self.ious[imgId, catId]) > 0 else self.ious[imgId, catId] + + T = len(p.iouThrs) + G = len(gt) + D = len(dt) + gtm = np.zeros((T,G)) + dtm = np.zeros((T,D)) + gtIg = np.array([g['_ignore'] for g in gt]) + dtIg = np.zeros((T,D)) + if not len(ious)==0: + for tind, t in enumerate(p.iouThrs): + for dind, d in enumerate(dt): + # information about best match so far (m=-1 -> unmatched) + iou = min([t,1-1e-10]) + m = -1 + for gind, g in enumerate(gt): + # if this gt already matched, and not a crowd, continue + if gtm[tind,gind]>0 and not iscrowd[gind]: + continue + # if dt matched to reg gt, and on ignore gt, stop + if m>-1 and gtIg[m]==0 and gtIg[gind]==1: + break + # continue to next gt unless better match made + if ious[dind,gind] < iou: + continue + # if match successful and best so far, store appropriately + iou=ious[dind,gind] + m=gind + # if match made store id of match for both dt and gt + if m ==-1: + continue + dtIg[tind,dind] = gtIg[m] + dtm[tind,dind] = gt[m]['id'] + gtm[tind,m] = d['id'] + # set unmatched detections outside of area range to ignore + a = np.array([d['area']aRng[1] for d in dt]).reshape((1, len(dt))) + dtIg = np.logical_or(dtIg, np.logical_and(dtm==0, np.repeat(a,T,0))) + # store results for given image and category + return { + 'image_id': imgId, + 'category_id': catId, + 'aRng': aRng, + 'maxDet': maxDet, + 'dtIds': [d['id'] for d in dt], + 'gtIds': [g['id'] for g in gt], + 'dtMatches': dtm, + 'gtMatches': gtm, + 'dtScores': [d['score'] for d in dt], + 'gtIgnore': gtIg, + 'dtIgnore': dtIg, + } + + def accumulate(self, p = None): + ''' + Accumulate per image evaluation results and store the result in self.eval + :param p: input params for evaluation + :return: None + ''' + print('Accumulating evaluation results...') + tic = time.time() + if not self.evalImgs: + print('Please run evaluate() first') + # allows input customized parameters + if p is None: + p = self.params + p.catIds = p.catIds if p.useCats == 1 else [-1] + T = len(p.iouThrs) + R = len(p.recThrs) + K = len(p.catIds) if p.useCats else 1 + A = len(p.areaRng) + M = len(p.maxDets) + precision = -np.ones((T,R,K,A,M)) # -1 for the precision of absent categories + recall = -np.ones((T,K,A,M)) + scores = -np.ones((T,R,K,A,M)) + + # create dictionary for future indexing + _pe = self._paramsEval + catIds = _pe.catIds if _pe.useCats else [-1] + setK = set(catIds) + setA = set(map(tuple, _pe.areaRng)) + setM = set(_pe.maxDets) + setI = set(_pe.imgIds) + # get inds to evaluate + k_list = [n for n, k in enumerate(p.catIds) if k in setK] + m_list = [m for n, m in enumerate(p.maxDets) if m in setM] + a_list = [n for n, a in enumerate(map(lambda x: tuple(x), p.areaRng)) if a in setA] + i_list = [n for n, i in enumerate(p.imgIds) if i in setI] + I0 = len(_pe.imgIds) + A0 = len(_pe.areaRng) + # retrieve E at each category, area range, and max number of detections + for k, k0 in enumerate(k_list): + Nk = k0*A0*I0 + for a, a0 in enumerate(a_list): + Na = a0*I0 + for m, maxDet in enumerate(m_list): + E = [self.evalImgs[Nk + Na + i] for i in i_list] + E = [e for e in E if not e is None] + if len(E) == 0: + continue + dtScores = np.concatenate([e['dtScores'][0:maxDet] for e in E]) + + # different sorting method generates slightly different results. + # mergesort is used to be consistent as Matlab implementation. + inds = np.argsort(-dtScores, kind='mergesort') + dtScoresSorted = dtScores[inds] + + dtm = np.concatenate([e['dtMatches'][:,0:maxDet] for e in E], axis=1)[:,inds] + dtIg = np.concatenate([e['dtIgnore'][:,0:maxDet] for e in E], axis=1)[:,inds] + gtIg = np.concatenate([e['gtIgnore'] for e in E]) + npig = np.count_nonzero(gtIg==0 ) + if npig == 0: + continue + tps = np.logical_and( dtm, np.logical_not(dtIg) ) + fps = np.logical_and(np.logical_not(dtm), np.logical_not(dtIg) ) + + tp_sum = np.cumsum(tps, axis=1).astype(dtype=np.float) + fp_sum = np.cumsum(fps, axis=1).astype(dtype=np.float) + for t, (tp, fp) in enumerate(zip(tp_sum, fp_sum)): + tp = np.array(tp) + fp = np.array(fp) + nd = len(tp) + rc = tp / npig + pr = tp / (fp+tp+np.spacing(1)) + q = np.zeros((R,)) + ss = np.zeros((R,)) + + if nd: + recall[t,k,a,m] = rc[-1] + else: + recall[t,k,a,m] = 0 + + # numpy is slow without cython optimization for accessing elements + # use python array gets significant speed improvement + pr = pr.tolist(); q = q.tolist() + + for i in range(nd-1, 0, -1): + if pr[i] > pr[i-1]: + pr[i-1] = pr[i] + + inds = np.searchsorted(rc, p.recThrs, side='left') + try: + for ri, pi in enumerate(inds): + q[ri] = pr[pi] + ss[ri] = dtScoresSorted[pi] + except: + pass + precision[t,:,k,a,m] = np.array(q) + scores[t,:,k,a,m] = np.array(ss) + self.eval = { + 'params': p, + 'counts': [T, R, K, A, M], + 'date': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), + 'precision': precision, + 'recall': recall, + 'scores': scores, + } + toc = time.time() + print('DONE (t={:0.2f}s).'.format( toc-tic)) + + def summarize(self): + ''' + Compute and display summary metrics for evaluation results. + Note this functin can *only* be applied on the default parameter setting + ''' + def _summarize( ap=1, iouThr=None, areaRng='all', maxDets=100 ): + p = self.params + iStr = ' {:<18} {} @[ IoU={:<9} | area={:>6s} | maxDets={:>3d} ] = {:0.3f}' + titleStr = 'Average Precision' if ap == 1 else 'Average Recall' + typeStr = '(AP)' if ap==1 else '(AR)' + iouStr = '{:0.2f}:{:0.2f}'.format(p.iouThrs[0], p.iouThrs[-1]) \ + if iouThr is None else '{:0.2f}'.format(iouThr) + + aind = [i for i, aRng in enumerate(p.areaRngLbl) if aRng == areaRng] + mind = [i for i, mDet in enumerate(p.maxDets) if mDet == maxDets] + if ap == 1: + # dimension of precision: [TxRxKxAxM] + s = self.eval['precision'] + # IoU + if iouThr is not None: + t = np.where(iouThr == p.iouThrs)[0] + s = s[t] + s = s[:,:,:,aind,mind] + else: + # dimension of recall: [TxKxAxM] + s = self.eval['recall'] + if iouThr is not None: + t = np.where(iouThr == p.iouThrs)[0] + s = s[t] + s = s[:,:,aind,mind] + if len(s[s>-1])==0: + mean_s = -1 + else: + mean_s = np.mean(s[s>-1]) + print(iStr.format(titleStr, typeStr, iouStr, areaRng, maxDets, mean_s)) + return mean_s + def _summarizeDets(): + stats = np.zeros((12,)) + stats[0] = _summarize(1) + stats[1] = _summarize(1, iouThr=.5, maxDets=self.params.maxDets[2]) + stats[2] = _summarize(1, iouThr=.75, maxDets=self.params.maxDets[2]) + stats[3] = _summarize(1, areaRng='small', maxDets=self.params.maxDets[2]) + stats[4] = _summarize(1, areaRng='medium', maxDets=self.params.maxDets[2]) + stats[5] = _summarize(1, areaRng='large', maxDets=self.params.maxDets[2]) + stats[6] = _summarize(0, maxDets=self.params.maxDets[0]) + stats[7] = _summarize(0, maxDets=self.params.maxDets[1]) + stats[8] = _summarize(0, maxDets=self.params.maxDets[2]) + stats[9] = _summarize(0, areaRng='small', maxDets=self.params.maxDets[2]) + stats[10] = _summarize(0, areaRng='medium', maxDets=self.params.maxDets[2]) + stats[11] = _summarize(0, areaRng='large', maxDets=self.params.maxDets[2]) + return stats + def _summarizeKps(): + stats = np.zeros((10,)) + stats[0] = _summarize(1, maxDets=20) + stats[1] = _summarize(1, maxDets=20, iouThr=.5) + stats[2] = _summarize(1, maxDets=20, iouThr=.75) + stats[3] = _summarize(1, maxDets=20, areaRng='medium') + stats[4] = _summarize(1, maxDets=20, areaRng='large') + stats[5] = _summarize(0, maxDets=20) + stats[6] = _summarize(0, maxDets=20, iouThr=.5) + stats[7] = _summarize(0, maxDets=20, iouThr=.75) + stats[8] = _summarize(0, maxDets=20, areaRng='medium') + stats[9] = _summarize(0, maxDets=20, areaRng='large') + return stats + if not self.eval: + raise Exception('Please run accumulate() first') + iouType = self.params.iouType + if iouType == 'segm' or iouType == 'bbox': + summarize = _summarizeDets + elif iouType == 'keypoints': + summarize = _summarizeKps + self.stats = summarize() + + def __str__(self): + self.summarize() + +class Params: + ''' + Params for coco evaluation api + ''' + def setDetParams(self): + self.imgIds = [] + self.catIds = [] + # np.arange causes trouble. the data point on arange is slightly larger than the true value + self.iouThrs = np.linspace(.5, 0.95, np.round((0.95 - .5) / .05) + 1, endpoint=True) + self.recThrs = np.linspace(.0, 1.00, np.round((1.00 - .0) / .01) + 1, endpoint=True) + self.maxDets = [1, 10, 100] + self.areaRng = [[0 ** 2, 1e5 ** 2], [0 ** 2, 32 ** 2], [32 ** 2, 96 ** 2], [96 ** 2, 1e5 ** 2]] + self.areaRngLbl = ['all', 'small', 'medium', 'large'] + self.useCats = 1 + + def setKpParams(self): + self.imgIds = [] + self.catIds = [] + # np.arange causes trouble. the data point on arange is slightly larger than the true value + self.iouThrs = np.linspace(.5, 0.95, np.round((0.95 - .5) / .05) + 1, endpoint=True) + self.recThrs = np.linspace(.0, 1.00, np.round((1.00 - .0) / .01) + 1, endpoint=True) + self.maxDets = [20] + self.areaRng = [[0 ** 2, 1e5 ** 2], [32 ** 2, 96 ** 2], [96 ** 2, 1e5 ** 2]] + self.areaRngLbl = ['all', 'medium', 'large'] + self.useCats = 1 + + def __init__(self, iouType='segm'): + if iouType == 'segm' or iouType == 'bbox': + self.setDetParams() + elif iouType == 'keypoints': + self.setKpParams() + else: + raise Exception('iouType not supported') + self.iouType = iouType + # useSegm is deprecated + self.useSegm = None \ No newline at end of file diff --git a/SiamMask/data/coco/pycocotools/common/gason.cpp b/SiamMask/data/coco/pycocotools/common/gason.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0f2c00e2669370921d4331c15820922c481a827b --- /dev/null +++ b/SiamMask/data/coco/pycocotools/common/gason.cpp @@ -0,0 +1,335 @@ +// https://github.com/vivkin/gason - pulled January 10, 2016 +#include "gason.h" +#include + +#define JSON_ZONE_SIZE 4096 +#define JSON_STACK_SIZE 32 + +const char *jsonStrError(int err) { + switch (err) { +#define XX(no, str) \ + case JSON_##no: \ + return str; + JSON_ERRNO_MAP(XX) +#undef XX + default: + return "unknown"; + } +} + +void *JsonAllocator::allocate(size_t size) { + size = (size + 7) & ~7; + + if (head && head->used + size <= JSON_ZONE_SIZE) { + char *p = (char *)head + head->used; + head->used += size; + return p; + } + + size_t allocSize = sizeof(Zone) + size; + Zone *zone = (Zone *)malloc(allocSize <= JSON_ZONE_SIZE ? JSON_ZONE_SIZE : allocSize); + if (zone == nullptr) + return nullptr; + zone->used = allocSize; + if (allocSize <= JSON_ZONE_SIZE || head == nullptr) { + zone->next = head; + head = zone; + } else { + zone->next = head->next; + head->next = zone; + } + return (char *)zone + sizeof(Zone); +} + +void JsonAllocator::deallocate() { + while (head) { + Zone *next = head->next; + free(head); + head = next; + } +} + +static inline bool isspace(char c) { + return c == ' ' || (c >= '\t' && c <= '\r'); +} + +static inline bool isdelim(char c) { + return c == ',' || c == ':' || c == ']' || c == '}' || isspace(c) || !c; +} + +static inline bool isdigit(char c) { + return c >= '0' && c <= '9'; +} + +static inline bool isxdigit(char c) { + return (c >= '0' && c <= '9') || ((c & ~' ') >= 'A' && (c & ~' ') <= 'F'); +} + +static inline int char2int(char c) { + if (c <= '9') + return c - '0'; + return (c & ~' ') - 'A' + 10; +} + +static double string2double(char *s, char **endptr) { + char ch = *s; + if (ch == '-') + ++s; + + double result = 0; + while (isdigit(*s)) + result = (result * 10) + (*s++ - '0'); + + if (*s == '.') { + ++s; + + double fraction = 1; + while (isdigit(*s)) { + fraction *= 0.1; + result += (*s++ - '0') * fraction; + } + } + + if (*s == 'e' || *s == 'E') { + ++s; + + double base = 10; + if (*s == '+') + ++s; + else if (*s == '-') { + ++s; + base = 0.1; + } + + unsigned int exponent = 0; + while (isdigit(*s)) + exponent = (exponent * 10) + (*s++ - '0'); + + double power = 1; + for (; exponent; exponent >>= 1, base *= base) + if (exponent & 1) + power *= base; + + result *= power; + } + + *endptr = s; + return ch == '-' ? -result : result; +} + +static inline JsonNode *insertAfter(JsonNode *tail, JsonNode *node) { + if (!tail) + return node->next = node; + node->next = tail->next; + tail->next = node; + return node; +} + +static inline JsonValue listToValue(JsonTag tag, JsonNode *tail) { + if (tail) { + auto head = tail->next; + tail->next = nullptr; + return JsonValue(tag, head); + } + return JsonValue(tag, nullptr); +} + +int jsonParse(char *s, char **endptr, JsonValue *value, JsonAllocator &allocator) { + JsonNode *tails[JSON_STACK_SIZE]; + JsonTag tags[JSON_STACK_SIZE]; + char *keys[JSON_STACK_SIZE]; + JsonValue o; + int pos = -1; + bool separator = true; + JsonNode *node; + *endptr = s; + + while (*s) { + while (isspace(*s)) { + ++s; + if (!*s) break; + } + *endptr = s++; + switch (**endptr) { + case '-': + if (!isdigit(*s) && *s != '.') { + *endptr = s; + return JSON_BAD_NUMBER; + } + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + o = JsonValue(string2double(*endptr, &s)); + if (!isdelim(*s)) { + *endptr = s; + return JSON_BAD_NUMBER; + } + break; + case '"': + o = JsonValue(JSON_STRING, s); + for (char *it = s; *s; ++it, ++s) { + int c = *it = *s; + if (c == '\\') { + c = *++s; + switch (c) { + case '\\': + case '"': + case '/': + *it = c; + break; + case 'b': + *it = '\b'; + break; + case 'f': + *it = '\f'; + break; + case 'n': + *it = '\n'; + break; + case 'r': + *it = '\r'; + break; + case 't': + *it = '\t'; + break; + case 'u': + c = 0; + for (int i = 0; i < 4; ++i) { + if (isxdigit(*++s)) { + c = c * 16 + char2int(*s); + } else { + *endptr = s; + return JSON_BAD_STRING; + } + } + if (c < 0x80) { + *it = c; + } else if (c < 0x800) { + *it++ = 0xC0 | (c >> 6); + *it = 0x80 | (c & 0x3F); + } else { + *it++ = 0xE0 | (c >> 12); + *it++ = 0x80 | ((c >> 6) & 0x3F); + *it = 0x80 | (c & 0x3F); + } + break; + default: + *endptr = s; + return JSON_BAD_STRING; + } + } else if ((unsigned int)c < ' ' || c == '\x7F') { + *endptr = s; + return JSON_BAD_STRING; + } else if (c == '"') { + *it = 0; + ++s; + break; + } + } + if (!isdelim(*s)) { + *endptr = s; + return JSON_BAD_STRING; + } + break; + case 't': + if (!(s[0] == 'r' && s[1] == 'u' && s[2] == 'e' && isdelim(s[3]))) + return JSON_BAD_IDENTIFIER; + o = JsonValue(JSON_TRUE); + s += 3; + break; + case 'f': + if (!(s[0] == 'a' && s[1] == 'l' && s[2] == 's' && s[3] == 'e' && isdelim(s[4]))) + return JSON_BAD_IDENTIFIER; + o = JsonValue(JSON_FALSE); + s += 4; + break; + case 'n': + if (!(s[0] == 'u' && s[1] == 'l' && s[2] == 'l' && isdelim(s[3]))) + return JSON_BAD_IDENTIFIER; + o = JsonValue(JSON_NULL); + s += 3; + break; + case ']': + if (pos == -1) + return JSON_STACK_UNDERFLOW; + if (tags[pos] != JSON_ARRAY) + return JSON_MISMATCH_BRACKET; + o = listToValue(JSON_ARRAY, tails[pos--]); + break; + case '}': + if (pos == -1) + return JSON_STACK_UNDERFLOW; + if (tags[pos] != JSON_OBJECT) + return JSON_MISMATCH_BRACKET; + if (keys[pos] != nullptr) + return JSON_UNEXPECTED_CHARACTER; + o = listToValue(JSON_OBJECT, tails[pos--]); + break; + case '[': + if (++pos == JSON_STACK_SIZE) + return JSON_STACK_OVERFLOW; + tails[pos] = nullptr; + tags[pos] = JSON_ARRAY; + keys[pos] = nullptr; + separator = true; + continue; + case '{': + if (++pos == JSON_STACK_SIZE) + return JSON_STACK_OVERFLOW; + tails[pos] = nullptr; + tags[pos] = JSON_OBJECT; + keys[pos] = nullptr; + separator = true; + continue; + case ':': + if (separator || keys[pos] == nullptr) + return JSON_UNEXPECTED_CHARACTER; + separator = true; + continue; + case ',': + if (separator || keys[pos] != nullptr) + return JSON_UNEXPECTED_CHARACTER; + separator = true; + continue; + case '\0': + continue; + default: + return JSON_UNEXPECTED_CHARACTER; + } + + separator = false; + + if (pos == -1) { + *endptr = s; + *value = o; + return JSON_OK; + } + + if (tags[pos] == JSON_OBJECT) { + if (!keys[pos]) { + if (o.getTag() != JSON_STRING) + return JSON_UNQUOTED_KEY; + keys[pos] = o.toString(); + continue; + } + if ((node = (JsonNode *) allocator.allocate(sizeof(JsonNode))) == nullptr) + return JSON_ALLOCATION_FAILURE; + tails[pos] = insertAfter(tails[pos], node); + tails[pos]->key = keys[pos]; + keys[pos] = nullptr; + } else { + if ((node = (JsonNode *) allocator.allocate(sizeof(JsonNode) - sizeof(char *))) == nullptr) + return JSON_ALLOCATION_FAILURE; + tails[pos] = insertAfter(tails[pos], node); + } + tails[pos]->value = o; + } + return JSON_BREAKING_BAD; +} diff --git a/SiamMask/data/coco/pycocotools/common/gason.h b/SiamMask/data/coco/pycocotools/common/gason.h new file mode 100644 index 0000000000000000000000000000000000000000..2e728d9f70763e565077e1174c379cf141c9ede9 --- /dev/null +++ b/SiamMask/data/coco/pycocotools/common/gason.h @@ -0,0 +1,136 @@ +// https://github.com/vivkin/gason - pulled January 10, 2016 +#pragma once + +#include +#include +#include + +enum JsonTag { + JSON_NUMBER = 0, + JSON_STRING, + JSON_ARRAY, + JSON_OBJECT, + JSON_TRUE, + JSON_FALSE, + JSON_NULL = 0xF +}; + +struct JsonNode; + +#define JSON_VALUE_PAYLOAD_MASK 0x00007FFFFFFFFFFFULL +#define JSON_VALUE_NAN_MASK 0x7FF8000000000000ULL +#define JSON_VALUE_TAG_MASK 0xF +#define JSON_VALUE_TAG_SHIFT 47 + +union JsonValue { + uint64_t ival; + double fval; + + JsonValue(double x) + : fval(x) { + } + JsonValue(JsonTag tag = JSON_NULL, void *payload = nullptr) { + assert((uintptr_t)payload <= JSON_VALUE_PAYLOAD_MASK); + ival = JSON_VALUE_NAN_MASK | ((uint64_t)tag << JSON_VALUE_TAG_SHIFT) | (uintptr_t)payload; + } + bool isDouble() const { + return (int64_t)ival <= (int64_t)JSON_VALUE_NAN_MASK; + } + JsonTag getTag() const { + return isDouble() ? JSON_NUMBER : JsonTag((ival >> JSON_VALUE_TAG_SHIFT) & JSON_VALUE_TAG_MASK); + } + uint64_t getPayload() const { + assert(!isDouble()); + return ival & JSON_VALUE_PAYLOAD_MASK; + } + double toNumber() const { + assert(getTag() == JSON_NUMBER); + return fval; + } + char *toString() const { + assert(getTag() == JSON_STRING); + return (char *)getPayload(); + } + JsonNode *toNode() const { + assert(getTag() == JSON_ARRAY || getTag() == JSON_OBJECT); + return (JsonNode *)getPayload(); + } +}; + +struct JsonNode { + JsonValue value; + JsonNode *next; + char *key; +}; + +struct JsonIterator { + JsonNode *p; + + void operator++() { + p = p->next; + } + bool operator!=(const JsonIterator &x) const { + return p != x.p; + } + JsonNode *operator*() const { + return p; + } + JsonNode *operator->() const { + return p; + } +}; + +inline JsonIterator begin(JsonValue o) { + return JsonIterator{o.toNode()}; +} +inline JsonIterator end(JsonValue) { + return JsonIterator{nullptr}; +} + +#define JSON_ERRNO_MAP(XX) \ + XX(OK, "ok") \ + XX(BAD_NUMBER, "bad number") \ + XX(BAD_STRING, "bad string") \ + XX(BAD_IDENTIFIER, "bad identifier") \ + XX(STACK_OVERFLOW, "stack overflow") \ + XX(STACK_UNDERFLOW, "stack underflow") \ + XX(MISMATCH_BRACKET, "mismatch bracket") \ + XX(UNEXPECTED_CHARACTER, "unexpected character") \ + XX(UNQUOTED_KEY, "unquoted key") \ + XX(BREAKING_BAD, "breaking bad") \ + XX(ALLOCATION_FAILURE, "allocation failure") + +enum JsonErrno { +#define XX(no, str) JSON_##no, + JSON_ERRNO_MAP(XX) +#undef XX +}; + +const char *jsonStrError(int err); + +class JsonAllocator { + struct Zone { + Zone *next; + size_t used; + } *head = nullptr; + +public: + JsonAllocator() = default; + JsonAllocator(const JsonAllocator &) = delete; + JsonAllocator &operator=(const JsonAllocator &) = delete; + JsonAllocator(JsonAllocator &&x) : head(x.head) { + x.head = nullptr; + } + JsonAllocator &operator=(JsonAllocator &&x) { + head = x.head; + x.head = nullptr; + return *this; + } + ~JsonAllocator() { + deallocate(); + } + void *allocate(size_t size); + void deallocate(); +}; + +int jsonParse(char *str, char **endptr, JsonValue *value, JsonAllocator &allocator); diff --git a/SiamMask/data/coco/pycocotools/common/maskApi.c b/SiamMask/data/coco/pycocotools/common/maskApi.c new file mode 100644 index 0000000000000000000000000000000000000000..85e397918278126ce11f225dc109efbeb8a9394f --- /dev/null +++ b/SiamMask/data/coco/pycocotools/common/maskApi.c @@ -0,0 +1,230 @@ +/************************************************************************** +* Microsoft COCO Toolbox. version 2.0 +* Data, paper, and tutorials available at: http://mscoco.org/ +* Code written by Piotr Dollar and Tsung-Yi Lin, 2015. +* Licensed under the Simplified BSD License [see coco/license.txt] +**************************************************************************/ +#include "maskApi.h" +#include +#include + +uint umin( uint a, uint b ) { return (ab) ? a : b; } + +void rleInit( RLE *R, siz h, siz w, siz m, uint *cnts ) { + R->h=h; R->w=w; R->m=m; R->cnts=(m==0)?0:malloc(sizeof(uint)*m); + siz j; if(cnts) for(j=0; jcnts[j]=cnts[j]; +} + +void rleFree( RLE *R ) { + free(R->cnts); R->cnts=0; +} + +void rlesInit( RLE **R, siz n ) { + siz i; *R = (RLE*) malloc(sizeof(RLE)*n); + for(i=0; i0 ) { + c=umin(ca,cb); cc+=c; ct=0; + ca-=c; if(!ca && a0) { + crowd=iscrowd!=NULL && iscrowd[g]; + if(dt[d].h!=gt[g].h || dt[d].w!=gt[g].w) { o[g*m+d]=-1; continue; } + siz ka, kb, a, b; uint c, ca, cb, ct, i, u; int va, vb; + ca=dt[d].cnts[0]; ka=dt[d].m; va=vb=0; + cb=gt[g].cnts[0]; kb=gt[g].m; a=b=1; i=u=0; ct=1; + while( ct>0 ) { + c=umin(ca,cb); if(va||vb) { u+=c; if(va&&vb) i+=c; } ct=0; + ca-=c; if(!ca && athr) keep[j]=0; + } + } +} + +void bbIou( BB dt, BB gt, siz m, siz n, byte *iscrowd, double *o ) { + double h, w, i, u, ga, da; siz g, d; int crowd; + for( g=0; gthr) keep[j]=0; + } + } +} + +void rleToBbox( const RLE *R, BB bb, siz n ) { + siz i; for( i=0; id?1:c=dy && xs>xe) || (dxye); + if(flip) { t=xs; xs=xe; xe=t; t=ys; ys=ye; ye=t; } + s = dx>=dy ? (double)(ye-ys)/dx : (double)(xe-xs)/dy; + if(dx>=dy) for( d=0; d<=dx; d++ ) { + t=flip?dx-d:d; u[m]=t+xs; v[m]=(int)(ys+s*t+.5); m++; + } else for( d=0; d<=dy; d++ ) { + t=flip?dy-d:d; v[m]=t+ys; u[m]=(int)(xs+s*t+.5); m++; + } + } + /* get points along y-boundary and downsample */ + free(x); free(y); k=m; m=0; double xd, yd; + x=malloc(sizeof(int)*k); y=malloc(sizeof(int)*k); + for( j=1; jw-1 ) continue; + yd=(double)(v[j]h) yd=h; yd=ceil(yd); + x[m]=(int) xd; y[m]=(int) yd; m++; + } + /* compute rle encoding given y-boundary points */ + k=m; a=malloc(sizeof(uint)*(k+1)); + for( j=0; j0) b[m++]=a[j++]; else { + j++; if(jm, p=0; long x; int more; + char *s=malloc(sizeof(char)*m*6); + for( i=0; icnts[i]; if(i>2) x-=(long) R->cnts[i-2]; more=1; + while( more ) { + char c=x & 0x1f; x >>= 5; more=(c & 0x10) ? x!=-1 : x!=0; + if(more) c |= 0x20; c+=48; s[p++]=c; + } + } + s[p]=0; return s; +} + +void rleFrString( RLE *R, char *s, siz h, siz w ) { + siz m=0, p=0, k; long x; int more; uint *cnts; + while( s[m] ) m++; cnts=malloc(sizeof(uint)*m); m=0; + while( s[p] ) { + x=0; k=0; more=1; + while( more ) { + char c=s[p]-48; x |= (c & 0x1f) << 5*k; + more = c & 0x20; p++; k++; + if(!more && (c & 0x10)) x |= -1 << 5*k; + } + if(m>2) x+=(long) cnts[m-2]; cnts[m++]=(uint) x; + } + rleInit(R,h,w,m,cnts); free(cnts); +} diff --git a/SiamMask/data/coco/pycocotools/common/maskApi.h b/SiamMask/data/coco/pycocotools/common/maskApi.h new file mode 100644 index 0000000000000000000000000000000000000000..ebc7892da38289b459d6be824e1f849878bd4069 --- /dev/null +++ b/SiamMask/data/coco/pycocotools/common/maskApi.h @@ -0,0 +1,60 @@ +/************************************************************************** +* Microsoft COCO Toolbox. version 2.0 +* Data, paper, and tutorials available at: http://mscoco.org/ +* Code written by Piotr Dollar and Tsung-Yi Lin, 2015. +* Licensed under the Simplified BSD License [see coco/license.txt] +**************************************************************************/ +#pragma once + +typedef unsigned int uint; +typedef unsigned long siz; +typedef unsigned char byte; +typedef double* BB; +typedef struct { siz h, w, m; uint *cnts; } RLE; + +/* Initialize/destroy RLE. */ +void rleInit( RLE *R, siz h, siz w, siz m, uint *cnts ); +void rleFree( RLE *R ); + +/* Initialize/destroy RLE array. */ +void rlesInit( RLE **R, siz n ); +void rlesFree( RLE **R, siz n ); + +/* Encode binary masks using RLE. */ +void rleEncode( RLE *R, const byte *mask, siz h, siz w, siz n ); + +/* Decode binary masks encoded via RLE. */ +void rleDecode( const RLE *R, byte *mask, siz n ); + +/* Compute union or intersection of encoded masks. */ +void rleMerge( const RLE *R, RLE *M, siz n, int intersect ); + +/* Compute area of encoded masks. */ +void rleArea( const RLE *R, siz n, uint *a ); + +/* Compute intersection over union between masks. */ +void rleIou( RLE *dt, RLE *gt, siz m, siz n, byte *iscrowd, double *o ); + +/* Compute non-maximum suppression between bounding masks */ +void rleNms( RLE *dt, siz n, uint *keep, double thr ); + +/* Compute intersection over union between bounding boxes. */ +void bbIou( BB dt, BB gt, siz m, siz n, byte *iscrowd, double *o ); + +/* Compute non-maximum suppression between bounding boxes */ +void bbNms( BB dt, siz n, uint *keep, double thr ); + +/* Get bounding boxes surrounding encoded masks. */ +void rleToBbox( const RLE *R, BB bb, siz n ); + +/* Convert bounding boxes to encoded masks. */ +void rleFrBbox( RLE *R, const BB bb, siz h, siz w, siz n ); + +/* Convert polygon to encoded mask. */ +void rleFrPoly( RLE *R, const double *xy, siz k, siz h, siz w ); + +/* Get compressed string representation of encoded mask. */ +char* rleToString( const RLE *R ); + +/* Convert from compressed string representation of encoded mask. */ +void rleFrString( RLE *R, char *s, siz h, siz w ); diff --git a/SiamMask/data/coco/pycocotools/mask.py b/SiamMask/data/coco/pycocotools/mask.py new file mode 100644 index 0000000000000000000000000000000000000000..3e4330b14f8efc412dc261df0ef6449424baad26 --- /dev/null +++ b/SiamMask/data/coco/pycocotools/mask.py @@ -0,0 +1,104 @@ +__author__ = 'tsungyi' + +#import pycocotools._mask as _mask +from . import _mask + +# Interface for manipulating masks stored in RLE format. +# +# RLE is a simple yet efficient format for storing binary masks. RLE +# first divides a vector (or vectorized image) into a series of piecewise +# constant regions and then for each piece simply stores the length of +# that piece. For example, given M=[0 0 1 1 1 0 1] the RLE counts would +# be [2 3 1 1], or for M=[1 1 1 1 1 1 0] the counts would be [0 6 1] +# (note that the odd counts are always the numbers of zeros). Instead of +# storing the counts directly, additional compression is achieved with a +# variable bitrate representation based on a common scheme called LEB128. +# +# Compression is greatest given large piecewise constant regions. +# Specifically, the size of the RLE is proportional to the number of +# *boundaries* in M (or for an image the number of boundaries in the y +# direction). Assuming fairly simple shapes, the RLE representation is +# O(sqrt(n)) where n is number of pixels in the object. Hence space usage +# is substantially lower, especially for large simple objects (large n). +# +# Many common operations on masks can be computed directly using the RLE +# (without need for decoding). This includes computations such as area, +# union, intersection, etc. All of these operations are linear in the +# size of the RLE, in other words they are O(sqrt(n)) where n is the area +# of the object. Computing these operations on the original mask is O(n). +# Thus, using the RLE can result in substantial computational savings. +# +# The following API functions are defined: +# encode - Encode binary masks using RLE. +# decode - Decode binary masks encoded via RLE. +# merge - Compute union or intersection of encoded masks. +# iou - Compute intersection over union between masks. +# area - Compute area of encoded masks. +# toBbox - Get bounding boxes surrounding encoded masks. +# frPyObjects - Convert polygon, bbox, and uncompressed RLE to encoded RLE mask. +# +# Usage: +# Rs = encode( masks ) +# masks = decode( Rs ) +# R = merge( Rs, intersect=false ) +# o = iou( dt, gt, iscrowd ) +# a = area( Rs ) +# bbs = toBbox( Rs ) +# Rs = frPyObjects( [pyObjects], h, w ) +# +# In the API the following formats are used: +# Rs - [dict] Run-length encoding of binary masks +# R - dict Run-length encoding of binary mask +# masks - [hxwxn] Binary mask(s) (must have type np.ndarray(dtype=uint8) in column-major order) +# iscrowd - [nx1] list of np.ndarray. 1 indicates corresponding gt image has crowd region to ignore +# bbs - [nx4] Bounding box(es) stored as [x y w h] +# poly - Polygon stored as [[x1 y1 x2 y2...],[x1 y1 ...],...] (2D list) +# dt,gt - May be either bounding boxes or encoded masks +# Both poly and bbs are 0-indexed (bbox=[0 0 1 1] encloses first pixel). +# +# Finally, a note about the intersection over union (iou) computation. +# The standard iou of a ground truth (gt) and detected (dt) object is +# iou(gt,dt) = area(intersect(gt,dt)) / area(union(gt,dt)) +# For "crowd" regions, we use a modified criteria. If a gt object is +# marked as "iscrowd", we allow a dt to match any subregion of the gt. +# Choosing gt' in the crowd gt that best matches the dt can be done using +# gt'=intersect(dt,gt). Since by definition union(gt',dt)=dt, computing +# iou(gt,dt,iscrowd) = iou(gt',dt) = area(intersect(gt,dt)) / area(dt) +# For crowd gt regions we use this modified criteria above for the iou. +# +# To compile run "python setup.py build_ext --inplace" +# Please do not contact us for help with compiling. +# +# Microsoft COCO Toolbox. version 2.0 +# Data, paper, and tutorials available at: http://mscoco.org/ +# Code written by Piotr Dollar and Tsung-Yi Lin, 2015. +# Licensed under the Simplified BSD License [see coco/license.txt] + +iou = _mask.iou +merge = _mask.merge +frPyObjects = _mask.frPyObjects + +def encode(bimask): + if len(bimask.shape) == 3: + return _mask.encode(bimask) + elif len(bimask.shape) == 2: + h, w = bimask.shape + return _mask.encode(bimask.reshape((h, w, 1), order='F'))[0] + +def decode(rleObjs): + if type(rleObjs) == list: + return _mask.decode(rleObjs) + else: + return _mask.decode([rleObjs])[:,:,0] + +def area(rleObjs): + if type(rleObjs) == list: + return _mask.area(rleObjs) + else: + return _mask.area([rleObjs])[0] + +def toBbox(rleObjs): + if type(rleObjs) == list: + return _mask.toBbox(rleObjs) + else: + return _mask.toBbox([rleObjs])[0] diff --git a/SiamMask/data/coco/pycocotools/setup.py b/SiamMask/data/coco/pycocotools/setup.py new file mode 100644 index 0000000000000000000000000000000000000000..9f252b834381d58037d0aec161fd2506a00e730d --- /dev/null +++ b/SiamMask/data/coco/pycocotools/setup.py @@ -0,0 +1,24 @@ +from distutils.core import setup +from Cython.Build import cythonize +from distutils.extension import Extension +import numpy as np + +# To compile and install locally run "python setup.py build_ext --inplace" +# To install library to Python site-packages run "python setup.py build_ext install" + +ext_modules = [ + Extension( + '_mask', + sources=['common/maskApi.c', '_mask.pyx'], + include_dirs = [np.get_include(), 'common'], + extra_compile_args=['-Wno-cpp', '-Wno-unused-function', '-std=c99'], + ) +] + +setup(name='pycocotools', + packages=['pycocotools'], + package_dir = {'pycocotools': '.'}, + version='2.0', + ext_modules= + cythonize(ext_modules) + ) diff --git a/SiamMask/data/coco/readme.md b/SiamMask/data/coco/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..d7a01aa7221c1fcb70dea119d4c5f78391050b9d --- /dev/null +++ b/SiamMask/data/coco/readme.md @@ -0,0 +1,22 @@ +# Preprocessing COCO + +### Download raw images and annotations + +````shell +wget http://images.cocodataset.org/zips/train2017.zip +wget http://images.cocodataset.org/zips/val2017.zip +wget http://images.cocodataset.org/annotations/annotations_trainval2017.zip + +unzip ./train2017.zip +unzip ./val2017.zip +unzip ./annotations_trainval2017.zip +cd pycocotools && make && cd .. +```` + +### Crop & Generate data info (~20 min) + +````shell +#python par_crop.py -h +python par_crop.py --enable_mask --num_threads 24 +python gen_json.py +```` diff --git a/SiamMask/data/coco/visual.py b/SiamMask/data/coco/visual.py new file mode 100644 index 0000000000000000000000000000000000000000..3745531dd829facd583e280bb000faa4f1ce8661 --- /dev/null +++ b/SiamMask/data/coco/visual.py @@ -0,0 +1,34 @@ +# -------------------------------------------------------- +# SiamMask +# Licensed under The MIT License +# Written by Qiang Wang (wangqiang2015 at ia.ac.cn) +# -------------------------------------------------------- +from pycocotools.coco import COCO +import cv2 +import numpy as np + +color_bar = np.random.randint(0, 255, (90, 3)) + +visual = True + +dataDir = '.' +dataType = 'val2017' +annFile = '{}/annotations/instances_{}.json'.format(dataDir,dataType) +coco = COCO(annFile) + +for img_id in coco.imgs: + img = coco.loadImgs(img_id)[0] + annIds = coco.getAnnIds(imgIds=img['id'], iscrowd=None) + anns = coco.loadAnns(annIds) + im = cv2.imread('{}/{}/{}'.format(dataDir, dataType, img['file_name'])) + for ann in anns: + rect = ann['bbox'] + c = ann['category_id'] + if visual: + pt1 = (int(rect[0]), int(rect[1])) + pt2 = (int(rect[0]+rect[2]-1), int(rect[1]+rect[3]-1)) + cv2.rectangle(im, pt1, pt2, color_bar[c-1], 3) + cv2.imshow('img', im) + cv2.waitKey(200) +print('done') + diff --git a/SiamMask/data/create_json.py b/SiamMask/data/create_json.py new file mode 100644 index 0000000000000000000000000000000000000000..823539300056cba262311d85e48b7f46633bd5e9 --- /dev/null +++ b/SiamMask/data/create_json.py @@ -0,0 +1,155 @@ +import json +import os +import re +import numpy as np +import cv2 + +from glob import glob +from fire import Fire + +def process(dataset_name): + with open(os.path.join(dataset_name, 'list.txt'), 'r') as f: + lines = f.readlines() + videos = [x.strip() for x in lines] + + # if dataset_name == 'VOT2016': + meta_data = {} + tags = [] + for video in videos: + with open(os.path.join(dataset_name, video, "groundtruth.txt"),'r') as f: + gt_traj = [list(map(float, x.strip().split(','))) for x in f.readlines()] + + img_names = sorted(glob(os.path.join(dataset_name, video, 'color', '*.jpg'))) + if len(img_names) == 0: + img_names = sorted(glob(os.path.join(dataset_name, video, '*.jpg'))) + im = cv2.imread(img_names[0]) + img_names = [x.split('/', 1)[1] for x in img_names] + # tag + if dataset_name in ['VOT2018', 'VOT2019']: + tag_file = os.path.join(dataset_name, video, 'camera_motion.tag') + if os.path.exists(tag_file): + with open(tag_file, 'r') as f: + camera_motion = [int(x.strip()) for x in f.readlines()] + camera_motion += [0] * (len(gt_traj) - len(camera_motion)) + else: + print("File not exists: ", tag_file) + camera_motion = [] # [0] * len(gt_traj) + + tag_file = os.path.join(dataset_name, video, 'illum_change.tag') + if os.path.exists(tag_file): + with open(tag_file, 'r') as f: + illum_change = [int(x.strip()) for x in f.readlines()] + illum_change += [0] * (len(gt_traj) - len(illum_change)) + else: + print("File not exists: ", tag_file) + illum_change = [] # [0] * len(gt_traj) + + tag_file = os.path.join(dataset_name, video, 'motion_change.tag') + if os.path.exists(tag_file): + with open(tag_file, 'r') as f: + motion_change = [int(x.strip()) for x in f.readlines()] + motion_change += [0] * (len(gt_traj) - len(motion_change)) + else: + print("File not exists: ", tag_file) + motion_change = [] # [0] * len(gt_traj) + + tag_file = os.path.join(dataset_name, video, 'size_change.tag') + if os.path.exists(tag_file): + with open(tag_file, 'r') as f: + size_change = [int(x.strip()) for x in f.readlines()] + size_change += [0] * (len(gt_traj) - len(size_change)) + else: + print("File not exists: ", tag_file) + size_change = [] # [0] * len(gt_traj) + + tag_file = os.path.join(dataset_name, video, 'occlusion.tag') + if os.path.exists(tag_file): + with open(tag_file, 'r') as f: + occlusion = [int(x.strip()) for x in f.readlines()] + occlusion += [0] * (len(gt_traj) - len(occlusion)) + else: + print("File not exists: ", tag_file) + occlusion = [] # [0] * len(gt_traj) + img_files = os.path.join('VOT2019', ) + meta_data[video] = {'video_dir': video, + 'init_rect': gt_traj[0], + 'img_names': img_names, + 'width': im.shape[1], + 'height': im.shape[0], + 'gt_rect': gt_traj, + 'camera_motion': camera_motion, + 'illum_change': illum_change, + 'motion_change': motion_change, + 'size_change': size_change, + 'occlusion': occlusion} + elif 'VOT2016' == dataset_name: + tag_file = os.path.join(dataset_name, video, 'camera_motion.label') + if os.path.exists(tag_file): + with open(tag_file, 'r') as f: + camera_motion = [int(x.strip()) for x in f.readlines()] + camera_motion += [0] * (len(gt_traj) - len(camera_motion)) + else: + print("File not exists: ", tag_file) + camera_motion = [] # [0] * len(gt_traj) + + tag_file = os.path.join(dataset_name, video, 'illum_change.label') + if os.path.exists(tag_file): + with open(tag_file, 'r') as f: + illum_change = [int(x.strip()) for x in f.readlines()] + illum_change += [0] * (len(gt_traj) - len(illum_change)) + else: + print("File not exists: ", tag_file) + illum_change = [] # [0] * len(gt_traj) + + tag_file = os.path.join(dataset_name, video, 'motion_change.label') + if os.path.exists(tag_file): + with open(tag_file, 'r') as f: + motion_change = [int(x.strip()) for x in f.readlines()] + motion_change += [0] * (len(gt_traj) - len(motion_change)) + else: + print("File not exists: ", tag_file) + motion_change = [] # [0] * len(gt_traj) + + tag_file = os.path.join(dataset_name, video, 'size_change.label') + if os.path.exists(tag_file): + with open(tag_file, 'r') as f: + size_change = [int(x.strip()) for x in f.readlines()] + size_change += [0] * (len(gt_traj) - len(size_change)) + else: + print("File not exists: ", tag_file) + size_change = [] # [0] * len(gt_traj) + + tag_file = os.path.join(dataset_name, video, 'occlusion.label') + if os.path.exists(tag_file): + with open(tag_file, 'r') as f: + occlusion = [int(x.strip()) for x in f.readlines()] + occlusion += [0] * (len(gt_traj) - len(occlusion)) + else: + print("File not exists: ", tag_file) + occlusion = [] # [0] * len(gt_traj) + + meta_data[video] = {'video_dir': video, + 'init_rect': gt_traj[0], + 'img_names': img_names, + 'gt_rect': gt_traj, + 'width': im.shape[1], + 'height': im.shape[0], + 'camera_motion': camera_motion, + 'illum_change': illum_change, + 'motion_change': motion_change, + 'size_change': size_change, + 'occlusion': occlusion} + else: + meta_data[video] = {'video_dir': video, + 'init_rect': gt_traj[0], + 'img_names': img_names, + 'gt_rect': gt_traj, + 'width': im.shape[1], + 'height': im.shape[0]} + + + json.dump(meta_data, open(dataset_name+'.json', 'w')) + +if __name__ == '__main__': + Fire(process) + diff --git a/SiamMask/data/det/gen_json.py b/SiamMask/data/det/gen_json.py new file mode 100644 index 0000000000000000000000000000000000000000..3e23eb81ae3c82ea26b34ca442765e90f3996178 --- /dev/null +++ b/SiamMask/data/det/gen_json.py @@ -0,0 +1,43 @@ +# -------------------------------------------------------- +# SiamMask +# Licensed under The MIT License +# Written by Qiang Wang (wangqiang2015 at ia.ac.cn) +# -------------------------------------------------------- +from os.path import join, isdir +from os import mkdir +import glob +import xml.etree.ElementTree as ET +import json + +js = {} +VID_base_path = './ILSVRC2015' +ann_base_path = join(VID_base_path, 'Annotations/DET/train/') +sub_sets = ('ILSVRC2013_train', 'ILSVRC2013_train_extra0', 'ILSVRC2013_train_extra1', 'ILSVRC2013_train_extra2', 'ILSVRC2013_train_extra3', 'ILSVRC2013_train_extra4', 'ILSVRC2013_train_extra5', 'ILSVRC2013_train_extra6', 'ILSVRC2013_train_extra7', 'ILSVRC2013_train_extra8', 'ILSVRC2013_train_extra9', 'ILSVRC2013_train_extra10', 'ILSVRC2014_train_0000', 'ILSVRC2014_train_0001','ILSVRC2014_train_0002','ILSVRC2014_train_0003','ILSVRC2014_train_0004','ILSVRC2014_train_0005','ILSVRC2014_train_0006') +for sub_set in sub_sets: + sub_set_base_path = join(ann_base_path, sub_set) + + if 'ILSVRC2013_train' == sub_set: + xmls = sorted(glob.glob(join(sub_set_base_path, '*', '*.xml'))) + else: + xmls = sorted(glob.glob(join(sub_set_base_path, '*.xml'))) + n_imgs = len(xmls) + for f, xml in enumerate(xmls): + print('subset: {} frame id: {:08d} / {:08d}'.format(sub_set, f, n_imgs)) + xmltree = ET.parse(xml) + objects = xmltree.findall('object') + + video = join(sub_set, xml.split('/')[-1].split('.')[0]) + + for id, object_iter in enumerate(objects): + bndbox = object_iter.find('bndbox') + bbox = [int(bndbox.find('xmin').text), int(bndbox.find('ymin').text), + int(bndbox.find('xmax').text), int(bndbox.find('ymax').text)] + frame = '%06d' % (0) + obj = '%02d' % (id) + if video not in js: + js[video] = {} + if obj not in js[video]: + js[video][obj] = {} + js[video][obj][frame] = bbox + +json.dump(js, open('train.json', 'w'), indent=4, sort_keys=True) diff --git a/SiamMask/data/det/par_crop.py b/SiamMask/data/det/par_crop.py new file mode 100644 index 0000000000000000000000000000000000000000..84d8a8486455c2b60aa6eb82426aa483fba0f25c --- /dev/null +++ b/SiamMask/data/det/par_crop.py @@ -0,0 +1,135 @@ +# -------------------------------------------------------- +# SiamMask +# Licensed under The MIT License +# Written by Qiang Wang (wangqiang2015 at ia.ac.cn) +# -------------------------------------------------------- +from os.path import join, isdir +from os import mkdir, makedirs +import cv2 +import numpy as np +import glob +import xml.etree.ElementTree as ET +from concurrent import futures +import time +import sys + + +# Print iterations progress (thanks StackOverflow) +def printProgress(iteration, total, prefix='', suffix='', decimals=1, barLength=100): + """ + Call in a loop to create terminal progress bar + @params: + iteration - Required : current iteration (Int) + total - Required : total iterations (Int) + prefix - Optional : prefix string (Str) + suffix - Optional : suffix string (Str) + decimals - Optional : positive number of decimals in percent complete (Int) + barLength - Optional : character length of bar (Int) + """ + formatStr = "{0:." + str(decimals) + "f}" + percents = formatStr.format(100 * (iteration / float(total))) + filledLength = int(round(barLength * iteration / float(total))) + bar = '' * filledLength + '-' * (barLength - filledLength) + sys.stdout.write('\r%s |%s| %s%s %s' % (prefix, bar, percents, '%', suffix)), + if iteration == total: + sys.stdout.write('\x1b[2K\r') + sys.stdout.flush() + + +def crop_hwc(image, bbox, out_sz, padding=(0, 0, 0)): + a = (out_sz - 1) / (bbox[2] - bbox[0]) + b = (out_sz - 1) / (bbox[3] - bbox[1]) + c = -a * bbox[0] + d = -b * bbox[1] + mapping = np.array([[a, 0, c], + [0, b, d]]).astype(np.float) + crop = cv2.warpAffine(image, mapping, (out_sz, out_sz), borderMode=cv2.BORDER_CONSTANT, borderValue=padding) + return crop + + +def pos_s_2_bbox(pos, s): + return [pos[0] - s / 2, pos[1] - s / 2, pos[0] + s / 2, pos[1] + s / 2] + + +def crop_like_SiamFC(image, bbox, context_amount=0.5, exemplar_size=127, instanc_size=255, padding=(0, 0, 0)): + target_pos = [(bbox[2] + bbox[0]) / 2., (bbox[3] + bbox[1]) / 2.] + target_size = [bbox[2] - bbox[0], bbox[3] - bbox[1]] + wc_z = target_size[1] + context_amount * sum(target_size) + hc_z = target_size[0] + context_amount * sum(target_size) + s_z = np.sqrt(wc_z * hc_z) + scale_z = exemplar_size / s_z + d_search = (instanc_size - exemplar_size) / 2 + pad = d_search / scale_z + s_x = s_z + 2 * pad + + z = crop_hwc(image, pos_s_2_bbox(target_pos, s_z), exemplar_size, padding) + x = crop_hwc(image, pos_s_2_bbox(target_pos, s_x), instanc_size, padding) + return z, x + + +def crop_like_SiamFCx(image, bbox, context_amount=0.5, exemplar_size=127, instanc_size=255, padding=(0, 0, 0)): + target_pos = [(bbox[2] + bbox[0]) / 2., (bbox[3] + bbox[1]) / 2.] + target_size = [bbox[2] - bbox[0], bbox[3] - bbox[1]] + wc_z = target_size[1] + context_amount * sum(target_size) + hc_z = target_size[0] + context_amount * sum(target_size) + s_z = np.sqrt(wc_z * hc_z) + scale_z = exemplar_size / s_z + d_search = (instanc_size - exemplar_size) / 2 + pad = d_search / scale_z + s_x = s_z + 2 * pad + + x = crop_hwc(image, pos_s_2_bbox(target_pos, s_x), instanc_size, padding) + return x + + +def crop_xml(xml, sub_set_crop_path, instanc_size=511): + xmltree = ET.parse(xml) + objects = xmltree.findall('object') + + frame_crop_base_path = join(sub_set_crop_path, xml.split('/')[-1].split('.')[0]) + if not isdir(frame_crop_base_path): makedirs(frame_crop_base_path) + + img_path = xml.replace('xml', 'JPEG').replace('Annotations', 'Data') + + im = cv2.imread(img_path) + avg_chans = np.mean(im, axis=(0, 1)) + + for id, object_iter in enumerate(objects): + bndbox = object_iter.find('bndbox') + bbox = [int(bndbox.find('xmin').text), int(bndbox.find('ymin').text), + int(bndbox.find('xmax').text), int(bndbox.find('ymax').text)] + + # z, x = crop_like_SiamFC(im, bbox, instanc_size=instanc_size, padding=avg_chans) + # x = crop_like_SiamFCx(im, bbox, instanc_size=instanc_size, padding=avg_chans) + # cv2.imwrite(join(frame_crop_base_path, '{:06d}.{:02d}.z.jpg'.format(0, id)), z) + x = crop_like_SiamFCx(im, bbox, instanc_size=instanc_size, padding=avg_chans) + cv2.imwrite(join(frame_crop_base_path, '{:06d}.{:02d}.x.jpg'.format(0, id)), x) + + +def main(instanc_size=511, num_threads=24): + crop_path = './crop{:d}'.format(instanc_size) + if not isdir(crop_path): mkdir(crop_path) + VID_base_path = './ILSVRC2015' + ann_base_path = join(VID_base_path, 'Annotations/DET/train/') + sub_sets = ('ILSVRC2013_train', 'ILSVRC2013_train_extra0', 'ILSVRC2013_train_extra1', 'ILSVRC2013_train_extra2', 'ILSVRC2013_train_extra3', 'ILSVRC2013_train_extra4', 'ILSVRC2013_train_extra5', 'ILSVRC2013_train_extra6', 'ILSVRC2013_train_extra7', 'ILSVRC2013_train_extra8', 'ILSVRC2013_train_extra9', 'ILSVRC2013_train_extra10', 'ILSVRC2014_train_0000', 'ILSVRC2014_train_0001','ILSVRC2014_train_0002','ILSVRC2014_train_0003','ILSVRC2014_train_0004','ILSVRC2014_train_0005','ILSVRC2014_train_0006') + for sub_set in sub_sets: + sub_set_base_path = join(ann_base_path, sub_set) + if 'ILSVRC2013_train' == sub_set: + xmls = sorted(glob.glob(join(sub_set_base_path, '*', '*.xml'))) + else: + xmls = sorted(glob.glob(join(sub_set_base_path, '*.xml'))) + + n_imgs = len(xmls) + sub_set_crop_path = join(crop_path, sub_set) + with futures.ProcessPoolExecutor(max_workers=num_threads) as executor: + fs = [executor.submit(crop_xml, xml, sub_set_crop_path, instanc_size) for xml in xmls] + for i, f in enumerate(futures.as_completed(fs)): + printProgress(i, n_imgs, prefix=sub_set, suffix='Done ', barLength=80) + + +if __name__ == '__main__': + since = time.time() + main(int(sys.argv[1]), int(sys.argv[2])) + time_elapsed = time.time() - since + print('Total complete in {:.0f}m {:.0f}s'.format( + time_elapsed // 60, time_elapsed % 60)) diff --git a/SiamMask/data/det/readme.md b/SiamMask/data/det/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..966ee82ed0c62832300babfcf055e472abc7aedd --- /dev/null +++ b/SiamMask/data/det/readme.md @@ -0,0 +1,17 @@ +# Preprocessing DET(Object detection) +Large Scale Visual Recognition Challenge 2015 (ILSVRC2015) + +### Download dataset (49GB) + +````shell +wget http://image-net.org/image/ILSVRC2015/ILSVRC2015_DET.tar.gz +tar -xzvf ./ILSVRC2015_DET.tar.gz +```` + +### Crop & Generate data info (10 min) + +````shell +#python par_crop.py [crop_size] [num_threads] +python par_crop.py 511 12 +python gen_json.py +```` diff --git a/SiamMask/data/det/visual.py b/SiamMask/data/det/visual.py new file mode 100644 index 0000000000000000000000000000000000000000..254133baed59402f7fee80df8794c3998ec3d2a9 --- /dev/null +++ b/SiamMask/data/det/visual.py @@ -0,0 +1,49 @@ +# -------------------------------------------------------- +# SiamMask +# Licensed under The MIT License +# Written by Qiang Wang (wangqiang2015 at ia.ac.cn) +# -------------------------------------------------------- +from os.path import join +from os import listdir +import cv2 +import numpy as np +import glob +import xml.etree.ElementTree as ET + +visual = False +color_bar = np.random.randint(0, 255, (90, 3)) + +VID_base_path = './ILSVRC2015' +ann_base_path = join(VID_base_path, 'Annotations/DET/train/') +img_base_path = join(VID_base_path, 'Data/DET/train/') +sub_sets = sorted({'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'}) +for sub_set in sub_sets: + sub_set_base_path = join(ann_base_path, sub_set) + class_names = sorted(listdir(sub_set_base_path)) + for vi, class_name in enumerate(class_names): + print('subset: {} video id: {:04d} / {:04d}'.format(sub_set, vi, len(class_names))) + + class_base_path = join(sub_set_base_path, class_name) + xmls = sorted(glob.glob(join(class_base_path, '*.xml'))) + for xml in xmls: + f = dict() + xmltree = ET.parse(xml) + size = xmltree.findall('size')[0] + frame_sz = [int(it.text) for it in size] + objects = xmltree.findall('object') + # if visual: + img_path = xml.replace('xml', 'JPEG').replace('Annotations', 'Data') + im = cv2.imread(img_path) + for object_iter in objects: + bndbox = object_iter.find('bndbox') + bbox = [int(bndbox.find('xmin').text), int(bndbox.find('ymin').text), + int(bndbox.find('xmax').text), int(bndbox.find('ymax').text)] + if visual: + pt1 = (int(bbox[0]), int(bbox[1])) + pt2 = (int(bbox[2]), int(bbox[3])) + cv2.rectangle(im, pt1, pt2, color_bar[vi], 3) + if visual: + cv2.imshow('img', im) + cv2.waitKey(500) + +print('done!') diff --git a/SiamMask/data/get_test_data.sh b/SiamMask/data/get_test_data.sh new file mode 100644 index 0000000000000000000000000000000000000000..4f207b245cace471cea2fb5b7223d14986544c34 --- /dev/null +++ b/SiamMask/data/get_test_data.sh @@ -0,0 +1,28 @@ +#!/bin/bash +# VOT +git clone https://github.com/jvlmdr/trackdat.git +cd trackdat +VOT_YEAR=2016 bash scripts/download_vot.sh dl/vot2016 +VOT_YEAR=2018 bash scripts/download_vot.sh dl/vot2018 +VOT_YEAR=2019 bash scripts/download_vot.sh dl/vot2019 +bash scripts/unpack_vot.sh dl/vot2016 ../VOT2016 +bash scripts/unpack_vot.sh dl/vot2018 ../VOT2018 +bash scripts/unpack_vot.sh dl/vot2019 ../VOT2019 +cp dl/vot2016/list.txt ../VOT2016/ +cp dl/vot2018/list.txt ../VOT2018/ +cp dl/vot2019/list.txt ../VOT2019/ +cd .. && rm -rf ./trackdat + +# json file for eval toolkit +wget http://www.robots.ox.ac.uk/~qwang/VOT2016.json +wget http://www.robots.ox.ac.uk/~qwang/VOT2018.json +python create_json.py VOT2019 + +# DAVIS +wget https://data.vision.ee.ethz.ch/csergi/share/davis/DAVIS-2017-trainval-480p.zip +unzip DAVIS-2017-trainval-480p.zip +ln -s ./DAVIS ./DAVIS2016 +ln -s ./DAVIS ./DAVIS2017 + + +# Youtube-VOS diff --git a/SiamMask/data/vid/gen_json.py b/SiamMask/data/vid/gen_json.py new file mode 100644 index 0000000000000000000000000000000000000000..00dd0df4521ca6aa91a7ba93aaac4f094c52164c --- /dev/null +++ b/SiamMask/data/vid/gen_json.py @@ -0,0 +1,85 @@ +# -------------------------------------------------------- +# SiamMask +# Licensed under The MIT License +# Written by Qiang Wang (wangqiang2015 at ia.ac.cn) +# -------------------------------------------------------- +from os.path import join +from os import listdir +import json +import numpy as np + +print('load json (raw vid info), please wait 20 seconds~') +vid = json.load(open('vid.json', 'r')) + + +def check_size(frame_sz, bbox): + min_ratio = 0.1 + max_ratio = 0.75 + # only accept objects >10% and <75% of the total frame + area_ratio = np.sqrt((bbox[2]-bbox[0])*(bbox[3]-bbox[1])/float(np.prod(frame_sz))) + ok = (area_ratio > min_ratio) and (area_ratio < max_ratio) + return ok + + +def check_borders(frame_sz, bbox): + dist_from_border = 0.05 * (bbox[2] - bbox[0] + bbox[3] - bbox[1])/2 + ok = (bbox[0] > dist_from_border) and (bbox[1] > dist_from_border) and \ + ((frame_sz[0] - bbox[2]) > dist_from_border) and \ + ((frame_sz[1] - bbox[3]) > dist_from_border) + return ok + + +snippets = dict() +n_snippets = 0 +n_videos = 0 +for subset in vid: + for video in subset: + n_videos += 1 + frames = video['frame'] + id_set = [] + id_frames = [[]] * 60 # at most 60 objects + for f, frame in enumerate(frames): + objs = frame['objs'] + frame_sz = frame['frame_sz'] + for obj in objs: + trackid = obj['trackid'] + occluded = obj['occ'] + bbox = obj['bbox'] + # if occluded: + # continue + # + # if not(check_size(frame_sz, bbox) and check_borders(frame_sz, bbox)): + # continue + # + # if obj['c'] in ['n01674464', 'n01726692', 'n04468005', 'n02062744']: + # continue + + if trackid not in id_set: + id_set.append(trackid) + id_frames[trackid] = [] + id_frames[trackid].append(f) + if len(id_set) > 0: + snippets[video['base_path']] = dict() + for selected in id_set: + frame_ids = sorted(id_frames[selected]) + sequences = np.split(frame_ids, np.array(np.where(np.diff(frame_ids) > 1)[0]) + 1) + sequences = [s for s in sequences if len(s) > 1] # remove isolated frame. + for seq in sequences: + snippet = dict() + for frame_id in seq: + frame = frames[frame_id] + for obj in frame['objs']: + if obj['trackid'] == selected: + o = obj + continue + snippet[frame['img_path'].split('.')[0]] = o['bbox'] + snippets[video['base_path']]['{:02d}'.format(selected)] = snippet + n_snippets += 1 + print('video: {:d} snippets_num: {:d}'.format(n_videos, n_snippets)) + +train = {k:v for (k,v) in snippets.items() if 'train' in k} +val = {k:v for (k,v) in snippets.items() if 'val' in k} + +json.dump(train, open('train.json', 'w'), indent=4, sort_keys=True) +json.dump(val, open('val.json', 'w'), indent=4, sort_keys=True) +print('done!') diff --git a/SiamMask/data/vid/par_crop.py b/SiamMask/data/vid/par_crop.py new file mode 100644 index 0000000000000000000000000000000000000000..d9c9fdec64844829217083bafe9cf1a504d84149 --- /dev/null +++ b/SiamMask/data/vid/par_crop.py @@ -0,0 +1,139 @@ +# -------------------------------------------------------- +# SiamMask +# Licensed under The MIT License +# Written by Qiang Wang (wangqiang2015 at ia.ac.cn) +# -------------------------------------------------------- +from os.path import join, isdir +from os import listdir, mkdir, makedirs +import cv2 +import numpy as np +import glob +import xml.etree.ElementTree as ET +from concurrent import futures +import sys +import time + +VID_base_path = './ILSVRC2015' +ann_base_path = join(VID_base_path, 'Annotations/VID/train/') +sub_sets= sorted({'ILSVRC2015_VID_train_0000', 'ILSVRC2015_VID_train_0001', 'ILSVRC2015_VID_train_0002', 'ILSVRC2015_VID_train_0003', 'val'}) +# Print iterations progress (thanks StackOverflow) +def printProgress(iteration, total, prefix='', suffix='', decimals=1, barLength=100): + """ + Call in a loop to create terminal progress bar + @params: + iteration - Required : current iteration (Int) + total - Required : total iterations (Int) + prefix - Optional : prefix string (Str) + suffix - Optional : suffix string (Str) + decimals - Optional : positive number of decimals in percent complete (Int) + barLength - Optional : character length of bar (Int) + """ + formatStr = "{0:." + str(decimals) + "f}" + percents = formatStr.format(100 * (iteration / float(total))) + filledLength = int(round(barLength * iteration / float(total))) + bar = '' * filledLength + '-' * (barLength - filledLength) + sys.stdout.write('\r%s |%s| %s%s %s' % (prefix, bar, percents, '%', suffix)), + if iteration == total: + sys.stdout.write('\x1b[2K\r') + sys.stdout.flush() + + +def crop_hwc(image, bbox, out_sz, padding=(0, 0, 0)): + a = (out_sz-1) / (bbox[2]-bbox[0]) + b = (out_sz-1) / (bbox[3]-bbox[1]) + c = -a * bbox[0] + d = -b * bbox[1] + mapping = np.array([[a, 0, c], + [0, b, d]]).astype(np.float) + crop = cv2.warpAffine(image, mapping, (out_sz, out_sz), borderMode=cv2.BORDER_CONSTANT, borderValue=padding) + return crop + + +def pos_s_2_bbox(pos, s): + return [pos[0]-s/2, pos[1]-s/2, pos[0]+s/2, pos[1]+s/2] + + +def crop_like_SiamFC(image, bbox, context_amount=0.5, exemplar_size=127, instanc_size=255, padding=(0, 0, 0)): + target_pos = [(bbox[2]+bbox[0])/2., (bbox[3]+bbox[1])/2.] + target_size = [bbox[2]-bbox[0], bbox[3]-bbox[1]] + wc_z = target_size[1] + context_amount * sum(target_size) + hc_z = target_size[0] + context_amount * sum(target_size) + s_z = np.sqrt(wc_z * hc_z) + scale_z = exemplar_size / s_z + d_search = (instanc_size - exemplar_size) / 2 + pad = d_search / scale_z + s_x = s_z + 2 * pad + + z = crop_hwc(image, pos_s_2_bbox(target_pos, s_z), exemplar_size, padding) + x = crop_hwc(image, pos_s_2_bbox(target_pos, s_x), instanc_size, padding) + return z, x + + +def crop_like_SiamFCx(image, bbox, context_amount=0.5, exemplar_size=127, instanc_size=255, padding=(0, 0, 0)): + target_pos = [(bbox[2]+bbox[0])/2., (bbox[3]+bbox[1])/2.] + target_size = [bbox[2]-bbox[0], bbox[3]-bbox[1]] + wc_z = target_size[1] + context_amount * sum(target_size) + hc_z = target_size[0] + context_amount * sum(target_size) + s_z = np.sqrt(wc_z * hc_z) + scale_z = exemplar_size / s_z + d_search = (instanc_size - exemplar_size) / 2 + pad = d_search / scale_z + s_x = s_z + 2 * pad + + x = crop_hwc(image, pos_s_2_bbox(target_pos, s_x), instanc_size, padding) + return x + + +def crop_video(sub_set, video, crop_path, instanc_size): + video_crop_base_path = join(crop_path, sub_set, video) + if not isdir(video_crop_base_path): makedirs(video_crop_base_path) + + sub_set_base_path = join(ann_base_path, sub_set) + xmls = sorted(glob.glob(join(sub_set_base_path, video, '*.xml'))) + for xml in xmls: + xmltree = ET.parse(xml) + # size = xmltree.findall('size')[0] + # frame_sz = [int(it.text) for it in size] + objects = xmltree.findall('object') + objs = [] + filename = xmltree.findall('filename')[0].text + + im = cv2.imread(xml.replace('xml', 'JPEG').replace('Annotations', 'Data')) + avg_chans = np.mean(im, axis=(0, 1)) + for object_iter in objects: + trackid = int(object_iter.find('trackid').text) + # name = (object_iter.find('name')).text + bndbox = object_iter.find('bndbox') + # occluded = int(object_iter.find('occluded').text) + + bbox = [int(bndbox.find('xmin').text), int(bndbox.find('ymin').text), + int(bndbox.find('xmax').text), int(bndbox.find('ymax').text)] + # z, x = crop_like_SiamFC(im, bbox, instanc_size=instanc_size, padding=avg_chans) + # cv2.imwrite(join(video_crop_base_path, '{:06d}.{:02d}.z.jpg'.format(int(filename), trackid)), z) + # cv2.imwrite(join(video_crop_base_path, '{:06d}.{:02d}.x.jpg'.format(int(filename), trackid)), x) + + x = crop_like_SiamFCx(im, bbox, instanc_size=instanc_size, padding=avg_chans) + cv2.imwrite(join(video_crop_base_path, '{:06d}.{:02d}.x.jpg'.format(int(filename), trackid)), x) + + +def main(instanc_size=511, num_threads=24): + crop_path = './crop{:d}'.format(instanc_size) + if not isdir(crop_path): mkdir(crop_path) + + for sub_set in sub_sets: + sub_set_base_path = join(ann_base_path, sub_set) + videos = sorted(listdir(sub_set_base_path)) + n_videos = len(videos) + with futures.ProcessPoolExecutor(max_workers=num_threads) as executor: + fs = [executor.submit(crop_video, sub_set, video, crop_path, instanc_size) for video in videos] + for i, f in enumerate(futures.as_completed(fs)): + # Write progress to error so that it can be seen + printProgress(i, n_videos, prefix=sub_set, suffix='Done ', barLength=40) + + +if __name__ == '__main__': + since = time.time() + main(int(sys.argv[1]), int(sys.argv[2])) + time_elapsed = time.time() - since + print('Total complete in {:.0f}m {:.0f}s'.format( + time_elapsed // 60, time_elapsed % 60)) diff --git a/SiamMask/data/vid/parse_vid.py b/SiamMask/data/vid/parse_vid.py new file mode 100644 index 0000000000000000000000000000000000000000..f5e8cd1a2a6b7c00dfd2c52867e4521eeab603e2 --- /dev/null +++ b/SiamMask/data/vid/parse_vid.py @@ -0,0 +1,56 @@ +# -------------------------------------------------------- +# SiamMask +# Licensed under The MIT License +# Written by Qiang Wang (wangqiang2015 at ia.ac.cn) +# -------------------------------------------------------- +from os.path import join +from os import listdir +import json +import glob +import xml.etree.ElementTree as ET + +VID_base_path = './ILSVRC2015' +ann_base_path = join(VID_base_path, 'Annotations/VID/train/') +img_base_path = join(VID_base_path, 'Data/VID/train/') +sub_sets = sorted({'ILSVRC2015_VID_train_0000', 'ILSVRC2015_VID_train_0001', 'ILSVRC2015_VID_train_0002', 'ILSVRC2015_VID_train_0003', 'val'}) + +vid = [] +for sub_set in sub_sets: + sub_set_base_path = join(ann_base_path, sub_set) + videos = sorted(listdir(sub_set_base_path)) + s = [] + for vi, video in enumerate(videos): + print('subset: {} video id: {:04d} / {:04d}'.format(sub_set, vi, len(videos))) + v = dict() + v['base_path'] = join(sub_set, video) + v['frame'] = [] + video_base_path = join(sub_set_base_path, video) + xmls = sorted(glob.glob(join(video_base_path, '*.xml'))) + for xml in xmls: + f = dict() + xmltree = ET.parse(xml) + size = xmltree.findall('size')[0] + frame_sz = [int(it.text) for it in size] + objects = xmltree.findall('object') + objs = [] + for object_iter in objects: + trackid = int(object_iter.find('trackid').text) + name = (object_iter.find('name')).text + bndbox = object_iter.find('bndbox') + occluded = int(object_iter.find('occluded').text) + o = dict() + o['c'] = name + o['bbox'] = [int(bndbox.find('xmin').text), int(bndbox.find('ymin').text), + int(bndbox.find('xmax').text), int(bndbox.find('ymax').text)] + o['trackid'] = trackid + o['occ'] = occluded + objs.append(o) + f['frame_sz'] = frame_sz + f['img_path'] = xml.split('/')[-1].replace('xml', 'JPEG') + f['objs'] = objs + v['frame'].append(f) + s.append(v) + vid.append(s) +print('save json (raw vid info), please wait 1 min~') +json.dump(vid, open('vid.json', 'w'), indent=4, sort_keys=True) +print('done!') diff --git a/SiamMask/data/vid/readme.md b/SiamMask/data/vid/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..b4e0d31eafa0635ddab6f0458098394237f1fe29 --- /dev/null +++ b/SiamMask/data/vid/readme.md @@ -0,0 +1,21 @@ +# Preprocessing VID(Object detection from video) +Large Scale Visual Recognition Challenge 2015 (ILSVRC2015) + +### Download dataset (86GB) + +````shell +wget http://bvisionweb1.cs.unc.edu/ilsvrc2015/ILSVRC2015_VID.tar.gz +tar -xzvf ./ILSVRC2015_VID.tar.gz +mv ILSVRC2015/Annotations/VID/val ILSVRC2015/Annotations/VID/train/ +mv ILSVRC2015/Data/VID/val ILSVRC2015/Data/VID/train/ +```` + +### Crop & Generate data info (20 min) + +````shell +python parse_vid.py + +#python par_crop.py [crop_size] [num_threads] +python par_crop.py 511 12 +python gen_json.py +```` diff --git a/SiamMask/data/vid/visual.py b/SiamMask/data/vid/visual.py new file mode 100644 index 0000000000000000000000000000000000000000..14f4af73ae788d5b711159c05fa5e59b1e9e8d6d --- /dev/null +++ b/SiamMask/data/vid/visual.py @@ -0,0 +1,49 @@ +# -------------------------------------------------------- +# SiamMask +# Licensed under The MIT License +# Written by Qiang Wang (wangqiang2015 at ia.ac.cn) +# -------------------------------------------------------- +from os.path import join +from os import listdir +import cv2 +import numpy as np +import glob +import xml.etree.ElementTree as ET + +visual = False +color_bar = np.random.randint(0, 255, (90, 3)) + +VID_base_path = './ILSVRC2015' +ann_base_path = join(VID_base_path, 'Annotations/VID/train/') +img_base_path = join(VID_base_path, 'Data/VID/train/') +sub_sets = sorted({'a', 'b', 'c', 'd', 'e'}) +for sub_set in sub_sets: + sub_set_base_path = join(ann_base_path, sub_set) + videos = sorted(listdir(sub_set_base_path)) + for vi, video in enumerate(videos): + print('subset: {} video id: {:04d} / {:04d}'.format(sub_set, vi, len(videos))) + + video_base_path = join(sub_set_base_path, video) + xmls = sorted(glob.glob(join(video_base_path, '*.xml'))) + for xml in xmls: + f = dict() + xmltree = ET.parse(xml) + size = xmltree.findall('size')[0] + frame_sz = [int(it.text) for it in size] + objects = xmltree.findall('object') + if visual: + im = cv2.imread(xml.replace('xml', 'JPEG').replace('Annotations', 'Data')) + for object_iter in objects: + trackid = int(object_iter.find('trackid').text) + bndbox = object_iter.find('bndbox') + bbox = [int(bndbox.find('xmin').text), int(bndbox.find('ymin').text), + int(bndbox.find('xmax').text), int(bndbox.find('ymax').text)] + if visual: + pt1 = (int(bbox[0]), int(bbox[1])) + pt2 = (int(bbox[2]), int(bbox[3])) + cv2.rectangle(im, pt1, pt2, color_bar[trackid], 3) + if visual: + cv2.imshow('img', im) + cv2.waitKey(1) + +print('done!') diff --git a/SiamMask/data/ytb_vos/download_from_gdrive.py b/SiamMask/data/ytb_vos/download_from_gdrive.py new file mode 100644 index 0000000000000000000000000000000000000000..b4f329f2b46657ae2b91185175ea867564dc203f --- /dev/null +++ b/SiamMask/data/ytb_vos/download_from_gdrive.py @@ -0,0 +1,152 @@ +#!/usr/bin/env python + +from __future__ import print_function + +import argparse +import os +import os.path as osp +import re +import shutil +import sys +import tempfile + +import requests +import six +import tqdm + + +# BORROWED FROM GDOWN + + + +CHUNK_SIZE = 512 * 1024 # 512KB + + +def get_url_from_gdrive_confirmation(contents): + url = '' + for line in contents.splitlines(): + m = re.search('href="(\/uc\?export=download[^"]+)', line) + if m: + url = 'https://docs.google.com' + m.groups()[0] + url = url.replace('&', '&') + return url + m = re.search('confirm=([^;&]+)', line) + if m: + confirm = m.groups()[0] + url = re.sub(r'confirm=([^;&]+)', r'confirm='+confirm, url) + return url + m = re.search('"downloadUrl":"([^"]+)', line) + if m: + url = m.groups()[0] + url = url.replace('\\u003d', '=') + url = url.replace('\\u0026', '&') + return url + + +def is_google_drive_url(url): + m = re.match('^https?://drive.google.com/uc\?id=.*$', url) + return m is not None + + +def download(url, output, quiet): + url_origin = url + sess = requests.session() + + is_gdrive = is_google_drive_url(url) + + while True: + res = sess.get(url, stream=True) + if 'Content-Disposition' in res.headers: + # This is the file + break + if not is_gdrive: + break + + # Need to redirect with confiramtion + url = get_url_from_gdrive_confirmation(res.text) + + if url is None: + print('Permission denied: %s' % url_origin, file=sys.stderr) + print("Maybe you need to change permission over " + "'Anyone with the link'?", file=sys.stderr) + return + + if output is None: + if is_gdrive: + m = re.search('filename="(.*)"', + res.headers['Content-Disposition']) + output = m.groups()[0] + else: + output = osp.basename(url) + + output_is_path = isinstance(output, six.string_types) + + if not quiet: + print('Downloading...', file=sys.stderr) + print('From:', url_origin, file=sys.stderr) + print('To:', osp.abspath(output) if output_is_path else output, + file=sys.stderr) + + if output_is_path: + tmp_file = tempfile.mktemp( + suffix=tempfile.template, + prefix=osp.basename(output), + dir=osp.dirname(output), + ) + f = open(tmp_file, 'wb') + else: + tmp_file = None + f = output + + try: + total = res.headers.get('Content-Length') + if total is not None: + total = int(total) + if not quiet: + pbar = tqdm.tqdm(total=total, unit='B', unit_scale=True) + for chunk in res.iter_content(chunk_size=CHUNK_SIZE): + f.write(chunk) + if not quiet: + pbar.update(len(chunk)) + if not quiet: + pbar.close() + if tmp_file: + f.close() + shutil.copy(tmp_file, output) + except IOError as e: + print(e, file=sys.stderr) + return + finally: + try: + if tmp_file: + os.remove(tmp_file) + except OSError: + pass + + return output + + + +def main(): + parser = argparse.ArgumentParser( + formatter_class=argparse.ArgumentDefaultsHelpFormatter) + parser.add_argument( + 'url_or_id', help='url or file id (with --id) to download file from') + parser.add_argument('-O', '--output', help='output filename') + parser.add_argument('-q', '--quiet', action='store_true', + help='suppress standard output') + parser.add_argument('--id', action='store_true', + help='flag to specify file id instead of url') + args = parser.parse_args() + + print(args) + if args.output == '-': + if six.PY3: + args.output = sys.stdout.buffer + else: + args.output = sys.stdout + + download(args.url_or_id, args.output, args.quiet) + +if __name__ == '__main__': + main() diff --git a/SiamMask/data/ytb_vos/gen_json.py b/SiamMask/data/ytb_vos/gen_json.py new file mode 100644 index 0000000000000000000000000000000000000000..7893e7cc8e1f3f310dd82c9953d0a246e1a890c4 --- /dev/null +++ b/SiamMask/data/ytb_vos/gen_json.py @@ -0,0 +1,30 @@ +# -------------------------------------------------------- +# SiamMask +# Licensed under The MIT License +# Written by Qiang Wang (wangqiang2015 at ia.ac.cn) +# -------------------------------------------------------- +import json + +print('load json (raw ytb_vos info), please wait 10 seconds~') +ytb_vos = json.load(open('instances_train.json', 'r')) +snippets = dict() +for k, v in ytb_vos.items(): + video = dict() + for i, o in enumerate(list(v)): + obj = v[o] + snippet = dict() + trackid = "{:02d}".format(i) + for frame in obj: + file_name = frame['file_name'] + frame_name = '{:06d}'.format(int(file_name.split('/')[-1])) + bbox = frame['bbox'] + bbox[2] += bbox[0] + bbox[3] += bbox[1] + snippet[frame_name] = bbox + video[trackid] = snippet + snippets['train/'+k] = video + +train = snippets + +json.dump(train, open('train.json', 'w'), indent=4, sort_keys=True) +print('done!') diff --git a/SiamMask/data/ytb_vos/par_crop.py b/SiamMask/data/ytb_vos/par_crop.py new file mode 100644 index 0000000000000000000000000000000000000000..34faf2915a4d9c58309262a2dc0815a4ff8573d4 --- /dev/null +++ b/SiamMask/data/ytb_vos/par_crop.py @@ -0,0 +1,140 @@ +# -------------------------------------------------------- +# SiamMask +# Licensed under The MIT License +# Written by Qiang Wang (wangqiang2015 at ia.ac.cn) +# -------------------------------------------------------- +import cv2 +import numpy as np +from os.path import join, isdir +from os import mkdir, makedirs +from concurrent import futures +import sys +import time +import json +import glob + + +# Print iterations progress (thanks StackOverflow) +def printProgress(iteration, total, prefix='', suffix='', decimals=1, barLength=100): + """ + Call in a loop to create terminal progress bar + @params: + iteration - Required : current iteration (Int) + total - Required : total iterations (Int) + prefix - Optional : prefix string (Str) + suffix - Optional : suffix string (Str) + decimals - Optional : positive number of decimals in percent complete (Int) + barLength - Optional : character length of bar (Int) + """ + formatStr = "{0:." + str(decimals) + "f}" + percents = formatStr.format(100 * (iteration / float(total))) + filledLength = int(round(barLength * iteration / float(total))) + bar = '' * filledLength + '-' * (barLength - filledLength) + sys.stdout.write('\r%s |%s| %s%s %s' % (prefix, bar, percents, '%', suffix)), + if iteration == total: + sys.stdout.write('\x1b[2K\r') + sys.stdout.flush() + + +def crop_hwc(image, bbox, out_sz, padding=(0, 0, 0)): + a = (out_sz-1) / (bbox[2]-bbox[0]) + b = (out_sz-1) / (bbox[3]-bbox[1]) + c = -a * bbox[0] + d = -b * bbox[1] + mapping = np.array([[a, 0, c], + [0, b, d]]).astype(np.float) + crop = cv2.warpAffine(image, mapping, (out_sz, out_sz), borderMode=cv2.BORDER_CONSTANT, borderValue=padding) + return crop + + +def pos_s_2_bbox(pos, s): + return [pos[0]-s/2, pos[1]-s/2, pos[0]+s/2, pos[1]+s/2] + + +def crop_like_SiamFC(image, bbox, context_amount=0.5, exemplar_size=127, instanc_size=255, padding=(0, 0, 0)): + target_pos = [(bbox[2]+bbox[0])/2., (bbox[3]+bbox[1])/2.] + target_size = [bbox[2]-bbox[0], bbox[3]-bbox[1]] + wc_z = target_size[1] + context_amount * sum(target_size) + hc_z = target_size[0] + context_amount * sum(target_size) + s_z = np.sqrt(wc_z * hc_z) + scale_z = exemplar_size / s_z + d_search = (instanc_size - exemplar_size) / 2 + pad = d_search / scale_z + s_x = s_z + 2 * pad + + z = crop_hwc(image, pos_s_2_bbox(target_pos, s_z), exemplar_size, padding) + x = crop_hwc(image, pos_s_2_bbox(target_pos, s_x), instanc_size, padding) + return z, x + + +def crop_like_SiamFCx(image, bbox, context_amount=0.5, exemplar_size=127, instanc_size=255, padding=(0, 0, 0)): + target_pos = [(bbox[2]+bbox[0])/2., (bbox[3]+bbox[1])/2.] + target_size = [bbox[2]-bbox[0], bbox[3]-bbox[1]] + wc_z = target_size[1] + context_amount * sum(target_size) + hc_z = target_size[0] + context_amount * sum(target_size) + s_z = np.sqrt(wc_z * hc_z) + scale_z = exemplar_size / s_z + d_search = (instanc_size - exemplar_size) / 2 + pad = d_search / scale_z + s_x = s_z + 2 * pad + + x = crop_hwc(image, pos_s_2_bbox(target_pos, s_x), instanc_size, padding) + return x + + +def crop_video(video, v, crop_path, data_path, instanc_size): + video_crop_base_path = join(crop_path, video) + if not isdir(video_crop_base_path): makedirs(video_crop_base_path) + + anno_base_path = join(data_path, 'Annotations') + img_base_path = join(data_path, 'JPEGImages') + + for trackid, o in enumerate(list(v)): + obj = v[o] + for frame in obj: + file_name = frame['file_name'] + ann_path = join(anno_base_path, file_name+'.png') + img_path = join(img_base_path, file_name+'.jpg') + im = cv2.imread(img_path) + label = cv2.imread(ann_path, 0) + avg_chans = np.mean(im, axis=(0, 1)) + bbox = frame['bbox'] + bbox[2] += bbox[0] + bbox[3] += bbox[1] + x = crop_like_SiamFCx(im, bbox, instanc_size=instanc_size, padding=avg_chans) + cv2.imwrite(join(video_crop_base_path, '{:06d}.{:02d}.x.jpg'.format(int(file_name.split('/')[-1]), trackid)), x) + mask = crop_like_SiamFCx((label==int(o)).astype(np.float32), bbox, instanc_size=instanc_size, padding=0) + mask = ((mask > 0.2)*255).astype(np.uint8) + x[:,:,0] = mask + (mask == 0)*x[:,:,0] + # cv2.imshow('maskonx', x) + # cv2.waitKey(0) + cv2.imwrite(join(video_crop_base_path, '{:06d}.{:02d}.m.png'.format(int(file_name.split('/')[-1]), trackid)), mask) + + +def main(instanc_size=511, num_threads=12): + dataDir = '.' + crop_path = './crop{:d}'.format(instanc_size) + if not isdir(crop_path): mkdir(crop_path) + + for dataType in ['train']: + set_crop_base_path = join(crop_path, dataType) + set_img_base_path = join(dataDir, dataType) + + annFile = '{}/instances_{}.json'.format(dataDir, dataType) + ytb_vos = json.load(open(annFile,'r')) + n_video = len(ytb_vos) + with futures.ProcessPoolExecutor(max_workers=num_threads) as executor: + fs = [executor.submit(crop_video, k, v, set_crop_base_path, set_img_base_path, instanc_size) + for k,v in ytb_vos.items()] + for i, f in enumerate(futures.as_completed(fs)): + # Write progress to error so that it can be seen + printProgress(i, n_video, prefix=dataType, suffix='Done ', barLength=40) + print('done') + + +if __name__ == '__main__': + since = time.time() + main(int(sys.argv[1]), int(sys.argv[2])) + time_elapsed = time.time() - since + print('Total complete in {:.0f}m {:.0f}s'.format( + time_elapsed // 60, time_elapsed % 60)) diff --git a/SiamMask/data/ytb_vos/parse_ytb_vos.py b/SiamMask/data/ytb_vos/parse_ytb_vos.py new file mode 100644 index 0000000000000000000000000000000000000000..53234842e30e13e12e26fa1893e865f8bc1e1a7a --- /dev/null +++ b/SiamMask/data/ytb_vos/parse_ytb_vos.py @@ -0,0 +1,174 @@ +# -------------------------------------------------------- +# SiamMask +# Licensed under The MIT License +# Written by Qiang Wang (wangqiang2015 at ia.ac.cn) +# -------------------------------------------------------- +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + +import argparse +import h5py +import json +import os +import scipy.misc +import sys +import numpy as np +import cv2 +from os.path import join + + +def parse_args(): + parser = argparse.ArgumentParser(description='Convert dataset') + parser.add_argument('--outdir', default='./', type=str, + help="output dir for json files") + parser.add_argument('--datadir', default='./', type=str, + help="data dir for annotations to be converted") + return parser.parse_args() + + +def xyxy_to_xywh(xyxy): + """Convert [x1 y1 x2 y2] box format to [x1 y1 w h] format.""" + if isinstance(xyxy, (list, tuple)): + # Single box given as a list of coordinates + assert len(xyxy) == 4 + x1, y1 = xyxy[0], xyxy[1] + w = xyxy[2] - x1 + 1 + h = xyxy[3] - y1 + 1 + return (x1, y1, w, h) + elif isinstance(xyxy, np.ndarray): + # Multiple boxes given as a 2D ndarray + return np.hstack((xyxy[:, 0:2], xyxy[:, 2:4] - xyxy[:, 0:2] + 1)) + else: + raise TypeError('Argument xyxy must be a list, tuple, or numpy array.') + + +def polys_to_boxes(polys): + """Convert a list of polygons into an array of tight bounding boxes.""" + boxes_from_polys = np.zeros((len(polys), 4), dtype=np.float32) + for i in range(len(polys)): + poly = polys[i] + x0 = min(min(p[::2]) for p in poly) + x1 = max(max(p[::2]) for p in poly) + y0 = min(min(p[1::2]) for p in poly) + y1 = max(max(p[1::2]) for p in poly) + boxes_from_polys[i, :] = [x0, y0, x1, y1] + return boxes_from_polys + + +class Instance(object): + instID = 0 + pixelCount = 0 + + def __init__(self, imgNp, instID): + if (instID ==0 ): + return + self.instID = int(instID) + self.pixelCount = int(self.getInstancePixels(imgNp, instID)) + + def getInstancePixels(self, imgNp, instLabel): + return (imgNp == instLabel).sum() + + def toDict(self): + buildDict = {} + buildDict["instID"] = self.instID + buildDict["pixelCount"] = self.pixelCount + return buildDict + + def __str__(self): + return "("+str(self.instID)+")" + + +def convert_ytb_vos(data_dir, out_dir): + sets = ['train'] + ann_dirs = ['train/Annotations/'] + json_name = 'instances_%s.json' + num_obj = 0 + num_ann = 0 + for data_set, ann_dir in zip(sets, ann_dirs): + print('Starting %s' % data_set) + ann_dict = {} + ann_dir = os.path.join(data_dir, ann_dir) + json_ann = json.load(open(os.path.join(ann_dir, '../meta.json'))) + for vid, video in enumerate(json_ann['videos']): + v = json_ann['videos'][video] + frames = [] + for obj in v['objects']: + o = v['objects'][obj] + frames.extend(o['frames']) + frames = sorted(set(frames)) + + annotations = [] + instanceIds = [] + for frame in frames: + file_name = join(video, frame) + fullname = os.path.join(ann_dir, file_name+'.png') + img = cv2.imread(fullname, 0) + h, w = img.shape[:2] + + objects = dict() + for instanceId in np.unique(img): + if instanceId == 0: + continue + instanceObj = Instance(img, instanceId) + instanceObj_dict = instanceObj.toDict() + mask = (img == instanceId).astype(np.uint8) + _, contour, _ = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) + polygons = [c.reshape(-1).tolist() for c in contour] + instanceObj_dict['contours'] = [p for p in polygons if len(p) > 4] + if len(instanceObj_dict['contours']) and instanceObj_dict['pixelCount'] > 1000: + objects[instanceId] = instanceObj_dict + # else: + # cv2.imshow("disappear?", mask) + # cv2.waitKey(0) + + for objId in objects: + if len(objects[objId]) == 0: + continue + obj = objects[objId] + len_p = [len(p) for p in obj['contours']] + if min(len_p) <= 4: + print('Warning: invalid contours.') + continue # skip non-instance categories + + ann = dict() + ann['h'] = h + ann['w'] = w + ann['file_name'] = file_name + ann['id'] = int(objId) + # ann['segmentation'] = obj['contours'] + # ann['iscrowd'] = 0 + ann['area'] = obj['pixelCount'] + ann['bbox'] = xyxy_to_xywh(polys_to_boxes([obj['contours']])).tolist()[0] + + annotations.append(ann) + instanceIds.append(objId) + num_ann += 1 + instanceIds = sorted(set(instanceIds)) + num_obj += len(instanceIds) + video_ann = {str(iId): [] for iId in instanceIds} + for ann in annotations: + video_ann[str(ann['id'])].append(ann) + + ann_dict[video] = video_ann + if vid % 50 == 0 and vid != 0: + print("process: %d video" % (vid+1)) + + print("Num Videos: %d" % len(ann_dict)) + print("Num Objects: %d" % num_obj) + print("Num Annotations: %d" % num_ann) + + items = list(ann_dict.items()) + train_dict = dict(items[:3000]) + val_dict = dict(items[3000:]) + with open(os.path.join(out_dir, json_name % 'train'), 'w') as outfile: + json.dump(train_dict, outfile) + + with open(os.path.join(out_dir, json_name % 'val'), 'w') as outfile: + json.dump(val_dict, outfile) + + +if __name__ == '__main__': + args = parse_args() + convert_ytb_vos(args.datadir, args.outdir) diff --git a/SiamMask/data/ytb_vos/readme.md b/SiamMask/data/ytb_vos/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..a924f8cc6ae1fd293849c9a236c74038df87cc95 --- /dev/null +++ b/SiamMask/data/ytb_vos/readme.md @@ -0,0 +1,17 @@ +# Preprocessing [Youtube-VOS](https://youtube-vos.org/dataset/download) + +### Download raw images and annotations ([website](https://youtube-vos.org/dataset/download), 8.3G) + +````shell +python download_from_gdrive.py https://drive.google.com/uc?id=18S_db1cFgSD1RsMsofJLkd6SyR9opk6a --output train.zip +unzip ./train.zip +python parse_ytb_vos.py # really slow +```` + +### Crop & Generate data info (10 min) + +````shell +#python par_crop.py [crop_size] [num_threads] +python par_crop.py 511 12 +python gen_json.py +```` diff --git a/SiamMask/datasets/__init__.py b/SiamMask/datasets/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SiamMask/datasets/siam_mask_dataset.py b/SiamMask/datasets/siam_mask_dataset.py new file mode 100644 index 0000000000000000000000000000000000000000..d8ccb0fc551a93d038629bcda844543af8f32669 --- /dev/null +++ b/SiamMask/datasets/siam_mask_dataset.py @@ -0,0 +1,607 @@ +# -------------------------------------------------------- +# SiamMask +# Licensed under The MIT License +# Written by Qiang Wang (wangqiang2015 at ia.ac.cn) +# -------------------------------------------------------- +from __future__ import division +from torch.utils.data import Dataset +import numpy as np +import json +import random +import logging +from os.path import join +from utils.bbox_helper import * +from utils.anchors import Anchors +import math +import sys +pyv = sys.version[0] +import cv2 +if pyv[0] == '3': + cv2.ocl.setUseOpenCL(False) + +logger = logging.getLogger('global') + + +sample_random = random.Random() +sample_random.seed(123456) + + +class SubDataSet(object): + def __init__(self, cfg): + for string in ['root', 'anno']: + if string not in cfg: + raise Exception('SubDataSet need "{}"'.format(string)) + + with open(cfg['anno']) as fin: + logger.info("loading " + cfg['anno']) + self.labels = self.filter_zero(json.load(fin), cfg) + + def isint(x): + try: + int(x) + return True + except: + return False + + # add frames args into labels + to_del = [] + for video in self.labels: + for track in self.labels[video]: + frames = self.labels[video][track] + frames = list(map(int, filter(lambda x: isint(x), frames.keys()))) + frames.sort() + self.labels[video][track]['frames'] = frames + if len(frames) <= 0: + logger.info("warning {}/{} has no frames.".format(video, track)) + to_del.append((video, track)) + + # delete tracks with no frames + for video, track in to_del: + del self.labels[video][track] + + # delete videos with no valid track + to_del = [] + for video in self.labels: + if len(self.labels[video]) <= 0: + logger.info("warning {} has no tracks".format(video)) + to_del.append(video) + + for video in to_del: + del self.labels[video] + + self.videos = list(self.labels.keys()) + + logger.info(cfg['anno'] + " loaded.") + + # default args + self.root = "/" + self.start = 0 + self.num = len(self.labels) + self.num_use = self.num + self.frame_range = 100 + self.mark = "vid" + self.path_format = "{}.{}.{}.jpg" + self.mask_format = "{}.{}.m.png" + + self.pick = [] + + # input args + self.__dict__.update(cfg) + + self.has_mask = self.mark in ['coco', 'ytb_vos'] + + self.num_use = int(self.num_use) + + # shuffle + self.shuffle() + + def filter_zero(self, anno, cfg): + name = cfg.get('mark', '') + + out = {} + tot = 0 + new = 0 + zero = 0 + + for video, tracks in anno.items(): + new_tracks = {} + for trk, frames in tracks.items(): + new_frames = {} + for frm, bbox in frames.items(): + tot += 1 + if len(bbox) == 4: + x1, y1, x2, y2 = bbox + w, h = x2 - x1, y2 - y1 + else: + w, h = bbox + if w == 0 or h == 0: + logger.info('Error, {name} {video} {trk} {bbox}'.format(**locals())) + zero += 1 + continue + new += 1 + new_frames[frm] = bbox + + if len(new_frames) > 0: + new_tracks[trk] = new_frames + + if len(new_tracks) > 0: + out[video] = new_tracks + + return out + + def log(self): + logger.info('SubDataSet {name} start-index {start} select [{select}/{num}] path {format}'.format( + name=self.mark, start=self.start, select=self.num_use, num=self.num, format=self.path_format + )) + + def shuffle(self): + lists = list(range(self.start, self.start + self.num)) + + m = 0 + pick = [] + while m < self.num_use: + sample_random.shuffle(lists) + pick += lists + m += self.num + + self.pick = pick[:self.num_use] + return self.pick + + def get_image_anno(self, video, track, frame): + frame = "{:06d}".format(frame) + image_path = join(self.root, video, self.path_format.format(frame, track, 'x')) + image_anno = self.labels[video][track][frame] + + mask_path = join(self.root, video, self.mask_format.format(frame, track)) + + return image_path, image_anno, mask_path + + def get_positive_pair(self, index): + video_name = self.videos[index] + video = self.labels[video_name] + track = random.choice(list(video.keys())) + track_info = video[track] + + frames = track_info['frames'] + + if 'hard' not in track_info: + template_frame = random.randint(0, len(frames)-1) + + left = max(template_frame - self.frame_range, 0) + right = min(template_frame + self.frame_range, len(frames)-1) + 1 + search_range = frames[left:right] + template_frame = frames[template_frame] + search_frame = random.choice(search_range) + else: + search_frame = random.choice(track_info['hard']) + left = max(search_frame - self.frame_range, 0) + right = min(search_frame + self.frame_range, len(frames)-1) + 1 # python [left:right+1) = [left:right] + template_range = frames[left:right] + template_frame = random.choice(template_range) + search_frame = frames[search_frame] + + return self.get_image_anno(video_name, track, template_frame), \ + self.get_image_anno(video_name, track, search_frame) + + def get_random_target(self, index=-1): + if index == -1: + index = random.randint(0, self.num-1) + video_name = self.videos[index] + video = self.labels[video_name] + track = random.choice(list(video.keys())) + track_info = video[track] + + frames = track_info['frames'] + frame = random.choice(frames) + + return self.get_image_anno(video_name, track, frame) + + +def crop_hwc(image, bbox, out_sz, padding=(0, 0, 0)): + bbox = [float(x) for x in bbox] + a = (out_sz-1) / (bbox[2]-bbox[0]) + b = (out_sz-1) / (bbox[3]-bbox[1]) + c = -a * bbox[0] + d = -b * bbox[1] + mapping = np.array([[a, 0, c], + [0, b, d]]).astype(np.float) + crop = cv2.warpAffine(image, mapping, (out_sz, out_sz), borderMode=cv2.BORDER_CONSTANT, borderValue=padding) + return crop + + +class Augmentation: + def __init__(self, cfg): + # default args + self.shift = 0 + self.scale = 0 + self.blur = 0 # False + self.resize = False + self.rgbVar = np.array([[-0.55919361, 0.98062831, - 0.41940627], + [1.72091413, 0.19879334, - 1.82968581], + [4.64467907, 4.73710203, 4.88324118]], dtype=np.float32) + self.flip = 0 + + self.eig_vec = np.array([ + [0.4009, 0.7192, -0.5675], + [-0.8140, -0.0045, -0.5808], + [0.4203, -0.6948, -0.5836], + ], dtype=np.float32) + + self.eig_val = np.array([[0.2175, 0.0188, 0.0045]], np.float32) + + self.__dict__.update(cfg) + + @staticmethod + def random(): + return random.random() * 2 - 1.0 + + def blur_image(self, image): + def rand_kernel(): + size = np.random.randn(1) + size = int(np.round(size)) * 2 + 1 + if size < 0: return None + if random.random() < 0.5: return None + size = min(size, 45) + kernel = np.zeros((size, size)) + c = int(size/2) + wx = random.random() + kernel[:, c] += 1. / size * wx + kernel[c, :] += 1. / size * (1-wx) + return kernel + + kernel = rand_kernel() + + if kernel is not None: + image = cv2.filter2D(image, -1, kernel) + return image + + def __call__(self, image, bbox, size, gray=False, mask=None): + if gray: + grayed = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) + image = np.zeros((grayed.shape[0], grayed.shape[1], 3), np.uint8) + image[:, :, 0] = image[:, :, 1] = image[:, :, 2] = grayed + + shape = image.shape + + crop_bbox = center2corner((shape[0]//2, shape[1]//2, size-1, size-1)) + + param = {} + if self.shift: + param['shift'] = (Augmentation.random() * self.shift, Augmentation.random() * self.shift) + + if self.scale: + param['scale'] = ((1.0 + Augmentation.random() * self.scale), (1.0 + Augmentation.random() * self.scale)) + + crop_bbox, _ = aug_apply(Corner(*crop_bbox), param, shape) + + x1 = crop_bbox.x1 + y1 = crop_bbox.y1 + + bbox = BBox(bbox.x1 - x1, bbox.y1 - y1, + bbox.x2 - x1, bbox.y2 - y1) + + if self.scale: + scale_x, scale_y = param['scale'] + bbox = Corner(bbox.x1 / scale_x, bbox.y1 / scale_y, bbox.x2 / scale_x, bbox.y2 / scale_y) + + image = crop_hwc(image, crop_bbox, size) + if not mask is None: + mask = crop_hwc(mask, crop_bbox, size) + + offset = np.dot(self.rgbVar, np.random.randn(3, 1)) + offset = offset[::-1] # bgr 2 rgb + offset = offset.reshape(3) + image = image - offset + + if self.blur > random.random(): + image = self.blur_image(image) + + if self.resize: + imageSize = image.shape[:2] + ratio = max(math.pow(random.random(), 0.5), 0.2) # 25 ~ 255 + rand_size = (int(round(ratio*imageSize[0])), int(round(ratio*imageSize[1]))) + image = cv2.resize(image, rand_size) + image = cv2.resize(image, tuple(imageSize)) + + if self.flip and self.flip > Augmentation.random(): + image = cv2.flip(image, 1) + mask = cv2.flip(mask, 1) + width = image.shape[1] + bbox = Corner(width - 1 - bbox.x2, bbox.y1, width - 1 - bbox.x1, bbox.y2) + + return image, bbox, mask + + +class AnchorTargetLayer: + def __init__(self, cfg): + self.thr_high = 0.6 + self.thr_low = 0.3 + self.negative = 16 + self.rpn_batch = 64 + self.positive = 16 + + self.__dict__.update(cfg) + + def __call__(self, anchor, target, size, neg=False, need_iou=False): + anchor_num = anchor.anchors.shape[0] + + cls = np.zeros((anchor_num, size, size), dtype=np.int64) + cls[...] = -1 # -1 ignore 0 negative 1 positive + delta = np.zeros((4, anchor_num, size, size), dtype=np.float32) + delta_weight = np.zeros((anchor_num, size, size), dtype=np.float32) + + def select(position, keep_num=16): + num = position[0].shape[0] + if num <= keep_num: + return position, num + slt = np.arange(num) + np.random.shuffle(slt) + slt = slt[:keep_num] + return tuple(p[slt] for p in position), keep_num + + if neg: + l = size // 2 - 3 + r = size // 2 + 3 + 1 + + cls[:, l:r, l:r] = 0 + + neg, neg_num = select(np.where(cls == 0), self.negative) + cls[:] = -1 + cls[neg] = 0 + + if not need_iou: + return cls, delta, delta_weight + else: + overlap = np.zeros((anchor_num, size, size), dtype=np.float32) + return cls, delta, delta_weight, overlap + + tcx, tcy, tw, th = corner2center(target) + + anchor_box = anchor.all_anchors[0] + anchor_center = anchor.all_anchors[1] + x1, y1, x2, y2 = anchor_box[0], anchor_box[1], anchor_box[2], anchor_box[3] + cx, cy, w, h = anchor_center[0], anchor_center[1], anchor_center[2], anchor_center[3] + + # delta + delta[0] = (tcx - cx) / w + delta[1] = (tcy - cy) / h + delta[2] = np.log(tw / w) + delta[3] = np.log(th / h) + + # IoU + overlap = IoU([x1, y1, x2, y2], target) + + pos = np.where(overlap > self.thr_high) + neg = np.where(overlap < self.thr_low) + + pos, pos_num = select(pos, self.positive) + neg, neg_num = select(neg, self.rpn_batch - pos_num) + + cls[pos] = 1 + delta_weight[pos] = 1. / (pos_num + 1e-6) + + cls[neg] = 0 + + if not need_iou: + return cls, delta, delta_weight + else: + return cls, delta, delta_weight, overlap + + +class DataSets(Dataset): + def __init__(self, cfg, anchor_cfg, num_epoch=1): + super(DataSets, self).__init__() + global logger + logger = logging.getLogger('global') + + # anchors + self.anchors = Anchors(anchor_cfg) + + # size + self.template_size = 127 + self.origin_size = 127 + self.search_size = 255 + self.size = 17 + self.base_size = 0 + self.crop_size = 0 + + if 'template_size' in cfg: + self.template_size = cfg['template_size'] + if 'origin_size' in cfg: + self.origin_size = cfg['origin_size'] + if 'search_size' in cfg: + self.search_size = cfg['search_size'] + if 'base_size' in cfg: + self.base_size = cfg['base_size'] + if 'size' in cfg: + self.size = cfg['size'] + + if (self.search_size - self.template_size) / self.anchors.stride + 1 + self.base_size != self.size: + raise Exception("size not match!") # TODO: calculate size online + if 'crop_size' in cfg: + self.crop_size = cfg['crop_size'] + self.template_small = False + if 'template_small' in cfg and cfg['template_small']: + self.template_small = True + + self.anchors.generate_all_anchors(im_c=self.search_size//2, size=self.size) + + if 'anchor_target' not in cfg: + cfg['anchor_target'] = {} + self.anchor_target = AnchorTargetLayer(cfg['anchor_target']) + + # data sets + if 'datasets' not in cfg: + raise(Exception('DataSet need "{}"'.format('datasets'))) + + self.all_data = [] + start = 0 + self.num = 0 + for name in cfg['datasets']: + dataset = cfg['datasets'][name] + dataset['mark'] = name + dataset['start'] = start + + dataset = SubDataSet(dataset) + dataset.log() + self.all_data.append(dataset) + + start += dataset.num # real video number + self.num += dataset.num_use # the number used for subset shuffle + + # data augmentation + aug_cfg = cfg['augmentation'] + self.template_aug = Augmentation(aug_cfg['template']) + self.search_aug = Augmentation(aug_cfg['search']) + self.gray = aug_cfg['gray'] + self.neg = aug_cfg['neg'] + self.inner_neg = 0 if 'inner_neg' not in aug_cfg else aug_cfg['inner_neg'] + + self.pick = None # list to save id for each img + if 'num' in cfg: # number used in training for all dataset + self.num = int(cfg['num']) + self.num *= num_epoch + self.shuffle() + + self.infos = { + 'template': self.template_size, + 'search': self.search_size, + 'template_small': self.template_small, + 'gray': self.gray, + 'neg': self.neg, + 'inner_neg': self.inner_neg, + 'crop_size': self.crop_size, + 'anchor_target': self.anchor_target.__dict__, + 'num': self.num // num_epoch + } + logger.info('dataset informations: \n{}'.format(json.dumps(self.infos, indent=4))) + + def imread(self, path): + img = cv2.imread(path) + + if self.origin_size == self.template_size: + return img, 1.0 + + def map_size(exe, size): + return int(round(((exe + 1) / (self.origin_size + 1) * (size+1) - 1))) + + nsize = map_size(self.template_size, img.shape[1]) + + img = cv2.resize(img, (nsize, nsize)) + + return img, nsize / img.shape[1] + + def shuffle(self): + pick = [] + m = 0 + while m < self.num: + p = [] + for subset in self.all_data: + sub_p = subset.shuffle() + p += sub_p + + sample_random.shuffle(p) + + pick += p + m = len(pick) + self.pick = pick + logger.info("shuffle done!") + logger.info("dataset length {}".format(self.num)) + + def __len__(self): + return self.num + + def find_dataset(self, index): + for dataset in self.all_data: + if dataset.start + dataset.num > index: + return dataset, index - dataset.start + + def __getitem__(self, index, debug=False): + index = self.pick[index] + dataset, index = self.find_dataset(index) + + gray = self.gray and self.gray > random.random() + neg = self.neg and self.neg > random.random() + + if neg: + template = dataset.get_random_target(index) + if self.inner_neg and self.inner_neg > random.random(): + search = dataset.get_random_target() + else: + search = random.choice(self.all_data).get_random_target() + else: + template, search = dataset.get_positive_pair(index) + + def center_crop(img, size): + shape = img.shape[1] + if shape == size: return img + c = shape // 2 + l = c - size // 2 + r = c + size // 2 + 1 + return img[l:r, l:r] + + template_image, scale_z = self.imread(template[0]) + + if self.template_small: + template_image = center_crop(template_image, self.template_size) + + search_image, scale_x = self.imread(search[0]) + + if dataset.has_mask and not neg: + search_mask = (cv2.imread(search[2], 0) > 0).astype(np.float32) + else: + search_mask = np.zeros(search_image.shape[:2], dtype=np.float32) + + if self.crop_size > 0: + search_image = center_crop(search_image, self.crop_size) + search_mask = center_crop(search_mask, self.crop_size) + + def toBBox(image, shape): + imh, imw = image.shape[:2] + if len(shape) == 4: + w, h = shape[2]-shape[0], shape[3]-shape[1] + else: + w, h = shape + context_amount = 0.5 + exemplar_size = self.template_size # 127 + wc_z = w + context_amount * (w+h) + hc_z = h + context_amount * (w+h) + s_z = np.sqrt(wc_z * hc_z) + scale_z = exemplar_size / s_z + w = w*scale_z + h = h*scale_z + cx, cy = imw//2, imh//2 + bbox = center2corner(Center(cx, cy, w, h)) + return bbox + + template_box = toBBox(template_image, template[1]) + search_box = toBBox(search_image, search[1]) + + template, _, _ = self.template_aug(template_image, template_box, self.template_size, gray=gray) + search, bbox, mask = self.search_aug(search_image, search_box, self.search_size, gray=gray, mask=search_mask) + + def draw(image, box, name): + image = image.copy() + x1, y1, x2, y2 = map(lambda x: int(round(x)), box) + cv2.rectangle(image, (x1, y1), (x2, y2), (0, 255, 0)) + cv2.imwrite(name, image) + + if debug: + draw(template_image, template_box, "debug/{:06d}_ot.jpg".format(index)) + draw(search_image, search_box, "debug/{:06d}_os.jpg".format(index)) + draw(template, _, "debug/{:06d}_t.jpg".format(index)) + draw(search, bbox, "debug/{:06d}_s.jpg".format(index)) + + cls, delta, delta_weight = self.anchor_target(self.anchors, bbox, self.size, neg) + if dataset.has_mask and not neg: + mask_weight = cls.max(axis=0, keepdims=True) + else: + mask_weight = np.zeros([1, cls.shape[1], cls.shape[2]], dtype=np.float32) + + template, search = map(lambda x: np.transpose(x, (2, 0, 1)).astype(np.float32), [template, search]) + + mask = (np.expand_dims(mask, axis=0) > 0.5) * 2 - 1 # 1*H*W + + return template, search, cls, delta, delta_weight, np.array(bbox, np.float32), \ + np.array(mask, np.float32), np.array(mask_weight, np.float32) + diff --git a/SiamMask/datasets/siam_rpn_dataset.py b/SiamMask/datasets/siam_rpn_dataset.py new file mode 100644 index 0000000000000000000000000000000000000000..7a6f6736c72628b1b580dc74d0f0c97884d8be48 --- /dev/null +++ b/SiamMask/datasets/siam_rpn_dataset.py @@ -0,0 +1,585 @@ +# -------------------------------------------------------- +# SiamMask +# Licensed under The MIT License +# Written by Qiang Wang (wangqiang2015 at ia.ac.cn) +# -------------------------------------------------------- +from __future__ import division +from torch.utils.data import Dataset +import numpy as np +import json +import random +import logging +from os.path import join +from utils.bbox_helper import * +from utils.anchors import Anchors +import math +import sys +pyv = sys.version[0] +import cv2 +if pyv[0] == '3': + cv2.ocl.setUseOpenCL(False) + +logger = logging.getLogger('global') + + +sample_random = random.Random() +sample_random.seed(123456) + + +class SubDataSet(object): + def __init__(self, cfg): + for string in ['root', 'anno']: + if string not in cfg: + raise Exception('SubDataSet need "{}"'.format(string)) + + with open(cfg['anno']) as fin: + logger.info("loading " + cfg['anno']) + self.labels = self.filter_zero(json.load(fin), cfg) + + def isint(x): + try: + int(x) + return True + except: + return False + + # add frames args into labels + to_del = [] + for video in self.labels: + for track in self.labels[video]: + frames = self.labels[video][track] + frames = list(map(int, filter(lambda x: isint(x), frames.keys()))) + frames.sort() + self.labels[video][track]['frames'] = frames + if len(frames) <= 0: + logger.info("warning {}/{} has no frames.".format(video, track)) + to_del.append((video, track)) + + # delete tracks with no frames + for video, track in to_del: + del self.labels[video][track] + + # delete videos with no valid track + to_del = [] + for video in self.labels: + if len(self.labels[video]) <= 0: + logger.info("warning {} has no tracks".format(video)) + to_del.append(video) + + for video in to_del: + del self.labels[video] + + self.videos = list(self.labels.keys()) + + logger.info(cfg['anno'] + " loaded.") + + # default args + self.root = "/" + self.start = 0 + self.num = len(self.labels) + self.num_use = self.num + self.frame_range = 100 + self.mark = "vid" + self.path_format = "{}.{}.{}.jpg" + + self.pick = [] + + # input args + self.__dict__.update(cfg) + + self.num_use = int(self.num_use) + + # shuffle + self.shuffle() + + def filter_zero(self, anno, cfg): + name = cfg.get('mark', '') + + out = {} + tot = 0 + new = 0 + zero = 0 + + for video, tracks in anno.items(): + new_tracks = {} + for trk, frames in tracks.items(): + new_frames = {} + for frm, bbox in frames.items(): + tot += 1 + if len(bbox) == 4: + x1, y1, x2, y2 = bbox + w, h = x2 - x1, y2 -y1 + else: + w, h= bbox + if w == 0 or h == 0: + logger.info('Error, {name} {video} {trk} {bbox}'.format(**locals())) + zero += 1 + continue + new += 1 + new_frames[frm] = bbox + + if len(new_frames) > 0: + new_tracks[trk] = new_frames + + if len(new_tracks) > 0: + out[video] = new_tracks + + return out + + def log(self): + logger.info('SubDataSet {name} start-index {start} select [{select}/{num}] path {format}'.format( + name=self.mark, start=self.start, select=self.num_use, num=self.num, format=self.path_format + )) + + def shuffle(self): + lists = list(range(self.start, self.start + self.num)) + + m = 0 + pick = [] + while m < self.num_use: + sample_random.shuffle(lists) + pick += lists + m += self.num + + self.pick = pick[:self.num_use] + return self.pick + + def get_image_anno(self, video, track, frame): + frame = "{:06d}".format(frame) + image_path = join(self.root, video, self.path_format.format(frame, track, 'x')) + image_anno = self.labels[video][track][frame] + + return image_path, image_anno + + def get_positive_pair(self, index): + video_name = self.videos[index] + video = self.labels[video_name] + track = random.choice(list(video.keys())) + track_info = video[track] + + frames = track_info['frames'] + + if 'hard' not in track_info: + template_frame = random.randint(0, len(frames)-1) + + left = max(template_frame - self.frame_range, 0) + right = min(template_frame + self.frame_range, len(frames)-1) + 1 + search_range = frames[left:right] + template_frame = frames[template_frame] + search_frame = random.choice(search_range) + else: + search_frame = random.choice(track_info['hard']) + left = max(search_frame - self.frame_range, 0) + right = min(search_frame + self.frame_range, len(frames)-1) + 1 # python [left:right+1) = [left:right] + template_range = frames[left:right] + template_frame = random.choice(template_range) + search_frame = frames[search_frame] + + return self.get_image_anno(video_name, track, template_frame), \ + self.get_image_anno(video_name, track, search_frame) + + def get_random_target(self, index=-1): + if index == -1: + index = random.randint(0, self.num-1) + video_name = self.videos[index] + video = self.labels[video_name] + track = random.choice(list(video.keys())) + track_info = video[track] + + frames = track_info['frames'] + frame = random.choice(frames) + + return self.get_image_anno(video_name, track, frame) + + +def crop_hwc(image, bbox, out_sz, padding=(0, 0, 0)): + bbox = [float(x) for x in bbox] + a = (out_sz-1) / (bbox[2]-bbox[0]) + b = (out_sz-1) / (bbox[3]-bbox[1]) + c = -a * bbox[0] + d = -b * bbox[1] + mapping = np.array([[a, 0, c], + [0, b, d]]).astype(np.float) + crop = cv2.warpAffine(image, mapping, (out_sz, out_sz), borderMode=cv2.BORDER_CONSTANT, borderValue=padding) + return crop + + +class Augmentation: + def __init__(self, cfg): + # default args + self.shift = 0 + self.scale = 0 + self.blur = 0 #False + self.resize = False + self.rgbVar = np.array([[-0.55919361, 0.98062831, - 0.41940627], + [1.72091413, 0.19879334, - 1.82968581], + [4.64467907, 4.73710203, 4.88324118]], dtype=np.float32) + self.flip = 0 + + self.eig_vec = np.array([ + [0.4009, 0.7192, -0.5675], + [-0.8140, -0.0045, -0.5808], + [0.4203, -0.6948, -0.5836], + ], dtype=np.float32) + + self.eig_val = np.array([[0.2175, 0.0188, 0.0045]], np.float32) + + self.__dict__.update(cfg) + + @staticmethod + def random(): + return random.random() * 2 - 1.0 + + def blur_image(self, image): + def rand_kernel(): + size = np.random.randn(1) + size = int(np.round(size)) * 2 + 1 + if size < 0: return None + if random.random() < 0.5: return None + size = min(size, 45) + kernel = np.zeros((size, size)) + c = int(size/2) + wx = random.random() + kernel[:, c] += 1. / size * wx + kernel[c, :] += 1. / size * (1-wx) + return kernel + + kernel = rand_kernel() + + if kernel is not None: + image = cv2.filter2D(image, -1, kernel) + return image + + def __call__(self, image, bbox, size, gray=False): + if gray: + grayed = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) + image = np.zeros((grayed.shape[0], grayed.shape[1], 3), np.uint8) + image[:, :, 0] = image[:, :, 1] = image[:, :, 2] = grayed + + shape = image.shape + + crop_bbox = center2corner((shape[0]//2, shape[1]//2, size-1, size-1)) + + param = {} + if self.shift: + param['shift'] = (Augmentation.random() * self.shift, Augmentation.random() * self.shift) + + if self.scale: + param['scale'] = ((1.0 + Augmentation.random() * self.scale), (1.0 + Augmentation.random() * self.scale)) + + crop_bbox, _ = aug_apply(Corner(*crop_bbox), param, shape) + + x1 = crop_bbox.x1 + y1 = crop_bbox.y1 + + bbox = BBox(bbox.x1 - x1, bbox.y1 - y1, + bbox.x2 - x1, bbox.y2 - y1) + + if self.scale: + scale_x, scale_y = param['scale'] + bbox = Corner(bbox.x1 / scale_x, bbox.y1 / scale_y, bbox.x2 / scale_x, bbox.y2 / scale_y) + + image = crop_hwc(image, crop_bbox, size) + + offset = np.dot(self.rgbVar, np.random.randn(3, 1)) + offset = offset[::-1] # bgr 2 rgb + offset = offset.reshape(3) + image = image - offset + + if self.blur > random.random(): + image = self.blur_image(image) + + if self.resize: + imageSize = image.shape[:2] + ratio = max(math.pow(random.random(), 0.5), 0.2) # 25 ~ 255 + rand_size = (int(round(ratio*imageSize[0])), int(round(ratio*imageSize[1]))) + image = cv2.resize(image, rand_size) + image = cv2.resize(image, tuple(imageSize)) + + if self.flip and self.flip > Augmentation.random(): + image = cv2.flip(image, 1) + width = image.shape[1] + bbox = Corner(width - 1 - bbox.x2, bbox.y1, width - 1 - bbox.x1, bbox.y2) + + return image, bbox + + +class AnchorTargetLayer: + def __init__(self, cfg): + self.thr_high = 0.6 + self.thr_low = 0.3 + self.negative = 16 + self.rpn_batch = 64 + self.positive = 16 + + self.__dict__.update(cfg) + + def __call__(self, anchor, target, size, neg=False, need_iou=False): + anchor_num = anchor.anchors.shape[0] + + cls = np.zeros((anchor_num, size, size), dtype=np.int64) + cls[...] = -1 # -1 ignore 0 negative 1 positive + delta = np.zeros((4, anchor_num, size, size), dtype=np.float32) + delta_weight = np.zeros((anchor_num, size, size), dtype=np.float32) + + def select(position, keep_num=16): + num = position[0].shape[0] + if num <= keep_num: + return position, num + slt = np.arange(num) + np.random.shuffle(slt) + slt = slt[:keep_num] + return tuple(p[slt] for p in position), keep_num + + if neg: + l = size // 2 - 3 + r = size // 2 + 3 + 1 + + cls[:, l:r, l:r] = 0 + + neg, neg_num = select(np.where(cls == 0), self.negative) + cls[:] = -1 + cls[neg] = 0 + + if not need_iou: + return cls, delta, delta_weight + else: + overlap = np.zeros((anchor_num, size, size), dtype=np.float32) + return cls, delta, delta_weight, overlap + + tcx, tcy, tw, th = corner2center(target) + + anchor_box = anchor.all_anchors[0] + anchor_center = anchor.all_anchors[1] + x1, y1, x2, y2 = anchor_box[0], anchor_box[1], anchor_box[2], anchor_box[3] + cx, cy, w, h = anchor_center[0], anchor_center[1], anchor_center[2], anchor_center[3] + + # delta + delta[0] = (tcx - cx) / w + delta[1] = (tcy - cy) / h + delta[2] = np.log(tw / w) + delta[3] = np.log(th / h) + + # IoU + overlap = IoU([x1, y1, x2, y2], target) + + pos = np.where(overlap > self.thr_high) + neg = np.where(overlap < self.thr_low) + + pos, pos_num = select(pos, self.positive) + neg, neg_num = select(neg, self.rpn_batch - pos_num) + + cls[pos] = 1 + delta_weight[pos] = 1. / (pos_num + 1e-6) + + cls[neg] = 0 + + if not need_iou: + return cls, delta, delta_weight + else: + return cls, delta, delta_weight, overlap + + +class DataSets(Dataset): + def __init__(self, cfg, anchor_cfg, num_epoch=1): + super(DataSets, self).__init__() + global logger + logger = logging.getLogger('global') + + # anchors + self.anchors = Anchors(anchor_cfg) + + # size + self.template_size = 127 + self.origin_size = 127 + self.search_size = 255 + self.size = 17 + self.base_size = 0 + self.crop_size = 0 + + if 'template_size' in cfg: + self.template_size = cfg['template_size'] + if 'origin_size' in cfg: + self.origin_size = cfg['origin_size'] + if 'search_size' in cfg: + self.search_size = cfg['search_size'] + if 'base_size' in cfg: + self.base_size = cfg['base_size'] + if 'size' in cfg: + self.size = cfg['size'] + + if (self.search_size - self.template_size) / self.anchors.stride + 1 + self.base_size != self.size: + raise Exception("size not match!") # TODO: calculate size online + if 'crop_size' in cfg: + self.crop_size = cfg['crop_size'] + self.template_small = False + if 'template_small' in cfg and cfg['template_small']: + self.template_small = True + + self.anchors.generate_all_anchors(im_c=self.search_size//2, size=self.size) + + if 'anchor_target' not in cfg: + cfg['anchor_target'] = {} + self.anchor_target = AnchorTargetLayer(cfg['anchor_target']) + + # data sets + if 'datasets' not in cfg: + raise(Exception('DataSet need "{}"'.format('datasets'))) + + self.all_data = [] + start = 0 + self.num = 0 + for name in cfg['datasets']: + dataset = cfg['datasets'][name] + dataset['mark'] = name + dataset['start'] = start + + dataset = SubDataSet(dataset) + dataset.log() + self.all_data.append(dataset) + + start += dataset.num # real video number + self.num += dataset.num_use # the number used for subset shuffle + + # data augmentation + aug_cfg = cfg['augmentation'] + self.template_aug = Augmentation(aug_cfg['template']) + self.search_aug = Augmentation(aug_cfg['search']) + self.gray = aug_cfg['gray'] + self.neg = aug_cfg['neg'] + self.inner_neg = 0 if 'inner_neg' not in aug_cfg else aug_cfg['inner_neg'] + + self.pick = None # list to save id for each img + if 'num' in cfg: # number used in training for all dataset + self.num = int(cfg['num']) + self.num *= num_epoch + self.shuffle() + + self.infos = { + 'template': self.template_size, + 'search': self.search_size, + 'template_small': self.template_small, + 'gray': self.gray, + 'neg': self.neg, + 'inner_neg': self.inner_neg, + 'crop_size': self.crop_size, + 'anchor_target': self.anchor_target.__dict__, + 'num': self.num // num_epoch + } + logger.info('dataset informations: \n{}'.format(json.dumps(self.infos, indent=4))) + + def imread(self, path): + img = cv2.imread(path) + + if self.origin_size == self.template_size: + return img, 1.0 + + def map_size(exe, size): + return int(round(((exe + 1) / (self.origin_size + 1) * (size+1) - 1))) + + nsize = map_size(self.template_size, img.shape[1]) + + img = cv2.resize(img, (nsize, nsize)) + + return img, nsize / img.shape[1] + + def shuffle(self): + pick = [] + m = 0 + while m < self.num: + p = [] + for subset in self.all_data: + sub_p = subset.shuffle() + p += sub_p + + sample_random.shuffle(p) + + pick += p + m = len(pick) + self.pick = pick + logger.info("shuffle done!") + logger.info("dataset length {}".format(self.num)) + + def __len__(self): + return self.num + + def find_dataset(self, index): + for dataset in self.all_data: + if dataset.start + dataset.num > index: + return dataset, index - dataset.start + + def __getitem__(self, index, debug=False): + index = self.pick[index] + dataset, index = self.find_dataset(index) + + gray = self.gray and self.gray > random.random() + neg = self.neg and self.neg > random.random() + + if neg: + template = dataset.get_random_target(index) + if self.inner_neg and self.inner_neg > random.random(): + search = dataset.get_random_target() + else: + search = random.choice(self.all_data).get_random_target() + else: + template, search = dataset.get_positive_pair(index) + + def center_crop(img, size): + shape = img.shape[1] + if shape == size: return img + c = shape // 2 + l = c - size // 2 + r = c + size // 2 + 1 + return img[l:r, l:r] + + template_image, scale_z = self.imread(template[0]) + + if self.template_small: + template_image = center_crop(template_image, self.template_size) + + search_image, scale_x = self.imread(search[0]) + if self.crop_size > 0: + search_image = center_crop(search_image, self.crop_size) + + def toBBox(image, shape): + imh, imw = image.shape[:2] + if len(shape) == 4: + w, h = shape[2]-shape[0], shape[3]-shape[1] + else: + w, h = shape + context_amount = 0.5 + exemplar_size = self.template_size # 127 + wc_z = w + context_amount * (w+h) + hc_z = h + context_amount * (w+h) + s_z = np.sqrt(wc_z * hc_z) + scale_z = exemplar_size / s_z + w = w*scale_z + h = h*scale_z + cx, cy = imw//2, imh//2 + bbox = center2corner(Center(cx, cy, w, h)) + return bbox + + template_box = toBBox(template_image, template[1]) + search_box = toBBox(search_image, search[1]) + + template, _ = self.template_aug(template_image, template_box, self.template_size, gray=gray) + search, bbox = self.search_aug(search_image, search_box, self.search_size, gray=gray) + + def draw(image, box, name): + image = image.copy() + x1, y1, x2, y2 = map(lambda x: int(round(x)), box) + cv2.rectangle(image, (x1, y1), (x2, y2), (0, 255, 0)) + cv2.imwrite(name, image) + + if debug: + draw(template_image, template_box, "debug/{:06d}_ot.jpg".format(index)) + draw(search_image, search_box, "debug/{:06d}_os.jpg".format(index)) + draw(template, _, "debug/{:06d}_t.jpg".format(index)) + draw(search, bbox, "debug/{:06d}_s.jpg".format(index)) + + cls, delta, delta_weight = self.anchor_target(self.anchors, bbox, self.size, neg) + + template, search = map(lambda x: np.transpose(x, (2, 0, 1)).astype(np.float32), [template, search]) + + return template, search, cls, delta, delta_weight, np.array(bbox, np.float32) + diff --git a/SiamMask/experiments/siammask_base/config.json b/SiamMask/experiments/siammask_base/config.json new file mode 100644 index 0000000000000000000000000000000000000000..d94a91997cbf5aecdf78b1d48ac75f93c578aaec --- /dev/null +++ b/SiamMask/experiments/siammask_base/config.json @@ -0,0 +1,100 @@ +{ + "network": { + "arch": "Custom" + }, + "hp": { + "instance_size": 255, + "base_size": 8 + }, + "lr": { + "type": "log", + "start_lr": 0.005, + "end_lr": 0.0025, + "warmup": { + "start_lr": 0.001, + "end_lr": 0.005, + "type": "step", + "step": 1, + "epoch": 5 + } + }, + "loss": { + "weight": [1.0, 1.2, 36] + }, + "train_datasets": { + "datasets": { + "ytb_vos": { + "root": "../../data/ytb_vos/crop511", + "anno": "../../data/ytb_vos/train.json", + "num_use": 200000, + "frame_range": 20 + }, + "vid": { + "root": "../../data/vid/crop511", + "anno": "../../data/vid/train.json", + "num_use": 200000, + "frame_range": 100 + }, + "coco": { + "root": "../../data/coco/crop511", + "anno": "../../data/coco/train2017.json", + "frame_range": 1 + }, + "det": { + "root": "../../data/det/crop511", + "anno": "../../data/det/train.json", + "num_use": 100000, + "frame_range": 1 + } + }, + "template_size": 127, + "search_size": 255, + "base_size": 8, + "size": 25, + + "num" : 600000, + + "augmentation": { + "template": { + "shift": 4, "scale": 0.05 + }, + "search": { + "shift": 64, "scale": 0.18, "blur": 0.18 + }, + "neg": 0.2, + "gray": 0.25 + } + }, + + "val_datasets": { + "datasets": { + "vid": { + "root": "../../data/vid/crop511", + "anno": "../../data/vid/val.json", + "num_use": 1000 + } + }, + "template_size": 127, + "search_size": 255, + "size": 17, + + "num" : 1000, + + "augmentation": { + "template": { + "shift": 0, "scale": 0.00 + }, + "search": { + "shift": 12, "scale": 0.18 + }, + "neg": 0, + "gray": 0 + } + }, + "anchors": { + "stride": 8, + "ratios": [0.33, 0.5, 1, 2, 3], + "scales": [8], + "round_dight": 0 + } +} diff --git a/SiamMask/experiments/siammask_base/custom.py b/SiamMask/experiments/siammask_base/custom.py new file mode 100644 index 0000000000000000000000000000000000000000..fd22ae59d717d537d36a0a4c58029d99d825c2bb --- /dev/null +++ b/SiamMask/experiments/siammask_base/custom.py @@ -0,0 +1,113 @@ +from models.siammask import SiamMask +from models.features import MultiStageFeature +from models.rpn import RPN, DepthCorr +from models.mask import Mask +import torch +import torch.nn as nn +from utils.load_helper import load_pretrain +from resnet import resnet50 + + +class ResDownS(nn.Module): + def __init__(self, inplane, outplane): + super(ResDownS, self).__init__() + self.downsample = nn.Sequential( + nn.Conv2d(inplane, outplane, kernel_size=1, bias=False), + nn.BatchNorm2d(outplane)) + + def forward(self, x): + x = self.downsample(x) + if x.size(3) < 20: + l = 4 + r = -4 + x = x[:, :, l:r, l:r] + return x + + +class ResDown(MultiStageFeature): + def __init__(self, pretrain=False): + super(ResDown, self).__init__() + self.features = resnet50(layer3=True, layer4=False) + if pretrain: + load_pretrain(self.features, 'resnet.model') + + self.downsample = ResDownS(1024, 256) + + self.layers = [self.downsample, self.features.layer2, self.features.layer3] + self.train_nums = [1, 3] + self.change_point = [0, 0.5] + + self.unfix(0.0) + + def param_groups(self, start_lr, feature_mult=1): + lr = start_lr * feature_mult + + def _params(module, mult=1): + params = list(filter(lambda x:x.requires_grad, module.parameters())) + if len(params): + return [{'params': params, 'lr': lr * mult}] + else: + return [] + + groups = [] + groups += _params(self.downsample) + groups += _params(self.features, 0.1) + return groups + + def forward(self, x): + output = self.features(x) + p3 = self.downsample(output[1]) + return p3 + + +class UP(RPN): + def __init__(self, anchor_num=5, feature_in=256, feature_out=256): + super(UP, self).__init__() + + self.anchor_num = anchor_num + self.feature_in = feature_in + self.feature_out = feature_out + + self.cls_output = 2 * self.anchor_num + self.loc_output = 4 * self.anchor_num + + self.cls = DepthCorr(feature_in, feature_out, self.cls_output) + self.loc = DepthCorr(feature_in, feature_out, self.loc_output) + + def forward(self, z_f, x_f): + cls = self.cls(z_f, x_f) + loc = self.loc(z_f, x_f) + return cls, loc + + +class MaskCorr(Mask): + def __init__(self, oSz=63): + super(MaskCorr, self).__init__() + self.oSz = oSz + self.mask = DepthCorr(256, 256, self.oSz**2) + + def forward(self, z, x): + return self.mask(z, x) + + +class Custom(SiamMask): + def __init__(self, pretrain=False, **kwargs): + super(Custom, self).__init__(**kwargs) + self.features = ResDown(pretrain=pretrain) + self.rpn_model = UP(anchor_num=self.anchor_num, feature_in=256, feature_out=256) + self.mask_model = MaskCorr() + + def template(self, template): + self.zf = self.features(template) + + def track(self, search): + search = self.features(search) + rpn_pred_cls, rpn_pred_loc = self.rpn(self.zf, search) + return rpn_pred_cls, rpn_pred_loc + + def track_mask(self, search): + search = self.features(search) + rpn_pred_cls, rpn_pred_loc = self.rpn(self.zf, search) + pred_mask = self.mask(self.zf, search) + return rpn_pred_cls, rpn_pred_loc, pred_mask + diff --git a/SiamMask/experiments/siammask_base/resnet.py b/SiamMask/experiments/siammask_base/resnet.py new file mode 100644 index 0000000000000000000000000000000000000000..4b81f0ade06b44b5bdbb02b3095f1e48aaaf07b8 --- /dev/null +++ b/SiamMask/experiments/siammask_base/resnet.py @@ -0,0 +1,360 @@ +import torch.nn as nn +import torch +from torch.autograd import Variable +import math +import torch.utils.model_zoo as model_zoo +from models.features import Features +from utils.log_helper import log_once + + +__all__ = ['ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101', + 'resnet152'] + + +model_urls = { + 'resnet18': 'https://download.pytorch.org/models/resnet18-5c106cde.pth', + 'resnet34': 'https://download.pytorch.org/models/resnet34-333f7ec4.pth', + 'resnet50': 'https://download.pytorch.org/models/resnet50-19c8e357.pth', + 'resnet101': 'https://download.pytorch.org/models/resnet101-5d3b4d8f.pth', + 'resnet152': 'https://download.pytorch.org/models/resnet152-b121ed2d.pth', +} + + +def conv3x3(in_planes, out_planes, stride=1): + "3x3 convolution with padding" + return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride, + padding=1, bias=False) + + +class BasicBlock(nn.Module): + expansion = 1 + + def __init__(self, inplanes, planes, stride=1, downsample=None): + super(BasicBlock, self).__init__() + self.conv1 = conv3x3(inplanes, planes, stride) + self.bn1 = nn.BatchNorm2d(planes) + self.relu = nn.ReLU(inplace=True) + self.conv2 = conv3x3(planes, planes) + self.bn2 = nn.BatchNorm2d(planes) + self.downsample = downsample + self.stride = stride + + def forward(self, x): + residual = x + + out = self.conv1(x) + out = self.bn1(out) + out = self.relu(out) + + out = self.conv2(out) + out = self.bn2(out) + + if self.downsample is not None: + residual = self.downsample(x) + + out += residual + out = self.relu(out) + + return out + + +class Bottleneck(Features): + expansion = 4 + + def __init__(self, inplanes, planes, stride=1, downsample=None, dilation=1): + super(Bottleneck, self).__init__() + self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False) + self.bn1 = nn.BatchNorm2d(planes) + # padding = (2 - stride) + (dilation // 2 - 1) + padding = 2 - stride + assert stride==1 or dilation==1, "stride and dilation must have one equals to zero at least" + if dilation > 1: + padding = dilation + self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, + padding=padding, bias=False, dilation=dilation) + self.bn2 = nn.BatchNorm2d(planes) + self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False) + self.bn3 = nn.BatchNorm2d(planes * 4) + self.relu = nn.ReLU(inplace=True) + self.downsample = downsample + self.stride = stride + + def forward(self, x): + residual = x + + out = self.conv1(x) + out = self.bn1(out) + out = self.relu(out) + + out = self.conv2(out) + out = self.bn2(out) + out = self.relu(out) + + out = self.conv3(out) + out = self.bn3(out) + + if self.downsample is not None: + residual = self.downsample(x) + + if out.size() != residual.size(): + print(out.size(), residual.size()) + out += residual + + out = self.relu(out) + + return out + + +class Bottleneck_nop(nn.Module): + expansion = 4 + + def __init__(self, inplanes, planes, stride=1, downsample=None): + super(Bottleneck_nop, self).__init__() + self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False) + self.bn1 = nn.BatchNorm2d(planes) + self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, + padding=0, bias=False) + self.bn2 = nn.BatchNorm2d(planes) + self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False) + self.bn3 = nn.BatchNorm2d(planes * 4) + self.relu = nn.ReLU(inplace=True) + self.downsample = downsample + self.stride = stride + + def forward(self, x): + residual = x + + out = self.conv1(x) + out = self.bn1(out) + out = self.relu(out) + + out = self.conv2(out) + out = self.bn2(out) + out = self.relu(out) + + out = self.conv3(out) + out = self.bn3(out) + + if self.downsample is not None: + residual = self.downsample(x) + + s = residual.size(3) + residual = residual[:, :, 1:s-1, 1:s-1] + + out += residual + out = self.relu(out) + + return out + + +class ResNet(nn.Module): + + def __init__(self, block, layers, layer4=False, layer3=False): + self.inplanes = 64 + super(ResNet, self).__init__() + self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=0, # 3 + bias=False) + self.bn1 = nn.BatchNorm2d(64) + self.relu = nn.ReLU(inplace=True) + self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) + self.layer1 = self._make_layer(block, 64, layers[0]) + self.layer2 = self._make_layer(block, 128, layers[1], stride=2) # 31x31, 15x15 + + self.feature_size = 128 * block.expansion + + if layer3: + self.layer3 = self._make_layer(block, 256, layers[2], stride=1, dilation=2) # 15x15, 7x7 + self.feature_size = (256 + 128) * block.expansion + else: + self.layer3 = lambda x:x # identity + + if layer4: + self.layer4 = self._make_layer(block, 512, layers[3], stride=1, dilation=4) # 7x7, 3x3 + self.feature_size = 512 * block.expansion + else: + self.layer4 = lambda x:x # identity + + for m in self.modules(): + if isinstance(m, nn.Conv2d): + n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels + m.weight.data.normal_(0, math.sqrt(2. / n)) + elif isinstance(m, nn.BatchNorm2d): + m.weight.data.fill_(1) + m.bias.data.zero_() + + def _make_layer(self, block, planes, blocks, stride=1, dilation=1): + downsample = None + dd = dilation + if stride != 1 or self.inplanes != planes * block.expansion: + if stride == 1 and dilation == 1: + downsample = nn.Sequential( + nn.Conv2d(self.inplanes, planes * block.expansion, + kernel_size=1, stride=stride, bias=False), + nn.BatchNorm2d(planes * block.expansion), + ) + else: + if dilation > 1: + dd = dilation // 2 + padding = dd + else: + dd = 1 + padding = 0 + downsample = nn.Sequential( + nn.Conv2d(self.inplanes, planes * block.expansion, + kernel_size=3, stride=stride, bias=False, + padding=padding, dilation=dd), + nn.BatchNorm2d(planes * block.expansion), + ) + + layers = [] + # layers.append(block(self.inplanes, planes, stride, downsample, dilation=dilation)) + layers.append(block(self.inplanes, planes, stride, downsample, dilation=dd)) + self.inplanes = planes * block.expansion + for i in range(1, blocks): + layers.append(block(self.inplanes, planes, dilation=dilation)) + + return nn.Sequential(*layers) + + def forward(self, x): + x = self.conv1(x) + x = self.bn1(x) + x = self.relu(x) + # print x.size() + x = self.maxpool(x) + # print x.size() + + p1 = self.layer1(x) + p2 = self.layer2(p1) + p3 = self.layer3(p2) + # p3 = torch.cat([p2, p3], 1) + + log_once("p3 {}".format(p3.size())) + p4 = self.layer4(p3) + + return p2, p3, p4 + + +class ResAdjust(nn.Module): + def __init__(self, + block=Bottleneck, + out_channels=256, + adjust_number=1, + fuse_layers=[2,3,4]): + super(ResAdjust, self).__init__() + self.fuse_layers = set(fuse_layers) + + if 2 in self.fuse_layers: + self.layer2 = self._make_layer(block, 128, 1, out_channels, adjust_number) + if 3 in self.fuse_layers: + self.layer3 = self._make_layer(block, 256, 2, out_channels, adjust_number) + if 4 in self.fuse_layers: + self.layer4 = self._make_layer(block, 512, 4, out_channels, adjust_number) + + self.feature_size = out_channels * len(self.fuse_layers) + + + def _make_layer(self, block, plances, dilation, out, number=1): + + layers = [] + + for _ in range(number): + layer = block(plances * block.expansion, plances, dilation=dilation) + layers.append(layer) + + downsample = nn.Sequential( + nn.Conv2d(plances * block.expansion, out, kernel_size=3, padding=1, bias=False), + nn.BatchNorm2d(out) + ) + layers.append(downsample) + + return nn.Sequential(*layers) + + def forward(self, p2, p3, p4): + + outputs = [] + + if 2 in self.fuse_layers: + outputs.append(self.layer2(p2)) + if 3 in self.fuse_layers: + outputs.append(self.layer3(p3)) + if 4 in self.fuse_layers: + outputs.append(self.layer4(p4)) + # return torch.cat(outputs, 1) + return outputs + + +def resnet18(pretrained=False, **kwargs): + """Constructs a ResNet-18 model. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(BasicBlock, [2, 2, 2, 2], **kwargs) + if pretrained: + model.load_state_dict(model_zoo.load_url(model_urls['resnet18'])) + return model + + +def resnet34(pretrained=False, **kwargs): + """Constructs a ResNet-34 model. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(BasicBlock, [3, 4, 6, 3], **kwargs) + if pretrained: + model.load_state_dict(model_zoo.load_url(model_urls['resnet34'])) + return model + + +def resnet50(pretrained=False, **kwargs): + """Constructs a ResNet-50 model. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(Bottleneck, [3, 4, 6, 3], **kwargs) + if pretrained: + model.load_state_dict(model_zoo.load_url(model_urls['resnet50'])) + return model + + +def resnet101(pretrained=False, **kwargs): + """Constructs a ResNet-101 model. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(Bottleneck, [3, 4, 23, 3], **kwargs) + if pretrained: + model.load_state_dict(model_zoo.load_url(model_urls['resnet101'])) + return model + + +def resnet152(pretrained=False, **kwargs): + """Constructs a ResNet-152 model. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(Bottleneck, [3, 8, 36, 3], **kwargs) + if pretrained: + model.load_state_dict(model_zoo.load_url(model_urls['resnet152'])) + return model + + +if __name__ == '__main__': + net = resnet50() + print(net) + net = net.cuda() + + var = torch.FloatTensor(1,3,127,127).cuda() + var = Variable(var) + + net(var) + print('*************') + var = torch.FloatTensor(1,3,255,255).cuda() + var = Variable(var) + + net(var) + diff --git a/SiamMask/experiments/siammask_base/run.sh b/SiamMask/experiments/siammask_base/run.sh new file mode 100644 index 0000000000000000000000000000000000000000..3319df91a84a824aae6ebd9da7d9f4dd4c51d248 --- /dev/null +++ b/SiamMask/experiments/siammask_base/run.sh @@ -0,0 +1,13 @@ +ROOT=`git rev-parse --show-toplevel` +export PYTHONPATH=$ROOT:$PYTHONPATH + +mkdir -p logs + +python -u $ROOT/tools/train_siammask.py \ + --config=config.json -b 64 \ + -j 20 --resume snapshot/checkpoint_e9.pth\ + --epochs 20 \ + --log logs/log.txt \ + 2>&1 | tee logs/train.log + +bash test_all.sh -s 1 -e 20 -d VOT2018 -g 4 diff --git a/SiamMask/experiments/siammask_base/test.sh b/SiamMask/experiments/siammask_base/test.sh new file mode 100644 index 0000000000000000000000000000000000000000..3ae03cc1311243b8658cae415986e7652d6a4db8 --- /dev/null +++ b/SiamMask/experiments/siammask_base/test.sh @@ -0,0 +1,22 @@ +if [ -z "$3" ] + then + echo "Need input parameter!" + echo "Usage: bash `basename "$0"` \$MODEL \$DATASET \$GPUID" + exit +fi + +ROOT=`git rev-parse --show-toplevel` +export PYTHONPATH=$ROOT:$PYTHONPATH + +mkdir -p logs + +model=$1 +dataset=$2 +gpu=$3 + +CUDA_VISIBLE_DEVICES=$gpu python -u $ROOT/tools/test.py \ + --config config.json \ + --resume $model \ + --mask \ + --dataset $dataset 2>&1 | tee logs/test.log + diff --git a/SiamMask/experiments/siammask_base/test_all.sh b/SiamMask/experiments/siammask_base/test_all.sh new file mode 100644 index 0000000000000000000000000000000000000000..0b896ae1befccd2708bd697c6183ec24a2cd9352 --- /dev/null +++ b/SiamMask/experiments/siammask_base/test_all.sh @@ -0,0 +1,83 @@ +show_help() { +cat << EOF +Usage: + ${0##*/} [-h/--help] [-s/--start] [-e/--end] [-d/--dataset] [-m/--model] [-g/--gpu] + e.g. + bash ${0##*/} -s 1 -e 20 -d VOT2018 -g 4 # for test models + bash ${0##*/} -m snapshot/checkpoint_e10.pth -n 8 -g 4 # for tune models +EOF +} + +ROOT=`git rev-parse --show-toplevel` +source activate siammask +export PYTHONPATH=$ROOT:$PYTHONPATH +export PYTHONPATH=$PWD:$PYTHONPATH + +dataset=VOT2018 +NUM=4 +START=1 +END=20 +GPU=0 + +while [[ $# -gt 0 ]] +do + key="$1" + case $key in + -h|--help) + show_help + exit + ;; + -d|--dataset) + dataset=$2 + shift 2 + ;; + -n|--num) + NUM=$2 + shift 2 + ;; + -s|--start) + START=$2 + shift 2 + ;; + -e|--end) + END=$2 + shift 2 + ;; + -m|--model) + model=$2 + shift 2 + ;; + -g|--gpu) + GPU=$2 + shift 2 + ;; + *) + echo invalid arg [$1] + show_help + exit 1 + ;; + esac +done + +set -e + +if [ -z "$model" ]; then + echo test snapshot $START ~ $END on dataset $dataset with $GPU gpus. + for i in $(seq $START $END) + do + bash test.sh snapshot/checkpoint_e$i.pth $dataset $(($i % $GPU)) & + done + wait + + python $ROOT/tools/eval.py --dataset $dataset --num 20 --tracker_prefix C --result_dir ./test/$dataset 2>&1 | tee logs/eval_test_$dataset.log +else + echo tuning $model on dataset $dataset with $NUM jobs in $GPU gpus. + for i in $(seq 1 $NUM) + do + bash tune.sh $model $dataset $(($i % $GPU)) & + done + wait + rm finish.flag + + python $ROOT/tools/eval.py --dataset $dataset --num 20 --tracker_prefix C --result_dir ./result/$dataset 2>&1 | tee logs/eval_tune_$dataset.log +fi diff --git a/SiamMask/experiments/siammask_base/tune.sh b/SiamMask/experiments/siammask_base/tune.sh new file mode 100644 index 0000000000000000000000000000000000000000..7806379ab0f9f07580364573299d0998faa86995 --- /dev/null +++ b/SiamMask/experiments/siammask_base/tune.sh @@ -0,0 +1,29 @@ +if [ -z "$1" ] + then + echo "Need input parameter!" + echo "Usage: bash `basename "$0"` \$MODEL \$DATASETi \$GPUID" + exit +fi + +which python + +ROOT=`git rev-parse --show-toplevel` +source activate siammask +export PYTHONPATH=$ROOT:$PYTHONPATH +export PYTHONPATH=$PWD:$PYTHONPATH + +mkdir -p logs + +model=$1 +dataset=$2 +id=$3 + +CUDA_VISIBLE_DEVICES=$id python -u $ROOT/tools/tune_vot.py\ + --config config.json \ + --dataset $dataset \ + --penalty-k 0.0,0.25,0.02 \ + --window-influence 0.36,0.51,0.02 \ + --lr 0.25,0.56,0.05 \ + --search-region 255,256,16 \ + --resume $model 2>&1 | tee logs/tune.log + diff --git a/SiamMask/experiments/siammask_sharp/SiamMask_DAVIS.pth b/SiamMask/experiments/siammask_sharp/SiamMask_DAVIS.pth new file mode 100644 index 0000000000000000000000000000000000000000..9e3b43291979e9405187740cacc421898b2b934b --- /dev/null +++ b/SiamMask/experiments/siammask_sharp/SiamMask_DAVIS.pth @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d5a0e7cb13e2799bcf93545691261e7a48413ffb54bce9cb3b7fa3c560da4204 +size 105878246 diff --git a/SiamMask/experiments/siammask_sharp/__pycache__/custom.cpython-39.pyc b/SiamMask/experiments/siammask_sharp/__pycache__/custom.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d4a1f738e63ca31066f43905cb9c7aa07475234b Binary files /dev/null and b/SiamMask/experiments/siammask_sharp/__pycache__/custom.cpython-39.pyc differ diff --git a/SiamMask/experiments/siammask_sharp/__pycache__/resnet.cpython-39.pyc b/SiamMask/experiments/siammask_sharp/__pycache__/resnet.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e1b8ba8323f074e2d07e5bda6071f16b08e71c81 Binary files /dev/null and b/SiamMask/experiments/siammask_sharp/__pycache__/resnet.cpython-39.pyc differ diff --git a/SiamMask/experiments/siammask_sharp/config.json b/SiamMask/experiments/siammask_sharp/config.json new file mode 100644 index 0000000000000000000000000000000000000000..06acb8ca899316a690cdf0dc6e30ebcabc75e742 --- /dev/null +++ b/SiamMask/experiments/siammask_sharp/config.json @@ -0,0 +1,60 @@ +{ + "network": { + "arch": "Custom" + }, + "hp": { + "instance_size": 255, + "base_size": 8, + "out_size": 127, + "seg_thr": 0.35, + "penalty_k": 0.04, + "window_influence": 0.4, + "lr": 1.0 + }, + "lr": { + "type": "log", + "start_lr": 0.01, + "end_lr": 0.0025 + }, + "loss": { + "weight": [0, 0, 36] + }, + "train_datasets": { + "datasets": { + "ytb_vos": { + "root": "../../data/ytb_vos/crop511", + "anno": "../../data/ytb_vos/train.json", + "num_use": 100000, + "frame_range": 20 + }, + "coco": { + "root": "../../data/coco/crop511", + "anno": "../../data/coco/train2017.json", + "frame_range": 1 + } + }, + "template_size": 127, + "search_size": 143, + "base_size": 0, + "size": 3, + + "num" : 200000, + + "augmentation": { + "template": { + "shift": 4, "scale": 0.05 + }, + "search": { + "shift": 8, "scale": 0.18, "blur": 0.18 + }, + "neg": 0, + "gray": 0.25 + } + }, + "anchors": { + "stride": 8, + "ratios": [0.33, 0.5, 1, 2, 3], + "scales": [8], + "round_dight": 0 + } +} diff --git a/SiamMask/experiments/siammask_sharp/config_davis.json b/SiamMask/experiments/siammask_sharp/config_davis.json new file mode 100644 index 0000000000000000000000000000000000000000..30522f6142d72042f9c1fecd15847f4f76ee0ebc --- /dev/null +++ b/SiamMask/experiments/siammask_sharp/config_davis.json @@ -0,0 +1,20 @@ +{ + "network": { + "arch": "Custom" + }, + "hp": { + "instance_size": 255, + "base_size": 8, + "out_size": 127, + "seg_thr": 0.35, + "penalty_k": 0.04, + "window_influence": 0.4, + "lr": 1.0 + }, + "anchors": { + "stride": 8, + "ratios": [0.33, 0.5, 1, 2, 3], + "scales": [8], + "round_dight": 0 + } +} diff --git a/SiamMask/experiments/siammask_sharp/config_vot.json b/SiamMask/experiments/siammask_sharp/config_vot.json new file mode 100644 index 0000000000000000000000000000000000000000..279f4c825d7b01fa5ed1dc538b0b3b184cf64d21 --- /dev/null +++ b/SiamMask/experiments/siammask_sharp/config_vot.json @@ -0,0 +1,20 @@ +{ + "network": { + "arch": "Custom" + }, + "hp": { + "instance_size": 255, + "base_size": 8, + "out_size": 127, + "seg_thr": 0.30, + "penalty_k": 0.04, + "window_influence": 0.42, + "lr": 0.25 + }, + "anchors": { + "stride": 8, + "ratios": [0.33, 0.5, 1, 2, 3], + "scales": [8], + "round_dight": 0 + } +} diff --git a/SiamMask/experiments/siammask_sharp/config_vot18.json b/SiamMask/experiments/siammask_sharp/config_vot18.json new file mode 100644 index 0000000000000000000000000000000000000000..b902c52c54c569612030fab318c406334b2bd627 --- /dev/null +++ b/SiamMask/experiments/siammask_sharp/config_vot18.json @@ -0,0 +1,20 @@ +{ + "network": { + "arch": "Custom" + }, + "hp": { + "instance_size": 255, + "base_size": 8, + "out_size": 127, + "seg_thr": 0.15, + "penalty_k": 0.10, + "window_influence": 0.41, + "lr": 0.32 + }, + "anchors": { + "stride": 8, + "ratios": [0.33, 0.5, 1, 2, 3], + "scales": [8], + "round_dight": 0 + } +} diff --git a/SiamMask/experiments/siammask_sharp/custom.py b/SiamMask/experiments/siammask_sharp/custom.py new file mode 100644 index 0000000000000000000000000000000000000000..380c610dbe00995f57c79a3ee7b4e7286f0ffb14 --- /dev/null +++ b/SiamMask/experiments/siammask_sharp/custom.py @@ -0,0 +1,191 @@ +from models.siammask_sharp import SiamMask +from models.features import MultiStageFeature +from models.rpn import RPN, DepthCorr +from models.mask import Mask +import torch +import torch.nn as nn +import torch.nn.functional as F +from utils.load_helper import load_pretrain +from resnet import resnet50 + + +class ResDownS(nn.Module): + def __init__(self, inplane, outplane): + super(ResDownS, self).__init__() + self.downsample = nn.Sequential( + nn.Conv2d(inplane, outplane, kernel_size=1, bias=False), + nn.BatchNorm2d(outplane)) + + def forward(self, x): + x = self.downsample(x) + if x.size(3) < 20: + l = 4 + r = -4 + x = x[:, :, l:r, l:r] + return x + + +class ResDown(MultiStageFeature): + def __init__(self, pretrain=False): + super(ResDown, self).__init__() + self.features = resnet50(layer3=True, layer4=False) + if pretrain: + load_pretrain(self.features, 'resnet.model') + + self.downsample = ResDownS(1024, 256) + + self.layers = [self.downsample, self.features.layer2, self.features.layer3] + self.train_nums = [1, 3] + self.change_point = [0, 0.5] + + self.unfix(0.0) + + def param_groups(self, start_lr, feature_mult=1): + lr = start_lr * feature_mult + + def _params(module, mult=1): + params = list(filter(lambda x:x.requires_grad, module.parameters())) + if len(params): + return [{'params': params, 'lr': lr * mult}] + else: + return [] + + groups = [] + groups += _params(self.downsample) + groups += _params(self.features, 0.1) + return groups + + def forward(self, x): + output = self.features(x) + p3 = self.downsample(output[-1]) + return p3 + + def forward_all(self, x): + output = self.features(x) + p3 = self.downsample(output[-1]) + return output, p3 + + +class UP(RPN): + def __init__(self, anchor_num=5, feature_in=256, feature_out=256): + super(UP, self).__init__() + + self.anchor_num = anchor_num + self.feature_in = feature_in + self.feature_out = feature_out + + self.cls_output = 2 * self.anchor_num + self.loc_output = 4 * self.anchor_num + + self.cls = DepthCorr(feature_in, feature_out, self.cls_output) + self.loc = DepthCorr(feature_in, feature_out, self.loc_output) + + def forward(self, z_f, x_f): + cls = self.cls(z_f, x_f) + loc = self.loc(z_f, x_f) + return cls, loc + + +class MaskCorr(Mask): + def __init__(self, oSz=63): + super(MaskCorr, self).__init__() + self.oSz = oSz + self.mask = DepthCorr(256, 256, self.oSz**2) + + def forward(self, z, x): + return self.mask(z, x) + + +class Refine(nn.Module): + def __init__(self): + super(Refine, self).__init__() + self.v0 = nn.Sequential(nn.Conv2d(64, 16, 3, padding=1), nn.ReLU(), + nn.Conv2d(16, 4, 3, padding=1),nn.ReLU()) + + self.v1 = nn.Sequential(nn.Conv2d(256, 64, 3, padding=1), nn.ReLU(), + nn.Conv2d(64, 16, 3, padding=1), nn.ReLU()) + + self.v2 = nn.Sequential(nn.Conv2d(512, 128, 3, padding=1), nn.ReLU(), + nn.Conv2d(128, 32, 3, padding=1), nn.ReLU()) + + self.h2 = nn.Sequential(nn.Conv2d(32, 32, 3, padding=1), nn.ReLU(), + nn.Conv2d(32, 32, 3, padding=1), nn.ReLU()) + + self.h1 = nn.Sequential(nn.Conv2d(16, 16, 3, padding=1), nn.ReLU(), + nn.Conv2d(16, 16, 3, padding=1), nn.ReLU()) + + self.h0 = nn.Sequential(nn.Conv2d(4, 4, 3, padding=1), nn.ReLU(), + nn.Conv2d(4, 4, 3, padding=1), nn.ReLU()) + + self.deconv = nn.ConvTranspose2d(256, 32, 15, 15) + + self.post0 = nn.Conv2d(32, 16, 3, padding=1) + self.post1 = nn.Conv2d(16, 4, 3, padding=1) + self.post2 = nn.Conv2d(4, 1, 3, padding=1) + + for modules in [self.v0, self.v1, self.v2, self.h2, self.h1, self.h0, self.deconv, self.post0, self.post1, self.post2,]: + for l in modules.modules(): + if isinstance(l, nn.Conv2d): + nn.init.kaiming_uniform_(l.weight, a=1) + + def forward(self, f, corr_feature, pos=None, test=False): + if test: + p0 = torch.nn.functional.pad(f[0], [16, 16, 16, 16])[:, :, 4*pos[0]:4*pos[0]+61, 4*pos[1]:4*pos[1]+61] + p1 = torch.nn.functional.pad(f[1], [8, 8, 8, 8])[:, :, 2 * pos[0]:2 * pos[0] + 31, 2 * pos[1]:2 * pos[1] + 31] + p2 = torch.nn.functional.pad(f[2], [4, 4, 4, 4])[:, :, pos[0]:pos[0] + 15, pos[1]:pos[1] + 15] + else: + p0 = F.unfold(f[0], (61, 61), padding=0, stride=4).permute(0, 2, 1).contiguous().view(-1, 64, 61, 61) + if not (pos is None): p0 = torch.index_select(p0, 0, pos) + p1 = F.unfold(f[1], (31, 31), padding=0, stride=2).permute(0, 2, 1).contiguous().view(-1, 256, 31, 31) + if not (pos is None): p1 = torch.index_select(p1, 0, pos) + p2 = F.unfold(f[2], (15, 15), padding=0, stride=1).permute(0, 2, 1).contiguous().view(-1, 512, 15, 15) + if not (pos is None): p2 = torch.index_select(p2, 0, pos) + + if not(pos is None): + p3 = corr_feature[:, :, pos[0], pos[1]].view(-1, 256, 1, 1) + else: + p3 = corr_feature.permute(0, 2, 3, 1).contiguous().view(-1, 256, 1, 1) + + out = self.deconv(p3) + out = self.post0(F.upsample(self.h2(out) + self.v2(p2), size=(31, 31))) + out = self.post1(F.upsample(self.h1(out) + self.v1(p1), size=(61, 61))) + out = self.post2(F.upsample(self.h0(out) + self.v0(p0), size=(127, 127))) + out = out.view(-1, 127*127) + return out + + def param_groups(self, start_lr, feature_mult=1): + params = filter(lambda x:x.requires_grad, self.parameters()) + params = [{'params': params, 'lr': start_lr * feature_mult}] + return params + + +class Custom(SiamMask): + def __init__(self, pretrain=False, **kwargs): + super(Custom, self).__init__(**kwargs) + self.features = ResDown(pretrain=pretrain) + self.rpn_model = UP(anchor_num=self.anchor_num, feature_in=256, feature_out=256) + self.mask_model = MaskCorr() + self.refine_model = Refine() + + def refine(self, f, pos=None): + return self.refine_model(f, pos) + + def template(self, template): + self.zf = self.features(template) + + def track(self, search): + search = self.features(search) + rpn_pred_cls, rpn_pred_loc = self.rpn(self.zf, search) + return rpn_pred_cls, rpn_pred_loc + + def track_mask(self, search): + self.feature, self.search = self.features.forward_all(search) + rpn_pred_cls, rpn_pred_loc = self.rpn(self.zf, self.search) + self.corr_feature = self.mask_model.mask.forward_corr(self.zf, self.search) + pred_mask = self.mask_model.mask.head(self.corr_feature) + return rpn_pred_cls, rpn_pred_loc, pred_mask + + def track_refine(self, pos): + pred_mask = self.refine_model(self.feature, self.corr_feature, pos=pos, test=True) + return pred_mask + diff --git a/SiamMask/experiments/siammask_sharp/resnet.py b/SiamMask/experiments/siammask_sharp/resnet.py new file mode 100644 index 0000000000000000000000000000000000000000..5d2b596b59fe9fc1c4cb71d8bcca4429e2fdb214 --- /dev/null +++ b/SiamMask/experiments/siammask_sharp/resnet.py @@ -0,0 +1,352 @@ +import torch.nn as nn +import torch +from torch.autograd import Variable +import math +import torch.utils.model_zoo as model_zoo +from models.features import Features + +__all__ = ['ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101', + 'resnet152'] + + +model_urls = { + 'resnet18': 'https://download.pytorch.org/models/resnet18-5c106cde.pth', + 'resnet34': 'https://download.pytorch.org/models/resnet34-333f7ec4.pth', + 'resnet50': 'https://download.pytorch.org/models/resnet50-19c8e357.pth', + 'resnet101': 'https://download.pytorch.org/models/resnet101-5d3b4d8f.pth', + 'resnet152': 'https://download.pytorch.org/models/resnet152-b121ed2d.pth', +} + + +def conv3x3(in_planes, out_planes, stride=1): + "3x3 convolution with padding" + return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride, + padding=1, bias=False) + + +class BasicBlock(nn.Module): + expansion = 1 + + def __init__(self, inplanes, planes, stride=1, downsample=None): + super(BasicBlock, self).__init__() + self.conv1 = conv3x3(inplanes, planes, stride) + self.bn1 = nn.BatchNorm2d(planes) + self.relu = nn.ReLU(inplace=True) + self.conv2 = conv3x3(planes, planes) + self.bn2 = nn.BatchNorm2d(planes) + self.downsample = downsample + self.stride = stride + + def forward(self, x): + residual = x + + out = self.conv1(x) + out = self.bn1(out) + out = self.relu(out) + + out = self.conv2(out) + out = self.bn2(out) + + if self.downsample is not None: + residual = self.downsample(x) + + out += residual + out = self.relu(out) + + return out + + +class Bottleneck(Features): + expansion = 4 + + def __init__(self, inplanes, planes, stride=1, downsample=None, dilation=1): + super(Bottleneck, self).__init__() + self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False) + self.bn1 = nn.BatchNorm2d(planes) + # padding = (2 - stride) + (dilation // 2 - 1) + padding = 2 - stride + assert stride==1 or dilation==1, "stride and dilation must have one equals to zero at least" + if dilation > 1: + padding = dilation + self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, + padding=padding, bias=False, dilation=dilation) + self.bn2 = nn.BatchNorm2d(planes) + self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False) + self.bn3 = nn.BatchNorm2d(planes * 4) + self.relu = nn.ReLU(inplace=True) + self.downsample = downsample + self.stride = stride + + def forward(self, x): + residual = x + + out = self.conv1(x) + out = self.bn1(out) + out = self.relu(out) + + out = self.conv2(out) + out = self.bn2(out) + out = self.relu(out) + + out = self.conv3(out) + out = self.bn3(out) + + if self.downsample is not None: + residual = self.downsample(x) + + if out.size() != residual.size(): + print(out.size(), residual.size()) + out += residual + + out = self.relu(out) + + return out + + + +class Bottleneck_nop(nn.Module): + expansion = 4 + + def __init__(self, inplanes, planes, stride=1, downsample=None): + super(Bottleneck_nop, self).__init__() + self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False) + self.bn1 = nn.BatchNorm2d(planes) + self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, + padding=0, bias=False) + self.bn2 = nn.BatchNorm2d(planes) + self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False) + self.bn3 = nn.BatchNorm2d(planes * 4) + self.relu = nn.ReLU(inplace=True) + self.downsample = downsample + self.stride = stride + + def forward(self, x): + residual = x + + out = self.conv1(x) + out = self.bn1(out) + out = self.relu(out) + + out = self.conv2(out) + out = self.bn2(out) + out = self.relu(out) + + out = self.conv3(out) + out = self.bn3(out) + + if self.downsample is not None: + residual = self.downsample(x) + + s = residual.size(3) + residual = residual[:, :, 1:s-1, 1:s-1] + + out += residual + out = self.relu(out) + + return out + + +class ResNet(nn.Module): + + def __init__(self, block, layers, layer4=False, layer3=False): + self.inplanes = 64 + super(ResNet, self).__init__() + self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=0, # 3 + bias=False) + self.bn1 = nn.BatchNorm2d(64) + self.relu = nn.ReLU(inplace=True) + self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) + self.layer1 = self._make_layer(block, 64, layers[0]) + self.layer2 = self._make_layer(block, 128, layers[1], stride=2) # 31x31, 15x15 + + self.feature_size = 128 * block.expansion + + if layer3: + self.layer3 = self._make_layer(block, 256, layers[2], stride=1, dilation=2) # 15x15, 7x7 + self.feature_size = (256 + 128) * block.expansion + else: + self.layer3 = lambda x:x # identity + + if layer4: + self.layer4 = self._make_layer(block, 512, layers[3], stride=1, dilation=4) # 7x7, 3x3 + self.feature_size = 512 * block.expansion + else: + self.layer4 = lambda x:x # identity + + for m in self.modules(): + if isinstance(m, nn.Conv2d): + n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels + m.weight.data.normal_(0, math.sqrt(2. / n)) + elif isinstance(m, nn.BatchNorm2d): + m.weight.data.fill_(1) + m.bias.data.zero_() + + def _make_layer(self, block, planes, blocks, stride=1, dilation=1): + downsample = None + dd = dilation + if stride != 1 or self.inplanes != planes * block.expansion: + if stride == 1 and dilation == 1: + downsample = nn.Sequential( + nn.Conv2d(self.inplanes, planes * block.expansion, + kernel_size=1, stride=stride, bias=False), + nn.BatchNorm2d(planes * block.expansion), + ) + else: + if dilation > 1: + dd = dilation // 2 + padding = dd + else: + dd = 1 + padding = 0 + downsample = nn.Sequential( + nn.Conv2d(self.inplanes, planes * block.expansion, + kernel_size=3, stride=stride, bias=False, + padding=padding, dilation=dd), + nn.BatchNorm2d(planes * block.expansion), + ) + + layers = [] + # layers.append(block(self.inplanes, planes, stride, downsample, dilation=dilation)) + layers.append(block(self.inplanes, planes, stride, downsample, dilation=dd)) + self.inplanes = planes * block.expansion + for i in range(1, blocks): + layers.append(block(self.inplanes, planes, dilation=dilation)) + + return nn.Sequential(*layers) + + def forward(self, x): + x = self.conv1(x) + x = self.bn1(x) + p0 = self.relu(x) + x = self.maxpool(p0) + + p1 = self.layer1(x) + p2 = self.layer2(p1) + p3 = self.layer3(p2) + + return p0, p1, p2, p3 + + +class ResAdjust(nn.Module): + def __init__(self, + block=Bottleneck, + out_channels=256, + adjust_number=1, + fuse_layers=[2,3,4]): + super(ResAdjust, self).__init__() + self.fuse_layers = set(fuse_layers) + + if 2 in self.fuse_layers: + self.layer2 = self._make_layer(block, 128, 1, out_channels, adjust_number) + if 3 in self.fuse_layers: + self.layer3 = self._make_layer(block, 256, 2, out_channels, adjust_number) + if 4 in self.fuse_layers: + self.layer4 = self._make_layer(block, 512, 4, out_channels, adjust_number) + + self.feature_size = out_channels * len(self.fuse_layers) + + + def _make_layer(self, block, plances, dilation, out, number=1): + + layers = [] + + for _ in range(number): + layer = block(plances * block.expansion, plances, dilation=dilation) + layers.append(layer) + + downsample = nn.Sequential( + nn.Conv2d(plances * block.expansion, out, kernel_size=3, padding=1, bias=False), + nn.BatchNorm2d(out) + ) + layers.append(downsample) + + return nn.Sequential(*layers) + + def forward(self, p2, p3, p4): + + outputs = [] + + if 2 in self.fuse_layers: + outputs.append(self.layer2(p2)) + if 3 in self.fuse_layers: + outputs.append(self.layer3(p3)) + if 4 in self.fuse_layers: + outputs.append(self.layer4(p4)) + # return torch.cat(outputs, 1) + return outputs + + +def resnet18(pretrained=False, **kwargs): + """Constructs a ResNet-18 model. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(BasicBlock, [2, 2, 2, 2], **kwargs) + if pretrained: + model.load_state_dict(model_zoo.load_url(model_urls['resnet18'])) + return model + + +def resnet34(pretrained=False, **kwargs): + """Constructs a ResNet-34 model. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(BasicBlock, [3, 4, 6, 3], **kwargs) + if pretrained: + model.load_state_dict(model_zoo.load_url(model_urls['resnet34'])) + return model + + +def resnet50(pretrained=False, **kwargs): + """Constructs a ResNet-50 model. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(Bottleneck, [3, 4, 6, 3], **kwargs) + if pretrained: + model.load_state_dict(model_zoo.load_url(model_urls['resnet50'])) + return model + + +def resnet101(pretrained=False, **kwargs): + """Constructs a ResNet-101 model. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(Bottleneck, [3, 4, 23, 3], **kwargs) + if pretrained: + model.load_state_dict(model_zoo.load_url(model_urls['resnet101'])) + return model + + +def resnet152(pretrained=False, **kwargs): + """Constructs a ResNet-152 model. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(Bottleneck, [3, 8, 36, 3], **kwargs) + if pretrained: + model.load_state_dict(model_zoo.load_url(model_urls['resnet152'])) + return model + +if __name__ == '__main__': + net = resnet50() + print(net) + net = net.cuda() + + var = torch.FloatTensor(1,3,127,127).cuda() + var = Variable(var) + + net(var) + print('*************') + var = torch.FloatTensor(1,3,255,255).cuda() + var = Variable(var) + + net(var) + diff --git a/SiamMask/experiments/siammask_sharp/run.sh b/SiamMask/experiments/siammask_sharp/run.sh new file mode 100644 index 0000000000000000000000000000000000000000..3646ec5f99a4de987fa893a1d6d8c371dc4226ad --- /dev/null +++ b/SiamMask/experiments/siammask_sharp/run.sh @@ -0,0 +1,20 @@ +if [ -z "$1" ] + then + echo "Need input base model!" + echo "Usage: bash `basename "$0"` \$BASE_MODEL" + exit +fi + + +ROOT=`git rev-parse --show-toplevel` +export PYTHONPATH=$ROOT:$PYTHONPATH + +mkdir -p logs + +base=$1 + +python -u $ROOT/tools/train_siammask_refine.py \ + --config=config.json -b 64 \ + -j 20 --pretrained $base \ + --epochs 20 \ + 2>&1 | tee logs/train.log diff --git a/SiamMask/experiments/siammask_sharp/test_all.sh b/SiamMask/experiments/siammask_sharp/test_all.sh new file mode 100644 index 0000000000000000000000000000000000000000..4f7e83f18591a72b2afd66961c9e91f31fc61e92 --- /dev/null +++ b/SiamMask/experiments/siammask_sharp/test_all.sh @@ -0,0 +1,83 @@ +show_help() { +cat << EOF +Usage: + ${0##*/} [-h/--help] [-s/--start] [-e/--end] [-d/--dataset] [-m/--model] [-g/--gpu] + e.g. + bash ${0##*/} -s 1 -e 20 -d VOT2018 -g 4 # for test models + bash ${0##*/} -m snapshot/checkpoint_e10.pth -n 8 -g 4 # for tune models +EOF +} + +ROOT=`git rev-parse --show-toplevel` +source activate siammask +export PYTHONPATH=$ROOT:$PYTHONPATH +export PYTHONPATH=$PWD:$PYTHONPATH + +dataset=VOT2018 +NUM=4 +START=1 +END=20 +GPU=0 + +while [[ $# -gt 0 ]] +do + key="$1" + case $key in + -h|--help) + show_help + exit + ;; + -d|--dataset) + dataset=$2 + shift 2 + ;; + -n|--num) + NUM=$2 + shift 2 + ;; + -s|--start) + START=$2 + shift 2 + ;; + -e|--end) + END=$2 + shift 2 + ;; + -m|--model) + model=$2 + shift 2 + ;; + -g|--gpu) + GPU=$2 + shift 2 + ;; + *) + echo invalid arg [$1] + show_help + exit 1 + ;; + esac +done + +set -e + +if [ -z "$model" ]; then + echo test snapshot $START ~ $END on dataset $dataset with $GPU gpus. + for i in $(seq $START $END) + do + bash test_mask_refine.sh config_vot18.json snapshot/checkpoint_e$i.pth $dataset $(($i % $GPU)) & + done + wait + + python $ROOT/tools/eval.py --dataset $dataset --num 20 --tracker_prefix C --result_dir ./test/$dataset 2>&1 | tee logs/eval_test_$dataset.log +else + echo tuning $model on dataset $dataset with $NUM jobs in $GPU gpus. + for i in $(seq 1 $NUM) + do + bash tune.sh $model $dataset $(($i % $GPU)) & + done + wait + rm finish.flag + + python $ROOT/tools/eval.py --dataset $dataset --num 20 --tracker_prefix C --result_dir ./result/$dataset 2>&1 | tee logs/eval_tune_$dataset.log +fi diff --git a/SiamMask/experiments/siammask_sharp/test_mask_refine.sh b/SiamMask/experiments/siammask_sharp/test_mask_refine.sh new file mode 100644 index 0000000000000000000000000000000000000000..0cdcfcfc6e04df41fa76f1050415dc0bb8b6d0fe --- /dev/null +++ b/SiamMask/experiments/siammask_sharp/test_mask_refine.sh @@ -0,0 +1,23 @@ +if [ -z "$4" ] + then + echo "Need input parameter!" + echo "Usage: bash `basename "$0"` \$CONFIG \$MODEL \$DATASET \$GPUID" + exit +fi + +ROOT=`git rev-parse --show-toplevel` +export PYTHONPATH=$ROOT:$PYTHONPATH + +mkdir -p logs + +config=$1 +model=$2 +dataset=$3 +gpu=$4 + +CUDA_VISIBLE_DEVICES=$gpu python -u $ROOT/tools/test.py \ + --config $config \ + --resume $model \ + --mask --refine \ + --dataset $dataset 2>&1 | tee logs/test_$dataset.log + diff --git a/SiamMask/experiments/siammask_sharp/tune.sh b/SiamMask/experiments/siammask_sharp/tune.sh new file mode 100644 index 0000000000000000000000000000000000000000..14b5c5bebfc6227b8e575f5a210ae27d21bbe730 --- /dev/null +++ b/SiamMask/experiments/siammask_sharp/tune.sh @@ -0,0 +1,30 @@ +if [ -z "$1" ] + then + echo "Need input parameter!" + echo "Usage: bash `basename "$0"` \$MODEL \$DATASETi \$GPUID" + exit +fi + +which python + +ROOT=`git rev-parse --show-toplevel` +source activate siammask +export PYTHONPATH=$ROOT:$PYTHONPATH +export PYTHONPATH=$PWD:$PYTHONPATH + +mkdir -p logs + +model=$1 +dataset=$2 +id=$3 + +CUDA_VISIBLE_DEVICES=$id python -u $ROOT/tools/tune_vot.py\ + --config config_vot18.json \ + --dataset $dataset \ + --penalty-k 0.08,0.13,0.01 \ + --window-influence 0.38,0.44,0.01 \ + --lr 0.3,0.35,0.01 \ + --search-region 255,256,16 \ + --mask --refine \ + --resume $model 2>&1 | tee logs/tune.log + diff --git a/SiamMask/experiments/siamrpn_resnet/config.json b/SiamMask/experiments/siamrpn_resnet/config.json new file mode 100644 index 0000000000000000000000000000000000000000..6c72b00953912cb25644ee6aaedc8fcc9b3d2c53 --- /dev/null +++ b/SiamMask/experiments/siamrpn_resnet/config.json @@ -0,0 +1,100 @@ +{ + "network": { + "arch": "Custom" + }, + "hp": { + "instance_size": 255, + "base_size": 8 + }, + "lr": { + "type": "log", + "start_lr": 0.005, + "end_lr": 0.0025, + "warmup": { + "start_lr": 0.001, + "end_lr": 0.005, + "type": "step", + "step": 1, + "epoch": 5 + } + }, + "loss": { + "weight": [1.0, 1.0] + }, + "train_datasets": { + "datasets": { + "ytb_vos": { + "root": "../../data/ytb_vos/crop511", + "anno": "../../data/ytb_vos/train.json", + "num_use": 200000, + "frame_range": 20 + }, + "vid": { + "root": "../../data/vid/crop511", + "anno": "../../data/vid/train.json", + "frame_range": 100, + "num_use": 200000 + }, + "coco": { + "root": "../../data/coco/crop511", + "anno": "../../data/coco/train2017.json", + "frame_range": 1 + }, + "det": { + "root": "../../data/det/crop511", + "anno": "../../data/det/train.json", + "num_use": 100000, + "frame_range": 1 + } + }, + "template_size": 127, + "search_size": 255, + "base_size": 8, + "size": 25, + + "num" : 600000, + + "augmentation": { + "template": { + "shift": 4, "scale": 0.05 + }, + "search": { + "shift": 64, "scale": 0.18, "blur": 0.18 + }, + "neg": 0.2, + "gray": 0.25 + } + }, + + "val_datasets": { + "datasets": { + "vid": { + "root": "../../data/vid/crop511", + "anno": "../../data/vid/val.json", + "num_use": 1000 + } + }, + "template_size": 127, + "search_size": 255, + "size": 17, + + "num" : 1000, + + "augmentation": { + "template": { + "shift": 0, "scale": 0.00 + }, + "search": { + "shift": 12, "scale": 0.18 + }, + "neg": 0, + "gray": 0 + } + }, + "anchors": { + "stride": 8, + "ratios": [0.33, 0.5, 1, 2, 3], + "scales": [8], + "round_dight": 0 + } +} diff --git a/SiamMask/experiments/siamrpn_resnet/custom.py b/SiamMask/experiments/siamrpn_resnet/custom.py new file mode 100644 index 0000000000000000000000000000000000000000..da1cc742b83196f8674bbbe0645350b4e8c8df82 --- /dev/null +++ b/SiamMask/experiments/siamrpn_resnet/custom.py @@ -0,0 +1,93 @@ +from models.siamrpn import SiamRPN +from models.features import MultiStageFeature +from models.rpn import RPN, DepthCorr +import torch.nn as nn +from utils.load_helper import load_pretrain +from resnet import resnet50 + + +class ResDownS(nn.Module): + def __init__(self, inplane, outplane): + super(ResDownS, self).__init__() + self.downsample = nn.Sequential( + nn.Conv2d(inplane, outplane, kernel_size=1, bias=False), + nn.BatchNorm2d(outplane)) + + def forward(self, x): + x = self.downsample(x) + if x.size(3) < 20: + l = 4 + r = -4 + x = x[:, :, l:r, l:r] + return x + + +class ResDown(MultiStageFeature): + def __init__(self, pretrain=False): + super(ResDown, self).__init__() + self.features = resnet50(layer3=True, layer4=False) + if pretrain: + load_pretrain(self.features, 'resnet.model') + + self.downsample = ResDownS(1024, 256) + self.layers = [self.downsample, self.features.layer2, self.features.layer3] + self.train_nums = [1, 3] + self.change_point = [0, 0.5] + + self.unfix(0.0) + + def param_groups(self, start_lr, feature_mult=1): + lr = start_lr * feature_mult + + def _params(module, mult=1): + params = list(filter(lambda x:x.requires_grad, module.parameters())) + if len(params): + return [{'params': params, 'lr': lr * mult}] + else: + return [] + + groups = [] + groups += _params(self.downsample) + groups += _params(self.features, 0.1) + return groups + + def forward(self, x): + output = self.features(x) + p2, p3, p4 = output + p3 = self.downsample(p3) + return p3 + + +class UP(RPN): + def __init__(self, anchor_num=5, feature_in=256, feature_out=256): + super(UP, self).__init__() + + self.anchor_num = anchor_num + self.feature_in = feature_in + self.feature_out = feature_out + + self.cls_output = 2 * self.anchor_num + self.loc_output = 4 * self.anchor_num + + self.cls = DepthCorr(feature_in, feature_out, self.cls_output) + self.loc = DepthCorr(feature_in, feature_out, self.loc_output) + + def forward(self, z_f, x_f): + cls = self.cls(z_f, x_f) + loc = self.loc(z_f, x_f) + return cls, loc + + +class Custom(SiamRPN): + def __init__(self, pretrain=False, **kwargs): + super(Custom, self).__init__(**kwargs) + self.features = ResDown(pretrain=pretrain) + self.rpn_model = UP(anchor_num=self.anchor_num, feature_in=256, feature_out=256) + + def template(self, template): + self.zf = self.features(template) + + def track(self, search): + search = self.features(search) + rpn_pred_cls, rpn_pred_loc = self.rpn(self.zf, search) + return rpn_pred_cls, rpn_pred_loc diff --git a/SiamMask/experiments/siamrpn_resnet/resnet.py b/SiamMask/experiments/siamrpn_resnet/resnet.py new file mode 100644 index 0000000000000000000000000000000000000000..4ca45fc4b5593460ab2943c6eff71dba1c07fb17 --- /dev/null +++ b/SiamMask/experiments/siamrpn_resnet/resnet.py @@ -0,0 +1,359 @@ +import torch.nn as nn +import torch +from torch.autograd import Variable +import math +import torch.utils.model_zoo as model_zoo +from models.features import Features +from utils.log_helper import log_once + + +__all__ = ['ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101', + 'resnet152'] + + +model_urls = { + 'resnet18': 'https://download.pytorch.org/models/resnet18-5c106cde.pth', + 'resnet34': 'https://download.pytorch.org/models/resnet34-333f7ec4.pth', + 'resnet50': 'https://download.pytorch.org/models/resnet50-19c8e357.pth', + 'resnet101': 'https://download.pytorch.org/models/resnet101-5d3b4d8f.pth', + 'resnet152': 'https://download.pytorch.org/models/resnet152-b121ed2d.pth', +} + + +def conv3x3(in_planes, out_planes, stride=1): + "3x3 convolution with padding" + return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride, + padding=1, bias=False) + + +class BasicBlock(nn.Module): + expansion = 1 + + def __init__(self, inplanes, planes, stride=1, downsample=None): + super(BasicBlock, self).__init__() + self.conv1 = conv3x3(inplanes, planes, stride) + self.bn1 = nn.BatchNorm2d(planes) + self.relu = nn.ReLU(inplace=True) + self.conv2 = conv3x3(planes, planes) + self.bn2 = nn.BatchNorm2d(planes) + self.downsample = downsample + self.stride = stride + + def forward(self, x): + residual = x + + out = self.conv1(x) + out = self.bn1(out) + out = self.relu(out) + + out = self.conv2(out) + out = self.bn2(out) + + if self.downsample is not None: + residual = self.downsample(x) + + out += residual + out = self.relu(out) + + return out + + +class Bottleneck(Features): + expansion = 4 + + def __init__(self, inplanes, planes, stride=1, downsample=None, dilation=1): + super(Bottleneck, self).__init__() + self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False) + self.bn1 = nn.BatchNorm2d(planes) + # padding = (2 - stride) + (dilation // 2 - 1) + padding = 2 - stride + assert stride==1 or dilation==1, "stride and dilation must have one equals to zero at least" + if dilation > 1: + padding = dilation + self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, + padding=padding, bias=False, dilation=dilation) + self.bn2 = nn.BatchNorm2d(planes) + self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False) + self.bn3 = nn.BatchNorm2d(planes * 4) + self.relu = nn.ReLU(inplace=True) + self.downsample = downsample + self.stride = stride + + def forward(self, x): + residual = x + + out = self.conv1(x) + out = self.bn1(out) + out = self.relu(out) + + out = self.conv2(out) + out = self.bn2(out) + out = self.relu(out) + + out = self.conv3(out) + out = self.bn3(out) + + if self.downsample is not None: + residual = self.downsample(x) + + if out.size() != residual.size(): + print(out.size(), residual.size()) + out += residual + + out = self.relu(out) + + return out + + +class Bottleneck_nop(nn.Module): + expansion = 4 + + def __init__(self, inplanes, planes, stride=1, downsample=None): + super(Bottleneck_nop, self).__init__() + self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False) + self.bn1 = nn.BatchNorm2d(planes) + self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, + padding=0, bias=False) + self.bn2 = nn.BatchNorm2d(planes) + self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False) + self.bn3 = nn.BatchNorm2d(planes * 4) + self.relu = nn.ReLU(inplace=True) + self.downsample = downsample + self.stride = stride + + def forward(self, x): + residual = x + + out = self.conv1(x) + out = self.bn1(out) + out = self.relu(out) + + out = self.conv2(out) + out = self.bn2(out) + out = self.relu(out) + + out = self.conv3(out) + out = self.bn3(out) + + if self.downsample is not None: + residual = self.downsample(x) + + s = residual.size(3) + residual = residual[:, :, 1:s-1, 1:s-1] + + out += residual + out = self.relu(out) + + return out + + +class ResNet(nn.Module): + + def __init__(self, block, layers, layer4=False, layer3=False): + self.inplanes = 64 + super(ResNet, self).__init__() + self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=0, # 3 + bias=False) + self.bn1 = nn.BatchNorm2d(64) + self.relu = nn.ReLU(inplace=True) + self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) + self.layer1 = self._make_layer(block, 64, layers[0]) + self.layer2 = self._make_layer(block, 128, layers[1], stride=2) # 31x31, 15x15 + + self.feature_size = 128 * block.expansion + + if layer3: + self.layer3 = self._make_layer(block, 256, layers[2], stride=1, dilation=2) # 15x15, 7x7 + self.feature_size = (256 + 128) * block.expansion + else: + self.layer3 = lambda x:x # identity + + if layer4: + self.layer4 = self._make_layer(block, 512, layers[3], stride=1, dilation=4) # 7x7, 3x3 + self.feature_size = 512 * block.expansion + else: + self.layer4 = lambda x:x # identity + + for m in self.modules(): + if isinstance(m, nn.Conv2d): + n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels + m.weight.data.normal_(0, math.sqrt(2. / n)) + elif isinstance(m, nn.BatchNorm2d): + m.weight.data.fill_(1) + m.bias.data.zero_() + + def _make_layer(self, block, planes, blocks, stride=1, dilation=1): + downsample = None + dd = dilation + if stride != 1 or self.inplanes != planes * block.expansion: + if stride == 1 and dilation == 1: + downsample = nn.Sequential( + nn.Conv2d(self.inplanes, planes * block.expansion, + kernel_size=1, stride=stride, bias=False), + nn.BatchNorm2d(planes * block.expansion), + ) + else: + if dilation > 1: + dd = dilation // 2 + padding = dd + else: + dd = 1 + padding = 0 + downsample = nn.Sequential( + nn.Conv2d(self.inplanes, planes * block.expansion, + kernel_size=3, stride=stride, bias=False, + padding=padding, dilation=dd), + nn.BatchNorm2d(planes * block.expansion), + ) + + layers = [] + # layers.append(block(self.inplanes, planes, stride, downsample, dilation=dilation)) + layers.append(block(self.inplanes, planes, stride, downsample, dilation=dd)) + self.inplanes = planes * block.expansion + for i in range(1, blocks): + layers.append(block(self.inplanes, planes, dilation=dilation)) + + return nn.Sequential(*layers) + + def forward(self, x): + x = self.conv1(x) + x = self.bn1(x) + x = self.relu(x) + # print x.size() + x = self.maxpool(x) + # print x.size() + + p1 = self.layer1(x) + p2 = self.layer2(p1) + p3 = self.layer3(p2) + # p3 = torch.cat([p2, p3], 1) + + log_once("p3 {}".format(p3.size())) + p4 = self.layer4(p3) + + return p2, p3, p4 + + +class ResAdjust(nn.Module): + def __init__(self, + block=Bottleneck, + out_channels=256, + adjust_number=1, + fuse_layers=[2,3,4]): + super(ResAdjust, self).__init__() + self.fuse_layers = set(fuse_layers) + + if 2 in self.fuse_layers: + self.layer2 = self._make_layer(block, 128, 1, out_channels, adjust_number) + if 3 in self.fuse_layers: + self.layer3 = self._make_layer(block, 256, 2, out_channels, adjust_number) + if 4 in self.fuse_layers: + self.layer4 = self._make_layer(block, 512, 4, out_channels, adjust_number) + + self.feature_size = out_channels * len(self.fuse_layers) + + def _make_layer(self, block, plances, dilation, out, number=1): + + layers = [] + + for _ in range(number): + layer = block(plances * block.expansion, plances, dilation=dilation) + layers.append(layer) + + downsample = nn.Sequential( + nn.Conv2d(plances * block.expansion, out, kernel_size=3, padding=1, bias=False), + nn.BatchNorm2d(out) + ) + layers.append(downsample) + + return nn.Sequential(*layers) + + def forward(self, p2, p3, p4): + + outputs = [] + + if 2 in self.fuse_layers: + outputs.append(self.layer2(p2)) + if 3 in self.fuse_layers: + outputs.append(self.layer3(p3)) + if 4 in self.fuse_layers: + outputs.append(self.layer4(p4)) + # return torch.cat(outputs, 1) + return outputs + + +def resnet18(pretrained=False, **kwargs): + """Constructs a ResNet-18 model. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(BasicBlock, [2, 2, 2, 2], **kwargs) + if pretrained: + model.load_state_dict(model_zoo.load_url(model_urls['resnet18'])) + return model + + +def resnet34(pretrained=False, **kwargs): + """Constructs a ResNet-34 model. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(BasicBlock, [3, 4, 6, 3], **kwargs) + if pretrained: + model.load_state_dict(model_zoo.load_url(model_urls['resnet34'])) + return model + + +def resnet50(pretrained=False, **kwargs): + """Constructs a ResNet-50 model. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(Bottleneck, [3, 4, 6, 3], **kwargs) + if pretrained: + model.load_state_dict(model_zoo.load_url(model_urls['resnet50'])) + return model + + +def resnet101(pretrained=False, **kwargs): + """Constructs a ResNet-101 model. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(Bottleneck, [3, 4, 23, 3], **kwargs) + if pretrained: + model.load_state_dict(model_zoo.load_url(model_urls['resnet101'])) + return model + + +def resnet152(pretrained=False, **kwargs): + """Constructs a ResNet-152 model. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(Bottleneck, [3, 8, 36, 3], **kwargs) + if pretrained: + model.load_state_dict(model_zoo.load_url(model_urls['resnet152'])) + return model + + +if __name__ == '__main__': + net = resnet50() + print(net) + net = net.cuda() + + var = torch.FloatTensor(1,3,127,127).cuda() + var = Variable(var) + template = net(var) + print('Examplar Size: {}'.format(template.shape)) + + var = torch.FloatTensor(1,3,255,255).cuda() + var = Variable(var) + + net(var) + diff --git a/SiamMask/experiments/siamrpn_resnet/run.sh b/SiamMask/experiments/siamrpn_resnet/run.sh new file mode 100644 index 0000000000000000000000000000000000000000..31f7f008b33eed74656cb1e1fd76d6897e23234d --- /dev/null +++ b/SiamMask/experiments/siamrpn_resnet/run.sh @@ -0,0 +1,13 @@ +ROOT=`git rev-parse --show-toplevel` +export PYTHONPATH=$ROOT:$PYTHONPATH + +mkdir -p logs + +python -u $ROOT/tools/train_siamrpn.py \ + --config=config.json -b 256 \ + -j 20 \ + --epochs 20 \ + --log logs/log.txt \ + 2>&1 | tee logs/train.log + +bash test_all.sh -s 1 -e 20 -d VOT2018 -g 4 diff --git a/SiamMask/experiments/siamrpn_resnet/test.sh b/SiamMask/experiments/siamrpn_resnet/test.sh new file mode 100644 index 0000000000000000000000000000000000000000..9e3e6c095a3f63b1624edd9e3387fd28b1bafbfb --- /dev/null +++ b/SiamMask/experiments/siamrpn_resnet/test.sh @@ -0,0 +1,23 @@ +if [ -z "$3" ] + then + echo "Need input parameter!" + echo "Usage: bash `basename "$0"` \$MODEL \$DATASETi \$GPUID" + exit +fi + +source activate siammask +ROOT=`git rev-parse --show-toplevel` +export PYTHONPATH=$ROOT:$PYTHONPATH +export PYTHONPATH=$PWD:$PYTHONPATH + +mkdir -p logs + +model=$1 +dataset=$2 +gpu=$3 + +CUDA_VISIBLE_DEVICES=$gpu python -u $ROOT/tools/test.py \ + --config config.json \ + --resume $model \ + --dataset $dataset 2>&1 | tee logs/test.log + diff --git a/SiamMask/experiments/siamrpn_resnet/test_all.sh b/SiamMask/experiments/siamrpn_resnet/test_all.sh new file mode 100644 index 0000000000000000000000000000000000000000..0b896ae1befccd2708bd697c6183ec24a2cd9352 --- /dev/null +++ b/SiamMask/experiments/siamrpn_resnet/test_all.sh @@ -0,0 +1,83 @@ +show_help() { +cat << EOF +Usage: + ${0##*/} [-h/--help] [-s/--start] [-e/--end] [-d/--dataset] [-m/--model] [-g/--gpu] + e.g. + bash ${0##*/} -s 1 -e 20 -d VOT2018 -g 4 # for test models + bash ${0##*/} -m snapshot/checkpoint_e10.pth -n 8 -g 4 # for tune models +EOF +} + +ROOT=`git rev-parse --show-toplevel` +source activate siammask +export PYTHONPATH=$ROOT:$PYTHONPATH +export PYTHONPATH=$PWD:$PYTHONPATH + +dataset=VOT2018 +NUM=4 +START=1 +END=20 +GPU=0 + +while [[ $# -gt 0 ]] +do + key="$1" + case $key in + -h|--help) + show_help + exit + ;; + -d|--dataset) + dataset=$2 + shift 2 + ;; + -n|--num) + NUM=$2 + shift 2 + ;; + -s|--start) + START=$2 + shift 2 + ;; + -e|--end) + END=$2 + shift 2 + ;; + -m|--model) + model=$2 + shift 2 + ;; + -g|--gpu) + GPU=$2 + shift 2 + ;; + *) + echo invalid arg [$1] + show_help + exit 1 + ;; + esac +done + +set -e + +if [ -z "$model" ]; then + echo test snapshot $START ~ $END on dataset $dataset with $GPU gpus. + for i in $(seq $START $END) + do + bash test.sh snapshot/checkpoint_e$i.pth $dataset $(($i % $GPU)) & + done + wait + + python $ROOT/tools/eval.py --dataset $dataset --num 20 --tracker_prefix C --result_dir ./test/$dataset 2>&1 | tee logs/eval_test_$dataset.log +else + echo tuning $model on dataset $dataset with $NUM jobs in $GPU gpus. + for i in $(seq 1 $NUM) + do + bash tune.sh $model $dataset $(($i % $GPU)) & + done + wait + rm finish.flag + + python $ROOT/tools/eval.py --dataset $dataset --num 20 --tracker_prefix C --result_dir ./result/$dataset 2>&1 | tee logs/eval_tune_$dataset.log +fi diff --git a/SiamMask/experiments/siamrpn_resnet/tune.sh b/SiamMask/experiments/siamrpn_resnet/tune.sh new file mode 100644 index 0000000000000000000000000000000000000000..7806379ab0f9f07580364573299d0998faa86995 --- /dev/null +++ b/SiamMask/experiments/siamrpn_resnet/tune.sh @@ -0,0 +1,29 @@ +if [ -z "$1" ] + then + echo "Need input parameter!" + echo "Usage: bash `basename "$0"` \$MODEL \$DATASETi \$GPUID" + exit +fi + +which python + +ROOT=`git rev-parse --show-toplevel` +source activate siammask +export PYTHONPATH=$ROOT:$PYTHONPATH +export PYTHONPATH=$PWD:$PYTHONPATH + +mkdir -p logs + +model=$1 +dataset=$2 +id=$3 + +CUDA_VISIBLE_DEVICES=$id python -u $ROOT/tools/tune_vot.py\ + --config config.json \ + --dataset $dataset \ + --penalty-k 0.0,0.25,0.02 \ + --window-influence 0.36,0.51,0.02 \ + --lr 0.25,0.56,0.05 \ + --search-region 255,256,16 \ + --resume $model 2>&1 | tee logs/tune.log + diff --git a/SiamMask/make.sh b/SiamMask/make.sh new file mode 100644 index 0000000000000000000000000000000000000000..4183c7e9a0f7c1cf645925b9a401c4d96f6a1fd4 --- /dev/null +++ b/SiamMask/make.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +cd utils/pyvotkit +python setup.py build_ext --inplace +cd ../../ + +cd utils/pysot/utils/ +python setup.py build_ext --inplace +cd ../../../ diff --git a/SiamMask/models/__init__.py b/SiamMask/models/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SiamMask/models/__pycache__/__init__.cpython-39.pyc b/SiamMask/models/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ec653ad02425f97b9c881a7667ea04d3fa37f0d9 Binary files /dev/null and b/SiamMask/models/__pycache__/__init__.cpython-39.pyc differ diff --git a/SiamMask/models/__pycache__/features.cpython-39.pyc b/SiamMask/models/__pycache__/features.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d8e544488bd2ffa67cdea08bb080f9fedbd17265 Binary files /dev/null and b/SiamMask/models/__pycache__/features.cpython-39.pyc differ diff --git a/SiamMask/models/__pycache__/mask.cpython-39.pyc b/SiamMask/models/__pycache__/mask.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ef0b1d595d33f643d4514ca7c9f9294d16893c0e Binary files /dev/null and b/SiamMask/models/__pycache__/mask.cpython-39.pyc differ diff --git a/SiamMask/models/__pycache__/rpn.cpython-39.pyc b/SiamMask/models/__pycache__/rpn.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a9ac9e8714964ac3ff57fc40d9920310625424d0 Binary files /dev/null and b/SiamMask/models/__pycache__/rpn.cpython-39.pyc differ diff --git a/SiamMask/models/__pycache__/siammask_sharp.cpython-39.pyc b/SiamMask/models/__pycache__/siammask_sharp.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..210492bdba1dede49d70eaf51908e030e8f6c617 Binary files /dev/null and b/SiamMask/models/__pycache__/siammask_sharp.cpython-39.pyc differ diff --git a/SiamMask/models/features.py b/SiamMask/models/features.py new file mode 100644 index 0000000000000000000000000000000000000000..9ebd8d422100f712582f7b74a812db95c96ebbd4 --- /dev/null +++ b/SiamMask/models/features.py @@ -0,0 +1,79 @@ +# -------------------------------------------------------- +# SiamMask +# Licensed under The MIT License +# Written by Qiang Wang (wangqiang2015 at ia.ac.cn) +# -------------------------------------------------------- +import torch.nn as nn +import logging + +logger = logging.getLogger('global') + + +class Features(nn.Module): + def __init__(self): + super(Features, self).__init__() + self.feature_size = -1 + + def forward(self, x): + raise NotImplementedError + + def param_groups(self, start_lr, feature_mult=1): + params = filter(lambda x:x.requires_grad, self.parameters()) + params = [{'params': params, 'lr': start_lr * feature_mult}] + return params + + def load_model(self, f='pretrain.model'): + with open(f) as f: + pretrained_dict = torch.load(f) + model_dict = self.state_dict() + print(pretrained_dict.keys()) + pretrained_dict = {k: v for k, v in pretrained_dict.items() if k in model_dict} + print(pretrained_dict.keys()) + model_dict.update(pretrained_dict) + self.load_state_dict(model_dict) + + +class MultiStageFeature(Features): + def __init__(self): + super(MultiStageFeature, self).__init__() + + self.layers = [] + self.train_num = -1 + self.change_point = [] + self.train_nums = [] + + def unfix(self, ratio=0.0): + if self.train_num == -1: + self.train_num = 0 + self.unlock() + self.eval() + for p, t in reversed(list(zip(self.change_point, self.train_nums))): + if ratio >= p: + if self.train_num != t: + self.train_num = t + self.unlock() + return True + break + return False + + def train_layers(self): + return self.layers[:self.train_num] + + def unlock(self): + for p in self.parameters(): + p.requires_grad = False + + logger.info('Current training {} layers:\n\t'.format(self.train_num, self.train_layers())) + for m in self.train_layers(): + for p in m.parameters(): + p.requires_grad = True + + def train(self, mode): + self.training = mode + if mode == False: + super(MultiStageFeature,self).train(False) + else: + for m in self.train_layers(): + m.train(True) + + return self diff --git a/SiamMask/models/mask.py b/SiamMask/models/mask.py new file mode 100644 index 0000000000000000000000000000000000000000..b32f9ea27f2eb5c93e06bc38ced5b816cb0a4b94 --- /dev/null +++ b/SiamMask/models/mask.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------- +# SiamMask +# Licensed under The MIT License +# Written by Qiang Wang (wangqiang2015 at ia.ac.cn) +# -------------------------------------------------------- +import torch.nn as nn + + +class Mask(nn.Module): + def __init__(self): + super(Mask, self).__init__() + + def forward(self, z_f, x_f): + raise NotImplementedError + + def template(self, template): + raise NotImplementedError + + def track(self, search): + raise NotImplementedError + + def param_groups(self, start_lr, feature_mult=1): + params = filter(lambda x:x.requires_grad, self.parameters()) + params = [{'params': params, 'lr': start_lr * feature_mult}] + return params diff --git a/SiamMask/models/rpn.py b/SiamMask/models/rpn.py new file mode 100644 index 0000000000000000000000000000000000000000..e6158ac77b5267b1fca9ce14ed43294c84d79390 --- /dev/null +++ b/SiamMask/models/rpn.py @@ -0,0 +1,72 @@ +# -------------------------------------------------------- +# SiamMask +# Licensed under The MIT License +# Written by Qiang Wang (wangqiang2015 at ia.ac.cn) +# -------------------------------------------------------- +import torch.nn as nn +import torch.nn.functional as F + + +class RPN(nn.Module): + def __init__(self): + super(RPN, self).__init__() + + def forward(self, z_f, x_f): + raise NotImplementedError + + def template(self, template): + raise NotImplementedError + + def track(self, search): + raise NotImplementedError + + def param_groups(self, start_lr, feature_mult=1, key=None): + if key is None: + params = filter(lambda x:x.requires_grad, self.parameters()) + else: + params = [v for k, v in self.named_parameters() if (key in k) and v.requires_grad] + params = [{'params': params, 'lr': start_lr * feature_mult}] + return params + + +def conv2d_dw_group(x, kernel): + batch, channel = kernel.shape[:2] + x = x.view(1, batch*channel, x.size(2), x.size(3)) # 1 * (b*c) * k * k + kernel = kernel.view(batch*channel, 1, kernel.size(2), kernel.size(3)) # (b*c) * 1 * H * W + out = F.conv2d(x, kernel, groups=batch*channel) + out = out.view(batch, channel, out.size(2), out.size(3)) + return out + + +class DepthCorr(nn.Module): + def __init__(self, in_channels, hidden, out_channels, kernel_size=3): + super(DepthCorr, self).__init__() + # adjust layer for asymmetrical features + self.conv_kernel = nn.Sequential( + nn.Conv2d(in_channels, hidden, kernel_size=kernel_size, bias=False), + nn.BatchNorm2d(hidden), + nn.ReLU(inplace=True), + ) + self.conv_search = nn.Sequential( + nn.Conv2d(in_channels, hidden, kernel_size=kernel_size, bias=False), + nn.BatchNorm2d(hidden), + nn.ReLU(inplace=True), + ) + + self.head = nn.Sequential( + nn.Conv2d(hidden, hidden, kernel_size=1, bias=False), + nn.BatchNorm2d(hidden), + nn.ReLU(inplace=True), + nn.Conv2d(hidden, out_channels, kernel_size=1) + ) + + def forward_corr(self, kernel, input): + kernel = self.conv_kernel(kernel) + input = self.conv_search(input) + feature = conv2d_dw_group(input, kernel) + return feature + + def forward(self, kernel, search): + feature = self.forward_corr(kernel, search) + out = self.head(feature) + return out diff --git a/SiamMask/models/siammask.py b/SiamMask/models/siammask.py new file mode 100644 index 0000000000000000000000000000000000000000..a15b559682b5641e2503e20a948aa633f36bea01 --- /dev/null +++ b/SiamMask/models/siammask.py @@ -0,0 +1,192 @@ +# -------------------------------------------------------- +# SiamMask +# Licensed under The MIT License +# Written by Qiang Wang (wangqiang2015 at ia.ac.cn) +# -------------------------------------------------------- +import torch +import torch.nn as nn +import torch.nn.functional as F +from torch.autograd import Variable +from utils.anchors import Anchors + + +class SiamMask(nn.Module): + def __init__(self, anchors=None, o_sz=63, g_sz=127): + super(SiamMask, self).__init__() + self.anchors = anchors # anchor_cfg + self.anchor_num = len(self.anchors["ratios"]) * len(self.anchors["scales"]) + self.anchor = Anchors(anchors) + self.features = None + self.rpn_model = None + self.mask_model = None + self.o_sz = o_sz + self.g_sz = g_sz + self.upSample = nn.UpsamplingBilinear2d(size=[g_sz, g_sz]) + + self.all_anchors = None + + def set_all_anchors(self, image_center, size): + # cx,cy,w,h + if not self.anchor.generate_all_anchors(image_center, size): + return + all_anchors = self.anchor.all_anchors[1] # cx, cy, w, h + self.all_anchors = torch.from_numpy(all_anchors).float().cuda() + self.all_anchors = [self.all_anchors[i] for i in range(4)] + + def feature_extractor(self, x): + return self.features(x) + + def rpn(self, template, search): + pred_cls, pred_loc = self.rpn_model(template, search) + return pred_cls, pred_loc + + def mask(self, template, search): + pred_mask = self.mask_model(template, search) + return pred_mask + + def _add_rpn_loss(self, label_cls, label_loc, lable_loc_weight, label_mask, label_mask_weight, + rpn_pred_cls, rpn_pred_loc, rpn_pred_mask): + rpn_loss_cls = select_cross_entropy_loss(rpn_pred_cls, label_cls) + + rpn_loss_loc = weight_l1_loss(rpn_pred_loc, label_loc, lable_loc_weight) + + rpn_loss_mask, iou_m, iou_5, iou_7 = select_mask_logistic_loss(rpn_pred_mask, label_mask, label_mask_weight) + + return rpn_loss_cls, rpn_loss_loc, rpn_loss_mask, iou_m, iou_5, iou_7 + + def run(self, template, search, softmax=False): + """ + run network + """ + template_feature = self.feature_extractor(template) + search_feature = self.feature_extractor(search) + rpn_pred_cls, rpn_pred_loc = self.rpn(template_feature, search_feature) + rpn_pred_mask = self.mask(template_feature, search_feature) # (b, 63*63, w, h) + + if softmax: + rpn_pred_cls = self.softmax(rpn_pred_cls) + return rpn_pred_cls, rpn_pred_loc, rpn_pred_mask, template_feature, search_feature + + def softmax(self, cls): + b, a2, h, w = cls.size() + cls = cls.view(b, 2, a2//2, h, w) + cls = cls.permute(0, 2, 3, 4, 1).contiguous() + cls = F.log_softmax(cls, dim=4) + return cls + + def forward(self, input): + """ + :param input: dict of input with keys of: + 'template': [b, 3, h1, w1], input template image. + 'search': [b, 3, h2, w2], input search image. + 'label_cls':[b, max_num_gts, 5] or None(self.training==False), + each gt contains x1,y1,x2,y2,class. + :return: dict of loss, predict, accuracy + """ + template = input['template'] + search = input['search'] + if self.training: + label_cls = input['label_cls'] + label_loc = input['label_loc'] + lable_loc_weight = input['label_loc_weight'] + label_mask = input['label_mask'] + label_mask_weight = input['label_mask_weight'] + + rpn_pred_cls, rpn_pred_loc, rpn_pred_mask, template_feature, search_feature = \ + self.run(template, search, softmax=self.training) + + outputs = dict() + + outputs['predict'] = [rpn_pred_loc, rpn_pred_cls, rpn_pred_mask, template_feature, search_feature] + + if self.training: + rpn_loss_cls, rpn_loss_loc, rpn_loss_mask, iou_acc_mean, iou_acc_5, iou_acc_7 = \ + self._add_rpn_loss(label_cls, label_loc, lable_loc_weight, label_mask, label_mask_weight, + rpn_pred_cls, rpn_pred_loc, rpn_pred_mask) + outputs['losses'] = [rpn_loss_cls, rpn_loss_loc, rpn_loss_mask] + outputs['accuracy'] = [iou_acc_mean, iou_acc_5, iou_acc_7] + + return outputs + + def template(self, z): + self.zf = self.feature_extractor(z) + cls_kernel, loc_kernel = self.rpn_model.template(self.zf) + return cls_kernel, loc_kernel + + def track(self, x, cls_kernel=None, loc_kernel=None, softmax=False): + xf = self.feature_extractor(x) + rpn_pred_cls, rpn_pred_loc = self.rpn_model.track(xf, cls_kernel, loc_kernel) + if softmax: + rpn_pred_cls = self.softmax(rpn_pred_cls) + return rpn_pred_cls, rpn_pred_loc + + +def get_cls_loss(pred, label, select): + if select.nelement() == 0: return pred.sum()*0. + pred = torch.index_select(pred, 0, select) + label = torch.index_select(label, 0, select) + + return F.nll_loss(pred, label) + + +def select_cross_entropy_loss(pred, label): + pred = pred.view(-1, 2) + label = label.view(-1) + pos = Variable(label.data.eq(1).nonzero().squeeze()).cuda() + neg = Variable(label.data.eq(0).nonzero().squeeze()).cuda() + + loss_pos = get_cls_loss(pred, label, pos) + loss_neg = get_cls_loss(pred, label, neg) + return loss_pos * 0.5 + loss_neg * 0.5 + + +def weight_l1_loss(pred_loc, label_loc, loss_weight): + """ + :param pred_loc: [b, 4k, h, w] + :param label_loc: [b, 4k, h, w] + :param loss_weight: [b, k, h, w] + :return: loc loss value + """ + b, _, sh, sw = pred_loc.size() + pred_loc = pred_loc.view(b, 4, -1, sh, sw) + diff = (pred_loc - label_loc).abs() + diff = diff.sum(dim=1).view(b, -1, sh, sw) + loss = diff * loss_weight + return loss.sum().div(b) + + +def select_mask_logistic_loss(p_m, mask, weight, o_sz=63, g_sz=127): + weight = weight.view(-1) + pos = Variable(weight.data.eq(1).nonzero().squeeze()) + if pos.nelement() == 0: return p_m.sum() * 0, p_m.sum() * 0, p_m.sum() * 0, p_m.sum() * 0 + + p_m = p_m.permute(0, 2, 3, 1).contiguous().view(-1, 1, o_sz, o_sz) + p_m = torch.index_select(p_m, 0, pos) + p_m = nn.UpsamplingBilinear2d(size=[g_sz, g_sz])(p_m) + p_m = p_m.view(-1, g_sz * g_sz) + + mask_uf = F.unfold(mask, (g_sz, g_sz), padding=32, stride=8) + mask_uf = torch.transpose(mask_uf, 1, 2).contiguous().view(-1, g_sz * g_sz) + + mask_uf = torch.index_select(mask_uf, 0, pos) + loss = F.soft_margin_loss(p_m, mask_uf) + iou_m, iou_5, iou_7 = iou_measure(p_m, mask_uf) + return loss, iou_m, iou_5, iou_7 + + +def iou_measure(pred, label): + pred = pred.ge(0) + mask_sum = pred.eq(1).add(label.eq(1)) + intxn = torch.sum(mask_sum == 2, dim=1).float() + union = torch.sum(mask_sum > 0, dim=1).float() + iou = intxn/union + return torch.mean(iou), (torch.sum(iou > 0.5).float()/iou.shape[0]), (torch.sum(iou > 0.7).float()/iou.shape[0]) + + +if __name__ == "__main__": + p_m = torch.randn(4, 63*63, 25, 25) + cls = torch.randn(4, 1, 25, 25) > 0.9 + mask = torch.randn(4, 1, 255, 255) * 2 - 1 + + loss = select_mask_logistic_loss(p_m, mask, cls) + print(loss) diff --git a/SiamMask/models/siammask_sharp.py b/SiamMask/models/siammask_sharp.py new file mode 100644 index 0000000000000000000000000000000000000000..bccdf80730877c2fff94a8d7fcff7f3ea9317b81 --- /dev/null +++ b/SiamMask/models/siammask_sharp.py @@ -0,0 +1,196 @@ +# -------------------------------------------------------- +# SiamMask +# Licensed under The MIT License +# Written by Qiang Wang (wangqiang2015 at ia.ac.cn) +# -------------------------------------------------------- +import torch +import torch.nn as nn +import torch.nn.functional as F +from torch.autograd import Variable +from utils.anchors import Anchors + + +class SiamMask(nn.Module): + def __init__(self, anchors=None, o_sz=127, g_sz=127): + super(SiamMask, self).__init__() + self.anchors = anchors # anchor_cfg + self.anchor_num = len(self.anchors["ratios"]) * len(self.anchors["scales"]) + self.anchor = Anchors(anchors) + self.features = None + self.rpn_model = None + self.mask_model = None + self.o_sz = o_sz + self.g_sz = g_sz + self.upSample = nn.UpsamplingBilinear2d(size=[g_sz, g_sz]) + + self.all_anchors = None + + def set_all_anchors(self, image_center, size): + # cx,cy,w,h + if not self.anchor.generate_all_anchors(image_center, size): + return + all_anchors = self.anchor.all_anchors[1] # cx, cy, w, h + self.all_anchors = torch.from_numpy(all_anchors).float().cuda() + self.all_anchors = [self.all_anchors[i] for i in range(4)] + + def feature_extractor(self, x): + return self.features(x) + + def rpn(self, template, search): + pred_cls, pred_loc = self.rpn_model(template, search) + return pred_cls, pred_loc + + def mask(self, template, search): + pred_mask = self.mask_model(template, search) + return pred_mask + + def _add_rpn_loss(self, label_cls, label_loc, lable_loc_weight, label_mask, label_mask_weight, + rpn_pred_cls, rpn_pred_loc, rpn_pred_mask): + rpn_loss_cls = select_cross_entropy_loss(rpn_pred_cls, label_cls) + + rpn_loss_loc = weight_l1_loss(rpn_pred_loc, label_loc, lable_loc_weight) + + rpn_loss_mask, iou_m, iou_5, iou_7 = select_mask_logistic_loss(rpn_pred_mask, label_mask, label_mask_weight) + + return rpn_loss_cls, rpn_loss_loc, rpn_loss_mask, iou_m, iou_5, iou_7 + + def run(self, template, search, softmax=False): + """ + run network + """ + template_feature = self.feature_extractor(template) + feature, search_feature = self.features.forward_all(search) + rpn_pred_cls, rpn_pred_loc = self.rpn(template_feature, search_feature) + corr_feature = self.mask_model.mask.forward_corr(template_feature, search_feature) # (b, 256, w, h) + rpn_pred_mask = self.refine_model(feature, corr_feature) + + if softmax: + rpn_pred_cls = self.softmax(rpn_pred_cls) + return rpn_pred_cls, rpn_pred_loc, rpn_pred_mask, template_feature, search_feature + + def softmax(self, cls): + b, a2, h, w = cls.size() + cls = cls.view(b, 2, a2//2, h, w) + cls = cls.permute(0, 2, 3, 4, 1).contiguous() + cls = F.log_softmax(cls, dim=4) + return cls + + def forward(self, input): + """ + :param input: dict of input with keys of: + 'template': [b, 3, h1, w1], input template image. + 'search': [b, 3, h2, w2], input search image. + 'label_cls':[b, max_num_gts, 5] or None(self.training==False), + each gt contains x1,y1,x2,y2,class. + :return: dict of loss, predict, accuracy + """ + template = input['template'] + search = input['search'] + if self.training: + label_cls = input['label_cls'] + label_loc = input['label_loc'] + lable_loc_weight = input['label_loc_weight'] + label_mask = input['label_mask'] + label_mask_weight = input['label_mask_weight'] + + rpn_pred_cls, rpn_pred_loc, rpn_pred_mask, template_feature, search_feature = \ + self.run(template, search, softmax=self.training) + + outputs = dict() + + outputs['predict'] = [rpn_pred_loc, rpn_pred_cls, rpn_pred_mask, template_feature, search_feature] + + if self.training: + rpn_loss_cls, rpn_loss_loc, rpn_loss_mask, iou_acc_mean, iou_acc_5, iou_acc_7 = \ + self._add_rpn_loss(label_cls, label_loc, lable_loc_weight, label_mask, label_mask_weight, + rpn_pred_cls, rpn_pred_loc, rpn_pred_mask) + outputs['losses'] = [rpn_loss_cls, rpn_loss_loc, rpn_loss_mask] + outputs['accuracy'] = [iou_acc_mean, iou_acc_5, iou_acc_7] + + return outputs + + def template(self, z): + self.zf = self.feature_extractor(z) + cls_kernel, loc_kernel = self.rpn_model.template(self.zf) + return cls_kernel, loc_kernel + + def track(self, x, cls_kernel=None, loc_kernel=None, softmax=False): + xf = self.feature_extractor(x) + rpn_pred_cls, rpn_pred_loc = self.rpn_model.track(xf, cls_kernel, loc_kernel) + if softmax: + rpn_pred_cls = self.softmax(rpn_pred_cls) + return rpn_pred_cls, rpn_pred_loc + + +def get_cls_loss(pred, label, select): + if select.nelement() == 0: return pred.sum()*0. + pred = torch.index_select(pred, 0, select) + label = torch.index_select(label, 0, select) + + return F.nll_loss(pred, label) + + +def select_cross_entropy_loss(pred, label): + pred = pred.view(-1, 2) + label = label.view(-1) + pos = Variable(label.data.eq(1).nonzero().squeeze()).cuda() + neg = Variable(label.data.eq(0).nonzero().squeeze()).cuda() + + loss_pos = get_cls_loss(pred, label, pos) + loss_neg = get_cls_loss(pred, label, neg) + return loss_pos * 0.5 + loss_neg * 0.5 + + +def weight_l1_loss(pred_loc, label_loc, loss_weight): + """ + :param pred_loc: [b, 4k, h, w] + :param label_loc: [b, 4k, h, w] + :param loss_weight: [b, k, h, w] + :return: loc loss value + """ + b, _, sh, sw = pred_loc.size() + pred_loc = pred_loc.view(b, 4, -1, sh, sw) + diff = (pred_loc - label_loc).abs() + diff = diff.sum(dim=1).view(b, -1, sh, sw) + loss = diff * loss_weight + return loss.sum().div(b) + + +def select_mask_logistic_loss(p_m, mask, weight, o_sz=63, g_sz=127): + weight = weight.view(-1) + pos = Variable(weight.data.eq(1).nonzero().squeeze()) + if pos.nelement() == 0: return p_m.sum() * 0, p_m.sum() * 0, p_m.sum() * 0, p_m.sum() * 0 + + if len(p_m.shape) == 4: + p_m = p_m.permute(0, 2, 3, 1).contiguous().view(-1, 1, o_sz, o_sz) + p_m = torch.index_select(p_m, 0, pos) + p_m = nn.UpsamplingBilinear2d(size=[g_sz, g_sz])(p_m) + p_m = p_m.view(-1, g_sz * g_sz) + else: + p_m = torch.index_select(p_m, 0, pos) + + mask_uf = F.unfold(mask, (g_sz, g_sz), padding=0, stride=8) + mask_uf = torch.transpose(mask_uf, 1, 2).contiguous().view(-1, g_sz * g_sz) + + mask_uf = torch.index_select(mask_uf, 0, pos) + loss = F.soft_margin_loss(p_m, mask_uf) + iou_m, iou_5, iou_7 = iou_measure(p_m, mask_uf) + return loss, iou_m, iou_5, iou_7 + + +def iou_measure(pred, label): + pred = pred.ge(0) + mask_sum = pred.eq(1).add(label.eq(1)) + intxn = torch.sum(mask_sum == 2, dim=1).float() + union = torch.sum(mask_sum > 0, dim=1).float() + iou = intxn/union + return torch.mean(iou), (torch.sum(iou > 0.5).float()/iou.shape[0]), (torch.sum(iou > 0.7).float()/iou.shape[0]) + + +if __name__ == "__main__": + p_m = torch.randn(4, 63*63, 25, 25) + cls = torch.randn(4, 1, 25, 25) > 0.9 + mask = torch.randn(4, 1, 255, 255) * 2 - 1 + + loss = select_mask_logistic_loss(p_m, mask, cls) + print(loss) diff --git a/SiamMask/models/siamrpn.py b/SiamMask/models/siamrpn.py new file mode 100644 index 0000000000000000000000000000000000000000..827252bc0a2183157c906dbb4c18859161bfa212 --- /dev/null +++ b/SiamMask/models/siamrpn.py @@ -0,0 +1,144 @@ +# -------------------------------------------------------- +# SiamMask +# Licensed under The MIT License +# Written by Qiang Wang (wangqiang2015 at ia.ac.cn) +# -------------------------------------------------------- +import torch +import torch.nn as nn +import torch.nn.functional as F +from utils.bbox_helper import center2corner +from torch.autograd import Variable +from utils.anchors import Anchors + + +class SiamRPN(nn.Module): + def __init__(self, anchors=None): + super(SiamRPN, self).__init__() + self.anchors = anchors # anchor_cfg + self.anchor = Anchors(anchors) + self.anchor_num = self.anchor.anchor_num + self.features = None + self.rpn_model = None + + self.all_anchors = None + + def set_all_anchors(self, image_center, size): + # cx,cy,w,h + if not self.anchor.generate_all_anchors(image_center, size): + return + all_anchors = self.anchor.all_anchors[1] # cx, cy, w, h + self.all_anchors = torch.from_numpy(all_anchors).float().cuda() + self.all_anchors = [self.all_anchors[i] for i in range(4)] + + def feature_extractor(self, x): + return self.features(x) + + def rpn(self, template, search): + pred_cls, pred_loc = self.rpn_model(template, search) + return pred_cls, pred_loc + + def _add_rpn_loss(self, label_cls, label_loc, lable_loc_weight, rpn_pred_cls, + rpn_pred_loc): + ''' + :param compute_anchor_targets_fn: functions to produce anchors' learning targets. + :param rpn_pred_cls: [B, num_anchors * 2, h, w], output of rpn for classification. + :param rpn_pred_loc: [B, num_anchors * 4, h, w], output of rpn for localization. + :return: loss of classification and localization, respectively. + ''' + rpn_loss_cls = select_cross_entropy_loss(rpn_pred_cls, label_cls) + + rpn_loss_loc = weight_l1_loss(rpn_pred_loc, label_loc, lable_loc_weight) + + # classification accuracy, top1 + acc = torch.zeros(1) # TODO + return rpn_loss_cls, rpn_loss_loc, acc + + def run(self, template, search, softmax=False): + """ + run network + """ + template_feature = self.feature_extractor(template) + search_feature = self.feature_extractor(search) + rpn_pred_cls, rpn_pred_loc = self.rpn(template_feature, search_feature) + if softmax: + rpn_pred_cls = self.softmax(rpn_pred_cls) + return rpn_pred_cls, rpn_pred_loc, template_feature, search_feature + + def softmax(self, cls): + b, a2, h, w = cls.size() + cls = cls.view(b, 2, a2//2, h, w) + cls = cls.permute(0, 2, 3, 4, 1).contiguous() + cls = F.log_softmax(cls, dim=4) + return cls + + def forward(self, input): + """ + :param input: dict of input with keys of: + 'template': [b, 3, h1, w1], input template image. + 'search': [b, 3, h2, w2], input search image. + 'label_cls':[b, max_num_gts, 5] or None(self.training==False), + each gt contains x1,y1,x2,y2,class. + :return: dict of loss, predict, accuracy + """ + template = input['template'] + search = input['search'] + if self.training: + label_cls = input['label_cls'] + label_loc = input['label_loc'] + lable_loc_weight = input['label_loc_weight'] + + rpn_pred_cls, rpn_pred_loc, template_feature, search_feature = self.run(template, search, softmax=self.training) + + outputs = dict(predict=[], losses=[], accuracy=[]) + + outputs['predict'] = [rpn_pred_loc, rpn_pred_cls, template_feature, search_feature] + if self.training: + rpn_loss_cls, rpn_loss_loc, rpn_acc = self._add_rpn_loss(label_cls, label_loc, lable_loc_weight, + rpn_pred_cls, rpn_pred_loc) + outputs['losses'] = [rpn_loss_cls, rpn_loss_loc] + return outputs + + def template(self, z): + self.zf = self.feature_extractor(z) + cls_kernel, loc_kernel = self.rpn_model.template(self.zf) + return cls_kernel, loc_kernel + + def track(self, x, cls_kernel=None, loc_kernel=None, softmax=False): + xf = self.feature_extractor(x) + rpn_pred_cls, rpn_pred_loc = self.rpn_model.track(xf, cls_kernel, loc_kernel) + if softmax: + rpn_pred_cls = self.softmax(rpn_pred_cls) + return rpn_pred_cls, rpn_pred_loc + + +def get_cls_loss(pred, label, select): + if len(select.size()) == 0: return 0 + pred = torch.index_select(pred, 0, select) + label = torch.index_select(label, 0, select) + return F.nll_loss(pred, label) + + +def select_cross_entropy_loss(pred, label): + pred = pred.view(-1, 2) + label = label.view(-1) + pos = Variable(label.data.eq(1).nonzero().squeeze()).cuda() + neg = Variable(label.data.eq(0).nonzero().squeeze()).cuda() + + loss_pos = get_cls_loss(pred, label, pos) + loss_neg = get_cls_loss(pred, label, neg) + return loss_pos * 0.5 + loss_neg * 0.5 + + +def weight_l1_loss(pred_loc, label_loc, loss_weight): + """ + :param pred_loc: [b, 4k, h, w] + :param label_loc: [b, 4k, h, w] + :param loss_weight: [b, k, h, w] + :return: loc loss value + """ + b, _, sh, sw = pred_loc.size() + pred_loc = pred_loc.view(b, 4, -1, sh, sw) + diff = (pred_loc - label_loc).abs() + diff = diff.sum(dim=1).view(b, -1, sh, sw) + loss = diff * loss_weight + return loss.sum().div(b) diff --git a/SiamMask/tools/__init__.py b/SiamMask/tools/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SiamMask/tools/__pycache__/__init__.cpython-39.pyc b/SiamMask/tools/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ed3aa2db2bdd1af8d99efef8ca5c5c88f7356be6 Binary files /dev/null and b/SiamMask/tools/__pycache__/__init__.cpython-39.pyc differ diff --git a/SiamMask/tools/__pycache__/test.cpython-39.pyc b/SiamMask/tools/__pycache__/test.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2537e56a344b7c593735d84896071760882d930b Binary files /dev/null and b/SiamMask/tools/__pycache__/test.cpython-39.pyc differ diff --git a/SiamMask/tools/demo.py b/SiamMask/tools/demo.py new file mode 100644 index 0000000000000000000000000000000000000000..0e4cec4da48855786141cd9c10e31fe5b6b7f6ea --- /dev/null +++ b/SiamMask/tools/demo.py @@ -0,0 +1,69 @@ +# -------------------------------------------------------- +# SiamMask +# Licensed under The MIT License +# Written by Qiang Wang (wangqiang2015 at ia.ac.cn) +# -------------------------------------------------------- +import glob +from tools.test import * + +parser = argparse.ArgumentParser(description='PyTorch Tracking Demo') + +parser.add_argument('--resume', default='', type=str, required=True, + metavar='PATH',help='path to latest checkpoint (default: none)') +parser.add_argument('--config', dest='config', default='config_davis.json', + help='hyper-parameter of SiamMask in json format') +parser.add_argument('--base_path', default='../../data/tennis', help='datasets') +parser.add_argument('--cpu', action='store_true', help='cpu mode') +args = parser.parse_args() + +if __name__ == '__main__': + # Setup device + device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') + torch.backends.cudnn.benchmark = True + + # Setup Model + cfg = load_config(args) + from custom import Custom + siammask = Custom(anchors=cfg['anchors']) + if args.resume: + assert isfile(args.resume), 'Please download {} first.'.format(args.resume) + siammask = load_pretrain(siammask, args.resume) + + siammask.eval().to(device) + + # Parse Image file + img_files = sorted(glob.glob(join(args.base_path, '*.jp*'))) + ims = [cv2.imread(imf) for imf in img_files] + + # Select ROI + cv2.namedWindow("SiamMask", cv2.WND_PROP_FULLSCREEN) + # cv2.setWindowProperty("SiamMask", cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN) + try: + init_rect = cv2.selectROI('SiamMask', ims[0], False, False) + x, y, w, h = init_rect + except: + exit() + + toc = 0 + for f, im in enumerate(ims): + tic = cv2.getTickCount() + if f == 0: # init + target_pos = np.array([x + w / 2, y + h / 2]) + target_sz = np.array([w, h]) + state = siamese_init(im, target_pos, target_sz, siammask, cfg['hp'], device=device) # init tracker + elif f > 0: # tracking + state = siamese_track(state, im, mask_enable=True, refine_enable=True, device=device) # track + location = state['ploygon'].flatten() + mask = state['mask'] > state['p'].seg_thr + + im[:, :, 2] = (mask > 0) * 255 + (mask == 0) * im[:, :, 2] + cv2.polylines(im, [np.int0(location).reshape((-1, 1, 2))], True, (0, 255, 0), 3) + cv2.imshow('SiamMask', im) + key = cv2.waitKey(1) + if key > 0: + break + + toc += cv2.getTickCount() - tic + toc /= cv2.getTickFrequency() + fps = f / toc + print('SiamMask Time: {:02.1f}s Speed: {:3.1f}fps (with visulization!)'.format(toc, fps)) diff --git a/SiamMask/tools/eval.py b/SiamMask/tools/eval.py new file mode 100644 index 0000000000000000000000000000000000000000..c662d44e014e5ceef01cb26bb90bd8fd5cf4d374 --- /dev/null +++ b/SiamMask/tools/eval.py @@ -0,0 +1,51 @@ +# -------------------------------------------------------- +# Python Single Object Tracking Evaluation +# Licensed under The MIT License [see LICENSE for details] +# Written by Fangyi Zhang +# @author fangyi.zhang@vipl.ict.ac.cn +# @project https://github.com/StrangerZhang/pysot-toolkit.git +# Revised for SiamMask by foolwood +# -------------------------------------------------------- +import argparse +import glob +from os.path import join, realpath, dirname + +from tqdm import tqdm +from multiprocessing import Pool +from utils.pysot.datasets import VOTDataset +from utils.pysot.evaluation import AccuracyRobustnessBenchmark, EAOBenchmark + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='VOT Evaluation') + parser.add_argument('--dataset', type=str, help='dataset name') + parser.add_argument('--result_dir', type=str, help='tracker result root') + parser.add_argument('--tracker_prefix', type=str, help='tracker prefix') + parser.add_argument('--show_video_level', action='store_true') + parser.add_argument('--num', type=int, help='number of processes to eval', default=1) + args = parser.parse_args() + + root = join(realpath(dirname(__file__)), '../data') + tracker_dir = args.result_dir + trackers = glob.glob(join(tracker_dir, args.tracker_prefix+'*')) + trackers = [t.split('/')[-1] for t in trackers] + + assert len(trackers) > 0 + args.num = min(args.num, len(trackers)) + + if args.dataset in ['VOT2016', 'VOT2018', 'VOT2019']: + dataset = VOTDataset(args.dataset, root) + dataset.set_tracker(tracker_dir, trackers) + ar_benchmark = AccuracyRobustnessBenchmark(dataset) + ar_result = {} + with Pool(processes=args.num) as pool: + for ret in tqdm(pool.imap_unordered(ar_benchmark.eval, + trackers), desc='eval ar', total=len(trackers), ncols=100): + ar_result.update(ret) + + benchmark = EAOBenchmark(dataset) + eao_result = {} + with Pool(processes=args.num) as pool: + for ret in tqdm(pool.imap_unordered(benchmark.eval, + trackers), desc='eval eao', total=len(trackers), ncols=100): + eao_result.update(ret) + ar_benchmark.show_result(ar_result, eao_result, show_video_level=args.show_video_level) diff --git a/SiamMask/tools/test.py b/SiamMask/tools/test.py new file mode 100644 index 0000000000000000000000000000000000000000..073530e2837f8bc6e56ca0de308e511154118d1a --- /dev/null +++ b/SiamMask/tools/test.py @@ -0,0 +1,608 @@ +# -------------------------------------------------------- +# SiamMask +# Licensed under The MIT License +# Written by Qiang Wang (wangqiang2015 at ia.ac.cn) +# -------------------------------------------------------- +from __future__ import division +import argparse +import logging +import numpy as np +import cv2 +from PIL import Image +from os import makedirs +from os.path import join, isdir, isfile + +from utils.log_helper import init_log, add_file_handler +from utils.load_helper import load_pretrain +from utils.bbox_helper import get_axis_aligned_bbox, cxy_wh_2_rect +from utils.benchmark_helper import load_dataset, dataset_zoo + +import torch +from torch.autograd import Variable +import torch.nn.functional as F + +from utils.anchors import Anchors +from utils.tracker_config import TrackerConfig + +from utils.config_helper import load_config +from utils.pyvotkit.region import vot_overlap, vot_float2str + +thrs = np.arange(0.3, 0.5, 0.05) + +parser = argparse.ArgumentParser(description='Test SiamMask') +parser.add_argument('--arch', dest='arch', default='', choices=['Custom',], + help='architecture of pretrained model') +parser.add_argument('--config', dest='config', required=True, help='hyper-parameter for SiamMask') +parser.add_argument('--resume', default='', type=str, required=True, + metavar='PATH', help='path to latest checkpoint (default: none)') +parser.add_argument('--mask', action='store_true', help='whether use mask output') +parser.add_argument('--refine', action='store_true', help='whether use mask refine output') +parser.add_argument('--dataset', dest='dataset', default='VOT2018', choices=dataset_zoo, + help='datasets') +parser.add_argument('-l', '--log', default="log_test.txt", type=str, help='log file') +parser.add_argument('-v', '--visualization', dest='visualization', action='store_true', + help='whether visualize result') +parser.add_argument('--save_mask', action='store_true', help='whether use save mask for davis') +parser.add_argument('--gt', action='store_true', help='whether use gt rect for davis (Oracle)') +parser.add_argument('--video', default='', type=str, help='test special video') +parser.add_argument('--cpu', action='store_true', help='cpu mode') +parser.add_argument('--debug', action='store_true', help='debug mode') + + +def to_torch(ndarray): + if type(ndarray).__module__ == 'numpy': + return torch.from_numpy(ndarray) + elif not torch.is_tensor(ndarray): + raise ValueError("Cannot convert {} to torch tensor" + .format(type(ndarray))) + return ndarray + + +def im_to_torch(img): + img = np.transpose(img, (2, 0, 1)) # C*H*W + img = to_torch(img).float() + return img + + +def get_subwindow_tracking(im, pos, model_sz, original_sz, avg_chans, out_mode='torch'): + if isinstance(pos, float): + pos = [pos, pos] + sz = original_sz + im_sz = im.shape + c = (original_sz + 1) / 2 + context_xmin = round(pos[0] - c) + context_xmax = context_xmin + sz - 1 + context_ymin = round(pos[1] - c) + context_ymax = context_ymin + sz - 1 + left_pad = int(max(0., -context_xmin)) + top_pad = int(max(0., -context_ymin)) + right_pad = int(max(0., context_xmax - im_sz[1] + 1)) + bottom_pad = int(max(0., context_ymax - im_sz[0] + 1)) + + context_xmin = context_xmin + left_pad + context_xmax = context_xmax + left_pad + context_ymin = context_ymin + top_pad + context_ymax = context_ymax + top_pad + + # zzp: a more easy speed version + r, c, k = im.shape + if any([top_pad, bottom_pad, left_pad, right_pad]): + te_im = np.zeros((r + top_pad + bottom_pad, c + left_pad + right_pad, k), np.uint8) + te_im[top_pad:top_pad + r, left_pad:left_pad + c, :] = im + if top_pad: + te_im[0:top_pad, left_pad:left_pad + c, :] = avg_chans + if bottom_pad: + te_im[r + top_pad:, left_pad:left_pad + c, :] = avg_chans + if left_pad: + te_im[:, 0:left_pad, :] = avg_chans + if right_pad: + te_im[:, c + left_pad:, :] = avg_chans + im_patch_original = te_im[int(context_ymin):int(context_ymax + 1), int(context_xmin):int(context_xmax + 1), :] + else: + im_patch_original = im[int(context_ymin):int(context_ymax + 1), int(context_xmin):int(context_xmax + 1), :] + + if not np.array_equal(model_sz, original_sz): + im_patch = cv2.resize(im_patch_original, (model_sz, model_sz)) + else: + im_patch = im_patch_original + # cv2.imshow('crop', im_patch) + # cv2.waitKey(0) + return im_to_torch(im_patch) if out_mode in 'torch' else im_patch + + +def generate_anchor(cfg, score_size): + anchors = Anchors(cfg) + anchor = anchors.anchors + x1, y1, x2, y2 = anchor[:, 0], anchor[:, 1], anchor[:, 2], anchor[:, 3] + anchor = np.stack([(x1+x2)*0.5, (y1+y2)*0.5, x2-x1, y2-y1], 1) + + total_stride = anchors.stride + anchor_num = anchor.shape[0] + + anchor = np.tile(anchor, score_size * score_size).reshape((-1, 4)) + ori = - (score_size // 2) * total_stride + xx, yy = np.meshgrid([ori + total_stride * dx for dx in range(score_size)], + [ori + total_stride * dy for dy in range(score_size)]) + xx, yy = np.tile(xx.flatten(), (anchor_num, 1)).flatten(), \ + np.tile(yy.flatten(), (anchor_num, 1)).flatten() + anchor[:, 0], anchor[:, 1] = xx.astype(np.float32), yy.astype(np.float32) + return anchor + + +def siamese_init(im, target_pos, target_sz, model, hp=None, device='cpu'): + state = dict() + state['im_h'] = im.shape[0] + state['im_w'] = im.shape[1] + p = TrackerConfig() + p.update(hp, model.anchors) + + p.renew() + + net = model + p.scales = model.anchors['scales'] + p.ratios = model.anchors['ratios'] + p.anchor_num = model.anchor_num + p.anchor = generate_anchor(model.anchors, p.score_size) + avg_chans = np.mean(im, axis=(0, 1)) + + wc_z = target_sz[0] + p.context_amount * sum(target_sz) + hc_z = target_sz[1] + p.context_amount * sum(target_sz) + s_z = round(np.sqrt(wc_z * hc_z)) + # initialize the exemplar + z_crop = get_subwindow_tracking(im, target_pos, p.exemplar_size, s_z, avg_chans) + + z = Variable(z_crop.unsqueeze(0)) + net.template(z.to(device)) + + if p.windowing == 'cosine': + window = np.outer(np.hanning(p.score_size), np.hanning(p.score_size)) + elif p.windowing == 'uniform': + window = np.ones((p.score_size, p.score_size)) + window = np.tile(window.flatten(), p.anchor_num) + + state['p'] = p + state['net'] = net + state['avg_chans'] = avg_chans + state['window'] = window + state['target_pos'] = target_pos + state['target_sz'] = target_sz + return state + + +def siamese_track(state, im, mask_enable=False, refine_enable=False, device='cpu', debug=False): + p = state['p'] + net = state['net'] + avg_chans = state['avg_chans'] + window = state['window'] + target_pos = state['target_pos'] + target_sz = state['target_sz'] + + wc_x = target_sz[1] + p.context_amount * sum(target_sz) + hc_x = target_sz[0] + p.context_amount * sum(target_sz) + s_x = np.sqrt(wc_x * hc_x) + scale_x = p.exemplar_size / s_x + d_search = (p.instance_size - p.exemplar_size) / 2 + pad = d_search / scale_x + s_x = s_x + 2 * pad + crop_box = [target_pos[0] - round(s_x) / 2, target_pos[1] - round(s_x) / 2, round(s_x), round(s_x)] + + if debug: + im_debug = im.copy() + crop_box_int = np.int0(crop_box) + cv2.rectangle(im_debug, (crop_box_int[0], crop_box_int[1]), + (crop_box_int[0] + crop_box_int[2], crop_box_int[1] + crop_box_int[3]), (255, 0, 0), 2) + cv2.imshow('search area', im_debug) + cv2.waitKey(0) + + # extract scaled crops for search region x at previous target position + x_crop = Variable(get_subwindow_tracking(im, target_pos, p.instance_size, round(s_x), avg_chans).unsqueeze(0)) + + if mask_enable: + score, delta, mask = net.track_mask(x_crop.to(device)) + else: + score, delta = net.track(x_crop.to(device)) + + delta = delta.permute(1, 2, 3, 0).contiguous().view(4, -1).data.cpu().numpy() + score = F.softmax(score.permute(1, 2, 3, 0).contiguous().view(2, -1).permute(1, 0), dim=1).data[:, + 1].cpu().numpy() + + delta[0, :] = delta[0, :] * p.anchor[:, 2] + p.anchor[:, 0] + delta[1, :] = delta[1, :] * p.anchor[:, 3] + p.anchor[:, 1] + delta[2, :] = np.exp(delta[2, :]) * p.anchor[:, 2] + delta[3, :] = np.exp(delta[3, :]) * p.anchor[:, 3] + + def change(r): + return np.maximum(r, 1. / r) + + def sz(w, h): + pad = (w + h) * 0.5 + sz2 = (w + pad) * (h + pad) + return np.sqrt(sz2) + + def sz_wh(wh): + pad = (wh[0] + wh[1]) * 0.5 + sz2 = (wh[0] + pad) * (wh[1] + pad) + return np.sqrt(sz2) + + # size penalty + target_sz_in_crop = target_sz*scale_x + s_c = change(sz(delta[2, :], delta[3, :]) / (sz_wh(target_sz_in_crop))) # scale penalty + r_c = change((target_sz_in_crop[0] / target_sz_in_crop[1]) / (delta[2, :] / delta[3, :])) # ratio penalty + + penalty = np.exp(-(r_c * s_c - 1) * p.penalty_k) + pscore = penalty * score + + # cos window (motion model) + pscore = pscore * (1 - p.window_influence) + window * p.window_influence + best_pscore_id = np.argmax(pscore) + + pred_in_crop = delta[:, best_pscore_id] / scale_x + lr = penalty[best_pscore_id] * score[best_pscore_id] * p.lr # lr for OTB + + res_x = pred_in_crop[0] + target_pos[0] + res_y = pred_in_crop[1] + target_pos[1] + + res_w = target_sz[0] * (1 - lr) + pred_in_crop[2] * lr + res_h = target_sz[1] * (1 - lr) + pred_in_crop[3] * lr + + target_pos = np.array([res_x, res_y]) + target_sz = np.array([res_w, res_h]) + + # for Mask Branch + if mask_enable: + best_pscore_id_mask = np.unravel_index(best_pscore_id, (5, p.score_size, p.score_size)) + delta_x, delta_y = best_pscore_id_mask[2], best_pscore_id_mask[1] + + if refine_enable: + mask = net.track_refine((delta_y, delta_x)).to(device).sigmoid().squeeze().view( + p.out_size, p.out_size).cpu().data.numpy() + else: + mask = mask[0, :, delta_y, delta_x].sigmoid(). \ + squeeze().view(p.out_size, p.out_size).cpu().data.numpy() + + def crop_back(image, bbox, out_sz, padding=-1): + a = (out_sz[0] - 1) / bbox[2] + b = (out_sz[1] - 1) / bbox[3] + c = -a * bbox[0] + d = -b * bbox[1] + mapping = np.array([[a, 0, c], + [0, b, d]]).astype(np.float) + crop = cv2.warpAffine(image, mapping, (out_sz[0], out_sz[1]), + flags=cv2.INTER_LINEAR, + borderMode=cv2.BORDER_CONSTANT, + borderValue=padding) + return crop + + s = crop_box[2] / p.instance_size + sub_box = [crop_box[0] + (delta_x - p.base_size / 2) * p.total_stride * s, + crop_box[1] + (delta_y - p.base_size / 2) * p.total_stride * s, + s * p.exemplar_size, s * p.exemplar_size] + s = p.out_size / sub_box[2] + back_box = [-sub_box[0] * s, -sub_box[1] * s, state['im_w'] * s, state['im_h'] * s] + mask_in_img = crop_back(mask, back_box, (state['im_w'], state['im_h'])) + + target_mask = (mask_in_img > p.seg_thr).astype(np.uint8) + if cv2.__version__[-5] == '4': + contours, _ = cv2.findContours(target_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) + else: + _, contours, _ = cv2.findContours(target_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) + cnt_area = [cv2.contourArea(cnt) for cnt in contours] + if len(contours) != 0 and np.max(cnt_area) > 100: + contour = contours[np.argmax(cnt_area)] # use max area polygon + polygon = contour.reshape(-1, 2) + # pbox = cv2.boundingRect(polygon) # Min Max Rectangle + prbox = cv2.boxPoints(cv2.minAreaRect(polygon)) # Rotated Rectangle + + # box_in_img = pbox + rbox_in_img = prbox + else: # empty mask + location = cxy_wh_2_rect(target_pos, target_sz) + rbox_in_img = np.array([[location[0], location[1]], + [location[0] + location[2], location[1]], + [location[0] + location[2], location[1] + location[3]], + [location[0], location[1] + location[3]]]) + + target_pos[0] = max(0, min(state['im_w'], target_pos[0])) + target_pos[1] = max(0, min(state['im_h'], target_pos[1])) + target_sz[0] = max(10, min(state['im_w'], target_sz[0])) + target_sz[1] = max(10, min(state['im_h'], target_sz[1])) + + state['target_pos'] = target_pos + state['target_sz'] = target_sz + state['score'] = score[best_pscore_id] + state['mask'] = mask_in_img if mask_enable else [] + state['ploygon'] = rbox_in_img if mask_enable else [] + return state + + +def track_vot(model, video, hp=None, mask_enable=False, refine_enable=False, device='cpu'): + regions = [] # result and states[1 init / 2 lost / 0 skip] + image_files, gt = video['image_files'], video['gt'] + + start_frame, end_frame, lost_times, toc = 0, len(image_files), 0, 0 + + for f, image_file in enumerate(image_files): + im = cv2.imread(image_file) + tic = cv2.getTickCount() + if f == start_frame: # init + cx, cy, w, h = get_axis_aligned_bbox(gt[f]) + target_pos = np.array([cx, cy]) + target_sz = np.array([w, h]) + state = siamese_init(im, target_pos, target_sz, model, hp, device) # init tracker + location = cxy_wh_2_rect(state['target_pos'], state['target_sz']) + regions.append(1 if 'VOT' in args.dataset else gt[f]) + elif f > start_frame: # tracking + state = siamese_track(state, im, mask_enable, refine_enable, device, args.debug) # track + if mask_enable: + location = state['ploygon'].flatten() + mask = state['mask'] + else: + location = cxy_wh_2_rect(state['target_pos'], state['target_sz']) + mask = [] + + if 'VOT' in args.dataset: + gt_polygon = ((gt[f][0], gt[f][1]), (gt[f][2], gt[f][3]), + (gt[f][4], gt[f][5]), (gt[f][6], gt[f][7])) + if mask_enable: + pred_polygon = ((location[0], location[1]), (location[2], location[3]), + (location[4], location[5]), (location[6], location[7])) + else: + pred_polygon = ((location[0], location[1]), + (location[0] + location[2], location[1]), + (location[0] + location[2], location[1] + location[3]), + (location[0], location[1] + location[3])) + b_overlap = vot_overlap(gt_polygon, pred_polygon, (im.shape[1], im.shape[0])) + else: + b_overlap = 1 + + if b_overlap: + regions.append(location) + else: # lost + regions.append(2) + lost_times += 1 + start_frame = f + 5 # skip 5 frames + else: # skip + regions.append(0) + toc += cv2.getTickCount() - tic + + if args.visualization and f >= start_frame: # visualization (skip lost frame) + im_show = im.copy() + if f == 0: cv2.destroyAllWindows() + if gt.shape[0] > f: + if len(gt[f]) == 8: + cv2.polylines(im_show, [np.array(gt[f], np.int).reshape((-1, 1, 2))], True, (0, 255, 0), 3) + else: + cv2.rectangle(im_show, (gt[f, 0], gt[f, 1]), (gt[f, 0] + gt[f, 2], gt[f, 1] + gt[f, 3]), (0, 255, 0), 3) + if len(location) == 8: + if mask_enable: + mask = mask > state['p'].seg_thr + im_show[:, :, 2] = mask * 255 + (1 - mask) * im_show[:, :, 2] + location_int = np.int0(location) + cv2.polylines(im_show, [location_int.reshape((-1, 1, 2))], True, (0, 255, 255), 3) + else: + location = [int(l) for l in location] + cv2.rectangle(im_show, (location[0], location[1]), + (location[0] + location[2], location[1] + location[3]), (0, 255, 255), 3) + cv2.putText(im_show, str(f), (40, 40), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 255), 2) + cv2.putText(im_show, str(lost_times), (40, 80), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2) + cv2.putText(im_show, str(state['score']) if 'score' in state else '', (40, 120), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2) + + cv2.imshow(video['name'], im_show) + cv2.waitKey(1) + toc /= cv2.getTickFrequency() + + # save result + name = args.arch.split('.')[0] + '_' + ('mask_' if mask_enable else '') + ('refine_' if refine_enable else '') +\ + args.resume.split('/')[-1].split('.')[0] + + if 'VOT' in args.dataset: + video_path = join('test', args.dataset, name, + 'baseline', video['name']) + if not isdir(video_path): makedirs(video_path) + result_path = join(video_path, '{:s}_001.txt'.format(video['name'])) + with open(result_path, "w") as fin: + for x in regions: + fin.write("{:d}\n".format(x)) if isinstance(x, int) else \ + fin.write(','.join([vot_float2str("%.4f", i) for i in x]) + '\n') + else: # OTB + video_path = join('test', args.dataset, name) + if not isdir(video_path): makedirs(video_path) + result_path = join(video_path, '{:s}.txt'.format(video['name'])) + with open(result_path, "w") as fin: + for x in regions: + fin.write(','.join([str(i) for i in x])+'\n') + + logger.info('({:d}) Video: {:12s} Time: {:02.1f}s Speed: {:3.1f}fps Lost: {:d}'.format( + v_id, video['name'], toc, f / toc, lost_times)) + + return lost_times, f / toc + + +def MultiBatchIouMeter(thrs, outputs, targets, start=None, end=None): + targets = np.array(targets) + outputs = np.array(outputs) + + num_frame = targets.shape[0] + if start is None: + object_ids = np.array(list(range(outputs.shape[0]))) + 1 + else: + object_ids = [int(id) for id in start] + + num_object = len(object_ids) + res = np.zeros((num_object, len(thrs)), dtype=np.float32) + + output_max_id = np.argmax(outputs, axis=0).astype('uint8')+1 + outputs_max = np.max(outputs, axis=0) + for k, thr in enumerate(thrs): + output_thr = outputs_max > thr + for j in range(num_object): + target_j = targets == object_ids[j] + + if start is None: + start_frame, end_frame = 1, num_frame - 1 + else: + start_frame, end_frame = start[str(object_ids[j])] + 1, end[str(object_ids[j])] - 1 + iou = [] + for i in range(start_frame, end_frame): + pred = (output_thr[i] * output_max_id[i]) == (j+1) + mask_sum = (pred == 1).astype(np.uint8) + (target_j[i] > 0).astype(np.uint8) + intxn = np.sum(mask_sum == 2) + union = np.sum(mask_sum > 0) + if union > 0: + iou.append(intxn / union) + elif union == 0 and intxn == 0: + iou.append(1) + res[j, k] = np.mean(iou) + return res + + +def track_vos(model, video, hp=None, mask_enable=False, refine_enable=False, mot_enable=False, device='cpu'): + image_files = video['image_files'] + + annos = [np.array(Image.open(x)) for x in video['anno_files']] + if 'anno_init_files' in video: + annos_init = [np.array(Image.open(x)) for x in video['anno_init_files']] + else: + annos_init = [annos[0]] + + if not mot_enable: + annos = [(anno > 0).astype(np.uint8) for anno in annos] + annos_init = [(anno_init > 0).astype(np.uint8) for anno_init in annos_init] + + if 'start_frame' in video: + object_ids = [int(id) for id in video['start_frame']] + else: + object_ids = [o_id for o_id in np.unique(annos[0]) if o_id != 0] + if len(object_ids) != len(annos_init): + annos_init = annos_init*len(object_ids) + object_num = len(object_ids) + toc = 0 + pred_masks = np.zeros((object_num, len(image_files), annos[0].shape[0], annos[0].shape[1]))-1 + for obj_id, o_id in enumerate(object_ids): + + if 'start_frame' in video: + start_frame = video['start_frame'][str(o_id)] + end_frame = video['end_frame'][str(o_id)] + else: + start_frame, end_frame = 0, len(image_files) + + for f, image_file in enumerate(image_files): + im = cv2.imread(image_file) + tic = cv2.getTickCount() + if f == start_frame: # init + mask = annos_init[obj_id] == o_id + x, y, w, h = cv2.boundingRect((mask).astype(np.uint8)) + cx, cy = x + w/2, y + h/2 + target_pos = np.array([cx, cy]) + target_sz = np.array([w, h]) + state = siamese_init(im, target_pos, target_sz, model, hp, device=device) # init tracker + elif end_frame >= f > start_frame: # tracking + state = siamese_track(state, im, mask_enable, refine_enable, device=device) # track + mask = state['mask'] + toc += cv2.getTickCount() - tic + if end_frame >= f >= start_frame: + pred_masks[obj_id, f, :, :] = mask + toc /= cv2.getTickFrequency() + + if len(annos) == len(image_files): + multi_mean_iou = MultiBatchIouMeter(thrs, pred_masks, annos, + start=video['start_frame'] if 'start_frame' in video else None, + end=video['end_frame'] if 'end_frame' in video else None) + for i in range(object_num): + for j, thr in enumerate(thrs): + logger.info('Fusion Multi Object{:20s} IOU at {:.2f}: {:.4f}'.format(video['name'] + '_' + str(i + 1), thr, + multi_mean_iou[i, j])) + else: + multi_mean_iou = [] + + if args.save_mask: + video_path = join('test', args.dataset, 'SiamMask', video['name']) + if not isdir(video_path): makedirs(video_path) + pred_mask_final = np.array(pred_masks) + pred_mask_final = (np.argmax(pred_mask_final, axis=0).astype('uint8') + 1) * ( + np.max(pred_mask_final, axis=0) > state['p'].seg_thr).astype('uint8') + for i in range(pred_mask_final.shape[0]): + cv2.imwrite(join(video_path, image_files[i].split('/')[-1].split('.')[0] + '.png'), pred_mask_final[i].astype(np.uint8)) + + if args.visualization: + pred_mask_final = np.array(pred_masks) + pred_mask_final = (np.argmax(pred_mask_final, axis=0).astype('uint8') + 1) * ( + np.max(pred_mask_final, axis=0) > state['p'].seg_thr).astype('uint8') + COLORS = np.random.randint(128, 255, size=(object_num, 3), dtype="uint8") + COLORS = np.vstack([[0, 0, 0], COLORS]).astype("uint8") + mask = COLORS[pred_mask_final] + for f, image_file in enumerate(image_files): + output = ((0.4 * cv2.imread(image_file)) + (0.6 * mask[f,:,:,:])).astype("uint8") + cv2.imshow("mask", output) + cv2.waitKey(1) + + logger.info('({:d}) Video: {:12s} Time: {:02.1f}s Speed: {:3.1f}fps'.format( + v_id, video['name'], toc, f*len(object_ids) / toc)) + + return multi_mean_iou, f*len(object_ids) / toc + + +def main(): + global args, logger, v_id + args = parser.parse_args() + cfg = load_config(args) + + init_log('global', logging.INFO) + if args.log != "": + add_file_handler('global', args.log, logging.INFO) + + logger = logging.getLogger('global') + logger.info(args) + + # setup model + if args.arch == 'Custom': + from custom import Custom + model = Custom(anchors=cfg['anchors']) + else: + parser.error('invalid architecture: {}'.format(args.arch)) + + if args.resume: + assert isfile(args.resume), '{} is not a valid file'.format(args.resume) + model = load_pretrain(model, args.resume) + model.eval() + device = torch.device('cuda' if (torch.cuda.is_available() and not args.cpu) else 'cpu') + model = model.to(device) + # setup dataset + dataset = load_dataset(args.dataset) + + # VOS or VOT? + if args.dataset in ['DAVIS2016', 'DAVIS2017', 'ytb_vos'] and args.mask: + vos_enable = True # enable Mask output + else: + vos_enable = False + + total_lost = 0 # VOT + iou_lists = [] # VOS + speed_list = [] + + for v_id, video in enumerate(dataset.keys(), start=1): + if args.video != '' and video != args.video: + continue + + if vos_enable: + iou_list, speed = track_vos(model, dataset[video], cfg['hp'] if 'hp' in cfg.keys() else None, + args.mask, args.refine, args.dataset in ['DAVIS2017', 'ytb_vos'], device=device) + iou_lists.append(iou_list) + else: + lost, speed = track_vot(model, dataset[video], cfg['hp'] if 'hp' in cfg.keys() else None, + args.mask, args.refine, device=device) + total_lost += lost + speed_list.append(speed) + + # report final result + if vos_enable: + for thr, iou in zip(thrs, np.mean(np.concatenate(iou_lists), axis=0)): + logger.info('Segmentation Threshold {:.2f} mIoU: {:.3f}'.format(thr, iou)) + else: + logger.info('Total Lost: {:d}'.format(total_lost)) + + logger.info('Mean Speed: {:.2f} FPS'.format(np.mean(speed_list))) + + +if __name__ == '__main__': + main() diff --git a/SiamMask/tools/train_siammask.py b/SiamMask/tools/train_siammask.py new file mode 100644 index 0000000000000000000000000000000000000000..19f215a73d86115e87689f887f3f1096da1f687d --- /dev/null +++ b/SiamMask/tools/train_siammask.py @@ -0,0 +1,292 @@ +# -------------------------------------------------------- +# SiamMask +# Licensed under The MIT License +# Written by Qiang Wang (wangqiang2015 at ia.ac.cn) +# -------------------------------------------------------- +import argparse +import logging +import os +import cv2 +import shutil +import time +import json +import math +import torch +from torch.utils.data import DataLoader + +from utils.log_helper import init_log, print_speed, add_file_handler, Dummy +from utils.load_helper import load_pretrain, restore_from +from utils.average_meter_helper import AverageMeter + +from datasets.siam_mask_dataset import DataSets + +from utils.lr_helper import build_lr_scheduler +from tensorboardX import SummaryWriter + +from utils.config_helper import load_config +from torch.utils.collect_env import get_pretty_env_info + +torch.backends.cudnn.benchmark = True + +parser = argparse.ArgumentParser(description='PyTorch Tracking SiamMask Training') + +parser.add_argument('-j', '--workers', default=16, type=int, metavar='N', + help='number of data loading workers (default: 16)') +parser.add_argument('--epochs', default=50, type=int, metavar='N', + help='number of total epochs to run') +parser.add_argument('--start-epoch', default=0, type=int, metavar='N', + help='manual epoch number (useful on restarts)') +parser.add_argument('-b', '--batch', default=64, type=int, + metavar='N', help='mini-batch size (default: 64)') +parser.add_argument('--lr', '--learning-rate', default=0.001, type=float, + metavar='LR', help='initial learning rate') +parser.add_argument('--momentum', default=0.9, type=float, metavar='M', + help='momentum') +parser.add_argument('--weight-decay', '--wd', default=1e-4, type=float, + metavar='W', help='weight decay (default: 1e-4)') +parser.add_argument('--clip', default=10.0, type=float, + help='gradient clip value') +parser.add_argument('--print-freq', '-p', default=10, type=int, + metavar='N', help='print frequency (default: 10)') +parser.add_argument('--resume', default='', type=str, metavar='PATH', + help='path to latest checkpoint (default: none)') +parser.add_argument('--pretrained', dest='pretrained', default='', + help='use pre-trained model') +parser.add_argument('--config', dest='config', required=True, + help='hyperparameter of SiamMask in json format') +parser.add_argument('--arch', dest='arch', default='', choices=['Custom',], + help='architecture of pretrained model') +parser.add_argument('-l', '--log', default="log.txt", type=str, + help='log file') +parser.add_argument('-s', '--save_dir', default='snapshot', type=str, + help='save dir') +parser.add_argument('--log-dir', default='board', help='TensorBoard log dir') + + +best_acc = 0. + + +def collect_env_info(): + env_str = get_pretty_env_info() + env_str += "\n OpenCV ({})".format(cv2.__version__) + return env_str + + +def build_data_loader(cfg): + logger = logging.getLogger('global') + + logger.info("build train dataset") # train_dataset + train_set = DataSets(cfg['train_datasets'], cfg['anchors'], args.epochs) + train_set.shuffle() + + logger.info("build val dataset") # val_dataset + if not 'val_datasets' in cfg.keys(): + cfg['val_datasets'] = cfg['train_datasets'] + val_set = DataSets(cfg['val_datasets'], cfg['anchors']) + val_set.shuffle() + + train_loader = DataLoader(train_set, batch_size=args.batch, num_workers=args.workers, + pin_memory=True, sampler=None) + val_loader = DataLoader(val_set, batch_size=args.batch, num_workers=args.workers, + pin_memory=True, sampler=None) + + logger.info('build dataset done') + return train_loader, val_loader + + +def build_opt_lr(model, cfg, args, epoch): + backbone_feature = model.features.param_groups(cfg['lr']['start_lr'], cfg['lr']['feature_lr_mult']) + if len(backbone_feature) == 0: + trainable_params = model.rpn_model.param_groups(cfg['lr']['start_lr'], cfg['lr']['rpn_lr_mult'], 'mask') + else: + trainable_params = backbone_feature + \ + model.rpn_model.param_groups(cfg['lr']['start_lr'], cfg['lr']['rpn_lr_mult']) + \ + model.mask_model.param_groups(cfg['lr']['start_lr'], cfg['lr']['mask_lr_mult']) + + optimizer = torch.optim.SGD(trainable_params, args.lr, + momentum=args.momentum, + weight_decay=args.weight_decay) + + lr_scheduler = build_lr_scheduler(optimizer, cfg['lr'], epochs=args.epochs) + + lr_scheduler.step(epoch) + + return optimizer, lr_scheduler + + +def main(): + global args, best_acc, tb_writer, logger + args = parser.parse_args() + + init_log('global', logging.INFO) + + if args.log != "": + add_file_handler('global', args.log, logging.INFO) + + logger = logging.getLogger('global') + logger.info("\n" + collect_env_info()) + logger.info(args) + + cfg = load_config(args) + logger.info("config \n{}".format(json.dumps(cfg, indent=4))) + + if args.log_dir: + tb_writer = SummaryWriter(args.log_dir) + else: + tb_writer = Dummy() + + # build dataset + train_loader, val_loader = build_data_loader(cfg) + + if args.arch == 'Custom': + from custom import Custom + model = Custom(pretrain=True, anchors=cfg['anchors']) + else: + exit() + logger.info(model) + + if args.pretrained: + model = load_pretrain(model, args.pretrained) + + model = model.cuda() + dist_model = torch.nn.DataParallel(model, list(range(torch.cuda.device_count()))).cuda() + + if args.resume and args.start_epoch != 0: + model.features.unfix((args.start_epoch - 1) / args.epochs) + + optimizer, lr_scheduler = build_opt_lr(model, cfg, args, args.start_epoch) + # optionally resume from a checkpoint + if args.resume: + assert os.path.isfile(args.resume), '{} is not a valid file'.format(args.resume) + model, optimizer, args.start_epoch, best_acc, arch = restore_from(model, optimizer, args.resume) + dist_model = torch.nn.DataParallel(model, list(range(torch.cuda.device_count()))).cuda() + + logger.info(lr_scheduler) + + logger.info('model prepare done') + + train(train_loader, dist_model, optimizer, lr_scheduler, args.start_epoch, cfg) + + +def train(train_loader, model, optimizer, lr_scheduler, epoch, cfg): + global tb_index, best_acc, cur_lr, logger + cur_lr = lr_scheduler.get_cur_lr() + logger = logging.getLogger('global') + avg = AverageMeter() + model.train() + model = model.cuda() + end = time.time() + + def is_valid_number(x): + return not(math.isnan(x) or math.isinf(x) or x > 1e4) + + num_per_epoch = len(train_loader.dataset) // args.epochs // args.batch + start_epoch = epoch + epoch = epoch + for iter, input in enumerate(train_loader): + + if epoch != iter // num_per_epoch + start_epoch: # next epoch + epoch = iter // num_per_epoch + start_epoch + + if not os.path.exists(args.save_dir): # makedir/save model + os.makedirs(args.save_dir) + + save_checkpoint({ + 'epoch': epoch, + 'arch': args.arch, + 'state_dict': model.module.state_dict(), + 'best_acc': best_acc, + 'optimizer': optimizer.state_dict(), + 'anchor_cfg': cfg['anchors'] + }, False, + os.path.join(args.save_dir, 'checkpoint_e%d.pth' % (epoch)), + os.path.join(args.save_dir, 'best.pth')) + + if epoch == args.epochs: + return + + if model.module.features.unfix(epoch/args.epochs): + logger.info('unfix part model.') + optimizer, lr_scheduler = build_opt_lr(model.module, cfg, args, epoch) + + lr_scheduler.step(epoch) + cur_lr = lr_scheduler.get_cur_lr() + + logger.info('epoch:{}'.format(epoch)) + + tb_index = iter + if iter % num_per_epoch == 0 and iter != 0: + for idx, pg in enumerate(optimizer.param_groups): + logger.info("epoch {} lr {}".format(epoch, pg['lr'])) + tb_writer.add_scalar('lr/group%d' % (idx+1), pg['lr'], tb_index) + + data_time = time.time() - end + avg.update(data_time=data_time) + x = { + 'cfg': cfg, + 'template': torch.autograd.Variable(input[0]).cuda(), + 'search': torch.autograd.Variable(input[1]).cuda(), + 'label_cls': torch.autograd.Variable(input[2]).cuda(), + 'label_loc': torch.autograd.Variable(input[3]).cuda(), + 'label_loc_weight': torch.autograd.Variable(input[4]).cuda(), + 'label_mask': torch.autograd.Variable(input[6]).cuda(), + 'label_mask_weight': torch.autograd.Variable(input[7]).cuda(), + } + + outputs = model(x) + + rpn_cls_loss, rpn_loc_loss, rpn_mask_loss = torch.mean(outputs['losses'][0]), torch.mean(outputs['losses'][1]), torch.mean(outputs['losses'][2]) + mask_iou_mean, mask_iou_at_5, mask_iou_at_7 = torch.mean(outputs['accuracy'][0]), torch.mean(outputs['accuracy'][1]), torch.mean(outputs['accuracy'][2]) + + cls_weight, reg_weight, mask_weight = cfg['loss']['weight'] + + loss = rpn_cls_loss * cls_weight + rpn_loc_loss * reg_weight + rpn_mask_loss * mask_weight + + optimizer.zero_grad() + loss.backward() + + if cfg['clip']['split']: + torch.nn.utils.clip_grad_norm_(model.module.features.parameters(), cfg['clip']['feature']) + torch.nn.utils.clip_grad_norm_(model.module.rpn_model.parameters(), cfg['clip']['rpn']) + torch.nn.utils.clip_grad_norm_(model.module.mask_model.parameters(), cfg['clip']['mask']) + else: + torch.nn.utils.clip_grad_norm_(model.parameters(), args.clip) # gradient clip + + if is_valid_number(loss.item()): + optimizer.step() + + siammask_loss = loss.item() + + batch_time = time.time() - end + + avg.update(batch_time=batch_time, rpn_cls_loss=rpn_cls_loss, rpn_loc_loss=rpn_loc_loss, + rpn_mask_loss=rpn_mask_loss, siammask_loss=siammask_loss, + mask_iou_mean=mask_iou_mean, mask_iou_at_5=mask_iou_at_5, mask_iou_at_7=mask_iou_at_7) + + tb_writer.add_scalar('loss/cls', rpn_cls_loss, tb_index) + tb_writer.add_scalar('loss/loc', rpn_loc_loss, tb_index) + tb_writer.add_scalar('loss/mask', rpn_mask_loss, tb_index) + tb_writer.add_scalar('mask/mIoU', mask_iou_mean, tb_index) + tb_writer.add_scalar('mask/AP@.5', mask_iou_at_5, tb_index) + tb_writer.add_scalar('mask/AP@.7', mask_iou_at_7, tb_index) + end = time.time() + + if (iter + 1) % args.print_freq == 0: + logger.info('Epoch: [{0}][{1}/{2}] lr: {lr:.6f}\t{batch_time:s}\t{data_time:s}' + '\t{rpn_cls_loss:s}\t{rpn_loc_loss:s}\t{rpn_mask_loss:s}\t{siammask_loss:s}' + '\t{mask_iou_mean:s}\t{mask_iou_at_5:s}\t{mask_iou_at_7:s}'.format( + epoch+1, (iter + 1) % num_per_epoch, num_per_epoch, lr=cur_lr, batch_time=avg.batch_time, + data_time=avg.data_time, rpn_cls_loss=avg.rpn_cls_loss, rpn_loc_loss=avg.rpn_loc_loss, + rpn_mask_loss=avg.rpn_mask_loss, siammask_loss=avg.siammask_loss, mask_iou_mean=avg.mask_iou_mean, + mask_iou_at_5=avg.mask_iou_at_5,mask_iou_at_7=avg.mask_iou_at_7)) + print_speed(iter + 1, avg.batch_time.avg, args.epochs * num_per_epoch) + + +def save_checkpoint(state, is_best, filename='checkpoint.pth', best_file='model_best.pth'): + torch.save(state, filename) + if is_best: + shutil.copyfile(filename, best_file) + + +if __name__ == '__main__': + main() diff --git a/SiamMask/tools/train_siammask_refine.py b/SiamMask/tools/train_siammask_refine.py new file mode 100644 index 0000000000000000000000000000000000000000..04b9bf7dd5ff39896c46fee08df4d64a637df792 --- /dev/null +++ b/SiamMask/tools/train_siammask_refine.py @@ -0,0 +1,301 @@ +# -------------------------------------------------------- +# SiamMask +# Licensed under The MIT License +# Written by Qiang Wang (wangqiang2015 at ia.ac.cn) +# -------------------------------------------------------- +import argparse +import logging +import os +import cv2 +import shutil +import time +import json +import math +import torch +from torch.utils.data import DataLoader + +from utils.log_helper import init_log, print_speed, add_file_handler, Dummy +from utils.load_helper import load_pretrain, restore_from +from utils.average_meter_helper import AverageMeter + +from datasets.siam_mask_dataset import DataSets + +from utils.lr_helper import build_lr_scheduler +from tensorboardX import SummaryWriter + +from utils.config_helper import load_config +from torch.utils.collect_env import get_pretty_env_info + +torch.backends.cudnn.benchmark = True + + +parser = argparse.ArgumentParser(description='PyTorch Tracking Training') + +parser.add_argument('-j', '--workers', default=16, type=int, metavar='N', + help='number of data loading workers (default: 16)') +parser.add_argument('--epochs', default=50, type=int, metavar='N', + help='number of total epochs to run') +parser.add_argument('--start-epoch', default=0, type=int, metavar='N', + help='manual epoch number (useful on restarts)') +parser.add_argument('-b', '--batch', default=64, type=int, + metavar='N', help='mini-batch size (default: 64)') +parser.add_argument('--lr', '--learning-rate', default=0.001, type=float, + metavar='LR', help='initial learning rate') +parser.add_argument('--momentum', default=0.9, type=float, metavar='M', + help='momentum') +parser.add_argument('--weight-decay', '--wd', default=1e-4, type=float, + metavar='W', help='weight decay (default: 1e-4)') +parser.add_argument('--clip', default=10.0, type=float, + help='gradient clip value') +parser.add_argument('--print-freq', '-p', default=10, type=int, + metavar='N', help='print frequency (default: 10)') +parser.add_argument('--resume', default='', type=str, metavar='PATH', + help='path to latest checkpoint (default: none)') +parser.add_argument('--pretrained', dest='pretrained', default='', + help='use pre-trained model') +parser.add_argument('--config', dest='config', required=True, + help='hyperparameter of SiamRPN in json format') +parser.add_argument('--arch', dest='arch', default='', choices=['Custom',''], + help='architecture of pretrained model') +parser.add_argument('-l', '--log', default="log.txt", type=str, + help='log file') +parser.add_argument('-s', '--save_dir', default='snapshot', type=str, + help='save dir') +parser.add_argument('--log-dir', default='board', help='TensorBoard log dir') + + +best_acc = 0. + + +def collect_env_info(): + env_str = get_pretty_env_info() + env_str += "\n OpenCV ({})".format(cv2.__version__) + return env_str + + +def build_data_loader(cfg): + logger = logging.getLogger('global') + + logger.info("build train dataset") # train_dataset + train_set = DataSets(cfg['train_datasets'], cfg['anchors'], args.epochs) + train_set.shuffle() + + logger.info("build val dataset") # val_dataset + if not 'val_datasets' in cfg.keys(): + cfg['val_datasets'] = cfg['train_datasets'] + val_set = DataSets(cfg['val_datasets'], cfg['anchors']) + val_set.shuffle() + + train_loader = DataLoader(train_set, batch_size=args.batch, num_workers=args.workers, + pin_memory=True, sampler=None) + val_loader = DataLoader(val_set, batch_size=args.batch, num_workers=args.workers, + pin_memory=True, sampler=None) + + logger.info('build dataset done') + return train_loader, val_loader + + +def build_opt_lr(model, cfg, args, epoch): + trainable_params = model.mask_model.param_groups(cfg['lr']['start_lr'], cfg['lr']['mask_lr_mult']) + \ + model.refine_model.param_groups(cfg['lr']['start_lr'], cfg['lr']['mask_lr_mult']) + + optimizer = torch.optim.SGD(trainable_params, args.lr, + momentum=args.momentum, + weight_decay=args.weight_decay) + + lr_scheduler = build_lr_scheduler(optimizer, cfg['lr'], epochs=args.epochs) + + lr_scheduler.step(epoch) + + return optimizer, lr_scheduler + + +def main(): + global args, best_acc, tb_writer, logger + args = parser.parse_args() + + init_log('global', logging.INFO) + + if args.log != "": + add_file_handler('global', args.log, logging.INFO) + + logger = logging.getLogger('global') + logger.info("\n" + collect_env_info()) + logger.info(args) + + cfg = load_config(args) + logger.info("config \n{}".format(json.dumps(cfg, indent=4))) + + if args.log_dir: + tb_writer = SummaryWriter(args.log_dir) + else: + tb_writer = Dummy() + + # build dataset + train_loader, val_loader = build_data_loader(cfg) + + if args.arch == 'Custom': + from custom import Custom + model = Custom(anchors=cfg['anchors']) + else: + model = models.__dict__[args.arch](anchors=cfg['anchors']) + + logger.info(model) + + if args.pretrained: + model = load_pretrain(model, args.pretrained) + + model = model.cuda() + dist_model = torch.nn.DataParallel(model, list(range(torch.cuda.device_count()))).cuda() + + if args.resume and args.start_epoch != 0: + model.features.unfix((args.start_epoch - 1) / args.epochs) + + optimizer, lr_scheduler = build_opt_lr(model, cfg, args, args.start_epoch) + # optionally resume from a checkpoint + if args.resume: + assert os.path.isfile(args.resume), '{} is not a valid file'.format(args.resume) + model, optimizer, args.start_epoch, best_acc, arch = restore_from(model, optimizer, args.resume) + dist_model = torch.nn.DataParallel(model, list(range(torch.cuda.device_count()))).cuda() + + logger.info(lr_scheduler) + + logger.info('model prepare done') + + train(train_loader, dist_model, optimizer, lr_scheduler, args.start_epoch, cfg) + + +def BNtoFixed(m): + class_name = m.__class__.__name__ + if class_name.find('BatchNorm') != -1: + m.eval() + + +def train(train_loader, model, optimizer, lr_scheduler, epoch, cfg): + global tb_index, best_acc, cur_lr, logger + cur_lr = lr_scheduler.get_cur_lr() + logger = logging.getLogger('global') + avg = AverageMeter() + model.train() + model.module.features.eval() + model.module.rpn_model.eval() + model.module.features.apply(BNtoFixed) + model.module.rpn_model.apply(BNtoFixed) + + model.module.mask_model.train() + model.module.refine_model.train() + model = model.cuda() + end = time.time() + + def is_valid_number(x): + return not(math.isnan(x) or math.isinf(x) or x > 1e4) + + num_per_epoch = len(train_loader.dataset) // args.epochs // args.batch + start_epoch = epoch + epoch = epoch + for iter, input in enumerate(train_loader): + + if epoch != iter // num_per_epoch + start_epoch: # next epoch + epoch = iter // num_per_epoch + start_epoch + + if not os.path.exists(args.save_dir): # makedir/save model + os.makedirs(args.save_dir) + + save_checkpoint({ + 'epoch': epoch, + 'arch': args.arch, + 'state_dict': model.module.state_dict(), + 'best_acc': best_acc, + 'optimizer': optimizer.state_dict(), + 'anchor_cfg': cfg['anchors'] + }, False, + os.path.join(args.save_dir, 'checkpoint_e%d.pth' % (epoch)), + os.path.join(args.save_dir, 'best.pth')) + + if epoch == args.epochs: + return + + optimizer, lr_scheduler = build_opt_lr(model.module, cfg, args, epoch) + + lr_scheduler.step(epoch) + cur_lr = lr_scheduler.get_cur_lr() + + logger.info('epoch:{}'.format(epoch)) + + tb_index = iter + if iter % num_per_epoch == 0 and iter != 0: + for idx, pg in enumerate(optimizer.param_groups): + logger.info("epoch {} lr {}".format(epoch, pg['lr'])) + tb_writer.add_scalar('lr/group%d' % (idx+1), pg['lr'], tb_index) + + data_time = time.time() - end + avg.update(data_time=data_time) + x = { + 'cfg': cfg, + 'template': torch.autograd.Variable(input[0]).cuda(), + 'search': torch.autograd.Variable(input[1]).cuda(), + 'label_cls': torch.autograd.Variable(input[2]).cuda(), + 'label_loc': torch.autograd.Variable(input[3]).cuda(), + 'label_loc_weight': torch.autograd.Variable(input[4]).cuda(), + 'label_mask': torch.autograd.Variable(input[6]).cuda(), + 'label_mask_weight': torch.autograd.Variable(input[7]).cuda(), + } + + outputs = model(x) + + rpn_cls_loss, rpn_loc_loss, rpn_mask_loss = torch.mean(outputs['losses'][0]), torch.mean(outputs['losses'][1]), torch.mean(outputs['losses'][2]) + mask_iou_mean, mask_iou_at_5, mask_iou_at_7 = torch.mean(outputs['accuracy'][0]), torch.mean(outputs['accuracy'][1]), torch.mean(outputs['accuracy'][2]) + + cls_weight, reg_weight, mask_weight = cfg['loss']['weight'] + + loss = rpn_cls_loss * cls_weight + rpn_loc_loss * reg_weight + rpn_mask_loss * mask_weight + + optimizer.zero_grad() + loss.backward() + + if cfg['clip']['split']: + torch.nn.utils.clip_grad_norm_(model.module.features.parameters(), cfg['clip']['feature']) + torch.nn.utils.clip_grad_norm_(model.module.rpn_model.parameters(), cfg['clip']['rpn']) + torch.nn.utils.clip_grad_norm_(model.module.mask_model.parameters(), cfg['clip']['mask']) + torch.nn.utils.clip_grad_norm_(model.module.refine_model.parameters(), cfg['clip']['mask']) + else: + torch.nn.utils.clip_grad_norm_(model.parameters(), args.clip) # gradient clip + + if is_valid_number(loss.item()): + optimizer.step() + + siammask_loss = loss.item() + + batch_time = time.time() - end + + avg.update(batch_time=batch_time, rpn_cls_loss=rpn_cls_loss, rpn_loc_loss=rpn_loc_loss, + rpn_mask_loss=rpn_mask_loss, siammask_loss=siammask_loss, + mask_iou_mean=mask_iou_mean, mask_iou_at_5=mask_iou_at_5, mask_iou_at_7=mask_iou_at_7) + + tb_writer.add_scalar('loss/cls', rpn_cls_loss, tb_index) + tb_writer.add_scalar('loss/loc', rpn_loc_loss, tb_index) + tb_writer.add_scalar('loss/mask', rpn_mask_loss, tb_index) + tb_writer.add_scalar('mask/mIoU', mask_iou_mean, tb_index) + tb_writer.add_scalar('mask/AP@.5', mask_iou_at_5, tb_index) + tb_writer.add_scalar('mask/AP@.7', mask_iou_at_7, tb_index) + end = time.time() + + if (iter + 1) % args.print_freq == 0: + logger.info('Epoch: [{0}][{1}/{2}] lr: {lr:.6f}\t{batch_time:s}\t{data_time:s}' + '\t{rpn_cls_loss:s}\t{rpn_loc_loss:s}\t{rpn_mask_loss:s}\t{siammask_loss:s}' + '\t{mask_iou_mean:s}\t{mask_iou_at_5:s}\t{mask_iou_at_7:s}'.format( + epoch+1, (iter + 1) % num_per_epoch, num_per_epoch, lr=cur_lr, batch_time=avg.batch_time, + data_time=avg.data_time, rpn_cls_loss=avg.rpn_cls_loss, rpn_loc_loss=avg.rpn_loc_loss, + rpn_mask_loss=avg.rpn_mask_loss, siammask_loss=avg.siammask_loss, mask_iou_mean=avg.mask_iou_mean, + mask_iou_at_5=avg.mask_iou_at_5,mask_iou_at_7=avg.mask_iou_at_7)) + print_speed(iter + 1, avg.batch_time.avg, args.epochs * num_per_epoch) + + +def save_checkpoint(state, is_best, filename='checkpoint.pth', best_file='model_best.pth'): + torch.save(state, filename) + if is_best: + shutil.copyfile(filename, best_file) + + +if __name__ == '__main__': + main() diff --git a/SiamMask/tools/train_siamrpn.py b/SiamMask/tools/train_siamrpn.py new file mode 100644 index 0000000000000000000000000000000000000000..fb666c3978850911f4fb1e5c4a1bd6f4930a04be --- /dev/null +++ b/SiamMask/tools/train_siamrpn.py @@ -0,0 +1,292 @@ +# -------------------------------------------------------- +# SiamMask +# Licensed under The MIT License +# Written by Qiang Wang (wangqiang2015 at ia.ac.cn) +# -------------------------------------------------------- +import argparse +import logging +import os +import shutil +import time +import torch +from torch.utils.data import DataLoader + +from utils.log_helper import init_log, print_speed, add_file_handler, Dummy +from utils.load_helper import load_pretrain, restore_from +from utils.average_meter_helper import AverageMeter + +from datasets.siam_rpn_dataset import DataSets +import models as models +import math + +from utils.lr_helper import build_lr_scheduler +from tensorboardX import SummaryWriter + +from utils.config_helper import load_config +import json +import cv2 +from torch.utils.collect_env import get_pretty_env_info + +torch.backends.cudnn.benchmark = True + +model_zoo = sorted(name for name in models.__dict__ + if not name.startswith("__") + and callable(models.__dict__[name])) + +parser = argparse.ArgumentParser(description='PyTorch Tracking Training') + +parser.add_argument('-j', '--workers', default=16, type=int, metavar='N', + help='number of data loading workers (default: 16)') +parser.add_argument('--epochs', default=50, type=int, metavar='N', + help='number of total epochs to run') +parser.add_argument('--start-epoch', default=0, type=int, metavar='N', + help='manual epoch number (useful on restarts)') +parser.add_argument('-b', '--batch', default=64, type=int, + metavar='N', help='mini-batch size (default: 64)') +parser.add_argument('--lr', '--learning-rate', default=0.001, type=float, + metavar='LR', help='initial learning rate') +parser.add_argument('--momentum', default=0.9, type=float, metavar='M', + help='momentum') +parser.add_argument('--weight-decay', '--wd', default=1e-4, type=float, + metavar='W', help='weight decay (default: 1e-4)') +parser.add_argument('--clip', default=10.0, type=float, + help='gradient clip value') +parser.add_argument('--print-freq', '-p', default=10, type=int, + metavar='N', help='print frequency (default: 10)') +parser.add_argument('--resume', default='', type=str, metavar='PATH', + help='path to latest checkpoint (default: none)') +parser.add_argument('--pretrained', dest='pretrained', default='', + help='use pre-trained model') +parser.add_argument('--config', dest='config', required=True, + help='hyperparameter of SiamRPN in json format') +parser.add_argument('--arch', dest='arch', default='', choices=model_zoo + ['Custom',''], + help='architecture of pretrained model') +parser.add_argument('-l', '--log', default="log.txt", type=str, + help='log file') +parser.add_argument('-s', '--save_dir', default='snapshot', type=str, + help='save dir') +parser.add_argument('--log-dir', default='board', help='TensorBoard log dir') + +best_acc = 0. + + +def collect_env_info(): + env_str = get_pretty_env_info() + env_str += "\n OpenCV ({})".format(cv2.__version__) + return env_str + + +def build_data_loader(cfg): + logger = logging.getLogger('global') + + logger.info("build train dataset") # train_dataset + train_set = DataSets(cfg['train_datasets'], cfg['anchors'], args.epochs) + train_set.shuffle() + + logger.info("build val dataset") # val_dataset + if not 'val_datasets' in cfg.keys(): + cfg['val_datasets'] = cfg['train_datasets'] + val_set = DataSets(cfg['val_datasets'], cfg['anchors']) + val_set.shuffle() + + train_loader = DataLoader(train_set, batch_size=args.batch, num_workers=args.workers, + pin_memory=True, sampler=None) + val_loader = DataLoader(val_set, batch_size=args.batch, num_workers=args.workers, + pin_memory=True, sampler=None) + + logger.info('build dataset done') + return train_loader, val_loader + + +def build_opt_lr(model, cfg, args, epoch): + trainable_params = model.features.param_groups(cfg['lr']['start_lr'], cfg['lr']['feature_lr_mult']) + \ + model.rpn_model.param_groups(cfg['lr']['start_lr'], cfg['lr']['rpn_lr_mult']) + + optimizer = torch.optim.SGD(trainable_params, args.lr, + momentum=args.momentum, + weight_decay=args.weight_decay) + + lr_scheduler = build_lr_scheduler(optimizer, cfg['lr'], epochs=args.epochs) + + lr_scheduler.step(epoch) + + return optimizer, lr_scheduler + + +def main(): + global args, best_acc, tb_writer, logger + args = parser.parse_args() + + init_log('global', logging.INFO) + + if args.log != "": + add_file_handler('global', args.log, logging.INFO) + + logger = logging.getLogger('global') + logger.info(args) + + cfg = load_config(args) + + logger.info("config \n{}".format(json.dumps(cfg, indent=4))) + + logger.info("\n" + collect_env_info()) + + if args.log_dir: + tb_writer = SummaryWriter(args.log_dir) + else: + tb_writer = Dummy() + + # build dataset + train_loader, val_loader = build_data_loader(cfg) + + if args.arch == 'Custom': + from custom import Custom + model = Custom(pretrain=True, anchors=cfg['anchors']) + else: + model = models.__dict__[args.arch](anchors=cfg['anchors']) + + logger.info(model) + + if args.pretrained: + model = load_pretrain(model, args.pretrained) + + model = model.cuda() + dist_model = torch.nn.DataParallel(model, list(range(torch.cuda.device_count()))).cuda() + + if args.resume and args.start_epoch != 0: + model.features.unfix((args.start_epoch - 1) / args.epochs) + + optimizer, lr_scheduler = build_opt_lr(model, cfg, args, args.start_epoch) + logger.info(lr_scheduler) + # optionally resume from a checkpoint + if args.resume: + assert os.path.isfile(args.resume), '{} is not a valid file'.format(args.resume) + model, optimizer, args.start_epoch, best_acc, arch = restore_from(model, optimizer, args.resume) + dist_model = torch.nn.DataParallel(model, list(range(torch.cuda.device_count()))).cuda() + epoch = args.start_epoch + if dist_model.module.features.unfix(epoch/args.epochs): + logger.info('unfix part model.') + optimizer, lr_scheduler = build_opt_lr(dist_model.module, cfg, args, epoch) + lr_scheduler.step(epoch) + cur_lr = lr_scheduler.get_cur_lr() + logger.info('epoch:{} resume lr {}'.format(epoch, cur_lr)) + + logger.info('model prepare done') + + train(train_loader, dist_model, optimizer, lr_scheduler, args.start_epoch, cfg) + + +def train(train_loader, model, optimizer, lr_scheduler, epoch, cfg): + global tb_index, best_acc, cur_lr + cur_lr = lr_scheduler.get_cur_lr() + logger = logging.getLogger('global') + avg = AverageMeter() + model.train() + model = model.cuda() + end = time.time() + + def is_valid_number(x): + return not(math.isnan(x) or math.isinf(x) or x > 1e4) + + num_per_epoch = len(train_loader.dataset) // args.epochs // args.batch + start_epoch = epoch + epoch = epoch + for iter, input in enumerate(train_loader): + # next epoch + if epoch != iter // num_per_epoch + start_epoch: + epoch = iter // num_per_epoch + start_epoch + + if not os.path.exists(args.save_dir): # makedir/save model + os.makedirs(args.save_dir) + + save_checkpoint({ + 'epoch': epoch, + 'arch': args.arch, + 'state_dict': model.module.state_dict(), + 'best_acc': best_acc, + 'optimizer': optimizer.state_dict(), + 'anchor_cfg': cfg['anchors'] + }, False, + os.path.join(args.save_dir, 'checkpoint_e%d.pth' % (epoch)), + os.path.join(args.save_dir, 'best.pth')) + + if epoch == args.epochs: + return + + if model.module.features.unfix(epoch/args.epochs): + logger.info('unfix part model.') + optimizer, lr_scheduler = build_opt_lr(model.module, cfg, args, epoch) + + lr_scheduler.step(epoch) + cur_lr = lr_scheduler.get_cur_lr() + + logger.info('epoch:{}'.format(epoch)) + + tb_index = iter + if iter % num_per_epoch == 0 and iter != 0: + for idx, pg in enumerate(optimizer.param_groups): + logger.info("epoch {} lr {}".format(epoch, pg['lr'])) + tb_writer.add_scalar('lr/group%d'%(idx+1), pg['lr'], tb_index) + + data_time = time.time() - end + avg.update(data_time=data_time) + x = { + 'cfg': cfg, + 'template': torch.autograd.Variable(input[0]).cuda(), + 'search': torch.autograd.Variable(input[1]).cuda(), + 'label_cls': torch.autograd.Variable(input[2]).cuda(), + 'label_loc': torch.autograd.Variable(input[3]).cuda(), + 'label_loc_weight': torch.autograd.Variable(input[4]).cuda(), + } + + optimizer.zero_grad() + outputs = model(x) + + rpn_cls_loss, rpn_loc_loss = outputs['losses'] + + rpn_cls_loss, rpn_loc_loss = torch.mean(rpn_cls_loss), torch.mean(rpn_loc_loss) + + cls_weight, reg_weight = cfg['loss']['weight'] + + loss = rpn_cls_loss * cls_weight + rpn_loc_loss * reg_weight + + loss.backward() + + if cfg['clip']['split']: + torch.nn.utils.clip_grad_norm_(model.module.features.parameters(), cfg['clip']['feature']) + torch.nn.utils.clip_grad_norm_(model.module.rpn_model.parameters(), cfg['clip']['rpn']) + else: + torch.nn.utils.clip_grad_norm_(model.parameters(), args.clip) # gradient clip + + siamrpn_loss = loss.item() + + if is_valid_number(siamrpn_loss): + optimizer.step() + + batch_time = time.time() - end + + avg.update(batch_time=batch_time, rpn_cls_loss=rpn_cls_loss, + rpn_loc_loss=rpn_loc_loss, siamrpn_loss=siamrpn_loss) + + tb_writer.add_scalar('loss/cls', rpn_cls_loss, tb_index) + tb_writer.add_scalar('loss/loc', rpn_loc_loss, tb_index) + + end = time.time() + + if (iter + 1) % args.print_freq == 0: + logger.info('Epoch: [{0}][{1}/{2}] lr: {lr:.6f}\t{batch_time:s}\t{data_time:s}' + '\t{rpn_cls_loss:s}\t{rpn_loc_loss:s}\t{siamrpn_loss:s}'.format( + epoch+1, (iter + 1) % num_per_epoch, num_per_epoch, lr=cur_lr, + batch_time=avg.batch_time, data_time=avg.data_time, rpn_cls_loss=avg.rpn_cls_loss, + rpn_loc_loss=avg.rpn_loc_loss, siamrpn_loss=avg.siamrpn_loss)) + print_speed(iter + 1, avg.batch_time.avg, args.epochs * num_per_epoch) + + +def save_checkpoint(state, is_best, filename='checkpoint.pth', best_file='model_best.pth'): + torch.save(state, filename) + if is_best: + shutil.copyfile(filename, best_file) + + +if __name__ == '__main__': + main() diff --git a/SiamMask/tools/tune_vos.py b/SiamMask/tools/tune_vos.py new file mode 100644 index 0000000000000000000000000000000000000000..f392e18197a5a5f6d31a85595c463639a5bad543 --- /dev/null +++ b/SiamMask/tools/tune_vos.py @@ -0,0 +1,213 @@ +# -------------------------------------------------------- +# SiamMask +# Licensed under The MIT License +# Written by Qiang Wang (wangqiang2015 at ia.ac.cn) +# -------------------------------------------------------- +import argparse +import logging +import numpy as np +import cv2 +from PIL import Image +from os import makedirs +from os.path import isfile, isdir, join + +from utils.log_helper import init_log, add_file_handler +from utils.bbox_helper import cxy_wh_2_rect +from utils.load_helper import load_pretrain +from utils.benchmark_helper import load_dataset +from utils.average_meter_helper import IouMeter + +import models as models +from tools.test import siamese_init, siamese_track +from utils.config_helper import load_config + +thrs = np.arange(0.3, 0.81, 0.05) + +model_zoo = sorted(name for name in models.__dict__ + if not name.startswith("__") + and callable(models.__dict__[name])) + + +def parse_range(arg): + param = map(float, arg.split(',')) + return np.arange(*param) + + +def parse_range_int(arg): + param = map(int, arg.split(',')) + return np.arange(*param) + + +parser = argparse.ArgumentParser(description='Finetune parameters for SiamMask tracker on DAVIS') +parser.add_argument('--arch', dest='arch', default='SiamRPNA', choices=model_zoo + ['Custom'], + help='architecture of pretrained model') +parser.add_argument('--resume', default='', type=str, required=True, + metavar='PATH',help='path to latest checkpoint (default: none)') +parser.add_argument('--config', dest='config',help='hyperparameter of SiamMask in json format') +parser.add_argument('--mask', action='store_true', help='whether use mask output') +parser.add_argument('--refine', action='store_true', help='whether use mask refine output') +parser.add_argument('--dataset', default='DAVIS2016', type=str, + metavar='DATASET', help='dataset') +parser.add_argument('-l', '--log', default="log_tune_davis.txt", type=str, + help='log file') +parser.add_argument('--penalty-k', default='0.0,0.1,0.03', type=parse_range, + help='penalty_k range') +parser.add_argument('--lr', default='0.8,1.01,0.05', type=parse_range, + help='lr range') +parser.add_argument('--window-influence', default='0.3,0.5,0.04', type=parse_range, + help='window influence range') +parser.add_argument('--search-region', default='255,256,8', type=parse_range_int, + help='search region size') +parser.add_argument('-v', '--visualization', dest='visualization', action='store_true', + help='whether visualize result') + +args = parser.parse_args() + + +def tune(param): + regions = [] # result and states[1 init / 2 lost / 0 skip] + # save result + benchmark_result_path = join('result', param['dataset']) + tracker_path = join(benchmark_result_path, (param['network_name'] + ('_refine' if args.refine else '') + + '_r{}'.format(param['hp']['instance_size']) + + '_penalty_k_{:.3f}'.format(param['hp']['penalty_k']) + + '_window_influence_{:.3f}'.format(param['hp']['window_influence']) + + '_lr_{:.3f}'.format(param['hp']['lr'])).replace('.', '_')) # no . + video_path = tracker_path + result_path = join(video_path, param['video'] + '.txt') + + if isfile(result_path): + return + + try: + if not isdir(video_path): + makedirs(video_path) + except OSError as err: + print(err) + + with open(result_path, 'w') as f: # Occupation + f.write('Occ') + + global ims, gt, annos, image_files, anno_files + if ims is None: + print(param['video'] + ' Only load image once and if needed') + ims = [cv2.imread(x) for x in image_files] + annos = [np.array(Image.open(x)) for x in anno_files] + + iou = IouMeter(thrs, len(ims) - 2) + start_frame, end_frame, toc = 0, len(ims) - 1, 0 + for f, (im, anno) in enumerate(zip(ims, annos)): + tic = cv2.getTickCount() + if f == start_frame: # init + target_pos = np.array([gt[f, 0]+gt[f, 2]/2, gt[f, 1]+gt[f, 3]/2]) + target_sz = np.array([gt[f, 2], gt[f, 3]]) + state = siamese_init(im, target_pos, target_sz, param['network'], param['hp']) # init tracker + location = cxy_wh_2_rect(state['target_pos'], state['target_sz']) + regions.append(gt[f]) + elif f > start_frame: # tracking + state = siamese_track(state, im, args.mask, args.refine) # track + location = state['ploygon'].flatten() + mask = state['mask'] + + regions.append(location) + if start_frame < f < end_frame: iou.add(mask, anno) + + toc += cv2.getTickCount() - tic + + if args.visualization and f >= start_frame: # visualization (skip lost frame) + im_show = im.copy() + if f == 0: cv2.destroyAllWindows() + if len(gt[f]) == 8: + cv2.polylines(im_show, [np.array(gt[f], np.int).reshape((-1, 1, 2))], True, (0, 255, 0), 3) + else: + cv2.rectangle(im_show, (gt[f, 0], gt[f, 1]), (gt[f, 0] + gt[f, 2], gt[f, 1] + gt[f, 3]), (0, 255, 0), 3) + if len(location) == 8: + im_show[:,:,2] = mask*255 + (1-mask)*im_show[:,:,2] + cv2.polylines(im_show, [np.int0(location).reshape((-1, 1, 2))], True, (0, 255, 255), 3) + else: + location = [int(l) for l in location] # bad support for OPENCV + cv2.rectangle(im_show, (location[0], location[1]), + (location[0] + location[2], location[1] + location[3]), (0, 255, 255), 3) + cv2.putText(im_show, str(f), (40, 40), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 255), 2) # frame id + + cv2.imshow(param['video'], im_show) + cv2.waitKey(1) + toc /= cv2.getTickFrequency() + iou_list = iou.value('mean') + print('Video: {:12s} Time: {:2.1f}s Speed: {:3.1f}fps IOU: {:.3f}'.format(param['video'], toc, f / toc, iou_list.max())) + + with open(result_path, 'w') as f: + f.write(','.join(["%.5f" % i for i in iou_list]) + '\n') + + return iou_list + + +def main(): + init_log('global', logging.INFO) + if args.log != "": + add_file_handler('global', args.log, logging.INFO) + + params = {'penalty_k': args.penalty_k, + 'window_influence': args.window_influence, + 'lr': args.lr, + 'instance_size': args.search_region} + + num_search = len(params['penalty_k']) * len(params['window_influence']) * \ + len(params['lr']) * len(params['instance_size']) + + print(params) + print(num_search) + + cfg = load_config(args) + if args.arch == 'Custom': + from custom import Custom + model = Custom(anchors=cfg['anchors']) + else: + model = models.__dict__[args.arch](anchors=cfg['anchors']) + + if args.resume: + assert isfile(args.resume), '{} is not a valid file'.format(args.resume) + model = load_pretrain(model, args.resume) + model.eval() + model = model.cuda() + + default_hp = cfg.get('hp', {}) + + p = dict() + + p['network'] = model + p['network_name'] = args.arch+'_mask_'+args.resume.split('/')[-1].split('.')[0] + p['dataset'] = args.dataset + + global ims, gt, annos, image_files, anno_files + + dataset_info = load_dataset(args.dataset) + videos = list(dataset_info.keys()) + np.random.shuffle(videos) + for video in videos: + print(video) + p['video'] = video + ims = None + annos = None + image_files = dataset_info[video]['image_files'] + anno_files = dataset_info[video]['anno_files'] + gt = dataset_info[video]['gt'] + + np.random.shuffle(params['penalty_k']) + np.random.shuffle(params['window_influence']) + np.random.shuffle(params['lr']) + for penalty_k in params['penalty_k']: + for window_influence in params['window_influence']: + for lr in params['lr']: + for instance_size in params['instance_size']: + p['hp'] = default_hp.copy() + p['hp'].update({'penalty_k':penalty_k, + 'window_influence':window_influence, + 'lr':lr, + 'instance_size': instance_size, + }) + tune(p) + + +if __name__ == '__main__': + main() diff --git a/SiamMask/tools/tune_vot.py b/SiamMask/tools/tune_vot.py new file mode 100644 index 0000000000000000000000000000000000000000..32984411b704811d4d6ee3a6c9fb78bce80b431a --- /dev/null +++ b/SiamMask/tools/tune_vot.py @@ -0,0 +1,241 @@ +# -------------------------------------------------------- +# SiamMask +# Licensed under The MIT License +# Written by Qiang Wang (wangqiang2015 at ia.ac.cn) +# -------------------------------------------------------- +import argparse +import logging +import numpy as np +import cv2 +import torch +from os import makedirs +from os.path import isfile, isdir, join + +from utils.log_helper import init_log, add_file_handler +from utils.bbox_helper import get_axis_aligned_bbox, cxy_wh_2_rect +from utils.load_helper import load_pretrain +from utils.benchmark_helper import load_dataset + +from tools.test import siamese_init, siamese_track +from utils.config_helper import load_config +from utils.pyvotkit.region import vot_overlap, vot_float2str + +def parse_range(arg): + param = map(float, arg.split(',')) + return np.arange(*param) + + +def parse_range_int(arg): + param = map(int, arg.split(',')) + return np.arange(*param) + + +parser = argparse.ArgumentParser(description='Finetune parameters for SiamMask tracker on VOT') +parser.add_argument('--arch', dest='arch', default='Custom', choices=['Custom', ], + help='architecture of pretrained model') +parser.add_argument('--resume', default='', type=str, required=True, + metavar='PATH',help='path to latest checkpoint (default: none)') +parser.add_argument('--config', dest='config',help='hyperparameter of SiamRPN in json format') +parser.add_argument('--mask', action='store_true', help='whether use mask output') +parser.add_argument('--refine', action='store_true', help='whether use mask refine output') +parser.add_argument('-v', '--visualization', dest='visualization', action='store_true', + help='whether visualize result') +parser.add_argument('--dataset', default='VOT2018', type=str, + metavar='DATASET', help='dataset') +parser.add_argument('-l', '--log', default="log_tune.txt", type=str, + help='log file') +parser.add_argument('--penalty-k', default='0.05,0.5,0.05', type=parse_range, + help='penalty_k range') +parser.add_argument('--lr', default='0.35,0.5,0.05', type=parse_range, + help='lr range') +parser.add_argument('--window-influence', default='0.1,0.8,0.05', type=parse_range, + help='window influence range') +parser.add_argument('--search-region', default='255,256,8', type=parse_range_int, + help='search region size') + +args = parser.parse_args() +device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') + + +def tune(param): + regions = [] # result and states[1 init / 2 lost / 0 skip] + # save result + benchmark_result_path = join('result', param['dataset']) + tracker_path = join(benchmark_result_path, (param['network_name'] + + '_r{}'.format(param['hp']['instance_size']) + + '_penalty_k_{:.3f}'.format(param['hp']['penalty_k']) + + '_window_influence_{:.3f}'.format(param['hp']['window_influence']) + + '_lr_{:.3f}'.format(param['hp']['lr'])).replace('.', '_')) # no . + if param['dataset'].startswith('VOT'): + baseline_path = join(tracker_path, 'baseline') + video_path = join(baseline_path, param['video']) + result_path = join(video_path, param['video'] + '_001.txt') + elif param['dataset'].startswith('OTB') or param['dataset'].startswith('DAVIS'): + video_path = tracker_path + result_path = join(video_path, param['video']+'.txt') + + if isfile(result_path): + return + + try: + if not isdir(video_path): + makedirs(video_path) + except OSError as err: + print(err) + + with open(result_path, 'w') as f: # Occupation + f.write('Occ') + + global ims, gt, image_files + if ims is None: + print(param['video'] + ' Only load image once and if needed') + ims = [cv2.imread(x) for x in image_files] + start_frame, lost_times, toc = 0, 0, 0 + for f, im in enumerate(ims): + tic = cv2.getTickCount() + if f == start_frame: # init + cx, cy, w, h = get_axis_aligned_bbox(gt[f]) + target_pos = np.array([cx, cy]) + target_sz = np.array([w, h]) + state = siamese_init(im, target_pos, target_sz, param['network'], param['hp'], device=device) # init tracker + location = cxy_wh_2_rect(state['target_pos'], state['target_sz']) + if param['dataset'].startswith('VOT'): + regions.append(1) + elif param['dataset'].startswith('OTB') or param['dataset'].startswith('DAVIS'): + regions.append(gt[f]) + elif f > start_frame: # tracking + state = siamese_track(state, im, args.mask, args.refine, device=device) + if args.mask: + location = state['ploygon'].flatten() + else: + location = cxy_wh_2_rect(state['target_pos'], state['target_sz']) + if param['dataset'].startswith('VOT'): + if 'VOT' in args.dataset: + gt_polygon = ((gt[f][0], gt[f][1]), + (gt[f][2], gt[f][3]), + (gt[f][4], gt[f][5]), + (gt[f][6], gt[f][7])) + if args.mask: + pred_polygon = ((location[0], location[1]), (location[2], location[3]), + (location[4], location[5]), (location[6], location[7])) + else: + pred_polygon = ((location[0], location[1]), + (location[0] + location[2], location[1]), + (location[0] + location[2], location[1] + location[3]), + (location[0], location[1] + location[3])) + b_overlap = vot_overlap(gt_polygon, pred_polygon, (im.shape[1], im.shape[0])) + else: + b_overlap = 1 + + if b_overlap: # continue to track + regions.append(location) + else: # lost + regions.append(2) + lost_times += 1 + start_frame = f + 5 # skip 5 frames + else: + regions.append(location) + else: # skip + regions.append(0) + toc += cv2.getTickCount() - tic + + if args.visualization and f >= start_frame: # visualization (skip lost frame) + if f == 0: cv2.destroyAllWindows() + if len(gt[f]) == 8: + cv2.polylines(im, [np.array(gt[f], np.int).reshape((-1, 1, 2))], True, (0, 255, 0), 3) + else: + cv2.rectangle(im, (gt[f, 0], gt[f, 1]), (gt[f, 0] + gt[f, 2], gt[f, 1] + gt[f, 3]), (0, 255, 0), 3) + if len(location) == 8: + location = np.int0(location) + cv2.polylines(im, [location.reshape((-1, 1, 2))], True, (0, 255, 255), 3) + else: + location = [int(l) for l in location] # bad support for OPENCV + cv2.rectangle(im, (location[0], location[1]), + (location[0] + location[2], location[1] + location[3]), (0, 255, 255), 3) + cv2.putText(im, str(f), (40, 40), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 255), 2) # frame id + cv2.putText(im, str(lost_times), (40, 80), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2) # lost time + + cv2.imshow(param['video'], im) + cv2.waitKey(1) + toc /= cv2.getTickFrequency() + print('Video: {:12s} Time: {:2.1f}s Speed: {:3.1f}fps Lost: {:d}'.format(param['video'], toc, f / toc, lost_times)) + + with open(result_path, 'w') as f: + for x in regions: + f.write('{:d}\n'.format(x)) if isinstance(x, int) else \ + f.write(','.join([vot_float2str("%.4f", i) for i in x]) + '\n') + + +def main(): + init_log('global', logging.INFO) + if args.log != "": + add_file_handler('global', args.log, logging.INFO) + + params = {'penalty_k': args.penalty_k, + 'window_influence': args.window_influence, + 'lr': args.lr, + 'instance_size': args.search_region} + + num_search = len(params['penalty_k']) * len(params['window_influence']) * \ + len(params['lr']) * len(params['instance_size']) + + print(params) + print(num_search) + + cfg = load_config(args) + if args.arch == 'Custom': + from custom import Custom + model = Custom(anchors=cfg['anchors']) + else: + model = models.__dict__[args.arch](anchors=cfg['anchors']) + + if args.resume: + assert isfile(args.resume), '{} is not a valid file'.format(args.resume) + model = load_pretrain(model, args.resume) + model.eval() + model = model.to(device) + + default_hp = cfg.get('hp', {}) + + p = dict() + + p['network'] = model + p['network_name'] = args.arch+'_'+args.resume.split('/')[-1].split('.')[0] + p['dataset'] = args.dataset + + global ims, gt, image_files + + dataset_info = load_dataset(args.dataset) + videos = list(dataset_info.keys()) + np.random.shuffle(videos) + + for video in videos: + print(video) + if isfile('finish.flag'): + return + + p['video'] = video + ims = None + image_files = dataset_info[video]['image_files'] + gt = dataset_info[video]['gt'] + + np.random.shuffle(params['penalty_k']) + np.random.shuffle(params['window_influence']) + np.random.shuffle(params['lr']) + for penalty_k in params['penalty_k']: + for window_influence in params['window_influence']: + for lr in params['lr']: + for instance_size in params['instance_size']: + p['hp'] = default_hp.copy() + p['hp'].update({'penalty_k':penalty_k, + 'window_influence':window_influence, + 'lr':lr, + 'instance_size': instance_size, + }) + tune(p) + + +if __name__ == '__main__': + main() + with open('finish.flag', 'w') as f: # Occupation + f.write('finish') diff --git a/SiamMask/utils/__init__.py b/SiamMask/utils/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SiamMask/utils/__pycache__/__init__.cpython-39.pyc b/SiamMask/utils/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..aba9fb020b3f7b9d6f6d8fc59ae2a327492b6314 Binary files /dev/null and b/SiamMask/utils/__pycache__/__init__.cpython-39.pyc differ diff --git a/SiamMask/utils/__pycache__/anchors.cpython-39.pyc b/SiamMask/utils/__pycache__/anchors.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4562e0445f09341ff5c1563a8a5bcb517792d1fe Binary files /dev/null and b/SiamMask/utils/__pycache__/anchors.cpython-39.pyc differ diff --git a/SiamMask/utils/__pycache__/bbox_helper.cpython-39.pyc b/SiamMask/utils/__pycache__/bbox_helper.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4a34a2aa05a6cbe4c3cf7e581ee2c13751ffafe7 Binary files /dev/null and b/SiamMask/utils/__pycache__/bbox_helper.cpython-39.pyc differ diff --git a/SiamMask/utils/__pycache__/benchmark_helper.cpython-39.pyc b/SiamMask/utils/__pycache__/benchmark_helper.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..825bd0970ed7db2c1bdfa56be2d4407964d7f2d5 Binary files /dev/null and b/SiamMask/utils/__pycache__/benchmark_helper.cpython-39.pyc differ diff --git a/SiamMask/utils/__pycache__/config_helper.cpython-39.pyc b/SiamMask/utils/__pycache__/config_helper.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0c67b9df357b11e8b2f321d578439d82d52a81de Binary files /dev/null and b/SiamMask/utils/__pycache__/config_helper.cpython-39.pyc differ diff --git a/SiamMask/utils/__pycache__/load_helper.cpython-39.pyc b/SiamMask/utils/__pycache__/load_helper.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fb137dd387056eeecacb2ee1be2369b7ca55f3fa Binary files /dev/null and b/SiamMask/utils/__pycache__/load_helper.cpython-39.pyc differ diff --git a/SiamMask/utils/__pycache__/log_helper.cpython-39.pyc b/SiamMask/utils/__pycache__/log_helper.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b612fe2cd5951eeee87f38622ffb8a7be787abe9 Binary files /dev/null and b/SiamMask/utils/__pycache__/log_helper.cpython-39.pyc differ diff --git a/SiamMask/utils/__pycache__/tracker_config.cpython-39.pyc b/SiamMask/utils/__pycache__/tracker_config.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fe15e448387a211cd50b4474d83925c27bf49ebd Binary files /dev/null and b/SiamMask/utils/__pycache__/tracker_config.cpython-39.pyc differ diff --git a/SiamMask/utils/anchors.py b/SiamMask/utils/anchors.py new file mode 100644 index 0000000000000000000000000000000000000000..a013da7b1b648319d9a3a3558708cbcaac6701ce --- /dev/null +++ b/SiamMask/utils/anchors.py @@ -0,0 +1,90 @@ +# -------------------------------------------------------- +# SiamMask +# Licensed under The MIT License +# Written by Qiang Wang (wangqiang2015 at ia.ac.cn) +# -------------------------------------------------------- +import numpy as np +import math +from utils.bbox_helper import center2corner, corner2center + + +class Anchors: + def __init__(self, cfg): + self.stride = 8 + self.ratios = [0.33, 0.5, 1, 2, 3] + self.scales = [8] + self.round_dight = 0 + self.image_center = 0 + self.size = 0 + self.anchor_density = 1 + + self.__dict__.update(cfg) + + self.anchor_num = len(self.scales) * len(self.ratios) * (self.anchor_density**2) + self.anchors = None # in single position (anchor_num*4) + self.all_anchors = None # in all position 2*(4*anchor_num*h*w) + self.generate_anchors() + + def generate_anchors(self): + self.anchors = np.zeros((self.anchor_num, 4), dtype=np.float32) + + size = self.stride * self.stride + count = 0 + anchors_offset = self.stride / self.anchor_density + anchors_offset = np.arange(self.anchor_density)*anchors_offset + anchors_offset = anchors_offset - np.mean(anchors_offset) + x_offsets, y_offsets = np.meshgrid(anchors_offset, anchors_offset) + + for x_offset, y_offset in zip(x_offsets.flatten(), y_offsets.flatten()): + for r in self.ratios: + if self.round_dight > 0: + ws = round(math.sqrt(size*1. / r), self.round_dight) + hs = round(ws * r, self.round_dight) + else: + ws = int(math.sqrt(size*1. / r)) + hs = int(ws * r) + + for s in self.scales: + w = ws * s + h = hs * s + self.anchors[count][:] = [-w*0.5+x_offset, -h*0.5+y_offset, w*0.5+x_offset, h*0.5+y_offset][:] + count += 1 + + def generate_all_anchors(self, im_c, size): + if self.image_center == im_c and self.size == size: + return False + self.image_center = im_c + self.size = size + + a0x = im_c - size // 2 * self.stride + ori = np.array([a0x] * 4, dtype=np.float32) + zero_anchors = self.anchors + ori + + x1 = zero_anchors[:, 0] + y1 = zero_anchors[:, 1] + x2 = zero_anchors[:, 2] + y2 = zero_anchors[:, 3] + + x1, y1, x2, y2 = map(lambda x: x.reshape(self.anchor_num, 1, 1), [x1, y1, x2, y2]) + cx, cy, w, h = corner2center([x1, y1, x2, y2]) + + disp_x = np.arange(0, size).reshape(1, 1, -1) * self.stride + disp_y = np.arange(0, size).reshape(1, -1, 1) * self.stride + + cx = cx + disp_x + cy = cy + disp_y + + # broadcast + zero = np.zeros((self.anchor_num, size, size), dtype=np.float32) + cx, cy, w, h = map(lambda x: x + zero, [cx, cy, w, h]) + x1, y1, x2, y2 = center2corner([cx, cy, w, h]) + + self.all_anchors = np.stack([x1, y1, x2, y2]), np.stack([cx, cy, w, h]) + return True + + +# if __name__ == '__main__': +# anchors = Anchors(cfg={'stride':16, 'anchor_density': 2}) +# anchors.generate_all_anchors(im_c=255//2, size=(255-127)//16+1+8) +# a = 1 + diff --git a/SiamMask/utils/average_meter_helper.py b/SiamMask/utils/average_meter_helper.py new file mode 100644 index 0000000000000000000000000000000000000000..7df8a7a841ddb9d59423049a2b93919512cc670f --- /dev/null +++ b/SiamMask/utils/average_meter_helper.py @@ -0,0 +1,129 @@ +# -------------------------------------------------------- +# SiamMask +# Licensed under The MIT License +# Written by Qiang Wang (wangqiang2015 at ia.ac.cn) +# -------------------------------------------------------- +import numpy as np + + +class Meter(object): + def __init__(self, name, val, avg): + self.name = name + self.val = val + self.avg = avg + + def __repr__(self): + return "{name}: {val:.6f} ({avg:.6f})".format( + name=self.name, val=self.val, avg=self.avg + ) + + def __format__(self, *tuples, **kwargs): + return self.__repr__() + + +class AverageMeter(object): + """Computes and stores the average and current value""" + def __init__(self): + self.reset() + + def reset(self): + self.val = {} + self.sum = {} + self.count = {} + + def update(self, batch=1, **kwargs): + val = {} + for k in kwargs: + val[k] = kwargs[k] / float(batch) + self.val.update(val) + for k in kwargs: + if k not in self.sum: + self.sum[k] = 0 + self.count[k] = 0 + self.sum[k] += kwargs[k] + self.count[k] += batch + + def __repr__(self): + s = '' + for k in self.sum: + s += self.format_str(k) + return s + + def format_str(self, attr): + return "{name}: {val:.6f} ({avg:.6f}) ".format( + name=attr, + val=float(self.val[attr]), + avg=float(self.sum[attr]) / self.count[attr]) + + def __getattr__(self, attr): + if attr in self.__dict__: + return super(AverageMeter, self).__getattr__(attr) + if attr not in self.sum: + # logger.warn("invalid key '{}'".format(attr)) + print("invalid key '{}'".format(attr)) + return Meter(attr, 0, 0) + return Meter(attr, self.val[attr], self.avg(attr)) + + def avg(self, attr): + return float(self.sum[attr]) / self.count[attr] + + +class IouMeter(object): + def __init__(self, thrs, sz): + self.sz = sz + self.iou = np.zeros((sz, len(thrs)), dtype=np.float32) + self.thrs = thrs + self.reset() + + def reset(self): + self.iou.fill(0.) + self.n = 0 + + def add(self, output, target): + if self.n >= len(self.iou): + return + target, output = target.squeeze(), output.squeeze() + for i, thr in enumerate(self.thrs): + pred = output > thr + mask_sum = (pred == 1).astype(np.uint8) + (target > 0).astype(np.uint8) + intxn = np.sum(mask_sum == 2) + union = np.sum(mask_sum > 0) + if union > 0: + self.iou[self.n, i] = intxn / union + elif union == 0 and intxn == 0: + self.iou[self.n, i] = 1 + self.n += 1 + + def value(self, s): + nb = max(int(np.sum(self.iou > 0)), 1) + iou = self.iou[:nb] + + def is_number(s): + try: + float(s) + return True + except ValueError: + return False + if s == 'mean': + res = np.mean(iou, axis=0) + elif s == 'median': + res = np.median(iou, axis=0) + elif is_number(s): + res = np.sum(iou > float(s), axis=0) / float(nb) + return res + + +if __name__ == '__main__': + avg = AverageMeter() + avg.update(time=1.1, accuracy=.99) + avg.update(time=1.0, accuracy=.90) + + print(avg) + + print(avg.time) + print(avg.time.avg) + print(avg.time.val) + print(avg.SS) + + + diff --git a/SiamMask/utils/bbox_helper.py b/SiamMask/utils/bbox_helper.py new file mode 100644 index 0000000000000000000000000000000000000000..167048ed96821425c52ea6a30b2a60ebdb888976 --- /dev/null +++ b/SiamMask/utils/bbox_helper.py @@ -0,0 +1,165 @@ +# -------------------------------------------------------- +# SiamMask +# Licensed under The MIT License +# Written by Qiang Wang (wangqiang2015 at ia.ac.cn) +# -------------------------------------------------------- +import numpy as np +from collections import namedtuple + +Corner = namedtuple('Corner', 'x1 y1 x2 y2') +BBox = Corner +Center = namedtuple('Center', 'x y w h') + + +def corner2center(corner): + """ + :param corner: Corner or np.array 4*N + :return: Center or 4 np.array N + """ + if isinstance(corner, Corner): + x1, y1, x2, y2 = corner + return Center((x1 + x2) * 0.5, (y1 + y2) * 0.5, (x2 - x1), (y2 - y1)) + else: + x1, y1, x2, y2 = corner[0], corner[1], corner[2], corner[3] + x = (x1 + x2) * 0.5 + y = (y1 + y2) * 0.5 + w = x2 - x1 + h = y2 - y1 + return x, y, w, h + + +def center2corner(center): + """ + :param center: Center or np.array 4*N + :return: Corner or np.array 4*N + """ + if isinstance(center, Center): + x, y, w, h = center + return Corner(x - w * 0.5, y - h * 0.5, x + w * 0.5, y + h * 0.5) + else: + x, y, w, h = center[0], center[1], center[2], center[3] + x1 = x - w * 0.5 + y1 = y - h * 0.5 + x2 = x + w * 0.5 + y2 = y + h * 0.5 + return x1, y1, x2, y2 + + +def cxy_wh_2_rect(pos, sz): + return np.array([pos[0]-sz[0]/2, pos[1]-sz[1]/2, sz[0], sz[1]]) # 0-index + + +def get_axis_aligned_bbox(region): + nv = region.size + if nv == 8: + cx = np.mean(region[0::2]) + cy = np.mean(region[1::2]) + x1 = min(region[0::2]) + x2 = max(region[0::2]) + y1 = min(region[1::2]) + y2 = max(region[1::2]) + A1 = np.linalg.norm(region[0:2] - region[2:4]) * np.linalg.norm(region[2:4] - region[4:6]) + A2 = (x2 - x1) * (y2 - y1) + s = np.sqrt(A1 / A2) + w = s * (x2 - x1) + 1 + h = s * (y2 - y1) + 1 + else: + x = region[0] + y = region[1] + w = region[2] + h = region[3] + cx = x+w/2 + cy = y+h/2 + + return cx, cy, w, h + + +def aug_apply(bbox, param, shape, inv=False, rd=False): + """ + apply augmentation + :param bbox: original bbox in image + :param param: augmentation param, shift/scale + :param shape: image shape, h, w, (c) + :param inv: inverse + :param rd: round bbox + :return: bbox(, param) + bbox: augmented bbox + param: real augmentation param + """ + if not inv: + center = corner2center(bbox) + original_center = center + + real_param = {} + if 'scale' in param: + scale_x, scale_y = param['scale'] + imh, imw = shape[:2] + h, w = center.h, center.w + + scale_x = min(scale_x, float(imw) / w) + scale_y = min(scale_y, float(imh) / h) + + # center.w *= scale_x + # center.h *= scale_y + center = Center(center.x, center.y, center.w * scale_x, center.h * scale_y) + + bbox = center2corner(center) + + if 'shift' in param: + tx, ty = param['shift'] + x1, y1, x2, y2 = bbox + imh, imw = shape[:2] + + tx = max(-x1, min(imw - 1 - x2, tx)) + ty = max(-y1, min(imh - 1 - y2, ty)) + + bbox = Corner(x1 + tx, y1 + ty, x2 + tx, y2 + ty) + + if rd: + bbox = Corner(*map(round, bbox)) + + current_center = corner2center(bbox) + + real_param['scale'] = current_center.w / original_center.w, current_center.h / original_center.h + real_param['shift'] = current_center.x - original_center.x, current_center.y - original_center.y + + return bbox, real_param + else: + if 'scale' in param: + scale_x, scale_y = param['scale'] + else: + scale_x, scale_y = 1., 1. + + if 'shift' in param: + tx, ty = param['shift'] + else: + tx, ty = 0, 0 + + center = corner2center(bbox) + + center = Center(center.x - tx, center.y - ty, center.w / scale_x, center.h / scale_y) + + return center2corner(center) + + +def IoU(rect1, rect2): + # overlap + x1, y1, x2, y2 = rect1[0], rect1[1], rect1[2], rect1[3] + tx1, ty1, tx2, ty2 = rect2[0], rect2[1], rect2[2], rect2[3] + + xx1 = np.maximum(tx1, x1) + yy1 = np.maximum(ty1, y1) + xx2 = np.minimum(tx2, x2) + yy2 = np.minimum(ty2, y2) + + ww = np.maximum(0, xx2 - xx1) + hh = np.maximum(0, yy2 - yy1) + + area = (x2-x1) * (y2-y1) + + target_a = (tx2-tx1) * (ty2 - ty1) + + inter = ww * hh + overlap = inter / (area + target_a - inter) + + return overlap diff --git a/SiamMask/utils/benchmark_helper.py b/SiamMask/utils/benchmark_helper.py new file mode 100644 index 0000000000000000000000000000000000000000..eded166297e350b12ba855d62aabf5c55beff3f4 --- /dev/null +++ b/SiamMask/utils/benchmark_helper.py @@ -0,0 +1,108 @@ +# -------------------------------------------------------- +# SiamMask +# Licensed under The MIT License +# Written by Qiang Wang (wangqiang2015 at ia.ac.cn) +# -------------------------------------------------------- +from os.path import join, realpath, dirname, exists, isdir +from os import listdir +import logging +import glob +import numpy as np +import json +from collections import OrderedDict + + +def get_dataset_zoo(): + root = realpath(join(dirname(__file__), '../data')) + zoos = listdir(root) + + def valid(x): + y = join(root, x) + if not isdir(y): return False + + return exists(join(y, 'list.txt')) \ + or exists(join(y, 'train', 'meta.json')) \ + or exists(join(y, 'ImageSets', '2016', 'val.txt')) \ + or exists(join(y, 'ImageSets', '2017', 'test-dev.txt')) + + zoos = list(filter(valid, zoos)) + return zoos + + +dataset_zoo = get_dataset_zoo() + + +def load_dataset(dataset): + info = OrderedDict() + if 'VOT' in dataset: + base_path = join(realpath(dirname(__file__)), '../data', dataset) + if not exists(base_path): + logging.error("Please download test dataset!!!") + exit() + list_path = join(base_path, 'list.txt') + with open(list_path) as f: + videos = [v.strip() for v in f.readlines()] + for video in videos: + video_path = join(base_path, video) + image_path = join(video_path, '*.jpg') + image_files = sorted(glob.glob(image_path)) + if len(image_files) == 0: # VOT2018 + image_path = join(video_path, 'color', '*.jpg') + image_files = sorted(glob.glob(image_path)) + gt_path = join(video_path, 'groundtruth.txt') + gt = np.loadtxt(gt_path, delimiter=',').astype(np.float64) + if gt.shape[1] == 4: + gt = np.column_stack((gt[:, 0], gt[:, 1], gt[:, 0], gt[:, 1] + gt[:, 3]-1, + gt[:, 0] + gt[:, 2]-1, gt[:, 1] + gt[:, 3]-1, gt[:, 0] + gt[:, 2]-1, gt[:, 1])) + info[video] = {'image_files': image_files, 'gt': gt, 'name': video} + elif 'DAVIS' in dataset and 'TEST' not in dataset: + base_path = join(realpath(dirname(__file__)), '../data', 'DAVIS') + list_path = join(realpath(dirname(__file__)), '../data', 'DAVIS', 'ImageSets', dataset[-4:], 'val.txt') + with open(list_path) as f: + videos = [v.strip() for v in f.readlines()] + for video in videos: + info[video] = {} + info[video]['anno_files'] = sorted(glob.glob(join(base_path, 'Annotations/480p', video, '*.png'))) + info[video]['image_files'] = sorted(glob.glob(join(base_path, 'JPEGImages/480p', video, '*.jpg'))) + info[video]['name'] = video + elif 'ytb_vos' in dataset: + base_path = join(realpath(dirname(__file__)), '../data', 'ytb_vos', 'valid') + json_path = join(realpath(dirname(__file__)), '../data', 'ytb_vos', 'valid', 'meta.json') + meta = json.load(open(json_path, 'r')) + meta = meta['videos'] + info = dict() + for v in meta.keys(): + objects = meta[v]['objects'] + frames = [] + anno_frames = [] + info[v] = dict() + for obj in objects: + frames += objects[obj]['frames'] + anno_frames += [objects[obj]['frames'][0]] + frames = sorted(np.unique(frames)) + info[v]['anno_files'] = [join(base_path, 'Annotations', v, im_f+'.png') for im_f in frames] + info[v]['anno_init_files'] = [join(base_path, 'Annotations', v, im_f + '.png') for im_f in anno_frames] + info[v]['image_files'] = [join(base_path, 'JPEGImages', v, im_f+'.jpg') for im_f in frames] + info[v]['name'] = v + + info[v]['start_frame'] = dict() + info[v]['end_frame'] = dict() + for obj in objects: + start_file = objects[obj]['frames'][0] + end_file = objects[obj]['frames'][-1] + info[v]['start_frame'][obj] = frames.index(start_file) + info[v]['end_frame'][obj] = frames.index(end_file) + elif 'TEST' in dataset: + base_path = join(realpath(dirname(__file__)), '../data', 'DAVIS2017TEST') + list_path = join(realpath(dirname(__file__)), '../data', 'DAVIS2017TEST', 'ImageSets', '2017', 'test-dev.txt') + with open(list_path) as f: + videos = [v.strip() for v in f.readlines()] + for video in videos: + info[video] = {} + info[video]['anno_files'] = sorted(glob.glob(join(base_path, 'Annotations/480p', video, '*.png'))) + info[video]['image_files'] = sorted(glob.glob(join(base_path, 'JPEGImages/480p', video, '*.jpg'))) + info[video]['name'] = video + else: + logging.error('Not support') + exit() + return info diff --git a/SiamMask/utils/config_helper.py b/SiamMask/utils/config_helper.py new file mode 100644 index 0000000000000000000000000000000000000000..37c7ef65bb447070a4834ee499d2f6239f34dd58 --- /dev/null +++ b/SiamMask/utils/config_helper.py @@ -0,0 +1,73 @@ +# -------------------------------------------------------- +# SiamMask +# Licensed under The MIT License +# Written by Qiang Wang (wangqiang2015 at ia.ac.cn) +# -------------------------------------------------------- +import json +from os.path import exists + + +def proccess_loss(cfg): + if 'reg' not in cfg: + cfg['reg'] = {'loss': 'L1Loss'} + else: + if 'loss' not in cfg['reg']: + cfg['reg']['loss'] = 'L1Loss' + + if 'cls' not in cfg: + cfg['cls'] = {'split': True} + + cfg['weight'] = cfg.get('weight', [1, 1, 36]) # cls, reg, mask + + +def add_default(conf, default): + default.update(conf) + return default + + +def load_config(args): + assert exists(args.config), '"{}" not exists'.format(args.config) + config = json.load(open(args.config)) + + # deal with network + if 'network' not in config: + print('Warning: network lost in config. This will be error in next version') + + config['network'] = {} + + if not args.arch: + raise Exception('no arch provided') + args.arch = config['network']['arch'] + + # deal with loss + if 'loss' not in config: + config['loss'] = {} + + proccess_loss(config['loss']) + + # deal with lr + if 'lr' not in config: + config['lr'] = {} + default = { + 'feature_lr_mult': 1.0, + 'rpn_lr_mult': 1.0, + 'mask_lr_mult': 1.0, + 'type': 'log', + 'start_lr': 0.03 + } + default.update(config['lr']) + config['lr'] = default + + # clip + if 'clip' in config or 'clip' in args.__dict__: + if 'clip' not in config: + config['clip'] = {} + config['clip'] = add_default(config['clip'], + {'feature': args.clip, 'rpn': args.clip, 'split': False}) + if config['clip']['feature'] != config['clip']['rpn']: + config['clip']['split'] = True + if not config['clip']['split']: + args.clip = config['clip']['feature'] + + return config + diff --git a/SiamMask/utils/load_helper.py b/SiamMask/utils/load_helper.py new file mode 100644 index 0000000000000000000000000000000000000000..63d877915b40c21853fff9f40a00396ddc7cc6f4 --- /dev/null +++ b/SiamMask/utils/load_helper.py @@ -0,0 +1,70 @@ +import torch +import logging +logger = logging.getLogger('global') + + +def check_keys(model, pretrained_state_dict): + ckpt_keys = set(pretrained_state_dict.keys()) + model_keys = set(model.state_dict().keys()) + used_pretrained_keys = model_keys & ckpt_keys + unused_pretrained_keys = ckpt_keys - model_keys + missing_keys = model_keys - ckpt_keys + if len(missing_keys) > 0: + logger.info('[Warning] missing keys: {}'.format(missing_keys)) + logger.info('missing keys:{}'.format(len(missing_keys))) + if len(unused_pretrained_keys) > 0: + logger.info('[Warning] unused_pretrained_keys: {}'.format(unused_pretrained_keys)) + logger.info('unused checkpoint keys:{}'.format(len(unused_pretrained_keys))) + logger.info('used keys:{}'.format(len(used_pretrained_keys))) + assert len(used_pretrained_keys) > 0, 'load NONE from pretrained checkpoint' + return True + + +def remove_prefix(state_dict, prefix): + ''' Old style model is stored with all names of parameters share common prefix 'module.' ''' + logger.info('remove prefix \'{}\''.format(prefix)) + f = lambda x: x.split(prefix, 1)[-1] if x.startswith(prefix) else x + return {f(key): value for key, value in state_dict.items()} + + +def load_pretrain(model, pretrained_path): + logger.info('load pretrained model from {}'.format(pretrained_path)) + if not torch.cuda.is_available(): + pretrained_dict = torch.load(pretrained_path, map_location=lambda storage, loc: storage) + else: + device = torch.cuda.current_device() + pretrained_dict = torch.load(pretrained_path, map_location=lambda storage, loc: storage.cuda(device)) + + if "state_dict" in pretrained_dict.keys(): + pretrained_dict = remove_prefix(pretrained_dict['state_dict'], 'module.') + else: + pretrained_dict = remove_prefix(pretrained_dict, 'module.') + + try: + check_keys(model, pretrained_dict) + except: + logger.info('[Warning]: using pretrain as features. Adding "features." as prefix') + new_dict = {} + for k, v in pretrained_dict.items(): + k = 'features.' + k + new_dict[k] = v + pretrained_dict = new_dict + check_keys(model, pretrained_dict) + model.load_state_dict(pretrained_dict, strict=False) + return model + + +def restore_from(model, optimizer, ckpt_path): + logger.info('restore from {}'.format(ckpt_path)) + device = torch.cuda.current_device() + ckpt = torch.load(ckpt_path, map_location=lambda storage, loc: storage.cuda(device)) + epoch = ckpt['epoch'] + best_acc = ckpt['best_acc'] + arch = ckpt['arch'] + ckpt_model_dict = remove_prefix(ckpt['state_dict'], 'module.') + check_keys(model, ckpt_model_dict) + model.load_state_dict(ckpt_model_dict, strict=False) + + check_keys(optimizer, ckpt['optimizer']) + optimizer.load_state_dict(ckpt['optimizer']) + return model, optimizer, epoch, best_acc, arch diff --git a/SiamMask/utils/log_helper.py b/SiamMask/utils/log_helper.py new file mode 100644 index 0000000000000000000000000000000000000000..e9ca6e5466757b0edac09e630a74b9558909a2d8 --- /dev/null +++ b/SiamMask/utils/log_helper.py @@ -0,0 +1,143 @@ +# -------------------------------------------------------- +# SiamMask +# Licensed under The MIT License +# Written by Qiang Wang (wangqiang2015 at ia.ac.cn) +# -------------------------------------------------------- +from __future__ import division + +import os +import logging +import sys +import math + +if hasattr(sys, 'frozen'): # support for py2exe + _srcfile = "logging%s__init__%s" % (os.sep, __file__[-4:]) +elif __file__[-4:].lower() in ['.pyc', '.pyo']: + _srcfile = __file__[:-4] + '.py' +else: + _srcfile = __file__ +_srcfile = os.path.normcase(_srcfile) + + +logs = set() + + +class Filter: + def __init__(self, flag): + self.flag = flag + + def filter(self, x): return self.flag + + +class Dummy: + def __init__(self, *arg, **kwargs): + pass + + def __getattr__(self, arg): + def dummy(*args, **kwargs): pass + return dummy + + +def get_format(logger, level): + if 'SLURM_PROCID' in os.environ: + rank = int(os.environ['SLURM_PROCID']) + + if level == logging.INFO: + logger.addFilter(Filter(rank == 0)) + else: + rank = 0 + format_str = '[%(asctime)s-rk{}-%(filename)s#%(lineno)3d] %(message)s'.format(rank) + formatter = logging.Formatter(format_str) + return formatter + + +def get_format_custom(logger, level): + if 'SLURM_PROCID' in os.environ: + rank = int(os.environ['SLURM_PROCID']) + if level == logging.INFO: + logger.addFilter(Filter(rank == 0)) + else: + rank = 0 + format_str = '[%(asctime)s-rk{}-%(message)s'.format(rank) + formatter = logging.Formatter(format_str) + return formatter + + +def init_log(name, level = logging.INFO, format_func=get_format): + if (name, level) in logs: return + logs.add((name, level)) + logger = logging.getLogger(name) + logger.setLevel(level) + ch = logging.StreamHandler() + ch.setLevel(level) + formatter = format_func(logger, level) + ch.setFormatter(formatter) + logger.addHandler(ch) + return logger + + +def add_file_handler(name, log_file, level = logging.INFO): + logger = logging.getLogger(name) + fh = logging.FileHandler(log_file) + fh.setFormatter(get_format(logger, level)) + logger.addHandler(fh) + + +init_log('global') + + +def print_speed(i, i_time, n): + """print_speed(index, index_time, total_iteration)""" + logger = logging.getLogger('global') + average_time = i_time + remaining_time = (n - i) * average_time + remaining_day = math.floor(remaining_time / 86400) + remaining_hour = math.floor(remaining_time / 3600 - remaining_day * 24) + remaining_min = math.floor(remaining_time / 60 - remaining_day * 1440 - remaining_hour * 60) + logger.info('Progress: %d / %d [%d%%], Speed: %.3f s/iter, ETA %d:%02d:%02d (D:H:M)\n' % (i, n, i/n*100, average_time, remaining_day, remaining_hour, remaining_min)) + + +def find_caller(): + def current_frame(): + try: + raise Exception + except: + return sys.exc_info()[2].tb_frame.f_back + + f = current_frame() + if f is not None: + f = f.f_back + rv = "(unknown file)", 0, "(unknown function)" + while hasattr(f, "f_code"): + co = f.f_code + filename = os.path.normcase(co.co_filename) + rv = (co.co_filename, f.f_lineno, co.co_name) + if filename == _srcfile: + f = f.f_back + continue + break + rv = list(rv) + rv[0] = os.path.basename(rv[0]) + return rv + + +class LogOnce: + def __init__(self): + self.logged = set() + self.logger = init_log('log_once', format_func=get_format_custom) + + def log(self, strings): + fn, lineno, caller = find_caller() + key = (fn, lineno, caller, strings) + if key in self.logged: + return + self.logged.add(key) + message = "{filename:s}<{caller}>#{lineno:3d}] {strings}".format(filename=fn, lineno=lineno, strings=strings, caller=caller) + self.logger.info(message) + + +once_logger = LogOnce() + + +def log_once(strings): + once_logger.log(strings) diff --git a/SiamMask/utils/lr_helper.py b/SiamMask/utils/lr_helper.py new file mode 100644 index 0000000000000000000000000000000000000000..664480ea5a9f9a8a2ca099093da27ac251dd8b66 --- /dev/null +++ b/SiamMask/utils/lr_helper.py @@ -0,0 +1,210 @@ +# -------------------------------------------------------- +# SiamMask +# Licensed under The MIT License +# Written by Qiang Wang (wangqiang2015 at ia.ac.cn) +# -------------------------------------------------------- +from __future__ import division +import numpy as np +import math +from torch.optim.lr_scheduler import _LRScheduler + + +class LRScheduler(_LRScheduler): + def __init__(self, optimizer, last_epoch=-1): + if 'lr_spaces' not in self.__dict__: + raise Exception('lr_spaces must be set in "LRSchduler"') + super(LRScheduler, self).__init__(optimizer, last_epoch) + + def get_cur_lr(self): + return self.lr_spaces[self.last_epoch] + + def get_lr(self): + epoch = self.last_epoch + return [self.lr_spaces[epoch] * pg['initial_lr'] / self.start_lr for pg in self.optimizer.param_groups] + + def __repr__(self): + return "({}) lr spaces: \n{}".format(self.__class__.__name__, self.lr_spaces) + + +class LogScheduler(LRScheduler): + def __init__(self, optimizer, start_lr=0.03, end_lr=5e-4, epochs=50, last_epoch=-1, **kwargs): + self.start_lr = start_lr + self.end_lr = end_lr + self.epochs = epochs + self.lr_spaces = np.logspace(math.log10(start_lr), math.log10(end_lr), epochs) + + super(LogScheduler, self).__init__(optimizer, last_epoch) + + +class StepScheduler(LRScheduler): + def __init__(self, optimizer, start_lr=0.01, end_lr=None, step=10, mult=0.1, epochs=50, last_epoch=-1, **kwargs): + if end_lr is not None: + if start_lr is None: + start_lr = end_lr / (mult ** (epochs // step)) + else: # for warm up policy + mult = math.pow(end_lr/start_lr, 1. / (epochs // step)) + self.start_lr = start_lr + self.lr_spaces = self.start_lr * (mult**(np.arange(epochs) // step)) + self.mult = mult + self._step = step + + super(StepScheduler, self).__init__(optimizer, last_epoch) + + +class MultiStepScheduler(LRScheduler): + def __init__(self, optimizer, start_lr=0.01, end_lr=None, steps=[10,20,30,40], mult=0.5, epochs=50, last_epoch=-1, **kwargs): + if end_lr is not None: + if start_lr is None: + start_lr = end_lr / (mult ** (len(steps))) + else: + mult = math.pow(end_lr/start_lr, 1. / len(steps)) + self.start_lr = start_lr + self.lr_spaces = self._build_lr(start_lr, steps, mult, epochs) + self.mult = mult + self.steps = steps + + super(MultiStepScheduler, self).__init__(optimizer, last_epoch) + + def _build_lr(self, start_lr, steps, mult, epochs): + lr = [0] * epochs + lr[0] = start_lr + for i in range(1, epochs): + lr[i] = lr[i-1] + if i in steps: + lr[i] *= mult + return np.array(lr, dtype=np.float32) + + +class LinearStepScheduler(LRScheduler): + def __init__(self, optimizer, start_lr=0.01, end_lr=0.005, epochs=50, last_epoch=-1, **kwargs): + self.start_lr = start_lr + self.end_lr = end_lr + self.lr_spaces = np.linspace(start_lr, end_lr, epochs) + + super(LinearStepScheduler, self).__init__(optimizer, last_epoch) + + +class CosStepScheduler(LRScheduler): + def __init__(self, optimizer, start_lr=0.01, end_lr=0.005, epochs=50, last_epoch=-1, **kwargs): + self.start_lr = start_lr + self.end_lr = end_lr + self.lr_spaces = self._build_lr(start_lr, end_lr, epochs) + + super(CosStepScheduler, self).__init__(optimizer, last_epoch) + + def _build_lr(self, start_lr, end_lr, epochs): + index = np.arange(epochs).astype(np.float32) + lr = end_lr + (start_lr - end_lr) * (1. + np.cos(index * np.pi/ epochs)) * 0.5 + return lr.astype(np.float32) + + +class WarmUPScheduler(LRScheduler): + def __init__(self, optimizer, warmup, normal, epochs=50, last_epoch=-1): + warmup = warmup.lr_spaces # [::-1] + normal = normal.lr_spaces + self.lr_spaces = np.concatenate([warmup, normal]) + self.start_lr = normal[0] + + super(WarmUPScheduler, self).__init__(optimizer, last_epoch) + + +LRs = { + 'log': LogScheduler, + 'step': StepScheduler, + 'multi-step': MultiStepScheduler, + 'linear': LinearStepScheduler, + 'cos': CosStepScheduler} + + +def _build_lr_scheduler(optimizer, cfg, epochs=50, last_epoch=-1): + if 'type' not in cfg: + # return LogScheduler(optimizer, last_epoch=last_epoch, epochs=epochs) + cfg['type'] = 'log' + + if cfg['type'] not in LRs: + raise Exception('Unknown type of LR Scheduler "%s"'%cfg['type']) + + return LRs[cfg['type']](optimizer, last_epoch=last_epoch, epochs=epochs, **cfg) + + +def _build_warm_up_scheduler(optimizer, cfg, epochs=50, last_epoch=-1): + warmup_epoch = cfg['warmup']['epoch'] + sc1 = _build_lr_scheduler(optimizer, cfg['warmup'], warmup_epoch, last_epoch) + sc2 = _build_lr_scheduler(optimizer, cfg, epochs - warmup_epoch, last_epoch) + return WarmUPScheduler(optimizer, sc1, sc2, epochs, last_epoch) + + +def build_lr_scheduler(optimizer, cfg, epochs=50, last_epoch=-1): + if 'warmup' in cfg: + return _build_warm_up_scheduler(optimizer, cfg, epochs, last_epoch) + else: + return _build_lr_scheduler(optimizer, cfg, epochs, last_epoch) + + +if __name__ == '__main__': + import torch.nn as nn + from torch.optim import SGD + + class Net(nn.Module): + def __init__(self): + super(Net, self).__init__() + self.conv = nn.Conv2d(10, 10, kernel_size=3) + net = Net().parameters() + optimizer = SGD(net, lr=0.01) + + # test1 + step = { + 'type': 'step', + 'start_lr': 0.01, + 'step': 10, + 'mult': 0.1 + } + lr = build_lr_scheduler(optimizer, step) + print(lr) + + log = { + 'type': 'log', + 'start_lr': 0.03, + 'end_lr': 5e-4, + } + lr = build_lr_scheduler(optimizer, log) + + print(lr) + + log = { + 'type': 'multi-step', + "start_lr": 0.01, + "mult": 0.1, + "steps": [10, 15, 20] + } + lr = build_lr_scheduler(optimizer, log) + print(lr) + + cos = { + "type": 'cos', + 'start_lr': 0.01, + 'end_lr': 0.0005, + } + lr = build_lr_scheduler(optimizer, cos) + print(lr) + + step = { + 'type': 'step', + 'start_lr': 0.001, + 'end_lr': 0.03, + 'step': 1, + } + + warmup = log.copy() + warmup['warmup'] = step + warmup['warmup']['epoch'] = 5 + lr = build_lr_scheduler(optimizer, warmup, epochs=55) + print(lr) + + lr.step() + print(lr.last_epoch) + + lr.step(5) + print(lr.last_epoch) + + diff --git a/SiamMask/utils/pysot/__init__.py b/SiamMask/utils/pysot/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SiamMask/utils/pysot/datasets/__init__.py b/SiamMask/utils/pysot/datasets/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..c3b8cb1f21c8478a916dd409883ed8e79cdf6ad1 --- /dev/null +++ b/SiamMask/utils/pysot/datasets/__init__.py @@ -0,0 +1,29 @@ +# -------------------------------------------------------- +# Python Single Object Tracking Evaluation +# Licensed under The MIT License [see LICENSE for details] +# Written by Fangyi Zhang +# @author fangyi.zhang@vipl.ict.ac.cn +# @project https://github.com/StrangerZhang/pysot-toolkit.git +# Revised for SiamMask by foolwood +# -------------------------------------------------------- +from .vot import VOTDataset + + +class DatasetFactory(object): + @staticmethod + def create_dataset(**kwargs): + """ + Args: + name: dataset name 'VOT2018', 'VOT2016' + dataset_root: dataset root + Return: + dataset + """ + assert 'name' in kwargs, "should provide dataset name" + name = kwargs['name'] + if 'VOT2018' == name or 'VOT2016' == name: + dataset = VOTDataset(**kwargs) + else: + raise Exception("unknow dataset {}".format(kwargs['name'])) + return dataset + diff --git a/SiamMask/utils/pysot/datasets/dataset.py b/SiamMask/utils/pysot/datasets/dataset.py new file mode 100644 index 0000000000000000000000000000000000000000..7847e486b36d7fffa34afdb332e22c2fda8a1133 --- /dev/null +++ b/SiamMask/utils/pysot/datasets/dataset.py @@ -0,0 +1,36 @@ +# -------------------------------------------------------- +# Python Single Object Tracking Evaluation +# Licensed under The MIT License [see LICENSE for details] +# Written by Fangyi Zhang +# @author fangyi.zhang@vipl.ict.ac.cn +# @project https://github.com/StrangerZhang/pysot-toolkit.git +# Revised for SiamMask by foolwood +# -------------------------------------------------------- +class Dataset(object): + def __init__(self, name, dataset_root): + self.name = name + self.dataset_root = dataset_root + self.videos = None + + def __getitem__(self, idx): + if isinstance(idx, str): + return self.videos[idx] + elif isinstance(idx, int): + return self.videos[sorted(list(self.videos.keys()))[idx]] + + def __len__(self): + return len(self.videos) + + def __iter__(self): + keys = sorted(list(self.videos.keys())) + for key in keys: + yield self.videos[key] + + def set_tracker(self, path, tracker_names): + """ + Args: + path: path to tracker results, + tracker_names: list of tracker name + """ + self.tracker_path = path + self.tracker_names = tracker_names diff --git a/SiamMask/utils/pysot/datasets/video.py b/SiamMask/utils/pysot/datasets/video.py new file mode 100644 index 0000000000000000000000000000000000000000..d934f078e571562a979d716544a85205bbe6a911 --- /dev/null +++ b/SiamMask/utils/pysot/datasets/video.py @@ -0,0 +1,80 @@ +# -------------------------------------------------------- +# Python Single Object Tracking Evaluation +# Licensed under The MIT License [see LICENSE for details] +# Written by Fangyi Zhang +# @author fangyi.zhang@vipl.ict.ac.cn +# @project https://github.com/StrangerZhang/pysot-toolkit.git +# Revised for SiamMask by foolwood +# -------------------------------------------------------- +import os +import cv2 + +from glob import glob + + +class Video(object): + def __init__(self, name, root, video_dir, init_rect, img_names, + gt_rect, attr): + self.name = name + self.video_dir = video_dir + self.init_rect = init_rect + self.gt_traj = gt_rect + self.attr = attr + self.pred_trajs = {} + self.img_names = [os.path.join(root, x) for x in img_names] + self.imgs = None + + def load_tracker(self, path, tracker_names=None, store=True): + """ + Args: + path(str): path to result + tracker_name(list): name of tracker + """ + if not tracker_names: + tracker_names = [x.split('/')[-1] for x in glob(path) + if os.path.isdir(x)] + if isinstance(tracker_names, str): + tracker_names = [tracker_names] + for name in tracker_names: + traj_file = os.path.join(path, name, self.name+'.txt') + if os.path.exists(traj_file): + with open(traj_file, 'r') as f : + pred_traj = [list(map(float, x.strip().split(','))) + for x in f.readlines()] + if len(pred_traj) != len(self.gt_traj): + print(name, len(pred_traj), len(self.gt_traj), self.name) + if store: + self.pred_trajs[name] = pred_traj + else: + return pred_traj + else: + print(traj_file) + self.tracker_names = list(self.pred_trajs.keys()) + + def load_img(self): + if self.imgs is None: + self.imgs = [cv2.imread(x) + for x in self.img_names] + self.width = self.imgs[0].shape[1] + self.height = self.imgs[0].shape[0] + + def free_img(self): + self.imgs = None + + def __len__(self): + return len(self.img_names) + + def __getitem__(self, idx): + if self.imgs is None: + return cv2.imread(self.img_names[idx]), \ + self.gt_traj[idx] + else: + return self.imgs[idx], self.gt_traj[idx] + + def __iter__(self): + for i in range(len(self.img_names)): + if self.imgs is not None: + yield self.imgs[i], self.gt_traj[i] + else: + yield cv2.imread(self.img_names[i]), \ + self.gt_traj[i] diff --git a/SiamMask/utils/pysot/datasets/vot.py b/SiamMask/utils/pysot/datasets/vot.py new file mode 100644 index 0000000000000000000000000000000000000000..7817209c5378494153f0b74ca3d785674726e579 --- /dev/null +++ b/SiamMask/utils/pysot/datasets/vot.py @@ -0,0 +1,128 @@ +# -------------------------------------------------------- +# Python Single Object Tracking Evaluation +# Licensed under The MIT License [see LICENSE for details] +# Written by Fangyi Zhang +# @author fangyi.zhang@vipl.ict.ac.cn +# @project https://github.com/StrangerZhang/pysot-toolkit.git +# Revised for SiamMask by foolwood +# -------------------------------------------------------- +import os +import json +import numpy as np + +from glob import glob +from tqdm import tqdm + +from .dataset import Dataset +from .video import Video + + +class VOTVideo(Video): + """ + Args: + name: video name + root: dataset root + video_dir: video directory + init_rect: init rectangle + img_names: image names + gt_rect: groundtruth rectangle + camera_motion: camera motion tag + illum_change: illum change tag + motion_change: motion change tag + size_change: size change + occlusion: occlusion + """ + def __init__(self, name, root, video_dir, init_rect, img_names, gt_rect, + camera_motion, illum_change, motion_change, size_change, occlusion, width, height): + super(VOTVideo, self).__init__(name, root, video_dir, init_rect, img_names, gt_rect, None) + self.tags= {'all': [1] * len(gt_rect)} + self.tags['camera_motion'] = camera_motion + self.tags['illum_change'] = illum_change + self.tags['motion_change'] = motion_change + self.tags['size_change'] = size_change + self.tags['occlusion'] = occlusion + + self.width = width + self.height = height + + # empty tag + all_tag = [v for k, v in self.tags.items() if len(v) > 0 ] + self.tags['empty'] = np.all(1 - np.array(all_tag), axis=1).astype(np.int32).tolist() + + self.tag_names = list(self.tags.keys()) + + def select_tag(self, tag, start=0, end=0): + if tag == 'empty': + return self.tags[tag] + return self.tags[tag][start:end] + + def load_tracker(self, path, tracker_names=None, store=True): + """ + Args: + path(str): path to result + tracker_name(list): name of tracker + """ + if not tracker_names: + tracker_names = [x.split('/')[-1] for x in glob(path) + if os.path.isdir(x)] + if isinstance(tracker_names, str): + tracker_names = [tracker_names] + for name in tracker_names: + traj_files = glob(os.path.join(path, name, 'baseline', self.name, '*0*.txt')) + if len(traj_files) == 15: + traj_files = traj_files + else: + traj_files = traj_files[0:1] + pred_traj = [] + for traj_file in traj_files: + with open(traj_file, 'r') as f: + traj = [list(map(float, x.strip().split(','))) + for x in f.readlines()] + pred_traj.append(traj) + if store: + self.pred_trajs[name] = pred_traj + else: + return pred_traj + + +class VOTDataset(Dataset): + """ + Args: + name: dataset name, should be 'VOT2018', 'VOT2016' + dataset_root: dataset root + load_img: wether to load all imgs + """ + def __init__(self, name, dataset_root): + super(VOTDataset, self).__init__(name, dataset_root) + try: + with open(os.path.join(dataset_root, name+'.json'), 'r') as f: + meta_data = json.load(f) + except: + download_str = '# download json file for eval toolkit\n'+\ + 'cd $SiamMask/data\n'+\ + 'wget http://www.robots.ox.ac.uk/~qwang/VOT2016.json\n'+\ + 'wget http://www.robots.ox.ac.uk/~qwang/VOT2018.json' + print(download_str) + exit() + + # load videos + pbar = tqdm(meta_data.keys(), desc='loading '+name, ncols=100) + self.videos = {} + for video in pbar: + pbar.set_postfix_str(video) + self.videos[video] = VOTVideo(video, + dataset_root, + meta_data[video]['video_dir'], + meta_data[video]['init_rect'], + meta_data[video]['img_names'], + meta_data[video]['gt_rect'], + meta_data[video]['camera_motion'], + meta_data[video]['illum_change'], + meta_data[video]['motion_change'], + meta_data[video]['size_change'], + meta_data[video]['occlusion'], + meta_data[video]['width'], + meta_data[video]['height']) + + self.tags = ['all', 'camera_motion', 'illum_change', 'motion_change', + 'size_change', 'occlusion', 'empty'] diff --git a/SiamMask/utils/pysot/evaluation/__init__.py b/SiamMask/utils/pysot/evaluation/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..fc28998ecd5fc051580a6e488347f597db990374 --- /dev/null +++ b/SiamMask/utils/pysot/evaluation/__init__.py @@ -0,0 +1,10 @@ +# -------------------------------------------------------- +# Python Single Object Tracking Evaluation +# Licensed under The MIT License [see LICENSE for details] +# Written by Fangyi Zhang +# @author fangyi.zhang@vipl.ict.ac.cn +# @project https://github.com/StrangerZhang/pysot-toolkit.git +# Revised for SiamMask by foolwood +# -------------------------------------------------------- +from .ar_benchmark import AccuracyRobustnessBenchmark +from .eao_benchmark import EAOBenchmark diff --git a/SiamMask/utils/pysot/evaluation/ar_benchmark.py b/SiamMask/utils/pysot/evaluation/ar_benchmark.py new file mode 100644 index 0000000000000000000000000000000000000000..37cef62326f96e31e071f1c1a8d2832652fbe241 --- /dev/null +++ b/SiamMask/utils/pysot/evaluation/ar_benchmark.py @@ -0,0 +1,146 @@ +# -------------------------------------------------------- +# Python Single Object Tracking Evaluation +# Licensed under The MIT License [see LICENSE for details] +# Written by Fangyi Zhang +# @author fangyi.zhang@vipl.ict.ac.cn +# @project https://github.com/StrangerZhang/pysot-toolkit.git +# Revised for SiamMask by foolwood +# -------------------------------------------------------- + +import warnings +import itertools +import numpy as np + +from colorama import Style, Fore +from ..utils import calculate_failures, calculate_accuracy + + +class AccuracyRobustnessBenchmark: + """ + Args: + dataset: + burnin: + """ + def __init__(self, dataset, burnin=10): + self.dataset = dataset + self.burnin = burnin + + def eval(self, eval_trackers=None): + """ + Args: + eval_tags: list of tag + eval_trackers: list of tracker name + Returns: + ret: dict of results + """ + if eval_trackers is None: + eval_trackers = self.dataset.tracker_names + if isinstance(eval_trackers, str): + eval_trackers = [eval_trackers] + + result = {} + for tracker_name in eval_trackers: + accuracy, failures = self._calculate_accuracy_robustness(tracker_name) + result[tracker_name] = {'overlaps': accuracy, + 'failures': failures} + return result + + def show_result(self, result, eao_result=None, show_video_level=False, helight_threshold=0.5): + """pretty print result + Args: + result: returned dict from function eval + """ + tracker_name_len = max((max([len(x) for x in result.keys()])+2), 12) + if eao_result is not None: + header = "|{:^"+str(tracker_name_len)+"}|{:^10}|{:^12}|{:^13}|{:^7}|" + header = header.format('Tracker Name', + 'Accuracy', 'Robustness', 'Lost Number', 'EAO') + formatter = "|{:^"+str(tracker_name_len)+"}|{:^10.3f}|{:^12.3f}|{:^13.1f}|{:^7.3f}|" + else: + header = "|{:^"+str(tracker_name_len)+"}|{:^10}|{:^12}|{:^13}|" + header = header.format('Tracker Name', + 'Accuracy', 'Robustness', 'Lost Number') + formatter = "|{:^"+str(tracker_name_len)+"}|{:^10.3f}|{:^12.3f}|{:^13.1f}|" + bar = '-'*len(header) + print(bar) + print(header) + print(bar) + if eao_result is not None: + tracker_eao = sorted(eao_result.items(), + key=lambda x:x[1]['all'], + reverse=True)[:20] + tracker_names = [x[0] for x in tracker_eao] + else: + tracker_names = list(result.keys()) + for tracker_name in tracker_names: + ret = result[tracker_name] + overlaps = list(itertools.chain(*ret['overlaps'].values())) + accuracy = np.nanmean(overlaps) + length = sum([len(x) for x in ret['overlaps'].values()]) + failures = list(ret['failures'].values()) + lost_number = np.mean(np.sum(failures, axis=0)) + robustness = np.mean(np.sum(np.array(failures), axis=0) / length) * 100 + if eao_result is None: + print(formatter.format(tracker_name, accuracy, robustness, lost_number)) + else: + print(formatter.format(tracker_name, accuracy, robustness, lost_number, eao_result[tracker_name]['all'])) + print(bar) + + if show_video_level and len(result) < 10: + print('\n\n') + header1 = "|{:^14}|".format("Tracker name") + header2 = "|{:^14}|".format("Video name") + for tracker_name in result.keys(): + header1 += ("{:^17}|").format(tracker_name) + header2 += "{:^8}|{:^8}|".format("Acc", "LN") + print('-'*len(header1)) + print(header1) + print('-'*len(header1)) + print(header2) + print('-'*len(header1)) + videos = list(result[tracker_name]['overlaps'].keys()) + for video in videos: + row = "|{:^14}|".format(video) + for tracker_name in result.keys(): + overlaps = result[tracker_name]['overlaps'][video] + accuracy = np.nanmean(overlaps) + failures = result[tracker_name]['failures'][video] + lost_number = np.mean(failures) + + accuracy_str = "{:^8.3f}".format(accuracy) + if accuracy < helight_threshold: + row += f'{Fore.RED}{accuracy_str}{Style.RESET_ALL}|' + else: + row += accuracy_str+'|' + lost_num_str = "{:^8.3f}".format(lost_number) + if lost_number > 0: + row += f'{Fore.RED}{lost_num_str}{Style.RESET_ALL}|' + else: + row += lost_num_str+'|' + print(row) + print('-'*len(header1)) + + def _calculate_accuracy_robustness(self, tracker_name): + overlaps = {} + failures = {} + all_length = {} + for i in range(len(self.dataset)): + video = self.dataset[i] + gt_traj = video.gt_traj + if tracker_name not in video.pred_trajs: + tracker_trajs = video.load_tracker(self.dataset.tracker_path, tracker_name, False) + else: + tracker_trajs = video.pred_trajs[tracker_name] + overlaps_group = [] + num_failures_group = [] + for tracker_traj in tracker_trajs: + num_failures = calculate_failures(tracker_traj)[0] + overlaps_ = calculate_accuracy(tracker_traj, gt_traj, + burnin=10, bound=(video.width, video.height))[1] + overlaps_group.append(overlaps_) + num_failures_group.append(num_failures) + with warnings.catch_warnings(): + warnings.simplefilter("ignore", category=RuntimeWarning) + overlaps[video.name] = np.nanmean(overlaps_group, axis=0).tolist() + failures[video.name] = num_failures_group + return overlaps, failures diff --git a/SiamMask/utils/pysot/evaluation/eao_benchmark.py b/SiamMask/utils/pysot/evaluation/eao_benchmark.py new file mode 100644 index 0000000000000000000000000000000000000000..848eafffdab66c7a72330c309a8601f6052dfa7e --- /dev/null +++ b/SiamMask/utils/pysot/evaluation/eao_benchmark.py @@ -0,0 +1,159 @@ +# -------------------------------------------------------- +# Python Single Object Tracking Evaluation +# Licensed under The MIT License [see LICENSE for details] +# Written by Fangyi Zhang +# @author fangyi.zhang@vipl.ict.ac.cn +# @project https://github.com/StrangerZhang/pysot-toolkit.git +# Revised for SiamMask by foolwood +# -------------------------------------------------------- +import numpy as np + +from ..utils import calculate_failures, calculate_accuracy, calculate_expected_overlap + + +class EAOBenchmark: + """ + Args: + dataset: + """ + def __init__(self, dataset, skipping=5, tags=['all']): + self.dataset = dataset + self.skipping = skipping + self.tags = tags + # NOTE we not use gmm to generate low, high, peak value + if dataset.name in ['VOT2019']: + self.low = 46 + self.high = 291 + self.peak = 128 + elif dataset.name in ['VOT2018', 'VOT2017']: + self.low = 100 + self.high = 356 + self.peak = 160 + elif dataset.name == 'VOT2016': + self.low = 100 # TODO + self.high = 356 + self.peak = 160 + + def eval(self, eval_trackers=None): + """ + Args: + eval_tags: list of tag + eval_trackers: list of tracker name + Returns: + eao: dict of results + """ + if eval_trackers is None: + eval_trackers = self.dataset.tracker_names + if isinstance(eval_trackers, str): + eval_trackers = [eval_trackers] + + ret = {} + for tracker_name in eval_trackers: + eao = self._calculate_eao(tracker_name, self.tags) + ret[tracker_name] = eao + return ret + + def show_result(self, result, topk=10): + """pretty print result + Args: + result: returned dict from function eval + """ + if len(self.tags) == 1: + tracker_name_len = max((max([len(x) for x in result.keys()])+2), 12) + header = ("|{:^"+str(tracker_name_len)+"}|{:^10}|").format('Tracker Name', 'EAO') + bar = '-'*len(header) + formatter = "|{:^20}|{:^10.3f}|" + print(bar) + print(header) + print(bar) + tracker_eao = sorted(result.items(), + key=lambda x: x[1]['all'], + reverse=True)[:topk] + for tracker_name, eao in tracker_eao: + print(formatter.format(tracker_name, eao)) + print(bar) + else: + header = "|{:^20}|".format('Tracker Name') + header += "{:^7}|{:^15}|{:^14}|{:^15}|{:^13}|{:^11}|{:^7}|".format(*self.tags) + bar = '-'*len(header) + formatter = "{:^7.3f}|{:^15.3f}|{:^14.3f}|{:^15.3f}|{:^13.3f}|{:^11.3f}|{:^7.3f}|" + print(bar) + print(header) + print(bar) + sorted_tacker = sorted(result.items(), + key=lambda x: x[1]['all'], + reverse=True)[:topk] + sorted_tacker = [x[0] for x in sorted_tacker] + for tracker_name in sorted_tacker: + print("|{:^20}|".format(tracker_name)+formatter.format( + *[result[tracker_name][x] for x in self.tags])) + print(bar) + + def _calculate_eao(self, tracker_name, tags): + all_overlaps = [] + all_failures = [] + video_names = [] + gt_traj_length = [] + for video in self.dataset: + gt_traj = video.gt_traj + if tracker_name not in video.pred_trajs: + tracker_trajs = video.load_tracker(self.dataset.tracker_path, tracker_name, False) + else: + tracker_trajs = video.pred_trajs[tracker_name] + for tracker_traj in tracker_trajs: + gt_traj_length.append(len(gt_traj)) + video_names.append(video.name) + overlaps = calculate_accuracy(tracker_traj, gt_traj, bound=(video.width-1, video.height-1))[1] + failures = calculate_failures(tracker_traj)[1] + all_overlaps.append(overlaps) + all_failures.append(failures) + fragment_num = sum([len(x)+1 for x in all_failures]) + max_len = max([len(x) for x in all_overlaps]) + seq_weight = 1 / len(tracker_trajs) + + eao = {} + for tag in tags: + # prepare segments + fweights = np.ones((fragment_num)) * np.nan + fragments = np.ones((fragment_num, max_len)) * np.nan + seg_counter = 0 + for name, traj_len, failures, overlaps in zip(video_names, gt_traj_length, + all_failures, all_overlaps): + if len(failures) > 0: + points = [x+self.skipping for x in failures if + x+self.skipping <= len(overlaps)] + points.insert(0, 0) + for i in range(len(points)): + if i != len(points) - 1: + fragment = np.array(overlaps[points[i]:points[i+1]+1]) + fragments[seg_counter, :] = 0 + else: + fragment = np.array(overlaps[points[i]:]) + fragment[np.isnan(fragment)] = 0 + fragments[seg_counter, :len(fragment)] = fragment + if i != len(points) - 1: + tag_value = self.dataset[name].select_tag(tag, points[i], points[i+1]+1) + w = sum(tag_value) / (points[i+1] - points[i]+1) + fweights[seg_counter] = seq_weight * w + else: + tag_value = self.dataset[name].select_tag(tag, points[i], len(overlaps)) + w = sum(tag_value) / (traj_len - points[i]+1e-16) + fweights[seg_counter] = seq_weight * w + seg_counter += 1 + else: + # no failure + max_idx = min(len(overlaps), max_len) + fragments[seg_counter, :max_idx] = overlaps[:max_idx] + tag_value = self.dataset[name].select_tag(tag, 0, max_idx) + w = sum(tag_value) / max_idx + fweights[seg_counter] = seq_weight * w + seg_counter += 1 + + expected_overlaps = calculate_expected_overlap(fragments, fweights) + # caculate eao + weight = np.zeros((len(expected_overlaps))) + weight[self.low-1:self.high-1+1] = 1 + is_valid = np.logical_not(np.isnan(expected_overlaps)) + eao_ = np.sum(expected_overlaps[is_valid] * weight[is_valid]) / np.sum(weight[is_valid]) + eao[tag] = eao_ + return eao diff --git a/SiamMask/utils/pysot/utils/__init__.py b/SiamMask/utils/pysot/utils/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..ffc725f5ddd7abb133f9a5d1e79d46b19a322fae --- /dev/null +++ b/SiamMask/utils/pysot/utils/__init__.py @@ -0,0 +1,10 @@ +# -------------------------------------------------------- +# Python Single Object Tracking Evaluation +# Licensed under The MIT License [see LICENSE for details] +# Written by Fangyi Zhang +# @author fangyi.zhang@vipl.ict.ac.cn +# @project https://github.com/StrangerZhang/pysot-toolkit.git +# Revised for SiamMask by foolwood +# -------------------------------------------------------- +from . import region +from .statistics import * diff --git a/SiamMask/utils/pysot/utils/build/temp.linux-x86_64-3.9/region.o b/SiamMask/utils/pysot/utils/build/temp.linux-x86_64-3.9/region.o new file mode 100644 index 0000000000000000000000000000000000000000..20ba262b58b9e21044730025dcfdeb325d3836f3 --- /dev/null +++ b/SiamMask/utils/pysot/utils/build/temp.linux-x86_64-3.9/region.o @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c16187e08b7dbba78c887037e2155ad5b791ab578f50142dd079ca000895e5ee +size 2300616 diff --git a/SiamMask/utils/pysot/utils/build/temp.linux-x86_64-3.9/src/region.o b/SiamMask/utils/pysot/utils/build/temp.linux-x86_64-3.9/src/region.o new file mode 100644 index 0000000000000000000000000000000000000000..630730faa68fcd7839f9c7151051b9950eac928a --- /dev/null +++ b/SiamMask/utils/pysot/utils/build/temp.linux-x86_64-3.9/src/region.o @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:14599dceeb9ab24f6ab4bf5a042bb1f55955599a1df097a2026243d58edc46f2 +size 81096 diff --git a/SiamMask/utils/pysot/utils/c_region.pxd b/SiamMask/utils/pysot/utils/c_region.pxd new file mode 100644 index 0000000000000000000000000000000000000000..1e4312ed21c9ade80ceed5d555aaab9887cd9ee5 --- /dev/null +++ b/SiamMask/utils/pysot/utils/c_region.pxd @@ -0,0 +1,50 @@ +cdef extern from "src/region.h": + ctypedef enum region_type "RegionType": + EMTPY + SPECIAL + RECTANGEL + POLYGON + MASK + + ctypedef struct region_bounds: + float top + float bottom + float left + float right + + ctypedef struct region_rectangle: + float x + float y + float width + float height + + # ctypedef struct region_mask: + # int x + # int y + # int width + # int height + # char *data + + ctypedef struct region_polygon: + int count + float *x + float *y + + ctypedef union region_container_data: + region_rectangle rectangle + region_polygon polygon + # region_mask mask + int special + + ctypedef struct region_container: + region_type type + region_container_data data + + # ctypedef struct region_overlap: + # float overlap + # float only1 + # float only2 + + # region_overlap region_compute_overlap(const region_container* ra, const region_container* rb, region_bounds bounds) + + float compute_polygon_overlap(const region_polygon* p1, const region_polygon* p2, float *only1, float *only2, region_bounds bounds) diff --git a/SiamMask/utils/pysot/utils/misc.py b/SiamMask/utils/pysot/utils/misc.py new file mode 100644 index 0000000000000000000000000000000000000000..9018652525e0864b15cc610156f373c43d84e210 --- /dev/null +++ b/SiamMask/utils/pysot/utils/misc.py @@ -0,0 +1,35 @@ +# -------------------------------------------------------- +# Python Single Object Tracking Evaluation +# Licensed under The MIT License [see LICENSE for details] +# Written by Fangyi Zhang +# @author fangyi.zhang@vipl.ict.ac.cn +# @project https://github.com/StrangerZhang/pysot-toolkit.git +# Revised for SiamMask by foolwood +# -------------------------------------------------------- +import numpy as np + +def determine_thresholds(confidence, resolution=100): + """choose threshold according to confidence + + Args: + confidence: list or numpy array or numpy array + reolution: number of threshold to choose + + Restures: + threshold: numpy array + """ + if isinstance(confidence, list): + confidence = np.array(confidence) + confidence = confidence.flatten() + confidence = confidence[~np.isnan(confidence)] + confidence.sort() + + assert len(confidence) > resolution and resolution > 2 + + thresholds = np.ones((resolution)) + thresholds[0] = - np.inf + thresholds[-1] = np.inf + delta = np.floor(len(confidence) / (resolution - 2)) + idxs = np.linspace(delta, len(confidence)-delta, resolution-2, dtype=np.int32) + thresholds[1:-1] = confidence[idxs] + return thresholds diff --git a/SiamMask/utils/pysot/utils/region.c b/SiamMask/utils/pysot/utils/region.c new file mode 100644 index 0000000000000000000000000000000000000000..61a7cc720e2f63e41c117fec4c2b90aacf30a54f --- /dev/null +++ b/SiamMask/utils/pysot/utils/region.c @@ -0,0 +1,13085 @@ +/* Generated by Cython 0.29.34 */ + +/* BEGIN: Cython Metadata +{ + "distutils": { + "depends": [ + "src/region.h" + ], + "include_dirs": [ + "src/", + "." + ], + "name": "region", + "sources": [ + "region.pyx", + "src/region.c" + ] + }, + "module_name": "region" +} +END: Cython Metadata */ + +#ifndef PY_SSIZE_T_CLEAN +#define PY_SSIZE_T_CLEAN +#endif /* PY_SSIZE_T_CLEAN */ +#include "Python.h" +#ifndef Py_PYTHON_H + #error Python headers needed to compile C extensions, please install development version of Python. +#elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000) + #error Cython requires Python 2.6+ or Python 3.3+. +#else +#define CYTHON_ABI "0_29_34" +#define CYTHON_HEX_VERSION 0x001D22F0 +#define CYTHON_FUTURE_DIVISION 0 +#include +#ifndef offsetof + #define offsetof(type, member) ( (size_t) & ((type*)0) -> member ) +#endif +#if !defined(WIN32) && !defined(MS_WINDOWS) + #ifndef __stdcall + #define __stdcall + #endif + #ifndef __cdecl + #define __cdecl + #endif + #ifndef __fastcall + #define __fastcall + #endif +#endif +#ifndef DL_IMPORT + #define DL_IMPORT(t) t +#endif +#ifndef DL_EXPORT + #define DL_EXPORT(t) t +#endif +#define __PYX_COMMA , +#ifndef HAVE_LONG_LONG + #if PY_VERSION_HEX >= 0x02070000 + #define HAVE_LONG_LONG + #endif +#endif +#ifndef PY_LONG_LONG + #define PY_LONG_LONG LONG_LONG +#endif +#ifndef Py_HUGE_VAL + #define Py_HUGE_VAL HUGE_VAL +#endif +#ifdef PYPY_VERSION + #define CYTHON_COMPILING_IN_PYPY 1 + #define CYTHON_COMPILING_IN_PYSTON 0 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_NOGIL 0 + #undef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 0 + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #if PY_VERSION_HEX < 0x03050000 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #elif !defined(CYTHON_USE_ASYNC_SLOTS) + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #undef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 0 + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #undef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 1 + #undef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 0 + #undef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 0 + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 0 + #undef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 0 + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 0 + #endif +#elif defined(PYSTON_VERSION) + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_PYSTON 1 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_NOGIL 0 + #ifndef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 1 + #endif + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #ifndef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 1 + #endif + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #ifndef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 0 + #endif + #ifndef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 1 + #endif + #ifndef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 1 + #endif + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 0 + #undef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 0 + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 0 + #endif +#elif defined(PY_NOGIL) + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_PYSTON 0 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_NOGIL 1 + #ifndef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 1 + #endif + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #ifndef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #ifndef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 1 + #endif + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #ifndef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 0 + #endif + #ifndef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 1 + #endif + #ifndef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 1 + #endif + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #ifndef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #endif + #ifndef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 1 + #endif + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 +#else + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_PYSTON 0 + #define CYTHON_COMPILING_IN_CPYTHON 1 + #define CYTHON_COMPILING_IN_NOGIL 0 + #ifndef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 1 + #endif + #if PY_VERSION_HEX < 0x02070000 + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #elif !defined(CYTHON_USE_PYTYPE_LOOKUP) + #define CYTHON_USE_PYTYPE_LOOKUP 1 + #endif + #if PY_MAJOR_VERSION < 3 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #elif !defined(CYTHON_USE_ASYNC_SLOTS) + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #if PY_VERSION_HEX < 0x02070000 + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #elif !defined(CYTHON_USE_PYLONG_INTERNALS) + #define CYTHON_USE_PYLONG_INTERNALS (PY_VERSION_HEX < 0x030C00A5) + #endif + #ifndef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 1 + #endif + #ifndef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 1 + #endif + #if PY_VERSION_HEX < 0x030300F0 || PY_VERSION_HEX >= 0x030B00A2 + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #elif !defined(CYTHON_USE_UNICODE_WRITER) + #define CYTHON_USE_UNICODE_WRITER 1 + #endif + #ifndef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 0 + #endif + #ifndef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 1 + #endif + #ifndef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 1 + #endif + #if PY_VERSION_HEX >= 0x030B00A4 + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #elif !defined(CYTHON_FAST_THREAD_STATE) + #define CYTHON_FAST_THREAD_STATE 1 + #endif + #ifndef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL (PY_VERSION_HEX < 0x030A0000) + #endif + #ifndef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT (PY_VERSION_HEX >= 0x03050000) + #endif + #ifndef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE (PY_VERSION_HEX >= 0x030400a1) + #endif + #ifndef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS ((PY_VERSION_HEX >= 0x030600B1) && (PY_VERSION_HEX < 0x030C00A5)) + #endif + #if PY_VERSION_HEX >= 0x030B00A4 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #elif !defined(CYTHON_USE_EXC_INFO_STACK) + #define CYTHON_USE_EXC_INFO_STACK (PY_VERSION_HEX >= 0x030700A3) + #endif + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 1 + #endif +#endif +#if !defined(CYTHON_FAST_PYCCALL) +#define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1) +#endif +#if CYTHON_USE_PYLONG_INTERNALS + #if PY_MAJOR_VERSION < 3 + #include "longintrepr.h" + #endif + #undef SHIFT + #undef BASE + #undef MASK + #ifdef SIZEOF_VOID_P + enum { __pyx_check_sizeof_voidp = 1 / (int)(SIZEOF_VOID_P == sizeof(void*)) }; + #endif +#endif +#ifndef __has_attribute + #define __has_attribute(x) 0 +#endif +#ifndef __has_cpp_attribute + #define __has_cpp_attribute(x) 0 +#endif +#ifndef CYTHON_RESTRICT + #if defined(__GNUC__) + #define CYTHON_RESTRICT __restrict__ + #elif defined(_MSC_VER) && _MSC_VER >= 1400 + #define CYTHON_RESTRICT __restrict + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define CYTHON_RESTRICT restrict + #else + #define CYTHON_RESTRICT + #endif +#endif +#ifndef CYTHON_UNUSED +# if defined(__GNUC__) +# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) +# define CYTHON_UNUSED __attribute__ ((__unused__)) +# else +# define CYTHON_UNUSED +# endif +# elif defined(__ICC) || (defined(__INTEL_COMPILER) && !defined(_MSC_VER)) +# define CYTHON_UNUSED __attribute__ ((__unused__)) +# else +# define CYTHON_UNUSED +# endif +#endif +#ifndef CYTHON_MAYBE_UNUSED_VAR +# if defined(__cplusplus) + template void CYTHON_MAYBE_UNUSED_VAR( const T& ) { } +# else +# define CYTHON_MAYBE_UNUSED_VAR(x) (void)(x) +# endif +#endif +#ifndef CYTHON_NCP_UNUSED +# if CYTHON_COMPILING_IN_CPYTHON +# define CYTHON_NCP_UNUSED +# else +# define CYTHON_NCP_UNUSED CYTHON_UNUSED +# endif +#endif +#define __Pyx_void_to_None(void_result) ((void)(void_result), Py_INCREF(Py_None), Py_None) +#ifdef _MSC_VER + #ifndef _MSC_STDINT_H_ + #if _MSC_VER < 1300 + typedef unsigned char uint8_t; + typedef unsigned int uint32_t; + #else + typedef unsigned __int8 uint8_t; + typedef unsigned __int32 uint32_t; + #endif + #endif +#else + #include +#endif +#ifndef CYTHON_FALLTHROUGH + #if defined(__cplusplus) && __cplusplus >= 201103L + #if __has_cpp_attribute(fallthrough) + #define CYTHON_FALLTHROUGH [[fallthrough]] + #elif __has_cpp_attribute(clang::fallthrough) + #define CYTHON_FALLTHROUGH [[clang::fallthrough]] + #elif __has_cpp_attribute(gnu::fallthrough) + #define CYTHON_FALLTHROUGH [[gnu::fallthrough]] + #endif + #endif + #ifndef CYTHON_FALLTHROUGH + #if __has_attribute(fallthrough) + #define CYTHON_FALLTHROUGH __attribute__((fallthrough)) + #else + #define CYTHON_FALLTHROUGH + #endif + #endif + #if defined(__clang__ ) && defined(__apple_build_version__) + #if __apple_build_version__ < 7000000 + #undef CYTHON_FALLTHROUGH + #define CYTHON_FALLTHROUGH + #endif + #endif +#endif + +#ifndef CYTHON_INLINE + #if defined(__clang__) + #define CYTHON_INLINE __inline__ __attribute__ ((__unused__)) + #elif defined(__GNUC__) + #define CYTHON_INLINE __inline__ + #elif defined(_MSC_VER) + #define CYTHON_INLINE __inline + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define CYTHON_INLINE inline + #else + #define CYTHON_INLINE + #endif +#endif + +#if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX < 0x02070600 && !defined(Py_OptimizeFlag) + #define Py_OptimizeFlag 0 +#endif +#define __PYX_BUILD_PY_SSIZE_T "n" +#define CYTHON_FORMAT_SSIZE_T "z" +#if PY_MAJOR_VERSION < 3 + #define __Pyx_BUILTIN_MODULE_NAME "__builtin__" + #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ + PyCode_New(a+k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) + #define __Pyx_DefaultClassType PyClass_Type +#else + #define __Pyx_BUILTIN_MODULE_NAME "builtins" + #define __Pyx_DefaultClassType PyType_Type +#if PY_VERSION_HEX >= 0x030B00A1 + static CYTHON_INLINE PyCodeObject* __Pyx_PyCode_New(int a, int k, int l, int s, int f, + PyObject *code, PyObject *c, PyObject* n, PyObject *v, + PyObject *fv, PyObject *cell, PyObject* fn, + PyObject *name, int fline, PyObject *lnos) { + PyObject *kwds=NULL, *argcount=NULL, *posonlyargcount=NULL, *kwonlyargcount=NULL; + PyObject *nlocals=NULL, *stacksize=NULL, *flags=NULL, *replace=NULL, *call_result=NULL, *empty=NULL; + const char *fn_cstr=NULL; + const char *name_cstr=NULL; + PyCodeObject* co=NULL; + PyObject *type, *value, *traceback; + PyErr_Fetch(&type, &value, &traceback); + if (!(kwds=PyDict_New())) goto end; + if (!(argcount=PyLong_FromLong(a))) goto end; + if (PyDict_SetItemString(kwds, "co_argcount", argcount) != 0) goto end; + if (!(posonlyargcount=PyLong_FromLong(0))) goto end; + if (PyDict_SetItemString(kwds, "co_posonlyargcount", posonlyargcount) != 0) goto end; + if (!(kwonlyargcount=PyLong_FromLong(k))) goto end; + if (PyDict_SetItemString(kwds, "co_kwonlyargcount", kwonlyargcount) != 0) goto end; + if (!(nlocals=PyLong_FromLong(l))) goto end; + if (PyDict_SetItemString(kwds, "co_nlocals", nlocals) != 0) goto end; + if (!(stacksize=PyLong_FromLong(s))) goto end; + if (PyDict_SetItemString(kwds, "co_stacksize", stacksize) != 0) goto end; + if (!(flags=PyLong_FromLong(f))) goto end; + if (PyDict_SetItemString(kwds, "co_flags", flags) != 0) goto end; + if (PyDict_SetItemString(kwds, "co_code", code) != 0) goto end; + if (PyDict_SetItemString(kwds, "co_consts", c) != 0) goto end; + if (PyDict_SetItemString(kwds, "co_names", n) != 0) goto end; + if (PyDict_SetItemString(kwds, "co_varnames", v) != 0) goto end; + if (PyDict_SetItemString(kwds, "co_freevars", fv) != 0) goto end; + if (PyDict_SetItemString(kwds, "co_cellvars", cell) != 0) goto end; + if (PyDict_SetItemString(kwds, "co_linetable", lnos) != 0) goto end; + if (!(fn_cstr=PyUnicode_AsUTF8AndSize(fn, NULL))) goto end; + if (!(name_cstr=PyUnicode_AsUTF8AndSize(name, NULL))) goto end; + if (!(co = PyCode_NewEmpty(fn_cstr, name_cstr, fline))) goto end; + if (!(replace = PyObject_GetAttrString((PyObject*)co, "replace"))) goto cleanup_code_too; + if (!(empty = PyTuple_New(0))) goto cleanup_code_too; // unfortunately __pyx_empty_tuple isn't available here + if (!(call_result = PyObject_Call(replace, empty, kwds))) goto cleanup_code_too; + Py_XDECREF((PyObject*)co); + co = (PyCodeObject*)call_result; + call_result = NULL; + if (0) { + cleanup_code_too: + Py_XDECREF((PyObject*)co); + co = NULL; + } + end: + Py_XDECREF(kwds); + Py_XDECREF(argcount); + Py_XDECREF(posonlyargcount); + Py_XDECREF(kwonlyargcount); + Py_XDECREF(nlocals); + Py_XDECREF(stacksize); + Py_XDECREF(replace); + Py_XDECREF(call_result); + Py_XDECREF(empty); + if (type) { + PyErr_Restore(type, value, traceback); + } + return co; + } +#else + #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ + PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) +#endif + #define __Pyx_DefaultClassType PyType_Type +#endif +#ifndef Py_TPFLAGS_CHECKTYPES + #define Py_TPFLAGS_CHECKTYPES 0 +#endif +#ifndef Py_TPFLAGS_HAVE_INDEX + #define Py_TPFLAGS_HAVE_INDEX 0 +#endif +#ifndef Py_TPFLAGS_HAVE_NEWBUFFER + #define Py_TPFLAGS_HAVE_NEWBUFFER 0 +#endif +#ifndef Py_TPFLAGS_HAVE_FINALIZE + #define Py_TPFLAGS_HAVE_FINALIZE 0 +#endif +#ifndef METH_STACKLESS + #define METH_STACKLESS 0 +#endif +#if PY_VERSION_HEX <= 0x030700A3 || !defined(METH_FASTCALL) + #ifndef METH_FASTCALL + #define METH_FASTCALL 0x80 + #endif + typedef PyObject *(*__Pyx_PyCFunctionFast) (PyObject *self, PyObject *const *args, Py_ssize_t nargs); + typedef PyObject *(*__Pyx_PyCFunctionFastWithKeywords) (PyObject *self, PyObject *const *args, + Py_ssize_t nargs, PyObject *kwnames); +#else + #define __Pyx_PyCFunctionFast _PyCFunctionFast + #define __Pyx_PyCFunctionFastWithKeywords _PyCFunctionFastWithKeywords +#endif +#if CYTHON_FAST_PYCCALL +#define __Pyx_PyFastCFunction_Check(func)\ + ((PyCFunction_Check(func) && (METH_FASTCALL == (PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST | METH_KEYWORDS | METH_STACKLESS))))) +#else +#define __Pyx_PyFastCFunction_Check(func) 0 +#endif +#if CYTHON_COMPILING_IN_PYPY && !defined(PyObject_Malloc) + #define PyObject_Malloc(s) PyMem_Malloc(s) + #define PyObject_Free(p) PyMem_Free(p) + #define PyObject_Realloc(p) PyMem_Realloc(p) +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030400A1 + #define PyMem_RawMalloc(n) PyMem_Malloc(n) + #define PyMem_RawRealloc(p, n) PyMem_Realloc(p, n) + #define PyMem_RawFree(p) PyMem_Free(p) +#endif +#if CYTHON_COMPILING_IN_PYSTON + #define __Pyx_PyCode_HasFreeVars(co) PyCode_HasFreeVars(co) + #define __Pyx_PyFrame_SetLineNumber(frame, lineno) PyFrame_SetLineNumber(frame, lineno) +#else + #define __Pyx_PyCode_HasFreeVars(co) (PyCode_GetNumFree(co) > 0) + #define __Pyx_PyFrame_SetLineNumber(frame, lineno) (frame)->f_lineno = (lineno) +#endif +#if !CYTHON_FAST_THREAD_STATE || PY_VERSION_HEX < 0x02070000 + #define __Pyx_PyThreadState_Current PyThreadState_GET() +#elif PY_VERSION_HEX >= 0x03060000 + #define __Pyx_PyThreadState_Current _PyThreadState_UncheckedGet() +#elif PY_VERSION_HEX >= 0x03000000 + #define __Pyx_PyThreadState_Current PyThreadState_GET() +#else + #define __Pyx_PyThreadState_Current _PyThreadState_Current +#endif +#if PY_VERSION_HEX < 0x030700A2 && !defined(PyThread_tss_create) && !defined(Py_tss_NEEDS_INIT) +#include "pythread.h" +#define Py_tss_NEEDS_INIT 0 +typedef int Py_tss_t; +static CYTHON_INLINE int PyThread_tss_create(Py_tss_t *key) { + *key = PyThread_create_key(); + return 0; +} +static CYTHON_INLINE Py_tss_t * PyThread_tss_alloc(void) { + Py_tss_t *key = (Py_tss_t *)PyObject_Malloc(sizeof(Py_tss_t)); + *key = Py_tss_NEEDS_INIT; + return key; +} +static CYTHON_INLINE void PyThread_tss_free(Py_tss_t *key) { + PyObject_Free(key); +} +static CYTHON_INLINE int PyThread_tss_is_created(Py_tss_t *key) { + return *key != Py_tss_NEEDS_INIT; +} +static CYTHON_INLINE void PyThread_tss_delete(Py_tss_t *key) { + PyThread_delete_key(*key); + *key = Py_tss_NEEDS_INIT; +} +static CYTHON_INLINE int PyThread_tss_set(Py_tss_t *key, void *value) { + return PyThread_set_key_value(*key, value); +} +static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { + return PyThread_get_key_value(*key); +} +#endif +#if CYTHON_COMPILING_IN_CPYTHON || defined(_PyDict_NewPresized) +#define __Pyx_PyDict_NewPresized(n) ((n <= 8) ? PyDict_New() : _PyDict_NewPresized(n)) +#else +#define __Pyx_PyDict_NewPresized(n) PyDict_New() +#endif +#if PY_MAJOR_VERSION >= 3 || CYTHON_FUTURE_DIVISION + #define __Pyx_PyNumber_Divide(x,y) PyNumber_TrueDivide(x,y) + #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceTrueDivide(x,y) +#else + #define __Pyx_PyNumber_Divide(x,y) PyNumber_Divide(x,y) + #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceDivide(x,y) +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030500A1 && CYTHON_USE_UNICODE_INTERNALS +#define __Pyx_PyDict_GetItemStr(dict, name) _PyDict_GetItem_KnownHash(dict, name, ((PyASCIIObject *) name)->hash) +#else +#define __Pyx_PyDict_GetItemStr(dict, name) PyDict_GetItem(dict, name) +#endif +#if PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND) + #define CYTHON_PEP393_ENABLED 1 + #if PY_VERSION_HEX >= 0x030C0000 + #define __Pyx_PyUnicode_READY(op) (0) + #else + #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\ + 0 : _PyUnicode_Ready((PyObject *)(op))) + #endif + #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_LENGTH(u) + #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) + #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u) + #define __Pyx_PyUnicode_KIND(u) PyUnicode_KIND(u) + #define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u) + #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) + #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, ch) + #if PY_VERSION_HEX >= 0x030C0000 + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_LENGTH(u)) + #else + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03090000 + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : ((PyCompactUnicodeObject *)(u))->wstr_length)) + #else + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u))) + #endif + #endif +#else + #define CYTHON_PEP393_ENABLED 0 + #define PyUnicode_1BYTE_KIND 1 + #define PyUnicode_2BYTE_KIND 2 + #define PyUnicode_4BYTE_KIND 4 + #define __Pyx_PyUnicode_READY(op) (0) + #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_SIZE(u) + #define __Pyx_PyUnicode_READ_CHAR(u, i) ((Py_UCS4)(PyUnicode_AS_UNICODE(u)[i])) + #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) ((sizeof(Py_UNICODE) == 2) ? 65535 : 1114111) + #define __Pyx_PyUnicode_KIND(u) (sizeof(Py_UNICODE)) + #define __Pyx_PyUnicode_DATA(u) ((void*)PyUnicode_AS_UNICODE(u)) + #define __Pyx_PyUnicode_READ(k, d, i) ((void)(k), (Py_UCS4)(((Py_UNICODE*)d)[i])) + #define __Pyx_PyUnicode_WRITE(k, d, i, ch) (((void)(k)), ((Py_UNICODE*)d)[i] = ch) + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_SIZE(u)) +#endif +#if CYTHON_COMPILING_IN_PYPY + #define __Pyx_PyUnicode_Concat(a, b) PyNumber_Add(a, b) + #define __Pyx_PyUnicode_ConcatSafe(a, b) PyNumber_Add(a, b) +#else + #define __Pyx_PyUnicode_Concat(a, b) PyUnicode_Concat(a, b) + #define __Pyx_PyUnicode_ConcatSafe(a, b) ((unlikely((a) == Py_None) || unlikely((b) == Py_None)) ?\ + PyNumber_Add(a, b) : __Pyx_PyUnicode_Concat(a, b)) +#endif +#if CYTHON_COMPILING_IN_PYPY && !defined(PyUnicode_Contains) + #define PyUnicode_Contains(u, s) PySequence_Contains(u, s) +#endif +#if CYTHON_COMPILING_IN_PYPY && !defined(PyByteArray_Check) + #define PyByteArray_Check(obj) PyObject_TypeCheck(obj, &PyByteArray_Type) +#endif +#if CYTHON_COMPILING_IN_PYPY && !defined(PyObject_Format) + #define PyObject_Format(obj, fmt) PyObject_CallMethod(obj, "__format__", "O", fmt) +#endif +#define __Pyx_PyString_FormatSafe(a, b) ((unlikely((a) == Py_None || (PyString_Check(b) && !PyString_CheckExact(b)))) ? PyNumber_Remainder(a, b) : __Pyx_PyString_Format(a, b)) +#define __Pyx_PyUnicode_FormatSafe(a, b) ((unlikely((a) == Py_None || (PyUnicode_Check(b) && !PyUnicode_CheckExact(b)))) ? PyNumber_Remainder(a, b) : PyUnicode_Format(a, b)) +#if PY_MAJOR_VERSION >= 3 + #define __Pyx_PyString_Format(a, b) PyUnicode_Format(a, b) +#else + #define __Pyx_PyString_Format(a, b) PyString_Format(a, b) +#endif +#if PY_MAJOR_VERSION < 3 && !defined(PyObject_ASCII) + #define PyObject_ASCII(o) PyObject_Repr(o) +#endif +#if PY_MAJOR_VERSION >= 3 + #define PyBaseString_Type PyUnicode_Type + #define PyStringObject PyUnicodeObject + #define PyString_Type PyUnicode_Type + #define PyString_Check PyUnicode_Check + #define PyString_CheckExact PyUnicode_CheckExact +#ifndef PyObject_Unicode + #define PyObject_Unicode PyObject_Str +#endif +#endif +#if PY_MAJOR_VERSION >= 3 + #define __Pyx_PyBaseString_Check(obj) PyUnicode_Check(obj) + #define __Pyx_PyBaseString_CheckExact(obj) PyUnicode_CheckExact(obj) +#else + #define __Pyx_PyBaseString_Check(obj) (PyString_Check(obj) || PyUnicode_Check(obj)) + #define __Pyx_PyBaseString_CheckExact(obj) (PyString_CheckExact(obj) || PyUnicode_CheckExact(obj)) +#endif +#ifndef PySet_CheckExact + #define PySet_CheckExact(obj) (Py_TYPE(obj) == &PySet_Type) +#endif +#if PY_VERSION_HEX >= 0x030900A4 + #define __Pyx_SET_REFCNT(obj, refcnt) Py_SET_REFCNT(obj, refcnt) + #define __Pyx_SET_SIZE(obj, size) Py_SET_SIZE(obj, size) +#else + #define __Pyx_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt) + #define __Pyx_SET_SIZE(obj, size) Py_SIZE(obj) = (size) +#endif +#if CYTHON_ASSUME_SAFE_MACROS + #define __Pyx_PySequence_SIZE(seq) Py_SIZE(seq) +#else + #define __Pyx_PySequence_SIZE(seq) PySequence_Size(seq) +#endif +#if PY_MAJOR_VERSION >= 3 + #define PyIntObject PyLongObject + #define PyInt_Type PyLong_Type + #define PyInt_Check(op) PyLong_Check(op) + #define PyInt_CheckExact(op) PyLong_CheckExact(op) + #define PyInt_FromString PyLong_FromString + #define PyInt_FromUnicode PyLong_FromUnicode + #define PyInt_FromLong PyLong_FromLong + #define PyInt_FromSize_t PyLong_FromSize_t + #define PyInt_FromSsize_t PyLong_FromSsize_t + #define PyInt_AsLong PyLong_AsLong + #define PyInt_AS_LONG PyLong_AS_LONG + #define PyInt_AsSsize_t PyLong_AsSsize_t + #define PyInt_AsUnsignedLongMask PyLong_AsUnsignedLongMask + #define PyInt_AsUnsignedLongLongMask PyLong_AsUnsignedLongLongMask + #define PyNumber_Int PyNumber_Long +#endif +#if PY_MAJOR_VERSION >= 3 + #define PyBoolObject PyLongObject +#endif +#if PY_MAJOR_VERSION >= 3 && CYTHON_COMPILING_IN_PYPY + #ifndef PyUnicode_InternFromString + #define PyUnicode_InternFromString(s) PyUnicode_FromString(s) + #endif +#endif +#if PY_VERSION_HEX < 0x030200A4 + typedef long Py_hash_t; + #define __Pyx_PyInt_FromHash_t PyInt_FromLong + #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsHash_t +#else + #define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t + #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsSsize_t +#endif +#if PY_MAJOR_VERSION >= 3 + #define __Pyx_PyMethod_New(func, self, klass) ((self) ? ((void)(klass), PyMethod_New(func, self)) : __Pyx_NewRef(func)) +#else + #define __Pyx_PyMethod_New(func, self, klass) PyMethod_New(func, self, klass) +#endif +#if CYTHON_USE_ASYNC_SLOTS + #if PY_VERSION_HEX >= 0x030500B1 + #define __Pyx_PyAsyncMethodsStruct PyAsyncMethods + #define __Pyx_PyType_AsAsync(obj) (Py_TYPE(obj)->tp_as_async) + #else + #define __Pyx_PyType_AsAsync(obj) ((__Pyx_PyAsyncMethodsStruct*) (Py_TYPE(obj)->tp_reserved)) + #endif +#else + #define __Pyx_PyType_AsAsync(obj) NULL +#endif +#ifndef __Pyx_PyAsyncMethodsStruct + typedef struct { + unaryfunc am_await; + unaryfunc am_aiter; + unaryfunc am_anext; + } __Pyx_PyAsyncMethodsStruct; +#endif + +#if defined(_WIN32) || defined(WIN32) || defined(MS_WINDOWS) + #if !defined(_USE_MATH_DEFINES) + #define _USE_MATH_DEFINES + #endif +#endif +#include +#ifdef NAN +#define __PYX_NAN() ((float) NAN) +#else +static CYTHON_INLINE float __PYX_NAN() { + float value; + memset(&value, 0xFF, sizeof(value)); + return value; +} +#endif +#if defined(__CYGWIN__) && defined(_LDBL_EQ_DBL) +#define __Pyx_truncl trunc +#else +#define __Pyx_truncl truncl +#endif + +#define __PYX_MARK_ERR_POS(f_index, lineno) \ + { __pyx_filename = __pyx_f[f_index]; (void)__pyx_filename; __pyx_lineno = lineno; (void)__pyx_lineno; __pyx_clineno = __LINE__; (void)__pyx_clineno; } +#define __PYX_ERR(f_index, lineno, Ln_error) \ + { __PYX_MARK_ERR_POS(f_index, lineno) goto Ln_error; } + +#ifndef __PYX_EXTERN_C + #ifdef __cplusplus + #define __PYX_EXTERN_C extern "C" + #else + #define __PYX_EXTERN_C extern + #endif +#endif + +#define __PYX_HAVE__region +#define __PYX_HAVE_API__region +/* Early includes */ +#include +#include +#include +#include "src/region.h" +#ifdef _OPENMP +#include +#endif /* _OPENMP */ + +#if defined(PYREX_WITHOUT_ASSERTIONS) && !defined(CYTHON_WITHOUT_ASSERTIONS) +#define CYTHON_WITHOUT_ASSERTIONS +#endif + +typedef struct {PyObject **p; const char *s; const Py_ssize_t n; const char* encoding; + const char is_unicode; const char is_str; const char intern; } __Pyx_StringTabEntry; + +#define __PYX_DEFAULT_STRING_ENCODING_IS_ASCII 0 +#define __PYX_DEFAULT_STRING_ENCODING_IS_UTF8 0 +#define __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT (PY_MAJOR_VERSION >= 3 && __PYX_DEFAULT_STRING_ENCODING_IS_UTF8) +#define __PYX_DEFAULT_STRING_ENCODING "" +#define __Pyx_PyObject_FromString __Pyx_PyBytes_FromString +#define __Pyx_PyObject_FromStringAndSize __Pyx_PyBytes_FromStringAndSize +#define __Pyx_uchar_cast(c) ((unsigned char)c) +#define __Pyx_long_cast(x) ((long)x) +#define __Pyx_fits_Py_ssize_t(v, type, is_signed) (\ + (sizeof(type) < sizeof(Py_ssize_t)) ||\ + (sizeof(type) > sizeof(Py_ssize_t) &&\ + likely(v < (type)PY_SSIZE_T_MAX ||\ + v == (type)PY_SSIZE_T_MAX) &&\ + (!is_signed || likely(v > (type)PY_SSIZE_T_MIN ||\ + v == (type)PY_SSIZE_T_MIN))) ||\ + (sizeof(type) == sizeof(Py_ssize_t) &&\ + (is_signed || likely(v < (type)PY_SSIZE_T_MAX ||\ + v == (type)PY_SSIZE_T_MAX))) ) +static CYTHON_INLINE int __Pyx_is_valid_index(Py_ssize_t i, Py_ssize_t limit) { + return (size_t) i < (size_t) limit; +} +#if defined (__cplusplus) && __cplusplus >= 201103L + #include + #define __Pyx_sst_abs(value) std::abs(value) +#elif SIZEOF_INT >= SIZEOF_SIZE_T + #define __Pyx_sst_abs(value) abs(value) +#elif SIZEOF_LONG >= SIZEOF_SIZE_T + #define __Pyx_sst_abs(value) labs(value) +#elif defined (_MSC_VER) + #define __Pyx_sst_abs(value) ((Py_ssize_t)_abs64(value)) +#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define __Pyx_sst_abs(value) llabs(value) +#elif defined (__GNUC__) + #define __Pyx_sst_abs(value) __builtin_llabs(value) +#else + #define __Pyx_sst_abs(value) ((value<0) ? -value : value) +#endif +static CYTHON_INLINE const char* __Pyx_PyObject_AsString(PyObject*); +static CYTHON_INLINE const char* __Pyx_PyObject_AsStringAndSize(PyObject*, Py_ssize_t* length); +#define __Pyx_PyByteArray_FromString(s) PyByteArray_FromStringAndSize((const char*)s, strlen((const char*)s)) +#define __Pyx_PyByteArray_FromStringAndSize(s, l) PyByteArray_FromStringAndSize((const char*)s, l) +#define __Pyx_PyBytes_FromString PyBytes_FromString +#define __Pyx_PyBytes_FromStringAndSize PyBytes_FromStringAndSize +static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char*); +#if PY_MAJOR_VERSION < 3 + #define __Pyx_PyStr_FromString __Pyx_PyBytes_FromString + #define __Pyx_PyStr_FromStringAndSize __Pyx_PyBytes_FromStringAndSize +#else + #define __Pyx_PyStr_FromString __Pyx_PyUnicode_FromString + #define __Pyx_PyStr_FromStringAndSize __Pyx_PyUnicode_FromStringAndSize +#endif +#define __Pyx_PyBytes_AsWritableString(s) ((char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsWritableSString(s) ((signed char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsWritableUString(s) ((unsigned char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsString(s) ((const char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsSString(s) ((const signed char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsUString(s) ((const unsigned char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyObject_AsWritableString(s) ((char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsWritableSString(s) ((signed char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsWritableUString(s) ((unsigned char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsSString(s) ((const signed char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsUString(s) ((const unsigned char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_FromCString(s) __Pyx_PyObject_FromString((const char*)s) +#define __Pyx_PyBytes_FromCString(s) __Pyx_PyBytes_FromString((const char*)s) +#define __Pyx_PyByteArray_FromCString(s) __Pyx_PyByteArray_FromString((const char*)s) +#define __Pyx_PyStr_FromCString(s) __Pyx_PyStr_FromString((const char*)s) +#define __Pyx_PyUnicode_FromCString(s) __Pyx_PyUnicode_FromString((const char*)s) +static CYTHON_INLINE size_t __Pyx_Py_UNICODE_strlen(const Py_UNICODE *u) { + const Py_UNICODE *u_end = u; + while (*u_end++) ; + return (size_t)(u_end - u - 1); +} +#define __Pyx_PyUnicode_FromUnicode(u) PyUnicode_FromUnicode(u, __Pyx_Py_UNICODE_strlen(u)) +#define __Pyx_PyUnicode_FromUnicodeAndLength PyUnicode_FromUnicode +#define __Pyx_PyUnicode_AsUnicode PyUnicode_AsUnicode +#define __Pyx_NewRef(obj) (Py_INCREF(obj), obj) +#define __Pyx_Owned_Py_None(b) __Pyx_NewRef(Py_None) +static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b); +static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*); +static CYTHON_INLINE int __Pyx_PyObject_IsTrueAndDecref(PyObject*); +static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x); +#define __Pyx_PySequence_Tuple(obj)\ + (likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj)) +static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); +static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); +static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject*); +#if CYTHON_ASSUME_SAFE_MACROS +#define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) +#else +#define __pyx_PyFloat_AsDouble(x) PyFloat_AsDouble(x) +#endif +#define __pyx_PyFloat_AsFloat(x) ((float) __pyx_PyFloat_AsDouble(x)) +#if PY_MAJOR_VERSION >= 3 +#define __Pyx_PyNumber_Int(x) (PyLong_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Long(x)) +#else +#define __Pyx_PyNumber_Int(x) (PyInt_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Int(x)) +#endif +#define __Pyx_PyNumber_Float(x) (PyFloat_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Float(x)) +#if PY_MAJOR_VERSION < 3 && __PYX_DEFAULT_STRING_ENCODING_IS_ASCII +static int __Pyx_sys_getdefaultencoding_not_ascii; +static int __Pyx_init_sys_getdefaultencoding_params(void) { + PyObject* sys; + PyObject* default_encoding = NULL; + PyObject* ascii_chars_u = NULL; + PyObject* ascii_chars_b = NULL; + const char* default_encoding_c; + sys = PyImport_ImportModule("sys"); + if (!sys) goto bad; + default_encoding = PyObject_CallMethod(sys, (char*) "getdefaultencoding", NULL); + Py_DECREF(sys); + if (!default_encoding) goto bad; + default_encoding_c = PyBytes_AsString(default_encoding); + if (!default_encoding_c) goto bad; + if (strcmp(default_encoding_c, "ascii") == 0) { + __Pyx_sys_getdefaultencoding_not_ascii = 0; + } else { + char ascii_chars[128]; + int c; + for (c = 0; c < 128; c++) { + ascii_chars[c] = c; + } + __Pyx_sys_getdefaultencoding_not_ascii = 1; + ascii_chars_u = PyUnicode_DecodeASCII(ascii_chars, 128, NULL); + if (!ascii_chars_u) goto bad; + ascii_chars_b = PyUnicode_AsEncodedString(ascii_chars_u, default_encoding_c, NULL); + if (!ascii_chars_b || !PyBytes_Check(ascii_chars_b) || memcmp(ascii_chars, PyBytes_AS_STRING(ascii_chars_b), 128) != 0) { + PyErr_Format( + PyExc_ValueError, + "This module compiled with c_string_encoding=ascii, but default encoding '%.200s' is not a superset of ascii.", + default_encoding_c); + goto bad; + } + Py_DECREF(ascii_chars_u); + Py_DECREF(ascii_chars_b); + } + Py_DECREF(default_encoding); + return 0; +bad: + Py_XDECREF(default_encoding); + Py_XDECREF(ascii_chars_u); + Py_XDECREF(ascii_chars_b); + return -1; +} +#endif +#if __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT && PY_MAJOR_VERSION >= 3 +#define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_DecodeUTF8(c_str, size, NULL) +#else +#define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_Decode(c_str, size, __PYX_DEFAULT_STRING_ENCODING, NULL) +#if __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT +static char* __PYX_DEFAULT_STRING_ENCODING; +static int __Pyx_init_sys_getdefaultencoding_params(void) { + PyObject* sys; + PyObject* default_encoding = NULL; + char* default_encoding_c; + sys = PyImport_ImportModule("sys"); + if (!sys) goto bad; + default_encoding = PyObject_CallMethod(sys, (char*) (const char*) "getdefaultencoding", NULL); + Py_DECREF(sys); + if (!default_encoding) goto bad; + default_encoding_c = PyBytes_AsString(default_encoding); + if (!default_encoding_c) goto bad; + __PYX_DEFAULT_STRING_ENCODING = (char*) malloc(strlen(default_encoding_c) + 1); + if (!__PYX_DEFAULT_STRING_ENCODING) goto bad; + strcpy(__PYX_DEFAULT_STRING_ENCODING, default_encoding_c); + Py_DECREF(default_encoding); + return 0; +bad: + Py_XDECREF(default_encoding); + return -1; +} +#endif +#endif + + +/* Test for GCC > 2.95 */ +#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95))) + #define likely(x) __builtin_expect(!!(x), 1) + #define unlikely(x) __builtin_expect(!!(x), 0) +#else /* !__GNUC__ or GCC < 2.95 */ + #define likely(x) (x) + #define unlikely(x) (x) +#endif /* __GNUC__ */ +static CYTHON_INLINE void __Pyx_pretend_to_initialize(void* ptr) { (void)ptr; } + +static PyObject *__pyx_m = NULL; +static PyObject *__pyx_d; +static PyObject *__pyx_b; +static PyObject *__pyx_cython_runtime = NULL; +static PyObject *__pyx_empty_tuple; +static PyObject *__pyx_empty_bytes; +static PyObject *__pyx_empty_unicode; +static int __pyx_lineno; +static int __pyx_clineno = 0; +static const char * __pyx_cfilenm= __FILE__; +static const char *__pyx_filename; + + +static const char *__pyx_f[] = { + "region.pyx", + "stringsource", +}; + +/*--- Type declarations ---*/ +struct __pyx_obj_6region_RegionBounds; +struct __pyx_obj_6region_Rectangle; +struct __pyx_obj_6region_Polygon; +struct __pyx_obj___Pyx_EnumMeta; + +/* "region.pyx":19 + * cimport c_region + * + * cpdef enum RegionType: # <<<<<<<<<<<<<< + * EMTPY + * SPECIAL + */ +enum __pyx_t_6region_RegionType { + __pyx_e_6region_EMTPY, + __pyx_e_6region_SPECIAL, + __pyx_e_6region_RECTANGEL, + __pyx_e_6region_POLYGON, + __pyx_e_6region_MASK +}; + +/* "region.pyx":26 + * MASK + * + * cdef class RegionBounds: # <<<<<<<<<<<<<< + * cdef c_region.region_bounds* _c_region_bounds + * + */ +struct __pyx_obj_6region_RegionBounds { + PyObject_HEAD + region_bounds *_c_region_bounds; +}; + + +/* "region.pyx":63 + * self._c_region_bounds.right = right + * + * cdef class Rectangle: # <<<<<<<<<<<<<< + * cdef c_region.region_rectangle* _c_region_rectangle + * + */ +struct __pyx_obj_6region_Rectangle { + PyObject_HEAD + region_rectangle *_c_region_rectangle; +}; + + +/* "region.pyx":104 + * self._c_region_rectangle.height) + * + * cdef class Polygon: # <<<<<<<<<<<<<< + * cdef c_region.region_polygon* _c_region_polygon + * + */ +struct __pyx_obj_6region_Polygon { + PyObject_HEAD + region_polygon *_c_region_polygon; +}; + + +/* "EnumBase":15 + * + * @cython.internal + * cdef class __Pyx_EnumMeta(type): # <<<<<<<<<<<<<< + * def __init__(cls, name, parents, dct): + * type.__init__(cls, name, parents, dct) + */ +struct __pyx_obj___Pyx_EnumMeta { + PyHeapTypeObject __pyx_base; +}; + + +/* --- Runtime support code (head) --- */ +/* Refnanny.proto */ +#ifndef CYTHON_REFNANNY + #define CYTHON_REFNANNY 0 +#endif +#if CYTHON_REFNANNY + typedef struct { + void (*INCREF)(void*, PyObject*, int); + void (*DECREF)(void*, PyObject*, int); + void (*GOTREF)(void*, PyObject*, int); + void (*GIVEREF)(void*, PyObject*, int); + void* (*SetupContext)(const char*, int, const char*); + void (*FinishContext)(void**); + } __Pyx_RefNannyAPIStruct; + static __Pyx_RefNannyAPIStruct *__Pyx_RefNanny = NULL; + static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname); + #define __Pyx_RefNannyDeclarations void *__pyx_refnanny = NULL; +#ifdef WITH_THREAD + #define __Pyx_RefNannySetupContext(name, acquire_gil)\ + if (acquire_gil) {\ + PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__);\ + PyGILState_Release(__pyx_gilstate_save);\ + } else {\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__);\ + } +#else + #define __Pyx_RefNannySetupContext(name, acquire_gil)\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__) +#endif + #define __Pyx_RefNannyFinishContext()\ + __Pyx_RefNanny->FinishContext(&__pyx_refnanny) + #define __Pyx_INCREF(r) __Pyx_RefNanny->INCREF(__pyx_refnanny, (PyObject *)(r), __LINE__) + #define __Pyx_DECREF(r) __Pyx_RefNanny->DECREF(__pyx_refnanny, (PyObject *)(r), __LINE__) + #define __Pyx_GOTREF(r) __Pyx_RefNanny->GOTREF(__pyx_refnanny, (PyObject *)(r), __LINE__) + #define __Pyx_GIVEREF(r) __Pyx_RefNanny->GIVEREF(__pyx_refnanny, (PyObject *)(r), __LINE__) + #define __Pyx_XINCREF(r) do { if((r) != NULL) {__Pyx_INCREF(r); }} while(0) + #define __Pyx_XDECREF(r) do { if((r) != NULL) {__Pyx_DECREF(r); }} while(0) + #define __Pyx_XGOTREF(r) do { if((r) != NULL) {__Pyx_GOTREF(r); }} while(0) + #define __Pyx_XGIVEREF(r) do { if((r) != NULL) {__Pyx_GIVEREF(r);}} while(0) +#else + #define __Pyx_RefNannyDeclarations + #define __Pyx_RefNannySetupContext(name, acquire_gil) + #define __Pyx_RefNannyFinishContext() + #define __Pyx_INCREF(r) Py_INCREF(r) + #define __Pyx_DECREF(r) Py_DECREF(r) + #define __Pyx_GOTREF(r) + #define __Pyx_GIVEREF(r) + #define __Pyx_XINCREF(r) Py_XINCREF(r) + #define __Pyx_XDECREF(r) Py_XDECREF(r) + #define __Pyx_XGOTREF(r) + #define __Pyx_XGIVEREF(r) +#endif +#define __Pyx_XDECREF_SET(r, v) do {\ + PyObject *tmp = (PyObject *) r;\ + r = v; __Pyx_XDECREF(tmp);\ + } while (0) +#define __Pyx_DECREF_SET(r, v) do {\ + PyObject *tmp = (PyObject *) r;\ + r = v; __Pyx_DECREF(tmp);\ + } while (0) +#define __Pyx_CLEAR(r) do { PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);} while(0) +#define __Pyx_XCLEAR(r) do { if((r) != NULL) {PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);}} while(0) + +/* PyObjectGetAttrStr.proto */ +#if CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name); +#else +#define __Pyx_PyObject_GetAttrStr(o,n) PyObject_GetAttr(o,n) +#endif + +/* GetBuiltinName.proto */ +static PyObject *__Pyx_GetBuiltinName(PyObject *name); + +/* RaiseArgTupleInvalid.proto */ +static void __Pyx_RaiseArgtupleInvalid(const char* func_name, int exact, + Py_ssize_t num_min, Py_ssize_t num_max, Py_ssize_t num_found); + +/* KeywordStringCheck.proto */ +static int __Pyx_CheckKeywordStrings(PyObject *kwdict, const char* function_name, int kw_allowed); + +/* RaiseDoubleKeywords.proto */ +static void __Pyx_RaiseDoubleKeywordsError(const char* func_name, PyObject* kw_name); + +/* ParseKeywords.proto */ +static int __Pyx_ParseOptionalKeywords(PyObject *kwds, PyObject **argnames[],\ + PyObject *kwds2, PyObject *values[], Py_ssize_t num_pos_args,\ + const char* function_name); + +/* PyFunctionFastCall.proto */ +#if CYTHON_FAST_PYCALL +#define __Pyx_PyFunction_FastCall(func, args, nargs)\ + __Pyx_PyFunction_FastCallDict((func), (args), (nargs), NULL) +#if 1 || PY_VERSION_HEX < 0x030600B1 +static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, PyObject *kwargs); +#else +#define __Pyx_PyFunction_FastCallDict(func, args, nargs, kwargs) _PyFunction_FastCallDict(func, args, nargs, kwargs) +#endif +#define __Pyx_BUILD_ASSERT_EXPR(cond)\ + (sizeof(char [1 - 2*!(cond)]) - 1) +#ifndef Py_MEMBER_SIZE +#define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member) +#endif +#if CYTHON_FAST_PYCALL + static size_t __pyx_pyframe_localsplus_offset = 0; + #include "frameobject.h" +#if PY_VERSION_HEX >= 0x030b00a6 + #ifndef Py_BUILD_CORE + #define Py_BUILD_CORE 1 + #endif + #include "internal/pycore_frame.h" +#endif + #define __Pxy_PyFrame_Initialize_Offsets()\ + ((void)__Pyx_BUILD_ASSERT_EXPR(sizeof(PyFrameObject) == offsetof(PyFrameObject, f_localsplus) + Py_MEMBER_SIZE(PyFrameObject, f_localsplus)),\ + (void)(__pyx_pyframe_localsplus_offset = ((size_t)PyFrame_Type.tp_basicsize) - Py_MEMBER_SIZE(PyFrameObject, f_localsplus))) + #define __Pyx_PyFrame_GetLocalsplus(frame)\ + (assert(__pyx_pyframe_localsplus_offset), (PyObject **)(((char *)(frame)) + __pyx_pyframe_localsplus_offset)) +#endif // CYTHON_FAST_PYCALL +#endif + +/* PyCFunctionFastCall.proto */ +#if CYTHON_FAST_PYCCALL +static CYTHON_INLINE PyObject *__Pyx_PyCFunction_FastCall(PyObject *func, PyObject **args, Py_ssize_t nargs); +#else +#define __Pyx_PyCFunction_FastCall(func, args, nargs) (assert(0), NULL) +#endif + +/* PyObjectCall.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw); +#else +#define __Pyx_PyObject_Call(func, arg, kw) PyObject_Call(func, arg, kw) +#endif + +/* PyThreadStateGet.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyThreadState_declare PyThreadState *__pyx_tstate; +#define __Pyx_PyThreadState_assign __pyx_tstate = __Pyx_PyThreadState_Current; +#define __Pyx_PyErr_Occurred() __pyx_tstate->curexc_type +#else +#define __Pyx_PyThreadState_declare +#define __Pyx_PyThreadState_assign +#define __Pyx_PyErr_Occurred() PyErr_Occurred() +#endif + +/* PyErrFetchRestore.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyErr_Clear() __Pyx_ErrRestore(NULL, NULL, NULL) +#define __Pyx_ErrRestoreWithState(type, value, tb) __Pyx_ErrRestoreInState(PyThreadState_GET(), type, value, tb) +#define __Pyx_ErrFetchWithState(type, value, tb) __Pyx_ErrFetchInState(PyThreadState_GET(), type, value, tb) +#define __Pyx_ErrRestore(type, value, tb) __Pyx_ErrRestoreInState(__pyx_tstate, type, value, tb) +#define __Pyx_ErrFetch(type, value, tb) __Pyx_ErrFetchInState(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb); +static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#if CYTHON_COMPILING_IN_CPYTHON +#define __Pyx_PyErr_SetNone(exc) (Py_INCREF(exc), __Pyx_ErrRestore((exc), NULL, NULL)) +#else +#define __Pyx_PyErr_SetNone(exc) PyErr_SetNone(exc) +#endif +#else +#define __Pyx_PyErr_Clear() PyErr_Clear() +#define __Pyx_PyErr_SetNone(exc) PyErr_SetNone(exc) +#define __Pyx_ErrRestoreWithState(type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetchWithState(type, value, tb) PyErr_Fetch(type, value, tb) +#define __Pyx_ErrRestoreInState(tstate, type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetchInState(tstate, type, value, tb) PyErr_Fetch(type, value, tb) +#define __Pyx_ErrRestore(type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetch(type, value, tb) PyErr_Fetch(type, value, tb) +#endif + +/* RaiseException.proto */ +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause); + +/* DivInt[Py_ssize_t].proto */ +static CYTHON_INLINE Py_ssize_t __Pyx_div_Py_ssize_t(Py_ssize_t, Py_ssize_t); + +/* PyObjectCallMethO.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg); +#endif + +/* PyObjectCallOneArg.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg); + +/* GetItemInt.proto */ +#define __Pyx_GetItemInt(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_GetItemInt_Fast(o, (Py_ssize_t)i, is_list, wraparound, boundscheck) :\ + (is_list ? (PyErr_SetString(PyExc_IndexError, "list index out of range"), (PyObject*)NULL) :\ + __Pyx_GetItemInt_Generic(o, to_py_func(i)))) +#define __Pyx_GetItemInt_List(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_GetItemInt_List_Fast(o, (Py_ssize_t)i, wraparound, boundscheck) :\ + (PyErr_SetString(PyExc_IndexError, "list index out of range"), (PyObject*)NULL)) +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i, + int wraparound, int boundscheck); +#define __Pyx_GetItemInt_Tuple(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_GetItemInt_Tuple_Fast(o, (Py_ssize_t)i, wraparound, boundscheck) :\ + (PyErr_SetString(PyExc_IndexError, "tuple index out of range"), (PyObject*)NULL)) +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i, + int wraparound, int boundscheck); +static PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j); +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, + int is_list, int wraparound, int boundscheck); + +/* ObjectGetItem.proto */ +#if CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PyObject *__Pyx_PyObject_GetItem(PyObject *obj, PyObject* key); +#else +#define __Pyx_PyObject_GetItem(obj, key) PyObject_GetItem(obj, key) +#endif + +/* PyIntBinop.proto */ +#if !CYTHON_COMPILING_IN_PYPY +static PyObject* __Pyx_PyInt_AddObjC(PyObject *op1, PyObject *op2, long intval, int inplace, int zerodivision_check); +#else +#define __Pyx_PyInt_AddObjC(op1, op2, intval, inplace, zerodivision_check)\ + (inplace ? PyNumber_InPlaceAdd(op1, op2) : PyNumber_Add(op1, op2)) +#endif + +/* pyobject_as_double.proto */ +static double __Pyx__PyObject_AsDouble(PyObject* obj); +#if CYTHON_COMPILING_IN_PYPY +#define __Pyx_PyObject_AsDouble(obj)\ +(likely(PyFloat_CheckExact(obj)) ? PyFloat_AS_DOUBLE(obj) :\ + likely(PyInt_CheckExact(obj)) ?\ + PyFloat_AsDouble(obj) : __Pyx__PyObject_AsDouble(obj)) +#else +#define __Pyx_PyObject_AsDouble(obj)\ +((likely(PyFloat_CheckExact(obj))) ?\ + PyFloat_AS_DOUBLE(obj) : __Pyx__PyObject_AsDouble(obj)) +#endif + +/* PyDictVersioning.proto */ +#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_TYPE_SLOTS +#define __PYX_DICT_VERSION_INIT ((PY_UINT64_T) -1) +#define __PYX_GET_DICT_VERSION(dict) (((PyDictObject*)(dict))->ma_version_tag) +#define __PYX_UPDATE_DICT_CACHE(dict, value, cache_var, version_var)\ + (version_var) = __PYX_GET_DICT_VERSION(dict);\ + (cache_var) = (value); +#define __PYX_PY_DICT_LOOKUP_IF_MODIFIED(VAR, DICT, LOOKUP) {\ + static PY_UINT64_T __pyx_dict_version = 0;\ + static PyObject *__pyx_dict_cached_value = NULL;\ + if (likely(__PYX_GET_DICT_VERSION(DICT) == __pyx_dict_version)) {\ + (VAR) = __pyx_dict_cached_value;\ + } else {\ + (VAR) = __pyx_dict_cached_value = (LOOKUP);\ + __pyx_dict_version = __PYX_GET_DICT_VERSION(DICT);\ + }\ +} +static CYTHON_INLINE PY_UINT64_T __Pyx_get_tp_dict_version(PyObject *obj); +static CYTHON_INLINE PY_UINT64_T __Pyx_get_object_dict_version(PyObject *obj); +static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UINT64_T tp_dict_version, PY_UINT64_T obj_dict_version); +#else +#define __PYX_GET_DICT_VERSION(dict) (0) +#define __PYX_UPDATE_DICT_CACHE(dict, value, cache_var, version_var) +#define __PYX_PY_DICT_LOOKUP_IF_MODIFIED(VAR, DICT, LOOKUP) (VAR) = (LOOKUP); +#endif + +/* GetModuleGlobalName.proto */ +#if CYTHON_USE_DICT_VERSIONS +#define __Pyx_GetModuleGlobalName(var, name) do {\ + static PY_UINT64_T __pyx_dict_version = 0;\ + static PyObject *__pyx_dict_cached_value = NULL;\ + (var) = (likely(__pyx_dict_version == __PYX_GET_DICT_VERSION(__pyx_d))) ?\ + (likely(__pyx_dict_cached_value) ? __Pyx_NewRef(__pyx_dict_cached_value) : __Pyx_GetBuiltinName(name)) :\ + __Pyx__GetModuleGlobalName(name, &__pyx_dict_version, &__pyx_dict_cached_value);\ +} while(0) +#define __Pyx_GetModuleGlobalNameUncached(var, name) do {\ + PY_UINT64_T __pyx_dict_version;\ + PyObject *__pyx_dict_cached_value;\ + (var) = __Pyx__GetModuleGlobalName(name, &__pyx_dict_version, &__pyx_dict_cached_value);\ +} while(0) +static PyObject *__Pyx__GetModuleGlobalName(PyObject *name, PY_UINT64_T *dict_version, PyObject **dict_cached_value); +#else +#define __Pyx_GetModuleGlobalName(var, name) (var) = __Pyx__GetModuleGlobalName(name) +#define __Pyx_GetModuleGlobalNameUncached(var, name) (var) = __Pyx__GetModuleGlobalName(name) +static CYTHON_INLINE PyObject *__Pyx__GetModuleGlobalName(PyObject *name); +#endif + +/* ListAppend.proto */ +#if CYTHON_USE_PYLIST_INTERNALS && CYTHON_ASSUME_SAFE_MACROS +static CYTHON_INLINE int __Pyx_PyList_Append(PyObject* list, PyObject* x) { + PyListObject* L = (PyListObject*) list; + Py_ssize_t len = Py_SIZE(list); + if (likely(L->allocated > len) & likely(len > (L->allocated >> 1))) { + Py_INCREF(x); + PyList_SET_ITEM(list, len, x); + __Pyx_SET_SIZE(list, len + 1); + return 0; + } + return PyList_Append(list, x); +} +#else +#define __Pyx_PyList_Append(L,x) PyList_Append(L,x) +#endif + +/* PyObjectCallNoArg.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func); +#else +#define __Pyx_PyObject_CallNoArg(func) __Pyx_PyObject_Call(func, __pyx_empty_tuple, NULL) +#endif + +/* IncludeStringH.proto */ +#include + +/* decode_c_string_utf16.proto */ +static CYTHON_INLINE PyObject *__Pyx_PyUnicode_DecodeUTF16(const char *s, Py_ssize_t size, const char *errors) { + int byteorder = 0; + return PyUnicode_DecodeUTF16(s, size, errors, &byteorder); +} +static CYTHON_INLINE PyObject *__Pyx_PyUnicode_DecodeUTF16LE(const char *s, Py_ssize_t size, const char *errors) { + int byteorder = -1; + return PyUnicode_DecodeUTF16(s, size, errors, &byteorder); +} +static CYTHON_INLINE PyObject *__Pyx_PyUnicode_DecodeUTF16BE(const char *s, Py_ssize_t size, const char *errors) { + int byteorder = 1; + return PyUnicode_DecodeUTF16(s, size, errors, &byteorder); +} + +/* decode_c_string.proto */ +static CYTHON_INLINE PyObject* __Pyx_decode_c_string( + const char* cstring, Py_ssize_t start, Py_ssize_t stop, + const char* encoding, const char* errors, + PyObject* (*decode_func)(const char *s, Py_ssize_t size, const char *errors)); + +/* GetException.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_GetException(type, value, tb) __Pyx__GetException(__pyx_tstate, type, value, tb) +static int __Pyx__GetException(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#else +static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb); +#endif + +/* SwapException.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_ExceptionSwap(type, value, tb) __Pyx__ExceptionSwap(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx__ExceptionSwap(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#else +static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value, PyObject **tb); +#endif + +/* GetTopmostException.proto */ +#if CYTHON_USE_EXC_INFO_STACK +static _PyErr_StackItem * __Pyx_PyErr_GetTopmostException(PyThreadState *tstate); +#endif + +/* SaveResetException.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_ExceptionSave(type, value, tb) __Pyx__ExceptionSave(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx__ExceptionSave(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#define __Pyx_ExceptionReset(type, value, tb) __Pyx__ExceptionReset(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb); +#else +#define __Pyx_ExceptionSave(type, value, tb) PyErr_GetExcInfo(type, value, tb) +#define __Pyx_ExceptionReset(type, value, tb) PyErr_SetExcInfo(type, value, tb) +#endif + +/* PyObjectSetAttrStr.proto */ +#if CYTHON_USE_TYPE_SLOTS +#define __Pyx_PyObject_DelAttrStr(o,n) __Pyx_PyObject_SetAttrStr(o, n, NULL) +static CYTHON_INLINE int __Pyx_PyObject_SetAttrStr(PyObject* obj, PyObject* attr_name, PyObject* value); +#else +#define __Pyx_PyObject_DelAttrStr(o,n) PyObject_DelAttr(o,n) +#define __Pyx_PyObject_SetAttrStr(o,n,v) PyObject_SetAttr(o,n,v) +#endif + +/* PyErrExceptionMatches.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyErr_ExceptionMatches(err) __Pyx_PyErr_ExceptionMatchesInState(__pyx_tstate, err) +static CYTHON_INLINE int __Pyx_PyErr_ExceptionMatchesInState(PyThreadState* tstate, PyObject* err); +#else +#define __Pyx_PyErr_ExceptionMatches(err) PyErr_ExceptionMatches(err) +#endif + +/* GetAttr.proto */ +static CYTHON_INLINE PyObject *__Pyx_GetAttr(PyObject *, PyObject *); + +/* GetAttr3.proto */ +static CYTHON_INLINE PyObject *__Pyx_GetAttr3(PyObject *, PyObject *, PyObject *); + +/* PySequenceContains.proto */ +static CYTHON_INLINE int __Pyx_PySequence_ContainsTF(PyObject* item, PyObject* seq, int eq) { + int result = PySequence_Contains(seq, item); + return unlikely(result < 0) ? result : (result == (eq == Py_EQ)); +} + +/* Import.proto */ +static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level); + +/* ImportFrom.proto */ +static PyObject* __Pyx_ImportFrom(PyObject* module, PyObject* name); + +/* PyObjectCall2Args.proto */ +static CYTHON_UNUSED PyObject* __Pyx_PyObject_Call2Args(PyObject* function, PyObject* arg1, PyObject* arg2); + +/* HasAttr.proto */ +static CYTHON_INLINE int __Pyx_HasAttr(PyObject *, PyObject *); + +/* PyObject_GenericGetAttrNoDict.proto */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static CYTHON_INLINE PyObject* __Pyx_PyObject_GenericGetAttrNoDict(PyObject* obj, PyObject* attr_name); +#else +#define __Pyx_PyObject_GenericGetAttrNoDict PyObject_GenericGetAttr +#endif + +/* PyObject_GenericGetAttr.proto */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_name); +#else +#define __Pyx_PyObject_GenericGetAttr PyObject_GenericGetAttr +#endif + +/* PyObjectGetAttrStrNoError.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name); + +/* SetupReduce.proto */ +static int __Pyx_setup_reduce(PyObject* type_obj); + +/* CalculateMetaclass.proto */ +static PyObject *__Pyx_CalculateMetaclass(PyTypeObject *metaclass, PyObject *bases); + +/* SetNameInClass.proto */ +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030500A1 +#define __Pyx_SetNameInClass(ns, name, value)\ + (likely(PyDict_CheckExact(ns)) ? _PyDict_SetItem_KnownHash(ns, name, value, ((PyASCIIObject *) name)->hash) : PyObject_SetItem(ns, name, value)) +#elif CYTHON_COMPILING_IN_CPYTHON +#define __Pyx_SetNameInClass(ns, name, value)\ + (likely(PyDict_CheckExact(ns)) ? PyDict_SetItem(ns, name, value) : PyObject_SetItem(ns, name, value)) +#else +#define __Pyx_SetNameInClass(ns, name, value) PyObject_SetItem(ns, name, value) +#endif + +/* FetchCommonType.proto */ +static PyTypeObject* __Pyx_FetchCommonType(PyTypeObject* type); + +/* CythonFunctionShared.proto */ +#define __Pyx_CyFunction_USED 1 +#define __Pyx_CYFUNCTION_STATICMETHOD 0x01 +#define __Pyx_CYFUNCTION_CLASSMETHOD 0x02 +#define __Pyx_CYFUNCTION_CCLASS 0x04 +#define __Pyx_CyFunction_GetClosure(f)\ + (((__pyx_CyFunctionObject *) (f))->func_closure) +#define __Pyx_CyFunction_GetClassObj(f)\ + (((__pyx_CyFunctionObject *) (f))->func_classobj) +#define __Pyx_CyFunction_Defaults(type, f)\ + ((type *)(((__pyx_CyFunctionObject *) (f))->defaults)) +#define __Pyx_CyFunction_SetDefaultsGetter(f, g)\ + ((__pyx_CyFunctionObject *) (f))->defaults_getter = (g) +typedef struct { + PyCFunctionObject func; +#if PY_VERSION_HEX < 0x030500A0 + PyObject *func_weakreflist; +#endif + PyObject *func_dict; + PyObject *func_name; + PyObject *func_qualname; + PyObject *func_doc; + PyObject *func_globals; + PyObject *func_code; + PyObject *func_closure; + PyObject *func_classobj; + void *defaults; + int defaults_pyobjects; + size_t defaults_size; // used by FusedFunction for copying defaults + int flags; + PyObject *defaults_tuple; + PyObject *defaults_kwdict; + PyObject *(*defaults_getter)(PyObject *); + PyObject *func_annotations; +} __pyx_CyFunctionObject; +static PyTypeObject *__pyx_CyFunctionType = 0; +#define __Pyx_CyFunction_Check(obj) (__Pyx_TypeCheck(obj, __pyx_CyFunctionType)) +static PyObject *__Pyx_CyFunction_Init(__pyx_CyFunctionObject* op, PyMethodDef *ml, + int flags, PyObject* qualname, + PyObject *self, + PyObject *module, PyObject *globals, + PyObject* code); +static CYTHON_INLINE void *__Pyx_CyFunction_InitDefaults(PyObject *m, + size_t size, + int pyobjects); +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsTuple(PyObject *m, + PyObject *tuple); +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsKwDict(PyObject *m, + PyObject *dict); +static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *m, + PyObject *dict); +static int __pyx_CyFunction_init(void); + +/* CythonFunction.proto */ +static PyObject *__Pyx_CyFunction_New(PyMethodDef *ml, + int flags, PyObject* qualname, + PyObject *closure, + PyObject *module, PyObject *globals, + PyObject* code); + +/* Py3ClassCreate.proto */ +static PyObject *__Pyx_Py3MetaclassPrepare(PyObject *metaclass, PyObject *bases, PyObject *name, PyObject *qualname, + PyObject *mkw, PyObject *modname, PyObject *doc); +static PyObject *__Pyx_Py3ClassCreate(PyObject *metaclass, PyObject *name, PyObject *bases, PyObject *dict, + PyObject *mkw, int calculate_metaclass, int allow_py2_metaclass); + +/* Globals.proto */ +static PyObject* __Pyx_Globals(void); + +/* CLineInTraceback.proto */ +#ifdef CYTHON_CLINE_IN_TRACEBACK +#define __Pyx_CLineForTraceback(tstate, c_line) (((CYTHON_CLINE_IN_TRACEBACK)) ? c_line : 0) +#else +static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line); +#endif + +/* CodeObjectCache.proto */ +typedef struct { + PyCodeObject* code_object; + int code_line; +} __Pyx_CodeObjectCacheEntry; +struct __Pyx_CodeObjectCache { + int count; + int max_count; + __Pyx_CodeObjectCacheEntry* entries; +}; +static struct __Pyx_CodeObjectCache __pyx_code_cache = {0,0,NULL}; +static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line); +static PyCodeObject *__pyx_find_code_object(int code_line); +static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object); + +/* AddTraceback.proto */ +static void __Pyx_AddTraceback(const char *funcname, int c_line, + int py_line, const char *filename); + +/* GCCDiagnostics.proto */ +#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) +#define __Pyx_HAS_GCC_DIAGNOSTIC +#endif + +/* CIntFromPy.proto */ +static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); + +/* CIntFromPy.proto */ +static CYTHON_INLINE size_t __Pyx_PyInt_As_size_t(PyObject *); + +/* CIntToPy.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); + +/* CIntFromPy.proto */ +static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *); + +/* CIntToPy.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum____pyx_t_6region_RegionType(enum __pyx_t_6region_RegionType value); + +/* FastTypeChecks.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +#define __Pyx_TypeCheck(obj, type) __Pyx_IsSubtype(Py_TYPE(obj), (PyTypeObject *)type) +static CYTHON_INLINE int __Pyx_IsSubtype(PyTypeObject *a, PyTypeObject *b); +static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches(PyObject *err, PyObject *type); +static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches2(PyObject *err, PyObject *type1, PyObject *type2); +#else +#define __Pyx_TypeCheck(obj, type) PyObject_TypeCheck(obj, (PyTypeObject *)type) +#define __Pyx_PyErr_GivenExceptionMatches(err, type) PyErr_GivenExceptionMatches(err, type) +#define __Pyx_PyErr_GivenExceptionMatches2(err, type1, type2) (PyErr_GivenExceptionMatches(err, type1) || PyErr_GivenExceptionMatches(err, type2)) +#endif +#define __Pyx_PyException_Check(obj) __Pyx_TypeCheck(obj, PyExc_Exception) + +/* CheckBinaryVersion.proto */ +static int __Pyx_check_binary_version(void); + +/* InitStrings.proto */ +static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); + + +/* Module declarations from 'libc.string' */ + +/* Module declarations from 'libc.stdlib' */ + +/* Module declarations from 'libc.stdio' */ + +/* Module declarations from 'c_region' */ + +/* Module declarations from 'region' */ +static PyTypeObject *__pyx_ptype_6region_RegionBounds = 0; +static PyTypeObject *__pyx_ptype_6region_Rectangle = 0; +static PyTypeObject *__pyx_ptype_6region_Polygon = 0; +static PyTypeObject *__pyx_ptype___Pyx_EnumMeta = 0; +static PyObject *__Pyx_OrderedDict = 0; +static PyObject *__Pyx_EnumBase = 0; +static PyObject *__Pyx_globals = 0; +static PyObject *__pyx_unpickle___Pyx_EnumMeta__set_state(struct __pyx_obj___Pyx_EnumMeta *, PyObject *); /*proto*/ +#define __Pyx_MODULE_NAME "region" +extern int __pyx_module_is_main_region; +int __pyx_module_is_main_region = 0; + +/* Implementation of 'region' */ +static PyObject *__pyx_builtin_MemoryError; +static PyObject *__pyx_builtin_TypeError; +static PyObject *__pyx_builtin_range; +static PyObject *__pyx_builtin_ValueError; +static const char __pyx_k_i[] = "i"; +static const char __pyx_k_v[] = "v"; +static const char __pyx_k_x[] = "x"; +static const char __pyx_k_y[] = "y"; +static const char __pyx_k__5[] = ""; +static const char __pyx_k_cls[] = "cls"; +static const char __pyx_k_dct[] = "dct"; +static const char __pyx_k_doc[] = "__doc__"; +static const char __pyx_k_inf[] = "inf"; +static const char __pyx_k_nan[] = "nan"; +static const char __pyx_k_new[] = "__new__"; +static const char __pyx_k_res[] = "res"; +static const char __pyx_k_ret[] = "ret"; +static const char __pyx_k_s_s[] = "%s.%s"; +static const char __pyx_k_set[] = "set"; +static const char __pyx_k_str[] = "__str__"; +static const char __pyx_k_top[] = "top"; +static const char __pyx_k_MASK[] = "MASK"; +static const char __pyx_k_dict[] = "__dict__"; +static const char __pyx_k_enum[] = "enum"; +static const char __pyx_k_init[] = "__init__"; +static const char __pyx_k_left[] = "left"; +static const char __pyx_k_main[] = "__main__"; +static const char __pyx_k_name[] = "name"; +static const char __pyx_k_repr[] = "__repr__"; +static const char __pyx_k_self[] = "self"; +static const char __pyx_k_test[] = "__test__"; +static const char __pyx_k_3f_3f[] = "({:.3f} {:.3f}) "; +static const char __pyx_k_EMTPY[] = "EMTPY"; +static const char __pyx_k_class[] = "__class__"; +static const char __pyx_k_only1[] = "only1"; +static const char __pyx_k_only2[] = "only2"; +static const char __pyx_k_range[] = "range"; +static const char __pyx_k_right[] = "right"; +static const char __pyx_k_s_s_d[] = "<%s.%s: %d>"; +static const char __pyx_k_value[] = "value"; +static const char __pyx_k_width[] = "width"; +static const char __pyx_k_bottom[] = "bottom"; +static const char __pyx_k_bounds[] = "bounds"; +static const char __pyx_k_encode[] = "encode"; +static const char __pyx_k_format[] = "format"; +static const char __pyx_k_height[] = "height"; +static const char __pyx_k_import[] = "__import__"; +static const char __pyx_k_module[] = "__module__"; +static const char __pyx_k_name_2[] = "__name__"; +static const char __pyx_k_output[] = "output"; +static const char __pyx_k_pickle[] = "pickle"; +static const char __pyx_k_points[] = "points"; +static const char __pyx_k_reduce[] = "__reduce__"; +static const char __pyx_k_region[] = "region"; +static const char __pyx_k_update[] = "update"; +static const char __pyx_k_values[] = "values"; +static const char __pyx_k_3f_3f_2[] = "({:.3f} {:.3f})"; +static const char __pyx_k_IntEnum[] = "IntEnum"; +static const char __pyx_k_POLYGON[] = "POLYGON"; +static const char __pyx_k_Polygon[] = "Polygon"; +static const char __pyx_k_SPECIAL[] = "SPECIAL"; +static const char __pyx_k_members[] = "__members__"; +static const char __pyx_k_overlap[] = "overlap"; +static const char __pyx_k_parents[] = "parents"; +static const char __pyx_k_prepare[] = "__prepare__"; +static const char __pyx_k_EnumBase[] = "EnumBase"; +static const char __pyx_k_EnumType[] = "EnumType"; +static const char __pyx_k_getstate[] = "__getstate__"; +static const char __pyx_k_overlaps[] = "overlaps"; +static const char __pyx_k_polygon1[] = "polygon1"; +static const char __pyx_k_polygon2[] = "polygon2"; +static const char __pyx_k_pyx_type[] = "__pyx_type"; +static const char __pyx_k_qualname[] = "__qualname__"; +static const char __pyx_k_setstate[] = "__setstate__"; +static const char __pyx_k_template[] = "template"; +static const char __pyx_k_RECTANGEL[] = "RECTANGEL"; +static const char __pyx_k_Rectangle[] = "Rectangle"; +static const char __pyx_k_TypeError[] = "TypeError"; +static const char __pyx_k_ctemplate[] = "ctemplate"; +static const char __pyx_k_metaclass[] = "__metaclass__"; +static const char __pyx_k_no_bounds[] = "no_bounds"; +static const char __pyx_k_polygons1[] = "polygons1"; +static const char __pyx_k_polygons2[] = "polygons2"; +static const char __pyx_k_ptemplate[] = "ptemplate"; +static const char __pyx_k_pyx_state[] = "__pyx_state"; +static const char __pyx_k_reduce_ex[] = "__reduce_ex__"; +static const char __pyx_k_RegionType[] = "RegionType"; +static const char __pyx_k_ValueError[] = "ValueError"; +static const char __pyx_k_c_polygon1[] = "c_polygon1"; +static const char __pyx_k_c_polygon2[] = "c_polygon2"; +static const char __pyx_k_pno_bounds[] = "pno_bounds"; +static const char __pyx_k_polygon1_2[] = "polygon1_"; +static const char __pyx_k_polygon2_2[] = "polygon2_"; +static const char __pyx_k_pyx_result[] = "__pyx_result"; +static const char __pyx_k_region_pyx[] = "region.pyx"; +static const char __pyx_k_MemoryError[] = "MemoryError"; +static const char __pyx_k_OrderedDict[] = "OrderedDict"; +static const char __pyx_k_PickleError[] = "PickleError"; +static const char __pyx_k_collections[] = "collections"; +static const char __pyx_k_vot_overlap[] = "vot_overlap"; +static const char __pyx_k_Pyx_EnumBase[] = "__Pyx_EnumBase"; +static const char __pyx_k_RegionBounds[] = "RegionBounds"; +static const char __pyx_k_pyx_checksum[] = "__pyx_checksum"; +static const char __pyx_k_stringsource[] = "stringsource"; +static const char __pyx_k_reduce_cython[] = "__reduce_cython__"; +static const char __pyx_k_vot_float2str[] = "vot_float2str"; +static const char __pyx_k_pyx_PickleError[] = "__pyx_PickleError"; +static const char __pyx_k_setstate_cython[] = "__setstate_cython__"; +static const char __pyx_k_vot_overlap_traj[] = "vot_overlap_traj"; +static const char __pyx_k_Pyx_EnumBase___new[] = "__Pyx_EnumBase.__new__"; +static const char __pyx_k_Pyx_EnumBase___str[] = "__Pyx_EnumBase.__str__"; +static const char __pyx_k_cline_in_traceback[] = "cline_in_traceback"; +static const char __pyx_k_Pyx_EnumBase___repr[] = "__Pyx_EnumBase.__repr__"; +static const char __pyx_k_Unknown_enum_value_s[] = "Unknown enum value: '%s'"; +static const char __pyx_k_pyx_unpickle___Pyx_EnumMeta[] = "__pyx_unpickle___Pyx_EnumMeta"; +static const char __pyx_k_x_3f_y_3f_width_3f_height_3f[] = "x: {:.3f} y: {:.3f} width: {:.3f} height: {:.3f}"; +static const char __pyx_k_top_3f_bottom_3f_left_3f_reight[] = "top: {:.3f} bottom: {:.3f} left: {:.3f} reight: {:.3f}"; +static const char __pyx_k_Incompatible_checksums_0x_x_vs_0[] = "Incompatible checksums (0x%x vs (0xd41d8cd, 0xe3b0c44, 0xda39a3e) = ())"; +static const char __pyx_k_no_default___reduce___due_to_non[] = "no default __reduce__ due to non-trivial __cinit__"; +static PyObject *__pyx_kp_s_3f_3f; +static PyObject *__pyx_kp_s_3f_3f_2; +static PyObject *__pyx_n_s_EMTPY; +static PyObject *__pyx_n_s_EnumBase; +static PyObject *__pyx_n_s_EnumType; +static PyObject *__pyx_kp_s_Incompatible_checksums_0x_x_vs_0; +static PyObject *__pyx_n_s_IntEnum; +static PyObject *__pyx_n_s_MASK; +static PyObject *__pyx_n_s_MemoryError; +static PyObject *__pyx_n_s_OrderedDict; +static PyObject *__pyx_n_s_POLYGON; +static PyObject *__pyx_n_s_PickleError; +static PyObject *__pyx_n_s_Polygon; +static PyObject *__pyx_n_s_Pyx_EnumBase; +static PyObject *__pyx_n_s_Pyx_EnumBase___new; +static PyObject *__pyx_n_s_Pyx_EnumBase___repr; +static PyObject *__pyx_n_s_Pyx_EnumBase___str; +static PyObject *__pyx_n_s_RECTANGEL; +static PyObject *__pyx_n_s_Rectangle; +static PyObject *__pyx_n_s_RegionBounds; +static PyObject *__pyx_n_s_RegionType; +static PyObject *__pyx_n_s_SPECIAL; +static PyObject *__pyx_n_s_TypeError; +static PyObject *__pyx_kp_s_Unknown_enum_value_s; +static PyObject *__pyx_n_s_ValueError; +static PyObject *__pyx_kp_s__5; +static PyObject *__pyx_n_s_bottom; +static PyObject *__pyx_n_s_bounds; +static PyObject *__pyx_n_s_c_polygon1; +static PyObject *__pyx_n_s_c_polygon2; +static PyObject *__pyx_n_s_class; +static PyObject *__pyx_n_s_cline_in_traceback; +static PyObject *__pyx_n_s_cls; +static PyObject *__pyx_n_s_collections; +static PyObject *__pyx_n_s_ctemplate; +static PyObject *__pyx_n_s_dct; +static PyObject *__pyx_n_s_dict; +static PyObject *__pyx_n_s_doc; +static PyObject *__pyx_n_s_encode; +static PyObject *__pyx_n_s_enum; +static PyObject *__pyx_n_s_format; +static PyObject *__pyx_n_s_getstate; +static PyObject *__pyx_n_s_height; +static PyObject *__pyx_n_s_i; +static PyObject *__pyx_n_s_import; +static PyObject *__pyx_n_s_inf; +static PyObject *__pyx_n_s_init; +static PyObject *__pyx_n_s_left; +static PyObject *__pyx_n_s_main; +static PyObject *__pyx_n_s_members; +static PyObject *__pyx_n_s_metaclass; +static PyObject *__pyx_n_s_module; +static PyObject *__pyx_n_s_name; +static PyObject *__pyx_n_s_name_2; +static PyObject *__pyx_n_s_nan; +static PyObject *__pyx_n_s_new; +static PyObject *__pyx_n_s_no_bounds; +static PyObject *__pyx_kp_s_no_default___reduce___due_to_non; +static PyObject *__pyx_n_s_only1; +static PyObject *__pyx_n_s_only2; +static PyObject *__pyx_n_s_output; +static PyObject *__pyx_n_s_overlap; +static PyObject *__pyx_n_s_overlaps; +static PyObject *__pyx_n_s_parents; +static PyObject *__pyx_n_s_pickle; +static PyObject *__pyx_n_s_pno_bounds; +static PyObject *__pyx_n_s_points; +static PyObject *__pyx_n_s_polygon1; +static PyObject *__pyx_n_s_polygon1_2; +static PyObject *__pyx_n_s_polygon2; +static PyObject *__pyx_n_s_polygon2_2; +static PyObject *__pyx_n_s_polygons1; +static PyObject *__pyx_n_s_polygons2; +static PyObject *__pyx_n_s_prepare; +static PyObject *__pyx_n_s_ptemplate; +static PyObject *__pyx_n_s_pyx_PickleError; +static PyObject *__pyx_n_s_pyx_checksum; +static PyObject *__pyx_n_s_pyx_result; +static PyObject *__pyx_n_s_pyx_state; +static PyObject *__pyx_n_s_pyx_type; +static PyObject *__pyx_n_s_pyx_unpickle___Pyx_EnumMeta; +static PyObject *__pyx_n_s_qualname; +static PyObject *__pyx_n_s_range; +static PyObject *__pyx_n_s_reduce; +static PyObject *__pyx_n_s_reduce_cython; +static PyObject *__pyx_n_s_reduce_ex; +static PyObject *__pyx_n_s_region; +static PyObject *__pyx_kp_s_region_pyx; +static PyObject *__pyx_n_s_repr; +static PyObject *__pyx_n_s_res; +static PyObject *__pyx_n_s_ret; +static PyObject *__pyx_n_s_right; +static PyObject *__pyx_kp_s_s_s; +static PyObject *__pyx_kp_s_s_s_d; +static PyObject *__pyx_n_s_self; +static PyObject *__pyx_n_s_set; +static PyObject *__pyx_n_s_setstate; +static PyObject *__pyx_n_s_setstate_cython; +static PyObject *__pyx_n_s_str; +static PyObject *__pyx_kp_s_stringsource; +static PyObject *__pyx_n_s_template; +static PyObject *__pyx_n_s_test; +static PyObject *__pyx_n_s_top; +static PyObject *__pyx_kp_s_top_3f_bottom_3f_left_3f_reight; +static PyObject *__pyx_n_s_update; +static PyObject *__pyx_n_s_v; +static PyObject *__pyx_n_s_value; +static PyObject *__pyx_n_s_values; +static PyObject *__pyx_n_s_vot_float2str; +static PyObject *__pyx_n_s_vot_overlap; +static PyObject *__pyx_n_s_vot_overlap_traj; +static PyObject *__pyx_n_s_width; +static PyObject *__pyx_n_s_x; +static PyObject *__pyx_kp_s_x_3f_y_3f_width_3f_height_3f; +static PyObject *__pyx_n_s_y; +static int __pyx_pf_6region_12RegionBounds___cinit__(struct __pyx_obj_6region_RegionBounds *__pyx_v_self); /* proto */ +static int __pyx_pf_6region_12RegionBounds_2__init__(struct __pyx_obj_6region_RegionBounds *__pyx_v_self, PyObject *__pyx_v_top, PyObject *__pyx_v_bottom, PyObject *__pyx_v_left, PyObject *__pyx_v_right); /* proto */ +static void __pyx_pf_6region_12RegionBounds_4__dealloc__(struct __pyx_obj_6region_RegionBounds *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_6region_12RegionBounds_6__str__(struct __pyx_obj_6region_RegionBounds *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_6region_12RegionBounds_8get(struct __pyx_obj_6region_RegionBounds *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_6region_12RegionBounds_10set(struct __pyx_obj_6region_RegionBounds *__pyx_v_self, PyObject *__pyx_v_top, PyObject *__pyx_v_bottom, PyObject *__pyx_v_left, PyObject *__pyx_v_right); /* proto */ +static PyObject *__pyx_pf_6region_12RegionBounds_12__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_6region_RegionBounds *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_6region_12RegionBounds_14__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_6region_RegionBounds *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */ +static int __pyx_pf_6region_9Rectangle___cinit__(struct __pyx_obj_6region_Rectangle *__pyx_v_self); /* proto */ +static int __pyx_pf_6region_9Rectangle_2__init__(struct __pyx_obj_6region_Rectangle *__pyx_v_self, PyObject *__pyx_v_x, PyObject *__pyx_v_y, PyObject *__pyx_v_width, PyObject *__pyx_v_height); /* proto */ +static void __pyx_pf_6region_9Rectangle_4__dealloc__(struct __pyx_obj_6region_Rectangle *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_6region_9Rectangle_6__str__(struct __pyx_obj_6region_Rectangle *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_6region_9Rectangle_8set(struct __pyx_obj_6region_Rectangle *__pyx_v_self, PyObject *__pyx_v_x, PyObject *__pyx_v_y, PyObject *__pyx_v_width, PyObject *__pyx_v_height); /* proto */ +static PyObject *__pyx_pf_6region_9Rectangle_10get(struct __pyx_obj_6region_Rectangle *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_6region_9Rectangle_12__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_6region_Rectangle *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_6region_9Rectangle_14__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_6region_Rectangle *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */ +static int __pyx_pf_6region_7Polygon___cinit__(struct __pyx_obj_6region_Polygon *__pyx_v_self, PyObject *__pyx_v_points); /* proto */ +static void __pyx_pf_6region_7Polygon_2__dealloc__(struct __pyx_obj_6region_Polygon *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_6region_7Polygon_4__str__(struct __pyx_obj_6region_Polygon *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_6region_7Polygon_6__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_6region_Polygon *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_6region_7Polygon_8__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_6region_Polygon *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */ +static PyObject *__pyx_pf_6region_vot_overlap(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_polygon1, PyObject *__pyx_v_polygon2, PyObject *__pyx_v_bounds); /* proto */ +static PyObject *__pyx_pf_6region_2vot_overlap_traj(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_polygons1, PyObject *__pyx_v_polygons2, PyObject *__pyx_v_bounds); /* proto */ +static PyObject *__pyx_pf_6region_4vot_float2str(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_template, float __pyx_v_value); /* proto */ +static int __pyx_pf_8EnumBase_14__Pyx_EnumMeta___init__(struct __pyx_obj___Pyx_EnumMeta *__pyx_v_cls, PyObject *__pyx_v_name, PyObject *__pyx_v_parents, PyObject *__pyx_v_dct); /* proto */ +static PyObject *__pyx_pf_8EnumBase_14__Pyx_EnumMeta_2__iter__(struct __pyx_obj___Pyx_EnumMeta *__pyx_v_cls); /* proto */ +static PyObject *__pyx_pf_8EnumBase_14__Pyx_EnumMeta_4__getitem__(struct __pyx_obj___Pyx_EnumMeta *__pyx_v_cls, PyObject *__pyx_v_name); /* proto */ +static PyObject *__pyx_pf_8EnumBase_14__Pyx_EnumMeta_6__reduce_cython__(struct __pyx_obj___Pyx_EnumMeta *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_8EnumBase_14__Pyx_EnumMeta_8__setstate_cython__(struct __pyx_obj___Pyx_EnumMeta *__pyx_v_self, PyObject *__pyx_v___pyx_state); /* proto */ +static PyObject *__pyx_pf_8EnumBase_14__Pyx_EnumBase___new__(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_cls, PyObject *__pyx_v_value, PyObject *__pyx_v_name); /* proto */ +static PyObject *__pyx_pf_8EnumBase_14__Pyx_EnumBase_2__repr__(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_8EnumBase_14__Pyx_EnumBase_4__str__(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_8EnumBase___pyx_unpickle___Pyx_EnumMeta(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v___pyx_type, long __pyx_v___pyx_checksum, PyObject *__pyx_v___pyx_state); /* proto */ +static PyObject *__pyx_tp_new_6region_RegionBounds(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new_6region_Rectangle(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new_6region_Polygon(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new___Pyx_EnumMeta(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_int_0; +static PyObject *__pyx_int_1; +static PyObject *__pyx_int_2; +static PyObject *__pyx_int_222419149; +static PyObject *__pyx_int_228825662; +static PyObject *__pyx_int_238750788; +static PyObject *__pyx_tuple_; +static PyObject *__pyx_tuple__2; +static PyObject *__pyx_tuple__3; +static PyObject *__pyx_tuple__4; +static PyObject *__pyx_tuple__6; +static PyObject *__pyx_tuple__7; +static PyObject *__pyx_tuple__8; +static PyObject *__pyx_tuple__9; +static PyObject *__pyx_tuple__11; +static PyObject *__pyx_tuple__13; +static PyObject *__pyx_tuple__15; +static PyObject *__pyx_tuple__17; +static PyObject *__pyx_tuple__18; +static PyObject *__pyx_tuple__20; +static PyObject *__pyx_tuple__22; +static PyObject *__pyx_codeobj__10; +static PyObject *__pyx_codeobj__12; +static PyObject *__pyx_codeobj__14; +static PyObject *__pyx_codeobj__16; +static PyObject *__pyx_codeobj__19; +static PyObject *__pyx_codeobj__21; +static PyObject *__pyx_codeobj__23; +/* Late includes */ + +/* "region.pyx":29 + * cdef c_region.region_bounds* _c_region_bounds + * + * def __cinit__(self): # <<<<<<<<<<<<<< + * self._c_region_bounds = malloc( + * sizeof(c_region.region_bounds)) + */ + +/* Python wrapper */ +static int __pyx_pw_6region_12RegionBounds_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static int __pyx_pw_6region_12RegionBounds_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0); + if (unlikely(PyTuple_GET_SIZE(__pyx_args) > 0)) { + __Pyx_RaiseArgtupleInvalid("__cinit__", 1, 0, 0, PyTuple_GET_SIZE(__pyx_args)); return -1;} + if (unlikely(__pyx_kwds) && unlikely(PyDict_Size(__pyx_kwds) > 0) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "__cinit__", 0))) return -1; + __pyx_r = __pyx_pf_6region_12RegionBounds___cinit__(((struct __pyx_obj_6region_RegionBounds *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_pf_6region_12RegionBounds___cinit__(struct __pyx_obj_6region_RegionBounds *__pyx_v_self) { + int __pyx_r; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__cinit__", 0); + + /* "region.pyx":30 + * + * def __cinit__(self): + * self._c_region_bounds = malloc( # <<<<<<<<<<<<<< + * sizeof(c_region.region_bounds)) + * if not self._c_region_bounds: + */ + __pyx_v_self->_c_region_bounds = ((region_bounds *)malloc((sizeof(region_bounds)))); + + /* "region.pyx":32 + * self._c_region_bounds = malloc( + * sizeof(c_region.region_bounds)) + * if not self._c_region_bounds: # <<<<<<<<<<<<<< + * self._c_region_bounds = NULL + * raise MemoryError() + */ + __pyx_t_1 = ((!(__pyx_v_self->_c_region_bounds != 0)) != 0); + if (unlikely(__pyx_t_1)) { + + /* "region.pyx":33 + * sizeof(c_region.region_bounds)) + * if not self._c_region_bounds: + * self._c_region_bounds = NULL # <<<<<<<<<<<<<< + * raise MemoryError() + * + */ + __pyx_v_self->_c_region_bounds = NULL; + + /* "region.pyx":34 + * if not self._c_region_bounds: + * self._c_region_bounds = NULL + * raise MemoryError() # <<<<<<<<<<<<<< + * + * def __init__(self, top, bottom, left, right): + */ + PyErr_NoMemory(); __PYX_ERR(0, 34, __pyx_L1_error) + + /* "region.pyx":32 + * self._c_region_bounds = malloc( + * sizeof(c_region.region_bounds)) + * if not self._c_region_bounds: # <<<<<<<<<<<<<< + * self._c_region_bounds = NULL + * raise MemoryError() + */ + } + + /* "region.pyx":29 + * cdef c_region.region_bounds* _c_region_bounds + * + * def __cinit__(self): # <<<<<<<<<<<<<< + * self._c_region_bounds = malloc( + * sizeof(c_region.region_bounds)) + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_AddTraceback("region.RegionBounds.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "region.pyx":36 + * raise MemoryError() + * + * def __init__(self, top, bottom, left, right): # <<<<<<<<<<<<<< + * self.set(top, bottom, left, right) + * + */ + +/* Python wrapper */ +static int __pyx_pw_6region_12RegionBounds_3__init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static int __pyx_pw_6region_12RegionBounds_3__init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_top = 0; + PyObject *__pyx_v_bottom = 0; + PyObject *__pyx_v_left = 0; + PyObject *__pyx_v_right = 0; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__init__ (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_top,&__pyx_n_s_bottom,&__pyx_n_s_left,&__pyx_n_s_right,0}; + PyObject* values[4] = {0,0,0,0}; + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_top)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_bottom)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("__init__", 1, 4, 4, 1); __PYX_ERR(0, 36, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_left)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("__init__", 1, 4, 4, 2); __PYX_ERR(0, 36, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 3: + if (likely((values[3] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_right)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("__init__", 1, 4, 4, 3); __PYX_ERR(0, 36, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__init__") < 0)) __PYX_ERR(0, 36, __pyx_L3_error) + } + } else if (PyTuple_GET_SIZE(__pyx_args) != 4) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + } + __pyx_v_top = values[0]; + __pyx_v_bottom = values[1]; + __pyx_v_left = values[2]; + __pyx_v_right = values[3]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__init__", 1, 4, 4, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 36, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("region.RegionBounds.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return -1; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6region_12RegionBounds_2__init__(((struct __pyx_obj_6region_RegionBounds *)__pyx_v_self), __pyx_v_top, __pyx_v_bottom, __pyx_v_left, __pyx_v_right); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_pf_6region_12RegionBounds_2__init__(struct __pyx_obj_6region_RegionBounds *__pyx_v_self, PyObject *__pyx_v_top, PyObject *__pyx_v_bottom, PyObject *__pyx_v_left, PyObject *__pyx_v_right) { + int __pyx_r; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__init__", 0); + + /* "region.pyx":37 + * + * def __init__(self, top, bottom, left, right): + * self.set(top, bottom, left, right) # <<<<<<<<<<<<<< + * + * def __dealloc__(self): + */ + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_set); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 37, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = NULL; + __pyx_t_4 = 0; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + __pyx_t_4 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[5] = {__pyx_t_3, __pyx_v_top, __pyx_v_bottom, __pyx_v_left, __pyx_v_right}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_2, __pyx_temp+1-__pyx_t_4, 4+__pyx_t_4); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 37, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[5] = {__pyx_t_3, __pyx_v_top, __pyx_v_bottom, __pyx_v_left, __pyx_v_right}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_2, __pyx_temp+1-__pyx_t_4, 4+__pyx_t_4); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 37, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + { + __pyx_t_5 = PyTuple_New(4+__pyx_t_4); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 37, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (__pyx_t_3) { + __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_3); __pyx_t_3 = NULL; + } + __Pyx_INCREF(__pyx_v_top); + __Pyx_GIVEREF(__pyx_v_top); + PyTuple_SET_ITEM(__pyx_t_5, 0+__pyx_t_4, __pyx_v_top); + __Pyx_INCREF(__pyx_v_bottom); + __Pyx_GIVEREF(__pyx_v_bottom); + PyTuple_SET_ITEM(__pyx_t_5, 1+__pyx_t_4, __pyx_v_bottom); + __Pyx_INCREF(__pyx_v_left); + __Pyx_GIVEREF(__pyx_v_left); + PyTuple_SET_ITEM(__pyx_t_5, 2+__pyx_t_4, __pyx_v_left); + __Pyx_INCREF(__pyx_v_right); + __Pyx_GIVEREF(__pyx_v_right); + PyTuple_SET_ITEM(__pyx_t_5, 3+__pyx_t_4, __pyx_v_right); + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_5, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 37, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + } + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "region.pyx":36 + * raise MemoryError() + * + * def __init__(self, top, bottom, left, right): # <<<<<<<<<<<<<< + * self.set(top, bottom, left, right) + * + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("region.RegionBounds.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "region.pyx":39 + * self.set(top, bottom, left, right) + * + * def __dealloc__(self): # <<<<<<<<<<<<<< + * if self._c_region_bounds is not NULL: + * free(self._c_region_bounds) + */ + +/* Python wrapper */ +static void __pyx_pw_6region_12RegionBounds_5__dealloc__(PyObject *__pyx_v_self); /*proto*/ +static void __pyx_pw_6region_12RegionBounds_5__dealloc__(PyObject *__pyx_v_self) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__dealloc__ (wrapper)", 0); + __pyx_pf_6region_12RegionBounds_4__dealloc__(((struct __pyx_obj_6region_RegionBounds *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); +} + +static void __pyx_pf_6region_12RegionBounds_4__dealloc__(struct __pyx_obj_6region_RegionBounds *__pyx_v_self) { + __Pyx_RefNannyDeclarations + int __pyx_t_1; + __Pyx_RefNannySetupContext("__dealloc__", 0); + + /* "region.pyx":40 + * + * def __dealloc__(self): + * if self._c_region_bounds is not NULL: # <<<<<<<<<<<<<< + * free(self._c_region_bounds) + * self._c_region_bounds = NULL + */ + __pyx_t_1 = ((__pyx_v_self->_c_region_bounds != NULL) != 0); + if (__pyx_t_1) { + + /* "region.pyx":41 + * def __dealloc__(self): + * if self._c_region_bounds is not NULL: + * free(self._c_region_bounds) # <<<<<<<<<<<<<< + * self._c_region_bounds = NULL + * + */ + free(__pyx_v_self->_c_region_bounds); + + /* "region.pyx":42 + * if self._c_region_bounds is not NULL: + * free(self._c_region_bounds) + * self._c_region_bounds = NULL # <<<<<<<<<<<<<< + * + * def __str__(self): + */ + __pyx_v_self->_c_region_bounds = NULL; + + /* "region.pyx":40 + * + * def __dealloc__(self): + * if self._c_region_bounds is not NULL: # <<<<<<<<<<<<<< + * free(self._c_region_bounds) + * self._c_region_bounds = NULL + */ + } + + /* "region.pyx":39 + * self.set(top, bottom, left, right) + * + * def __dealloc__(self): # <<<<<<<<<<<<<< + * if self._c_region_bounds is not NULL: + * free(self._c_region_bounds) + */ + + /* function exit code */ + __Pyx_RefNannyFinishContext(); +} + +/* "region.pyx":44 + * self._c_region_bounds = NULL + * + * def __str__(self): # <<<<<<<<<<<<<< + * return "top: {:.3f} bottom: {:.3f} left: {:.3f} reight: {:.3f}".format( + * self._c_region_bounds.top, + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6region_12RegionBounds_7__str__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_6region_12RegionBounds_7__str__(PyObject *__pyx_v_self) { + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__str__ (wrapper)", 0); + __pyx_r = __pyx_pf_6region_12RegionBounds_6__str__(((struct __pyx_obj_6region_RegionBounds *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6region_12RegionBounds_6__str__(struct __pyx_obj_6region_RegionBounds *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + int __pyx_t_8; + PyObject *__pyx_t_9 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__str__", 0); + + /* "region.pyx":45 + * + * def __str__(self): + * return "top: {:.3f} bottom: {:.3f} left: {:.3f} reight: {:.3f}".format( # <<<<<<<<<<<<<< + * self._c_region_bounds.top, + * self._c_region_bounds.bottom, + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_kp_s_top_3f_bottom_3f_left_3f_reight, __pyx_n_s_format); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 45, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + + /* "region.pyx":46 + * def __str__(self): + * return "top: {:.3f} bottom: {:.3f} left: {:.3f} reight: {:.3f}".format( + * self._c_region_bounds.top, # <<<<<<<<<<<<<< + * self._c_region_bounds.bottom, + * self._c_region_bounds.left, + */ + __pyx_t_3 = PyFloat_FromDouble(__pyx_v_self->_c_region_bounds->top); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 46, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + + /* "region.pyx":47 + * return "top: {:.3f} bottom: {:.3f} left: {:.3f} reight: {:.3f}".format( + * self._c_region_bounds.top, + * self._c_region_bounds.bottom, # <<<<<<<<<<<<<< + * self._c_region_bounds.left, + * self._c_region_bounds.right) + */ + __pyx_t_4 = PyFloat_FromDouble(__pyx_v_self->_c_region_bounds->bottom); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 47, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + + /* "region.pyx":48 + * self._c_region_bounds.top, + * self._c_region_bounds.bottom, + * self._c_region_bounds.left, # <<<<<<<<<<<<<< + * self._c_region_bounds.right) + * + */ + __pyx_t_5 = PyFloat_FromDouble(__pyx_v_self->_c_region_bounds->left); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 48, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + + /* "region.pyx":49 + * self._c_region_bounds.bottom, + * self._c_region_bounds.left, + * self._c_region_bounds.right) # <<<<<<<<<<<<<< + * + * def get(self): + */ + __pyx_t_6 = PyFloat_FromDouble(__pyx_v_self->_c_region_bounds->right); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 49, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_7 = NULL; + __pyx_t_8 = 0; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + __pyx_t_8 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[5] = {__pyx_t_7, __pyx_t_3, __pyx_t_4, __pyx_t_5, __pyx_t_6}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_2, __pyx_temp+1-__pyx_t_8, 4+__pyx_t_8); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 45, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[5] = {__pyx_t_7, __pyx_t_3, __pyx_t_4, __pyx_t_5, __pyx_t_6}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_2, __pyx_temp+1-__pyx_t_8, 4+__pyx_t_8); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 45, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else + #endif + { + __pyx_t_9 = PyTuple_New(4+__pyx_t_8); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 45, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + if (__pyx_t_7) { + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_7); __pyx_t_7 = NULL; + } + __Pyx_GIVEREF(__pyx_t_3); + PyTuple_SET_ITEM(__pyx_t_9, 0+__pyx_t_8, __pyx_t_3); + __Pyx_GIVEREF(__pyx_t_4); + PyTuple_SET_ITEM(__pyx_t_9, 1+__pyx_t_8, __pyx_t_4); + __Pyx_GIVEREF(__pyx_t_5); + PyTuple_SET_ITEM(__pyx_t_9, 2+__pyx_t_8, __pyx_t_5); + __Pyx_GIVEREF(__pyx_t_6); + PyTuple_SET_ITEM(__pyx_t_9, 3+__pyx_t_8, __pyx_t_6); + __pyx_t_3 = 0; + __pyx_t_4 = 0; + __pyx_t_5 = 0; + __pyx_t_6 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_9, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 45, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "region.pyx":44 + * self._c_region_bounds = NULL + * + * def __str__(self): # <<<<<<<<<<<<<< + * return "top: {:.3f} bottom: {:.3f} left: {:.3f} reight: {:.3f}".format( + * self._c_region_bounds.top, + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_AddTraceback("region.RegionBounds.__str__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "region.pyx":51 + * self._c_region_bounds.right) + * + * def get(self): # <<<<<<<<<<<<<< + * return (self._c_region_bounds.top, + * self._c_region_bounds.bottom, + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6region_12RegionBounds_9get(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/ +static PyObject *__pyx_pw_6region_12RegionBounds_9get(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) { + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("get (wrapper)", 0); + __pyx_r = __pyx_pf_6region_12RegionBounds_8get(((struct __pyx_obj_6region_RegionBounds *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6region_12RegionBounds_8get(struct __pyx_obj_6region_RegionBounds *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("get", 0); + + /* "region.pyx":52 + * + * def get(self): + * return (self._c_region_bounds.top, # <<<<<<<<<<<<<< + * self._c_region_bounds.bottom, + * self._c_region_bounds.left, + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PyFloat_FromDouble(__pyx_v_self->_c_region_bounds->top); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 52, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + + /* "region.pyx":53 + * def get(self): + * return (self._c_region_bounds.top, + * self._c_region_bounds.bottom, # <<<<<<<<<<<<<< + * self._c_region_bounds.left, + * self._c_region_bounds.right) + */ + __pyx_t_2 = PyFloat_FromDouble(__pyx_v_self->_c_region_bounds->bottom); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 53, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + + /* "region.pyx":54 + * return (self._c_region_bounds.top, + * self._c_region_bounds.bottom, + * self._c_region_bounds.left, # <<<<<<<<<<<<<< + * self._c_region_bounds.right) + * + */ + __pyx_t_3 = PyFloat_FromDouble(__pyx_v_self->_c_region_bounds->left); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 54, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + + /* "region.pyx":55 + * self._c_region_bounds.bottom, + * self._c_region_bounds.left, + * self._c_region_bounds.right) # <<<<<<<<<<<<<< + * + * def set(self, top, bottom, left, right): + */ + __pyx_t_4 = PyFloat_FromDouble(__pyx_v_self->_c_region_bounds->right); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 55, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + + /* "region.pyx":52 + * + * def get(self): + * return (self._c_region_bounds.top, # <<<<<<<<<<<<<< + * self._c_region_bounds.bottom, + * self._c_region_bounds.left, + */ + __pyx_t_5 = PyTuple_New(4); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 52, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_1); + __Pyx_GIVEREF(__pyx_t_2); + PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_t_2); + __Pyx_GIVEREF(__pyx_t_3); + PyTuple_SET_ITEM(__pyx_t_5, 2, __pyx_t_3); + __Pyx_GIVEREF(__pyx_t_4); + PyTuple_SET_ITEM(__pyx_t_5, 3, __pyx_t_4); + __pyx_t_1 = 0; + __pyx_t_2 = 0; + __pyx_t_3 = 0; + __pyx_t_4 = 0; + __pyx_r = __pyx_t_5; + __pyx_t_5 = 0; + goto __pyx_L0; + + /* "region.pyx":51 + * self._c_region_bounds.right) + * + * def get(self): # <<<<<<<<<<<<<< + * return (self._c_region_bounds.top, + * self._c_region_bounds.bottom, + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("region.RegionBounds.get", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "region.pyx":57 + * self._c_region_bounds.right) + * + * def set(self, top, bottom, left, right): # <<<<<<<<<<<<<< + * self._c_region_bounds.top = top + * self._c_region_bounds.bottom = bottom + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6region_12RegionBounds_11set(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static PyObject *__pyx_pw_6region_12RegionBounds_11set(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_top = 0; + PyObject *__pyx_v_bottom = 0; + PyObject *__pyx_v_left = 0; + PyObject *__pyx_v_right = 0; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("set (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_top,&__pyx_n_s_bottom,&__pyx_n_s_left,&__pyx_n_s_right,0}; + PyObject* values[4] = {0,0,0,0}; + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_top)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_bottom)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("set", 1, 4, 4, 1); __PYX_ERR(0, 57, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_left)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("set", 1, 4, 4, 2); __PYX_ERR(0, 57, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 3: + if (likely((values[3] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_right)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("set", 1, 4, 4, 3); __PYX_ERR(0, 57, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "set") < 0)) __PYX_ERR(0, 57, __pyx_L3_error) + } + } else if (PyTuple_GET_SIZE(__pyx_args) != 4) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + } + __pyx_v_top = values[0]; + __pyx_v_bottom = values[1]; + __pyx_v_left = values[2]; + __pyx_v_right = values[3]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("set", 1, 4, 4, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 57, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("region.RegionBounds.set", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6region_12RegionBounds_10set(((struct __pyx_obj_6region_RegionBounds *)__pyx_v_self), __pyx_v_top, __pyx_v_bottom, __pyx_v_left, __pyx_v_right); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6region_12RegionBounds_10set(struct __pyx_obj_6region_RegionBounds *__pyx_v_self, PyObject *__pyx_v_top, PyObject *__pyx_v_bottom, PyObject *__pyx_v_left, PyObject *__pyx_v_right) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + float __pyx_t_1; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("set", 0); + + /* "region.pyx":58 + * + * def set(self, top, bottom, left, right): + * self._c_region_bounds.top = top # <<<<<<<<<<<<<< + * self._c_region_bounds.bottom = bottom + * self._c_region_bounds.left = left + */ + __pyx_t_1 = __pyx_PyFloat_AsFloat(__pyx_v_top); if (unlikely((__pyx_t_1 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 58, __pyx_L1_error) + __pyx_v_self->_c_region_bounds->top = __pyx_t_1; + + /* "region.pyx":59 + * def set(self, top, bottom, left, right): + * self._c_region_bounds.top = top + * self._c_region_bounds.bottom = bottom # <<<<<<<<<<<<<< + * self._c_region_bounds.left = left + * self._c_region_bounds.right = right + */ + __pyx_t_1 = __pyx_PyFloat_AsFloat(__pyx_v_bottom); if (unlikely((__pyx_t_1 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 59, __pyx_L1_error) + __pyx_v_self->_c_region_bounds->bottom = __pyx_t_1; + + /* "region.pyx":60 + * self._c_region_bounds.top = top + * self._c_region_bounds.bottom = bottom + * self._c_region_bounds.left = left # <<<<<<<<<<<<<< + * self._c_region_bounds.right = right + * + */ + __pyx_t_1 = __pyx_PyFloat_AsFloat(__pyx_v_left); if (unlikely((__pyx_t_1 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 60, __pyx_L1_error) + __pyx_v_self->_c_region_bounds->left = __pyx_t_1; + + /* "region.pyx":61 + * self._c_region_bounds.bottom = bottom + * self._c_region_bounds.left = left + * self._c_region_bounds.right = right # <<<<<<<<<<<<<< + * + * cdef class Rectangle: + */ + __pyx_t_1 = __pyx_PyFloat_AsFloat(__pyx_v_right); if (unlikely((__pyx_t_1 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 61, __pyx_L1_error) + __pyx_v_self->_c_region_bounds->right = __pyx_t_1; + + /* "region.pyx":57 + * self._c_region_bounds.right) + * + * def set(self, top, bottom, left, right): # <<<<<<<<<<<<<< + * self._c_region_bounds.top = top + * self._c_region_bounds.bottom = bottom + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_AddTraceback("region.RegionBounds.set", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + * def __setstate_cython__(self, __pyx_state): + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6region_12RegionBounds_13__reduce_cython__(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/ +static PyObject *__pyx_pw_6region_12RegionBounds_13__reduce_cython__(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) { + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__reduce_cython__ (wrapper)", 0); + __pyx_r = __pyx_pf_6region_12RegionBounds_12__reduce_cython__(((struct __pyx_obj_6region_RegionBounds *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6region_12RegionBounds_12__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_6region_RegionBounds *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__reduce_cython__", 0); + + /* "(tree fragment)":2 + * def __reduce_cython__(self): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") # <<<<<<<<<<<<<< + * def __setstate_cython__(self, __pyx_state): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_TypeError, __pyx_tuple_, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 2, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(1, 2, __pyx_L1_error) + + /* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + * def __setstate_cython__(self, __pyx_state): + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("region.RegionBounds.__reduce_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6region_12RegionBounds_15__setstate_cython__(PyObject *__pyx_v_self, PyObject *__pyx_v___pyx_state); /*proto*/ +static PyObject *__pyx_pw_6region_12RegionBounds_15__setstate_cython__(PyObject *__pyx_v_self, PyObject *__pyx_v___pyx_state) { + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__setstate_cython__ (wrapper)", 0); + __pyx_r = __pyx_pf_6region_12RegionBounds_14__setstate_cython__(((struct __pyx_obj_6region_RegionBounds *)__pyx_v_self), ((PyObject *)__pyx_v___pyx_state)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6region_12RegionBounds_14__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_6region_RegionBounds *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__setstate_cython__", 0); + + /* "(tree fragment)":4 + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + * def __setstate_cython__(self, __pyx_state): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") # <<<<<<<<<<<<<< + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_TypeError, __pyx_tuple__2, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(1, 4, __pyx_L1_error) + + /* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("region.RegionBounds.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "region.pyx":66 + * cdef c_region.region_rectangle* _c_region_rectangle + * + * def __cinit__(self): # <<<<<<<<<<<<<< + * self._c_region_rectangle = malloc( + * sizeof(c_region.region_rectangle)) + */ + +/* Python wrapper */ +static int __pyx_pw_6region_9Rectangle_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static int __pyx_pw_6region_9Rectangle_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0); + if (unlikely(PyTuple_GET_SIZE(__pyx_args) > 0)) { + __Pyx_RaiseArgtupleInvalid("__cinit__", 1, 0, 0, PyTuple_GET_SIZE(__pyx_args)); return -1;} + if (unlikely(__pyx_kwds) && unlikely(PyDict_Size(__pyx_kwds) > 0) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "__cinit__", 0))) return -1; + __pyx_r = __pyx_pf_6region_9Rectangle___cinit__(((struct __pyx_obj_6region_Rectangle *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_pf_6region_9Rectangle___cinit__(struct __pyx_obj_6region_Rectangle *__pyx_v_self) { + int __pyx_r; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__cinit__", 0); + + /* "region.pyx":67 + * + * def __cinit__(self): + * self._c_region_rectangle = malloc( # <<<<<<<<<<<<<< + * sizeof(c_region.region_rectangle)) + * if not self._c_region_rectangle: + */ + __pyx_v_self->_c_region_rectangle = ((region_rectangle *)malloc((sizeof(region_rectangle)))); + + /* "region.pyx":69 + * self._c_region_rectangle = malloc( + * sizeof(c_region.region_rectangle)) + * if not self._c_region_rectangle: # <<<<<<<<<<<<<< + * self._c_region_rectangle = NULL + * raise MemoryError() + */ + __pyx_t_1 = ((!(__pyx_v_self->_c_region_rectangle != 0)) != 0); + if (unlikely(__pyx_t_1)) { + + /* "region.pyx":70 + * sizeof(c_region.region_rectangle)) + * if not self._c_region_rectangle: + * self._c_region_rectangle = NULL # <<<<<<<<<<<<<< + * raise MemoryError() + * + */ + __pyx_v_self->_c_region_rectangle = NULL; + + /* "region.pyx":71 + * if not self._c_region_rectangle: + * self._c_region_rectangle = NULL + * raise MemoryError() # <<<<<<<<<<<<<< + * + * def __init__(self, x, y, width, height): + */ + PyErr_NoMemory(); __PYX_ERR(0, 71, __pyx_L1_error) + + /* "region.pyx":69 + * self._c_region_rectangle = malloc( + * sizeof(c_region.region_rectangle)) + * if not self._c_region_rectangle: # <<<<<<<<<<<<<< + * self._c_region_rectangle = NULL + * raise MemoryError() + */ + } + + /* "region.pyx":66 + * cdef c_region.region_rectangle* _c_region_rectangle + * + * def __cinit__(self): # <<<<<<<<<<<<<< + * self._c_region_rectangle = malloc( + * sizeof(c_region.region_rectangle)) + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_AddTraceback("region.Rectangle.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "region.pyx":73 + * raise MemoryError() + * + * def __init__(self, x, y, width, height): # <<<<<<<<<<<<<< + * self.set(x, y, width, height) + * + */ + +/* Python wrapper */ +static int __pyx_pw_6region_9Rectangle_3__init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static int __pyx_pw_6region_9Rectangle_3__init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_x = 0; + PyObject *__pyx_v_y = 0; + PyObject *__pyx_v_width = 0; + PyObject *__pyx_v_height = 0; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__init__ (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_x,&__pyx_n_s_y,&__pyx_n_s_width,&__pyx_n_s_height,0}; + PyObject* values[4] = {0,0,0,0}; + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_x)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_y)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("__init__", 1, 4, 4, 1); __PYX_ERR(0, 73, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_width)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("__init__", 1, 4, 4, 2); __PYX_ERR(0, 73, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 3: + if (likely((values[3] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_height)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("__init__", 1, 4, 4, 3); __PYX_ERR(0, 73, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__init__") < 0)) __PYX_ERR(0, 73, __pyx_L3_error) + } + } else if (PyTuple_GET_SIZE(__pyx_args) != 4) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + } + __pyx_v_x = values[0]; + __pyx_v_y = values[1]; + __pyx_v_width = values[2]; + __pyx_v_height = values[3]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__init__", 1, 4, 4, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 73, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("region.Rectangle.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return -1; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6region_9Rectangle_2__init__(((struct __pyx_obj_6region_Rectangle *)__pyx_v_self), __pyx_v_x, __pyx_v_y, __pyx_v_width, __pyx_v_height); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_pf_6region_9Rectangle_2__init__(struct __pyx_obj_6region_Rectangle *__pyx_v_self, PyObject *__pyx_v_x, PyObject *__pyx_v_y, PyObject *__pyx_v_width, PyObject *__pyx_v_height) { + int __pyx_r; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__init__", 0); + + /* "region.pyx":74 + * + * def __init__(self, x, y, width, height): + * self.set(x, y, width, height) # <<<<<<<<<<<<<< + * + * def __dealloc__(self): + */ + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_set); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 74, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = NULL; + __pyx_t_4 = 0; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + __pyx_t_4 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[5] = {__pyx_t_3, __pyx_v_x, __pyx_v_y, __pyx_v_width, __pyx_v_height}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_2, __pyx_temp+1-__pyx_t_4, 4+__pyx_t_4); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 74, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[5] = {__pyx_t_3, __pyx_v_x, __pyx_v_y, __pyx_v_width, __pyx_v_height}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_2, __pyx_temp+1-__pyx_t_4, 4+__pyx_t_4); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 74, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + { + __pyx_t_5 = PyTuple_New(4+__pyx_t_4); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 74, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (__pyx_t_3) { + __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_3); __pyx_t_3 = NULL; + } + __Pyx_INCREF(__pyx_v_x); + __Pyx_GIVEREF(__pyx_v_x); + PyTuple_SET_ITEM(__pyx_t_5, 0+__pyx_t_4, __pyx_v_x); + __Pyx_INCREF(__pyx_v_y); + __Pyx_GIVEREF(__pyx_v_y); + PyTuple_SET_ITEM(__pyx_t_5, 1+__pyx_t_4, __pyx_v_y); + __Pyx_INCREF(__pyx_v_width); + __Pyx_GIVEREF(__pyx_v_width); + PyTuple_SET_ITEM(__pyx_t_5, 2+__pyx_t_4, __pyx_v_width); + __Pyx_INCREF(__pyx_v_height); + __Pyx_GIVEREF(__pyx_v_height); + PyTuple_SET_ITEM(__pyx_t_5, 3+__pyx_t_4, __pyx_v_height); + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_5, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 74, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + } + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "region.pyx":73 + * raise MemoryError() + * + * def __init__(self, x, y, width, height): # <<<<<<<<<<<<<< + * self.set(x, y, width, height) + * + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("region.Rectangle.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "region.pyx":76 + * self.set(x, y, width, height) + * + * def __dealloc__(self): # <<<<<<<<<<<<<< + * if self._c_region_rectangle is not NULL: + * free(self._c_region_rectangle) + */ + +/* Python wrapper */ +static void __pyx_pw_6region_9Rectangle_5__dealloc__(PyObject *__pyx_v_self); /*proto*/ +static void __pyx_pw_6region_9Rectangle_5__dealloc__(PyObject *__pyx_v_self) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__dealloc__ (wrapper)", 0); + __pyx_pf_6region_9Rectangle_4__dealloc__(((struct __pyx_obj_6region_Rectangle *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); +} + +static void __pyx_pf_6region_9Rectangle_4__dealloc__(struct __pyx_obj_6region_Rectangle *__pyx_v_self) { + __Pyx_RefNannyDeclarations + int __pyx_t_1; + __Pyx_RefNannySetupContext("__dealloc__", 0); + + /* "region.pyx":77 + * + * def __dealloc__(self): + * if self._c_region_rectangle is not NULL: # <<<<<<<<<<<<<< + * free(self._c_region_rectangle) + * self._c_region_rectangle = NULL + */ + __pyx_t_1 = ((__pyx_v_self->_c_region_rectangle != NULL) != 0); + if (__pyx_t_1) { + + /* "region.pyx":78 + * def __dealloc__(self): + * if self._c_region_rectangle is not NULL: + * free(self._c_region_rectangle) # <<<<<<<<<<<<<< + * self._c_region_rectangle = NULL + * + */ + free(__pyx_v_self->_c_region_rectangle); + + /* "region.pyx":79 + * if self._c_region_rectangle is not NULL: + * free(self._c_region_rectangle) + * self._c_region_rectangle = NULL # <<<<<<<<<<<<<< + * + * def __str__(self): + */ + __pyx_v_self->_c_region_rectangle = NULL; + + /* "region.pyx":77 + * + * def __dealloc__(self): + * if self._c_region_rectangle is not NULL: # <<<<<<<<<<<<<< + * free(self._c_region_rectangle) + * self._c_region_rectangle = NULL + */ + } + + /* "region.pyx":76 + * self.set(x, y, width, height) + * + * def __dealloc__(self): # <<<<<<<<<<<<<< + * if self._c_region_rectangle is not NULL: + * free(self._c_region_rectangle) + */ + + /* function exit code */ + __Pyx_RefNannyFinishContext(); +} + +/* "region.pyx":81 + * self._c_region_rectangle = NULL + * + * def __str__(self): # <<<<<<<<<<<<<< + * return "x: {:.3f} y: {:.3f} width: {:.3f} height: {:.3f}".format( + * self._c_region_rectangle.x, + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6region_9Rectangle_7__str__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_6region_9Rectangle_7__str__(PyObject *__pyx_v_self) { + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__str__ (wrapper)", 0); + __pyx_r = __pyx_pf_6region_9Rectangle_6__str__(((struct __pyx_obj_6region_Rectangle *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6region_9Rectangle_6__str__(struct __pyx_obj_6region_Rectangle *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + int __pyx_t_8; + PyObject *__pyx_t_9 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__str__", 0); + + /* "region.pyx":82 + * + * def __str__(self): + * return "x: {:.3f} y: {:.3f} width: {:.3f} height: {:.3f}".format( # <<<<<<<<<<<<<< + * self._c_region_rectangle.x, + * self._c_region_rectangle.y, + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_kp_s_x_3f_y_3f_width_3f_height_3f, __pyx_n_s_format); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 82, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + + /* "region.pyx":83 + * def __str__(self): + * return "x: {:.3f} y: {:.3f} width: {:.3f} height: {:.3f}".format( + * self._c_region_rectangle.x, # <<<<<<<<<<<<<< + * self._c_region_rectangle.y, + * self._c_region_rectangle.width, + */ + __pyx_t_3 = PyFloat_FromDouble(__pyx_v_self->_c_region_rectangle->x); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 83, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + + /* "region.pyx":84 + * return "x: {:.3f} y: {:.3f} width: {:.3f} height: {:.3f}".format( + * self._c_region_rectangle.x, + * self._c_region_rectangle.y, # <<<<<<<<<<<<<< + * self._c_region_rectangle.width, + * self._c_region_rectangle.height) + */ + __pyx_t_4 = PyFloat_FromDouble(__pyx_v_self->_c_region_rectangle->y); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 84, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + + /* "region.pyx":85 + * self._c_region_rectangle.x, + * self._c_region_rectangle.y, + * self._c_region_rectangle.width, # <<<<<<<<<<<<<< + * self._c_region_rectangle.height) + * + */ + __pyx_t_5 = PyFloat_FromDouble(__pyx_v_self->_c_region_rectangle->width); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 85, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + + /* "region.pyx":86 + * self._c_region_rectangle.y, + * self._c_region_rectangle.width, + * self._c_region_rectangle.height) # <<<<<<<<<<<<<< + * + * def set(self, x, y, width, height): + */ + __pyx_t_6 = PyFloat_FromDouble(__pyx_v_self->_c_region_rectangle->height); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 86, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_7 = NULL; + __pyx_t_8 = 0; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + __pyx_t_8 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[5] = {__pyx_t_7, __pyx_t_3, __pyx_t_4, __pyx_t_5, __pyx_t_6}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_2, __pyx_temp+1-__pyx_t_8, 4+__pyx_t_8); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 82, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[5] = {__pyx_t_7, __pyx_t_3, __pyx_t_4, __pyx_t_5, __pyx_t_6}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_2, __pyx_temp+1-__pyx_t_8, 4+__pyx_t_8); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 82, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else + #endif + { + __pyx_t_9 = PyTuple_New(4+__pyx_t_8); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 82, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + if (__pyx_t_7) { + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_7); __pyx_t_7 = NULL; + } + __Pyx_GIVEREF(__pyx_t_3); + PyTuple_SET_ITEM(__pyx_t_9, 0+__pyx_t_8, __pyx_t_3); + __Pyx_GIVEREF(__pyx_t_4); + PyTuple_SET_ITEM(__pyx_t_9, 1+__pyx_t_8, __pyx_t_4); + __Pyx_GIVEREF(__pyx_t_5); + PyTuple_SET_ITEM(__pyx_t_9, 2+__pyx_t_8, __pyx_t_5); + __Pyx_GIVEREF(__pyx_t_6); + PyTuple_SET_ITEM(__pyx_t_9, 3+__pyx_t_8, __pyx_t_6); + __pyx_t_3 = 0; + __pyx_t_4 = 0; + __pyx_t_5 = 0; + __pyx_t_6 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_9, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 82, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "region.pyx":81 + * self._c_region_rectangle = NULL + * + * def __str__(self): # <<<<<<<<<<<<<< + * return "x: {:.3f} y: {:.3f} width: {:.3f} height: {:.3f}".format( + * self._c_region_rectangle.x, + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_AddTraceback("region.Rectangle.__str__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "region.pyx":88 + * self._c_region_rectangle.height) + * + * def set(self, x, y, width, height): # <<<<<<<<<<<<<< + * self._c_region_rectangle.x = x + * self._c_region_rectangle.y = y + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6region_9Rectangle_9set(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static PyObject *__pyx_pw_6region_9Rectangle_9set(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_x = 0; + PyObject *__pyx_v_y = 0; + PyObject *__pyx_v_width = 0; + PyObject *__pyx_v_height = 0; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("set (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_x,&__pyx_n_s_y,&__pyx_n_s_width,&__pyx_n_s_height,0}; + PyObject* values[4] = {0,0,0,0}; + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_x)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_y)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("set", 1, 4, 4, 1); __PYX_ERR(0, 88, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_width)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("set", 1, 4, 4, 2); __PYX_ERR(0, 88, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 3: + if (likely((values[3] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_height)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("set", 1, 4, 4, 3); __PYX_ERR(0, 88, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "set") < 0)) __PYX_ERR(0, 88, __pyx_L3_error) + } + } else if (PyTuple_GET_SIZE(__pyx_args) != 4) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + } + __pyx_v_x = values[0]; + __pyx_v_y = values[1]; + __pyx_v_width = values[2]; + __pyx_v_height = values[3]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("set", 1, 4, 4, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 88, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("region.Rectangle.set", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6region_9Rectangle_8set(((struct __pyx_obj_6region_Rectangle *)__pyx_v_self), __pyx_v_x, __pyx_v_y, __pyx_v_width, __pyx_v_height); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6region_9Rectangle_8set(struct __pyx_obj_6region_Rectangle *__pyx_v_self, PyObject *__pyx_v_x, PyObject *__pyx_v_y, PyObject *__pyx_v_width, PyObject *__pyx_v_height) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + float __pyx_t_1; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("set", 0); + + /* "region.pyx":89 + * + * def set(self, x, y, width, height): + * self._c_region_rectangle.x = x # <<<<<<<<<<<<<< + * self._c_region_rectangle.y = y + * self._c_region_rectangle.width = width + */ + __pyx_t_1 = __pyx_PyFloat_AsFloat(__pyx_v_x); if (unlikely((__pyx_t_1 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 89, __pyx_L1_error) + __pyx_v_self->_c_region_rectangle->x = __pyx_t_1; + + /* "region.pyx":90 + * def set(self, x, y, width, height): + * self._c_region_rectangle.x = x + * self._c_region_rectangle.y = y # <<<<<<<<<<<<<< + * self._c_region_rectangle.width = width + * self._c_region_rectangle.height = height + */ + __pyx_t_1 = __pyx_PyFloat_AsFloat(__pyx_v_y); if (unlikely((__pyx_t_1 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 90, __pyx_L1_error) + __pyx_v_self->_c_region_rectangle->y = __pyx_t_1; + + /* "region.pyx":91 + * self._c_region_rectangle.x = x + * self._c_region_rectangle.y = y + * self._c_region_rectangle.width = width # <<<<<<<<<<<<<< + * self._c_region_rectangle.height = height + * + */ + __pyx_t_1 = __pyx_PyFloat_AsFloat(__pyx_v_width); if (unlikely((__pyx_t_1 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 91, __pyx_L1_error) + __pyx_v_self->_c_region_rectangle->width = __pyx_t_1; + + /* "region.pyx":92 + * self._c_region_rectangle.y = y + * self._c_region_rectangle.width = width + * self._c_region_rectangle.height = height # <<<<<<<<<<<<<< + * + * def get(self): + */ + __pyx_t_1 = __pyx_PyFloat_AsFloat(__pyx_v_height); if (unlikely((__pyx_t_1 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 92, __pyx_L1_error) + __pyx_v_self->_c_region_rectangle->height = __pyx_t_1; + + /* "region.pyx":88 + * self._c_region_rectangle.height) + * + * def set(self, x, y, width, height): # <<<<<<<<<<<<<< + * self._c_region_rectangle.x = x + * self._c_region_rectangle.y = y + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_AddTraceback("region.Rectangle.set", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "region.pyx":94 + * self._c_region_rectangle.height = height + * + * def get(self): # <<<<<<<<<<<<<< + * """ + * return: + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6region_9Rectangle_11get(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/ +static char __pyx_doc_6region_9Rectangle_10get[] = "\n return:\n (x, y, width, height)\n "; +static PyObject *__pyx_pw_6region_9Rectangle_11get(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) { + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("get (wrapper)", 0); + __pyx_r = __pyx_pf_6region_9Rectangle_10get(((struct __pyx_obj_6region_Rectangle *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6region_9Rectangle_10get(struct __pyx_obj_6region_Rectangle *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("get", 0); + + /* "region.pyx":99 + * (x, y, width, height) + * """ + * return (self._c_region_rectangle.x, # <<<<<<<<<<<<<< + * self._c_region_rectangle.y, + * self._c_region_rectangle.width, + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PyFloat_FromDouble(__pyx_v_self->_c_region_rectangle->x); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 99, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + + /* "region.pyx":100 + * """ + * return (self._c_region_rectangle.x, + * self._c_region_rectangle.y, # <<<<<<<<<<<<<< + * self._c_region_rectangle.width, + * self._c_region_rectangle.height) + */ + __pyx_t_2 = PyFloat_FromDouble(__pyx_v_self->_c_region_rectangle->y); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 100, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + + /* "region.pyx":101 + * return (self._c_region_rectangle.x, + * self._c_region_rectangle.y, + * self._c_region_rectangle.width, # <<<<<<<<<<<<<< + * self._c_region_rectangle.height) + * + */ + __pyx_t_3 = PyFloat_FromDouble(__pyx_v_self->_c_region_rectangle->width); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 101, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + + /* "region.pyx":102 + * self._c_region_rectangle.y, + * self._c_region_rectangle.width, + * self._c_region_rectangle.height) # <<<<<<<<<<<<<< + * + * cdef class Polygon: + */ + __pyx_t_4 = PyFloat_FromDouble(__pyx_v_self->_c_region_rectangle->height); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 102, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + + /* "region.pyx":99 + * (x, y, width, height) + * """ + * return (self._c_region_rectangle.x, # <<<<<<<<<<<<<< + * self._c_region_rectangle.y, + * self._c_region_rectangle.width, + */ + __pyx_t_5 = PyTuple_New(4); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 99, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_1); + __Pyx_GIVEREF(__pyx_t_2); + PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_t_2); + __Pyx_GIVEREF(__pyx_t_3); + PyTuple_SET_ITEM(__pyx_t_5, 2, __pyx_t_3); + __Pyx_GIVEREF(__pyx_t_4); + PyTuple_SET_ITEM(__pyx_t_5, 3, __pyx_t_4); + __pyx_t_1 = 0; + __pyx_t_2 = 0; + __pyx_t_3 = 0; + __pyx_t_4 = 0; + __pyx_r = __pyx_t_5; + __pyx_t_5 = 0; + goto __pyx_L0; + + /* "region.pyx":94 + * self._c_region_rectangle.height = height + * + * def get(self): # <<<<<<<<<<<<<< + * """ + * return: + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("region.Rectangle.get", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + * def __setstate_cython__(self, __pyx_state): + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6region_9Rectangle_13__reduce_cython__(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/ +static PyObject *__pyx_pw_6region_9Rectangle_13__reduce_cython__(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) { + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__reduce_cython__ (wrapper)", 0); + __pyx_r = __pyx_pf_6region_9Rectangle_12__reduce_cython__(((struct __pyx_obj_6region_Rectangle *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6region_9Rectangle_12__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_6region_Rectangle *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__reduce_cython__", 0); + + /* "(tree fragment)":2 + * def __reduce_cython__(self): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") # <<<<<<<<<<<<<< + * def __setstate_cython__(self, __pyx_state): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_TypeError, __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 2, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(1, 2, __pyx_L1_error) + + /* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + * def __setstate_cython__(self, __pyx_state): + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("region.Rectangle.__reduce_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6region_9Rectangle_15__setstate_cython__(PyObject *__pyx_v_self, PyObject *__pyx_v___pyx_state); /*proto*/ +static PyObject *__pyx_pw_6region_9Rectangle_15__setstate_cython__(PyObject *__pyx_v_self, PyObject *__pyx_v___pyx_state) { + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__setstate_cython__ (wrapper)", 0); + __pyx_r = __pyx_pf_6region_9Rectangle_14__setstate_cython__(((struct __pyx_obj_6region_Rectangle *)__pyx_v_self), ((PyObject *)__pyx_v___pyx_state)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6region_9Rectangle_14__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_6region_Rectangle *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__setstate_cython__", 0); + + /* "(tree fragment)":4 + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + * def __setstate_cython__(self, __pyx_state): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") # <<<<<<<<<<<<<< + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_TypeError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(1, 4, __pyx_L1_error) + + /* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("region.Rectangle.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "region.pyx":107 + * cdef c_region.region_polygon* _c_region_polygon + * + * def __cinit__(self, points): # <<<<<<<<<<<<<< + * """ + * args: + */ + +/* Python wrapper */ +static int __pyx_pw_6region_7Polygon_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static int __pyx_pw_6region_7Polygon_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_points = 0; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_points,0}; + PyObject* values[1] = {0}; + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_points)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__cinit__") < 0)) __PYX_ERR(0, 107, __pyx_L3_error) + } + } else if (PyTuple_GET_SIZE(__pyx_args) != 1) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + } + __pyx_v_points = values[0]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__cinit__", 1, 1, 1, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 107, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("region.Polygon.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return -1; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6region_7Polygon___cinit__(((struct __pyx_obj_6region_Polygon *)__pyx_v_self), __pyx_v_points); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_pf_6region_7Polygon___cinit__(struct __pyx_obj_6region_Polygon *__pyx_v_self, PyObject *__pyx_v_points) { + PyObject *__pyx_v_num = NULL; + PyObject *__pyx_v_i = NULL; + int __pyx_r; + __Pyx_RefNannyDeclarations + Py_ssize_t __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + int __pyx_t_3; + int __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + size_t __pyx_t_6; + PyObject *(*__pyx_t_7)(PyObject *); + PyObject *__pyx_t_8 = NULL; + float __pyx_t_9; + Py_ssize_t __pyx_t_10; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__cinit__", 0); + + /* "region.pyx":113 + * points = ((1, 1), (10, 10)) + * """ + * num = len(points) // 2 # <<<<<<<<<<<<<< + * self._c_region_polygon = malloc( + * sizeof(c_region.region_polygon)) + */ + __pyx_t_1 = PyObject_Length(__pyx_v_points); if (unlikely(__pyx_t_1 == ((Py_ssize_t)-1))) __PYX_ERR(0, 113, __pyx_L1_error) + __pyx_t_2 = PyInt_FromSsize_t(__Pyx_div_Py_ssize_t(__pyx_t_1, 2)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 113, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_v_num = __pyx_t_2; + __pyx_t_2 = 0; + + /* "region.pyx":114 + * """ + * num = len(points) // 2 + * self._c_region_polygon = malloc( # <<<<<<<<<<<<<< + * sizeof(c_region.region_polygon)) + * if not self._c_region_polygon: + */ + __pyx_v_self->_c_region_polygon = ((region_polygon *)malloc((sizeof(region_polygon)))); + + /* "region.pyx":116 + * self._c_region_polygon = malloc( + * sizeof(c_region.region_polygon)) + * if not self._c_region_polygon: # <<<<<<<<<<<<<< + * self._c_region_polygon = NULL + * raise MemoryError() + */ + __pyx_t_3 = ((!(__pyx_v_self->_c_region_polygon != 0)) != 0); + if (unlikely(__pyx_t_3)) { + + /* "region.pyx":117 + * sizeof(c_region.region_polygon)) + * if not self._c_region_polygon: + * self._c_region_polygon = NULL # <<<<<<<<<<<<<< + * raise MemoryError() + * self._c_region_polygon.count = num + */ + __pyx_v_self->_c_region_polygon = NULL; + + /* "region.pyx":118 + * if not self._c_region_polygon: + * self._c_region_polygon = NULL + * raise MemoryError() # <<<<<<<<<<<<<< + * self._c_region_polygon.count = num + * self._c_region_polygon.x = malloc(sizeof(float) * num) + */ + PyErr_NoMemory(); __PYX_ERR(0, 118, __pyx_L1_error) + + /* "region.pyx":116 + * self._c_region_polygon = malloc( + * sizeof(c_region.region_polygon)) + * if not self._c_region_polygon: # <<<<<<<<<<<<<< + * self._c_region_polygon = NULL + * raise MemoryError() + */ + } + + /* "region.pyx":119 + * self._c_region_polygon = NULL + * raise MemoryError() + * self._c_region_polygon.count = num # <<<<<<<<<<<<<< + * self._c_region_polygon.x = malloc(sizeof(float) * num) + * if not self._c_region_polygon.x: + */ + __pyx_t_4 = __Pyx_PyInt_As_int(__pyx_v_num); if (unlikely((__pyx_t_4 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 119, __pyx_L1_error) + __pyx_v_self->_c_region_polygon->count = __pyx_t_4; + + /* "region.pyx":120 + * raise MemoryError() + * self._c_region_polygon.count = num + * self._c_region_polygon.x = malloc(sizeof(float) * num) # <<<<<<<<<<<<<< + * if not self._c_region_polygon.x: + * raise MemoryError() + */ + __pyx_t_2 = __Pyx_PyInt_FromSize_t((sizeof(float))); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 120, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_5 = PyNumber_Multiply(__pyx_t_2, __pyx_v_num); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 120, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_6 = __Pyx_PyInt_As_size_t(__pyx_t_5); if (unlikely((__pyx_t_6 == (size_t)-1) && PyErr_Occurred())) __PYX_ERR(0, 120, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_v_self->_c_region_polygon->x = ((float *)malloc(__pyx_t_6)); + + /* "region.pyx":121 + * self._c_region_polygon.count = num + * self._c_region_polygon.x = malloc(sizeof(float) * num) + * if not self._c_region_polygon.x: # <<<<<<<<<<<<<< + * raise MemoryError() + * self._c_region_polygon.y = malloc(sizeof(float) * num) + */ + __pyx_t_3 = ((!(__pyx_v_self->_c_region_polygon->x != 0)) != 0); + if (unlikely(__pyx_t_3)) { + + /* "region.pyx":122 + * self._c_region_polygon.x = malloc(sizeof(float) * num) + * if not self._c_region_polygon.x: + * raise MemoryError() # <<<<<<<<<<<<<< + * self._c_region_polygon.y = malloc(sizeof(float) * num) + * if not self._c_region_polygon.y: + */ + PyErr_NoMemory(); __PYX_ERR(0, 122, __pyx_L1_error) + + /* "region.pyx":121 + * self._c_region_polygon.count = num + * self._c_region_polygon.x = malloc(sizeof(float) * num) + * if not self._c_region_polygon.x: # <<<<<<<<<<<<<< + * raise MemoryError() + * self._c_region_polygon.y = malloc(sizeof(float) * num) + */ + } + + /* "region.pyx":123 + * if not self._c_region_polygon.x: + * raise MemoryError() + * self._c_region_polygon.y = malloc(sizeof(float) * num) # <<<<<<<<<<<<<< + * if not self._c_region_polygon.y: + * raise MemoryError() + */ + __pyx_t_5 = __Pyx_PyInt_FromSize_t((sizeof(float))); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 123, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_2 = PyNumber_Multiply(__pyx_t_5, __pyx_v_num); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 123, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_6 = __Pyx_PyInt_As_size_t(__pyx_t_2); if (unlikely((__pyx_t_6 == (size_t)-1) && PyErr_Occurred())) __PYX_ERR(0, 123, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_self->_c_region_polygon->y = ((float *)malloc(__pyx_t_6)); + + /* "region.pyx":124 + * raise MemoryError() + * self._c_region_polygon.y = malloc(sizeof(float) * num) + * if not self._c_region_polygon.y: # <<<<<<<<<<<<<< + * raise MemoryError() + * + */ + __pyx_t_3 = ((!(__pyx_v_self->_c_region_polygon->y != 0)) != 0); + if (unlikely(__pyx_t_3)) { + + /* "region.pyx":125 + * self._c_region_polygon.y = malloc(sizeof(float) * num) + * if not self._c_region_polygon.y: + * raise MemoryError() # <<<<<<<<<<<<<< + * + * for i in range(num): + */ + PyErr_NoMemory(); __PYX_ERR(0, 125, __pyx_L1_error) + + /* "region.pyx":124 + * raise MemoryError() + * self._c_region_polygon.y = malloc(sizeof(float) * num) + * if not self._c_region_polygon.y: # <<<<<<<<<<<<<< + * raise MemoryError() + * + */ + } + + /* "region.pyx":127 + * raise MemoryError() + * + * for i in range(num): # <<<<<<<<<<<<<< + * self._c_region_polygon.x[i] = points[i*2] + * self._c_region_polygon.y[i] = points[i*2+1] + */ + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_builtin_range, __pyx_v_num); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 127, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (likely(PyList_CheckExact(__pyx_t_2)) || PyTuple_CheckExact(__pyx_t_2)) { + __pyx_t_5 = __pyx_t_2; __Pyx_INCREF(__pyx_t_5); __pyx_t_1 = 0; + __pyx_t_7 = NULL; + } else { + __pyx_t_1 = -1; __pyx_t_5 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 127, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_7 = Py_TYPE(__pyx_t_5)->tp_iternext; if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 127, __pyx_L1_error) + } + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + for (;;) { + if (likely(!__pyx_t_7)) { + if (likely(PyList_CheckExact(__pyx_t_5))) { + if (__pyx_t_1 >= PyList_GET_SIZE(__pyx_t_5)) break; + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_2 = PyList_GET_ITEM(__pyx_t_5, __pyx_t_1); __Pyx_INCREF(__pyx_t_2); __pyx_t_1++; if (unlikely(0 < 0)) __PYX_ERR(0, 127, __pyx_L1_error) + #else + __pyx_t_2 = PySequence_ITEM(__pyx_t_5, __pyx_t_1); __pyx_t_1++; if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 127, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + #endif + } else { + if (__pyx_t_1 >= PyTuple_GET_SIZE(__pyx_t_5)) break; + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_2 = PyTuple_GET_ITEM(__pyx_t_5, __pyx_t_1); __Pyx_INCREF(__pyx_t_2); __pyx_t_1++; if (unlikely(0 < 0)) __PYX_ERR(0, 127, __pyx_L1_error) + #else + __pyx_t_2 = PySequence_ITEM(__pyx_t_5, __pyx_t_1); __pyx_t_1++; if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 127, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + #endif + } + } else { + __pyx_t_2 = __pyx_t_7(__pyx_t_5); + if (unlikely(!__pyx_t_2)) { + PyObject* exc_type = PyErr_Occurred(); + if (exc_type) { + if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); + else __PYX_ERR(0, 127, __pyx_L1_error) + } + break; + } + __Pyx_GOTREF(__pyx_t_2); + } + __Pyx_XDECREF_SET(__pyx_v_i, __pyx_t_2); + __pyx_t_2 = 0; + + /* "region.pyx":128 + * + * for i in range(num): + * self._c_region_polygon.x[i] = points[i*2] # <<<<<<<<<<<<<< + * self._c_region_polygon.y[i] = points[i*2+1] + * + */ + __pyx_t_2 = PyNumber_Multiply(__pyx_v_i, __pyx_int_2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 128, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_8 = __Pyx_PyObject_GetItem(__pyx_v_points, __pyx_t_2); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 128, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_9 = __pyx_PyFloat_AsFloat(__pyx_t_8); if (unlikely((__pyx_t_9 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 128, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_t_10 = __Pyx_PyIndex_AsSsize_t(__pyx_v_i); if (unlikely((__pyx_t_10 == (Py_ssize_t)-1) && PyErr_Occurred())) __PYX_ERR(0, 128, __pyx_L1_error) + (__pyx_v_self->_c_region_polygon->x[__pyx_t_10]) = __pyx_t_9; + + /* "region.pyx":129 + * for i in range(num): + * self._c_region_polygon.x[i] = points[i*2] + * self._c_region_polygon.y[i] = points[i*2+1] # <<<<<<<<<<<<<< + * + * def __dealloc__(self): + */ + __pyx_t_8 = PyNumber_Multiply(__pyx_v_i, __pyx_int_2); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 129, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_2 = __Pyx_PyInt_AddObjC(__pyx_t_8, __pyx_int_1, 1, 0, 0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 129, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_t_8 = __Pyx_PyObject_GetItem(__pyx_v_points, __pyx_t_2); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 129, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_9 = __pyx_PyFloat_AsFloat(__pyx_t_8); if (unlikely((__pyx_t_9 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 129, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_t_10 = __Pyx_PyIndex_AsSsize_t(__pyx_v_i); if (unlikely((__pyx_t_10 == (Py_ssize_t)-1) && PyErr_Occurred())) __PYX_ERR(0, 129, __pyx_L1_error) + (__pyx_v_self->_c_region_polygon->y[__pyx_t_10]) = __pyx_t_9; + + /* "region.pyx":127 + * raise MemoryError() + * + * for i in range(num): # <<<<<<<<<<<<<< + * self._c_region_polygon.x[i] = points[i*2] + * self._c_region_polygon.y[i] = points[i*2+1] + */ + } + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + + /* "region.pyx":107 + * cdef c_region.region_polygon* _c_region_polygon + * + * def __cinit__(self, points): # <<<<<<<<<<<<<< + * """ + * args: + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_AddTraceback("region.Polygon.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_num); + __Pyx_XDECREF(__pyx_v_i); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "region.pyx":131 + * self._c_region_polygon.y[i] = points[i*2+1] + * + * def __dealloc__(self): # <<<<<<<<<<<<<< + * if self._c_region_polygon is not NULL: + * if self._c_region_polygon.x is not NULL: + */ + +/* Python wrapper */ +static void __pyx_pw_6region_7Polygon_3__dealloc__(PyObject *__pyx_v_self); /*proto*/ +static void __pyx_pw_6region_7Polygon_3__dealloc__(PyObject *__pyx_v_self) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__dealloc__ (wrapper)", 0); + __pyx_pf_6region_7Polygon_2__dealloc__(((struct __pyx_obj_6region_Polygon *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); +} + +static void __pyx_pf_6region_7Polygon_2__dealloc__(struct __pyx_obj_6region_Polygon *__pyx_v_self) { + __Pyx_RefNannyDeclarations + int __pyx_t_1; + __Pyx_RefNannySetupContext("__dealloc__", 0); + + /* "region.pyx":132 + * + * def __dealloc__(self): + * if self._c_region_polygon is not NULL: # <<<<<<<<<<<<<< + * if self._c_region_polygon.x is not NULL: + * free(self._c_region_polygon.x) + */ + __pyx_t_1 = ((__pyx_v_self->_c_region_polygon != NULL) != 0); + if (__pyx_t_1) { + + /* "region.pyx":133 + * def __dealloc__(self): + * if self._c_region_polygon is not NULL: + * if self._c_region_polygon.x is not NULL: # <<<<<<<<<<<<<< + * free(self._c_region_polygon.x) + * self._c_region_polygon.x = NULL + */ + __pyx_t_1 = ((__pyx_v_self->_c_region_polygon->x != NULL) != 0); + if (__pyx_t_1) { + + /* "region.pyx":134 + * if self._c_region_polygon is not NULL: + * if self._c_region_polygon.x is not NULL: + * free(self._c_region_polygon.x) # <<<<<<<<<<<<<< + * self._c_region_polygon.x = NULL + * if self._c_region_polygon.y is not NULL: + */ + free(__pyx_v_self->_c_region_polygon->x); + + /* "region.pyx":135 + * if self._c_region_polygon.x is not NULL: + * free(self._c_region_polygon.x) + * self._c_region_polygon.x = NULL # <<<<<<<<<<<<<< + * if self._c_region_polygon.y is not NULL: + * free(self._c_region_polygon.y) + */ + __pyx_v_self->_c_region_polygon->x = NULL; + + /* "region.pyx":133 + * def __dealloc__(self): + * if self._c_region_polygon is not NULL: + * if self._c_region_polygon.x is not NULL: # <<<<<<<<<<<<<< + * free(self._c_region_polygon.x) + * self._c_region_polygon.x = NULL + */ + } + + /* "region.pyx":136 + * free(self._c_region_polygon.x) + * self._c_region_polygon.x = NULL + * if self._c_region_polygon.y is not NULL: # <<<<<<<<<<<<<< + * free(self._c_region_polygon.y) + * self._c_region_polygon.y = NULL + */ + __pyx_t_1 = ((__pyx_v_self->_c_region_polygon->y != NULL) != 0); + if (__pyx_t_1) { + + /* "region.pyx":137 + * self._c_region_polygon.x = NULL + * if self._c_region_polygon.y is not NULL: + * free(self._c_region_polygon.y) # <<<<<<<<<<<<<< + * self._c_region_polygon.y = NULL + * free(self._c_region_polygon) + */ + free(__pyx_v_self->_c_region_polygon->y); + + /* "region.pyx":138 + * if self._c_region_polygon.y is not NULL: + * free(self._c_region_polygon.y) + * self._c_region_polygon.y = NULL # <<<<<<<<<<<<<< + * free(self._c_region_polygon) + * self._c_region_polygon = NULL + */ + __pyx_v_self->_c_region_polygon->y = NULL; + + /* "region.pyx":136 + * free(self._c_region_polygon.x) + * self._c_region_polygon.x = NULL + * if self._c_region_polygon.y is not NULL: # <<<<<<<<<<<<<< + * free(self._c_region_polygon.y) + * self._c_region_polygon.y = NULL + */ + } + + /* "region.pyx":139 + * free(self._c_region_polygon.y) + * self._c_region_polygon.y = NULL + * free(self._c_region_polygon) # <<<<<<<<<<<<<< + * self._c_region_polygon = NULL + * + */ + free(__pyx_v_self->_c_region_polygon); + + /* "region.pyx":140 + * self._c_region_polygon.y = NULL + * free(self._c_region_polygon) + * self._c_region_polygon = NULL # <<<<<<<<<<<<<< + * + * def __str__(self): + */ + __pyx_v_self->_c_region_polygon = NULL; + + /* "region.pyx":132 + * + * def __dealloc__(self): + * if self._c_region_polygon is not NULL: # <<<<<<<<<<<<<< + * if self._c_region_polygon.x is not NULL: + * free(self._c_region_polygon.x) + */ + } + + /* "region.pyx":131 + * self._c_region_polygon.y[i] = points[i*2+1] + * + * def __dealloc__(self): # <<<<<<<<<<<<<< + * if self._c_region_polygon is not NULL: + * if self._c_region_polygon.x is not NULL: + */ + + /* function exit code */ + __Pyx_RefNannyFinishContext(); +} + +/* "region.pyx":142 + * self._c_region_polygon = NULL + * + * def __str__(self): # <<<<<<<<<<<<<< + * ret = "" + * for i in range(self._c_region_polygon.count-1): + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6region_7Polygon_5__str__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_6region_7Polygon_5__str__(PyObject *__pyx_v_self) { + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__str__ (wrapper)", 0); + __pyx_r = __pyx_pf_6region_7Polygon_4__str__(((struct __pyx_obj_6region_Polygon *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6region_7Polygon_4__str__(struct __pyx_obj_6region_Polygon *__pyx_v_self) { + PyObject *__pyx_v_ret = NULL; + long __pyx_v_i; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + long __pyx_t_1; + long __pyx_t_2; + long __pyx_t_3; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + int __pyx_t_9; + PyObject *__pyx_t_10 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__str__", 0); + + /* "region.pyx":143 + * + * def __str__(self): + * ret = "" # <<<<<<<<<<<<<< + * for i in range(self._c_region_polygon.count-1): + * ret += "({:.3f} {:.3f}) ".format(self._c_region_polygon.x[i], + */ + __Pyx_INCREF(__pyx_kp_s__5); + __pyx_v_ret = __pyx_kp_s__5; + + /* "region.pyx":144 + * def __str__(self): + * ret = "" + * for i in range(self._c_region_polygon.count-1): # <<<<<<<<<<<<<< + * ret += "({:.3f} {:.3f}) ".format(self._c_region_polygon.x[i], + * self._c_region_polygon.y[i]) + */ + __pyx_t_1 = (__pyx_v_self->_c_region_polygon->count - 1); + __pyx_t_2 = __pyx_t_1; + for (__pyx_t_3 = 0; __pyx_t_3 < __pyx_t_2; __pyx_t_3+=1) { + __pyx_v_i = __pyx_t_3; + + /* "region.pyx":145 + * ret = "" + * for i in range(self._c_region_polygon.count-1): + * ret += "({:.3f} {:.3f}) ".format(self._c_region_polygon.x[i], # <<<<<<<<<<<<<< + * self._c_region_polygon.y[i]) + * ret += "({:.3f} {:.3f})".format(self._c_region_polygon.x[i], + */ + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_kp_s_3f_3f, __pyx_n_s_format); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 145, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = PyFloat_FromDouble((__pyx_v_self->_c_region_polygon->x[__pyx_v_i])); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 145, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + + /* "region.pyx":146 + * for i in range(self._c_region_polygon.count-1): + * ret += "({:.3f} {:.3f}) ".format(self._c_region_polygon.x[i], + * self._c_region_polygon.y[i]) # <<<<<<<<<<<<<< + * ret += "({:.3f} {:.3f})".format(self._c_region_polygon.x[i], + * self._c_region_polygon.y[i]) + */ + __pyx_t_7 = PyFloat_FromDouble((__pyx_v_self->_c_region_polygon->y[__pyx_v_i])); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 146, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_8 = NULL; + __pyx_t_9 = 0; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_8 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_8)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_8); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + __pyx_t_9 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[3] = {__pyx_t_8, __pyx_t_6, __pyx_t_7}; + __pyx_t_4 = __Pyx_PyFunction_FastCall(__pyx_t_5, __pyx_temp+1-__pyx_t_9, 2+__pyx_t_9); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 145, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[3] = {__pyx_t_8, __pyx_t_6, __pyx_t_7}; + __pyx_t_4 = __Pyx_PyCFunction_FastCall(__pyx_t_5, __pyx_temp+1-__pyx_t_9, 2+__pyx_t_9); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 145, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } else + #endif + { + __pyx_t_10 = PyTuple_New(2+__pyx_t_9); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 145, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + if (__pyx_t_8) { + __Pyx_GIVEREF(__pyx_t_8); PyTuple_SET_ITEM(__pyx_t_10, 0, __pyx_t_8); __pyx_t_8 = NULL; + } + __Pyx_GIVEREF(__pyx_t_6); + PyTuple_SET_ITEM(__pyx_t_10, 0+__pyx_t_9, __pyx_t_6); + __Pyx_GIVEREF(__pyx_t_7); + PyTuple_SET_ITEM(__pyx_t_10, 1+__pyx_t_9, __pyx_t_7); + __pyx_t_6 = 0; + __pyx_t_7 = 0; + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_10, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 145, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + } + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + + /* "region.pyx":145 + * ret = "" + * for i in range(self._c_region_polygon.count-1): + * ret += "({:.3f} {:.3f}) ".format(self._c_region_polygon.x[i], # <<<<<<<<<<<<<< + * self._c_region_polygon.y[i]) + * ret += "({:.3f} {:.3f})".format(self._c_region_polygon.x[i], + */ + __pyx_t_5 = PyNumber_InPlaceAdd(__pyx_v_ret, __pyx_t_4); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 145, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF_SET(__pyx_v_ret, __pyx_t_5); + __pyx_t_5 = 0; + } + + /* "region.pyx":147 + * ret += "({:.3f} {:.3f}) ".format(self._c_region_polygon.x[i], + * self._c_region_polygon.y[i]) + * ret += "({:.3f} {:.3f})".format(self._c_region_polygon.x[i], # <<<<<<<<<<<<<< + * self._c_region_polygon.y[i]) + * return ret + */ + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_kp_s_3f_3f_2, __pyx_n_s_format); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 147, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_10 = PyFloat_FromDouble((__pyx_v_self->_c_region_polygon->x[__pyx_v_i])); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 147, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + + /* "region.pyx":148 + * self._c_region_polygon.y[i]) + * ret += "({:.3f} {:.3f})".format(self._c_region_polygon.x[i], + * self._c_region_polygon.y[i]) # <<<<<<<<<<<<<< + * return ret + * + */ + __pyx_t_7 = PyFloat_FromDouble((__pyx_v_self->_c_region_polygon->y[__pyx_v_i])); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 148, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_6 = NULL; + __pyx_t_9 = 0; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_4))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_4); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_4, function); + __pyx_t_9 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_4)) { + PyObject *__pyx_temp[3] = {__pyx_t_6, __pyx_t_10, __pyx_t_7}; + __pyx_t_5 = __Pyx_PyFunction_FastCall(__pyx_t_4, __pyx_temp+1-__pyx_t_9, 2+__pyx_t_9); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 147, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_4)) { + PyObject *__pyx_temp[3] = {__pyx_t_6, __pyx_t_10, __pyx_t_7}; + __pyx_t_5 = __Pyx_PyCFunction_FastCall(__pyx_t_4, __pyx_temp+1-__pyx_t_9, 2+__pyx_t_9); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 147, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } else + #endif + { + __pyx_t_8 = PyTuple_New(2+__pyx_t_9); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 147, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + if (__pyx_t_6) { + __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_6); __pyx_t_6 = NULL; + } + __Pyx_GIVEREF(__pyx_t_10); + PyTuple_SET_ITEM(__pyx_t_8, 0+__pyx_t_9, __pyx_t_10); + __Pyx_GIVEREF(__pyx_t_7); + PyTuple_SET_ITEM(__pyx_t_8, 1+__pyx_t_9, __pyx_t_7); + __pyx_t_10 = 0; + __pyx_t_7 = 0; + __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_8, NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 147, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + + /* "region.pyx":147 + * ret += "({:.3f} {:.3f}) ".format(self._c_region_polygon.x[i], + * self._c_region_polygon.y[i]) + * ret += "({:.3f} {:.3f})".format(self._c_region_polygon.x[i], # <<<<<<<<<<<<<< + * self._c_region_polygon.y[i]) + * return ret + */ + __pyx_t_4 = PyNumber_InPlaceAdd(__pyx_v_ret, __pyx_t_5); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 147, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF_SET(__pyx_v_ret, __pyx_t_4); + __pyx_t_4 = 0; + + /* "region.pyx":149 + * ret += "({:.3f} {:.3f})".format(self._c_region_polygon.x[i], + * self._c_region_polygon.y[i]) + * return ret # <<<<<<<<<<<<<< + * + * def vot_overlap(polygon1, polygon2, bounds=None): + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_ret); + __pyx_r = __pyx_v_ret; + goto __pyx_L0; + + /* "region.pyx":142 + * self._c_region_polygon = NULL + * + * def __str__(self): # <<<<<<<<<<<<<< + * ret = "" + * for i in range(self._c_region_polygon.count-1): + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_XDECREF(__pyx_t_10); + __Pyx_AddTraceback("region.Polygon.__str__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_ret); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + * def __setstate_cython__(self, __pyx_state): + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6region_7Polygon_7__reduce_cython__(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/ +static PyObject *__pyx_pw_6region_7Polygon_7__reduce_cython__(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) { + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__reduce_cython__ (wrapper)", 0); + __pyx_r = __pyx_pf_6region_7Polygon_6__reduce_cython__(((struct __pyx_obj_6region_Polygon *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6region_7Polygon_6__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_6region_Polygon *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__reduce_cython__", 0); + + /* "(tree fragment)":2 + * def __reduce_cython__(self): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") # <<<<<<<<<<<<<< + * def __setstate_cython__(self, __pyx_state): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_TypeError, __pyx_tuple__6, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 2, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(1, 2, __pyx_L1_error) + + /* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + * def __setstate_cython__(self, __pyx_state): + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("region.Polygon.__reduce_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6region_7Polygon_9__setstate_cython__(PyObject *__pyx_v_self, PyObject *__pyx_v___pyx_state); /*proto*/ +static PyObject *__pyx_pw_6region_7Polygon_9__setstate_cython__(PyObject *__pyx_v_self, PyObject *__pyx_v___pyx_state) { + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__setstate_cython__ (wrapper)", 0); + __pyx_r = __pyx_pf_6region_7Polygon_8__setstate_cython__(((struct __pyx_obj_6region_Polygon *)__pyx_v_self), ((PyObject *)__pyx_v___pyx_state)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6region_7Polygon_8__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_6region_Polygon *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__setstate_cython__", 0); + + /* "(tree fragment)":4 + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + * def __setstate_cython__(self, __pyx_state): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") # <<<<<<<<<<<<<< + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_TypeError, __pyx_tuple__7, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(1, 4, __pyx_L1_error) + + /* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("region.Polygon.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "region.pyx":151 + * return ret + * + * def vot_overlap(polygon1, polygon2, bounds=None): # <<<<<<<<<<<<<< + * """ computing overlap between two polygon + * Args: + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6region_1vot_overlap(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6region_vot_overlap[] = " computing overlap between two polygon\n Args:\n polygon1: polygon tuple of points\n polygon2: polygon tuple of points\n bounds: tuple of (left, top, right, bottom) or tuple of (width height)\n Return:\n overlap: overlap between two polygons\n "; +static PyMethodDef __pyx_mdef_6region_1vot_overlap = {"vot_overlap", (PyCFunction)(void*)(PyCFunctionWithKeywords)__pyx_pw_6region_1vot_overlap, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6region_vot_overlap}; +static PyObject *__pyx_pw_6region_1vot_overlap(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_polygon1 = 0; + PyObject *__pyx_v_polygon2 = 0; + PyObject *__pyx_v_bounds = 0; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("vot_overlap (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_polygon1,&__pyx_n_s_polygon2,&__pyx_n_s_bounds,0}; + PyObject* values[3] = {0,0,0}; + values[2] = ((PyObject *)Py_None); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_polygon1)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_polygon2)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("vot_overlap", 0, 2, 3, 1); __PYX_ERR(0, 151, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_bounds); + if (value) { values[2] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "vot_overlap") < 0)) __PYX_ERR(0, 151, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_polygon1 = values[0]; + __pyx_v_polygon2 = values[1]; + __pyx_v_bounds = values[2]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("vot_overlap", 0, 2, 3, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 151, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("region.vot_overlap", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6region_vot_overlap(__pyx_self, __pyx_v_polygon1, __pyx_v_polygon2, __pyx_v_bounds); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6region_vot_overlap(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_polygon1, PyObject *__pyx_v_polygon2, PyObject *__pyx_v_bounds) { + struct __pyx_obj_6region_Polygon *__pyx_v_polygon1_ = NULL; + struct __pyx_obj_6region_Polygon *__pyx_v_polygon2_ = NULL; + struct __pyx_obj_6region_RegionBounds *__pyx_v_pno_bounds = NULL; + float __pyx_v_only1; + float __pyx_v_only2; + region_polygon *__pyx_v_c_polygon1; + region_polygon *__pyx_v_c_polygon2; + region_bounds __pyx_v_no_bounds; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + Py_ssize_t __pyx_t_2; + int __pyx_t_3; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + PyObject *__pyx_t_9 = NULL; + PyObject *__pyx_t_10 = NULL; + PyObject *__pyx_t_11 = NULL; + PyObject *__pyx_t_12 = NULL; + PyObject *__pyx_t_13 = NULL; + int __pyx_t_14; + double __pyx_t_15; + region_polygon *__pyx_t_16; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("vot_overlap", 0); + + /* "region.pyx":160 + * overlap: overlap between two polygons + * """ + * if len(polygon1) == 1 or len(polygon2) == 1: # <<<<<<<<<<<<<< + * return float("nan") + * + */ + __pyx_t_2 = PyObject_Length(__pyx_v_polygon1); if (unlikely(__pyx_t_2 == ((Py_ssize_t)-1))) __PYX_ERR(0, 160, __pyx_L1_error) + __pyx_t_3 = ((__pyx_t_2 == 1) != 0); + if (!__pyx_t_3) { + } else { + __pyx_t_1 = __pyx_t_3; + goto __pyx_L4_bool_binop_done; + } + __pyx_t_2 = PyObject_Length(__pyx_v_polygon2); if (unlikely(__pyx_t_2 == ((Py_ssize_t)-1))) __PYX_ERR(0, 160, __pyx_L1_error) + __pyx_t_3 = ((__pyx_t_2 == 1) != 0); + __pyx_t_1 = __pyx_t_3; + __pyx_L4_bool_binop_done:; + if (__pyx_t_1) { + + /* "region.pyx":161 + * """ + * if len(polygon1) == 1 or len(polygon2) == 1: + * return float("nan") # <<<<<<<<<<<<<< + * + * if len(polygon1) == 4: + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_4 = __Pyx_PyNumber_Float(__pyx_n_s_nan); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 161, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_r = __pyx_t_4; + __pyx_t_4 = 0; + goto __pyx_L0; + + /* "region.pyx":160 + * overlap: overlap between two polygons + * """ + * if len(polygon1) == 1 or len(polygon2) == 1: # <<<<<<<<<<<<<< + * return float("nan") + * + */ + } + + /* "region.pyx":163 + * return float("nan") + * + * if len(polygon1) == 4: # <<<<<<<<<<<<<< + * polygon1_ = Polygon([polygon1[0], polygon1[1], + * polygon1[0]+polygon1[2], polygon1[1], + */ + __pyx_t_2 = PyObject_Length(__pyx_v_polygon1); if (unlikely(__pyx_t_2 == ((Py_ssize_t)-1))) __PYX_ERR(0, 163, __pyx_L1_error) + __pyx_t_1 = ((__pyx_t_2 == 4) != 0); + if (__pyx_t_1) { + + /* "region.pyx":164 + * + * if len(polygon1) == 4: + * polygon1_ = Polygon([polygon1[0], polygon1[1], # <<<<<<<<<<<<<< + * polygon1[0]+polygon1[2], polygon1[1], + * polygon1[0]+polygon1[2], polygon1[1]+polygon1[3], + */ + __pyx_t_4 = __Pyx_GetItemInt(__pyx_v_polygon1, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 164, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = __Pyx_GetItemInt(__pyx_v_polygon1, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 164, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + + /* "region.pyx":165 + * if len(polygon1) == 4: + * polygon1_ = Polygon([polygon1[0], polygon1[1], + * polygon1[0]+polygon1[2], polygon1[1], # <<<<<<<<<<<<<< + * polygon1[0]+polygon1[2], polygon1[1]+polygon1[3], + * polygon1[0], polygon1[1]+polygon1[3]]) + */ + __pyx_t_6 = __Pyx_GetItemInt(__pyx_v_polygon1, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 165, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_7 = __Pyx_GetItemInt(__pyx_v_polygon1, 2, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 165, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_8 = PyNumber_Add(__pyx_t_6, __pyx_t_7); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 165, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = __Pyx_GetItemInt(__pyx_v_polygon1, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 165, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + + /* "region.pyx":166 + * polygon1_ = Polygon([polygon1[0], polygon1[1], + * polygon1[0]+polygon1[2], polygon1[1], + * polygon1[0]+polygon1[2], polygon1[1]+polygon1[3], # <<<<<<<<<<<<<< + * polygon1[0], polygon1[1]+polygon1[3]]) + * else: + */ + __pyx_t_6 = __Pyx_GetItemInt(__pyx_v_polygon1, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 166, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_9 = __Pyx_GetItemInt(__pyx_v_polygon1, 2, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 166, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_10 = PyNumber_Add(__pyx_t_6, __pyx_t_9); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 166, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __pyx_t_9 = __Pyx_GetItemInt(__pyx_v_polygon1, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 166, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_6 = __Pyx_GetItemInt(__pyx_v_polygon1, 3, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 166, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_11 = PyNumber_Add(__pyx_t_9, __pyx_t_6); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 166, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_11); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + + /* "region.pyx":167 + * polygon1[0]+polygon1[2], polygon1[1], + * polygon1[0]+polygon1[2], polygon1[1]+polygon1[3], + * polygon1[0], polygon1[1]+polygon1[3]]) # <<<<<<<<<<<<<< + * else: + * polygon1_ = Polygon(polygon1) + */ + __pyx_t_6 = __Pyx_GetItemInt(__pyx_v_polygon1, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 167, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_9 = __Pyx_GetItemInt(__pyx_v_polygon1, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 167, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_12 = __Pyx_GetItemInt(__pyx_v_polygon1, 3, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 167, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_12); + __pyx_t_13 = PyNumber_Add(__pyx_t_9, __pyx_t_12); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 167, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; + + /* "region.pyx":164 + * + * if len(polygon1) == 4: + * polygon1_ = Polygon([polygon1[0], polygon1[1], # <<<<<<<<<<<<<< + * polygon1[0]+polygon1[2], polygon1[1], + * polygon1[0]+polygon1[2], polygon1[1]+polygon1[3], + */ + __pyx_t_12 = PyList_New(8); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 164, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_12); + __Pyx_GIVEREF(__pyx_t_4); + PyList_SET_ITEM(__pyx_t_12, 0, __pyx_t_4); + __Pyx_GIVEREF(__pyx_t_5); + PyList_SET_ITEM(__pyx_t_12, 1, __pyx_t_5); + __Pyx_GIVEREF(__pyx_t_8); + PyList_SET_ITEM(__pyx_t_12, 2, __pyx_t_8); + __Pyx_GIVEREF(__pyx_t_7); + PyList_SET_ITEM(__pyx_t_12, 3, __pyx_t_7); + __Pyx_GIVEREF(__pyx_t_10); + PyList_SET_ITEM(__pyx_t_12, 4, __pyx_t_10); + __Pyx_GIVEREF(__pyx_t_11); + PyList_SET_ITEM(__pyx_t_12, 5, __pyx_t_11); + __Pyx_GIVEREF(__pyx_t_6); + PyList_SET_ITEM(__pyx_t_12, 6, __pyx_t_6); + __Pyx_GIVEREF(__pyx_t_13); + PyList_SET_ITEM(__pyx_t_12, 7, __pyx_t_13); + __pyx_t_4 = 0; + __pyx_t_5 = 0; + __pyx_t_8 = 0; + __pyx_t_7 = 0; + __pyx_t_10 = 0; + __pyx_t_11 = 0; + __pyx_t_6 = 0; + __pyx_t_13 = 0; + __pyx_t_13 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_6region_Polygon), __pyx_t_12); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 164, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; + __pyx_v_polygon1_ = ((struct __pyx_obj_6region_Polygon *)__pyx_t_13); + __pyx_t_13 = 0; + + /* "region.pyx":163 + * return float("nan") + * + * if len(polygon1) == 4: # <<<<<<<<<<<<<< + * polygon1_ = Polygon([polygon1[0], polygon1[1], + * polygon1[0]+polygon1[2], polygon1[1], + */ + goto __pyx_L6; + } + + /* "region.pyx":169 + * polygon1[0], polygon1[1]+polygon1[3]]) + * else: + * polygon1_ = Polygon(polygon1) # <<<<<<<<<<<<<< + * + * if len(polygon2) == 4: + */ + /*else*/ { + __pyx_t_13 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_6region_Polygon), __pyx_v_polygon1); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 169, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + __pyx_v_polygon1_ = ((struct __pyx_obj_6region_Polygon *)__pyx_t_13); + __pyx_t_13 = 0; + } + __pyx_L6:; + + /* "region.pyx":171 + * polygon1_ = Polygon(polygon1) + * + * if len(polygon2) == 4: # <<<<<<<<<<<<<< + * polygon2_ = Polygon([polygon2[0], polygon2[1], + * polygon2[0]+polygon2[2], polygon2[1], + */ + __pyx_t_2 = PyObject_Length(__pyx_v_polygon2); if (unlikely(__pyx_t_2 == ((Py_ssize_t)-1))) __PYX_ERR(0, 171, __pyx_L1_error) + __pyx_t_1 = ((__pyx_t_2 == 4) != 0); + if (__pyx_t_1) { + + /* "region.pyx":172 + * + * if len(polygon2) == 4: + * polygon2_ = Polygon([polygon2[0], polygon2[1], # <<<<<<<<<<<<<< + * polygon2[0]+polygon2[2], polygon2[1], + * polygon2[0]+polygon2[2], polygon2[1]+polygon2[3], + */ + __pyx_t_13 = __Pyx_GetItemInt(__pyx_v_polygon2, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 172, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + __pyx_t_12 = __Pyx_GetItemInt(__pyx_v_polygon2, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 172, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_12); + + /* "region.pyx":173 + * if len(polygon2) == 4: + * polygon2_ = Polygon([polygon2[0], polygon2[1], + * polygon2[0]+polygon2[2], polygon2[1], # <<<<<<<<<<<<<< + * polygon2[0]+polygon2[2], polygon2[1]+polygon2[3], + * polygon2[0], polygon2[1]+polygon2[3]]) + */ + __pyx_t_6 = __Pyx_GetItemInt(__pyx_v_polygon2, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 173, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_11 = __Pyx_GetItemInt(__pyx_v_polygon2, 2, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 173, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_11); + __pyx_t_10 = PyNumber_Add(__pyx_t_6, __pyx_t_11); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 173, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; + __pyx_t_11 = __Pyx_GetItemInt(__pyx_v_polygon2, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 173, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_11); + + /* "region.pyx":174 + * polygon2_ = Polygon([polygon2[0], polygon2[1], + * polygon2[0]+polygon2[2], polygon2[1], + * polygon2[0]+polygon2[2], polygon2[1]+polygon2[3], # <<<<<<<<<<<<<< + * polygon2[0], polygon2[1]+polygon2[3]]) + * else: + */ + __pyx_t_6 = __Pyx_GetItemInt(__pyx_v_polygon2, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 174, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_7 = __Pyx_GetItemInt(__pyx_v_polygon2, 2, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 174, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_8 = PyNumber_Add(__pyx_t_6, __pyx_t_7); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 174, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_7 = __Pyx_GetItemInt(__pyx_v_polygon2, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 174, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_6 = __Pyx_GetItemInt(__pyx_v_polygon2, 3, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 174, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_5 = PyNumber_Add(__pyx_t_7, __pyx_t_6); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 174, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + + /* "region.pyx":175 + * polygon2[0]+polygon2[2], polygon2[1], + * polygon2[0]+polygon2[2], polygon2[1]+polygon2[3], + * polygon2[0], polygon2[1]+polygon2[3]]) # <<<<<<<<<<<<<< + * else: + * polygon2_ = Polygon(polygon2) + */ + __pyx_t_6 = __Pyx_GetItemInt(__pyx_v_polygon2, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 175, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_7 = __Pyx_GetItemInt(__pyx_v_polygon2, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 175, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_4 = __Pyx_GetItemInt(__pyx_v_polygon2, 3, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 175, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_9 = PyNumber_Add(__pyx_t_7, __pyx_t_4); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 175, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + + /* "region.pyx":172 + * + * if len(polygon2) == 4: + * polygon2_ = Polygon([polygon2[0], polygon2[1], # <<<<<<<<<<<<<< + * polygon2[0]+polygon2[2], polygon2[1], + * polygon2[0]+polygon2[2], polygon2[1]+polygon2[3], + */ + __pyx_t_4 = PyList_New(8); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 172, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_GIVEREF(__pyx_t_13); + PyList_SET_ITEM(__pyx_t_4, 0, __pyx_t_13); + __Pyx_GIVEREF(__pyx_t_12); + PyList_SET_ITEM(__pyx_t_4, 1, __pyx_t_12); + __Pyx_GIVEREF(__pyx_t_10); + PyList_SET_ITEM(__pyx_t_4, 2, __pyx_t_10); + __Pyx_GIVEREF(__pyx_t_11); + PyList_SET_ITEM(__pyx_t_4, 3, __pyx_t_11); + __Pyx_GIVEREF(__pyx_t_8); + PyList_SET_ITEM(__pyx_t_4, 4, __pyx_t_8); + __Pyx_GIVEREF(__pyx_t_5); + PyList_SET_ITEM(__pyx_t_4, 5, __pyx_t_5); + __Pyx_GIVEREF(__pyx_t_6); + PyList_SET_ITEM(__pyx_t_4, 6, __pyx_t_6); + __Pyx_GIVEREF(__pyx_t_9); + PyList_SET_ITEM(__pyx_t_4, 7, __pyx_t_9); + __pyx_t_13 = 0; + __pyx_t_12 = 0; + __pyx_t_10 = 0; + __pyx_t_11 = 0; + __pyx_t_8 = 0; + __pyx_t_5 = 0; + __pyx_t_6 = 0; + __pyx_t_9 = 0; + __pyx_t_9 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_6region_Polygon), __pyx_t_4); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 172, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_v_polygon2_ = ((struct __pyx_obj_6region_Polygon *)__pyx_t_9); + __pyx_t_9 = 0; + + /* "region.pyx":171 + * polygon1_ = Polygon(polygon1) + * + * if len(polygon2) == 4: # <<<<<<<<<<<<<< + * polygon2_ = Polygon([polygon2[0], polygon2[1], + * polygon2[0]+polygon2[2], polygon2[1], + */ + goto __pyx_L7; + } + + /* "region.pyx":177 + * polygon2[0], polygon2[1]+polygon2[3]]) + * else: + * polygon2_ = Polygon(polygon2) # <<<<<<<<<<<<<< + * + * if bounds is not None and len(bounds) == 4: + */ + /*else*/ { + __pyx_t_9 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_6region_Polygon), __pyx_v_polygon2); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 177, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_v_polygon2_ = ((struct __pyx_obj_6region_Polygon *)__pyx_t_9); + __pyx_t_9 = 0; + } + __pyx_L7:; + + /* "region.pyx":179 + * polygon2_ = Polygon(polygon2) + * + * if bounds is not None and len(bounds) == 4: # <<<<<<<<<<<<<< + * pno_bounds = RegionBounds(bounds[0], bounds[1], bounds[2], bounds[3]) + * elif bounds is not None and len(bounds) == 2: + */ + __pyx_t_3 = (__pyx_v_bounds != Py_None); + __pyx_t_14 = (__pyx_t_3 != 0); + if (__pyx_t_14) { + } else { + __pyx_t_1 = __pyx_t_14; + goto __pyx_L9_bool_binop_done; + } + __pyx_t_2 = PyObject_Length(__pyx_v_bounds); if (unlikely(__pyx_t_2 == ((Py_ssize_t)-1))) __PYX_ERR(0, 179, __pyx_L1_error) + __pyx_t_14 = ((__pyx_t_2 == 4) != 0); + __pyx_t_1 = __pyx_t_14; + __pyx_L9_bool_binop_done:; + if (__pyx_t_1) { + + /* "region.pyx":180 + * + * if bounds is not None and len(bounds) == 4: + * pno_bounds = RegionBounds(bounds[0], bounds[1], bounds[2], bounds[3]) # <<<<<<<<<<<<<< + * elif bounds is not None and len(bounds) == 2: + * pno_bounds = RegionBounds(0, bounds[1], 0, bounds[0]) + */ + __pyx_t_9 = __Pyx_GetItemInt(__pyx_v_bounds, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 180, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_4 = __Pyx_GetItemInt(__pyx_v_bounds, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 180, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_6 = __Pyx_GetItemInt(__pyx_v_bounds, 2, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 180, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_5 = __Pyx_GetItemInt(__pyx_v_bounds, 3, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 180, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_8 = PyTuple_New(4); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 180, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_GIVEREF(__pyx_t_9); + PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_9); + __Pyx_GIVEREF(__pyx_t_4); + PyTuple_SET_ITEM(__pyx_t_8, 1, __pyx_t_4); + __Pyx_GIVEREF(__pyx_t_6); + PyTuple_SET_ITEM(__pyx_t_8, 2, __pyx_t_6); + __Pyx_GIVEREF(__pyx_t_5); + PyTuple_SET_ITEM(__pyx_t_8, 3, __pyx_t_5); + __pyx_t_9 = 0; + __pyx_t_4 = 0; + __pyx_t_6 = 0; + __pyx_t_5 = 0; + __pyx_t_5 = __Pyx_PyObject_Call(((PyObject *)__pyx_ptype_6region_RegionBounds), __pyx_t_8, NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 180, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_v_pno_bounds = ((struct __pyx_obj_6region_RegionBounds *)__pyx_t_5); + __pyx_t_5 = 0; + + /* "region.pyx":179 + * polygon2_ = Polygon(polygon2) + * + * if bounds is not None and len(bounds) == 4: # <<<<<<<<<<<<<< + * pno_bounds = RegionBounds(bounds[0], bounds[1], bounds[2], bounds[3]) + * elif bounds is not None and len(bounds) == 2: + */ + goto __pyx_L8; + } + + /* "region.pyx":181 + * if bounds is not None and len(bounds) == 4: + * pno_bounds = RegionBounds(bounds[0], bounds[1], bounds[2], bounds[3]) + * elif bounds is not None and len(bounds) == 2: # <<<<<<<<<<<<<< + * pno_bounds = RegionBounds(0, bounds[1], 0, bounds[0]) + * else: + */ + __pyx_t_14 = (__pyx_v_bounds != Py_None); + __pyx_t_3 = (__pyx_t_14 != 0); + if (__pyx_t_3) { + } else { + __pyx_t_1 = __pyx_t_3; + goto __pyx_L11_bool_binop_done; + } + __pyx_t_2 = PyObject_Length(__pyx_v_bounds); if (unlikely(__pyx_t_2 == ((Py_ssize_t)-1))) __PYX_ERR(0, 181, __pyx_L1_error) + __pyx_t_3 = ((__pyx_t_2 == 2) != 0); + __pyx_t_1 = __pyx_t_3; + __pyx_L11_bool_binop_done:; + if (__pyx_t_1) { + + /* "region.pyx":182 + * pno_bounds = RegionBounds(bounds[0], bounds[1], bounds[2], bounds[3]) + * elif bounds is not None and len(bounds) == 2: + * pno_bounds = RegionBounds(0, bounds[1], 0, bounds[0]) # <<<<<<<<<<<<<< + * else: + * pno_bounds = RegionBounds(-float("inf"), float("inf"), + */ + __pyx_t_5 = __Pyx_GetItemInt(__pyx_v_bounds, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 182, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_8 = __Pyx_GetItemInt(__pyx_v_bounds, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 182, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_6 = PyTuple_New(4); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 182, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_INCREF(__pyx_int_0); + __Pyx_GIVEREF(__pyx_int_0); + PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_int_0); + __Pyx_GIVEREF(__pyx_t_5); + PyTuple_SET_ITEM(__pyx_t_6, 1, __pyx_t_5); + __Pyx_INCREF(__pyx_int_0); + __Pyx_GIVEREF(__pyx_int_0); + PyTuple_SET_ITEM(__pyx_t_6, 2, __pyx_int_0); + __Pyx_GIVEREF(__pyx_t_8); + PyTuple_SET_ITEM(__pyx_t_6, 3, __pyx_t_8); + __pyx_t_5 = 0; + __pyx_t_8 = 0; + __pyx_t_8 = __Pyx_PyObject_Call(((PyObject *)__pyx_ptype_6region_RegionBounds), __pyx_t_6, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 182, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __pyx_v_pno_bounds = ((struct __pyx_obj_6region_RegionBounds *)__pyx_t_8); + __pyx_t_8 = 0; + + /* "region.pyx":181 + * if bounds is not None and len(bounds) == 4: + * pno_bounds = RegionBounds(bounds[0], bounds[1], bounds[2], bounds[3]) + * elif bounds is not None and len(bounds) == 2: # <<<<<<<<<<<<<< + * pno_bounds = RegionBounds(0, bounds[1], 0, bounds[0]) + * else: + */ + goto __pyx_L8; + } + + /* "region.pyx":184 + * pno_bounds = RegionBounds(0, bounds[1], 0, bounds[0]) + * else: + * pno_bounds = RegionBounds(-float("inf"), float("inf"), # <<<<<<<<<<<<<< + * -float("inf"), float("inf")) + * cdef float only1 = 0 + */ + /*else*/ { + __pyx_t_15 = __Pyx_PyObject_AsDouble(__pyx_n_s_inf); if (unlikely(__pyx_t_15 == ((double)((double)-1)) && PyErr_Occurred())) __PYX_ERR(0, 184, __pyx_L1_error) + __pyx_t_8 = PyFloat_FromDouble((-__pyx_t_15)); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 184, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_6 = __Pyx_PyNumber_Float(__pyx_n_s_inf); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 184, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + + /* "region.pyx":185 + * else: + * pno_bounds = RegionBounds(-float("inf"), float("inf"), + * -float("inf"), float("inf")) # <<<<<<<<<<<<<< + * cdef float only1 = 0 + * cdef float only2 = 0 + */ + __pyx_t_15 = __Pyx_PyObject_AsDouble(__pyx_n_s_inf); if (unlikely(__pyx_t_15 == ((double)((double)-1)) && PyErr_Occurred())) __PYX_ERR(0, 185, __pyx_L1_error) + __pyx_t_5 = PyFloat_FromDouble((-__pyx_t_15)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 185, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_4 = __Pyx_PyNumber_Float(__pyx_n_s_inf); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 185, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + + /* "region.pyx":184 + * pno_bounds = RegionBounds(0, bounds[1], 0, bounds[0]) + * else: + * pno_bounds = RegionBounds(-float("inf"), float("inf"), # <<<<<<<<<<<<<< + * -float("inf"), float("inf")) + * cdef float only1 = 0 + */ + __pyx_t_9 = PyTuple_New(4); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 184, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __Pyx_GIVEREF(__pyx_t_8); + PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_8); + __Pyx_GIVEREF(__pyx_t_6); + PyTuple_SET_ITEM(__pyx_t_9, 1, __pyx_t_6); + __Pyx_GIVEREF(__pyx_t_5); + PyTuple_SET_ITEM(__pyx_t_9, 2, __pyx_t_5); + __Pyx_GIVEREF(__pyx_t_4); + PyTuple_SET_ITEM(__pyx_t_9, 3, __pyx_t_4); + __pyx_t_8 = 0; + __pyx_t_6 = 0; + __pyx_t_5 = 0; + __pyx_t_4 = 0; + __pyx_t_4 = __Pyx_PyObject_Call(((PyObject *)__pyx_ptype_6region_RegionBounds), __pyx_t_9, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 184, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __pyx_v_pno_bounds = ((struct __pyx_obj_6region_RegionBounds *)__pyx_t_4); + __pyx_t_4 = 0; + } + __pyx_L8:; + + /* "region.pyx":186 + * pno_bounds = RegionBounds(-float("inf"), float("inf"), + * -float("inf"), float("inf")) + * cdef float only1 = 0 # <<<<<<<<<<<<<< + * cdef float only2 = 0 + * cdef c_region.region_polygon* c_polygon1 = polygon1_._c_region_polygon + */ + __pyx_v_only1 = 0.0; + + /* "region.pyx":187 + * -float("inf"), float("inf")) + * cdef float only1 = 0 + * cdef float only2 = 0 # <<<<<<<<<<<<<< + * cdef c_region.region_polygon* c_polygon1 = polygon1_._c_region_polygon + * cdef c_region.region_polygon* c_polygon2 = polygon2_._c_region_polygon + */ + __pyx_v_only2 = 0.0; + + /* "region.pyx":188 + * cdef float only1 = 0 + * cdef float only2 = 0 + * cdef c_region.region_polygon* c_polygon1 = polygon1_._c_region_polygon # <<<<<<<<<<<<<< + * cdef c_region.region_polygon* c_polygon2 = polygon2_._c_region_polygon + * cdef c_region.region_bounds no_bounds = pno_bounds._c_region_bounds[0] # deference + */ + __pyx_t_16 = __pyx_v_polygon1_->_c_region_polygon; + __pyx_v_c_polygon1 = __pyx_t_16; + + /* "region.pyx":189 + * cdef float only2 = 0 + * cdef c_region.region_polygon* c_polygon1 = polygon1_._c_region_polygon + * cdef c_region.region_polygon* c_polygon2 = polygon2_._c_region_polygon # <<<<<<<<<<<<<< + * cdef c_region.region_bounds no_bounds = pno_bounds._c_region_bounds[0] # deference + * return c_region.compute_polygon_overlap(c_polygon1, + */ + __pyx_t_16 = __pyx_v_polygon2_->_c_region_polygon; + __pyx_v_c_polygon2 = __pyx_t_16; + + /* "region.pyx":190 + * cdef c_region.region_polygon* c_polygon1 = polygon1_._c_region_polygon + * cdef c_region.region_polygon* c_polygon2 = polygon2_._c_region_polygon + * cdef c_region.region_bounds no_bounds = pno_bounds._c_region_bounds[0] # deference # <<<<<<<<<<<<<< + * return c_region.compute_polygon_overlap(c_polygon1, + * c_polygon2, + */ + __pyx_v_no_bounds = (__pyx_v_pno_bounds->_c_region_bounds[0]); + + /* "region.pyx":191 + * cdef c_region.region_polygon* c_polygon2 = polygon2_._c_region_polygon + * cdef c_region.region_bounds no_bounds = pno_bounds._c_region_bounds[0] # deference + * return c_region.compute_polygon_overlap(c_polygon1, # <<<<<<<<<<<<<< + * c_polygon2, + * &only1, + */ + __Pyx_XDECREF(__pyx_r); + + /* "region.pyx":195 + * &only1, + * &only2, + * no_bounds) # <<<<<<<<<<<<<< + * + * def vot_overlap_traj(polygons1, polygons2, bounds=None): + */ + __pyx_t_4 = PyFloat_FromDouble(compute_polygon_overlap(__pyx_v_c_polygon1, __pyx_v_c_polygon2, (&__pyx_v_only1), (&__pyx_v_only2), __pyx_v_no_bounds)); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 191, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_r = __pyx_t_4; + __pyx_t_4 = 0; + goto __pyx_L0; + + /* "region.pyx":151 + * return ret + * + * def vot_overlap(polygon1, polygon2, bounds=None): # <<<<<<<<<<<<<< + * """ computing overlap between two polygon + * Args: + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_XDECREF(__pyx_t_10); + __Pyx_XDECREF(__pyx_t_11); + __Pyx_XDECREF(__pyx_t_12); + __Pyx_XDECREF(__pyx_t_13); + __Pyx_AddTraceback("region.vot_overlap", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_polygon1_); + __Pyx_XDECREF((PyObject *)__pyx_v_polygon2_); + __Pyx_XDECREF((PyObject *)__pyx_v_pno_bounds); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "region.pyx":197 + * no_bounds) + * + * def vot_overlap_traj(polygons1, polygons2, bounds=None): # <<<<<<<<<<<<<< + * """ computing overlap between two trajectory + * Args: + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6region_3vot_overlap_traj(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6region_2vot_overlap_traj[] = " computing overlap between two trajectory\n Args:\n polygons1: list of polygon\n polygons2: list of polygon\n bounds: tuple of (left, top, right, bottom) or tuple of (width height)\n Return:\n overlaps: overlaps between all pair of polygons\n "; +static PyMethodDef __pyx_mdef_6region_3vot_overlap_traj = {"vot_overlap_traj", (PyCFunction)(void*)(PyCFunctionWithKeywords)__pyx_pw_6region_3vot_overlap_traj, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6region_2vot_overlap_traj}; +static PyObject *__pyx_pw_6region_3vot_overlap_traj(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_polygons1 = 0; + PyObject *__pyx_v_polygons2 = 0; + PyObject *__pyx_v_bounds = 0; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("vot_overlap_traj (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_polygons1,&__pyx_n_s_polygons2,&__pyx_n_s_bounds,0}; + PyObject* values[3] = {0,0,0}; + values[2] = ((PyObject *)Py_None); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_polygons1)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_polygons2)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("vot_overlap_traj", 0, 2, 3, 1); __PYX_ERR(0, 197, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_bounds); + if (value) { values[2] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "vot_overlap_traj") < 0)) __PYX_ERR(0, 197, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_polygons1 = values[0]; + __pyx_v_polygons2 = values[1]; + __pyx_v_bounds = values[2]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("vot_overlap_traj", 0, 2, 3, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 197, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("region.vot_overlap_traj", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6region_2vot_overlap_traj(__pyx_self, __pyx_v_polygons1, __pyx_v_polygons2, __pyx_v_bounds); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6region_2vot_overlap_traj(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_polygons1, PyObject *__pyx_v_polygons2, PyObject *__pyx_v_bounds) { + PyObject *__pyx_v_overlaps = NULL; + Py_ssize_t __pyx_v_i; + PyObject *__pyx_v_overlap = NULL; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + Py_ssize_t __pyx_t_1; + Py_ssize_t __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + Py_ssize_t __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + int __pyx_t_8; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("vot_overlap_traj", 0); + + /* "region.pyx":206 + * overlaps: overlaps between all pair of polygons + * """ + * assert len(polygons1) == len(polygons2) # <<<<<<<<<<<<<< + * overlaps = [] + * for i in range(len(polygons1)): + */ + #ifndef CYTHON_WITHOUT_ASSERTIONS + if (unlikely(!Py_OptimizeFlag)) { + __pyx_t_1 = PyObject_Length(__pyx_v_polygons1); if (unlikely(__pyx_t_1 == ((Py_ssize_t)-1))) __PYX_ERR(0, 206, __pyx_L1_error) + __pyx_t_2 = PyObject_Length(__pyx_v_polygons2); if (unlikely(__pyx_t_2 == ((Py_ssize_t)-1))) __PYX_ERR(0, 206, __pyx_L1_error) + if (unlikely(!((__pyx_t_1 == __pyx_t_2) != 0))) { + PyErr_SetNone(PyExc_AssertionError); + __PYX_ERR(0, 206, __pyx_L1_error) + } + } + #endif + + /* "region.pyx":207 + * """ + * assert len(polygons1) == len(polygons2) + * overlaps = [] # <<<<<<<<<<<<<< + * for i in range(len(polygons1)): + * overlap = vot_overlap(polygons1[i], polygons2[i], bounds=bounds) + */ + __pyx_t_3 = PyList_New(0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 207, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_v_overlaps = ((PyObject*)__pyx_t_3); + __pyx_t_3 = 0; + + /* "region.pyx":208 + * assert len(polygons1) == len(polygons2) + * overlaps = [] + * for i in range(len(polygons1)): # <<<<<<<<<<<<<< + * overlap = vot_overlap(polygons1[i], polygons2[i], bounds=bounds) + * overlaps.append(overlap) + */ + __pyx_t_2 = PyObject_Length(__pyx_v_polygons1); if (unlikely(__pyx_t_2 == ((Py_ssize_t)-1))) __PYX_ERR(0, 208, __pyx_L1_error) + __pyx_t_1 = __pyx_t_2; + for (__pyx_t_4 = 0; __pyx_t_4 < __pyx_t_1; __pyx_t_4+=1) { + __pyx_v_i = __pyx_t_4; + + /* "region.pyx":209 + * overlaps = [] + * for i in range(len(polygons1)): + * overlap = vot_overlap(polygons1[i], polygons2[i], bounds=bounds) # <<<<<<<<<<<<<< + * overlaps.append(overlap) + * return overlaps + */ + __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_vot_overlap); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 209, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_5 = __Pyx_GetItemInt(__pyx_v_polygons1, __pyx_v_i, Py_ssize_t, 1, PyInt_FromSsize_t, 0, 1, 1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 209, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = __Pyx_GetItemInt(__pyx_v_polygons2, __pyx_v_i, Py_ssize_t, 1, PyInt_FromSsize_t, 0, 1, 1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 209, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_7 = PyTuple_New(2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 209, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_GIVEREF(__pyx_t_5); + PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_5); + __Pyx_GIVEREF(__pyx_t_6); + PyTuple_SET_ITEM(__pyx_t_7, 1, __pyx_t_6); + __pyx_t_5 = 0; + __pyx_t_6 = 0; + __pyx_t_6 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 209, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + if (PyDict_SetItem(__pyx_t_6, __pyx_n_s_bounds, __pyx_v_bounds) < 0) __PYX_ERR(0, 209, __pyx_L1_error) + __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_7, __pyx_t_6); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 209, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_XDECREF_SET(__pyx_v_overlap, __pyx_t_5); + __pyx_t_5 = 0; + + /* "region.pyx":210 + * for i in range(len(polygons1)): + * overlap = vot_overlap(polygons1[i], polygons2[i], bounds=bounds) + * overlaps.append(overlap) # <<<<<<<<<<<<<< + * return overlaps + * + */ + __pyx_t_8 = __Pyx_PyList_Append(__pyx_v_overlaps, __pyx_v_overlap); if (unlikely(__pyx_t_8 == ((int)-1))) __PYX_ERR(0, 210, __pyx_L1_error) + } + + /* "region.pyx":211 + * overlap = vot_overlap(polygons1[i], polygons2[i], bounds=bounds) + * overlaps.append(overlap) + * return overlaps # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_overlaps); + __pyx_r = __pyx_v_overlaps; + goto __pyx_L0; + + /* "region.pyx":197 + * no_bounds) + * + * def vot_overlap_traj(polygons1, polygons2, bounds=None): # <<<<<<<<<<<<<< + * """ computing overlap between two trajectory + * Args: + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_AddTraceback("region.vot_overlap_traj", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_overlaps); + __Pyx_XDECREF(__pyx_v_overlap); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "region.pyx":214 + * + * + * def vot_float2str(template, float value): # <<<<<<<<<<<<<< + * """ + * Args: + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6region_5vot_float2str(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6region_4vot_float2str[] = "\n Args:\n tempate: like \"%.3f\" in C syntax\n value: float value\n "; +static PyMethodDef __pyx_mdef_6region_5vot_float2str = {"vot_float2str", (PyCFunction)(void*)(PyCFunctionWithKeywords)__pyx_pw_6region_5vot_float2str, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6region_4vot_float2str}; +static PyObject *__pyx_pw_6region_5vot_float2str(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_template = 0; + float __pyx_v_value; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("vot_float2str (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_template,&__pyx_n_s_value,0}; + PyObject* values[2] = {0,0}; + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_template)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_value)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("vot_float2str", 1, 2, 2, 1); __PYX_ERR(0, 214, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "vot_float2str") < 0)) __PYX_ERR(0, 214, __pyx_L3_error) + } + } else if (PyTuple_GET_SIZE(__pyx_args) != 2) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + } + __pyx_v_template = values[0]; + __pyx_v_value = __pyx_PyFloat_AsFloat(values[1]); if (unlikely((__pyx_v_value == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 214, __pyx_L3_error) + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("vot_float2str", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 214, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("region.vot_float2str", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6region_4vot_float2str(__pyx_self, __pyx_v_template, __pyx_v_value); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6region_4vot_float2str(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_template, float __pyx_v_value) { + PyObject *__pyx_v_ptemplate = 0; + char const *__pyx_v_ctemplate; + char *__pyx_v_output; + PyObject *__pyx_v_ret = NULL; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + char const *__pyx_t_4; + int __pyx_t_5; + int __pyx_t_6; + int __pyx_t_7; + char const *__pyx_t_8; + PyObject *__pyx_t_9 = NULL; + PyObject *__pyx_t_10 = NULL; + PyObject *__pyx_t_11 = NULL; + PyObject *__pyx_t_12 = NULL; + PyObject *__pyx_t_13 = NULL; + PyObject *__pyx_t_14 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("vot_float2str", 0); + + /* "region.pyx":220 + * value: float value + * """ + * cdef bytes ptemplate = template.encode() # <<<<<<<<<<<<<< + * cdef const char* ctemplate = ptemplate + * cdef char* output = malloc(sizeof(char) * 100) + */ + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_template, __pyx_n_s_encode); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 220, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + } + } + __pyx_t_1 = (__pyx_t_3) ? __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_3) : __Pyx_PyObject_CallNoArg(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 220, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (!(likely(PyBytes_CheckExact(__pyx_t_1))||((__pyx_t_1) == Py_None)||((void)PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytes", Py_TYPE(__pyx_t_1)->tp_name), 0))) __PYX_ERR(0, 220, __pyx_L1_error) + __pyx_v_ptemplate = ((PyObject*)__pyx_t_1); + __pyx_t_1 = 0; + + /* "region.pyx":221 + * """ + * cdef bytes ptemplate = template.encode() + * cdef const char* ctemplate = ptemplate # <<<<<<<<<<<<<< + * cdef char* output = malloc(sizeof(char) * 100) + * if not output: + */ + if (unlikely(__pyx_v_ptemplate == Py_None)) { + PyErr_SetString(PyExc_TypeError, "expected bytes, NoneType found"); + __PYX_ERR(0, 221, __pyx_L1_error) + } + __pyx_t_4 = __Pyx_PyBytes_AsString(__pyx_v_ptemplate); if (unlikely((!__pyx_t_4) && PyErr_Occurred())) __PYX_ERR(0, 221, __pyx_L1_error) + __pyx_v_ctemplate = __pyx_t_4; + + /* "region.pyx":222 + * cdef bytes ptemplate = template.encode() + * cdef const char* ctemplate = ptemplate + * cdef char* output = malloc(sizeof(char) * 100) # <<<<<<<<<<<<<< + * if not output: + * raise MemoryError() + */ + __pyx_v_output = ((char *)malloc(((sizeof(char)) * 0x64))); + + /* "region.pyx":223 + * cdef const char* ctemplate = ptemplate + * cdef char* output = malloc(sizeof(char) * 100) + * if not output: # <<<<<<<<<<<<<< + * raise MemoryError() + * sprintf(output, ctemplate, value) + */ + __pyx_t_5 = ((!(__pyx_v_output != 0)) != 0); + if (unlikely(__pyx_t_5)) { + + /* "region.pyx":224 + * cdef char* output = malloc(sizeof(char) * 100) + * if not output: + * raise MemoryError() # <<<<<<<<<<<<<< + * sprintf(output, ctemplate, value) + * try: + */ + PyErr_NoMemory(); __PYX_ERR(0, 224, __pyx_L1_error) + + /* "region.pyx":223 + * cdef const char* ctemplate = ptemplate + * cdef char* output = malloc(sizeof(char) * 100) + * if not output: # <<<<<<<<<<<<<< + * raise MemoryError() + * sprintf(output, ctemplate, value) + */ + } + + /* "region.pyx":225 + * if not output: + * raise MemoryError() + * sprintf(output, ctemplate, value) # <<<<<<<<<<<<<< + * try: + * ret = output[:strlen(output)].decode() + */ + (void)(sprintf(__pyx_v_output, __pyx_v_ctemplate, __pyx_v_value)); + + /* "region.pyx":226 + * raise MemoryError() + * sprintf(output, ctemplate, value) + * try: # <<<<<<<<<<<<<< + * ret = output[:strlen(output)].decode() + * finally: + */ + /*try:*/ { + + /* "region.pyx":227 + * sprintf(output, ctemplate, value) + * try: + * ret = output[:strlen(output)].decode() # <<<<<<<<<<<<<< + * finally: + * free(output) + */ + __pyx_t_1 = __Pyx_decode_c_string(__pyx_v_output, 0, strlen(__pyx_v_output), NULL, NULL, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 227, __pyx_L5_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_ret = __pyx_t_1; + __pyx_t_1 = 0; + } + + /* "region.pyx":229 + * ret = output[:strlen(output)].decode() + * finally: + * free(output) # <<<<<<<<<<<<<< + * return ret + */ + /*finally:*/ { + /*normal exit:*/{ + free(__pyx_v_output); + goto __pyx_L6; + } + __pyx_L5_error:; + /*exception exit:*/{ + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __pyx_t_9 = 0; __pyx_t_10 = 0; __pyx_t_11 = 0; __pyx_t_12 = 0; __pyx_t_13 = 0; __pyx_t_14 = 0; + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + if (PY_MAJOR_VERSION >= 3) __Pyx_ExceptionSwap(&__pyx_t_12, &__pyx_t_13, &__pyx_t_14); + if ((PY_MAJOR_VERSION < 3) || unlikely(__Pyx_GetException(&__pyx_t_9, &__pyx_t_10, &__pyx_t_11) < 0)) __Pyx_ErrFetch(&__pyx_t_9, &__pyx_t_10, &__pyx_t_11); + __Pyx_XGOTREF(__pyx_t_9); + __Pyx_XGOTREF(__pyx_t_10); + __Pyx_XGOTREF(__pyx_t_11); + __Pyx_XGOTREF(__pyx_t_12); + __Pyx_XGOTREF(__pyx_t_13); + __Pyx_XGOTREF(__pyx_t_14); + __pyx_t_6 = __pyx_lineno; __pyx_t_7 = __pyx_clineno; __pyx_t_8 = __pyx_filename; + { + free(__pyx_v_output); + } + if (PY_MAJOR_VERSION >= 3) { + __Pyx_XGIVEREF(__pyx_t_12); + __Pyx_XGIVEREF(__pyx_t_13); + __Pyx_XGIVEREF(__pyx_t_14); + __Pyx_ExceptionReset(__pyx_t_12, __pyx_t_13, __pyx_t_14); + } + __Pyx_XGIVEREF(__pyx_t_9); + __Pyx_XGIVEREF(__pyx_t_10); + __Pyx_XGIVEREF(__pyx_t_11); + __Pyx_ErrRestore(__pyx_t_9, __pyx_t_10, __pyx_t_11); + __pyx_t_9 = 0; __pyx_t_10 = 0; __pyx_t_11 = 0; __pyx_t_12 = 0; __pyx_t_13 = 0; __pyx_t_14 = 0; + __pyx_lineno = __pyx_t_6; __pyx_clineno = __pyx_t_7; __pyx_filename = __pyx_t_8; + goto __pyx_L1_error; + } + __pyx_L6:; + } + + /* "region.pyx":230 + * finally: + * free(output) + * return ret # <<<<<<<<<<<<<< + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_ret); + __pyx_r = __pyx_v_ret; + goto __pyx_L0; + + /* "region.pyx":214 + * + * + * def vot_float2str(template, float value): # <<<<<<<<<<<<<< + * """ + * Args: + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("region.vot_float2str", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_ptemplate); + __Pyx_XDECREF(__pyx_v_ret); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "EnumBase":16 + * @cython.internal + * cdef class __Pyx_EnumMeta(type): + * def __init__(cls, name, parents, dct): # <<<<<<<<<<<<<< + * type.__init__(cls, name, parents, dct) + * cls.__members__ = __Pyx_OrderedDict() + */ + +/* Python wrapper */ +static int __pyx_pw_8EnumBase_14__Pyx_EnumMeta_1__init__(PyObject *__pyx_v_cls, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static int __pyx_pw_8EnumBase_14__Pyx_EnumMeta_1__init__(PyObject *__pyx_v_cls, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_name = 0; + PyObject *__pyx_v_parents = 0; + PyObject *__pyx_v_dct = 0; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__init__ (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_name,&__pyx_n_s_parents,&__pyx_n_s_dct,0}; + PyObject* values[3] = {0,0,0}; + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_name)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_parents)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("__init__", 1, 3, 3, 1); __PYX_ERR(1, 16, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_dct)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("__init__", 1, 3, 3, 2); __PYX_ERR(1, 16, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__init__") < 0)) __PYX_ERR(1, 16, __pyx_L3_error) + } + } else if (PyTuple_GET_SIZE(__pyx_args) != 3) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + } + __pyx_v_name = values[0]; + __pyx_v_parents = values[1]; + __pyx_v_dct = values[2]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__init__", 1, 3, 3, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(1, 16, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("EnumBase.__Pyx_EnumMeta.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return -1; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_8EnumBase_14__Pyx_EnumMeta___init__(((struct __pyx_obj___Pyx_EnumMeta *)__pyx_v_cls), __pyx_v_name, __pyx_v_parents, __pyx_v_dct); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_pf_8EnumBase_14__Pyx_EnumMeta___init__(struct __pyx_obj___Pyx_EnumMeta *__pyx_v_cls, PyObject *__pyx_v_name, PyObject *__pyx_v_parents, PyObject *__pyx_v_dct) { + int __pyx_r; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__init__", 0); + + /* "EnumBase":17 + * cdef class __Pyx_EnumMeta(type): + * def __init__(cls, name, parents, dct): + * type.__init__(cls, name, parents, dct) # <<<<<<<<<<<<<< + * cls.__members__ = __Pyx_OrderedDict() + * def __iter__(cls): + */ + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)(&PyType_Type)), __pyx_n_s_init); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 17, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = NULL; + __pyx_t_4 = 0; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + __pyx_t_4 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[5] = {__pyx_t_3, ((PyObject *)__pyx_v_cls), __pyx_v_name, __pyx_v_parents, __pyx_v_dct}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_2, __pyx_temp+1-__pyx_t_4, 4+__pyx_t_4); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 17, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[5] = {__pyx_t_3, ((PyObject *)__pyx_v_cls), __pyx_v_name, __pyx_v_parents, __pyx_v_dct}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_2, __pyx_temp+1-__pyx_t_4, 4+__pyx_t_4); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 17, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + { + __pyx_t_5 = PyTuple_New(4+__pyx_t_4); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 17, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (__pyx_t_3) { + __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_3); __pyx_t_3 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_cls)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_cls)); + PyTuple_SET_ITEM(__pyx_t_5, 0+__pyx_t_4, ((PyObject *)__pyx_v_cls)); + __Pyx_INCREF(__pyx_v_name); + __Pyx_GIVEREF(__pyx_v_name); + PyTuple_SET_ITEM(__pyx_t_5, 1+__pyx_t_4, __pyx_v_name); + __Pyx_INCREF(__pyx_v_parents); + __Pyx_GIVEREF(__pyx_v_parents); + PyTuple_SET_ITEM(__pyx_t_5, 2+__pyx_t_4, __pyx_v_parents); + __Pyx_INCREF(__pyx_v_dct); + __Pyx_GIVEREF(__pyx_v_dct); + PyTuple_SET_ITEM(__pyx_t_5, 3+__pyx_t_4, __pyx_v_dct); + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_5, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 17, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + } + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "EnumBase":18 + * def __init__(cls, name, parents, dct): + * type.__init__(cls, name, parents, dct) + * cls.__members__ = __Pyx_OrderedDict() # <<<<<<<<<<<<<< + * def __iter__(cls): + * return iter(cls.__members__.values()) + */ + __Pyx_INCREF(__Pyx_OrderedDict); + __pyx_t_2 = __Pyx_OrderedDict; __pyx_t_5 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_5)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_5); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + } + } + __pyx_t_1 = (__pyx_t_5) ? __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_5) : __Pyx_PyObject_CallNoArg(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 18, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (__Pyx_PyObject_SetAttrStr(((PyObject *)__pyx_v_cls), __pyx_n_s_members, __pyx_t_1) < 0) __PYX_ERR(1, 18, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "EnumBase":16 + * @cython.internal + * cdef class __Pyx_EnumMeta(type): + * def __init__(cls, name, parents, dct): # <<<<<<<<<<<<<< + * type.__init__(cls, name, parents, dct) + * cls.__members__ = __Pyx_OrderedDict() + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("EnumBase.__Pyx_EnumMeta.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "EnumBase":19 + * type.__init__(cls, name, parents, dct) + * cls.__members__ = __Pyx_OrderedDict() + * def __iter__(cls): # <<<<<<<<<<<<<< + * return iter(cls.__members__.values()) + * def __getitem__(cls, name): + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_8EnumBase_14__Pyx_EnumMeta_3__iter__(PyObject *__pyx_v_cls); /*proto*/ +static PyObject *__pyx_pw_8EnumBase_14__Pyx_EnumMeta_3__iter__(PyObject *__pyx_v_cls) { + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__iter__ (wrapper)", 0); + __pyx_r = __pyx_pf_8EnumBase_14__Pyx_EnumMeta_2__iter__(((struct __pyx_obj___Pyx_EnumMeta *)__pyx_v_cls)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_8EnumBase_14__Pyx_EnumMeta_2__iter__(struct __pyx_obj___Pyx_EnumMeta *__pyx_v_cls) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__iter__", 0); + + /* "EnumBase":20 + * cls.__members__ = __Pyx_OrderedDict() + * def __iter__(cls): + * return iter(cls.__members__.values()) # <<<<<<<<<<<<<< + * def __getitem__(cls, name): + * return cls.__members__[name] + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_cls), __pyx_n_s_members); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 20, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_values); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 20, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_3))) { + __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_3); + if (likely(__pyx_t_2)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3); + __Pyx_INCREF(__pyx_t_2); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_3, function); + } + } + __pyx_t_1 = (__pyx_t_2) ? __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_t_2) : __Pyx_PyObject_CallNoArg(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 20, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 20, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_3; + __pyx_t_3 = 0; + goto __pyx_L0; + + /* "EnumBase":19 + * type.__init__(cls, name, parents, dct) + * cls.__members__ = __Pyx_OrderedDict() + * def __iter__(cls): # <<<<<<<<<<<<<< + * return iter(cls.__members__.values()) + * def __getitem__(cls, name): + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("EnumBase.__Pyx_EnumMeta.__iter__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "EnumBase":21 + * def __iter__(cls): + * return iter(cls.__members__.values()) + * def __getitem__(cls, name): # <<<<<<<<<<<<<< + * return cls.__members__[name] + * + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_8EnumBase_14__Pyx_EnumMeta_5__getitem__(PyObject *__pyx_v_cls, PyObject *__pyx_v_name); /*proto*/ +static PyObject *__pyx_pw_8EnumBase_14__Pyx_EnumMeta_5__getitem__(PyObject *__pyx_v_cls, PyObject *__pyx_v_name) { + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__getitem__ (wrapper)", 0); + __pyx_r = __pyx_pf_8EnumBase_14__Pyx_EnumMeta_4__getitem__(((struct __pyx_obj___Pyx_EnumMeta *)__pyx_v_cls), ((PyObject *)__pyx_v_name)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_8EnumBase_14__Pyx_EnumMeta_4__getitem__(struct __pyx_obj___Pyx_EnumMeta *__pyx_v_cls, PyObject *__pyx_v_name) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__getitem__", 0); + + /* "EnumBase":22 + * return iter(cls.__members__.values()) + * def __getitem__(cls, name): + * return cls.__members__[name] # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_cls), __pyx_n_s_members); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 22, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyObject_GetItem(__pyx_t_1, __pyx_v_name); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 22, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "EnumBase":21 + * def __iter__(cls): + * return iter(cls.__members__.values()) + * def __getitem__(cls, name): # <<<<<<<<<<<<<< + * return cls.__members__[name] + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("EnumBase.__Pyx_EnumMeta.__getitem__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * cdef tuple state + * cdef object _dict + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_8EnumBase_14__Pyx_EnumMeta_7__reduce_cython__(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/ +static PyObject *__pyx_pw_8EnumBase_14__Pyx_EnumMeta_7__reduce_cython__(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) { + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__reduce_cython__ (wrapper)", 0); + __pyx_r = __pyx_pf_8EnumBase_14__Pyx_EnumMeta_6__reduce_cython__(((struct __pyx_obj___Pyx_EnumMeta *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_8EnumBase_14__Pyx_EnumMeta_6__reduce_cython__(struct __pyx_obj___Pyx_EnumMeta *__pyx_v_self) { + PyObject *__pyx_v_state = 0; + PyObject *__pyx_v__dict = 0; + int __pyx_v_use_setstate; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + int __pyx_t_3; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__reduce_cython__", 0); + + /* "(tree fragment)":5 + * cdef object _dict + * cdef bint use_setstate + * state = () # <<<<<<<<<<<<<< + * _dict = getattr(self, '__dict__', None) + * if _dict is not None: + */ + __Pyx_INCREF(__pyx_empty_tuple); + __pyx_v_state = __pyx_empty_tuple; + + /* "(tree fragment)":6 + * cdef bint use_setstate + * state = () + * _dict = getattr(self, '__dict__', None) # <<<<<<<<<<<<<< + * if _dict is not None: + * state += (_dict,) + */ + __pyx_t_1 = __Pyx_GetAttr3(((PyObject *)__pyx_v_self), __pyx_n_s_dict, Py_None); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 6, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v__dict = __pyx_t_1; + __pyx_t_1 = 0; + + /* "(tree fragment)":7 + * state = () + * _dict = getattr(self, '__dict__', None) + * if _dict is not None: # <<<<<<<<<<<<<< + * state += (_dict,) + * use_setstate = True + */ + __pyx_t_2 = (__pyx_v__dict != Py_None); + __pyx_t_3 = (__pyx_t_2 != 0); + if (__pyx_t_3) { + + /* "(tree fragment)":8 + * _dict = getattr(self, '__dict__', None) + * if _dict is not None: + * state += (_dict,) # <<<<<<<<<<<<<< + * use_setstate = True + * else: + */ + __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 8, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(__pyx_v__dict); + __Pyx_GIVEREF(__pyx_v__dict); + PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_v__dict); + __pyx_t_4 = PyNumber_InPlaceAdd(__pyx_v_state, __pyx_t_1); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 8, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF_SET(__pyx_v_state, ((PyObject*)__pyx_t_4)); + __pyx_t_4 = 0; + + /* "(tree fragment)":9 + * if _dict is not None: + * state += (_dict,) + * use_setstate = True # <<<<<<<<<<<<<< + * else: + * use_setstate = False + */ + __pyx_v_use_setstate = 1; + + /* "(tree fragment)":7 + * state = () + * _dict = getattr(self, '__dict__', None) + * if _dict is not None: # <<<<<<<<<<<<<< + * state += (_dict,) + * use_setstate = True + */ + goto __pyx_L3; + } + + /* "(tree fragment)":11 + * use_setstate = True + * else: + * use_setstate = False # <<<<<<<<<<<<<< + * if use_setstate: + * return __pyx_unpickle___Pyx_EnumMeta, (type(self), 0xd41d8cd, None), state + */ + /*else*/ { + __pyx_v_use_setstate = 0; + } + __pyx_L3:; + + /* "(tree fragment)":12 + * else: + * use_setstate = False + * if use_setstate: # <<<<<<<<<<<<<< + * return __pyx_unpickle___Pyx_EnumMeta, (type(self), 0xd41d8cd, None), state + * else: + */ + __pyx_t_3 = (__pyx_v_use_setstate != 0); + if (__pyx_t_3) { + + /* "(tree fragment)":13 + * use_setstate = False + * if use_setstate: + * return __pyx_unpickle___Pyx_EnumMeta, (type(self), 0xd41d8cd, None), state # <<<<<<<<<<<<<< + * else: + * return __pyx_unpickle___Pyx_EnumMeta, (type(self), 0xd41d8cd, state) + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_pyx_unpickle___Pyx_EnumMeta); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 13, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_1 = PyTuple_New(3); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 13, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(((PyObject *)Py_TYPE(((PyObject *)__pyx_v_self)))); + __Pyx_GIVEREF(((PyObject *)Py_TYPE(((PyObject *)__pyx_v_self)))); + PyTuple_SET_ITEM(__pyx_t_1, 0, ((PyObject *)Py_TYPE(((PyObject *)__pyx_v_self)))); + __Pyx_INCREF(__pyx_int_222419149); + __Pyx_GIVEREF(__pyx_int_222419149); + PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_int_222419149); + __Pyx_INCREF(Py_None); + __Pyx_GIVEREF(Py_None); + PyTuple_SET_ITEM(__pyx_t_1, 2, Py_None); + __pyx_t_5 = PyTuple_New(3); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 13, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_GIVEREF(__pyx_t_4); + PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_4); + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_t_1); + __Pyx_INCREF(__pyx_v_state); + __Pyx_GIVEREF(__pyx_v_state); + PyTuple_SET_ITEM(__pyx_t_5, 2, __pyx_v_state); + __pyx_t_4 = 0; + __pyx_t_1 = 0; + __pyx_r = __pyx_t_5; + __pyx_t_5 = 0; + goto __pyx_L0; + + /* "(tree fragment)":12 + * else: + * use_setstate = False + * if use_setstate: # <<<<<<<<<<<<<< + * return __pyx_unpickle___Pyx_EnumMeta, (type(self), 0xd41d8cd, None), state + * else: + */ + } + + /* "(tree fragment)":15 + * return __pyx_unpickle___Pyx_EnumMeta, (type(self), 0xd41d8cd, None), state + * else: + * return __pyx_unpickle___Pyx_EnumMeta, (type(self), 0xd41d8cd, state) # <<<<<<<<<<<<<< + * def __setstate_cython__(self, __pyx_state): + * __pyx_unpickle___Pyx_EnumMeta__set_state(self, __pyx_state) + */ + /*else*/ { + __Pyx_XDECREF(__pyx_r); + __Pyx_GetModuleGlobalName(__pyx_t_5, __pyx_n_s_pyx_unpickle___Pyx_EnumMeta); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 15, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_1 = PyTuple_New(3); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 15, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(((PyObject *)Py_TYPE(((PyObject *)__pyx_v_self)))); + __Pyx_GIVEREF(((PyObject *)Py_TYPE(((PyObject *)__pyx_v_self)))); + PyTuple_SET_ITEM(__pyx_t_1, 0, ((PyObject *)Py_TYPE(((PyObject *)__pyx_v_self)))); + __Pyx_INCREF(__pyx_int_222419149); + __Pyx_GIVEREF(__pyx_int_222419149); + PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_int_222419149); + __Pyx_INCREF(__pyx_v_state); + __Pyx_GIVEREF(__pyx_v_state); + PyTuple_SET_ITEM(__pyx_t_1, 2, __pyx_v_state); + __pyx_t_4 = PyTuple_New(2); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 15, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_GIVEREF(__pyx_t_5); + PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_5); + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_4, 1, __pyx_t_1); + __pyx_t_5 = 0; + __pyx_t_1 = 0; + __pyx_r = __pyx_t_4; + __pyx_t_4 = 0; + goto __pyx_L0; + } + + /* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * cdef tuple state + * cdef object _dict + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("EnumBase.__Pyx_EnumMeta.__reduce_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_state); + __Pyx_XDECREF(__pyx_v__dict); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":16 + * else: + * return __pyx_unpickle___Pyx_EnumMeta, (type(self), 0xd41d8cd, state) + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * __pyx_unpickle___Pyx_EnumMeta__set_state(self, __pyx_state) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_8EnumBase_14__Pyx_EnumMeta_9__setstate_cython__(PyObject *__pyx_v_self, PyObject *__pyx_v___pyx_state); /*proto*/ +static PyObject *__pyx_pw_8EnumBase_14__Pyx_EnumMeta_9__setstate_cython__(PyObject *__pyx_v_self, PyObject *__pyx_v___pyx_state) { + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__setstate_cython__ (wrapper)", 0); + __pyx_r = __pyx_pf_8EnumBase_14__Pyx_EnumMeta_8__setstate_cython__(((struct __pyx_obj___Pyx_EnumMeta *)__pyx_v_self), ((PyObject *)__pyx_v___pyx_state)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_8EnumBase_14__Pyx_EnumMeta_8__setstate_cython__(struct __pyx_obj___Pyx_EnumMeta *__pyx_v_self, PyObject *__pyx_v___pyx_state) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__setstate_cython__", 0); + + /* "(tree fragment)":17 + * return __pyx_unpickle___Pyx_EnumMeta, (type(self), 0xd41d8cd, state) + * def __setstate_cython__(self, __pyx_state): + * __pyx_unpickle___Pyx_EnumMeta__set_state(self, __pyx_state) # <<<<<<<<<<<<<< + */ + if (!(likely(PyTuple_CheckExact(__pyx_v___pyx_state))||((__pyx_v___pyx_state) == Py_None)||((void)PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "tuple", Py_TYPE(__pyx_v___pyx_state)->tp_name), 0))) __PYX_ERR(1, 17, __pyx_L1_error) + __pyx_t_1 = __pyx_unpickle___Pyx_EnumMeta__set_state(__pyx_v_self, ((PyObject*)__pyx_v___pyx_state)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 17, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "(tree fragment)":16 + * else: + * return __pyx_unpickle___Pyx_EnumMeta, (type(self), 0xd41d8cd, state) + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * __pyx_unpickle___Pyx_EnumMeta__set_state(self, __pyx_state) + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("EnumBase.__Pyx_EnumMeta.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "EnumBase":28 + * class __Pyx_EnumBase(int): + * __metaclass__ = __Pyx_EnumMeta + * def __new__(cls, value, name=None): # <<<<<<<<<<<<<< + * for v in cls: + * if v == value: + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_8EnumBase_14__Pyx_EnumBase_1__new__(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static PyMethodDef __pyx_mdef_8EnumBase_14__Pyx_EnumBase_1__new__ = {"__new__", (PyCFunction)(void*)(PyCFunctionWithKeywords)__pyx_pw_8EnumBase_14__Pyx_EnumBase_1__new__, METH_VARARGS|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_8EnumBase_14__Pyx_EnumBase_1__new__(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_cls = 0; + PyObject *__pyx_v_value = 0; + PyObject *__pyx_v_name = 0; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__new__ (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_cls,&__pyx_n_s_value,&__pyx_n_s_name,0}; + PyObject* values[3] = {0,0,0}; + values[2] = ((PyObject *)((PyObject *)Py_None)); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_cls)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_value)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("__new__", 0, 2, 3, 1); __PYX_ERR(1, 28, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_name); + if (value) { values[2] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__new__") < 0)) __PYX_ERR(1, 28, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_cls = values[0]; + __pyx_v_value = values[1]; + __pyx_v_name = values[2]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__new__", 0, 2, 3, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(1, 28, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("EnumBase.__Pyx_EnumBase.__new__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_8EnumBase_14__Pyx_EnumBase___new__(__pyx_self, __pyx_v_cls, __pyx_v_value, __pyx_v_name); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_8EnumBase_14__Pyx_EnumBase___new__(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_cls, PyObject *__pyx_v_value, PyObject *__pyx_v_name) { + PyObject *__pyx_v_v = NULL; + PyObject *__pyx_v_res = NULL; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + Py_ssize_t __pyx_t_2; + PyObject *(*__pyx_t_3)(PyObject *); + PyObject *__pyx_t_4 = NULL; + int __pyx_t_5; + int __pyx_t_6; + PyObject *__pyx_t_7 = NULL; + int __pyx_t_8; + PyObject *__pyx_t_9 = NULL; + int __pyx_t_10; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__new__", 0); + + /* "EnumBase":29 + * __metaclass__ = __Pyx_EnumMeta + * def __new__(cls, value, name=None): + * for v in cls: # <<<<<<<<<<<<<< + * if v == value: + * return v + */ + if (likely(PyList_CheckExact(__pyx_v_cls)) || PyTuple_CheckExact(__pyx_v_cls)) { + __pyx_t_1 = __pyx_v_cls; __Pyx_INCREF(__pyx_t_1); __pyx_t_2 = 0; + __pyx_t_3 = NULL; + } else { + __pyx_t_2 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_v_cls); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 29, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = Py_TYPE(__pyx_t_1)->tp_iternext; if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 29, __pyx_L1_error) + } + for (;;) { + if (likely(!__pyx_t_3)) { + if (likely(PyList_CheckExact(__pyx_t_1))) { + if (__pyx_t_2 >= PyList_GET_SIZE(__pyx_t_1)) break; + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_4 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely(0 < 0)) __PYX_ERR(1, 29, __pyx_L1_error) + #else + __pyx_t_4 = PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 29, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + #endif + } else { + if (__pyx_t_2 >= PyTuple_GET_SIZE(__pyx_t_1)) break; + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_4 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely(0 < 0)) __PYX_ERR(1, 29, __pyx_L1_error) + #else + __pyx_t_4 = PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 29, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + #endif + } + } else { + __pyx_t_4 = __pyx_t_3(__pyx_t_1); + if (unlikely(!__pyx_t_4)) { + PyObject* exc_type = PyErr_Occurred(); + if (exc_type) { + if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); + else __PYX_ERR(1, 29, __pyx_L1_error) + } + break; + } + __Pyx_GOTREF(__pyx_t_4); + } + __Pyx_XDECREF_SET(__pyx_v_v, __pyx_t_4); + __pyx_t_4 = 0; + + /* "EnumBase":30 + * def __new__(cls, value, name=None): + * for v in cls: + * if v == value: # <<<<<<<<<<<<<< + * return v + * if name is None: + */ + __pyx_t_4 = PyObject_RichCompare(__pyx_v_v, __pyx_v_value, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 30, __pyx_L1_error) + __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_5 < 0)) __PYX_ERR(1, 30, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (__pyx_t_5) { + + /* "EnumBase":31 + * for v in cls: + * if v == value: + * return v # <<<<<<<<<<<<<< + * if name is None: + * raise ValueError("Unknown enum value: '%s'" % value) + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_v); + __pyx_r = __pyx_v_v; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + goto __pyx_L0; + + /* "EnumBase":30 + * def __new__(cls, value, name=None): + * for v in cls: + * if v == value: # <<<<<<<<<<<<<< + * return v + * if name is None: + */ + } + + /* "EnumBase":29 + * __metaclass__ = __Pyx_EnumMeta + * def __new__(cls, value, name=None): + * for v in cls: # <<<<<<<<<<<<<< + * if v == value: + * return v + */ + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "EnumBase":32 + * if v == value: + * return v + * if name is None: # <<<<<<<<<<<<<< + * raise ValueError("Unknown enum value: '%s'" % value) + * res = int.__new__(cls, value) + */ + __pyx_t_5 = (__pyx_v_name == Py_None); + __pyx_t_6 = (__pyx_t_5 != 0); + if (unlikely(__pyx_t_6)) { + + /* "EnumBase":33 + * return v + * if name is None: + * raise ValueError("Unknown enum value: '%s'" % value) # <<<<<<<<<<<<<< + * res = int.__new__(cls, value) + * res.name = name + */ + __pyx_t_1 = __Pyx_PyString_FormatSafe(__pyx_kp_s_Unknown_enum_value_s, __pyx_v_value); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 33, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_1); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 33, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_Raise(__pyx_t_4, 0, 0, 0); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __PYX_ERR(1, 33, __pyx_L1_error) + + /* "EnumBase":32 + * if v == value: + * return v + * if name is None: # <<<<<<<<<<<<<< + * raise ValueError("Unknown enum value: '%s'" % value) + * res = int.__new__(cls, value) + */ + } + + /* "EnumBase":34 + * if name is None: + * raise ValueError("Unknown enum value: '%s'" % value) + * res = int.__new__(cls, value) # <<<<<<<<<<<<<< + * res.name = name + * setattr(cls, name, res) + */ + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)(&PyInt_Type)), __pyx_n_s_new); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 34, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_7 = NULL; + __pyx_t_8 = 0; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_1))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_1); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_1, function); + __pyx_t_8 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[3] = {__pyx_t_7, __pyx_v_cls, __pyx_v_value}; + __pyx_t_4 = __Pyx_PyFunction_FastCall(__pyx_t_1, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 34, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_4); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[3] = {__pyx_t_7, __pyx_v_cls, __pyx_v_value}; + __pyx_t_4 = __Pyx_PyCFunction_FastCall(__pyx_t_1, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 34, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_4); + } else + #endif + { + __pyx_t_9 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_9)) __PYX_ERR(1, 34, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + if (__pyx_t_7) { + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_7); __pyx_t_7 = NULL; + } + __Pyx_INCREF(__pyx_v_cls); + __Pyx_GIVEREF(__pyx_v_cls); + PyTuple_SET_ITEM(__pyx_t_9, 0+__pyx_t_8, __pyx_v_cls); + __Pyx_INCREF(__pyx_v_value); + __Pyx_GIVEREF(__pyx_v_value); + PyTuple_SET_ITEM(__pyx_t_9, 1+__pyx_t_8, __pyx_v_value); + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_9, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 34, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_res = __pyx_t_4; + __pyx_t_4 = 0; + + /* "EnumBase":35 + * raise ValueError("Unknown enum value: '%s'" % value) + * res = int.__new__(cls, value) + * res.name = name # <<<<<<<<<<<<<< + * setattr(cls, name, res) + * cls.__members__[name] = res + */ + if (__Pyx_PyObject_SetAttrStr(__pyx_v_res, __pyx_n_s_name, __pyx_v_name) < 0) __PYX_ERR(1, 35, __pyx_L1_error) + + /* "EnumBase":36 + * res = int.__new__(cls, value) + * res.name = name + * setattr(cls, name, res) # <<<<<<<<<<<<<< + * cls.__members__[name] = res + * return res + */ + __pyx_t_10 = PyObject_SetAttr(__pyx_v_cls, __pyx_v_name, __pyx_v_res); if (unlikely(__pyx_t_10 == ((int)-1))) __PYX_ERR(1, 36, __pyx_L1_error) + + /* "EnumBase":37 + * res.name = name + * setattr(cls, name, res) + * cls.__members__[name] = res # <<<<<<<<<<<<<< + * return res + * def __repr__(self): + */ + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_cls, __pyx_n_s_members); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 37, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + if (unlikely(PyObject_SetItem(__pyx_t_4, __pyx_v_name, __pyx_v_res) < 0)) __PYX_ERR(1, 37, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + + /* "EnumBase":38 + * setattr(cls, name, res) + * cls.__members__[name] = res + * return res # <<<<<<<<<<<<<< + * def __repr__(self): + * return "<%s.%s: %d>" % (self.__class__.__name__, self.name, self) + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_res); + __pyx_r = __pyx_v_res; + goto __pyx_L0; + + /* "EnumBase":28 + * class __Pyx_EnumBase(int): + * __metaclass__ = __Pyx_EnumMeta + * def __new__(cls, value, name=None): # <<<<<<<<<<<<<< + * for v in cls: + * if v == value: + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_AddTraceback("EnumBase.__Pyx_EnumBase.__new__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_v); + __Pyx_XDECREF(__pyx_v_res); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "EnumBase":39 + * cls.__members__[name] = res + * return res + * def __repr__(self): # <<<<<<<<<<<<<< + * return "<%s.%s: %d>" % (self.__class__.__name__, self.name, self) + * def __str__(self): + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_8EnumBase_14__Pyx_EnumBase_3__repr__(PyObject *__pyx_self, PyObject *__pyx_v_self); /*proto*/ +static PyMethodDef __pyx_mdef_8EnumBase_14__Pyx_EnumBase_3__repr__ = {"__repr__", (PyCFunction)__pyx_pw_8EnumBase_14__Pyx_EnumBase_3__repr__, METH_O, 0}; +static PyObject *__pyx_pw_8EnumBase_14__Pyx_EnumBase_3__repr__(PyObject *__pyx_self, PyObject *__pyx_v_self) { + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__repr__ (wrapper)", 0); + __pyx_r = __pyx_pf_8EnumBase_14__Pyx_EnumBase_2__repr__(__pyx_self, ((PyObject *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_8EnumBase_14__Pyx_EnumBase_2__repr__(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__repr__", 0); + + /* "EnumBase":40 + * return res + * def __repr__(self): + * return "<%s.%s: %d>" % (self.__class__.__name__, self.name, self) # <<<<<<<<<<<<<< + * def __str__(self): + * return "%s.%s" % (self.__class__.__name__, self.name) + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_class); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 40, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_name_2); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 40, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_name); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 40, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = PyTuple_New(3); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 40, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_GIVEREF(__pyx_t_2); + PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_2); + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_t_1); + __Pyx_INCREF(__pyx_v_self); + __Pyx_GIVEREF(__pyx_v_self); + PyTuple_SET_ITEM(__pyx_t_3, 2, __pyx_v_self); + __pyx_t_2 = 0; + __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_PyString_Format(__pyx_kp_s_s_s_d, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 40, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "EnumBase":39 + * cls.__members__[name] = res + * return res + * def __repr__(self): # <<<<<<<<<<<<<< + * return "<%s.%s: %d>" % (self.__class__.__name__, self.name, self) + * def __str__(self): + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("EnumBase.__Pyx_EnumBase.__repr__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "EnumBase":41 + * def __repr__(self): + * return "<%s.%s: %d>" % (self.__class__.__name__, self.name, self) + * def __str__(self): # <<<<<<<<<<<<<< + * return "%s.%s" % (self.__class__.__name__, self.name) + * + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_8EnumBase_14__Pyx_EnumBase_5__str__(PyObject *__pyx_self, PyObject *__pyx_v_self); /*proto*/ +static PyMethodDef __pyx_mdef_8EnumBase_14__Pyx_EnumBase_5__str__ = {"__str__", (PyCFunction)__pyx_pw_8EnumBase_14__Pyx_EnumBase_5__str__, METH_O, 0}; +static PyObject *__pyx_pw_8EnumBase_14__Pyx_EnumBase_5__str__(PyObject *__pyx_self, PyObject *__pyx_v_self) { + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__str__ (wrapper)", 0); + __pyx_r = __pyx_pf_8EnumBase_14__Pyx_EnumBase_4__str__(__pyx_self, ((PyObject *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_8EnumBase_14__Pyx_EnumBase_4__str__(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__str__", 0); + + /* "EnumBase":42 + * return "<%s.%s: %d>" % (self.__class__.__name__, self.name, self) + * def __str__(self): + * return "%s.%s" % (self.__class__.__name__, self.name) # <<<<<<<<<<<<<< + * + * if PY_VERSION_HEX >= 0x03040000: + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_class); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 42, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_name_2); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 42, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_name); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 42, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 42, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_GIVEREF(__pyx_t_2); + PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_2); + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_t_1); + __pyx_t_2 = 0; + __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_PyString_Format(__pyx_kp_s_s_s, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 42, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "EnumBase":41 + * def __repr__(self): + * return "<%s.%s: %d>" % (self.__class__.__name__, self.name, self) + * def __str__(self): # <<<<<<<<<<<<<< + * return "%s.%s" % (self.__class__.__name__, self.name) + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("EnumBase.__Pyx_EnumBase.__str__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":1 + * def __pyx_unpickle___Pyx_EnumMeta(__pyx_type, long __pyx_checksum, __pyx_state): # <<<<<<<<<<<<<< + * cdef object __pyx_PickleError + * cdef object __pyx_result + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_8EnumBase_1__pyx_unpickle___Pyx_EnumMeta(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static PyMethodDef __pyx_mdef_8EnumBase_1__pyx_unpickle___Pyx_EnumMeta = {"__pyx_unpickle___Pyx_EnumMeta", (PyCFunction)(void*)(PyCFunctionWithKeywords)__pyx_pw_8EnumBase_1__pyx_unpickle___Pyx_EnumMeta, METH_VARARGS|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_8EnumBase_1__pyx_unpickle___Pyx_EnumMeta(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v___pyx_type = 0; + long __pyx_v___pyx_checksum; + PyObject *__pyx_v___pyx_state = 0; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__pyx_unpickle___Pyx_EnumMeta (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_pyx_type,&__pyx_n_s_pyx_checksum,&__pyx_n_s_pyx_state,0}; + PyObject* values[3] = {0,0,0}; + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_pyx_type)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_pyx_checksum)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("__pyx_unpickle___Pyx_EnumMeta", 1, 3, 3, 1); __PYX_ERR(1, 1, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_pyx_state)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("__pyx_unpickle___Pyx_EnumMeta", 1, 3, 3, 2); __PYX_ERR(1, 1, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__pyx_unpickle___Pyx_EnumMeta") < 0)) __PYX_ERR(1, 1, __pyx_L3_error) + } + } else if (PyTuple_GET_SIZE(__pyx_args) != 3) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + } + __pyx_v___pyx_type = values[0]; + __pyx_v___pyx_checksum = __Pyx_PyInt_As_long(values[1]); if (unlikely((__pyx_v___pyx_checksum == (long)-1) && PyErr_Occurred())) __PYX_ERR(1, 1, __pyx_L3_error) + __pyx_v___pyx_state = values[2]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__pyx_unpickle___Pyx_EnumMeta", 1, 3, 3, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(1, 1, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("EnumBase.__pyx_unpickle___Pyx_EnumMeta", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_8EnumBase___pyx_unpickle___Pyx_EnumMeta(__pyx_self, __pyx_v___pyx_type, __pyx_v___pyx_checksum, __pyx_v___pyx_state); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_8EnumBase___pyx_unpickle___Pyx_EnumMeta(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v___pyx_type, long __pyx_v___pyx_checksum, PyObject *__pyx_v___pyx_state) { + PyObject *__pyx_v___pyx_PickleError = 0; + PyObject *__pyx_v___pyx_result = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + int __pyx_t_3; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__pyx_unpickle___Pyx_EnumMeta", 0); + + /* "(tree fragment)":4 + * cdef object __pyx_PickleError + * cdef object __pyx_result + * if __pyx_checksum not in (0xd41d8cd, 0xe3b0c44, 0xda39a3e): # <<<<<<<<<<<<<< + * from pickle import PickleError as __pyx_PickleError + * raise __pyx_PickleError("Incompatible checksums (0x%x vs (0xd41d8cd, 0xe3b0c44, 0xda39a3e) = ())" % __pyx_checksum) + */ + __pyx_t_1 = __Pyx_PyInt_From_long(__pyx_v___pyx_checksum); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = (__Pyx_PySequence_ContainsTF(__pyx_t_1, __pyx_tuple__8, Py_NE)); if (unlikely(__pyx_t_2 < 0)) __PYX_ERR(1, 4, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_3 = (__pyx_t_2 != 0); + if (__pyx_t_3) { + + /* "(tree fragment)":5 + * cdef object __pyx_result + * if __pyx_checksum not in (0xd41d8cd, 0xe3b0c44, 0xda39a3e): + * from pickle import PickleError as __pyx_PickleError # <<<<<<<<<<<<<< + * raise __pyx_PickleError("Incompatible checksums (0x%x vs (0xd41d8cd, 0xe3b0c44, 0xda39a3e) = ())" % __pyx_checksum) + * __pyx_result = __Pyx_EnumMeta.__new__(__pyx_type) + */ + __pyx_t_1 = PyList_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 5, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(__pyx_n_s_PickleError); + __Pyx_GIVEREF(__pyx_n_s_PickleError); + PyList_SET_ITEM(__pyx_t_1, 0, __pyx_n_s_PickleError); + __pyx_t_4 = __Pyx_Import(__pyx_n_s_pickle, __pyx_t_1, -1); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 5, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_ImportFrom(__pyx_t_4, __pyx_n_s_PickleError); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 5, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(__pyx_t_1); + __pyx_v___pyx_PickleError = __pyx_t_1; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + + /* "(tree fragment)":6 + * if __pyx_checksum not in (0xd41d8cd, 0xe3b0c44, 0xda39a3e): + * from pickle import PickleError as __pyx_PickleError + * raise __pyx_PickleError("Incompatible checksums (0x%x vs (0xd41d8cd, 0xe3b0c44, 0xda39a3e) = ())" % __pyx_checksum) # <<<<<<<<<<<<<< + * __pyx_result = __Pyx_EnumMeta.__new__(__pyx_type) + * if __pyx_state is not None: + */ + __pyx_t_1 = __Pyx_PyInt_From_long(__pyx_v___pyx_checksum); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 6, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_5 = __Pyx_PyString_Format(__pyx_kp_s_Incompatible_checksums_0x_x_vs_0, __pyx_t_1); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 6, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_INCREF(__pyx_v___pyx_PickleError); + __pyx_t_1 = __pyx_v___pyx_PickleError; __pyx_t_6 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_1))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_1); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_1, function); + } + } + __pyx_t_4 = (__pyx_t_6) ? __Pyx_PyObject_Call2Args(__pyx_t_1, __pyx_t_6, __pyx_t_5) : __Pyx_PyObject_CallOneArg(__pyx_t_1, __pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 6, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_Raise(__pyx_t_4, 0, 0, 0); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __PYX_ERR(1, 6, __pyx_L1_error) + + /* "(tree fragment)":4 + * cdef object __pyx_PickleError + * cdef object __pyx_result + * if __pyx_checksum not in (0xd41d8cd, 0xe3b0c44, 0xda39a3e): # <<<<<<<<<<<<<< + * from pickle import PickleError as __pyx_PickleError + * raise __pyx_PickleError("Incompatible checksums (0x%x vs (0xd41d8cd, 0xe3b0c44, 0xda39a3e) = ())" % __pyx_checksum) + */ + } + + /* "(tree fragment)":7 + * from pickle import PickleError as __pyx_PickleError + * raise __pyx_PickleError("Incompatible checksums (0x%x vs (0xd41d8cd, 0xe3b0c44, 0xda39a3e) = ())" % __pyx_checksum) + * __pyx_result = __Pyx_EnumMeta.__new__(__pyx_type) # <<<<<<<<<<<<<< + * if __pyx_state is not None: + * __pyx_unpickle___Pyx_EnumMeta__set_state(<__Pyx_EnumMeta> __pyx_result, __pyx_state) + */ + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_ptype___Pyx_EnumMeta), __pyx_n_s_new); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 7, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_5 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_1))) { + __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_1); + if (likely(__pyx_t_5)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1); + __Pyx_INCREF(__pyx_t_5); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_1, function); + } + } + __pyx_t_4 = (__pyx_t_5) ? __Pyx_PyObject_Call2Args(__pyx_t_1, __pyx_t_5, __pyx_v___pyx_type) : __Pyx_PyObject_CallOneArg(__pyx_t_1, __pyx_v___pyx_type); + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 7, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v___pyx_result = __pyx_t_4; + __pyx_t_4 = 0; + + /* "(tree fragment)":8 + * raise __pyx_PickleError("Incompatible checksums (0x%x vs (0xd41d8cd, 0xe3b0c44, 0xda39a3e) = ())" % __pyx_checksum) + * __pyx_result = __Pyx_EnumMeta.__new__(__pyx_type) + * if __pyx_state is not None: # <<<<<<<<<<<<<< + * __pyx_unpickle___Pyx_EnumMeta__set_state(<__Pyx_EnumMeta> __pyx_result, __pyx_state) + * return __pyx_result + */ + __pyx_t_3 = (__pyx_v___pyx_state != Py_None); + __pyx_t_2 = (__pyx_t_3 != 0); + if (__pyx_t_2) { + + /* "(tree fragment)":9 + * __pyx_result = __Pyx_EnumMeta.__new__(__pyx_type) + * if __pyx_state is not None: + * __pyx_unpickle___Pyx_EnumMeta__set_state(<__Pyx_EnumMeta> __pyx_result, __pyx_state) # <<<<<<<<<<<<<< + * return __pyx_result + * cdef __pyx_unpickle___Pyx_EnumMeta__set_state(__Pyx_EnumMeta __pyx_result, tuple __pyx_state): + */ + if (!(likely(PyTuple_CheckExact(__pyx_v___pyx_state))||((__pyx_v___pyx_state) == Py_None)||((void)PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "tuple", Py_TYPE(__pyx_v___pyx_state)->tp_name), 0))) __PYX_ERR(1, 9, __pyx_L1_error) + __pyx_t_4 = __pyx_unpickle___Pyx_EnumMeta__set_state(((struct __pyx_obj___Pyx_EnumMeta *)__pyx_v___pyx_result), ((PyObject*)__pyx_v___pyx_state)); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 9, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + + /* "(tree fragment)":8 + * raise __pyx_PickleError("Incompatible checksums (0x%x vs (0xd41d8cd, 0xe3b0c44, 0xda39a3e) = ())" % __pyx_checksum) + * __pyx_result = __Pyx_EnumMeta.__new__(__pyx_type) + * if __pyx_state is not None: # <<<<<<<<<<<<<< + * __pyx_unpickle___Pyx_EnumMeta__set_state(<__Pyx_EnumMeta> __pyx_result, __pyx_state) + * return __pyx_result + */ + } + + /* "(tree fragment)":10 + * if __pyx_state is not None: + * __pyx_unpickle___Pyx_EnumMeta__set_state(<__Pyx_EnumMeta> __pyx_result, __pyx_state) + * return __pyx_result # <<<<<<<<<<<<<< + * cdef __pyx_unpickle___Pyx_EnumMeta__set_state(__Pyx_EnumMeta __pyx_result, tuple __pyx_state): + * if len(__pyx_state) > 0 and hasattr(__pyx_result, '__dict__'): + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v___pyx_result); + __pyx_r = __pyx_v___pyx_result; + goto __pyx_L0; + + /* "(tree fragment)":1 + * def __pyx_unpickle___Pyx_EnumMeta(__pyx_type, long __pyx_checksum, __pyx_state): # <<<<<<<<<<<<<< + * cdef object __pyx_PickleError + * cdef object __pyx_result + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_AddTraceback("EnumBase.__pyx_unpickle___Pyx_EnumMeta", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v___pyx_PickleError); + __Pyx_XDECREF(__pyx_v___pyx_result); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":11 + * __pyx_unpickle___Pyx_EnumMeta__set_state(<__Pyx_EnumMeta> __pyx_result, __pyx_state) + * return __pyx_result + * cdef __pyx_unpickle___Pyx_EnumMeta__set_state(__Pyx_EnumMeta __pyx_result, tuple __pyx_state): # <<<<<<<<<<<<<< + * if len(__pyx_state) > 0 and hasattr(__pyx_result, '__dict__'): + * __pyx_result.__dict__.update(__pyx_state[0]) + */ + +static PyObject *__pyx_unpickle___Pyx_EnumMeta__set_state(struct __pyx_obj___Pyx_EnumMeta *__pyx_v___pyx_result, PyObject *__pyx_v___pyx_state) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + Py_ssize_t __pyx_t_2; + int __pyx_t_3; + int __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__pyx_unpickle___Pyx_EnumMeta__set_state", 0); + + /* "(tree fragment)":12 + * return __pyx_result + * cdef __pyx_unpickle___Pyx_EnumMeta__set_state(__Pyx_EnumMeta __pyx_result, tuple __pyx_state): + * if len(__pyx_state) > 0 and hasattr(__pyx_result, '__dict__'): # <<<<<<<<<<<<<< + * __pyx_result.__dict__.update(__pyx_state[0]) + */ + if (unlikely(__pyx_v___pyx_state == Py_None)) { + PyErr_SetString(PyExc_TypeError, "object of type 'NoneType' has no len()"); + __PYX_ERR(1, 12, __pyx_L1_error) + } + __pyx_t_2 = PyTuple_GET_SIZE(__pyx_v___pyx_state); if (unlikely(__pyx_t_2 == ((Py_ssize_t)-1))) __PYX_ERR(1, 12, __pyx_L1_error) + __pyx_t_3 = ((__pyx_t_2 > 0) != 0); + if (__pyx_t_3) { + } else { + __pyx_t_1 = __pyx_t_3; + goto __pyx_L4_bool_binop_done; + } + __pyx_t_3 = __Pyx_HasAttr(((PyObject *)__pyx_v___pyx_result), __pyx_n_s_dict); if (unlikely(__pyx_t_3 == ((int)-1))) __PYX_ERR(1, 12, __pyx_L1_error) + __pyx_t_4 = (__pyx_t_3 != 0); + __pyx_t_1 = __pyx_t_4; + __pyx_L4_bool_binop_done:; + if (__pyx_t_1) { + + /* "(tree fragment)":13 + * cdef __pyx_unpickle___Pyx_EnumMeta__set_state(__Pyx_EnumMeta __pyx_result, tuple __pyx_state): + * if len(__pyx_state) > 0 and hasattr(__pyx_result, '__dict__'): + * __pyx_result.__dict__.update(__pyx_state[0]) # <<<<<<<<<<<<<< + */ + __pyx_t_6 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v___pyx_result), __pyx_n_s_dict); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 13, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_n_s_update); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 13, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + if (unlikely(__pyx_v___pyx_state == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(1, 13, __pyx_L1_error) + } + __pyx_t_6 = __Pyx_GetItemInt_Tuple(__pyx_v___pyx_state, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 13, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_8 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_8 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_8)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_8); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + } + } + __pyx_t_5 = (__pyx_t_8) ? __Pyx_PyObject_Call2Args(__pyx_t_7, __pyx_t_8, __pyx_t_6) : __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_t_6); + __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 13, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + + /* "(tree fragment)":12 + * return __pyx_result + * cdef __pyx_unpickle___Pyx_EnumMeta__set_state(__Pyx_EnumMeta __pyx_result, tuple __pyx_state): + * if len(__pyx_state) > 0 and hasattr(__pyx_result, '__dict__'): # <<<<<<<<<<<<<< + * __pyx_result.__dict__.update(__pyx_state[0]) + */ + } + + /* "(tree fragment)":11 + * __pyx_unpickle___Pyx_EnumMeta__set_state(<__Pyx_EnumMeta> __pyx_result, __pyx_state) + * return __pyx_result + * cdef __pyx_unpickle___Pyx_EnumMeta__set_state(__Pyx_EnumMeta __pyx_result, tuple __pyx_state): # <<<<<<<<<<<<<< + * if len(__pyx_state) > 0 and hasattr(__pyx_result, '__dict__'): + * __pyx_result.__dict__.update(__pyx_state[0]) + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_AddTraceback("EnumBase.__pyx_unpickle___Pyx_EnumMeta__set_state", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_tp_new_6region_RegionBounds(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { + PyObject *o; + if (likely((t->tp_flags & Py_TPFLAGS_IS_ABSTRACT) == 0)) { + o = (*t->tp_alloc)(t, 0); + } else { + o = (PyObject *) PyBaseObject_Type.tp_new(t, __pyx_empty_tuple, 0); + } + if (unlikely(!o)) return 0; + if (unlikely(__pyx_pw_6region_12RegionBounds_1__cinit__(o, __pyx_empty_tuple, NULL) < 0)) goto bad; + return o; + bad: + Py_DECREF(o); o = 0; + return NULL; +} + +static void __pyx_tp_dealloc_6region_RegionBounds(PyObject *o) { + #if CYTHON_USE_TP_FINALIZE + if (unlikely(PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE) && Py_TYPE(o)->tp_finalize) && (!PyType_IS_GC(Py_TYPE(o)) || !_PyGC_FINALIZED(o))) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + #endif + { + PyObject *etype, *eval, *etb; + PyErr_Fetch(&etype, &eval, &etb); + __Pyx_SET_REFCNT(o, Py_REFCNT(o) + 1); + __pyx_pw_6region_12RegionBounds_5__dealloc__(o); + __Pyx_SET_REFCNT(o, Py_REFCNT(o) - 1); + PyErr_Restore(etype, eval, etb); + } + (*Py_TYPE(o)->tp_free)(o); +} + +static PyMethodDef __pyx_methods_6region_RegionBounds[] = { + {"get", (PyCFunction)__pyx_pw_6region_12RegionBounds_9get, METH_NOARGS, 0}, + {"set", (PyCFunction)(void*)(PyCFunctionWithKeywords)__pyx_pw_6region_12RegionBounds_11set, METH_VARARGS|METH_KEYWORDS, 0}, + {"__reduce_cython__", (PyCFunction)__pyx_pw_6region_12RegionBounds_13__reduce_cython__, METH_NOARGS, 0}, + {"__setstate_cython__", (PyCFunction)__pyx_pw_6region_12RegionBounds_15__setstate_cython__, METH_O, 0}, + {0, 0, 0, 0} +}; + +static PyTypeObject __pyx_type_6region_RegionBounds = { + PyVarObject_HEAD_INIT(0, 0) + "region.RegionBounds", /*tp_name*/ + sizeof(struct __pyx_obj_6region_RegionBounds), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_6region_RegionBounds, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + __pyx_pw_6region_12RegionBounds_7__str__, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + __pyx_methods_6region_RegionBounds, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + __pyx_pw_6region_12RegionBounds_3__init__, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_6region_RegionBounds, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + 0, /*tp_finalize*/ + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 + 0, /*tp_print*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 + 0, /*tp_pypy_flags*/ + #endif +}; + +static PyObject *__pyx_tp_new_6region_Rectangle(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { + PyObject *o; + if (likely((t->tp_flags & Py_TPFLAGS_IS_ABSTRACT) == 0)) { + o = (*t->tp_alloc)(t, 0); + } else { + o = (PyObject *) PyBaseObject_Type.tp_new(t, __pyx_empty_tuple, 0); + } + if (unlikely(!o)) return 0; + if (unlikely(__pyx_pw_6region_9Rectangle_1__cinit__(o, __pyx_empty_tuple, NULL) < 0)) goto bad; + return o; + bad: + Py_DECREF(o); o = 0; + return NULL; +} + +static void __pyx_tp_dealloc_6region_Rectangle(PyObject *o) { + #if CYTHON_USE_TP_FINALIZE + if (unlikely(PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE) && Py_TYPE(o)->tp_finalize) && (!PyType_IS_GC(Py_TYPE(o)) || !_PyGC_FINALIZED(o))) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + #endif + { + PyObject *etype, *eval, *etb; + PyErr_Fetch(&etype, &eval, &etb); + __Pyx_SET_REFCNT(o, Py_REFCNT(o) + 1); + __pyx_pw_6region_9Rectangle_5__dealloc__(o); + __Pyx_SET_REFCNT(o, Py_REFCNT(o) - 1); + PyErr_Restore(etype, eval, etb); + } + (*Py_TYPE(o)->tp_free)(o); +} + +static PyMethodDef __pyx_methods_6region_Rectangle[] = { + {"set", (PyCFunction)(void*)(PyCFunctionWithKeywords)__pyx_pw_6region_9Rectangle_9set, METH_VARARGS|METH_KEYWORDS, 0}, + {"get", (PyCFunction)__pyx_pw_6region_9Rectangle_11get, METH_NOARGS, __pyx_doc_6region_9Rectangle_10get}, + {"__reduce_cython__", (PyCFunction)__pyx_pw_6region_9Rectangle_13__reduce_cython__, METH_NOARGS, 0}, + {"__setstate_cython__", (PyCFunction)__pyx_pw_6region_9Rectangle_15__setstate_cython__, METH_O, 0}, + {0, 0, 0, 0} +}; + +static PyTypeObject __pyx_type_6region_Rectangle = { + PyVarObject_HEAD_INIT(0, 0) + "region.Rectangle", /*tp_name*/ + sizeof(struct __pyx_obj_6region_Rectangle), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_6region_Rectangle, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + __pyx_pw_6region_9Rectangle_7__str__, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + __pyx_methods_6region_Rectangle, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + __pyx_pw_6region_9Rectangle_3__init__, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_6region_Rectangle, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + 0, /*tp_finalize*/ + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 + 0, /*tp_print*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 + 0, /*tp_pypy_flags*/ + #endif +}; + +static PyObject *__pyx_tp_new_6region_Polygon(PyTypeObject *t, PyObject *a, PyObject *k) { + PyObject *o; + if (likely((t->tp_flags & Py_TPFLAGS_IS_ABSTRACT) == 0)) { + o = (*t->tp_alloc)(t, 0); + } else { + o = (PyObject *) PyBaseObject_Type.tp_new(t, __pyx_empty_tuple, 0); + } + if (unlikely(!o)) return 0; + if (unlikely(__pyx_pw_6region_7Polygon_1__cinit__(o, a, k) < 0)) goto bad; + return o; + bad: + Py_DECREF(o); o = 0; + return NULL; +} + +static void __pyx_tp_dealloc_6region_Polygon(PyObject *o) { + #if CYTHON_USE_TP_FINALIZE + if (unlikely(PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE) && Py_TYPE(o)->tp_finalize) && (!PyType_IS_GC(Py_TYPE(o)) || !_PyGC_FINALIZED(o))) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + #endif + { + PyObject *etype, *eval, *etb; + PyErr_Fetch(&etype, &eval, &etb); + __Pyx_SET_REFCNT(o, Py_REFCNT(o) + 1); + __pyx_pw_6region_7Polygon_3__dealloc__(o); + __Pyx_SET_REFCNT(o, Py_REFCNT(o) - 1); + PyErr_Restore(etype, eval, etb); + } + (*Py_TYPE(o)->tp_free)(o); +} + +static PyMethodDef __pyx_methods_6region_Polygon[] = { + {"__reduce_cython__", (PyCFunction)__pyx_pw_6region_7Polygon_7__reduce_cython__, METH_NOARGS, 0}, + {"__setstate_cython__", (PyCFunction)__pyx_pw_6region_7Polygon_9__setstate_cython__, METH_O, 0}, + {0, 0, 0, 0} +}; + +static PyTypeObject __pyx_type_6region_Polygon = { + PyVarObject_HEAD_INIT(0, 0) + "region.Polygon", /*tp_name*/ + sizeof(struct __pyx_obj_6region_Polygon), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_6region_Polygon, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + __pyx_pw_6region_7Polygon_5__str__, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + __pyx_methods_6region_Polygon, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_6region_Polygon, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + 0, /*tp_finalize*/ + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 + 0, /*tp_print*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 + 0, /*tp_pypy_flags*/ + #endif +}; + +static PyObject *__pyx_tp_new___Pyx_EnumMeta(PyTypeObject *t, PyObject *a, PyObject *k) { + PyObject *o = (&PyType_Type)->tp_new(t, a, k); + if (unlikely(!o)) return 0; + return o; +} + +static void __pyx_tp_dealloc___Pyx_EnumMeta(PyObject *o) { + #if CYTHON_USE_TP_FINALIZE + if (unlikely(PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE) && Py_TYPE(o)->tp_finalize) && !_PyGC_FINALIZED(o)) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + #endif + PyObject_GC_UnTrack(o); + PyObject_GC_Track(o); + (&PyType_Type)->tp_dealloc(o); +} + +static int __pyx_tp_traverse___Pyx_EnumMeta(PyObject *o, visitproc v, void *a) { + int e; + if (!(&PyType_Type)->tp_traverse); else { e = (&PyType_Type)->tp_traverse(o,v,a); if (e) return e; } + return 0; +} + +static int __pyx_tp_clear___Pyx_EnumMeta(PyObject *o) { + if (!(&PyType_Type)->tp_clear); else (&PyType_Type)->tp_clear(o); + return 0; +} +static PyObject *__pyx_sq_item___Pyx_EnumMeta(PyObject *o, Py_ssize_t i) { + PyObject *r; + PyObject *x = PyInt_FromSsize_t(i); if(!x) return 0; + r = Py_TYPE(o)->tp_as_mapping->mp_subscript(o, x); + Py_DECREF(x); + return r; +} + +static PyMethodDef __pyx_methods___Pyx_EnumMeta[] = { + {"__reduce_cython__", (PyCFunction)__pyx_pw_8EnumBase_14__Pyx_EnumMeta_7__reduce_cython__, METH_NOARGS, 0}, + {"__setstate_cython__", (PyCFunction)__pyx_pw_8EnumBase_14__Pyx_EnumMeta_9__setstate_cython__, METH_O, 0}, + {0, 0, 0, 0} +}; + +static PySequenceMethods __pyx_tp_as_sequence___Pyx_EnumMeta = { + 0, /*sq_length*/ + 0, /*sq_concat*/ + 0, /*sq_repeat*/ + __pyx_sq_item___Pyx_EnumMeta, /*sq_item*/ + 0, /*sq_slice*/ + 0, /*sq_ass_item*/ + 0, /*sq_ass_slice*/ + 0, /*sq_contains*/ + 0, /*sq_inplace_concat*/ + 0, /*sq_inplace_repeat*/ +}; + +static PyMappingMethods __pyx_tp_as_mapping___Pyx_EnumMeta = { + 0, /*mp_length*/ + __pyx_pw_8EnumBase_14__Pyx_EnumMeta_5__getitem__, /*mp_subscript*/ + 0, /*mp_ass_subscript*/ +}; + +static PyTypeObject __Pyx_EnumMeta = { + PyVarObject_HEAD_INIT(0, 0) + "region.__Pyx_EnumMeta", /*tp_name*/ + sizeof(struct __pyx_obj___Pyx_EnumMeta), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc___Pyx_EnumMeta, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + &__pyx_tp_as_sequence___Pyx_EnumMeta, /*tp_as_sequence*/ + &__pyx_tp_as_mapping___Pyx_EnumMeta, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, /*tp_flags*/ + 0, /*tp_doc*/ + __pyx_tp_traverse___Pyx_EnumMeta, /*tp_traverse*/ + __pyx_tp_clear___Pyx_EnumMeta, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + __pyx_pw_8EnumBase_14__Pyx_EnumMeta_3__iter__, /*tp_iter*/ + 0, /*tp_iternext*/ + __pyx_methods___Pyx_EnumMeta, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + __pyx_pw_8EnumBase_14__Pyx_EnumMeta_1__init__, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new___Pyx_EnumMeta, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + 0, /*tp_finalize*/ + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 + 0, /*tp_print*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 + 0, /*tp_pypy_flags*/ + #endif +}; + +static PyMethodDef __pyx_methods[] = { + {0, 0, 0, 0} +}; + +#if PY_MAJOR_VERSION >= 3 +#if CYTHON_PEP489_MULTI_PHASE_INIT +static PyObject* __pyx_pymod_create(PyObject *spec, PyModuleDef *def); /*proto*/ +static int __pyx_pymod_exec_region(PyObject* module); /*proto*/ +static PyModuleDef_Slot __pyx_moduledef_slots[] = { + {Py_mod_create, (void*)__pyx_pymod_create}, + {Py_mod_exec, (void*)__pyx_pymod_exec_region}, + {0, NULL} +}; +#endif + +static struct PyModuleDef __pyx_moduledef = { + PyModuleDef_HEAD_INIT, + "region", + 0, /* m_doc */ + #if CYTHON_PEP489_MULTI_PHASE_INIT + 0, /* m_size */ + #else + -1, /* m_size */ + #endif + __pyx_methods /* m_methods */, + #if CYTHON_PEP489_MULTI_PHASE_INIT + __pyx_moduledef_slots, /* m_slots */ + #else + NULL, /* m_reload */ + #endif + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL /* m_free */ +}; +#endif +#ifndef CYTHON_SMALL_CODE +#if defined(__clang__) + #define CYTHON_SMALL_CODE +#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) + #define CYTHON_SMALL_CODE __attribute__((cold)) +#else + #define CYTHON_SMALL_CODE +#endif +#endif + +static __Pyx_StringTabEntry __pyx_string_tab[] = { + {&__pyx_kp_s_3f_3f, __pyx_k_3f_3f, sizeof(__pyx_k_3f_3f), 0, 0, 1, 0}, + {&__pyx_kp_s_3f_3f_2, __pyx_k_3f_3f_2, sizeof(__pyx_k_3f_3f_2), 0, 0, 1, 0}, + {&__pyx_n_s_EMTPY, __pyx_k_EMTPY, sizeof(__pyx_k_EMTPY), 0, 0, 1, 1}, + {&__pyx_n_s_EnumBase, __pyx_k_EnumBase, sizeof(__pyx_k_EnumBase), 0, 0, 1, 1}, + {&__pyx_n_s_EnumType, __pyx_k_EnumType, sizeof(__pyx_k_EnumType), 0, 0, 1, 1}, + {&__pyx_kp_s_Incompatible_checksums_0x_x_vs_0, __pyx_k_Incompatible_checksums_0x_x_vs_0, sizeof(__pyx_k_Incompatible_checksums_0x_x_vs_0), 0, 0, 1, 0}, + {&__pyx_n_s_IntEnum, __pyx_k_IntEnum, sizeof(__pyx_k_IntEnum), 0, 0, 1, 1}, + {&__pyx_n_s_MASK, __pyx_k_MASK, sizeof(__pyx_k_MASK), 0, 0, 1, 1}, + {&__pyx_n_s_MemoryError, __pyx_k_MemoryError, sizeof(__pyx_k_MemoryError), 0, 0, 1, 1}, + {&__pyx_n_s_OrderedDict, __pyx_k_OrderedDict, sizeof(__pyx_k_OrderedDict), 0, 0, 1, 1}, + {&__pyx_n_s_POLYGON, __pyx_k_POLYGON, sizeof(__pyx_k_POLYGON), 0, 0, 1, 1}, + {&__pyx_n_s_PickleError, __pyx_k_PickleError, sizeof(__pyx_k_PickleError), 0, 0, 1, 1}, + {&__pyx_n_s_Polygon, __pyx_k_Polygon, sizeof(__pyx_k_Polygon), 0, 0, 1, 1}, + {&__pyx_n_s_Pyx_EnumBase, __pyx_k_Pyx_EnumBase, sizeof(__pyx_k_Pyx_EnumBase), 0, 0, 1, 1}, + {&__pyx_n_s_Pyx_EnumBase___new, __pyx_k_Pyx_EnumBase___new, sizeof(__pyx_k_Pyx_EnumBase___new), 0, 0, 1, 1}, + {&__pyx_n_s_Pyx_EnumBase___repr, __pyx_k_Pyx_EnumBase___repr, sizeof(__pyx_k_Pyx_EnumBase___repr), 0, 0, 1, 1}, + {&__pyx_n_s_Pyx_EnumBase___str, __pyx_k_Pyx_EnumBase___str, sizeof(__pyx_k_Pyx_EnumBase___str), 0, 0, 1, 1}, + {&__pyx_n_s_RECTANGEL, __pyx_k_RECTANGEL, sizeof(__pyx_k_RECTANGEL), 0, 0, 1, 1}, + {&__pyx_n_s_Rectangle, __pyx_k_Rectangle, sizeof(__pyx_k_Rectangle), 0, 0, 1, 1}, + {&__pyx_n_s_RegionBounds, __pyx_k_RegionBounds, sizeof(__pyx_k_RegionBounds), 0, 0, 1, 1}, + {&__pyx_n_s_RegionType, __pyx_k_RegionType, sizeof(__pyx_k_RegionType), 0, 0, 1, 1}, + {&__pyx_n_s_SPECIAL, __pyx_k_SPECIAL, sizeof(__pyx_k_SPECIAL), 0, 0, 1, 1}, + {&__pyx_n_s_TypeError, __pyx_k_TypeError, sizeof(__pyx_k_TypeError), 0, 0, 1, 1}, + {&__pyx_kp_s_Unknown_enum_value_s, __pyx_k_Unknown_enum_value_s, sizeof(__pyx_k_Unknown_enum_value_s), 0, 0, 1, 0}, + {&__pyx_n_s_ValueError, __pyx_k_ValueError, sizeof(__pyx_k_ValueError), 0, 0, 1, 1}, + {&__pyx_kp_s__5, __pyx_k__5, sizeof(__pyx_k__5), 0, 0, 1, 0}, + {&__pyx_n_s_bottom, __pyx_k_bottom, sizeof(__pyx_k_bottom), 0, 0, 1, 1}, + {&__pyx_n_s_bounds, __pyx_k_bounds, sizeof(__pyx_k_bounds), 0, 0, 1, 1}, + {&__pyx_n_s_c_polygon1, __pyx_k_c_polygon1, sizeof(__pyx_k_c_polygon1), 0, 0, 1, 1}, + {&__pyx_n_s_c_polygon2, __pyx_k_c_polygon2, sizeof(__pyx_k_c_polygon2), 0, 0, 1, 1}, + {&__pyx_n_s_class, __pyx_k_class, sizeof(__pyx_k_class), 0, 0, 1, 1}, + {&__pyx_n_s_cline_in_traceback, __pyx_k_cline_in_traceback, sizeof(__pyx_k_cline_in_traceback), 0, 0, 1, 1}, + {&__pyx_n_s_cls, __pyx_k_cls, sizeof(__pyx_k_cls), 0, 0, 1, 1}, + {&__pyx_n_s_collections, __pyx_k_collections, sizeof(__pyx_k_collections), 0, 0, 1, 1}, + {&__pyx_n_s_ctemplate, __pyx_k_ctemplate, sizeof(__pyx_k_ctemplate), 0, 0, 1, 1}, + {&__pyx_n_s_dct, __pyx_k_dct, sizeof(__pyx_k_dct), 0, 0, 1, 1}, + {&__pyx_n_s_dict, __pyx_k_dict, sizeof(__pyx_k_dict), 0, 0, 1, 1}, + {&__pyx_n_s_doc, __pyx_k_doc, sizeof(__pyx_k_doc), 0, 0, 1, 1}, + {&__pyx_n_s_encode, __pyx_k_encode, sizeof(__pyx_k_encode), 0, 0, 1, 1}, + {&__pyx_n_s_enum, __pyx_k_enum, sizeof(__pyx_k_enum), 0, 0, 1, 1}, + {&__pyx_n_s_format, __pyx_k_format, sizeof(__pyx_k_format), 0, 0, 1, 1}, + {&__pyx_n_s_getstate, __pyx_k_getstate, sizeof(__pyx_k_getstate), 0, 0, 1, 1}, + {&__pyx_n_s_height, __pyx_k_height, sizeof(__pyx_k_height), 0, 0, 1, 1}, + {&__pyx_n_s_i, __pyx_k_i, sizeof(__pyx_k_i), 0, 0, 1, 1}, + {&__pyx_n_s_import, __pyx_k_import, sizeof(__pyx_k_import), 0, 0, 1, 1}, + {&__pyx_n_s_inf, __pyx_k_inf, sizeof(__pyx_k_inf), 0, 0, 1, 1}, + {&__pyx_n_s_init, __pyx_k_init, sizeof(__pyx_k_init), 0, 0, 1, 1}, + {&__pyx_n_s_left, __pyx_k_left, sizeof(__pyx_k_left), 0, 0, 1, 1}, + {&__pyx_n_s_main, __pyx_k_main, sizeof(__pyx_k_main), 0, 0, 1, 1}, + {&__pyx_n_s_members, __pyx_k_members, sizeof(__pyx_k_members), 0, 0, 1, 1}, + {&__pyx_n_s_metaclass, __pyx_k_metaclass, sizeof(__pyx_k_metaclass), 0, 0, 1, 1}, + {&__pyx_n_s_module, __pyx_k_module, sizeof(__pyx_k_module), 0, 0, 1, 1}, + {&__pyx_n_s_name, __pyx_k_name, sizeof(__pyx_k_name), 0, 0, 1, 1}, + {&__pyx_n_s_name_2, __pyx_k_name_2, sizeof(__pyx_k_name_2), 0, 0, 1, 1}, + {&__pyx_n_s_nan, __pyx_k_nan, sizeof(__pyx_k_nan), 0, 0, 1, 1}, + {&__pyx_n_s_new, __pyx_k_new, sizeof(__pyx_k_new), 0, 0, 1, 1}, + {&__pyx_n_s_no_bounds, __pyx_k_no_bounds, sizeof(__pyx_k_no_bounds), 0, 0, 1, 1}, + {&__pyx_kp_s_no_default___reduce___due_to_non, __pyx_k_no_default___reduce___due_to_non, sizeof(__pyx_k_no_default___reduce___due_to_non), 0, 0, 1, 0}, + {&__pyx_n_s_only1, __pyx_k_only1, sizeof(__pyx_k_only1), 0, 0, 1, 1}, + {&__pyx_n_s_only2, __pyx_k_only2, sizeof(__pyx_k_only2), 0, 0, 1, 1}, + {&__pyx_n_s_output, __pyx_k_output, sizeof(__pyx_k_output), 0, 0, 1, 1}, + {&__pyx_n_s_overlap, __pyx_k_overlap, sizeof(__pyx_k_overlap), 0, 0, 1, 1}, + {&__pyx_n_s_overlaps, __pyx_k_overlaps, sizeof(__pyx_k_overlaps), 0, 0, 1, 1}, + {&__pyx_n_s_parents, __pyx_k_parents, sizeof(__pyx_k_parents), 0, 0, 1, 1}, + {&__pyx_n_s_pickle, __pyx_k_pickle, sizeof(__pyx_k_pickle), 0, 0, 1, 1}, + {&__pyx_n_s_pno_bounds, __pyx_k_pno_bounds, sizeof(__pyx_k_pno_bounds), 0, 0, 1, 1}, + {&__pyx_n_s_points, __pyx_k_points, sizeof(__pyx_k_points), 0, 0, 1, 1}, + {&__pyx_n_s_polygon1, __pyx_k_polygon1, sizeof(__pyx_k_polygon1), 0, 0, 1, 1}, + {&__pyx_n_s_polygon1_2, __pyx_k_polygon1_2, sizeof(__pyx_k_polygon1_2), 0, 0, 1, 1}, + {&__pyx_n_s_polygon2, __pyx_k_polygon2, sizeof(__pyx_k_polygon2), 0, 0, 1, 1}, + {&__pyx_n_s_polygon2_2, __pyx_k_polygon2_2, sizeof(__pyx_k_polygon2_2), 0, 0, 1, 1}, + {&__pyx_n_s_polygons1, __pyx_k_polygons1, sizeof(__pyx_k_polygons1), 0, 0, 1, 1}, + {&__pyx_n_s_polygons2, __pyx_k_polygons2, sizeof(__pyx_k_polygons2), 0, 0, 1, 1}, + {&__pyx_n_s_prepare, __pyx_k_prepare, sizeof(__pyx_k_prepare), 0, 0, 1, 1}, + {&__pyx_n_s_ptemplate, __pyx_k_ptemplate, sizeof(__pyx_k_ptemplate), 0, 0, 1, 1}, + {&__pyx_n_s_pyx_PickleError, __pyx_k_pyx_PickleError, sizeof(__pyx_k_pyx_PickleError), 0, 0, 1, 1}, + {&__pyx_n_s_pyx_checksum, __pyx_k_pyx_checksum, sizeof(__pyx_k_pyx_checksum), 0, 0, 1, 1}, + {&__pyx_n_s_pyx_result, __pyx_k_pyx_result, sizeof(__pyx_k_pyx_result), 0, 0, 1, 1}, + {&__pyx_n_s_pyx_state, __pyx_k_pyx_state, sizeof(__pyx_k_pyx_state), 0, 0, 1, 1}, + {&__pyx_n_s_pyx_type, __pyx_k_pyx_type, sizeof(__pyx_k_pyx_type), 0, 0, 1, 1}, + {&__pyx_n_s_pyx_unpickle___Pyx_EnumMeta, __pyx_k_pyx_unpickle___Pyx_EnumMeta, sizeof(__pyx_k_pyx_unpickle___Pyx_EnumMeta), 0, 0, 1, 1}, + {&__pyx_n_s_qualname, __pyx_k_qualname, sizeof(__pyx_k_qualname), 0, 0, 1, 1}, + {&__pyx_n_s_range, __pyx_k_range, sizeof(__pyx_k_range), 0, 0, 1, 1}, + {&__pyx_n_s_reduce, __pyx_k_reduce, sizeof(__pyx_k_reduce), 0, 0, 1, 1}, + {&__pyx_n_s_reduce_cython, __pyx_k_reduce_cython, sizeof(__pyx_k_reduce_cython), 0, 0, 1, 1}, + {&__pyx_n_s_reduce_ex, __pyx_k_reduce_ex, sizeof(__pyx_k_reduce_ex), 0, 0, 1, 1}, + {&__pyx_n_s_region, __pyx_k_region, sizeof(__pyx_k_region), 0, 0, 1, 1}, + {&__pyx_kp_s_region_pyx, __pyx_k_region_pyx, sizeof(__pyx_k_region_pyx), 0, 0, 1, 0}, + {&__pyx_n_s_repr, __pyx_k_repr, sizeof(__pyx_k_repr), 0, 0, 1, 1}, + {&__pyx_n_s_res, __pyx_k_res, sizeof(__pyx_k_res), 0, 0, 1, 1}, + {&__pyx_n_s_ret, __pyx_k_ret, sizeof(__pyx_k_ret), 0, 0, 1, 1}, + {&__pyx_n_s_right, __pyx_k_right, sizeof(__pyx_k_right), 0, 0, 1, 1}, + {&__pyx_kp_s_s_s, __pyx_k_s_s, sizeof(__pyx_k_s_s), 0, 0, 1, 0}, + {&__pyx_kp_s_s_s_d, __pyx_k_s_s_d, sizeof(__pyx_k_s_s_d), 0, 0, 1, 0}, + {&__pyx_n_s_self, __pyx_k_self, sizeof(__pyx_k_self), 0, 0, 1, 1}, + {&__pyx_n_s_set, __pyx_k_set, sizeof(__pyx_k_set), 0, 0, 1, 1}, + {&__pyx_n_s_setstate, __pyx_k_setstate, sizeof(__pyx_k_setstate), 0, 0, 1, 1}, + {&__pyx_n_s_setstate_cython, __pyx_k_setstate_cython, sizeof(__pyx_k_setstate_cython), 0, 0, 1, 1}, + {&__pyx_n_s_str, __pyx_k_str, sizeof(__pyx_k_str), 0, 0, 1, 1}, + {&__pyx_kp_s_stringsource, __pyx_k_stringsource, sizeof(__pyx_k_stringsource), 0, 0, 1, 0}, + {&__pyx_n_s_template, __pyx_k_template, sizeof(__pyx_k_template), 0, 0, 1, 1}, + {&__pyx_n_s_test, __pyx_k_test, sizeof(__pyx_k_test), 0, 0, 1, 1}, + {&__pyx_n_s_top, __pyx_k_top, sizeof(__pyx_k_top), 0, 0, 1, 1}, + {&__pyx_kp_s_top_3f_bottom_3f_left_3f_reight, __pyx_k_top_3f_bottom_3f_left_3f_reight, sizeof(__pyx_k_top_3f_bottom_3f_left_3f_reight), 0, 0, 1, 0}, + {&__pyx_n_s_update, __pyx_k_update, sizeof(__pyx_k_update), 0, 0, 1, 1}, + {&__pyx_n_s_v, __pyx_k_v, sizeof(__pyx_k_v), 0, 0, 1, 1}, + {&__pyx_n_s_value, __pyx_k_value, sizeof(__pyx_k_value), 0, 0, 1, 1}, + {&__pyx_n_s_values, __pyx_k_values, sizeof(__pyx_k_values), 0, 0, 1, 1}, + {&__pyx_n_s_vot_float2str, __pyx_k_vot_float2str, sizeof(__pyx_k_vot_float2str), 0, 0, 1, 1}, + {&__pyx_n_s_vot_overlap, __pyx_k_vot_overlap, sizeof(__pyx_k_vot_overlap), 0, 0, 1, 1}, + {&__pyx_n_s_vot_overlap_traj, __pyx_k_vot_overlap_traj, sizeof(__pyx_k_vot_overlap_traj), 0, 0, 1, 1}, + {&__pyx_n_s_width, __pyx_k_width, sizeof(__pyx_k_width), 0, 0, 1, 1}, + {&__pyx_n_s_x, __pyx_k_x, sizeof(__pyx_k_x), 0, 0, 1, 1}, + {&__pyx_kp_s_x_3f_y_3f_width_3f_height_3f, __pyx_k_x_3f_y_3f_width_3f_height_3f, sizeof(__pyx_k_x_3f_y_3f_width_3f_height_3f), 0, 0, 1, 0}, + {&__pyx_n_s_y, __pyx_k_y, sizeof(__pyx_k_y), 0, 0, 1, 1}, + {0, 0, 0, 0, 0, 0, 0} +}; +static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(void) { + __pyx_builtin_MemoryError = __Pyx_GetBuiltinName(__pyx_n_s_MemoryError); if (!__pyx_builtin_MemoryError) __PYX_ERR(0, 34, __pyx_L1_error) + __pyx_builtin_TypeError = __Pyx_GetBuiltinName(__pyx_n_s_TypeError); if (!__pyx_builtin_TypeError) __PYX_ERR(1, 2, __pyx_L1_error) + __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) __PYX_ERR(0, 127, __pyx_L1_error) + __pyx_builtin_ValueError = __Pyx_GetBuiltinName(__pyx_n_s_ValueError); if (!__pyx_builtin_ValueError) __PYX_ERR(1, 33, __pyx_L1_error) + return 0; + __pyx_L1_error:; + return -1; +} + +static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_InitCachedConstants", 0); + + /* "(tree fragment)":2 + * def __reduce_cython__(self): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") # <<<<<<<<<<<<<< + * def __setstate_cython__(self, __pyx_state): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + */ + __pyx_tuple_ = PyTuple_Pack(1, __pyx_kp_s_no_default___reduce___due_to_non); if (unlikely(!__pyx_tuple_)) __PYX_ERR(1, 2, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple_); + __Pyx_GIVEREF(__pyx_tuple_); + + /* "(tree fragment)":4 + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + * def __setstate_cython__(self, __pyx_state): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") # <<<<<<<<<<<<<< + */ + __pyx_tuple__2 = PyTuple_Pack(1, __pyx_kp_s_no_default___reduce___due_to_non); if (unlikely(!__pyx_tuple__2)) __PYX_ERR(1, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__2); + __Pyx_GIVEREF(__pyx_tuple__2); + + /* "(tree fragment)":2 + * def __reduce_cython__(self): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") # <<<<<<<<<<<<<< + * def __setstate_cython__(self, __pyx_state): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + */ + __pyx_tuple__3 = PyTuple_Pack(1, __pyx_kp_s_no_default___reduce___due_to_non); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(1, 2, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__3); + __Pyx_GIVEREF(__pyx_tuple__3); + + /* "(tree fragment)":4 + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + * def __setstate_cython__(self, __pyx_state): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") # <<<<<<<<<<<<<< + */ + __pyx_tuple__4 = PyTuple_Pack(1, __pyx_kp_s_no_default___reduce___due_to_non); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(1, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__4); + __Pyx_GIVEREF(__pyx_tuple__4); + + /* "(tree fragment)":2 + * def __reduce_cython__(self): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") # <<<<<<<<<<<<<< + * def __setstate_cython__(self, __pyx_state): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + */ + __pyx_tuple__6 = PyTuple_Pack(1, __pyx_kp_s_no_default___reduce___due_to_non); if (unlikely(!__pyx_tuple__6)) __PYX_ERR(1, 2, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__6); + __Pyx_GIVEREF(__pyx_tuple__6); + + /* "(tree fragment)":4 + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + * def __setstate_cython__(self, __pyx_state): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") # <<<<<<<<<<<<<< + */ + __pyx_tuple__7 = PyTuple_Pack(1, __pyx_kp_s_no_default___reduce___due_to_non); if (unlikely(!__pyx_tuple__7)) __PYX_ERR(1, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__7); + __Pyx_GIVEREF(__pyx_tuple__7); + __pyx_tuple__8 = PyTuple_Pack(3, __pyx_int_222419149, __pyx_int_238750788, __pyx_int_228825662); if (unlikely(!__pyx_tuple__8)) __PYX_ERR(1, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__8); + __Pyx_GIVEREF(__pyx_tuple__8); + + /* "region.pyx":151 + * return ret + * + * def vot_overlap(polygon1, polygon2, bounds=None): # <<<<<<<<<<<<<< + * """ computing overlap between two polygon + * Args: + */ + __pyx_tuple__9 = PyTuple_Pack(11, __pyx_n_s_polygon1, __pyx_n_s_polygon2, __pyx_n_s_bounds, __pyx_n_s_polygon1_2, __pyx_n_s_polygon2_2, __pyx_n_s_pno_bounds, __pyx_n_s_only1, __pyx_n_s_only2, __pyx_n_s_c_polygon1, __pyx_n_s_c_polygon2, __pyx_n_s_no_bounds); if (unlikely(!__pyx_tuple__9)) __PYX_ERR(0, 151, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__9); + __Pyx_GIVEREF(__pyx_tuple__9); + __pyx_codeobj__10 = (PyObject*)__Pyx_PyCode_New(3, 0, 11, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__9, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_region_pyx, __pyx_n_s_vot_overlap, 151, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__10)) __PYX_ERR(0, 151, __pyx_L1_error) + + /* "region.pyx":197 + * no_bounds) + * + * def vot_overlap_traj(polygons1, polygons2, bounds=None): # <<<<<<<<<<<<<< + * """ computing overlap between two trajectory + * Args: + */ + __pyx_tuple__11 = PyTuple_Pack(6, __pyx_n_s_polygons1, __pyx_n_s_polygons2, __pyx_n_s_bounds, __pyx_n_s_overlaps, __pyx_n_s_i, __pyx_n_s_overlap); if (unlikely(!__pyx_tuple__11)) __PYX_ERR(0, 197, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__11); + __Pyx_GIVEREF(__pyx_tuple__11); + __pyx_codeobj__12 = (PyObject*)__Pyx_PyCode_New(3, 0, 6, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__11, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_region_pyx, __pyx_n_s_vot_overlap_traj, 197, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__12)) __PYX_ERR(0, 197, __pyx_L1_error) + + /* "region.pyx":214 + * + * + * def vot_float2str(template, float value): # <<<<<<<<<<<<<< + * """ + * Args: + */ + __pyx_tuple__13 = PyTuple_Pack(6, __pyx_n_s_template, __pyx_n_s_value, __pyx_n_s_ptemplate, __pyx_n_s_ctemplate, __pyx_n_s_output, __pyx_n_s_ret); if (unlikely(!__pyx_tuple__13)) __PYX_ERR(0, 214, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__13); + __Pyx_GIVEREF(__pyx_tuple__13); + __pyx_codeobj__14 = (PyObject*)__Pyx_PyCode_New(2, 0, 6, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__13, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_region_pyx, __pyx_n_s_vot_float2str, 214, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__14)) __PYX_ERR(0, 214, __pyx_L1_error) + + /* "EnumBase":28 + * class __Pyx_EnumBase(int): + * __metaclass__ = __Pyx_EnumMeta + * def __new__(cls, value, name=None): # <<<<<<<<<<<<<< + * for v in cls: + * if v == value: + */ + __pyx_tuple__15 = PyTuple_Pack(5, __pyx_n_s_cls, __pyx_n_s_value, __pyx_n_s_name, __pyx_n_s_v, __pyx_n_s_res); if (unlikely(!__pyx_tuple__15)) __PYX_ERR(1, 28, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__15); + __Pyx_GIVEREF(__pyx_tuple__15); + __pyx_codeobj__16 = (PyObject*)__Pyx_PyCode_New(3, 0, 5, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__15, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_stringsource, __pyx_n_s_new, 28, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__16)) __PYX_ERR(1, 28, __pyx_L1_error) + __pyx_tuple__17 = PyTuple_Pack(1, ((PyObject *)Py_None)); if (unlikely(!__pyx_tuple__17)) __PYX_ERR(1, 28, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__17); + __Pyx_GIVEREF(__pyx_tuple__17); + + /* "EnumBase":39 + * cls.__members__[name] = res + * return res + * def __repr__(self): # <<<<<<<<<<<<<< + * return "<%s.%s: %d>" % (self.__class__.__name__, self.name, self) + * def __str__(self): + */ + __pyx_tuple__18 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__18)) __PYX_ERR(1, 39, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__18); + __Pyx_GIVEREF(__pyx_tuple__18); + __pyx_codeobj__19 = (PyObject*)__Pyx_PyCode_New(1, 0, 1, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__18, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_stringsource, __pyx_n_s_repr, 39, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__19)) __PYX_ERR(1, 39, __pyx_L1_error) + + /* "EnumBase":41 + * def __repr__(self): + * return "<%s.%s: %d>" % (self.__class__.__name__, self.name, self) + * def __str__(self): # <<<<<<<<<<<<<< + * return "%s.%s" % (self.__class__.__name__, self.name) + * + */ + __pyx_tuple__20 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__20)) __PYX_ERR(1, 41, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__20); + __Pyx_GIVEREF(__pyx_tuple__20); + __pyx_codeobj__21 = (PyObject*)__Pyx_PyCode_New(1, 0, 1, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__20, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_stringsource, __pyx_n_s_str, 41, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__21)) __PYX_ERR(1, 41, __pyx_L1_error) + + /* "(tree fragment)":1 + * def __pyx_unpickle___Pyx_EnumMeta(__pyx_type, long __pyx_checksum, __pyx_state): # <<<<<<<<<<<<<< + * cdef object __pyx_PickleError + * cdef object __pyx_result + */ + __pyx_tuple__22 = PyTuple_Pack(5, __pyx_n_s_pyx_type, __pyx_n_s_pyx_checksum, __pyx_n_s_pyx_state, __pyx_n_s_pyx_PickleError, __pyx_n_s_pyx_result); if (unlikely(!__pyx_tuple__22)) __PYX_ERR(1, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__22); + __Pyx_GIVEREF(__pyx_tuple__22); + __pyx_codeobj__23 = (PyObject*)__Pyx_PyCode_New(3, 0, 5, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__22, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_stringsource, __pyx_n_s_pyx_unpickle___Pyx_EnumMeta, 1, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__23)) __PYX_ERR(1, 1, __pyx_L1_error) + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_RefNannyFinishContext(); + return -1; +} + +static CYTHON_SMALL_CODE int __Pyx_InitGlobals(void) { + if (__Pyx_InitStrings(__pyx_string_tab) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_0 = PyInt_FromLong(0); if (unlikely(!__pyx_int_0)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_1 = PyInt_FromLong(1); if (unlikely(!__pyx_int_1)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_2 = PyInt_FromLong(2); if (unlikely(!__pyx_int_2)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_222419149 = PyInt_FromLong(222419149L); if (unlikely(!__pyx_int_222419149)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_228825662 = PyInt_FromLong(228825662L); if (unlikely(!__pyx_int_228825662)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_238750788 = PyInt_FromLong(238750788L); if (unlikely(!__pyx_int_238750788)) __PYX_ERR(0, 1, __pyx_L1_error) + return 0; + __pyx_L1_error:; + return -1; +} + +static CYTHON_SMALL_CODE int __Pyx_modinit_global_init_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_variable_export_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_function_export_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_type_init_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_type_import_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_variable_import_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_function_import_code(void); /*proto*/ + +static int __Pyx_modinit_global_init_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_global_init_code", 0); + /*--- Global init code ---*/ + __Pyx_OrderedDict = Py_None; Py_INCREF(Py_None); + __Pyx_EnumBase = Py_None; Py_INCREF(Py_None); + __Pyx_globals = ((PyObject*)Py_None); Py_INCREF(Py_None); + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_variable_export_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_variable_export_code", 0); + /*--- Variable export code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_function_export_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_function_export_code", 0); + /*--- Function export code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_type_init_code(void) { + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__Pyx_modinit_type_init_code", 0); + /*--- Type init code ---*/ + if (PyType_Ready(&__pyx_type_6region_RegionBounds) < 0) __PYX_ERR(0, 26, __pyx_L1_error) + #if PY_VERSION_HEX < 0x030800B1 + __pyx_type_6region_RegionBounds.tp_print = 0; + #endif + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_type_6region_RegionBounds.tp_dictoffset && __pyx_type_6region_RegionBounds.tp_getattro == PyObject_GenericGetAttr)) { + __pyx_type_6region_RegionBounds.tp_getattro = __Pyx_PyObject_GenericGetAttr; + } + if (PyObject_SetAttr(__pyx_m, __pyx_n_s_RegionBounds, (PyObject *)&__pyx_type_6region_RegionBounds) < 0) __PYX_ERR(0, 26, __pyx_L1_error) + if (__Pyx_setup_reduce((PyObject*)&__pyx_type_6region_RegionBounds) < 0) __PYX_ERR(0, 26, __pyx_L1_error) + __pyx_ptype_6region_RegionBounds = &__pyx_type_6region_RegionBounds; + if (PyType_Ready(&__pyx_type_6region_Rectangle) < 0) __PYX_ERR(0, 63, __pyx_L1_error) + #if PY_VERSION_HEX < 0x030800B1 + __pyx_type_6region_Rectangle.tp_print = 0; + #endif + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_type_6region_Rectangle.tp_dictoffset && __pyx_type_6region_Rectangle.tp_getattro == PyObject_GenericGetAttr)) { + __pyx_type_6region_Rectangle.tp_getattro = __Pyx_PyObject_GenericGetAttr; + } + if (PyObject_SetAttr(__pyx_m, __pyx_n_s_Rectangle, (PyObject *)&__pyx_type_6region_Rectangle) < 0) __PYX_ERR(0, 63, __pyx_L1_error) + if (__Pyx_setup_reduce((PyObject*)&__pyx_type_6region_Rectangle) < 0) __PYX_ERR(0, 63, __pyx_L1_error) + __pyx_ptype_6region_Rectangle = &__pyx_type_6region_Rectangle; + if (PyType_Ready(&__pyx_type_6region_Polygon) < 0) __PYX_ERR(0, 104, __pyx_L1_error) + #if PY_VERSION_HEX < 0x030800B1 + __pyx_type_6region_Polygon.tp_print = 0; + #endif + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_type_6region_Polygon.tp_dictoffset && __pyx_type_6region_Polygon.tp_getattro == PyObject_GenericGetAttr)) { + __pyx_type_6region_Polygon.tp_getattro = __Pyx_PyObject_GenericGetAttr; + } + if (PyObject_SetAttr(__pyx_m, __pyx_n_s_Polygon, (PyObject *)&__pyx_type_6region_Polygon) < 0) __PYX_ERR(0, 104, __pyx_L1_error) + if (__Pyx_setup_reduce((PyObject*)&__pyx_type_6region_Polygon) < 0) __PYX_ERR(0, 104, __pyx_L1_error) + __pyx_ptype_6region_Polygon = &__pyx_type_6region_Polygon; + __Pyx_EnumMeta.tp_base = (&PyType_Type); + if (PyType_Ready(&__Pyx_EnumMeta) < 0) __PYX_ERR(1, 15, __pyx_L1_error) + #if PY_VERSION_HEX < 0x030800B1 + __Pyx_EnumMeta.tp_print = 0; + #endif + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__Pyx_EnumMeta.tp_dictoffset && __Pyx_EnumMeta.tp_getattro == PyObject_GenericGetAttr)) { + __Pyx_EnumMeta.tp_getattro = __Pyx_PyObject_GenericGetAttr; + } + if (__Pyx_setup_reduce((PyObject*)&__Pyx_EnumMeta) < 0) __PYX_ERR(1, 15, __pyx_L1_error) + __pyx_ptype___Pyx_EnumMeta = &__Pyx_EnumMeta; + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_RefNannyFinishContext(); + return -1; +} + +static int __Pyx_modinit_type_import_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_type_import_code", 0); + /*--- Type import code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_variable_import_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_variable_import_code", 0); + /*--- Variable import code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_function_import_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_function_import_code", 0); + /*--- Function import code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + + +#ifndef CYTHON_NO_PYINIT_EXPORT +#define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC +#elif PY_MAJOR_VERSION < 3 +#ifdef __cplusplus +#define __Pyx_PyMODINIT_FUNC extern "C" void +#else +#define __Pyx_PyMODINIT_FUNC void +#endif +#else +#ifdef __cplusplus +#define __Pyx_PyMODINIT_FUNC extern "C" PyObject * +#else +#define __Pyx_PyMODINIT_FUNC PyObject * +#endif +#endif + + +#if PY_MAJOR_VERSION < 3 +__Pyx_PyMODINIT_FUNC initregion(void) CYTHON_SMALL_CODE; /*proto*/ +__Pyx_PyMODINIT_FUNC initregion(void) +#else +__Pyx_PyMODINIT_FUNC PyInit_region(void) CYTHON_SMALL_CODE; /*proto*/ +__Pyx_PyMODINIT_FUNC PyInit_region(void) +#if CYTHON_PEP489_MULTI_PHASE_INIT +{ + return PyModuleDef_Init(&__pyx_moduledef); +} +static CYTHON_SMALL_CODE int __Pyx_check_single_interpreter(void) { + #if PY_VERSION_HEX >= 0x030700A1 + static PY_INT64_T main_interpreter_id = -1; + PY_INT64_T current_id = PyInterpreterState_GetID(PyThreadState_Get()->interp); + if (main_interpreter_id == -1) { + main_interpreter_id = current_id; + return (unlikely(current_id == -1)) ? -1 : 0; + } else if (unlikely(main_interpreter_id != current_id)) + #else + static PyInterpreterState *main_interpreter = NULL; + PyInterpreterState *current_interpreter = PyThreadState_Get()->interp; + if (!main_interpreter) { + main_interpreter = current_interpreter; + } else if (unlikely(main_interpreter != current_interpreter)) + #endif + { + PyErr_SetString( + PyExc_ImportError, + "Interpreter change detected - this module can only be loaded into one interpreter per process."); + return -1; + } + return 0; +} +static CYTHON_SMALL_CODE int __Pyx_copy_spec_to_module(PyObject *spec, PyObject *moddict, const char* from_name, const char* to_name, int allow_none) { + PyObject *value = PyObject_GetAttrString(spec, from_name); + int result = 0; + if (likely(value)) { + if (allow_none || value != Py_None) { + result = PyDict_SetItemString(moddict, to_name, value); + } + Py_DECREF(value); + } else if (PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Clear(); + } else { + result = -1; + } + return result; +} +static CYTHON_SMALL_CODE PyObject* __pyx_pymod_create(PyObject *spec, CYTHON_UNUSED PyModuleDef *def) { + PyObject *module = NULL, *moddict, *modname; + if (__Pyx_check_single_interpreter()) + return NULL; + if (__pyx_m) + return __Pyx_NewRef(__pyx_m); + modname = PyObject_GetAttrString(spec, "name"); + if (unlikely(!modname)) goto bad; + module = PyModule_NewObject(modname); + Py_DECREF(modname); + if (unlikely(!module)) goto bad; + moddict = PyModule_GetDict(module); + if (unlikely(!moddict)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "loader", "__loader__", 1) < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "origin", "__file__", 1) < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "parent", "__package__", 1) < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "submodule_search_locations", "__path__", 0) < 0)) goto bad; + return module; +bad: + Py_XDECREF(module); + return NULL; +} + + +static CYTHON_SMALL_CODE int __pyx_pymod_exec_region(PyObject *__pyx_pyinit_module) +#endif +#endif +{ + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannyDeclarations + #if CYTHON_PEP489_MULTI_PHASE_INIT + if (__pyx_m) { + if (__pyx_m == __pyx_pyinit_module) return 0; + PyErr_SetString(PyExc_RuntimeError, "Module 'region' has already been imported. Re-initialisation is not supported."); + return -1; + } + #elif PY_MAJOR_VERSION >= 3 + if (__pyx_m) return __Pyx_NewRef(__pyx_m); + #endif + #if CYTHON_REFNANNY +__Pyx_RefNanny = __Pyx_RefNannyImportAPI("refnanny"); +if (!__Pyx_RefNanny) { + PyErr_Clear(); + __Pyx_RefNanny = __Pyx_RefNannyImportAPI("Cython.Runtime.refnanny"); + if (!__Pyx_RefNanny) + Py_FatalError("failed to import 'refnanny' module"); +} +#endif + __Pyx_RefNannySetupContext("__Pyx_PyMODINIT_FUNC PyInit_region(void)", 0); + if (__Pyx_check_binary_version() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #ifdef __Pxy_PyFrame_Initialize_Offsets + __Pxy_PyFrame_Initialize_Offsets(); + #endif + __pyx_empty_tuple = PyTuple_New(0); if (unlikely(!__pyx_empty_tuple)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_empty_bytes = PyBytes_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_bytes)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_empty_unicode = PyUnicode_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_unicode)) __PYX_ERR(0, 1, __pyx_L1_error) + #ifdef __Pyx_CyFunction_USED + if (__pyx_CyFunction_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_FusedFunction_USED + if (__pyx_FusedFunction_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_Coroutine_USED + if (__pyx_Coroutine_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_Generator_USED + if (__pyx_Generator_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_AsyncGen_USED + if (__pyx_AsyncGen_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_StopAsyncIteration_USED + if (__pyx_StopAsyncIteration_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + /*--- Library function declarations ---*/ + /*--- Threads initialization code ---*/ + #if defined(WITH_THREAD) && PY_VERSION_HEX < 0x030700F0 && defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS + PyEval_InitThreads(); + #endif + /*--- Module creation code ---*/ + #if CYTHON_PEP489_MULTI_PHASE_INIT + __pyx_m = __pyx_pyinit_module; + Py_INCREF(__pyx_m); + #else + #if PY_MAJOR_VERSION < 3 + __pyx_m = Py_InitModule4("region", __pyx_methods, 0, 0, PYTHON_API_VERSION); Py_XINCREF(__pyx_m); + #else + __pyx_m = PyModule_Create(&__pyx_moduledef); + #endif + if (unlikely(!__pyx_m)) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + __pyx_d = PyModule_GetDict(__pyx_m); if (unlikely(!__pyx_d)) __PYX_ERR(0, 1, __pyx_L1_error) + Py_INCREF(__pyx_d); + __pyx_b = PyImport_AddModule(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_b)) __PYX_ERR(0, 1, __pyx_L1_error) + Py_INCREF(__pyx_b); + __pyx_cython_runtime = PyImport_AddModule((char *) "cython_runtime"); if (unlikely(!__pyx_cython_runtime)) __PYX_ERR(0, 1, __pyx_L1_error) + Py_INCREF(__pyx_cython_runtime); + if (PyObject_SetAttrString(__pyx_m, "__builtins__", __pyx_b) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + /*--- Initialize various global constants etc. ---*/ + if (__Pyx_InitGlobals() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #if PY_MAJOR_VERSION < 3 && (__PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT) + if (__Pyx_init_sys_getdefaultencoding_params() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + if (__pyx_module_is_main_region) { + if (PyObject_SetAttr(__pyx_m, __pyx_n_s_name_2, __pyx_n_s_main) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + } + #if PY_MAJOR_VERSION >= 3 + { + PyObject *modules = PyImport_GetModuleDict(); if (unlikely(!modules)) __PYX_ERR(0, 1, __pyx_L1_error) + if (!PyDict_GetItemString(modules, "region")) { + if (unlikely(PyDict_SetItemString(modules, "region", __pyx_m) < 0)) __PYX_ERR(0, 1, __pyx_L1_error) + } + } + #endif + /*--- Builtin init code ---*/ + if (__Pyx_InitCachedBuiltins() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + /*--- Constants init code ---*/ + if (__Pyx_InitCachedConstants() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + /*--- Global type/function init code ---*/ + (void)__Pyx_modinit_global_init_code(); + (void)__Pyx_modinit_variable_export_code(); + (void)__Pyx_modinit_function_export_code(); + if (unlikely(__Pyx_modinit_type_init_code() < 0)) __PYX_ERR(0, 1, __pyx_L1_error) + (void)__Pyx_modinit_type_import_code(); + (void)__Pyx_modinit_variable_import_code(); + (void)__Pyx_modinit_function_import_code(); + /*--- Execution code ---*/ + #if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED) + if (__Pyx_patch_abc() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + + /* "region.pyx":151 + * return ret + * + * def vot_overlap(polygon1, polygon2, bounds=None): # <<<<<<<<<<<<<< + * """ computing overlap between two polygon + * Args: + */ + __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_6region_1vot_overlap, NULL, __pyx_n_s_region); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 151, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_vot_overlap, __pyx_t_1) < 0) __PYX_ERR(0, 151, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "region.pyx":197 + * no_bounds) + * + * def vot_overlap_traj(polygons1, polygons2, bounds=None): # <<<<<<<<<<<<<< + * """ computing overlap between two trajectory + * Args: + */ + __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_6region_3vot_overlap_traj, NULL, __pyx_n_s_region); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 197, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_vot_overlap_traj, __pyx_t_1) < 0) __PYX_ERR(0, 197, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "region.pyx":214 + * + * + * def vot_float2str(template, float value): # <<<<<<<<<<<<<< + * """ + * Args: + */ + __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_6region_5vot_float2str, NULL, __pyx_n_s_region); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 214, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_vot_float2str, __pyx_t_1) < 0) __PYX_ERR(0, 214, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "region.pyx":1 + * # -------------------------------------------------------- # <<<<<<<<<<<<<< + * # Python Single Object Tracking Evaluation + * # Licensed under The MIT License [see LICENSE for details] + */ + __pyx_t_1 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "EnumBase":9 + * + * cdef object __Pyx_OrderedDict + * if PY_VERSION_HEX >= 0x02070000: # <<<<<<<<<<<<<< + * from collections import OrderedDict as __Pyx_OrderedDict + * else: + */ + __pyx_t_2 = ((PY_VERSION_HEX >= 0x02070000) != 0); + if (__pyx_t_2) { + + /* "EnumBase":10 + * cdef object __Pyx_OrderedDict + * if PY_VERSION_HEX >= 0x02070000: + * from collections import OrderedDict as __Pyx_OrderedDict # <<<<<<<<<<<<<< + * else: + * __Pyx_OrderedDict = dict + */ + __pyx_t_1 = PyList_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 10, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(__pyx_n_s_OrderedDict); + __Pyx_GIVEREF(__pyx_n_s_OrderedDict); + PyList_SET_ITEM(__pyx_t_1, 0, __pyx_n_s_OrderedDict); + __pyx_t_3 = __Pyx_Import(__pyx_n_s_collections, __pyx_t_1, -1); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 10, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_ImportFrom(__pyx_t_3, __pyx_n_s_OrderedDict); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 10, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(__pyx_t_1); + __Pyx_XGOTREF(__Pyx_OrderedDict); + __Pyx_DECREF_SET(__Pyx_OrderedDict, __pyx_t_1); + __Pyx_GIVEREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "EnumBase":9 + * + * cdef object __Pyx_OrderedDict + * if PY_VERSION_HEX >= 0x02070000: # <<<<<<<<<<<<<< + * from collections import OrderedDict as __Pyx_OrderedDict + * else: + */ + goto __pyx_L2; + } + + /* "EnumBase":12 + * from collections import OrderedDict as __Pyx_OrderedDict + * else: + * __Pyx_OrderedDict = dict # <<<<<<<<<<<<<< + * + * @cython.internal + */ + /*else*/ { + __Pyx_INCREF(((PyObject *)(&PyDict_Type))); + __Pyx_XGOTREF(__Pyx_OrderedDict); + __Pyx_DECREF_SET(__Pyx_OrderedDict, ((PyObject *)(&PyDict_Type))); + __Pyx_GIVEREF(((PyObject *)(&PyDict_Type))); + } + __pyx_L2:; + + /* "EnumBase":26 + * + * cdef object __Pyx_EnumBase + * class __Pyx_EnumBase(int): # <<<<<<<<<<<<<< + * __metaclass__ = __Pyx_EnumMeta + * def __new__(cls, value, name=None): + */ + __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 26, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_INCREF(((PyObject *)(&PyInt_Type))); + __Pyx_GIVEREF(((PyObject *)(&PyInt_Type))); + PyTuple_SET_ITEM(__pyx_t_3, 0, ((PyObject *)(&PyInt_Type))); + __pyx_t_1 = __Pyx_CalculateMetaclass(NULL, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 26, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_4 = __Pyx_Py3MetaclassPrepare(__pyx_t_1, __pyx_t_3, __pyx_n_s_Pyx_EnumBase, __pyx_n_s_Pyx_EnumBase, (PyObject *) NULL, __pyx_n_s_EnumBase, (PyObject *) NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 26, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + + /* "EnumBase":27 + * cdef object __Pyx_EnumBase + * class __Pyx_EnumBase(int): + * __metaclass__ = __Pyx_EnumMeta # <<<<<<<<<<<<<< + * def __new__(cls, value, name=None): + * for v in cls: + */ + if (__Pyx_SetNameInClass(__pyx_t_4, __pyx_n_s_metaclass, ((PyObject *)__pyx_ptype___Pyx_EnumMeta)) < 0) __PYX_ERR(1, 27, __pyx_L1_error) + + /* "EnumBase":28 + * class __Pyx_EnumBase(int): + * __metaclass__ = __Pyx_EnumMeta + * def __new__(cls, value, name=None): # <<<<<<<<<<<<<< + * for v in cls: + * if v == value: + */ + __pyx_t_5 = __Pyx_CyFunction_New(&__pyx_mdef_8EnumBase_14__Pyx_EnumBase_1__new__, __Pyx_CYFUNCTION_STATICMETHOD, __pyx_n_s_Pyx_EnumBase___new, NULL, __pyx_n_s_EnumBase, __pyx_d, ((PyObject *)__pyx_codeobj__16)); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 28, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_5, __pyx_tuple__17); + if (__Pyx_SetNameInClass(__pyx_t_4, __pyx_n_s_new, __pyx_t_5) < 0) __PYX_ERR(1, 28, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + + /* "EnumBase":39 + * cls.__members__[name] = res + * return res + * def __repr__(self): # <<<<<<<<<<<<<< + * return "<%s.%s: %d>" % (self.__class__.__name__, self.name, self) + * def __str__(self): + */ + __pyx_t_5 = __Pyx_CyFunction_New(&__pyx_mdef_8EnumBase_14__Pyx_EnumBase_3__repr__, 0, __pyx_n_s_Pyx_EnumBase___repr, NULL, __pyx_n_s_EnumBase, __pyx_d, ((PyObject *)__pyx_codeobj__19)); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 39, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (__Pyx_SetNameInClass(__pyx_t_4, __pyx_n_s_repr, __pyx_t_5) < 0) __PYX_ERR(1, 39, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + + /* "EnumBase":41 + * def __repr__(self): + * return "<%s.%s: %d>" % (self.__class__.__name__, self.name, self) + * def __str__(self): # <<<<<<<<<<<<<< + * return "%s.%s" % (self.__class__.__name__, self.name) + * + */ + __pyx_t_5 = __Pyx_CyFunction_New(&__pyx_mdef_8EnumBase_14__Pyx_EnumBase_5__str__, 0, __pyx_n_s_Pyx_EnumBase___str, NULL, __pyx_n_s_EnumBase, __pyx_d, ((PyObject *)__pyx_codeobj__21)); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 41, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (__Pyx_SetNameInClass(__pyx_t_4, __pyx_n_s_str, __pyx_t_5) < 0) __PYX_ERR(1, 41, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + + /* "EnumBase":26 + * + * cdef object __Pyx_EnumBase + * class __Pyx_EnumBase(int): # <<<<<<<<<<<<<< + * __metaclass__ = __Pyx_EnumMeta + * def __new__(cls, value, name=None): + */ + __pyx_t_5 = __Pyx_Py3ClassCreate(__pyx_t_1, __pyx_n_s_Pyx_EnumBase, __pyx_t_3, __pyx_t_4, NULL, 0, 1); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 26, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_XGOTREF(__Pyx_EnumBase); + __Pyx_DECREF_SET(__Pyx_EnumBase, __pyx_t_5); + __Pyx_GIVEREF(__pyx_t_5); + __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "EnumBase":44 + * return "%s.%s" % (self.__class__.__name__, self.name) + * + * if PY_VERSION_HEX >= 0x03040000: # <<<<<<<<<<<<<< + * from enum import IntEnum as __Pyx_EnumBase + * + */ + __pyx_t_2 = ((PY_VERSION_HEX >= 0x03040000) != 0); + if (__pyx_t_2) { + + /* "EnumBase":45 + * + * if PY_VERSION_HEX >= 0x03040000: + * from enum import IntEnum as __Pyx_EnumBase # <<<<<<<<<<<<<< + * + */ + __pyx_t_3 = PyList_New(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 45, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_INCREF(__pyx_n_s_IntEnum); + __Pyx_GIVEREF(__pyx_n_s_IntEnum); + PyList_SET_ITEM(__pyx_t_3, 0, __pyx_n_s_IntEnum); + __pyx_t_1 = __Pyx_Import(__pyx_n_s_enum, __pyx_t_3, -1); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 45, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = __Pyx_ImportFrom(__pyx_t_1, __pyx_n_s_IntEnum); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 45, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_INCREF(__pyx_t_3); + __Pyx_XGOTREF(__Pyx_EnumBase); + __Pyx_DECREF_SET(__Pyx_EnumBase, __pyx_t_3); + __Pyx_GIVEREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "EnumBase":44 + * return "%s.%s" % (self.__class__.__name__, self.name) + * + * if PY_VERSION_HEX >= 0x03040000: # <<<<<<<<<<<<<< + * from enum import IntEnum as __Pyx_EnumBase + * + */ + } + + /* "(tree fragment)":1 + * def __pyx_unpickle___Pyx_EnumMeta(__pyx_type, long __pyx_checksum, __pyx_state): # <<<<<<<<<<<<<< + * cdef object __pyx_PickleError + * cdef object __pyx_result + */ + __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_8EnumBase_1__pyx_unpickle___Pyx_EnumMeta, NULL, __pyx_n_s_EnumBase); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_pyx_unpickle___Pyx_EnumMeta, __pyx_t_1) < 0) __PYX_ERR(1, 1, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "EnumType":50 + * + * + * cdef dict __Pyx_globals = globals() # <<<<<<<<<<<<<< + * if PY_VERSION_HEX >= 0x03040000: + * + */ + __pyx_t_1 = __Pyx_Globals(); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 50, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (!(likely(PyDict_CheckExact(__pyx_t_1))||((__pyx_t_1) == Py_None)||((void)PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "dict", Py_TYPE(__pyx_t_1)->tp_name), 0))) __PYX_ERR(1, 50, __pyx_L1_error) + __Pyx_XGOTREF(__Pyx_globals); + __Pyx_DECREF_SET(__Pyx_globals, ((PyObject*)__pyx_t_1)); + __Pyx_GIVEREF(__pyx_t_1); + __pyx_t_1 = 0; + + /* "EnumType":51 + * + * cdef dict __Pyx_globals = globals() + * if PY_VERSION_HEX >= 0x03040000: # <<<<<<<<<<<<<< + * + * RegionType = __Pyx_EnumBase('RegionType', __Pyx_OrderedDict([ + */ + __pyx_t_2 = ((PY_VERSION_HEX >= 0x03040000) != 0); + if (__pyx_t_2) { + + /* "EnumType":54 + * + * RegionType = __Pyx_EnumBase('RegionType', __Pyx_OrderedDict([ + * ('EMTPY', EMTPY), # <<<<<<<<<<<<<< + * ('SPECIAL', SPECIAL), + * ('RECTANGEL', RECTANGEL), + */ + __pyx_t_1 = __Pyx_PyInt_From_enum____pyx_t_6region_RegionType(__pyx_e_6region_EMTPY); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 54, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 54, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_INCREF(__pyx_n_s_EMTPY); + __Pyx_GIVEREF(__pyx_n_s_EMTPY); + PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_n_s_EMTPY); + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_t_1); + __pyx_t_1 = 0; + + /* "EnumType":55 + * RegionType = __Pyx_EnumBase('RegionType', __Pyx_OrderedDict([ + * ('EMTPY', EMTPY), + * ('SPECIAL', SPECIAL), # <<<<<<<<<<<<<< + * ('RECTANGEL', RECTANGEL), + * ('POLYGON', POLYGON), + */ + __pyx_t_1 = __Pyx_PyInt_From_enum____pyx_t_6region_RegionType(__pyx_e_6region_SPECIAL); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 55, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_4 = PyTuple_New(2); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 55, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_INCREF(__pyx_n_s_SPECIAL); + __Pyx_GIVEREF(__pyx_n_s_SPECIAL); + PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_n_s_SPECIAL); + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_4, 1, __pyx_t_1); + __pyx_t_1 = 0; + + /* "EnumType":56 + * ('EMTPY', EMTPY), + * ('SPECIAL', SPECIAL), + * ('RECTANGEL', RECTANGEL), # <<<<<<<<<<<<<< + * ('POLYGON', POLYGON), + * ('MASK', MASK), + */ + __pyx_t_1 = __Pyx_PyInt_From_enum____pyx_t_6region_RegionType(__pyx_e_6region_RECTANGEL); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 56, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_5 = PyTuple_New(2); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 56, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_INCREF(__pyx_n_s_RECTANGEL); + __Pyx_GIVEREF(__pyx_n_s_RECTANGEL); + PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_n_s_RECTANGEL); + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_t_1); + __pyx_t_1 = 0; + + /* "EnumType":57 + * ('SPECIAL', SPECIAL), + * ('RECTANGEL', RECTANGEL), + * ('POLYGON', POLYGON), # <<<<<<<<<<<<<< + * ('MASK', MASK), + * ])) + */ + __pyx_t_1 = __Pyx_PyInt_From_enum____pyx_t_6region_RegionType(__pyx_e_6region_POLYGON); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 57, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_6 = PyTuple_New(2); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 57, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_INCREF(__pyx_n_s_POLYGON); + __Pyx_GIVEREF(__pyx_n_s_POLYGON); + PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_n_s_POLYGON); + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_6, 1, __pyx_t_1); + __pyx_t_1 = 0; + + /* "EnumType":58 + * ('RECTANGEL', RECTANGEL), + * ('POLYGON', POLYGON), + * ('MASK', MASK), # <<<<<<<<<<<<<< + * ])) + * __Pyx_globals['EMTPY'] = RegionType.EMTPY + */ + __pyx_t_1 = __Pyx_PyInt_From_enum____pyx_t_6region_RegionType(__pyx_e_6region_MASK); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 58, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_7 = PyTuple_New(2); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 58, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_INCREF(__pyx_n_s_MASK); + __Pyx_GIVEREF(__pyx_n_s_MASK); + PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_n_s_MASK); + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_7, 1, __pyx_t_1); + __pyx_t_1 = 0; + + /* "EnumType":53 + * if PY_VERSION_HEX >= 0x03040000: + * + * RegionType = __Pyx_EnumBase('RegionType', __Pyx_OrderedDict([ # <<<<<<<<<<<<<< + * ('EMTPY', EMTPY), + * ('SPECIAL', SPECIAL), + */ + __pyx_t_1 = PyList_New(5); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 53, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_GIVEREF(__pyx_t_3); + PyList_SET_ITEM(__pyx_t_1, 0, __pyx_t_3); + __Pyx_GIVEREF(__pyx_t_4); + PyList_SET_ITEM(__pyx_t_1, 1, __pyx_t_4); + __Pyx_GIVEREF(__pyx_t_5); + PyList_SET_ITEM(__pyx_t_1, 2, __pyx_t_5); + __Pyx_GIVEREF(__pyx_t_6); + PyList_SET_ITEM(__pyx_t_1, 3, __pyx_t_6); + __Pyx_GIVEREF(__pyx_t_7); + PyList_SET_ITEM(__pyx_t_1, 4, __pyx_t_7); + __pyx_t_3 = 0; + __pyx_t_4 = 0; + __pyx_t_5 = 0; + __pyx_t_6 = 0; + __pyx_t_7 = 0; + __pyx_t_7 = __Pyx_PyObject_CallOneArg(__Pyx_OrderedDict, __pyx_t_1); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 53, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = PyTuple_New(2); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 53, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(__pyx_n_s_RegionType); + __Pyx_GIVEREF(__pyx_n_s_RegionType); + PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_n_s_RegionType); + __Pyx_GIVEREF(__pyx_t_7); + PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_t_7); + __pyx_t_7 = 0; + __pyx_t_7 = __Pyx_PyObject_Call(__Pyx_EnumBase, __pyx_t_1, NULL); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 53, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_RegionType, __pyx_t_7) < 0) __PYX_ERR(1, 53, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "EnumType":60 + * ('MASK', MASK), + * ])) + * __Pyx_globals['EMTPY'] = RegionType.EMTPY # <<<<<<<<<<<<<< + * __Pyx_globals['SPECIAL'] = RegionType.SPECIAL + * __Pyx_globals['RECTANGEL'] = RegionType.RECTANGEL + */ + __Pyx_GetModuleGlobalName(__pyx_t_7, __pyx_n_s_RegionType); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 60, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_EMTPY); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 60, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (unlikely(__Pyx_globals == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(1, 60, __pyx_L1_error) + } + if (unlikely(PyDict_SetItem(__Pyx_globals, __pyx_n_s_EMTPY, __pyx_t_1) < 0)) __PYX_ERR(1, 60, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "EnumType":61 + * ])) + * __Pyx_globals['EMTPY'] = RegionType.EMTPY + * __Pyx_globals['SPECIAL'] = RegionType.SPECIAL # <<<<<<<<<<<<<< + * __Pyx_globals['RECTANGEL'] = RegionType.RECTANGEL + * __Pyx_globals['POLYGON'] = RegionType.POLYGON + */ + __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_RegionType); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 61, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_SPECIAL); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 61, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(__Pyx_globals == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(1, 61, __pyx_L1_error) + } + if (unlikely(PyDict_SetItem(__Pyx_globals, __pyx_n_s_SPECIAL, __pyx_t_7) < 0)) __PYX_ERR(1, 61, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "EnumType":62 + * __Pyx_globals['EMTPY'] = RegionType.EMTPY + * __Pyx_globals['SPECIAL'] = RegionType.SPECIAL + * __Pyx_globals['RECTANGEL'] = RegionType.RECTANGEL # <<<<<<<<<<<<<< + * __Pyx_globals['POLYGON'] = RegionType.POLYGON + * __Pyx_globals['MASK'] = RegionType.MASK + */ + __Pyx_GetModuleGlobalName(__pyx_t_7, __pyx_n_s_RegionType); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 62, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_RECTANGEL); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 62, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (unlikely(__Pyx_globals == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(1, 62, __pyx_L1_error) + } + if (unlikely(PyDict_SetItem(__Pyx_globals, __pyx_n_s_RECTANGEL, __pyx_t_1) < 0)) __PYX_ERR(1, 62, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "EnumType":63 + * __Pyx_globals['SPECIAL'] = RegionType.SPECIAL + * __Pyx_globals['RECTANGEL'] = RegionType.RECTANGEL + * __Pyx_globals['POLYGON'] = RegionType.POLYGON # <<<<<<<<<<<<<< + * __Pyx_globals['MASK'] = RegionType.MASK + * else: + */ + __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_RegionType); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 63, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_POLYGON); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 63, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(__Pyx_globals == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(1, 63, __pyx_L1_error) + } + if (unlikely(PyDict_SetItem(__Pyx_globals, __pyx_n_s_POLYGON, __pyx_t_7) < 0)) __PYX_ERR(1, 63, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "EnumType":64 + * __Pyx_globals['RECTANGEL'] = RegionType.RECTANGEL + * __Pyx_globals['POLYGON'] = RegionType.POLYGON + * __Pyx_globals['MASK'] = RegionType.MASK # <<<<<<<<<<<<<< + * else: + * class RegionType(__Pyx_EnumBase): + */ + __Pyx_GetModuleGlobalName(__pyx_t_7, __pyx_n_s_RegionType); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 64, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_MASK); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 64, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (unlikely(__Pyx_globals == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(1, 64, __pyx_L1_error) + } + if (unlikely(PyDict_SetItem(__Pyx_globals, __pyx_n_s_MASK, __pyx_t_1) < 0)) __PYX_ERR(1, 64, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "EnumType":51 + * + * cdef dict __Pyx_globals = globals() + * if PY_VERSION_HEX >= 0x03040000: # <<<<<<<<<<<<<< + * + * RegionType = __Pyx_EnumBase('RegionType', __Pyx_OrderedDict([ + */ + goto __pyx_L4; + } + + /* "EnumType":66 + * __Pyx_globals['MASK'] = RegionType.MASK + * else: + * class RegionType(__Pyx_EnumBase): # <<<<<<<<<<<<<< + * pass + * __Pyx_globals['EMTPY'] = RegionType(EMTPY, 'EMTPY') + */ + /*else*/ { + __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 66, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(__Pyx_EnumBase); + __Pyx_GIVEREF(__Pyx_EnumBase); + PyTuple_SET_ITEM(__pyx_t_1, 0, __Pyx_EnumBase); + __pyx_t_7 = __Pyx_CalculateMetaclass(NULL, __pyx_t_1); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 66, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_6 = __Pyx_Py3MetaclassPrepare(__pyx_t_7, __pyx_t_1, __pyx_n_s_RegionType, __pyx_n_s_RegionType, (PyObject *) NULL, __pyx_n_s_EnumType, (PyObject *) NULL); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 66, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_5 = __Pyx_Py3ClassCreate(__pyx_t_7, __pyx_n_s_RegionType, __pyx_t_1, __pyx_t_6, NULL, 0, 1); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 66, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_RegionType, __pyx_t_5) < 0) __PYX_ERR(1, 66, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "EnumType":68 + * class RegionType(__Pyx_EnumBase): + * pass + * __Pyx_globals['EMTPY'] = RegionType(EMTPY, 'EMTPY') # <<<<<<<<<<<<<< + * __Pyx_globals['SPECIAL'] = RegionType(SPECIAL, 'SPECIAL') + * __Pyx_globals['RECTANGEL'] = RegionType(RECTANGEL, 'RECTANGEL') + */ + __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_RegionType); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 68, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_7 = __Pyx_PyInt_From_enum____pyx_t_6region_RegionType(__pyx_e_6region_EMTPY); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 68, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_6 = PyTuple_New(2); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 68, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_GIVEREF(__pyx_t_7); + PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_7); + __Pyx_INCREF(__pyx_n_s_EMTPY); + __Pyx_GIVEREF(__pyx_n_s_EMTPY); + PyTuple_SET_ITEM(__pyx_t_6, 1, __pyx_n_s_EMTPY); + __pyx_t_7 = 0; + __pyx_t_7 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_6, NULL); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 68, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + if (unlikely(__Pyx_globals == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(1, 68, __pyx_L1_error) + } + if (unlikely(PyDict_SetItem(__Pyx_globals, __pyx_n_s_EMTPY, __pyx_t_7) < 0)) __PYX_ERR(1, 68, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "EnumType":69 + * pass + * __Pyx_globals['EMTPY'] = RegionType(EMTPY, 'EMTPY') + * __Pyx_globals['SPECIAL'] = RegionType(SPECIAL, 'SPECIAL') # <<<<<<<<<<<<<< + * __Pyx_globals['RECTANGEL'] = RegionType(RECTANGEL, 'RECTANGEL') + * __Pyx_globals['POLYGON'] = RegionType(POLYGON, 'POLYGON') + */ + __Pyx_GetModuleGlobalName(__pyx_t_7, __pyx_n_s_RegionType); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 69, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_6 = __Pyx_PyInt_From_enum____pyx_t_6region_RegionType(__pyx_e_6region_SPECIAL); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 69, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_1 = PyTuple_New(2); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 69, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_GIVEREF(__pyx_t_6); + PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_t_6); + __Pyx_INCREF(__pyx_n_s_SPECIAL); + __Pyx_GIVEREF(__pyx_n_s_SPECIAL); + PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_n_s_SPECIAL); + __pyx_t_6 = 0; + __pyx_t_6 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_1, NULL); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 69, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(__Pyx_globals == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(1, 69, __pyx_L1_error) + } + if (unlikely(PyDict_SetItem(__Pyx_globals, __pyx_n_s_SPECIAL, __pyx_t_6) < 0)) __PYX_ERR(1, 69, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + + /* "EnumType":70 + * __Pyx_globals['EMTPY'] = RegionType(EMTPY, 'EMTPY') + * __Pyx_globals['SPECIAL'] = RegionType(SPECIAL, 'SPECIAL') + * __Pyx_globals['RECTANGEL'] = RegionType(RECTANGEL, 'RECTANGEL') # <<<<<<<<<<<<<< + * __Pyx_globals['POLYGON'] = RegionType(POLYGON, 'POLYGON') + * __Pyx_globals['MASK'] = RegionType(MASK, 'MASK') + */ + __Pyx_GetModuleGlobalName(__pyx_t_6, __pyx_n_s_RegionType); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 70, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_1 = __Pyx_PyInt_From_enum____pyx_t_6region_RegionType(__pyx_e_6region_RECTANGEL); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 70, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_7 = PyTuple_New(2); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 70, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_1); + __Pyx_INCREF(__pyx_n_s_RECTANGEL); + __Pyx_GIVEREF(__pyx_n_s_RECTANGEL); + PyTuple_SET_ITEM(__pyx_t_7, 1, __pyx_n_s_RECTANGEL); + __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_7, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 70, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (unlikely(__Pyx_globals == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(1, 70, __pyx_L1_error) + } + if (unlikely(PyDict_SetItem(__Pyx_globals, __pyx_n_s_RECTANGEL, __pyx_t_1) < 0)) __PYX_ERR(1, 70, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "EnumType":71 + * __Pyx_globals['SPECIAL'] = RegionType(SPECIAL, 'SPECIAL') + * __Pyx_globals['RECTANGEL'] = RegionType(RECTANGEL, 'RECTANGEL') + * __Pyx_globals['POLYGON'] = RegionType(POLYGON, 'POLYGON') # <<<<<<<<<<<<<< + * __Pyx_globals['MASK'] = RegionType(MASK, 'MASK') + * + */ + __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_RegionType); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 71, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_7 = __Pyx_PyInt_From_enum____pyx_t_6region_RegionType(__pyx_e_6region_POLYGON); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 71, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_6 = PyTuple_New(2); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 71, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_GIVEREF(__pyx_t_7); + PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_7); + __Pyx_INCREF(__pyx_n_s_POLYGON); + __Pyx_GIVEREF(__pyx_n_s_POLYGON); + PyTuple_SET_ITEM(__pyx_t_6, 1, __pyx_n_s_POLYGON); + __pyx_t_7 = 0; + __pyx_t_7 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_6, NULL); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 71, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + if (unlikely(__Pyx_globals == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(1, 71, __pyx_L1_error) + } + if (unlikely(PyDict_SetItem(__Pyx_globals, __pyx_n_s_POLYGON, __pyx_t_7) < 0)) __PYX_ERR(1, 71, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "EnumType":72 + * __Pyx_globals['RECTANGEL'] = RegionType(RECTANGEL, 'RECTANGEL') + * __Pyx_globals['POLYGON'] = RegionType(POLYGON, 'POLYGON') + * __Pyx_globals['MASK'] = RegionType(MASK, 'MASK') # <<<<<<<<<<<<<< + * + */ + __Pyx_GetModuleGlobalName(__pyx_t_7, __pyx_n_s_RegionType); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 72, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_6 = __Pyx_PyInt_From_enum____pyx_t_6region_RegionType(__pyx_e_6region_MASK); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 72, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_1 = PyTuple_New(2); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 72, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_GIVEREF(__pyx_t_6); + PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_t_6); + __Pyx_INCREF(__pyx_n_s_MASK); + __Pyx_GIVEREF(__pyx_n_s_MASK); + PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_n_s_MASK); + __pyx_t_6 = 0; + __pyx_t_6 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_1, NULL); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 72, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(__Pyx_globals == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(1, 72, __pyx_L1_error) + } + if (unlikely(PyDict_SetItem(__Pyx_globals, __pyx_n_s_MASK, __pyx_t_6) < 0)) __PYX_ERR(1, 72, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } + __pyx_L4:; + + /*--- Wrapped vars code ---*/ + + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + if (__pyx_m) { + if (__pyx_d) { + __Pyx_AddTraceback("init region", __pyx_clineno, __pyx_lineno, __pyx_filename); + } + Py_CLEAR(__pyx_m); + } else if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ImportError, "init region"); + } + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + #if CYTHON_PEP489_MULTI_PHASE_INIT + return (__pyx_m != NULL) ? 0 : -1; + #elif PY_MAJOR_VERSION >= 3 + return __pyx_m; + #else + return; + #endif +} + +/* --- Runtime support code --- */ +/* Refnanny */ +#if CYTHON_REFNANNY +static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname) { + PyObject *m = NULL, *p = NULL; + void *r = NULL; + m = PyImport_ImportModule(modname); + if (!m) goto end; + p = PyObject_GetAttrString(m, "RefNannyAPI"); + if (!p) goto end; + r = PyLong_AsVoidPtr(p); +end: + Py_XDECREF(p); + Py_XDECREF(m); + return (__Pyx_RefNannyAPIStruct *)r; +} +#endif + +/* PyObjectGetAttrStr */ +#if CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name) { + PyTypeObject* tp = Py_TYPE(obj); + if (likely(tp->tp_getattro)) + return tp->tp_getattro(obj, attr_name); +#if PY_MAJOR_VERSION < 3 + if (likely(tp->tp_getattr)) + return tp->tp_getattr(obj, PyString_AS_STRING(attr_name)); +#endif + return PyObject_GetAttr(obj, attr_name); +} +#endif + +/* GetBuiltinName */ +static PyObject *__Pyx_GetBuiltinName(PyObject *name) { + PyObject* result = __Pyx_PyObject_GetAttrStr(__pyx_b, name); + if (unlikely(!result)) { + PyErr_Format(PyExc_NameError, +#if PY_MAJOR_VERSION >= 3 + "name '%U' is not defined", name); +#else + "name '%.200s' is not defined", PyString_AS_STRING(name)); +#endif + } + return result; +} + +/* RaiseArgTupleInvalid */ +static void __Pyx_RaiseArgtupleInvalid( + const char* func_name, + int exact, + Py_ssize_t num_min, + Py_ssize_t num_max, + Py_ssize_t num_found) +{ + Py_ssize_t num_expected; + const char *more_or_less; + if (num_found < num_min) { + num_expected = num_min; + more_or_less = "at least"; + } else { + num_expected = num_max; + more_or_less = "at most"; + } + if (exact) { + more_or_less = "exactly"; + } + PyErr_Format(PyExc_TypeError, + "%.200s() takes %.8s %" CYTHON_FORMAT_SSIZE_T "d positional argument%.1s (%" CYTHON_FORMAT_SSIZE_T "d given)", + func_name, more_or_less, num_expected, + (num_expected == 1) ? "" : "s", num_found); +} + +/* KeywordStringCheck */ +static int __Pyx_CheckKeywordStrings( + PyObject *kwdict, + const char* function_name, + int kw_allowed) +{ + PyObject* key = 0; + Py_ssize_t pos = 0; +#if CYTHON_COMPILING_IN_PYPY + if (!kw_allowed && PyDict_Next(kwdict, &pos, &key, 0)) + goto invalid_keyword; + return 1; +#else + while (PyDict_Next(kwdict, &pos, &key, 0)) { + #if PY_MAJOR_VERSION < 3 + if (unlikely(!PyString_Check(key))) + #endif + if (unlikely(!PyUnicode_Check(key))) + goto invalid_keyword_type; + } + if ((!kw_allowed) && unlikely(key)) + goto invalid_keyword; + return 1; +invalid_keyword_type: + PyErr_Format(PyExc_TypeError, + "%.200s() keywords must be strings", function_name); + return 0; +#endif +invalid_keyword: + PyErr_Format(PyExc_TypeError, + #if PY_MAJOR_VERSION < 3 + "%.200s() got an unexpected keyword argument '%.200s'", + function_name, PyString_AsString(key)); + #else + "%s() got an unexpected keyword argument '%U'", + function_name, key); + #endif + return 0; +} + +/* RaiseDoubleKeywords */ +static void __Pyx_RaiseDoubleKeywordsError( + const char* func_name, + PyObject* kw_name) +{ + PyErr_Format(PyExc_TypeError, + #if PY_MAJOR_VERSION >= 3 + "%s() got multiple values for keyword argument '%U'", func_name, kw_name); + #else + "%s() got multiple values for keyword argument '%s'", func_name, + PyString_AsString(kw_name)); + #endif +} + +/* ParseKeywords */ +static int __Pyx_ParseOptionalKeywords( + PyObject *kwds, + PyObject **argnames[], + PyObject *kwds2, + PyObject *values[], + Py_ssize_t num_pos_args, + const char* function_name) +{ + PyObject *key = 0, *value = 0; + Py_ssize_t pos = 0; + PyObject*** name; + PyObject*** first_kw_arg = argnames + num_pos_args; + while (PyDict_Next(kwds, &pos, &key, &value)) { + name = first_kw_arg; + while (*name && (**name != key)) name++; + if (*name) { + values[name-argnames] = value; + continue; + } + name = first_kw_arg; + #if PY_MAJOR_VERSION < 3 + if (likely(PyString_Check(key))) { + while (*name) { + if ((CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**name) == PyString_GET_SIZE(key)) + && _PyString_Eq(**name, key)) { + values[name-argnames] = value; + break; + } + name++; + } + if (*name) continue; + else { + PyObject*** argname = argnames; + while (argname != first_kw_arg) { + if ((**argname == key) || ( + (CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**argname) == PyString_GET_SIZE(key)) + && _PyString_Eq(**argname, key))) { + goto arg_passed_twice; + } + argname++; + } + } + } else + #endif + if (likely(PyUnicode_Check(key))) { + while (*name) { + int cmp = (**name == key) ? 0 : + #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 + (__Pyx_PyUnicode_GET_LENGTH(**name) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : + #endif + PyUnicode_Compare(**name, key); + if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; + if (cmp == 0) { + values[name-argnames] = value; + break; + } + name++; + } + if (*name) continue; + else { + PyObject*** argname = argnames; + while (argname != first_kw_arg) { + int cmp = (**argname == key) ? 0 : + #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 + (__Pyx_PyUnicode_GET_LENGTH(**argname) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : + #endif + PyUnicode_Compare(**argname, key); + if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; + if (cmp == 0) goto arg_passed_twice; + argname++; + } + } + } else + goto invalid_keyword_type; + if (kwds2) { + if (unlikely(PyDict_SetItem(kwds2, key, value))) goto bad; + } else { + goto invalid_keyword; + } + } + return 0; +arg_passed_twice: + __Pyx_RaiseDoubleKeywordsError(function_name, key); + goto bad; +invalid_keyword_type: + PyErr_Format(PyExc_TypeError, + "%.200s() keywords must be strings", function_name); + goto bad; +invalid_keyword: + PyErr_Format(PyExc_TypeError, + #if PY_MAJOR_VERSION < 3 + "%.200s() got an unexpected keyword argument '%.200s'", + function_name, PyString_AsString(key)); + #else + "%s() got an unexpected keyword argument '%U'", + function_name, key); + #endif +bad: + return -1; +} + +/* PyFunctionFastCall */ +#if CYTHON_FAST_PYCALL +static PyObject* __Pyx_PyFunction_FastCallNoKw(PyCodeObject *co, PyObject **args, Py_ssize_t na, + PyObject *globals) { + PyFrameObject *f; + PyThreadState *tstate = __Pyx_PyThreadState_Current; + PyObject **fastlocals; + Py_ssize_t i; + PyObject *result; + assert(globals != NULL); + /* XXX Perhaps we should create a specialized + PyFrame_New() that doesn't take locals, but does + take builtins without sanity checking them. + */ + assert(tstate != NULL); + f = PyFrame_New(tstate, co, globals, NULL); + if (f == NULL) { + return NULL; + } + fastlocals = __Pyx_PyFrame_GetLocalsplus(f); + for (i = 0; i < na; i++) { + Py_INCREF(*args); + fastlocals[i] = *args++; + } + result = PyEval_EvalFrameEx(f,0); + ++tstate->recursion_depth; + Py_DECREF(f); + --tstate->recursion_depth; + return result; +} +#if 1 || PY_VERSION_HEX < 0x030600B1 +static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, PyObject *kwargs) { + PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); + PyObject *globals = PyFunction_GET_GLOBALS(func); + PyObject *argdefs = PyFunction_GET_DEFAULTS(func); + PyObject *closure; +#if PY_MAJOR_VERSION >= 3 + PyObject *kwdefs; +#endif + PyObject *kwtuple, **k; + PyObject **d; + Py_ssize_t nd; + Py_ssize_t nk; + PyObject *result; + assert(kwargs == NULL || PyDict_Check(kwargs)); + nk = kwargs ? PyDict_Size(kwargs) : 0; + if (Py_EnterRecursiveCall((char*)" while calling a Python object")) { + return NULL; + } + if ( +#if PY_MAJOR_VERSION >= 3 + co->co_kwonlyargcount == 0 && +#endif + likely(kwargs == NULL || nk == 0) && + co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) { + if (argdefs == NULL && co->co_argcount == nargs) { + result = __Pyx_PyFunction_FastCallNoKw(co, args, nargs, globals); + goto done; + } + else if (nargs == 0 && argdefs != NULL + && co->co_argcount == Py_SIZE(argdefs)) { + /* function called with no arguments, but all parameters have + a default value: use default values as arguments .*/ + args = &PyTuple_GET_ITEM(argdefs, 0); + result =__Pyx_PyFunction_FastCallNoKw(co, args, Py_SIZE(argdefs), globals); + goto done; + } + } + if (kwargs != NULL) { + Py_ssize_t pos, i; + kwtuple = PyTuple_New(2 * nk); + if (kwtuple == NULL) { + result = NULL; + goto done; + } + k = &PyTuple_GET_ITEM(kwtuple, 0); + pos = i = 0; + while (PyDict_Next(kwargs, &pos, &k[i], &k[i+1])) { + Py_INCREF(k[i]); + Py_INCREF(k[i+1]); + i += 2; + } + nk = i / 2; + } + else { + kwtuple = NULL; + k = NULL; + } + closure = PyFunction_GET_CLOSURE(func); +#if PY_MAJOR_VERSION >= 3 + kwdefs = PyFunction_GET_KW_DEFAULTS(func); +#endif + if (argdefs != NULL) { + d = &PyTuple_GET_ITEM(argdefs, 0); + nd = Py_SIZE(argdefs); + } + else { + d = NULL; + nd = 0; + } +#if PY_MAJOR_VERSION >= 3 + result = PyEval_EvalCodeEx((PyObject*)co, globals, (PyObject *)NULL, + args, (int)nargs, + k, (int)nk, + d, (int)nd, kwdefs, closure); +#else + result = PyEval_EvalCodeEx(co, globals, (PyObject *)NULL, + args, (int)nargs, + k, (int)nk, + d, (int)nd, closure); +#endif + Py_XDECREF(kwtuple); +done: + Py_LeaveRecursiveCall(); + return result; +} +#endif +#endif + +/* PyCFunctionFastCall */ +#if CYTHON_FAST_PYCCALL +static CYTHON_INLINE PyObject * __Pyx_PyCFunction_FastCall(PyObject *func_obj, PyObject **args, Py_ssize_t nargs) { + PyCFunctionObject *func = (PyCFunctionObject*)func_obj; + PyCFunction meth = PyCFunction_GET_FUNCTION(func); + PyObject *self = PyCFunction_GET_SELF(func); + int flags = PyCFunction_GET_FLAGS(func); + assert(PyCFunction_Check(func)); + assert(METH_FASTCALL == (flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST | METH_KEYWORDS | METH_STACKLESS))); + assert(nargs >= 0); + assert(nargs == 0 || args != NULL); + /* _PyCFunction_FastCallDict() must not be called with an exception set, + because it may clear it (directly or indirectly) and so the + caller loses its exception */ + assert(!PyErr_Occurred()); + if ((PY_VERSION_HEX < 0x030700A0) || unlikely(flags & METH_KEYWORDS)) { + return (*((__Pyx_PyCFunctionFastWithKeywords)(void*)meth)) (self, args, nargs, NULL); + } else { + return (*((__Pyx_PyCFunctionFast)(void*)meth)) (self, args, nargs); + } +} +#endif + +/* PyObjectCall */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { + PyObject *result; + ternaryfunc call = Py_TYPE(func)->tp_call; + if (unlikely(!call)) + return PyObject_Call(func, arg, kw); + if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) + return NULL; + result = (*call)(func, arg, kw); + Py_LeaveRecursiveCall(); + if (unlikely(!result) && unlikely(!PyErr_Occurred())) { + PyErr_SetString( + PyExc_SystemError, + "NULL result without error in PyObject_Call"); + } + return result; +} +#endif + +/* PyErrFetchRestore */ +#if CYTHON_FAST_THREAD_STATE +static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) { + PyObject *tmp_type, *tmp_value, *tmp_tb; + tmp_type = tstate->curexc_type; + tmp_value = tstate->curexc_value; + tmp_tb = tstate->curexc_traceback; + tstate->curexc_type = type; + tstate->curexc_value = value; + tstate->curexc_traceback = tb; + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); +} +static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { + *type = tstate->curexc_type; + *value = tstate->curexc_value; + *tb = tstate->curexc_traceback; + tstate->curexc_type = 0; + tstate->curexc_value = 0; + tstate->curexc_traceback = 0; +} +#endif + +/* RaiseException */ +#if PY_MAJOR_VERSION < 3 +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, + CYTHON_UNUSED PyObject *cause) { + __Pyx_PyThreadState_declare + Py_XINCREF(type); + if (!value || value == Py_None) + value = NULL; + else + Py_INCREF(value); + if (!tb || tb == Py_None) + tb = NULL; + else { + Py_INCREF(tb); + if (!PyTraceBack_Check(tb)) { + PyErr_SetString(PyExc_TypeError, + "raise: arg 3 must be a traceback or None"); + goto raise_error; + } + } + if (PyType_Check(type)) { +#if CYTHON_COMPILING_IN_PYPY + if (!value) { + Py_INCREF(Py_None); + value = Py_None; + } +#endif + PyErr_NormalizeException(&type, &value, &tb); + } else { + if (value) { + PyErr_SetString(PyExc_TypeError, + "instance exception may not have a separate value"); + goto raise_error; + } + value = type; + type = (PyObject*) Py_TYPE(type); + Py_INCREF(type); + if (!PyType_IsSubtype((PyTypeObject *)type, (PyTypeObject *)PyExc_BaseException)) { + PyErr_SetString(PyExc_TypeError, + "raise: exception class must be a subclass of BaseException"); + goto raise_error; + } + } + __Pyx_PyThreadState_assign + __Pyx_ErrRestore(type, value, tb); + return; +raise_error: + Py_XDECREF(value); + Py_XDECREF(type); + Py_XDECREF(tb); + return; +} +#else +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause) { + PyObject* owned_instance = NULL; + if (tb == Py_None) { + tb = 0; + } else if (tb && !PyTraceBack_Check(tb)) { + PyErr_SetString(PyExc_TypeError, + "raise: arg 3 must be a traceback or None"); + goto bad; + } + if (value == Py_None) + value = 0; + if (PyExceptionInstance_Check(type)) { + if (value) { + PyErr_SetString(PyExc_TypeError, + "instance exception may not have a separate value"); + goto bad; + } + value = type; + type = (PyObject*) Py_TYPE(value); + } else if (PyExceptionClass_Check(type)) { + PyObject *instance_class = NULL; + if (value && PyExceptionInstance_Check(value)) { + instance_class = (PyObject*) Py_TYPE(value); + if (instance_class != type) { + int is_subclass = PyObject_IsSubclass(instance_class, type); + if (!is_subclass) { + instance_class = NULL; + } else if (unlikely(is_subclass == -1)) { + goto bad; + } else { + type = instance_class; + } + } + } + if (!instance_class) { + PyObject *args; + if (!value) + args = PyTuple_New(0); + else if (PyTuple_Check(value)) { + Py_INCREF(value); + args = value; + } else + args = PyTuple_Pack(1, value); + if (!args) + goto bad; + owned_instance = PyObject_Call(type, args, NULL); + Py_DECREF(args); + if (!owned_instance) + goto bad; + value = owned_instance; + if (!PyExceptionInstance_Check(value)) { + PyErr_Format(PyExc_TypeError, + "calling %R should have returned an instance of " + "BaseException, not %R", + type, Py_TYPE(value)); + goto bad; + } + } + } else { + PyErr_SetString(PyExc_TypeError, + "raise: exception class must be a subclass of BaseException"); + goto bad; + } + if (cause) { + PyObject *fixed_cause; + if (cause == Py_None) { + fixed_cause = NULL; + } else if (PyExceptionClass_Check(cause)) { + fixed_cause = PyObject_CallObject(cause, NULL); + if (fixed_cause == NULL) + goto bad; + } else if (PyExceptionInstance_Check(cause)) { + fixed_cause = cause; + Py_INCREF(fixed_cause); + } else { + PyErr_SetString(PyExc_TypeError, + "exception causes must derive from " + "BaseException"); + goto bad; + } + PyException_SetCause(value, fixed_cause); + } + PyErr_SetObject(type, value); + if (tb) { +#if CYTHON_FAST_THREAD_STATE + PyThreadState *tstate = __Pyx_PyThreadState_Current; + PyObject* tmp_tb = tstate->curexc_traceback; + if (tb != tmp_tb) { + Py_INCREF(tb); + tstate->curexc_traceback = tb; + Py_XDECREF(tmp_tb); + } +#else + PyObject *tmp_type, *tmp_value, *tmp_tb; + PyErr_Fetch(&tmp_type, &tmp_value, &tmp_tb); + Py_INCREF(tb); + PyErr_Restore(tmp_type, tmp_value, tb); + Py_XDECREF(tmp_tb); +#endif + } +bad: + Py_XDECREF(owned_instance); + return; +} +#endif + +/* DivInt[Py_ssize_t] */ +static CYTHON_INLINE Py_ssize_t __Pyx_div_Py_ssize_t(Py_ssize_t a, Py_ssize_t b) { + Py_ssize_t q = a / b; + Py_ssize_t r = a - q*b; + q -= ((r != 0) & ((r ^ b) < 0)); + return q; +} + +/* PyObjectCallMethO */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg) { + PyObject *self, *result; + PyCFunction cfunc; + cfunc = PyCFunction_GET_FUNCTION(func); + self = PyCFunction_GET_SELF(func); + if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) + return NULL; + result = cfunc(self, arg); + Py_LeaveRecursiveCall(); + if (unlikely(!result) && unlikely(!PyErr_Occurred())) { + PyErr_SetString( + PyExc_SystemError, + "NULL result without error in PyObject_Call"); + } + return result; +} +#endif + +/* PyObjectCallOneArg */ +#if CYTHON_COMPILING_IN_CPYTHON +static PyObject* __Pyx__PyObject_CallOneArg(PyObject *func, PyObject *arg) { + PyObject *result; + PyObject *args = PyTuple_New(1); + if (unlikely(!args)) return NULL; + Py_INCREF(arg); + PyTuple_SET_ITEM(args, 0, arg); + result = __Pyx_PyObject_Call(func, args, NULL); + Py_DECREF(args); + return result; +} +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) { +#if CYTHON_FAST_PYCALL + if (PyFunction_Check(func)) { + return __Pyx_PyFunction_FastCall(func, &arg, 1); + } +#endif + if (likely(PyCFunction_Check(func))) { + if (likely(PyCFunction_GET_FLAGS(func) & METH_O)) { + return __Pyx_PyObject_CallMethO(func, arg); +#if CYTHON_FAST_PYCCALL + } else if (__Pyx_PyFastCFunction_Check(func)) { + return __Pyx_PyCFunction_FastCall(func, &arg, 1); +#endif + } + } + return __Pyx__PyObject_CallOneArg(func, arg); +} +#else +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) { + PyObject *result; + PyObject *args = PyTuple_Pack(1, arg); + if (unlikely(!args)) return NULL; + result = __Pyx_PyObject_Call(func, args, NULL); + Py_DECREF(args); + return result; +} +#endif + +/* GetItemInt */ +static PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j) { + PyObject *r; + if (!j) return NULL; + r = PyObject_GetItem(o, j); + Py_DECREF(j); + return r; +} +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i, + CYTHON_NCP_UNUSED int wraparound, + CYTHON_NCP_UNUSED int boundscheck) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + Py_ssize_t wrapped_i = i; + if (wraparound & unlikely(i < 0)) { + wrapped_i += PyList_GET_SIZE(o); + } + if ((!boundscheck) || likely(__Pyx_is_valid_index(wrapped_i, PyList_GET_SIZE(o)))) { + PyObject *r = PyList_GET_ITEM(o, wrapped_i); + Py_INCREF(r); + return r; + } + return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); +#else + return PySequence_GetItem(o, i); +#endif +} +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i, + CYTHON_NCP_UNUSED int wraparound, + CYTHON_NCP_UNUSED int boundscheck) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + Py_ssize_t wrapped_i = i; + if (wraparound & unlikely(i < 0)) { + wrapped_i += PyTuple_GET_SIZE(o); + } + if ((!boundscheck) || likely(__Pyx_is_valid_index(wrapped_i, PyTuple_GET_SIZE(o)))) { + PyObject *r = PyTuple_GET_ITEM(o, wrapped_i); + Py_INCREF(r); + return r; + } + return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); +#else + return PySequence_GetItem(o, i); +#endif +} +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, int is_list, + CYTHON_NCP_UNUSED int wraparound, + CYTHON_NCP_UNUSED int boundscheck) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS && CYTHON_USE_TYPE_SLOTS + if (is_list || PyList_CheckExact(o)) { + Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyList_GET_SIZE(o); + if ((!boundscheck) || (likely(__Pyx_is_valid_index(n, PyList_GET_SIZE(o))))) { + PyObject *r = PyList_GET_ITEM(o, n); + Py_INCREF(r); + return r; + } + } + else if (PyTuple_CheckExact(o)) { + Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyTuple_GET_SIZE(o); + if ((!boundscheck) || likely(__Pyx_is_valid_index(n, PyTuple_GET_SIZE(o)))) { + PyObject *r = PyTuple_GET_ITEM(o, n); + Py_INCREF(r); + return r; + } + } else { + PySequenceMethods *m = Py_TYPE(o)->tp_as_sequence; + if (likely(m && m->sq_item)) { + if (wraparound && unlikely(i < 0) && likely(m->sq_length)) { + Py_ssize_t l = m->sq_length(o); + if (likely(l >= 0)) { + i += l; + } else { + if (!PyErr_ExceptionMatches(PyExc_OverflowError)) + return NULL; + PyErr_Clear(); + } + } + return m->sq_item(o, i); + } + } +#else + if (is_list || PySequence_Check(o)) { + return PySequence_GetItem(o, i); + } +#endif + return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); +} + +/* ObjectGetItem */ +#if CYTHON_USE_TYPE_SLOTS +static PyObject *__Pyx_PyObject_GetIndex(PyObject *obj, PyObject* index) { + PyObject *runerr = NULL; + Py_ssize_t key_value; + PySequenceMethods *m = Py_TYPE(obj)->tp_as_sequence; + if (unlikely(!(m && m->sq_item))) { + PyErr_Format(PyExc_TypeError, "'%.200s' object is not subscriptable", Py_TYPE(obj)->tp_name); + return NULL; + } + key_value = __Pyx_PyIndex_AsSsize_t(index); + if (likely(key_value != -1 || !(runerr = PyErr_Occurred()))) { + return __Pyx_GetItemInt_Fast(obj, key_value, 0, 1, 1); + } + if (PyErr_GivenExceptionMatches(runerr, PyExc_OverflowError)) { + PyErr_Clear(); + PyErr_Format(PyExc_IndexError, "cannot fit '%.200s' into an index-sized integer", Py_TYPE(index)->tp_name); + } + return NULL; +} +static PyObject *__Pyx_PyObject_GetItem(PyObject *obj, PyObject* key) { + PyMappingMethods *m = Py_TYPE(obj)->tp_as_mapping; + if (likely(m && m->mp_subscript)) { + return m->mp_subscript(obj, key); + } + return __Pyx_PyObject_GetIndex(obj, key); +} +#endif + +/* PyIntBinop */ +#if !CYTHON_COMPILING_IN_PYPY +static PyObject* __Pyx_PyInt_AddObjC(PyObject *op1, PyObject *op2, CYTHON_UNUSED long intval, int inplace, int zerodivision_check) { + (void)inplace; + (void)zerodivision_check; + #if PY_MAJOR_VERSION < 3 + if (likely(PyInt_CheckExact(op1))) { + const long b = intval; + long x; + long a = PyInt_AS_LONG(op1); + x = (long)((unsigned long)a + b); + if (likely((x^a) >= 0 || (x^b) >= 0)) + return PyInt_FromLong(x); + return PyLong_Type.tp_as_number->nb_add(op1, op2); + } + #endif + #if CYTHON_USE_PYLONG_INTERNALS + if (likely(PyLong_CheckExact(op1))) { + const long b = intval; + long a, x; +#ifdef HAVE_LONG_LONG + const PY_LONG_LONG llb = intval; + PY_LONG_LONG lla, llx; +#endif + const digit* digits = ((PyLongObject*)op1)->ob_digit; + const Py_ssize_t size = Py_SIZE(op1); + if (likely(__Pyx_sst_abs(size) <= 1)) { + a = likely(size) ? digits[0] : 0; + if (size == -1) a = -a; + } else { + switch (size) { + case -2: + if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { + a = -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); + break; +#ifdef HAVE_LONG_LONG + } else if (8 * sizeof(PY_LONG_LONG) - 1 > 2 * PyLong_SHIFT) { + lla = -(PY_LONG_LONG) (((((unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0])); + goto long_long; +#endif + } + CYTHON_FALLTHROUGH; + case 2: + if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { + a = (long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); + break; +#ifdef HAVE_LONG_LONG + } else if (8 * sizeof(PY_LONG_LONG) - 1 > 2 * PyLong_SHIFT) { + lla = (PY_LONG_LONG) (((((unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0])); + goto long_long; +#endif + } + CYTHON_FALLTHROUGH; + case -3: + if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { + a = -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); + break; +#ifdef HAVE_LONG_LONG + } else if (8 * sizeof(PY_LONG_LONG) - 1 > 3 * PyLong_SHIFT) { + lla = -(PY_LONG_LONG) (((((((unsigned PY_LONG_LONG)digits[2]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0])); + goto long_long; +#endif + } + CYTHON_FALLTHROUGH; + case 3: + if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { + a = (long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); + break; +#ifdef HAVE_LONG_LONG + } else if (8 * sizeof(PY_LONG_LONG) - 1 > 3 * PyLong_SHIFT) { + lla = (PY_LONG_LONG) (((((((unsigned PY_LONG_LONG)digits[2]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0])); + goto long_long; +#endif + } + CYTHON_FALLTHROUGH; + case -4: + if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { + a = -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); + break; +#ifdef HAVE_LONG_LONG + } else if (8 * sizeof(PY_LONG_LONG) - 1 > 4 * PyLong_SHIFT) { + lla = -(PY_LONG_LONG) (((((((((unsigned PY_LONG_LONG)digits[3]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[2]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0])); + goto long_long; +#endif + } + CYTHON_FALLTHROUGH; + case 4: + if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { + a = (long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); + break; +#ifdef HAVE_LONG_LONG + } else if (8 * sizeof(PY_LONG_LONG) - 1 > 4 * PyLong_SHIFT) { + lla = (PY_LONG_LONG) (((((((((unsigned PY_LONG_LONG)digits[3]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[2]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0])); + goto long_long; +#endif + } + CYTHON_FALLTHROUGH; + default: return PyLong_Type.tp_as_number->nb_add(op1, op2); + } + } + x = a + b; + return PyLong_FromLong(x); +#ifdef HAVE_LONG_LONG + long_long: + llx = lla + llb; + return PyLong_FromLongLong(llx); +#endif + + + } + #endif + if (PyFloat_CheckExact(op1)) { + const long b = intval; + double a = PyFloat_AS_DOUBLE(op1); + double result; + PyFPE_START_PROTECT("add", return NULL) + result = ((double)a) + (double)b; + PyFPE_END_PROTECT(result) + return PyFloat_FromDouble(result); + } + return (inplace ? PyNumber_InPlaceAdd : PyNumber_Add)(op1, op2); +} +#endif + +/* pyobject_as_double */ +static double __Pyx__PyObject_AsDouble(PyObject* obj) { + PyObject* float_value; +#if !CYTHON_USE_TYPE_SLOTS + float_value = PyNumber_Float(obj); if ((0)) goto bad; +#else + PyNumberMethods *nb = Py_TYPE(obj)->tp_as_number; + if (likely(nb) && likely(nb->nb_float)) { + float_value = nb->nb_float(obj); + if (likely(float_value) && unlikely(!PyFloat_Check(float_value))) { + PyErr_Format(PyExc_TypeError, + "__float__ returned non-float (type %.200s)", + Py_TYPE(float_value)->tp_name); + Py_DECREF(float_value); + goto bad; + } + } else if (PyUnicode_CheckExact(obj) || PyBytes_CheckExact(obj)) { +#if PY_MAJOR_VERSION >= 3 + float_value = PyFloat_FromString(obj); +#else + float_value = PyFloat_FromString(obj, 0); +#endif + } else { + PyObject* args = PyTuple_New(1); + if (unlikely(!args)) goto bad; + PyTuple_SET_ITEM(args, 0, obj); + float_value = PyObject_Call((PyObject*)&PyFloat_Type, args, 0); + PyTuple_SET_ITEM(args, 0, 0); + Py_DECREF(args); + } +#endif + if (likely(float_value)) { + double value = PyFloat_AS_DOUBLE(float_value); + Py_DECREF(float_value); + return value; + } +bad: + return (double)-1; +} + +/* PyDictVersioning */ +#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PY_UINT64_T __Pyx_get_tp_dict_version(PyObject *obj) { + PyObject *dict = Py_TYPE(obj)->tp_dict; + return likely(dict) ? __PYX_GET_DICT_VERSION(dict) : 0; +} +static CYTHON_INLINE PY_UINT64_T __Pyx_get_object_dict_version(PyObject *obj) { + PyObject **dictptr = NULL; + Py_ssize_t offset = Py_TYPE(obj)->tp_dictoffset; + if (offset) { +#if CYTHON_COMPILING_IN_CPYTHON + dictptr = (likely(offset > 0)) ? (PyObject **) ((char *)obj + offset) : _PyObject_GetDictPtr(obj); +#else + dictptr = _PyObject_GetDictPtr(obj); +#endif + } + return (dictptr && *dictptr) ? __PYX_GET_DICT_VERSION(*dictptr) : 0; +} +static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UINT64_T tp_dict_version, PY_UINT64_T obj_dict_version) { + PyObject *dict = Py_TYPE(obj)->tp_dict; + if (unlikely(!dict) || unlikely(tp_dict_version != __PYX_GET_DICT_VERSION(dict))) + return 0; + return obj_dict_version == __Pyx_get_object_dict_version(obj); +} +#endif + +/* GetModuleGlobalName */ +#if CYTHON_USE_DICT_VERSIONS +static PyObject *__Pyx__GetModuleGlobalName(PyObject *name, PY_UINT64_T *dict_version, PyObject **dict_cached_value) +#else +static CYTHON_INLINE PyObject *__Pyx__GetModuleGlobalName(PyObject *name) +#endif +{ + PyObject *result; +#if !CYTHON_AVOID_BORROWED_REFS +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030500A1 + result = _PyDict_GetItem_KnownHash(__pyx_d, name, ((PyASCIIObject *) name)->hash); + __PYX_UPDATE_DICT_CACHE(__pyx_d, result, *dict_cached_value, *dict_version) + if (likely(result)) { + return __Pyx_NewRef(result); + } else if (unlikely(PyErr_Occurred())) { + return NULL; + } +#else + result = PyDict_GetItem(__pyx_d, name); + __PYX_UPDATE_DICT_CACHE(__pyx_d, result, *dict_cached_value, *dict_version) + if (likely(result)) { + return __Pyx_NewRef(result); + } +#endif +#else + result = PyObject_GetItem(__pyx_d, name); + __PYX_UPDATE_DICT_CACHE(__pyx_d, result, *dict_cached_value, *dict_version) + if (likely(result)) { + return __Pyx_NewRef(result); + } + PyErr_Clear(); +#endif + return __Pyx_GetBuiltinName(name); +} + +/* PyObjectCallNoArg */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func) { +#if CYTHON_FAST_PYCALL + if (PyFunction_Check(func)) { + return __Pyx_PyFunction_FastCall(func, NULL, 0); + } +#endif +#if defined(__Pyx_CyFunction_USED) && defined(NDEBUG) + if (likely(PyCFunction_Check(func) || __Pyx_CyFunction_Check(func))) +#else + if (likely(PyCFunction_Check(func))) +#endif + { + if (likely(PyCFunction_GET_FLAGS(func) & METH_NOARGS)) { + return __Pyx_PyObject_CallMethO(func, NULL); + } + } + return __Pyx_PyObject_Call(func, __pyx_empty_tuple, NULL); +} +#endif + +/* decode_c_string */ +static CYTHON_INLINE PyObject* __Pyx_decode_c_string( + const char* cstring, Py_ssize_t start, Py_ssize_t stop, + const char* encoding, const char* errors, + PyObject* (*decode_func)(const char *s, Py_ssize_t size, const char *errors)) { + Py_ssize_t length; + if (unlikely((start < 0) | (stop < 0))) { + size_t slen = strlen(cstring); + if (unlikely(slen > (size_t) PY_SSIZE_T_MAX)) { + PyErr_SetString(PyExc_OverflowError, + "c-string too long to convert to Python"); + return NULL; + } + length = (Py_ssize_t) slen; + if (start < 0) { + start += length; + if (start < 0) + start = 0; + } + if (stop < 0) + stop += length; + } + if (unlikely(stop <= start)) + return __Pyx_NewRef(__pyx_empty_unicode); + length = stop - start; + cstring += start; + if (decode_func) { + return decode_func(cstring, length, errors); + } else { + return PyUnicode_Decode(cstring, length, encoding, errors); + } +} + +/* GetException */ +#if CYTHON_FAST_THREAD_STATE +static int __Pyx__GetException(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) +#else +static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb) +#endif +{ + PyObject *local_type, *local_value, *local_tb; +#if CYTHON_FAST_THREAD_STATE + PyObject *tmp_type, *tmp_value, *tmp_tb; + local_type = tstate->curexc_type; + local_value = tstate->curexc_value; + local_tb = tstate->curexc_traceback; + tstate->curexc_type = 0; + tstate->curexc_value = 0; + tstate->curexc_traceback = 0; +#else + PyErr_Fetch(&local_type, &local_value, &local_tb); +#endif + PyErr_NormalizeException(&local_type, &local_value, &local_tb); +#if CYTHON_FAST_THREAD_STATE + if (unlikely(tstate->curexc_type)) +#else + if (unlikely(PyErr_Occurred())) +#endif + goto bad; + #if PY_MAJOR_VERSION >= 3 + if (local_tb) { + if (unlikely(PyException_SetTraceback(local_value, local_tb) < 0)) + goto bad; + } + #endif + Py_XINCREF(local_tb); + Py_XINCREF(local_type); + Py_XINCREF(local_value); + *type = local_type; + *value = local_value; + *tb = local_tb; +#if CYTHON_FAST_THREAD_STATE + #if CYTHON_USE_EXC_INFO_STACK + { + _PyErr_StackItem *exc_info = tstate->exc_info; + tmp_type = exc_info->exc_type; + tmp_value = exc_info->exc_value; + tmp_tb = exc_info->exc_traceback; + exc_info->exc_type = local_type; + exc_info->exc_value = local_value; + exc_info->exc_traceback = local_tb; + } + #else + tmp_type = tstate->exc_type; + tmp_value = tstate->exc_value; + tmp_tb = tstate->exc_traceback; + tstate->exc_type = local_type; + tstate->exc_value = local_value; + tstate->exc_traceback = local_tb; + #endif + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); +#else + PyErr_SetExcInfo(local_type, local_value, local_tb); +#endif + return 0; +bad: + *type = 0; + *value = 0; + *tb = 0; + Py_XDECREF(local_type); + Py_XDECREF(local_value); + Py_XDECREF(local_tb); + return -1; +} + +/* SwapException */ +#if CYTHON_FAST_THREAD_STATE +static CYTHON_INLINE void __Pyx__ExceptionSwap(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { + PyObject *tmp_type, *tmp_value, *tmp_tb; + #if CYTHON_USE_EXC_INFO_STACK + _PyErr_StackItem *exc_info = tstate->exc_info; + tmp_type = exc_info->exc_type; + tmp_value = exc_info->exc_value; + tmp_tb = exc_info->exc_traceback; + exc_info->exc_type = *type; + exc_info->exc_value = *value; + exc_info->exc_traceback = *tb; + #else + tmp_type = tstate->exc_type; + tmp_value = tstate->exc_value; + tmp_tb = tstate->exc_traceback; + tstate->exc_type = *type; + tstate->exc_value = *value; + tstate->exc_traceback = *tb; + #endif + *type = tmp_type; + *value = tmp_value; + *tb = tmp_tb; +} +#else +static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value, PyObject **tb) { + PyObject *tmp_type, *tmp_value, *tmp_tb; + PyErr_GetExcInfo(&tmp_type, &tmp_value, &tmp_tb); + PyErr_SetExcInfo(*type, *value, *tb); + *type = tmp_type; + *value = tmp_value; + *tb = tmp_tb; +} +#endif + +/* GetTopmostException */ +#if CYTHON_USE_EXC_INFO_STACK +static _PyErr_StackItem * +__Pyx_PyErr_GetTopmostException(PyThreadState *tstate) +{ + _PyErr_StackItem *exc_info = tstate->exc_info; + while ((exc_info->exc_type == NULL || exc_info->exc_type == Py_None) && + exc_info->previous_item != NULL) + { + exc_info = exc_info->previous_item; + } + return exc_info; +} +#endif + +/* SaveResetException */ +#if CYTHON_FAST_THREAD_STATE +static CYTHON_INLINE void __Pyx__ExceptionSave(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { + #if CYTHON_USE_EXC_INFO_STACK + _PyErr_StackItem *exc_info = __Pyx_PyErr_GetTopmostException(tstate); + *type = exc_info->exc_type; + *value = exc_info->exc_value; + *tb = exc_info->exc_traceback; + #else + *type = tstate->exc_type; + *value = tstate->exc_value; + *tb = tstate->exc_traceback; + #endif + Py_XINCREF(*type); + Py_XINCREF(*value); + Py_XINCREF(*tb); +} +static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) { + PyObject *tmp_type, *tmp_value, *tmp_tb; + #if CYTHON_USE_EXC_INFO_STACK + _PyErr_StackItem *exc_info = tstate->exc_info; + tmp_type = exc_info->exc_type; + tmp_value = exc_info->exc_value; + tmp_tb = exc_info->exc_traceback; + exc_info->exc_type = type; + exc_info->exc_value = value; + exc_info->exc_traceback = tb; + #else + tmp_type = tstate->exc_type; + tmp_value = tstate->exc_value; + tmp_tb = tstate->exc_traceback; + tstate->exc_type = type; + tstate->exc_value = value; + tstate->exc_traceback = tb; + #endif + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); +} +#endif + +/* PyObjectSetAttrStr */ +#if CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE int __Pyx_PyObject_SetAttrStr(PyObject* obj, PyObject* attr_name, PyObject* value) { + PyTypeObject* tp = Py_TYPE(obj); + if (likely(tp->tp_setattro)) + return tp->tp_setattro(obj, attr_name, value); +#if PY_MAJOR_VERSION < 3 + if (likely(tp->tp_setattr)) + return tp->tp_setattr(obj, PyString_AS_STRING(attr_name), value); +#endif + return PyObject_SetAttr(obj, attr_name, value); +} +#endif + +/* PyErrExceptionMatches */ +#if CYTHON_FAST_THREAD_STATE +static int __Pyx_PyErr_ExceptionMatchesTuple(PyObject *exc_type, PyObject *tuple) { + Py_ssize_t i, n; + n = PyTuple_GET_SIZE(tuple); +#if PY_MAJOR_VERSION >= 3 + for (i=0; icurexc_type; + if (exc_type == err) return 1; + if (unlikely(!exc_type)) return 0; + if (unlikely(PyTuple_Check(err))) + return __Pyx_PyErr_ExceptionMatchesTuple(exc_type, err); + return __Pyx_PyErr_GivenExceptionMatches(exc_type, err); +} +#endif + +/* GetAttr */ +static CYTHON_INLINE PyObject *__Pyx_GetAttr(PyObject *o, PyObject *n) { +#if CYTHON_USE_TYPE_SLOTS +#if PY_MAJOR_VERSION >= 3 + if (likely(PyUnicode_Check(n))) +#else + if (likely(PyString_Check(n))) +#endif + return __Pyx_PyObject_GetAttrStr(o, n); +#endif + return PyObject_GetAttr(o, n); +} + +/* GetAttr3 */ +static PyObject *__Pyx_GetAttr3Default(PyObject *d) { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + if (unlikely(!__Pyx_PyErr_ExceptionMatches(PyExc_AttributeError))) + return NULL; + __Pyx_PyErr_Clear(); + Py_INCREF(d); + return d; +} +static CYTHON_INLINE PyObject *__Pyx_GetAttr3(PyObject *o, PyObject *n, PyObject *d) { + PyObject *r = __Pyx_GetAttr(o, n); + return (likely(r)) ? r : __Pyx_GetAttr3Default(d); +} + +/* Import */ +static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level) { + PyObject *empty_list = 0; + PyObject *module = 0; + PyObject *global_dict = 0; + PyObject *empty_dict = 0; + PyObject *list; + #if PY_MAJOR_VERSION < 3 + PyObject *py_import; + py_import = __Pyx_PyObject_GetAttrStr(__pyx_b, __pyx_n_s_import); + if (!py_import) + goto bad; + #endif + if (from_list) + list = from_list; + else { + empty_list = PyList_New(0); + if (!empty_list) + goto bad; + list = empty_list; + } + global_dict = PyModule_GetDict(__pyx_m); + if (!global_dict) + goto bad; + empty_dict = PyDict_New(); + if (!empty_dict) + goto bad; + { + #if PY_MAJOR_VERSION >= 3 + if (level == -1) { + if ((1) && (strchr(__Pyx_MODULE_NAME, '.'))) { + module = PyImport_ImportModuleLevelObject( + name, global_dict, empty_dict, list, 1); + if (!module) { + if (!PyErr_ExceptionMatches(PyExc_ImportError)) + goto bad; + PyErr_Clear(); + } + } + level = 0; + } + #endif + if (!module) { + #if PY_MAJOR_VERSION < 3 + PyObject *py_level = PyInt_FromLong(level); + if (!py_level) + goto bad; + module = PyObject_CallFunctionObjArgs(py_import, + name, global_dict, empty_dict, list, py_level, (PyObject *)NULL); + Py_DECREF(py_level); + #else + module = PyImport_ImportModuleLevelObject( + name, global_dict, empty_dict, list, level); + #endif + } + } +bad: + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(py_import); + #endif + Py_XDECREF(empty_list); + Py_XDECREF(empty_dict); + return module; +} + +/* ImportFrom */ +static PyObject* __Pyx_ImportFrom(PyObject* module, PyObject* name) { + PyObject* value = __Pyx_PyObject_GetAttrStr(module, name); + if (unlikely(!value) && PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Format(PyExc_ImportError, + #if PY_MAJOR_VERSION < 3 + "cannot import name %.230s", PyString_AS_STRING(name)); + #else + "cannot import name %S", name); + #endif + } + return value; +} + +/* PyObjectCall2Args */ +static CYTHON_UNUSED PyObject* __Pyx_PyObject_Call2Args(PyObject* function, PyObject* arg1, PyObject* arg2) { + PyObject *args, *result = NULL; + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(function)) { + PyObject *args[2] = {arg1, arg2}; + return __Pyx_PyFunction_FastCall(function, args, 2); + } + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(function)) { + PyObject *args[2] = {arg1, arg2}; + return __Pyx_PyCFunction_FastCall(function, args, 2); + } + #endif + args = PyTuple_New(2); + if (unlikely(!args)) goto done; + Py_INCREF(arg1); + PyTuple_SET_ITEM(args, 0, arg1); + Py_INCREF(arg2); + PyTuple_SET_ITEM(args, 1, arg2); + Py_INCREF(function); + result = __Pyx_PyObject_Call(function, args, NULL); + Py_DECREF(args); + Py_DECREF(function); +done: + return result; +} + +/* HasAttr */ +static CYTHON_INLINE int __Pyx_HasAttr(PyObject *o, PyObject *n) { + PyObject *r; + if (unlikely(!__Pyx_PyBaseString_Check(n))) { + PyErr_SetString(PyExc_TypeError, + "hasattr(): attribute name must be string"); + return -1; + } + r = __Pyx_GetAttr(o, n); + if (unlikely(!r)) { + PyErr_Clear(); + return 0; + } else { + Py_DECREF(r); + return 1; + } +} + +/* PyObject_GenericGetAttrNoDict */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static PyObject *__Pyx_RaiseGenericGetAttributeError(PyTypeObject *tp, PyObject *attr_name) { + PyErr_Format(PyExc_AttributeError, +#if PY_MAJOR_VERSION >= 3 + "'%.50s' object has no attribute '%U'", + tp->tp_name, attr_name); +#else + "'%.50s' object has no attribute '%.400s'", + tp->tp_name, PyString_AS_STRING(attr_name)); +#endif + return NULL; +} +static CYTHON_INLINE PyObject* __Pyx_PyObject_GenericGetAttrNoDict(PyObject* obj, PyObject* attr_name) { + PyObject *descr; + PyTypeObject *tp = Py_TYPE(obj); + if (unlikely(!PyString_Check(attr_name))) { + return PyObject_GenericGetAttr(obj, attr_name); + } + assert(!tp->tp_dictoffset); + descr = _PyType_Lookup(tp, attr_name); + if (unlikely(!descr)) { + return __Pyx_RaiseGenericGetAttributeError(tp, attr_name); + } + Py_INCREF(descr); + #if PY_MAJOR_VERSION < 3 + if (likely(PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_HAVE_CLASS))) + #endif + { + descrgetfunc f = Py_TYPE(descr)->tp_descr_get; + if (unlikely(f)) { + PyObject *res = f(descr, obj, (PyObject *)tp); + Py_DECREF(descr); + return res; + } + } + return descr; +} +#endif + +/* PyObject_GenericGetAttr */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_name) { + if (unlikely(Py_TYPE(obj)->tp_dictoffset)) { + return PyObject_GenericGetAttr(obj, attr_name); + } + return __Pyx_PyObject_GenericGetAttrNoDict(obj, attr_name); +} +#endif + +/* PyObjectGetAttrStrNoError */ +static void __Pyx_PyObject_GetAttrStr_ClearAttributeError(void) { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + if (likely(__Pyx_PyErr_ExceptionMatches(PyExc_AttributeError))) + __Pyx_PyErr_Clear(); +} +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name) { + PyObject *result; +#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_TYPE_SLOTS && PY_VERSION_HEX >= 0x030700B1 + PyTypeObject* tp = Py_TYPE(obj); + if (likely(tp->tp_getattro == PyObject_GenericGetAttr)) { + return _PyObject_GenericGetAttrWithDict(obj, attr_name, NULL, 1); + } +#endif + result = __Pyx_PyObject_GetAttrStr(obj, attr_name); + if (unlikely(!result)) { + __Pyx_PyObject_GetAttrStr_ClearAttributeError(); + } + return result; +} + +/* SetupReduce */ +static int __Pyx_setup_reduce_is_named(PyObject* meth, PyObject* name) { + int ret; + PyObject *name_attr; + name_attr = __Pyx_PyObject_GetAttrStr(meth, __pyx_n_s_name_2); + if (likely(name_attr)) { + ret = PyObject_RichCompareBool(name_attr, name, Py_EQ); + } else { + ret = -1; + } + if (unlikely(ret < 0)) { + PyErr_Clear(); + ret = 0; + } + Py_XDECREF(name_attr); + return ret; +} +static int __Pyx_setup_reduce(PyObject* type_obj) { + int ret = 0; + PyObject *object_reduce = NULL; + PyObject *object_getstate = NULL; + PyObject *object_reduce_ex = NULL; + PyObject *reduce = NULL; + PyObject *reduce_ex = NULL; + PyObject *reduce_cython = NULL; + PyObject *setstate = NULL; + PyObject *setstate_cython = NULL; + PyObject *getstate = NULL; +#if CYTHON_USE_PYTYPE_LOOKUP + getstate = _PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate); +#else + getstate = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_getstate); + if (!getstate && PyErr_Occurred()) { + goto __PYX_BAD; + } +#endif + if (getstate) { +#if CYTHON_USE_PYTYPE_LOOKUP + object_getstate = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_getstate); +#else + object_getstate = __Pyx_PyObject_GetAttrStrNoError((PyObject*)&PyBaseObject_Type, __pyx_n_s_getstate); + if (!object_getstate && PyErr_Occurred()) { + goto __PYX_BAD; + } +#endif + if (object_getstate != getstate) { + goto __PYX_GOOD; + } + } +#if CYTHON_USE_PYTYPE_LOOKUP + object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; +#else + object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; +#endif + reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto __PYX_BAD; + if (reduce_ex == object_reduce_ex) { +#if CYTHON_USE_PYTYPE_LOOKUP + object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; +#else + object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; +#endif + reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto __PYX_BAD; + if (reduce == object_reduce || __Pyx_setup_reduce_is_named(reduce, __pyx_n_s_reduce_cython)) { + reduce_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_reduce_cython); + if (likely(reduce_cython)) { + ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; + ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; + } else if (reduce == object_reduce || PyErr_Occurred()) { + goto __PYX_BAD; + } + setstate = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_setstate); + if (!setstate) PyErr_Clear(); + if (!setstate || __Pyx_setup_reduce_is_named(setstate, __pyx_n_s_setstate_cython)) { + setstate_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_setstate_cython); + if (likely(setstate_cython)) { + ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; + ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; + } else if (!setstate || PyErr_Occurred()) { + goto __PYX_BAD; + } + } + PyType_Modified((PyTypeObject*)type_obj); + } + } + goto __PYX_GOOD; +__PYX_BAD: + if (!PyErr_Occurred()) + PyErr_Format(PyExc_RuntimeError, "Unable to initialize pickling for %s", ((PyTypeObject*)type_obj)->tp_name); + ret = -1; +__PYX_GOOD: +#if !CYTHON_USE_PYTYPE_LOOKUP + Py_XDECREF(object_reduce); + Py_XDECREF(object_reduce_ex); + Py_XDECREF(object_getstate); + Py_XDECREF(getstate); +#endif + Py_XDECREF(reduce); + Py_XDECREF(reduce_ex); + Py_XDECREF(reduce_cython); + Py_XDECREF(setstate); + Py_XDECREF(setstate_cython); + return ret; +} + +/* CalculateMetaclass */ +static PyObject *__Pyx_CalculateMetaclass(PyTypeObject *metaclass, PyObject *bases) { + Py_ssize_t i, nbases = PyTuple_GET_SIZE(bases); + for (i=0; i < nbases; i++) { + PyTypeObject *tmptype; + PyObject *tmp = PyTuple_GET_ITEM(bases, i); + tmptype = Py_TYPE(tmp); +#if PY_MAJOR_VERSION < 3 + if (tmptype == &PyClass_Type) + continue; +#endif + if (!metaclass) { + metaclass = tmptype; + continue; + } + if (PyType_IsSubtype(metaclass, tmptype)) + continue; + if (PyType_IsSubtype(tmptype, metaclass)) { + metaclass = tmptype; + continue; + } + PyErr_SetString(PyExc_TypeError, + "metaclass conflict: " + "the metaclass of a derived class " + "must be a (non-strict) subclass " + "of the metaclasses of all its bases"); + return NULL; + } + if (!metaclass) { +#if PY_MAJOR_VERSION < 3 + metaclass = &PyClass_Type; +#else + metaclass = &PyType_Type; +#endif + } + Py_INCREF((PyObject*) metaclass); + return (PyObject*) metaclass; +} + +/* FetchCommonType */ +static PyTypeObject* __Pyx_FetchCommonType(PyTypeObject* type) { + PyObject* fake_module; + PyTypeObject* cached_type = NULL; + fake_module = PyImport_AddModule((char*) "_cython_" CYTHON_ABI); + if (!fake_module) return NULL; + Py_INCREF(fake_module); + cached_type = (PyTypeObject*) PyObject_GetAttrString(fake_module, type->tp_name); + if (cached_type) { + if (!PyType_Check((PyObject*)cached_type)) { + PyErr_Format(PyExc_TypeError, + "Shared Cython type %.200s is not a type object", + type->tp_name); + goto bad; + } + if (cached_type->tp_basicsize != type->tp_basicsize) { + PyErr_Format(PyExc_TypeError, + "Shared Cython type %.200s has the wrong size, try recompiling", + type->tp_name); + goto bad; + } + } else { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) goto bad; + PyErr_Clear(); + if (PyType_Ready(type) < 0) goto bad; + if (PyObject_SetAttrString(fake_module, type->tp_name, (PyObject*) type) < 0) + goto bad; + Py_INCREF(type); + cached_type = type; + } +done: + Py_DECREF(fake_module); + return cached_type; +bad: + Py_XDECREF(cached_type); + cached_type = NULL; + goto done; +} + +/* CythonFunctionShared */ +#include +static PyObject * +__Pyx_CyFunction_get_doc(__pyx_CyFunctionObject *op, CYTHON_UNUSED void *closure) +{ + if (unlikely(op->func_doc == NULL)) { + if (op->func.m_ml->ml_doc) { +#if PY_MAJOR_VERSION >= 3 + op->func_doc = PyUnicode_FromString(op->func.m_ml->ml_doc); +#else + op->func_doc = PyString_FromString(op->func.m_ml->ml_doc); +#endif + if (unlikely(op->func_doc == NULL)) + return NULL; + } else { + Py_INCREF(Py_None); + return Py_None; + } + } + Py_INCREF(op->func_doc); + return op->func_doc; +} +static int +__Pyx_CyFunction_set_doc(__pyx_CyFunctionObject *op, PyObject *value, CYTHON_UNUSED void *context) +{ + PyObject *tmp = op->func_doc; + if (value == NULL) { + value = Py_None; + } + Py_INCREF(value); + op->func_doc = value; + Py_XDECREF(tmp); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_name(__pyx_CyFunctionObject *op, CYTHON_UNUSED void *context) +{ + if (unlikely(op->func_name == NULL)) { +#if PY_MAJOR_VERSION >= 3 + op->func_name = PyUnicode_InternFromString(op->func.m_ml->ml_name); +#else + op->func_name = PyString_InternFromString(op->func.m_ml->ml_name); +#endif + if (unlikely(op->func_name == NULL)) + return NULL; + } + Py_INCREF(op->func_name); + return op->func_name; +} +static int +__Pyx_CyFunction_set_name(__pyx_CyFunctionObject *op, PyObject *value, CYTHON_UNUSED void *context) +{ + PyObject *tmp; +#if PY_MAJOR_VERSION >= 3 + if (unlikely(value == NULL || !PyUnicode_Check(value))) +#else + if (unlikely(value == NULL || !PyString_Check(value))) +#endif + { + PyErr_SetString(PyExc_TypeError, + "__name__ must be set to a string object"); + return -1; + } + tmp = op->func_name; + Py_INCREF(value); + op->func_name = value; + Py_XDECREF(tmp); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_qualname(__pyx_CyFunctionObject *op, CYTHON_UNUSED void *context) +{ + Py_INCREF(op->func_qualname); + return op->func_qualname; +} +static int +__Pyx_CyFunction_set_qualname(__pyx_CyFunctionObject *op, PyObject *value, CYTHON_UNUSED void *context) +{ + PyObject *tmp; +#if PY_MAJOR_VERSION >= 3 + if (unlikely(value == NULL || !PyUnicode_Check(value))) +#else + if (unlikely(value == NULL || !PyString_Check(value))) +#endif + { + PyErr_SetString(PyExc_TypeError, + "__qualname__ must be set to a string object"); + return -1; + } + tmp = op->func_qualname; + Py_INCREF(value); + op->func_qualname = value; + Py_XDECREF(tmp); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_self(__pyx_CyFunctionObject *m, CYTHON_UNUSED void *closure) +{ + PyObject *self; + self = m->func_closure; + if (self == NULL) + self = Py_None; + Py_INCREF(self); + return self; +} +static PyObject * +__Pyx_CyFunction_get_dict(__pyx_CyFunctionObject *op, CYTHON_UNUSED void *context) +{ + if (unlikely(op->func_dict == NULL)) { + op->func_dict = PyDict_New(); + if (unlikely(op->func_dict == NULL)) + return NULL; + } + Py_INCREF(op->func_dict); + return op->func_dict; +} +static int +__Pyx_CyFunction_set_dict(__pyx_CyFunctionObject *op, PyObject *value, CYTHON_UNUSED void *context) +{ + PyObject *tmp; + if (unlikely(value == NULL)) { + PyErr_SetString(PyExc_TypeError, + "function's dictionary may not be deleted"); + return -1; + } + if (unlikely(!PyDict_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "setting function's dictionary to a non-dict"); + return -1; + } + tmp = op->func_dict; + Py_INCREF(value); + op->func_dict = value; + Py_XDECREF(tmp); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_globals(__pyx_CyFunctionObject *op, CYTHON_UNUSED void *context) +{ + Py_INCREF(op->func_globals); + return op->func_globals; +} +static PyObject * +__Pyx_CyFunction_get_closure(CYTHON_UNUSED __pyx_CyFunctionObject *op, CYTHON_UNUSED void *context) +{ + Py_INCREF(Py_None); + return Py_None; +} +static PyObject * +__Pyx_CyFunction_get_code(__pyx_CyFunctionObject *op, CYTHON_UNUSED void *context) +{ + PyObject* result = (op->func_code) ? op->func_code : Py_None; + Py_INCREF(result); + return result; +} +static int +__Pyx_CyFunction_init_defaults(__pyx_CyFunctionObject *op) { + int result = 0; + PyObject *res = op->defaults_getter((PyObject *) op); + if (unlikely(!res)) + return -1; + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + op->defaults_tuple = PyTuple_GET_ITEM(res, 0); + Py_INCREF(op->defaults_tuple); + op->defaults_kwdict = PyTuple_GET_ITEM(res, 1); + Py_INCREF(op->defaults_kwdict); + #else + op->defaults_tuple = PySequence_ITEM(res, 0); + if (unlikely(!op->defaults_tuple)) result = -1; + else { + op->defaults_kwdict = PySequence_ITEM(res, 1); + if (unlikely(!op->defaults_kwdict)) result = -1; + } + #endif + Py_DECREF(res); + return result; +} +static int +__Pyx_CyFunction_set_defaults(__pyx_CyFunctionObject *op, PyObject* value, CYTHON_UNUSED void *context) { + PyObject* tmp; + if (!value) { + value = Py_None; + } else if (value != Py_None && !PyTuple_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "__defaults__ must be set to a tuple object"); + return -1; + } + Py_INCREF(value); + tmp = op->defaults_tuple; + op->defaults_tuple = value; + Py_XDECREF(tmp); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_defaults(__pyx_CyFunctionObject *op, CYTHON_UNUSED void *context) { + PyObject* result = op->defaults_tuple; + if (unlikely(!result)) { + if (op->defaults_getter) { + if (__Pyx_CyFunction_init_defaults(op) < 0) return NULL; + result = op->defaults_tuple; + } else { + result = Py_None; + } + } + Py_INCREF(result); + return result; +} +static int +__Pyx_CyFunction_set_kwdefaults(__pyx_CyFunctionObject *op, PyObject* value, CYTHON_UNUSED void *context) { + PyObject* tmp; + if (!value) { + value = Py_None; + } else if (value != Py_None && !PyDict_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "__kwdefaults__ must be set to a dict object"); + return -1; + } + Py_INCREF(value); + tmp = op->defaults_kwdict; + op->defaults_kwdict = value; + Py_XDECREF(tmp); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_kwdefaults(__pyx_CyFunctionObject *op, CYTHON_UNUSED void *context) { + PyObject* result = op->defaults_kwdict; + if (unlikely(!result)) { + if (op->defaults_getter) { + if (__Pyx_CyFunction_init_defaults(op) < 0) return NULL; + result = op->defaults_kwdict; + } else { + result = Py_None; + } + } + Py_INCREF(result); + return result; +} +static int +__Pyx_CyFunction_set_annotations(__pyx_CyFunctionObject *op, PyObject* value, CYTHON_UNUSED void *context) { + PyObject* tmp; + if (!value || value == Py_None) { + value = NULL; + } else if (!PyDict_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "__annotations__ must be set to a dict object"); + return -1; + } + Py_XINCREF(value); + tmp = op->func_annotations; + op->func_annotations = value; + Py_XDECREF(tmp); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_annotations(__pyx_CyFunctionObject *op, CYTHON_UNUSED void *context) { + PyObject* result = op->func_annotations; + if (unlikely(!result)) { + result = PyDict_New(); + if (unlikely(!result)) return NULL; + op->func_annotations = result; + } + Py_INCREF(result); + return result; +} +static PyGetSetDef __pyx_CyFunction_getsets[] = { + {(char *) "func_doc", (getter)__Pyx_CyFunction_get_doc, (setter)__Pyx_CyFunction_set_doc, 0, 0}, + {(char *) "__doc__", (getter)__Pyx_CyFunction_get_doc, (setter)__Pyx_CyFunction_set_doc, 0, 0}, + {(char *) "func_name", (getter)__Pyx_CyFunction_get_name, (setter)__Pyx_CyFunction_set_name, 0, 0}, + {(char *) "__name__", (getter)__Pyx_CyFunction_get_name, (setter)__Pyx_CyFunction_set_name, 0, 0}, + {(char *) "__qualname__", (getter)__Pyx_CyFunction_get_qualname, (setter)__Pyx_CyFunction_set_qualname, 0, 0}, + {(char *) "__self__", (getter)__Pyx_CyFunction_get_self, 0, 0, 0}, + {(char *) "func_dict", (getter)__Pyx_CyFunction_get_dict, (setter)__Pyx_CyFunction_set_dict, 0, 0}, + {(char *) "__dict__", (getter)__Pyx_CyFunction_get_dict, (setter)__Pyx_CyFunction_set_dict, 0, 0}, + {(char *) "func_globals", (getter)__Pyx_CyFunction_get_globals, 0, 0, 0}, + {(char *) "__globals__", (getter)__Pyx_CyFunction_get_globals, 0, 0, 0}, + {(char *) "func_closure", (getter)__Pyx_CyFunction_get_closure, 0, 0, 0}, + {(char *) "__closure__", (getter)__Pyx_CyFunction_get_closure, 0, 0, 0}, + {(char *) "func_code", (getter)__Pyx_CyFunction_get_code, 0, 0, 0}, + {(char *) "__code__", (getter)__Pyx_CyFunction_get_code, 0, 0, 0}, + {(char *) "func_defaults", (getter)__Pyx_CyFunction_get_defaults, (setter)__Pyx_CyFunction_set_defaults, 0, 0}, + {(char *) "__defaults__", (getter)__Pyx_CyFunction_get_defaults, (setter)__Pyx_CyFunction_set_defaults, 0, 0}, + {(char *) "__kwdefaults__", (getter)__Pyx_CyFunction_get_kwdefaults, (setter)__Pyx_CyFunction_set_kwdefaults, 0, 0}, + {(char *) "__annotations__", (getter)__Pyx_CyFunction_get_annotations, (setter)__Pyx_CyFunction_set_annotations, 0, 0}, + {0, 0, 0, 0, 0} +}; +static PyMemberDef __pyx_CyFunction_members[] = { + {(char *) "__module__", T_OBJECT, offsetof(PyCFunctionObject, m_module), PY_WRITE_RESTRICTED, 0}, + {0, 0, 0, 0, 0} +}; +static PyObject * +__Pyx_CyFunction_reduce(__pyx_CyFunctionObject *m, CYTHON_UNUSED PyObject *args) +{ +#if PY_MAJOR_VERSION >= 3 + Py_INCREF(m->func_qualname); + return m->func_qualname; +#else + return PyString_FromString(m->func.m_ml->ml_name); +#endif +} +static PyMethodDef __pyx_CyFunction_methods[] = { + {"__reduce__", (PyCFunction)__Pyx_CyFunction_reduce, METH_VARARGS, 0}, + {0, 0, 0, 0} +}; +#if PY_VERSION_HEX < 0x030500A0 +#define __Pyx_CyFunction_weakreflist(cyfunc) ((cyfunc)->func_weakreflist) +#else +#define __Pyx_CyFunction_weakreflist(cyfunc) ((cyfunc)->func.m_weakreflist) +#endif +static PyObject *__Pyx_CyFunction_Init(__pyx_CyFunctionObject *op, PyMethodDef *ml, int flags, PyObject* qualname, + PyObject *closure, PyObject *module, PyObject* globals, PyObject* code) { + if (unlikely(op == NULL)) + return NULL; + op->flags = flags; + __Pyx_CyFunction_weakreflist(op) = NULL; + op->func.m_ml = ml; + op->func.m_self = (PyObject *) op; + Py_XINCREF(closure); + op->func_closure = closure; + Py_XINCREF(module); + op->func.m_module = module; + op->func_dict = NULL; + op->func_name = NULL; + Py_INCREF(qualname); + op->func_qualname = qualname; + op->func_doc = NULL; + op->func_classobj = NULL; + op->func_globals = globals; + Py_INCREF(op->func_globals); + Py_XINCREF(code); + op->func_code = code; + op->defaults_pyobjects = 0; + op->defaults_size = 0; + op->defaults = NULL; + op->defaults_tuple = NULL; + op->defaults_kwdict = NULL; + op->defaults_getter = NULL; + op->func_annotations = NULL; + return (PyObject *) op; +} +static int +__Pyx_CyFunction_clear(__pyx_CyFunctionObject *m) +{ + Py_CLEAR(m->func_closure); + Py_CLEAR(m->func.m_module); + Py_CLEAR(m->func_dict); + Py_CLEAR(m->func_name); + Py_CLEAR(m->func_qualname); + Py_CLEAR(m->func_doc); + Py_CLEAR(m->func_globals); + Py_CLEAR(m->func_code); + Py_CLEAR(m->func_classobj); + Py_CLEAR(m->defaults_tuple); + Py_CLEAR(m->defaults_kwdict); + Py_CLEAR(m->func_annotations); + if (m->defaults) { + PyObject **pydefaults = __Pyx_CyFunction_Defaults(PyObject *, m); + int i; + for (i = 0; i < m->defaults_pyobjects; i++) + Py_XDECREF(pydefaults[i]); + PyObject_Free(m->defaults); + m->defaults = NULL; + } + return 0; +} +static void __Pyx__CyFunction_dealloc(__pyx_CyFunctionObject *m) +{ + if (__Pyx_CyFunction_weakreflist(m) != NULL) + PyObject_ClearWeakRefs((PyObject *) m); + __Pyx_CyFunction_clear(m); + PyObject_GC_Del(m); +} +static void __Pyx_CyFunction_dealloc(__pyx_CyFunctionObject *m) +{ + PyObject_GC_UnTrack(m); + __Pyx__CyFunction_dealloc(m); +} +static int __Pyx_CyFunction_traverse(__pyx_CyFunctionObject *m, visitproc visit, void *arg) +{ + Py_VISIT(m->func_closure); + Py_VISIT(m->func.m_module); + Py_VISIT(m->func_dict); + Py_VISIT(m->func_name); + Py_VISIT(m->func_qualname); + Py_VISIT(m->func_doc); + Py_VISIT(m->func_globals); + Py_VISIT(m->func_code); + Py_VISIT(m->func_classobj); + Py_VISIT(m->defaults_tuple); + Py_VISIT(m->defaults_kwdict); + if (m->defaults) { + PyObject **pydefaults = __Pyx_CyFunction_Defaults(PyObject *, m); + int i; + for (i = 0; i < m->defaults_pyobjects; i++) + Py_VISIT(pydefaults[i]); + } + return 0; +} +static PyObject *__Pyx_CyFunction_descr_get(PyObject *func, PyObject *obj, PyObject *type) +{ +#if PY_MAJOR_VERSION < 3 + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + if (m->flags & __Pyx_CYFUNCTION_STATICMETHOD) { + Py_INCREF(func); + return func; + } + if (m->flags & __Pyx_CYFUNCTION_CLASSMETHOD) { + if (type == NULL) + type = (PyObject *)(Py_TYPE(obj)); + return __Pyx_PyMethod_New(func, type, (PyObject *)(Py_TYPE(type))); + } + if (obj == Py_None) + obj = NULL; +#endif + return __Pyx_PyMethod_New(func, obj, type); +} +static PyObject* +__Pyx_CyFunction_repr(__pyx_CyFunctionObject *op) +{ +#if PY_MAJOR_VERSION >= 3 + return PyUnicode_FromFormat("", + op->func_qualname, (void *)op); +#else + return PyString_FromFormat("", + PyString_AsString(op->func_qualname), (void *)op); +#endif +} +static PyObject * __Pyx_CyFunction_CallMethod(PyObject *func, PyObject *self, PyObject *arg, PyObject *kw) { + PyCFunctionObject* f = (PyCFunctionObject*)func; + PyCFunction meth = f->m_ml->ml_meth; + Py_ssize_t size; + switch (f->m_ml->ml_flags & (METH_VARARGS | METH_KEYWORDS | METH_NOARGS | METH_O)) { + case METH_VARARGS: + if (likely(kw == NULL || PyDict_Size(kw) == 0)) + return (*meth)(self, arg); + break; + case METH_VARARGS | METH_KEYWORDS: + return (*(PyCFunctionWithKeywords)(void*)meth)(self, arg, kw); + case METH_NOARGS: + if (likely(kw == NULL || PyDict_Size(kw) == 0)) { + size = PyTuple_GET_SIZE(arg); + if (likely(size == 0)) + return (*meth)(self, NULL); + PyErr_Format(PyExc_TypeError, + "%.200s() takes no arguments (%" CYTHON_FORMAT_SSIZE_T "d given)", + f->m_ml->ml_name, size); + return NULL; + } + break; + case METH_O: + if (likely(kw == NULL || PyDict_Size(kw) == 0)) { + size = PyTuple_GET_SIZE(arg); + if (likely(size == 1)) { + PyObject *result, *arg0; + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + arg0 = PyTuple_GET_ITEM(arg, 0); + #else + arg0 = PySequence_ITEM(arg, 0); if (unlikely(!arg0)) return NULL; + #endif + result = (*meth)(self, arg0); + #if !(CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS) + Py_DECREF(arg0); + #endif + return result; + } + PyErr_Format(PyExc_TypeError, + "%.200s() takes exactly one argument (%" CYTHON_FORMAT_SSIZE_T "d given)", + f->m_ml->ml_name, size); + return NULL; + } + break; + default: + PyErr_SetString(PyExc_SystemError, "Bad call flags in " + "__Pyx_CyFunction_Call. METH_OLDARGS is no " + "longer supported!"); + return NULL; + } + PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", + f->m_ml->ml_name); + return NULL; +} +static CYTHON_INLINE PyObject *__Pyx_CyFunction_Call(PyObject *func, PyObject *arg, PyObject *kw) { + return __Pyx_CyFunction_CallMethod(func, ((PyCFunctionObject*)func)->m_self, arg, kw); +} +static PyObject *__Pyx_CyFunction_CallAsMethod(PyObject *func, PyObject *args, PyObject *kw) { + PyObject *result; + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *) func; + if ((cyfunc->flags & __Pyx_CYFUNCTION_CCLASS) && !(cyfunc->flags & __Pyx_CYFUNCTION_STATICMETHOD)) { + Py_ssize_t argc; + PyObject *new_args; + PyObject *self; + argc = PyTuple_GET_SIZE(args); + new_args = PyTuple_GetSlice(args, 1, argc); + if (unlikely(!new_args)) + return NULL; + self = PyTuple_GetItem(args, 0); + if (unlikely(!self)) { + Py_DECREF(new_args); +#if PY_MAJOR_VERSION > 2 + PyErr_Format(PyExc_TypeError, + "unbound method %.200S() needs an argument", + cyfunc->func_qualname); +#else + PyErr_SetString(PyExc_TypeError, + "unbound method needs an argument"); +#endif + return NULL; + } + result = __Pyx_CyFunction_CallMethod(func, self, new_args, kw); + Py_DECREF(new_args); + } else { + result = __Pyx_CyFunction_Call(func, args, kw); + } + return result; +} +static PyTypeObject __pyx_CyFunctionType_type = { + PyVarObject_HEAD_INIT(0, 0) + "cython_function_or_method", + sizeof(__pyx_CyFunctionObject), + 0, + (destructor) __Pyx_CyFunction_dealloc, + 0, + 0, + 0, +#if PY_MAJOR_VERSION < 3 + 0, +#else + 0, +#endif + (reprfunc) __Pyx_CyFunction_repr, + 0, + 0, + 0, + 0, + __Pyx_CyFunction_CallAsMethod, + 0, + 0, + 0, + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, + 0, + (traverseproc) __Pyx_CyFunction_traverse, + (inquiry) __Pyx_CyFunction_clear, + 0, +#if PY_VERSION_HEX < 0x030500A0 + offsetof(__pyx_CyFunctionObject, func_weakreflist), +#else + offsetof(PyCFunctionObject, m_weakreflist), +#endif + 0, + 0, + __pyx_CyFunction_methods, + __pyx_CyFunction_members, + __pyx_CyFunction_getsets, + 0, + 0, + __Pyx_CyFunction_descr_get, + 0, + offsetof(__pyx_CyFunctionObject, func_dict), + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, +#if PY_VERSION_HEX >= 0x030400a1 + 0, +#endif +#if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, +#endif +#if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 + 0, +#endif +#if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 + 0, +#endif +}; +static int __pyx_CyFunction_init(void) { + __pyx_CyFunctionType = __Pyx_FetchCommonType(&__pyx_CyFunctionType_type); + if (unlikely(__pyx_CyFunctionType == NULL)) { + return -1; + } + return 0; +} +static CYTHON_INLINE void *__Pyx_CyFunction_InitDefaults(PyObject *func, size_t size, int pyobjects) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->defaults = PyObject_Malloc(size); + if (unlikely(!m->defaults)) + return PyErr_NoMemory(); + memset(m->defaults, 0, size); + m->defaults_pyobjects = pyobjects; + m->defaults_size = size; + return m->defaults; +} +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsTuple(PyObject *func, PyObject *tuple) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->defaults_tuple = tuple; + Py_INCREF(tuple); +} +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsKwDict(PyObject *func, PyObject *dict) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->defaults_kwdict = dict; + Py_INCREF(dict); +} +static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *func, PyObject *dict) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->func_annotations = dict; + Py_INCREF(dict); +} + +/* CythonFunction */ +static PyObject *__Pyx_CyFunction_New(PyMethodDef *ml, int flags, PyObject* qualname, + PyObject *closure, PyObject *module, PyObject* globals, PyObject* code) { + PyObject *op = __Pyx_CyFunction_Init( + PyObject_GC_New(__pyx_CyFunctionObject, __pyx_CyFunctionType), + ml, flags, qualname, closure, module, globals, code + ); + if (likely(op)) { + PyObject_GC_Track(op); + } + return op; +} + +/* Py3ClassCreate */ +static PyObject *__Pyx_Py3MetaclassPrepare(PyObject *metaclass, PyObject *bases, PyObject *name, + PyObject *qualname, PyObject *mkw, PyObject *modname, PyObject *doc) { + PyObject *ns; + if (metaclass) { + PyObject *prep = __Pyx_PyObject_GetAttrStr(metaclass, __pyx_n_s_prepare); + if (prep) { + PyObject *pargs = PyTuple_Pack(2, name, bases); + if (unlikely(!pargs)) { + Py_DECREF(prep); + return NULL; + } + ns = PyObject_Call(prep, pargs, mkw); + Py_DECREF(prep); + Py_DECREF(pargs); + } else { + if (unlikely(!PyErr_ExceptionMatches(PyExc_AttributeError))) + return NULL; + PyErr_Clear(); + ns = PyDict_New(); + } + } else { + ns = PyDict_New(); + } + if (unlikely(!ns)) + return NULL; + if (unlikely(PyObject_SetItem(ns, __pyx_n_s_module, modname) < 0)) goto bad; + if (unlikely(PyObject_SetItem(ns, __pyx_n_s_qualname, qualname) < 0)) goto bad; + if (unlikely(doc && PyObject_SetItem(ns, __pyx_n_s_doc, doc) < 0)) goto bad; + return ns; +bad: + Py_DECREF(ns); + return NULL; +} +static PyObject *__Pyx_Py3ClassCreate(PyObject *metaclass, PyObject *name, PyObject *bases, + PyObject *dict, PyObject *mkw, + int calculate_metaclass, int allow_py2_metaclass) { + PyObject *result, *margs; + PyObject *owned_metaclass = NULL; + if (allow_py2_metaclass) { + owned_metaclass = PyObject_GetItem(dict, __pyx_n_s_metaclass); + if (owned_metaclass) { + metaclass = owned_metaclass; + } else if (likely(PyErr_ExceptionMatches(PyExc_KeyError))) { + PyErr_Clear(); + } else { + return NULL; + } + } + if (calculate_metaclass && (!metaclass || PyType_Check(metaclass))) { + metaclass = __Pyx_CalculateMetaclass((PyTypeObject*) metaclass, bases); + Py_XDECREF(owned_metaclass); + if (unlikely(!metaclass)) + return NULL; + owned_metaclass = metaclass; + } + margs = PyTuple_Pack(3, name, bases, dict); + if (unlikely(!margs)) { + result = NULL; + } else { + result = PyObject_Call(metaclass, margs, mkw); + Py_DECREF(margs); + } + Py_XDECREF(owned_metaclass); + return result; +} + +/* Globals */ +static PyObject* __Pyx_Globals(void) { + Py_ssize_t i; + PyObject *names; + PyObject *globals = __pyx_d; + Py_INCREF(globals); + names = PyObject_Dir(__pyx_m); + if (!names) + goto bad; + for (i = PyList_GET_SIZE(names)-1; i >= 0; i--) { +#if CYTHON_COMPILING_IN_PYPY + PyObject* name = PySequence_ITEM(names, i); + if (!name) + goto bad; +#else + PyObject* name = PyList_GET_ITEM(names, i); +#endif + if (!PyDict_Contains(globals, name)) { + PyObject* value = __Pyx_GetAttr(__pyx_m, name); + if (!value) { +#if CYTHON_COMPILING_IN_PYPY + Py_DECREF(name); +#endif + goto bad; + } + if (PyDict_SetItem(globals, name, value) < 0) { +#if CYTHON_COMPILING_IN_PYPY + Py_DECREF(name); +#endif + Py_DECREF(value); + goto bad; + } + } +#if CYTHON_COMPILING_IN_PYPY + Py_DECREF(name); +#endif + } + Py_DECREF(names); + return globals; +bad: + Py_XDECREF(names); + Py_XDECREF(globals); + return NULL; +} + +/* CLineInTraceback */ +#ifndef CYTHON_CLINE_IN_TRACEBACK +static int __Pyx_CLineForTraceback(CYTHON_UNUSED PyThreadState *tstate, int c_line) { + PyObject *use_cline; + PyObject *ptype, *pvalue, *ptraceback; +#if CYTHON_COMPILING_IN_CPYTHON + PyObject **cython_runtime_dict; +#endif + if (unlikely(!__pyx_cython_runtime)) { + return c_line; + } + __Pyx_ErrFetchInState(tstate, &ptype, &pvalue, &ptraceback); +#if CYTHON_COMPILING_IN_CPYTHON + cython_runtime_dict = _PyObject_GetDictPtr(__pyx_cython_runtime); + if (likely(cython_runtime_dict)) { + __PYX_PY_DICT_LOOKUP_IF_MODIFIED( + use_cline, *cython_runtime_dict, + __Pyx_PyDict_GetItemStr(*cython_runtime_dict, __pyx_n_s_cline_in_traceback)) + } else +#endif + { + PyObject *use_cline_obj = __Pyx_PyObject_GetAttrStr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback); + if (use_cline_obj) { + use_cline = PyObject_Not(use_cline_obj) ? Py_False : Py_True; + Py_DECREF(use_cline_obj); + } else { + PyErr_Clear(); + use_cline = NULL; + } + } + if (!use_cline) { + c_line = 0; + (void) PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); + } + else if (use_cline == Py_False || (use_cline != Py_True && PyObject_Not(use_cline) != 0)) { + c_line = 0; + } + __Pyx_ErrRestoreInState(tstate, ptype, pvalue, ptraceback); + return c_line; +} +#endif + +/* CodeObjectCache */ +static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line) { + int start = 0, mid = 0, end = count - 1; + if (end >= 0 && code_line > entries[end].code_line) { + return count; + } + while (start < end) { + mid = start + (end - start) / 2; + if (code_line < entries[mid].code_line) { + end = mid; + } else if (code_line > entries[mid].code_line) { + start = mid + 1; + } else { + return mid; + } + } + if (code_line <= entries[mid].code_line) { + return mid; + } else { + return mid + 1; + } +} +static PyCodeObject *__pyx_find_code_object(int code_line) { + PyCodeObject* code_object; + int pos; + if (unlikely(!code_line) || unlikely(!__pyx_code_cache.entries)) { + return NULL; + } + pos = __pyx_bisect_code_objects(__pyx_code_cache.entries, __pyx_code_cache.count, code_line); + if (unlikely(pos >= __pyx_code_cache.count) || unlikely(__pyx_code_cache.entries[pos].code_line != code_line)) { + return NULL; + } + code_object = __pyx_code_cache.entries[pos].code_object; + Py_INCREF(code_object); + return code_object; +} +static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { + int pos, i; + __Pyx_CodeObjectCacheEntry* entries = __pyx_code_cache.entries; + if (unlikely(!code_line)) { + return; + } + if (unlikely(!entries)) { + entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Malloc(64*sizeof(__Pyx_CodeObjectCacheEntry)); + if (likely(entries)) { + __pyx_code_cache.entries = entries; + __pyx_code_cache.max_count = 64; + __pyx_code_cache.count = 1; + entries[0].code_line = code_line; + entries[0].code_object = code_object; + Py_INCREF(code_object); + } + return; + } + pos = __pyx_bisect_code_objects(__pyx_code_cache.entries, __pyx_code_cache.count, code_line); + if ((pos < __pyx_code_cache.count) && unlikely(__pyx_code_cache.entries[pos].code_line == code_line)) { + PyCodeObject* tmp = entries[pos].code_object; + entries[pos].code_object = code_object; + Py_DECREF(tmp); + return; + } + if (__pyx_code_cache.count == __pyx_code_cache.max_count) { + int new_max = __pyx_code_cache.max_count + 64; + entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Realloc( + __pyx_code_cache.entries, ((size_t)new_max) * sizeof(__Pyx_CodeObjectCacheEntry)); + if (unlikely(!entries)) { + return; + } + __pyx_code_cache.entries = entries; + __pyx_code_cache.max_count = new_max; + } + for (i=__pyx_code_cache.count; i>pos; i--) { + entries[i] = entries[i-1]; + } + entries[pos].code_line = code_line; + entries[pos].code_object = code_object; + __pyx_code_cache.count++; + Py_INCREF(code_object); +} + +/* AddTraceback */ +#include "compile.h" +#include "frameobject.h" +#include "traceback.h" +#if PY_VERSION_HEX >= 0x030b00a6 + #ifndef Py_BUILD_CORE + #define Py_BUILD_CORE 1 + #endif + #include "internal/pycore_frame.h" +#endif +static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( + const char *funcname, int c_line, + int py_line, const char *filename) { + PyCodeObject *py_code = NULL; + PyObject *py_funcname = NULL; + #if PY_MAJOR_VERSION < 3 + PyObject *py_srcfile = NULL; + py_srcfile = PyString_FromString(filename); + if (!py_srcfile) goto bad; + #endif + if (c_line) { + #if PY_MAJOR_VERSION < 3 + py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); + if (!py_funcname) goto bad; + #else + py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); + if (!py_funcname) goto bad; + funcname = PyUnicode_AsUTF8(py_funcname); + if (!funcname) goto bad; + #endif + } + else { + #if PY_MAJOR_VERSION < 3 + py_funcname = PyString_FromString(funcname); + if (!py_funcname) goto bad; + #endif + } + #if PY_MAJOR_VERSION < 3 + py_code = __Pyx_PyCode_New( + 0, + 0, + 0, + 0, + 0, + __pyx_empty_bytes, /*PyObject *code,*/ + __pyx_empty_tuple, /*PyObject *consts,*/ + __pyx_empty_tuple, /*PyObject *names,*/ + __pyx_empty_tuple, /*PyObject *varnames,*/ + __pyx_empty_tuple, /*PyObject *freevars,*/ + __pyx_empty_tuple, /*PyObject *cellvars,*/ + py_srcfile, /*PyObject *filename,*/ + py_funcname, /*PyObject *name,*/ + py_line, + __pyx_empty_bytes /*PyObject *lnotab*/ + ); + Py_DECREF(py_srcfile); + #else + py_code = PyCode_NewEmpty(filename, funcname, py_line); + #endif + Py_XDECREF(py_funcname); // XDECREF since it's only set on Py3 if cline + return py_code; +bad: + Py_XDECREF(py_funcname); + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(py_srcfile); + #endif + return NULL; +} +static void __Pyx_AddTraceback(const char *funcname, int c_line, + int py_line, const char *filename) { + PyCodeObject *py_code = 0; + PyFrameObject *py_frame = 0; + PyThreadState *tstate = __Pyx_PyThreadState_Current; + PyObject *ptype, *pvalue, *ptraceback; + if (c_line) { + c_line = __Pyx_CLineForTraceback(tstate, c_line); + } + py_code = __pyx_find_code_object(c_line ? -c_line : py_line); + if (!py_code) { + __Pyx_ErrFetchInState(tstate, &ptype, &pvalue, &ptraceback); + py_code = __Pyx_CreateCodeObjectForTraceback( + funcname, c_line, py_line, filename); + if (!py_code) { + /* If the code object creation fails, then we should clear the + fetched exception references and propagate the new exception */ + Py_XDECREF(ptype); + Py_XDECREF(pvalue); + Py_XDECREF(ptraceback); + goto bad; + } + __Pyx_ErrRestoreInState(tstate, ptype, pvalue, ptraceback); + __pyx_insert_code_object(c_line ? -c_line : py_line, py_code); + } + py_frame = PyFrame_New( + tstate, /*PyThreadState *tstate,*/ + py_code, /*PyCodeObject *code,*/ + __pyx_d, /*PyObject *globals,*/ + 0 /*PyObject *locals*/ + ); + if (!py_frame) goto bad; + __Pyx_PyFrame_SetLineNumber(py_frame, py_line); + PyTraceBack_Here(py_frame); +bad: + Py_XDECREF(py_code); + Py_XDECREF(py_frame); +} + +/* CIntFromPyVerify */ +#define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value)\ + __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 0) +#define __PYX_VERIFY_RETURN_INT_EXC(target_type, func_type, func_value)\ + __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 1) +#define __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, exc)\ + {\ + func_type value = func_value;\ + if (sizeof(target_type) < sizeof(func_type)) {\ + if (unlikely(value != (func_type) (target_type) value)) {\ + func_type zero = 0;\ + if (exc && unlikely(value == (func_type)-1 && PyErr_Occurred()))\ + return (target_type) -1;\ + if (is_unsigned && unlikely(value < zero))\ + goto raise_neg_overflow;\ + else\ + goto raise_overflow;\ + }\ + }\ + return (target_type) value;\ + } + +/* CIntFromPy */ +static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const int neg_one = (int) -1, const_zero = (int) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if (sizeof(int) < sizeof(long)) { + __PYX_VERIFY_RETURN_INT(int, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (int) val; + } + } else +#endif + if (likely(PyLong_Check(x))) { + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (int) 0; + case 1: __PYX_VERIFY_RETURN_INT(int, digit, digits[0]) + case 2: + if (8 * sizeof(int) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) >= 2 * PyLong_SHIFT) { + return (int) (((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + case 3: + if (8 * sizeof(int) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) >= 3 * PyLong_SHIFT) { + return (int) (((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + case 4: + if (8 * sizeof(int) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) >= 4 * PyLong_SHIFT) { + return (int) (((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (int) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if (sizeof(int) <= sizeof(unsigned long)) { + __PYX_VERIFY_RETURN_INT_EXC(int, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(int, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (int) 0; + case -1: __PYX_VERIFY_RETURN_INT(int, sdigit, (sdigit) (-(sdigit)digits[0])) + case 1: __PYX_VERIFY_RETURN_INT(int, digit, +digits[0]) + case -2: + if (8 * sizeof(int) - 1 > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { + return (int) (((int)-1)*(((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 2: + if (8 * sizeof(int) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { + return (int) ((((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case -3: + if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { + return (int) (((int)-1)*(((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 3: + if (8 * sizeof(int) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { + return (int) ((((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case -4: + if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { + return (int) (((int)-1)*(((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 4: + if (8 * sizeof(int) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { + return (int) ((((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + } +#endif + if (sizeof(int) <= sizeof(long)) { + __PYX_VERIFY_RETURN_INT_EXC(int, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(int, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { +#if CYTHON_COMPILING_IN_PYPY && !defined(_PyLong_AsByteArray) + PyErr_SetString(PyExc_RuntimeError, + "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); +#else + int val; + PyObject *v = __Pyx_PyNumber_IntOrLong(x); + #if PY_MAJOR_VERSION < 3 + if (likely(v) && !PyLong_Check(v)) { + PyObject *tmp = v; + v = PyNumber_Long(tmp); + Py_DECREF(tmp); + } + #endif + if (likely(v)) { + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + int ret = _PyLong_AsByteArray((PyLongObject *)v, + bytes, sizeof(val), + is_little, !is_unsigned); + Py_DECREF(v); + if (likely(!ret)) + return val; + } +#endif + return (int) -1; + } + } else { + int val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (int) -1; + val = __Pyx_PyInt_As_int(tmp); + Py_DECREF(tmp); + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to int"); + return (int) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to int"); + return (int) -1; +} + +/* CIntFromPy */ +static CYTHON_INLINE size_t __Pyx_PyInt_As_size_t(PyObject *x) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const size_t neg_one = (size_t) -1, const_zero = (size_t) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if (sizeof(size_t) < sizeof(long)) { + __PYX_VERIFY_RETURN_INT(size_t, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (size_t) val; + } + } else +#endif + if (likely(PyLong_Check(x))) { + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (size_t) 0; + case 1: __PYX_VERIFY_RETURN_INT(size_t, digit, digits[0]) + case 2: + if (8 * sizeof(size_t) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(size_t, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(size_t) >= 2 * PyLong_SHIFT) { + return (size_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + } + break; + case 3: + if (8 * sizeof(size_t) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(size_t, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(size_t) >= 3 * PyLong_SHIFT) { + return (size_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + } + break; + case 4: + if (8 * sizeof(size_t) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(size_t, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(size_t) >= 4 * PyLong_SHIFT) { + return (size_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + } + break; + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (size_t) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if (sizeof(size_t) <= sizeof(unsigned long)) { + __PYX_VERIFY_RETURN_INT_EXC(size_t, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(size_t) <= sizeof(unsigned PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(size_t, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (size_t) 0; + case -1: __PYX_VERIFY_RETURN_INT(size_t, sdigit, (sdigit) (-(sdigit)digits[0])) + case 1: __PYX_VERIFY_RETURN_INT(size_t, digit, +digits[0]) + case -2: + if (8 * sizeof(size_t) - 1 > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(size_t, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(size_t) - 1 > 2 * PyLong_SHIFT) { + return (size_t) (((size_t)-1)*(((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0]))); + } + } + break; + case 2: + if (8 * sizeof(size_t) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(size_t, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(size_t) - 1 > 2 * PyLong_SHIFT) { + return (size_t) ((((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0]))); + } + } + break; + case -3: + if (8 * sizeof(size_t) - 1 > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(size_t, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(size_t) - 1 > 3 * PyLong_SHIFT) { + return (size_t) (((size_t)-1)*(((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0]))); + } + } + break; + case 3: + if (8 * sizeof(size_t) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(size_t, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(size_t) - 1 > 3 * PyLong_SHIFT) { + return (size_t) ((((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0]))); + } + } + break; + case -4: + if (8 * sizeof(size_t) - 1 > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(size_t, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(size_t) - 1 > 4 * PyLong_SHIFT) { + return (size_t) (((size_t)-1)*(((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0]))); + } + } + break; + case 4: + if (8 * sizeof(size_t) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(size_t, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(size_t) - 1 > 4 * PyLong_SHIFT) { + return (size_t) ((((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0]))); + } + } + break; + } +#endif + if (sizeof(size_t) <= sizeof(long)) { + __PYX_VERIFY_RETURN_INT_EXC(size_t, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(size_t) <= sizeof(PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(size_t, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { +#if CYTHON_COMPILING_IN_PYPY && !defined(_PyLong_AsByteArray) + PyErr_SetString(PyExc_RuntimeError, + "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); +#else + size_t val; + PyObject *v = __Pyx_PyNumber_IntOrLong(x); + #if PY_MAJOR_VERSION < 3 + if (likely(v) && !PyLong_Check(v)) { + PyObject *tmp = v; + v = PyNumber_Long(tmp); + Py_DECREF(tmp); + } + #endif + if (likely(v)) { + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + int ret = _PyLong_AsByteArray((PyLongObject *)v, + bytes, sizeof(val), + is_little, !is_unsigned); + Py_DECREF(v); + if (likely(!ret)) + return val; + } +#endif + return (size_t) -1; + } + } else { + size_t val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (size_t) -1; + val = __Pyx_PyInt_As_size_t(tmp); + Py_DECREF(tmp); + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to size_t"); + return (size_t) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to size_t"); + return (size_t) -1; +} + +/* CIntToPy */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const long neg_one = (long) -1, const_zero = (long) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; + if (is_unsigned) { + if (sizeof(long) < sizeof(long)) { + return PyInt_FromLong((long) value); + } else if (sizeof(long) <= sizeof(unsigned long)) { + return PyLong_FromUnsignedLong((unsigned long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { + return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); +#endif + } + } else { + if (sizeof(long) <= sizeof(long)) { + return PyInt_FromLong((long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { + return PyLong_FromLongLong((PY_LONG_LONG) value); +#endif + } + } + { + int one = 1; int little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&value; + return _PyLong_FromByteArray(bytes, sizeof(long), + little, !is_unsigned); + } +} + +/* CIntFromPy */ +static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const long neg_one = (long) -1, const_zero = (long) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if (sizeof(long) < sizeof(long)) { + __PYX_VERIFY_RETURN_INT(long, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (long) val; + } + } else +#endif + if (likely(PyLong_Check(x))) { + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (long) 0; + case 1: __PYX_VERIFY_RETURN_INT(long, digit, digits[0]) + case 2: + if (8 * sizeof(long) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) >= 2 * PyLong_SHIFT) { + return (long) (((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + case 3: + if (8 * sizeof(long) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) >= 3 * PyLong_SHIFT) { + return (long) (((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + case 4: + if (8 * sizeof(long) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) >= 4 * PyLong_SHIFT) { + return (long) (((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (long) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if (sizeof(long) <= sizeof(unsigned long)) { + __PYX_VERIFY_RETURN_INT_EXC(long, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(long, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (long) 0; + case -1: __PYX_VERIFY_RETURN_INT(long, sdigit, (sdigit) (-(sdigit)digits[0])) + case 1: __PYX_VERIFY_RETURN_INT(long, digit, +digits[0]) + case -2: + if (8 * sizeof(long) - 1 > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { + return (long) (((long)-1)*(((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 2: + if (8 * sizeof(long) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { + return (long) ((((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case -3: + if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { + return (long) (((long)-1)*(((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 3: + if (8 * sizeof(long) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { + return (long) ((((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case -4: + if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { + return (long) (((long)-1)*(((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 4: + if (8 * sizeof(long) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { + return (long) ((((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + } +#endif + if (sizeof(long) <= sizeof(long)) { + __PYX_VERIFY_RETURN_INT_EXC(long, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(long, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { +#if CYTHON_COMPILING_IN_PYPY && !defined(_PyLong_AsByteArray) + PyErr_SetString(PyExc_RuntimeError, + "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); +#else + long val; + PyObject *v = __Pyx_PyNumber_IntOrLong(x); + #if PY_MAJOR_VERSION < 3 + if (likely(v) && !PyLong_Check(v)) { + PyObject *tmp = v; + v = PyNumber_Long(tmp); + Py_DECREF(tmp); + } + #endif + if (likely(v)) { + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + int ret = _PyLong_AsByteArray((PyLongObject *)v, + bytes, sizeof(val), + is_little, !is_unsigned); + Py_DECREF(v); + if (likely(!ret)) + return val; + } +#endif + return (long) -1; + } + } else { + long val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (long) -1; + val = __Pyx_PyInt_As_long(tmp); + Py_DECREF(tmp); + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to long"); + return (long) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to long"); + return (long) -1; +} + +/* CIntToPy */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum____pyx_t_6region_RegionType(enum __pyx_t_6region_RegionType value) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const enum __pyx_t_6region_RegionType neg_one = (enum __pyx_t_6region_RegionType) -1, const_zero = (enum __pyx_t_6region_RegionType) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; + if (is_unsigned) { + if (sizeof(enum __pyx_t_6region_RegionType) < sizeof(long)) { + return PyInt_FromLong((long) value); + } else if (sizeof(enum __pyx_t_6region_RegionType) <= sizeof(unsigned long)) { + return PyLong_FromUnsignedLong((unsigned long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(enum __pyx_t_6region_RegionType) <= sizeof(unsigned PY_LONG_LONG)) { + return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); +#endif + } + } else { + if (sizeof(enum __pyx_t_6region_RegionType) <= sizeof(long)) { + return PyInt_FromLong((long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(enum __pyx_t_6region_RegionType) <= sizeof(PY_LONG_LONG)) { + return PyLong_FromLongLong((PY_LONG_LONG) value); +#endif + } + } + { + int one = 1; int little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&value; + return _PyLong_FromByteArray(bytes, sizeof(enum __pyx_t_6region_RegionType), + little, !is_unsigned); + } +} + +/* FastTypeChecks */ +#if CYTHON_COMPILING_IN_CPYTHON +static int __Pyx_InBases(PyTypeObject *a, PyTypeObject *b) { + while (a) { + a = a->tp_base; + if (a == b) + return 1; + } + return b == &PyBaseObject_Type; +} +static CYTHON_INLINE int __Pyx_IsSubtype(PyTypeObject *a, PyTypeObject *b) { + PyObject *mro; + if (a == b) return 1; + mro = a->tp_mro; + if (likely(mro)) { + Py_ssize_t i, n; + n = PyTuple_GET_SIZE(mro); + for (i = 0; i < n; i++) { + if (PyTuple_GET_ITEM(mro, i) == (PyObject *)b) + return 1; + } + return 0; + } + return __Pyx_InBases(a, b); +} +#if PY_MAJOR_VERSION == 2 +static int __Pyx_inner_PyErr_GivenExceptionMatches2(PyObject *err, PyObject* exc_type1, PyObject* exc_type2) { + PyObject *exception, *value, *tb; + int res; + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ErrFetch(&exception, &value, &tb); + res = exc_type1 ? PyObject_IsSubclass(err, exc_type1) : 0; + if (unlikely(res == -1)) { + PyErr_WriteUnraisable(err); + res = 0; + } + if (!res) { + res = PyObject_IsSubclass(err, exc_type2); + if (unlikely(res == -1)) { + PyErr_WriteUnraisable(err); + res = 0; + } + } + __Pyx_ErrRestore(exception, value, tb); + return res; +} +#else +static CYTHON_INLINE int __Pyx_inner_PyErr_GivenExceptionMatches2(PyObject *err, PyObject* exc_type1, PyObject *exc_type2) { + int res = exc_type1 ? __Pyx_IsSubtype((PyTypeObject*)err, (PyTypeObject*)exc_type1) : 0; + if (!res) { + res = __Pyx_IsSubtype((PyTypeObject*)err, (PyTypeObject*)exc_type2); + } + return res; +} +#endif +static int __Pyx_PyErr_GivenExceptionMatchesTuple(PyObject *exc_type, PyObject *tuple) { + Py_ssize_t i, n; + assert(PyExceptionClass_Check(exc_type)); + n = PyTuple_GET_SIZE(tuple); +#if PY_MAJOR_VERSION >= 3 + for (i=0; i '9'); + break; + } + if (rt_from_call[i] != ctversion[i]) { + same = 0; + break; + } + } + if (!same) { + char rtversion[5] = {'\0'}; + char message[200]; + for (i=0; i<4; ++i) { + if (rt_from_call[i] == '.') { + if (found_dot) break; + found_dot = 1; + } else if (rt_from_call[i] < '0' || rt_from_call[i] > '9') { + break; + } + rtversion[i] = rt_from_call[i]; + } + PyOS_snprintf(message, sizeof(message), + "compiletime version %s of module '%.100s' " + "does not match runtime version %s", + ctversion, __Pyx_MODULE_NAME, rtversion); + return PyErr_WarnEx(NULL, message, 1); + } + return 0; +} + +/* InitStrings */ +static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) { + while (t->p) { + #if PY_MAJOR_VERSION < 3 + if (t->is_unicode) { + *t->p = PyUnicode_DecodeUTF8(t->s, t->n - 1, NULL); + } else if (t->intern) { + *t->p = PyString_InternFromString(t->s); + } else { + *t->p = PyString_FromStringAndSize(t->s, t->n - 1); + } + #else + if (t->is_unicode | t->is_str) { + if (t->intern) { + *t->p = PyUnicode_InternFromString(t->s); + } else if (t->encoding) { + *t->p = PyUnicode_Decode(t->s, t->n - 1, t->encoding, NULL); + } else { + *t->p = PyUnicode_FromStringAndSize(t->s, t->n - 1); + } + } else { + *t->p = PyBytes_FromStringAndSize(t->s, t->n - 1); + } + #endif + if (!*t->p) + return -1; + if (PyObject_Hash(*t->p) == -1) + return -1; + ++t; + } + return 0; +} + +static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char* c_str) { + return __Pyx_PyUnicode_FromStringAndSize(c_str, (Py_ssize_t)strlen(c_str)); +} +static CYTHON_INLINE const char* __Pyx_PyObject_AsString(PyObject* o) { + Py_ssize_t ignore; + return __Pyx_PyObject_AsStringAndSize(o, &ignore); +} +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT +#if !CYTHON_PEP393_ENABLED +static const char* __Pyx_PyUnicode_AsStringAndSize(PyObject* o, Py_ssize_t *length) { + char* defenc_c; + PyObject* defenc = _PyUnicode_AsDefaultEncodedString(o, NULL); + if (!defenc) return NULL; + defenc_c = PyBytes_AS_STRING(defenc); +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + { + char* end = defenc_c + PyBytes_GET_SIZE(defenc); + char* c; + for (c = defenc_c; c < end; c++) { + if ((unsigned char) (*c) >= 128) { + PyUnicode_AsASCIIString(o); + return NULL; + } + } + } +#endif + *length = PyBytes_GET_SIZE(defenc); + return defenc_c; +} +#else +static CYTHON_INLINE const char* __Pyx_PyUnicode_AsStringAndSize(PyObject* o, Py_ssize_t *length) { + if (unlikely(__Pyx_PyUnicode_READY(o) == -1)) return NULL; +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + if (likely(PyUnicode_IS_ASCII(o))) { + *length = PyUnicode_GET_LENGTH(o); + return PyUnicode_AsUTF8(o); + } else { + PyUnicode_AsASCIIString(o); + return NULL; + } +#else + return PyUnicode_AsUTF8AndSize(o, length); +#endif +} +#endif +#endif +static CYTHON_INLINE const char* __Pyx_PyObject_AsStringAndSize(PyObject* o, Py_ssize_t *length) { +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT + if ( +#if PY_MAJOR_VERSION < 3 && __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + __Pyx_sys_getdefaultencoding_not_ascii && +#endif + PyUnicode_Check(o)) { + return __Pyx_PyUnicode_AsStringAndSize(o, length); + } else +#endif +#if (!CYTHON_COMPILING_IN_PYPY) || (defined(PyByteArray_AS_STRING) && defined(PyByteArray_GET_SIZE)) + if (PyByteArray_Check(o)) { + *length = PyByteArray_GET_SIZE(o); + return PyByteArray_AS_STRING(o); + } else +#endif + { + char* result; + int r = PyBytes_AsStringAndSize(o, &result, length); + if (unlikely(r < 0)) { + return NULL; + } else { + return result; + } + } +} +static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject* x) { + int is_true = x == Py_True; + if (is_true | (x == Py_False) | (x == Py_None)) return is_true; + else return PyObject_IsTrue(x); +} +static CYTHON_INLINE int __Pyx_PyObject_IsTrueAndDecref(PyObject* x) { + int retval; + if (unlikely(!x)) return -1; + retval = __Pyx_PyObject_IsTrue(x); + Py_DECREF(x); + return retval; +} +static PyObject* __Pyx_PyNumber_IntOrLongWrongResultType(PyObject* result, const char* type_name) { +#if PY_MAJOR_VERSION >= 3 + if (PyLong_Check(result)) { + if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, + "__int__ returned non-int (type %.200s). " + "The ability to return an instance of a strict subclass of int " + "is deprecated, and may be removed in a future version of Python.", + Py_TYPE(result)->tp_name)) { + Py_DECREF(result); + return NULL; + } + return result; + } +#endif + PyErr_Format(PyExc_TypeError, + "__%.4s__ returned non-%.4s (type %.200s)", + type_name, type_name, Py_TYPE(result)->tp_name); + Py_DECREF(result); + return NULL; +} +static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x) { +#if CYTHON_USE_TYPE_SLOTS + PyNumberMethods *m; +#endif + const char *name = NULL; + PyObject *res = NULL; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x) || PyLong_Check(x))) +#else + if (likely(PyLong_Check(x))) +#endif + return __Pyx_NewRef(x); +#if CYTHON_USE_TYPE_SLOTS + m = Py_TYPE(x)->tp_as_number; + #if PY_MAJOR_VERSION < 3 + if (m && m->nb_int) { + name = "int"; + res = m->nb_int(x); + } + else if (m && m->nb_long) { + name = "long"; + res = m->nb_long(x); + } + #else + if (likely(m && m->nb_int)) { + name = "int"; + res = m->nb_int(x); + } + #endif +#else + if (!PyBytes_CheckExact(x) && !PyUnicode_CheckExact(x)) { + res = PyNumber_Int(x); + } +#endif + if (likely(res)) { +#if PY_MAJOR_VERSION < 3 + if (unlikely(!PyInt_Check(res) && !PyLong_Check(res))) { +#else + if (unlikely(!PyLong_CheckExact(res))) { +#endif + return __Pyx_PyNumber_IntOrLongWrongResultType(res, name); + } + } + else if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, + "an integer is required"); + } + return res; +} +static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { + Py_ssize_t ival; + PyObject *x; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_CheckExact(b))) { + if (sizeof(Py_ssize_t) >= sizeof(long)) + return PyInt_AS_LONG(b); + else + return PyInt_AsSsize_t(b); + } +#endif + if (likely(PyLong_CheckExact(b))) { + #if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)b)->ob_digit; + const Py_ssize_t size = Py_SIZE(b); + if (likely(__Pyx_sst_abs(size) <= 1)) { + ival = likely(size) ? digits[0] : 0; + if (size == -1) ival = -ival; + return ival; + } else { + switch (size) { + case 2: + if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { + return (Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -2: + if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case 3: + if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { + return (Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -3: + if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case 4: + if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { + return (Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -4: + if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + } + } + #endif + return PyLong_AsSsize_t(b); + } + x = PyNumber_Index(b); + if (!x) return -1; + ival = PyInt_AsSsize_t(x); + Py_DECREF(x); + return ival; +} +static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject* o) { + if (sizeof(Py_hash_t) == sizeof(Py_ssize_t)) { + return (Py_hash_t) __Pyx_PyIndex_AsSsize_t(o); +#if PY_MAJOR_VERSION < 3 + } else if (likely(PyInt_CheckExact(o))) { + return PyInt_AS_LONG(o); +#endif + } else { + Py_ssize_t ival; + PyObject *x; + x = PyNumber_Index(o); + if (!x) return -1; + ival = PyInt_AsLong(x); + Py_DECREF(x); + return ival; + } +} +static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) { + return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False); +} +static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t ival) { + return PyInt_FromSize_t(ival); +} + + +#endif /* Py_PYTHON_H */ diff --git a/SiamMask/utils/pysot/utils/region.cpython-39-x86_64-linux-gnu.so b/SiamMask/utils/pysot/utils/region.cpython-39-x86_64-linux-gnu.so new file mode 100644 index 0000000000000000000000000000000000000000..40140ad49c91e244da8ddb496ed2bd532bc57f36 Binary files /dev/null and b/SiamMask/utils/pysot/utils/region.cpython-39-x86_64-linux-gnu.so differ diff --git a/SiamMask/utils/pysot/utils/region.pyx b/SiamMask/utils/pysot/utils/region.pyx new file mode 100644 index 0000000000000000000000000000000000000000..df7748d543cb7bed10478e97a8434ec081bac47e --- /dev/null +++ b/SiamMask/utils/pysot/utils/region.pyx @@ -0,0 +1,230 @@ +# -------------------------------------------------------- +# Python Single Object Tracking Evaluation +# Licensed under The MIT License [see LICENSE for details] +# Written by Fangyi Zhang +# @author fangyi.zhang@vipl.ict.ac.cn +# @project https://github.com/StrangerZhang/pysot-toolkit.git +# Revised for SiamMask by foolwood +# -------------------------------------------------------- + +# distutils: sources = src/region.c +# distutils: include_dirs = src/ + +from libc.stdlib cimport malloc, free +from libc.stdio cimport sprintf +from libc.string cimport strlen + +cimport c_region + +cpdef enum RegionType: + EMTPY + SPECIAL + RECTANGEL + POLYGON + MASK + +cdef class RegionBounds: + cdef c_region.region_bounds* _c_region_bounds + + def __cinit__(self): + self._c_region_bounds = malloc( + sizeof(c_region.region_bounds)) + if not self._c_region_bounds: + self._c_region_bounds = NULL + raise MemoryError() + + def __init__(self, top, bottom, left, right): + self.set(top, bottom, left, right) + + def __dealloc__(self): + if self._c_region_bounds is not NULL: + free(self._c_region_bounds) + self._c_region_bounds = NULL + + def __str__(self): + return "top: {:.3f} bottom: {:.3f} left: {:.3f} reight: {:.3f}".format( + self._c_region_bounds.top, + self._c_region_bounds.bottom, + self._c_region_bounds.left, + self._c_region_bounds.right) + + def get(self): + return (self._c_region_bounds.top, + self._c_region_bounds.bottom, + self._c_region_bounds.left, + self._c_region_bounds.right) + + def set(self, top, bottom, left, right): + self._c_region_bounds.top = top + self._c_region_bounds.bottom = bottom + self._c_region_bounds.left = left + self._c_region_bounds.right = right + +cdef class Rectangle: + cdef c_region.region_rectangle* _c_region_rectangle + + def __cinit__(self): + self._c_region_rectangle = malloc( + sizeof(c_region.region_rectangle)) + if not self._c_region_rectangle: + self._c_region_rectangle = NULL + raise MemoryError() + + def __init__(self, x, y, width, height): + self.set(x, y, width, height) + + def __dealloc__(self): + if self._c_region_rectangle is not NULL: + free(self._c_region_rectangle) + self._c_region_rectangle = NULL + + def __str__(self): + return "x: {:.3f} y: {:.3f} width: {:.3f} height: {:.3f}".format( + self._c_region_rectangle.x, + self._c_region_rectangle.y, + self._c_region_rectangle.width, + self._c_region_rectangle.height) + + def set(self, x, y, width, height): + self._c_region_rectangle.x = x + self._c_region_rectangle.y = y + self._c_region_rectangle.width = width + self._c_region_rectangle.height = height + + def get(self): + """ + return: + (x, y, width, height) + """ + return (self._c_region_rectangle.x, + self._c_region_rectangle.y, + self._c_region_rectangle.width, + self._c_region_rectangle.height) + +cdef class Polygon: + cdef c_region.region_polygon* _c_region_polygon + + def __cinit__(self, points): + """ + args: + points: tuple of point + points = ((1, 1), (10, 10)) + """ + num = len(points) // 2 + self._c_region_polygon = malloc( + sizeof(c_region.region_polygon)) + if not self._c_region_polygon: + self._c_region_polygon = NULL + raise MemoryError() + self._c_region_polygon.count = num + self._c_region_polygon.x = malloc(sizeof(float) * num) + if not self._c_region_polygon.x: + raise MemoryError() + self._c_region_polygon.y = malloc(sizeof(float) * num) + if not self._c_region_polygon.y: + raise MemoryError() + + for i in range(num): + self._c_region_polygon.x[i] = points[i*2] + self._c_region_polygon.y[i] = points[i*2+1] + + def __dealloc__(self): + if self._c_region_polygon is not NULL: + if self._c_region_polygon.x is not NULL: + free(self._c_region_polygon.x) + self._c_region_polygon.x = NULL + if self._c_region_polygon.y is not NULL: + free(self._c_region_polygon.y) + self._c_region_polygon.y = NULL + free(self._c_region_polygon) + self._c_region_polygon = NULL + + def __str__(self): + ret = "" + for i in range(self._c_region_polygon.count-1): + ret += "({:.3f} {:.3f}) ".format(self._c_region_polygon.x[i], + self._c_region_polygon.y[i]) + ret += "({:.3f} {:.3f})".format(self._c_region_polygon.x[i], + self._c_region_polygon.y[i]) + return ret + +def vot_overlap(polygon1, polygon2, bounds=None): + """ computing overlap between two polygon + Args: + polygon1: polygon tuple of points + polygon2: polygon tuple of points + bounds: tuple of (left, top, right, bottom) or tuple of (width height) + Return: + overlap: overlap between two polygons + """ + if len(polygon1) == 1 or len(polygon2) == 1: + return float("nan") + + if len(polygon1) == 4: + polygon1_ = Polygon([polygon1[0], polygon1[1], + polygon1[0]+polygon1[2], polygon1[1], + polygon1[0]+polygon1[2], polygon1[1]+polygon1[3], + polygon1[0], polygon1[1]+polygon1[3]]) + else: + polygon1_ = Polygon(polygon1) + + if len(polygon2) == 4: + polygon2_ = Polygon([polygon2[0], polygon2[1], + polygon2[0]+polygon2[2], polygon2[1], + polygon2[0]+polygon2[2], polygon2[1]+polygon2[3], + polygon2[0], polygon2[1]+polygon2[3]]) + else: + polygon2_ = Polygon(polygon2) + + if bounds is not None and len(bounds) == 4: + pno_bounds = RegionBounds(bounds[0], bounds[1], bounds[2], bounds[3]) + elif bounds is not None and len(bounds) == 2: + pno_bounds = RegionBounds(0, bounds[1], 0, bounds[0]) + else: + pno_bounds = RegionBounds(-float("inf"), float("inf"), + -float("inf"), float("inf")) + cdef float only1 = 0 + cdef float only2 = 0 + cdef c_region.region_polygon* c_polygon1 = polygon1_._c_region_polygon + cdef c_region.region_polygon* c_polygon2 = polygon2_._c_region_polygon + cdef c_region.region_bounds no_bounds = pno_bounds._c_region_bounds[0] # deference + return c_region.compute_polygon_overlap(c_polygon1, + c_polygon2, + &only1, + &only2, + no_bounds) + +def vot_overlap_traj(polygons1, polygons2, bounds=None): + """ computing overlap between two trajectory + Args: + polygons1: list of polygon + polygons2: list of polygon + bounds: tuple of (left, top, right, bottom) or tuple of (width height) + Return: + overlaps: overlaps between all pair of polygons + """ + assert len(polygons1) == len(polygons2) + overlaps = [] + for i in range(len(polygons1)): + overlap = vot_overlap(polygons1[i], polygons2[i], bounds=bounds) + overlaps.append(overlap) + return overlaps + + +def vot_float2str(template, float value): + """ + Args: + tempate: like "%.3f" in C syntax + value: float value + """ + cdef bytes ptemplate = template.encode() + cdef const char* ctemplate = ptemplate + cdef char* output = malloc(sizeof(char) * 100) + if not output: + raise MemoryError() + sprintf(output, ctemplate, value) + try: + ret = output[:strlen(output)].decode() + finally: + free(output) + return ret diff --git a/SiamMask/utils/pysot/utils/setup.py b/SiamMask/utils/pysot/utils/setup.py new file mode 100644 index 0000000000000000000000000000000000000000..f5123e9961badda98dac4b76f6273095f540c52b --- /dev/null +++ b/SiamMask/utils/pysot/utils/setup.py @@ -0,0 +1,16 @@ +# -------------------------------------------------------- +# Python Single Object Tracking Evaluation +# Licensed under The MIT License [see LICENSE for details] +# Written by Fangyi Zhang +# @author fangyi.zhang@vipl.ict.ac.cn +# @project https://github.com/StrangerZhang/pysot-toolkit.git +# Revised for SiamMask by foolwood +# -------------------------------------------------------- +from distutils.core import setup +from distutils.extension import Extension +from Cython.Build import cythonize + +setup( + ext_modules = cythonize([Extension("region", ["region.pyx", "src/region.c"])]), +) + diff --git a/SiamMask/utils/pysot/utils/src/buffer.h b/SiamMask/utils/pysot/utils/src/buffer.h new file mode 100644 index 0000000000000000000000000000000000000000..99986afb7c0c2d66dd4d3341d9446725975f6e8f --- /dev/null +++ b/SiamMask/utils/pysot/utils/src/buffer.h @@ -0,0 +1,190 @@ + +#ifndef __STRING_BUFFER_H +#define __STRING_BUFFER_H + +// Enable MinGW secure API for _snprintf_s +#define MINGW_HAS_SECURE_API 1 + +#ifdef _MSC_VER +#define __INLINE __inline +#else +#define __INLINE inline +#endif + +#include +#include +#include + +typedef struct string_buffer { + char* buffer; + int position; + int size; +} string_buffer; + +typedef struct string_list { + char** buffer; + int position; + int size; +} string_list; + +#define BUFFER_INCREMENT_STEP 4096 + +static __INLINE string_buffer* buffer_create(int L) { + string_buffer* B = (string_buffer*) malloc(sizeof(string_buffer)); + B->size = L; + B->buffer = (char*) malloc(sizeof(char) * B->size); + B->position = 0; + return B; +} + +static __INLINE void buffer_reset(string_buffer* B) { + B->position = 0; +} + +static __INLINE void buffer_destroy(string_buffer** B) { + if (!(*B)) return; + if ((*B)->buffer) { + free((*B)->buffer); + (*B)->buffer = NULL; + } + free((*B)); + (*B) = NULL; +} + +static __INLINE char* buffer_extract(const string_buffer* B) { + char *S = (char*) malloc(sizeof(char) * (B->position + 1)); + memcpy(S, B->buffer, B->position); + S[B->position] = '\0'; + return S; +} + +static __INLINE int buffer_size(const string_buffer* B) { + return B->position; +} + +static __INLINE void buffer_push(string_buffer* B, char C) { + int required = 1; + if (required > B->size - B->position) { + B->size = B->position + BUFFER_INCREMENT_STEP; + B->buffer = (char*) realloc(B->buffer, sizeof(char) * B->size); + } + B->buffer[B->position] = C; + B->position += required; +} + +static __INLINE void buffer_append(string_buffer* B, const char *format, ...) { + + int required; + va_list args; + +#if defined(__OS2__) || defined(__WINDOWS__) || defined(WIN32) || defined(_MSC_VER) + + va_start(args, format); + required = _vscprintf(format, args) + 1; + va_end(args); + if (required >= B->size - B->position) { + B->size = B->position + required + 1; + B->buffer = (char*) realloc(B->buffer, sizeof(char) * B->size); + } + va_start(args, format); + required = _vsnprintf_s(&(B->buffer[B->position]), B->size - B->position, _TRUNCATE, format, args); + va_end(args); + B->position += required; + +#else + va_start(args, format); + required = vsnprintf(&(B->buffer[B->position]), B->size - B->position, format, args); + va_end(args); + if (required >= B->size - B->position) { + B->size = B->position + required + 1; + B->buffer = (char*) realloc(B->buffer, sizeof(char) * B->size); + va_start(args, format); + required = vsnprintf(&(B->buffer[B->position]), B->size - B->position, format, args); + va_end(args); + } + B->position += required; +#endif + +} + +static __INLINE string_list* list_create(int L) { + string_list* B = (string_list*) malloc(sizeof(string_list)); + B->size = L; + B->buffer = (char**) malloc(sizeof(char*) * B->size); + memset(B->buffer, 0, sizeof(char*) * B->size); + B->position = 0; + return B; +} + +static __INLINE void list_reset(string_list* B) { + int i; + for (i = 0; i < B->position; i++) { + if (B->buffer[i]) free(B->buffer[i]); + B->buffer[i] = NULL; + } + B->position = 0; +} + +static __INLINE void list_destroy(string_list **B) { + int i; + + if (!(*B)) return; + + for (i = 0; i < (*B)->position; i++) { + if ((*B)->buffer[i]) free((*B)->buffer[i]); (*B)->buffer[i] = NULL; + } + + if ((*B)->buffer) { + free((*B)->buffer); (*B)->buffer = NULL; + } + + free((*B)); + (*B) = NULL; +} + +static __INLINE char* list_get(const string_list *B, int I) { + if (I < 0 || I >= B->position) { + return NULL; + } else { + if (!B->buffer[I]) { + return NULL; + } else { + char *S; + int length = strlen(B->buffer[I]); + S = (char*) malloc(sizeof(char) * (length + 1)); + memcpy(S, B->buffer[I], length + 1); + return S; + } + } +} + +static __INLINE int list_size(const string_list *B) { + return B->position; +} + +static __INLINE void list_append(string_list *B, char* S) { + int required = 1; + int length = strlen(S); + if (required > B->size - B->position) { + B->size = B->position + 16; + B->buffer = (char**) realloc(B->buffer, sizeof(char*) * B->size); + } + B->buffer[B->position] = (char*) malloc(sizeof(char) * (length + 1)); + memcpy(B->buffer[B->position], S, length + 1); + B->position += required; +} + +// This version of the append does not copy the string but simply takes the control of its allocation +static __INLINE void list_append_direct(string_list *B, char* S) { + int required = 1; + // int length = strlen(S); + if (required > B->size - B->position) { + B->size = B->position + 16; + B->buffer = (char**) realloc(B->buffer, sizeof(char*) * B->size); + } + B->buffer[B->position] = S; + B->position += required; +} + + +#endif diff --git a/SiamMask/utils/pysot/utils/src/region.c b/SiamMask/utils/pysot/utils/src/region.c new file mode 100644 index 0000000000000000000000000000000000000000..b91c43b6f5885e082b2bb88ed7dff0d0f295e911 --- /dev/null +++ b/SiamMask/utils/pysot/utils/src/region.c @@ -0,0 +1,1033 @@ + +#include +#include +#include +#include +#include +#include +#include + +#include "region.h" +#include "buffer.h" + +#if defined(__OS2__) || defined(__WINDOWS__) || defined(WIN32) || defined(_MSC_VER) +#ifndef isnan +#define isnan(x) _isnan(x) +#endif +#ifndef isinf +#define isinf(x) (!_finite(x)) +#endif +#ifndef inline +#define inline _inline +#endif +#endif + +/* Visual Studio 2013 was first to add C99 INFINITY and NAN */ +#if defined (_MSC_VER) && _MSC_VER < 1800 +#define INFINITY (DBL_MAX+DBL_MAX) +#define NAN (INFINITY-INFINITY) +#define round(fp) (int)((fp) >= 0 ? (fp) + 0.5 : (fp) - 0.5) +#endif + +#define PRINT_BOUNDS(B) printf("[left: %.2f, top: %.2f, right: %.2f, bottom: %.2f]\n", B.left, B.top, B.right, B.bottom) + +const region_bounds region_no_bounds = { -FLT_MAX, FLT_MAX, -FLT_MAX, FLT_MAX }; + +int __flags = 0; + +int region_set_flags(int mask) { + + __flags |= mask; + + return __flags; + +} + +int region_clear_flags(int mask) { + + __flags &= ~mask; + + return __flags; + +} + +int __is_valid_sequence(float* sequence, int len) { + int i; + + for (i = 0; i < len; i++) { + if (isnan(sequence[i])) return 0; + } + + return 1; +} + + +#define MAX_URI_SCHEME 16 + +const char* __parse_uri_prefix(const char* buffer, region_type* type) { + + int i = 0; + + *type = EMPTY; + + for (; i < MAX_URI_SCHEME; i++) { + if ((buffer[i] >= 'a' && buffer[i] <= 'z') || buffer[i] == '+' || buffer[i] == '.' || buffer[i] == '-') continue; + + if (buffer[i] == ':') { + if (strncmp(buffer, "rect", i - 1) == 0) + *type = RECTANGLE; + else if (strncmp(buffer, "poly", i - 1) == 0) + *type = POLYGON; + else if (strncmp(buffer, "mask", i - 1) == 0) + *type = MASK; + else if (strncmp(buffer, "special", i - 1) == 0) + *type = SPECIAL; + return &(buffer[i + 1]); + } + + return buffer; + } + + return buffer; + +} + +region_container* __create_region(region_type type) { + + region_container* reg = (region_container*) malloc(sizeof(region_container)); + + reg->type = type; + + return reg; + +} + +static inline const char* _str_find(const char* in, const char delimiter) { + + int i = 0; + while (in[i] && in[i] != delimiter) { + i++; + } + + return (in[i] == delimiter) ? &(in[i]) + 1 : NULL; + +} + +int _parse_sequence(const char* buffer, float** data) { + + int i; + + float* numbers = (float*) malloc(sizeof(float) * (strlen(buffer) / 2)); + + const char* pch = buffer; + for (i = 0; ; i++) { + + if (pch) { +#if defined (_MSC_VER) + if (tolower(pch[0]) == 'n' && tolower(pch[1]) == 'a' && tolower(pch[2]) == 'n') { + numbers[i] = NAN; + } else { + numbers[i] = (float) atof(pch); + } +#else + numbers[i] = (float) atof(pch); +#endif + } else + break; + + pch = _str_find(pch, ','); + } + + if (i > 0) { + int j; + *data = (float*) malloc(sizeof(float) * i); + for (j = 0; j < i; j++) { (*data)[j] = numbers[j]; } + free(numbers); + } else { + *data = NULL; + free(numbers); + } + + return i; +} + +int region_parse(const char* buffer, region_container** region) { + + float* data = NULL; + const char* strdata = NULL; + int num; + + region_type prefix_type; + + // const char* tmp = buffer; + + (*region) = NULL; + + if (!buffer || !buffer[0]) { + return 1; + } + + strdata = __parse_uri_prefix(buffer, &prefix_type); + + num = _parse_sequence(strdata, &data); + + // If at least one of the elements is NaN, then the region cannot be parsed + // We return special region with a default code. + if (!__is_valid_sequence(data, num) || num == 0) { + // Preserve legacy support: if four values are given and the fourth one is a number + // then this number is taken as a code. + if (num == 4 && !isnan(data[3])) { + (*region) = region_create_special(-(int) data[3]); + } else { + (*region) = region_create_special(TRAX_DEFAULT_CODE); + } + free(data); + return 1; + } + + if (prefix_type == EMPTY && num > 0) { + if (num == 1) + prefix_type = SPECIAL; + else if (num == 4) + prefix_type = RECTANGLE; + else if (num >= 6 && num % 2 == 0) + prefix_type = POLYGON; + } + + switch (prefix_type) { + case SPECIAL: { + assert(num == 1); + (*region) = (region_container*) malloc(sizeof(region_container)); + (*region)->type = SPECIAL; + (*region)->data.special = (int) data[0]; + free(data); + return 1; + + } + case RECTANGLE: { + assert(num == 4); + (*region) = (region_container*) malloc(sizeof(region_container)); + (*region)->type = RECTANGLE; + + (*region)->data.rectangle.x = data[0]; + (*region)->data.rectangle.y = data[1]; + (*region)->data.rectangle.width = data[2]; + (*region)->data.rectangle.height = data[3]; + + free(data); + return 1; + + } + case POLYGON: { + int j; + + assert(num >= 6 && num % 2 == 0); + + (*region) = (region_container*) malloc(sizeof(region_container)); + (*region)->type = POLYGON; + + (*region)->data.polygon.count = num / 2; + (*region)->data.polygon.x = (float*) malloc(sizeof(float) * (*region)->data.polygon.count); + (*region)->data.polygon.y = (float*) malloc(sizeof(float) * (*region)->data.polygon.count); + + for (j = 0; j < (*region)->data.polygon.count; j++) { + (*region)->data.polygon.x[j] = data[j * 2]; + (*region)->data.polygon.y[j] = data[j * 2 + 1]; + } + + free(data); + return 1; + case EMPTY: + return 1; + case MASK: + return 1; + } + /* case MASK: { + + int i; + int position; + int value; + + assert(num > 4); + + (*region) = (region_container*) malloc(sizeof(region_container)); + (*region)->type = MASK; + + (*region)->data.mask.x = (int) data[0]; + (*region)->data.mask.y = (int) data[1]; + (*region)->data.mask.width = (int) data[2]; + (*region)->data.mask.height = (int) data[3]; + + (*region)->data.mask.data = (char*) malloc(sizeof(char) * (*region)->data.mask.width * (*region)->data.mask.height); + + value = 0; + position = 0; + + for (i = 4; i < num; i++) { + + int count = + + + + + } + + + }*/ + } + + if (data) free(data); + + return 0; +} + +char* region_string(region_container* region) { + + int i; + char* result = NULL; + string_buffer *buffer; + + if (!region) return NULL; + + buffer = buffer_create(32); + + if (region->type == SPECIAL) { + + buffer_append(buffer, "%d", region->data.special); + + } else if (region->type == RECTANGLE) { + + buffer_append(buffer, "%.4f,%.4f,%.4f,%.4f", + region->data.rectangle.x, region->data.rectangle.y, + region->data.rectangle.width, region->data.rectangle.height); + + } else if (region->type == POLYGON) { + + for (i = 0; i < region->data.polygon.count; i++) { + buffer_append(buffer, (i == 0 ? "%.4f,%.4f" : ",%.4f,%.4f"), region->data.polygon.x[i], region->data.polygon.y[i]); + } + } + + if (buffer_size(buffer) > 0) + result = buffer_extract(buffer); + buffer_destroy(&buffer); + + return result; +} + +void region_print(FILE* out, region_container* region) { + + char* buffer = region_string(region); + + if (buffer) { + fputs(buffer, out); + free(buffer); + } + +} + +region_container* region_convert(const region_container* region, region_type type) { + + region_container* reg = NULL; + switch (type) { + + case RECTANGLE: { + + reg = (region_container*) malloc(sizeof(region_container)); + reg->type = type; + + switch (region->type) { + case RECTANGLE: + reg->data.rectangle = region->data.rectangle; + break; + case POLYGON: { + + float top = FLT_MAX; + float bottom = FLT_MIN; + float left = FLT_MAX; + float right = FLT_MIN; + int i; + + for (i = 0; i < region->data.polygon.count; i++) { + top = MIN(top, region->data.polygon.y[i]); + bottom = MAX(bottom, region->data.polygon.y[i]); + left = MIN(left, region->data.polygon.x[i]); + right = MAX(right, region->data.polygon.x[i]); + } + + reg->data.rectangle.x = left; + reg->data.rectangle.y = top; + reg->data.rectangle.width = right - left; + reg->data.rectangle.height = bottom - top; + break; + } + case SPECIAL: { + free(reg); reg = NULL; + break; + } + default: { + free(reg); reg = NULL; + break; + } + } + break; + } + + case POLYGON: { + + reg = (region_container*) malloc(sizeof(region_container)); + reg->type = type; + + switch (region->type) { + case RECTANGLE: { + + reg->data.polygon.count = 4; + + reg->data.polygon.x = (float *) malloc(sizeof(float) * reg->data.polygon.count); + reg->data.polygon.y = (float *) malloc(sizeof(float) * reg->data.polygon.count); + + if (__flags & REGION_LEGACY_RASTERIZATION) { + + reg->data.polygon.x[0] = region->data.rectangle.x; + reg->data.polygon.x[1] = region->data.rectangle.x + region->data.rectangle.width; + reg->data.polygon.x[2] = region->data.rectangle.x + region->data.rectangle.width; + reg->data.polygon.x[3] = region->data.rectangle.x; + + reg->data.polygon.y[0] = region->data.rectangle.y; + reg->data.polygon.y[1] = region->data.rectangle.y; + reg->data.polygon.y[2] = region->data.rectangle.y + region->data.rectangle.height; + reg->data.polygon.y[3] = region->data.rectangle.y + region->data.rectangle.height; + + } else { + + reg->data.polygon.x[0] = region->data.rectangle.x; + reg->data.polygon.x[1] = region->data.rectangle.x + region->data.rectangle.width - 1; + reg->data.polygon.x[2] = region->data.rectangle.x + region->data.rectangle.width - 1; + reg->data.polygon.x[3] = region->data.rectangle.x; + + reg->data.polygon.y[0] = region->data.rectangle.y; + reg->data.polygon.y[1] = region->data.rectangle.y; + reg->data.polygon.y[2] = region->data.rectangle.y + region->data.rectangle.height - 1; + reg->data.polygon.y[3] = region->data.rectangle.y + region->data.rectangle.height - 1; + + } + + break; + } + case POLYGON: { + + reg->data.polygon.count = region->data.polygon.count; + + reg->data.polygon.x = (float *) malloc(sizeof(float) * region->data.polygon.count); + reg->data.polygon.y = (float *) malloc(sizeof(float) * region->data.polygon.count); + + memcpy(reg->data.polygon.x, region->data.polygon.x, sizeof(float) * region->data.polygon.count); + memcpy(reg->data.polygon.y, region->data.polygon.y, sizeof(float) * region->data.polygon.count); + + break; + } + case SPECIAL: { + free(reg); reg = NULL; + break; + } + default: { + free(reg); reg = NULL; + break; + } + } + break; + + case SPECIAL: { + if (region->type == SPECIAL) + // If source is also code then just copy the value + reg = region_create_special(region->data.special); + else + // All types are converted to default region + reg = region_create_special(TRAX_DEFAULT_CODE); + break; + } + + default: + break; + + } + + } + + return reg; + +} + +void region_release(region_container** region) { + + switch ((*region)->type) { + case RECTANGLE: + break; + case POLYGON: + free((*region)->data.polygon.x); + free((*region)->data.polygon.y); + (*region)->data.polygon.count = 0; + break; + case SPECIAL: { + break; + } + case MASK: + break; + case EMPTY: + break; + } + + free(*region); + + *region = NULL; + +} + +region_container* region_create_special(int code) { + + region_container* reg = __create_region(SPECIAL); + + reg->data.special = code; + + return reg; + +} + +region_container* region_create_rectangle(float x, float y, float width, float height) { + + region_container* reg = __create_region(RECTANGLE); + + reg->data.rectangle.width = width; + reg->data.rectangle.height = height; + reg->data.rectangle.x = x; + reg->data.rectangle.y = y; + + return reg; + +} + +region_container* region_create_polygon(int count) { + + assert(count > 0); + + { + + region_container* reg = __create_region(POLYGON); + + reg->data.polygon.count = count; + reg->data.polygon.x = (float *) malloc(sizeof(float) * count); + reg->data.polygon.y = (float *) malloc(sizeof(float) * count); + + return reg; + + } +} + +#define MAX_MASK 10000 + +void free_polygon(region_polygon* polygon) { + + free(polygon->x); + free(polygon->y); + + polygon->x = NULL; + polygon->y = NULL; + + polygon->count = 0; + +} + +region_polygon* allocate_polygon(int count) { + + region_polygon* polygon = (region_polygon*) malloc(sizeof(region_polygon)); + + polygon->count = count; + + polygon->x = (float*) malloc(sizeof(float) * count); + polygon->y = (float*) malloc(sizeof(float) * count); + + memset(polygon->x, 0, sizeof(float) * count); + memset(polygon->y, 0, sizeof(float) * count); + + return polygon; +} + +region_polygon* clone_polygon(const region_polygon* polygon) { + + region_polygon* clone = allocate_polygon(polygon->count); + + memcpy(clone->x, polygon->x, sizeof(float) * polygon->count); + memcpy(clone->y, polygon->y, sizeof(float) * polygon->count); + + return clone; +} + +region_polygon* offset_polygon(const region_polygon* polygon, float x, float y) { + + int i; + region_polygon* clone = clone_polygon(polygon); + + for (i = 0; i < clone->count; i++) { + clone->x[i] += x; + clone->y[i] += y; + } + + return clone; +} + +region_polygon* round_polygon(const region_polygon* polygon) { + + int i; + region_polygon* clone = clone_polygon(polygon); + + for (i = 0; i < clone->count; i++) { + clone->x[i] = round(clone->x[i]); + clone->y[i] = round(clone->y[i]); + } + + return clone; +} + +int point_in_polygon(const region_polygon* polygon, float x, float y) { + int i, j, c = 0; + for (i = 0, j = polygon->count - 1; i < polygon->count; j = i++) { + if ( ((polygon->y[i] > y) != (polygon->y[j] > y)) && + (x < (polygon->x[j] - polygon->x[i]) * (y - polygon->y[i]) / (polygon->y[j] - polygon->y[i]) + polygon->x[i]) ) + c = !c; + } + return c; +} + +void print_polygon(const region_polygon* polygon) { + + int i; + printf("%d:", polygon->count); + + for (i = 0; i < polygon->count; i++) { + printf(" (%f, %f)", polygon->x[i], polygon->y[i]); + } + + printf("\n"); + +} + +region_bounds compute_bounds(const region_polygon* polygon) { + + int i; + region_bounds bounds; + bounds.top = FLT_MAX; + bounds.bottom = -FLT_MAX; + bounds.left = FLT_MAX; + bounds.right = -FLT_MAX; + + for (i = 0; i < polygon->count; i++) { + bounds.top = MIN(bounds.top, polygon->y[i]); + bounds.bottom = MAX(bounds.bottom, polygon->y[i]); + bounds.left = MIN(bounds.left, polygon->x[i]); + bounds.right = MAX(bounds.right, polygon->x[i]); + } + + return bounds; + +} + +region_bounds bounds_round(region_bounds bounds) { + + bounds.top = floor(bounds.top); + bounds.bottom = ceil(bounds.bottom); + bounds.left = floor(bounds.left); + bounds.right = ceil(bounds.right); + + return bounds; + +} + +region_bounds bounds_intersection(region_bounds a, region_bounds b) { + + region_bounds result; + + result.top = MAX(a.top, b.top); + result.bottom = MIN(a.bottom, b.bottom); + result.left = MAX(a.left, b.left); + result.right = MIN(a.right, b.right); + + return result; + +} + +region_bounds bounds_union(region_bounds a, region_bounds b) { + + region_bounds result; + + result.top = MIN(a.top, b.top); + result.bottom = MAX(a.bottom, b.bottom); + result.left = MIN(a.left, b.left); + result.right = MAX(a.right, b.right); + + return result; + +} + +float bounds_overlap(region_bounds a, region_bounds b) { + + region_bounds rintersection = bounds_intersection(a, b); + float intersection = (rintersection.right - rintersection.left) * (rintersection.bottom - rintersection.top); + + return MAX(0, intersection / (((a.right - a.left) * (a.bottom - a.top)) + ((b.right - b.left) * (b.bottom - b.top)) - intersection)); + +} + +region_bounds region_create_bounds(float left, float top, float right, float bottom) { + + region_bounds result; + + result.top = top; + result.bottom = bottom; + result.left = left; + result.right = right; + + return result; +} + +region_bounds region_compute_bounds(const region_container* region) { + + region_bounds bounds; + switch (region->type) { + case RECTANGLE: + if (__flags & REGION_LEGACY_RASTERIZATION) { + bounds = region_create_bounds(region->data.rectangle.x, + region->data.rectangle.y, + region->data.rectangle.x + region->data.rectangle.width, + region->data.rectangle.y + region->data.rectangle.height); + } else { + bounds = region_create_bounds(region->data.rectangle.x, + region->data.rectangle.y, + region->data.rectangle.x + region->data.rectangle.width - 1, + region->data.rectangle.y + region->data.rectangle.height - 1); + } + break; + case POLYGON: { + bounds = compute_bounds(&(region->data.polygon)); + break; + } + default: { + bounds = region_no_bounds; + break; + } + } + + return bounds; + +} + +int rasterize_polygon(const region_polygon* polygon_input, char* mask, int width, int height) { + + int nodes, pixelY, i, j, swap; + int sum = 0; + region_polygon* polygon = (region_polygon*) polygon_input; + + int* nodeX = (int*) malloc(sizeof(int) * polygon->count); + + if (mask) memset(mask, 0, width * height * sizeof(char)); + + if (__flags & REGION_LEGACY_RASTERIZATION) { + + /* Loop through the rows of the image. */ + for (pixelY = 0; pixelY < height; pixelY++) { + + /* Build a list of nodes. */ + nodes = 0; + j = polygon->count - 1; + + for (i = 0; i < polygon->count; i++) { + if (((polygon->y[i] < (double) pixelY) && (polygon->y[j] >= (double) pixelY)) || + ((polygon->y[j] < (double) pixelY) && (polygon->y[i] >= (double) pixelY))) { + nodeX[nodes++] = (int) (polygon->x[i] + (pixelY - polygon->y[i]) / + (polygon->y[j] - polygon->y[i]) * (polygon->x[j] - polygon->x[i])); + } + j = i; + } + + /* Sort the nodes, via a simple “Bubble” sort. */ + i = 0; + while (i < nodes - 1) { + if (nodeX[i] > nodeX[i + 1]) { + swap = nodeX[i]; + nodeX[i] = nodeX[i + 1]; + nodeX[i + 1] = swap; + if (i) i--; + } else { + i++; + } + } + + /* Fill the pixels between node pairs. */ + for (i = 0; i < nodes; i += 2) { + if (nodeX[i] >= width) break; + if (nodeX[i + 1] > 0 ) { + if (nodeX[i] < 0 ) nodeX[i] = 0; + if (nodeX[i + 1] > width) nodeX[i + 1] = width - 1; + for (j = nodeX[i]; j < nodeX[i + 1]; j++) { + if (mask) mask[pixelY * width + j] = 1; + sum++; + } + } + } + } + + } else { + + polygon = round_polygon(polygon_input); + + /* Loop through the rows of the image. */ + for (pixelY = 0; pixelY < height; pixelY++) { + + /* Build a list of nodes. */ + nodes = 0; + j = polygon->count - 1; + + for (i = 0; i < polygon->count; i++) { + if ((((int)polygon->y[i] <= pixelY) && ((int)polygon->y[j] > pixelY)) || + (((int)polygon->y[j] <= pixelY) && ((int)polygon->y[i] > pixelY)) || + (((int)polygon->y[i] < pixelY) && ((int)polygon->y[j] >= pixelY)) || + (((int)polygon->y[j] < pixelY) && ((int)polygon->y[i] >= pixelY)) || + (((int)polygon->y[i] == (int)polygon->y[j]) && ((int)polygon->y[i] == pixelY))) { + double r = (polygon->y[j] - polygon->y[i]); + double k = (polygon->x[j] - polygon->x[i]); + if (r != 0) + nodeX[nodes++] = (int) ((double) polygon->x[i] + (double) (pixelY - polygon->y[i]) / r * k); + } + j = i; + } + /* Sort the nodes, via a simple “Bubble” sort. */ + i = 0; + while (i < nodes - 1) { + if (nodeX[i] > nodeX[i + 1]) { + swap = nodeX[i]; + nodeX[i] = nodeX[i + 1]; + nodeX[i + 1] = swap; + if (i) i--; + } else { + i++; + } + } + + /* Fill the pixels between node pairs. */ + i = 0; + while (i < nodes - 1) { + // If a point is in the line then we get two identical values + // Ignore the first + if (nodeX[i] == nodeX[i + 1]) { + i++; + continue; + } + + if (nodeX[i] >= width) break; + if (nodeX[i + 1] >= 0) { + if (nodeX[i] < 0) nodeX[i] = 0; + if (nodeX[i + 1] >= width) nodeX[i + 1] = width - 1; + for (j = nodeX[i]; j <= nodeX[i + 1]; j++) { + if (mask) mask[pixelY * width + j] = 1; + sum++; + } + } + i += 2; + + } + } + + free_polygon(polygon); + + } + + free(nodeX); + + return sum; +} + +float compute_polygon_overlap(const region_polygon* p1, const region_polygon* p2, float *only1, float *only2, region_bounds bounds) { + + int i; + int vol_1 = 0; + int vol_2 = 0; + int mask_1 = 0; + int mask_2 = 0; + int mask_intersect = 0; + char* mask1 = NULL; + char* mask2 = NULL; + double a1, a2; + float x, y; + int width, height; + region_polygon *op1, *op2; + region_bounds b1, b2; + + if (__flags & REGION_LEGACY_RASTERIZATION) { + b1 = bounds_intersection(compute_bounds(p1), bounds); + b2 = bounds_intersection(compute_bounds(p2), bounds); + } else { + b1 = bounds_intersection(bounds_round(compute_bounds(p1)), bounds); + b2 = bounds_intersection(bounds_round(compute_bounds(p2)), bounds); + } + + x = MIN(b1.left, b2.left); + y = MIN(b1.top, b2.top); + + width = (int) (MAX(b1.right, b2.right) - x) + 1; + height = (int) (MAX(b1.bottom, b2.bottom) - y) + 1; + + // Fixing crashes due to overflowed regions, a simple check if the ratio + // between the two bounding boxes is simply too big and the overlap would + // be 0 anyway. + + a1 = (b1.right - b1.left) * (b1.bottom - b1.top); + a2 = (b2.right - b2.left) * (b2.bottom - b2.top); + + if (a1 / a2 < 1e-10 || a2 / a1 < 1e-10 || width < 1 || height < 1) { + + if (only1) + (*only1) = 0; + + if (only2) + (*only2) = 0; + + return 0; + + } + + if (bounds_overlap(b1, b2) == 0) { + + if (only1 || only2) { + vol_1 = rasterize_polygon(p1, NULL, b1.right - b1.left + 1, b1.bottom - b1.top + 1); + vol_2 = rasterize_polygon(p2, NULL, b2.right - b2.left + 1, b2.bottom - b2.top + 1); + + if (only1) + (*only1) = (float) vol_1 / (float) (vol_1 + vol_2); + + if (only2) + (*only2) = (float) vol_2 / (float) (vol_1 + vol_2); + } + + return 0; + + } + + mask1 = (char*) malloc(sizeof(char) * width * height); + mask2 = (char*) malloc(sizeof(char) * width * height); + + op1 = offset_polygon(p1, -x, -y); + op2 = offset_polygon(p2, -x, -y); + + rasterize_polygon(op1, mask1, width, height); + rasterize_polygon(op2, mask2, width, height); + + for (i = 0; i < width * height; i++) { + if (mask1[i]) vol_1++; + if (mask2[i]) vol_2++; + if (mask1[i] && mask2[i]) mask_intersect++; + else if (mask1[i]) mask_1++; + else if (mask2[i]) mask_2++; + } + + free_polygon(op1); + free_polygon(op2); + + free(mask1); + free(mask2); + + if (only1) + (*only1) = (float) mask_1 / (float) (mask_1 + mask_2 + mask_intersect); + + if (only2) + (*only2) = (float) mask_2 / (float) (mask_1 + mask_2 + mask_intersect); + + return (float) mask_intersect / (float) (mask_1 + mask_2 + mask_intersect); + +} + +#define COPY_POLYGON(TP, P) { P.count = TP->data.polygon.count; P.x = TP->data.polygon.x; P.y = TP->data.polygon.y; } + +region_overlap region_compute_overlap(const region_container* ra, const region_container* rb, region_bounds bounds) { + + region_container* ta = (region_container *) ra; + region_container* tb = (region_container *) rb; + region_overlap overlap; + overlap.overlap = 0; + overlap.only1 = 0; + overlap.only2 = 0; + + if (ra->type == RECTANGLE) + ta = region_convert(ra, POLYGON); + + if (rb->type == RECTANGLE) + tb = region_convert(rb, POLYGON); + + if (ta->type == POLYGON && tb->type == POLYGON) { + + region_polygon p1, p2; + + COPY_POLYGON(ta, p1); + COPY_POLYGON(tb, p2); + + overlap.overlap = compute_polygon_overlap(&p1, &p2, &(overlap.only1), &(overlap.only2), bounds); + + } + + if (ta != ra) + region_release(&ta); + + if (tb != rb) + region_release(&tb); + + return overlap; + +} + +int region_contains_point(region_container* r, float x, float y) { + + if (r->type == RECTANGLE) { + if (x >= (r->data.rectangle).x && x <= ((r->data.rectangle).width + (r->data.rectangle).x) && + y >= (r->data.rectangle).y && y <= ((r->data.rectangle).height + (r->data.rectangle).y)) + return 1; + return 0; + } + + if (r->type == POLYGON) + return point_in_polygon(&(r->data.polygon), x, y); + + return 0; + +} + +void region_get_mask(region_container* r, char* mask, int width, int height) { + + region_container* t = r; + + if (r->type == RECTANGLE) + t = region_convert(r, POLYGON); + + rasterize_polygon(&(t->data.polygon), mask, width, height); + + if (t != r) + region_release(&t); + +} + +void region_get_mask_offset(region_container* r, char* mask, int x, int y, int width, int height) { + + region_container* t = r; + region_polygon *p; + + if (r->type == RECTANGLE) + t = region_convert(r, POLYGON); + + p = offset_polygon(&(t->data.polygon), -x, -y); + + rasterize_polygon(p, mask, width, height); + + free_polygon(p); + + if (t != r) + region_release(&t); + +} + diff --git a/SiamMask/utils/pysot/utils/src/region.h b/SiamMask/utils/pysot/utils/src/region.h new file mode 100644 index 0000000000000000000000000000000000000000..abf57c2d97080ff57e6df9027e395fee0f792fd5 --- /dev/null +++ b/SiamMask/utils/pysot/utils/src/region.h @@ -0,0 +1,145 @@ +/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 4 -*- */ + +#ifndef _REGION_H_ +#define _REGION_H_ + +#ifdef TRAX_STATIC_DEFINE +# define __TRAX_EXPORT +#else +# ifndef __TRAX_EXPORT +# if defined(_MSC_VER) +# ifdef trax_EXPORTS + /* We are building this library */ +# define __TRAX_EXPORT __declspec(dllexport) +# else + /* We are using this library */ +# define __TRAX_EXPORT __declspec(dllimport) +# endif +# elif defined(__GNUC__) +# ifdef trax_EXPORTS + /* We are building this library */ +# define __TRAX_EXPORT __attribute__((visibility("default"))) +# else + /* We are using this library */ +# define __TRAX_EXPORT __attribute__((visibility("default"))) +# endif +# endif +# endif +#endif + +#ifndef MAX +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifndef MIN +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#define TRAX_DEFAULT_CODE 0 + +#define REGION_LEGACY_RASTERIZATION 1 + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum region_type {EMPTY, SPECIAL, RECTANGLE, POLYGON, MASK} region_type; + +typedef struct region_bounds { + + float top; + float bottom; + float left; + float right; + +} region_bounds; + +typedef struct region_polygon { + + int count; + + float* x; + float* y; + +} region_polygon; + +typedef struct region_mask { + + int x; + int y; + + int width; + int height; + + char* data; + +} region_mask; + +typedef struct region_rectangle { + + float x; + float y; + float width; + float height; + +} region_rectangle; + +typedef struct region_container { + enum region_type type; + union { + region_rectangle rectangle; + region_polygon polygon; + region_mask mask; + int special; + } data; +} region_container; + +typedef struct region_overlap { + + float overlap; + float only1; + float only2; + +} region_overlap; + +extern const region_bounds region_no_bounds; + +__TRAX_EXPORT int region_set_flags(int mask); + +__TRAX_EXPORT int region_clear_flags(int mask); + +__TRAX_EXPORT region_overlap region_compute_overlap(const region_container* ra, const region_container* rb, region_bounds bounds); + +__TRAX_EXPORT float compute_polygon_overlap(const region_polygon* p1, const region_polygon* p2, float *only1, float *only2, region_bounds bounds); + +__TRAX_EXPORT region_bounds region_create_bounds(float left, float top, float right, float bottom); + +__TRAX_EXPORT region_bounds region_compute_bounds(const region_container* region); + +__TRAX_EXPORT int region_parse(const char* buffer, region_container** region); + +__TRAX_EXPORT char* region_string(region_container* region); + +__TRAX_EXPORT void region_print(FILE* out, region_container* region); + +__TRAX_EXPORT region_container* region_convert(const region_container* region, region_type type); + +__TRAX_EXPORT void region_release(region_container** region); + +__TRAX_EXPORT region_container* region_create_special(int code); + +__TRAX_EXPORT region_container* region_create_rectangle(float x, float y, float width, float height); + +__TRAX_EXPORT region_container* region_create_polygon(int count); + +__TRAX_EXPORT int region_contains_point(region_container* r, float x, float y); + +__TRAX_EXPORT void region_get_mask(region_container* r, char* mask, int width, int height); + +__TRAX_EXPORT void region_get_mask_offset(region_container* r, char* mask, int x, int y, int width, int height); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/SiamMask/utils/pysot/utils/statistics.py b/SiamMask/utils/pysot/utils/statistics.py new file mode 100644 index 0000000000000000000000000000000000000000..2165165ced48dfa34df29e258d1795d19b1efb96 --- /dev/null +++ b/SiamMask/utils/pysot/utils/statistics.py @@ -0,0 +1,161 @@ +# -------------------------------------------------------- +# Python Single Object Tracking Evaluation +# Licensed under The MIT License [see LICENSE for details] +# Written by Fangyi Zhang +# @author fangyi.zhang@vipl.ict.ac.cn +# @project https://github.com/StrangerZhang/pysot-toolkit.git +# Revised for SiamMask by foolwood +# -------------------------------------------------------- + +import numpy as np +from numba import jit +from . import region + +def calculate_failures(trajectory): + """ Calculate number of failures + Args: + trajectory: list of bbox + Returns: + num_failures: number of failures + failures: failures point in trajectory, start with 0 + """ + failures = [i for i, x in zip(range(len(trajectory)), trajectory) + if len(x) == 1 and x[0] == 2] + num_failures = len(failures) + return num_failures, failures + +def calculate_accuracy(pred_trajectory, gt_trajectory, + burnin=0, ignore_unknown=True, bound=None): + """Caculate accuracy socre as average overlap over the entire sequence + Args: + trajectory: list of bbox + gt_trajectory: list of bbox + burnin: number of frames that have to be ignored after the failure + ignore_unknown: ignore frames where the overlap is unknown + bound: bounding region + Return: + acc: average overlap + overlaps: per frame overlaps + """ + pred_trajectory_ = pred_trajectory + if not ignore_unknown: + unkown = [len(x)==1 and x[0] == 0 for x in pred_trajectory] + + if burnin > 0: + pred_trajectory_ = pred_trajectory[:] + mask = [len(x)==1 and x[0] == 1 for x in pred_trajectory] + for i in range(len(mask)): + if mask[i]: + for j in range(burnin): + if i + j < len(mask): + pred_trajectory_[i+j] = [0] + min_len = min(len(pred_trajectory_), len(gt_trajectory)) + overlaps = region.vot_overlap_traj(pred_trajectory_[:min_len], + gt_trajectory[:min_len], bound) + + if not ignore_unknown: + overlaps = [u if u else 0 for u in unkown] + + acc = 0 + if len(overlaps) > 0: + acc = np.nanmean(overlaps) + return acc, overlaps + +@jit(nopython=True) +def overlap_ratio(rect1, rect2): + '''Compute overlap ratio between two rects + Args + rect:2d array of N x [x,y,w,h] + Return: + iou + ''' + # if rect1.ndim==1: + # rect1 = rect1[np.newaxis, :] + # if rect2.ndim==1: + # rect2 = rect2[np.newaxis, :] + left = np.maximum(rect1[:,0], rect2[:,0]) + right = np.minimum(rect1[:,0]+rect1[:,2], rect2[:,0]+rect2[:,2]) + top = np.maximum(rect1[:,1], rect2[:,1]) + bottom = np.minimum(rect1[:,1]+rect1[:,3], rect2[:,1]+rect2[:,3]) + + intersect = np.maximum(0,right - left) * np.maximum(0,bottom - top) + union = rect1[:,2]*rect1[:,3] + rect2[:,2]*rect2[:,3] - intersect + iou = intersect / union + iou = np.maximum(np.minimum(1, iou), 0) + return iou + +@jit(nopython=True) +def success_overlap(gt_bb, result_bb, n_frame): + thresholds_overlap = np.arange(0, 1.05, 0.05) + success = np.zeros(len(thresholds_overlap)) + iou = np.ones(len(gt_bb)) * (-1) + mask = np.sum(gt_bb > 0, axis=1) == 4 + iou[mask] = overlap_ratio(gt_bb[mask], result_bb[mask]) + for i in range(len(thresholds_overlap)): + success[i] = np.sum(iou > thresholds_overlap[i]) / float(n_frame) + return success + +@jit(nopython=True) +def success_error(gt_center, result_center, thresholds, n_frame): + # n_frame = len(gt_center) + success = np.zeros(len(thresholds)) + dist = np.ones(len(gt_center)) * (-1) + mask = np.sum(gt_center > 0, axis=1) == 2 + dist[mask] = np.sqrt(np.sum( + np.power(gt_center[mask] - result_center[mask], 2), axis=1)) + for i in range(len(thresholds)): + success[i] = np.sum(dist <= thresholds[i]) / float(n_frame) + return success + +@jit(nopython=True) +def determine_thresholds(scores, resolution=100): + """ + Args: + scores: 1d array of score + """ + scores = np.sort(scores[np.logical_not(np.isnan(scores))]) + delta = np.floor(len(scores) / (resolution - 2)) + idxs = np.floor(np.linspace(delta-1, len(scores)-delta, resolution-2)+0.5).astype(np.int32) + thresholds = np.zeros((resolution)) + thresholds[0] = - np.inf + thresholds[-1] = np.inf + thresholds[1:-1] = scores[idxs] + return thresholds + +@jit(nopython=True) +def calculate_f1(overlaps, score, bound, thresholds, N): + overlaps = np.array(overlaps) + overlaps[np.isnan(overlaps)] = 0 + score = np.array(score) + score[np.isnan(score)] = 0 + precision = np.zeros(len(thresholds)) + recall = np.zeros(len(thresholds)) + for i, th in enumerate(thresholds): + if th == - np.inf: + idx = score > 0 + else: + idx = score >= th + if np.sum(idx) == 0: + precision[i] = 1 + recall[i] = 0 + else: + precision[i] = np.mean(overlaps[idx]) + recall[i] = np.sum(overlaps[idx]) / N + f1 = 2 * precision * recall / (precision + recall) + return f1, precision, recall + +@jit(nopython=True) +def calculate_expected_overlap(fragments, fweights): + max_len = fragments.shape[1] + expected_overlaps = np.zeros((max_len), np.float32) + expected_overlaps[0] = 1 + + # TODO Speed Up + for i in range(1, max_len): + mask = np.logical_not(np.isnan(fragments[:, i])) + if np.any(mask): + fragment = fragments[mask, 1:i+1] + seq_mean = np.sum(fragment, 1) / fragment.shape[1] + expected_overlaps[i] = np.sum(seq_mean * + fweights[mask]) / np.sum(fweights[mask]) + return expected_overlaps diff --git a/SiamMask/utils/pyvotkit/__init__.py b/SiamMask/utils/pyvotkit/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..9c00e1a7a4f09725f164189c4f35d18d520280d0 --- /dev/null +++ b/SiamMask/utils/pyvotkit/__init__.py @@ -0,0 +1,9 @@ +# -------------------------------------------------------- +# Python Single Object Tracking Evaluation +# Licensed under The MIT License [see LICENSE for details] +# Written by Fangyi Zhang +# @author fangyi.zhang@vipl.ict.ac.cn +# @project https://github.com/StrangerZhang/pysot-toolkit.git +# Revised for SiamMask by foolwood +# -------------------------------------------------------- +from . import region diff --git a/SiamMask/utils/pyvotkit/__pycache__/__init__.cpython-39.pyc b/SiamMask/utils/pyvotkit/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..38fe573cca6e3c1e1f208c701bb761f6bb384237 Binary files /dev/null and b/SiamMask/utils/pyvotkit/__pycache__/__init__.cpython-39.pyc differ diff --git a/SiamMask/utils/pyvotkit/build/temp.linux-x86_64-3.9/region.o b/SiamMask/utils/pyvotkit/build/temp.linux-x86_64-3.9/region.o new file mode 100644 index 0000000000000000000000000000000000000000..14153142bbab865a93c40456d9a62573e0f91711 --- /dev/null +++ b/SiamMask/utils/pyvotkit/build/temp.linux-x86_64-3.9/region.o @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ae27d05a7e62bf41ce7fa2528996c5a3062f191a022e77f4701bfe01581a49f1 +size 2124856 diff --git a/SiamMask/utils/pyvotkit/build/temp.linux-x86_64-3.9/src/region.o b/SiamMask/utils/pyvotkit/build/temp.linux-x86_64-3.9/src/region.o new file mode 100644 index 0000000000000000000000000000000000000000..632e52c1b97d4003c08cab579bc1cef944e611a5 --- /dev/null +++ b/SiamMask/utils/pyvotkit/build/temp.linux-x86_64-3.9/src/region.o @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:03a76502415ae472d03827f96254d8182c6bf09f73593e0e56bc3926535cd365 +size 81096 diff --git a/SiamMask/utils/pyvotkit/c_region.pxd b/SiamMask/utils/pyvotkit/c_region.pxd new file mode 100644 index 0000000000000000000000000000000000000000..4abea62ce5ac39b2062f3c0ac67ab5bab42ea00e --- /dev/null +++ b/SiamMask/utils/pyvotkit/c_region.pxd @@ -0,0 +1,50 @@ +cdef extern from "region.h": + ctypedef enum region_type "RegionType": + EMTPY + SPECIAL + RECTANGEL + POLYGON + MASK + + ctypedef struct region_bounds: + float top + float bottom + float left + float right + + ctypedef struct region_rectangle: + float x + float y + float width + float height + + # ctypedef struct region_mask: + # int x + # int y + # int width + # int height + # char *data + + ctypedef struct region_polygon: + int count + float *x + float *y + + ctypedef union region_container_data: + region_rectangle rectangle + region_polygon polygon + # region_mask mask + int special + + ctypedef struct region_container: + region_type type + region_container_data data + + # ctypedef struct region_overlap: + # float overlap + # float only1 + # float only2 + + # region_overlap region_compute_overlap(const region_container* ra, const region_container* rb, region_bounds bounds) + + float compute_polygon_overlap(const region_polygon* p1, const region_polygon* p2, float *only1, float *only2, region_bounds bounds) diff --git a/SiamMask/utils/pyvotkit/region.c b/SiamMask/utils/pyvotkit/region.c new file mode 100644 index 0000000000000000000000000000000000000000..e4f3dad9403e0bc579695404fb653df6436c4dfb --- /dev/null +++ b/SiamMask/utils/pyvotkit/region.c @@ -0,0 +1,12684 @@ +/* Generated by Cython 0.29.34 */ + +/* BEGIN: Cython Metadata +{ + "distutils": { + "depends": [ + "src/region.h" + ], + "include_dirs": [ + "src/" + ], + "name": "region", + "sources": [ + "region.pyx", + "src/region.c" + ] + }, + "module_name": "region" +} +END: Cython Metadata */ + +#ifndef PY_SSIZE_T_CLEAN +#define PY_SSIZE_T_CLEAN +#endif /* PY_SSIZE_T_CLEAN */ +#include "Python.h" +#ifndef Py_PYTHON_H + #error Python headers needed to compile C extensions, please install development version of Python. +#elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000) + #error Cython requires Python 2.6+ or Python 3.3+. +#else +#define CYTHON_ABI "0_29_34" +#define CYTHON_HEX_VERSION 0x001D22F0 +#define CYTHON_FUTURE_DIVISION 0 +#include +#ifndef offsetof + #define offsetof(type, member) ( (size_t) & ((type*)0) -> member ) +#endif +#if !defined(WIN32) && !defined(MS_WINDOWS) + #ifndef __stdcall + #define __stdcall + #endif + #ifndef __cdecl + #define __cdecl + #endif + #ifndef __fastcall + #define __fastcall + #endif +#endif +#ifndef DL_IMPORT + #define DL_IMPORT(t) t +#endif +#ifndef DL_EXPORT + #define DL_EXPORT(t) t +#endif +#define __PYX_COMMA , +#ifndef HAVE_LONG_LONG + #if PY_VERSION_HEX >= 0x02070000 + #define HAVE_LONG_LONG + #endif +#endif +#ifndef PY_LONG_LONG + #define PY_LONG_LONG LONG_LONG +#endif +#ifndef Py_HUGE_VAL + #define Py_HUGE_VAL HUGE_VAL +#endif +#ifdef PYPY_VERSION + #define CYTHON_COMPILING_IN_PYPY 1 + #define CYTHON_COMPILING_IN_PYSTON 0 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_NOGIL 0 + #undef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 0 + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #if PY_VERSION_HEX < 0x03050000 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #elif !defined(CYTHON_USE_ASYNC_SLOTS) + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #undef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 0 + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #undef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 1 + #undef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 0 + #undef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 0 + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 0 + #undef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 0 + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 0 + #endif +#elif defined(PYSTON_VERSION) + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_PYSTON 1 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_NOGIL 0 + #ifndef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 1 + #endif + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #ifndef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 1 + #endif + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #ifndef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 0 + #endif + #ifndef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 1 + #endif + #ifndef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 1 + #endif + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 0 + #undef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 0 + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 0 + #endif +#elif defined(PY_NOGIL) + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_PYSTON 0 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #define CYTHON_COMPILING_IN_NOGIL 1 + #ifndef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 1 + #endif + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #ifndef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #ifndef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 1 + #endif + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #ifndef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 0 + #endif + #ifndef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 1 + #endif + #ifndef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 1 + #endif + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #ifndef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 1 + #endif + #ifndef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 1 + #endif + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 +#else + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_PYSTON 0 + #define CYTHON_COMPILING_IN_CPYTHON 1 + #define CYTHON_COMPILING_IN_NOGIL 0 + #ifndef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 1 + #endif + #if PY_VERSION_HEX < 0x02070000 + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #elif !defined(CYTHON_USE_PYTYPE_LOOKUP) + #define CYTHON_USE_PYTYPE_LOOKUP 1 + #endif + #if PY_MAJOR_VERSION < 3 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #elif !defined(CYTHON_USE_ASYNC_SLOTS) + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #if PY_VERSION_HEX < 0x02070000 + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #elif !defined(CYTHON_USE_PYLONG_INTERNALS) + #define CYTHON_USE_PYLONG_INTERNALS (PY_VERSION_HEX < 0x030C00A5) + #endif + #ifndef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 1 + #endif + #ifndef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 1 + #endif + #if PY_VERSION_HEX < 0x030300F0 || PY_VERSION_HEX >= 0x030B00A2 + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #elif !defined(CYTHON_USE_UNICODE_WRITER) + #define CYTHON_USE_UNICODE_WRITER 1 + #endif + #ifndef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 0 + #endif + #ifndef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 1 + #endif + #ifndef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 1 + #endif + #if PY_VERSION_HEX >= 0x030B00A4 + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #elif !defined(CYTHON_FAST_THREAD_STATE) + #define CYTHON_FAST_THREAD_STATE 1 + #endif + #ifndef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL (PY_VERSION_HEX < 0x030A0000) + #endif + #ifndef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT (PY_VERSION_HEX >= 0x03050000) + #endif + #ifndef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE (PY_VERSION_HEX >= 0x030400a1) + #endif + #ifndef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS ((PY_VERSION_HEX >= 0x030600B1) && (PY_VERSION_HEX < 0x030C00A5)) + #endif + #if PY_VERSION_HEX >= 0x030B00A4 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 + #elif !defined(CYTHON_USE_EXC_INFO_STACK) + #define CYTHON_USE_EXC_INFO_STACK (PY_VERSION_HEX >= 0x030700A3) + #endif + #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC + #define CYTHON_UPDATE_DESCRIPTOR_DOC 1 + #endif +#endif +#if !defined(CYTHON_FAST_PYCCALL) +#define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1) +#endif +#if CYTHON_USE_PYLONG_INTERNALS + #if PY_MAJOR_VERSION < 3 + #include "longintrepr.h" + #endif + #undef SHIFT + #undef BASE + #undef MASK + #ifdef SIZEOF_VOID_P + enum { __pyx_check_sizeof_voidp = 1 / (int)(SIZEOF_VOID_P == sizeof(void*)) }; + #endif +#endif +#ifndef __has_attribute + #define __has_attribute(x) 0 +#endif +#ifndef __has_cpp_attribute + #define __has_cpp_attribute(x) 0 +#endif +#ifndef CYTHON_RESTRICT + #if defined(__GNUC__) + #define CYTHON_RESTRICT __restrict__ + #elif defined(_MSC_VER) && _MSC_VER >= 1400 + #define CYTHON_RESTRICT __restrict + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define CYTHON_RESTRICT restrict + #else + #define CYTHON_RESTRICT + #endif +#endif +#ifndef CYTHON_UNUSED +# if defined(__GNUC__) +# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) +# define CYTHON_UNUSED __attribute__ ((__unused__)) +# else +# define CYTHON_UNUSED +# endif +# elif defined(__ICC) || (defined(__INTEL_COMPILER) && !defined(_MSC_VER)) +# define CYTHON_UNUSED __attribute__ ((__unused__)) +# else +# define CYTHON_UNUSED +# endif +#endif +#ifndef CYTHON_MAYBE_UNUSED_VAR +# if defined(__cplusplus) + template void CYTHON_MAYBE_UNUSED_VAR( const T& ) { } +# else +# define CYTHON_MAYBE_UNUSED_VAR(x) (void)(x) +# endif +#endif +#ifndef CYTHON_NCP_UNUSED +# if CYTHON_COMPILING_IN_CPYTHON +# define CYTHON_NCP_UNUSED +# else +# define CYTHON_NCP_UNUSED CYTHON_UNUSED +# endif +#endif +#define __Pyx_void_to_None(void_result) ((void)(void_result), Py_INCREF(Py_None), Py_None) +#ifdef _MSC_VER + #ifndef _MSC_STDINT_H_ + #if _MSC_VER < 1300 + typedef unsigned char uint8_t; + typedef unsigned int uint32_t; + #else + typedef unsigned __int8 uint8_t; + typedef unsigned __int32 uint32_t; + #endif + #endif +#else + #include +#endif +#ifndef CYTHON_FALLTHROUGH + #if defined(__cplusplus) && __cplusplus >= 201103L + #if __has_cpp_attribute(fallthrough) + #define CYTHON_FALLTHROUGH [[fallthrough]] + #elif __has_cpp_attribute(clang::fallthrough) + #define CYTHON_FALLTHROUGH [[clang::fallthrough]] + #elif __has_cpp_attribute(gnu::fallthrough) + #define CYTHON_FALLTHROUGH [[gnu::fallthrough]] + #endif + #endif + #ifndef CYTHON_FALLTHROUGH + #if __has_attribute(fallthrough) + #define CYTHON_FALLTHROUGH __attribute__((fallthrough)) + #else + #define CYTHON_FALLTHROUGH + #endif + #endif + #if defined(__clang__ ) && defined(__apple_build_version__) + #if __apple_build_version__ < 7000000 + #undef CYTHON_FALLTHROUGH + #define CYTHON_FALLTHROUGH + #endif + #endif +#endif + +#ifndef CYTHON_INLINE + #if defined(__clang__) + #define CYTHON_INLINE __inline__ __attribute__ ((__unused__)) + #elif defined(__GNUC__) + #define CYTHON_INLINE __inline__ + #elif defined(_MSC_VER) + #define CYTHON_INLINE __inline + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define CYTHON_INLINE inline + #else + #define CYTHON_INLINE + #endif +#endif + +#if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX < 0x02070600 && !defined(Py_OptimizeFlag) + #define Py_OptimizeFlag 0 +#endif +#define __PYX_BUILD_PY_SSIZE_T "n" +#define CYTHON_FORMAT_SSIZE_T "z" +#if PY_MAJOR_VERSION < 3 + #define __Pyx_BUILTIN_MODULE_NAME "__builtin__" + #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ + PyCode_New(a+k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) + #define __Pyx_DefaultClassType PyClass_Type +#else + #define __Pyx_BUILTIN_MODULE_NAME "builtins" + #define __Pyx_DefaultClassType PyType_Type +#if PY_VERSION_HEX >= 0x030B00A1 + static CYTHON_INLINE PyCodeObject* __Pyx_PyCode_New(int a, int k, int l, int s, int f, + PyObject *code, PyObject *c, PyObject* n, PyObject *v, + PyObject *fv, PyObject *cell, PyObject* fn, + PyObject *name, int fline, PyObject *lnos) { + PyObject *kwds=NULL, *argcount=NULL, *posonlyargcount=NULL, *kwonlyargcount=NULL; + PyObject *nlocals=NULL, *stacksize=NULL, *flags=NULL, *replace=NULL, *call_result=NULL, *empty=NULL; + const char *fn_cstr=NULL; + const char *name_cstr=NULL; + PyCodeObject* co=NULL; + PyObject *type, *value, *traceback; + PyErr_Fetch(&type, &value, &traceback); + if (!(kwds=PyDict_New())) goto end; + if (!(argcount=PyLong_FromLong(a))) goto end; + if (PyDict_SetItemString(kwds, "co_argcount", argcount) != 0) goto end; + if (!(posonlyargcount=PyLong_FromLong(0))) goto end; + if (PyDict_SetItemString(kwds, "co_posonlyargcount", posonlyargcount) != 0) goto end; + if (!(kwonlyargcount=PyLong_FromLong(k))) goto end; + if (PyDict_SetItemString(kwds, "co_kwonlyargcount", kwonlyargcount) != 0) goto end; + if (!(nlocals=PyLong_FromLong(l))) goto end; + if (PyDict_SetItemString(kwds, "co_nlocals", nlocals) != 0) goto end; + if (!(stacksize=PyLong_FromLong(s))) goto end; + if (PyDict_SetItemString(kwds, "co_stacksize", stacksize) != 0) goto end; + if (!(flags=PyLong_FromLong(f))) goto end; + if (PyDict_SetItemString(kwds, "co_flags", flags) != 0) goto end; + if (PyDict_SetItemString(kwds, "co_code", code) != 0) goto end; + if (PyDict_SetItemString(kwds, "co_consts", c) != 0) goto end; + if (PyDict_SetItemString(kwds, "co_names", n) != 0) goto end; + if (PyDict_SetItemString(kwds, "co_varnames", v) != 0) goto end; + if (PyDict_SetItemString(kwds, "co_freevars", fv) != 0) goto end; + if (PyDict_SetItemString(kwds, "co_cellvars", cell) != 0) goto end; + if (PyDict_SetItemString(kwds, "co_linetable", lnos) != 0) goto end; + if (!(fn_cstr=PyUnicode_AsUTF8AndSize(fn, NULL))) goto end; + if (!(name_cstr=PyUnicode_AsUTF8AndSize(name, NULL))) goto end; + if (!(co = PyCode_NewEmpty(fn_cstr, name_cstr, fline))) goto end; + if (!(replace = PyObject_GetAttrString((PyObject*)co, "replace"))) goto cleanup_code_too; + if (!(empty = PyTuple_New(0))) goto cleanup_code_too; // unfortunately __pyx_empty_tuple isn't available here + if (!(call_result = PyObject_Call(replace, empty, kwds))) goto cleanup_code_too; + Py_XDECREF((PyObject*)co); + co = (PyCodeObject*)call_result; + call_result = NULL; + if (0) { + cleanup_code_too: + Py_XDECREF((PyObject*)co); + co = NULL; + } + end: + Py_XDECREF(kwds); + Py_XDECREF(argcount); + Py_XDECREF(posonlyargcount); + Py_XDECREF(kwonlyargcount); + Py_XDECREF(nlocals); + Py_XDECREF(stacksize); + Py_XDECREF(replace); + Py_XDECREF(call_result); + Py_XDECREF(empty); + if (type) { + PyErr_Restore(type, value, traceback); + } + return co; + } +#else + #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ + PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) +#endif + #define __Pyx_DefaultClassType PyType_Type +#endif +#ifndef Py_TPFLAGS_CHECKTYPES + #define Py_TPFLAGS_CHECKTYPES 0 +#endif +#ifndef Py_TPFLAGS_HAVE_INDEX + #define Py_TPFLAGS_HAVE_INDEX 0 +#endif +#ifndef Py_TPFLAGS_HAVE_NEWBUFFER + #define Py_TPFLAGS_HAVE_NEWBUFFER 0 +#endif +#ifndef Py_TPFLAGS_HAVE_FINALIZE + #define Py_TPFLAGS_HAVE_FINALIZE 0 +#endif +#ifndef METH_STACKLESS + #define METH_STACKLESS 0 +#endif +#if PY_VERSION_HEX <= 0x030700A3 || !defined(METH_FASTCALL) + #ifndef METH_FASTCALL + #define METH_FASTCALL 0x80 + #endif + typedef PyObject *(*__Pyx_PyCFunctionFast) (PyObject *self, PyObject *const *args, Py_ssize_t nargs); + typedef PyObject *(*__Pyx_PyCFunctionFastWithKeywords) (PyObject *self, PyObject *const *args, + Py_ssize_t nargs, PyObject *kwnames); +#else + #define __Pyx_PyCFunctionFast _PyCFunctionFast + #define __Pyx_PyCFunctionFastWithKeywords _PyCFunctionFastWithKeywords +#endif +#if CYTHON_FAST_PYCCALL +#define __Pyx_PyFastCFunction_Check(func)\ + ((PyCFunction_Check(func) && (METH_FASTCALL == (PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST | METH_KEYWORDS | METH_STACKLESS))))) +#else +#define __Pyx_PyFastCFunction_Check(func) 0 +#endif +#if CYTHON_COMPILING_IN_PYPY && !defined(PyObject_Malloc) + #define PyObject_Malloc(s) PyMem_Malloc(s) + #define PyObject_Free(p) PyMem_Free(p) + #define PyObject_Realloc(p) PyMem_Realloc(p) +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030400A1 + #define PyMem_RawMalloc(n) PyMem_Malloc(n) + #define PyMem_RawRealloc(p, n) PyMem_Realloc(p, n) + #define PyMem_RawFree(p) PyMem_Free(p) +#endif +#if CYTHON_COMPILING_IN_PYSTON + #define __Pyx_PyCode_HasFreeVars(co) PyCode_HasFreeVars(co) + #define __Pyx_PyFrame_SetLineNumber(frame, lineno) PyFrame_SetLineNumber(frame, lineno) +#else + #define __Pyx_PyCode_HasFreeVars(co) (PyCode_GetNumFree(co) > 0) + #define __Pyx_PyFrame_SetLineNumber(frame, lineno) (frame)->f_lineno = (lineno) +#endif +#if !CYTHON_FAST_THREAD_STATE || PY_VERSION_HEX < 0x02070000 + #define __Pyx_PyThreadState_Current PyThreadState_GET() +#elif PY_VERSION_HEX >= 0x03060000 + #define __Pyx_PyThreadState_Current _PyThreadState_UncheckedGet() +#elif PY_VERSION_HEX >= 0x03000000 + #define __Pyx_PyThreadState_Current PyThreadState_GET() +#else + #define __Pyx_PyThreadState_Current _PyThreadState_Current +#endif +#if PY_VERSION_HEX < 0x030700A2 && !defined(PyThread_tss_create) && !defined(Py_tss_NEEDS_INIT) +#include "pythread.h" +#define Py_tss_NEEDS_INIT 0 +typedef int Py_tss_t; +static CYTHON_INLINE int PyThread_tss_create(Py_tss_t *key) { + *key = PyThread_create_key(); + return 0; +} +static CYTHON_INLINE Py_tss_t * PyThread_tss_alloc(void) { + Py_tss_t *key = (Py_tss_t *)PyObject_Malloc(sizeof(Py_tss_t)); + *key = Py_tss_NEEDS_INIT; + return key; +} +static CYTHON_INLINE void PyThread_tss_free(Py_tss_t *key) { + PyObject_Free(key); +} +static CYTHON_INLINE int PyThread_tss_is_created(Py_tss_t *key) { + return *key != Py_tss_NEEDS_INIT; +} +static CYTHON_INLINE void PyThread_tss_delete(Py_tss_t *key) { + PyThread_delete_key(*key); + *key = Py_tss_NEEDS_INIT; +} +static CYTHON_INLINE int PyThread_tss_set(Py_tss_t *key, void *value) { + return PyThread_set_key_value(*key, value); +} +static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { + return PyThread_get_key_value(*key); +} +#endif +#if CYTHON_COMPILING_IN_CPYTHON || defined(_PyDict_NewPresized) +#define __Pyx_PyDict_NewPresized(n) ((n <= 8) ? PyDict_New() : _PyDict_NewPresized(n)) +#else +#define __Pyx_PyDict_NewPresized(n) PyDict_New() +#endif +#if PY_MAJOR_VERSION >= 3 || CYTHON_FUTURE_DIVISION + #define __Pyx_PyNumber_Divide(x,y) PyNumber_TrueDivide(x,y) + #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceTrueDivide(x,y) +#else + #define __Pyx_PyNumber_Divide(x,y) PyNumber_Divide(x,y) + #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceDivide(x,y) +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030500A1 && CYTHON_USE_UNICODE_INTERNALS +#define __Pyx_PyDict_GetItemStr(dict, name) _PyDict_GetItem_KnownHash(dict, name, ((PyASCIIObject *) name)->hash) +#else +#define __Pyx_PyDict_GetItemStr(dict, name) PyDict_GetItem(dict, name) +#endif +#if PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND) + #define CYTHON_PEP393_ENABLED 1 + #if PY_VERSION_HEX >= 0x030C0000 + #define __Pyx_PyUnicode_READY(op) (0) + #else + #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\ + 0 : _PyUnicode_Ready((PyObject *)(op))) + #endif + #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_LENGTH(u) + #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) + #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u) + #define __Pyx_PyUnicode_KIND(u) PyUnicode_KIND(u) + #define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u) + #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) + #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, ch) + #if PY_VERSION_HEX >= 0x030C0000 + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_LENGTH(u)) + #else + #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03090000 + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : ((PyCompactUnicodeObject *)(u))->wstr_length)) + #else + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u))) + #endif + #endif +#else + #define CYTHON_PEP393_ENABLED 0 + #define PyUnicode_1BYTE_KIND 1 + #define PyUnicode_2BYTE_KIND 2 + #define PyUnicode_4BYTE_KIND 4 + #define __Pyx_PyUnicode_READY(op) (0) + #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_SIZE(u) + #define __Pyx_PyUnicode_READ_CHAR(u, i) ((Py_UCS4)(PyUnicode_AS_UNICODE(u)[i])) + #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) ((sizeof(Py_UNICODE) == 2) ? 65535 : 1114111) + #define __Pyx_PyUnicode_KIND(u) (sizeof(Py_UNICODE)) + #define __Pyx_PyUnicode_DATA(u) ((void*)PyUnicode_AS_UNICODE(u)) + #define __Pyx_PyUnicode_READ(k, d, i) ((void)(k), (Py_UCS4)(((Py_UNICODE*)d)[i])) + #define __Pyx_PyUnicode_WRITE(k, d, i, ch) (((void)(k)), ((Py_UNICODE*)d)[i] = ch) + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_SIZE(u)) +#endif +#if CYTHON_COMPILING_IN_PYPY + #define __Pyx_PyUnicode_Concat(a, b) PyNumber_Add(a, b) + #define __Pyx_PyUnicode_ConcatSafe(a, b) PyNumber_Add(a, b) +#else + #define __Pyx_PyUnicode_Concat(a, b) PyUnicode_Concat(a, b) + #define __Pyx_PyUnicode_ConcatSafe(a, b) ((unlikely((a) == Py_None) || unlikely((b) == Py_None)) ?\ + PyNumber_Add(a, b) : __Pyx_PyUnicode_Concat(a, b)) +#endif +#if CYTHON_COMPILING_IN_PYPY && !defined(PyUnicode_Contains) + #define PyUnicode_Contains(u, s) PySequence_Contains(u, s) +#endif +#if CYTHON_COMPILING_IN_PYPY && !defined(PyByteArray_Check) + #define PyByteArray_Check(obj) PyObject_TypeCheck(obj, &PyByteArray_Type) +#endif +#if CYTHON_COMPILING_IN_PYPY && !defined(PyObject_Format) + #define PyObject_Format(obj, fmt) PyObject_CallMethod(obj, "__format__", "O", fmt) +#endif +#define __Pyx_PyString_FormatSafe(a, b) ((unlikely((a) == Py_None || (PyString_Check(b) && !PyString_CheckExact(b)))) ? PyNumber_Remainder(a, b) : __Pyx_PyString_Format(a, b)) +#define __Pyx_PyUnicode_FormatSafe(a, b) ((unlikely((a) == Py_None || (PyUnicode_Check(b) && !PyUnicode_CheckExact(b)))) ? PyNumber_Remainder(a, b) : PyUnicode_Format(a, b)) +#if PY_MAJOR_VERSION >= 3 + #define __Pyx_PyString_Format(a, b) PyUnicode_Format(a, b) +#else + #define __Pyx_PyString_Format(a, b) PyString_Format(a, b) +#endif +#if PY_MAJOR_VERSION < 3 && !defined(PyObject_ASCII) + #define PyObject_ASCII(o) PyObject_Repr(o) +#endif +#if PY_MAJOR_VERSION >= 3 + #define PyBaseString_Type PyUnicode_Type + #define PyStringObject PyUnicodeObject + #define PyString_Type PyUnicode_Type + #define PyString_Check PyUnicode_Check + #define PyString_CheckExact PyUnicode_CheckExact +#ifndef PyObject_Unicode + #define PyObject_Unicode PyObject_Str +#endif +#endif +#if PY_MAJOR_VERSION >= 3 + #define __Pyx_PyBaseString_Check(obj) PyUnicode_Check(obj) + #define __Pyx_PyBaseString_CheckExact(obj) PyUnicode_CheckExact(obj) +#else + #define __Pyx_PyBaseString_Check(obj) (PyString_Check(obj) || PyUnicode_Check(obj)) + #define __Pyx_PyBaseString_CheckExact(obj) (PyString_CheckExact(obj) || PyUnicode_CheckExact(obj)) +#endif +#ifndef PySet_CheckExact + #define PySet_CheckExact(obj) (Py_TYPE(obj) == &PySet_Type) +#endif +#if PY_VERSION_HEX >= 0x030900A4 + #define __Pyx_SET_REFCNT(obj, refcnt) Py_SET_REFCNT(obj, refcnt) + #define __Pyx_SET_SIZE(obj, size) Py_SET_SIZE(obj, size) +#else + #define __Pyx_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt) + #define __Pyx_SET_SIZE(obj, size) Py_SIZE(obj) = (size) +#endif +#if CYTHON_ASSUME_SAFE_MACROS + #define __Pyx_PySequence_SIZE(seq) Py_SIZE(seq) +#else + #define __Pyx_PySequence_SIZE(seq) PySequence_Size(seq) +#endif +#if PY_MAJOR_VERSION >= 3 + #define PyIntObject PyLongObject + #define PyInt_Type PyLong_Type + #define PyInt_Check(op) PyLong_Check(op) + #define PyInt_CheckExact(op) PyLong_CheckExact(op) + #define PyInt_FromString PyLong_FromString + #define PyInt_FromUnicode PyLong_FromUnicode + #define PyInt_FromLong PyLong_FromLong + #define PyInt_FromSize_t PyLong_FromSize_t + #define PyInt_FromSsize_t PyLong_FromSsize_t + #define PyInt_AsLong PyLong_AsLong + #define PyInt_AS_LONG PyLong_AS_LONG + #define PyInt_AsSsize_t PyLong_AsSsize_t + #define PyInt_AsUnsignedLongMask PyLong_AsUnsignedLongMask + #define PyInt_AsUnsignedLongLongMask PyLong_AsUnsignedLongLongMask + #define PyNumber_Int PyNumber_Long +#endif +#if PY_MAJOR_VERSION >= 3 + #define PyBoolObject PyLongObject +#endif +#if PY_MAJOR_VERSION >= 3 && CYTHON_COMPILING_IN_PYPY + #ifndef PyUnicode_InternFromString + #define PyUnicode_InternFromString(s) PyUnicode_FromString(s) + #endif +#endif +#if PY_VERSION_HEX < 0x030200A4 + typedef long Py_hash_t; + #define __Pyx_PyInt_FromHash_t PyInt_FromLong + #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsHash_t +#else + #define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t + #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsSsize_t +#endif +#if PY_MAJOR_VERSION >= 3 + #define __Pyx_PyMethod_New(func, self, klass) ((self) ? ((void)(klass), PyMethod_New(func, self)) : __Pyx_NewRef(func)) +#else + #define __Pyx_PyMethod_New(func, self, klass) PyMethod_New(func, self, klass) +#endif +#if CYTHON_USE_ASYNC_SLOTS + #if PY_VERSION_HEX >= 0x030500B1 + #define __Pyx_PyAsyncMethodsStruct PyAsyncMethods + #define __Pyx_PyType_AsAsync(obj) (Py_TYPE(obj)->tp_as_async) + #else + #define __Pyx_PyType_AsAsync(obj) ((__Pyx_PyAsyncMethodsStruct*) (Py_TYPE(obj)->tp_reserved)) + #endif +#else + #define __Pyx_PyType_AsAsync(obj) NULL +#endif +#ifndef __Pyx_PyAsyncMethodsStruct + typedef struct { + unaryfunc am_await; + unaryfunc am_aiter; + unaryfunc am_anext; + } __Pyx_PyAsyncMethodsStruct; +#endif + +#if defined(_WIN32) || defined(WIN32) || defined(MS_WINDOWS) + #if !defined(_USE_MATH_DEFINES) + #define _USE_MATH_DEFINES + #endif +#endif +#include +#ifdef NAN +#define __PYX_NAN() ((float) NAN) +#else +static CYTHON_INLINE float __PYX_NAN() { + float value; + memset(&value, 0xFF, sizeof(value)); + return value; +} +#endif +#if defined(__CYGWIN__) && defined(_LDBL_EQ_DBL) +#define __Pyx_truncl trunc +#else +#define __Pyx_truncl truncl +#endif + +#define __PYX_MARK_ERR_POS(f_index, lineno) \ + { __pyx_filename = __pyx_f[f_index]; (void)__pyx_filename; __pyx_lineno = lineno; (void)__pyx_lineno; __pyx_clineno = __LINE__; (void)__pyx_clineno; } +#define __PYX_ERR(f_index, lineno, Ln_error) \ + { __PYX_MARK_ERR_POS(f_index, lineno) goto Ln_error; } + +#ifndef __PYX_EXTERN_C + #ifdef __cplusplus + #define __PYX_EXTERN_C extern "C" + #else + #define __PYX_EXTERN_C extern + #endif +#endif + +#define __PYX_HAVE__region +#define __PYX_HAVE_API__region +/* Early includes */ +#include +#include +#include +#include "region.h" +#ifdef _OPENMP +#include +#endif /* _OPENMP */ + +#if defined(PYREX_WITHOUT_ASSERTIONS) && !defined(CYTHON_WITHOUT_ASSERTIONS) +#define CYTHON_WITHOUT_ASSERTIONS +#endif + +typedef struct {PyObject **p; const char *s; const Py_ssize_t n; const char* encoding; + const char is_unicode; const char is_str; const char intern; } __Pyx_StringTabEntry; + +#define __PYX_DEFAULT_STRING_ENCODING_IS_ASCII 0 +#define __PYX_DEFAULT_STRING_ENCODING_IS_UTF8 0 +#define __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT (PY_MAJOR_VERSION >= 3 && __PYX_DEFAULT_STRING_ENCODING_IS_UTF8) +#define __PYX_DEFAULT_STRING_ENCODING "" +#define __Pyx_PyObject_FromString __Pyx_PyBytes_FromString +#define __Pyx_PyObject_FromStringAndSize __Pyx_PyBytes_FromStringAndSize +#define __Pyx_uchar_cast(c) ((unsigned char)c) +#define __Pyx_long_cast(x) ((long)x) +#define __Pyx_fits_Py_ssize_t(v, type, is_signed) (\ + (sizeof(type) < sizeof(Py_ssize_t)) ||\ + (sizeof(type) > sizeof(Py_ssize_t) &&\ + likely(v < (type)PY_SSIZE_T_MAX ||\ + v == (type)PY_SSIZE_T_MAX) &&\ + (!is_signed || likely(v > (type)PY_SSIZE_T_MIN ||\ + v == (type)PY_SSIZE_T_MIN))) ||\ + (sizeof(type) == sizeof(Py_ssize_t) &&\ + (is_signed || likely(v < (type)PY_SSIZE_T_MAX ||\ + v == (type)PY_SSIZE_T_MAX))) ) +static CYTHON_INLINE int __Pyx_is_valid_index(Py_ssize_t i, Py_ssize_t limit) { + return (size_t) i < (size_t) limit; +} +#if defined (__cplusplus) && __cplusplus >= 201103L + #include + #define __Pyx_sst_abs(value) std::abs(value) +#elif SIZEOF_INT >= SIZEOF_SIZE_T + #define __Pyx_sst_abs(value) abs(value) +#elif SIZEOF_LONG >= SIZEOF_SIZE_T + #define __Pyx_sst_abs(value) labs(value) +#elif defined (_MSC_VER) + #define __Pyx_sst_abs(value) ((Py_ssize_t)_abs64(value)) +#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define __Pyx_sst_abs(value) llabs(value) +#elif defined (__GNUC__) + #define __Pyx_sst_abs(value) __builtin_llabs(value) +#else + #define __Pyx_sst_abs(value) ((value<0) ? -value : value) +#endif +static CYTHON_INLINE const char* __Pyx_PyObject_AsString(PyObject*); +static CYTHON_INLINE const char* __Pyx_PyObject_AsStringAndSize(PyObject*, Py_ssize_t* length); +#define __Pyx_PyByteArray_FromString(s) PyByteArray_FromStringAndSize((const char*)s, strlen((const char*)s)) +#define __Pyx_PyByteArray_FromStringAndSize(s, l) PyByteArray_FromStringAndSize((const char*)s, l) +#define __Pyx_PyBytes_FromString PyBytes_FromString +#define __Pyx_PyBytes_FromStringAndSize PyBytes_FromStringAndSize +static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char*); +#if PY_MAJOR_VERSION < 3 + #define __Pyx_PyStr_FromString __Pyx_PyBytes_FromString + #define __Pyx_PyStr_FromStringAndSize __Pyx_PyBytes_FromStringAndSize +#else + #define __Pyx_PyStr_FromString __Pyx_PyUnicode_FromString + #define __Pyx_PyStr_FromStringAndSize __Pyx_PyUnicode_FromStringAndSize +#endif +#define __Pyx_PyBytes_AsWritableString(s) ((char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsWritableSString(s) ((signed char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsWritableUString(s) ((unsigned char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsString(s) ((const char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsSString(s) ((const signed char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsUString(s) ((const unsigned char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyObject_AsWritableString(s) ((char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsWritableSString(s) ((signed char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsWritableUString(s) ((unsigned char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsSString(s) ((const signed char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsUString(s) ((const unsigned char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_FromCString(s) __Pyx_PyObject_FromString((const char*)s) +#define __Pyx_PyBytes_FromCString(s) __Pyx_PyBytes_FromString((const char*)s) +#define __Pyx_PyByteArray_FromCString(s) __Pyx_PyByteArray_FromString((const char*)s) +#define __Pyx_PyStr_FromCString(s) __Pyx_PyStr_FromString((const char*)s) +#define __Pyx_PyUnicode_FromCString(s) __Pyx_PyUnicode_FromString((const char*)s) +static CYTHON_INLINE size_t __Pyx_Py_UNICODE_strlen(const Py_UNICODE *u) { + const Py_UNICODE *u_end = u; + while (*u_end++) ; + return (size_t)(u_end - u - 1); +} +#define __Pyx_PyUnicode_FromUnicode(u) PyUnicode_FromUnicode(u, __Pyx_Py_UNICODE_strlen(u)) +#define __Pyx_PyUnicode_FromUnicodeAndLength PyUnicode_FromUnicode +#define __Pyx_PyUnicode_AsUnicode PyUnicode_AsUnicode +#define __Pyx_NewRef(obj) (Py_INCREF(obj), obj) +#define __Pyx_Owned_Py_None(b) __Pyx_NewRef(Py_None) +static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b); +static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*); +static CYTHON_INLINE int __Pyx_PyObject_IsTrueAndDecref(PyObject*); +static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x); +#define __Pyx_PySequence_Tuple(obj)\ + (likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj)) +static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); +static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); +static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject*); +#if CYTHON_ASSUME_SAFE_MACROS +#define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) +#else +#define __pyx_PyFloat_AsDouble(x) PyFloat_AsDouble(x) +#endif +#define __pyx_PyFloat_AsFloat(x) ((float) __pyx_PyFloat_AsDouble(x)) +#if PY_MAJOR_VERSION >= 3 +#define __Pyx_PyNumber_Int(x) (PyLong_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Long(x)) +#else +#define __Pyx_PyNumber_Int(x) (PyInt_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Int(x)) +#endif +#define __Pyx_PyNumber_Float(x) (PyFloat_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Float(x)) +#if PY_MAJOR_VERSION < 3 && __PYX_DEFAULT_STRING_ENCODING_IS_ASCII +static int __Pyx_sys_getdefaultencoding_not_ascii; +static int __Pyx_init_sys_getdefaultencoding_params(void) { + PyObject* sys; + PyObject* default_encoding = NULL; + PyObject* ascii_chars_u = NULL; + PyObject* ascii_chars_b = NULL; + const char* default_encoding_c; + sys = PyImport_ImportModule("sys"); + if (!sys) goto bad; + default_encoding = PyObject_CallMethod(sys, (char*) "getdefaultencoding", NULL); + Py_DECREF(sys); + if (!default_encoding) goto bad; + default_encoding_c = PyBytes_AsString(default_encoding); + if (!default_encoding_c) goto bad; + if (strcmp(default_encoding_c, "ascii") == 0) { + __Pyx_sys_getdefaultencoding_not_ascii = 0; + } else { + char ascii_chars[128]; + int c; + for (c = 0; c < 128; c++) { + ascii_chars[c] = c; + } + __Pyx_sys_getdefaultencoding_not_ascii = 1; + ascii_chars_u = PyUnicode_DecodeASCII(ascii_chars, 128, NULL); + if (!ascii_chars_u) goto bad; + ascii_chars_b = PyUnicode_AsEncodedString(ascii_chars_u, default_encoding_c, NULL); + if (!ascii_chars_b || !PyBytes_Check(ascii_chars_b) || memcmp(ascii_chars, PyBytes_AS_STRING(ascii_chars_b), 128) != 0) { + PyErr_Format( + PyExc_ValueError, + "This module compiled with c_string_encoding=ascii, but default encoding '%.200s' is not a superset of ascii.", + default_encoding_c); + goto bad; + } + Py_DECREF(ascii_chars_u); + Py_DECREF(ascii_chars_b); + } + Py_DECREF(default_encoding); + return 0; +bad: + Py_XDECREF(default_encoding); + Py_XDECREF(ascii_chars_u); + Py_XDECREF(ascii_chars_b); + return -1; +} +#endif +#if __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT && PY_MAJOR_VERSION >= 3 +#define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_DecodeUTF8(c_str, size, NULL) +#else +#define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_Decode(c_str, size, __PYX_DEFAULT_STRING_ENCODING, NULL) +#if __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT +static char* __PYX_DEFAULT_STRING_ENCODING; +static int __Pyx_init_sys_getdefaultencoding_params(void) { + PyObject* sys; + PyObject* default_encoding = NULL; + char* default_encoding_c; + sys = PyImport_ImportModule("sys"); + if (!sys) goto bad; + default_encoding = PyObject_CallMethod(sys, (char*) (const char*) "getdefaultencoding", NULL); + Py_DECREF(sys); + if (!default_encoding) goto bad; + default_encoding_c = PyBytes_AsString(default_encoding); + if (!default_encoding_c) goto bad; + __PYX_DEFAULT_STRING_ENCODING = (char*) malloc(strlen(default_encoding_c) + 1); + if (!__PYX_DEFAULT_STRING_ENCODING) goto bad; + strcpy(__PYX_DEFAULT_STRING_ENCODING, default_encoding_c); + Py_DECREF(default_encoding); + return 0; +bad: + Py_XDECREF(default_encoding); + return -1; +} +#endif +#endif + + +/* Test for GCC > 2.95 */ +#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95))) + #define likely(x) __builtin_expect(!!(x), 1) + #define unlikely(x) __builtin_expect(!!(x), 0) +#else /* !__GNUC__ or GCC < 2.95 */ + #define likely(x) (x) + #define unlikely(x) (x) +#endif /* __GNUC__ */ +static CYTHON_INLINE void __Pyx_pretend_to_initialize(void* ptr) { (void)ptr; } + +static PyObject *__pyx_m = NULL; +static PyObject *__pyx_d; +static PyObject *__pyx_b; +static PyObject *__pyx_cython_runtime = NULL; +static PyObject *__pyx_empty_tuple; +static PyObject *__pyx_empty_bytes; +static PyObject *__pyx_empty_unicode; +static int __pyx_lineno; +static int __pyx_clineno = 0; +static const char * __pyx_cfilenm= __FILE__; +static const char *__pyx_filename; + + +static const char *__pyx_f[] = { + "region.pyx", + "stringsource", +}; + +/*--- Type declarations ---*/ +struct __pyx_obj_6region_RegionBounds; +struct __pyx_obj_6region_Rectangle; +struct __pyx_obj_6region_Polygon; +struct __pyx_obj___Pyx_EnumMeta; + +/* "region.pyx":10 + * cimport c_region + * + * cpdef enum RegionType: # <<<<<<<<<<<<<< + * EMTPY + * SPECIAL + */ +enum __pyx_t_6region_RegionType { + __pyx_e_6region_EMTPY, + __pyx_e_6region_SPECIAL, + __pyx_e_6region_RECTANGEL, + __pyx_e_6region_POLYGON, + __pyx_e_6region_MASK +}; + +/* "region.pyx":17 + * MASK + * + * cdef class RegionBounds: # <<<<<<<<<<<<<< + * cdef c_region.region_bounds* _c_region_bounds + * + */ +struct __pyx_obj_6region_RegionBounds { + PyObject_HEAD + region_bounds *_c_region_bounds; +}; + + +/* "region.pyx":56 + * + * + * cdef class Rectangle: # <<<<<<<<<<<<<< + * cdef c_region.region_rectangle* _c_region_rectangle + * + */ +struct __pyx_obj_6region_Rectangle { + PyObject_HEAD + region_rectangle *_c_region_rectangle; +}; + + +/* "region.pyx":97 + * self._c_region_rectangle.height) + * + * cdef class Polygon: # <<<<<<<<<<<<<< + * cdef c_region.region_polygon* _c_region_polygon + * + */ +struct __pyx_obj_6region_Polygon { + PyObject_HEAD + region_polygon *_c_region_polygon; +}; + + +/* "EnumBase":15 + * + * @cython.internal + * cdef class __Pyx_EnumMeta(type): # <<<<<<<<<<<<<< + * def __init__(cls, name, parents, dct): + * type.__init__(cls, name, parents, dct) + */ +struct __pyx_obj___Pyx_EnumMeta { + PyHeapTypeObject __pyx_base; +}; + + +/* --- Runtime support code (head) --- */ +/* Refnanny.proto */ +#ifndef CYTHON_REFNANNY + #define CYTHON_REFNANNY 0 +#endif +#if CYTHON_REFNANNY + typedef struct { + void (*INCREF)(void*, PyObject*, int); + void (*DECREF)(void*, PyObject*, int); + void (*GOTREF)(void*, PyObject*, int); + void (*GIVEREF)(void*, PyObject*, int); + void* (*SetupContext)(const char*, int, const char*); + void (*FinishContext)(void**); + } __Pyx_RefNannyAPIStruct; + static __Pyx_RefNannyAPIStruct *__Pyx_RefNanny = NULL; + static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname); + #define __Pyx_RefNannyDeclarations void *__pyx_refnanny = NULL; +#ifdef WITH_THREAD + #define __Pyx_RefNannySetupContext(name, acquire_gil)\ + if (acquire_gil) {\ + PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__);\ + PyGILState_Release(__pyx_gilstate_save);\ + } else {\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__);\ + } +#else + #define __Pyx_RefNannySetupContext(name, acquire_gil)\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__) +#endif + #define __Pyx_RefNannyFinishContext()\ + __Pyx_RefNanny->FinishContext(&__pyx_refnanny) + #define __Pyx_INCREF(r) __Pyx_RefNanny->INCREF(__pyx_refnanny, (PyObject *)(r), __LINE__) + #define __Pyx_DECREF(r) __Pyx_RefNanny->DECREF(__pyx_refnanny, (PyObject *)(r), __LINE__) + #define __Pyx_GOTREF(r) __Pyx_RefNanny->GOTREF(__pyx_refnanny, (PyObject *)(r), __LINE__) + #define __Pyx_GIVEREF(r) __Pyx_RefNanny->GIVEREF(__pyx_refnanny, (PyObject *)(r), __LINE__) + #define __Pyx_XINCREF(r) do { if((r) != NULL) {__Pyx_INCREF(r); }} while(0) + #define __Pyx_XDECREF(r) do { if((r) != NULL) {__Pyx_DECREF(r); }} while(0) + #define __Pyx_XGOTREF(r) do { if((r) != NULL) {__Pyx_GOTREF(r); }} while(0) + #define __Pyx_XGIVEREF(r) do { if((r) != NULL) {__Pyx_GIVEREF(r);}} while(0) +#else + #define __Pyx_RefNannyDeclarations + #define __Pyx_RefNannySetupContext(name, acquire_gil) + #define __Pyx_RefNannyFinishContext() + #define __Pyx_INCREF(r) Py_INCREF(r) + #define __Pyx_DECREF(r) Py_DECREF(r) + #define __Pyx_GOTREF(r) + #define __Pyx_GIVEREF(r) + #define __Pyx_XINCREF(r) Py_XINCREF(r) + #define __Pyx_XDECREF(r) Py_XDECREF(r) + #define __Pyx_XGOTREF(r) + #define __Pyx_XGIVEREF(r) +#endif +#define __Pyx_XDECREF_SET(r, v) do {\ + PyObject *tmp = (PyObject *) r;\ + r = v; __Pyx_XDECREF(tmp);\ + } while (0) +#define __Pyx_DECREF_SET(r, v) do {\ + PyObject *tmp = (PyObject *) r;\ + r = v; __Pyx_DECREF(tmp);\ + } while (0) +#define __Pyx_CLEAR(r) do { PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);} while(0) +#define __Pyx_XCLEAR(r) do { if((r) != NULL) {PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);}} while(0) + +/* PyObjectGetAttrStr.proto */ +#if CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name); +#else +#define __Pyx_PyObject_GetAttrStr(o,n) PyObject_GetAttr(o,n) +#endif + +/* GetBuiltinName.proto */ +static PyObject *__Pyx_GetBuiltinName(PyObject *name); + +/* RaiseArgTupleInvalid.proto */ +static void __Pyx_RaiseArgtupleInvalid(const char* func_name, int exact, + Py_ssize_t num_min, Py_ssize_t num_max, Py_ssize_t num_found); + +/* KeywordStringCheck.proto */ +static int __Pyx_CheckKeywordStrings(PyObject *kwdict, const char* function_name, int kw_allowed); + +/* RaiseDoubleKeywords.proto */ +static void __Pyx_RaiseDoubleKeywordsError(const char* func_name, PyObject* kw_name); + +/* ParseKeywords.proto */ +static int __Pyx_ParseOptionalKeywords(PyObject *kwds, PyObject **argnames[],\ + PyObject *kwds2, PyObject *values[], Py_ssize_t num_pos_args,\ + const char* function_name); + +/* PyFunctionFastCall.proto */ +#if CYTHON_FAST_PYCALL +#define __Pyx_PyFunction_FastCall(func, args, nargs)\ + __Pyx_PyFunction_FastCallDict((func), (args), (nargs), NULL) +#if 1 || PY_VERSION_HEX < 0x030600B1 +static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, PyObject *kwargs); +#else +#define __Pyx_PyFunction_FastCallDict(func, args, nargs, kwargs) _PyFunction_FastCallDict(func, args, nargs, kwargs) +#endif +#define __Pyx_BUILD_ASSERT_EXPR(cond)\ + (sizeof(char [1 - 2*!(cond)]) - 1) +#ifndef Py_MEMBER_SIZE +#define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member) +#endif +#if CYTHON_FAST_PYCALL + static size_t __pyx_pyframe_localsplus_offset = 0; + #include "frameobject.h" +#if PY_VERSION_HEX >= 0x030b00a6 + #ifndef Py_BUILD_CORE + #define Py_BUILD_CORE 1 + #endif + #include "internal/pycore_frame.h" +#endif + #define __Pxy_PyFrame_Initialize_Offsets()\ + ((void)__Pyx_BUILD_ASSERT_EXPR(sizeof(PyFrameObject) == offsetof(PyFrameObject, f_localsplus) + Py_MEMBER_SIZE(PyFrameObject, f_localsplus)),\ + (void)(__pyx_pyframe_localsplus_offset = ((size_t)PyFrame_Type.tp_basicsize) - Py_MEMBER_SIZE(PyFrameObject, f_localsplus))) + #define __Pyx_PyFrame_GetLocalsplus(frame)\ + (assert(__pyx_pyframe_localsplus_offset), (PyObject **)(((char *)(frame)) + __pyx_pyframe_localsplus_offset)) +#endif // CYTHON_FAST_PYCALL +#endif + +/* PyCFunctionFastCall.proto */ +#if CYTHON_FAST_PYCCALL +static CYTHON_INLINE PyObject *__Pyx_PyCFunction_FastCall(PyObject *func, PyObject **args, Py_ssize_t nargs); +#else +#define __Pyx_PyCFunction_FastCall(func, args, nargs) (assert(0), NULL) +#endif + +/* PyObjectCall.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw); +#else +#define __Pyx_PyObject_Call(func, arg, kw) PyObject_Call(func, arg, kw) +#endif + +/* PyThreadStateGet.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyThreadState_declare PyThreadState *__pyx_tstate; +#define __Pyx_PyThreadState_assign __pyx_tstate = __Pyx_PyThreadState_Current; +#define __Pyx_PyErr_Occurred() __pyx_tstate->curexc_type +#else +#define __Pyx_PyThreadState_declare +#define __Pyx_PyThreadState_assign +#define __Pyx_PyErr_Occurred() PyErr_Occurred() +#endif + +/* PyErrFetchRestore.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyErr_Clear() __Pyx_ErrRestore(NULL, NULL, NULL) +#define __Pyx_ErrRestoreWithState(type, value, tb) __Pyx_ErrRestoreInState(PyThreadState_GET(), type, value, tb) +#define __Pyx_ErrFetchWithState(type, value, tb) __Pyx_ErrFetchInState(PyThreadState_GET(), type, value, tb) +#define __Pyx_ErrRestore(type, value, tb) __Pyx_ErrRestoreInState(__pyx_tstate, type, value, tb) +#define __Pyx_ErrFetch(type, value, tb) __Pyx_ErrFetchInState(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb); +static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#if CYTHON_COMPILING_IN_CPYTHON +#define __Pyx_PyErr_SetNone(exc) (Py_INCREF(exc), __Pyx_ErrRestore((exc), NULL, NULL)) +#else +#define __Pyx_PyErr_SetNone(exc) PyErr_SetNone(exc) +#endif +#else +#define __Pyx_PyErr_Clear() PyErr_Clear() +#define __Pyx_PyErr_SetNone(exc) PyErr_SetNone(exc) +#define __Pyx_ErrRestoreWithState(type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetchWithState(type, value, tb) PyErr_Fetch(type, value, tb) +#define __Pyx_ErrRestoreInState(tstate, type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetchInState(tstate, type, value, tb) PyErr_Fetch(type, value, tb) +#define __Pyx_ErrRestore(type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetch(type, value, tb) PyErr_Fetch(type, value, tb) +#endif + +/* RaiseException.proto */ +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause); + +/* PyObjectCallMethO.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg); +#endif + +/* PyObjectCallOneArg.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg); + +/* GetItemInt.proto */ +#define __Pyx_GetItemInt(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_GetItemInt_Fast(o, (Py_ssize_t)i, is_list, wraparound, boundscheck) :\ + (is_list ? (PyErr_SetString(PyExc_IndexError, "list index out of range"), (PyObject*)NULL) :\ + __Pyx_GetItemInt_Generic(o, to_py_func(i)))) +#define __Pyx_GetItemInt_List(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_GetItemInt_List_Fast(o, (Py_ssize_t)i, wraparound, boundscheck) :\ + (PyErr_SetString(PyExc_IndexError, "list index out of range"), (PyObject*)NULL)) +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i, + int wraparound, int boundscheck); +#define __Pyx_GetItemInt_Tuple(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ + (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ + __Pyx_GetItemInt_Tuple_Fast(o, (Py_ssize_t)i, wraparound, boundscheck) :\ + (PyErr_SetString(PyExc_IndexError, "tuple index out of range"), (PyObject*)NULL)) +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i, + int wraparound, int boundscheck); +static PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j); +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, + int is_list, int wraparound, int boundscheck); + +/* ObjectGetItem.proto */ +#if CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PyObject *__Pyx_PyObject_GetItem(PyObject *obj, PyObject* key); +#else +#define __Pyx_PyObject_GetItem(obj, key) PyObject_GetItem(obj, key) +#endif + +/* PyObjectSetAttrStr.proto */ +#if CYTHON_USE_TYPE_SLOTS +#define __Pyx_PyObject_DelAttrStr(o,n) __Pyx_PyObject_SetAttrStr(o, n, NULL) +static CYTHON_INLINE int __Pyx_PyObject_SetAttrStr(PyObject* obj, PyObject* attr_name, PyObject* value); +#else +#define __Pyx_PyObject_DelAttrStr(o,n) PyObject_DelAttr(o,n) +#define __Pyx_PyObject_SetAttrStr(o,n,v) PyObject_SetAttr(o,n,v) +#endif + +/* pyobject_as_double.proto */ +static double __Pyx__PyObject_AsDouble(PyObject* obj); +#if CYTHON_COMPILING_IN_PYPY +#define __Pyx_PyObject_AsDouble(obj)\ +(likely(PyFloat_CheckExact(obj)) ? PyFloat_AS_DOUBLE(obj) :\ + likely(PyInt_CheckExact(obj)) ?\ + PyFloat_AsDouble(obj) : __Pyx__PyObject_AsDouble(obj)) +#else +#define __Pyx_PyObject_AsDouble(obj)\ +((likely(PyFloat_CheckExact(obj))) ?\ + PyFloat_AS_DOUBLE(obj) : __Pyx__PyObject_AsDouble(obj)) +#endif + +/* ListAppend.proto */ +#if CYTHON_USE_PYLIST_INTERNALS && CYTHON_ASSUME_SAFE_MACROS +static CYTHON_INLINE int __Pyx_PyList_Append(PyObject* list, PyObject* x) { + PyListObject* L = (PyListObject*) list; + Py_ssize_t len = Py_SIZE(list); + if (likely(L->allocated > len) & likely(len > (L->allocated >> 1))) { + Py_INCREF(x); + PyList_SET_ITEM(list, len, x); + __Pyx_SET_SIZE(list, len + 1); + return 0; + } + return PyList_Append(list, x); +} +#else +#define __Pyx_PyList_Append(L,x) PyList_Append(L,x) +#endif + +/* PyObjectCallNoArg.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func); +#else +#define __Pyx_PyObject_CallNoArg(func) __Pyx_PyObject_Call(func, __pyx_empty_tuple, NULL) +#endif + +/* IncludeStringH.proto */ +#include + +/* decode_c_string_utf16.proto */ +static CYTHON_INLINE PyObject *__Pyx_PyUnicode_DecodeUTF16(const char *s, Py_ssize_t size, const char *errors) { + int byteorder = 0; + return PyUnicode_DecodeUTF16(s, size, errors, &byteorder); +} +static CYTHON_INLINE PyObject *__Pyx_PyUnicode_DecodeUTF16LE(const char *s, Py_ssize_t size, const char *errors) { + int byteorder = -1; + return PyUnicode_DecodeUTF16(s, size, errors, &byteorder); +} +static CYTHON_INLINE PyObject *__Pyx_PyUnicode_DecodeUTF16BE(const char *s, Py_ssize_t size, const char *errors) { + int byteorder = 1; + return PyUnicode_DecodeUTF16(s, size, errors, &byteorder); +} + +/* decode_c_string.proto */ +static CYTHON_INLINE PyObject* __Pyx_decode_c_string( + const char* cstring, Py_ssize_t start, Py_ssize_t stop, + const char* encoding, const char* errors, + PyObject* (*decode_func)(const char *s, Py_ssize_t size, const char *errors)); + +/* GetException.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_GetException(type, value, tb) __Pyx__GetException(__pyx_tstate, type, value, tb) +static int __Pyx__GetException(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#else +static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb); +#endif + +/* SwapException.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_ExceptionSwap(type, value, tb) __Pyx__ExceptionSwap(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx__ExceptionSwap(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#else +static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value, PyObject **tb); +#endif + +/* GetTopmostException.proto */ +#if CYTHON_USE_EXC_INFO_STACK +static _PyErr_StackItem * __Pyx_PyErr_GetTopmostException(PyThreadState *tstate); +#endif + +/* SaveResetException.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_ExceptionSave(type, value, tb) __Pyx__ExceptionSave(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx__ExceptionSave(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#define __Pyx_ExceptionReset(type, value, tb) __Pyx__ExceptionReset(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb); +#else +#define __Pyx_ExceptionSave(type, value, tb) PyErr_GetExcInfo(type, value, tb) +#define __Pyx_ExceptionReset(type, value, tb) PyErr_SetExcInfo(type, value, tb) +#endif + +/* PyErrExceptionMatches.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyErr_ExceptionMatches(err) __Pyx_PyErr_ExceptionMatchesInState(__pyx_tstate, err) +static CYTHON_INLINE int __Pyx_PyErr_ExceptionMatchesInState(PyThreadState* tstate, PyObject* err); +#else +#define __Pyx_PyErr_ExceptionMatches(err) PyErr_ExceptionMatches(err) +#endif + +/* GetAttr.proto */ +static CYTHON_INLINE PyObject *__Pyx_GetAttr(PyObject *, PyObject *); + +/* GetAttr3.proto */ +static CYTHON_INLINE PyObject *__Pyx_GetAttr3(PyObject *, PyObject *, PyObject *); + +/* PyDictVersioning.proto */ +#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_TYPE_SLOTS +#define __PYX_DICT_VERSION_INIT ((PY_UINT64_T) -1) +#define __PYX_GET_DICT_VERSION(dict) (((PyDictObject*)(dict))->ma_version_tag) +#define __PYX_UPDATE_DICT_CACHE(dict, value, cache_var, version_var)\ + (version_var) = __PYX_GET_DICT_VERSION(dict);\ + (cache_var) = (value); +#define __PYX_PY_DICT_LOOKUP_IF_MODIFIED(VAR, DICT, LOOKUP) {\ + static PY_UINT64_T __pyx_dict_version = 0;\ + static PyObject *__pyx_dict_cached_value = NULL;\ + if (likely(__PYX_GET_DICT_VERSION(DICT) == __pyx_dict_version)) {\ + (VAR) = __pyx_dict_cached_value;\ + } else {\ + (VAR) = __pyx_dict_cached_value = (LOOKUP);\ + __pyx_dict_version = __PYX_GET_DICT_VERSION(DICT);\ + }\ +} +static CYTHON_INLINE PY_UINT64_T __Pyx_get_tp_dict_version(PyObject *obj); +static CYTHON_INLINE PY_UINT64_T __Pyx_get_object_dict_version(PyObject *obj); +static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UINT64_T tp_dict_version, PY_UINT64_T obj_dict_version); +#else +#define __PYX_GET_DICT_VERSION(dict) (0) +#define __PYX_UPDATE_DICT_CACHE(dict, value, cache_var, version_var) +#define __PYX_PY_DICT_LOOKUP_IF_MODIFIED(VAR, DICT, LOOKUP) (VAR) = (LOOKUP); +#endif + +/* GetModuleGlobalName.proto */ +#if CYTHON_USE_DICT_VERSIONS +#define __Pyx_GetModuleGlobalName(var, name) do {\ + static PY_UINT64_T __pyx_dict_version = 0;\ + static PyObject *__pyx_dict_cached_value = NULL;\ + (var) = (likely(__pyx_dict_version == __PYX_GET_DICT_VERSION(__pyx_d))) ?\ + (likely(__pyx_dict_cached_value) ? __Pyx_NewRef(__pyx_dict_cached_value) : __Pyx_GetBuiltinName(name)) :\ + __Pyx__GetModuleGlobalName(name, &__pyx_dict_version, &__pyx_dict_cached_value);\ +} while(0) +#define __Pyx_GetModuleGlobalNameUncached(var, name) do {\ + PY_UINT64_T __pyx_dict_version;\ + PyObject *__pyx_dict_cached_value;\ + (var) = __Pyx__GetModuleGlobalName(name, &__pyx_dict_version, &__pyx_dict_cached_value);\ +} while(0) +static PyObject *__Pyx__GetModuleGlobalName(PyObject *name, PY_UINT64_T *dict_version, PyObject **dict_cached_value); +#else +#define __Pyx_GetModuleGlobalName(var, name) (var) = __Pyx__GetModuleGlobalName(name) +#define __Pyx_GetModuleGlobalNameUncached(var, name) (var) = __Pyx__GetModuleGlobalName(name) +static CYTHON_INLINE PyObject *__Pyx__GetModuleGlobalName(PyObject *name); +#endif + +/* PySequenceContains.proto */ +static CYTHON_INLINE int __Pyx_PySequence_ContainsTF(PyObject* item, PyObject* seq, int eq) { + int result = PySequence_Contains(seq, item); + return unlikely(result < 0) ? result : (result == (eq == Py_EQ)); +} + +/* Import.proto */ +static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level); + +/* ImportFrom.proto */ +static PyObject* __Pyx_ImportFrom(PyObject* module, PyObject* name); + +/* PyObjectCall2Args.proto */ +static CYTHON_UNUSED PyObject* __Pyx_PyObject_Call2Args(PyObject* function, PyObject* arg1, PyObject* arg2); + +/* HasAttr.proto */ +static CYTHON_INLINE int __Pyx_HasAttr(PyObject *, PyObject *); + +/* PyObject_GenericGetAttrNoDict.proto */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static CYTHON_INLINE PyObject* __Pyx_PyObject_GenericGetAttrNoDict(PyObject* obj, PyObject* attr_name); +#else +#define __Pyx_PyObject_GenericGetAttrNoDict PyObject_GenericGetAttr +#endif + +/* PyObject_GenericGetAttr.proto */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_name); +#else +#define __Pyx_PyObject_GenericGetAttr PyObject_GenericGetAttr +#endif + +/* PyObjectGetAttrStrNoError.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name); + +/* SetupReduce.proto */ +static int __Pyx_setup_reduce(PyObject* type_obj); + +/* CalculateMetaclass.proto */ +static PyObject *__Pyx_CalculateMetaclass(PyTypeObject *metaclass, PyObject *bases); + +/* SetNameInClass.proto */ +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030500A1 +#define __Pyx_SetNameInClass(ns, name, value)\ + (likely(PyDict_CheckExact(ns)) ? _PyDict_SetItem_KnownHash(ns, name, value, ((PyASCIIObject *) name)->hash) : PyObject_SetItem(ns, name, value)) +#elif CYTHON_COMPILING_IN_CPYTHON +#define __Pyx_SetNameInClass(ns, name, value)\ + (likely(PyDict_CheckExact(ns)) ? PyDict_SetItem(ns, name, value) : PyObject_SetItem(ns, name, value)) +#else +#define __Pyx_SetNameInClass(ns, name, value) PyObject_SetItem(ns, name, value) +#endif + +/* FetchCommonType.proto */ +static PyTypeObject* __Pyx_FetchCommonType(PyTypeObject* type); + +/* CythonFunctionShared.proto */ +#define __Pyx_CyFunction_USED 1 +#define __Pyx_CYFUNCTION_STATICMETHOD 0x01 +#define __Pyx_CYFUNCTION_CLASSMETHOD 0x02 +#define __Pyx_CYFUNCTION_CCLASS 0x04 +#define __Pyx_CyFunction_GetClosure(f)\ + (((__pyx_CyFunctionObject *) (f))->func_closure) +#define __Pyx_CyFunction_GetClassObj(f)\ + (((__pyx_CyFunctionObject *) (f))->func_classobj) +#define __Pyx_CyFunction_Defaults(type, f)\ + ((type *)(((__pyx_CyFunctionObject *) (f))->defaults)) +#define __Pyx_CyFunction_SetDefaultsGetter(f, g)\ + ((__pyx_CyFunctionObject *) (f))->defaults_getter = (g) +typedef struct { + PyCFunctionObject func; +#if PY_VERSION_HEX < 0x030500A0 + PyObject *func_weakreflist; +#endif + PyObject *func_dict; + PyObject *func_name; + PyObject *func_qualname; + PyObject *func_doc; + PyObject *func_globals; + PyObject *func_code; + PyObject *func_closure; + PyObject *func_classobj; + void *defaults; + int defaults_pyobjects; + size_t defaults_size; // used by FusedFunction for copying defaults + int flags; + PyObject *defaults_tuple; + PyObject *defaults_kwdict; + PyObject *(*defaults_getter)(PyObject *); + PyObject *func_annotations; +} __pyx_CyFunctionObject; +static PyTypeObject *__pyx_CyFunctionType = 0; +#define __Pyx_CyFunction_Check(obj) (__Pyx_TypeCheck(obj, __pyx_CyFunctionType)) +static PyObject *__Pyx_CyFunction_Init(__pyx_CyFunctionObject* op, PyMethodDef *ml, + int flags, PyObject* qualname, + PyObject *self, + PyObject *module, PyObject *globals, + PyObject* code); +static CYTHON_INLINE void *__Pyx_CyFunction_InitDefaults(PyObject *m, + size_t size, + int pyobjects); +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsTuple(PyObject *m, + PyObject *tuple); +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsKwDict(PyObject *m, + PyObject *dict); +static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *m, + PyObject *dict); +static int __pyx_CyFunction_init(void); + +/* CythonFunction.proto */ +static PyObject *__Pyx_CyFunction_New(PyMethodDef *ml, + int flags, PyObject* qualname, + PyObject *closure, + PyObject *module, PyObject *globals, + PyObject* code); + +/* Py3ClassCreate.proto */ +static PyObject *__Pyx_Py3MetaclassPrepare(PyObject *metaclass, PyObject *bases, PyObject *name, PyObject *qualname, + PyObject *mkw, PyObject *modname, PyObject *doc); +static PyObject *__Pyx_Py3ClassCreate(PyObject *metaclass, PyObject *name, PyObject *bases, PyObject *dict, + PyObject *mkw, int calculate_metaclass, int allow_py2_metaclass); + +/* Globals.proto */ +static PyObject* __Pyx_Globals(void); + +/* CLineInTraceback.proto */ +#ifdef CYTHON_CLINE_IN_TRACEBACK +#define __Pyx_CLineForTraceback(tstate, c_line) (((CYTHON_CLINE_IN_TRACEBACK)) ? c_line : 0) +#else +static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line); +#endif + +/* CodeObjectCache.proto */ +typedef struct { + PyCodeObject* code_object; + int code_line; +} __Pyx_CodeObjectCacheEntry; +struct __Pyx_CodeObjectCache { + int count; + int max_count; + __Pyx_CodeObjectCacheEntry* entries; +}; +static struct __Pyx_CodeObjectCache __pyx_code_cache = {0,0,NULL}; +static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line); +static PyCodeObject *__pyx_find_code_object(int code_line); +static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object); + +/* AddTraceback.proto */ +static void __Pyx_AddTraceback(const char *funcname, int c_line, + int py_line, const char *filename); + +/* GCCDiagnostics.proto */ +#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) +#define __Pyx_HAS_GCC_DIAGNOSTIC +#endif + +/* CIntFromPy.proto */ +static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); + +/* CIntFromPy.proto */ +static CYTHON_INLINE size_t __Pyx_PyInt_As_size_t(PyObject *); + +/* CIntToPy.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); + +/* CIntFromPy.proto */ +static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *); + +/* CIntToPy.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum____pyx_t_6region_RegionType(enum __pyx_t_6region_RegionType value); + +/* FastTypeChecks.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +#define __Pyx_TypeCheck(obj, type) __Pyx_IsSubtype(Py_TYPE(obj), (PyTypeObject *)type) +static CYTHON_INLINE int __Pyx_IsSubtype(PyTypeObject *a, PyTypeObject *b); +static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches(PyObject *err, PyObject *type); +static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches2(PyObject *err, PyObject *type1, PyObject *type2); +#else +#define __Pyx_TypeCheck(obj, type) PyObject_TypeCheck(obj, (PyTypeObject *)type) +#define __Pyx_PyErr_GivenExceptionMatches(err, type) PyErr_GivenExceptionMatches(err, type) +#define __Pyx_PyErr_GivenExceptionMatches2(err, type1, type2) (PyErr_GivenExceptionMatches(err, type1) || PyErr_GivenExceptionMatches(err, type2)) +#endif +#define __Pyx_PyException_Check(obj) __Pyx_TypeCheck(obj, PyExc_Exception) + +/* CheckBinaryVersion.proto */ +static int __Pyx_check_binary_version(void); + +/* InitStrings.proto */ +static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); + + +/* Module declarations from 'libc.string' */ + +/* Module declarations from 'libc.stdlib' */ + +/* Module declarations from 'libc.stdio' */ + +/* Module declarations from 'c_region' */ + +/* Module declarations from 'region' */ +static PyTypeObject *__pyx_ptype_6region_RegionBounds = 0; +static PyTypeObject *__pyx_ptype_6region_Rectangle = 0; +static PyTypeObject *__pyx_ptype_6region_Polygon = 0; +static PyTypeObject *__pyx_ptype___Pyx_EnumMeta = 0; +static PyObject *__Pyx_OrderedDict = 0; +static PyObject *__Pyx_EnumBase = 0; +static PyObject *__Pyx_globals = 0; +static PyObject *__pyx_unpickle___Pyx_EnumMeta__set_state(struct __pyx_obj___Pyx_EnumMeta *, PyObject *); /*proto*/ +#define __Pyx_MODULE_NAME "region" +extern int __pyx_module_is_main_region; +int __pyx_module_is_main_region = 0; + +/* Implementation of 'region' */ +static PyObject *__pyx_builtin_MemoryError; +static PyObject *__pyx_builtin_TypeError; +static PyObject *__pyx_builtin_range; +static PyObject *__pyx_builtin_ValueError; +static const char __pyx_k_i[] = "i"; +static const char __pyx_k_v[] = "v"; +static const char __pyx_k_x[] = "x"; +static const char __pyx_k_y[] = "y"; +static const char __pyx_k__5[] = ""; +static const char __pyx_k_cls[] = "cls"; +static const char __pyx_k_dct[] = "dct"; +static const char __pyx_k_doc[] = "__doc__"; +static const char __pyx_k_inf[] = "inf"; +static const char __pyx_k_new[] = "__new__"; +static const char __pyx_k_num[] = "num"; +static const char __pyx_k_res[] = "res"; +static const char __pyx_k_ret[] = "ret"; +static const char __pyx_k_s_s[] = "%s.%s"; +static const char __pyx_k_set[] = "set"; +static const char __pyx_k_str[] = "__str__"; +static const char __pyx_k_top[] = "top"; +static const char __pyx_k_MASK[] = "MASK"; +static const char __pyx_k_dict[] = "__dict__"; +static const char __pyx_k_enum[] = "enum"; +static const char __pyx_k_init[] = "__init__"; +static const char __pyx_k_left[] = "left"; +static const char __pyx_k_main[] = "__main__"; +static const char __pyx_k_name[] = "name"; +static const char __pyx_k_repr[] = "__repr__"; +static const char __pyx_k_self[] = "self"; +static const char __pyx_k_test[] = "__test__"; +static const char __pyx_k_3f_3f[] = "({:.3f} {:.3f}) "; +static const char __pyx_k_EMTPY[] = "EMTPY"; +static const char __pyx_k_class[] = "__class__"; +static const char __pyx_k_only1[] = "only1"; +static const char __pyx_k_only2[] = "only2"; +static const char __pyx_k_range[] = "range"; +static const char __pyx_k_right[] = "right"; +static const char __pyx_k_s_s_d[] = "<%s.%s: %d>"; +static const char __pyx_k_value[] = "value"; +static const char __pyx_k_width[] = "width"; +static const char __pyx_k_bottom[] = "bottom"; +static const char __pyx_k_bounds[] = "bounds"; +static const char __pyx_k_encode[] = "encode"; +static const char __pyx_k_format[] = "format"; +static const char __pyx_k_height[] = "height"; +static const char __pyx_k_import[] = "__import__"; +static const char __pyx_k_module[] = "__module__"; +static const char __pyx_k_name_2[] = "__name__"; +static const char __pyx_k_output[] = "output"; +static const char __pyx_k_pickle[] = "pickle"; +static const char __pyx_k_points[] = "points"; +static const char __pyx_k_reduce[] = "__reduce__"; +static const char __pyx_k_region[] = "region"; +static const char __pyx_k_update[] = "update"; +static const char __pyx_k_values[] = "values"; +static const char __pyx_k_3f_3f_2[] = "({:.3f} {:.3f})"; +static const char __pyx_k_IntEnum[] = "IntEnum"; +static const char __pyx_k_POLYGON[] = "POLYGON"; +static const char __pyx_k_Polygon[] = "Polygon"; +static const char __pyx_k_SPECIAL[] = "SPECIAL"; +static const char __pyx_k_members[] = "__members__"; +static const char __pyx_k_overlap[] = "overlap"; +static const char __pyx_k_parents[] = "parents"; +static const char __pyx_k_prepare[] = "__prepare__"; +static const char __pyx_k_EnumBase[] = "EnumBase"; +static const char __pyx_k_EnumType[] = "EnumType"; +static const char __pyx_k_getstate[] = "__getstate__"; +static const char __pyx_k_overlaps[] = "overlaps"; +static const char __pyx_k_polygon1[] = "polygon1"; +static const char __pyx_k_polygon2[] = "polygon2"; +static const char __pyx_k_pyx_type[] = "__pyx_type"; +static const char __pyx_k_qualname[] = "__qualname__"; +static const char __pyx_k_setstate[] = "__setstate__"; +static const char __pyx_k_template[] = "template"; +static const char __pyx_k_RECTANGEL[] = "RECTANGEL"; +static const char __pyx_k_Rectangle[] = "Rectangle"; +static const char __pyx_k_TypeError[] = "TypeError"; +static const char __pyx_k_ctemplate[] = "ctemplate"; +static const char __pyx_k_metaclass[] = "__metaclass__"; +static const char __pyx_k_no_bounds[] = "no_bounds"; +static const char __pyx_k_polygons1[] = "polygons1"; +static const char __pyx_k_polygons2[] = "polygons2"; +static const char __pyx_k_ptemplate[] = "ptemplate"; +static const char __pyx_k_pyx_state[] = "__pyx_state"; +static const char __pyx_k_reduce_ex[] = "__reduce_ex__"; +static const char __pyx_k_RegionType[] = "RegionType"; +static const char __pyx_k_ValueError[] = "ValueError"; +static const char __pyx_k_c_polygon1[] = "c_polygon1"; +static const char __pyx_k_c_polygon2[] = "c_polygon2"; +static const char __pyx_k_polygon1_2[] = "polygon1_"; +static const char __pyx_k_polygon2_2[] = "polygon2_"; +static const char __pyx_k_pyx_result[] = "__pyx_result"; +static const char __pyx_k_region_pyx[] = "region.pyx"; +static const char __pyx_k_MemoryError[] = "MemoryError"; +static const char __pyx_k_OrderedDict[] = "OrderedDict"; +static const char __pyx_k_PickleError[] = "PickleError"; +static const char __pyx_k_collections[] = "collections"; +static const char __pyx_k_vot_overlap[] = "vot_overlap"; +static const char __pyx_k_Pyx_EnumBase[] = "__Pyx_EnumBase"; +static const char __pyx_k_RegionBounds[] = "RegionBounds"; +static const char __pyx_k_pyx_checksum[] = "__pyx_checksum"; +static const char __pyx_k_stringsource[] = "stringsource"; +static const char __pyx_k_reduce_cython[] = "__reduce_cython__"; +static const char __pyx_k_vot_float2str[] = "vot_float2str"; +static const char __pyx_k_pyx_PickleError[] = "__pyx_PickleError"; +static const char __pyx_k_setstate_cython[] = "__setstate_cython__"; +static const char __pyx_k_vot_overlap_traj[] = "vot_overlap_traj"; +static const char __pyx_k_Pyx_EnumBase___new[] = "__Pyx_EnumBase.__new__"; +static const char __pyx_k_Pyx_EnumBase___str[] = "__Pyx_EnumBase.__str__"; +static const char __pyx_k_cline_in_traceback[] = "cline_in_traceback"; +static const char __pyx_k_Pyx_EnumBase___repr[] = "__Pyx_EnumBase.__repr__"; +static const char __pyx_k_Unknown_enum_value_s[] = "Unknown enum value: '%s'"; +static const char __pyx_k_pyx_unpickle___Pyx_EnumMeta[] = "__pyx_unpickle___Pyx_EnumMeta"; +static const char __pyx_k_x_3f_y_3f_width_3f_height_3f[] = "x: {:.3f} y: {:.3f} width: {:.3f} height: {:.3f}"; +static const char __pyx_k_top_3f_bottom_3f_left_3f_reight[] = "top: {:.3f} bottom: {:.3f} left: {:.3f} reight: {:.3f}"; +static const char __pyx_k_Incompatible_checksums_0x_x_vs_0[] = "Incompatible checksums (0x%x vs (0xd41d8cd, 0xe3b0c44, 0xda39a3e) = ())"; +static const char __pyx_k_no_default___reduce___due_to_non[] = "no default __reduce__ due to non-trivial __cinit__"; +static PyObject *__pyx_kp_s_3f_3f; +static PyObject *__pyx_kp_s_3f_3f_2; +static PyObject *__pyx_n_s_EMTPY; +static PyObject *__pyx_n_s_EnumBase; +static PyObject *__pyx_n_s_EnumType; +static PyObject *__pyx_kp_s_Incompatible_checksums_0x_x_vs_0; +static PyObject *__pyx_n_s_IntEnum; +static PyObject *__pyx_n_s_MASK; +static PyObject *__pyx_n_s_MemoryError; +static PyObject *__pyx_n_s_OrderedDict; +static PyObject *__pyx_n_s_POLYGON; +static PyObject *__pyx_n_s_PickleError; +static PyObject *__pyx_n_s_Polygon; +static PyObject *__pyx_n_s_Pyx_EnumBase; +static PyObject *__pyx_n_s_Pyx_EnumBase___new; +static PyObject *__pyx_n_s_Pyx_EnumBase___repr; +static PyObject *__pyx_n_s_Pyx_EnumBase___str; +static PyObject *__pyx_n_s_RECTANGEL; +static PyObject *__pyx_n_s_Rectangle; +static PyObject *__pyx_n_s_RegionBounds; +static PyObject *__pyx_n_s_RegionType; +static PyObject *__pyx_n_s_SPECIAL; +static PyObject *__pyx_n_s_TypeError; +static PyObject *__pyx_kp_s_Unknown_enum_value_s; +static PyObject *__pyx_n_s_ValueError; +static PyObject *__pyx_kp_s__5; +static PyObject *__pyx_n_s_bottom; +static PyObject *__pyx_n_s_bounds; +static PyObject *__pyx_n_s_c_polygon1; +static PyObject *__pyx_n_s_c_polygon2; +static PyObject *__pyx_n_s_class; +static PyObject *__pyx_n_s_cline_in_traceback; +static PyObject *__pyx_n_s_cls; +static PyObject *__pyx_n_s_collections; +static PyObject *__pyx_n_s_ctemplate; +static PyObject *__pyx_n_s_dct; +static PyObject *__pyx_n_s_dict; +static PyObject *__pyx_n_s_doc; +static PyObject *__pyx_n_s_encode; +static PyObject *__pyx_n_s_enum; +static PyObject *__pyx_n_s_format; +static PyObject *__pyx_n_s_getstate; +static PyObject *__pyx_n_s_height; +static PyObject *__pyx_n_s_i; +static PyObject *__pyx_n_s_import; +static PyObject *__pyx_n_s_inf; +static PyObject *__pyx_n_s_init; +static PyObject *__pyx_n_s_left; +static PyObject *__pyx_n_s_main; +static PyObject *__pyx_n_s_members; +static PyObject *__pyx_n_s_metaclass; +static PyObject *__pyx_n_s_module; +static PyObject *__pyx_n_s_name; +static PyObject *__pyx_n_s_name_2; +static PyObject *__pyx_n_s_new; +static PyObject *__pyx_n_s_no_bounds; +static PyObject *__pyx_kp_s_no_default___reduce___due_to_non; +static PyObject *__pyx_n_s_num; +static PyObject *__pyx_n_s_only1; +static PyObject *__pyx_n_s_only2; +static PyObject *__pyx_n_s_output; +static PyObject *__pyx_n_s_overlap; +static PyObject *__pyx_n_s_overlaps; +static PyObject *__pyx_n_s_parents; +static PyObject *__pyx_n_s_pickle; +static PyObject *__pyx_n_s_points; +static PyObject *__pyx_n_s_polygon1; +static PyObject *__pyx_n_s_polygon1_2; +static PyObject *__pyx_n_s_polygon2; +static PyObject *__pyx_n_s_polygon2_2; +static PyObject *__pyx_n_s_polygons1; +static PyObject *__pyx_n_s_polygons2; +static PyObject *__pyx_n_s_prepare; +static PyObject *__pyx_n_s_ptemplate; +static PyObject *__pyx_n_s_pyx_PickleError; +static PyObject *__pyx_n_s_pyx_checksum; +static PyObject *__pyx_n_s_pyx_result; +static PyObject *__pyx_n_s_pyx_state; +static PyObject *__pyx_n_s_pyx_type; +static PyObject *__pyx_n_s_pyx_unpickle___Pyx_EnumMeta; +static PyObject *__pyx_n_s_qualname; +static PyObject *__pyx_n_s_range; +static PyObject *__pyx_n_s_reduce; +static PyObject *__pyx_n_s_reduce_cython; +static PyObject *__pyx_n_s_reduce_ex; +static PyObject *__pyx_n_s_region; +static PyObject *__pyx_kp_s_region_pyx; +static PyObject *__pyx_n_s_repr; +static PyObject *__pyx_n_s_res; +static PyObject *__pyx_n_s_ret; +static PyObject *__pyx_n_s_right; +static PyObject *__pyx_kp_s_s_s; +static PyObject *__pyx_kp_s_s_s_d; +static PyObject *__pyx_n_s_self; +static PyObject *__pyx_n_s_set; +static PyObject *__pyx_n_s_setstate; +static PyObject *__pyx_n_s_setstate_cython; +static PyObject *__pyx_n_s_str; +static PyObject *__pyx_kp_s_stringsource; +static PyObject *__pyx_n_s_template; +static PyObject *__pyx_n_s_test; +static PyObject *__pyx_n_s_top; +static PyObject *__pyx_kp_s_top_3f_bottom_3f_left_3f_reight; +static PyObject *__pyx_n_s_update; +static PyObject *__pyx_n_s_v; +static PyObject *__pyx_n_s_value; +static PyObject *__pyx_n_s_values; +static PyObject *__pyx_n_s_vot_float2str; +static PyObject *__pyx_n_s_vot_overlap; +static PyObject *__pyx_n_s_vot_overlap_traj; +static PyObject *__pyx_n_s_width; +static PyObject *__pyx_n_s_x; +static PyObject *__pyx_kp_s_x_3f_y_3f_width_3f_height_3f; +static PyObject *__pyx_n_s_y; +static int __pyx_pf_6region_12RegionBounds___cinit__(struct __pyx_obj_6region_RegionBounds *__pyx_v_self); /* proto */ +static int __pyx_pf_6region_12RegionBounds_2__init__(struct __pyx_obj_6region_RegionBounds *__pyx_v_self, PyObject *__pyx_v_top, PyObject *__pyx_v_bottom, PyObject *__pyx_v_left, PyObject *__pyx_v_right); /* proto */ +static void __pyx_pf_6region_12RegionBounds_4__dealloc__(struct __pyx_obj_6region_RegionBounds *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_6region_12RegionBounds_6__str__(struct __pyx_obj_6region_RegionBounds *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_6region_12RegionBounds_8get(struct __pyx_obj_6region_RegionBounds *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_6region_12RegionBounds_10set(struct __pyx_obj_6region_RegionBounds *__pyx_v_self, PyObject *__pyx_v_top, PyObject *__pyx_v_bottom, PyObject *__pyx_v_left, PyObject *__pyx_v_right); /* proto */ +static PyObject *__pyx_pf_6region_12RegionBounds_12__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_6region_RegionBounds *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_6region_12RegionBounds_14__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_6region_RegionBounds *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */ +static int __pyx_pf_6region_9Rectangle___cinit__(struct __pyx_obj_6region_Rectangle *__pyx_v_self); /* proto */ +static int __pyx_pf_6region_9Rectangle_2__init__(struct __pyx_obj_6region_Rectangle *__pyx_v_self, PyObject *__pyx_v_x, PyObject *__pyx_v_y, PyObject *__pyx_v_width, PyObject *__pyx_v_height); /* proto */ +static void __pyx_pf_6region_9Rectangle_4__dealloc__(struct __pyx_obj_6region_Rectangle *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_6region_9Rectangle_6__str__(struct __pyx_obj_6region_Rectangle *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_6region_9Rectangle_8set(struct __pyx_obj_6region_Rectangle *__pyx_v_self, PyObject *__pyx_v_x, PyObject *__pyx_v_y, PyObject *__pyx_v_width, PyObject *__pyx_v_height); /* proto */ +static PyObject *__pyx_pf_6region_9Rectangle_10get(struct __pyx_obj_6region_Rectangle *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_6region_9Rectangle_12__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_6region_Rectangle *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_6region_9Rectangle_14__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_6region_Rectangle *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */ +static int __pyx_pf_6region_7Polygon___cinit__(struct __pyx_obj_6region_Polygon *__pyx_v_self, PyObject *__pyx_v_points); /* proto */ +static void __pyx_pf_6region_7Polygon_2__dealloc__(struct __pyx_obj_6region_Polygon *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_6region_7Polygon_4__str__(struct __pyx_obj_6region_Polygon *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_6region_7Polygon_6__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_6region_Polygon *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_6region_7Polygon_8__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_6region_Polygon *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */ +static PyObject *__pyx_pf_6region_vot_overlap(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_polygon1, PyObject *__pyx_v_polygon2, PyObject *__pyx_v_bounds); /* proto */ +static PyObject *__pyx_pf_6region_2vot_overlap_traj(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_polygons1, PyObject *__pyx_v_polygons2, CYTHON_UNUSED PyObject *__pyx_v_bounds); /* proto */ +static PyObject *__pyx_pf_6region_4vot_float2str(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_template, float __pyx_v_value); /* proto */ +static int __pyx_pf_8EnumBase_14__Pyx_EnumMeta___init__(struct __pyx_obj___Pyx_EnumMeta *__pyx_v_cls, PyObject *__pyx_v_name, PyObject *__pyx_v_parents, PyObject *__pyx_v_dct); /* proto */ +static PyObject *__pyx_pf_8EnumBase_14__Pyx_EnumMeta_2__iter__(struct __pyx_obj___Pyx_EnumMeta *__pyx_v_cls); /* proto */ +static PyObject *__pyx_pf_8EnumBase_14__Pyx_EnumMeta_4__getitem__(struct __pyx_obj___Pyx_EnumMeta *__pyx_v_cls, PyObject *__pyx_v_name); /* proto */ +static PyObject *__pyx_pf_8EnumBase_14__Pyx_EnumMeta_6__reduce_cython__(struct __pyx_obj___Pyx_EnumMeta *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_8EnumBase_14__Pyx_EnumMeta_8__setstate_cython__(struct __pyx_obj___Pyx_EnumMeta *__pyx_v_self, PyObject *__pyx_v___pyx_state); /* proto */ +static PyObject *__pyx_pf_8EnumBase_14__Pyx_EnumBase___new__(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_cls, PyObject *__pyx_v_value, PyObject *__pyx_v_name); /* proto */ +static PyObject *__pyx_pf_8EnumBase_14__Pyx_EnumBase_2__repr__(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_8EnumBase_14__Pyx_EnumBase_4__str__(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */ +static PyObject *__pyx_pf_8EnumBase___pyx_unpickle___Pyx_EnumMeta(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v___pyx_type, long __pyx_v___pyx_checksum, PyObject *__pyx_v___pyx_state); /* proto */ +static PyObject *__pyx_tp_new_6region_RegionBounds(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new_6region_Rectangle(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new_6region_Polygon(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_tp_new___Pyx_EnumMeta(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ +static PyObject *__pyx_int_222419149; +static PyObject *__pyx_int_228825662; +static PyObject *__pyx_int_238750788; +static PyObject *__pyx_tuple_; +static PyObject *__pyx_tuple__2; +static PyObject *__pyx_tuple__3; +static PyObject *__pyx_tuple__4; +static PyObject *__pyx_tuple__6; +static PyObject *__pyx_tuple__7; +static PyObject *__pyx_tuple__8; +static PyObject *__pyx_tuple__9; +static PyObject *__pyx_tuple__11; +static PyObject *__pyx_tuple__13; +static PyObject *__pyx_tuple__15; +static PyObject *__pyx_tuple__17; +static PyObject *__pyx_tuple__18; +static PyObject *__pyx_tuple__20; +static PyObject *__pyx_tuple__22; +static PyObject *__pyx_codeobj__10; +static PyObject *__pyx_codeobj__12; +static PyObject *__pyx_codeobj__14; +static PyObject *__pyx_codeobj__16; +static PyObject *__pyx_codeobj__19; +static PyObject *__pyx_codeobj__21; +static PyObject *__pyx_codeobj__23; +/* Late includes */ + +/* "region.pyx":20 + * cdef c_region.region_bounds* _c_region_bounds + * + * def __cinit__(self): # <<<<<<<<<<<<<< + * self._c_region_bounds = malloc( + * sizeof(c_region.region_bounds)) + */ + +/* Python wrapper */ +static int __pyx_pw_6region_12RegionBounds_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static int __pyx_pw_6region_12RegionBounds_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0); + if (unlikely(PyTuple_GET_SIZE(__pyx_args) > 0)) { + __Pyx_RaiseArgtupleInvalid("__cinit__", 1, 0, 0, PyTuple_GET_SIZE(__pyx_args)); return -1;} + if (unlikely(__pyx_kwds) && unlikely(PyDict_Size(__pyx_kwds) > 0) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "__cinit__", 0))) return -1; + __pyx_r = __pyx_pf_6region_12RegionBounds___cinit__(((struct __pyx_obj_6region_RegionBounds *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_pf_6region_12RegionBounds___cinit__(struct __pyx_obj_6region_RegionBounds *__pyx_v_self) { + int __pyx_r; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__cinit__", 0); + + /* "region.pyx":21 + * + * def __cinit__(self): + * self._c_region_bounds = malloc( # <<<<<<<<<<<<<< + * sizeof(c_region.region_bounds)) + * if not self._c_region_bounds: + */ + __pyx_v_self->_c_region_bounds = ((region_bounds *)malloc((sizeof(region_bounds)))); + + /* "region.pyx":23 + * self._c_region_bounds = malloc( + * sizeof(c_region.region_bounds)) + * if not self._c_region_bounds: # <<<<<<<<<<<<<< + * self._c_region_bounds = NULL + * raise MemoryError() + */ + __pyx_t_1 = ((!(__pyx_v_self->_c_region_bounds != 0)) != 0); + if (unlikely(__pyx_t_1)) { + + /* "region.pyx":24 + * sizeof(c_region.region_bounds)) + * if not self._c_region_bounds: + * self._c_region_bounds = NULL # <<<<<<<<<<<<<< + * raise MemoryError() + * + */ + __pyx_v_self->_c_region_bounds = NULL; + + /* "region.pyx":25 + * if not self._c_region_bounds: + * self._c_region_bounds = NULL + * raise MemoryError() # <<<<<<<<<<<<<< + * + * def __init__(self, top, bottom, left, right): + */ + PyErr_NoMemory(); __PYX_ERR(0, 25, __pyx_L1_error) + + /* "region.pyx":23 + * self._c_region_bounds = malloc( + * sizeof(c_region.region_bounds)) + * if not self._c_region_bounds: # <<<<<<<<<<<<<< + * self._c_region_bounds = NULL + * raise MemoryError() + */ + } + + /* "region.pyx":20 + * cdef c_region.region_bounds* _c_region_bounds + * + * def __cinit__(self): # <<<<<<<<<<<<<< + * self._c_region_bounds = malloc( + * sizeof(c_region.region_bounds)) + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_AddTraceback("region.RegionBounds.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "region.pyx":27 + * raise MemoryError() + * + * def __init__(self, top, bottom, left, right): # <<<<<<<<<<<<<< + * self.set(top, bottom, left, right) + * + */ + +/* Python wrapper */ +static int __pyx_pw_6region_12RegionBounds_3__init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static int __pyx_pw_6region_12RegionBounds_3__init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_top = 0; + PyObject *__pyx_v_bottom = 0; + PyObject *__pyx_v_left = 0; + PyObject *__pyx_v_right = 0; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__init__ (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_top,&__pyx_n_s_bottom,&__pyx_n_s_left,&__pyx_n_s_right,0}; + PyObject* values[4] = {0,0,0,0}; + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_top)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_bottom)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("__init__", 1, 4, 4, 1); __PYX_ERR(0, 27, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_left)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("__init__", 1, 4, 4, 2); __PYX_ERR(0, 27, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 3: + if (likely((values[3] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_right)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("__init__", 1, 4, 4, 3); __PYX_ERR(0, 27, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__init__") < 0)) __PYX_ERR(0, 27, __pyx_L3_error) + } + } else if (PyTuple_GET_SIZE(__pyx_args) != 4) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + } + __pyx_v_top = values[0]; + __pyx_v_bottom = values[1]; + __pyx_v_left = values[2]; + __pyx_v_right = values[3]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__init__", 1, 4, 4, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 27, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("region.RegionBounds.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return -1; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6region_12RegionBounds_2__init__(((struct __pyx_obj_6region_RegionBounds *)__pyx_v_self), __pyx_v_top, __pyx_v_bottom, __pyx_v_left, __pyx_v_right); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_pf_6region_12RegionBounds_2__init__(struct __pyx_obj_6region_RegionBounds *__pyx_v_self, PyObject *__pyx_v_top, PyObject *__pyx_v_bottom, PyObject *__pyx_v_left, PyObject *__pyx_v_right) { + int __pyx_r; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__init__", 0); + + /* "region.pyx":28 + * + * def __init__(self, top, bottom, left, right): + * self.set(top, bottom, left, right) # <<<<<<<<<<<<<< + * + * def __dealloc__(self): + */ + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_set); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 28, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = NULL; + __pyx_t_4 = 0; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + __pyx_t_4 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[5] = {__pyx_t_3, __pyx_v_top, __pyx_v_bottom, __pyx_v_left, __pyx_v_right}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_2, __pyx_temp+1-__pyx_t_4, 4+__pyx_t_4); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 28, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[5] = {__pyx_t_3, __pyx_v_top, __pyx_v_bottom, __pyx_v_left, __pyx_v_right}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_2, __pyx_temp+1-__pyx_t_4, 4+__pyx_t_4); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 28, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + { + __pyx_t_5 = PyTuple_New(4+__pyx_t_4); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 28, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (__pyx_t_3) { + __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_3); __pyx_t_3 = NULL; + } + __Pyx_INCREF(__pyx_v_top); + __Pyx_GIVEREF(__pyx_v_top); + PyTuple_SET_ITEM(__pyx_t_5, 0+__pyx_t_4, __pyx_v_top); + __Pyx_INCREF(__pyx_v_bottom); + __Pyx_GIVEREF(__pyx_v_bottom); + PyTuple_SET_ITEM(__pyx_t_5, 1+__pyx_t_4, __pyx_v_bottom); + __Pyx_INCREF(__pyx_v_left); + __Pyx_GIVEREF(__pyx_v_left); + PyTuple_SET_ITEM(__pyx_t_5, 2+__pyx_t_4, __pyx_v_left); + __Pyx_INCREF(__pyx_v_right); + __Pyx_GIVEREF(__pyx_v_right); + PyTuple_SET_ITEM(__pyx_t_5, 3+__pyx_t_4, __pyx_v_right); + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_5, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 28, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + } + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "region.pyx":27 + * raise MemoryError() + * + * def __init__(self, top, bottom, left, right): # <<<<<<<<<<<<<< + * self.set(top, bottom, left, right) + * + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("region.RegionBounds.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "region.pyx":30 + * self.set(top, bottom, left, right) + * + * def __dealloc__(self): # <<<<<<<<<<<<<< + * if self._c_region_bounds is not NULL: + * free(self._c_region_bounds) + */ + +/* Python wrapper */ +static void __pyx_pw_6region_12RegionBounds_5__dealloc__(PyObject *__pyx_v_self); /*proto*/ +static void __pyx_pw_6region_12RegionBounds_5__dealloc__(PyObject *__pyx_v_self) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__dealloc__ (wrapper)", 0); + __pyx_pf_6region_12RegionBounds_4__dealloc__(((struct __pyx_obj_6region_RegionBounds *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); +} + +static void __pyx_pf_6region_12RegionBounds_4__dealloc__(struct __pyx_obj_6region_RegionBounds *__pyx_v_self) { + __Pyx_RefNannyDeclarations + int __pyx_t_1; + __Pyx_RefNannySetupContext("__dealloc__", 0); + + /* "region.pyx":31 + * + * def __dealloc__(self): + * if self._c_region_bounds is not NULL: # <<<<<<<<<<<<<< + * free(self._c_region_bounds) + * self._c_region_bounds = NULL + */ + __pyx_t_1 = ((__pyx_v_self->_c_region_bounds != NULL) != 0); + if (__pyx_t_1) { + + /* "region.pyx":32 + * def __dealloc__(self): + * if self._c_region_bounds is not NULL: + * free(self._c_region_bounds) # <<<<<<<<<<<<<< + * self._c_region_bounds = NULL + * + */ + free(__pyx_v_self->_c_region_bounds); + + /* "region.pyx":33 + * if self._c_region_bounds is not NULL: + * free(self._c_region_bounds) + * self._c_region_bounds = NULL # <<<<<<<<<<<<<< + * + * def __str__(self): + */ + __pyx_v_self->_c_region_bounds = NULL; + + /* "region.pyx":31 + * + * def __dealloc__(self): + * if self._c_region_bounds is not NULL: # <<<<<<<<<<<<<< + * free(self._c_region_bounds) + * self._c_region_bounds = NULL + */ + } + + /* "region.pyx":30 + * self.set(top, bottom, left, right) + * + * def __dealloc__(self): # <<<<<<<<<<<<<< + * if self._c_region_bounds is not NULL: + * free(self._c_region_bounds) + */ + + /* function exit code */ + __Pyx_RefNannyFinishContext(); +} + +/* "region.pyx":35 + * self._c_region_bounds = NULL + * + * def __str__(self): # <<<<<<<<<<<<<< + * return "top: {:.3f} bottom: {:.3f} left: {:.3f} reight: {:.3f}".format( + * self._c_region_bounds.top, + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6region_12RegionBounds_7__str__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_6region_12RegionBounds_7__str__(PyObject *__pyx_v_self) { + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__str__ (wrapper)", 0); + __pyx_r = __pyx_pf_6region_12RegionBounds_6__str__(((struct __pyx_obj_6region_RegionBounds *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6region_12RegionBounds_6__str__(struct __pyx_obj_6region_RegionBounds *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + int __pyx_t_8; + PyObject *__pyx_t_9 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__str__", 0); + + /* "region.pyx":36 + * + * def __str__(self): + * return "top: {:.3f} bottom: {:.3f} left: {:.3f} reight: {:.3f}".format( # <<<<<<<<<<<<<< + * self._c_region_bounds.top, + * self._c_region_bounds.bottom, + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_kp_s_top_3f_bottom_3f_left_3f_reight, __pyx_n_s_format); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 36, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + + /* "region.pyx":37 + * def __str__(self): + * return "top: {:.3f} bottom: {:.3f} left: {:.3f} reight: {:.3f}".format( + * self._c_region_bounds.top, # <<<<<<<<<<<<<< + * self._c_region_bounds.bottom, + * self._c_region_bounds.left, + */ + __pyx_t_3 = PyFloat_FromDouble(__pyx_v_self->_c_region_bounds->top); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 37, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + + /* "region.pyx":38 + * return "top: {:.3f} bottom: {:.3f} left: {:.3f} reight: {:.3f}".format( + * self._c_region_bounds.top, + * self._c_region_bounds.bottom, # <<<<<<<<<<<<<< + * self._c_region_bounds.left, + * self._c_region_bounds.right) + */ + __pyx_t_4 = PyFloat_FromDouble(__pyx_v_self->_c_region_bounds->bottom); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 38, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + + /* "region.pyx":39 + * self._c_region_bounds.top, + * self._c_region_bounds.bottom, + * self._c_region_bounds.left, # <<<<<<<<<<<<<< + * self._c_region_bounds.right) + * + */ + __pyx_t_5 = PyFloat_FromDouble(__pyx_v_self->_c_region_bounds->left); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 39, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + + /* "region.pyx":40 + * self._c_region_bounds.bottom, + * self._c_region_bounds.left, + * self._c_region_bounds.right) # <<<<<<<<<<<<<< + * + * def get(self): + */ + __pyx_t_6 = PyFloat_FromDouble(__pyx_v_self->_c_region_bounds->right); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 40, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_7 = NULL; + __pyx_t_8 = 0; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + __pyx_t_8 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[5] = {__pyx_t_7, __pyx_t_3, __pyx_t_4, __pyx_t_5, __pyx_t_6}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_2, __pyx_temp+1-__pyx_t_8, 4+__pyx_t_8); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 36, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[5] = {__pyx_t_7, __pyx_t_3, __pyx_t_4, __pyx_t_5, __pyx_t_6}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_2, __pyx_temp+1-__pyx_t_8, 4+__pyx_t_8); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 36, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else + #endif + { + __pyx_t_9 = PyTuple_New(4+__pyx_t_8); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 36, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + if (__pyx_t_7) { + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_7); __pyx_t_7 = NULL; + } + __Pyx_GIVEREF(__pyx_t_3); + PyTuple_SET_ITEM(__pyx_t_9, 0+__pyx_t_8, __pyx_t_3); + __Pyx_GIVEREF(__pyx_t_4); + PyTuple_SET_ITEM(__pyx_t_9, 1+__pyx_t_8, __pyx_t_4); + __Pyx_GIVEREF(__pyx_t_5); + PyTuple_SET_ITEM(__pyx_t_9, 2+__pyx_t_8, __pyx_t_5); + __Pyx_GIVEREF(__pyx_t_6); + PyTuple_SET_ITEM(__pyx_t_9, 3+__pyx_t_8, __pyx_t_6); + __pyx_t_3 = 0; + __pyx_t_4 = 0; + __pyx_t_5 = 0; + __pyx_t_6 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_9, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 36, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "region.pyx":35 + * self._c_region_bounds = NULL + * + * def __str__(self): # <<<<<<<<<<<<<< + * return "top: {:.3f} bottom: {:.3f} left: {:.3f} reight: {:.3f}".format( + * self._c_region_bounds.top, + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_AddTraceback("region.RegionBounds.__str__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "region.pyx":42 + * self._c_region_bounds.right) + * + * def get(self): # <<<<<<<<<<<<<< + * return (self._c_region_bounds.top, + * self._c_region_bounds.bottom, + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6region_12RegionBounds_9get(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/ +static PyObject *__pyx_pw_6region_12RegionBounds_9get(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) { + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("get (wrapper)", 0); + __pyx_r = __pyx_pf_6region_12RegionBounds_8get(((struct __pyx_obj_6region_RegionBounds *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6region_12RegionBounds_8get(struct __pyx_obj_6region_RegionBounds *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("get", 0); + + /* "region.pyx":43 + * + * def get(self): + * return (self._c_region_bounds.top, # <<<<<<<<<<<<<< + * self._c_region_bounds.bottom, + * self._c_region_bounds.left, + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PyFloat_FromDouble(__pyx_v_self->_c_region_bounds->top); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 43, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + + /* "region.pyx":44 + * def get(self): + * return (self._c_region_bounds.top, + * self._c_region_bounds.bottom, # <<<<<<<<<<<<<< + * self._c_region_bounds.left, + * self._c_region_bounds.right) + */ + __pyx_t_2 = PyFloat_FromDouble(__pyx_v_self->_c_region_bounds->bottom); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 44, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + + /* "region.pyx":45 + * return (self._c_region_bounds.top, + * self._c_region_bounds.bottom, + * self._c_region_bounds.left, # <<<<<<<<<<<<<< + * self._c_region_bounds.right) + * + */ + __pyx_t_3 = PyFloat_FromDouble(__pyx_v_self->_c_region_bounds->left); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 45, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + + /* "region.pyx":46 + * self._c_region_bounds.bottom, + * self._c_region_bounds.left, + * self._c_region_bounds.right) # <<<<<<<<<<<<<< + * + * def set(self, top, bottom, left, right): + */ + __pyx_t_4 = PyFloat_FromDouble(__pyx_v_self->_c_region_bounds->right); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 46, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + + /* "region.pyx":43 + * + * def get(self): + * return (self._c_region_bounds.top, # <<<<<<<<<<<<<< + * self._c_region_bounds.bottom, + * self._c_region_bounds.left, + */ + __pyx_t_5 = PyTuple_New(4); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 43, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_1); + __Pyx_GIVEREF(__pyx_t_2); + PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_t_2); + __Pyx_GIVEREF(__pyx_t_3); + PyTuple_SET_ITEM(__pyx_t_5, 2, __pyx_t_3); + __Pyx_GIVEREF(__pyx_t_4); + PyTuple_SET_ITEM(__pyx_t_5, 3, __pyx_t_4); + __pyx_t_1 = 0; + __pyx_t_2 = 0; + __pyx_t_3 = 0; + __pyx_t_4 = 0; + __pyx_r = __pyx_t_5; + __pyx_t_5 = 0; + goto __pyx_L0; + + /* "region.pyx":42 + * self._c_region_bounds.right) + * + * def get(self): # <<<<<<<<<<<<<< + * return (self._c_region_bounds.top, + * self._c_region_bounds.bottom, + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("region.RegionBounds.get", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "region.pyx":48 + * self._c_region_bounds.right) + * + * def set(self, top, bottom, left, right): # <<<<<<<<<<<<<< + * self._c_region_bounds.top = top + * self._c_region_bounds.bottom = bottom + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6region_12RegionBounds_11set(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static PyObject *__pyx_pw_6region_12RegionBounds_11set(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_top = 0; + PyObject *__pyx_v_bottom = 0; + PyObject *__pyx_v_left = 0; + PyObject *__pyx_v_right = 0; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("set (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_top,&__pyx_n_s_bottom,&__pyx_n_s_left,&__pyx_n_s_right,0}; + PyObject* values[4] = {0,0,0,0}; + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_top)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_bottom)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("set", 1, 4, 4, 1); __PYX_ERR(0, 48, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_left)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("set", 1, 4, 4, 2); __PYX_ERR(0, 48, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 3: + if (likely((values[3] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_right)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("set", 1, 4, 4, 3); __PYX_ERR(0, 48, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "set") < 0)) __PYX_ERR(0, 48, __pyx_L3_error) + } + } else if (PyTuple_GET_SIZE(__pyx_args) != 4) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + } + __pyx_v_top = values[0]; + __pyx_v_bottom = values[1]; + __pyx_v_left = values[2]; + __pyx_v_right = values[3]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("set", 1, 4, 4, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 48, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("region.RegionBounds.set", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6region_12RegionBounds_10set(((struct __pyx_obj_6region_RegionBounds *)__pyx_v_self), __pyx_v_top, __pyx_v_bottom, __pyx_v_left, __pyx_v_right); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6region_12RegionBounds_10set(struct __pyx_obj_6region_RegionBounds *__pyx_v_self, PyObject *__pyx_v_top, PyObject *__pyx_v_bottom, PyObject *__pyx_v_left, PyObject *__pyx_v_right) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + float __pyx_t_1; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("set", 0); + + /* "region.pyx":49 + * + * def set(self, top, bottom, left, right): + * self._c_region_bounds.top = top # <<<<<<<<<<<<<< + * self._c_region_bounds.bottom = bottom + * self._c_region_bounds.left = left + */ + __pyx_t_1 = __pyx_PyFloat_AsFloat(__pyx_v_top); if (unlikely((__pyx_t_1 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 49, __pyx_L1_error) + __pyx_v_self->_c_region_bounds->top = __pyx_t_1; + + /* "region.pyx":50 + * def set(self, top, bottom, left, right): + * self._c_region_bounds.top = top + * self._c_region_bounds.bottom = bottom # <<<<<<<<<<<<<< + * self._c_region_bounds.left = left + * self._c_region_bounds.right = right + */ + __pyx_t_1 = __pyx_PyFloat_AsFloat(__pyx_v_bottom); if (unlikely((__pyx_t_1 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 50, __pyx_L1_error) + __pyx_v_self->_c_region_bounds->bottom = __pyx_t_1; + + /* "region.pyx":51 + * self._c_region_bounds.top = top + * self._c_region_bounds.bottom = bottom + * self._c_region_bounds.left = left # <<<<<<<<<<<<<< + * self._c_region_bounds.right = right + * + */ + __pyx_t_1 = __pyx_PyFloat_AsFloat(__pyx_v_left); if (unlikely((__pyx_t_1 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 51, __pyx_L1_error) + __pyx_v_self->_c_region_bounds->left = __pyx_t_1; + + /* "region.pyx":52 + * self._c_region_bounds.bottom = bottom + * self._c_region_bounds.left = left + * self._c_region_bounds.right = right # <<<<<<<<<<<<<< + * + * + */ + __pyx_t_1 = __pyx_PyFloat_AsFloat(__pyx_v_right); if (unlikely((__pyx_t_1 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 52, __pyx_L1_error) + __pyx_v_self->_c_region_bounds->right = __pyx_t_1; + + /* "region.pyx":48 + * self._c_region_bounds.right) + * + * def set(self, top, bottom, left, right): # <<<<<<<<<<<<<< + * self._c_region_bounds.top = top + * self._c_region_bounds.bottom = bottom + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_AddTraceback("region.RegionBounds.set", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + * def __setstate_cython__(self, __pyx_state): + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6region_12RegionBounds_13__reduce_cython__(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/ +static PyObject *__pyx_pw_6region_12RegionBounds_13__reduce_cython__(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) { + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__reduce_cython__ (wrapper)", 0); + __pyx_r = __pyx_pf_6region_12RegionBounds_12__reduce_cython__(((struct __pyx_obj_6region_RegionBounds *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6region_12RegionBounds_12__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_6region_RegionBounds *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__reduce_cython__", 0); + + /* "(tree fragment)":2 + * def __reduce_cython__(self): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") # <<<<<<<<<<<<<< + * def __setstate_cython__(self, __pyx_state): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_TypeError, __pyx_tuple_, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 2, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(1, 2, __pyx_L1_error) + + /* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + * def __setstate_cython__(self, __pyx_state): + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("region.RegionBounds.__reduce_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6region_12RegionBounds_15__setstate_cython__(PyObject *__pyx_v_self, PyObject *__pyx_v___pyx_state); /*proto*/ +static PyObject *__pyx_pw_6region_12RegionBounds_15__setstate_cython__(PyObject *__pyx_v_self, PyObject *__pyx_v___pyx_state) { + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__setstate_cython__ (wrapper)", 0); + __pyx_r = __pyx_pf_6region_12RegionBounds_14__setstate_cython__(((struct __pyx_obj_6region_RegionBounds *)__pyx_v_self), ((PyObject *)__pyx_v___pyx_state)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6region_12RegionBounds_14__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_6region_RegionBounds *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__setstate_cython__", 0); + + /* "(tree fragment)":4 + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + * def __setstate_cython__(self, __pyx_state): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") # <<<<<<<<<<<<<< + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_TypeError, __pyx_tuple__2, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(1, 4, __pyx_L1_error) + + /* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("region.RegionBounds.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "region.pyx":59 + * cdef c_region.region_rectangle* _c_region_rectangle + * + * def __cinit__(self): # <<<<<<<<<<<<<< + * self._c_region_rectangle = malloc( + * sizeof(c_region.region_rectangle)) + */ + +/* Python wrapper */ +static int __pyx_pw_6region_9Rectangle_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static int __pyx_pw_6region_9Rectangle_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0); + if (unlikely(PyTuple_GET_SIZE(__pyx_args) > 0)) { + __Pyx_RaiseArgtupleInvalid("__cinit__", 1, 0, 0, PyTuple_GET_SIZE(__pyx_args)); return -1;} + if (unlikely(__pyx_kwds) && unlikely(PyDict_Size(__pyx_kwds) > 0) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "__cinit__", 0))) return -1; + __pyx_r = __pyx_pf_6region_9Rectangle___cinit__(((struct __pyx_obj_6region_Rectangle *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_pf_6region_9Rectangle___cinit__(struct __pyx_obj_6region_Rectangle *__pyx_v_self) { + int __pyx_r; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__cinit__", 0); + + /* "region.pyx":60 + * + * def __cinit__(self): + * self._c_region_rectangle = malloc( # <<<<<<<<<<<<<< + * sizeof(c_region.region_rectangle)) + * if not self._c_region_rectangle: + */ + __pyx_v_self->_c_region_rectangle = ((region_rectangle *)malloc((sizeof(region_rectangle)))); + + /* "region.pyx":62 + * self._c_region_rectangle = malloc( + * sizeof(c_region.region_rectangle)) + * if not self._c_region_rectangle: # <<<<<<<<<<<<<< + * self._c_region_rectangle = NULL + * raise MemoryError() + */ + __pyx_t_1 = ((!(__pyx_v_self->_c_region_rectangle != 0)) != 0); + if (unlikely(__pyx_t_1)) { + + /* "region.pyx":63 + * sizeof(c_region.region_rectangle)) + * if not self._c_region_rectangle: + * self._c_region_rectangle = NULL # <<<<<<<<<<<<<< + * raise MemoryError() + * + */ + __pyx_v_self->_c_region_rectangle = NULL; + + /* "region.pyx":64 + * if not self._c_region_rectangle: + * self._c_region_rectangle = NULL + * raise MemoryError() # <<<<<<<<<<<<<< + * + * def __init__(self, x, y, width, height): + */ + PyErr_NoMemory(); __PYX_ERR(0, 64, __pyx_L1_error) + + /* "region.pyx":62 + * self._c_region_rectangle = malloc( + * sizeof(c_region.region_rectangle)) + * if not self._c_region_rectangle: # <<<<<<<<<<<<<< + * self._c_region_rectangle = NULL + * raise MemoryError() + */ + } + + /* "region.pyx":59 + * cdef c_region.region_rectangle* _c_region_rectangle + * + * def __cinit__(self): # <<<<<<<<<<<<<< + * self._c_region_rectangle = malloc( + * sizeof(c_region.region_rectangle)) + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_AddTraceback("region.Rectangle.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "region.pyx":66 + * raise MemoryError() + * + * def __init__(self, x, y, width, height): # <<<<<<<<<<<<<< + * self.set(x, y, width, height) + * + */ + +/* Python wrapper */ +static int __pyx_pw_6region_9Rectangle_3__init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static int __pyx_pw_6region_9Rectangle_3__init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_x = 0; + PyObject *__pyx_v_y = 0; + PyObject *__pyx_v_width = 0; + PyObject *__pyx_v_height = 0; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__init__ (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_x,&__pyx_n_s_y,&__pyx_n_s_width,&__pyx_n_s_height,0}; + PyObject* values[4] = {0,0,0,0}; + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_x)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_y)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("__init__", 1, 4, 4, 1); __PYX_ERR(0, 66, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_width)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("__init__", 1, 4, 4, 2); __PYX_ERR(0, 66, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 3: + if (likely((values[3] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_height)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("__init__", 1, 4, 4, 3); __PYX_ERR(0, 66, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__init__") < 0)) __PYX_ERR(0, 66, __pyx_L3_error) + } + } else if (PyTuple_GET_SIZE(__pyx_args) != 4) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + } + __pyx_v_x = values[0]; + __pyx_v_y = values[1]; + __pyx_v_width = values[2]; + __pyx_v_height = values[3]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__init__", 1, 4, 4, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 66, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("region.Rectangle.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return -1; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6region_9Rectangle_2__init__(((struct __pyx_obj_6region_Rectangle *)__pyx_v_self), __pyx_v_x, __pyx_v_y, __pyx_v_width, __pyx_v_height); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_pf_6region_9Rectangle_2__init__(struct __pyx_obj_6region_Rectangle *__pyx_v_self, PyObject *__pyx_v_x, PyObject *__pyx_v_y, PyObject *__pyx_v_width, PyObject *__pyx_v_height) { + int __pyx_r; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__init__", 0); + + /* "region.pyx":67 + * + * def __init__(self, x, y, width, height): + * self.set(x, y, width, height) # <<<<<<<<<<<<<< + * + * def __dealloc__(self): + */ + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_set); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 67, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = NULL; + __pyx_t_4 = 0; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + __pyx_t_4 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[5] = {__pyx_t_3, __pyx_v_x, __pyx_v_y, __pyx_v_width, __pyx_v_height}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_2, __pyx_temp+1-__pyx_t_4, 4+__pyx_t_4); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 67, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[5] = {__pyx_t_3, __pyx_v_x, __pyx_v_y, __pyx_v_width, __pyx_v_height}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_2, __pyx_temp+1-__pyx_t_4, 4+__pyx_t_4); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 67, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + { + __pyx_t_5 = PyTuple_New(4+__pyx_t_4); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 67, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (__pyx_t_3) { + __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_3); __pyx_t_3 = NULL; + } + __Pyx_INCREF(__pyx_v_x); + __Pyx_GIVEREF(__pyx_v_x); + PyTuple_SET_ITEM(__pyx_t_5, 0+__pyx_t_4, __pyx_v_x); + __Pyx_INCREF(__pyx_v_y); + __Pyx_GIVEREF(__pyx_v_y); + PyTuple_SET_ITEM(__pyx_t_5, 1+__pyx_t_4, __pyx_v_y); + __Pyx_INCREF(__pyx_v_width); + __Pyx_GIVEREF(__pyx_v_width); + PyTuple_SET_ITEM(__pyx_t_5, 2+__pyx_t_4, __pyx_v_width); + __Pyx_INCREF(__pyx_v_height); + __Pyx_GIVEREF(__pyx_v_height); + PyTuple_SET_ITEM(__pyx_t_5, 3+__pyx_t_4, __pyx_v_height); + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_5, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 67, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + } + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "region.pyx":66 + * raise MemoryError() + * + * def __init__(self, x, y, width, height): # <<<<<<<<<<<<<< + * self.set(x, y, width, height) + * + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("region.Rectangle.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "region.pyx":69 + * self.set(x, y, width, height) + * + * def __dealloc__(self): # <<<<<<<<<<<<<< + * if self._c_region_rectangle is not NULL: + * free(self._c_region_rectangle) + */ + +/* Python wrapper */ +static void __pyx_pw_6region_9Rectangle_5__dealloc__(PyObject *__pyx_v_self); /*proto*/ +static void __pyx_pw_6region_9Rectangle_5__dealloc__(PyObject *__pyx_v_self) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__dealloc__ (wrapper)", 0); + __pyx_pf_6region_9Rectangle_4__dealloc__(((struct __pyx_obj_6region_Rectangle *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); +} + +static void __pyx_pf_6region_9Rectangle_4__dealloc__(struct __pyx_obj_6region_Rectangle *__pyx_v_self) { + __Pyx_RefNannyDeclarations + int __pyx_t_1; + __Pyx_RefNannySetupContext("__dealloc__", 0); + + /* "region.pyx":70 + * + * def __dealloc__(self): + * if self._c_region_rectangle is not NULL: # <<<<<<<<<<<<<< + * free(self._c_region_rectangle) + * self._c_region_rectangle = NULL + */ + __pyx_t_1 = ((__pyx_v_self->_c_region_rectangle != NULL) != 0); + if (__pyx_t_1) { + + /* "region.pyx":71 + * def __dealloc__(self): + * if self._c_region_rectangle is not NULL: + * free(self._c_region_rectangle) # <<<<<<<<<<<<<< + * self._c_region_rectangle = NULL + * + */ + free(__pyx_v_self->_c_region_rectangle); + + /* "region.pyx":72 + * if self._c_region_rectangle is not NULL: + * free(self._c_region_rectangle) + * self._c_region_rectangle = NULL # <<<<<<<<<<<<<< + * + * def __str__(self): + */ + __pyx_v_self->_c_region_rectangle = NULL; + + /* "region.pyx":70 + * + * def __dealloc__(self): + * if self._c_region_rectangle is not NULL: # <<<<<<<<<<<<<< + * free(self._c_region_rectangle) + * self._c_region_rectangle = NULL + */ + } + + /* "region.pyx":69 + * self.set(x, y, width, height) + * + * def __dealloc__(self): # <<<<<<<<<<<<<< + * if self._c_region_rectangle is not NULL: + * free(self._c_region_rectangle) + */ + + /* function exit code */ + __Pyx_RefNannyFinishContext(); +} + +/* "region.pyx":74 + * self._c_region_rectangle = NULL + * + * def __str__(self): # <<<<<<<<<<<<<< + * return "x: {:.3f} y: {:.3f} width: {:.3f} height: {:.3f}".format( + * self._c_region_rectangle.x, + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6region_9Rectangle_7__str__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_6region_9Rectangle_7__str__(PyObject *__pyx_v_self) { + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__str__ (wrapper)", 0); + __pyx_r = __pyx_pf_6region_9Rectangle_6__str__(((struct __pyx_obj_6region_Rectangle *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6region_9Rectangle_6__str__(struct __pyx_obj_6region_Rectangle *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + int __pyx_t_8; + PyObject *__pyx_t_9 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__str__", 0); + + /* "region.pyx":75 + * + * def __str__(self): + * return "x: {:.3f} y: {:.3f} width: {:.3f} height: {:.3f}".format( # <<<<<<<<<<<<<< + * self._c_region_rectangle.x, + * self._c_region_rectangle.y, + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_kp_s_x_3f_y_3f_width_3f_height_3f, __pyx_n_s_format); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 75, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + + /* "region.pyx":76 + * def __str__(self): + * return "x: {:.3f} y: {:.3f} width: {:.3f} height: {:.3f}".format( + * self._c_region_rectangle.x, # <<<<<<<<<<<<<< + * self._c_region_rectangle.y, + * self._c_region_rectangle.width, + */ + __pyx_t_3 = PyFloat_FromDouble(__pyx_v_self->_c_region_rectangle->x); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 76, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + + /* "region.pyx":77 + * return "x: {:.3f} y: {:.3f} width: {:.3f} height: {:.3f}".format( + * self._c_region_rectangle.x, + * self._c_region_rectangle.y, # <<<<<<<<<<<<<< + * self._c_region_rectangle.width, + * self._c_region_rectangle.height) + */ + __pyx_t_4 = PyFloat_FromDouble(__pyx_v_self->_c_region_rectangle->y); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 77, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + + /* "region.pyx":78 + * self._c_region_rectangle.x, + * self._c_region_rectangle.y, + * self._c_region_rectangle.width, # <<<<<<<<<<<<<< + * self._c_region_rectangle.height) + * + */ + __pyx_t_5 = PyFloat_FromDouble(__pyx_v_self->_c_region_rectangle->width); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 78, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + + /* "region.pyx":79 + * self._c_region_rectangle.y, + * self._c_region_rectangle.width, + * self._c_region_rectangle.height) # <<<<<<<<<<<<<< + * + * def set(self, x, y, width, height): + */ + __pyx_t_6 = PyFloat_FromDouble(__pyx_v_self->_c_region_rectangle->height); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 79, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_7 = NULL; + __pyx_t_8 = 0; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + __pyx_t_8 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[5] = {__pyx_t_7, __pyx_t_3, __pyx_t_4, __pyx_t_5, __pyx_t_6}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_2, __pyx_temp+1-__pyx_t_8, 4+__pyx_t_8); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 75, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[5] = {__pyx_t_7, __pyx_t_3, __pyx_t_4, __pyx_t_5, __pyx_t_6}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_2, __pyx_temp+1-__pyx_t_8, 4+__pyx_t_8); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 75, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } else + #endif + { + __pyx_t_9 = PyTuple_New(4+__pyx_t_8); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 75, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + if (__pyx_t_7) { + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_7); __pyx_t_7 = NULL; + } + __Pyx_GIVEREF(__pyx_t_3); + PyTuple_SET_ITEM(__pyx_t_9, 0+__pyx_t_8, __pyx_t_3); + __Pyx_GIVEREF(__pyx_t_4); + PyTuple_SET_ITEM(__pyx_t_9, 1+__pyx_t_8, __pyx_t_4); + __Pyx_GIVEREF(__pyx_t_5); + PyTuple_SET_ITEM(__pyx_t_9, 2+__pyx_t_8, __pyx_t_5); + __Pyx_GIVEREF(__pyx_t_6); + PyTuple_SET_ITEM(__pyx_t_9, 3+__pyx_t_8, __pyx_t_6); + __pyx_t_3 = 0; + __pyx_t_4 = 0; + __pyx_t_5 = 0; + __pyx_t_6 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_9, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 75, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "region.pyx":74 + * self._c_region_rectangle = NULL + * + * def __str__(self): # <<<<<<<<<<<<<< + * return "x: {:.3f} y: {:.3f} width: {:.3f} height: {:.3f}".format( + * self._c_region_rectangle.x, + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_AddTraceback("region.Rectangle.__str__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "region.pyx":81 + * self._c_region_rectangle.height) + * + * def set(self, x, y, width, height): # <<<<<<<<<<<<<< + * self._c_region_rectangle.x = x + * self._c_region_rectangle.y = y + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6region_9Rectangle_9set(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static PyObject *__pyx_pw_6region_9Rectangle_9set(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_x = 0; + PyObject *__pyx_v_y = 0; + PyObject *__pyx_v_width = 0; + PyObject *__pyx_v_height = 0; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("set (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_x,&__pyx_n_s_y,&__pyx_n_s_width,&__pyx_n_s_height,0}; + PyObject* values[4] = {0,0,0,0}; + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_x)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_y)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("set", 1, 4, 4, 1); __PYX_ERR(0, 81, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_width)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("set", 1, 4, 4, 2); __PYX_ERR(0, 81, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 3: + if (likely((values[3] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_height)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("set", 1, 4, 4, 3); __PYX_ERR(0, 81, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "set") < 0)) __PYX_ERR(0, 81, __pyx_L3_error) + } + } else if (PyTuple_GET_SIZE(__pyx_args) != 4) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + } + __pyx_v_x = values[0]; + __pyx_v_y = values[1]; + __pyx_v_width = values[2]; + __pyx_v_height = values[3]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("set", 1, 4, 4, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 81, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("region.Rectangle.set", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6region_9Rectangle_8set(((struct __pyx_obj_6region_Rectangle *)__pyx_v_self), __pyx_v_x, __pyx_v_y, __pyx_v_width, __pyx_v_height); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6region_9Rectangle_8set(struct __pyx_obj_6region_Rectangle *__pyx_v_self, PyObject *__pyx_v_x, PyObject *__pyx_v_y, PyObject *__pyx_v_width, PyObject *__pyx_v_height) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + float __pyx_t_1; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("set", 0); + + /* "region.pyx":82 + * + * def set(self, x, y, width, height): + * self._c_region_rectangle.x = x # <<<<<<<<<<<<<< + * self._c_region_rectangle.y = y + * self._c_region_rectangle.width = width + */ + __pyx_t_1 = __pyx_PyFloat_AsFloat(__pyx_v_x); if (unlikely((__pyx_t_1 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 82, __pyx_L1_error) + __pyx_v_self->_c_region_rectangle->x = __pyx_t_1; + + /* "region.pyx":83 + * def set(self, x, y, width, height): + * self._c_region_rectangle.x = x + * self._c_region_rectangle.y = y # <<<<<<<<<<<<<< + * self._c_region_rectangle.width = width + * self._c_region_rectangle.height = height + */ + __pyx_t_1 = __pyx_PyFloat_AsFloat(__pyx_v_y); if (unlikely((__pyx_t_1 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 83, __pyx_L1_error) + __pyx_v_self->_c_region_rectangle->y = __pyx_t_1; + + /* "region.pyx":84 + * self._c_region_rectangle.x = x + * self._c_region_rectangle.y = y + * self._c_region_rectangle.width = width # <<<<<<<<<<<<<< + * self._c_region_rectangle.height = height + * + */ + __pyx_t_1 = __pyx_PyFloat_AsFloat(__pyx_v_width); if (unlikely((__pyx_t_1 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 84, __pyx_L1_error) + __pyx_v_self->_c_region_rectangle->width = __pyx_t_1; + + /* "region.pyx":85 + * self._c_region_rectangle.y = y + * self._c_region_rectangle.width = width + * self._c_region_rectangle.height = height # <<<<<<<<<<<<<< + * + * def get(self): + */ + __pyx_t_1 = __pyx_PyFloat_AsFloat(__pyx_v_height); if (unlikely((__pyx_t_1 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 85, __pyx_L1_error) + __pyx_v_self->_c_region_rectangle->height = __pyx_t_1; + + /* "region.pyx":81 + * self._c_region_rectangle.height) + * + * def set(self, x, y, width, height): # <<<<<<<<<<<<<< + * self._c_region_rectangle.x = x + * self._c_region_rectangle.y = y + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_AddTraceback("region.Rectangle.set", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "region.pyx":87 + * self._c_region_rectangle.height = height + * + * def get(self): # <<<<<<<<<<<<<< + * """ + * return: + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6region_9Rectangle_11get(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/ +static char __pyx_doc_6region_9Rectangle_10get[] = "\n return:\n (x, y, width, height)\n "; +static PyObject *__pyx_pw_6region_9Rectangle_11get(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) { + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("get (wrapper)", 0); + __pyx_r = __pyx_pf_6region_9Rectangle_10get(((struct __pyx_obj_6region_Rectangle *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6region_9Rectangle_10get(struct __pyx_obj_6region_Rectangle *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("get", 0); + + /* "region.pyx":92 + * (x, y, width, height) + * """ + * return (self._c_region_rectangle.x, # <<<<<<<<<<<<<< + * self._c_region_rectangle.y, + * self._c_region_rectangle.width, + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PyFloat_FromDouble(__pyx_v_self->_c_region_rectangle->x); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 92, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + + /* "region.pyx":93 + * """ + * return (self._c_region_rectangle.x, + * self._c_region_rectangle.y, # <<<<<<<<<<<<<< + * self._c_region_rectangle.width, + * self._c_region_rectangle.height) + */ + __pyx_t_2 = PyFloat_FromDouble(__pyx_v_self->_c_region_rectangle->y); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 93, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + + /* "region.pyx":94 + * return (self._c_region_rectangle.x, + * self._c_region_rectangle.y, + * self._c_region_rectangle.width, # <<<<<<<<<<<<<< + * self._c_region_rectangle.height) + * + */ + __pyx_t_3 = PyFloat_FromDouble(__pyx_v_self->_c_region_rectangle->width); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 94, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + + /* "region.pyx":95 + * self._c_region_rectangle.y, + * self._c_region_rectangle.width, + * self._c_region_rectangle.height) # <<<<<<<<<<<<<< + * + * cdef class Polygon: + */ + __pyx_t_4 = PyFloat_FromDouble(__pyx_v_self->_c_region_rectangle->height); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 95, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + + /* "region.pyx":92 + * (x, y, width, height) + * """ + * return (self._c_region_rectangle.x, # <<<<<<<<<<<<<< + * self._c_region_rectangle.y, + * self._c_region_rectangle.width, + */ + __pyx_t_5 = PyTuple_New(4); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 92, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_1); + __Pyx_GIVEREF(__pyx_t_2); + PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_t_2); + __Pyx_GIVEREF(__pyx_t_3); + PyTuple_SET_ITEM(__pyx_t_5, 2, __pyx_t_3); + __Pyx_GIVEREF(__pyx_t_4); + PyTuple_SET_ITEM(__pyx_t_5, 3, __pyx_t_4); + __pyx_t_1 = 0; + __pyx_t_2 = 0; + __pyx_t_3 = 0; + __pyx_t_4 = 0; + __pyx_r = __pyx_t_5; + __pyx_t_5 = 0; + goto __pyx_L0; + + /* "region.pyx":87 + * self._c_region_rectangle.height = height + * + * def get(self): # <<<<<<<<<<<<<< + * """ + * return: + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("region.Rectangle.get", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + * def __setstate_cython__(self, __pyx_state): + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6region_9Rectangle_13__reduce_cython__(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/ +static PyObject *__pyx_pw_6region_9Rectangle_13__reduce_cython__(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) { + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__reduce_cython__ (wrapper)", 0); + __pyx_r = __pyx_pf_6region_9Rectangle_12__reduce_cython__(((struct __pyx_obj_6region_Rectangle *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6region_9Rectangle_12__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_6region_Rectangle *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__reduce_cython__", 0); + + /* "(tree fragment)":2 + * def __reduce_cython__(self): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") # <<<<<<<<<<<<<< + * def __setstate_cython__(self, __pyx_state): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_TypeError, __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 2, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(1, 2, __pyx_L1_error) + + /* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + * def __setstate_cython__(self, __pyx_state): + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("region.Rectangle.__reduce_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6region_9Rectangle_15__setstate_cython__(PyObject *__pyx_v_self, PyObject *__pyx_v___pyx_state); /*proto*/ +static PyObject *__pyx_pw_6region_9Rectangle_15__setstate_cython__(PyObject *__pyx_v_self, PyObject *__pyx_v___pyx_state) { + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__setstate_cython__ (wrapper)", 0); + __pyx_r = __pyx_pf_6region_9Rectangle_14__setstate_cython__(((struct __pyx_obj_6region_Rectangle *)__pyx_v_self), ((PyObject *)__pyx_v___pyx_state)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6region_9Rectangle_14__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_6region_Rectangle *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__setstate_cython__", 0); + + /* "(tree fragment)":4 + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + * def __setstate_cython__(self, __pyx_state): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") # <<<<<<<<<<<<<< + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_TypeError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(1, 4, __pyx_L1_error) + + /* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("region.Rectangle.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "region.pyx":100 + * cdef c_region.region_polygon* _c_region_polygon + * + * def __cinit__(self, points): # <<<<<<<<<<<<<< + * """ + * args: + */ + +/* Python wrapper */ +static int __pyx_pw_6region_7Polygon_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static int __pyx_pw_6region_7Polygon_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_points = 0; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_points,0}; + PyObject* values[1] = {0}; + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_points)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__cinit__") < 0)) __PYX_ERR(0, 100, __pyx_L3_error) + } + } else if (PyTuple_GET_SIZE(__pyx_args) != 1) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + } + __pyx_v_points = values[0]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__cinit__", 1, 1, 1, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 100, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("region.Polygon.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return -1; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6region_7Polygon___cinit__(((struct __pyx_obj_6region_Polygon *)__pyx_v_self), __pyx_v_points); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_pf_6region_7Polygon___cinit__(struct __pyx_obj_6region_Polygon *__pyx_v_self, PyObject *__pyx_v_points) { + PyObject *__pyx_v_num = NULL; + PyObject *__pyx_v_i = NULL; + int __pyx_r; + __Pyx_RefNannyDeclarations + Py_ssize_t __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + int __pyx_t_3; + int __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + size_t __pyx_t_6; + PyObject *(*__pyx_t_7)(PyObject *); + PyObject *__pyx_t_8 = NULL; + float __pyx_t_9; + Py_ssize_t __pyx_t_10; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__cinit__", 0); + + /* "region.pyx":107 + * points = ((1, 1), (10, 10)) + * """ + * num = len(points) # <<<<<<<<<<<<<< + * self._c_region_polygon = malloc( + * sizeof(c_region.region_polygon)) + */ + __pyx_t_1 = PyObject_Length(__pyx_v_points); if (unlikely(__pyx_t_1 == ((Py_ssize_t)-1))) __PYX_ERR(0, 107, __pyx_L1_error) + __pyx_t_2 = PyInt_FromSsize_t(__pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 107, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_v_num = __pyx_t_2; + __pyx_t_2 = 0; + + /* "region.pyx":108 + * """ + * num = len(points) + * self._c_region_polygon = malloc( # <<<<<<<<<<<<<< + * sizeof(c_region.region_polygon)) + * if not self._c_region_polygon: + */ + __pyx_v_self->_c_region_polygon = ((region_polygon *)malloc((sizeof(region_polygon)))); + + /* "region.pyx":110 + * self._c_region_polygon = malloc( + * sizeof(c_region.region_polygon)) + * if not self._c_region_polygon: # <<<<<<<<<<<<<< + * self._c_region_polygon = NULL + * raise MemoryError() + */ + __pyx_t_3 = ((!(__pyx_v_self->_c_region_polygon != 0)) != 0); + if (unlikely(__pyx_t_3)) { + + /* "region.pyx":111 + * sizeof(c_region.region_polygon)) + * if not self._c_region_polygon: + * self._c_region_polygon = NULL # <<<<<<<<<<<<<< + * raise MemoryError() + * self._c_region_polygon.count = num + */ + __pyx_v_self->_c_region_polygon = NULL; + + /* "region.pyx":112 + * if not self._c_region_polygon: + * self._c_region_polygon = NULL + * raise MemoryError() # <<<<<<<<<<<<<< + * self._c_region_polygon.count = num + * self._c_region_polygon.x = malloc(sizeof(float) * num) + */ + PyErr_NoMemory(); __PYX_ERR(0, 112, __pyx_L1_error) + + /* "region.pyx":110 + * self._c_region_polygon = malloc( + * sizeof(c_region.region_polygon)) + * if not self._c_region_polygon: # <<<<<<<<<<<<<< + * self._c_region_polygon = NULL + * raise MemoryError() + */ + } + + /* "region.pyx":113 + * self._c_region_polygon = NULL + * raise MemoryError() + * self._c_region_polygon.count = num # <<<<<<<<<<<<<< + * self._c_region_polygon.x = malloc(sizeof(float) * num) + * if not self._c_region_polygon.x: + */ + __pyx_t_4 = __Pyx_PyInt_As_int(__pyx_v_num); if (unlikely((__pyx_t_4 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 113, __pyx_L1_error) + __pyx_v_self->_c_region_polygon->count = __pyx_t_4; + + /* "region.pyx":114 + * raise MemoryError() + * self._c_region_polygon.count = num + * self._c_region_polygon.x = malloc(sizeof(float) * num) # <<<<<<<<<<<<<< + * if not self._c_region_polygon.x: + * raise MemoryError() + */ + __pyx_t_2 = __Pyx_PyInt_FromSize_t((sizeof(float))); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 114, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_5 = PyNumber_Multiply(__pyx_t_2, __pyx_v_num); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 114, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_6 = __Pyx_PyInt_As_size_t(__pyx_t_5); if (unlikely((__pyx_t_6 == (size_t)-1) && PyErr_Occurred())) __PYX_ERR(0, 114, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_v_self->_c_region_polygon->x = ((float *)malloc(__pyx_t_6)); + + /* "region.pyx":115 + * self._c_region_polygon.count = num + * self._c_region_polygon.x = malloc(sizeof(float) * num) + * if not self._c_region_polygon.x: # <<<<<<<<<<<<<< + * raise MemoryError() + * self._c_region_polygon.y = malloc(sizeof(float) * num) + */ + __pyx_t_3 = ((!(__pyx_v_self->_c_region_polygon->x != 0)) != 0); + if (unlikely(__pyx_t_3)) { + + /* "region.pyx":116 + * self._c_region_polygon.x = malloc(sizeof(float) * num) + * if not self._c_region_polygon.x: + * raise MemoryError() # <<<<<<<<<<<<<< + * self._c_region_polygon.y = malloc(sizeof(float) * num) + * if not self._c_region_polygon.y: + */ + PyErr_NoMemory(); __PYX_ERR(0, 116, __pyx_L1_error) + + /* "region.pyx":115 + * self._c_region_polygon.count = num + * self._c_region_polygon.x = malloc(sizeof(float) * num) + * if not self._c_region_polygon.x: # <<<<<<<<<<<<<< + * raise MemoryError() + * self._c_region_polygon.y = malloc(sizeof(float) * num) + */ + } + + /* "region.pyx":117 + * if not self._c_region_polygon.x: + * raise MemoryError() + * self._c_region_polygon.y = malloc(sizeof(float) * num) # <<<<<<<<<<<<<< + * if not self._c_region_polygon.y: + * raise MemoryError() + */ + __pyx_t_5 = __Pyx_PyInt_FromSize_t((sizeof(float))); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 117, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_2 = PyNumber_Multiply(__pyx_t_5, __pyx_v_num); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 117, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __pyx_t_6 = __Pyx_PyInt_As_size_t(__pyx_t_2); if (unlikely((__pyx_t_6 == (size_t)-1) && PyErr_Occurred())) __PYX_ERR(0, 117, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_self->_c_region_polygon->y = ((float *)malloc(__pyx_t_6)); + + /* "region.pyx":118 + * raise MemoryError() + * self._c_region_polygon.y = malloc(sizeof(float) * num) + * if not self._c_region_polygon.y: # <<<<<<<<<<<<<< + * raise MemoryError() + * + */ + __pyx_t_3 = ((!(__pyx_v_self->_c_region_polygon->y != 0)) != 0); + if (unlikely(__pyx_t_3)) { + + /* "region.pyx":119 + * self._c_region_polygon.y = malloc(sizeof(float) * num) + * if not self._c_region_polygon.y: + * raise MemoryError() # <<<<<<<<<<<<<< + * + * for i in range(num): + */ + PyErr_NoMemory(); __PYX_ERR(0, 119, __pyx_L1_error) + + /* "region.pyx":118 + * raise MemoryError() + * self._c_region_polygon.y = malloc(sizeof(float) * num) + * if not self._c_region_polygon.y: # <<<<<<<<<<<<<< + * raise MemoryError() + * + */ + } + + /* "region.pyx":121 + * raise MemoryError() + * + * for i in range(num): # <<<<<<<<<<<<<< + * self._c_region_polygon.x[i] = points[i][0] + * self._c_region_polygon.y[i] = points[i][1] + */ + __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_builtin_range, __pyx_v_num); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 121, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + if (likely(PyList_CheckExact(__pyx_t_2)) || PyTuple_CheckExact(__pyx_t_2)) { + __pyx_t_5 = __pyx_t_2; __Pyx_INCREF(__pyx_t_5); __pyx_t_1 = 0; + __pyx_t_7 = NULL; + } else { + __pyx_t_1 = -1; __pyx_t_5 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 121, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_7 = Py_TYPE(__pyx_t_5)->tp_iternext; if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 121, __pyx_L1_error) + } + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + for (;;) { + if (likely(!__pyx_t_7)) { + if (likely(PyList_CheckExact(__pyx_t_5))) { + if (__pyx_t_1 >= PyList_GET_SIZE(__pyx_t_5)) break; + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_2 = PyList_GET_ITEM(__pyx_t_5, __pyx_t_1); __Pyx_INCREF(__pyx_t_2); __pyx_t_1++; if (unlikely(0 < 0)) __PYX_ERR(0, 121, __pyx_L1_error) + #else + __pyx_t_2 = PySequence_ITEM(__pyx_t_5, __pyx_t_1); __pyx_t_1++; if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 121, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + #endif + } else { + if (__pyx_t_1 >= PyTuple_GET_SIZE(__pyx_t_5)) break; + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_2 = PyTuple_GET_ITEM(__pyx_t_5, __pyx_t_1); __Pyx_INCREF(__pyx_t_2); __pyx_t_1++; if (unlikely(0 < 0)) __PYX_ERR(0, 121, __pyx_L1_error) + #else + __pyx_t_2 = PySequence_ITEM(__pyx_t_5, __pyx_t_1); __pyx_t_1++; if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 121, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + #endif + } + } else { + __pyx_t_2 = __pyx_t_7(__pyx_t_5); + if (unlikely(!__pyx_t_2)) { + PyObject* exc_type = PyErr_Occurred(); + if (exc_type) { + if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); + else __PYX_ERR(0, 121, __pyx_L1_error) + } + break; + } + __Pyx_GOTREF(__pyx_t_2); + } + __Pyx_XDECREF_SET(__pyx_v_i, __pyx_t_2); + __pyx_t_2 = 0; + + /* "region.pyx":122 + * + * for i in range(num): + * self._c_region_polygon.x[i] = points[i][0] # <<<<<<<<<<<<<< + * self._c_region_polygon.y[i] = points[i][1] + * + */ + __pyx_t_2 = __Pyx_PyObject_GetItem(__pyx_v_points, __pyx_v_i); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 122, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_8 = __Pyx_GetItemInt(__pyx_t_2, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 122, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_9 = __pyx_PyFloat_AsFloat(__pyx_t_8); if (unlikely((__pyx_t_9 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 122, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_t_10 = __Pyx_PyIndex_AsSsize_t(__pyx_v_i); if (unlikely((__pyx_t_10 == (Py_ssize_t)-1) && PyErr_Occurred())) __PYX_ERR(0, 122, __pyx_L1_error) + (__pyx_v_self->_c_region_polygon->x[__pyx_t_10]) = __pyx_t_9; + + /* "region.pyx":123 + * for i in range(num): + * self._c_region_polygon.x[i] = points[i][0] + * self._c_region_polygon.y[i] = points[i][1] # <<<<<<<<<<<<<< + * + * def __dealloc__(self): + */ + __pyx_t_8 = __Pyx_PyObject_GetItem(__pyx_v_points, __pyx_v_i); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 123, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_2 = __Pyx_GetItemInt(__pyx_t_8, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 123, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __pyx_t_9 = __pyx_PyFloat_AsFloat(__pyx_t_2); if (unlikely((__pyx_t_9 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 123, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_10 = __Pyx_PyIndex_AsSsize_t(__pyx_v_i); if (unlikely((__pyx_t_10 == (Py_ssize_t)-1) && PyErr_Occurred())) __PYX_ERR(0, 123, __pyx_L1_error) + (__pyx_v_self->_c_region_polygon->y[__pyx_t_10]) = __pyx_t_9; + + /* "region.pyx":121 + * raise MemoryError() + * + * for i in range(num): # <<<<<<<<<<<<<< + * self._c_region_polygon.x[i] = points[i][0] + * self._c_region_polygon.y[i] = points[i][1] + */ + } + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + + /* "region.pyx":100 + * cdef c_region.region_polygon* _c_region_polygon + * + * def __cinit__(self, points): # <<<<<<<<<<<<<< + * """ + * args: + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_AddTraceback("region.Polygon.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_num); + __Pyx_XDECREF(__pyx_v_i); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "region.pyx":125 + * self._c_region_polygon.y[i] = points[i][1] + * + * def __dealloc__(self): # <<<<<<<<<<<<<< + * if self._c_region_polygon is not NULL: + * if self._c_region_polygon.x is not NULL: + */ + +/* Python wrapper */ +static void __pyx_pw_6region_7Polygon_3__dealloc__(PyObject *__pyx_v_self); /*proto*/ +static void __pyx_pw_6region_7Polygon_3__dealloc__(PyObject *__pyx_v_self) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__dealloc__ (wrapper)", 0); + __pyx_pf_6region_7Polygon_2__dealloc__(((struct __pyx_obj_6region_Polygon *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); +} + +static void __pyx_pf_6region_7Polygon_2__dealloc__(struct __pyx_obj_6region_Polygon *__pyx_v_self) { + __Pyx_RefNannyDeclarations + int __pyx_t_1; + __Pyx_RefNannySetupContext("__dealloc__", 0); + + /* "region.pyx":126 + * + * def __dealloc__(self): + * if self._c_region_polygon is not NULL: # <<<<<<<<<<<<<< + * if self._c_region_polygon.x is not NULL: + * free(self._c_region_polygon.x) + */ + __pyx_t_1 = ((__pyx_v_self->_c_region_polygon != NULL) != 0); + if (__pyx_t_1) { + + /* "region.pyx":127 + * def __dealloc__(self): + * if self._c_region_polygon is not NULL: + * if self._c_region_polygon.x is not NULL: # <<<<<<<<<<<<<< + * free(self._c_region_polygon.x) + * self._c_region_polygon.x = NULL + */ + __pyx_t_1 = ((__pyx_v_self->_c_region_polygon->x != NULL) != 0); + if (__pyx_t_1) { + + /* "region.pyx":128 + * if self._c_region_polygon is not NULL: + * if self._c_region_polygon.x is not NULL: + * free(self._c_region_polygon.x) # <<<<<<<<<<<<<< + * self._c_region_polygon.x = NULL + * if self._c_region_polygon.y is not NULL: + */ + free(__pyx_v_self->_c_region_polygon->x); + + /* "region.pyx":129 + * if self._c_region_polygon.x is not NULL: + * free(self._c_region_polygon.x) + * self._c_region_polygon.x = NULL # <<<<<<<<<<<<<< + * if self._c_region_polygon.y is not NULL: + * free(self._c_region_polygon.y) + */ + __pyx_v_self->_c_region_polygon->x = NULL; + + /* "region.pyx":127 + * def __dealloc__(self): + * if self._c_region_polygon is not NULL: + * if self._c_region_polygon.x is not NULL: # <<<<<<<<<<<<<< + * free(self._c_region_polygon.x) + * self._c_region_polygon.x = NULL + */ + } + + /* "region.pyx":130 + * free(self._c_region_polygon.x) + * self._c_region_polygon.x = NULL + * if self._c_region_polygon.y is not NULL: # <<<<<<<<<<<<<< + * free(self._c_region_polygon.y) + * self._c_region_polygon.y = NULL + */ + __pyx_t_1 = ((__pyx_v_self->_c_region_polygon->y != NULL) != 0); + if (__pyx_t_1) { + + /* "region.pyx":131 + * self._c_region_polygon.x = NULL + * if self._c_region_polygon.y is not NULL: + * free(self._c_region_polygon.y) # <<<<<<<<<<<<<< + * self._c_region_polygon.y = NULL + * free(self._c_region_polygon) + */ + free(__pyx_v_self->_c_region_polygon->y); + + /* "region.pyx":132 + * if self._c_region_polygon.y is not NULL: + * free(self._c_region_polygon.y) + * self._c_region_polygon.y = NULL # <<<<<<<<<<<<<< + * free(self._c_region_polygon) + * self._c_region_polygon = NULL + */ + __pyx_v_self->_c_region_polygon->y = NULL; + + /* "region.pyx":130 + * free(self._c_region_polygon.x) + * self._c_region_polygon.x = NULL + * if self._c_region_polygon.y is not NULL: # <<<<<<<<<<<<<< + * free(self._c_region_polygon.y) + * self._c_region_polygon.y = NULL + */ + } + + /* "region.pyx":133 + * free(self._c_region_polygon.y) + * self._c_region_polygon.y = NULL + * free(self._c_region_polygon) # <<<<<<<<<<<<<< + * self._c_region_polygon = NULL + * + */ + free(__pyx_v_self->_c_region_polygon); + + /* "region.pyx":134 + * self._c_region_polygon.y = NULL + * free(self._c_region_polygon) + * self._c_region_polygon = NULL # <<<<<<<<<<<<<< + * + * def __str__(self): + */ + __pyx_v_self->_c_region_polygon = NULL; + + /* "region.pyx":126 + * + * def __dealloc__(self): + * if self._c_region_polygon is not NULL: # <<<<<<<<<<<<<< + * if self._c_region_polygon.x is not NULL: + * free(self._c_region_polygon.x) + */ + } + + /* "region.pyx":125 + * self._c_region_polygon.y[i] = points[i][1] + * + * def __dealloc__(self): # <<<<<<<<<<<<<< + * if self._c_region_polygon is not NULL: + * if self._c_region_polygon.x is not NULL: + */ + + /* function exit code */ + __Pyx_RefNannyFinishContext(); +} + +/* "region.pyx":136 + * self._c_region_polygon = NULL + * + * def __str__(self): # <<<<<<<<<<<<<< + * ret = "" + * for i in range(self._c_region_polygon.count-1): + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6region_7Polygon_5__str__(PyObject *__pyx_v_self); /*proto*/ +static PyObject *__pyx_pw_6region_7Polygon_5__str__(PyObject *__pyx_v_self) { + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__str__ (wrapper)", 0); + __pyx_r = __pyx_pf_6region_7Polygon_4__str__(((struct __pyx_obj_6region_Polygon *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6region_7Polygon_4__str__(struct __pyx_obj_6region_Polygon *__pyx_v_self) { + PyObject *__pyx_v_ret = NULL; + long __pyx_v_i; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + long __pyx_t_1; + long __pyx_t_2; + long __pyx_t_3; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + int __pyx_t_9; + PyObject *__pyx_t_10 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__str__", 0); + + /* "region.pyx":137 + * + * def __str__(self): + * ret = "" # <<<<<<<<<<<<<< + * for i in range(self._c_region_polygon.count-1): + * ret += "({:.3f} {:.3f}) ".format(self._c_region_polygon.x[i], + */ + __Pyx_INCREF(__pyx_kp_s__5); + __pyx_v_ret = __pyx_kp_s__5; + + /* "region.pyx":138 + * def __str__(self): + * ret = "" + * for i in range(self._c_region_polygon.count-1): # <<<<<<<<<<<<<< + * ret += "({:.3f} {:.3f}) ".format(self._c_region_polygon.x[i], + * self._c_region_polygon.y[i]) + */ + __pyx_t_1 = (__pyx_v_self->_c_region_polygon->count - 1); + __pyx_t_2 = __pyx_t_1; + for (__pyx_t_3 = 0; __pyx_t_3 < __pyx_t_2; __pyx_t_3+=1) { + __pyx_v_i = __pyx_t_3; + + /* "region.pyx":139 + * ret = "" + * for i in range(self._c_region_polygon.count-1): + * ret += "({:.3f} {:.3f}) ".format(self._c_region_polygon.x[i], # <<<<<<<<<<<<<< + * self._c_region_polygon.y[i]) + * ret += "({:.3f} {:.3f})".format(self._c_region_polygon.x[i], + */ + __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_kp_s_3f_3f, __pyx_n_s_format); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 139, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = PyFloat_FromDouble((__pyx_v_self->_c_region_polygon->x[__pyx_v_i])); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 139, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + + /* "region.pyx":140 + * for i in range(self._c_region_polygon.count-1): + * ret += "({:.3f} {:.3f}) ".format(self._c_region_polygon.x[i], + * self._c_region_polygon.y[i]) # <<<<<<<<<<<<<< + * ret += "({:.3f} {:.3f})".format(self._c_region_polygon.x[i], + * self._c_region_polygon.y[i]) + */ + __pyx_t_7 = PyFloat_FromDouble((__pyx_v_self->_c_region_polygon->y[__pyx_v_i])); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 140, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_8 = NULL; + __pyx_t_9 = 0; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_5))) { + __pyx_t_8 = PyMethod_GET_SELF(__pyx_t_5); + if (likely(__pyx_t_8)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); + __Pyx_INCREF(__pyx_t_8); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_5, function); + __pyx_t_9 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[3] = {__pyx_t_8, __pyx_t_6, __pyx_t_7}; + __pyx_t_4 = __Pyx_PyFunction_FastCall(__pyx_t_5, __pyx_temp+1-__pyx_t_9, 2+__pyx_t_9); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 139, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_5)) { + PyObject *__pyx_temp[3] = {__pyx_t_8, __pyx_t_6, __pyx_t_7}; + __pyx_t_4 = __Pyx_PyCFunction_FastCall(__pyx_t_5, __pyx_temp+1-__pyx_t_9, 2+__pyx_t_9); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 139, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } else + #endif + { + __pyx_t_10 = PyTuple_New(2+__pyx_t_9); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 139, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + if (__pyx_t_8) { + __Pyx_GIVEREF(__pyx_t_8); PyTuple_SET_ITEM(__pyx_t_10, 0, __pyx_t_8); __pyx_t_8 = NULL; + } + __Pyx_GIVEREF(__pyx_t_6); + PyTuple_SET_ITEM(__pyx_t_10, 0+__pyx_t_9, __pyx_t_6); + __Pyx_GIVEREF(__pyx_t_7); + PyTuple_SET_ITEM(__pyx_t_10, 1+__pyx_t_9, __pyx_t_7); + __pyx_t_6 = 0; + __pyx_t_7 = 0; + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_10, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 139, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + } + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + + /* "region.pyx":139 + * ret = "" + * for i in range(self._c_region_polygon.count-1): + * ret += "({:.3f} {:.3f}) ".format(self._c_region_polygon.x[i], # <<<<<<<<<<<<<< + * self._c_region_polygon.y[i]) + * ret += "({:.3f} {:.3f})".format(self._c_region_polygon.x[i], + */ + __pyx_t_5 = PyNumber_InPlaceAdd(__pyx_v_ret, __pyx_t_4); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 139, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF_SET(__pyx_v_ret, __pyx_t_5); + __pyx_t_5 = 0; + } + + /* "region.pyx":141 + * ret += "({:.3f} {:.3f}) ".format(self._c_region_polygon.x[i], + * self._c_region_polygon.y[i]) + * ret += "({:.3f} {:.3f})".format(self._c_region_polygon.x[i], # <<<<<<<<<<<<<< + * self._c_region_polygon.y[i]) + * return ret + */ + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_kp_s_3f_3f_2, __pyx_n_s_format); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 141, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_10 = PyFloat_FromDouble((__pyx_v_self->_c_region_polygon->x[__pyx_v_i])); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 141, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + + /* "region.pyx":142 + * self._c_region_polygon.y[i]) + * ret += "({:.3f} {:.3f})".format(self._c_region_polygon.x[i], + * self._c_region_polygon.y[i]) # <<<<<<<<<<<<<< + * return ret + * + */ + __pyx_t_7 = PyFloat_FromDouble((__pyx_v_self->_c_region_polygon->y[__pyx_v_i])); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 142, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_6 = NULL; + __pyx_t_9 = 0; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_4))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_4); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_4, function); + __pyx_t_9 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_4)) { + PyObject *__pyx_temp[3] = {__pyx_t_6, __pyx_t_10, __pyx_t_7}; + __pyx_t_5 = __Pyx_PyFunction_FastCall(__pyx_t_4, __pyx_temp+1-__pyx_t_9, 2+__pyx_t_9); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 141, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_4)) { + PyObject *__pyx_temp[3] = {__pyx_t_6, __pyx_t_10, __pyx_t_7}; + __pyx_t_5 = __Pyx_PyCFunction_FastCall(__pyx_t_4, __pyx_temp+1-__pyx_t_9, 2+__pyx_t_9); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 141, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + } else + #endif + { + __pyx_t_8 = PyTuple_New(2+__pyx_t_9); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 141, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + if (__pyx_t_6) { + __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_6); __pyx_t_6 = NULL; + } + __Pyx_GIVEREF(__pyx_t_10); + PyTuple_SET_ITEM(__pyx_t_8, 0+__pyx_t_9, __pyx_t_10); + __Pyx_GIVEREF(__pyx_t_7); + PyTuple_SET_ITEM(__pyx_t_8, 1+__pyx_t_9, __pyx_t_7); + __pyx_t_10 = 0; + __pyx_t_7 = 0; + __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_8, NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 141, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + + /* "region.pyx":141 + * ret += "({:.3f} {:.3f}) ".format(self._c_region_polygon.x[i], + * self._c_region_polygon.y[i]) + * ret += "({:.3f} {:.3f})".format(self._c_region_polygon.x[i], # <<<<<<<<<<<<<< + * self._c_region_polygon.y[i]) + * return ret + */ + __pyx_t_4 = PyNumber_InPlaceAdd(__pyx_v_ret, __pyx_t_5); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 141, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF_SET(__pyx_v_ret, __pyx_t_4); + __pyx_t_4 = 0; + + /* "region.pyx":143 + * ret += "({:.3f} {:.3f})".format(self._c_region_polygon.x[i], + * self._c_region_polygon.y[i]) + * return ret # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_ret); + __pyx_r = __pyx_v_ret; + goto __pyx_L0; + + /* "region.pyx":136 + * self._c_region_polygon = NULL + * + * def __str__(self): # <<<<<<<<<<<<<< + * ret = "" + * for i in range(self._c_region_polygon.count-1): + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_XDECREF(__pyx_t_10); + __Pyx_AddTraceback("region.Polygon.__str__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_ret); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + * def __setstate_cython__(self, __pyx_state): + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6region_7Polygon_7__reduce_cython__(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/ +static PyObject *__pyx_pw_6region_7Polygon_7__reduce_cython__(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) { + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__reduce_cython__ (wrapper)", 0); + __pyx_r = __pyx_pf_6region_7Polygon_6__reduce_cython__(((struct __pyx_obj_6region_Polygon *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6region_7Polygon_6__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_6region_Polygon *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__reduce_cython__", 0); + + /* "(tree fragment)":2 + * def __reduce_cython__(self): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") # <<<<<<<<<<<<<< + * def __setstate_cython__(self, __pyx_state): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_TypeError, __pyx_tuple__6, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 2, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(1, 2, __pyx_L1_error) + + /* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + * def __setstate_cython__(self, __pyx_state): + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("region.Polygon.__reduce_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6region_7Polygon_9__setstate_cython__(PyObject *__pyx_v_self, PyObject *__pyx_v___pyx_state); /*proto*/ +static PyObject *__pyx_pw_6region_7Polygon_9__setstate_cython__(PyObject *__pyx_v_self, PyObject *__pyx_v___pyx_state) { + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__setstate_cython__ (wrapper)", 0); + __pyx_r = __pyx_pf_6region_7Polygon_8__setstate_cython__(((struct __pyx_obj_6region_Polygon *)__pyx_v_self), ((PyObject *)__pyx_v___pyx_state)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6region_7Polygon_8__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_6region_Polygon *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__setstate_cython__", 0); + + /* "(tree fragment)":4 + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + * def __setstate_cython__(self, __pyx_state): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") # <<<<<<<<<<<<<< + */ + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_TypeError, __pyx_tuple__7, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_Raise(__pyx_t_1, 0, 0, 0); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __PYX_ERR(1, 4, __pyx_L1_error) + + /* "(tree fragment)":3 + * def __reduce_cython__(self): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("region.Polygon.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "region.pyx":161 + * # return c_vot_overlap(p1, p2) + * + * def vot_overlap(polygon1, polygon2, bounds=None): # <<<<<<<<<<<<<< + * """ computing overlap between two polygon + * Args: + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6region_1vot_overlap(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6region_vot_overlap[] = " computing overlap between two polygon\n Args:\n polygon1: polygon tuple of points\n polygon2: polygon tuple of points\n bounds: tuple of (left, top, right, bottom)\n Return:\n overlap: overlap between two polygons\n "; +static PyMethodDef __pyx_mdef_6region_1vot_overlap = {"vot_overlap", (PyCFunction)(void*)(PyCFunctionWithKeywords)__pyx_pw_6region_1vot_overlap, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6region_vot_overlap}; +static PyObject *__pyx_pw_6region_1vot_overlap(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_polygon1 = 0; + PyObject *__pyx_v_polygon2 = 0; + PyObject *__pyx_v_bounds = 0; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("vot_overlap (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_polygon1,&__pyx_n_s_polygon2,&__pyx_n_s_bounds,0}; + PyObject* values[3] = {0,0,0}; + values[2] = ((PyObject *)Py_None); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_polygon1)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_polygon2)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("vot_overlap", 0, 2, 3, 1); __PYX_ERR(0, 161, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_bounds); + if (value) { values[2] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "vot_overlap") < 0)) __PYX_ERR(0, 161, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_polygon1 = values[0]; + __pyx_v_polygon2 = values[1]; + __pyx_v_bounds = values[2]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("vot_overlap", 0, 2, 3, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 161, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("region.vot_overlap", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6region_vot_overlap(__pyx_self, __pyx_v_polygon1, __pyx_v_polygon2, __pyx_v_bounds); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6region_vot_overlap(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_polygon1, PyObject *__pyx_v_polygon2, PyObject *__pyx_v_bounds) { + struct __pyx_obj_6region_Polygon *__pyx_v_polygon1_ = NULL; + struct __pyx_obj_6region_Polygon *__pyx_v_polygon2_ = NULL; + float __pyx_v_only1; + float __pyx_v_only2; + region_polygon *__pyx_v_c_polygon1; + region_polygon *__pyx_v_c_polygon2; + region_bounds __pyx_v_no_bounds; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + region_polygon *__pyx_t_2; + int __pyx_t_3; + int __pyx_t_4; + int __pyx_t_5; + Py_ssize_t __pyx_t_6; + float __pyx_t_7; + double __pyx_t_8; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("vot_overlap", 0); + + /* "region.pyx":170 + * overlap: overlap between two polygons + * """ + * polygon1_ = Polygon(polygon1) # <<<<<<<<<<<<<< + * polygon2_ = Polygon(polygon2) + * cdef float only1 = 0 + */ + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_6region_Polygon), __pyx_v_polygon1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 170, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_polygon1_ = ((struct __pyx_obj_6region_Polygon *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "region.pyx":171 + * """ + * polygon1_ = Polygon(polygon1) + * polygon2_ = Polygon(polygon2) # <<<<<<<<<<<<<< + * cdef float only1 = 0 + * cdef float only2 = 0 + */ + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_6region_Polygon), __pyx_v_polygon2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 171, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_polygon2_ = ((struct __pyx_obj_6region_Polygon *)__pyx_t_1); + __pyx_t_1 = 0; + + /* "region.pyx":172 + * polygon1_ = Polygon(polygon1) + * polygon2_ = Polygon(polygon2) + * cdef float only1 = 0 # <<<<<<<<<<<<<< + * cdef float only2 = 0 + * # cdef c_region.region_polygon* c_polygon1 = polygon1._c_region_polygon + */ + __pyx_v_only1 = 0.0; + + /* "region.pyx":173 + * polygon2_ = Polygon(polygon2) + * cdef float only1 = 0 + * cdef float only2 = 0 # <<<<<<<<<<<<<< + * # cdef c_region.region_polygon* c_polygon1 = polygon1._c_region_polygon + * # cdef c_region.region_polygon* c_polygon2 = polygon2._c_region_polygon + */ + __pyx_v_only2 = 0.0; + + /* "region.pyx":176 + * # cdef c_region.region_polygon* c_polygon1 = polygon1._c_region_polygon + * # cdef c_region.region_polygon* c_polygon2 = polygon2._c_region_polygon + * cdef c_region.region_polygon* c_polygon1 = polygon1_._c_region_polygon # <<<<<<<<<<<<<< + * cdef c_region.region_polygon* c_polygon2 = polygon2_._c_region_polygon + * cdef c_region.region_bounds no_bounds + */ + __pyx_t_2 = __pyx_v_polygon1_->_c_region_polygon; + __pyx_v_c_polygon1 = __pyx_t_2; + + /* "region.pyx":177 + * # cdef c_region.region_polygon* c_polygon2 = polygon2._c_region_polygon + * cdef c_region.region_polygon* c_polygon1 = polygon1_._c_region_polygon + * cdef c_region.region_polygon* c_polygon2 = polygon2_._c_region_polygon # <<<<<<<<<<<<<< + * cdef c_region.region_bounds no_bounds + * if bounds is not None and len(bounds) == 2: + */ + __pyx_t_2 = __pyx_v_polygon2_->_c_region_polygon; + __pyx_v_c_polygon2 = __pyx_t_2; + + /* "region.pyx":179 + * cdef c_region.region_polygon* c_polygon2 = polygon2_._c_region_polygon + * cdef c_region.region_bounds no_bounds + * if bounds is not None and len(bounds) == 2: # <<<<<<<<<<<<<< + * no_bounds.top = 0 + * no_bounds.bottom = bounds[1] + */ + __pyx_t_4 = (__pyx_v_bounds != Py_None); + __pyx_t_5 = (__pyx_t_4 != 0); + if (__pyx_t_5) { + } else { + __pyx_t_3 = __pyx_t_5; + goto __pyx_L4_bool_binop_done; + } + __pyx_t_6 = PyObject_Length(__pyx_v_bounds); if (unlikely(__pyx_t_6 == ((Py_ssize_t)-1))) __PYX_ERR(0, 179, __pyx_L1_error) + __pyx_t_5 = ((__pyx_t_6 == 2) != 0); + __pyx_t_3 = __pyx_t_5; + __pyx_L4_bool_binop_done:; + if (__pyx_t_3) { + + /* "region.pyx":180 + * cdef c_region.region_bounds no_bounds + * if bounds is not None and len(bounds) == 2: + * no_bounds.top = 0 # <<<<<<<<<<<<<< + * no_bounds.bottom = bounds[1] + * no_bounds.left = 0 + */ + __pyx_v_no_bounds.top = 0.0; + + /* "region.pyx":181 + * if bounds is not None and len(bounds) == 2: + * no_bounds.top = 0 + * no_bounds.bottom = bounds[1] # <<<<<<<<<<<<<< + * no_bounds.left = 0 + * no_bounds.right = bounds[0] + */ + __pyx_t_1 = __Pyx_GetItemInt(__pyx_v_bounds, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 181, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_7 = __pyx_PyFloat_AsFloat(__pyx_t_1); if (unlikely((__pyx_t_7 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 181, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_no_bounds.bottom = __pyx_t_7; + + /* "region.pyx":182 + * no_bounds.top = 0 + * no_bounds.bottom = bounds[1] + * no_bounds.left = 0 # <<<<<<<<<<<<<< + * no_bounds.right = bounds[0] + * elif bounds is not None and len(bounds) == 4: + */ + __pyx_v_no_bounds.left = 0.0; + + /* "region.pyx":183 + * no_bounds.bottom = bounds[1] + * no_bounds.left = 0 + * no_bounds.right = bounds[0] # <<<<<<<<<<<<<< + * elif bounds is not None and len(bounds) == 4: + * bounds.left = bounds[0] + */ + __pyx_t_1 = __Pyx_GetItemInt(__pyx_v_bounds, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 183, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_7 = __pyx_PyFloat_AsFloat(__pyx_t_1); if (unlikely((__pyx_t_7 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 183, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_no_bounds.right = __pyx_t_7; + + /* "region.pyx":179 + * cdef c_region.region_polygon* c_polygon2 = polygon2_._c_region_polygon + * cdef c_region.region_bounds no_bounds + * if bounds is not None and len(bounds) == 2: # <<<<<<<<<<<<<< + * no_bounds.top = 0 + * no_bounds.bottom = bounds[1] + */ + goto __pyx_L3; + } + + /* "region.pyx":184 + * no_bounds.left = 0 + * no_bounds.right = bounds[0] + * elif bounds is not None and len(bounds) == 4: # <<<<<<<<<<<<<< + * bounds.left = bounds[0] + * bounds.top = bounds[1] + */ + __pyx_t_5 = (__pyx_v_bounds != Py_None); + __pyx_t_4 = (__pyx_t_5 != 0); + if (__pyx_t_4) { + } else { + __pyx_t_3 = __pyx_t_4; + goto __pyx_L6_bool_binop_done; + } + __pyx_t_6 = PyObject_Length(__pyx_v_bounds); if (unlikely(__pyx_t_6 == ((Py_ssize_t)-1))) __PYX_ERR(0, 184, __pyx_L1_error) + __pyx_t_4 = ((__pyx_t_6 == 4) != 0); + __pyx_t_3 = __pyx_t_4; + __pyx_L6_bool_binop_done:; + if (__pyx_t_3) { + + /* "region.pyx":185 + * no_bounds.right = bounds[0] + * elif bounds is not None and len(bounds) == 4: + * bounds.left = bounds[0] # <<<<<<<<<<<<<< + * bounds.top = bounds[1] + * bounds.right = bounds[2] + */ + __pyx_t_1 = __Pyx_GetItemInt(__pyx_v_bounds, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 185, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (__Pyx_PyObject_SetAttrStr(__pyx_v_bounds, __pyx_n_s_left, __pyx_t_1) < 0) __PYX_ERR(0, 185, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "region.pyx":186 + * elif bounds is not None and len(bounds) == 4: + * bounds.left = bounds[0] + * bounds.top = bounds[1] # <<<<<<<<<<<<<< + * bounds.right = bounds[2] + * bounds.bottom = bounds[3] + */ + __pyx_t_1 = __Pyx_GetItemInt(__pyx_v_bounds, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 186, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (__Pyx_PyObject_SetAttrStr(__pyx_v_bounds, __pyx_n_s_top, __pyx_t_1) < 0) __PYX_ERR(0, 186, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "region.pyx":187 + * bounds.left = bounds[0] + * bounds.top = bounds[1] + * bounds.right = bounds[2] # <<<<<<<<<<<<<< + * bounds.bottom = bounds[3] + * else: + */ + __pyx_t_1 = __Pyx_GetItemInt(__pyx_v_bounds, 2, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 187, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (__Pyx_PyObject_SetAttrStr(__pyx_v_bounds, __pyx_n_s_right, __pyx_t_1) < 0) __PYX_ERR(0, 187, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "region.pyx":188 + * bounds.top = bounds[1] + * bounds.right = bounds[2] + * bounds.bottom = bounds[3] # <<<<<<<<<<<<<< + * else: + * no_bounds.top = -float("inf") + */ + __pyx_t_1 = __Pyx_GetItemInt(__pyx_v_bounds, 3, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 188, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (__Pyx_PyObject_SetAttrStr(__pyx_v_bounds, __pyx_n_s_bottom, __pyx_t_1) < 0) __PYX_ERR(0, 188, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "region.pyx":184 + * no_bounds.left = 0 + * no_bounds.right = bounds[0] + * elif bounds is not None and len(bounds) == 4: # <<<<<<<<<<<<<< + * bounds.left = bounds[0] + * bounds.top = bounds[1] + */ + goto __pyx_L3; + } + + /* "region.pyx":190 + * bounds.bottom = bounds[3] + * else: + * no_bounds.top = -float("inf") # <<<<<<<<<<<<<< + * no_bounds.bottom = float("inf") + * no_bounds.left = -float("inf") + */ + /*else*/ { + __pyx_t_8 = __Pyx_PyObject_AsDouble(__pyx_n_s_inf); if (unlikely(__pyx_t_8 == ((double)((double)-1)) && PyErr_Occurred())) __PYX_ERR(0, 190, __pyx_L1_error) + __pyx_v_no_bounds.top = (-__pyx_t_8); + + /* "region.pyx":191 + * else: + * no_bounds.top = -float("inf") + * no_bounds.bottom = float("inf") # <<<<<<<<<<<<<< + * no_bounds.left = -float("inf") + * no_bounds.right = float("inf") + */ + __pyx_t_8 = __Pyx_PyObject_AsDouble(__pyx_n_s_inf); if (unlikely(__pyx_t_8 == ((double)((double)-1)) && PyErr_Occurred())) __PYX_ERR(0, 191, __pyx_L1_error) + __pyx_v_no_bounds.bottom = __pyx_t_8; + + /* "region.pyx":192 + * no_bounds.top = -float("inf") + * no_bounds.bottom = float("inf") + * no_bounds.left = -float("inf") # <<<<<<<<<<<<<< + * no_bounds.right = float("inf") + * return c_region.compute_polygon_overlap(c_polygon1, + */ + __pyx_t_8 = __Pyx_PyObject_AsDouble(__pyx_n_s_inf); if (unlikely(__pyx_t_8 == ((double)((double)-1)) && PyErr_Occurred())) __PYX_ERR(0, 192, __pyx_L1_error) + __pyx_v_no_bounds.left = (-__pyx_t_8); + + /* "region.pyx":193 + * no_bounds.bottom = float("inf") + * no_bounds.left = -float("inf") + * no_bounds.right = float("inf") # <<<<<<<<<<<<<< + * return c_region.compute_polygon_overlap(c_polygon1, + * c_polygon2, + */ + __pyx_t_8 = __Pyx_PyObject_AsDouble(__pyx_n_s_inf); if (unlikely(__pyx_t_8 == ((double)((double)-1)) && PyErr_Occurred())) __PYX_ERR(0, 193, __pyx_L1_error) + __pyx_v_no_bounds.right = __pyx_t_8; + } + __pyx_L3:; + + /* "region.pyx":194 + * no_bounds.left = -float("inf") + * no_bounds.right = float("inf") + * return c_region.compute_polygon_overlap(c_polygon1, # <<<<<<<<<<<<<< + * c_polygon2, + * &only1, + */ + __Pyx_XDECREF(__pyx_r); + + /* "region.pyx":198 + * &only1, + * &only2, + * no_bounds) # <<<<<<<<<<<<<< + * + * def vot_overlap_traj(polygons1, polygons2, bounds): + */ + __pyx_t_1 = PyFloat_FromDouble(compute_polygon_overlap(__pyx_v_c_polygon1, __pyx_v_c_polygon2, (&__pyx_v_only1), (&__pyx_v_only2), __pyx_v_no_bounds)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 194, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "region.pyx":161 + * # return c_vot_overlap(p1, p2) + * + * def vot_overlap(polygon1, polygon2, bounds=None): # <<<<<<<<<<<<<< + * """ computing overlap between two polygon + * Args: + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("region.vot_overlap", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_polygon1_); + __Pyx_XDECREF((PyObject *)__pyx_v_polygon2_); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "region.pyx":200 + * no_bounds) + * + * def vot_overlap_traj(polygons1, polygons2, bounds): # <<<<<<<<<<<<<< + * """ computing overlap between two trajectory + * Args: + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6region_3vot_overlap_traj(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_6region_2vot_overlap_traj[] = " computing overlap between two trajectory\n Args:\n polygons1: list of polygon\n polygons2: list of polygon\n "; +static PyMethodDef __pyx_mdef_6region_3vot_overlap_traj = {"vot_overlap_traj", (PyCFunction)(void*)(PyCFunctionWithKeywords)__pyx_pw_6region_3vot_overlap_traj, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6region_2vot_overlap_traj}; +static PyObject *__pyx_pw_6region_3vot_overlap_traj(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_polygons1 = 0; + PyObject *__pyx_v_polygons2 = 0; + CYTHON_UNUSED PyObject *__pyx_v_bounds = 0; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("vot_overlap_traj (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_polygons1,&__pyx_n_s_polygons2,&__pyx_n_s_bounds,0}; + PyObject* values[3] = {0,0,0}; + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_polygons1)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_polygons2)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("vot_overlap_traj", 1, 3, 3, 1); __PYX_ERR(0, 200, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_bounds)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("vot_overlap_traj", 1, 3, 3, 2); __PYX_ERR(0, 200, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "vot_overlap_traj") < 0)) __PYX_ERR(0, 200, __pyx_L3_error) + } + } else if (PyTuple_GET_SIZE(__pyx_args) != 3) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + } + __pyx_v_polygons1 = values[0]; + __pyx_v_polygons2 = values[1]; + __pyx_v_bounds = values[2]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("vot_overlap_traj", 1, 3, 3, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 200, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("region.vot_overlap_traj", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6region_2vot_overlap_traj(__pyx_self, __pyx_v_polygons1, __pyx_v_polygons2, __pyx_v_bounds); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6region_2vot_overlap_traj(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_polygons1, PyObject *__pyx_v_polygons2, CYTHON_UNUSED PyObject *__pyx_v_bounds) { + PyObject *__pyx_v_overlaps = NULL; + Py_ssize_t __pyx_v_num; + float __pyx_v_only1; + float __pyx_v_only2; + region_bounds __pyx_v_no_bounds; + region_polygon *__pyx_v_c_polygon1; + region_polygon *__pyx_v_c_polygon2; + Py_ssize_t __pyx_v_i; + struct __pyx_obj_6region_Polygon *__pyx_v_polygon1_ = NULL; + struct __pyx_obj_6region_Polygon *__pyx_v_polygon2_ = NULL; + PyObject *__pyx_v_overlap = NULL; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + Py_ssize_t __pyx_t_2; + double __pyx_t_3; + Py_ssize_t __pyx_t_4; + Py_ssize_t __pyx_t_5; + PyObject *__pyx_t_6 = NULL; + region_polygon *__pyx_t_7; + int __pyx_t_8; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("vot_overlap_traj", 0); + + /* "region.pyx":206 + * polygons2: list of polygon + * """ + * overlaps = [] # <<<<<<<<<<<<<< + * num = len(polygons1) + * cdef float only1 = 0 + */ + __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 206, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_overlaps = ((PyObject*)__pyx_t_1); + __pyx_t_1 = 0; + + /* "region.pyx":207 + * """ + * overlaps = [] + * num = len(polygons1) # <<<<<<<<<<<<<< + * cdef float only1 = 0 + * cdef float only2 = 0 + */ + __pyx_t_2 = PyObject_Length(__pyx_v_polygons1); if (unlikely(__pyx_t_2 == ((Py_ssize_t)-1))) __PYX_ERR(0, 207, __pyx_L1_error) + __pyx_v_num = __pyx_t_2; + + /* "region.pyx":208 + * overlaps = [] + * num = len(polygons1) + * cdef float only1 = 0 # <<<<<<<<<<<<<< + * cdef float only2 = 0 + * cdef c_region.region_bounds no_bounds + */ + __pyx_v_only1 = 0.0; + + /* "region.pyx":209 + * num = len(polygons1) + * cdef float only1 = 0 + * cdef float only2 = 0 # <<<<<<<<<<<<<< + * cdef c_region.region_bounds no_bounds + * no_bounds.top = -float("inf") + */ + __pyx_v_only2 = 0.0; + + /* "region.pyx":211 + * cdef float only2 = 0 + * cdef c_region.region_bounds no_bounds + * no_bounds.top = -float("inf") # <<<<<<<<<<<<<< + * no_bounds.bottom = float("inf") + * no_bounds.left = -float("inf") + */ + __pyx_t_3 = __Pyx_PyObject_AsDouble(__pyx_n_s_inf); if (unlikely(__pyx_t_3 == ((double)((double)-1)) && PyErr_Occurred())) __PYX_ERR(0, 211, __pyx_L1_error) + __pyx_v_no_bounds.top = (-__pyx_t_3); + + /* "region.pyx":212 + * cdef c_region.region_bounds no_bounds + * no_bounds.top = -float("inf") + * no_bounds.bottom = float("inf") # <<<<<<<<<<<<<< + * no_bounds.left = -float("inf") + * no_bounds.right = float("inf") + */ + __pyx_t_3 = __Pyx_PyObject_AsDouble(__pyx_n_s_inf); if (unlikely(__pyx_t_3 == ((double)((double)-1)) && PyErr_Occurred())) __PYX_ERR(0, 212, __pyx_L1_error) + __pyx_v_no_bounds.bottom = __pyx_t_3; + + /* "region.pyx":213 + * no_bounds.top = -float("inf") + * no_bounds.bottom = float("inf") + * no_bounds.left = -float("inf") # <<<<<<<<<<<<<< + * no_bounds.right = float("inf") + * cdef c_region.region_polygon* c_polygon1 + */ + __pyx_t_3 = __Pyx_PyObject_AsDouble(__pyx_n_s_inf); if (unlikely(__pyx_t_3 == ((double)((double)-1)) && PyErr_Occurred())) __PYX_ERR(0, 213, __pyx_L1_error) + __pyx_v_no_bounds.left = (-__pyx_t_3); + + /* "region.pyx":214 + * no_bounds.bottom = float("inf") + * no_bounds.left = -float("inf") + * no_bounds.right = float("inf") # <<<<<<<<<<<<<< + * cdef c_region.region_polygon* c_polygon1 + * cdef c_region.region_polygon* c_polygon2 + */ + __pyx_t_3 = __Pyx_PyObject_AsDouble(__pyx_n_s_inf); if (unlikely(__pyx_t_3 == ((double)((double)-1)) && PyErr_Occurred())) __PYX_ERR(0, 214, __pyx_L1_error) + __pyx_v_no_bounds.right = __pyx_t_3; + + /* "region.pyx":217 + * cdef c_region.region_polygon* c_polygon1 + * cdef c_region.region_polygon* c_polygon2 + * for i in range(num): # <<<<<<<<<<<<<< + * polygon1_ = Polygon(polygons1[i]) + * polygon2_ = Polygon(polygons2[i]) + */ + __pyx_t_2 = __pyx_v_num; + __pyx_t_4 = __pyx_t_2; + for (__pyx_t_5 = 0; __pyx_t_5 < __pyx_t_4; __pyx_t_5+=1) { + __pyx_v_i = __pyx_t_5; + + /* "region.pyx":218 + * cdef c_region.region_polygon* c_polygon2 + * for i in range(num): + * polygon1_ = Polygon(polygons1[i]) # <<<<<<<<<<<<<< + * polygon2_ = Polygon(polygons2[i]) + * c_polygon1 = polygon1_._c_region_polygon + */ + __pyx_t_1 = __Pyx_GetItemInt(__pyx_v_polygons1, __pyx_v_i, Py_ssize_t, 1, PyInt_FromSsize_t, 0, 1, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 218, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_6 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_6region_Polygon), __pyx_t_1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 218, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_XDECREF_SET(__pyx_v_polygon1_, ((struct __pyx_obj_6region_Polygon *)__pyx_t_6)); + __pyx_t_6 = 0; + + /* "region.pyx":219 + * for i in range(num): + * polygon1_ = Polygon(polygons1[i]) + * polygon2_ = Polygon(polygons2[i]) # <<<<<<<<<<<<<< + * c_polygon1 = polygon1_._c_region_polygon + * c_polygon2 = polygon2_._c_region_polygon + */ + __pyx_t_6 = __Pyx_GetItemInt(__pyx_v_polygons2, __pyx_v_i, Py_ssize_t, 1, PyInt_FromSsize_t, 0, 1, 1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 219, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_1 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_6region_Polygon), __pyx_t_6); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 219, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_XDECREF_SET(__pyx_v_polygon2_, ((struct __pyx_obj_6region_Polygon *)__pyx_t_1)); + __pyx_t_1 = 0; + + /* "region.pyx":220 + * polygon1_ = Polygon(polygons1[i]) + * polygon2_ = Polygon(polygons2[i]) + * c_polygon1 = polygon1_._c_region_polygon # <<<<<<<<<<<<<< + * c_polygon2 = polygon2_._c_region_polygon + * overlap = c_region.compute_polygon_overlap(c_polygon1, + */ + __pyx_t_7 = __pyx_v_polygon1_->_c_region_polygon; + __pyx_v_c_polygon1 = __pyx_t_7; + + /* "region.pyx":221 + * polygon2_ = Polygon(polygons2[i]) + * c_polygon1 = polygon1_._c_region_polygon + * c_polygon2 = polygon2_._c_region_polygon # <<<<<<<<<<<<<< + * overlap = c_region.compute_polygon_overlap(c_polygon1, + * c_polygon2, + */ + __pyx_t_7 = __pyx_v_polygon2_->_c_region_polygon; + __pyx_v_c_polygon2 = __pyx_t_7; + + /* "region.pyx":222 + * c_polygon1 = polygon1_._c_region_polygon + * c_polygon2 = polygon2_._c_region_polygon + * overlap = c_region.compute_polygon_overlap(c_polygon1, # <<<<<<<<<<<<<< + * c_polygon2, + * &only1, + */ + __pyx_t_1 = PyFloat_FromDouble(compute_polygon_overlap(__pyx_v_c_polygon1, __pyx_v_c_polygon2, (&__pyx_v_only1), (&__pyx_v_only2), __pyx_v_no_bounds)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 222, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_XDECREF_SET(__pyx_v_overlap, __pyx_t_1); + __pyx_t_1 = 0; + + /* "region.pyx":227 + * &only2, + * no_bounds) + * overlaps.append(overlap) # <<<<<<<<<<<<<< + * return overlaps + * + */ + __pyx_t_8 = __Pyx_PyList_Append(__pyx_v_overlaps, __pyx_v_overlap); if (unlikely(__pyx_t_8 == ((int)-1))) __PYX_ERR(0, 227, __pyx_L1_error) + } + + /* "region.pyx":228 + * no_bounds) + * overlaps.append(overlap) + * return overlaps # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_overlaps); + __pyx_r = __pyx_v_overlaps; + goto __pyx_L0; + + /* "region.pyx":200 + * no_bounds) + * + * def vot_overlap_traj(polygons1, polygons2, bounds): # <<<<<<<<<<<<<< + * """ computing overlap between two trajectory + * Args: + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_AddTraceback("region.vot_overlap_traj", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_overlaps); + __Pyx_XDECREF((PyObject *)__pyx_v_polygon1_); + __Pyx_XDECREF((PyObject *)__pyx_v_polygon2_); + __Pyx_XDECREF(__pyx_v_overlap); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "region.pyx":231 + * + * + * def vot_float2str(template, float value): # <<<<<<<<<<<<<< + * cdef bytes ptemplate = template.encode() + * cdef const char* ctemplate = ptemplate + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_6region_5vot_float2str(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static PyMethodDef __pyx_mdef_6region_5vot_float2str = {"vot_float2str", (PyCFunction)(void*)(PyCFunctionWithKeywords)__pyx_pw_6region_5vot_float2str, METH_VARARGS|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_6region_5vot_float2str(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_template = 0; + float __pyx_v_value; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("vot_float2str (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_template,&__pyx_n_s_value,0}; + PyObject* values[2] = {0,0}; + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_template)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_value)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("vot_float2str", 1, 2, 2, 1); __PYX_ERR(0, 231, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "vot_float2str") < 0)) __PYX_ERR(0, 231, __pyx_L3_error) + } + } else if (PyTuple_GET_SIZE(__pyx_args) != 2) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + } + __pyx_v_template = values[0]; + __pyx_v_value = __pyx_PyFloat_AsFloat(values[1]); if (unlikely((__pyx_v_value == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 231, __pyx_L3_error) + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("vot_float2str", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 231, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("region.vot_float2str", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_6region_4vot_float2str(__pyx_self, __pyx_v_template, __pyx_v_value); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_6region_4vot_float2str(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_template, float __pyx_v_value) { + PyObject *__pyx_v_ptemplate = 0; + char const *__pyx_v_ctemplate; + char *__pyx_v_output; + PyObject *__pyx_v_ret = NULL; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + char const *__pyx_t_4; + int __pyx_t_5; + int __pyx_t_6; + int __pyx_t_7; + char const *__pyx_t_8; + PyObject *__pyx_t_9 = NULL; + PyObject *__pyx_t_10 = NULL; + PyObject *__pyx_t_11 = NULL; + PyObject *__pyx_t_12 = NULL; + PyObject *__pyx_t_13 = NULL; + PyObject *__pyx_t_14 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("vot_float2str", 0); + + /* "region.pyx":232 + * + * def vot_float2str(template, float value): + * cdef bytes ptemplate = template.encode() # <<<<<<<<<<<<<< + * cdef const char* ctemplate = ptemplate + * cdef char* output = malloc(sizeof(char) * 100) + */ + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_template, __pyx_n_s_encode); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 232, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + } + } + __pyx_t_1 = (__pyx_t_3) ? __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_3) : __Pyx_PyObject_CallNoArg(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 232, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (!(likely(PyBytes_CheckExact(__pyx_t_1))||((__pyx_t_1) == Py_None)||((void)PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytes", Py_TYPE(__pyx_t_1)->tp_name), 0))) __PYX_ERR(0, 232, __pyx_L1_error) + __pyx_v_ptemplate = ((PyObject*)__pyx_t_1); + __pyx_t_1 = 0; + + /* "region.pyx":233 + * def vot_float2str(template, float value): + * cdef bytes ptemplate = template.encode() + * cdef const char* ctemplate = ptemplate # <<<<<<<<<<<<<< + * cdef char* output = malloc(sizeof(char) * 100) + * if not output: + */ + if (unlikely(__pyx_v_ptemplate == Py_None)) { + PyErr_SetString(PyExc_TypeError, "expected bytes, NoneType found"); + __PYX_ERR(0, 233, __pyx_L1_error) + } + __pyx_t_4 = __Pyx_PyBytes_AsString(__pyx_v_ptemplate); if (unlikely((!__pyx_t_4) && PyErr_Occurred())) __PYX_ERR(0, 233, __pyx_L1_error) + __pyx_v_ctemplate = __pyx_t_4; + + /* "region.pyx":234 + * cdef bytes ptemplate = template.encode() + * cdef const char* ctemplate = ptemplate + * cdef char* output = malloc(sizeof(char) * 100) # <<<<<<<<<<<<<< + * if not output: + * raise MemoryError() + */ + __pyx_v_output = ((char *)malloc(((sizeof(char)) * 0x64))); + + /* "region.pyx":235 + * cdef const char* ctemplate = ptemplate + * cdef char* output = malloc(sizeof(char) * 100) + * if not output: # <<<<<<<<<<<<<< + * raise MemoryError() + * sprintf(output, ctemplate, value) + */ + __pyx_t_5 = ((!(__pyx_v_output != 0)) != 0); + if (unlikely(__pyx_t_5)) { + + /* "region.pyx":236 + * cdef char* output = malloc(sizeof(char) * 100) + * if not output: + * raise MemoryError() # <<<<<<<<<<<<<< + * sprintf(output, ctemplate, value) + * try: + */ + PyErr_NoMemory(); __PYX_ERR(0, 236, __pyx_L1_error) + + /* "region.pyx":235 + * cdef const char* ctemplate = ptemplate + * cdef char* output = malloc(sizeof(char) * 100) + * if not output: # <<<<<<<<<<<<<< + * raise MemoryError() + * sprintf(output, ctemplate, value) + */ + } + + /* "region.pyx":237 + * if not output: + * raise MemoryError() + * sprintf(output, ctemplate, value) # <<<<<<<<<<<<<< + * try: + * ret = output[:strlen(output)].decode() + */ + (void)(sprintf(__pyx_v_output, __pyx_v_ctemplate, __pyx_v_value)); + + /* "region.pyx":238 + * raise MemoryError() + * sprintf(output, ctemplate, value) + * try: # <<<<<<<<<<<<<< + * ret = output[:strlen(output)].decode() + * finally: + */ + /*try:*/ { + + /* "region.pyx":239 + * sprintf(output, ctemplate, value) + * try: + * ret = output[:strlen(output)].decode() # <<<<<<<<<<<<<< + * finally: + * free(output) + */ + __pyx_t_1 = __Pyx_decode_c_string(__pyx_v_output, 0, strlen(__pyx_v_output), NULL, NULL, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 239, __pyx_L5_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v_ret = __pyx_t_1; + __pyx_t_1 = 0; + } + + /* "region.pyx":241 + * ret = output[:strlen(output)].decode() + * finally: + * free(output) # <<<<<<<<<<<<<< + * return ret + */ + /*finally:*/ { + /*normal exit:*/{ + free(__pyx_v_output); + goto __pyx_L6; + } + __pyx_L5_error:; + /*exception exit:*/{ + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __pyx_t_9 = 0; __pyx_t_10 = 0; __pyx_t_11 = 0; __pyx_t_12 = 0; __pyx_t_13 = 0; __pyx_t_14 = 0; + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + if (PY_MAJOR_VERSION >= 3) __Pyx_ExceptionSwap(&__pyx_t_12, &__pyx_t_13, &__pyx_t_14); + if ((PY_MAJOR_VERSION < 3) || unlikely(__Pyx_GetException(&__pyx_t_9, &__pyx_t_10, &__pyx_t_11) < 0)) __Pyx_ErrFetch(&__pyx_t_9, &__pyx_t_10, &__pyx_t_11); + __Pyx_XGOTREF(__pyx_t_9); + __Pyx_XGOTREF(__pyx_t_10); + __Pyx_XGOTREF(__pyx_t_11); + __Pyx_XGOTREF(__pyx_t_12); + __Pyx_XGOTREF(__pyx_t_13); + __Pyx_XGOTREF(__pyx_t_14); + __pyx_t_6 = __pyx_lineno; __pyx_t_7 = __pyx_clineno; __pyx_t_8 = __pyx_filename; + { + free(__pyx_v_output); + } + if (PY_MAJOR_VERSION >= 3) { + __Pyx_XGIVEREF(__pyx_t_12); + __Pyx_XGIVEREF(__pyx_t_13); + __Pyx_XGIVEREF(__pyx_t_14); + __Pyx_ExceptionReset(__pyx_t_12, __pyx_t_13, __pyx_t_14); + } + __Pyx_XGIVEREF(__pyx_t_9); + __Pyx_XGIVEREF(__pyx_t_10); + __Pyx_XGIVEREF(__pyx_t_11); + __Pyx_ErrRestore(__pyx_t_9, __pyx_t_10, __pyx_t_11); + __pyx_t_9 = 0; __pyx_t_10 = 0; __pyx_t_11 = 0; __pyx_t_12 = 0; __pyx_t_13 = 0; __pyx_t_14 = 0; + __pyx_lineno = __pyx_t_6; __pyx_clineno = __pyx_t_7; __pyx_filename = __pyx_t_8; + goto __pyx_L1_error; + } + __pyx_L6:; + } + + /* "region.pyx":242 + * finally: + * free(output) + * return ret # <<<<<<<<<<<<<< + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_ret); + __pyx_r = __pyx_v_ret; + goto __pyx_L0; + + /* "region.pyx":231 + * + * + * def vot_float2str(template, float value): # <<<<<<<<<<<<<< + * cdef bytes ptemplate = template.encode() + * cdef const char* ctemplate = ptemplate + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("region.vot_float2str", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_ptemplate); + __Pyx_XDECREF(__pyx_v_ret); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "EnumBase":16 + * @cython.internal + * cdef class __Pyx_EnumMeta(type): + * def __init__(cls, name, parents, dct): # <<<<<<<<<<<<<< + * type.__init__(cls, name, parents, dct) + * cls.__members__ = __Pyx_OrderedDict() + */ + +/* Python wrapper */ +static int __pyx_pw_8EnumBase_14__Pyx_EnumMeta_1__init__(PyObject *__pyx_v_cls, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static int __pyx_pw_8EnumBase_14__Pyx_EnumMeta_1__init__(PyObject *__pyx_v_cls, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_name = 0; + PyObject *__pyx_v_parents = 0; + PyObject *__pyx_v_dct = 0; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__init__ (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_name,&__pyx_n_s_parents,&__pyx_n_s_dct,0}; + PyObject* values[3] = {0,0,0}; + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_name)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_parents)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("__init__", 1, 3, 3, 1); __PYX_ERR(1, 16, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_dct)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("__init__", 1, 3, 3, 2); __PYX_ERR(1, 16, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__init__") < 0)) __PYX_ERR(1, 16, __pyx_L3_error) + } + } else if (PyTuple_GET_SIZE(__pyx_args) != 3) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + } + __pyx_v_name = values[0]; + __pyx_v_parents = values[1]; + __pyx_v_dct = values[2]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__init__", 1, 3, 3, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(1, 16, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("EnumBase.__Pyx_EnumMeta.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return -1; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_8EnumBase_14__Pyx_EnumMeta___init__(((struct __pyx_obj___Pyx_EnumMeta *)__pyx_v_cls), __pyx_v_name, __pyx_v_parents, __pyx_v_dct); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_pf_8EnumBase_14__Pyx_EnumMeta___init__(struct __pyx_obj___Pyx_EnumMeta *__pyx_v_cls, PyObject *__pyx_v_name, PyObject *__pyx_v_parents, PyObject *__pyx_v_dct) { + int __pyx_r; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__init__", 0); + + /* "EnumBase":17 + * cdef class __Pyx_EnumMeta(type): + * def __init__(cls, name, parents, dct): + * type.__init__(cls, name, parents, dct) # <<<<<<<<<<<<<< + * cls.__members__ = __Pyx_OrderedDict() + * def __iter__(cls): + */ + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)(&PyType_Type)), __pyx_n_s_init); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 17, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = NULL; + __pyx_t_4 = 0; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_3)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + __pyx_t_4 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[5] = {__pyx_t_3, ((PyObject *)__pyx_v_cls), __pyx_v_name, __pyx_v_parents, __pyx_v_dct}; + __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_2, __pyx_temp+1-__pyx_t_4, 4+__pyx_t_4); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 17, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_2)) { + PyObject *__pyx_temp[5] = {__pyx_t_3, ((PyObject *)__pyx_v_cls), __pyx_v_name, __pyx_v_parents, __pyx_v_dct}; + __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_2, __pyx_temp+1-__pyx_t_4, 4+__pyx_t_4); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 17, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_GOTREF(__pyx_t_1); + } else + #endif + { + __pyx_t_5 = PyTuple_New(4+__pyx_t_4); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 17, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (__pyx_t_3) { + __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_3); __pyx_t_3 = NULL; + } + __Pyx_INCREF(((PyObject *)__pyx_v_cls)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_cls)); + PyTuple_SET_ITEM(__pyx_t_5, 0+__pyx_t_4, ((PyObject *)__pyx_v_cls)); + __Pyx_INCREF(__pyx_v_name); + __Pyx_GIVEREF(__pyx_v_name); + PyTuple_SET_ITEM(__pyx_t_5, 1+__pyx_t_4, __pyx_v_name); + __Pyx_INCREF(__pyx_v_parents); + __Pyx_GIVEREF(__pyx_v_parents); + PyTuple_SET_ITEM(__pyx_t_5, 2+__pyx_t_4, __pyx_v_parents); + __Pyx_INCREF(__pyx_v_dct); + __Pyx_GIVEREF(__pyx_v_dct); + PyTuple_SET_ITEM(__pyx_t_5, 3+__pyx_t_4, __pyx_v_dct); + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_5, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 17, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + } + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "EnumBase":18 + * def __init__(cls, name, parents, dct): + * type.__init__(cls, name, parents, dct) + * cls.__members__ = __Pyx_OrderedDict() # <<<<<<<<<<<<<< + * def __iter__(cls): + * return iter(cls.__members__.values()) + */ + __Pyx_INCREF(__Pyx_OrderedDict); + __pyx_t_2 = __Pyx_OrderedDict; __pyx_t_5 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_2))) { + __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_2); + if (likely(__pyx_t_5)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); + __Pyx_INCREF(__pyx_t_5); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_2, function); + } + } + __pyx_t_1 = (__pyx_t_5) ? __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_5) : __Pyx_PyObject_CallNoArg(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 18, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + if (__Pyx_PyObject_SetAttrStr(((PyObject *)__pyx_v_cls), __pyx_n_s_members, __pyx_t_1) < 0) __PYX_ERR(1, 18, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "EnumBase":16 + * @cython.internal + * cdef class __Pyx_EnumMeta(type): + * def __init__(cls, name, parents, dct): # <<<<<<<<<<<<<< + * type.__init__(cls, name, parents, dct) + * cls.__members__ = __Pyx_OrderedDict() + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("EnumBase.__Pyx_EnumMeta.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "EnumBase":19 + * type.__init__(cls, name, parents, dct) + * cls.__members__ = __Pyx_OrderedDict() + * def __iter__(cls): # <<<<<<<<<<<<<< + * return iter(cls.__members__.values()) + * def __getitem__(cls, name): + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_8EnumBase_14__Pyx_EnumMeta_3__iter__(PyObject *__pyx_v_cls); /*proto*/ +static PyObject *__pyx_pw_8EnumBase_14__Pyx_EnumMeta_3__iter__(PyObject *__pyx_v_cls) { + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__iter__ (wrapper)", 0); + __pyx_r = __pyx_pf_8EnumBase_14__Pyx_EnumMeta_2__iter__(((struct __pyx_obj___Pyx_EnumMeta *)__pyx_v_cls)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_8EnumBase_14__Pyx_EnumMeta_2__iter__(struct __pyx_obj___Pyx_EnumMeta *__pyx_v_cls) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__iter__", 0); + + /* "EnumBase":20 + * cls.__members__ = __Pyx_OrderedDict() + * def __iter__(cls): + * return iter(cls.__members__.values()) # <<<<<<<<<<<<<< + * def __getitem__(cls, name): + * return cls.__members__[name] + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_cls), __pyx_n_s_members); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 20, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_values); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 20, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_t_2 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_3))) { + __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_3); + if (likely(__pyx_t_2)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3); + __Pyx_INCREF(__pyx_t_2); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_3, function); + } + } + __pyx_t_1 = (__pyx_t_2) ? __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_t_2) : __Pyx_PyObject_CallNoArg(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 20, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 20, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_3; + __pyx_t_3 = 0; + goto __pyx_L0; + + /* "EnumBase":19 + * type.__init__(cls, name, parents, dct) + * cls.__members__ = __Pyx_OrderedDict() + * def __iter__(cls): # <<<<<<<<<<<<<< + * return iter(cls.__members__.values()) + * def __getitem__(cls, name): + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("EnumBase.__Pyx_EnumMeta.__iter__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "EnumBase":21 + * def __iter__(cls): + * return iter(cls.__members__.values()) + * def __getitem__(cls, name): # <<<<<<<<<<<<<< + * return cls.__members__[name] + * + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_8EnumBase_14__Pyx_EnumMeta_5__getitem__(PyObject *__pyx_v_cls, PyObject *__pyx_v_name); /*proto*/ +static PyObject *__pyx_pw_8EnumBase_14__Pyx_EnumMeta_5__getitem__(PyObject *__pyx_v_cls, PyObject *__pyx_v_name) { + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__getitem__ (wrapper)", 0); + __pyx_r = __pyx_pf_8EnumBase_14__Pyx_EnumMeta_4__getitem__(((struct __pyx_obj___Pyx_EnumMeta *)__pyx_v_cls), ((PyObject *)__pyx_v_name)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_8EnumBase_14__Pyx_EnumMeta_4__getitem__(struct __pyx_obj___Pyx_EnumMeta *__pyx_v_cls, PyObject *__pyx_v_name) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__getitem__", 0); + + /* "EnumBase":22 + * return iter(cls.__members__.values()) + * def __getitem__(cls, name): + * return cls.__members__[name] # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_cls), __pyx_n_s_members); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 22, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyObject_GetItem(__pyx_t_1, __pyx_v_name); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 22, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "EnumBase":21 + * def __iter__(cls): + * return iter(cls.__members__.values()) + * def __getitem__(cls, name): # <<<<<<<<<<<<<< + * return cls.__members__[name] + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("EnumBase.__Pyx_EnumMeta.__getitem__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * cdef tuple state + * cdef object _dict + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_8EnumBase_14__Pyx_EnumMeta_7__reduce_cython__(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/ +static PyObject *__pyx_pw_8EnumBase_14__Pyx_EnumMeta_7__reduce_cython__(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) { + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__reduce_cython__ (wrapper)", 0); + __pyx_r = __pyx_pf_8EnumBase_14__Pyx_EnumMeta_6__reduce_cython__(((struct __pyx_obj___Pyx_EnumMeta *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_8EnumBase_14__Pyx_EnumMeta_6__reduce_cython__(struct __pyx_obj___Pyx_EnumMeta *__pyx_v_self) { + PyObject *__pyx_v_state = 0; + PyObject *__pyx_v__dict = 0; + int __pyx_v_use_setstate; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + int __pyx_t_3; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__reduce_cython__", 0); + + /* "(tree fragment)":5 + * cdef object _dict + * cdef bint use_setstate + * state = () # <<<<<<<<<<<<<< + * _dict = getattr(self, '__dict__', None) + * if _dict is not None: + */ + __Pyx_INCREF(__pyx_empty_tuple); + __pyx_v_state = __pyx_empty_tuple; + + /* "(tree fragment)":6 + * cdef bint use_setstate + * state = () + * _dict = getattr(self, '__dict__', None) # <<<<<<<<<<<<<< + * if _dict is not None: + * state += (_dict,) + */ + __pyx_t_1 = __Pyx_GetAttr3(((PyObject *)__pyx_v_self), __pyx_n_s_dict, Py_None); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 6, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_v__dict = __pyx_t_1; + __pyx_t_1 = 0; + + /* "(tree fragment)":7 + * state = () + * _dict = getattr(self, '__dict__', None) + * if _dict is not None: # <<<<<<<<<<<<<< + * state += (_dict,) + * use_setstate = True + */ + __pyx_t_2 = (__pyx_v__dict != Py_None); + __pyx_t_3 = (__pyx_t_2 != 0); + if (__pyx_t_3) { + + /* "(tree fragment)":8 + * _dict = getattr(self, '__dict__', None) + * if _dict is not None: + * state += (_dict,) # <<<<<<<<<<<<<< + * use_setstate = True + * else: + */ + __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 8, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(__pyx_v__dict); + __Pyx_GIVEREF(__pyx_v__dict); + PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_v__dict); + __pyx_t_4 = PyNumber_InPlaceAdd(__pyx_v_state, __pyx_t_1); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 8, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF_SET(__pyx_v_state, ((PyObject*)__pyx_t_4)); + __pyx_t_4 = 0; + + /* "(tree fragment)":9 + * if _dict is not None: + * state += (_dict,) + * use_setstate = True # <<<<<<<<<<<<<< + * else: + * use_setstate = False + */ + __pyx_v_use_setstate = 1; + + /* "(tree fragment)":7 + * state = () + * _dict = getattr(self, '__dict__', None) + * if _dict is not None: # <<<<<<<<<<<<<< + * state += (_dict,) + * use_setstate = True + */ + goto __pyx_L3; + } + + /* "(tree fragment)":11 + * use_setstate = True + * else: + * use_setstate = False # <<<<<<<<<<<<<< + * if use_setstate: + * return __pyx_unpickle___Pyx_EnumMeta, (type(self), 0xd41d8cd, None), state + */ + /*else*/ { + __pyx_v_use_setstate = 0; + } + __pyx_L3:; + + /* "(tree fragment)":12 + * else: + * use_setstate = False + * if use_setstate: # <<<<<<<<<<<<<< + * return __pyx_unpickle___Pyx_EnumMeta, (type(self), 0xd41d8cd, None), state + * else: + */ + __pyx_t_3 = (__pyx_v_use_setstate != 0); + if (__pyx_t_3) { + + /* "(tree fragment)":13 + * use_setstate = False + * if use_setstate: + * return __pyx_unpickle___Pyx_EnumMeta, (type(self), 0xd41d8cd, None), state # <<<<<<<<<<<<<< + * else: + * return __pyx_unpickle___Pyx_EnumMeta, (type(self), 0xd41d8cd, state) + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_pyx_unpickle___Pyx_EnumMeta); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 13, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_1 = PyTuple_New(3); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 13, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(((PyObject *)Py_TYPE(((PyObject *)__pyx_v_self)))); + __Pyx_GIVEREF(((PyObject *)Py_TYPE(((PyObject *)__pyx_v_self)))); + PyTuple_SET_ITEM(__pyx_t_1, 0, ((PyObject *)Py_TYPE(((PyObject *)__pyx_v_self)))); + __Pyx_INCREF(__pyx_int_222419149); + __Pyx_GIVEREF(__pyx_int_222419149); + PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_int_222419149); + __Pyx_INCREF(Py_None); + __Pyx_GIVEREF(Py_None); + PyTuple_SET_ITEM(__pyx_t_1, 2, Py_None); + __pyx_t_5 = PyTuple_New(3); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 13, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_GIVEREF(__pyx_t_4); + PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_4); + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_t_1); + __Pyx_INCREF(__pyx_v_state); + __Pyx_GIVEREF(__pyx_v_state); + PyTuple_SET_ITEM(__pyx_t_5, 2, __pyx_v_state); + __pyx_t_4 = 0; + __pyx_t_1 = 0; + __pyx_r = __pyx_t_5; + __pyx_t_5 = 0; + goto __pyx_L0; + + /* "(tree fragment)":12 + * else: + * use_setstate = False + * if use_setstate: # <<<<<<<<<<<<<< + * return __pyx_unpickle___Pyx_EnumMeta, (type(self), 0xd41d8cd, None), state + * else: + */ + } + + /* "(tree fragment)":15 + * return __pyx_unpickle___Pyx_EnumMeta, (type(self), 0xd41d8cd, None), state + * else: + * return __pyx_unpickle___Pyx_EnumMeta, (type(self), 0xd41d8cd, state) # <<<<<<<<<<<<<< + * def __setstate_cython__(self, __pyx_state): + * __pyx_unpickle___Pyx_EnumMeta__set_state(self, __pyx_state) + */ + /*else*/ { + __Pyx_XDECREF(__pyx_r); + __Pyx_GetModuleGlobalName(__pyx_t_5, __pyx_n_s_pyx_unpickle___Pyx_EnumMeta); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 15, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_1 = PyTuple_New(3); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 15, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(((PyObject *)Py_TYPE(((PyObject *)__pyx_v_self)))); + __Pyx_GIVEREF(((PyObject *)Py_TYPE(((PyObject *)__pyx_v_self)))); + PyTuple_SET_ITEM(__pyx_t_1, 0, ((PyObject *)Py_TYPE(((PyObject *)__pyx_v_self)))); + __Pyx_INCREF(__pyx_int_222419149); + __Pyx_GIVEREF(__pyx_int_222419149); + PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_int_222419149); + __Pyx_INCREF(__pyx_v_state); + __Pyx_GIVEREF(__pyx_v_state); + PyTuple_SET_ITEM(__pyx_t_1, 2, __pyx_v_state); + __pyx_t_4 = PyTuple_New(2); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 15, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_GIVEREF(__pyx_t_5); + PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_5); + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_4, 1, __pyx_t_1); + __pyx_t_5 = 0; + __pyx_t_1 = 0; + __pyx_r = __pyx_t_4; + __pyx_t_4 = 0; + goto __pyx_L0; + } + + /* "(tree fragment)":1 + * def __reduce_cython__(self): # <<<<<<<<<<<<<< + * cdef tuple state + * cdef object _dict + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("EnumBase.__Pyx_EnumMeta.__reduce_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_state); + __Pyx_XDECREF(__pyx_v__dict); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":16 + * else: + * return __pyx_unpickle___Pyx_EnumMeta, (type(self), 0xd41d8cd, state) + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * __pyx_unpickle___Pyx_EnumMeta__set_state(self, __pyx_state) + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_8EnumBase_14__Pyx_EnumMeta_9__setstate_cython__(PyObject *__pyx_v_self, PyObject *__pyx_v___pyx_state); /*proto*/ +static PyObject *__pyx_pw_8EnumBase_14__Pyx_EnumMeta_9__setstate_cython__(PyObject *__pyx_v_self, PyObject *__pyx_v___pyx_state) { + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__setstate_cython__ (wrapper)", 0); + __pyx_r = __pyx_pf_8EnumBase_14__Pyx_EnumMeta_8__setstate_cython__(((struct __pyx_obj___Pyx_EnumMeta *)__pyx_v_self), ((PyObject *)__pyx_v___pyx_state)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_8EnumBase_14__Pyx_EnumMeta_8__setstate_cython__(struct __pyx_obj___Pyx_EnumMeta *__pyx_v_self, PyObject *__pyx_v___pyx_state) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__setstate_cython__", 0); + + /* "(tree fragment)":17 + * return __pyx_unpickle___Pyx_EnumMeta, (type(self), 0xd41d8cd, state) + * def __setstate_cython__(self, __pyx_state): + * __pyx_unpickle___Pyx_EnumMeta__set_state(self, __pyx_state) # <<<<<<<<<<<<<< + */ + if (!(likely(PyTuple_CheckExact(__pyx_v___pyx_state))||((__pyx_v___pyx_state) == Py_None)||((void)PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "tuple", Py_TYPE(__pyx_v___pyx_state)->tp_name), 0))) __PYX_ERR(1, 17, __pyx_L1_error) + __pyx_t_1 = __pyx_unpickle___Pyx_EnumMeta__set_state(__pyx_v_self, ((PyObject*)__pyx_v___pyx_state)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 17, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "(tree fragment)":16 + * else: + * return __pyx_unpickle___Pyx_EnumMeta, (type(self), 0xd41d8cd, state) + * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< + * __pyx_unpickle___Pyx_EnumMeta__set_state(self, __pyx_state) + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("EnumBase.__Pyx_EnumMeta.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "EnumBase":28 + * class __Pyx_EnumBase(int): + * __metaclass__ = __Pyx_EnumMeta + * def __new__(cls, value, name=None): # <<<<<<<<<<<<<< + * for v in cls: + * if v == value: + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_8EnumBase_14__Pyx_EnumBase_1__new__(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static PyMethodDef __pyx_mdef_8EnumBase_14__Pyx_EnumBase_1__new__ = {"__new__", (PyCFunction)(void*)(PyCFunctionWithKeywords)__pyx_pw_8EnumBase_14__Pyx_EnumBase_1__new__, METH_VARARGS|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_8EnumBase_14__Pyx_EnumBase_1__new__(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v_cls = 0; + PyObject *__pyx_v_value = 0; + PyObject *__pyx_v_name = 0; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__new__ (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_cls,&__pyx_n_s_value,&__pyx_n_s_name,0}; + PyObject* values[3] = {0,0,0}; + values[2] = ((PyObject *)((PyObject *)Py_None)); + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_cls)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_value)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("__new__", 0, 2, 3, 1); __PYX_ERR(1, 28, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (kw_args > 0) { + PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_name); + if (value) { values[2] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__new__") < 0)) __PYX_ERR(1, 28, __pyx_L3_error) + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + break; + default: goto __pyx_L5_argtuple_error; + } + } + __pyx_v_cls = values[0]; + __pyx_v_value = values[1]; + __pyx_v_name = values[2]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__new__", 0, 2, 3, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(1, 28, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("EnumBase.__Pyx_EnumBase.__new__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_8EnumBase_14__Pyx_EnumBase___new__(__pyx_self, __pyx_v_cls, __pyx_v_value, __pyx_v_name); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_8EnumBase_14__Pyx_EnumBase___new__(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_cls, PyObject *__pyx_v_value, PyObject *__pyx_v_name) { + PyObject *__pyx_v_v = NULL; + PyObject *__pyx_v_res = NULL; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + Py_ssize_t __pyx_t_2; + PyObject *(*__pyx_t_3)(PyObject *); + PyObject *__pyx_t_4 = NULL; + int __pyx_t_5; + int __pyx_t_6; + PyObject *__pyx_t_7 = NULL; + int __pyx_t_8; + PyObject *__pyx_t_9 = NULL; + int __pyx_t_10; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__new__", 0); + + /* "EnumBase":29 + * __metaclass__ = __Pyx_EnumMeta + * def __new__(cls, value, name=None): + * for v in cls: # <<<<<<<<<<<<<< + * if v == value: + * return v + */ + if (likely(PyList_CheckExact(__pyx_v_cls)) || PyTuple_CheckExact(__pyx_v_cls)) { + __pyx_t_1 = __pyx_v_cls; __Pyx_INCREF(__pyx_t_1); __pyx_t_2 = 0; + __pyx_t_3 = NULL; + } else { + __pyx_t_2 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_v_cls); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 29, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = Py_TYPE(__pyx_t_1)->tp_iternext; if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 29, __pyx_L1_error) + } + for (;;) { + if (likely(!__pyx_t_3)) { + if (likely(PyList_CheckExact(__pyx_t_1))) { + if (__pyx_t_2 >= PyList_GET_SIZE(__pyx_t_1)) break; + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_4 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely(0 < 0)) __PYX_ERR(1, 29, __pyx_L1_error) + #else + __pyx_t_4 = PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 29, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + #endif + } else { + if (__pyx_t_2 >= PyTuple_GET_SIZE(__pyx_t_1)) break; + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_4 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely(0 < 0)) __PYX_ERR(1, 29, __pyx_L1_error) + #else + __pyx_t_4 = PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 29, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + #endif + } + } else { + __pyx_t_4 = __pyx_t_3(__pyx_t_1); + if (unlikely(!__pyx_t_4)) { + PyObject* exc_type = PyErr_Occurred(); + if (exc_type) { + if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); + else __PYX_ERR(1, 29, __pyx_L1_error) + } + break; + } + __Pyx_GOTREF(__pyx_t_4); + } + __Pyx_XDECREF_SET(__pyx_v_v, __pyx_t_4); + __pyx_t_4 = 0; + + /* "EnumBase":30 + * def __new__(cls, value, name=None): + * for v in cls: + * if v == value: # <<<<<<<<<<<<<< + * return v + * if name is None: + */ + __pyx_t_4 = PyObject_RichCompare(__pyx_v_v, __pyx_v_value, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 30, __pyx_L1_error) + __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_5 < 0)) __PYX_ERR(1, 30, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (__pyx_t_5) { + + /* "EnumBase":31 + * for v in cls: + * if v == value: + * return v # <<<<<<<<<<<<<< + * if name is None: + * raise ValueError("Unknown enum value: '%s'" % value) + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_v); + __pyx_r = __pyx_v_v; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + goto __pyx_L0; + + /* "EnumBase":30 + * def __new__(cls, value, name=None): + * for v in cls: + * if v == value: # <<<<<<<<<<<<<< + * return v + * if name is None: + */ + } + + /* "EnumBase":29 + * __metaclass__ = __Pyx_EnumMeta + * def __new__(cls, value, name=None): + * for v in cls: # <<<<<<<<<<<<<< + * if v == value: + * return v + */ + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "EnumBase":32 + * if v == value: + * return v + * if name is None: # <<<<<<<<<<<<<< + * raise ValueError("Unknown enum value: '%s'" % value) + * res = int.__new__(cls, value) + */ + __pyx_t_5 = (__pyx_v_name == Py_None); + __pyx_t_6 = (__pyx_t_5 != 0); + if (unlikely(__pyx_t_6)) { + + /* "EnumBase":33 + * return v + * if name is None: + * raise ValueError("Unknown enum value: '%s'" % value) # <<<<<<<<<<<<<< + * res = int.__new__(cls, value) + * res.name = name + */ + __pyx_t_1 = __Pyx_PyString_FormatSafe(__pyx_kp_s_Unknown_enum_value_s, __pyx_v_value); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 33, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_1); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 33, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_Raise(__pyx_t_4, 0, 0, 0); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __PYX_ERR(1, 33, __pyx_L1_error) + + /* "EnumBase":32 + * if v == value: + * return v + * if name is None: # <<<<<<<<<<<<<< + * raise ValueError("Unknown enum value: '%s'" % value) + * res = int.__new__(cls, value) + */ + } + + /* "EnumBase":34 + * if name is None: + * raise ValueError("Unknown enum value: '%s'" % value) + * res = int.__new__(cls, value) # <<<<<<<<<<<<<< + * res.name = name + * setattr(cls, name, res) + */ + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)(&PyInt_Type)), __pyx_n_s_new); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 34, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_7 = NULL; + __pyx_t_8 = 0; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_1))) { + __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_1); + if (likely(__pyx_t_7)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1); + __Pyx_INCREF(__pyx_t_7); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_1, function); + __pyx_t_8 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[3] = {__pyx_t_7, __pyx_v_cls, __pyx_v_value}; + __pyx_t_4 = __Pyx_PyFunction_FastCall(__pyx_t_1, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 34, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_4); + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_1)) { + PyObject *__pyx_temp[3] = {__pyx_t_7, __pyx_v_cls, __pyx_v_value}; + __pyx_t_4 = __Pyx_PyCFunction_FastCall(__pyx_t_1, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 34, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_GOTREF(__pyx_t_4); + } else + #endif + { + __pyx_t_9 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_9)) __PYX_ERR(1, 34, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + if (__pyx_t_7) { + __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_7); __pyx_t_7 = NULL; + } + __Pyx_INCREF(__pyx_v_cls); + __Pyx_GIVEREF(__pyx_v_cls); + PyTuple_SET_ITEM(__pyx_t_9, 0+__pyx_t_8, __pyx_v_cls); + __Pyx_INCREF(__pyx_v_value); + __Pyx_GIVEREF(__pyx_v_value); + PyTuple_SET_ITEM(__pyx_t_9, 1+__pyx_t_8, __pyx_v_value); + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_9, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 34, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_res = __pyx_t_4; + __pyx_t_4 = 0; + + /* "EnumBase":35 + * raise ValueError("Unknown enum value: '%s'" % value) + * res = int.__new__(cls, value) + * res.name = name # <<<<<<<<<<<<<< + * setattr(cls, name, res) + * cls.__members__[name] = res + */ + if (__Pyx_PyObject_SetAttrStr(__pyx_v_res, __pyx_n_s_name, __pyx_v_name) < 0) __PYX_ERR(1, 35, __pyx_L1_error) + + /* "EnumBase":36 + * res = int.__new__(cls, value) + * res.name = name + * setattr(cls, name, res) # <<<<<<<<<<<<<< + * cls.__members__[name] = res + * return res + */ + __pyx_t_10 = PyObject_SetAttr(__pyx_v_cls, __pyx_v_name, __pyx_v_res); if (unlikely(__pyx_t_10 == ((int)-1))) __PYX_ERR(1, 36, __pyx_L1_error) + + /* "EnumBase":37 + * res.name = name + * setattr(cls, name, res) + * cls.__members__[name] = res # <<<<<<<<<<<<<< + * return res + * def __repr__(self): + */ + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_cls, __pyx_n_s_members); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 37, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + if (unlikely(PyObject_SetItem(__pyx_t_4, __pyx_v_name, __pyx_v_res) < 0)) __PYX_ERR(1, 37, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + + /* "EnumBase":38 + * setattr(cls, name, res) + * cls.__members__[name] = res + * return res # <<<<<<<<<<<<<< + * def __repr__(self): + * return "<%s.%s: %d>" % (self.__class__.__name__, self.name, self) + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_res); + __pyx_r = __pyx_v_res; + goto __pyx_L0; + + /* "EnumBase":28 + * class __Pyx_EnumBase(int): + * __metaclass__ = __Pyx_EnumMeta + * def __new__(cls, value, name=None): # <<<<<<<<<<<<<< + * for v in cls: + * if v == value: + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_AddTraceback("EnumBase.__Pyx_EnumBase.__new__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_v); + __Pyx_XDECREF(__pyx_v_res); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "EnumBase":39 + * cls.__members__[name] = res + * return res + * def __repr__(self): # <<<<<<<<<<<<<< + * return "<%s.%s: %d>" % (self.__class__.__name__, self.name, self) + * def __str__(self): + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_8EnumBase_14__Pyx_EnumBase_3__repr__(PyObject *__pyx_self, PyObject *__pyx_v_self); /*proto*/ +static PyMethodDef __pyx_mdef_8EnumBase_14__Pyx_EnumBase_3__repr__ = {"__repr__", (PyCFunction)__pyx_pw_8EnumBase_14__Pyx_EnumBase_3__repr__, METH_O, 0}; +static PyObject *__pyx_pw_8EnumBase_14__Pyx_EnumBase_3__repr__(PyObject *__pyx_self, PyObject *__pyx_v_self) { + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__repr__ (wrapper)", 0); + __pyx_r = __pyx_pf_8EnumBase_14__Pyx_EnumBase_2__repr__(__pyx_self, ((PyObject *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_8EnumBase_14__Pyx_EnumBase_2__repr__(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__repr__", 0); + + /* "EnumBase":40 + * return res + * def __repr__(self): + * return "<%s.%s: %d>" % (self.__class__.__name__, self.name, self) # <<<<<<<<<<<<<< + * def __str__(self): + * return "%s.%s" % (self.__class__.__name__, self.name) + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_class); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 40, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_name_2); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 40, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_name); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 40, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = PyTuple_New(3); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 40, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_GIVEREF(__pyx_t_2); + PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_2); + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_t_1); + __Pyx_INCREF(__pyx_v_self); + __Pyx_GIVEREF(__pyx_v_self); + PyTuple_SET_ITEM(__pyx_t_3, 2, __pyx_v_self); + __pyx_t_2 = 0; + __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_PyString_Format(__pyx_kp_s_s_s_d, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 40, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "EnumBase":39 + * cls.__members__[name] = res + * return res + * def __repr__(self): # <<<<<<<<<<<<<< + * return "<%s.%s: %d>" % (self.__class__.__name__, self.name, self) + * def __str__(self): + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("EnumBase.__Pyx_EnumBase.__repr__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "EnumBase":41 + * def __repr__(self): + * return "<%s.%s: %d>" % (self.__class__.__name__, self.name, self) + * def __str__(self): # <<<<<<<<<<<<<< + * return "%s.%s" % (self.__class__.__name__, self.name) + * + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_8EnumBase_14__Pyx_EnumBase_5__str__(PyObject *__pyx_self, PyObject *__pyx_v_self); /*proto*/ +static PyMethodDef __pyx_mdef_8EnumBase_14__Pyx_EnumBase_5__str__ = {"__str__", (PyCFunction)__pyx_pw_8EnumBase_14__Pyx_EnumBase_5__str__, METH_O, 0}; +static PyObject *__pyx_pw_8EnumBase_14__Pyx_EnumBase_5__str__(PyObject *__pyx_self, PyObject *__pyx_v_self) { + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__str__ (wrapper)", 0); + __pyx_r = __pyx_pf_8EnumBase_14__Pyx_EnumBase_4__str__(__pyx_self, ((PyObject *)__pyx_v_self)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_8EnumBase_14__Pyx_EnumBase_4__str__(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__str__", 0); + + /* "EnumBase":42 + * return "<%s.%s: %d>" % (self.__class__.__name__, self.name, self) + * def __str__(self): + * return "%s.%s" % (self.__class__.__name__, self.name) # <<<<<<<<<<<<<< + * + * if PY_VERSION_HEX >= 0x03040000: + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_class); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 42, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_name_2); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 42, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_name); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 42, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 42, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_GIVEREF(__pyx_t_2); + PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_2); + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_t_1); + __pyx_t_2 = 0; + __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_PyString_Format(__pyx_kp_s_s_s, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 42, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "EnumBase":41 + * def __repr__(self): + * return "<%s.%s: %d>" % (self.__class__.__name__, self.name, self) + * def __str__(self): # <<<<<<<<<<<<<< + * return "%s.%s" % (self.__class__.__name__, self.name) + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_AddTraceback("EnumBase.__Pyx_EnumBase.__str__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":1 + * def __pyx_unpickle___Pyx_EnumMeta(__pyx_type, long __pyx_checksum, __pyx_state): # <<<<<<<<<<<<<< + * cdef object __pyx_PickleError + * cdef object __pyx_result + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_8EnumBase_1__pyx_unpickle___Pyx_EnumMeta(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static PyMethodDef __pyx_mdef_8EnumBase_1__pyx_unpickle___Pyx_EnumMeta = {"__pyx_unpickle___Pyx_EnumMeta", (PyCFunction)(void*)(PyCFunctionWithKeywords)__pyx_pw_8EnumBase_1__pyx_unpickle___Pyx_EnumMeta, METH_VARARGS|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_8EnumBase_1__pyx_unpickle___Pyx_EnumMeta(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyObject *__pyx_v___pyx_type = 0; + long __pyx_v___pyx_checksum; + PyObject *__pyx_v___pyx_state = 0; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__pyx_unpickle___Pyx_EnumMeta (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_pyx_type,&__pyx_n_s_pyx_checksum,&__pyx_n_s_pyx_state,0}; + PyObject* values[3] = {0,0,0}; + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_pyx_type)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_pyx_checksum)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("__pyx_unpickle___Pyx_EnumMeta", 1, 3, 3, 1); __PYX_ERR(1, 1, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_pyx_state)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("__pyx_unpickle___Pyx_EnumMeta", 1, 3, 3, 2); __PYX_ERR(1, 1, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__pyx_unpickle___Pyx_EnumMeta") < 0)) __PYX_ERR(1, 1, __pyx_L3_error) + } + } else if (PyTuple_GET_SIZE(__pyx_args) != 3) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + } + __pyx_v___pyx_type = values[0]; + __pyx_v___pyx_checksum = __Pyx_PyInt_As_long(values[1]); if (unlikely((__pyx_v___pyx_checksum == (long)-1) && PyErr_Occurred())) __PYX_ERR(1, 1, __pyx_L3_error) + __pyx_v___pyx_state = values[2]; + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("__pyx_unpickle___Pyx_EnumMeta", 1, 3, 3, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(1, 1, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("EnumBase.__pyx_unpickle___Pyx_EnumMeta", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_8EnumBase___pyx_unpickle___Pyx_EnumMeta(__pyx_self, __pyx_v___pyx_type, __pyx_v___pyx_checksum, __pyx_v___pyx_state); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_8EnumBase___pyx_unpickle___Pyx_EnumMeta(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v___pyx_type, long __pyx_v___pyx_checksum, PyObject *__pyx_v___pyx_state) { + PyObject *__pyx_v___pyx_PickleError = 0; + PyObject *__pyx_v___pyx_result = 0; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + int __pyx_t_3; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__pyx_unpickle___Pyx_EnumMeta", 0); + + /* "(tree fragment)":4 + * cdef object __pyx_PickleError + * cdef object __pyx_result + * if __pyx_checksum not in (0xd41d8cd, 0xe3b0c44, 0xda39a3e): # <<<<<<<<<<<<<< + * from pickle import PickleError as __pyx_PickleError + * raise __pyx_PickleError("Incompatible checksums (0x%x vs (0xd41d8cd, 0xe3b0c44, 0xda39a3e) = ())" % __pyx_checksum) + */ + __pyx_t_1 = __Pyx_PyInt_From_long(__pyx_v___pyx_checksum); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = (__Pyx_PySequence_ContainsTF(__pyx_t_1, __pyx_tuple__8, Py_NE)); if (unlikely(__pyx_t_2 < 0)) __PYX_ERR(1, 4, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_3 = (__pyx_t_2 != 0); + if (__pyx_t_3) { + + /* "(tree fragment)":5 + * cdef object __pyx_result + * if __pyx_checksum not in (0xd41d8cd, 0xe3b0c44, 0xda39a3e): + * from pickle import PickleError as __pyx_PickleError # <<<<<<<<<<<<<< + * raise __pyx_PickleError("Incompatible checksums (0x%x vs (0xd41d8cd, 0xe3b0c44, 0xda39a3e) = ())" % __pyx_checksum) + * __pyx_result = __Pyx_EnumMeta.__new__(__pyx_type) + */ + __pyx_t_1 = PyList_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 5, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(__pyx_n_s_PickleError); + __Pyx_GIVEREF(__pyx_n_s_PickleError); + PyList_SET_ITEM(__pyx_t_1, 0, __pyx_n_s_PickleError); + __pyx_t_4 = __Pyx_Import(__pyx_n_s_pickle, __pyx_t_1, -1); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 5, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_ImportFrom(__pyx_t_4, __pyx_n_s_PickleError); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 5, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(__pyx_t_1); + __pyx_v___pyx_PickleError = __pyx_t_1; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + + /* "(tree fragment)":6 + * if __pyx_checksum not in (0xd41d8cd, 0xe3b0c44, 0xda39a3e): + * from pickle import PickleError as __pyx_PickleError + * raise __pyx_PickleError("Incompatible checksums (0x%x vs (0xd41d8cd, 0xe3b0c44, 0xda39a3e) = ())" % __pyx_checksum) # <<<<<<<<<<<<<< + * __pyx_result = __Pyx_EnumMeta.__new__(__pyx_type) + * if __pyx_state is not None: + */ + __pyx_t_1 = __Pyx_PyInt_From_long(__pyx_v___pyx_checksum); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 6, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_5 = __Pyx_PyString_Format(__pyx_kp_s_Incompatible_checksums_0x_x_vs_0, __pyx_t_1); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 6, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_INCREF(__pyx_v___pyx_PickleError); + __pyx_t_1 = __pyx_v___pyx_PickleError; __pyx_t_6 = NULL; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_1))) { + __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_1); + if (likely(__pyx_t_6)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1); + __Pyx_INCREF(__pyx_t_6); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_1, function); + } + } + __pyx_t_4 = (__pyx_t_6) ? __Pyx_PyObject_Call2Args(__pyx_t_1, __pyx_t_6, __pyx_t_5) : __Pyx_PyObject_CallOneArg(__pyx_t_1, __pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 6, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_Raise(__pyx_t_4, 0, 0, 0); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __PYX_ERR(1, 6, __pyx_L1_error) + + /* "(tree fragment)":4 + * cdef object __pyx_PickleError + * cdef object __pyx_result + * if __pyx_checksum not in (0xd41d8cd, 0xe3b0c44, 0xda39a3e): # <<<<<<<<<<<<<< + * from pickle import PickleError as __pyx_PickleError + * raise __pyx_PickleError("Incompatible checksums (0x%x vs (0xd41d8cd, 0xe3b0c44, 0xda39a3e) = ())" % __pyx_checksum) + */ + } + + /* "(tree fragment)":7 + * from pickle import PickleError as __pyx_PickleError + * raise __pyx_PickleError("Incompatible checksums (0x%x vs (0xd41d8cd, 0xe3b0c44, 0xda39a3e) = ())" % __pyx_checksum) + * __pyx_result = __Pyx_EnumMeta.__new__(__pyx_type) # <<<<<<<<<<<<<< + * if __pyx_state is not None: + * __pyx_unpickle___Pyx_EnumMeta__set_state(<__Pyx_EnumMeta> __pyx_result, __pyx_state) + */ + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_ptype___Pyx_EnumMeta), __pyx_n_s_new); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 7, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_5 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_1))) { + __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_1); + if (likely(__pyx_t_5)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1); + __Pyx_INCREF(__pyx_t_5); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_1, function); + } + } + __pyx_t_4 = (__pyx_t_5) ? __Pyx_PyObject_Call2Args(__pyx_t_1, __pyx_t_5, __pyx_v___pyx_type) : __Pyx_PyObject_CallOneArg(__pyx_t_1, __pyx_v___pyx_type); + __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; + if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 7, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v___pyx_result = __pyx_t_4; + __pyx_t_4 = 0; + + /* "(tree fragment)":8 + * raise __pyx_PickleError("Incompatible checksums (0x%x vs (0xd41d8cd, 0xe3b0c44, 0xda39a3e) = ())" % __pyx_checksum) + * __pyx_result = __Pyx_EnumMeta.__new__(__pyx_type) + * if __pyx_state is not None: # <<<<<<<<<<<<<< + * __pyx_unpickle___Pyx_EnumMeta__set_state(<__Pyx_EnumMeta> __pyx_result, __pyx_state) + * return __pyx_result + */ + __pyx_t_3 = (__pyx_v___pyx_state != Py_None); + __pyx_t_2 = (__pyx_t_3 != 0); + if (__pyx_t_2) { + + /* "(tree fragment)":9 + * __pyx_result = __Pyx_EnumMeta.__new__(__pyx_type) + * if __pyx_state is not None: + * __pyx_unpickle___Pyx_EnumMeta__set_state(<__Pyx_EnumMeta> __pyx_result, __pyx_state) # <<<<<<<<<<<<<< + * return __pyx_result + * cdef __pyx_unpickle___Pyx_EnumMeta__set_state(__Pyx_EnumMeta __pyx_result, tuple __pyx_state): + */ + if (!(likely(PyTuple_CheckExact(__pyx_v___pyx_state))||((__pyx_v___pyx_state) == Py_None)||((void)PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "tuple", Py_TYPE(__pyx_v___pyx_state)->tp_name), 0))) __PYX_ERR(1, 9, __pyx_L1_error) + __pyx_t_4 = __pyx_unpickle___Pyx_EnumMeta__set_state(((struct __pyx_obj___Pyx_EnumMeta *)__pyx_v___pyx_result), ((PyObject*)__pyx_v___pyx_state)); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 9, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + + /* "(tree fragment)":8 + * raise __pyx_PickleError("Incompatible checksums (0x%x vs (0xd41d8cd, 0xe3b0c44, 0xda39a3e) = ())" % __pyx_checksum) + * __pyx_result = __Pyx_EnumMeta.__new__(__pyx_type) + * if __pyx_state is not None: # <<<<<<<<<<<<<< + * __pyx_unpickle___Pyx_EnumMeta__set_state(<__Pyx_EnumMeta> __pyx_result, __pyx_state) + * return __pyx_result + */ + } + + /* "(tree fragment)":10 + * if __pyx_state is not None: + * __pyx_unpickle___Pyx_EnumMeta__set_state(<__Pyx_EnumMeta> __pyx_result, __pyx_state) + * return __pyx_result # <<<<<<<<<<<<<< + * cdef __pyx_unpickle___Pyx_EnumMeta__set_state(__Pyx_EnumMeta __pyx_result, tuple __pyx_state): + * if len(__pyx_state) > 0 and hasattr(__pyx_result, '__dict__'): + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v___pyx_result); + __pyx_r = __pyx_v___pyx_result; + goto __pyx_L0; + + /* "(tree fragment)":1 + * def __pyx_unpickle___Pyx_EnumMeta(__pyx_type, long __pyx_checksum, __pyx_state): # <<<<<<<<<<<<<< + * cdef object __pyx_PickleError + * cdef object __pyx_result + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_AddTraceback("EnumBase.__pyx_unpickle___Pyx_EnumMeta", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v___pyx_PickleError); + __Pyx_XDECREF(__pyx_v___pyx_result); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "(tree fragment)":11 + * __pyx_unpickle___Pyx_EnumMeta__set_state(<__Pyx_EnumMeta> __pyx_result, __pyx_state) + * return __pyx_result + * cdef __pyx_unpickle___Pyx_EnumMeta__set_state(__Pyx_EnumMeta __pyx_result, tuple __pyx_state): # <<<<<<<<<<<<<< + * if len(__pyx_state) > 0 and hasattr(__pyx_result, '__dict__'): + * __pyx_result.__dict__.update(__pyx_state[0]) + */ + +static PyObject *__pyx_unpickle___Pyx_EnumMeta__set_state(struct __pyx_obj___Pyx_EnumMeta *__pyx_v___pyx_result, PyObject *__pyx_v___pyx_state) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + Py_ssize_t __pyx_t_2; + int __pyx_t_3; + int __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__pyx_unpickle___Pyx_EnumMeta__set_state", 0); + + /* "(tree fragment)":12 + * return __pyx_result + * cdef __pyx_unpickle___Pyx_EnumMeta__set_state(__Pyx_EnumMeta __pyx_result, tuple __pyx_state): + * if len(__pyx_state) > 0 and hasattr(__pyx_result, '__dict__'): # <<<<<<<<<<<<<< + * __pyx_result.__dict__.update(__pyx_state[0]) + */ + if (unlikely(__pyx_v___pyx_state == Py_None)) { + PyErr_SetString(PyExc_TypeError, "object of type 'NoneType' has no len()"); + __PYX_ERR(1, 12, __pyx_L1_error) + } + __pyx_t_2 = PyTuple_GET_SIZE(__pyx_v___pyx_state); if (unlikely(__pyx_t_2 == ((Py_ssize_t)-1))) __PYX_ERR(1, 12, __pyx_L1_error) + __pyx_t_3 = ((__pyx_t_2 > 0) != 0); + if (__pyx_t_3) { + } else { + __pyx_t_1 = __pyx_t_3; + goto __pyx_L4_bool_binop_done; + } + __pyx_t_3 = __Pyx_HasAttr(((PyObject *)__pyx_v___pyx_result), __pyx_n_s_dict); if (unlikely(__pyx_t_3 == ((int)-1))) __PYX_ERR(1, 12, __pyx_L1_error) + __pyx_t_4 = (__pyx_t_3 != 0); + __pyx_t_1 = __pyx_t_4; + __pyx_L4_bool_binop_done:; + if (__pyx_t_1) { + + /* "(tree fragment)":13 + * cdef __pyx_unpickle___Pyx_EnumMeta__set_state(__Pyx_EnumMeta __pyx_result, tuple __pyx_state): + * if len(__pyx_state) > 0 and hasattr(__pyx_result, '__dict__'): + * __pyx_result.__dict__.update(__pyx_state[0]) # <<<<<<<<<<<<<< + */ + __pyx_t_6 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v___pyx_result), __pyx_n_s_dict); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 13, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_n_s_update); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 13, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + if (unlikely(__pyx_v___pyx_state == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(1, 13, __pyx_L1_error) + } + __pyx_t_6 = __Pyx_GetItemInt_Tuple(__pyx_v___pyx_state, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 13, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_8 = NULL; + if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_8 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_8)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_8); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + } + } + __pyx_t_5 = (__pyx_t_8) ? __Pyx_PyObject_Call2Args(__pyx_t_7, __pyx_t_8, __pyx_t_6) : __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_t_6); + __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 13, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + + /* "(tree fragment)":12 + * return __pyx_result + * cdef __pyx_unpickle___Pyx_EnumMeta__set_state(__Pyx_EnumMeta __pyx_result, tuple __pyx_state): + * if len(__pyx_state) > 0 and hasattr(__pyx_result, '__dict__'): # <<<<<<<<<<<<<< + * __pyx_result.__dict__.update(__pyx_state[0]) + */ + } + + /* "(tree fragment)":11 + * __pyx_unpickle___Pyx_EnumMeta__set_state(<__Pyx_EnumMeta> __pyx_result, __pyx_state) + * return __pyx_result + * cdef __pyx_unpickle___Pyx_EnumMeta__set_state(__Pyx_EnumMeta __pyx_result, tuple __pyx_state): # <<<<<<<<<<<<<< + * if len(__pyx_state) > 0 and hasattr(__pyx_result, '__dict__'): + * __pyx_result.__dict__.update(__pyx_state[0]) + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_AddTraceback("EnumBase.__pyx_unpickle___Pyx_EnumMeta__set_state", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_tp_new_6region_RegionBounds(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { + PyObject *o; + if (likely((t->tp_flags & Py_TPFLAGS_IS_ABSTRACT) == 0)) { + o = (*t->tp_alloc)(t, 0); + } else { + o = (PyObject *) PyBaseObject_Type.tp_new(t, __pyx_empty_tuple, 0); + } + if (unlikely(!o)) return 0; + if (unlikely(__pyx_pw_6region_12RegionBounds_1__cinit__(o, __pyx_empty_tuple, NULL) < 0)) goto bad; + return o; + bad: + Py_DECREF(o); o = 0; + return NULL; +} + +static void __pyx_tp_dealloc_6region_RegionBounds(PyObject *o) { + #if CYTHON_USE_TP_FINALIZE + if (unlikely(PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE) && Py_TYPE(o)->tp_finalize) && (!PyType_IS_GC(Py_TYPE(o)) || !_PyGC_FINALIZED(o))) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + #endif + { + PyObject *etype, *eval, *etb; + PyErr_Fetch(&etype, &eval, &etb); + __Pyx_SET_REFCNT(o, Py_REFCNT(o) + 1); + __pyx_pw_6region_12RegionBounds_5__dealloc__(o); + __Pyx_SET_REFCNT(o, Py_REFCNT(o) - 1); + PyErr_Restore(etype, eval, etb); + } + (*Py_TYPE(o)->tp_free)(o); +} + +static PyMethodDef __pyx_methods_6region_RegionBounds[] = { + {"get", (PyCFunction)__pyx_pw_6region_12RegionBounds_9get, METH_NOARGS, 0}, + {"set", (PyCFunction)(void*)(PyCFunctionWithKeywords)__pyx_pw_6region_12RegionBounds_11set, METH_VARARGS|METH_KEYWORDS, 0}, + {"__reduce_cython__", (PyCFunction)__pyx_pw_6region_12RegionBounds_13__reduce_cython__, METH_NOARGS, 0}, + {"__setstate_cython__", (PyCFunction)__pyx_pw_6region_12RegionBounds_15__setstate_cython__, METH_O, 0}, + {0, 0, 0, 0} +}; + +static PyTypeObject __pyx_type_6region_RegionBounds = { + PyVarObject_HEAD_INIT(0, 0) + "region.RegionBounds", /*tp_name*/ + sizeof(struct __pyx_obj_6region_RegionBounds), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_6region_RegionBounds, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + __pyx_pw_6region_12RegionBounds_7__str__, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + __pyx_methods_6region_RegionBounds, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + __pyx_pw_6region_12RegionBounds_3__init__, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_6region_RegionBounds, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + 0, /*tp_finalize*/ + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 + 0, /*tp_print*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 + 0, /*tp_pypy_flags*/ + #endif +}; + +static PyObject *__pyx_tp_new_6region_Rectangle(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { + PyObject *o; + if (likely((t->tp_flags & Py_TPFLAGS_IS_ABSTRACT) == 0)) { + o = (*t->tp_alloc)(t, 0); + } else { + o = (PyObject *) PyBaseObject_Type.tp_new(t, __pyx_empty_tuple, 0); + } + if (unlikely(!o)) return 0; + if (unlikely(__pyx_pw_6region_9Rectangle_1__cinit__(o, __pyx_empty_tuple, NULL) < 0)) goto bad; + return o; + bad: + Py_DECREF(o); o = 0; + return NULL; +} + +static void __pyx_tp_dealloc_6region_Rectangle(PyObject *o) { + #if CYTHON_USE_TP_FINALIZE + if (unlikely(PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE) && Py_TYPE(o)->tp_finalize) && (!PyType_IS_GC(Py_TYPE(o)) || !_PyGC_FINALIZED(o))) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + #endif + { + PyObject *etype, *eval, *etb; + PyErr_Fetch(&etype, &eval, &etb); + __Pyx_SET_REFCNT(o, Py_REFCNT(o) + 1); + __pyx_pw_6region_9Rectangle_5__dealloc__(o); + __Pyx_SET_REFCNT(o, Py_REFCNT(o) - 1); + PyErr_Restore(etype, eval, etb); + } + (*Py_TYPE(o)->tp_free)(o); +} + +static PyMethodDef __pyx_methods_6region_Rectangle[] = { + {"set", (PyCFunction)(void*)(PyCFunctionWithKeywords)__pyx_pw_6region_9Rectangle_9set, METH_VARARGS|METH_KEYWORDS, 0}, + {"get", (PyCFunction)__pyx_pw_6region_9Rectangle_11get, METH_NOARGS, __pyx_doc_6region_9Rectangle_10get}, + {"__reduce_cython__", (PyCFunction)__pyx_pw_6region_9Rectangle_13__reduce_cython__, METH_NOARGS, 0}, + {"__setstate_cython__", (PyCFunction)__pyx_pw_6region_9Rectangle_15__setstate_cython__, METH_O, 0}, + {0, 0, 0, 0} +}; + +static PyTypeObject __pyx_type_6region_Rectangle = { + PyVarObject_HEAD_INIT(0, 0) + "region.Rectangle", /*tp_name*/ + sizeof(struct __pyx_obj_6region_Rectangle), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_6region_Rectangle, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + __pyx_pw_6region_9Rectangle_7__str__, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + __pyx_methods_6region_Rectangle, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + __pyx_pw_6region_9Rectangle_3__init__, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_6region_Rectangle, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + 0, /*tp_finalize*/ + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 + 0, /*tp_print*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 + 0, /*tp_pypy_flags*/ + #endif +}; + +static PyObject *__pyx_tp_new_6region_Polygon(PyTypeObject *t, PyObject *a, PyObject *k) { + PyObject *o; + if (likely((t->tp_flags & Py_TPFLAGS_IS_ABSTRACT) == 0)) { + o = (*t->tp_alloc)(t, 0); + } else { + o = (PyObject *) PyBaseObject_Type.tp_new(t, __pyx_empty_tuple, 0); + } + if (unlikely(!o)) return 0; + if (unlikely(__pyx_pw_6region_7Polygon_1__cinit__(o, a, k) < 0)) goto bad; + return o; + bad: + Py_DECREF(o); o = 0; + return NULL; +} + +static void __pyx_tp_dealloc_6region_Polygon(PyObject *o) { + #if CYTHON_USE_TP_FINALIZE + if (unlikely(PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE) && Py_TYPE(o)->tp_finalize) && (!PyType_IS_GC(Py_TYPE(o)) || !_PyGC_FINALIZED(o))) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + #endif + { + PyObject *etype, *eval, *etb; + PyErr_Fetch(&etype, &eval, &etb); + __Pyx_SET_REFCNT(o, Py_REFCNT(o) + 1); + __pyx_pw_6region_7Polygon_3__dealloc__(o); + __Pyx_SET_REFCNT(o, Py_REFCNT(o) - 1); + PyErr_Restore(etype, eval, etb); + } + (*Py_TYPE(o)->tp_free)(o); +} + +static PyMethodDef __pyx_methods_6region_Polygon[] = { + {"__reduce_cython__", (PyCFunction)__pyx_pw_6region_7Polygon_7__reduce_cython__, METH_NOARGS, 0}, + {"__setstate_cython__", (PyCFunction)__pyx_pw_6region_7Polygon_9__setstate_cython__, METH_O, 0}, + {0, 0, 0, 0} +}; + +static PyTypeObject __pyx_type_6region_Polygon = { + PyVarObject_HEAD_INIT(0, 0) + "region.Polygon", /*tp_name*/ + sizeof(struct __pyx_obj_6region_Polygon), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc_6region_Polygon, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + __pyx_pw_6region_7Polygon_5__str__, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + __pyx_methods_6region_Polygon, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + 0, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new_6region_Polygon, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + 0, /*tp_finalize*/ + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 + 0, /*tp_print*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 + 0, /*tp_pypy_flags*/ + #endif +}; + +static PyObject *__pyx_tp_new___Pyx_EnumMeta(PyTypeObject *t, PyObject *a, PyObject *k) { + PyObject *o = (&PyType_Type)->tp_new(t, a, k); + if (unlikely(!o)) return 0; + return o; +} + +static void __pyx_tp_dealloc___Pyx_EnumMeta(PyObject *o) { + #if CYTHON_USE_TP_FINALIZE + if (unlikely(PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE) && Py_TYPE(o)->tp_finalize) && !_PyGC_FINALIZED(o)) { + if (PyObject_CallFinalizerFromDealloc(o)) return; + } + #endif + PyObject_GC_UnTrack(o); + PyObject_GC_Track(o); + (&PyType_Type)->tp_dealloc(o); +} + +static int __pyx_tp_traverse___Pyx_EnumMeta(PyObject *o, visitproc v, void *a) { + int e; + if (!(&PyType_Type)->tp_traverse); else { e = (&PyType_Type)->tp_traverse(o,v,a); if (e) return e; } + return 0; +} + +static int __pyx_tp_clear___Pyx_EnumMeta(PyObject *o) { + if (!(&PyType_Type)->tp_clear); else (&PyType_Type)->tp_clear(o); + return 0; +} +static PyObject *__pyx_sq_item___Pyx_EnumMeta(PyObject *o, Py_ssize_t i) { + PyObject *r; + PyObject *x = PyInt_FromSsize_t(i); if(!x) return 0; + r = Py_TYPE(o)->tp_as_mapping->mp_subscript(o, x); + Py_DECREF(x); + return r; +} + +static PyMethodDef __pyx_methods___Pyx_EnumMeta[] = { + {"__reduce_cython__", (PyCFunction)__pyx_pw_8EnumBase_14__Pyx_EnumMeta_7__reduce_cython__, METH_NOARGS, 0}, + {"__setstate_cython__", (PyCFunction)__pyx_pw_8EnumBase_14__Pyx_EnumMeta_9__setstate_cython__, METH_O, 0}, + {0, 0, 0, 0} +}; + +static PySequenceMethods __pyx_tp_as_sequence___Pyx_EnumMeta = { + 0, /*sq_length*/ + 0, /*sq_concat*/ + 0, /*sq_repeat*/ + __pyx_sq_item___Pyx_EnumMeta, /*sq_item*/ + 0, /*sq_slice*/ + 0, /*sq_ass_item*/ + 0, /*sq_ass_slice*/ + 0, /*sq_contains*/ + 0, /*sq_inplace_concat*/ + 0, /*sq_inplace_repeat*/ +}; + +static PyMappingMethods __pyx_tp_as_mapping___Pyx_EnumMeta = { + 0, /*mp_length*/ + __pyx_pw_8EnumBase_14__Pyx_EnumMeta_5__getitem__, /*mp_subscript*/ + 0, /*mp_ass_subscript*/ +}; + +static PyTypeObject __Pyx_EnumMeta = { + PyVarObject_HEAD_INIT(0, 0) + "region.__Pyx_EnumMeta", /*tp_name*/ + sizeof(struct __pyx_obj___Pyx_EnumMeta), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + __pyx_tp_dealloc___Pyx_EnumMeta, /*tp_dealloc*/ + #if PY_VERSION_HEX < 0x030800b4 + 0, /*tp_print*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 + 0, /*tp_vectorcall_offset*/ + #endif + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + #if PY_MAJOR_VERSION < 3 + 0, /*tp_compare*/ + #endif + #if PY_MAJOR_VERSION >= 3 + 0, /*tp_as_async*/ + #endif + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + &__pyx_tp_as_sequence___Pyx_EnumMeta, /*tp_as_sequence*/ + &__pyx_tp_as_mapping___Pyx_EnumMeta, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, /*tp_flags*/ + 0, /*tp_doc*/ + __pyx_tp_traverse___Pyx_EnumMeta, /*tp_traverse*/ + __pyx_tp_clear___Pyx_EnumMeta, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + __pyx_pw_8EnumBase_14__Pyx_EnumMeta_3__iter__, /*tp_iter*/ + 0, /*tp_iternext*/ + __pyx_methods___Pyx_EnumMeta, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + __pyx_pw_8EnumBase_14__Pyx_EnumMeta_1__init__, /*tp_init*/ + 0, /*tp_alloc*/ + __pyx_tp_new___Pyx_EnumMeta, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + #if PY_VERSION_HEX >= 0x030400a1 + 0, /*tp_finalize*/ + #endif + #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, /*tp_vectorcall*/ + #endif + #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 + 0, /*tp_print*/ + #endif + #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 + 0, /*tp_pypy_flags*/ + #endif +}; + +static PyMethodDef __pyx_methods[] = { + {0, 0, 0, 0} +}; + +#if PY_MAJOR_VERSION >= 3 +#if CYTHON_PEP489_MULTI_PHASE_INIT +static PyObject* __pyx_pymod_create(PyObject *spec, PyModuleDef *def); /*proto*/ +static int __pyx_pymod_exec_region(PyObject* module); /*proto*/ +static PyModuleDef_Slot __pyx_moduledef_slots[] = { + {Py_mod_create, (void*)__pyx_pymod_create}, + {Py_mod_exec, (void*)__pyx_pymod_exec_region}, + {0, NULL} +}; +#endif + +static struct PyModuleDef __pyx_moduledef = { + PyModuleDef_HEAD_INIT, + "region", + 0, /* m_doc */ + #if CYTHON_PEP489_MULTI_PHASE_INIT + 0, /* m_size */ + #else + -1, /* m_size */ + #endif + __pyx_methods /* m_methods */, + #if CYTHON_PEP489_MULTI_PHASE_INIT + __pyx_moduledef_slots, /* m_slots */ + #else + NULL, /* m_reload */ + #endif + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL /* m_free */ +}; +#endif +#ifndef CYTHON_SMALL_CODE +#if defined(__clang__) + #define CYTHON_SMALL_CODE +#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) + #define CYTHON_SMALL_CODE __attribute__((cold)) +#else + #define CYTHON_SMALL_CODE +#endif +#endif + +static __Pyx_StringTabEntry __pyx_string_tab[] = { + {&__pyx_kp_s_3f_3f, __pyx_k_3f_3f, sizeof(__pyx_k_3f_3f), 0, 0, 1, 0}, + {&__pyx_kp_s_3f_3f_2, __pyx_k_3f_3f_2, sizeof(__pyx_k_3f_3f_2), 0, 0, 1, 0}, + {&__pyx_n_s_EMTPY, __pyx_k_EMTPY, sizeof(__pyx_k_EMTPY), 0, 0, 1, 1}, + {&__pyx_n_s_EnumBase, __pyx_k_EnumBase, sizeof(__pyx_k_EnumBase), 0, 0, 1, 1}, + {&__pyx_n_s_EnumType, __pyx_k_EnumType, sizeof(__pyx_k_EnumType), 0, 0, 1, 1}, + {&__pyx_kp_s_Incompatible_checksums_0x_x_vs_0, __pyx_k_Incompatible_checksums_0x_x_vs_0, sizeof(__pyx_k_Incompatible_checksums_0x_x_vs_0), 0, 0, 1, 0}, + {&__pyx_n_s_IntEnum, __pyx_k_IntEnum, sizeof(__pyx_k_IntEnum), 0, 0, 1, 1}, + {&__pyx_n_s_MASK, __pyx_k_MASK, sizeof(__pyx_k_MASK), 0, 0, 1, 1}, + {&__pyx_n_s_MemoryError, __pyx_k_MemoryError, sizeof(__pyx_k_MemoryError), 0, 0, 1, 1}, + {&__pyx_n_s_OrderedDict, __pyx_k_OrderedDict, sizeof(__pyx_k_OrderedDict), 0, 0, 1, 1}, + {&__pyx_n_s_POLYGON, __pyx_k_POLYGON, sizeof(__pyx_k_POLYGON), 0, 0, 1, 1}, + {&__pyx_n_s_PickleError, __pyx_k_PickleError, sizeof(__pyx_k_PickleError), 0, 0, 1, 1}, + {&__pyx_n_s_Polygon, __pyx_k_Polygon, sizeof(__pyx_k_Polygon), 0, 0, 1, 1}, + {&__pyx_n_s_Pyx_EnumBase, __pyx_k_Pyx_EnumBase, sizeof(__pyx_k_Pyx_EnumBase), 0, 0, 1, 1}, + {&__pyx_n_s_Pyx_EnumBase___new, __pyx_k_Pyx_EnumBase___new, sizeof(__pyx_k_Pyx_EnumBase___new), 0, 0, 1, 1}, + {&__pyx_n_s_Pyx_EnumBase___repr, __pyx_k_Pyx_EnumBase___repr, sizeof(__pyx_k_Pyx_EnumBase___repr), 0, 0, 1, 1}, + {&__pyx_n_s_Pyx_EnumBase___str, __pyx_k_Pyx_EnumBase___str, sizeof(__pyx_k_Pyx_EnumBase___str), 0, 0, 1, 1}, + {&__pyx_n_s_RECTANGEL, __pyx_k_RECTANGEL, sizeof(__pyx_k_RECTANGEL), 0, 0, 1, 1}, + {&__pyx_n_s_Rectangle, __pyx_k_Rectangle, sizeof(__pyx_k_Rectangle), 0, 0, 1, 1}, + {&__pyx_n_s_RegionBounds, __pyx_k_RegionBounds, sizeof(__pyx_k_RegionBounds), 0, 0, 1, 1}, + {&__pyx_n_s_RegionType, __pyx_k_RegionType, sizeof(__pyx_k_RegionType), 0, 0, 1, 1}, + {&__pyx_n_s_SPECIAL, __pyx_k_SPECIAL, sizeof(__pyx_k_SPECIAL), 0, 0, 1, 1}, + {&__pyx_n_s_TypeError, __pyx_k_TypeError, sizeof(__pyx_k_TypeError), 0, 0, 1, 1}, + {&__pyx_kp_s_Unknown_enum_value_s, __pyx_k_Unknown_enum_value_s, sizeof(__pyx_k_Unknown_enum_value_s), 0, 0, 1, 0}, + {&__pyx_n_s_ValueError, __pyx_k_ValueError, sizeof(__pyx_k_ValueError), 0, 0, 1, 1}, + {&__pyx_kp_s__5, __pyx_k__5, sizeof(__pyx_k__5), 0, 0, 1, 0}, + {&__pyx_n_s_bottom, __pyx_k_bottom, sizeof(__pyx_k_bottom), 0, 0, 1, 1}, + {&__pyx_n_s_bounds, __pyx_k_bounds, sizeof(__pyx_k_bounds), 0, 0, 1, 1}, + {&__pyx_n_s_c_polygon1, __pyx_k_c_polygon1, sizeof(__pyx_k_c_polygon1), 0, 0, 1, 1}, + {&__pyx_n_s_c_polygon2, __pyx_k_c_polygon2, sizeof(__pyx_k_c_polygon2), 0, 0, 1, 1}, + {&__pyx_n_s_class, __pyx_k_class, sizeof(__pyx_k_class), 0, 0, 1, 1}, + {&__pyx_n_s_cline_in_traceback, __pyx_k_cline_in_traceback, sizeof(__pyx_k_cline_in_traceback), 0, 0, 1, 1}, + {&__pyx_n_s_cls, __pyx_k_cls, sizeof(__pyx_k_cls), 0, 0, 1, 1}, + {&__pyx_n_s_collections, __pyx_k_collections, sizeof(__pyx_k_collections), 0, 0, 1, 1}, + {&__pyx_n_s_ctemplate, __pyx_k_ctemplate, sizeof(__pyx_k_ctemplate), 0, 0, 1, 1}, + {&__pyx_n_s_dct, __pyx_k_dct, sizeof(__pyx_k_dct), 0, 0, 1, 1}, + {&__pyx_n_s_dict, __pyx_k_dict, sizeof(__pyx_k_dict), 0, 0, 1, 1}, + {&__pyx_n_s_doc, __pyx_k_doc, sizeof(__pyx_k_doc), 0, 0, 1, 1}, + {&__pyx_n_s_encode, __pyx_k_encode, sizeof(__pyx_k_encode), 0, 0, 1, 1}, + {&__pyx_n_s_enum, __pyx_k_enum, sizeof(__pyx_k_enum), 0, 0, 1, 1}, + {&__pyx_n_s_format, __pyx_k_format, sizeof(__pyx_k_format), 0, 0, 1, 1}, + {&__pyx_n_s_getstate, __pyx_k_getstate, sizeof(__pyx_k_getstate), 0, 0, 1, 1}, + {&__pyx_n_s_height, __pyx_k_height, sizeof(__pyx_k_height), 0, 0, 1, 1}, + {&__pyx_n_s_i, __pyx_k_i, sizeof(__pyx_k_i), 0, 0, 1, 1}, + {&__pyx_n_s_import, __pyx_k_import, sizeof(__pyx_k_import), 0, 0, 1, 1}, + {&__pyx_n_s_inf, __pyx_k_inf, sizeof(__pyx_k_inf), 0, 0, 1, 1}, + {&__pyx_n_s_init, __pyx_k_init, sizeof(__pyx_k_init), 0, 0, 1, 1}, + {&__pyx_n_s_left, __pyx_k_left, sizeof(__pyx_k_left), 0, 0, 1, 1}, + {&__pyx_n_s_main, __pyx_k_main, sizeof(__pyx_k_main), 0, 0, 1, 1}, + {&__pyx_n_s_members, __pyx_k_members, sizeof(__pyx_k_members), 0, 0, 1, 1}, + {&__pyx_n_s_metaclass, __pyx_k_metaclass, sizeof(__pyx_k_metaclass), 0, 0, 1, 1}, + {&__pyx_n_s_module, __pyx_k_module, sizeof(__pyx_k_module), 0, 0, 1, 1}, + {&__pyx_n_s_name, __pyx_k_name, sizeof(__pyx_k_name), 0, 0, 1, 1}, + {&__pyx_n_s_name_2, __pyx_k_name_2, sizeof(__pyx_k_name_2), 0, 0, 1, 1}, + {&__pyx_n_s_new, __pyx_k_new, sizeof(__pyx_k_new), 0, 0, 1, 1}, + {&__pyx_n_s_no_bounds, __pyx_k_no_bounds, sizeof(__pyx_k_no_bounds), 0, 0, 1, 1}, + {&__pyx_kp_s_no_default___reduce___due_to_non, __pyx_k_no_default___reduce___due_to_non, sizeof(__pyx_k_no_default___reduce___due_to_non), 0, 0, 1, 0}, + {&__pyx_n_s_num, __pyx_k_num, sizeof(__pyx_k_num), 0, 0, 1, 1}, + {&__pyx_n_s_only1, __pyx_k_only1, sizeof(__pyx_k_only1), 0, 0, 1, 1}, + {&__pyx_n_s_only2, __pyx_k_only2, sizeof(__pyx_k_only2), 0, 0, 1, 1}, + {&__pyx_n_s_output, __pyx_k_output, sizeof(__pyx_k_output), 0, 0, 1, 1}, + {&__pyx_n_s_overlap, __pyx_k_overlap, sizeof(__pyx_k_overlap), 0, 0, 1, 1}, + {&__pyx_n_s_overlaps, __pyx_k_overlaps, sizeof(__pyx_k_overlaps), 0, 0, 1, 1}, + {&__pyx_n_s_parents, __pyx_k_parents, sizeof(__pyx_k_parents), 0, 0, 1, 1}, + {&__pyx_n_s_pickle, __pyx_k_pickle, sizeof(__pyx_k_pickle), 0, 0, 1, 1}, + {&__pyx_n_s_points, __pyx_k_points, sizeof(__pyx_k_points), 0, 0, 1, 1}, + {&__pyx_n_s_polygon1, __pyx_k_polygon1, sizeof(__pyx_k_polygon1), 0, 0, 1, 1}, + {&__pyx_n_s_polygon1_2, __pyx_k_polygon1_2, sizeof(__pyx_k_polygon1_2), 0, 0, 1, 1}, + {&__pyx_n_s_polygon2, __pyx_k_polygon2, sizeof(__pyx_k_polygon2), 0, 0, 1, 1}, + {&__pyx_n_s_polygon2_2, __pyx_k_polygon2_2, sizeof(__pyx_k_polygon2_2), 0, 0, 1, 1}, + {&__pyx_n_s_polygons1, __pyx_k_polygons1, sizeof(__pyx_k_polygons1), 0, 0, 1, 1}, + {&__pyx_n_s_polygons2, __pyx_k_polygons2, sizeof(__pyx_k_polygons2), 0, 0, 1, 1}, + {&__pyx_n_s_prepare, __pyx_k_prepare, sizeof(__pyx_k_prepare), 0, 0, 1, 1}, + {&__pyx_n_s_ptemplate, __pyx_k_ptemplate, sizeof(__pyx_k_ptemplate), 0, 0, 1, 1}, + {&__pyx_n_s_pyx_PickleError, __pyx_k_pyx_PickleError, sizeof(__pyx_k_pyx_PickleError), 0, 0, 1, 1}, + {&__pyx_n_s_pyx_checksum, __pyx_k_pyx_checksum, sizeof(__pyx_k_pyx_checksum), 0, 0, 1, 1}, + {&__pyx_n_s_pyx_result, __pyx_k_pyx_result, sizeof(__pyx_k_pyx_result), 0, 0, 1, 1}, + {&__pyx_n_s_pyx_state, __pyx_k_pyx_state, sizeof(__pyx_k_pyx_state), 0, 0, 1, 1}, + {&__pyx_n_s_pyx_type, __pyx_k_pyx_type, sizeof(__pyx_k_pyx_type), 0, 0, 1, 1}, + {&__pyx_n_s_pyx_unpickle___Pyx_EnumMeta, __pyx_k_pyx_unpickle___Pyx_EnumMeta, sizeof(__pyx_k_pyx_unpickle___Pyx_EnumMeta), 0, 0, 1, 1}, + {&__pyx_n_s_qualname, __pyx_k_qualname, sizeof(__pyx_k_qualname), 0, 0, 1, 1}, + {&__pyx_n_s_range, __pyx_k_range, sizeof(__pyx_k_range), 0, 0, 1, 1}, + {&__pyx_n_s_reduce, __pyx_k_reduce, sizeof(__pyx_k_reduce), 0, 0, 1, 1}, + {&__pyx_n_s_reduce_cython, __pyx_k_reduce_cython, sizeof(__pyx_k_reduce_cython), 0, 0, 1, 1}, + {&__pyx_n_s_reduce_ex, __pyx_k_reduce_ex, sizeof(__pyx_k_reduce_ex), 0, 0, 1, 1}, + {&__pyx_n_s_region, __pyx_k_region, sizeof(__pyx_k_region), 0, 0, 1, 1}, + {&__pyx_kp_s_region_pyx, __pyx_k_region_pyx, sizeof(__pyx_k_region_pyx), 0, 0, 1, 0}, + {&__pyx_n_s_repr, __pyx_k_repr, sizeof(__pyx_k_repr), 0, 0, 1, 1}, + {&__pyx_n_s_res, __pyx_k_res, sizeof(__pyx_k_res), 0, 0, 1, 1}, + {&__pyx_n_s_ret, __pyx_k_ret, sizeof(__pyx_k_ret), 0, 0, 1, 1}, + {&__pyx_n_s_right, __pyx_k_right, sizeof(__pyx_k_right), 0, 0, 1, 1}, + {&__pyx_kp_s_s_s, __pyx_k_s_s, sizeof(__pyx_k_s_s), 0, 0, 1, 0}, + {&__pyx_kp_s_s_s_d, __pyx_k_s_s_d, sizeof(__pyx_k_s_s_d), 0, 0, 1, 0}, + {&__pyx_n_s_self, __pyx_k_self, sizeof(__pyx_k_self), 0, 0, 1, 1}, + {&__pyx_n_s_set, __pyx_k_set, sizeof(__pyx_k_set), 0, 0, 1, 1}, + {&__pyx_n_s_setstate, __pyx_k_setstate, sizeof(__pyx_k_setstate), 0, 0, 1, 1}, + {&__pyx_n_s_setstate_cython, __pyx_k_setstate_cython, sizeof(__pyx_k_setstate_cython), 0, 0, 1, 1}, + {&__pyx_n_s_str, __pyx_k_str, sizeof(__pyx_k_str), 0, 0, 1, 1}, + {&__pyx_kp_s_stringsource, __pyx_k_stringsource, sizeof(__pyx_k_stringsource), 0, 0, 1, 0}, + {&__pyx_n_s_template, __pyx_k_template, sizeof(__pyx_k_template), 0, 0, 1, 1}, + {&__pyx_n_s_test, __pyx_k_test, sizeof(__pyx_k_test), 0, 0, 1, 1}, + {&__pyx_n_s_top, __pyx_k_top, sizeof(__pyx_k_top), 0, 0, 1, 1}, + {&__pyx_kp_s_top_3f_bottom_3f_left_3f_reight, __pyx_k_top_3f_bottom_3f_left_3f_reight, sizeof(__pyx_k_top_3f_bottom_3f_left_3f_reight), 0, 0, 1, 0}, + {&__pyx_n_s_update, __pyx_k_update, sizeof(__pyx_k_update), 0, 0, 1, 1}, + {&__pyx_n_s_v, __pyx_k_v, sizeof(__pyx_k_v), 0, 0, 1, 1}, + {&__pyx_n_s_value, __pyx_k_value, sizeof(__pyx_k_value), 0, 0, 1, 1}, + {&__pyx_n_s_values, __pyx_k_values, sizeof(__pyx_k_values), 0, 0, 1, 1}, + {&__pyx_n_s_vot_float2str, __pyx_k_vot_float2str, sizeof(__pyx_k_vot_float2str), 0, 0, 1, 1}, + {&__pyx_n_s_vot_overlap, __pyx_k_vot_overlap, sizeof(__pyx_k_vot_overlap), 0, 0, 1, 1}, + {&__pyx_n_s_vot_overlap_traj, __pyx_k_vot_overlap_traj, sizeof(__pyx_k_vot_overlap_traj), 0, 0, 1, 1}, + {&__pyx_n_s_width, __pyx_k_width, sizeof(__pyx_k_width), 0, 0, 1, 1}, + {&__pyx_n_s_x, __pyx_k_x, sizeof(__pyx_k_x), 0, 0, 1, 1}, + {&__pyx_kp_s_x_3f_y_3f_width_3f_height_3f, __pyx_k_x_3f_y_3f_width_3f_height_3f, sizeof(__pyx_k_x_3f_y_3f_width_3f_height_3f), 0, 0, 1, 0}, + {&__pyx_n_s_y, __pyx_k_y, sizeof(__pyx_k_y), 0, 0, 1, 1}, + {0, 0, 0, 0, 0, 0, 0} +}; +static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(void) { + __pyx_builtin_MemoryError = __Pyx_GetBuiltinName(__pyx_n_s_MemoryError); if (!__pyx_builtin_MemoryError) __PYX_ERR(0, 25, __pyx_L1_error) + __pyx_builtin_TypeError = __Pyx_GetBuiltinName(__pyx_n_s_TypeError); if (!__pyx_builtin_TypeError) __PYX_ERR(1, 2, __pyx_L1_error) + __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) __PYX_ERR(0, 121, __pyx_L1_error) + __pyx_builtin_ValueError = __Pyx_GetBuiltinName(__pyx_n_s_ValueError); if (!__pyx_builtin_ValueError) __PYX_ERR(1, 33, __pyx_L1_error) + return 0; + __pyx_L1_error:; + return -1; +} + +static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_InitCachedConstants", 0); + + /* "(tree fragment)":2 + * def __reduce_cython__(self): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") # <<<<<<<<<<<<<< + * def __setstate_cython__(self, __pyx_state): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + */ + __pyx_tuple_ = PyTuple_Pack(1, __pyx_kp_s_no_default___reduce___due_to_non); if (unlikely(!__pyx_tuple_)) __PYX_ERR(1, 2, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple_); + __Pyx_GIVEREF(__pyx_tuple_); + + /* "(tree fragment)":4 + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + * def __setstate_cython__(self, __pyx_state): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") # <<<<<<<<<<<<<< + */ + __pyx_tuple__2 = PyTuple_Pack(1, __pyx_kp_s_no_default___reduce___due_to_non); if (unlikely(!__pyx_tuple__2)) __PYX_ERR(1, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__2); + __Pyx_GIVEREF(__pyx_tuple__2); + + /* "(tree fragment)":2 + * def __reduce_cython__(self): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") # <<<<<<<<<<<<<< + * def __setstate_cython__(self, __pyx_state): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + */ + __pyx_tuple__3 = PyTuple_Pack(1, __pyx_kp_s_no_default___reduce___due_to_non); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(1, 2, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__3); + __Pyx_GIVEREF(__pyx_tuple__3); + + /* "(tree fragment)":4 + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + * def __setstate_cython__(self, __pyx_state): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") # <<<<<<<<<<<<<< + */ + __pyx_tuple__4 = PyTuple_Pack(1, __pyx_kp_s_no_default___reduce___due_to_non); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(1, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__4); + __Pyx_GIVEREF(__pyx_tuple__4); + + /* "(tree fragment)":2 + * def __reduce_cython__(self): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") # <<<<<<<<<<<<<< + * def __setstate_cython__(self, __pyx_state): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + */ + __pyx_tuple__6 = PyTuple_Pack(1, __pyx_kp_s_no_default___reduce___due_to_non); if (unlikely(!__pyx_tuple__6)) __PYX_ERR(1, 2, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__6); + __Pyx_GIVEREF(__pyx_tuple__6); + + /* "(tree fragment)":4 + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") + * def __setstate_cython__(self, __pyx_state): + * raise TypeError("no default __reduce__ due to non-trivial __cinit__") # <<<<<<<<<<<<<< + */ + __pyx_tuple__7 = PyTuple_Pack(1, __pyx_kp_s_no_default___reduce___due_to_non); if (unlikely(!__pyx_tuple__7)) __PYX_ERR(1, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__7); + __Pyx_GIVEREF(__pyx_tuple__7); + __pyx_tuple__8 = PyTuple_Pack(3, __pyx_int_222419149, __pyx_int_238750788, __pyx_int_228825662); if (unlikely(!__pyx_tuple__8)) __PYX_ERR(1, 4, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__8); + __Pyx_GIVEREF(__pyx_tuple__8); + + /* "region.pyx":161 + * # return c_vot_overlap(p1, p2) + * + * def vot_overlap(polygon1, polygon2, bounds=None): # <<<<<<<<<<<<<< + * """ computing overlap between two polygon + * Args: + */ + __pyx_tuple__9 = PyTuple_Pack(10, __pyx_n_s_polygon1, __pyx_n_s_polygon2, __pyx_n_s_bounds, __pyx_n_s_polygon1_2, __pyx_n_s_polygon2_2, __pyx_n_s_only1, __pyx_n_s_only2, __pyx_n_s_c_polygon1, __pyx_n_s_c_polygon2, __pyx_n_s_no_bounds); if (unlikely(!__pyx_tuple__9)) __PYX_ERR(0, 161, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__9); + __Pyx_GIVEREF(__pyx_tuple__9); + __pyx_codeobj__10 = (PyObject*)__Pyx_PyCode_New(3, 0, 10, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__9, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_region_pyx, __pyx_n_s_vot_overlap, 161, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__10)) __PYX_ERR(0, 161, __pyx_L1_error) + + /* "region.pyx":200 + * no_bounds) + * + * def vot_overlap_traj(polygons1, polygons2, bounds): # <<<<<<<<<<<<<< + * """ computing overlap between two trajectory + * Args: + */ + __pyx_tuple__11 = PyTuple_Pack(14, __pyx_n_s_polygons1, __pyx_n_s_polygons2, __pyx_n_s_bounds, __pyx_n_s_overlaps, __pyx_n_s_num, __pyx_n_s_only1, __pyx_n_s_only2, __pyx_n_s_no_bounds, __pyx_n_s_c_polygon1, __pyx_n_s_c_polygon2, __pyx_n_s_i, __pyx_n_s_polygon1_2, __pyx_n_s_polygon2_2, __pyx_n_s_overlap); if (unlikely(!__pyx_tuple__11)) __PYX_ERR(0, 200, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__11); + __Pyx_GIVEREF(__pyx_tuple__11); + __pyx_codeobj__12 = (PyObject*)__Pyx_PyCode_New(3, 0, 14, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__11, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_region_pyx, __pyx_n_s_vot_overlap_traj, 200, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__12)) __PYX_ERR(0, 200, __pyx_L1_error) + + /* "region.pyx":231 + * + * + * def vot_float2str(template, float value): # <<<<<<<<<<<<<< + * cdef bytes ptemplate = template.encode() + * cdef const char* ctemplate = ptemplate + */ + __pyx_tuple__13 = PyTuple_Pack(6, __pyx_n_s_template, __pyx_n_s_value, __pyx_n_s_ptemplate, __pyx_n_s_ctemplate, __pyx_n_s_output, __pyx_n_s_ret); if (unlikely(!__pyx_tuple__13)) __PYX_ERR(0, 231, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__13); + __Pyx_GIVEREF(__pyx_tuple__13); + __pyx_codeobj__14 = (PyObject*)__Pyx_PyCode_New(2, 0, 6, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__13, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_region_pyx, __pyx_n_s_vot_float2str, 231, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__14)) __PYX_ERR(0, 231, __pyx_L1_error) + + /* "EnumBase":28 + * class __Pyx_EnumBase(int): + * __metaclass__ = __Pyx_EnumMeta + * def __new__(cls, value, name=None): # <<<<<<<<<<<<<< + * for v in cls: + * if v == value: + */ + __pyx_tuple__15 = PyTuple_Pack(5, __pyx_n_s_cls, __pyx_n_s_value, __pyx_n_s_name, __pyx_n_s_v, __pyx_n_s_res); if (unlikely(!__pyx_tuple__15)) __PYX_ERR(1, 28, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__15); + __Pyx_GIVEREF(__pyx_tuple__15); + __pyx_codeobj__16 = (PyObject*)__Pyx_PyCode_New(3, 0, 5, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__15, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_stringsource, __pyx_n_s_new, 28, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__16)) __PYX_ERR(1, 28, __pyx_L1_error) + __pyx_tuple__17 = PyTuple_Pack(1, ((PyObject *)Py_None)); if (unlikely(!__pyx_tuple__17)) __PYX_ERR(1, 28, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__17); + __Pyx_GIVEREF(__pyx_tuple__17); + + /* "EnumBase":39 + * cls.__members__[name] = res + * return res + * def __repr__(self): # <<<<<<<<<<<<<< + * return "<%s.%s: %d>" % (self.__class__.__name__, self.name, self) + * def __str__(self): + */ + __pyx_tuple__18 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__18)) __PYX_ERR(1, 39, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__18); + __Pyx_GIVEREF(__pyx_tuple__18); + __pyx_codeobj__19 = (PyObject*)__Pyx_PyCode_New(1, 0, 1, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__18, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_stringsource, __pyx_n_s_repr, 39, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__19)) __PYX_ERR(1, 39, __pyx_L1_error) + + /* "EnumBase":41 + * def __repr__(self): + * return "<%s.%s: %d>" % (self.__class__.__name__, self.name, self) + * def __str__(self): # <<<<<<<<<<<<<< + * return "%s.%s" % (self.__class__.__name__, self.name) + * + */ + __pyx_tuple__20 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__20)) __PYX_ERR(1, 41, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__20); + __Pyx_GIVEREF(__pyx_tuple__20); + __pyx_codeobj__21 = (PyObject*)__Pyx_PyCode_New(1, 0, 1, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__20, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_stringsource, __pyx_n_s_str, 41, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__21)) __PYX_ERR(1, 41, __pyx_L1_error) + + /* "(tree fragment)":1 + * def __pyx_unpickle___Pyx_EnumMeta(__pyx_type, long __pyx_checksum, __pyx_state): # <<<<<<<<<<<<<< + * cdef object __pyx_PickleError + * cdef object __pyx_result + */ + __pyx_tuple__22 = PyTuple_Pack(5, __pyx_n_s_pyx_type, __pyx_n_s_pyx_checksum, __pyx_n_s_pyx_state, __pyx_n_s_pyx_PickleError, __pyx_n_s_pyx_result); if (unlikely(!__pyx_tuple__22)) __PYX_ERR(1, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__22); + __Pyx_GIVEREF(__pyx_tuple__22); + __pyx_codeobj__23 = (PyObject*)__Pyx_PyCode_New(3, 0, 5, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__22, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_stringsource, __pyx_n_s_pyx_unpickle___Pyx_EnumMeta, 1, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__23)) __PYX_ERR(1, 1, __pyx_L1_error) + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_RefNannyFinishContext(); + return -1; +} + +static CYTHON_SMALL_CODE int __Pyx_InitGlobals(void) { + if (__Pyx_InitStrings(__pyx_string_tab) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_222419149 = PyInt_FromLong(222419149L); if (unlikely(!__pyx_int_222419149)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_228825662 = PyInt_FromLong(228825662L); if (unlikely(!__pyx_int_228825662)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_int_238750788 = PyInt_FromLong(238750788L); if (unlikely(!__pyx_int_238750788)) __PYX_ERR(0, 1, __pyx_L1_error) + return 0; + __pyx_L1_error:; + return -1; +} + +static CYTHON_SMALL_CODE int __Pyx_modinit_global_init_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_variable_export_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_function_export_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_type_init_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_type_import_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_variable_import_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_function_import_code(void); /*proto*/ + +static int __Pyx_modinit_global_init_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_global_init_code", 0); + /*--- Global init code ---*/ + __Pyx_OrderedDict = Py_None; Py_INCREF(Py_None); + __Pyx_EnumBase = Py_None; Py_INCREF(Py_None); + __Pyx_globals = ((PyObject*)Py_None); Py_INCREF(Py_None); + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_variable_export_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_variable_export_code", 0); + /*--- Variable export code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_function_export_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_function_export_code", 0); + /*--- Function export code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_type_init_code(void) { + __Pyx_RefNannyDeclarations + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("__Pyx_modinit_type_init_code", 0); + /*--- Type init code ---*/ + if (PyType_Ready(&__pyx_type_6region_RegionBounds) < 0) __PYX_ERR(0, 17, __pyx_L1_error) + #if PY_VERSION_HEX < 0x030800B1 + __pyx_type_6region_RegionBounds.tp_print = 0; + #endif + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_type_6region_RegionBounds.tp_dictoffset && __pyx_type_6region_RegionBounds.tp_getattro == PyObject_GenericGetAttr)) { + __pyx_type_6region_RegionBounds.tp_getattro = __Pyx_PyObject_GenericGetAttr; + } + if (PyObject_SetAttr(__pyx_m, __pyx_n_s_RegionBounds, (PyObject *)&__pyx_type_6region_RegionBounds) < 0) __PYX_ERR(0, 17, __pyx_L1_error) + if (__Pyx_setup_reduce((PyObject*)&__pyx_type_6region_RegionBounds) < 0) __PYX_ERR(0, 17, __pyx_L1_error) + __pyx_ptype_6region_RegionBounds = &__pyx_type_6region_RegionBounds; + if (PyType_Ready(&__pyx_type_6region_Rectangle) < 0) __PYX_ERR(0, 56, __pyx_L1_error) + #if PY_VERSION_HEX < 0x030800B1 + __pyx_type_6region_Rectangle.tp_print = 0; + #endif + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_type_6region_Rectangle.tp_dictoffset && __pyx_type_6region_Rectangle.tp_getattro == PyObject_GenericGetAttr)) { + __pyx_type_6region_Rectangle.tp_getattro = __Pyx_PyObject_GenericGetAttr; + } + if (PyObject_SetAttr(__pyx_m, __pyx_n_s_Rectangle, (PyObject *)&__pyx_type_6region_Rectangle) < 0) __PYX_ERR(0, 56, __pyx_L1_error) + if (__Pyx_setup_reduce((PyObject*)&__pyx_type_6region_Rectangle) < 0) __PYX_ERR(0, 56, __pyx_L1_error) + __pyx_ptype_6region_Rectangle = &__pyx_type_6region_Rectangle; + if (PyType_Ready(&__pyx_type_6region_Polygon) < 0) __PYX_ERR(0, 97, __pyx_L1_error) + #if PY_VERSION_HEX < 0x030800B1 + __pyx_type_6region_Polygon.tp_print = 0; + #endif + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_type_6region_Polygon.tp_dictoffset && __pyx_type_6region_Polygon.tp_getattro == PyObject_GenericGetAttr)) { + __pyx_type_6region_Polygon.tp_getattro = __Pyx_PyObject_GenericGetAttr; + } + if (PyObject_SetAttr(__pyx_m, __pyx_n_s_Polygon, (PyObject *)&__pyx_type_6region_Polygon) < 0) __PYX_ERR(0, 97, __pyx_L1_error) + if (__Pyx_setup_reduce((PyObject*)&__pyx_type_6region_Polygon) < 0) __PYX_ERR(0, 97, __pyx_L1_error) + __pyx_ptype_6region_Polygon = &__pyx_type_6region_Polygon; + __Pyx_EnumMeta.tp_base = (&PyType_Type); + if (PyType_Ready(&__Pyx_EnumMeta) < 0) __PYX_ERR(1, 15, __pyx_L1_error) + #if PY_VERSION_HEX < 0x030800B1 + __Pyx_EnumMeta.tp_print = 0; + #endif + if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__Pyx_EnumMeta.tp_dictoffset && __Pyx_EnumMeta.tp_getattro == PyObject_GenericGetAttr)) { + __Pyx_EnumMeta.tp_getattro = __Pyx_PyObject_GenericGetAttr; + } + if (__Pyx_setup_reduce((PyObject*)&__Pyx_EnumMeta) < 0) __PYX_ERR(1, 15, __pyx_L1_error) + __pyx_ptype___Pyx_EnumMeta = &__Pyx_EnumMeta; + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_RefNannyFinishContext(); + return -1; +} + +static int __Pyx_modinit_type_import_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_type_import_code", 0); + /*--- Type import code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_variable_import_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_variable_import_code", 0); + /*--- Variable import code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_function_import_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_function_import_code", 0); + /*--- Function import code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + + +#ifndef CYTHON_NO_PYINIT_EXPORT +#define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC +#elif PY_MAJOR_VERSION < 3 +#ifdef __cplusplus +#define __Pyx_PyMODINIT_FUNC extern "C" void +#else +#define __Pyx_PyMODINIT_FUNC void +#endif +#else +#ifdef __cplusplus +#define __Pyx_PyMODINIT_FUNC extern "C" PyObject * +#else +#define __Pyx_PyMODINIT_FUNC PyObject * +#endif +#endif + + +#if PY_MAJOR_VERSION < 3 +__Pyx_PyMODINIT_FUNC initregion(void) CYTHON_SMALL_CODE; /*proto*/ +__Pyx_PyMODINIT_FUNC initregion(void) +#else +__Pyx_PyMODINIT_FUNC PyInit_region(void) CYTHON_SMALL_CODE; /*proto*/ +__Pyx_PyMODINIT_FUNC PyInit_region(void) +#if CYTHON_PEP489_MULTI_PHASE_INIT +{ + return PyModuleDef_Init(&__pyx_moduledef); +} +static CYTHON_SMALL_CODE int __Pyx_check_single_interpreter(void) { + #if PY_VERSION_HEX >= 0x030700A1 + static PY_INT64_T main_interpreter_id = -1; + PY_INT64_T current_id = PyInterpreterState_GetID(PyThreadState_Get()->interp); + if (main_interpreter_id == -1) { + main_interpreter_id = current_id; + return (unlikely(current_id == -1)) ? -1 : 0; + } else if (unlikely(main_interpreter_id != current_id)) + #else + static PyInterpreterState *main_interpreter = NULL; + PyInterpreterState *current_interpreter = PyThreadState_Get()->interp; + if (!main_interpreter) { + main_interpreter = current_interpreter; + } else if (unlikely(main_interpreter != current_interpreter)) + #endif + { + PyErr_SetString( + PyExc_ImportError, + "Interpreter change detected - this module can only be loaded into one interpreter per process."); + return -1; + } + return 0; +} +static CYTHON_SMALL_CODE int __Pyx_copy_spec_to_module(PyObject *spec, PyObject *moddict, const char* from_name, const char* to_name, int allow_none) { + PyObject *value = PyObject_GetAttrString(spec, from_name); + int result = 0; + if (likely(value)) { + if (allow_none || value != Py_None) { + result = PyDict_SetItemString(moddict, to_name, value); + } + Py_DECREF(value); + } else if (PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Clear(); + } else { + result = -1; + } + return result; +} +static CYTHON_SMALL_CODE PyObject* __pyx_pymod_create(PyObject *spec, CYTHON_UNUSED PyModuleDef *def) { + PyObject *module = NULL, *moddict, *modname; + if (__Pyx_check_single_interpreter()) + return NULL; + if (__pyx_m) + return __Pyx_NewRef(__pyx_m); + modname = PyObject_GetAttrString(spec, "name"); + if (unlikely(!modname)) goto bad; + module = PyModule_NewObject(modname); + Py_DECREF(modname); + if (unlikely(!module)) goto bad; + moddict = PyModule_GetDict(module); + if (unlikely(!moddict)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "loader", "__loader__", 1) < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "origin", "__file__", 1) < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "parent", "__package__", 1) < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "submodule_search_locations", "__path__", 0) < 0)) goto bad; + return module; +bad: + Py_XDECREF(module); + return NULL; +} + + +static CYTHON_SMALL_CODE int __pyx_pymod_exec_region(PyObject *__pyx_pyinit_module) +#endif +#endif +{ + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannyDeclarations + #if CYTHON_PEP489_MULTI_PHASE_INIT + if (__pyx_m) { + if (__pyx_m == __pyx_pyinit_module) return 0; + PyErr_SetString(PyExc_RuntimeError, "Module 'region' has already been imported. Re-initialisation is not supported."); + return -1; + } + #elif PY_MAJOR_VERSION >= 3 + if (__pyx_m) return __Pyx_NewRef(__pyx_m); + #endif + #if CYTHON_REFNANNY +__Pyx_RefNanny = __Pyx_RefNannyImportAPI("refnanny"); +if (!__Pyx_RefNanny) { + PyErr_Clear(); + __Pyx_RefNanny = __Pyx_RefNannyImportAPI("Cython.Runtime.refnanny"); + if (!__Pyx_RefNanny) + Py_FatalError("failed to import 'refnanny' module"); +} +#endif + __Pyx_RefNannySetupContext("__Pyx_PyMODINIT_FUNC PyInit_region(void)", 0); + if (__Pyx_check_binary_version() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #ifdef __Pxy_PyFrame_Initialize_Offsets + __Pxy_PyFrame_Initialize_Offsets(); + #endif + __pyx_empty_tuple = PyTuple_New(0); if (unlikely(!__pyx_empty_tuple)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_empty_bytes = PyBytes_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_bytes)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_empty_unicode = PyUnicode_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_unicode)) __PYX_ERR(0, 1, __pyx_L1_error) + #ifdef __Pyx_CyFunction_USED + if (__pyx_CyFunction_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_FusedFunction_USED + if (__pyx_FusedFunction_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_Coroutine_USED + if (__pyx_Coroutine_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_Generator_USED + if (__pyx_Generator_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_AsyncGen_USED + if (__pyx_AsyncGen_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_StopAsyncIteration_USED + if (__pyx_StopAsyncIteration_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + /*--- Library function declarations ---*/ + /*--- Threads initialization code ---*/ + #if defined(WITH_THREAD) && PY_VERSION_HEX < 0x030700F0 && defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS + PyEval_InitThreads(); + #endif + /*--- Module creation code ---*/ + #if CYTHON_PEP489_MULTI_PHASE_INIT + __pyx_m = __pyx_pyinit_module; + Py_INCREF(__pyx_m); + #else + #if PY_MAJOR_VERSION < 3 + __pyx_m = Py_InitModule4("region", __pyx_methods, 0, 0, PYTHON_API_VERSION); Py_XINCREF(__pyx_m); + #else + __pyx_m = PyModule_Create(&__pyx_moduledef); + #endif + if (unlikely(!__pyx_m)) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + __pyx_d = PyModule_GetDict(__pyx_m); if (unlikely(!__pyx_d)) __PYX_ERR(0, 1, __pyx_L1_error) + Py_INCREF(__pyx_d); + __pyx_b = PyImport_AddModule(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_b)) __PYX_ERR(0, 1, __pyx_L1_error) + Py_INCREF(__pyx_b); + __pyx_cython_runtime = PyImport_AddModule((char *) "cython_runtime"); if (unlikely(!__pyx_cython_runtime)) __PYX_ERR(0, 1, __pyx_L1_error) + Py_INCREF(__pyx_cython_runtime); + if (PyObject_SetAttrString(__pyx_m, "__builtins__", __pyx_b) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + /*--- Initialize various global constants etc. ---*/ + if (__Pyx_InitGlobals() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #if PY_MAJOR_VERSION < 3 && (__PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT) + if (__Pyx_init_sys_getdefaultencoding_params() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + if (__pyx_module_is_main_region) { + if (PyObject_SetAttr(__pyx_m, __pyx_n_s_name_2, __pyx_n_s_main) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + } + #if PY_MAJOR_VERSION >= 3 + { + PyObject *modules = PyImport_GetModuleDict(); if (unlikely(!modules)) __PYX_ERR(0, 1, __pyx_L1_error) + if (!PyDict_GetItemString(modules, "region")) { + if (unlikely(PyDict_SetItemString(modules, "region", __pyx_m) < 0)) __PYX_ERR(0, 1, __pyx_L1_error) + } + } + #endif + /*--- Builtin init code ---*/ + if (__Pyx_InitCachedBuiltins() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + /*--- Constants init code ---*/ + if (__Pyx_InitCachedConstants() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + /*--- Global type/function init code ---*/ + (void)__Pyx_modinit_global_init_code(); + (void)__Pyx_modinit_variable_export_code(); + (void)__Pyx_modinit_function_export_code(); + if (unlikely(__Pyx_modinit_type_init_code() < 0)) __PYX_ERR(0, 1, __pyx_L1_error) + (void)__Pyx_modinit_type_import_code(); + (void)__Pyx_modinit_variable_import_code(); + (void)__Pyx_modinit_function_import_code(); + /*--- Execution code ---*/ + #if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED) + if (__Pyx_patch_abc() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + + /* "region.pyx":161 + * # return c_vot_overlap(p1, p2) + * + * def vot_overlap(polygon1, polygon2, bounds=None): # <<<<<<<<<<<<<< + * """ computing overlap between two polygon + * Args: + */ + __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_6region_1vot_overlap, NULL, __pyx_n_s_region); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 161, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_vot_overlap, __pyx_t_1) < 0) __PYX_ERR(0, 161, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "region.pyx":200 + * no_bounds) + * + * def vot_overlap_traj(polygons1, polygons2, bounds): # <<<<<<<<<<<<<< + * """ computing overlap between two trajectory + * Args: + */ + __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_6region_3vot_overlap_traj, NULL, __pyx_n_s_region); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 200, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_vot_overlap_traj, __pyx_t_1) < 0) __PYX_ERR(0, 200, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "region.pyx":231 + * + * + * def vot_float2str(template, float value): # <<<<<<<<<<<<<< + * cdef bytes ptemplate = template.encode() + * cdef const char* ctemplate = ptemplate + */ + __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_6region_5vot_float2str, NULL, __pyx_n_s_region); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 231, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_vot_float2str, __pyx_t_1) < 0) __PYX_ERR(0, 231, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "region.pyx":1 + * # distutils: sources = src/region.c # <<<<<<<<<<<<<< + * # distutils: include_dirs = src/ + * + */ + __pyx_t_1 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "EnumBase":9 + * + * cdef object __Pyx_OrderedDict + * if PY_VERSION_HEX >= 0x02070000: # <<<<<<<<<<<<<< + * from collections import OrderedDict as __Pyx_OrderedDict + * else: + */ + __pyx_t_2 = ((PY_VERSION_HEX >= 0x02070000) != 0); + if (__pyx_t_2) { + + /* "EnumBase":10 + * cdef object __Pyx_OrderedDict + * if PY_VERSION_HEX >= 0x02070000: + * from collections import OrderedDict as __Pyx_OrderedDict # <<<<<<<<<<<<<< + * else: + * __Pyx_OrderedDict = dict + */ + __pyx_t_1 = PyList_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 10, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(__pyx_n_s_OrderedDict); + __Pyx_GIVEREF(__pyx_n_s_OrderedDict); + PyList_SET_ITEM(__pyx_t_1, 0, __pyx_n_s_OrderedDict); + __pyx_t_3 = __Pyx_Import(__pyx_n_s_collections, __pyx_t_1, -1); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 10, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_ImportFrom(__pyx_t_3, __pyx_n_s_OrderedDict); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 10, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(__pyx_t_1); + __Pyx_XGOTREF(__Pyx_OrderedDict); + __Pyx_DECREF_SET(__Pyx_OrderedDict, __pyx_t_1); + __Pyx_GIVEREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "EnumBase":9 + * + * cdef object __Pyx_OrderedDict + * if PY_VERSION_HEX >= 0x02070000: # <<<<<<<<<<<<<< + * from collections import OrderedDict as __Pyx_OrderedDict + * else: + */ + goto __pyx_L2; + } + + /* "EnumBase":12 + * from collections import OrderedDict as __Pyx_OrderedDict + * else: + * __Pyx_OrderedDict = dict # <<<<<<<<<<<<<< + * + * @cython.internal + */ + /*else*/ { + __Pyx_INCREF(((PyObject *)(&PyDict_Type))); + __Pyx_XGOTREF(__Pyx_OrderedDict); + __Pyx_DECREF_SET(__Pyx_OrderedDict, ((PyObject *)(&PyDict_Type))); + __Pyx_GIVEREF(((PyObject *)(&PyDict_Type))); + } + __pyx_L2:; + + /* "EnumBase":26 + * + * cdef object __Pyx_EnumBase + * class __Pyx_EnumBase(int): # <<<<<<<<<<<<<< + * __metaclass__ = __Pyx_EnumMeta + * def __new__(cls, value, name=None): + */ + __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 26, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_INCREF(((PyObject *)(&PyInt_Type))); + __Pyx_GIVEREF(((PyObject *)(&PyInt_Type))); + PyTuple_SET_ITEM(__pyx_t_3, 0, ((PyObject *)(&PyInt_Type))); + __pyx_t_1 = __Pyx_CalculateMetaclass(NULL, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 26, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_4 = __Pyx_Py3MetaclassPrepare(__pyx_t_1, __pyx_t_3, __pyx_n_s_Pyx_EnumBase, __pyx_n_s_Pyx_EnumBase, (PyObject *) NULL, __pyx_n_s_EnumBase, (PyObject *) NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 26, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + + /* "EnumBase":27 + * cdef object __Pyx_EnumBase + * class __Pyx_EnumBase(int): + * __metaclass__ = __Pyx_EnumMeta # <<<<<<<<<<<<<< + * def __new__(cls, value, name=None): + * for v in cls: + */ + if (__Pyx_SetNameInClass(__pyx_t_4, __pyx_n_s_metaclass, ((PyObject *)__pyx_ptype___Pyx_EnumMeta)) < 0) __PYX_ERR(1, 27, __pyx_L1_error) + + /* "EnumBase":28 + * class __Pyx_EnumBase(int): + * __metaclass__ = __Pyx_EnumMeta + * def __new__(cls, value, name=None): # <<<<<<<<<<<<<< + * for v in cls: + * if v == value: + */ + __pyx_t_5 = __Pyx_CyFunction_New(&__pyx_mdef_8EnumBase_14__Pyx_EnumBase_1__new__, __Pyx_CYFUNCTION_STATICMETHOD, __pyx_n_s_Pyx_EnumBase___new, NULL, __pyx_n_s_EnumBase, __pyx_d, ((PyObject *)__pyx_codeobj__16)); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 28, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_5, __pyx_tuple__17); + if (__Pyx_SetNameInClass(__pyx_t_4, __pyx_n_s_new, __pyx_t_5) < 0) __PYX_ERR(1, 28, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + + /* "EnumBase":39 + * cls.__members__[name] = res + * return res + * def __repr__(self): # <<<<<<<<<<<<<< + * return "<%s.%s: %d>" % (self.__class__.__name__, self.name, self) + * def __str__(self): + */ + __pyx_t_5 = __Pyx_CyFunction_New(&__pyx_mdef_8EnumBase_14__Pyx_EnumBase_3__repr__, 0, __pyx_n_s_Pyx_EnumBase___repr, NULL, __pyx_n_s_EnumBase, __pyx_d, ((PyObject *)__pyx_codeobj__19)); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 39, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (__Pyx_SetNameInClass(__pyx_t_4, __pyx_n_s_repr, __pyx_t_5) < 0) __PYX_ERR(1, 39, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + + /* "EnumBase":41 + * def __repr__(self): + * return "<%s.%s: %d>" % (self.__class__.__name__, self.name, self) + * def __str__(self): # <<<<<<<<<<<<<< + * return "%s.%s" % (self.__class__.__name__, self.name) + * + */ + __pyx_t_5 = __Pyx_CyFunction_New(&__pyx_mdef_8EnumBase_14__Pyx_EnumBase_5__str__, 0, __pyx_n_s_Pyx_EnumBase___str, NULL, __pyx_n_s_EnumBase, __pyx_d, ((PyObject *)__pyx_codeobj__21)); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 41, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (__Pyx_SetNameInClass(__pyx_t_4, __pyx_n_s_str, __pyx_t_5) < 0) __PYX_ERR(1, 41, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + + /* "EnumBase":26 + * + * cdef object __Pyx_EnumBase + * class __Pyx_EnumBase(int): # <<<<<<<<<<<<<< + * __metaclass__ = __Pyx_EnumMeta + * def __new__(cls, value, name=None): + */ + __pyx_t_5 = __Pyx_Py3ClassCreate(__pyx_t_1, __pyx_n_s_Pyx_EnumBase, __pyx_t_3, __pyx_t_4, NULL, 0, 1); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 26, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_XGOTREF(__Pyx_EnumBase); + __Pyx_DECREF_SET(__Pyx_EnumBase, __pyx_t_5); + __Pyx_GIVEREF(__pyx_t_5); + __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + + /* "EnumBase":44 + * return "%s.%s" % (self.__class__.__name__, self.name) + * + * if PY_VERSION_HEX >= 0x03040000: # <<<<<<<<<<<<<< + * from enum import IntEnum as __Pyx_EnumBase + * + */ + __pyx_t_2 = ((PY_VERSION_HEX >= 0x03040000) != 0); + if (__pyx_t_2) { + + /* "EnumBase":45 + * + * if PY_VERSION_HEX >= 0x03040000: + * from enum import IntEnum as __Pyx_EnumBase # <<<<<<<<<<<<<< + * + */ + __pyx_t_3 = PyList_New(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 45, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_INCREF(__pyx_n_s_IntEnum); + __Pyx_GIVEREF(__pyx_n_s_IntEnum); + PyList_SET_ITEM(__pyx_t_3, 0, __pyx_n_s_IntEnum); + __pyx_t_1 = __Pyx_Import(__pyx_n_s_enum, __pyx_t_3, -1); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 45, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = __Pyx_ImportFrom(__pyx_t_1, __pyx_n_s_IntEnum); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 45, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_INCREF(__pyx_t_3); + __Pyx_XGOTREF(__Pyx_EnumBase); + __Pyx_DECREF_SET(__Pyx_EnumBase, __pyx_t_3); + __Pyx_GIVEREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "EnumBase":44 + * return "%s.%s" % (self.__class__.__name__, self.name) + * + * if PY_VERSION_HEX >= 0x03040000: # <<<<<<<<<<<<<< + * from enum import IntEnum as __Pyx_EnumBase + * + */ + } + + /* "(tree fragment)":1 + * def __pyx_unpickle___Pyx_EnumMeta(__pyx_type, long __pyx_checksum, __pyx_state): # <<<<<<<<<<<<<< + * cdef object __pyx_PickleError + * cdef object __pyx_result + */ + __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_8EnumBase_1__pyx_unpickle___Pyx_EnumMeta, NULL, __pyx_n_s_EnumBase); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_pyx_unpickle___Pyx_EnumMeta, __pyx_t_1) < 0) __PYX_ERR(1, 1, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "EnumType":50 + * + * + * cdef dict __Pyx_globals = globals() # <<<<<<<<<<<<<< + * if PY_VERSION_HEX >= 0x03040000: + * + */ + __pyx_t_1 = __Pyx_Globals(); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 50, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (!(likely(PyDict_CheckExact(__pyx_t_1))||((__pyx_t_1) == Py_None)||((void)PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "dict", Py_TYPE(__pyx_t_1)->tp_name), 0))) __PYX_ERR(1, 50, __pyx_L1_error) + __Pyx_XGOTREF(__Pyx_globals); + __Pyx_DECREF_SET(__Pyx_globals, ((PyObject*)__pyx_t_1)); + __Pyx_GIVEREF(__pyx_t_1); + __pyx_t_1 = 0; + + /* "EnumType":51 + * + * cdef dict __Pyx_globals = globals() + * if PY_VERSION_HEX >= 0x03040000: # <<<<<<<<<<<<<< + * + * RegionType = __Pyx_EnumBase('RegionType', __Pyx_OrderedDict([ + */ + __pyx_t_2 = ((PY_VERSION_HEX >= 0x03040000) != 0); + if (__pyx_t_2) { + + /* "EnumType":54 + * + * RegionType = __Pyx_EnumBase('RegionType', __Pyx_OrderedDict([ + * ('EMTPY', EMTPY), # <<<<<<<<<<<<<< + * ('SPECIAL', SPECIAL), + * ('RECTANGEL', RECTANGEL), + */ + __pyx_t_1 = __Pyx_PyInt_From_enum____pyx_t_6region_RegionType(__pyx_e_6region_EMTPY); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 54, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 54, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_INCREF(__pyx_n_s_EMTPY); + __Pyx_GIVEREF(__pyx_n_s_EMTPY); + PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_n_s_EMTPY); + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_t_1); + __pyx_t_1 = 0; + + /* "EnumType":55 + * RegionType = __Pyx_EnumBase('RegionType', __Pyx_OrderedDict([ + * ('EMTPY', EMTPY), + * ('SPECIAL', SPECIAL), # <<<<<<<<<<<<<< + * ('RECTANGEL', RECTANGEL), + * ('POLYGON', POLYGON), + */ + __pyx_t_1 = __Pyx_PyInt_From_enum____pyx_t_6region_RegionType(__pyx_e_6region_SPECIAL); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 55, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_4 = PyTuple_New(2); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 55, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_INCREF(__pyx_n_s_SPECIAL); + __Pyx_GIVEREF(__pyx_n_s_SPECIAL); + PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_n_s_SPECIAL); + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_4, 1, __pyx_t_1); + __pyx_t_1 = 0; + + /* "EnumType":56 + * ('EMTPY', EMTPY), + * ('SPECIAL', SPECIAL), + * ('RECTANGEL', RECTANGEL), # <<<<<<<<<<<<<< + * ('POLYGON', POLYGON), + * ('MASK', MASK), + */ + __pyx_t_1 = __Pyx_PyInt_From_enum____pyx_t_6region_RegionType(__pyx_e_6region_RECTANGEL); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 56, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_5 = PyTuple_New(2); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 56, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_INCREF(__pyx_n_s_RECTANGEL); + __Pyx_GIVEREF(__pyx_n_s_RECTANGEL); + PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_n_s_RECTANGEL); + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_t_1); + __pyx_t_1 = 0; + + /* "EnumType":57 + * ('SPECIAL', SPECIAL), + * ('RECTANGEL', RECTANGEL), + * ('POLYGON', POLYGON), # <<<<<<<<<<<<<< + * ('MASK', MASK), + * ])) + */ + __pyx_t_1 = __Pyx_PyInt_From_enum____pyx_t_6region_RegionType(__pyx_e_6region_POLYGON); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 57, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_6 = PyTuple_New(2); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 57, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_INCREF(__pyx_n_s_POLYGON); + __Pyx_GIVEREF(__pyx_n_s_POLYGON); + PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_n_s_POLYGON); + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_6, 1, __pyx_t_1); + __pyx_t_1 = 0; + + /* "EnumType":58 + * ('RECTANGEL', RECTANGEL), + * ('POLYGON', POLYGON), + * ('MASK', MASK), # <<<<<<<<<<<<<< + * ])) + * __Pyx_globals['EMTPY'] = RegionType.EMTPY + */ + __pyx_t_1 = __Pyx_PyInt_From_enum____pyx_t_6region_RegionType(__pyx_e_6region_MASK); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 58, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_7 = PyTuple_New(2); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 58, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_INCREF(__pyx_n_s_MASK); + __Pyx_GIVEREF(__pyx_n_s_MASK); + PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_n_s_MASK); + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_7, 1, __pyx_t_1); + __pyx_t_1 = 0; + + /* "EnumType":53 + * if PY_VERSION_HEX >= 0x03040000: + * + * RegionType = __Pyx_EnumBase('RegionType', __Pyx_OrderedDict([ # <<<<<<<<<<<<<< + * ('EMTPY', EMTPY), + * ('SPECIAL', SPECIAL), + */ + __pyx_t_1 = PyList_New(5); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 53, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_GIVEREF(__pyx_t_3); + PyList_SET_ITEM(__pyx_t_1, 0, __pyx_t_3); + __Pyx_GIVEREF(__pyx_t_4); + PyList_SET_ITEM(__pyx_t_1, 1, __pyx_t_4); + __Pyx_GIVEREF(__pyx_t_5); + PyList_SET_ITEM(__pyx_t_1, 2, __pyx_t_5); + __Pyx_GIVEREF(__pyx_t_6); + PyList_SET_ITEM(__pyx_t_1, 3, __pyx_t_6); + __Pyx_GIVEREF(__pyx_t_7); + PyList_SET_ITEM(__pyx_t_1, 4, __pyx_t_7); + __pyx_t_3 = 0; + __pyx_t_4 = 0; + __pyx_t_5 = 0; + __pyx_t_6 = 0; + __pyx_t_7 = 0; + __pyx_t_7 = __Pyx_PyObject_CallOneArg(__Pyx_OrderedDict, __pyx_t_1); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 53, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = PyTuple_New(2); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 53, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(__pyx_n_s_RegionType); + __Pyx_GIVEREF(__pyx_n_s_RegionType); + PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_n_s_RegionType); + __Pyx_GIVEREF(__pyx_t_7); + PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_t_7); + __pyx_t_7 = 0; + __pyx_t_7 = __Pyx_PyObject_Call(__Pyx_EnumBase, __pyx_t_1, NULL); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 53, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (PyDict_SetItem(__pyx_d, __pyx_n_s_RegionType, __pyx_t_7) < 0) __PYX_ERR(1, 53, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "EnumType":60 + * ('MASK', MASK), + * ])) + * __Pyx_globals['EMTPY'] = RegionType.EMTPY # <<<<<<<<<<<<<< + * __Pyx_globals['SPECIAL'] = RegionType.SPECIAL + * __Pyx_globals['RECTANGEL'] = RegionType.RECTANGEL + */ + __Pyx_GetModuleGlobalName(__pyx_t_7, __pyx_n_s_RegionType); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 60, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_EMTPY); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 60, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (unlikely(__Pyx_globals == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(1, 60, __pyx_L1_error) + } + if (unlikely(PyDict_SetItem(__Pyx_globals, __pyx_n_s_EMTPY, __pyx_t_1) < 0)) __PYX_ERR(1, 60, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "EnumType":61 + * ])) + * __Pyx_globals['EMTPY'] = RegionType.EMTPY + * __Pyx_globals['SPECIAL'] = RegionType.SPECIAL # <<<<<<<<<<<<<< + * __Pyx_globals['RECTANGEL'] = RegionType.RECTANGEL + * __Pyx_globals['POLYGON'] = RegionType.POLYGON + */ + __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_RegionType); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 61, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_SPECIAL); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 61, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(__Pyx_globals == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(1, 61, __pyx_L1_error) + } + if (unlikely(PyDict_SetItem(__Pyx_globals, __pyx_n_s_SPECIAL, __pyx_t_7) < 0)) __PYX_ERR(1, 61, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "EnumType":62 + * __Pyx_globals['EMTPY'] = RegionType.EMTPY + * __Pyx_globals['SPECIAL'] = RegionType.SPECIAL + * __Pyx_globals['RECTANGEL'] = RegionType.RECTANGEL # <<<<<<<<<<<<<< + * __Pyx_globals['POLYGON'] = RegionType.POLYGON + * __Pyx_globals['MASK'] = RegionType.MASK + */ + __Pyx_GetModuleGlobalName(__pyx_t_7, __pyx_n_s_RegionType); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 62, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_RECTANGEL); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 62, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (unlikely(__Pyx_globals == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(1, 62, __pyx_L1_error) + } + if (unlikely(PyDict_SetItem(__Pyx_globals, __pyx_n_s_RECTANGEL, __pyx_t_1) < 0)) __PYX_ERR(1, 62, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "EnumType":63 + * __Pyx_globals['SPECIAL'] = RegionType.SPECIAL + * __Pyx_globals['RECTANGEL'] = RegionType.RECTANGEL + * __Pyx_globals['POLYGON'] = RegionType.POLYGON # <<<<<<<<<<<<<< + * __Pyx_globals['MASK'] = RegionType.MASK + * else: + */ + __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_RegionType); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 63, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_POLYGON); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 63, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(__Pyx_globals == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(1, 63, __pyx_L1_error) + } + if (unlikely(PyDict_SetItem(__Pyx_globals, __pyx_n_s_POLYGON, __pyx_t_7) < 0)) __PYX_ERR(1, 63, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "EnumType":64 + * __Pyx_globals['RECTANGEL'] = RegionType.RECTANGEL + * __Pyx_globals['POLYGON'] = RegionType.POLYGON + * __Pyx_globals['MASK'] = RegionType.MASK # <<<<<<<<<<<<<< + * else: + * class RegionType(__Pyx_EnumBase): + */ + __Pyx_GetModuleGlobalName(__pyx_t_7, __pyx_n_s_RegionType); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 64, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_MASK); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 64, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (unlikely(__Pyx_globals == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(1, 64, __pyx_L1_error) + } + if (unlikely(PyDict_SetItem(__Pyx_globals, __pyx_n_s_MASK, __pyx_t_1) < 0)) __PYX_ERR(1, 64, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "EnumType":51 + * + * cdef dict __Pyx_globals = globals() + * if PY_VERSION_HEX >= 0x03040000: # <<<<<<<<<<<<<< + * + * RegionType = __Pyx_EnumBase('RegionType', __Pyx_OrderedDict([ + */ + goto __pyx_L4; + } + + /* "EnumType":66 + * __Pyx_globals['MASK'] = RegionType.MASK + * else: + * class RegionType(__Pyx_EnumBase): # <<<<<<<<<<<<<< + * pass + * __Pyx_globals['EMTPY'] = RegionType(EMTPY, 'EMTPY') + */ + /*else*/ { + __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 66, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_INCREF(__Pyx_EnumBase); + __Pyx_GIVEREF(__Pyx_EnumBase); + PyTuple_SET_ITEM(__pyx_t_1, 0, __Pyx_EnumBase); + __pyx_t_7 = __Pyx_CalculateMetaclass(NULL, __pyx_t_1); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 66, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_6 = __Pyx_Py3MetaclassPrepare(__pyx_t_7, __pyx_t_1, __pyx_n_s_RegionType, __pyx_n_s_RegionType, (PyObject *) NULL, __pyx_n_s_EnumType, (PyObject *) NULL); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 66, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_5 = __Pyx_Py3ClassCreate(__pyx_t_7, __pyx_n_s_RegionType, __pyx_t_1, __pyx_t_6, NULL, 0, 1); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 66, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_RegionType, __pyx_t_5) < 0) __PYX_ERR(1, 66, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "EnumType":68 + * class RegionType(__Pyx_EnumBase): + * pass + * __Pyx_globals['EMTPY'] = RegionType(EMTPY, 'EMTPY') # <<<<<<<<<<<<<< + * __Pyx_globals['SPECIAL'] = RegionType(SPECIAL, 'SPECIAL') + * __Pyx_globals['RECTANGEL'] = RegionType(RECTANGEL, 'RECTANGEL') + */ + __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_RegionType); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 68, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_7 = __Pyx_PyInt_From_enum____pyx_t_6region_RegionType(__pyx_e_6region_EMTPY); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 68, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_6 = PyTuple_New(2); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 68, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_GIVEREF(__pyx_t_7); + PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_7); + __Pyx_INCREF(__pyx_n_s_EMTPY); + __Pyx_GIVEREF(__pyx_n_s_EMTPY); + PyTuple_SET_ITEM(__pyx_t_6, 1, __pyx_n_s_EMTPY); + __pyx_t_7 = 0; + __pyx_t_7 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_6, NULL); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 68, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + if (unlikely(__Pyx_globals == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(1, 68, __pyx_L1_error) + } + if (unlikely(PyDict_SetItem(__Pyx_globals, __pyx_n_s_EMTPY, __pyx_t_7) < 0)) __PYX_ERR(1, 68, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "EnumType":69 + * pass + * __Pyx_globals['EMTPY'] = RegionType(EMTPY, 'EMTPY') + * __Pyx_globals['SPECIAL'] = RegionType(SPECIAL, 'SPECIAL') # <<<<<<<<<<<<<< + * __Pyx_globals['RECTANGEL'] = RegionType(RECTANGEL, 'RECTANGEL') + * __Pyx_globals['POLYGON'] = RegionType(POLYGON, 'POLYGON') + */ + __Pyx_GetModuleGlobalName(__pyx_t_7, __pyx_n_s_RegionType); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 69, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_6 = __Pyx_PyInt_From_enum____pyx_t_6region_RegionType(__pyx_e_6region_SPECIAL); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 69, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_1 = PyTuple_New(2); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 69, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_GIVEREF(__pyx_t_6); + PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_t_6); + __Pyx_INCREF(__pyx_n_s_SPECIAL); + __Pyx_GIVEREF(__pyx_n_s_SPECIAL); + PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_n_s_SPECIAL); + __pyx_t_6 = 0; + __pyx_t_6 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_1, NULL); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 69, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(__Pyx_globals == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(1, 69, __pyx_L1_error) + } + if (unlikely(PyDict_SetItem(__Pyx_globals, __pyx_n_s_SPECIAL, __pyx_t_6) < 0)) __PYX_ERR(1, 69, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + + /* "EnumType":70 + * __Pyx_globals['EMTPY'] = RegionType(EMTPY, 'EMTPY') + * __Pyx_globals['SPECIAL'] = RegionType(SPECIAL, 'SPECIAL') + * __Pyx_globals['RECTANGEL'] = RegionType(RECTANGEL, 'RECTANGEL') # <<<<<<<<<<<<<< + * __Pyx_globals['POLYGON'] = RegionType(POLYGON, 'POLYGON') + * __Pyx_globals['MASK'] = RegionType(MASK, 'MASK') + */ + __Pyx_GetModuleGlobalName(__pyx_t_6, __pyx_n_s_RegionType); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 70, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_1 = __Pyx_PyInt_From_enum____pyx_t_6region_RegionType(__pyx_e_6region_RECTANGEL); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 70, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_7 = PyTuple_New(2); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 70, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_1); + __Pyx_INCREF(__pyx_n_s_RECTANGEL); + __Pyx_GIVEREF(__pyx_n_s_RECTANGEL); + PyTuple_SET_ITEM(__pyx_t_7, 1, __pyx_n_s_RECTANGEL); + __pyx_t_1 = 0; + __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_7, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 70, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + if (unlikely(__Pyx_globals == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(1, 70, __pyx_L1_error) + } + if (unlikely(PyDict_SetItem(__Pyx_globals, __pyx_n_s_RECTANGEL, __pyx_t_1) < 0)) __PYX_ERR(1, 70, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "EnumType":71 + * __Pyx_globals['SPECIAL'] = RegionType(SPECIAL, 'SPECIAL') + * __Pyx_globals['RECTANGEL'] = RegionType(RECTANGEL, 'RECTANGEL') + * __Pyx_globals['POLYGON'] = RegionType(POLYGON, 'POLYGON') # <<<<<<<<<<<<<< + * __Pyx_globals['MASK'] = RegionType(MASK, 'MASK') + * + */ + __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_RegionType); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 71, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_7 = __Pyx_PyInt_From_enum____pyx_t_6region_RegionType(__pyx_e_6region_POLYGON); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 71, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_6 = PyTuple_New(2); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 71, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_GIVEREF(__pyx_t_7); + PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_7); + __Pyx_INCREF(__pyx_n_s_POLYGON); + __Pyx_GIVEREF(__pyx_n_s_POLYGON); + PyTuple_SET_ITEM(__pyx_t_6, 1, __pyx_n_s_POLYGON); + __pyx_t_7 = 0; + __pyx_t_7 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_6, NULL); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 71, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + if (unlikely(__Pyx_globals == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(1, 71, __pyx_L1_error) + } + if (unlikely(PyDict_SetItem(__Pyx_globals, __pyx_n_s_POLYGON, __pyx_t_7) < 0)) __PYX_ERR(1, 71, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + + /* "EnumType":72 + * __Pyx_globals['RECTANGEL'] = RegionType(RECTANGEL, 'RECTANGEL') + * __Pyx_globals['POLYGON'] = RegionType(POLYGON, 'POLYGON') + * __Pyx_globals['MASK'] = RegionType(MASK, 'MASK') # <<<<<<<<<<<<<< + * + */ + __Pyx_GetModuleGlobalName(__pyx_t_7, __pyx_n_s_RegionType); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 72, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_6 = __Pyx_PyInt_From_enum____pyx_t_6region_RegionType(__pyx_e_6region_MASK); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 72, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_1 = PyTuple_New(2); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 72, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __Pyx_GIVEREF(__pyx_t_6); + PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_t_6); + __Pyx_INCREF(__pyx_n_s_MASK); + __Pyx_GIVEREF(__pyx_n_s_MASK); + PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_n_s_MASK); + __pyx_t_6 = 0; + __pyx_t_6 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_1, NULL); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 72, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + if (unlikely(__Pyx_globals == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(1, 72, __pyx_L1_error) + } + if (unlikely(PyDict_SetItem(__Pyx_globals, __pyx_n_s_MASK, __pyx_t_6) < 0)) __PYX_ERR(1, 72, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + } + __pyx_L4:; + + /*--- Wrapped vars code ---*/ + + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + if (__pyx_m) { + if (__pyx_d) { + __Pyx_AddTraceback("init region", __pyx_clineno, __pyx_lineno, __pyx_filename); + } + Py_CLEAR(__pyx_m); + } else if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ImportError, "init region"); + } + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + #if CYTHON_PEP489_MULTI_PHASE_INIT + return (__pyx_m != NULL) ? 0 : -1; + #elif PY_MAJOR_VERSION >= 3 + return __pyx_m; + #else + return; + #endif +} + +/* --- Runtime support code --- */ +/* Refnanny */ +#if CYTHON_REFNANNY +static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname) { + PyObject *m = NULL, *p = NULL; + void *r = NULL; + m = PyImport_ImportModule(modname); + if (!m) goto end; + p = PyObject_GetAttrString(m, "RefNannyAPI"); + if (!p) goto end; + r = PyLong_AsVoidPtr(p); +end: + Py_XDECREF(p); + Py_XDECREF(m); + return (__Pyx_RefNannyAPIStruct *)r; +} +#endif + +/* PyObjectGetAttrStr */ +#if CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name) { + PyTypeObject* tp = Py_TYPE(obj); + if (likely(tp->tp_getattro)) + return tp->tp_getattro(obj, attr_name); +#if PY_MAJOR_VERSION < 3 + if (likely(tp->tp_getattr)) + return tp->tp_getattr(obj, PyString_AS_STRING(attr_name)); +#endif + return PyObject_GetAttr(obj, attr_name); +} +#endif + +/* GetBuiltinName */ +static PyObject *__Pyx_GetBuiltinName(PyObject *name) { + PyObject* result = __Pyx_PyObject_GetAttrStr(__pyx_b, name); + if (unlikely(!result)) { + PyErr_Format(PyExc_NameError, +#if PY_MAJOR_VERSION >= 3 + "name '%U' is not defined", name); +#else + "name '%.200s' is not defined", PyString_AS_STRING(name)); +#endif + } + return result; +} + +/* RaiseArgTupleInvalid */ +static void __Pyx_RaiseArgtupleInvalid( + const char* func_name, + int exact, + Py_ssize_t num_min, + Py_ssize_t num_max, + Py_ssize_t num_found) +{ + Py_ssize_t num_expected; + const char *more_or_less; + if (num_found < num_min) { + num_expected = num_min; + more_or_less = "at least"; + } else { + num_expected = num_max; + more_or_less = "at most"; + } + if (exact) { + more_or_less = "exactly"; + } + PyErr_Format(PyExc_TypeError, + "%.200s() takes %.8s %" CYTHON_FORMAT_SSIZE_T "d positional argument%.1s (%" CYTHON_FORMAT_SSIZE_T "d given)", + func_name, more_or_less, num_expected, + (num_expected == 1) ? "" : "s", num_found); +} + +/* KeywordStringCheck */ +static int __Pyx_CheckKeywordStrings( + PyObject *kwdict, + const char* function_name, + int kw_allowed) +{ + PyObject* key = 0; + Py_ssize_t pos = 0; +#if CYTHON_COMPILING_IN_PYPY + if (!kw_allowed && PyDict_Next(kwdict, &pos, &key, 0)) + goto invalid_keyword; + return 1; +#else + while (PyDict_Next(kwdict, &pos, &key, 0)) { + #if PY_MAJOR_VERSION < 3 + if (unlikely(!PyString_Check(key))) + #endif + if (unlikely(!PyUnicode_Check(key))) + goto invalid_keyword_type; + } + if ((!kw_allowed) && unlikely(key)) + goto invalid_keyword; + return 1; +invalid_keyword_type: + PyErr_Format(PyExc_TypeError, + "%.200s() keywords must be strings", function_name); + return 0; +#endif +invalid_keyword: + PyErr_Format(PyExc_TypeError, + #if PY_MAJOR_VERSION < 3 + "%.200s() got an unexpected keyword argument '%.200s'", + function_name, PyString_AsString(key)); + #else + "%s() got an unexpected keyword argument '%U'", + function_name, key); + #endif + return 0; +} + +/* RaiseDoubleKeywords */ +static void __Pyx_RaiseDoubleKeywordsError( + const char* func_name, + PyObject* kw_name) +{ + PyErr_Format(PyExc_TypeError, + #if PY_MAJOR_VERSION >= 3 + "%s() got multiple values for keyword argument '%U'", func_name, kw_name); + #else + "%s() got multiple values for keyword argument '%s'", func_name, + PyString_AsString(kw_name)); + #endif +} + +/* ParseKeywords */ +static int __Pyx_ParseOptionalKeywords( + PyObject *kwds, + PyObject **argnames[], + PyObject *kwds2, + PyObject *values[], + Py_ssize_t num_pos_args, + const char* function_name) +{ + PyObject *key = 0, *value = 0; + Py_ssize_t pos = 0; + PyObject*** name; + PyObject*** first_kw_arg = argnames + num_pos_args; + while (PyDict_Next(kwds, &pos, &key, &value)) { + name = first_kw_arg; + while (*name && (**name != key)) name++; + if (*name) { + values[name-argnames] = value; + continue; + } + name = first_kw_arg; + #if PY_MAJOR_VERSION < 3 + if (likely(PyString_Check(key))) { + while (*name) { + if ((CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**name) == PyString_GET_SIZE(key)) + && _PyString_Eq(**name, key)) { + values[name-argnames] = value; + break; + } + name++; + } + if (*name) continue; + else { + PyObject*** argname = argnames; + while (argname != first_kw_arg) { + if ((**argname == key) || ( + (CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**argname) == PyString_GET_SIZE(key)) + && _PyString_Eq(**argname, key))) { + goto arg_passed_twice; + } + argname++; + } + } + } else + #endif + if (likely(PyUnicode_Check(key))) { + while (*name) { + int cmp = (**name == key) ? 0 : + #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 + (__Pyx_PyUnicode_GET_LENGTH(**name) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : + #endif + PyUnicode_Compare(**name, key); + if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; + if (cmp == 0) { + values[name-argnames] = value; + break; + } + name++; + } + if (*name) continue; + else { + PyObject*** argname = argnames; + while (argname != first_kw_arg) { + int cmp = (**argname == key) ? 0 : + #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 + (__Pyx_PyUnicode_GET_LENGTH(**argname) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : + #endif + PyUnicode_Compare(**argname, key); + if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; + if (cmp == 0) goto arg_passed_twice; + argname++; + } + } + } else + goto invalid_keyword_type; + if (kwds2) { + if (unlikely(PyDict_SetItem(kwds2, key, value))) goto bad; + } else { + goto invalid_keyword; + } + } + return 0; +arg_passed_twice: + __Pyx_RaiseDoubleKeywordsError(function_name, key); + goto bad; +invalid_keyword_type: + PyErr_Format(PyExc_TypeError, + "%.200s() keywords must be strings", function_name); + goto bad; +invalid_keyword: + PyErr_Format(PyExc_TypeError, + #if PY_MAJOR_VERSION < 3 + "%.200s() got an unexpected keyword argument '%.200s'", + function_name, PyString_AsString(key)); + #else + "%s() got an unexpected keyword argument '%U'", + function_name, key); + #endif +bad: + return -1; +} + +/* PyFunctionFastCall */ +#if CYTHON_FAST_PYCALL +static PyObject* __Pyx_PyFunction_FastCallNoKw(PyCodeObject *co, PyObject **args, Py_ssize_t na, + PyObject *globals) { + PyFrameObject *f; + PyThreadState *tstate = __Pyx_PyThreadState_Current; + PyObject **fastlocals; + Py_ssize_t i; + PyObject *result; + assert(globals != NULL); + /* XXX Perhaps we should create a specialized + PyFrame_New() that doesn't take locals, but does + take builtins without sanity checking them. + */ + assert(tstate != NULL); + f = PyFrame_New(tstate, co, globals, NULL); + if (f == NULL) { + return NULL; + } + fastlocals = __Pyx_PyFrame_GetLocalsplus(f); + for (i = 0; i < na; i++) { + Py_INCREF(*args); + fastlocals[i] = *args++; + } + result = PyEval_EvalFrameEx(f,0); + ++tstate->recursion_depth; + Py_DECREF(f); + --tstate->recursion_depth; + return result; +} +#if 1 || PY_VERSION_HEX < 0x030600B1 +static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, PyObject *kwargs) { + PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); + PyObject *globals = PyFunction_GET_GLOBALS(func); + PyObject *argdefs = PyFunction_GET_DEFAULTS(func); + PyObject *closure; +#if PY_MAJOR_VERSION >= 3 + PyObject *kwdefs; +#endif + PyObject *kwtuple, **k; + PyObject **d; + Py_ssize_t nd; + Py_ssize_t nk; + PyObject *result; + assert(kwargs == NULL || PyDict_Check(kwargs)); + nk = kwargs ? PyDict_Size(kwargs) : 0; + if (Py_EnterRecursiveCall((char*)" while calling a Python object")) { + return NULL; + } + if ( +#if PY_MAJOR_VERSION >= 3 + co->co_kwonlyargcount == 0 && +#endif + likely(kwargs == NULL || nk == 0) && + co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) { + if (argdefs == NULL && co->co_argcount == nargs) { + result = __Pyx_PyFunction_FastCallNoKw(co, args, nargs, globals); + goto done; + } + else if (nargs == 0 && argdefs != NULL + && co->co_argcount == Py_SIZE(argdefs)) { + /* function called with no arguments, but all parameters have + a default value: use default values as arguments .*/ + args = &PyTuple_GET_ITEM(argdefs, 0); + result =__Pyx_PyFunction_FastCallNoKw(co, args, Py_SIZE(argdefs), globals); + goto done; + } + } + if (kwargs != NULL) { + Py_ssize_t pos, i; + kwtuple = PyTuple_New(2 * nk); + if (kwtuple == NULL) { + result = NULL; + goto done; + } + k = &PyTuple_GET_ITEM(kwtuple, 0); + pos = i = 0; + while (PyDict_Next(kwargs, &pos, &k[i], &k[i+1])) { + Py_INCREF(k[i]); + Py_INCREF(k[i+1]); + i += 2; + } + nk = i / 2; + } + else { + kwtuple = NULL; + k = NULL; + } + closure = PyFunction_GET_CLOSURE(func); +#if PY_MAJOR_VERSION >= 3 + kwdefs = PyFunction_GET_KW_DEFAULTS(func); +#endif + if (argdefs != NULL) { + d = &PyTuple_GET_ITEM(argdefs, 0); + nd = Py_SIZE(argdefs); + } + else { + d = NULL; + nd = 0; + } +#if PY_MAJOR_VERSION >= 3 + result = PyEval_EvalCodeEx((PyObject*)co, globals, (PyObject *)NULL, + args, (int)nargs, + k, (int)nk, + d, (int)nd, kwdefs, closure); +#else + result = PyEval_EvalCodeEx(co, globals, (PyObject *)NULL, + args, (int)nargs, + k, (int)nk, + d, (int)nd, closure); +#endif + Py_XDECREF(kwtuple); +done: + Py_LeaveRecursiveCall(); + return result; +} +#endif +#endif + +/* PyCFunctionFastCall */ +#if CYTHON_FAST_PYCCALL +static CYTHON_INLINE PyObject * __Pyx_PyCFunction_FastCall(PyObject *func_obj, PyObject **args, Py_ssize_t nargs) { + PyCFunctionObject *func = (PyCFunctionObject*)func_obj; + PyCFunction meth = PyCFunction_GET_FUNCTION(func); + PyObject *self = PyCFunction_GET_SELF(func); + int flags = PyCFunction_GET_FLAGS(func); + assert(PyCFunction_Check(func)); + assert(METH_FASTCALL == (flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST | METH_KEYWORDS | METH_STACKLESS))); + assert(nargs >= 0); + assert(nargs == 0 || args != NULL); + /* _PyCFunction_FastCallDict() must not be called with an exception set, + because it may clear it (directly or indirectly) and so the + caller loses its exception */ + assert(!PyErr_Occurred()); + if ((PY_VERSION_HEX < 0x030700A0) || unlikely(flags & METH_KEYWORDS)) { + return (*((__Pyx_PyCFunctionFastWithKeywords)(void*)meth)) (self, args, nargs, NULL); + } else { + return (*((__Pyx_PyCFunctionFast)(void*)meth)) (self, args, nargs); + } +} +#endif + +/* PyObjectCall */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { + PyObject *result; + ternaryfunc call = Py_TYPE(func)->tp_call; + if (unlikely(!call)) + return PyObject_Call(func, arg, kw); + if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) + return NULL; + result = (*call)(func, arg, kw); + Py_LeaveRecursiveCall(); + if (unlikely(!result) && unlikely(!PyErr_Occurred())) { + PyErr_SetString( + PyExc_SystemError, + "NULL result without error in PyObject_Call"); + } + return result; +} +#endif + +/* PyErrFetchRestore */ +#if CYTHON_FAST_THREAD_STATE +static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) { + PyObject *tmp_type, *tmp_value, *tmp_tb; + tmp_type = tstate->curexc_type; + tmp_value = tstate->curexc_value; + tmp_tb = tstate->curexc_traceback; + tstate->curexc_type = type; + tstate->curexc_value = value; + tstate->curexc_traceback = tb; + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); +} +static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { + *type = tstate->curexc_type; + *value = tstate->curexc_value; + *tb = tstate->curexc_traceback; + tstate->curexc_type = 0; + tstate->curexc_value = 0; + tstate->curexc_traceback = 0; +} +#endif + +/* RaiseException */ +#if PY_MAJOR_VERSION < 3 +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, + CYTHON_UNUSED PyObject *cause) { + __Pyx_PyThreadState_declare + Py_XINCREF(type); + if (!value || value == Py_None) + value = NULL; + else + Py_INCREF(value); + if (!tb || tb == Py_None) + tb = NULL; + else { + Py_INCREF(tb); + if (!PyTraceBack_Check(tb)) { + PyErr_SetString(PyExc_TypeError, + "raise: arg 3 must be a traceback or None"); + goto raise_error; + } + } + if (PyType_Check(type)) { +#if CYTHON_COMPILING_IN_PYPY + if (!value) { + Py_INCREF(Py_None); + value = Py_None; + } +#endif + PyErr_NormalizeException(&type, &value, &tb); + } else { + if (value) { + PyErr_SetString(PyExc_TypeError, + "instance exception may not have a separate value"); + goto raise_error; + } + value = type; + type = (PyObject*) Py_TYPE(type); + Py_INCREF(type); + if (!PyType_IsSubtype((PyTypeObject *)type, (PyTypeObject *)PyExc_BaseException)) { + PyErr_SetString(PyExc_TypeError, + "raise: exception class must be a subclass of BaseException"); + goto raise_error; + } + } + __Pyx_PyThreadState_assign + __Pyx_ErrRestore(type, value, tb); + return; +raise_error: + Py_XDECREF(value); + Py_XDECREF(type); + Py_XDECREF(tb); + return; +} +#else +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause) { + PyObject* owned_instance = NULL; + if (tb == Py_None) { + tb = 0; + } else if (tb && !PyTraceBack_Check(tb)) { + PyErr_SetString(PyExc_TypeError, + "raise: arg 3 must be a traceback or None"); + goto bad; + } + if (value == Py_None) + value = 0; + if (PyExceptionInstance_Check(type)) { + if (value) { + PyErr_SetString(PyExc_TypeError, + "instance exception may not have a separate value"); + goto bad; + } + value = type; + type = (PyObject*) Py_TYPE(value); + } else if (PyExceptionClass_Check(type)) { + PyObject *instance_class = NULL; + if (value && PyExceptionInstance_Check(value)) { + instance_class = (PyObject*) Py_TYPE(value); + if (instance_class != type) { + int is_subclass = PyObject_IsSubclass(instance_class, type); + if (!is_subclass) { + instance_class = NULL; + } else if (unlikely(is_subclass == -1)) { + goto bad; + } else { + type = instance_class; + } + } + } + if (!instance_class) { + PyObject *args; + if (!value) + args = PyTuple_New(0); + else if (PyTuple_Check(value)) { + Py_INCREF(value); + args = value; + } else + args = PyTuple_Pack(1, value); + if (!args) + goto bad; + owned_instance = PyObject_Call(type, args, NULL); + Py_DECREF(args); + if (!owned_instance) + goto bad; + value = owned_instance; + if (!PyExceptionInstance_Check(value)) { + PyErr_Format(PyExc_TypeError, + "calling %R should have returned an instance of " + "BaseException, not %R", + type, Py_TYPE(value)); + goto bad; + } + } + } else { + PyErr_SetString(PyExc_TypeError, + "raise: exception class must be a subclass of BaseException"); + goto bad; + } + if (cause) { + PyObject *fixed_cause; + if (cause == Py_None) { + fixed_cause = NULL; + } else if (PyExceptionClass_Check(cause)) { + fixed_cause = PyObject_CallObject(cause, NULL); + if (fixed_cause == NULL) + goto bad; + } else if (PyExceptionInstance_Check(cause)) { + fixed_cause = cause; + Py_INCREF(fixed_cause); + } else { + PyErr_SetString(PyExc_TypeError, + "exception causes must derive from " + "BaseException"); + goto bad; + } + PyException_SetCause(value, fixed_cause); + } + PyErr_SetObject(type, value); + if (tb) { +#if CYTHON_FAST_THREAD_STATE + PyThreadState *tstate = __Pyx_PyThreadState_Current; + PyObject* tmp_tb = tstate->curexc_traceback; + if (tb != tmp_tb) { + Py_INCREF(tb); + tstate->curexc_traceback = tb; + Py_XDECREF(tmp_tb); + } +#else + PyObject *tmp_type, *tmp_value, *tmp_tb; + PyErr_Fetch(&tmp_type, &tmp_value, &tmp_tb); + Py_INCREF(tb); + PyErr_Restore(tmp_type, tmp_value, tb); + Py_XDECREF(tmp_tb); +#endif + } +bad: + Py_XDECREF(owned_instance); + return; +} +#endif + +/* PyObjectCallMethO */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg) { + PyObject *self, *result; + PyCFunction cfunc; + cfunc = PyCFunction_GET_FUNCTION(func); + self = PyCFunction_GET_SELF(func); + if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) + return NULL; + result = cfunc(self, arg); + Py_LeaveRecursiveCall(); + if (unlikely(!result) && unlikely(!PyErr_Occurred())) { + PyErr_SetString( + PyExc_SystemError, + "NULL result without error in PyObject_Call"); + } + return result; +} +#endif + +/* PyObjectCallOneArg */ +#if CYTHON_COMPILING_IN_CPYTHON +static PyObject* __Pyx__PyObject_CallOneArg(PyObject *func, PyObject *arg) { + PyObject *result; + PyObject *args = PyTuple_New(1); + if (unlikely(!args)) return NULL; + Py_INCREF(arg); + PyTuple_SET_ITEM(args, 0, arg); + result = __Pyx_PyObject_Call(func, args, NULL); + Py_DECREF(args); + return result; +} +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) { +#if CYTHON_FAST_PYCALL + if (PyFunction_Check(func)) { + return __Pyx_PyFunction_FastCall(func, &arg, 1); + } +#endif + if (likely(PyCFunction_Check(func))) { + if (likely(PyCFunction_GET_FLAGS(func) & METH_O)) { + return __Pyx_PyObject_CallMethO(func, arg); +#if CYTHON_FAST_PYCCALL + } else if (__Pyx_PyFastCFunction_Check(func)) { + return __Pyx_PyCFunction_FastCall(func, &arg, 1); +#endif + } + } + return __Pyx__PyObject_CallOneArg(func, arg); +} +#else +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) { + PyObject *result; + PyObject *args = PyTuple_Pack(1, arg); + if (unlikely(!args)) return NULL; + result = __Pyx_PyObject_Call(func, args, NULL); + Py_DECREF(args); + return result; +} +#endif + +/* GetItemInt */ +static PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j) { + PyObject *r; + if (!j) return NULL; + r = PyObject_GetItem(o, j); + Py_DECREF(j); + return r; +} +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i, + CYTHON_NCP_UNUSED int wraparound, + CYTHON_NCP_UNUSED int boundscheck) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + Py_ssize_t wrapped_i = i; + if (wraparound & unlikely(i < 0)) { + wrapped_i += PyList_GET_SIZE(o); + } + if ((!boundscheck) || likely(__Pyx_is_valid_index(wrapped_i, PyList_GET_SIZE(o)))) { + PyObject *r = PyList_GET_ITEM(o, wrapped_i); + Py_INCREF(r); + return r; + } + return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); +#else + return PySequence_GetItem(o, i); +#endif +} +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i, + CYTHON_NCP_UNUSED int wraparound, + CYTHON_NCP_UNUSED int boundscheck) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + Py_ssize_t wrapped_i = i; + if (wraparound & unlikely(i < 0)) { + wrapped_i += PyTuple_GET_SIZE(o); + } + if ((!boundscheck) || likely(__Pyx_is_valid_index(wrapped_i, PyTuple_GET_SIZE(o)))) { + PyObject *r = PyTuple_GET_ITEM(o, wrapped_i); + Py_INCREF(r); + return r; + } + return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); +#else + return PySequence_GetItem(o, i); +#endif +} +static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, int is_list, + CYTHON_NCP_UNUSED int wraparound, + CYTHON_NCP_UNUSED int boundscheck) { +#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS && CYTHON_USE_TYPE_SLOTS + if (is_list || PyList_CheckExact(o)) { + Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyList_GET_SIZE(o); + if ((!boundscheck) || (likely(__Pyx_is_valid_index(n, PyList_GET_SIZE(o))))) { + PyObject *r = PyList_GET_ITEM(o, n); + Py_INCREF(r); + return r; + } + } + else if (PyTuple_CheckExact(o)) { + Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyTuple_GET_SIZE(o); + if ((!boundscheck) || likely(__Pyx_is_valid_index(n, PyTuple_GET_SIZE(o)))) { + PyObject *r = PyTuple_GET_ITEM(o, n); + Py_INCREF(r); + return r; + } + } else { + PySequenceMethods *m = Py_TYPE(o)->tp_as_sequence; + if (likely(m && m->sq_item)) { + if (wraparound && unlikely(i < 0) && likely(m->sq_length)) { + Py_ssize_t l = m->sq_length(o); + if (likely(l >= 0)) { + i += l; + } else { + if (!PyErr_ExceptionMatches(PyExc_OverflowError)) + return NULL; + PyErr_Clear(); + } + } + return m->sq_item(o, i); + } + } +#else + if (is_list || PySequence_Check(o)) { + return PySequence_GetItem(o, i); + } +#endif + return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); +} + +/* ObjectGetItem */ +#if CYTHON_USE_TYPE_SLOTS +static PyObject *__Pyx_PyObject_GetIndex(PyObject *obj, PyObject* index) { + PyObject *runerr = NULL; + Py_ssize_t key_value; + PySequenceMethods *m = Py_TYPE(obj)->tp_as_sequence; + if (unlikely(!(m && m->sq_item))) { + PyErr_Format(PyExc_TypeError, "'%.200s' object is not subscriptable", Py_TYPE(obj)->tp_name); + return NULL; + } + key_value = __Pyx_PyIndex_AsSsize_t(index); + if (likely(key_value != -1 || !(runerr = PyErr_Occurred()))) { + return __Pyx_GetItemInt_Fast(obj, key_value, 0, 1, 1); + } + if (PyErr_GivenExceptionMatches(runerr, PyExc_OverflowError)) { + PyErr_Clear(); + PyErr_Format(PyExc_IndexError, "cannot fit '%.200s' into an index-sized integer", Py_TYPE(index)->tp_name); + } + return NULL; +} +static PyObject *__Pyx_PyObject_GetItem(PyObject *obj, PyObject* key) { + PyMappingMethods *m = Py_TYPE(obj)->tp_as_mapping; + if (likely(m && m->mp_subscript)) { + return m->mp_subscript(obj, key); + } + return __Pyx_PyObject_GetIndex(obj, key); +} +#endif + +/* PyObjectSetAttrStr */ +#if CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE int __Pyx_PyObject_SetAttrStr(PyObject* obj, PyObject* attr_name, PyObject* value) { + PyTypeObject* tp = Py_TYPE(obj); + if (likely(tp->tp_setattro)) + return tp->tp_setattro(obj, attr_name, value); +#if PY_MAJOR_VERSION < 3 + if (likely(tp->tp_setattr)) + return tp->tp_setattr(obj, PyString_AS_STRING(attr_name), value); +#endif + return PyObject_SetAttr(obj, attr_name, value); +} +#endif + +/* pyobject_as_double */ +static double __Pyx__PyObject_AsDouble(PyObject* obj) { + PyObject* float_value; +#if !CYTHON_USE_TYPE_SLOTS + float_value = PyNumber_Float(obj); if ((0)) goto bad; +#else + PyNumberMethods *nb = Py_TYPE(obj)->tp_as_number; + if (likely(nb) && likely(nb->nb_float)) { + float_value = nb->nb_float(obj); + if (likely(float_value) && unlikely(!PyFloat_Check(float_value))) { + PyErr_Format(PyExc_TypeError, + "__float__ returned non-float (type %.200s)", + Py_TYPE(float_value)->tp_name); + Py_DECREF(float_value); + goto bad; + } + } else if (PyUnicode_CheckExact(obj) || PyBytes_CheckExact(obj)) { +#if PY_MAJOR_VERSION >= 3 + float_value = PyFloat_FromString(obj); +#else + float_value = PyFloat_FromString(obj, 0); +#endif + } else { + PyObject* args = PyTuple_New(1); + if (unlikely(!args)) goto bad; + PyTuple_SET_ITEM(args, 0, obj); + float_value = PyObject_Call((PyObject*)&PyFloat_Type, args, 0); + PyTuple_SET_ITEM(args, 0, 0); + Py_DECREF(args); + } +#endif + if (likely(float_value)) { + double value = PyFloat_AS_DOUBLE(float_value); + Py_DECREF(float_value); + return value; + } +bad: + return (double)-1; +} + +/* PyObjectCallNoArg */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func) { +#if CYTHON_FAST_PYCALL + if (PyFunction_Check(func)) { + return __Pyx_PyFunction_FastCall(func, NULL, 0); + } +#endif +#if defined(__Pyx_CyFunction_USED) && defined(NDEBUG) + if (likely(PyCFunction_Check(func) || __Pyx_CyFunction_Check(func))) +#else + if (likely(PyCFunction_Check(func))) +#endif + { + if (likely(PyCFunction_GET_FLAGS(func) & METH_NOARGS)) { + return __Pyx_PyObject_CallMethO(func, NULL); + } + } + return __Pyx_PyObject_Call(func, __pyx_empty_tuple, NULL); +} +#endif + +/* decode_c_string */ +static CYTHON_INLINE PyObject* __Pyx_decode_c_string( + const char* cstring, Py_ssize_t start, Py_ssize_t stop, + const char* encoding, const char* errors, + PyObject* (*decode_func)(const char *s, Py_ssize_t size, const char *errors)) { + Py_ssize_t length; + if (unlikely((start < 0) | (stop < 0))) { + size_t slen = strlen(cstring); + if (unlikely(slen > (size_t) PY_SSIZE_T_MAX)) { + PyErr_SetString(PyExc_OverflowError, + "c-string too long to convert to Python"); + return NULL; + } + length = (Py_ssize_t) slen; + if (start < 0) { + start += length; + if (start < 0) + start = 0; + } + if (stop < 0) + stop += length; + } + if (unlikely(stop <= start)) + return __Pyx_NewRef(__pyx_empty_unicode); + length = stop - start; + cstring += start; + if (decode_func) { + return decode_func(cstring, length, errors); + } else { + return PyUnicode_Decode(cstring, length, encoding, errors); + } +} + +/* GetException */ +#if CYTHON_FAST_THREAD_STATE +static int __Pyx__GetException(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) +#else +static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb) +#endif +{ + PyObject *local_type, *local_value, *local_tb; +#if CYTHON_FAST_THREAD_STATE + PyObject *tmp_type, *tmp_value, *tmp_tb; + local_type = tstate->curexc_type; + local_value = tstate->curexc_value; + local_tb = tstate->curexc_traceback; + tstate->curexc_type = 0; + tstate->curexc_value = 0; + tstate->curexc_traceback = 0; +#else + PyErr_Fetch(&local_type, &local_value, &local_tb); +#endif + PyErr_NormalizeException(&local_type, &local_value, &local_tb); +#if CYTHON_FAST_THREAD_STATE + if (unlikely(tstate->curexc_type)) +#else + if (unlikely(PyErr_Occurred())) +#endif + goto bad; + #if PY_MAJOR_VERSION >= 3 + if (local_tb) { + if (unlikely(PyException_SetTraceback(local_value, local_tb) < 0)) + goto bad; + } + #endif + Py_XINCREF(local_tb); + Py_XINCREF(local_type); + Py_XINCREF(local_value); + *type = local_type; + *value = local_value; + *tb = local_tb; +#if CYTHON_FAST_THREAD_STATE + #if CYTHON_USE_EXC_INFO_STACK + { + _PyErr_StackItem *exc_info = tstate->exc_info; + tmp_type = exc_info->exc_type; + tmp_value = exc_info->exc_value; + tmp_tb = exc_info->exc_traceback; + exc_info->exc_type = local_type; + exc_info->exc_value = local_value; + exc_info->exc_traceback = local_tb; + } + #else + tmp_type = tstate->exc_type; + tmp_value = tstate->exc_value; + tmp_tb = tstate->exc_traceback; + tstate->exc_type = local_type; + tstate->exc_value = local_value; + tstate->exc_traceback = local_tb; + #endif + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); +#else + PyErr_SetExcInfo(local_type, local_value, local_tb); +#endif + return 0; +bad: + *type = 0; + *value = 0; + *tb = 0; + Py_XDECREF(local_type); + Py_XDECREF(local_value); + Py_XDECREF(local_tb); + return -1; +} + +/* SwapException */ +#if CYTHON_FAST_THREAD_STATE +static CYTHON_INLINE void __Pyx__ExceptionSwap(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { + PyObject *tmp_type, *tmp_value, *tmp_tb; + #if CYTHON_USE_EXC_INFO_STACK + _PyErr_StackItem *exc_info = tstate->exc_info; + tmp_type = exc_info->exc_type; + tmp_value = exc_info->exc_value; + tmp_tb = exc_info->exc_traceback; + exc_info->exc_type = *type; + exc_info->exc_value = *value; + exc_info->exc_traceback = *tb; + #else + tmp_type = tstate->exc_type; + tmp_value = tstate->exc_value; + tmp_tb = tstate->exc_traceback; + tstate->exc_type = *type; + tstate->exc_value = *value; + tstate->exc_traceback = *tb; + #endif + *type = tmp_type; + *value = tmp_value; + *tb = tmp_tb; +} +#else +static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value, PyObject **tb) { + PyObject *tmp_type, *tmp_value, *tmp_tb; + PyErr_GetExcInfo(&tmp_type, &tmp_value, &tmp_tb); + PyErr_SetExcInfo(*type, *value, *tb); + *type = tmp_type; + *value = tmp_value; + *tb = tmp_tb; +} +#endif + +/* GetTopmostException */ +#if CYTHON_USE_EXC_INFO_STACK +static _PyErr_StackItem * +__Pyx_PyErr_GetTopmostException(PyThreadState *tstate) +{ + _PyErr_StackItem *exc_info = tstate->exc_info; + while ((exc_info->exc_type == NULL || exc_info->exc_type == Py_None) && + exc_info->previous_item != NULL) + { + exc_info = exc_info->previous_item; + } + return exc_info; +} +#endif + +/* SaveResetException */ +#if CYTHON_FAST_THREAD_STATE +static CYTHON_INLINE void __Pyx__ExceptionSave(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { + #if CYTHON_USE_EXC_INFO_STACK + _PyErr_StackItem *exc_info = __Pyx_PyErr_GetTopmostException(tstate); + *type = exc_info->exc_type; + *value = exc_info->exc_value; + *tb = exc_info->exc_traceback; + #else + *type = tstate->exc_type; + *value = tstate->exc_value; + *tb = tstate->exc_traceback; + #endif + Py_XINCREF(*type); + Py_XINCREF(*value); + Py_XINCREF(*tb); +} +static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) { + PyObject *tmp_type, *tmp_value, *tmp_tb; + #if CYTHON_USE_EXC_INFO_STACK + _PyErr_StackItem *exc_info = tstate->exc_info; + tmp_type = exc_info->exc_type; + tmp_value = exc_info->exc_value; + tmp_tb = exc_info->exc_traceback; + exc_info->exc_type = type; + exc_info->exc_value = value; + exc_info->exc_traceback = tb; + #else + tmp_type = tstate->exc_type; + tmp_value = tstate->exc_value; + tmp_tb = tstate->exc_traceback; + tstate->exc_type = type; + tstate->exc_value = value; + tstate->exc_traceback = tb; + #endif + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); +} +#endif + +/* PyErrExceptionMatches */ +#if CYTHON_FAST_THREAD_STATE +static int __Pyx_PyErr_ExceptionMatchesTuple(PyObject *exc_type, PyObject *tuple) { + Py_ssize_t i, n; + n = PyTuple_GET_SIZE(tuple); +#if PY_MAJOR_VERSION >= 3 + for (i=0; icurexc_type; + if (exc_type == err) return 1; + if (unlikely(!exc_type)) return 0; + if (unlikely(PyTuple_Check(err))) + return __Pyx_PyErr_ExceptionMatchesTuple(exc_type, err); + return __Pyx_PyErr_GivenExceptionMatches(exc_type, err); +} +#endif + +/* GetAttr */ +static CYTHON_INLINE PyObject *__Pyx_GetAttr(PyObject *o, PyObject *n) { +#if CYTHON_USE_TYPE_SLOTS +#if PY_MAJOR_VERSION >= 3 + if (likely(PyUnicode_Check(n))) +#else + if (likely(PyString_Check(n))) +#endif + return __Pyx_PyObject_GetAttrStr(o, n); +#endif + return PyObject_GetAttr(o, n); +} + +/* GetAttr3 */ +static PyObject *__Pyx_GetAttr3Default(PyObject *d) { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + if (unlikely(!__Pyx_PyErr_ExceptionMatches(PyExc_AttributeError))) + return NULL; + __Pyx_PyErr_Clear(); + Py_INCREF(d); + return d; +} +static CYTHON_INLINE PyObject *__Pyx_GetAttr3(PyObject *o, PyObject *n, PyObject *d) { + PyObject *r = __Pyx_GetAttr(o, n); + return (likely(r)) ? r : __Pyx_GetAttr3Default(d); +} + +/* PyDictVersioning */ +#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PY_UINT64_T __Pyx_get_tp_dict_version(PyObject *obj) { + PyObject *dict = Py_TYPE(obj)->tp_dict; + return likely(dict) ? __PYX_GET_DICT_VERSION(dict) : 0; +} +static CYTHON_INLINE PY_UINT64_T __Pyx_get_object_dict_version(PyObject *obj) { + PyObject **dictptr = NULL; + Py_ssize_t offset = Py_TYPE(obj)->tp_dictoffset; + if (offset) { +#if CYTHON_COMPILING_IN_CPYTHON + dictptr = (likely(offset > 0)) ? (PyObject **) ((char *)obj + offset) : _PyObject_GetDictPtr(obj); +#else + dictptr = _PyObject_GetDictPtr(obj); +#endif + } + return (dictptr && *dictptr) ? __PYX_GET_DICT_VERSION(*dictptr) : 0; +} +static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UINT64_T tp_dict_version, PY_UINT64_T obj_dict_version) { + PyObject *dict = Py_TYPE(obj)->tp_dict; + if (unlikely(!dict) || unlikely(tp_dict_version != __PYX_GET_DICT_VERSION(dict))) + return 0; + return obj_dict_version == __Pyx_get_object_dict_version(obj); +} +#endif + +/* GetModuleGlobalName */ +#if CYTHON_USE_DICT_VERSIONS +static PyObject *__Pyx__GetModuleGlobalName(PyObject *name, PY_UINT64_T *dict_version, PyObject **dict_cached_value) +#else +static CYTHON_INLINE PyObject *__Pyx__GetModuleGlobalName(PyObject *name) +#endif +{ + PyObject *result; +#if !CYTHON_AVOID_BORROWED_REFS +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030500A1 + result = _PyDict_GetItem_KnownHash(__pyx_d, name, ((PyASCIIObject *) name)->hash); + __PYX_UPDATE_DICT_CACHE(__pyx_d, result, *dict_cached_value, *dict_version) + if (likely(result)) { + return __Pyx_NewRef(result); + } else if (unlikely(PyErr_Occurred())) { + return NULL; + } +#else + result = PyDict_GetItem(__pyx_d, name); + __PYX_UPDATE_DICT_CACHE(__pyx_d, result, *dict_cached_value, *dict_version) + if (likely(result)) { + return __Pyx_NewRef(result); + } +#endif +#else + result = PyObject_GetItem(__pyx_d, name); + __PYX_UPDATE_DICT_CACHE(__pyx_d, result, *dict_cached_value, *dict_version) + if (likely(result)) { + return __Pyx_NewRef(result); + } + PyErr_Clear(); +#endif + return __Pyx_GetBuiltinName(name); +} + +/* Import */ +static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level) { + PyObject *empty_list = 0; + PyObject *module = 0; + PyObject *global_dict = 0; + PyObject *empty_dict = 0; + PyObject *list; + #if PY_MAJOR_VERSION < 3 + PyObject *py_import; + py_import = __Pyx_PyObject_GetAttrStr(__pyx_b, __pyx_n_s_import); + if (!py_import) + goto bad; + #endif + if (from_list) + list = from_list; + else { + empty_list = PyList_New(0); + if (!empty_list) + goto bad; + list = empty_list; + } + global_dict = PyModule_GetDict(__pyx_m); + if (!global_dict) + goto bad; + empty_dict = PyDict_New(); + if (!empty_dict) + goto bad; + { + #if PY_MAJOR_VERSION >= 3 + if (level == -1) { + if ((1) && (strchr(__Pyx_MODULE_NAME, '.'))) { + module = PyImport_ImportModuleLevelObject( + name, global_dict, empty_dict, list, 1); + if (!module) { + if (!PyErr_ExceptionMatches(PyExc_ImportError)) + goto bad; + PyErr_Clear(); + } + } + level = 0; + } + #endif + if (!module) { + #if PY_MAJOR_VERSION < 3 + PyObject *py_level = PyInt_FromLong(level); + if (!py_level) + goto bad; + module = PyObject_CallFunctionObjArgs(py_import, + name, global_dict, empty_dict, list, py_level, (PyObject *)NULL); + Py_DECREF(py_level); + #else + module = PyImport_ImportModuleLevelObject( + name, global_dict, empty_dict, list, level); + #endif + } + } +bad: + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(py_import); + #endif + Py_XDECREF(empty_list); + Py_XDECREF(empty_dict); + return module; +} + +/* ImportFrom */ +static PyObject* __Pyx_ImportFrom(PyObject* module, PyObject* name) { + PyObject* value = __Pyx_PyObject_GetAttrStr(module, name); + if (unlikely(!value) && PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Format(PyExc_ImportError, + #if PY_MAJOR_VERSION < 3 + "cannot import name %.230s", PyString_AS_STRING(name)); + #else + "cannot import name %S", name); + #endif + } + return value; +} + +/* PyObjectCall2Args */ +static CYTHON_UNUSED PyObject* __Pyx_PyObject_Call2Args(PyObject* function, PyObject* arg1, PyObject* arg2) { + PyObject *args, *result = NULL; + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(function)) { + PyObject *args[2] = {arg1, arg2}; + return __Pyx_PyFunction_FastCall(function, args, 2); + } + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(function)) { + PyObject *args[2] = {arg1, arg2}; + return __Pyx_PyCFunction_FastCall(function, args, 2); + } + #endif + args = PyTuple_New(2); + if (unlikely(!args)) goto done; + Py_INCREF(arg1); + PyTuple_SET_ITEM(args, 0, arg1); + Py_INCREF(arg2); + PyTuple_SET_ITEM(args, 1, arg2); + Py_INCREF(function); + result = __Pyx_PyObject_Call(function, args, NULL); + Py_DECREF(args); + Py_DECREF(function); +done: + return result; +} + +/* HasAttr */ +static CYTHON_INLINE int __Pyx_HasAttr(PyObject *o, PyObject *n) { + PyObject *r; + if (unlikely(!__Pyx_PyBaseString_Check(n))) { + PyErr_SetString(PyExc_TypeError, + "hasattr(): attribute name must be string"); + return -1; + } + r = __Pyx_GetAttr(o, n); + if (unlikely(!r)) { + PyErr_Clear(); + return 0; + } else { + Py_DECREF(r); + return 1; + } +} + +/* PyObject_GenericGetAttrNoDict */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static PyObject *__Pyx_RaiseGenericGetAttributeError(PyTypeObject *tp, PyObject *attr_name) { + PyErr_Format(PyExc_AttributeError, +#if PY_MAJOR_VERSION >= 3 + "'%.50s' object has no attribute '%U'", + tp->tp_name, attr_name); +#else + "'%.50s' object has no attribute '%.400s'", + tp->tp_name, PyString_AS_STRING(attr_name)); +#endif + return NULL; +} +static CYTHON_INLINE PyObject* __Pyx_PyObject_GenericGetAttrNoDict(PyObject* obj, PyObject* attr_name) { + PyObject *descr; + PyTypeObject *tp = Py_TYPE(obj); + if (unlikely(!PyString_Check(attr_name))) { + return PyObject_GenericGetAttr(obj, attr_name); + } + assert(!tp->tp_dictoffset); + descr = _PyType_Lookup(tp, attr_name); + if (unlikely(!descr)) { + return __Pyx_RaiseGenericGetAttributeError(tp, attr_name); + } + Py_INCREF(descr); + #if PY_MAJOR_VERSION < 3 + if (likely(PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_HAVE_CLASS))) + #endif + { + descrgetfunc f = Py_TYPE(descr)->tp_descr_get; + if (unlikely(f)) { + PyObject *res = f(descr, obj, (PyObject *)tp); + Py_DECREF(descr); + return res; + } + } + return descr; +} +#endif + +/* PyObject_GenericGetAttr */ +#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 +static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_name) { + if (unlikely(Py_TYPE(obj)->tp_dictoffset)) { + return PyObject_GenericGetAttr(obj, attr_name); + } + return __Pyx_PyObject_GenericGetAttrNoDict(obj, attr_name); +} +#endif + +/* PyObjectGetAttrStrNoError */ +static void __Pyx_PyObject_GetAttrStr_ClearAttributeError(void) { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + if (likely(__Pyx_PyErr_ExceptionMatches(PyExc_AttributeError))) + __Pyx_PyErr_Clear(); +} +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name) { + PyObject *result; +#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_TYPE_SLOTS && PY_VERSION_HEX >= 0x030700B1 + PyTypeObject* tp = Py_TYPE(obj); + if (likely(tp->tp_getattro == PyObject_GenericGetAttr)) { + return _PyObject_GenericGetAttrWithDict(obj, attr_name, NULL, 1); + } +#endif + result = __Pyx_PyObject_GetAttrStr(obj, attr_name); + if (unlikely(!result)) { + __Pyx_PyObject_GetAttrStr_ClearAttributeError(); + } + return result; +} + +/* SetupReduce */ +static int __Pyx_setup_reduce_is_named(PyObject* meth, PyObject* name) { + int ret; + PyObject *name_attr; + name_attr = __Pyx_PyObject_GetAttrStr(meth, __pyx_n_s_name_2); + if (likely(name_attr)) { + ret = PyObject_RichCompareBool(name_attr, name, Py_EQ); + } else { + ret = -1; + } + if (unlikely(ret < 0)) { + PyErr_Clear(); + ret = 0; + } + Py_XDECREF(name_attr); + return ret; +} +static int __Pyx_setup_reduce(PyObject* type_obj) { + int ret = 0; + PyObject *object_reduce = NULL; + PyObject *object_getstate = NULL; + PyObject *object_reduce_ex = NULL; + PyObject *reduce = NULL; + PyObject *reduce_ex = NULL; + PyObject *reduce_cython = NULL; + PyObject *setstate = NULL; + PyObject *setstate_cython = NULL; + PyObject *getstate = NULL; +#if CYTHON_USE_PYTYPE_LOOKUP + getstate = _PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate); +#else + getstate = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_getstate); + if (!getstate && PyErr_Occurred()) { + goto __PYX_BAD; + } +#endif + if (getstate) { +#if CYTHON_USE_PYTYPE_LOOKUP + object_getstate = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_getstate); +#else + object_getstate = __Pyx_PyObject_GetAttrStrNoError((PyObject*)&PyBaseObject_Type, __pyx_n_s_getstate); + if (!object_getstate && PyErr_Occurred()) { + goto __PYX_BAD; + } +#endif + if (object_getstate != getstate) { + goto __PYX_GOOD; + } + } +#if CYTHON_USE_PYTYPE_LOOKUP + object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; +#else + object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; +#endif + reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto __PYX_BAD; + if (reduce_ex == object_reduce_ex) { +#if CYTHON_USE_PYTYPE_LOOKUP + object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; +#else + object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; +#endif + reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto __PYX_BAD; + if (reduce == object_reduce || __Pyx_setup_reduce_is_named(reduce, __pyx_n_s_reduce_cython)) { + reduce_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_reduce_cython); + if (likely(reduce_cython)) { + ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; + ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; + } else if (reduce == object_reduce || PyErr_Occurred()) { + goto __PYX_BAD; + } + setstate = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_setstate); + if (!setstate) PyErr_Clear(); + if (!setstate || __Pyx_setup_reduce_is_named(setstate, __pyx_n_s_setstate_cython)) { + setstate_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_setstate_cython); + if (likely(setstate_cython)) { + ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; + ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; + } else if (!setstate || PyErr_Occurred()) { + goto __PYX_BAD; + } + } + PyType_Modified((PyTypeObject*)type_obj); + } + } + goto __PYX_GOOD; +__PYX_BAD: + if (!PyErr_Occurred()) + PyErr_Format(PyExc_RuntimeError, "Unable to initialize pickling for %s", ((PyTypeObject*)type_obj)->tp_name); + ret = -1; +__PYX_GOOD: +#if !CYTHON_USE_PYTYPE_LOOKUP + Py_XDECREF(object_reduce); + Py_XDECREF(object_reduce_ex); + Py_XDECREF(object_getstate); + Py_XDECREF(getstate); +#endif + Py_XDECREF(reduce); + Py_XDECREF(reduce_ex); + Py_XDECREF(reduce_cython); + Py_XDECREF(setstate); + Py_XDECREF(setstate_cython); + return ret; +} + +/* CalculateMetaclass */ +static PyObject *__Pyx_CalculateMetaclass(PyTypeObject *metaclass, PyObject *bases) { + Py_ssize_t i, nbases = PyTuple_GET_SIZE(bases); + for (i=0; i < nbases; i++) { + PyTypeObject *tmptype; + PyObject *tmp = PyTuple_GET_ITEM(bases, i); + tmptype = Py_TYPE(tmp); +#if PY_MAJOR_VERSION < 3 + if (tmptype == &PyClass_Type) + continue; +#endif + if (!metaclass) { + metaclass = tmptype; + continue; + } + if (PyType_IsSubtype(metaclass, tmptype)) + continue; + if (PyType_IsSubtype(tmptype, metaclass)) { + metaclass = tmptype; + continue; + } + PyErr_SetString(PyExc_TypeError, + "metaclass conflict: " + "the metaclass of a derived class " + "must be a (non-strict) subclass " + "of the metaclasses of all its bases"); + return NULL; + } + if (!metaclass) { +#if PY_MAJOR_VERSION < 3 + metaclass = &PyClass_Type; +#else + metaclass = &PyType_Type; +#endif + } + Py_INCREF((PyObject*) metaclass); + return (PyObject*) metaclass; +} + +/* FetchCommonType */ +static PyTypeObject* __Pyx_FetchCommonType(PyTypeObject* type) { + PyObject* fake_module; + PyTypeObject* cached_type = NULL; + fake_module = PyImport_AddModule((char*) "_cython_" CYTHON_ABI); + if (!fake_module) return NULL; + Py_INCREF(fake_module); + cached_type = (PyTypeObject*) PyObject_GetAttrString(fake_module, type->tp_name); + if (cached_type) { + if (!PyType_Check((PyObject*)cached_type)) { + PyErr_Format(PyExc_TypeError, + "Shared Cython type %.200s is not a type object", + type->tp_name); + goto bad; + } + if (cached_type->tp_basicsize != type->tp_basicsize) { + PyErr_Format(PyExc_TypeError, + "Shared Cython type %.200s has the wrong size, try recompiling", + type->tp_name); + goto bad; + } + } else { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) goto bad; + PyErr_Clear(); + if (PyType_Ready(type) < 0) goto bad; + if (PyObject_SetAttrString(fake_module, type->tp_name, (PyObject*) type) < 0) + goto bad; + Py_INCREF(type); + cached_type = type; + } +done: + Py_DECREF(fake_module); + return cached_type; +bad: + Py_XDECREF(cached_type); + cached_type = NULL; + goto done; +} + +/* CythonFunctionShared */ +#include +static PyObject * +__Pyx_CyFunction_get_doc(__pyx_CyFunctionObject *op, CYTHON_UNUSED void *closure) +{ + if (unlikely(op->func_doc == NULL)) { + if (op->func.m_ml->ml_doc) { +#if PY_MAJOR_VERSION >= 3 + op->func_doc = PyUnicode_FromString(op->func.m_ml->ml_doc); +#else + op->func_doc = PyString_FromString(op->func.m_ml->ml_doc); +#endif + if (unlikely(op->func_doc == NULL)) + return NULL; + } else { + Py_INCREF(Py_None); + return Py_None; + } + } + Py_INCREF(op->func_doc); + return op->func_doc; +} +static int +__Pyx_CyFunction_set_doc(__pyx_CyFunctionObject *op, PyObject *value, CYTHON_UNUSED void *context) +{ + PyObject *tmp = op->func_doc; + if (value == NULL) { + value = Py_None; + } + Py_INCREF(value); + op->func_doc = value; + Py_XDECREF(tmp); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_name(__pyx_CyFunctionObject *op, CYTHON_UNUSED void *context) +{ + if (unlikely(op->func_name == NULL)) { +#if PY_MAJOR_VERSION >= 3 + op->func_name = PyUnicode_InternFromString(op->func.m_ml->ml_name); +#else + op->func_name = PyString_InternFromString(op->func.m_ml->ml_name); +#endif + if (unlikely(op->func_name == NULL)) + return NULL; + } + Py_INCREF(op->func_name); + return op->func_name; +} +static int +__Pyx_CyFunction_set_name(__pyx_CyFunctionObject *op, PyObject *value, CYTHON_UNUSED void *context) +{ + PyObject *tmp; +#if PY_MAJOR_VERSION >= 3 + if (unlikely(value == NULL || !PyUnicode_Check(value))) +#else + if (unlikely(value == NULL || !PyString_Check(value))) +#endif + { + PyErr_SetString(PyExc_TypeError, + "__name__ must be set to a string object"); + return -1; + } + tmp = op->func_name; + Py_INCREF(value); + op->func_name = value; + Py_XDECREF(tmp); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_qualname(__pyx_CyFunctionObject *op, CYTHON_UNUSED void *context) +{ + Py_INCREF(op->func_qualname); + return op->func_qualname; +} +static int +__Pyx_CyFunction_set_qualname(__pyx_CyFunctionObject *op, PyObject *value, CYTHON_UNUSED void *context) +{ + PyObject *tmp; +#if PY_MAJOR_VERSION >= 3 + if (unlikely(value == NULL || !PyUnicode_Check(value))) +#else + if (unlikely(value == NULL || !PyString_Check(value))) +#endif + { + PyErr_SetString(PyExc_TypeError, + "__qualname__ must be set to a string object"); + return -1; + } + tmp = op->func_qualname; + Py_INCREF(value); + op->func_qualname = value; + Py_XDECREF(tmp); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_self(__pyx_CyFunctionObject *m, CYTHON_UNUSED void *closure) +{ + PyObject *self; + self = m->func_closure; + if (self == NULL) + self = Py_None; + Py_INCREF(self); + return self; +} +static PyObject * +__Pyx_CyFunction_get_dict(__pyx_CyFunctionObject *op, CYTHON_UNUSED void *context) +{ + if (unlikely(op->func_dict == NULL)) { + op->func_dict = PyDict_New(); + if (unlikely(op->func_dict == NULL)) + return NULL; + } + Py_INCREF(op->func_dict); + return op->func_dict; +} +static int +__Pyx_CyFunction_set_dict(__pyx_CyFunctionObject *op, PyObject *value, CYTHON_UNUSED void *context) +{ + PyObject *tmp; + if (unlikely(value == NULL)) { + PyErr_SetString(PyExc_TypeError, + "function's dictionary may not be deleted"); + return -1; + } + if (unlikely(!PyDict_Check(value))) { + PyErr_SetString(PyExc_TypeError, + "setting function's dictionary to a non-dict"); + return -1; + } + tmp = op->func_dict; + Py_INCREF(value); + op->func_dict = value; + Py_XDECREF(tmp); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_globals(__pyx_CyFunctionObject *op, CYTHON_UNUSED void *context) +{ + Py_INCREF(op->func_globals); + return op->func_globals; +} +static PyObject * +__Pyx_CyFunction_get_closure(CYTHON_UNUSED __pyx_CyFunctionObject *op, CYTHON_UNUSED void *context) +{ + Py_INCREF(Py_None); + return Py_None; +} +static PyObject * +__Pyx_CyFunction_get_code(__pyx_CyFunctionObject *op, CYTHON_UNUSED void *context) +{ + PyObject* result = (op->func_code) ? op->func_code : Py_None; + Py_INCREF(result); + return result; +} +static int +__Pyx_CyFunction_init_defaults(__pyx_CyFunctionObject *op) { + int result = 0; + PyObject *res = op->defaults_getter((PyObject *) op); + if (unlikely(!res)) + return -1; + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + op->defaults_tuple = PyTuple_GET_ITEM(res, 0); + Py_INCREF(op->defaults_tuple); + op->defaults_kwdict = PyTuple_GET_ITEM(res, 1); + Py_INCREF(op->defaults_kwdict); + #else + op->defaults_tuple = PySequence_ITEM(res, 0); + if (unlikely(!op->defaults_tuple)) result = -1; + else { + op->defaults_kwdict = PySequence_ITEM(res, 1); + if (unlikely(!op->defaults_kwdict)) result = -1; + } + #endif + Py_DECREF(res); + return result; +} +static int +__Pyx_CyFunction_set_defaults(__pyx_CyFunctionObject *op, PyObject* value, CYTHON_UNUSED void *context) { + PyObject* tmp; + if (!value) { + value = Py_None; + } else if (value != Py_None && !PyTuple_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "__defaults__ must be set to a tuple object"); + return -1; + } + Py_INCREF(value); + tmp = op->defaults_tuple; + op->defaults_tuple = value; + Py_XDECREF(tmp); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_defaults(__pyx_CyFunctionObject *op, CYTHON_UNUSED void *context) { + PyObject* result = op->defaults_tuple; + if (unlikely(!result)) { + if (op->defaults_getter) { + if (__Pyx_CyFunction_init_defaults(op) < 0) return NULL; + result = op->defaults_tuple; + } else { + result = Py_None; + } + } + Py_INCREF(result); + return result; +} +static int +__Pyx_CyFunction_set_kwdefaults(__pyx_CyFunctionObject *op, PyObject* value, CYTHON_UNUSED void *context) { + PyObject* tmp; + if (!value) { + value = Py_None; + } else if (value != Py_None && !PyDict_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "__kwdefaults__ must be set to a dict object"); + return -1; + } + Py_INCREF(value); + tmp = op->defaults_kwdict; + op->defaults_kwdict = value; + Py_XDECREF(tmp); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_kwdefaults(__pyx_CyFunctionObject *op, CYTHON_UNUSED void *context) { + PyObject* result = op->defaults_kwdict; + if (unlikely(!result)) { + if (op->defaults_getter) { + if (__Pyx_CyFunction_init_defaults(op) < 0) return NULL; + result = op->defaults_kwdict; + } else { + result = Py_None; + } + } + Py_INCREF(result); + return result; +} +static int +__Pyx_CyFunction_set_annotations(__pyx_CyFunctionObject *op, PyObject* value, CYTHON_UNUSED void *context) { + PyObject* tmp; + if (!value || value == Py_None) { + value = NULL; + } else if (!PyDict_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "__annotations__ must be set to a dict object"); + return -1; + } + Py_XINCREF(value); + tmp = op->func_annotations; + op->func_annotations = value; + Py_XDECREF(tmp); + return 0; +} +static PyObject * +__Pyx_CyFunction_get_annotations(__pyx_CyFunctionObject *op, CYTHON_UNUSED void *context) { + PyObject* result = op->func_annotations; + if (unlikely(!result)) { + result = PyDict_New(); + if (unlikely(!result)) return NULL; + op->func_annotations = result; + } + Py_INCREF(result); + return result; +} +static PyGetSetDef __pyx_CyFunction_getsets[] = { + {(char *) "func_doc", (getter)__Pyx_CyFunction_get_doc, (setter)__Pyx_CyFunction_set_doc, 0, 0}, + {(char *) "__doc__", (getter)__Pyx_CyFunction_get_doc, (setter)__Pyx_CyFunction_set_doc, 0, 0}, + {(char *) "func_name", (getter)__Pyx_CyFunction_get_name, (setter)__Pyx_CyFunction_set_name, 0, 0}, + {(char *) "__name__", (getter)__Pyx_CyFunction_get_name, (setter)__Pyx_CyFunction_set_name, 0, 0}, + {(char *) "__qualname__", (getter)__Pyx_CyFunction_get_qualname, (setter)__Pyx_CyFunction_set_qualname, 0, 0}, + {(char *) "__self__", (getter)__Pyx_CyFunction_get_self, 0, 0, 0}, + {(char *) "func_dict", (getter)__Pyx_CyFunction_get_dict, (setter)__Pyx_CyFunction_set_dict, 0, 0}, + {(char *) "__dict__", (getter)__Pyx_CyFunction_get_dict, (setter)__Pyx_CyFunction_set_dict, 0, 0}, + {(char *) "func_globals", (getter)__Pyx_CyFunction_get_globals, 0, 0, 0}, + {(char *) "__globals__", (getter)__Pyx_CyFunction_get_globals, 0, 0, 0}, + {(char *) "func_closure", (getter)__Pyx_CyFunction_get_closure, 0, 0, 0}, + {(char *) "__closure__", (getter)__Pyx_CyFunction_get_closure, 0, 0, 0}, + {(char *) "func_code", (getter)__Pyx_CyFunction_get_code, 0, 0, 0}, + {(char *) "__code__", (getter)__Pyx_CyFunction_get_code, 0, 0, 0}, + {(char *) "func_defaults", (getter)__Pyx_CyFunction_get_defaults, (setter)__Pyx_CyFunction_set_defaults, 0, 0}, + {(char *) "__defaults__", (getter)__Pyx_CyFunction_get_defaults, (setter)__Pyx_CyFunction_set_defaults, 0, 0}, + {(char *) "__kwdefaults__", (getter)__Pyx_CyFunction_get_kwdefaults, (setter)__Pyx_CyFunction_set_kwdefaults, 0, 0}, + {(char *) "__annotations__", (getter)__Pyx_CyFunction_get_annotations, (setter)__Pyx_CyFunction_set_annotations, 0, 0}, + {0, 0, 0, 0, 0} +}; +static PyMemberDef __pyx_CyFunction_members[] = { + {(char *) "__module__", T_OBJECT, offsetof(PyCFunctionObject, m_module), PY_WRITE_RESTRICTED, 0}, + {0, 0, 0, 0, 0} +}; +static PyObject * +__Pyx_CyFunction_reduce(__pyx_CyFunctionObject *m, CYTHON_UNUSED PyObject *args) +{ +#if PY_MAJOR_VERSION >= 3 + Py_INCREF(m->func_qualname); + return m->func_qualname; +#else + return PyString_FromString(m->func.m_ml->ml_name); +#endif +} +static PyMethodDef __pyx_CyFunction_methods[] = { + {"__reduce__", (PyCFunction)__Pyx_CyFunction_reduce, METH_VARARGS, 0}, + {0, 0, 0, 0} +}; +#if PY_VERSION_HEX < 0x030500A0 +#define __Pyx_CyFunction_weakreflist(cyfunc) ((cyfunc)->func_weakreflist) +#else +#define __Pyx_CyFunction_weakreflist(cyfunc) ((cyfunc)->func.m_weakreflist) +#endif +static PyObject *__Pyx_CyFunction_Init(__pyx_CyFunctionObject *op, PyMethodDef *ml, int flags, PyObject* qualname, + PyObject *closure, PyObject *module, PyObject* globals, PyObject* code) { + if (unlikely(op == NULL)) + return NULL; + op->flags = flags; + __Pyx_CyFunction_weakreflist(op) = NULL; + op->func.m_ml = ml; + op->func.m_self = (PyObject *) op; + Py_XINCREF(closure); + op->func_closure = closure; + Py_XINCREF(module); + op->func.m_module = module; + op->func_dict = NULL; + op->func_name = NULL; + Py_INCREF(qualname); + op->func_qualname = qualname; + op->func_doc = NULL; + op->func_classobj = NULL; + op->func_globals = globals; + Py_INCREF(op->func_globals); + Py_XINCREF(code); + op->func_code = code; + op->defaults_pyobjects = 0; + op->defaults_size = 0; + op->defaults = NULL; + op->defaults_tuple = NULL; + op->defaults_kwdict = NULL; + op->defaults_getter = NULL; + op->func_annotations = NULL; + return (PyObject *) op; +} +static int +__Pyx_CyFunction_clear(__pyx_CyFunctionObject *m) +{ + Py_CLEAR(m->func_closure); + Py_CLEAR(m->func.m_module); + Py_CLEAR(m->func_dict); + Py_CLEAR(m->func_name); + Py_CLEAR(m->func_qualname); + Py_CLEAR(m->func_doc); + Py_CLEAR(m->func_globals); + Py_CLEAR(m->func_code); + Py_CLEAR(m->func_classobj); + Py_CLEAR(m->defaults_tuple); + Py_CLEAR(m->defaults_kwdict); + Py_CLEAR(m->func_annotations); + if (m->defaults) { + PyObject **pydefaults = __Pyx_CyFunction_Defaults(PyObject *, m); + int i; + for (i = 0; i < m->defaults_pyobjects; i++) + Py_XDECREF(pydefaults[i]); + PyObject_Free(m->defaults); + m->defaults = NULL; + } + return 0; +} +static void __Pyx__CyFunction_dealloc(__pyx_CyFunctionObject *m) +{ + if (__Pyx_CyFunction_weakreflist(m) != NULL) + PyObject_ClearWeakRefs((PyObject *) m); + __Pyx_CyFunction_clear(m); + PyObject_GC_Del(m); +} +static void __Pyx_CyFunction_dealloc(__pyx_CyFunctionObject *m) +{ + PyObject_GC_UnTrack(m); + __Pyx__CyFunction_dealloc(m); +} +static int __Pyx_CyFunction_traverse(__pyx_CyFunctionObject *m, visitproc visit, void *arg) +{ + Py_VISIT(m->func_closure); + Py_VISIT(m->func.m_module); + Py_VISIT(m->func_dict); + Py_VISIT(m->func_name); + Py_VISIT(m->func_qualname); + Py_VISIT(m->func_doc); + Py_VISIT(m->func_globals); + Py_VISIT(m->func_code); + Py_VISIT(m->func_classobj); + Py_VISIT(m->defaults_tuple); + Py_VISIT(m->defaults_kwdict); + if (m->defaults) { + PyObject **pydefaults = __Pyx_CyFunction_Defaults(PyObject *, m); + int i; + for (i = 0; i < m->defaults_pyobjects; i++) + Py_VISIT(pydefaults[i]); + } + return 0; +} +static PyObject *__Pyx_CyFunction_descr_get(PyObject *func, PyObject *obj, PyObject *type) +{ +#if PY_MAJOR_VERSION < 3 + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + if (m->flags & __Pyx_CYFUNCTION_STATICMETHOD) { + Py_INCREF(func); + return func; + } + if (m->flags & __Pyx_CYFUNCTION_CLASSMETHOD) { + if (type == NULL) + type = (PyObject *)(Py_TYPE(obj)); + return __Pyx_PyMethod_New(func, type, (PyObject *)(Py_TYPE(type))); + } + if (obj == Py_None) + obj = NULL; +#endif + return __Pyx_PyMethod_New(func, obj, type); +} +static PyObject* +__Pyx_CyFunction_repr(__pyx_CyFunctionObject *op) +{ +#if PY_MAJOR_VERSION >= 3 + return PyUnicode_FromFormat("", + op->func_qualname, (void *)op); +#else + return PyString_FromFormat("", + PyString_AsString(op->func_qualname), (void *)op); +#endif +} +static PyObject * __Pyx_CyFunction_CallMethod(PyObject *func, PyObject *self, PyObject *arg, PyObject *kw) { + PyCFunctionObject* f = (PyCFunctionObject*)func; + PyCFunction meth = f->m_ml->ml_meth; + Py_ssize_t size; + switch (f->m_ml->ml_flags & (METH_VARARGS | METH_KEYWORDS | METH_NOARGS | METH_O)) { + case METH_VARARGS: + if (likely(kw == NULL || PyDict_Size(kw) == 0)) + return (*meth)(self, arg); + break; + case METH_VARARGS | METH_KEYWORDS: + return (*(PyCFunctionWithKeywords)(void*)meth)(self, arg, kw); + case METH_NOARGS: + if (likely(kw == NULL || PyDict_Size(kw) == 0)) { + size = PyTuple_GET_SIZE(arg); + if (likely(size == 0)) + return (*meth)(self, NULL); + PyErr_Format(PyExc_TypeError, + "%.200s() takes no arguments (%" CYTHON_FORMAT_SSIZE_T "d given)", + f->m_ml->ml_name, size); + return NULL; + } + break; + case METH_O: + if (likely(kw == NULL || PyDict_Size(kw) == 0)) { + size = PyTuple_GET_SIZE(arg); + if (likely(size == 1)) { + PyObject *result, *arg0; + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + arg0 = PyTuple_GET_ITEM(arg, 0); + #else + arg0 = PySequence_ITEM(arg, 0); if (unlikely(!arg0)) return NULL; + #endif + result = (*meth)(self, arg0); + #if !(CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS) + Py_DECREF(arg0); + #endif + return result; + } + PyErr_Format(PyExc_TypeError, + "%.200s() takes exactly one argument (%" CYTHON_FORMAT_SSIZE_T "d given)", + f->m_ml->ml_name, size); + return NULL; + } + break; + default: + PyErr_SetString(PyExc_SystemError, "Bad call flags in " + "__Pyx_CyFunction_Call. METH_OLDARGS is no " + "longer supported!"); + return NULL; + } + PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", + f->m_ml->ml_name); + return NULL; +} +static CYTHON_INLINE PyObject *__Pyx_CyFunction_Call(PyObject *func, PyObject *arg, PyObject *kw) { + return __Pyx_CyFunction_CallMethod(func, ((PyCFunctionObject*)func)->m_self, arg, kw); +} +static PyObject *__Pyx_CyFunction_CallAsMethod(PyObject *func, PyObject *args, PyObject *kw) { + PyObject *result; + __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *) func; + if ((cyfunc->flags & __Pyx_CYFUNCTION_CCLASS) && !(cyfunc->flags & __Pyx_CYFUNCTION_STATICMETHOD)) { + Py_ssize_t argc; + PyObject *new_args; + PyObject *self; + argc = PyTuple_GET_SIZE(args); + new_args = PyTuple_GetSlice(args, 1, argc); + if (unlikely(!new_args)) + return NULL; + self = PyTuple_GetItem(args, 0); + if (unlikely(!self)) { + Py_DECREF(new_args); +#if PY_MAJOR_VERSION > 2 + PyErr_Format(PyExc_TypeError, + "unbound method %.200S() needs an argument", + cyfunc->func_qualname); +#else + PyErr_SetString(PyExc_TypeError, + "unbound method needs an argument"); +#endif + return NULL; + } + result = __Pyx_CyFunction_CallMethod(func, self, new_args, kw); + Py_DECREF(new_args); + } else { + result = __Pyx_CyFunction_Call(func, args, kw); + } + return result; +} +static PyTypeObject __pyx_CyFunctionType_type = { + PyVarObject_HEAD_INIT(0, 0) + "cython_function_or_method", + sizeof(__pyx_CyFunctionObject), + 0, + (destructor) __Pyx_CyFunction_dealloc, + 0, + 0, + 0, +#if PY_MAJOR_VERSION < 3 + 0, +#else + 0, +#endif + (reprfunc) __Pyx_CyFunction_repr, + 0, + 0, + 0, + 0, + __Pyx_CyFunction_CallAsMethod, + 0, + 0, + 0, + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, + 0, + (traverseproc) __Pyx_CyFunction_traverse, + (inquiry) __Pyx_CyFunction_clear, + 0, +#if PY_VERSION_HEX < 0x030500A0 + offsetof(__pyx_CyFunctionObject, func_weakreflist), +#else + offsetof(PyCFunctionObject, m_weakreflist), +#endif + 0, + 0, + __pyx_CyFunction_methods, + __pyx_CyFunction_members, + __pyx_CyFunction_getsets, + 0, + 0, + __Pyx_CyFunction_descr_get, + 0, + offsetof(__pyx_CyFunctionObject, func_dict), + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, +#if PY_VERSION_HEX >= 0x030400a1 + 0, +#endif +#if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) + 0, +#endif +#if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 + 0, +#endif +#if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 + 0, +#endif +}; +static int __pyx_CyFunction_init(void) { + __pyx_CyFunctionType = __Pyx_FetchCommonType(&__pyx_CyFunctionType_type); + if (unlikely(__pyx_CyFunctionType == NULL)) { + return -1; + } + return 0; +} +static CYTHON_INLINE void *__Pyx_CyFunction_InitDefaults(PyObject *func, size_t size, int pyobjects) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->defaults = PyObject_Malloc(size); + if (unlikely(!m->defaults)) + return PyErr_NoMemory(); + memset(m->defaults, 0, size); + m->defaults_pyobjects = pyobjects; + m->defaults_size = size; + return m->defaults; +} +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsTuple(PyObject *func, PyObject *tuple) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->defaults_tuple = tuple; + Py_INCREF(tuple); +} +static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsKwDict(PyObject *func, PyObject *dict) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->defaults_kwdict = dict; + Py_INCREF(dict); +} +static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *func, PyObject *dict) { + __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; + m->func_annotations = dict; + Py_INCREF(dict); +} + +/* CythonFunction */ +static PyObject *__Pyx_CyFunction_New(PyMethodDef *ml, int flags, PyObject* qualname, + PyObject *closure, PyObject *module, PyObject* globals, PyObject* code) { + PyObject *op = __Pyx_CyFunction_Init( + PyObject_GC_New(__pyx_CyFunctionObject, __pyx_CyFunctionType), + ml, flags, qualname, closure, module, globals, code + ); + if (likely(op)) { + PyObject_GC_Track(op); + } + return op; +} + +/* Py3ClassCreate */ +static PyObject *__Pyx_Py3MetaclassPrepare(PyObject *metaclass, PyObject *bases, PyObject *name, + PyObject *qualname, PyObject *mkw, PyObject *modname, PyObject *doc) { + PyObject *ns; + if (metaclass) { + PyObject *prep = __Pyx_PyObject_GetAttrStr(metaclass, __pyx_n_s_prepare); + if (prep) { + PyObject *pargs = PyTuple_Pack(2, name, bases); + if (unlikely(!pargs)) { + Py_DECREF(prep); + return NULL; + } + ns = PyObject_Call(prep, pargs, mkw); + Py_DECREF(prep); + Py_DECREF(pargs); + } else { + if (unlikely(!PyErr_ExceptionMatches(PyExc_AttributeError))) + return NULL; + PyErr_Clear(); + ns = PyDict_New(); + } + } else { + ns = PyDict_New(); + } + if (unlikely(!ns)) + return NULL; + if (unlikely(PyObject_SetItem(ns, __pyx_n_s_module, modname) < 0)) goto bad; + if (unlikely(PyObject_SetItem(ns, __pyx_n_s_qualname, qualname) < 0)) goto bad; + if (unlikely(doc && PyObject_SetItem(ns, __pyx_n_s_doc, doc) < 0)) goto bad; + return ns; +bad: + Py_DECREF(ns); + return NULL; +} +static PyObject *__Pyx_Py3ClassCreate(PyObject *metaclass, PyObject *name, PyObject *bases, + PyObject *dict, PyObject *mkw, + int calculate_metaclass, int allow_py2_metaclass) { + PyObject *result, *margs; + PyObject *owned_metaclass = NULL; + if (allow_py2_metaclass) { + owned_metaclass = PyObject_GetItem(dict, __pyx_n_s_metaclass); + if (owned_metaclass) { + metaclass = owned_metaclass; + } else if (likely(PyErr_ExceptionMatches(PyExc_KeyError))) { + PyErr_Clear(); + } else { + return NULL; + } + } + if (calculate_metaclass && (!metaclass || PyType_Check(metaclass))) { + metaclass = __Pyx_CalculateMetaclass((PyTypeObject*) metaclass, bases); + Py_XDECREF(owned_metaclass); + if (unlikely(!metaclass)) + return NULL; + owned_metaclass = metaclass; + } + margs = PyTuple_Pack(3, name, bases, dict); + if (unlikely(!margs)) { + result = NULL; + } else { + result = PyObject_Call(metaclass, margs, mkw); + Py_DECREF(margs); + } + Py_XDECREF(owned_metaclass); + return result; +} + +/* Globals */ +static PyObject* __Pyx_Globals(void) { + Py_ssize_t i; + PyObject *names; + PyObject *globals = __pyx_d; + Py_INCREF(globals); + names = PyObject_Dir(__pyx_m); + if (!names) + goto bad; + for (i = PyList_GET_SIZE(names)-1; i >= 0; i--) { +#if CYTHON_COMPILING_IN_PYPY + PyObject* name = PySequence_ITEM(names, i); + if (!name) + goto bad; +#else + PyObject* name = PyList_GET_ITEM(names, i); +#endif + if (!PyDict_Contains(globals, name)) { + PyObject* value = __Pyx_GetAttr(__pyx_m, name); + if (!value) { +#if CYTHON_COMPILING_IN_PYPY + Py_DECREF(name); +#endif + goto bad; + } + if (PyDict_SetItem(globals, name, value) < 0) { +#if CYTHON_COMPILING_IN_PYPY + Py_DECREF(name); +#endif + Py_DECREF(value); + goto bad; + } + } +#if CYTHON_COMPILING_IN_PYPY + Py_DECREF(name); +#endif + } + Py_DECREF(names); + return globals; +bad: + Py_XDECREF(names); + Py_XDECREF(globals); + return NULL; +} + +/* CLineInTraceback */ +#ifndef CYTHON_CLINE_IN_TRACEBACK +static int __Pyx_CLineForTraceback(CYTHON_UNUSED PyThreadState *tstate, int c_line) { + PyObject *use_cline; + PyObject *ptype, *pvalue, *ptraceback; +#if CYTHON_COMPILING_IN_CPYTHON + PyObject **cython_runtime_dict; +#endif + if (unlikely(!__pyx_cython_runtime)) { + return c_line; + } + __Pyx_ErrFetchInState(tstate, &ptype, &pvalue, &ptraceback); +#if CYTHON_COMPILING_IN_CPYTHON + cython_runtime_dict = _PyObject_GetDictPtr(__pyx_cython_runtime); + if (likely(cython_runtime_dict)) { + __PYX_PY_DICT_LOOKUP_IF_MODIFIED( + use_cline, *cython_runtime_dict, + __Pyx_PyDict_GetItemStr(*cython_runtime_dict, __pyx_n_s_cline_in_traceback)) + } else +#endif + { + PyObject *use_cline_obj = __Pyx_PyObject_GetAttrStr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback); + if (use_cline_obj) { + use_cline = PyObject_Not(use_cline_obj) ? Py_False : Py_True; + Py_DECREF(use_cline_obj); + } else { + PyErr_Clear(); + use_cline = NULL; + } + } + if (!use_cline) { + c_line = 0; + (void) PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); + } + else if (use_cline == Py_False || (use_cline != Py_True && PyObject_Not(use_cline) != 0)) { + c_line = 0; + } + __Pyx_ErrRestoreInState(tstate, ptype, pvalue, ptraceback); + return c_line; +} +#endif + +/* CodeObjectCache */ +static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line) { + int start = 0, mid = 0, end = count - 1; + if (end >= 0 && code_line > entries[end].code_line) { + return count; + } + while (start < end) { + mid = start + (end - start) / 2; + if (code_line < entries[mid].code_line) { + end = mid; + } else if (code_line > entries[mid].code_line) { + start = mid + 1; + } else { + return mid; + } + } + if (code_line <= entries[mid].code_line) { + return mid; + } else { + return mid + 1; + } +} +static PyCodeObject *__pyx_find_code_object(int code_line) { + PyCodeObject* code_object; + int pos; + if (unlikely(!code_line) || unlikely(!__pyx_code_cache.entries)) { + return NULL; + } + pos = __pyx_bisect_code_objects(__pyx_code_cache.entries, __pyx_code_cache.count, code_line); + if (unlikely(pos >= __pyx_code_cache.count) || unlikely(__pyx_code_cache.entries[pos].code_line != code_line)) { + return NULL; + } + code_object = __pyx_code_cache.entries[pos].code_object; + Py_INCREF(code_object); + return code_object; +} +static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { + int pos, i; + __Pyx_CodeObjectCacheEntry* entries = __pyx_code_cache.entries; + if (unlikely(!code_line)) { + return; + } + if (unlikely(!entries)) { + entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Malloc(64*sizeof(__Pyx_CodeObjectCacheEntry)); + if (likely(entries)) { + __pyx_code_cache.entries = entries; + __pyx_code_cache.max_count = 64; + __pyx_code_cache.count = 1; + entries[0].code_line = code_line; + entries[0].code_object = code_object; + Py_INCREF(code_object); + } + return; + } + pos = __pyx_bisect_code_objects(__pyx_code_cache.entries, __pyx_code_cache.count, code_line); + if ((pos < __pyx_code_cache.count) && unlikely(__pyx_code_cache.entries[pos].code_line == code_line)) { + PyCodeObject* tmp = entries[pos].code_object; + entries[pos].code_object = code_object; + Py_DECREF(tmp); + return; + } + if (__pyx_code_cache.count == __pyx_code_cache.max_count) { + int new_max = __pyx_code_cache.max_count + 64; + entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Realloc( + __pyx_code_cache.entries, ((size_t)new_max) * sizeof(__Pyx_CodeObjectCacheEntry)); + if (unlikely(!entries)) { + return; + } + __pyx_code_cache.entries = entries; + __pyx_code_cache.max_count = new_max; + } + for (i=__pyx_code_cache.count; i>pos; i--) { + entries[i] = entries[i-1]; + } + entries[pos].code_line = code_line; + entries[pos].code_object = code_object; + __pyx_code_cache.count++; + Py_INCREF(code_object); +} + +/* AddTraceback */ +#include "compile.h" +#include "frameobject.h" +#include "traceback.h" +#if PY_VERSION_HEX >= 0x030b00a6 + #ifndef Py_BUILD_CORE + #define Py_BUILD_CORE 1 + #endif + #include "internal/pycore_frame.h" +#endif +static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( + const char *funcname, int c_line, + int py_line, const char *filename) { + PyCodeObject *py_code = NULL; + PyObject *py_funcname = NULL; + #if PY_MAJOR_VERSION < 3 + PyObject *py_srcfile = NULL; + py_srcfile = PyString_FromString(filename); + if (!py_srcfile) goto bad; + #endif + if (c_line) { + #if PY_MAJOR_VERSION < 3 + py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); + if (!py_funcname) goto bad; + #else + py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); + if (!py_funcname) goto bad; + funcname = PyUnicode_AsUTF8(py_funcname); + if (!funcname) goto bad; + #endif + } + else { + #if PY_MAJOR_VERSION < 3 + py_funcname = PyString_FromString(funcname); + if (!py_funcname) goto bad; + #endif + } + #if PY_MAJOR_VERSION < 3 + py_code = __Pyx_PyCode_New( + 0, + 0, + 0, + 0, + 0, + __pyx_empty_bytes, /*PyObject *code,*/ + __pyx_empty_tuple, /*PyObject *consts,*/ + __pyx_empty_tuple, /*PyObject *names,*/ + __pyx_empty_tuple, /*PyObject *varnames,*/ + __pyx_empty_tuple, /*PyObject *freevars,*/ + __pyx_empty_tuple, /*PyObject *cellvars,*/ + py_srcfile, /*PyObject *filename,*/ + py_funcname, /*PyObject *name,*/ + py_line, + __pyx_empty_bytes /*PyObject *lnotab*/ + ); + Py_DECREF(py_srcfile); + #else + py_code = PyCode_NewEmpty(filename, funcname, py_line); + #endif + Py_XDECREF(py_funcname); // XDECREF since it's only set on Py3 if cline + return py_code; +bad: + Py_XDECREF(py_funcname); + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(py_srcfile); + #endif + return NULL; +} +static void __Pyx_AddTraceback(const char *funcname, int c_line, + int py_line, const char *filename) { + PyCodeObject *py_code = 0; + PyFrameObject *py_frame = 0; + PyThreadState *tstate = __Pyx_PyThreadState_Current; + PyObject *ptype, *pvalue, *ptraceback; + if (c_line) { + c_line = __Pyx_CLineForTraceback(tstate, c_line); + } + py_code = __pyx_find_code_object(c_line ? -c_line : py_line); + if (!py_code) { + __Pyx_ErrFetchInState(tstate, &ptype, &pvalue, &ptraceback); + py_code = __Pyx_CreateCodeObjectForTraceback( + funcname, c_line, py_line, filename); + if (!py_code) { + /* If the code object creation fails, then we should clear the + fetched exception references and propagate the new exception */ + Py_XDECREF(ptype); + Py_XDECREF(pvalue); + Py_XDECREF(ptraceback); + goto bad; + } + __Pyx_ErrRestoreInState(tstate, ptype, pvalue, ptraceback); + __pyx_insert_code_object(c_line ? -c_line : py_line, py_code); + } + py_frame = PyFrame_New( + tstate, /*PyThreadState *tstate,*/ + py_code, /*PyCodeObject *code,*/ + __pyx_d, /*PyObject *globals,*/ + 0 /*PyObject *locals*/ + ); + if (!py_frame) goto bad; + __Pyx_PyFrame_SetLineNumber(py_frame, py_line); + PyTraceBack_Here(py_frame); +bad: + Py_XDECREF(py_code); + Py_XDECREF(py_frame); +} + +/* CIntFromPyVerify */ +#define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value)\ + __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 0) +#define __PYX_VERIFY_RETURN_INT_EXC(target_type, func_type, func_value)\ + __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 1) +#define __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, exc)\ + {\ + func_type value = func_value;\ + if (sizeof(target_type) < sizeof(func_type)) {\ + if (unlikely(value != (func_type) (target_type) value)) {\ + func_type zero = 0;\ + if (exc && unlikely(value == (func_type)-1 && PyErr_Occurred()))\ + return (target_type) -1;\ + if (is_unsigned && unlikely(value < zero))\ + goto raise_neg_overflow;\ + else\ + goto raise_overflow;\ + }\ + }\ + return (target_type) value;\ + } + +/* CIntFromPy */ +static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const int neg_one = (int) -1, const_zero = (int) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if (sizeof(int) < sizeof(long)) { + __PYX_VERIFY_RETURN_INT(int, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (int) val; + } + } else +#endif + if (likely(PyLong_Check(x))) { + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (int) 0; + case 1: __PYX_VERIFY_RETURN_INT(int, digit, digits[0]) + case 2: + if (8 * sizeof(int) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) >= 2 * PyLong_SHIFT) { + return (int) (((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + case 3: + if (8 * sizeof(int) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) >= 3 * PyLong_SHIFT) { + return (int) (((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + case 4: + if (8 * sizeof(int) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) >= 4 * PyLong_SHIFT) { + return (int) (((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (int) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if (sizeof(int) <= sizeof(unsigned long)) { + __PYX_VERIFY_RETURN_INT_EXC(int, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(int, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (int) 0; + case -1: __PYX_VERIFY_RETURN_INT(int, sdigit, (sdigit) (-(sdigit)digits[0])) + case 1: __PYX_VERIFY_RETURN_INT(int, digit, +digits[0]) + case -2: + if (8 * sizeof(int) - 1 > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { + return (int) (((int)-1)*(((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 2: + if (8 * sizeof(int) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { + return (int) ((((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case -3: + if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { + return (int) (((int)-1)*(((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 3: + if (8 * sizeof(int) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { + return (int) ((((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case -4: + if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { + return (int) (((int)-1)*(((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 4: + if (8 * sizeof(int) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { + return (int) ((((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + } +#endif + if (sizeof(int) <= sizeof(long)) { + __PYX_VERIFY_RETURN_INT_EXC(int, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(int, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { +#if CYTHON_COMPILING_IN_PYPY && !defined(_PyLong_AsByteArray) + PyErr_SetString(PyExc_RuntimeError, + "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); +#else + int val; + PyObject *v = __Pyx_PyNumber_IntOrLong(x); + #if PY_MAJOR_VERSION < 3 + if (likely(v) && !PyLong_Check(v)) { + PyObject *tmp = v; + v = PyNumber_Long(tmp); + Py_DECREF(tmp); + } + #endif + if (likely(v)) { + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + int ret = _PyLong_AsByteArray((PyLongObject *)v, + bytes, sizeof(val), + is_little, !is_unsigned); + Py_DECREF(v); + if (likely(!ret)) + return val; + } +#endif + return (int) -1; + } + } else { + int val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (int) -1; + val = __Pyx_PyInt_As_int(tmp); + Py_DECREF(tmp); + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to int"); + return (int) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to int"); + return (int) -1; +} + +/* CIntFromPy */ +static CYTHON_INLINE size_t __Pyx_PyInt_As_size_t(PyObject *x) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const size_t neg_one = (size_t) -1, const_zero = (size_t) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if (sizeof(size_t) < sizeof(long)) { + __PYX_VERIFY_RETURN_INT(size_t, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (size_t) val; + } + } else +#endif + if (likely(PyLong_Check(x))) { + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (size_t) 0; + case 1: __PYX_VERIFY_RETURN_INT(size_t, digit, digits[0]) + case 2: + if (8 * sizeof(size_t) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(size_t, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(size_t) >= 2 * PyLong_SHIFT) { + return (size_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + } + break; + case 3: + if (8 * sizeof(size_t) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(size_t, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(size_t) >= 3 * PyLong_SHIFT) { + return (size_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + } + break; + case 4: + if (8 * sizeof(size_t) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(size_t, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(size_t) >= 4 * PyLong_SHIFT) { + return (size_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + } + break; + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (size_t) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if (sizeof(size_t) <= sizeof(unsigned long)) { + __PYX_VERIFY_RETURN_INT_EXC(size_t, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(size_t) <= sizeof(unsigned PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(size_t, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (size_t) 0; + case -1: __PYX_VERIFY_RETURN_INT(size_t, sdigit, (sdigit) (-(sdigit)digits[0])) + case 1: __PYX_VERIFY_RETURN_INT(size_t, digit, +digits[0]) + case -2: + if (8 * sizeof(size_t) - 1 > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(size_t, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(size_t) - 1 > 2 * PyLong_SHIFT) { + return (size_t) (((size_t)-1)*(((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0]))); + } + } + break; + case 2: + if (8 * sizeof(size_t) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(size_t, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(size_t) - 1 > 2 * PyLong_SHIFT) { + return (size_t) ((((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0]))); + } + } + break; + case -3: + if (8 * sizeof(size_t) - 1 > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(size_t, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(size_t) - 1 > 3 * PyLong_SHIFT) { + return (size_t) (((size_t)-1)*(((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0]))); + } + } + break; + case 3: + if (8 * sizeof(size_t) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(size_t, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(size_t) - 1 > 3 * PyLong_SHIFT) { + return (size_t) ((((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0]))); + } + } + break; + case -4: + if (8 * sizeof(size_t) - 1 > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(size_t, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(size_t) - 1 > 4 * PyLong_SHIFT) { + return (size_t) (((size_t)-1)*(((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0]))); + } + } + break; + case 4: + if (8 * sizeof(size_t) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(size_t, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(size_t) - 1 > 4 * PyLong_SHIFT) { + return (size_t) ((((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0]))); + } + } + break; + } +#endif + if (sizeof(size_t) <= sizeof(long)) { + __PYX_VERIFY_RETURN_INT_EXC(size_t, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(size_t) <= sizeof(PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(size_t, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { +#if CYTHON_COMPILING_IN_PYPY && !defined(_PyLong_AsByteArray) + PyErr_SetString(PyExc_RuntimeError, + "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); +#else + size_t val; + PyObject *v = __Pyx_PyNumber_IntOrLong(x); + #if PY_MAJOR_VERSION < 3 + if (likely(v) && !PyLong_Check(v)) { + PyObject *tmp = v; + v = PyNumber_Long(tmp); + Py_DECREF(tmp); + } + #endif + if (likely(v)) { + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + int ret = _PyLong_AsByteArray((PyLongObject *)v, + bytes, sizeof(val), + is_little, !is_unsigned); + Py_DECREF(v); + if (likely(!ret)) + return val; + } +#endif + return (size_t) -1; + } + } else { + size_t val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (size_t) -1; + val = __Pyx_PyInt_As_size_t(tmp); + Py_DECREF(tmp); + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to size_t"); + return (size_t) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to size_t"); + return (size_t) -1; +} + +/* CIntToPy */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const long neg_one = (long) -1, const_zero = (long) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; + if (is_unsigned) { + if (sizeof(long) < sizeof(long)) { + return PyInt_FromLong((long) value); + } else if (sizeof(long) <= sizeof(unsigned long)) { + return PyLong_FromUnsignedLong((unsigned long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { + return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); +#endif + } + } else { + if (sizeof(long) <= sizeof(long)) { + return PyInt_FromLong((long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { + return PyLong_FromLongLong((PY_LONG_LONG) value); +#endif + } + } + { + int one = 1; int little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&value; + return _PyLong_FromByteArray(bytes, sizeof(long), + little, !is_unsigned); + } +} + +/* CIntFromPy */ +static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const long neg_one = (long) -1, const_zero = (long) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if (sizeof(long) < sizeof(long)) { + __PYX_VERIFY_RETURN_INT(long, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (long) val; + } + } else +#endif + if (likely(PyLong_Check(x))) { + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (long) 0; + case 1: __PYX_VERIFY_RETURN_INT(long, digit, digits[0]) + case 2: + if (8 * sizeof(long) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) >= 2 * PyLong_SHIFT) { + return (long) (((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + case 3: + if (8 * sizeof(long) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) >= 3 * PyLong_SHIFT) { + return (long) (((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + case 4: + if (8 * sizeof(long) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) >= 4 * PyLong_SHIFT) { + return (long) (((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (long) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if (sizeof(long) <= sizeof(unsigned long)) { + __PYX_VERIFY_RETURN_INT_EXC(long, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(long, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (long) 0; + case -1: __PYX_VERIFY_RETURN_INT(long, sdigit, (sdigit) (-(sdigit)digits[0])) + case 1: __PYX_VERIFY_RETURN_INT(long, digit, +digits[0]) + case -2: + if (8 * sizeof(long) - 1 > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { + return (long) (((long)-1)*(((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 2: + if (8 * sizeof(long) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { + return (long) ((((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case -3: + if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { + return (long) (((long)-1)*(((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 3: + if (8 * sizeof(long) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { + return (long) ((((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case -4: + if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { + return (long) (((long)-1)*(((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 4: + if (8 * sizeof(long) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { + return (long) ((((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + } +#endif + if (sizeof(long) <= sizeof(long)) { + __PYX_VERIFY_RETURN_INT_EXC(long, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(long, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { +#if CYTHON_COMPILING_IN_PYPY && !defined(_PyLong_AsByteArray) + PyErr_SetString(PyExc_RuntimeError, + "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); +#else + long val; + PyObject *v = __Pyx_PyNumber_IntOrLong(x); + #if PY_MAJOR_VERSION < 3 + if (likely(v) && !PyLong_Check(v)) { + PyObject *tmp = v; + v = PyNumber_Long(tmp); + Py_DECREF(tmp); + } + #endif + if (likely(v)) { + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + int ret = _PyLong_AsByteArray((PyLongObject *)v, + bytes, sizeof(val), + is_little, !is_unsigned); + Py_DECREF(v); + if (likely(!ret)) + return val; + } +#endif + return (long) -1; + } + } else { + long val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (long) -1; + val = __Pyx_PyInt_As_long(tmp); + Py_DECREF(tmp); + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to long"); + return (long) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to long"); + return (long) -1; +} + +/* CIntToPy */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum____pyx_t_6region_RegionType(enum __pyx_t_6region_RegionType value) { +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + const enum __pyx_t_6region_RegionType neg_one = (enum __pyx_t_6region_RegionType) -1, const_zero = (enum __pyx_t_6region_RegionType) 0; +#ifdef __Pyx_HAS_GCC_DIAGNOSTIC +#pragma GCC diagnostic pop +#endif + const int is_unsigned = neg_one > const_zero; + if (is_unsigned) { + if (sizeof(enum __pyx_t_6region_RegionType) < sizeof(long)) { + return PyInt_FromLong((long) value); + } else if (sizeof(enum __pyx_t_6region_RegionType) <= sizeof(unsigned long)) { + return PyLong_FromUnsignedLong((unsigned long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(enum __pyx_t_6region_RegionType) <= sizeof(unsigned PY_LONG_LONG)) { + return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); +#endif + } + } else { + if (sizeof(enum __pyx_t_6region_RegionType) <= sizeof(long)) { + return PyInt_FromLong((long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(enum __pyx_t_6region_RegionType) <= sizeof(PY_LONG_LONG)) { + return PyLong_FromLongLong((PY_LONG_LONG) value); +#endif + } + } + { + int one = 1; int little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&value; + return _PyLong_FromByteArray(bytes, sizeof(enum __pyx_t_6region_RegionType), + little, !is_unsigned); + } +} + +/* FastTypeChecks */ +#if CYTHON_COMPILING_IN_CPYTHON +static int __Pyx_InBases(PyTypeObject *a, PyTypeObject *b) { + while (a) { + a = a->tp_base; + if (a == b) + return 1; + } + return b == &PyBaseObject_Type; +} +static CYTHON_INLINE int __Pyx_IsSubtype(PyTypeObject *a, PyTypeObject *b) { + PyObject *mro; + if (a == b) return 1; + mro = a->tp_mro; + if (likely(mro)) { + Py_ssize_t i, n; + n = PyTuple_GET_SIZE(mro); + for (i = 0; i < n; i++) { + if (PyTuple_GET_ITEM(mro, i) == (PyObject *)b) + return 1; + } + return 0; + } + return __Pyx_InBases(a, b); +} +#if PY_MAJOR_VERSION == 2 +static int __Pyx_inner_PyErr_GivenExceptionMatches2(PyObject *err, PyObject* exc_type1, PyObject* exc_type2) { + PyObject *exception, *value, *tb; + int res; + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ErrFetch(&exception, &value, &tb); + res = exc_type1 ? PyObject_IsSubclass(err, exc_type1) : 0; + if (unlikely(res == -1)) { + PyErr_WriteUnraisable(err); + res = 0; + } + if (!res) { + res = PyObject_IsSubclass(err, exc_type2); + if (unlikely(res == -1)) { + PyErr_WriteUnraisable(err); + res = 0; + } + } + __Pyx_ErrRestore(exception, value, tb); + return res; +} +#else +static CYTHON_INLINE int __Pyx_inner_PyErr_GivenExceptionMatches2(PyObject *err, PyObject* exc_type1, PyObject *exc_type2) { + int res = exc_type1 ? __Pyx_IsSubtype((PyTypeObject*)err, (PyTypeObject*)exc_type1) : 0; + if (!res) { + res = __Pyx_IsSubtype((PyTypeObject*)err, (PyTypeObject*)exc_type2); + } + return res; +} +#endif +static int __Pyx_PyErr_GivenExceptionMatchesTuple(PyObject *exc_type, PyObject *tuple) { + Py_ssize_t i, n; + assert(PyExceptionClass_Check(exc_type)); + n = PyTuple_GET_SIZE(tuple); +#if PY_MAJOR_VERSION >= 3 + for (i=0; i '9'); + break; + } + if (rt_from_call[i] != ctversion[i]) { + same = 0; + break; + } + } + if (!same) { + char rtversion[5] = {'\0'}; + char message[200]; + for (i=0; i<4; ++i) { + if (rt_from_call[i] == '.') { + if (found_dot) break; + found_dot = 1; + } else if (rt_from_call[i] < '0' || rt_from_call[i] > '9') { + break; + } + rtversion[i] = rt_from_call[i]; + } + PyOS_snprintf(message, sizeof(message), + "compiletime version %s of module '%.100s' " + "does not match runtime version %s", + ctversion, __Pyx_MODULE_NAME, rtversion); + return PyErr_WarnEx(NULL, message, 1); + } + return 0; +} + +/* InitStrings */ +static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) { + while (t->p) { + #if PY_MAJOR_VERSION < 3 + if (t->is_unicode) { + *t->p = PyUnicode_DecodeUTF8(t->s, t->n - 1, NULL); + } else if (t->intern) { + *t->p = PyString_InternFromString(t->s); + } else { + *t->p = PyString_FromStringAndSize(t->s, t->n - 1); + } + #else + if (t->is_unicode | t->is_str) { + if (t->intern) { + *t->p = PyUnicode_InternFromString(t->s); + } else if (t->encoding) { + *t->p = PyUnicode_Decode(t->s, t->n - 1, t->encoding, NULL); + } else { + *t->p = PyUnicode_FromStringAndSize(t->s, t->n - 1); + } + } else { + *t->p = PyBytes_FromStringAndSize(t->s, t->n - 1); + } + #endif + if (!*t->p) + return -1; + if (PyObject_Hash(*t->p) == -1) + return -1; + ++t; + } + return 0; +} + +static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char* c_str) { + return __Pyx_PyUnicode_FromStringAndSize(c_str, (Py_ssize_t)strlen(c_str)); +} +static CYTHON_INLINE const char* __Pyx_PyObject_AsString(PyObject* o) { + Py_ssize_t ignore; + return __Pyx_PyObject_AsStringAndSize(o, &ignore); +} +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT +#if !CYTHON_PEP393_ENABLED +static const char* __Pyx_PyUnicode_AsStringAndSize(PyObject* o, Py_ssize_t *length) { + char* defenc_c; + PyObject* defenc = _PyUnicode_AsDefaultEncodedString(o, NULL); + if (!defenc) return NULL; + defenc_c = PyBytes_AS_STRING(defenc); +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + { + char* end = defenc_c + PyBytes_GET_SIZE(defenc); + char* c; + for (c = defenc_c; c < end; c++) { + if ((unsigned char) (*c) >= 128) { + PyUnicode_AsASCIIString(o); + return NULL; + } + } + } +#endif + *length = PyBytes_GET_SIZE(defenc); + return defenc_c; +} +#else +static CYTHON_INLINE const char* __Pyx_PyUnicode_AsStringAndSize(PyObject* o, Py_ssize_t *length) { + if (unlikely(__Pyx_PyUnicode_READY(o) == -1)) return NULL; +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + if (likely(PyUnicode_IS_ASCII(o))) { + *length = PyUnicode_GET_LENGTH(o); + return PyUnicode_AsUTF8(o); + } else { + PyUnicode_AsASCIIString(o); + return NULL; + } +#else + return PyUnicode_AsUTF8AndSize(o, length); +#endif +} +#endif +#endif +static CYTHON_INLINE const char* __Pyx_PyObject_AsStringAndSize(PyObject* o, Py_ssize_t *length) { +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT + if ( +#if PY_MAJOR_VERSION < 3 && __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + __Pyx_sys_getdefaultencoding_not_ascii && +#endif + PyUnicode_Check(o)) { + return __Pyx_PyUnicode_AsStringAndSize(o, length); + } else +#endif +#if (!CYTHON_COMPILING_IN_PYPY) || (defined(PyByteArray_AS_STRING) && defined(PyByteArray_GET_SIZE)) + if (PyByteArray_Check(o)) { + *length = PyByteArray_GET_SIZE(o); + return PyByteArray_AS_STRING(o); + } else +#endif + { + char* result; + int r = PyBytes_AsStringAndSize(o, &result, length); + if (unlikely(r < 0)) { + return NULL; + } else { + return result; + } + } +} +static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject* x) { + int is_true = x == Py_True; + if (is_true | (x == Py_False) | (x == Py_None)) return is_true; + else return PyObject_IsTrue(x); +} +static CYTHON_INLINE int __Pyx_PyObject_IsTrueAndDecref(PyObject* x) { + int retval; + if (unlikely(!x)) return -1; + retval = __Pyx_PyObject_IsTrue(x); + Py_DECREF(x); + return retval; +} +static PyObject* __Pyx_PyNumber_IntOrLongWrongResultType(PyObject* result, const char* type_name) { +#if PY_MAJOR_VERSION >= 3 + if (PyLong_Check(result)) { + if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, + "__int__ returned non-int (type %.200s). " + "The ability to return an instance of a strict subclass of int " + "is deprecated, and may be removed in a future version of Python.", + Py_TYPE(result)->tp_name)) { + Py_DECREF(result); + return NULL; + } + return result; + } +#endif + PyErr_Format(PyExc_TypeError, + "__%.4s__ returned non-%.4s (type %.200s)", + type_name, type_name, Py_TYPE(result)->tp_name); + Py_DECREF(result); + return NULL; +} +static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x) { +#if CYTHON_USE_TYPE_SLOTS + PyNumberMethods *m; +#endif + const char *name = NULL; + PyObject *res = NULL; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x) || PyLong_Check(x))) +#else + if (likely(PyLong_Check(x))) +#endif + return __Pyx_NewRef(x); +#if CYTHON_USE_TYPE_SLOTS + m = Py_TYPE(x)->tp_as_number; + #if PY_MAJOR_VERSION < 3 + if (m && m->nb_int) { + name = "int"; + res = m->nb_int(x); + } + else if (m && m->nb_long) { + name = "long"; + res = m->nb_long(x); + } + #else + if (likely(m && m->nb_int)) { + name = "int"; + res = m->nb_int(x); + } + #endif +#else + if (!PyBytes_CheckExact(x) && !PyUnicode_CheckExact(x)) { + res = PyNumber_Int(x); + } +#endif + if (likely(res)) { +#if PY_MAJOR_VERSION < 3 + if (unlikely(!PyInt_Check(res) && !PyLong_Check(res))) { +#else + if (unlikely(!PyLong_CheckExact(res))) { +#endif + return __Pyx_PyNumber_IntOrLongWrongResultType(res, name); + } + } + else if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, + "an integer is required"); + } + return res; +} +static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { + Py_ssize_t ival; + PyObject *x; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_CheckExact(b))) { + if (sizeof(Py_ssize_t) >= sizeof(long)) + return PyInt_AS_LONG(b); + else + return PyInt_AsSsize_t(b); + } +#endif + if (likely(PyLong_CheckExact(b))) { + #if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)b)->ob_digit; + const Py_ssize_t size = Py_SIZE(b); + if (likely(__Pyx_sst_abs(size) <= 1)) { + ival = likely(size) ? digits[0] : 0; + if (size == -1) ival = -ival; + return ival; + } else { + switch (size) { + case 2: + if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { + return (Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -2: + if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case 3: + if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { + return (Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -3: + if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case 4: + if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { + return (Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -4: + if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + } + } + #endif + return PyLong_AsSsize_t(b); + } + x = PyNumber_Index(b); + if (!x) return -1; + ival = PyInt_AsSsize_t(x); + Py_DECREF(x); + return ival; +} +static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject* o) { + if (sizeof(Py_hash_t) == sizeof(Py_ssize_t)) { + return (Py_hash_t) __Pyx_PyIndex_AsSsize_t(o); +#if PY_MAJOR_VERSION < 3 + } else if (likely(PyInt_CheckExact(o))) { + return PyInt_AS_LONG(o); +#endif + } else { + Py_ssize_t ival; + PyObject *x; + x = PyNumber_Index(o); + if (!x) return -1; + ival = PyInt_AsLong(x); + Py_DECREF(x); + return ival; + } +} +static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) { + return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False); +} +static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t ival) { + return PyInt_FromSize_t(ival); +} + + +#endif /* Py_PYTHON_H */ diff --git a/SiamMask/utils/pyvotkit/region.cpython-39-x86_64-linux-gnu.so b/SiamMask/utils/pyvotkit/region.cpython-39-x86_64-linux-gnu.so new file mode 100644 index 0000000000000000000000000000000000000000..577a062e84aabbffd5fae5788a8358d2607cd2bf Binary files /dev/null and b/SiamMask/utils/pyvotkit/region.cpython-39-x86_64-linux-gnu.so differ diff --git a/SiamMask/utils/pyvotkit/region.pyx b/SiamMask/utils/pyvotkit/region.pyx new file mode 100644 index 0000000000000000000000000000000000000000..59a99ce6f9b9a1b36efbf40283469f410ba280fd --- /dev/null +++ b/SiamMask/utils/pyvotkit/region.pyx @@ -0,0 +1,242 @@ +# distutils: sources = src/region.c +# distutils: include_dirs = src/ + +from libc.stdlib cimport malloc, free +from libc.stdio cimport sprintf +from libc.string cimport strlen + +cimport c_region + +cpdef enum RegionType: + EMTPY + SPECIAL + RECTANGEL + POLYGON + MASK + +cdef class RegionBounds: + cdef c_region.region_bounds* _c_region_bounds + + def __cinit__(self): + self._c_region_bounds = malloc( + sizeof(c_region.region_bounds)) + if not self._c_region_bounds: + self._c_region_bounds = NULL + raise MemoryError() + + def __init__(self, top, bottom, left, right): + self.set(top, bottom, left, right) + + def __dealloc__(self): + if self._c_region_bounds is not NULL: + free(self._c_region_bounds) + self._c_region_bounds = NULL + + def __str__(self): + return "top: {:.3f} bottom: {:.3f} left: {:.3f} reight: {:.3f}".format( + self._c_region_bounds.top, + self._c_region_bounds.bottom, + self._c_region_bounds.left, + self._c_region_bounds.right) + + def get(self): + return (self._c_region_bounds.top, + self._c_region_bounds.bottom, + self._c_region_bounds.left, + self._c_region_bounds.right) + + def set(self, top, bottom, left, right): + self._c_region_bounds.top = top + self._c_region_bounds.bottom = bottom + self._c_region_bounds.left = left + self._c_region_bounds.right = right + + + +cdef class Rectangle: + cdef c_region.region_rectangle* _c_region_rectangle + + def __cinit__(self): + self._c_region_rectangle = malloc( + sizeof(c_region.region_rectangle)) + if not self._c_region_rectangle: + self._c_region_rectangle = NULL + raise MemoryError() + + def __init__(self, x, y, width, height): + self.set(x, y, width, height) + + def __dealloc__(self): + if self._c_region_rectangle is not NULL: + free(self._c_region_rectangle) + self._c_region_rectangle = NULL + + def __str__(self): + return "x: {:.3f} y: {:.3f} width: {:.3f} height: {:.3f}".format( + self._c_region_rectangle.x, + self._c_region_rectangle.y, + self._c_region_rectangle.width, + self._c_region_rectangle.height) + + def set(self, x, y, width, height): + self._c_region_rectangle.x = x + self._c_region_rectangle.y = y + self._c_region_rectangle.width = width + self._c_region_rectangle.height = height + + def get(self): + """ + return: + (x, y, width, height) + """ + return (self._c_region_rectangle.x, + self._c_region_rectangle.y, + self._c_region_rectangle.width, + self._c_region_rectangle.height) + +cdef class Polygon: + cdef c_region.region_polygon* _c_region_polygon + + def __cinit__(self, points): + """ + args: + points: tuple of point + + points = ((1, 1), (10, 10)) + """ + num = len(points) + self._c_region_polygon = malloc( + sizeof(c_region.region_polygon)) + if not self._c_region_polygon: + self._c_region_polygon = NULL + raise MemoryError() + self._c_region_polygon.count = num + self._c_region_polygon.x = malloc(sizeof(float) * num) + if not self._c_region_polygon.x: + raise MemoryError() + self._c_region_polygon.y = malloc(sizeof(float) * num) + if not self._c_region_polygon.y: + raise MemoryError() + + for i in range(num): + self._c_region_polygon.x[i] = points[i][0] + self._c_region_polygon.y[i] = points[i][1] + + def __dealloc__(self): + if self._c_region_polygon is not NULL: + if self._c_region_polygon.x is not NULL: + free(self._c_region_polygon.x) + self._c_region_polygon.x = NULL + if self._c_region_polygon.y is not NULL: + free(self._c_region_polygon.y) + self._c_region_polygon.y = NULL + free(self._c_region_polygon) + self._c_region_polygon = NULL + + def __str__(self): + ret = "" + for i in range(self._c_region_polygon.count-1): + ret += "({:.3f} {:.3f}) ".format(self._c_region_polygon.x[i], + self._c_region_polygon.y[i]) + ret += "({:.3f} {:.3f})".format(self._c_region_polygon.x[i], + self._c_region_polygon.y[i]) + return ret + + + +# cdef float c_vot_overlap(c_region.region_polygon* p1, c_region.region_polygon* p2, +# bounds=RegionBounds(-float("inf"), float("inf"), +# float("inf"), float("inf"))): +# cdef float only1 = 0 +# cdef float only2 = 0 +# return c_region.compute_polygon_overlap(p1, +# p2, +# &only1, +# &only2, +# bounds._c_region_bounds) + +# def vot_overlap(p1, p2): +# return c_vot_overlap(p1, p2) + +def vot_overlap(polygon1, polygon2, bounds=None): + """ computing overlap between two polygon + Args: + polygon1: polygon tuple of points + polygon2: polygon tuple of points + bounds: tuple of (left, top, right, bottom) + Return: + overlap: overlap between two polygons + """ + polygon1_ = Polygon(polygon1) + polygon2_ = Polygon(polygon2) + cdef float only1 = 0 + cdef float only2 = 0 + # cdef c_region.region_polygon* c_polygon1 = polygon1._c_region_polygon + # cdef c_region.region_polygon* c_polygon2 = polygon2._c_region_polygon + cdef c_region.region_polygon* c_polygon1 = polygon1_._c_region_polygon + cdef c_region.region_polygon* c_polygon2 = polygon2_._c_region_polygon + cdef c_region.region_bounds no_bounds + if bounds is not None and len(bounds) == 2: + no_bounds.top = 0 + no_bounds.bottom = bounds[1] + no_bounds.left = 0 + no_bounds.right = bounds[0] + elif bounds is not None and len(bounds) == 4: + bounds.left = bounds[0] + bounds.top = bounds[1] + bounds.right = bounds[2] + bounds.bottom = bounds[3] + else: + no_bounds.top = -float("inf") + no_bounds.bottom = float("inf") + no_bounds.left = -float("inf") + no_bounds.right = float("inf") + return c_region.compute_polygon_overlap(c_polygon1, + c_polygon2, + &only1, + &only2, + no_bounds) + +def vot_overlap_traj(polygons1, polygons2, bounds): + """ computing overlap between two trajectory + Args: + polygons1: list of polygon + polygons2: list of polygon + """ + overlaps = [] + num = len(polygons1) + cdef float only1 = 0 + cdef float only2 = 0 + cdef c_region.region_bounds no_bounds + no_bounds.top = -float("inf") + no_bounds.bottom = float("inf") + no_bounds.left = -float("inf") + no_bounds.right = float("inf") + cdef c_region.region_polygon* c_polygon1 + cdef c_region.region_polygon* c_polygon2 + for i in range(num): + polygon1_ = Polygon(polygons1[i]) + polygon2_ = Polygon(polygons2[i]) + c_polygon1 = polygon1_._c_region_polygon + c_polygon2 = polygon2_._c_region_polygon + overlap = c_region.compute_polygon_overlap(c_polygon1, + c_polygon2, + &only1, + &only2, + no_bounds) + overlaps.append(overlap) + return overlaps + + +def vot_float2str(template, float value): + cdef bytes ptemplate = template.encode() + cdef const char* ctemplate = ptemplate + cdef char* output = malloc(sizeof(char) * 100) + if not output: + raise MemoryError() + sprintf(output, ctemplate, value) + try: + ret = output[:strlen(output)].decode() + finally: + free(output) + return ret diff --git a/SiamMask/utils/pyvotkit/setup.py b/SiamMask/utils/pyvotkit/setup.py new file mode 100644 index 0000000000000000000000000000000000000000..22d5879fda1e042c21de9ee34005a540fa38b1f2 --- /dev/null +++ b/SiamMask/utils/pyvotkit/setup.py @@ -0,0 +1,16 @@ +# -------------------------------------------------------- +# Python Single Object Tracking Evaluation +# Licensed under The MIT License [see LICENSE for details] +# Written by Fangyi Zhang +# @author fangyi.zhang@vipl.ict.ac.cn +# @project https://github.com/StrangerZhang/pysot-toolkit.git +# Revised for SiamMask by foolwood +# -------------------------------------------------------- +from distutils.core import setup +from distutils.extension import Extension +from Cython.Build import cythonize + +setup( + ext_modules = cythonize([Extension("region", ["region.pyx"])]) +) + diff --git a/SiamMask/utils/pyvotkit/src/buffer.h b/SiamMask/utils/pyvotkit/src/buffer.h new file mode 100644 index 0000000000000000000000000000000000000000..99986afb7c0c2d66dd4d3341d9446725975f6e8f --- /dev/null +++ b/SiamMask/utils/pyvotkit/src/buffer.h @@ -0,0 +1,190 @@ + +#ifndef __STRING_BUFFER_H +#define __STRING_BUFFER_H + +// Enable MinGW secure API for _snprintf_s +#define MINGW_HAS_SECURE_API 1 + +#ifdef _MSC_VER +#define __INLINE __inline +#else +#define __INLINE inline +#endif + +#include +#include +#include + +typedef struct string_buffer { + char* buffer; + int position; + int size; +} string_buffer; + +typedef struct string_list { + char** buffer; + int position; + int size; +} string_list; + +#define BUFFER_INCREMENT_STEP 4096 + +static __INLINE string_buffer* buffer_create(int L) { + string_buffer* B = (string_buffer*) malloc(sizeof(string_buffer)); + B->size = L; + B->buffer = (char*) malloc(sizeof(char) * B->size); + B->position = 0; + return B; +} + +static __INLINE void buffer_reset(string_buffer* B) { + B->position = 0; +} + +static __INLINE void buffer_destroy(string_buffer** B) { + if (!(*B)) return; + if ((*B)->buffer) { + free((*B)->buffer); + (*B)->buffer = NULL; + } + free((*B)); + (*B) = NULL; +} + +static __INLINE char* buffer_extract(const string_buffer* B) { + char *S = (char*) malloc(sizeof(char) * (B->position + 1)); + memcpy(S, B->buffer, B->position); + S[B->position] = '\0'; + return S; +} + +static __INLINE int buffer_size(const string_buffer* B) { + return B->position; +} + +static __INLINE void buffer_push(string_buffer* B, char C) { + int required = 1; + if (required > B->size - B->position) { + B->size = B->position + BUFFER_INCREMENT_STEP; + B->buffer = (char*) realloc(B->buffer, sizeof(char) * B->size); + } + B->buffer[B->position] = C; + B->position += required; +} + +static __INLINE void buffer_append(string_buffer* B, const char *format, ...) { + + int required; + va_list args; + +#if defined(__OS2__) || defined(__WINDOWS__) || defined(WIN32) || defined(_MSC_VER) + + va_start(args, format); + required = _vscprintf(format, args) + 1; + va_end(args); + if (required >= B->size - B->position) { + B->size = B->position + required + 1; + B->buffer = (char*) realloc(B->buffer, sizeof(char) * B->size); + } + va_start(args, format); + required = _vsnprintf_s(&(B->buffer[B->position]), B->size - B->position, _TRUNCATE, format, args); + va_end(args); + B->position += required; + +#else + va_start(args, format); + required = vsnprintf(&(B->buffer[B->position]), B->size - B->position, format, args); + va_end(args); + if (required >= B->size - B->position) { + B->size = B->position + required + 1; + B->buffer = (char*) realloc(B->buffer, sizeof(char) * B->size); + va_start(args, format); + required = vsnprintf(&(B->buffer[B->position]), B->size - B->position, format, args); + va_end(args); + } + B->position += required; +#endif + +} + +static __INLINE string_list* list_create(int L) { + string_list* B = (string_list*) malloc(sizeof(string_list)); + B->size = L; + B->buffer = (char**) malloc(sizeof(char*) * B->size); + memset(B->buffer, 0, sizeof(char*) * B->size); + B->position = 0; + return B; +} + +static __INLINE void list_reset(string_list* B) { + int i; + for (i = 0; i < B->position; i++) { + if (B->buffer[i]) free(B->buffer[i]); + B->buffer[i] = NULL; + } + B->position = 0; +} + +static __INLINE void list_destroy(string_list **B) { + int i; + + if (!(*B)) return; + + for (i = 0; i < (*B)->position; i++) { + if ((*B)->buffer[i]) free((*B)->buffer[i]); (*B)->buffer[i] = NULL; + } + + if ((*B)->buffer) { + free((*B)->buffer); (*B)->buffer = NULL; + } + + free((*B)); + (*B) = NULL; +} + +static __INLINE char* list_get(const string_list *B, int I) { + if (I < 0 || I >= B->position) { + return NULL; + } else { + if (!B->buffer[I]) { + return NULL; + } else { + char *S; + int length = strlen(B->buffer[I]); + S = (char*) malloc(sizeof(char) * (length + 1)); + memcpy(S, B->buffer[I], length + 1); + return S; + } + } +} + +static __INLINE int list_size(const string_list *B) { + return B->position; +} + +static __INLINE void list_append(string_list *B, char* S) { + int required = 1; + int length = strlen(S); + if (required > B->size - B->position) { + B->size = B->position + 16; + B->buffer = (char**) realloc(B->buffer, sizeof(char*) * B->size); + } + B->buffer[B->position] = (char*) malloc(sizeof(char) * (length + 1)); + memcpy(B->buffer[B->position], S, length + 1); + B->position += required; +} + +// This version of the append does not copy the string but simply takes the control of its allocation +static __INLINE void list_append_direct(string_list *B, char* S) { + int required = 1; + // int length = strlen(S); + if (required > B->size - B->position) { + B->size = B->position + 16; + B->buffer = (char**) realloc(B->buffer, sizeof(char*) * B->size); + } + B->buffer[B->position] = S; + B->position += required; +} + + +#endif diff --git a/SiamMask/utils/pyvotkit/src/region.c b/SiamMask/utils/pyvotkit/src/region.c new file mode 100644 index 0000000000000000000000000000000000000000..b91c43b6f5885e082b2bb88ed7dff0d0f295e911 --- /dev/null +++ b/SiamMask/utils/pyvotkit/src/region.c @@ -0,0 +1,1033 @@ + +#include +#include +#include +#include +#include +#include +#include + +#include "region.h" +#include "buffer.h" + +#if defined(__OS2__) || defined(__WINDOWS__) || defined(WIN32) || defined(_MSC_VER) +#ifndef isnan +#define isnan(x) _isnan(x) +#endif +#ifndef isinf +#define isinf(x) (!_finite(x)) +#endif +#ifndef inline +#define inline _inline +#endif +#endif + +/* Visual Studio 2013 was first to add C99 INFINITY and NAN */ +#if defined (_MSC_VER) && _MSC_VER < 1800 +#define INFINITY (DBL_MAX+DBL_MAX) +#define NAN (INFINITY-INFINITY) +#define round(fp) (int)((fp) >= 0 ? (fp) + 0.5 : (fp) - 0.5) +#endif + +#define PRINT_BOUNDS(B) printf("[left: %.2f, top: %.2f, right: %.2f, bottom: %.2f]\n", B.left, B.top, B.right, B.bottom) + +const region_bounds region_no_bounds = { -FLT_MAX, FLT_MAX, -FLT_MAX, FLT_MAX }; + +int __flags = 0; + +int region_set_flags(int mask) { + + __flags |= mask; + + return __flags; + +} + +int region_clear_flags(int mask) { + + __flags &= ~mask; + + return __flags; + +} + +int __is_valid_sequence(float* sequence, int len) { + int i; + + for (i = 0; i < len; i++) { + if (isnan(sequence[i])) return 0; + } + + return 1; +} + + +#define MAX_URI_SCHEME 16 + +const char* __parse_uri_prefix(const char* buffer, region_type* type) { + + int i = 0; + + *type = EMPTY; + + for (; i < MAX_URI_SCHEME; i++) { + if ((buffer[i] >= 'a' && buffer[i] <= 'z') || buffer[i] == '+' || buffer[i] == '.' || buffer[i] == '-') continue; + + if (buffer[i] == ':') { + if (strncmp(buffer, "rect", i - 1) == 0) + *type = RECTANGLE; + else if (strncmp(buffer, "poly", i - 1) == 0) + *type = POLYGON; + else if (strncmp(buffer, "mask", i - 1) == 0) + *type = MASK; + else if (strncmp(buffer, "special", i - 1) == 0) + *type = SPECIAL; + return &(buffer[i + 1]); + } + + return buffer; + } + + return buffer; + +} + +region_container* __create_region(region_type type) { + + region_container* reg = (region_container*) malloc(sizeof(region_container)); + + reg->type = type; + + return reg; + +} + +static inline const char* _str_find(const char* in, const char delimiter) { + + int i = 0; + while (in[i] && in[i] != delimiter) { + i++; + } + + return (in[i] == delimiter) ? &(in[i]) + 1 : NULL; + +} + +int _parse_sequence(const char* buffer, float** data) { + + int i; + + float* numbers = (float*) malloc(sizeof(float) * (strlen(buffer) / 2)); + + const char* pch = buffer; + for (i = 0; ; i++) { + + if (pch) { +#if defined (_MSC_VER) + if (tolower(pch[0]) == 'n' && tolower(pch[1]) == 'a' && tolower(pch[2]) == 'n') { + numbers[i] = NAN; + } else { + numbers[i] = (float) atof(pch); + } +#else + numbers[i] = (float) atof(pch); +#endif + } else + break; + + pch = _str_find(pch, ','); + } + + if (i > 0) { + int j; + *data = (float*) malloc(sizeof(float) * i); + for (j = 0; j < i; j++) { (*data)[j] = numbers[j]; } + free(numbers); + } else { + *data = NULL; + free(numbers); + } + + return i; +} + +int region_parse(const char* buffer, region_container** region) { + + float* data = NULL; + const char* strdata = NULL; + int num; + + region_type prefix_type; + + // const char* tmp = buffer; + + (*region) = NULL; + + if (!buffer || !buffer[0]) { + return 1; + } + + strdata = __parse_uri_prefix(buffer, &prefix_type); + + num = _parse_sequence(strdata, &data); + + // If at least one of the elements is NaN, then the region cannot be parsed + // We return special region with a default code. + if (!__is_valid_sequence(data, num) || num == 0) { + // Preserve legacy support: if four values are given and the fourth one is a number + // then this number is taken as a code. + if (num == 4 && !isnan(data[3])) { + (*region) = region_create_special(-(int) data[3]); + } else { + (*region) = region_create_special(TRAX_DEFAULT_CODE); + } + free(data); + return 1; + } + + if (prefix_type == EMPTY && num > 0) { + if (num == 1) + prefix_type = SPECIAL; + else if (num == 4) + prefix_type = RECTANGLE; + else if (num >= 6 && num % 2 == 0) + prefix_type = POLYGON; + } + + switch (prefix_type) { + case SPECIAL: { + assert(num == 1); + (*region) = (region_container*) malloc(sizeof(region_container)); + (*region)->type = SPECIAL; + (*region)->data.special = (int) data[0]; + free(data); + return 1; + + } + case RECTANGLE: { + assert(num == 4); + (*region) = (region_container*) malloc(sizeof(region_container)); + (*region)->type = RECTANGLE; + + (*region)->data.rectangle.x = data[0]; + (*region)->data.rectangle.y = data[1]; + (*region)->data.rectangle.width = data[2]; + (*region)->data.rectangle.height = data[3]; + + free(data); + return 1; + + } + case POLYGON: { + int j; + + assert(num >= 6 && num % 2 == 0); + + (*region) = (region_container*) malloc(sizeof(region_container)); + (*region)->type = POLYGON; + + (*region)->data.polygon.count = num / 2; + (*region)->data.polygon.x = (float*) malloc(sizeof(float) * (*region)->data.polygon.count); + (*region)->data.polygon.y = (float*) malloc(sizeof(float) * (*region)->data.polygon.count); + + for (j = 0; j < (*region)->data.polygon.count; j++) { + (*region)->data.polygon.x[j] = data[j * 2]; + (*region)->data.polygon.y[j] = data[j * 2 + 1]; + } + + free(data); + return 1; + case EMPTY: + return 1; + case MASK: + return 1; + } + /* case MASK: { + + int i; + int position; + int value; + + assert(num > 4); + + (*region) = (region_container*) malloc(sizeof(region_container)); + (*region)->type = MASK; + + (*region)->data.mask.x = (int) data[0]; + (*region)->data.mask.y = (int) data[1]; + (*region)->data.mask.width = (int) data[2]; + (*region)->data.mask.height = (int) data[3]; + + (*region)->data.mask.data = (char*) malloc(sizeof(char) * (*region)->data.mask.width * (*region)->data.mask.height); + + value = 0; + position = 0; + + for (i = 4; i < num; i++) { + + int count = + + + + + } + + + }*/ + } + + if (data) free(data); + + return 0; +} + +char* region_string(region_container* region) { + + int i; + char* result = NULL; + string_buffer *buffer; + + if (!region) return NULL; + + buffer = buffer_create(32); + + if (region->type == SPECIAL) { + + buffer_append(buffer, "%d", region->data.special); + + } else if (region->type == RECTANGLE) { + + buffer_append(buffer, "%.4f,%.4f,%.4f,%.4f", + region->data.rectangle.x, region->data.rectangle.y, + region->data.rectangle.width, region->data.rectangle.height); + + } else if (region->type == POLYGON) { + + for (i = 0; i < region->data.polygon.count; i++) { + buffer_append(buffer, (i == 0 ? "%.4f,%.4f" : ",%.4f,%.4f"), region->data.polygon.x[i], region->data.polygon.y[i]); + } + } + + if (buffer_size(buffer) > 0) + result = buffer_extract(buffer); + buffer_destroy(&buffer); + + return result; +} + +void region_print(FILE* out, region_container* region) { + + char* buffer = region_string(region); + + if (buffer) { + fputs(buffer, out); + free(buffer); + } + +} + +region_container* region_convert(const region_container* region, region_type type) { + + region_container* reg = NULL; + switch (type) { + + case RECTANGLE: { + + reg = (region_container*) malloc(sizeof(region_container)); + reg->type = type; + + switch (region->type) { + case RECTANGLE: + reg->data.rectangle = region->data.rectangle; + break; + case POLYGON: { + + float top = FLT_MAX; + float bottom = FLT_MIN; + float left = FLT_MAX; + float right = FLT_MIN; + int i; + + for (i = 0; i < region->data.polygon.count; i++) { + top = MIN(top, region->data.polygon.y[i]); + bottom = MAX(bottom, region->data.polygon.y[i]); + left = MIN(left, region->data.polygon.x[i]); + right = MAX(right, region->data.polygon.x[i]); + } + + reg->data.rectangle.x = left; + reg->data.rectangle.y = top; + reg->data.rectangle.width = right - left; + reg->data.rectangle.height = bottom - top; + break; + } + case SPECIAL: { + free(reg); reg = NULL; + break; + } + default: { + free(reg); reg = NULL; + break; + } + } + break; + } + + case POLYGON: { + + reg = (region_container*) malloc(sizeof(region_container)); + reg->type = type; + + switch (region->type) { + case RECTANGLE: { + + reg->data.polygon.count = 4; + + reg->data.polygon.x = (float *) malloc(sizeof(float) * reg->data.polygon.count); + reg->data.polygon.y = (float *) malloc(sizeof(float) * reg->data.polygon.count); + + if (__flags & REGION_LEGACY_RASTERIZATION) { + + reg->data.polygon.x[0] = region->data.rectangle.x; + reg->data.polygon.x[1] = region->data.rectangle.x + region->data.rectangle.width; + reg->data.polygon.x[2] = region->data.rectangle.x + region->data.rectangle.width; + reg->data.polygon.x[3] = region->data.rectangle.x; + + reg->data.polygon.y[0] = region->data.rectangle.y; + reg->data.polygon.y[1] = region->data.rectangle.y; + reg->data.polygon.y[2] = region->data.rectangle.y + region->data.rectangle.height; + reg->data.polygon.y[3] = region->data.rectangle.y + region->data.rectangle.height; + + } else { + + reg->data.polygon.x[0] = region->data.rectangle.x; + reg->data.polygon.x[1] = region->data.rectangle.x + region->data.rectangle.width - 1; + reg->data.polygon.x[2] = region->data.rectangle.x + region->data.rectangle.width - 1; + reg->data.polygon.x[3] = region->data.rectangle.x; + + reg->data.polygon.y[0] = region->data.rectangle.y; + reg->data.polygon.y[1] = region->data.rectangle.y; + reg->data.polygon.y[2] = region->data.rectangle.y + region->data.rectangle.height - 1; + reg->data.polygon.y[3] = region->data.rectangle.y + region->data.rectangle.height - 1; + + } + + break; + } + case POLYGON: { + + reg->data.polygon.count = region->data.polygon.count; + + reg->data.polygon.x = (float *) malloc(sizeof(float) * region->data.polygon.count); + reg->data.polygon.y = (float *) malloc(sizeof(float) * region->data.polygon.count); + + memcpy(reg->data.polygon.x, region->data.polygon.x, sizeof(float) * region->data.polygon.count); + memcpy(reg->data.polygon.y, region->data.polygon.y, sizeof(float) * region->data.polygon.count); + + break; + } + case SPECIAL: { + free(reg); reg = NULL; + break; + } + default: { + free(reg); reg = NULL; + break; + } + } + break; + + case SPECIAL: { + if (region->type == SPECIAL) + // If source is also code then just copy the value + reg = region_create_special(region->data.special); + else + // All types are converted to default region + reg = region_create_special(TRAX_DEFAULT_CODE); + break; + } + + default: + break; + + } + + } + + return reg; + +} + +void region_release(region_container** region) { + + switch ((*region)->type) { + case RECTANGLE: + break; + case POLYGON: + free((*region)->data.polygon.x); + free((*region)->data.polygon.y); + (*region)->data.polygon.count = 0; + break; + case SPECIAL: { + break; + } + case MASK: + break; + case EMPTY: + break; + } + + free(*region); + + *region = NULL; + +} + +region_container* region_create_special(int code) { + + region_container* reg = __create_region(SPECIAL); + + reg->data.special = code; + + return reg; + +} + +region_container* region_create_rectangle(float x, float y, float width, float height) { + + region_container* reg = __create_region(RECTANGLE); + + reg->data.rectangle.width = width; + reg->data.rectangle.height = height; + reg->data.rectangle.x = x; + reg->data.rectangle.y = y; + + return reg; + +} + +region_container* region_create_polygon(int count) { + + assert(count > 0); + + { + + region_container* reg = __create_region(POLYGON); + + reg->data.polygon.count = count; + reg->data.polygon.x = (float *) malloc(sizeof(float) * count); + reg->data.polygon.y = (float *) malloc(sizeof(float) * count); + + return reg; + + } +} + +#define MAX_MASK 10000 + +void free_polygon(region_polygon* polygon) { + + free(polygon->x); + free(polygon->y); + + polygon->x = NULL; + polygon->y = NULL; + + polygon->count = 0; + +} + +region_polygon* allocate_polygon(int count) { + + region_polygon* polygon = (region_polygon*) malloc(sizeof(region_polygon)); + + polygon->count = count; + + polygon->x = (float*) malloc(sizeof(float) * count); + polygon->y = (float*) malloc(sizeof(float) * count); + + memset(polygon->x, 0, sizeof(float) * count); + memset(polygon->y, 0, sizeof(float) * count); + + return polygon; +} + +region_polygon* clone_polygon(const region_polygon* polygon) { + + region_polygon* clone = allocate_polygon(polygon->count); + + memcpy(clone->x, polygon->x, sizeof(float) * polygon->count); + memcpy(clone->y, polygon->y, sizeof(float) * polygon->count); + + return clone; +} + +region_polygon* offset_polygon(const region_polygon* polygon, float x, float y) { + + int i; + region_polygon* clone = clone_polygon(polygon); + + for (i = 0; i < clone->count; i++) { + clone->x[i] += x; + clone->y[i] += y; + } + + return clone; +} + +region_polygon* round_polygon(const region_polygon* polygon) { + + int i; + region_polygon* clone = clone_polygon(polygon); + + for (i = 0; i < clone->count; i++) { + clone->x[i] = round(clone->x[i]); + clone->y[i] = round(clone->y[i]); + } + + return clone; +} + +int point_in_polygon(const region_polygon* polygon, float x, float y) { + int i, j, c = 0; + for (i = 0, j = polygon->count - 1; i < polygon->count; j = i++) { + if ( ((polygon->y[i] > y) != (polygon->y[j] > y)) && + (x < (polygon->x[j] - polygon->x[i]) * (y - polygon->y[i]) / (polygon->y[j] - polygon->y[i]) + polygon->x[i]) ) + c = !c; + } + return c; +} + +void print_polygon(const region_polygon* polygon) { + + int i; + printf("%d:", polygon->count); + + for (i = 0; i < polygon->count; i++) { + printf(" (%f, %f)", polygon->x[i], polygon->y[i]); + } + + printf("\n"); + +} + +region_bounds compute_bounds(const region_polygon* polygon) { + + int i; + region_bounds bounds; + bounds.top = FLT_MAX; + bounds.bottom = -FLT_MAX; + bounds.left = FLT_MAX; + bounds.right = -FLT_MAX; + + for (i = 0; i < polygon->count; i++) { + bounds.top = MIN(bounds.top, polygon->y[i]); + bounds.bottom = MAX(bounds.bottom, polygon->y[i]); + bounds.left = MIN(bounds.left, polygon->x[i]); + bounds.right = MAX(bounds.right, polygon->x[i]); + } + + return bounds; + +} + +region_bounds bounds_round(region_bounds bounds) { + + bounds.top = floor(bounds.top); + bounds.bottom = ceil(bounds.bottom); + bounds.left = floor(bounds.left); + bounds.right = ceil(bounds.right); + + return bounds; + +} + +region_bounds bounds_intersection(region_bounds a, region_bounds b) { + + region_bounds result; + + result.top = MAX(a.top, b.top); + result.bottom = MIN(a.bottom, b.bottom); + result.left = MAX(a.left, b.left); + result.right = MIN(a.right, b.right); + + return result; + +} + +region_bounds bounds_union(region_bounds a, region_bounds b) { + + region_bounds result; + + result.top = MIN(a.top, b.top); + result.bottom = MAX(a.bottom, b.bottom); + result.left = MIN(a.left, b.left); + result.right = MAX(a.right, b.right); + + return result; + +} + +float bounds_overlap(region_bounds a, region_bounds b) { + + region_bounds rintersection = bounds_intersection(a, b); + float intersection = (rintersection.right - rintersection.left) * (rintersection.bottom - rintersection.top); + + return MAX(0, intersection / (((a.right - a.left) * (a.bottom - a.top)) + ((b.right - b.left) * (b.bottom - b.top)) - intersection)); + +} + +region_bounds region_create_bounds(float left, float top, float right, float bottom) { + + region_bounds result; + + result.top = top; + result.bottom = bottom; + result.left = left; + result.right = right; + + return result; +} + +region_bounds region_compute_bounds(const region_container* region) { + + region_bounds bounds; + switch (region->type) { + case RECTANGLE: + if (__flags & REGION_LEGACY_RASTERIZATION) { + bounds = region_create_bounds(region->data.rectangle.x, + region->data.rectangle.y, + region->data.rectangle.x + region->data.rectangle.width, + region->data.rectangle.y + region->data.rectangle.height); + } else { + bounds = region_create_bounds(region->data.rectangle.x, + region->data.rectangle.y, + region->data.rectangle.x + region->data.rectangle.width - 1, + region->data.rectangle.y + region->data.rectangle.height - 1); + } + break; + case POLYGON: { + bounds = compute_bounds(&(region->data.polygon)); + break; + } + default: { + bounds = region_no_bounds; + break; + } + } + + return bounds; + +} + +int rasterize_polygon(const region_polygon* polygon_input, char* mask, int width, int height) { + + int nodes, pixelY, i, j, swap; + int sum = 0; + region_polygon* polygon = (region_polygon*) polygon_input; + + int* nodeX = (int*) malloc(sizeof(int) * polygon->count); + + if (mask) memset(mask, 0, width * height * sizeof(char)); + + if (__flags & REGION_LEGACY_RASTERIZATION) { + + /* Loop through the rows of the image. */ + for (pixelY = 0; pixelY < height; pixelY++) { + + /* Build a list of nodes. */ + nodes = 0; + j = polygon->count - 1; + + for (i = 0; i < polygon->count; i++) { + if (((polygon->y[i] < (double) pixelY) && (polygon->y[j] >= (double) pixelY)) || + ((polygon->y[j] < (double) pixelY) && (polygon->y[i] >= (double) pixelY))) { + nodeX[nodes++] = (int) (polygon->x[i] + (pixelY - polygon->y[i]) / + (polygon->y[j] - polygon->y[i]) * (polygon->x[j] - polygon->x[i])); + } + j = i; + } + + /* Sort the nodes, via a simple “Bubble” sort. */ + i = 0; + while (i < nodes - 1) { + if (nodeX[i] > nodeX[i + 1]) { + swap = nodeX[i]; + nodeX[i] = nodeX[i + 1]; + nodeX[i + 1] = swap; + if (i) i--; + } else { + i++; + } + } + + /* Fill the pixels between node pairs. */ + for (i = 0; i < nodes; i += 2) { + if (nodeX[i] >= width) break; + if (nodeX[i + 1] > 0 ) { + if (nodeX[i] < 0 ) nodeX[i] = 0; + if (nodeX[i + 1] > width) nodeX[i + 1] = width - 1; + for (j = nodeX[i]; j < nodeX[i + 1]; j++) { + if (mask) mask[pixelY * width + j] = 1; + sum++; + } + } + } + } + + } else { + + polygon = round_polygon(polygon_input); + + /* Loop through the rows of the image. */ + for (pixelY = 0; pixelY < height; pixelY++) { + + /* Build a list of nodes. */ + nodes = 0; + j = polygon->count - 1; + + for (i = 0; i < polygon->count; i++) { + if ((((int)polygon->y[i] <= pixelY) && ((int)polygon->y[j] > pixelY)) || + (((int)polygon->y[j] <= pixelY) && ((int)polygon->y[i] > pixelY)) || + (((int)polygon->y[i] < pixelY) && ((int)polygon->y[j] >= pixelY)) || + (((int)polygon->y[j] < pixelY) && ((int)polygon->y[i] >= pixelY)) || + (((int)polygon->y[i] == (int)polygon->y[j]) && ((int)polygon->y[i] == pixelY))) { + double r = (polygon->y[j] - polygon->y[i]); + double k = (polygon->x[j] - polygon->x[i]); + if (r != 0) + nodeX[nodes++] = (int) ((double) polygon->x[i] + (double) (pixelY - polygon->y[i]) / r * k); + } + j = i; + } + /* Sort the nodes, via a simple “Bubble” sort. */ + i = 0; + while (i < nodes - 1) { + if (nodeX[i] > nodeX[i + 1]) { + swap = nodeX[i]; + nodeX[i] = nodeX[i + 1]; + nodeX[i + 1] = swap; + if (i) i--; + } else { + i++; + } + } + + /* Fill the pixels between node pairs. */ + i = 0; + while (i < nodes - 1) { + // If a point is in the line then we get two identical values + // Ignore the first + if (nodeX[i] == nodeX[i + 1]) { + i++; + continue; + } + + if (nodeX[i] >= width) break; + if (nodeX[i + 1] >= 0) { + if (nodeX[i] < 0) nodeX[i] = 0; + if (nodeX[i + 1] >= width) nodeX[i + 1] = width - 1; + for (j = nodeX[i]; j <= nodeX[i + 1]; j++) { + if (mask) mask[pixelY * width + j] = 1; + sum++; + } + } + i += 2; + + } + } + + free_polygon(polygon); + + } + + free(nodeX); + + return sum; +} + +float compute_polygon_overlap(const region_polygon* p1, const region_polygon* p2, float *only1, float *only2, region_bounds bounds) { + + int i; + int vol_1 = 0; + int vol_2 = 0; + int mask_1 = 0; + int mask_2 = 0; + int mask_intersect = 0; + char* mask1 = NULL; + char* mask2 = NULL; + double a1, a2; + float x, y; + int width, height; + region_polygon *op1, *op2; + region_bounds b1, b2; + + if (__flags & REGION_LEGACY_RASTERIZATION) { + b1 = bounds_intersection(compute_bounds(p1), bounds); + b2 = bounds_intersection(compute_bounds(p2), bounds); + } else { + b1 = bounds_intersection(bounds_round(compute_bounds(p1)), bounds); + b2 = bounds_intersection(bounds_round(compute_bounds(p2)), bounds); + } + + x = MIN(b1.left, b2.left); + y = MIN(b1.top, b2.top); + + width = (int) (MAX(b1.right, b2.right) - x) + 1; + height = (int) (MAX(b1.bottom, b2.bottom) - y) + 1; + + // Fixing crashes due to overflowed regions, a simple check if the ratio + // between the two bounding boxes is simply too big and the overlap would + // be 0 anyway. + + a1 = (b1.right - b1.left) * (b1.bottom - b1.top); + a2 = (b2.right - b2.left) * (b2.bottom - b2.top); + + if (a1 / a2 < 1e-10 || a2 / a1 < 1e-10 || width < 1 || height < 1) { + + if (only1) + (*only1) = 0; + + if (only2) + (*only2) = 0; + + return 0; + + } + + if (bounds_overlap(b1, b2) == 0) { + + if (only1 || only2) { + vol_1 = rasterize_polygon(p1, NULL, b1.right - b1.left + 1, b1.bottom - b1.top + 1); + vol_2 = rasterize_polygon(p2, NULL, b2.right - b2.left + 1, b2.bottom - b2.top + 1); + + if (only1) + (*only1) = (float) vol_1 / (float) (vol_1 + vol_2); + + if (only2) + (*only2) = (float) vol_2 / (float) (vol_1 + vol_2); + } + + return 0; + + } + + mask1 = (char*) malloc(sizeof(char) * width * height); + mask2 = (char*) malloc(sizeof(char) * width * height); + + op1 = offset_polygon(p1, -x, -y); + op2 = offset_polygon(p2, -x, -y); + + rasterize_polygon(op1, mask1, width, height); + rasterize_polygon(op2, mask2, width, height); + + for (i = 0; i < width * height; i++) { + if (mask1[i]) vol_1++; + if (mask2[i]) vol_2++; + if (mask1[i] && mask2[i]) mask_intersect++; + else if (mask1[i]) mask_1++; + else if (mask2[i]) mask_2++; + } + + free_polygon(op1); + free_polygon(op2); + + free(mask1); + free(mask2); + + if (only1) + (*only1) = (float) mask_1 / (float) (mask_1 + mask_2 + mask_intersect); + + if (only2) + (*only2) = (float) mask_2 / (float) (mask_1 + mask_2 + mask_intersect); + + return (float) mask_intersect / (float) (mask_1 + mask_2 + mask_intersect); + +} + +#define COPY_POLYGON(TP, P) { P.count = TP->data.polygon.count; P.x = TP->data.polygon.x; P.y = TP->data.polygon.y; } + +region_overlap region_compute_overlap(const region_container* ra, const region_container* rb, region_bounds bounds) { + + region_container* ta = (region_container *) ra; + region_container* tb = (region_container *) rb; + region_overlap overlap; + overlap.overlap = 0; + overlap.only1 = 0; + overlap.only2 = 0; + + if (ra->type == RECTANGLE) + ta = region_convert(ra, POLYGON); + + if (rb->type == RECTANGLE) + tb = region_convert(rb, POLYGON); + + if (ta->type == POLYGON && tb->type == POLYGON) { + + region_polygon p1, p2; + + COPY_POLYGON(ta, p1); + COPY_POLYGON(tb, p2); + + overlap.overlap = compute_polygon_overlap(&p1, &p2, &(overlap.only1), &(overlap.only2), bounds); + + } + + if (ta != ra) + region_release(&ta); + + if (tb != rb) + region_release(&tb); + + return overlap; + +} + +int region_contains_point(region_container* r, float x, float y) { + + if (r->type == RECTANGLE) { + if (x >= (r->data.rectangle).x && x <= ((r->data.rectangle).width + (r->data.rectangle).x) && + y >= (r->data.rectangle).y && y <= ((r->data.rectangle).height + (r->data.rectangle).y)) + return 1; + return 0; + } + + if (r->type == POLYGON) + return point_in_polygon(&(r->data.polygon), x, y); + + return 0; + +} + +void region_get_mask(region_container* r, char* mask, int width, int height) { + + region_container* t = r; + + if (r->type == RECTANGLE) + t = region_convert(r, POLYGON); + + rasterize_polygon(&(t->data.polygon), mask, width, height); + + if (t != r) + region_release(&t); + +} + +void region_get_mask_offset(region_container* r, char* mask, int x, int y, int width, int height) { + + region_container* t = r; + region_polygon *p; + + if (r->type == RECTANGLE) + t = region_convert(r, POLYGON); + + p = offset_polygon(&(t->data.polygon), -x, -y); + + rasterize_polygon(p, mask, width, height); + + free_polygon(p); + + if (t != r) + region_release(&t); + +} + diff --git a/SiamMask/utils/pyvotkit/src/region.h b/SiamMask/utils/pyvotkit/src/region.h new file mode 100644 index 0000000000000000000000000000000000000000..abf57c2d97080ff57e6df9027e395fee0f792fd5 --- /dev/null +++ b/SiamMask/utils/pyvotkit/src/region.h @@ -0,0 +1,145 @@ +/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 4 -*- */ + +#ifndef _REGION_H_ +#define _REGION_H_ + +#ifdef TRAX_STATIC_DEFINE +# define __TRAX_EXPORT +#else +# ifndef __TRAX_EXPORT +# if defined(_MSC_VER) +# ifdef trax_EXPORTS + /* We are building this library */ +# define __TRAX_EXPORT __declspec(dllexport) +# else + /* We are using this library */ +# define __TRAX_EXPORT __declspec(dllimport) +# endif +# elif defined(__GNUC__) +# ifdef trax_EXPORTS + /* We are building this library */ +# define __TRAX_EXPORT __attribute__((visibility("default"))) +# else + /* We are using this library */ +# define __TRAX_EXPORT __attribute__((visibility("default"))) +# endif +# endif +# endif +#endif + +#ifndef MAX +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifndef MIN +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#define TRAX_DEFAULT_CODE 0 + +#define REGION_LEGACY_RASTERIZATION 1 + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum region_type {EMPTY, SPECIAL, RECTANGLE, POLYGON, MASK} region_type; + +typedef struct region_bounds { + + float top; + float bottom; + float left; + float right; + +} region_bounds; + +typedef struct region_polygon { + + int count; + + float* x; + float* y; + +} region_polygon; + +typedef struct region_mask { + + int x; + int y; + + int width; + int height; + + char* data; + +} region_mask; + +typedef struct region_rectangle { + + float x; + float y; + float width; + float height; + +} region_rectangle; + +typedef struct region_container { + enum region_type type; + union { + region_rectangle rectangle; + region_polygon polygon; + region_mask mask; + int special; + } data; +} region_container; + +typedef struct region_overlap { + + float overlap; + float only1; + float only2; + +} region_overlap; + +extern const region_bounds region_no_bounds; + +__TRAX_EXPORT int region_set_flags(int mask); + +__TRAX_EXPORT int region_clear_flags(int mask); + +__TRAX_EXPORT region_overlap region_compute_overlap(const region_container* ra, const region_container* rb, region_bounds bounds); + +__TRAX_EXPORT float compute_polygon_overlap(const region_polygon* p1, const region_polygon* p2, float *only1, float *only2, region_bounds bounds); + +__TRAX_EXPORT region_bounds region_create_bounds(float left, float top, float right, float bottom); + +__TRAX_EXPORT region_bounds region_compute_bounds(const region_container* region); + +__TRAX_EXPORT int region_parse(const char* buffer, region_container** region); + +__TRAX_EXPORT char* region_string(region_container* region); + +__TRAX_EXPORT void region_print(FILE* out, region_container* region); + +__TRAX_EXPORT region_container* region_convert(const region_container* region, region_type type); + +__TRAX_EXPORT void region_release(region_container** region); + +__TRAX_EXPORT region_container* region_create_special(int code); + +__TRAX_EXPORT region_container* region_create_rectangle(float x, float y, float width, float height); + +__TRAX_EXPORT region_container* region_create_polygon(int count); + +__TRAX_EXPORT int region_contains_point(region_container* r, float x, float y); + +__TRAX_EXPORT void region_get_mask(region_container* r, char* mask, int width, int height); + +__TRAX_EXPORT void region_get_mask_offset(region_container* r, char* mask, int x, int y, int width, int height); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/SiamMask/utils/tracker_config.py b/SiamMask/utils/tracker_config.py new file mode 100644 index 0000000000000000000000000000000000000000..630a3ddbd66a70635f730723b7a812a58ffb0ee9 --- /dev/null +++ b/SiamMask/utils/tracker_config.py @@ -0,0 +1,51 @@ +# -------------------------------------------------------- +# SiamMask +# Licensed under The MIT License +# Written by Qiang Wang (wangqiang2015 at ia.ac.cn) +# -------------------------------------------------------- +from __future__ import division +from utils.anchors import Anchors + + +class TrackerConfig(object): + # These are the default hyper-params for SiamMask + penalty_k = 0.09 + window_influence = 0.39 + lr = 0.38 + seg_thr = 0.3 # for mask + windowing = 'cosine' # to penalize large displacements [cosine/uniform] + # Params from the network architecture, have to be consistent with the training + exemplar_size = 127 # input z size + instance_size = 255 # input x size (search region) + total_stride = 8 + out_size = 63 # for mask + base_size = 8 + score_size = (instance_size-exemplar_size)//total_stride+1+base_size + context_amount = 0.5 # context amount for the exemplar + ratios = [0.33, 0.5, 1, 2, 3] + scales = [8, ] + anchor_num = len(ratios) * len(scales) + round_dight = 0 + anchor = [] + + def update(self, newparam=None, anchors=None): + if newparam: + for key, value in newparam.items(): + setattr(self, key, value) + if anchors is not None: + if isinstance(anchors, dict): + anchors = Anchors(anchors) + if isinstance(anchors, Anchors): + self.total_stride = anchors.stride + self.ratios = anchors.ratios + self.scales = anchors.scales + self.round_dight = anchors.round_dight + self.renew() + + def renew(self): + self.score_size = (self.instance_size - self.exemplar_size) // self.total_stride + 1 + self.base_size + self.anchor_num = len(self.ratios) * len(self.scales) + + + +