# -*- coding: UTF-8 -*-
import socket
import struct
import sys, os
import torch
import torch.nn as nn
import torch.nn.functional as F
import numpy as np

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

class Net(nn.Module):
    def __init__(self, out):
        super(Net, self).__init__()
        self.layer1 = nn.Sequential(
            nn.Conv2d(1, 27, kernel_size=6, stride=1, padding=2).double(),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2))
        self.layer2 = nn.Sequential(
            nn.Conv2d(27, 54, kernel_size=4, stride=1, padding=2).double(),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2))
        self.drop_out = nn.Dropout()
        self.fc1 = nn.Linear(5*7*54, 800).double()
        self.fc2 = nn.Linear(800, 200).double()
        self.fc3 = nn.Linear(200, out).double()
    def forward(self, x):
        out = self.layer1(x)
        out = self.layer2(out)
        out = out.reshape(out.size(0), -1)
        out = self.drop_out(out)
        out = F.relu(self.fc1(out))
        out = F.relu(self.fc2(out))
        out = self.fc3(out)
        return out

drev = {'A': 'А', 'B': 'Б', 'V': 'В', 'G': 'Г', 'D': 'Д', 'Dj': 'Ђ', 'DJ': 'Ђ', 'E': 'Е', 'I': 'И', 'J': 'Ј', 'K': 'К', 'L': 'Л', 'Lj': 'Љ', 'LJ': 'Љ', 'M': 'М', 'N': 'Н', 'Nj': 'Њ', 'NJ': 'Њ', 'O': 'О', 'P': 'П', 'R': 'Р', 'T': 'Т', 'U': 'У', 'F': 'Ф', 'H': 'Х', 'Dz': 'Џ', 'DZ': 'Џ', 'a': 'а', 'b': 'б', 'v': 'в', 'g': 'г', 'd': 'д', 'dj': 'ђ', 'e': 'е', 'i': 'и', 'j': 'ј', 'k': 'к', 'l': 'л', 'lj': 'љ', 'm': 'м', 'n': 'н', 'nj': 'њ', 'o': 'о', 'p': 'п', 'r': 'р', 't': 'т', 'u': 'у', 'f': 'ф', 'h': 'х', 'dz': 'џ'}
asci = [' ','a','b','v','g','d','dj','e','z','i','j','k','l','lj','m','n','nj','o','p','r','s','t','c','u','f','h','dz']
asci_len = len(asci)

predic = {
        ('s',0):'с',
        ('s',1):'ш',
        ('z',0):'з',
        ('z',1):'ж',
        ('c',0):'ц',
        ('c',1):'ћ',
        ('c',2):'ч',
        }

nets = {'s': Net(2).to(device), 'z': Net(2).to(device), 'c': Net(3).to(device)}

def load_nets(nets, nets_path):
    checkpoint = torch.load(nets_path, map_location=device)
    for k in nets.keys():
        nets[k].load_state_dict(checkpoint[k+'_net'])
        nets[k].eval()

critical_latin = ['s', 'z', 'c']
two_letter_letter = ['nj', 'lj', 'dz', 'dj']

def alpha_or_ws(x):
    if x == ' ':
        return True
    return x.isalpha()

def textToList(text):
    l = len(text)
    text += ' '
    caps = []
    huks = {}
    news = []
    orig = []
    i = 0
    while i < l:
        if not alpha_or_ws(text[i]):
            orig.append(text[i])
            i += 1
            continue
        if text[i] != ' ':
            caps.append(1 if text[i].isupper() else 0)
        if text[i:i+2].lower() in two_letter_letter:
            news.append(text[i:i+2].lower())
            orig.append(text[i:i+2].lower())
            i += 2
            continue
        if text[i].lower() in critical_latin:
            huks[i] = text[i].lower()
        news.append(text[i].lower())
        orig.append(text[i].lower())
        i += 1
    return caps, huks, news, orig

def seqToTensor(seq):
    tensor = [[0 for i in range(asci_len)] for x in range(len(seq))]
    for i, letter in enumerate(seq):
        tensor[i][asci.index(letter)] = 1
    return tensor

def huks_n_newsToData(huks, news):
    ins = {'s':[], 'z':[], 'c':[]}
    for i in huks.keys():
        t = huks[i]
        head = 10-i if 10-i > 0 else 0
        vector = [' ' for x in range(head)]
        vector += news[i-10 if i-10 > 0 else 0:i+11]
        vector += [' ' for x in range(21-len(vector))]
        vector = seqToTensor(vector)
        ins[t].append([vector])
    for i in ins.keys():
        ins[i] = torch.tensor(ins[i], device=device).double()
    return ins

def getOuts(nets, ins):
    outs = {}
    with torch.no_grad():
        for i in nets.keys():
            try:
                outs[i] = nets[i](ins[i])
            except RuntimeError:
                pass
    return outs

# def warn(xs):
#     ys = sorted(xs, reverse=True)
#     return 1 < (ys[0] - ys[1])

def percentage_prediction(outs):
    preds = {}
    # percs = {}
    for i in outs.keys():
        preds[i] = np.apply_along_axis(np.argmax, 1, outs[i])
        # percs[i] = np.apply_along_axis(warn, 1, outs[i])
    return preds, None #percs

def rev(caps, huks, preds, orig):
    l = len(orig)
    i = 0
    c = 0
    counters = {'s':0, 'z':0, 'c':0}
    while i < l:
        t = orig[i]
        if not t.isalpha():
            i += 1
            continue
        if t in critical_latin:
            orig[i] = predic[(t, preds[t][counters[t]])]
            counters[t] += 1
            if caps[c]:
                orig[i] = orig[i].upper()
            c += 1
            i += 1
        else:
            if caps[c]:
                orig[i] = t.upper()
            orig[i] = drev[orig[i]]
            c += 1
            i += 1
    return "".join(orig)

def convert(text):
    caps, huks, news, orig = textToList(text)
    ins = huks_n_newsToData(huks, news)
    outs = getOuts(nets, ins)
    preds, _ = percentage_prediction(outs)
    return rev(caps, huks, preds, orig)

def send_msg(sock, msg):
    msg = msg.encode()
    msg = struct.pack('>I', len(msg)) + msg
    sock.send(msg)

def recv_msg(sock):
    raw_msglen = recvall(sock, 4)
    if not raw_msglen:
        return None
    msglen = struct.unpack('>I', raw_msglen)[0]
    return recvall(sock, msglen).decode()

def recvall(sock, n):
    data = bytearray()
    while len(data) < n:
        packet = sock.recv(n - len(data))
        if not packet:
            return None
        data.extend(packet)
    return data

def kill_daemon():
    client = socket.socket()
    try:
        client.connect((socket.gethostname(),8082))
    except Exception as _:
        print('Cyr daemon is not running.')
        sys.exit()
    send_msg(client, "exit")
    client.close()
    sys.exit()

def check_daemon():
    client = socket.socket()
    try:
        client.connect((socket.gethostname(),8082))
    except Exception as _:
        print('Cyr daemon is not running.')
        sys.exit()
    send_msg(client, "check")
    data = recv_msg(client)
    if data == None:
        print("Unexpected message, daemon might still be running.")
        sys.exit()
    if data == "ok":
        print("Cyr daemon is running.")
    else:
        print("Cyr is running, but is possibly corrupted.")
    client.close()
    sys.exit()

def set_nets_path(nets_path):
    if "-d" in sys.argv:
        print("Nets are already loaded into daemon.")
        return nets_path
    return sys.argv[sys.argv.index("-n")+1]

def daemon(nets_path):
    try:
        load_nets(nets, nets_path)
    except Exception as _:
        print("Nets not found at "+nets_path + ".")
        sys.exit()
    server = socket.socket()
    try:
        server.bind((socket.gethostname(), 8082))
    except Exception as _:
        print("Daeomon already running or " + socket.gethostname() + ":8082 is already in use")
        sys.exit()
    server.listen(1)
    while True:
        client, _ = server.accept()
        data = recv_msg(client)
        if data == None:
            print("Unexpected EOF while converting.")
            sys.exit()
        if data == "exit":
            client.close()
            server.close()
            sys.exit()
        if data == "check":
            send_msg(client, "ok")
        else:
            send_msg(client, convert(data))
            client.close()
    server.close()
    sys.exit()

def start_daemon(nets_path):
    nohup_log = os.path.expanduser("~") + "/.cyr_nohup"
    if os.system("nohup cyr -s -n " + nets_path + " &> " + nohup_log + " &") != 0:
        print("Error starting daemon.")
    sys.exit()

def print_help():
    print(
"""cyr [-c] [-d] [-D] [-f FILE] [-h] [-i] [-K] [-n PATH] [-o FILE]
-c
    check daemon state.
-d
    use daemon instead of loading nets.
-D
    start daemon.
-f FILE
    specify file to read. reads from standard input by default.
-h
    display this help and exit.
-i
    edit file in place.
-K
    kill daemon.
-n PATH
    path to nets. default is $HOME/.cyr_nets.
-o FILE
    specify output file. writes to standard output by default.""")
    sys.exit()

def read_file(file_name, text):
    file_name = sys.argv[sys.argv.index("-f")+1]
    try:
        with open(file_name, "r") as f:
            text = f.read()
    except FileNotFoundError:
        print("File " + file_name + " not found.")
        sys.exit()
    except IndexError:
        print("No file given, run with -h option for help.")
        sys.exit()
    return file_name, text

def read_stdin(text):
    for line in sys.stdin:
        text += line
    return text

def pass_to_daemon(text):
    client = socket.socket()
    try:
        client.connect((socket.gethostname(),8082))
    except Exception as _:
        print('Make sure cyr daemon is running.')
        sys.exit()
    send_msg(client, text)
    data = recv_msg(client)
    if data == None:
        print("Unexpected message from daemon.")
        sys.exit()
    client.close()
    return data

def standalone(text, nets_path):
    try:
        load_nets(nets, nets_path)
    except Exception as _:
        print('Error loading nets.')
        sys.exit()
    return convert(text)

def write_to_file(new_text):
    try:
        with open(sys.argv[sys.argv.index("-o")+1], "w") as f:
            f.write(new_text)
    except Exception as _:
        print("Error writting file.")
        sys.exit()

def write_in_place(new_text, file_name):
    if file_name == "":
        print("You must specify file with -f option.")
        sys.exit()
    else:
        try:
            with open(file_name, "w") as f:
                f.write(new_text)
        except Exception as _:
            print("Error writting file.")
            sys.exit()

def main():
    new_text = ""
    text = ""
    nets_path = os.path.expanduser("~") + "/.cyr_nets"
    file_name = ""

    if "-K" in sys.argv:
        kill_daemon()
    if "-c" in sys.argv:
        check_daemon()
    if "-n" in sys.argv:
        nets_path = set_nets_path(nets_path)
    if "-s" in sys.argv:
        daemon(nets_path)
    if "-D" in sys.argv:
        start_daemon(nets_path)
    if "-h" in sys.argv:
        print_help()
    if "-f" in sys.argv:
        file_name, text = read_file(file_name, text)
    else:
        text = read_stdin(text)
    if "-d" in sys.argv:
        new_text = pass_to_daemon(text)
    else:
        new_text = standalone(text, nets_path)
    if "-o" in sys.argv:
        write_to_file(new_text)
    elif "-i" in sys.argv:
        write_in_place(new_text, file_name)
    else:
        print(new_text)

if __name__ == "__main__":
    main()


# --------------------------------------------------------
# Fast R-CNN
# Copyright (c) 2015 Microsoft
# Licensed under The MIT License [see LICENSE for details]
# Written by Ross Girshick
# --------------------------------------------------------

import os
from datasets.imdb import imdb
import datasets.ds_utils as ds_utils
import xml.etree.ElementTree as ET
import numpy as np
import scipy.sparse
import scipy.io as sio
import utils.cython_bbox
from utils.cython_bbox_grid import bbox_overlaps_grid
from utils.cython_bbox import bbox_overlaps
import cPickle
import subprocess
import uuid
from voc_eval import voc_eval
from fast_rcnn.config import cfg
import cv2
import PIL
from utils.timer import Timer
import glob
from utils.cython_bbox import bbox_overlaps
import warnings

warnings.filterwarnings('error')

class pascal_voc(imdb):
    def __init__(self, image_set, year, devkit_path=None):
        imdb.__init__(self, 'voc_' + year + '_' + image_set)
        self._year = year
        self._image_set = image_set
        self._devkit_path = self._get_default_path() if devkit_path is None \
            else devkit_path
        self._data_path = os.path.join(self._devkit_path, 'VOC' + self._year)
        self._classes = ('__background__',  # always index 0
                         'aeroplane', 'bicycle', 'bird', 'boat',
                         'bottle', 'bus', 'car', 'cat', 'chair',
                         'cow', 'diningtable', 'dog', 'horse',
                         'motorbike', 'person', 'pottedplant',
                         'sheep', 'sofa', 'train', 'tvmonitor')
        self._class_to_ind = dict(zip(self.classes, xrange(self.num_classes)))
        self._image_ext = '.jpg'
        self._image_index = self._load_image_set_index()
        # Default to roidb handler
        # self._roidb_handler = self.selective_search_roidb
        self._salt = str(uuid.uuid4())
        self._comp_id = 'comp4'

        # PASCAL specific config options
        self.config = {'cleanup': True,
                       'use_salt': True,
                       'use_diff': False,
                       'matlab_eval': False,
                       'rpn_file': None,
                       'min_size': 2}

        assert os.path.exists(self._devkit_path), \
            'VOCdevkit path does not exist: {}'.format(self._devkit_path)
        assert os.path.exists(self._data_path), \
            'Path does not exist: {}'.format(self._data_path)

    def image_path_at(self, i):
        """
        Return the absolute path to image i in the image sequence.
        """
        return self.image_path_from_index(self._image_index[i])

    def image_path_from_index(self, index):
        """
        Construct an image path from the image's "index" identifier.
        """
        image_path = os.path.join(self._data_path, 'JPEGImages',
                                  index + self._image_ext)
        assert os.path.exists(image_path), \
            'Path does not exist: {}'.format(image_path)
        return image_path

    def _load_image_set_index(self):
        """
        Load the indexes listed in this dataset's image set file.
        """
        # Example path to image set file:
        # self._devkit_path + /VOCdevkit2007/VOC2007/ImageSets/Main/val.txt
        image_set_file = os.path.join(self._data_path, 'ImageSets', 'Main',
                                      self._image_set + '.txt')
        assert os.path.exists(image_set_file), \
            'Path does not exist: {}'.format(image_set_file)
        with open(image_set_file) as f:
            image_index = [x.strip() for x in f.readlines()]
        return image_index

    def _get_default_path(self):
        """
        Return the default path where PASCAL VOC is expected to be installed.
        """
        return os.path.join(cfg.DATA_DIR, 'VOCdevkit' + self._year)

    def gt_roidb(self):
        """
        Return the database of ground-truth regions of interest.

        This function loads/saves from/to a cache file to speed up future calls.
        """
        cache_file = os.path.join(self.cache_path, self.name + '_gt_roidb_with_simu_points.pkl')
        if os.path.exists(cache_file):
            with open(cache_file, 'rb') as fid:
                roidb = cPickle.load(fid)
            print '{} gt roidb loaded from {}'.format(self.name, cache_file)
            return roidb

        gt_roidb = [self._load_pascal_annotation(index)
                    for index in self.image_index]
        with open(cache_file, 'wb') as fid:
            cPickle.dump(gt_roidb, fid, cPickle.HIGHEST_PROTOCOL)
        print 'wrote gt roidb to {}'.format(cache_file)

        return gt_roidb

    def gt_roidb_with_simu_points(self):
        """
        Return the database of ground-truth regions of interest.

        This function loads/saves from/to a cache file to speed up future calls.
        """
        cache_file = os.path.join(self.cache_path, self.name + '_gt_roidb_with_simu_points.pkl')
        if os.path.exists(cache_file):
            with open(cache_file, 'rb') as fid:
                roidb = cPickle.load(fid)
            print '{} gt roidb loaded from {}'.format(self.name, cache_file)
            return roidb

        gt_roidb = [self._load_pascal_annotation(index)
                    for index in self.image_index]
        with open(cache_file, 'wb') as fid:
            cPickle.dump(gt_roidb, fid, cPickle.HIGHEST_PROTOCOL)
        print 'wrote gt roidb to {}'.format(cache_file)

        return gt_roidb

    def selective_search_roidb(self):
        """
        Return the database of selective search regions of interest.
        Ground-truth ROIs are also included.

        This function loads/saves from/to a cache file to speed up future calls.
        """
        cache_file = os.path.join(self.cache_path,
                                  self.name + '_selective_search_roidb.pkl')

        if os.path.exists(cache_file):
            with open(cache_file, 'rb') as fid:
                roidb = cPickle.load(fid)
            print '{} ss roidb loaded from {}'.format(self.name, cache_file)
            return roidb

        if int(self._year) == 2007 or self._image_set != 'test':
            gt_roidb = self.gt_roidb()
            ss_roidb = self._load_selective_search_roidb(gt_roidb)
            roidb = imdb.merge_roidbs(gt_roidb, ss_roidb)
        else:
            roidb = self._load_selective_search_roidb(None)
        with open(cache_file, 'wb') as fid:
            cPickle.dump(roidb, fid, cPickle.HIGHEST_PROTOCOL)
        print 'wrote ss roidb to {}'.format(cache_file)

        return roidb

    def rpn_roidb(self):
        if int(self._year) == 2007 or self._image_set != 'test':
            gt_roidb = self.gt_roidb()
            rpn_roidb = self._load_rpn_roidb(gt_roidb)
            roidb = imdb.merge_roidbs(gt_roidb, rpn_roidb)
        else:
            roidb = self._load_rpn_roidb(None)

        return roidb

    def _load_rpn_roidb(self, gt_roidb):
        filename = self.config['rpn_file']
        print 'loading {}'.format(filename)
        assert os.path.exists(filename), \
            'rpn data not found at: {}'.format(filename)
        with open(filename, 'rb') as f:
            box_list = cPickle.load(f)
        return self.create_roidb_from_box_list(box_list, gt_roidb)

    def _load_selective_search_roidb(self, gt_roidb):
        filename = os.path.abspath(os.path.join(cfg.DATA_DIR,
                                                'selective_search_data',
                                                self.name + '.mat'))
        assert os.path.exists(filename), \
            'Selective search data not found at: {}'.format(filename)
        raw_data = sio.loadmat(filename)['boxes'].ravel()

        box_list = []
        for i in xrange(raw_data.shape[0]):
            boxes = raw_data[i][:, (1, 0, 3, 2)] - 1
            keep = ds_utils.unique_boxes(boxes)
            boxes = boxes[keep, :]
            keep = ds_utils.filter_small_boxes(boxes, self.config['min_size'])
            boxes = boxes[keep, :]
            box_list.append(boxes)

        return self.create_roidb_from_box_list(box_list, gt_roidb)

    def _load_pascal_annotation(self, index):
        """
        Load image and bounding boxes info from XML file in the PASCAL VOC
        format.
        """
        filename = os.path.join(self._data_path, 'Annotations', index + '.xml')
        tree = ET.parse(filename)
        objs = tree.findall('object')
        if self.config['use_diff']:
            # Exclude the samples labeled as difficult
            non_diff_objs = [
                obj for obj in objs if int(obj.find('difficult').text) == 0]
            if len(non_diff_objs) != len(objs):
                print 'Removed {} difficult objects'.format(
                    len(objs) - len(non_diff_objs))
            objs = non_diff_objs
        num_objs = len(objs)

        boxes = np.zeros((num_objs, 4), dtype=np.uint16)
        gt_points = np.zeros((num_objs, 2), dtype=np.uint16)
        simu_points = np.zeros((num_objs, 3), dtype=np.uint16)
        gt_classes = np.zeros((num_objs), dtype=np.int32)
        overlaps = np.zeros((num_objs, self.num_classes), dtype=np.float32)
        # "Seg" area for pascal is just the box area
        seg_areas = np.zeros((num_objs), dtype=np.float32)

        img_size = tree.find('size')
        width = float(img_size.find('width').text)
        height = float(img_size.find('height').text)
        print 'height:', height, 'width:', width
        # Load object bounding boxes into a data frame.
        for ix, obj in enumerate(objs):
            bbox = obj.find('bndbox')
            # Make pixel indexes 0-based
            x1 = float(bbox.find('xmin').text) - 1
            y1 = float(bbox.find('ymin').text) - 1
            x2 = float(bbox.find('xmax').text) - 1
            y2 = float(bbox.find('ymax').text) - 1
            cls = self._class_to_ind[obj.find('name').text.lower().strip()]
            boxes[ix, :] = [x1, y1, x2, y2]
            gt_point_x = (x1 + x2) / 2
            gt_point_y = (y1 + y2) / 2
            gt_points[ix, :] = [gt_point_x, gt_point_y]
            is_small_object = False
            small_object_thresh = 7  # 7 pixels to center
            big_object_thresh = 20  # 20 pixels to center

            if (x2 - x1) * (y2 - y1) / (width * height) < 0.1:
                is_small_object = True
                low_x = 0 if int(gt_point_x - small_object_thresh) < 0 else int(gt_point_x - small_object_thresh)
                high_x = width if int(gt_point_x + small_object_thresh) > width else int(
                    gt_point_x + small_object_thresh)
                low_y = 0 if int(gt_point_y - small_object_thresh) < 0 else int(gt_point_y - small_object_thresh)
                high_y = height if int(gt_point_y + small_object_thresh) > height else int(
                    gt_point_y + small_object_thresh)
            else:
                low_x = 0 if int(gt_point_x - big_object_thresh) < 0 else int(gt_point_x - big_object_thresh)
                high_x = width if int(gt_point_x + big_object_thresh) > width else int(
                    gt_point_x + big_object_thresh)
                low_y = 0 if int(gt_point_y - big_object_thresh) < 0 else int(gt_point_y - big_object_thresh)
                high_y = height if int(gt_point_y + big_object_thresh) > height else int(
                    gt_point_y + big_object_thresh)
            simu_x = np.random.randint(low=low_x, high=high_x)
            simu_y = np.random.randint(low=low_y, high=high_y)

            gt_classes[ix] = cls
            overlaps[ix, cls] = 1.0
            seg_areas[ix] = (x2 - x1 + 1) * (y2 - y1 + 1)
            simu_points[ix, :] = [simu_x, simu_y, int(is_small_object)]
        overlaps = scipy.sparse.csr_matrix(overlaps)

        return {'boxes': boxes,
                'gt_points': gt_points,
                'simu_points': simu_points,
                'gt_classes': gt_classes,
                }

def load_selective_search_roidb(dataset_name):
    name = dataset_name
    filename = os.path.abspath(os.path.join(cfg.DATA_DIR,
                                            'selective_search_data',
                                            name + '.mat'))
    assert os.path.exists(filename), \
        'Selective search data not found at: {}'.format(filename)
    raw_data = sio.loadmat(filename)['boxes'].ravel()

    box_list = []
    for i in xrange(raw_data.shape[0]):
        boxes = raw_data[i][:, (1, 0, 3, 2)] - 1
        keep = ds_utils.unique_boxes(boxes)
        boxes = boxes[keep, :]
        keep = ds_utils.filter_small_boxes(boxes, 2)
        boxes = boxes[keep, :]
        box_list.append(boxes)
    return box_list

def gt_roidb_with_simu_points(cache_path, dataset_name):
    """
    Return the database of ground-truth regions of interest.

    This function loads/saves from/to a cache file to speed up future calls.
    """
    cache_file = os.path.join(cache_path, dataset_name + '_gt_roidb_with_simu_points.pkl')
    if os.path.exists(cache_file):
        with open(cache_file, 'rb') as fid:
            roidb = cPickle.load(fid)
        print '{} gt roidb loaded from {}'.format(dataset_name, cache_file)
        return roidb

def average_bounding_boxes(d, roidb, boxlist):
    import matplotlib.pyplot as plt

    print len(boxlist), len(roidb)
    simu_gt_boxes_list = []
    for i_roi in xrange(len(roidb)):
        im = cv2.imread(d.image_path_at(i_roi))
        print 'image_index:', i_roi
        im = im[:, :, (2, 1, 0)]
        gt_boxes = roidb[i_roi]['boxes']
        gt_points = roidb[i_roi]['gt_points']
        simu_points = roidb[i_roi]['simu_points']
        simu_gt_boxes = np.zeros((len(gt_points), 4))
        for i_gt in xrange(len(gt_boxes)):
            bbox = gt_boxes[i_gt, :4]
            gt_p = gt_points[i_gt, :2]
            plt.cla()
            plt.imshow(im)
            plt.gca().add_patch(
                plt.Rectangle((bbox[0], bbox[1]),
                              bbox[2] - bbox[0],
                              bbox[3] - bbox[1], fill=False,
                              edgecolor='r', linewidth=3),
            )
            plt.gca().add_patch(
                plt.Rectangle((gt_p[0], gt_p[1]),
                              2,
                              2, fill=True,
                              edgecolor='r', linewidth=3)
            )
            plt.gca().add_patch(
                plt.Rectangle((simu_points[i_gt, 0], simu_points[i_gt, 1]),
                              2,
                              2, fill=True,
                              edgecolor='g', linewidth=3)
            )
            plt.title('{}  {}'.format('small object?', str(simu_points[i_gt, 2])))

            # for box in boxlist[i]:
            #     plt.gca().add_patch(
            #         plt.Rectangle((box[0], box[1]),
            #                       box[2] - box[0],
            #                       box[3] - box[1], fill=False,
            #                       edgecolor='blue', linewidth=1),
            #     )
            # print 'orginal len(boxlist[i])',len(boxlist[i]),np.dtype(simu_points[i_gt,2]),simu_points[i_gt,2],im.shape

            filted_boxlist = filter_selective_boxlist_average(im, simu_points, i_gt, boxlist, i_roi)
            # print 'len(filted_boxlist[i])', len(filted_boxlist)
            box_array = np.array(filted_boxlist)
            box_mean = np.mean(box_array, axis=0)
            plt.gca().add_patch(
                plt.Rectangle((box_mean[0], box_mean[1]),
                              box_mean[2] - box_mean[0],
                              box_mean[3] - box_mean[1], fill=False,
                              edgecolor='yellow', linewidth=1),
            )
            plt.show()
            simu_gt_boxes[i_gt, :] = box_mean
        simu_gt_boxes_list.append(simu_gt_boxes)
    cache_file = os.path.join(d.cache_path, d.name + '_gt_roidb_with_simu_bbox.pkl')
    with open(cache_file, 'wb') as fid:
        cPickle.dump(simu_gt_boxes_list, fid, cPickle.HIGHEST_PROTOCOL)
    print 'wrote gt roidb to {}'.format(cache_file)

def filter_selective_boxlist_average(im, simu_points, i_gt, boxlist, i):
    margin_thresh = 0
    filted_boxlist = []
    bbox_size_thresh = 1
    if simu_points[i_gt, 2] == 1:
        bbox_size_thresh = 0.15
    while len(filted_boxlist) == 0:
        for box in boxlist[i]:
            if (box[0] - margin_thresh < simu_points[i_gt, 0]) and (box[2] + margin_thresh > simu_points[i_gt, 0]) \
                    and (box[1] - margin_thresh < simu_points[i_gt, 1]) and (
                            box[3] + margin_thresh > simu_points[i_gt, 1]):

                if 1.0 * (box[2] - box[0]) * (box[3] - box[1]) / (
                                1.0 * im.shape[0] * im.shape[1]) < bbox_size_thresh:
                    # print 1.0*(bbox[2]-bbox[0])*(bbox[3]-bbox[1])/(1.0*im.shape[0]*im.shape[1])
                    # plt.gca().add_patch(
                    #     plt.Rectangle((box[0], box[1]),
                    #                   box[2] - box[0],
                    #                   box[3] - box[1], fill=False,
                    #                   edgecolor='blue', linewidth=1),
                    # )
                    if bbox_size_thresh == 1:  # if gt_box is big, just keep boxes whose size more than 0.05
                        if 1.0 * (box[2] - box[0]) * (box[3] - box[1]) / (
                                        1.0 * im.shape[0] * im.shape[1]) > 0.05:
                            filted_boxlist.append(box)
                    else:  # if gt_box is small, just keep boxes whose size less than 0.15
                        filted_boxlist.append(box)
        bbox_size_thresh = bbox_size_thresh + 0.05
        margin_thresh = margin_thresh + 1
        # print bbox_size_thresh,margin_thresh
    return filted_boxlist

def filter_selective_boxlist_heatmap(im, simu_points, i_gt, boxlist, i):
    filted_boxlist = []
    Top_N_Boxes_small = 8
    Top_N_Boxes_big = 8
    aspetct_ratio1 = 0.5
    aspetct_ratio2 = 1
    aspetct_ratio3 = 2
    area_ratio_small = 1
    area_ratio_big_low = 0.
    area_ratio_big_high = 1.
    print area_ratio_big_low, area_ratio_small, Top_N_Boxes_small, Top_N_Boxes_big, area_ratio_big_high

    def take_elem(elem):
        return elem['sum_diff']

    for box in boxlist[i]:
        box = box.astype(np.float)
        margin_thresh = 5  # for robustness to add some pixels
        if (box[0] - margin_thresh < simu_points[i_gt, 0]) and (box[2] + margin_thresh > simu_points[i_gt, 0]) \
                and (box[1] - margin_thresh < simu_points[i_gt, 1]) and (
                        box[3] + margin_thresh > simu_points[i_gt, 1]):
            distance_x = [np.abs(simu_points[i_gt, 0] - box[0]) + 0.001, np.abs(box[2] - simu_points[i_gt, 0]) + 0.001]
            distance_y = [np.abs(simu_points[i_gt, 1] - box[1] + 0.001), np.abs(box[3] - simu_points[i_gt, 1]) + 0.001]
            # print np.max(distance_x),np.min(distance_x)
            diff_x = np.abs(np.max(distance_x) / np.min(distance_x))
            diff_y = np.abs(np.max(distance_y) / np.min(distance_y))
            ratio = np.abs((box[2] - box[0]) / (box[3] - box[1]))
            sum_diff = (diff_x + diff_y)
            #
            #        * np.exp(
            # -np.linalg.norm([0.5 * (box[0] + box[2]) - 1.0 * simu_points[i_gt, 0],
            #                  0.5 * (box[1] + box[3]) - 1.0 * simu_points[i_gt, 1]])/200)
            object_area = (box[2] - box[0]) * (box[3] - box[1]) / (im.shape[0] * im.shape[1])
            if int(simu_points[i_gt, 2]) == 1:  # small object

                if object_area <= area_ratio_small:
                    filted_boxlist.append({'sum_diff': sum_diff,
                                           'boxes': box,
                                           'ratio': ratio})
            else:
                if object_area >= area_ratio_big_low and object_area <= area_ratio_big_high:
                    filted_boxlist.append({'sum_diff': sum_diff,
                                           'boxes': box,
                                           'ratio': ratio})
    filted_boxlist.sort(key=take_elem)
    # Top_N_Boxes = len(filted_boxlist)
    # if len(filted_boxlist) >= Top_N_Boxes:
    #     filterd = filted_boxlist[:Top_N_Boxes]
    # else:
    #     filterd = filted_boxlist
    # ratiolist = np.array([b['ratio'] for b in filterd])
    # aspetct_nums = [len(np.where(ratiolist <= aspetct_ratio1)[0]), len(np.where(ratiolist >= aspetct_ratio3)[0]),
    #                 len(np.where((ratiolist < aspetct_ratio3) & (ratiolist > aspetct_ratio1))[0])]
    # max_ratio = np.argmax(aspetct_nums)
    # min_ratio = np.argmin(aspetct_nums)
    # boxes_low_aspect = np.array([b['boxes'] for b in filterd])[np.where(ratiolist <= aspetct_ratio1)[0], :]
    # boxes_high_aspect = np.array([b['boxes'] for b in filterd])[np.where(ratiolist >= aspetct_ratio3)[0], :]
    # boxes_normal_aspect = np.array([b['boxes'] for b in filterd])[
    #                       np.where((ratiolist < aspetct_ratio3) & (ratiolist > aspetct_ratio1))[0], :]
    #
    # if max_ratio == 0 and min_ratio == 1:
    #     low, high, normal = 0.5, 0.3, 0.2
    #     if len(boxes_high_aspect) == 0 and len(boxes_normal_aspect) == 0:
    #         low, high, normal = 1.0, 0., 0.
    #     elif len(boxes_high_aspect) == 0:
    #         low, high, normal = 0.65, 0., 0.35
    #     elif len(boxes_normal_aspect) == 0:
    #         low, high, normal = 0.6, 0.4, 0.
    #
    # elif max_ratio == 0 and min_ratio == 2:
    #     low, high, normal = 0.5, 0.2, 0.3
    #     if len(boxes_high_aspect) == 0 and len(boxes_normal_aspect) == 0:
    #         low, high, normal = 1.0, 0., 0.
    #     elif len(boxes_high_aspect) == 0:
    #         low, high, normal = 0.6, 0., 0.4
    #     elif len(boxes_normal_aspect) == 0:
    #         low, high, normal = 0.65, 0.35, 0.
    #
    # elif max_ratio == 1 and min_ratio == 0:
    #     low, high, normal = 0.3, 0.5, 0.2
    #     if len(boxes_low_aspect) == 0 and len(boxes_normal_aspect) == 0:
    #         low, high, normal = 0., 1., 0.
    #     elif len(boxes_low_aspect) == 0:
    #         low, high, normal = 0., 0.65, 0.35
    #     elif len(boxes_normal_aspect) == 0:
    #         low, high, normal = 0.4, 0.6, 0.
    #
    # elif max_ratio == 1 and min_ratio == 2:
    #     low, high, normal = 0.2, 0.5, 0.3
    #     if len(boxes_low_aspect) == 0 and len(boxes_normal_aspect) == 0:
    #         low, high, normal = 0., 1., 0.
    #     elif len(boxes_low_aspect) == 0:
    #         low, high, normal = 0., 0.6, 0.4
    #     elif len(boxes_normal_aspect) == 0:
    #         low, high, normal = 0.35, 0.65, 0.
    #
    # elif max_ratio == 2 and min_ratio == 0:
    #     low, high, normal = 0.3, 0.2, 0.5
    #     if len(boxes_low_aspect) == 0 and len(boxes_high_aspect) == 0:
    #         low, high, normal = 0., 0., 1.
    #     elif len(boxes_low_aspect) == 0:
    #         low, high, normal = 0., 0.35, 0.65
    #     elif len(boxes_high_aspect) == 0:
    #         low, high, normal = 0.4, 0., 0.6
    #
    # else:
    #     low, high, normal = 0.2, 0.3, 0.5
    #     if len(boxes_low_aspect) == 0 and len(boxes_high_aspect) == 0:
    #         low, high, normal = 0., 0., 1.
    #     elif len(boxes_low_aspect) == 0:
    #         low, high, normal = 0., 0.4, 0.6
    #     elif len(boxes_high_aspect) == 0:
    #         low, high, normal = 0.35, 0., 0.65
    # if len(boxes_low_aspect) == 0:
    #     boxes_low_aspect = np.array([0, 0, 0, 0])
    # if len(boxes_high_aspect) == 0:
    #     boxes_high_aspect = np.array([0, 0, 0, 0])
    # if len(boxes_normal_aspect) == 0:
    #     boxes_normal_aspect = np.array([0, 0, 0, 0])
    #
    # assert len(boxes_low_aspect) is not 0
    # assert len(boxes_high_aspect) is not 0
    # assert len(boxes_normal_aspect) is not 0
    #
    # return np.average(boxes_low_aspect, axis=0) * low + np.average(boxes_high_aspect, axis=0) * high + np.average(
    #     boxes_normal_aspect, axis=0) * normal, np.array([b['boxes'] for b in filterd])
    if int(simu_points[i_gt, 2]) == 1:  # small object
        if len(filted_boxlist) >= Top_N_Boxes_small:
            return np.array([b['boxes'] for b in filted_boxlist[:Top_N_Boxes_small]]).reshape(
                (Top_N_Boxes_small, 4))
        else:
            return np.array([b['boxes'] for b in filted_boxlist[:len(filted_boxlist)]]).reshape(
                (len(filted_boxlist), 4))
    else:
        if len(filted_boxlist) >= Top_N_Boxes_big:
            return np.array([b['boxes'] for b in filted_boxlist[:Top_N_Boxes_big]]).reshape(
                (Top_N_Boxes_big, 4))
        else:
            return np.array([b['boxes'] for b in filted_boxlist[:len(filted_boxlist)]]).reshape(
                (len(filted_boxlist), 4))

def get_grid_bbox(im):
    grid_pixels = 10  # im.shape (rows,columns,channel) with respect to (height,width)
    grid_height_num = im.shape[0] / grid_pixels if im.shape[0] % grid_pixels == 0 else im.shape[0] / grid_pixels + 1
    grid_width_num = im.shape[1] / grid_pixels if im.shape[1] % grid_pixels == 0 else im.shape[1] / grid_pixels + 1
    img_grids = np.zeros((grid_height_num * grid_width_num, 4), dtype=np.uint16)
    index = 0
    for h in range(0, im.shape[0], grid_pixels):
        for w in range(0, im.shape[1], grid_pixels):
            img_grids[index] = [w, h,
                                w + grid_pixels if w <= im.shape[1] and im.shape[1] - w > grid_pixels else im.shape[
                                                                                1] - 1,
                                h + grid_pixels if h <= im.shape[0] and im.shape[0] - h > grid_pixels
                                else im.shape[0] - 1]
            index += 1
    return img_grids

def heat_map_bounding_boxes(d, roidb, boxlist):
    import matplotlib.pyplot as plt
    simu_gt_boxeslist = []
    view_result = False
    _t = {'total_time': Timer(), 'one_gt': Timer(),
          'filter_selective_boxlist': Timer(), 'get_grid_bbox': Timer(),
          'filter_grid': Timer(), 'bbox_overlaps_grid': Timer()}
    _t['total_time'].tic()
    for i_roi in xrange(len(roidb)):
        im = cv2.imread(d.image_path_at(i_roi))
        print 'image_index:', i_roi
        im = im[:, :, (2, 1, 0)]
        gt_boxes = roidb[i_roi]['boxes']
        gt_points = roidb[i_roi]['gt_points']
        simu_points = roidb[i_roi]['simu_points']
        simu_gt_boxes = np.zeros((len(gt_points), 4))
        _t['one_gt'].tic()
        for i_gt in xrange(len(gt_boxes)):
            gt_bbox = gt_boxes[i_gt, :4].astype(np.float)
            simu_point = simu_points[i_gt, :3]
            gt_point = gt_points[i_gt, :2]

            # show selective bounding box filtered
            # _t['filter_selective_boxlist'].tic()
            filted_boxlist = filter_selective_boxlist_heatmap(im, simu_points.astype(np.float),
                                                                                i_gt, boxlist, i_roi)
            averge_boxes = np.average(filted_boxlist, axis=0)
            # averge_boxes, filted_boxlist = filter_selective_boxlist_heatmap(simu_points.astype(np.float), i_gt, boxlist,
            #                                                                 i_roi)
            simu_gt_boxes[i_gt, :] = [averge_boxes[0], averge_boxes[1], averge_boxes[2], averge_boxes[3]]

            # vis_results2(d, i_roi, gt_point, simu_point, gt_bbox, filted_boxlist, averge_boxes,
            #              view_result)
            '''
            _t['filter_selective_boxlist'].toc()
            # visualize iou heatmap
            _t['get_grid_bbox'].tic()
            im_grids = get_grid_bbox(im)
            filtered_box_l = np.array(filted_boxlist)
            _t['get_grid_bbox'].toc()
            _t['bbox_overlaps_grid'].tic()
            grid_overlaps = bbox_overlaps_grid(im_grids.astype(np.float), filtered_box_l.astype(np.float))
            _t['bbox_overlaps_grid'].toc()

            sum_grids = np.sum(grid_overlaps, axis=1)
            # print(im_grids.shape, grid_overlaps.shape, sum_grids.shape)
            _max = np.max(sum_grids)
            _min = np.min(sum_grids)
            # to do distance beteen grid and mid coords
            pred_flag_init = False
            if int(simu_point[2]) is 1:
                alpha_thresh = 0.7
                # plt.title('small_object')
            else:
                alpha_thresh = 0.3
                # plt.title('large_object')
            # print(im.shape,gt_bbox,1.0*(gt_bbox[2]-gt_bbox[0])*(gt_bbox[3]-gt_bbox[1])/(im.shape[0]*im.shape[1]))
            _t['filter_grid'].tic()
            for i_grid in range(len(im_grids)):
                grid = im_grids[i_grid]
                distance = get_distance(simu_point[0], simu_point[1], 0, 0, 0.5 *
                                        (grid[0] + grid[2]), 0.5 * (grid[1] + grid[3]))
                if int(simu_point[2]) is not 1:
                    alpha = (sum_grids[i_grid] - _min) / (_max - _min) * np.exp(-1.0 * distance / 800)
                else:
                    alpha = (sum_grids[i_grid] - _min) / (_max - _min) * np.cos(distance / 160)
                    # np.exp(-1.0 * distance / 100)

                if alpha >= alpha_thresh:
                    # ax.add_patch(
                    #     plt.Rectangle((grid[0], grid[1]),
                    #                   grid[2] - grid[0],
                    #                   grid[3] - grid[1], fill=True,
                    #                   color='yellow', alpha=alpha, edgecolor=None)
                    # )
                    if not pred_flag_init:
                        pred_xmin, pred_xmax, pred_ymin, pred_ymax = grid[0], grid[2], grid[1], grid[3]
                        pred_flag_init = True
                    else:
                        if pred_xmin > grid[0]:
                            pred_xmin = grid[0]
                        if pred_ymin > grid[1]:
                            pred_ymin = grid[1]
                        if pred_xmax < grid[2]:
                            pred_xmax = grid[2]
                        if pred_ymax < grid[3]:
                            pred_ymax = grid[3]
            # ax.add_patch(
            #     plt.Rectangle((pred_xmin, pred_ymin),
            #                   pred_xmax - pred_xmin,
            #                   pred_ymax - pred_ymin, fill=False,
            #                   edgecolor='green', linewidth=3.5)
            # )
            if pred_xmax >= im.shape[1]:
                pred_xmax = pred_xmax - 1
            if pred_ymax >= im.shape[0]:
                pred_ymax = pred_ymax - 1
            _t['filter_grid'].toc()
            # if pred_xmin < 0 or pred_ymin < 0:
            #     print('pred_xmin:', pred_xmin, 'pred_ymin:', pred_ymin)
            simu_gt_boxes[i_gt, :4] = [pred_xmin, pred_ymin, pred_xmax, pred_ymax]  # gt_boxes[i,:]
        _t['one_gt'].toc()
        simu_gt_boxeslist.append(simu_gt_boxes)
        # print 'simu_gt_boxes',simu_gt_boxes
        # plt.axis('off')
        # plt.tight_layout()
        # plt.draw()
        # plt.show()
        # _t = {'total_time': Timer(), 'one_gt': Timer(),
        #       'filter_selective_boxlist': Timer(), 'get_grid_bbox': Timer(),
        #       'filter_grid': Timer}
        # print 'one_gt:  {:.3f}s filter_selective_boxlist : {:.3f}s get_grid_bbox : {:.3f}s ' \
        #       'bbox_overlaps_grid : {:.3f}s filter_grid :{:.3f}s' \
        #     .format(_t['one_gt'].average_time,_t['filter_selective_boxlist'].average_time,
        #             _t['get_grid_bbox'].average_time,
        #             _t['bbox_overlaps_grid'].average_time,_t['filter_grid'].average_time)
        '''
        simu_gt_boxeslist.append(simu_gt_boxes)
    cache_file = os.path.join(d.cache_path, d.name + '_gt_roidb_with_simu_bbox_heatmap_new.pkl')
    with open(cache_file, 'wb') as fid:
        cPickle.dump(simu_gt_boxeslist, fid, cPickle.HIGHEST_PROTOCOL)
    _t['total_time'].toc()
    print 'total_time:{:.3f}s'.format(_t['total_time'].average_time)

def get_distance(x_a, y_a, x_b, y_b, x_c, y_c):
    if int(x_b) is not 0 and int(y_b) is not 0:
        # the distance of a point to a line
        vector_a_b = np.array([x_b - x_a, y_b - y_a])
        vector_a_c = np.array([x_c - x_a, y_c - y_a])
        vector_c = np.dot(vector_a_b, vector_a_c) * vector_a_b / np.square(np.linalg.norm(vector_a_b))
        return np.linalg.norm(vector_a_c - vector_c)
    else:
        # the distance between 2 points
        return np.linalg.norm([x_c - x_a, y_c - y_a])

def calculate_corloc():
    cache_file_simu_points = os.path.join(_d.cache_path, 'voc_2007_trainval_gt_roidb_with_simu_points.pkl')
    if os.path.exists(cache_file_simu_points):
        with open(cache_file_simu_points, 'rb') as cache_file_simu_points_fid:
            roidb_simu_points = cPickle.load(cache_file_simu_points_fid)
            # print roidb_simu_points[0], len(roidb_simu_points[0])
            cache_file_simu_bbox = os.path.join(_d.cache_path,
                                                'voc_2007_trainval_gt_roidb_with_simu_bbox_heatmap.pkl')
            if os.path.exists(cache_file_simu_bbox):
                with open(cache_file_simu_bbox, 'rb') as cache_file_simu_bbox_fid:
                    roidb_simu_bbox = cPickle.load(cache_file_simu_bbox_fid)
                    # print roidb_simu_bbox[0], len(roidb_simu_bbox[0])
                    total_boxes = 0
                    boxes_over_thresh = 0
                    postive_picture = 0
                    objects = np.zeros((20, 2))
                    for index in xrange(len(roidb_simu_points)):
                        # print index
                        gt_bboxes = roidb_simu_points[index]['boxes']
                        simu_bboxes = roidb_simu_bbox[index]
                        assert np.shape(gt_bboxes) == np.shape(simu_bboxes)
                        overlaps = bbox_overlaps(gt_bboxes.astype(np.float), simu_bboxes.astype(np.float))

                        overlap_dia = overlaps.diagonal().copy()
                        gt_classes = roidb_simu_points[index]['gt_classes']
                        counted_class = []
                        for i_clss, gt_class_ in enumerate(gt_classes):
                            if int(gt_class_) not in counted_class:
                                if overlap_dia[i_clss] >= 0.5:
                                    objects[int(gt_class_) - 1, :] += 1
                                    counted_class.append(int(gt_class_))

                        for i_clss, gt_class_ in enumerate(gt_classes):
                            if int(gt_class_) not in counted_class:
                                objects[int(gt_class_) - 1, -1] += 1
                                counted_class.append(int(gt_class_))
                        # print overlaps,overlaps.diagonal(),len(overlaps.diagonal())
                        import warnings
                        warnings.filterwarnings('error')
                        try:
                            overlap_dia = overlaps.diagonal().copy()
                            # print overlap_dia
                            overlap_dia[overlap_dia >= 0.5] = 1
                            overlap_dia[overlap_dia < 0.5] = 0
                        except RuntimeWarning as rw:
                            print overlap_dia
                            print gt_bboxes
                            print simu_bboxes
                            print index
                            print rw
                        total_boxes += len(gt_bboxes)
                        boxes_over_thresh += np.size(np.nonzero(overlap_dia))
                        postive_picture += 1 if np.size(np.nonzero(overlap_dia)) is not 0 else 0
                        assert len(gt_bboxes) == len(simu_bboxes)
                    print 'LocCor=', boxes_over_thresh, total_boxes, 1.0 * boxes_over_thresh / total_boxes
                    print 'LocCor2=', postive_picture, len(roidb_simu_points), 1.0 * postive_picture / len(
                        roidb_simu_points)
                    print objects
                    print np.sum(objects,axis=0)
                    print 'true LocCor:', objects[:, 0] / objects[:, 1], np.mean(objects[:, 0] / objects[:, 1])

def calculate_positive_boxes(boxes, rpn_bboxes):
    assert np.shape(boxes) == np.shape(rpn_bboxes['rpn_simu_gt_boxes'][:, 0:4])
    overlaps = bbox_overlaps(boxes.astype(np.float),
                             rpn_bboxes['rpn_simu_gt_boxes'][:, 0:4].astype(np.float))
    overlap_dia = overlaps.diagonal().copy()
    # overlap_dia[overlap_dia >= 0.95] = 1
    overlap_dia[overlap_dia < 0.5] = 0
    return np.size(np.nonzero(overlap_dia))

def calculate_corloc_rpn(d):
    cache_file_simu_points = os.path.join(_d.cache_path, 'voc_2007_trainval_gt_roidb_with_simu_points.pkl')
    cache_file_simu_bbox = os.path.join(_d.cache_path, 'voc_2007_trainval_gt_roidb_with_simu_bbox_heatmap.pkl')
    rpn_file_list = glob.glob(_d.cache_path + '/voc_2007_trainval_rpn_pse_gt_boxes_classifi_bg_valid*.pkl')
    view_result = False
    if os.path.exists(cache_file_simu_points):
        with open(cache_file_simu_points, 'rb') as cache_file_simu_points_fid, open(cache_file_simu_bbox,
                                                                                'rb') as cache_file_simu_bbox_fid:
            roidb_simu_points = cPickle.load(cache_file_simu_points_fid)
            roidb_simu_boxes = cPickle.load(cache_file_simu_bbox_fid)
            for rpn_file in sorted(rpn_file_list, key=os.path.getmtime):
                rpn_file_bbox = os.path.join(rpn_file)
                if os.path.exists(rpn_file_bbox):
                    with open(rpn_file_bbox, 'rb') as rpn_bbox_fid:
                        roidb_rpn_boxes = cPickle.load(rpn_bbox_fid)
                        total_boxes = 0
                        boxes_over_thresh = 0
                        for index in xrange(len(roidb_simu_points)):
                            rpn_bboxes1 = roidb_rpn_boxes[2 * index]
                            rpn_bboxes2 = roidb_rpn_boxes[2 * index + 1]

                            assert rpn_bboxes1['img_index'] == rpn_bboxes2['img_index']
                            img_path = d.image_path_at(index)
                            gt_bboxes = roidb_simu_points[index]['boxes']
                            simu_bboxes = roidb_simu_boxes[index]
                            assert len(gt_bboxes) == len(rpn_bboxes1['rpn_simu_gt_boxes'])
                            assert len(gt_bboxes) == len(rpn_bboxes2['rpn_simu_gt_boxes'])
                            # width = PIL.Image.open(img_path).size[0]
                            im = cv2.imread(img_path)
                            width = im.shape[1]
                            im = im[:, :, (2, 1, 0)]
                            total_boxes += len(gt_bboxes) * 2
                            try:
                                # if (rpn_bboxes1['rpn_simu_gt_boxes'][:, 4].astype(np.int) == 1).all():
                                if rpn_bboxes1['flipped'] == 1:
                                    # flip boxes
                                    gt_boxes_ = gt_bboxes.copy()
                                    # print boxes
                                    oldx1 = gt_boxes_[:, 0].copy()
                                    oldx2 = gt_boxes_[:, 2].copy()
                                    gt_boxes_[:, 0] = width - oldx2 - 1
                                    gt_boxes_[:, 2] = width - oldx1 - 1

                                    simu_bboxes_ = simu_bboxes.copy()
                                    oldx1 = simu_bboxes_[:, 0].copy()
                                    oldx2 = simu_bboxes_[:, 2].copy()
                                    simu_bboxes_[:, 0] = width - oldx2 - 1
                                    simu_bboxes_[:, 2] = width - oldx1 - 1
                                    # print boxes
                                    boxes_over_thresh += calculate_positive_boxes(gt_boxes_, rpn_bboxes1)
                                    vis_results(im[:, ::-1, :], gt_boxes_, rpn_bboxes1, simu_bboxes_, view_result)
                                else:
                                    boxes_over_thresh += calculate_positive_boxes(gt_bboxes, rpn_bboxes1)
                                    vis_results(im, gt_bboxes, rpn_bboxes1, simu_bboxes, view_result)
                                # if (rpn_bboxes2['rpn_simu_gt_boxes'][:, 4].astype(np.int) == 1).all():
                                if rpn_bboxes2['flipped'] == 1:
                                    # flip boxes
                                    gt_boxes_ = gt_bboxes.copy()
                                    oldx1 = gt_boxes_[:, 0].copy()
                                    oldx2 = gt_boxes_[:, 2].copy()
                                    gt_boxes_[:, 0] = width - oldx2 - 1
                                    gt_boxes_[:, 2] = width - oldx1 - 1

                                    simu_bboxes_ = simu_bboxes.copy()
                                    oldx1 = simu_bboxes_[:, 0].copy()
                                    oldx2 = simu_bboxes_[:, 2].copy()
                                    simu_bboxes_[:, 0] = width - oldx2 - 1
                                    simu_bboxes_[:, 2] = width - oldx1 - 1
                                    boxes_over_thresh += calculate_positive_boxes(gt_boxes_, rpn_bboxes2)
                                    vis_results(im[:, ::-1, :], gt_boxes_, rpn_bboxes2, simu_bboxes_, view_result)
                                else:
                                    boxes_over_thresh += calculate_positive_boxes(gt_bboxes, rpn_bboxes2)
                                    vis_results(im, gt_bboxes, rpn_bboxes2, simu_bboxes, view_result)
                            except RuntimeWarning as rw:
                                print gt_bboxes
                                print rpn_bboxes1
                                print index
                                print rw
                        print rpn_file_bbox[-10:], ',LocCor=', boxes_over_thresh, ',', total_boxes, ',', \
                            1.0 * boxes_over_thresh / total_boxes

def vis_results2(d, i_roi, gt_point, simu_point, gt_bbox, filted_boxlist, full_filterd_boxlist, averge_boxes, show):
    import matplotlib.pyplot as plt
    if show:
        im = cv2.imread(d.image_path_at(i_roi))
        print 'image_index:', i_roi
        im = im[:, :, (2, 1, 0)]
        fig, ax = plt.subplots(figsize=(12, 12))
        ax.imshow(im, aspect='equal')

        ax.add_patch(
            plt.Rectangle((gt_bbox[0], gt_bbox[1]),
                          gt_bbox[2] - gt_bbox[0],
                          gt_bbox[3] - gt_bbox[1], fill=False,
                          edgecolor='red', linewidth=3.5)
        )
        plt.plot(simu_point[0], simu_point[1], marker='*', markersize=8)
        plt.plot(gt_point[0], gt_point[1], marker='o', markersize=8)
        for filter_box in filted_boxlist:
            ax.add_patch(
                plt.Rectangle((filter_box[0], filter_box[1]),
                              filter_box[2] - filter_box[0],
                              filter_box[3] - filter_box[1], fill=False,
                              edgecolor='green', linewidth=1.5)
            )
        ax.add_patch(
            plt.Rectangle((averge_boxes[0], averge_boxes[1]),
                          averge_boxes[2] - averge_boxes[0],
                          averge_boxes[3] - averge_boxes[1], fill=False,
                          edgecolor='yellow', linewidth=1.5)
        )

        overlap_bbox_each = []
        for index_i, temp_i in enumerate(full_filterd_boxlist):
            print 'first:', index_i, temp_i
            for _, temp_j in enumerate(full_filterd_boxlist[index_i + 1:]):
                print 'second:', _, temp_j
                overlap_box = []
                if temp_i[0] <= temp_j[0]:
                    overlap_box.append(temp_j[0])
                else:
                    overlap_box.append(temp_i[0])
                if temp_i[1] <= temp_j[1]:
                    overlap_box.append(temp_j[1])
                else:
                    overlap_box.append(temp_i[1])
                if temp_i[2] <= temp_j[2]:
                    overlap_box.append(temp_i[2])
                else:
                    overlap_box.append(temp_j[2])
                if temp_i[3] <= temp_j[3]:
                    overlap_box.append(temp_i[3])
                else:
                    overlap_box.append(temp_j[3])
                # print overlap_box,len(overlap_box)
                # if len(overlap_box) is not 0:
                #     ax.add_patch(
                #         plt.Rectangle((overlap_box[0], overlap_box[1]),
                #                       overlap_box[2] - overlap_box[0],
                #                       overlap_box[3] - overlap_box[1], fill=False,
                #                       edgecolor='yellow', linewidth=1)
                #     )
                overlap_bbox_each.append(np.array(overlap_box))
        assert len(overlap_bbox_each) == len(full_filterd_boxlist) * (len(full_filterd_boxlist) - 1) / 2
        overlap_average = np.average(np.array(overlap_bbox_each), axis=0)
        # print overlap_average
        ax.add_patch(
            plt.Rectangle((overlap_average[0], overlap_average[1]),
                          overlap_average[2] - overlap_average[0],
                          overlap_average[3] - overlap_average[1], fill=False,
                          edgecolor='blue', linewidth=1)
        )
        plt.axis('off')
        plt.tight_layout()
        plt.title('small_obj:' + str(simu_point[2]) + ',boxes:' + str(len(filted_boxlist)))
        plt.draw()
        plt.show()

def vis_results(im, boxes, rpn_bboxes, simu_boxes, isshow):
    import matplotlib.pyplot as plt
    if isshow:
        fig, ax = plt.subplots(figsize=(12, 12))
        ax.imshow(im, aspect='equal')
        for box in boxes:
            ax.add_patch(
                plt.Rectangle((box[0], box[1]),
                              box[2] - box[0],
                              box[3] - box[1], fill=False,
                              edgecolor='green', linewidth=1.5)
            )
        for rpn_box in rpn_bboxes['rpn_simu_gt_boxes']:
            ax.add_patch(
                plt.Rectangle((rpn_box[0], rpn_box[1]),
                              rpn_box[2] - rpn_box[0],
                              rpn_box[3] - rpn_box[1], fill=False,
                              edgecolor='red', linewidth=1.5)
            )
        for simu_box in simu_boxes:
            ax.add_patch(
                plt.Rectangle((simu_box[0], simu_box[1]),
                              simu_box[2] - simu_box[0],
                              simu_box[3] - simu_box[1], fill=False,
                              edgecolor='yellow', linewidth=1.5)
            )
        plt.axis('off')
        plt.tight_layout()
        plt.title('green:GT, red: rpn_simu, yellow: SS')
        plt.draw()
        plt.show()

if __name__ == '__main__':
    # from datasets.pascal_voc import pascal_voc
    _d = pascal_voc('trainval', '2007')

    # res = _d.roidb
    # from IPython import embed; embed()
    dataset_name = 'voc_2007_trainval'
    _roidb = gt_roidb_with_simu_points('/home/leochang/Downloads/PycharmProjects/py-faster-rcnn/data/cache',
                                       dataset_name)
    _boxlist = load_selective_search_roidb(dataset_name)
    # average_bounding_boxes(_d, _roidb, _boxlist)
    # heat_map_bounding_boxes(_d, _roidb, _boxlist)
    # calculate_corloc()
    calculate_corloc_rpn(_d)


import cv2
import keras
from keras.applications.imagenet_utils import preprocess_input
from keras.backend.tensorflow_backend import set_session
from keras.models import Model
from keras.preprocessing import image
import numpy as np
from scipy.misc import imread
import tensorflow as tf

from ssd import SSD300
from ssd_utils import BBoxUtility
from progressbar import ProgressBar

import datetime

# 書き出し設定
voc_classes = ['face'] #ラベル一覧
weight_file_name = "./checkpoints/weights.19-0.87.hdf5"
video_file_name = './free_data/lonestartx_free.mp4'
# -----------------------

def mosaic(src, ratio=0.1):
    small = cv2.resize(src, None, fx=ratio, fy=ratio, interpolation=cv2.INTER_NEAREST)
    return cv2.resize(small, src.shape[:2][::-1], interpolation=cv2.INTER_NEAREST)

def mosaic_area(src, x_min, y_min, x_max, y_max, ratio=0.1):
    dst = src.copy()
    dst[y_min:y_max, x_min:x_max] = mosaic(dst[y_min:y_max, x_min:x_max], ratio)
    return dst

np.set_printoptions(suppress=True)

config = tf.ConfigProto()
config.gpu_options.per_process_gpu_memory_fraction = 0.45
set_session(tf.Session(config=config))

NUM_CLASSES = len(voc_classes) + 1

input_shape=(300, 300, 3)
model = SSD300(input_shape, num_classes=NUM_CLASSES)
# model.load_weights('weights_SSD300.hdf5', by_name=True)
model.load_weights(weight_file_name, by_name=True)
bbox_util = BBoxUtility(NUM_CLASSES)

vid = cv2.VideoCapture(video_file_name)
if not vid.isOpened():
    raise IOError(("Couldn't open video file or webcam. If you're "
    "trying to open a webcam, make sure you video_path is an integer!"))

vidw = vid.get(cv2.CAP_PROP_FRAME_WIDTH)
vidh = vid.get(cv2.CAP_PROP_FRAME_HEIGHT)
fps = vid.get(cv2.CAP_PROP_FPS)

fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')
now = datetime.datetime.now()
out = cv2.VideoWriter('./free_data/output' + now.strftime("%Y-%m-%d-%H-%M-%S") + '.avi', int(fourcc), fps, (int(vidw), int(vidh)))

min = 0
max = int(vid.get(7))
p = ProgressBar(min, max)

while True:
# for i in range(10):  # for test
    retval, img = vid.read()
    if not retval:
        print("Done!")
        break
    p.update(int(vid.get(1)))
    inputs = []
    images = []
    images.append(img)
    img_org = img
    img = cv2.resize(img, (300, 300))
    img = image.img_to_array(img)
    inputs.append(img.copy())
    inputs = preprocess_input(np.array(inputs))

    preds = model.predict(inputs, batch_size=1, verbose=1)
    results = bbox_util.detection_out(preds)
    for i, img in enumerate(images):
        # Parse the outputs.
        det_label = results[i][:, 0]
        det_conf = results[i][:, 1]
        det_xmin = results[i][:, 2]
        det_ymin = results[i][:, 3]
        det_xmax = results[i][:, 4]
        det_ymax = results[i][:, 5]

        # Get detections with confidence higher than 0.6.
        top_indices = [i for i, conf in enumerate(det_conf) if conf >= 0.1]

        top_conf = det_conf[top_indices]
        top_label_indices = det_label[top_indices].tolist()
        top_xmin = det_xmin[top_indices]
        top_ymin = det_ymin[top_indices]
        top_xmax = det_xmax[top_indices]
        top_ymax = det_ymax[top_indices]

        for i in range(top_conf.shape[0]):
            xmin = int(round(top_xmin[i] * img.shape[1]))
            ymin = int(round(top_ymin[i] * img.shape[0]))
            xmax = int(round(top_xmax[i] * img.shape[1]))
            ymax = int(round(top_ymax[i] * img.shape[0]))

            score = top_conf[i]
            label = int(top_label_indices[i])
            label_name = voc_classes[label - 1]
            # print(label_name)
            # cv2.rectangle(img_org, (xmin, ymin), (xmax+1, ymax+1), (0, 0, 255), 1)  # red box
            img_org = mosaic_area(img_org, xmin, ymin, xmax+1, ymax+1, ratio=0.1) # mosaic

    out.write(img_org)

vid.release()
out.release()


#coding: utf-8
import pygame
from pygame.locals import *
import random
import sys
#import os
#import codecs
from PIL import Image
import numpy as np
import cv2

# import module that I made
import faceCamera
import detectFace

CS = 6 # cell size
SCR_RECT = Rect(0, 0, 6*int(800/6), 6*int(800/6)) # screen size depends on the size of detected face
THRESHOLD = 100 # the threshold to pixelate the pic
NUM_ROW = SCR_RECT.height / CS # row of field
NUM_COL = SCR_RECT.width / CS # column of field
DEAD, ALIVE, STAY = 0, 1, 2 # constant for live or dead
RAND_LIFE = 0.1

# You can choose the file from agtFace.jpg or face.jpg
img = np.array(Image.open('face.jpg').convert('L'))

# Adaptive Mean Thresholding
img = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY,21,2)
cv2.imwrite("faceAdapt.jpg",img)

img = cv2.medianBlur(img, 5)
cv2.imwrite("faceBlur1.jpg",img)
for i in range(10):
    img = cv2.medianBlur(img, 3)
    cv2.imwrite("faceBlur"+str(i+3)+".jpg",img)

class LifeGame:
    def __init__(self):
        pygame.init()
        screen = pygame.display.set_mode(SCR_RECT.size)
        pygame.display.set_caption(u"Conway's Game of Life")
        self.font = pygame.font.SysFont(None, 16)
        # Field that has size of NUM_ROW * NUM_ROL
        self.field = [[DEAD for x in range(NUM_COL)] for y in range(NUM_ROW)]
        self.color = [[DEAD for x in range(NUM_COL)] for y in range(NUM_ROW)]
        self.generation = 0 # the number of generation
        self.time = 100
        self.run = False # run or not
        self.cursor = [NUM_COL, NUM_ROW] # the position of carsor
        # initiate the life game
        self.clear()
        # main loop
        clock = pygame.time.Clock()

        if detectFace.isFace :
            self.draw_face()
        else :
            print "No face is detected..."
            return 0
        while True:
            clock.tick(30)
            self.update()
            self.draw(screen)
            pygame.display.update()
            for event in pygame.event.get():
                if event.type == QUIT:
                    pygame.quit()
                    sys.exit()
                elif event.type == KEYDOWN:
                    if event.key == K_ESCAPE:
                        pygame.quit()
                        sys.exit()
                    # move cursor by key
                    elif event.key == K_LEFT:
                        self.cursor[0] -= 1
                        if self.cursor[0] < 0: self.cursor[0] = 0
                    elif event.key == K_RIGHT:
                        self.cursor[0] += 1
                        if self.cursor[0] > NUM_COL-1: self.cursor[0] = NUM_COL-1
                    elif event.key == K_UP:
                        self.cursor[1] -= 1
                        if self.cursor[1] < 0: self.cursor[1] = 0
                    elif event.key == K_DOWN:
                        self.cursor[1] += 1
                        if self.cursor[1] > NUM_ROW-1: self.cursor[1] = NUM_ROW-1
                    # turn a cell when pushing space key
                    elif event.key == K_SPACE:
                        x, y = self.cursor
                        if self.field[y][x] == DEAD:
                            self.field[y][x] = ALIVE
                            self.color[y][x] = ALIVE
                        elif self.field[y][x] == ALIVE:
                            self.field[y][x] = DEAD
                    # start simulation when pushing 's' key
                    elif event.key == K_s:
                        self.run = not self.run
                    # progress just one generation by pushing 'n'
                    elif event.key == K_n:
                        self.step()
                    # clear by pushing 'c'
                    elif event.key == K_c:
                        self.clear()
                        self.run = False
                    # add a alive cell randomly by pushing 'r'
                    elif event.key == K_r:
                        self.rand()

                elif event.type == MOUSEBUTTONDOWN and event.button == 1:
                    # turn a cell by pushing left click
                    px, py = event.pos
                    x, y = px/CS, py/CS
                    self.cursor = [x, y]
                    if self.field[y][x] == DEAD:
                        self.field[y][x] = ALIVE
                        self.color[y][x] = ALIVE
                    elif self.field[y][x] == ALIVE:
                        self.field[y][x] = DEAD
                elif event.type == MOUSEMOTION and event.buttons == (1,0,0):
                    px, py = event.pos
                    x, y = px/CS, py/CS
                    if self.field[y][x] == DEAD:
                        self.field[y][x] = ALIVE
                        self.color[y][x] = ALIVE
                    elif self.field[y][x] == ALIVE:
                        self.field[y][x] = DEAD

    def clear(self):
        """Initiate a game"""
        self.generation = 0
        for y in range(NUM_ROW):
            for x in range(NUM_COL):
                self.field[y][x] = DEAD
    def rand(self):
        """Add a alive cell randomly"""
        for y in range(NUM_ROW):
            for x in range(NUM_COL):
                if random.random() < RAND_LIFE:
                    self.field[y][x] = ALIVE
                    self.color[y][x] = ALIVE
    def update(self):
        pygame.time.wait(200)
        """Update the field"""
        if self.run:
            self.step() # Progress one step
    def step(self):
        """Progress one generation"""
        # next field
        next_field = [[False for x in range(NUM_COL)] for y in range(NUM_ROW)]
        # Set the field by following the rule of life game
        sum_alive_cells = 0
        for y in range(NUM_ROW):
            for x in range(NUM_COL):
                num_alive_cells = self.around(x, y)
                if num_alive_cells == 2:
                    # keep a cell if 2 cells around the cell are alive
                    next_field[y][x] = self.field[y][x]
                    self.color[y][x] = STAY
                    sum_alive_cells += 1
                elif num_alive_cells == 3:
                    # born a cell if 3 cells around the cell are alive
                    next_field[y][x] = ALIVE
                    self.color[y][x] = ALIVE
                    sum_alive_cells += 1
                else:
                    # other cells are dead
                    next_field[y][x] = DEAD
                    self.color[y][x] = DEAD
        self.field = next_field
        self.generation += 1

    def draw(self, screen):
        """Draw the field"""
        # Paint cells
        for y in range(NUM_ROW):
            for x in range(NUM_COL):
                if self.field[y][x] == ALIVE:
                    if(self.color[y][x] == ALIVE):
                        pygame.draw.rect(screen, (255,255,0), Rect(x*CS,y*CS,CS,CS))
                    elif(self.color[y][x] == STAY):
                        pygame.draw.rect(screen, (255,0,255),Rect(x*CS,y*CS,CS,CS))
                elif self.field[y][x] == DEAD:
                    pygame.draw.rect(screen, (0,255,255), Rect(x*CS,y*CS,CS,CS))
                pygame.draw.line(screen, (255,255,255), (x*CS,0),(x*CS,SCR_RECT.height))
                pygame.draw.line(screen, (255,255,255), (0,y*CS),(SCR_RECT.width,y*CS))

        # Draw cursor
        pygame.draw.rect(screen, (0,0,255), Rect(self.cursor[0]*CS,self.cursor[1]*CS,CS,CS), 1)
        # Draw the information of the game
        screen.blit(self.font.render("generation:%d" % self.generation, True, (0,0,0)), (0,0))
        screen.blit(self.font.render("space : birth/kill",True,(0,0,0,)),(0,12))
        screen.blit(self.font.render("s : start/stop",True,(0,0,0)),(0,24))
        screen.blit(self.font.render("n : next",True,(0,0,0)),(0,36))
        screen.blit(self.font.render("r : random",True,(0,0,0)),(0,48))

    def around(self, x, y):
        """Return the number of the alive cells around (x,y)"""
        if x == 0 or x == NUM_COL-1 or y == 0 or y == NUM_ROW-1:
            return 0
        sum = 0
        sum += self.field[y-1][x-1] # cell at the upper left
        sum += self.field[y-1][x]   # cell at upper side
        sum += self.field[y-1][x+1] # cell at the upper right
        sum += self.field[y][x-1]   # cell at the left
        sum += self.field[y][x+1]   # cell at the right
        sum += self.field[y+1][x-1] # cell at the lower left
        sum += self.field[y+1][x]   # cell at the lower side
        sum += self.field[y+1][x+1] # cell at the lower right
        return sum

    def draw_face(self):
        x = detectFace.detectedFace[0] - 50
        y = detectFace.detectedFace[1] - 80
        width = detectFace.detectedFace[2] + 100
        height = detectFace.detectedFace[3] + 150

        THRESHOLD = np.average(img[x:x+width][y:y+height])

        for i in xrange(0,NUM_ROW):
            for j in xrange(0,NUM_COL):
                searchX = x + i*width/NUM_ROW
                searchY = y + j*height/NUM_COL
                if img[searchY][searchX] < THRESHOLD:
                    self.field[j][i] = ALIVE
                    self.color[j][i] = ALIVE

if __name__ == "__main__":
    LifeGame()


from access.DataBase import DataBase
from functions.CoordsTransform import CoordsTransform
from functions.GeoCorrect1Poly import GeoCorrect1Poly
from functions.GeoCorrect2Poly import GeoCorrect2Poly
from PIL import Image
from PyQt5.QtCore import QObject,pyqtSignal
import numpy as np

class CirclesAssign(QObject):
    processImage=pyqtSignal(int)

    def __init__(self,dbFile, geoCorrectMode):
        super(CirclesAssign,self).__init__()
        self.geoCorrectMode=geoCorrectMode
        self.database=DataBase(dbFile)
        self.database.connectDB()
        self.__initVariable()

    def __del__(self):
        self.database.closeDB()

    def __initVariable(self):
        self.width=None
        self.height=None
        # self.radius=None

        #下面的，长度相同
        self.ids=[]#图像id号
        self.parms=[]#图像转换参数
        self.limits=[]#图像范围

    def run(self):
        if not self.updateLimit():
            return False

        self.__getCircles()
        return True

    #更新图像的四个点坐标范围
    def updateLimit(self):
        if not self.__getImage():
            return False

        self.__convertLimits()
        return True

    def __getImage(self):
        self.ids,images,self.parms=self.database.getImageTransformParmsByState()
        num=len(self.ids)

        #发送图像个数
        self.processImage.emit(num)

        if num==0:
            return False

        #获取图像尺寸
        img=Image.open(images[0])
        self.width,self.height=img.size
        del img

        return True

    #计算每张图的地理坐标范围，并保存至数据库
    def __convertLimits(self):
        cf=CoordsTransform()
        pixels=[[0,0],[0,self.height-1],[self.width-1,self.height-1],[self.width-1,0]]

        #计算
        for idx,parm in zip(self.ids,self.parms):
            cf.setParms(parm)
            limit=cf.pixelsToGrounds(pixels)
            self.limits.append(limit)
        #保存
        self.database.updateImageLimit(self.ids,self.limits)

    #读取圆信息并开始处理
    def __getCircles(self):
        idCs,_,locations,radius=self.database.getCircles()
        if len(idCs)==0:
            self.processImage.emit(len(self.limits)-1)
            return
        # self.radius=radius[0]

        idCs=np.matrix(idCs)
        locations=np.matrix(locations)

        ####
        self.__filter(idCs,locations,radius)

    #根据地理坐标范围过滤，并求转换坐标
    def __filter(self,idCs,points,radius):
        cf=CoordsTransform()

        #对每张图
        for i,limit in enumerate(self.limits):
            #过滤的结果
            index=self.__pointsInRect(limit,points)
            #没有圆落在该图像内
            if index[0].size==0:
                self.processImage.emit(i)
                continue
            #位于某图像上的圆的id
            idCs_Image=idCs.T[index].tolist()[0]

            #位于某图像上的圆的地理坐标
            grounds_Image=points[index[0]].tolist()

            #计算对应的像素坐标
            cf.setParms(self.parms[i])

            #计算像素半径
            radiusPixel=cf.lengthGroundsToPixels(radius[i])

            if self.geoCorrectMode==0:
                pixels = cf.groundsToPixels(grounds_Image)
            else:
                if self.geoCorrectMode == 1:
                    coordsTool = GeoCorrect1Poly()
                    polyParms = self.database.getGeo1PloyParms(self.ids[i])
                elif self.geoCorrectMode == 2:
                    coordsTool = GeoCorrect2Poly()
                    polyParms=self.database.getGeo2PloyParms(self.ids[i])

                coordsTool.setParms(polyParms)
                pixels=coordsTool.groundsToPixels(grounds_Image)

            self.__saveCirclesInImageToDB(self.ids[i],idCs_Image,pixels,radiusPixel)

            #发送当前正在处理的图像序号
            self.processImage.emit(i)

    #保存至数据库
    def __saveCirclesInImageToDB(self,image_id,circle_ids,pixels,radius):
        self.database.insertSelectCircle(image_id,circle_ids,pixels,radius)

    #圆是否在矩形中，返回在矩形中的序号（行号）
    def __pointsInRect(self,limit,points):
        num=points.shape[0]

        limit=np.matrix(limit)
        #矩形框逆时针四个点
        p1=limit[0]
        p2=limit[1]
        p3=limit[2]
        p4=limit[3]

        #向量
        p2p0=points-p2
        p1p2=p2-p1
        p3p0=points-p3
        p3p4=p4-p3

        p1p0=points-p1
        p1p4=p4-p1
        p2p0=points-p2
        p2p3=p3-p2

        #(x1,y1)x(x2,y2)=x1*y2-x2*y1
        #p2p0   x p1p2
        s1=p2p0[:,0]*p1p2[0,1]-p1p2[0,0]*p2p0[:,1]
        #p3p0   X p3p4
        s2=p3p0[:,0]*p3p4[0,1]-p3p4[0,0]*p3p0[:,1]
        #p1p0   x p1p4
        s3=p1p0[:,0]*p1p4[0,1]-p1p4[0,0]*p1p0[:,1]
        #p2p0   x p2p3
        s4=p2p0[:,0]*p2p3[0,1]-p2p3[0,0]*p2p0[:,1]

        d1=np.multiply(s1,s2)>0
        d2=np.multiply(s3,s4)<0

        flag=d1 & d2

        return np.where(flag==True)

if __name__=='__main__':
    dbFile='C:/Users/liang/Desktop/tmp/acc.pro'
    ca=CirclesAssign(dbFile)
    ca.run()


from copy import deepcopy
import itertools
import numpy as np
import torch
from torch.optim import Adam
import gym
import time
import algos.pytorch.td3_sp.core as core
import os
os.environ["CUDA_VISIBLE_DEVICES"] = "0"
device = torch.device("cuda")

class ReplayBuffer:
    """
    A simple FIFO experience replay buffer for TD3 agents.
    """

    def __init__(self, obs_dim, act_dim, size):
        self.obs_buf = np.zeros(core.combined_shape(size, obs_dim), dtype=np.float32)
        self.obs2_buf = np.zeros(core.combined_shape(size, obs_dim), dtype=np.float32)
        self.act_buf = np.zeros(core.combined_shape(size, act_dim), dtype=np.float32)
        self.rew_buf = np.zeros(size, dtype=np.float32)
        self.done_buf = np.zeros(size, dtype=np.float32)
        self.ptr, self.size, self.max_size = 0, 0, size

    def store(self, obs, act, rew, next_obs, done):
        self.obs_buf[self.ptr] = obs
        self.obs2_buf[self.ptr] = next_obs
        self.act_buf[self.ptr] = act
        self.rew_buf[self.ptr] = rew
        self.done_buf[self.ptr] = done
        self.ptr = (self.ptr+1) % self.max_size
        self.size = min(self.size+1, self.max_size)

    def sample_batch(self, batch_size=32):
        idxs = np.random.randint(0, self.size, size=batch_size)
        batch = dict(obs=self.obs_buf[idxs],
                     obs2=self.obs2_buf[idxs],
                     act=self.act_buf[idxs],
                     rew=self.rew_buf[idxs],
                     done=self.done_buf[idxs])
        return {k: torch.as_tensor(v, dtype=torch.float32).cuda() for k,v in batch.items()}

class TD3:
    def __init__(self, a_dim, obs_dim, a_bound,
                actor_critic=core.MLPActorCritic,
                ac_kwargs=dict(), seed=0,
                steps_per_epoch=4000, epochs=100,
                replay_size=int(1e6), gamma=0.99,
                polyak=0.995, pi_lr=1e-3, q_lr=1e-3,
                act_noise=0.1, target_noise=0.2,
                noise_clip=0.5, policy_delay=2,
                logger_kwargs=dict(), save_freq=1):

        torch.manual_seed(seed)
        np.random.seed(seed)

        self.learn_step = 0
        self.obs_dim = obs_dim
        self.act_dim = a_dim
        self.act_limit = a_bound
        self.policy_delay = policy_delay
        self.action_noise = act_noise

        self.target_noise = target_noise
        self.noise_clip = noise_clip
        self.polyak = polyak
        self.policy_delay = policy_delay
        self.gamma = gamma

        # Share information about action space with policy architecture
        ac_kwargs['action_space'] = a_bound

        # Create actor-critic module and target networks
        self.ac = actor_critic(obs_dim=self.obs_dim, act_dim=self.act_dim, act_bound=self.act_limit).cuda()
        self.ac_targ = deepcopy(self.ac).cuda()

        # Freeze target networks with respect to optimizers (only update via polyak averaging)
        for p in self.ac_targ.parameters():
            p.requires_grad = False
        # List of parameters for both Q-networks (save this for convenience)
        self.q_params = itertools.chain(self.ac.q1.parameters(), self.ac.q2.parameters())
        # Experience buffer
        self.replay_buffer = ReplayBuffer(obs_dim=self.obs_dim, act_dim=self.act_dim, size=replay_size)

        # Count variables (protip: try to get a feel for how different size networks behave!)
        var_counts = tuple(core.count_vars(module) for module in [self.ac.pi, self.ac.q1, self.ac.q2])
        # Set up optimizers for policy and q-function
        self.pi_optimizer = Adam(self.ac.pi.parameters(), lr=pi_lr)
        self.q_optimizer = Adam(self.q_params, lr=q_lr)

    def get_action(self, s, noise_scale=0):
        s_cuda = torch.as_tensor(s, dtype=torch.float32).cuda()
        a = self.ac.act(s_cuda)
        a = a.detach().cpu().numpy()
        a += noise_scale * np.random.randn(self.act_dim)
        return np.clip(a, -self.act_limit, self.act_limit)

    def store_transition(self, transition):
        (s, a, r, s_, done) = transition
        self.replay_buffer.store(s, a, r, s_, done)

    def test_agent(self, env, max_ep_len=1000, n=5):
        ep_reward_list = []
        for j in range(n):
            s = env.reset()
            ep_reward = 0
            for i in range(max_ep_len):
                a = self.get_action(s)
                s, r, d, _ = env.step(a)
                ep_reward += r
            ep_reward_list.append(ep_reward)
        mean_ep_reward = np.mean(np.array(ep_reward_list))
        return mean_ep_reward

    def compute_loss_pi(self, data):
        o = data['obs']
        q1_pi = self.ac.q1(o, self.ac.pi(o))
        return -q1_pi.mean()

    def compute_loss_q(self, data):
        o, a, r, o2, d = data['obs'], data['act'], data['rew'], data['obs2'], data['done']
        q1 = self.ac.q1(o,a)
        q2 = self.ac.q2(o,a)
        # Bellman backup for Q functions
        with torch.no_grad():
            pi_targ = self.ac_targ.pi(o2)
            # Target policy smoothing
            epsilon = torch.randn_like(pi_targ) * self.target_noise
            epsilon = torch.clamp(epsilon, -self.noise_clip, self.noise_clip)
            a2 = pi_targ + epsilon
            a2 = torch.clamp(a2, -self.act_limit, self.act_limit)
            # Target Q-values
            q1_pi_targ = self.ac_targ.q1(o2, a2)
            q2_pi_targ = self.ac_targ.q2(o2, a2)
            q_pi_targ = torch.min(q1_pi_targ, q2_pi_targ)
            backup = r + self.gamma * (1 - d) * q_pi_targ
        # MSE loss against Bellman backup
        loss_q1 = ((q1 - backup)**2).mean()
        loss_q2 = ((q2 - backup)**2).mean()
        loss_q = loss_q1 + loss_q2
        # Useful info for logging
        # loss_info = dict(Q1Vals=q1.detach().numpy(),
        #                  Q2Vals=q2.detach().numpy())
        # loss_info = dict(Q1Vals=q1.detach().cpu().numpy(),
        #                  Q2Vals=q2.detach().cpu().numpy())
        loss_info = dict(Q1Vals=q1,
                         Q2Vals=q2)
        return loss_q, loss_info

    def learn(self, batch_size=100,
              actor_lr_input=0.001,
              critic_lr_input=0.001,
              ):
        # First run one gradient descent step for Q1 and Q2
        self.q_optimizer.zero_grad()
        data = self.replay_buffer.sample_batch(batch_size)
        loss_q, loss_info = self.compute_loss_q(data)
        loss_q.backward()
        self.q_optimizer.step()
        # Possibly update pi and target networks
        if self.learn_step % self.policy_delay == 0:
            for p in self.q_params:
                p.requires_grad = False
            # Next run one gradient descent step for pi.
            self.pi_optimizer.zero_grad()
            loss_pi = self.compute_loss_pi(data)
            loss_pi.backward()
            self.pi_optimizer.step()

            # Unfreeze Q-networks so you can optimize it at next DDPG step.
            for p in self.q_params:
                p.requires_grad = True

            with torch.no_grad():
                for p, p_targ in zip(self.ac.parameters(), self.ac_targ.parameters()):
                    # NB: We use an in-place operations "mul_", "add_" to update target
                    # params, as opposed to "mul" and "add", which would make new tensors.
                    p_targ.data.mul_(self.polyak)
                    p_targ.data.add_((1 - self.polyak) * p.data)
        self.learn_step += 1

if __name__ == '__main__':
    import argparse

    random_seed = int(time.time() * 1000 % 1000)
    parser = argparse.ArgumentParser()
    parser.add_argument('--env', type=str, default='HalfCheetah-v2')
    parser.add_argument('--hid', type=int, default=300)
    parser.add_argument('--l', type=int, default=1)
    parser.add_argument('--gamma', type=float, default=0.99)
    parser.add_argument('--seed', '-s', type=int, default=random_seed)
    parser.add_argument('--epochs', type=int, default=3000)
    parser.add_argument('--max_steps', type=int, default=1000)
    parser.add_argument('--exp_name', type=str, default='td3_torch_class')
    args = parser.parse_args()

    env = gym.make(args.env)
    env = env.unwrapped
    env.seed(args.seed)

    s_dim = env.observation_space.shape[0]
    a_dim = env.action_space.shape[0]
    a_bound = env.action_space.high[0]

    net = TD3(a_dim, s_dim, a_bound,
              )
    ep_reward_list = []
    test_ep_reward_list = []

    for i in range(args.epochs):
        s = env.reset()
        ep_reward = 0
        st = time.time()
        for j in range(args.max_steps):
            # Add exploration noise
            # if i < 10:
            #     a = np.random.rand(a_dim) * a_bound
            # else:
            #     # a = net.choose_action(s)
            a = net.get_action(s, 0.1)
            a = np.clip(a, -a_bound, a_bound)
            s_, r, done, info = env.step(a)
            done = False if j == args.max_steps - 1 else done

            net.store_transition((s, a, r, s_, done))

            s = s_
            ep_reward += r
            if j == args.max_steps - 1:
                up_st = time.time()
                for _ in range(args.max_steps):
                    net.learn()

                ep_update_time = time.time() - up_st

                ep_reward_list.append(ep_reward)
                print('Episode:', i, ' Reward: %i' % int(ep_reward),
                      "learn step:", net.learn_step,
                      "ep_time:", np.round(time.time()-st, 3),
                      "up_time:", np.round(ep_update_time, 3),
                      )
                # if ep_reward > -300:RENDER = True

                # 增加测试部分!
                if i % 20 == 0:
                    test_ep_reward = net.test_agent(env=env, n=5)
                    test_ep_reward_list.append(test_ep_reward)
                    print("-" * 20)
                    print('Episode:', i, ' Reward: %i' % int(ep_reward),
                          'Test Reward: %i' % int(test_ep_reward),
                          )
                    print("-" * 20)
                break

    import matplotlib.pyplot as plt
    plt.plot(ep_reward_list)
    img_name = str(args.exp_name + "_" + args.env + "_epochs" +
                   str(args.epochs) +
                   "_seed" + str(args.seed))
    plt.title(img_name + "_train")
    plt.savefig(img_name + ".png")
    plt.show()
    plt.close()

    plt.plot(test_ep_reward_list)
    plt.title(img_name + "_test")
    plt.savefig(img_name + ".png")
    plt.show()


# Copyright 2020 Google Research. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""A simple example on how to use keras model for inference."""

import os
import sys
# Allow relative imports when being executed as script.
if __name__ == "__main__" and __package__ is None:
  sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../..'))
  import efficientdet.keras
  __package__ = "efficientdet.keras"

import os
from absl import app
from absl import flags
from absl import logging
import numpy as np
from PIL import Image
import tensorflow as tf

from .. import hparams_config
from .. import inference
from . import efficientdet_keras

flags.DEFINE_string('image_path', None, 'Location of test image.')
flags.DEFINE_string('output_dir', None, 'Directory of annotated output images.')
flags.DEFINE_string('model_dir', None, 'Location of the checkpoint to run.')
flags.DEFINE_string('model_name', 'efficientdet-d0', 'Model name to use.')
flags.DEFINE_string('hparams', '', 'Comma separated k=v pairs or a yaml file')
flags.DEFINE_bool('debug', False, 'If true, run function in eager for debug.')
flags.DEFINE_string('saved_model_dir', None, 'Saved model directory')
FLAGS = flags.FLAGS

def main(_):

  # pylint: disable=line-too-long
  # Prepare images and checkpoints: please run these commands in shell.
  # !mkdir tmp
  # !wget https://user-images.githubusercontent.com/11736571/77320690-099af300-6d37-11ea-9d86-24f14dc2d540.png -O tmp/img.png
  # !wget https://storage.googleapis.com/cloud-tpu-checkpoints/efficientdet/coco/efficientdet-d0.tar.gz -O tmp/efficientdet-d0.tar.gz
  # !tar zxf tmp/efficientdet-d0.tar.gz -C tmp
  imgs = [np.array(Image.open(FLAGS.image_path))] * 2
  # Create model config.
  config = hparams_config.get_efficientdet_config('efficientdet-d0')
  config.is_training_bn = False
  config.image_size = '1920x1280'
  config.nms_configs.score_thresh = 0.4
  config.nms_configs.max_output_size = 100
  config.override(FLAGS.hparams)

  # Use 'mixed_float16' if running on GPUs.
  policy = tf.keras.mixed_precision.experimental.Policy('float32')
  tf.keras.mixed_precision.experimental.set_policy(policy)
  tf.config.experimental_run_functions_eagerly(FLAGS.debug)

  # Create and run the model.
  model = efficientdet_keras.EfficientDetModel(config=config)
  model.build((None, None, None, 3))
  model.load_weights(tf.train.latest_checkpoint(FLAGS.model_dir))
  model.summary()

  class ExportModel(tf.Module):

    def __init__(self, model):
      super().__init__()
      self.model = model

    @tf.function
    def f(self, imgs):
      return self.model(imgs, training=False, post_mode='global')

  imgs = tf.convert_to_tensor(imgs, dtype=tf.uint8)
  export_model = ExportModel(model)
  if FLAGS.saved_model_dir:
    tf.saved_model.save(
        export_model,
        FLAGS.saved_model_dir,
        signatures=export_model.f.get_concrete_function(
            tf.TensorSpec(shape=(None, None, None, 3), dtype=tf.uint8)))
    export_model = tf.saved_model.load(FLAGS.saved_model_dir)

  boxes, scores, classes, valid_len = export_model.f(imgs)

  # Visualize results.
  for i, img in enumerate(imgs):
    length = valid_len[i]
    img = inference.visualize_image(
        img,
        boxes[i].numpy()[:length],
        classes[i].numpy().astype(np.int)[:length],
        scores[i].numpy()[:length],
        label_map=config.label_map,
        min_score_thresh=config.nms_configs.score_thresh,
        max_boxes_to_draw=config.nms_configs.max_output_size)
    output_image_path = os.path.join(FLAGS.output_dir, str(i) + '.jpg')
    Image.fromarray(img).save(output_image_path)
    print('writing annotated image to %s' % output_image_path)

if __name__ == '__main__':
  flags.mark_flag_as_required('image_path')
  flags.mark_flag_as_required('output_dir')
  flags.mark_flag_as_required('model_dir')
  logging.set_verbosity(logging.ERROR)
  app.run(main)


from styx_msgs.msg import TrafficLight
import rospy
import numpy as np
import tensorflow as tf

graph_file_location = rospy.get_param("/tl_classifier_pb_file")

CONFIDENCE_THRESHOLD = 0.5

class TLClassifier(object):
    def __init__(self):

        # Load graph
        self.detection_graph = tf.Graph()
        with self.detection_graph.as_default():
            od_graph_def = tf.GraphDef()
            with tf.gfile.GFile(graph_file_location, 'rb') as fid:
                serialized_graph = fid.read()
                od_graph_def.ParseFromString(serialized_graph)
                tf.import_graph_def(od_graph_def, name='')

        self.image_tensor = self.detection_graph.get_tensor_by_name('image_tensor:0')
        self.detection_boxes = self.detection_graph.get_tensor_by_name('detection_boxes:0')
        self.detection_scores = self.detection_graph.get_tensor_by_name('detection_scores:0')
        self.detection_classes = self.detection_graph.get_tensor_by_name('detection_classes:0')

    def get_classification(self, image):
        """Determines the color of the traffic light in the image
        Args:
            image (cv::Mat): image containing the traffic light
        Returns:
            int: ID of traffic light color (specified in styx_msgs/TrafficLight)
        """

        image_np = np.expand_dims(np.asarray(image, dtype=np.uint8), 0)
        with tf.Session(graph=self.detection_graph) as sess:
            # Detection
            (boxes, scores, classes) = sess.run([self.detection_boxes, self.detection_scores, self.detection_classes],
                                                feed_dict={self.image_tensor: image_np})
            boxes = np.squeeze(boxes)
            scores = np.squeeze(scores)
            classes = np.squeeze(classes)

            # Filter boxes with a maximum confidence threshold
            idxs = []
            for i in range(len(classes)):
                if scores[i] >= CONFIDENCE_THRESHOLD:
                    idxs.append(i)
            boxes = boxes[idxs, ...]
            scores = scores[idxs, ...]
            classes = classes[idxs, ...]

            if classes.size != 0:
                if classes[0] == 1:
                    rospy.logwarn("[TL_CLASSIFIER] Green")
                    return TrafficLight.GREEN
                elif classes[0] == 2:
                    rospy.logwarn("[TL_CLASSIFIER] Red")
                    return TrafficLight.RED
                elif classes[0] == 3:
                    rospy.logwarn("[TL_CLASSIFIER] Yellow")
                    return TrafficLight.YELLOW

        rospy.logwarn("[TL_CLASSIFIER] Unknown")
        return TrafficLight.UNKNOWN