"""
Location data from Google Takeout

DEPRECATED: setup my.google.takeout.parser and use my.location.google_takeout instead
"""

REQUIRES = [
    'geopy', # checking that coordinates are valid
    'ijson',
]

from datetime import datetime, timezone
from itertools import islice
from pathlib import Path
from subprocess import Popen, PIPE
from typing import Iterable, NamedTuple, Optional, Sequence, IO, Tuple
import re

# pip3 install geopy
import geopy # type: ignore

from ..core.common import LazyLogger, mcachew
from ..core.cachew import cache_dir
from ..core import kompress

from my.core.warnings import high

high("Please set up my.google.takeout.parser module for better takeout support")

 # otherwise uses ijson
 # todo move to config??
USE_GREP = False

logger = LazyLogger(__name__)

class Location(NamedTuple):
    dt: datetime
    lat: float
    lon: float
    alt: Optional[float]

TsLatLon = Tuple[int, int, int]

def _iter_via_ijson(fo) -> Iterable[TsLatLon]:
    # ijson version takes 25 seconds for 1M items (without processing)
    # todo extract to common?
    try:
        # pip3 install ijson cffi
        import ijson.backends.yajl2_cffi as ijson # type: ignore
    except:
        import warnings
        warnings.warn("Falling back to default ijson because 'cffi' backend isn't found. It's up to 2x faster, you might want to check it out")
        import ijson # type: ignore

    for d in ijson.items(fo, 'locations.item'):
        yield (
            int(d['timestampMs']),
            d['latitudeE7' ],
            d['longitudeE7'],
        )

# todo ugh. fragile, not sure, maybe should do some assert in advance?
def _iter_via_grep(fo) -> Iterable[TsLatLon]:
    # grep version takes 5 seconds for 1M items (without processing)
    x = [-1, -1, -1]
    for i, line in enumerate(fo):
        if i > 0 and i % 3 == 0:
            yield tuple(x) # type: ignore[misc]
        n = re.search(b': "?(-?\\d+)"?,?$', line) # meh. somewhat fragile...
        assert n is not None
        j = i % 3
        x[j] = int(n.group(1).decode('ascii'))
    # make sure it's read what we expected
    assert (i + 1) % 3 == 0
    yield tuple(x) # type: ignore[misc]

# todo could also use pool? not sure if that would really be faster...
# search thread could process 100K at once?
# would need to find out a way to know when to stop? process in some sort of sqrt progression??

def _iter_locations_fo(fit) -> Iterable[Location]:
    total = 0
    errors = 0

    for tsMs, latE7, lonE7 in fit:
        dt = datetime.fromtimestamp(tsMs / 1000, tz=timezone.utc)
        total += 1
        if total % 10000 == 0:
            logger.info('processing item %d %s', total, dt)

        try:
            lat = float(latE7 / 1e7)
            lon = float(lonE7 / 1e7)
            # note: geopy is quite slow..
            point = geopy.Point(lat, lon) # kinda sanity check that coordinates are ok
        except Exception as e:
            logger.exception(e)
            errors += 1
            if float(errors) / total > 0.01:
                # todo make defensive?
                raise RuntimeError('too many errors! aborting')
            else:
                continue

        # todo support later
        # alt = j.get("altitude", None)
        alt = None
        yield Location(
            dt=dt,
            lat=lat,
            lon=lon,
            alt=alt,
        )

_LOCATION_JSON = 'Takeout/Location History/Location History.json'

# todo if start != 0, disable cache? again this is where nicer caching would come handy
# TODO hope they are sorted... (could assert for it)
# todo configure cache automatically?
@mcachew(cache_dir(), logger=logger)
def _iter_locations(path: Path, start=0, stop=None) -> Iterable[Location]:
    ctx: IO[str]
    if path.suffix == '.json':
        # todo: to support, should perhaps provide it as input= to Popen
        raise RuntimeError("Temporary not supported")
        ctx = path.open('r')
    else: # must be a takeout archive
        # todo CPath? although not sure if it can be iterative?
        ctx = kompress.open(path, _LOCATION_JSON)

    if USE_GREP:
        unzip = f'unzip -p "{path}" "{_LOCATION_JSON}"'
        extract = "grep -E '^    .(timestampMs|latitudeE7|longitudeE7)'"
        with Popen(f'{unzip} | {extract}', shell=True, stdout=PIPE) as p:
            out = p.stdout; assert out is not None
            fit = _iter_via_grep(out)
            fit = islice(fit, start, stop)
            yield from _iter_locations_fo(fit)
    else:
        with ctx as fo:
            # todo need to open as bytes
            fit = _iter_via_ijson(fo)
            fit = islice(fit, start, stop)
            yield from _iter_locations_fo(fit)
    # todo wonder if old takeouts could contribute as well??

def locations(**kwargs) -> Iterable[Location]:
    # NOTE: if this import isn't lazy, tests/tz.py breaks because it can't override config
    # very weird, as if this function captures the values of globals somehow?? investigate later.
    from ..google.takeout.paths import get_last_takeout
    last_takeout = get_last_takeout(path=_LOCATION_JSON)
    if last_takeout is None:
        return []

    return _iter_locations(path=last_takeout, **kwargs)

from ..core.common import stat, Stats
def stats() -> Stats:
    return stat(locations)

# todo add dataframe

# todo deprecate?
def get_locations(*args, **kwargs) -> Sequence[Location]:
    return list(locations(*args, **kwargs))


import xml.etree.ElementTree as ET

def boxes_in_groundtruth(gt_image_path):

    ground_truth_boxes = []
    tree = ET.parse(gt_image_path)
    root = tree.getroot()
    for items in root.findall('object/bndbox'):
        xmin = items.find('xmin')
        ymin = items.find('ymin')
        xmax = items.find('xmax')
        ymax = items.find('ymax')
        ground_truth_boxes.append([int(xmin.text), int(ymin.text), int(xmax.text), int(ymax.text)])
        #print("Ground truth images",ground_truth_boxes)
    return ground_truth_boxes

def area_of_intersection(box_100,groud_truth_box):
    #print(box_100,groud_truth_box)
    x1 = max(box_100[0], groud_truth_box[0])
    x2 = min(box_100[2], groud_truth_box[2])
    y1 = max(box_100[1], groud_truth_box[1])
    y2 = min(box_100[3], groud_truth_box[3])
    #print(x1,x2,y1,y2)
    if (x2 - x1 < 0) or (y2 - y1 < 0):
        return 0
    else:
        #print((x2 - x1 + 1) * (y2 - y1 + 1))
        return (x2 - x1 ) * (y2 - y1)

def find_IOU(boxes_100,ground_truth_boxes):
    iou_qual_boxes=[]
    boxes_best_iou=[]
    for box_g in ground_truth_boxes:
        best_iou=0
        best_box=0
        area_groundtruth_box= (box_g[2]-box_g[0] )* (box_g[3]-box_g[1])
        #print(box_g)
        #print(area_groundtruth_box)
        for box in boxes_100:
            area_box_100=(box[2]-box[0] )* (box[3]-box[1])
            area_of_intersec = area_of_intersection(box, box_g)
            #print(area_of_intersec)
            area_of_union = area_box_100 + area_groundtruth_box - area_of_intersec
            #print(area_of_union)
            iou = float(area_of_intersec) / float(area_of_union)
            #print(iou)
            if iou > 0.5:
                iou_qual_boxes.append(box)
                if iou > best_iou:
                    best_iou = iou
                    best_box = box
        if best_iou != 0:
            boxes_best_iou.append(best_box)
    return iou_qual_boxes, boxes_best_iou

import cv2
import argparse
image= cv2.imread("./HW2_Data/JPEGImages/000009.jpg")
cv2.imshow("000009",image)
parser = argparse.ArgumentParser()
parser.add_argument("strategy", default="color", type=str,
                        help="Enter the strategy - color for color strategy, all for all strategies")
args = parser.parse_args()
selective_search = cv2.ximgproc.segmentation.createSelectiveSearchSegmentation()
selective_search.setBaseImage(image)
RGB_image  = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
selective_search.addImage(RGB_image)
# graph_segmentation = cv2.ximgproc.segmentation.createGraphSegmentation()
# selective_search.addGraphSegmentation(graph_segmentation)
# color_strategy = cv2.ximgproc.segmentation.createSelectiveSearchSegmentationStrategyColor()
# selective_search.addStrategy(color_strategy)

#Creating strategy using color similarity and texture similarity
if args.strategy == "color":
    strategy_color = cv2.ximgproc.segmentation.createSelectiveSearchSegmentationStrategyColor()
    selective_search.addStrategy(strategy_color)
if args.strategy == "texture":
    strategy_texture = cv2.ximgproc.segmentation.createSelectiveSearchSegmentationStrategyTexture()
    selective_search.addStrategy(strategy_texture)

# Creating strategy using all similarities (size,color,fill,texture)
elif args.strategy == "all":
    strategy_color = cv2.ximgproc.segmentation.createSelectiveSearchSegmentationStrategyColor()
    strategy_fill = cv2.ximgproc.segmentation.createSelectiveSearchSegmentationStrategyFill()
    strategy_size = cv2.ximgproc.segmentation.createSelectiveSearchSegmentationStrategySize()
    strategy_texture = cv2.ximgproc.segmentation.createSelectiveSearchSegmentationStrategyTexture()
    strategy_multiple = cv2.ximgproc.segmentation.createSelectiveSearchSegmentationStrategyMultiple(
        strategy_color, strategy_fill, strategy_size, strategy_texture)
    selective_search.addStrategy(strategy_multiple)

selective_search.switchToSelectiveSearchFast()
get_boxes = selective_search.process()
print("Total proposals = ", len(get_boxes))
#print(get_boxes)
first_100_box= 100
boxes_100=[]
box_top_100=[]
for box in get_boxes[0:first_100_box]:
    box_top_100.append([box[0],box[1],box[0]+box[2],box[1]+box[3]])
for box in get_boxes:
    boxes_100.append([box[0],box[1],box[0]+box[2],box[1]+box[3]])
#print(boxes_100)
print (len(boxes_100))
#Get all ground truth images from annotated xml files
output_image_100= image.copy()
ground_truth_boxes= boxes_in_groundtruth("./HW2_Data/Annotations/000009.xml")
print("Number of Ground Truth Boxes = ", len(ground_truth_boxes))
for i in range(0,len(box_top_100)):
    x_top, y_top, x_bottom, y_bottom= box_top_100[i]
    #cv2.rectangle(image, start_point, end_point, color, thickness)
    cv2.rectangle(output_image_100, (x_top, y_top), (x_bottom, y_bottom), (0, 255, 0), 1, cv2.LINE_AA)
cv2.imshow("output_image_100", output_image_100)
cv2.imwrite("./Results/output_image_100_000009.png",output_image_100)
#cv2.waitKey(10000)
# cv2.destroyAllWindows()
IOU_qual_boxes, final_boxes = find_IOU(boxes_100, ground_truth_boxes)
print("Number of Qualified Boxes with IOU > 0.5 = ", len(IOU_qual_boxes))
#print("Qualified Boxes = ", IOU_qual_boxes)

output_img_iou_qualified = image.copy()
image_final = image.copy()

#Draw bounding boxes for iou_qualified_boxes
for i in range(0, len(IOU_qual_boxes)):
    top_x, top_y, bottom_x, bottom_y = IOU_qual_boxes[i]
    cv2.rectangle(output_img_iou_qualified, (top_x, top_y), (bottom_x, bottom_y), (0, 255, 0), 1, cv2.LINE_AA)
for i in range(0, len(ground_truth_boxes)):
    top_x, top_y, bottom_x, bottom_y = ground_truth_boxes[i]
    cv2.rectangle(output_img_iou_qualified, (top_x, top_y), (bottom_x, bottom_y), (0, 0, 255), 1, cv2.LINE_AA)
cv2.imshow("Output_IOU_Qualified_Proposals", output_img_iou_qualified)
cv2.imwrite("./Results/Output_IOU_Qualified_Proposals_000009.png", output_img_iou_qualified)
#cv2.waitKey(1000)

print("Number of final boxes = ", len(final_boxes))
print("Final boxes = ", final_boxes)

# Recall is calculated as the fraction of ground truth boxes that overlap with at least one proposal box with
# Intersection over Union (IoU) > 0.5
recall = len(final_boxes) / len(ground_truth_boxes)
print("Recall is = ", recall)

# Draw bounding boxes for final_boxes
for i in range(0, len(final_boxes)):
    top_x, top_y, bottom_x, bottom_y = final_boxes[i]
    cv2.rectangle(image_final, (top_x, top_y), (bottom_x, bottom_y), (0, 255, 0), 1, cv2.LINE_AA)
for i in range(0, len(ground_truth_boxes)):
    top_x, top_y, bottom_x, bottom_y = ground_truth_boxes[i]
    cv2.rectangle(image_final, (top_x, top_y), (bottom_x, bottom_y), (0, 0, 255), 1, cv2.LINE_AA)
cv2.imshow("Output_Final_Boxes", image_final)
cv2.imwrite("./Results/output_img_final_000009.png", image_final)
#cv2.waitKey(1000)


import chardet

# 파일 경로
file_path = 'data/perfume_data.csv'

# 파일의 실제 인코딩 확인
with open(file_path, 'rb') as file:
    result = chardet.detect(file.read())

# 확인된 인코딩 출력
print(f"파일의 실제 인코딩: {result['encoding']}, 신뢰도: {result['confidence']}")

# 파일을 확인된 인코딩(Windows-1254)으로 읽어오기
with open(file_path, 'r', encoding=result['encoding'], errors='replace') as file:
    content = file.read()

# 새로운 파일이 저장될 경로 (UTF-8로 저장할 파일)
new_file_path = 'data/perfume_data_new.csv'

# 파일 내용을 'UTF-8'로 인코딩하여 저장
with open(new_file_path, 'w', encoding='utf-8') as file:
    file.write(content)


import random
import numpy as np
import GPy
import heapq
from argparse import Namespace
from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor
from scipy.optimize import minimize
from rdkit import Chem, DataStructs
from rdkit.Chem import AllChem

from chemprop.utils import negative_log_likelihood

def confidence_estimator_builder(confidence_method: str):
    return {
        'nn': NNEstimator,
        'gaussian': GaussianProcessEstimator,
        'random_forest': RandomForestEstimator,
        'tanimoto': TanimotoEstimator,
        'ensemble': EnsembleEstimator,
        'latent_space': LatentSpaceEstimator,
        'bootstrap': BootstrapEstimator,
        'snapshot': SnapshotEstimator,
        'dropout': DropoutEstimator,
        'fp_random_forest': FPRandomForestEstimator,
        'fp_gaussian': FPGaussianProcessEstimator,
        'evidence': EvidenceEstimator,
        'sigmoid': SigmoidEstimator
    }[confidence_method]

class ConfidenceEstimator:
    def __init__(self, train_data, new_data, scaler, args):
        self.train_data = train_data
        self.new_data = new_data
        self.conf = np.zeros(shape=(len(self.new_data.smiles()), args.num_tasks))
        self.var = np.zeros(shape=(len(self.new_data.smiles()), args.num_tasks))
        self.computed_std = None
        self.scaler = scaler
        self.args = args

    def process_model(self, model, predict):
        pass

    def compute_confidence(self, new_preds):
        pass

    def _scale_confidence(self, confidence):
        return self.scaler.stds * confidence

    def export_std(self):
        """ Export the computed std function. This is handeled in compute_confidence"""
        return self.computed_std

class DroppingEstimator(ConfidenceEstimator):
    def __init__(self, train_data, new_data, scaler, args):
        super().__init__(train_data, new_data, scaler, args)

        self.sum_last_hidden_train = np.zeros(
            (len(self.train_data.smiles()), self.args.last_hidden_size))
        self.sum_last_hidden_new = np.zeros(
            (len(self.new_data.smiles()), self.args.last_hidden_size))

    def process_model(self, model, predict):
        model.eval()
        model.use_last_hidden = False

        last_hidden_train = predict(
            model=model,
            data=self.train_data,
            batch_size=self.args.batch_size,
            scaler=None,
            quiet=self.args.quiet
        )
        self.sum_last_hidden_train += np.array(last_hidden_train)

        last_hidden_new = predict(
            model=model,
            data=self.new_data,
            batch_size=self.args.batch_size,
            scaler=None,
            quiet=self.args.quiet
        )
        self.sum_last_hidden_new += np.array(last_hidden_new)

    def _compute_hidden_vals(self):
        avg_last_hidden_train = self.sum_last_hidden_train / self.args.ensemble_size
        avg_last_hidden_new = self.sum_last_hidden_new / self.args.ensemble_size
        return avg_last_hidden_train, avg_last_hidden_new

class NNEstimator(ConfidenceEstimator):
    def __init__(self, train_data, new_data, scaler, args):
        super().__init__(train_data, new_data, scaler, args)

    def process_model(self, model, predict):
        preds, confidence = predict(
            model=model,
            data=self.new_data,
            batch_size=self.args.batch_size,
            scaler=self.scaler,
            quiet=self.args.quiet,
            confidence=True,
        )
        if len(preds) != 0:
            self.conf += np.array(confidence).clip(min=0)

    def compute_confidence(self, new_preds):
        return (new_preds, np.sqrt(self.conf / self.args.ensemble_size))

class SigmoidEstimator(ConfidenceEstimator):
    def __init__(self, train_data, new_data, scaler, args):
        super().__init__(train_data, new_data, scaler, args)

    def process_model(self, model, predict):
        def categorical_variance(p): #assumes binary classification
            return p*(1-p)**2  + (1-p)*p**2

        preds = predict(
            model=model,
            data=self.new_data,
            batch_size=self.args.batch_size,
            scaler=self.scaler,
            quiet=self.args.quiet,
            confidence=True,
        )

        # Calculate the variance (option to compute entropy in run_training)
        var = categorical_variance(np.array(preds))
        if len(preds) != 0:
            self.conf += var.clip(min=0)

    def compute_confidence(self, new_preds):
        return (new_preds, np.sqrt(self.conf / self.args.ensemble_size))

class EvidenceEstimator(ConfidenceEstimator):
    def __init__(self, train_data, new_data, scaler, args):
        super().__init__(train_data, new_data, scaler, args)

    def process_model(self, model, predict):
        preds, confidence, var  = predict(
            model=model,
            data=self.new_data,
            batch_size=self.args.batch_size,
            scaler=self.scaler,
            quiet=self.args.quiet,
            confidence=True,
            export_var = True,
        )

        if len(preds) != 0:
            self.conf += np.array(confidence).clip(min=0)
            self.var += np.array(var).clip(min=0)

    def compute_confidence(self, new_preds):
        # Compute std for use in calibration curves
        self.computed_std = np.sqrt(self.var / self.args.ensemble_size)
        return (new_preds, np.sqrt(self.conf / self.args.ensemble_size))

class GaussianProcessEstimator(DroppingEstimator):
    def compute_confidence(self, new_preds):
        avg_last_hidden_train, avg_last_hidden_new = self._compute_hidden_vals()
        new_preds = np.zeros_like(self.conf)

        transformed = self.scaler.transform(np.array(self.train_data.targets()))

        for task in range(self.args.num_tasks):
            kernel = GPy.kern.Linear(input_dim=self.args.last_hidden_size)
            gaussian = GPy.models.SparseGPRegression(
                avg_last_hidden_train,
                transformed[:, task:task + 1], kernel)
            gaussian.optimize()

            avg_preds, avg_var = gaussian.predict(avg_last_hidden_new)

            new_preds[:, task:task+1] = avg_preds
            self.conf[:, task:task+1] = np.sqrt(avg_var)

        return (self.scaler.inverse_transform(new_preds),
                self._scale_confidence(self.conf))

class FPGaussianProcessEstimator(ConfidenceEstimator):
    def compute_confidence(self, new_preds):
        train_smiles = self.train_data.smiles()
        new_smiles = self.new_data.smiles()
        train_fps = np.array([morgan_fingerprint(s) for s in train_smiles])
        new_fps = np.array([morgan_fingerprint(s) for s in new_smiles])

        new_preds = np.zeros_like(self.conf)

        # Train targets are already scaled.
        scaled_train_targets = np.array(self.train_data.targets())

        for task in range(self.args.num_tasks):
            kernel = GPy.kern.Linear(input_dim=train_fps.shape[1])
            gaussian = GPy.models.SparseGPRegression(
                train_fps,
                scaled_train_targets[:, task:task + 1], kernel)
            gaussian.optimize()

            avg_preds, avg_var = gaussian.predict(new_fps)

            new_preds[:, task:task+1] = avg_preds
            self.conf[:, task:task+1] = np.sqrt(avg_var)

        return (self.scaler.inverse_transform(new_preds),
            self._scale_confidence(self.conf))

class RandomForestEstimator(DroppingEstimator):
    def compute_confidence(self, new_preds):
        avg_last_hidden_train, avg_last_hidden_new = self._compute_hidden_vals()
        transformed = self.scaler.transform(np.array(self.train_data.targets()))

        new_preds = np.zeros_like(self.train_conf)

        n_trees = 128
        for task in range(self.args.num_tasks):
            forest = RandomForestRegressor(n_estimators=n_trees)
            forest.fit(avg_last_hidden_train, transformed[:, task])

            new_preds[:, task] = forest.predict(avg_last_hidden_new)
            individual_predictions = np.array([
                estimator.predict(avg_last_hidden_new) for estimator in forest.estimators_])
            self.conf[:, task] = np.std(individual_predictions, axis=0)

        return (self.scaler.inverse_transform(new_preds),
                self._scale_confidence(self.conf))

class FPRandomForestEstimator(ConfidenceEstimator):
    def compute_confidence(self, new_preds):
        train_smiles = self.train_data.smiles()
        new_smiles = self.train_data.smiles()
        train_fps = np.array([morgan_fingerprint(s) for s in train_smiles])
        new_fps = np.array([morgan_fingerprint(s) for s in new_smiles])

        new_preds = np.zeros_like(self.conf)

        # Train targets are already scaled.
        scaled_train_targets = np.array(self.train_data.targets())

        n_trees = 128
        for task in range(self.args.num_tasks):
            forest = RandomForestRegressor(n_estimators=n_trees)
            forest.fit(train_fps, scaled_train_targets[:, task])

            new_preds[:, task] = forest.predict(new_fps)
            individual_predictions = np.array([
                estimator.predict(new_fps) for estimator in forest.estimators_])
            self.conf[:, task] = np.std(individual_predictions, axis=0)

        return (self.scaler.inverse_transform(new_preds),
                self._scale_confidence(self.conf))

class LatentSpaceEstimator(DroppingEstimator):
    def compute_confidence(self, new_preds):
        avg_last_hidden_train, avg_last_hidden_new = self._compute_hidden_vals()

        for input_ in range(len(avg_last_hidden_new)):
            distances = np.zeros(len(avg_last_hidden_train))
            for train_input in range(len(avg_last_hidden_train)):
                difference = avg_last_hidden_new[input_] - avg_last_hidden_train[train_input]
                distances[train_input] = np.sqrt(np.sum(difference * difference))

            self.conf[input_, :] = sum(heapq.nsmallest(5, distances))/5

        return (new_preds, self.conf)

class EnsembleEstimator(ConfidenceEstimator):
    def __init__(self, train_data, new_data, scaler, args):
        super().__init__(train_data, new_data, scaler, args)
        self.all_preds = []

    def process_model(self, model, predict):
        preds = predict(
            model=model,
            data=self.new_data,
            batch_size=self.args.batch_size,
            scaler=self.scaler,
            quiet=self.args.quiet,
        )
        self.all_preds.append(preds)

    def compute_confidence(self, new_preds):
        return (new_preds, np.std(self.all_preds, axis=0))

class BootstrapEstimator(EnsembleEstimator):
    def __init__(self, train_data, new_data, scaler, args):
        super().__init__(train_data, new_data, scaler, args)

class SnapshotEstimator(EnsembleEstimator):
    def __init__(self, train_data, new_data, scaler, args):
        super().__init__(train_data, new_data, scaler, args)

class DropoutEstimator(EnsembleEstimator):
    def __init__(self, train_data, new_data, scaler, args):
        super().__init__(train_data, new_data, scaler, args)

class TanimotoEstimator(ConfidenceEstimator):
    def compute_confidence(self, new_preds):
        train_smiles = self.train_data.smiles()
        new_smiles = self.new_data.smiles()

        train_smiles_sfp = [morgan_fingerprint(s) for s in train_smiles]
        new_smiles_sfp = [morgan_fingerprint(s) for s in new_smiles]

        for i in range(len(new_smiles)):
            self.conf[i, :] = np.ones((self.args.num_tasks)) * tanimoto(
                new_smiles[i], train_smiles_sfp, lambda x: sum(heapq.nsmallest(8, x))/8)

        return (new_preds, self.conf)

# Classification methods.
class ConformalEstimator(DroppingEstimator):
    pass

class BoostEstimator(DroppingEstimator):
    pass

def morgan_fingerprint(smiles: str, radius: int = 3, num_bits: int = 2048,
                       use_counts: bool = False) -> np.ndarray:
    """
    Generates a morgan fingerprint for a smiles string.

    :param smiles: A smiles string for a molecule.
    :param radius: The radius of the fingerprint.
    :param num_bits: The number of bits to use in the fingerprint.
    :param use_counts: Whether to use counts or just a bit vector for the fingerprint
    :return: A 1-D numpy array containing the morgan fingerprint.
    """
    if type(smiles) == str:
        mol = Chem.MolFromSmiles(smiles)
    else:
        mol = smiles
    if use_counts:
        fp_vect = AllChem.GetHashedMorganFingerprint(
            mol, radius, nBits=num_bits, useChirality=True)
    else:
        fp_vect = AllChem.GetMorganFingerprintAsBitVect(
            mol, radius, nBits=num_bits, useChirality=True)
    fp = np.zeros((1,))
    DataStructs.ConvertToNumpyArray(fp_vect, fp)

    return fp

def tanimoto(smile, train_smiles_sfp, operation):
    smiles = Chem.MolToSmiles(Chem.MolFromSmiles(smile))
    fp = morgan_fingerprint(smiles)
    tanimoto_distance = []

    for sfp in train_smiles_sfp:
        tsim = np.dot(fp, sfp) / (fp.sum() +
                                  sfp.sum() - np.dot(fp, sfp))
        tanimoto_distance.append(-np.log2(max(0.0001, tsim)))

    return operation(tanimoto_distance)


from tqdm import tqdm
from src.services.parser import Parser
from src.services.picker import Picker
from src.models.storage import Storage

class Controller:
    def __init__(self, capacity):
        self.storage = Storage(capacity)

    def run(self, input):
        parser = Parser(input)
        try:
            designs, flowers = parser.parse()
        except Exception as err:
            print("Error: {}".format(err))
            return

        picker = Picker(designs, self.storage)

        bouquets = []
        with tqdm(total=len(flowers)) as pbar:
            for i, flower in enumerate(flowers):
                pbar.update(1)
                try:
                    picker.handle(flower)
                    bouquet = picker.pick_up()
                    if bouquet:
                        bouquets.append(repr(bouquet))
                except Exception as err:
                    print("Error: {} parsing flowers' input at {} position".format(err, i))
                    return

        return '\n'.join(bouquets)


import argparse
import os
import logging
import subprocess
import shutil
import re

log_level = os.environ.get('LOGGING', default="INFO")
logging.basicConfig(format='%(asctime)s - %(levelname)s - %(message)s', level=log_level)

main_desc = "Script to rebrand nano-node as new block chain." \
            "Example: " \
            "rebrand.py"

# Initiate the parser
parser = argparse.ArgumentParser(description=main_desc)

# debug
parser.add_argument("--debug", help="Enable debug", action="store_true")

# version arg
parser.add_argument("-V", "--version", help="Shows version", action="store_true")

# Read arguments from the command line
args = parser.parse_args()

# Check for --version or -V
if args.version:
    print("V22.0_0.0.1")

def remove_prefix(text, prefix):
    return text[len(prefix):] if text.startswith(prefix) else text

def cwd(directory="./"):
    logging.debug(directory)
    if os.environ.get("CI") == "true" and os.environ.get("DRONE") == "true":
        directory = "/drone/src/"
    return directory

def get_env_variable(env):
    if not os.environ.get(env, None):
        return logging.error("%s is not defined!" % env)
    else:
        logging.debug("%s properly set." % env)
        return os.environ.get(env)

def key_create(a):
    lines = []
    proc = subprocess.Popen(['%snano-node-22.0.0-Linux/bin/nano_node' % cwd(), '--key_create'], stdout=subprocess.PIPE)
    while True:
        line = proc.stdout.readline()
        if not line:
            break
        lines.append(str(line.rstrip()))

    private = lines[0].split(": ")[1].rstrip("'")
    public = lines[1].split(": ")[1].rstrip("'")
    account = lines[2].split(": ")[1].rstrip("'").replace("nano_", a)

    return print('''{
    "private": "%s",
    "public": "%s",
    "account": "%s"
}
    ''' % (private, public, account))

def is_ignored(f, w_list):
    #if args.debug:
    #    print("f: %s" % f)
    #    print("Ignored words: %s" % w_list)

    if w_list is not None:
        if re.compile('|'.join(w_list)).search(f):
            return True
        else:
            return False
    else:
        return False

def find_and_replace(filename, find, replace):
    with open(filename, "rb") as orig_file_obj:
        with open("%s.tmp" % filename, "wb") as new_file_obj:
            orig_text = orig_file_obj.read()
            new_text = orig_text.replace(find, replace)
            new_file_obj.write(new_text)

    shutil.copyfile("%s.tmp" % filename, filename)
    os.remove("%s.tmp" % filename)

def replace_all(data, ignore_list, subdir):
    for dirname, dirs, files in os.walk(cwd()+subdir):
        for file_name in files:
            filepath = os.path.join(dirname, file_name)

            for x in data:
                if is_ignored(filepath, ignore_list):
                    logging.debug("IGNORED %s" % filepath)
                else:
                    find_and_replace(filepath, x[0], x[1])

# rename directories
def rename_dirs(dirs):
    for d in dirs:
        if os.path.exists(d[0]):
            os.rename(d[0], d[1])


import os

import pytest

from bpp_plugins.import_dbf.util import (
    addslashes,
    dbf2sql,
    exp_add_spacing,
    exp_parse_str,
    xls2dict,
    exp_split_poz_str,
)

def test_util_addslashes():
    assert addslashes(None) is None
    assert addslashes(1) == 1
    assert addslashes("foo'") == "foo''"

def test_util_import_dbf():
    dbf2sql(os.path.join(os.path.dirname(__file__), "test.dbf"))
    open(os.path.join(os.path.dirname(__file__), "test.dbf") + ".sql")

@pytest.mark.parametrize(
    "input, output",
    [
        (
            "#204$ #a$ Zachowania zdrowotne dzieci w wieku szkolnym - badania wstępne #b$ #c$ #d$ #e$ s.184-191 "
            "#f$ ryc., tab., bibliogr., streszcz.",
            {
                "id": 204,
                "a": "Zachowania zdrowotne dzieci w wieku szkolnym - badania wstępne",
                "b": "",
                "c": "",
                "d": "",
                "e": "s.184-191",
                "f": "ryc., tab., bibliogr., streszcz.",
            },
        ),
        (
            "#102$ #a$ Autologous hematopoietic stem cell transplant for progressive"
            " diffuse systemic sclerosis: procedural "
            "success and clinical outcome in 5-year follow-up #b$ #c$ #d$",
            {
                "id": 102,
                "a": "Autologous hematopoietic stem cell transplant for progressive diffuse systemic sclerosis: "
                "procedural success and clinical outcome in 5-year follow-up",
                "b": "",
                "c": "",
                "d": "",
            },
        ),
        (
            "#150$ #a$ Badania nad wpływem selenu na integralność chromatyny plemnikowej w przypadkach mężczyzn z "
            "upośledzoną płodnością #b$ #c$ #d$",
            {
                "id": 150,
                "a": "Badania nad wpływem selenu na integralność chromatyny plemnikowej w przypadkach mężczyzn "
                "z upośledzoną płodnością",
                "b": "",
                "c": "",
                "d": "",
            },
        ),
        (
            "#150$ #a$Neurologia #c$Howard L. Weiner, Lawrence P. Levitt	",
            {"id": 150, "a": "Neurologia", "c": "Howard L. Weiner, Lawrence P. Levitt"},
        ),
        (
            "#103$#a$ Abstracts of the 5-th World Congress on Heart Failure - Mechanisms and Managment. "
            "Washinfton, USA, 11-14 May, 1997",
            {
                "id": 103,
                "a": "Abstracts of the 5-th World Congress on Heart Failure - Mechanisms and Managment. "
                "Washinfton, USA, 11-14 May, 1997",
            },
        ),
    ],
)
def test_util_exp_parse_str(input, output):
    assert exp_parse_str(input) == output

@pytest.mark.parametrize(
    "input,output",
    [
        (
            "#153$ #a$ 162 s. #b$ bibliogr. #c$\r\n#154$ #a$|0000004804#b$ #c$\r\n"
            "nr 154 #d$ #e$\r\n#155$ #a$ ISBN 978-83-66066-86-1#988$ #a$|0000\r\n"
            "006505#b$|0000006506#991$ #a$ 10.34616/23.19.146\r\n#995$ #a$ http\r\n"
            "s://www.bibliotekacyfrowa.pl/publication/108240\r\n               ",
            [
                "#153$ #a$ 162 s. #b$ bibliogr. #c$",
                "#154$ #a$|0000004804#b$ #c$nr 154 #d$ #e$",
                "#155$ #a$ ISBN 978-83-66066-86-1",
                "#988$ #a$|0000006505#b$|0000006506",
                "#991$ #a$ 10.34616/23.19.146",
                "#995$ #a$ https://www.bibliotekacyfrowa.pl/publication/108240               ",
            ],
        )
    ],
)
def test_util_exp_split_poz_str(input, output):
    assert output == list(exp_split_poz_str(input))

def test_util_exp_parse_str_raises():
    bad = (
        "#105$ Electrophysiological estimation of the peripheral nerves conduction "
        "parameters and the autonomic nervous system function in the course"
        " of amyotrophic lateral sclerosis #b$"
    )
    with pytest.raises(ValueError):
        exp_parse_str(bad)

def test_util_exp_add_spacing():
    assert exp_add_spacing(" te  st (fa. ) ") == " te st (fa.) "

def test_xls2dict():
    ret = list(xls2dict(os.path.join(os.path.dirname(__file__), "test_chf.xlsx")))
    assert ret[0]["skrot"] == "PAA"


import os
import numpy as np
import random
from tqdm import tqdm
from torch.utils.data import Dataset, DataLoader
from medvqa.datasets.chest_imagenome import (
    CHEST_IMAGENOME_NUM_BBOX_CLASSES,
    get_chest_imagenome_gold_bbox_coords_and_presence_sorted_indices,
)
from medvqa.datasets.chest_imagenome.chest_imagenome_dataset_management import (
    load_chest_imagenome_gold_bboxes,
    load_chest_imagenome_silver_bboxes,
    load_gold_bbox_dicom_ids,
    load_nondecent_chest_imagenome_dicom_ids,
)
from medvqa.datasets.ms_cxr import get_ms_cxr_dicom_id_2_phrases_and_masks, get_ms_cxr_dicom_ids
from medvqa.datasets.segmentation_utils import compute_mask_from_bounding_box
from medvqa.datasets.mimiccxr import (
    MIMICCXR_LARGE_FAST_CACHE_DIR,
    MIMICCXR_ImageSizeModes,
    MIMICCXR_ViewModes,
    get_dicom_id_and_orientation_list,
    get_image_path_getter,
    load_mimiccxr_reports_detailed_metadata,
)
from medvqa.utils.files import get_cached_pickle_file, load_pickle, save_pickle
from medvqa.utils.logging import print_bold

class MIMICCXR_FactGroundingDataset(Dataset):

    def __init__(self, image_paths, image_transform, fact_embeddings, positive_facts, negative_facts, indices, num_facts):
        self.image_paths = image_paths
        self.image_transform = image_transform
        self.fact_embeddings = fact_embeddings
        self.positive_facts = positive_facts
        self.negative_facts = negative_facts
        self.indices = indices
        self.num_facts = num_facts

    def __len__(self):
        return len(self.indices)

    def __getitem__(self, i):
        idx = self.indices[i]
        image_path = self.image_paths[idx]
        image = self.image_transform(image_path)
        positive_facts = self.positive_facts[idx]
        if len(positive_facts) > self.num_facts: # sample a subset of positive facts
            positive_facts = random.sample(positive_facts, self.num_facts)
        negative_facts = self.negative_facts[idx]
        if len(negative_facts) > self.num_facts: # sample a subset of negative facts
            negative_facts = random.sample(negative_facts, self.num_facts)
        pos_embeddings = self.fact_embeddings[positive_facts]
        neg_embeddings = self.fact_embeddings[negative_facts]
        return {
            'i': image,
            'pe': pos_embeddings,
            'ne': neg_embeddings,
        }

class MIMICCXR_PhraseGroundingDataset(Dataset):

    def __init__(self, image_paths, image_transform, phrase_embeddings, phrase_grounding_masks, indices):
        self.image_paths = image_paths
        self.image_transform = image_transform
        self.phrase_embeddings = phrase_embeddings
        self.phrase_grounding_masks = phrase_grounding_masks
        self.indices = indices

    def __len__(self):
        return len(self.indices)

    def __getitem__(self, i):
        idx = self.indices[i]
        image_path = self.image_paths[idx]
        image = self.image_transform(image_path)
        phrase_embeddings = self.phrase_embeddings
        phrase_grounding_masks = self.phrase_grounding_masks[idx]
        return {
            'i': image,
            'pe': phrase_embeddings,
            'pgm': phrase_grounding_masks,
        }

class MIMICCXR_BBoxGroundingDataset(Dataset):

    def __init__(self, image_paths, image_transform, phrase_embeddings, phrase_grounding_masks, phrase_classification_labels,
                 bbox_coords, bbox_presence, use_yolov8=False):
        assert use_yolov8 # TODO: add support for non-YOLOv8
        self.image_paths = image_paths
        self.image_transform = image_transform
        self.phrase_embeddings = phrase_embeddings
        self.phrase_grounding_masks = phrase_grounding_masks
        self.phrase_classification_labels = phrase_classification_labels
        self.bbox_coords = bbox_coords
        self.bbox_presence = bbox_presence
        self.use_yolov8 = use_yolov8

    def __len__(self):
        return len(self.image_paths)

    def __getitem__(self, i):
        image_path = self.image_paths[i]
        tmp = self.image_transform(image_path, return_image_size=True)
        image, image_size_before, image_size_after = tmp
        phrase_embeddings = self.phrase_embeddings
        phrase_grounding_masks = self.phrase_grounding_masks[i]
        phrase_classification_labels = self.phrase_classification_labels[i]
        bbox_coords = self.bbox_coords[i]
        bbox_presence = self.bbox_presence[i]
        return {
            'i': image,
            'pe': phrase_embeddings,
            'pgm': phrase_grounding_masks,
            'pcl': phrase_classification_labels,
            'bc': bbox_coords,
            'bp': bbox_presence,
            # for YOLOv8
            'im_file': image_path,
            'ori_shape': image_size_before,
            'resized_shape': image_size_after,
        }

def _compute_mask_from_bounding_boxes(mask_height, mask_width, bbox_coords, bbox_presence):
    assert len(bbox_coords.shape) == 2
    assert bbox_coords.shape[1] == 4
    assert len(bbox_presence.shape) == 1
    assert bbox_presence.shape[0] == bbox_coords.shape[0]
    mask = np.zeros((len(bbox_coords), mask_height * mask_width), dtype=np.float32)
    for i in range(len(bbox_coords)):
        if bbox_presence[i] == 1:
            x1, y1, x2, y2 = bbox_coords[i]
            mask[i] = compute_mask_from_bounding_box(mask_height, mask_width, x1, y1, x2, y2, flatten=True)
    return mask

def _clean_bbox_coords_and_presence(bbox_coords, bbox_presence):
    bbox_coords = bbox_coords.reshape(-1, 4)
    assert len(bbox_coords) == len(bbox_presence)
    bbox_coords.clip(0, 1, out=bbox_coords)
    for i in range(len(bbox_coords)):
        w = bbox_coords[i, 2] - bbox_coords[i, 0]
        h = bbox_coords[i, 3] - bbox_coords[i, 1]
        if w <= 0 or h <= 0:
            bbox_presence[i] = 0
        else:
            assert bbox_presence[i] == 1
    return bbox_coords, bbox_presence

_shared_mask_height = None
_shared_mask_width = None
_shared_did2bboxes = None
def _clean_bbox_coords_and_presence_and_compute_mask(dicom_id):
    bboxes = _shared_did2bboxes[dicom_id]
    bbox_coords = bboxes['coords']
    bbox_presence = bboxes['presence']
    bbox_coords, bbox_presence = _clean_bbox_coords_and_presence(bbox_coords, bbox_presence)
    mask = _compute_mask_from_bounding_boxes(_shared_mask_height, _shared_mask_width, bbox_coords, bbox_presence)
    return bbox_coords, bbox_presence, mask

def _precompute_bbox_coords_and_presence_and_mask(mask_height, mask_width, did2bboxes, num_workers=None):
    save_path = os.path.join(MIMICCXR_LARGE_FAST_CACHE_DIR, f'bbox_coords_and_presence_and_mask({mask_height},{mask_width},{len(did2bboxes)}).pkl')
    if os.path.exists(save_path):
        print_bold(f'Loading precomputed bbox_coords_and_presence_and_mask from {save_path}...')
        return get_cached_pickle_file(save_path)

    print_bold(f'Precomputing bbox_coords_and_presence_and_mask({mask_height},{mask_width},{len(did2bboxes)})...')
    global _shared_mask_height, _shared_mask_width, _shared_did2bboxes
    _shared_mask_height = mask_height
    _shared_mask_width = mask_width
    _shared_did2bboxes = did2bboxes
    dicom_ids = list(did2bboxes.keys())
    dicom_ids.sort() # sort for reproducibility
    import multiprocessing as mp
    if num_workers is None:
        num_workers = mp.cpu_count()
    with mp.Pool(num_workers) as pool:
        results = pool.map(_clean_bbox_coords_and_presence_and_compute_mask, dicom_ids)
    bbox_coords = np.array([r[0] for r in results])
    bbox_presence = np.array([r[1] for r in results])
    phrase_grounding_masks = np.array([r[2] for r in results])
    print(f'bbox_coords.shape = {bbox_coords.shape}')
    print(f'bbox_presence.shape = {bbox_presence.shape}')
    print(f'phrase_grounding_masks.shape = {phrase_grounding_masks.shape}')
    output = {
        'dicom_ids': dicom_ids, # sorted
        'bbox_coords': bbox_coords,
        'bbox_presence': bbox_presence,
        'phrase_grounding_masks': phrase_grounding_masks,
    }
    save_pickle(output, save_path)
    return output

def visualize_mask(mask, mask_height, mask_width): # for debugging
    import matplotlib.pyplot as plt
    plt.figure(figsize=(10, 10))
    # use gray scale, where white = 1 and black = 0
    plt.imshow(mask.reshape(mask_height, mask_width), cmap='gray', vmin=0, vmax=1)
    plt.show()

class MIMICCXR_PhraseGroundingTrainer:

    def __init__(self,
                max_images_per_batch, max_phrases_per_batch, max_phrases_per_image,
                num_train_workers, num_test_workers,
                train_image_transform, test_image_transform,
                fact_grounding_collate_batch_fn=None,
                phrase_grounding_collate_batch_fn=None,
                bbox_grounding_collate_batch_fn=None,
                test_batch_size_factor=1,
                mask_width=None, mask_height=None,
                use_facts_for_train=False,
                dicom_id_to_pos_neg_facts_filepath=None,
                use_mscxr_for_test=False,
                mscxr_phrase2embedding_filepath=None,
                use_chest_imagenome_for_train=False,
                use_chest_imagenome_gold_for_test=False,
                chest_imagenome_bbox_phrase_embeddings_filepath=None,
                source_image_size_mode=MIMICCXR_ImageSizeModes.SMALL_256x256,
                exclude_noisy_images=False,
                use_yolov8=False,
                **unused_kwargs,
            ):

        if len(unused_kwargs) > 0:
            # Print warning in orange and bold
            print('\033[93m\033[1mWarning: unused kwargs in MIMICCXR_VisualModuleTrainer: {}\033[0m'.format(unused_kwargs))
        # Sanity checks
        assert sum([use_facts_for_train, use_chest_imagenome_for_train]) > 0
        assert sum([use_mscxr_for_test, use_chest_imagenome_gold_for_test]) > 0

        self.use_facts_for_train = use_facts_for_train
        self.use_chest_imagenome_for_train = use_chest_imagenome_for_train
        self.use_mscxr_for_test = use_mscxr_for_test
        self.use_chest_imagenome_gold_for_test = use_chest_imagenome_gold_for_test

        self.use_yolov8 = use_yolov8

        forbidden_train_dicom_ids = set()

        if exclude_noisy_images:
            noisy_dicom_ids = set(load_nondecent_chest_imagenome_dicom_ids())
            forbidden_train_dicom_ids |= noisy_dicom_ids

        if use_mscxr_for_test:
            ms_cxr_dicom_ids = set(get_ms_cxr_dicom_ids())
            forbidden_train_dicom_ids |= ms_cxr_dicom_ids

        if use_chest_imagenome_gold_for_test:
            gold_dicom_ids = set(load_gold_bbox_dicom_ids())
            forbidden_train_dicom_ids |= gold_dicom_ids

        print(f'len(forbidden_train_dicom_ids) = {len(forbidden_train_dicom_ids)}')

        # Create train mimiccxr facts dataset
        if use_facts_for_train:
            print_bold('Preparing MIMIC-CXR-Facts datasets and dataloaders for training...')
            assert dicom_id_to_pos_neg_facts_filepath is not None
            assert fact_grounding_collate_batch_fn is not None

            tmp = load_pickle(dicom_id_to_pos_neg_facts_filepath)
            fact_embeddings = tmp['fact_embeddings']
            dicom_id_to_pos_neg_facts = tmp['dicom_id_to_pos_neg_facts']
            print(f'fact_embeddings.shape = {fact_embeddings.shape}')

            BIG_ENOGUGH = 1000000
            image_paths = [None] * BIG_ENOGUGH
            positive_facts = [None] * BIG_ENOGUGH
            negative_facts = [None] * BIG_ENOGUGH
            image_path_getter = get_image_path_getter(source_image_size_mode, verbose=True)

            mimiccxr_metadata = load_mimiccxr_reports_detailed_metadata()

            idx = 0
            for rid, (part_id, subject_id, study_id, dicom_id_view_pairs) in \
                tqdm(enumerate(zip(mimiccxr_metadata['part_ids'],
                    mimiccxr_metadata['subject_ids'],
                    mimiccxr_metadata['study_ids'],
                    mimiccxr_metadata['dicom_id_view_pos_pairs'])), mininterval=2):
                for dicom_id, view in get_dicom_id_and_orientation_list(dicom_id_view_pairs, MIMICCXR_ViewModes.ALL):
                    if dicom_id in forbidden_train_dicom_ids:
                        continue
                    if dicom_id not in dicom_id_to_pos_neg_facts:
                        continue
                    image_paths[idx] = image_path_getter(part_id, subject_id, study_id, dicom_id)
                    pos_neg_facts = dicom_id_to_pos_neg_facts[dicom_id]
                    assert len(pos_neg_facts) == 2
                    positive_facts[idx] = pos_neg_facts[0]
                    negative_facts[idx] = pos_neg_facts[1]
                    idx += 1

            print(f'Total number of images: {idx}')
            image_paths = image_paths[:idx]
            positive_facts = positive_facts[:idx]
            negative_facts = negative_facts[:idx]

            # Create a mapping from number of facts to indices
            num_facts_2_idxs = {}
            for i, (pos_facts, neg_facts) in enumerate(zip(self.train_positive_facts, self.train_negative_facts)):
                assert len(pos_facts) > 0
                assert len(neg_facts) > 0
                num_facts = min(len(pos_facts), len(neg_facts), max_phrases_per_image)
                try:
                    num_facts_2_idxs[num_facts].append(i)
                except KeyError:
                    num_facts_2_idxs[num_facts] = [i]

            # Create dataset and dataloader for training
            self.train_fact_datasets = []
            self.train_fact_dataloaders = []
            for num_facts, indices in num_facts_2_idxs.items():
                print(f'Number of facts: {num_facts}, # images: {len(indices)}')
                dataset = MIMICCXR_FactGroundingDataset(
                    image_paths=image_paths, image_transform=train_image_transform,
                    fact_embeddings=fact_embeddings, positive_facts=positive_facts, negative_facts=negative_facts,
                    indices=indices, num_facts=num_facts)
                batch_size = max(min(max_images_per_batch, max_phrases_per_batch // num_facts), 1) # at least 1 image per batch
                dataloader = DataLoader(
                    dataset,
                    batch_size=batch_size,
                    shuffle=True,
                    num_workers=num_train_workers,
                    collate_fn=fact_grounding_collate_batch_fn,
                    pin_memory=True,
                )
                self.train_fact_datasets.append(dataset)
                self.train_fact_dataloaders.append(dataloader)

        # Create train chest imagenome dataset
        if use_chest_imagenome_for_train:
            print_bold('Preparing Chest Imagenome dataset and dataloader for training...')

            assert chest_imagenome_bbox_phrase_embeddings_filepath is not None
            assert mask_width is not None
            assert mask_height is not None
            assert bbox_grounding_collate_batch_fn is not None

            tmp = get_cached_pickle_file(chest_imagenome_bbox_phrase_embeddings_filepath)
            bbox_phrase_embeddings = tmp['bbox_phrase_embeddings']
            bbox_phrases = tmp['bbox_phrases']
            assert bbox_phrase_embeddings.shape[0] == len(bbox_phrases)
            print(f'bbox_phrase_embeddings.shape = {bbox_phrase_embeddings.shape}')
            print(f'len(bbox_phrases) = {len(bbox_phrases)}')
            for phrase in bbox_phrases:
                print('\t', phrase)

            BIG_ENOGUGH = 1000000
            image_paths = [None] * BIG_ENOGUGH
            chest_imagenome_bbox_coords = [None] * BIG_ENOGUGH
            chest_imagenome_bbox_presence = [None] * BIG_ENOGUGH
            phrase_grounding_masks = [None] * BIG_ENOGUGH
            image_path_getter = get_image_path_getter(source_image_size_mode, verbose=True)

            mimiccxr_metadata = load_mimiccxr_reports_detailed_metadata()
            did2bboxes = load_chest_imagenome_silver_bboxes()
            tmp = _precompute_bbox_coords_and_presence_and_mask(mask_height, mask_width, did2bboxes)
            dicom_ids = tmp['dicom_ids']
            did2idx = {dicom_id: idx for idx, dicom_id in enumerate(dicom_ids)}
            bbox_coords_array = tmp['bbox_coords']
            bbox_presence_array = tmp['bbox_presence']
            phrase_grounding_masks_array = tmp['phrase_grounding_masks']

            idx = 0
            for rid, (part_id, subject_id, study_id, dicom_id_view_pairs) in \
                tqdm(enumerate(zip(mimiccxr_metadata['part_ids'],
                    mimiccxr_metadata['subject_ids'],
                    mimiccxr_metadata['study_ids'],
                    mimiccxr_metadata['dicom_id_view_pos_pairs'])), mininterval=2):
                for dicom_id, view in get_dicom_id_and_orientation_list(dicom_id_view_pairs, MIMICCXR_ViewModes.ALL):
                    if dicom_id not in did2idx:
                        continue
                    if dicom_id in forbidden_train_dicom_ids:
                        continue
                    image_paths[idx] = image_path_getter(part_id, subject_id, study_id, dicom_id)
                    i = did2idx[dicom_id]
                    chest_imagenome_bbox_coords[idx] = bbox_coords_array[i]
                    chest_imagenome_bbox_presence[idx] = bbox_presence_array[i]
                    phrase_grounding_masks[idx] = phrase_grounding_masks_array[i]
                    idx += 1

            print(f'Total number of images: {idx}')
            image_paths = image_paths[:idx]
            chest_imagenome_bbox_coords = chest_imagenome_bbox_coords[:idx]
            chest_imagenome_bbox_presence = chest_imagenome_bbox_presence[:idx]
            phrase_grounding_masks = phrase_grounding_masks[:idx]

            # Create dataset and dataloader for training
            self.train_chest_imagenome_dataset = MIMICCXR_BBoxGroundingDataset(
                image_paths=image_paths, image_transform=train_image_transform,
                phrase_embeddings=bbox_phrase_embeddings, phrase_grounding_masks=phrase_grounding_masks,
                phrase_classification_labels=chest_imagenome_bbox_presence, # use bbox_presence as classification labels
                bbox_coords=chest_imagenome_bbox_coords, bbox_presence=chest_imagenome_bbox_presence,
                use_yolov8=use_yolov8)
            batch_size = max(min(max_images_per_batch, max_phrases_per_batch // len(bbox_phrases)), 1) # at least 1 image per batch
            self.train_chest_imagenome_dataloader = DataLoader(
                self.train_chest_imagenome_dataset,
                batch_size=batch_size,
                shuffle=True,
                num_workers=num_train_workers,
                collate_fn=lambda batch: bbox_grounding_collate_batch_fn(batch, training_mode=True),
                pin_memory=True,
            )

        # Create mscxr test dataset and dataloader
        if use_mscxr_for_test:
            print_bold('Preparing MS-CXR dataset and dataloader for testing...')
            assert mask_width is not None
            assert mask_height is not None
            assert mscxr_phrase2embedding_filepath is not None
            assert phrase_grounding_collate_batch_fn is not None

            dicom_id_2_phrases_and_masks = get_ms_cxr_dicom_id_2_phrases_and_masks(mask_height, mask_width)
            print(f'len(dicom_id_2_phrases_and_masks) = {len(dicom_id_2_phrases_and_masks)}')

            phrase2embedding = load_pickle(mscxr_phrase2embedding_filepath)
            print(f'len(phrase2embedding) = {len(phrase2embedding)}')

            BIG_ENOGUGH = 1000000
            image_paths = [None] * BIG_ENOGUGH
            phrase_embeddings = [None] * BIG_ENOGUGH
            phrase_grounding_masks = [None] * BIG_ENOGUGH
            image_path_getter = get_image_path_getter(source_image_size_mode, verbose=True)

            mimiccxr_metadata = load_mimiccxr_reports_detailed_metadata()

            idx = 0
            for rid, (part_id, subject_id, study_id, dicom_id_view_pairs) in \
                tqdm(enumerate(zip(mimiccxr_metadata['part_ids'],
                    mimiccxr_metadata['subject_ids'],
                    mimiccxr_metadata['study_ids'],
                    mimiccxr_metadata['dicom_id_view_pos_pairs'])), mininterval=2):
                for dicom_id, view in get_dicom_id_and_orientation_list(dicom_id_view_pairs, MIMICCXR_ViewModes.ALL):
                    if dicom_id not in dicom_id_2_phrases_and_masks:
                        continue
                    image_paths[idx] = image_path_getter(part_id, subject_id, study_id, dicom_id)
                    phrases, masks = dicom_id_2_phrases_and_masks[dicom_id]
                    phrase_embeddings[idx] = np.array([phrase2embedding[phrase] for phrase in phrases])
                    phrase_grounding_masks[idx] = np.array(masks)
                    idx += 1

            print(f'Total number of images: {idx}')
            image_paths = image_paths[:idx]
            phrase_embeddings = phrase_embeddings[:idx]
            phrase_grounding_masks = phrase_grounding_masks[:idx]

            # Create a mapping from number of phrases to indices
            num_phrases_2_idxs = {}
            for i, pe in enumerate(phrase_embeddings):
                num_phrases = len(pe)
                try:
                    num_phrases_2_idxs[num_phrases].append(i)
                except KeyError:
                    num_phrases_2_idxs[num_phrases] = [i]

            # Create datasets and dataloaders for testing
            self.test_mscxr_datasets = []
            self.test_mscxr_dataloaders = []
            for num_phrases, indices in num_phrases_2_idxs.items():
                print(f'Number of phrases: {num_phrases}, # images: {len(indices)}')
                dataset = MIMICCXR_PhraseGroundingDataset(
                    image_paths=image_paths, image_transform=test_image_transform,
                    phrase_embeddings=phrase_embeddings, phrase_grounding_masks=phrase_grounding_masks,
                    indices=indices)
                batch_size = max(min(max_images_per_batch, max_phrases_per_batch // num_phrases), 1) * test_batch_size_factor
                dataloader = DataLoader(
                    dataset,
                    batch_size=batch_size,
                    shuffle=False,
                    num_workers=num_test_workers,
                    collate_fn=phrase_grounding_collate_batch_fn,
                    pin_memory=True,
                )
                self.test_mscxr_datasets.append(dataset)
                self.test_mscxr_dataloaders.append(dataloader)

        # Create chest imagenome test dataset and dataloader
        if use_chest_imagenome_gold_for_test:
            print_bold('Preparing Chest Imagenome dataset and dataloader for testing...')
            assert mask_width is not None
            assert mask_height is not None
            assert chest_imagenome_bbox_phrase_embeddings_filepath is not None
            assert bbox_grounding_collate_batch_fn is not None

            _, gold_pres_indices = get_chest_imagenome_gold_bbox_coords_and_presence_sorted_indices()

            tmp = get_cached_pickle_file(chest_imagenome_bbox_phrase_embeddings_filepath)
            bbox_phrase_embeddings = tmp['bbox_phrase_embeddings']
            bbox_phrases = tmp['bbox_phrases']
            bbox_phrase_embeddings = bbox_phrase_embeddings[gold_pres_indices] # use only gold subset
            bbox_phrases = [bbox_phrases[i] for i in gold_pres_indices] # use only gold subset
            assert bbox_phrase_embeddings.shape[0] == len(bbox_phrases)
            print(f'bbox_phrase_embeddings.shape = {bbox_phrase_embeddings.shape}')
            print(f'len(bbox_phrases) = {len(bbox_phrases)}')
            for phrase in bbox_phrases:
                print('\t', phrase)

            BIG_ENOGUGH = 1000000
            image_paths = [None] * BIG_ENOGUGH
            chest_imagenome_bbox_coords = [None] * BIG_ENOGUGH
            chest_imagenome_bbox_presence = [None] * BIG_ENOGUGH
            phrase_grounding_masks = [None] * BIG_ENOGUGH
            phrase_classification_labels = [None] * BIG_ENOGUGH
            image_path_getter = get_image_path_getter(source_image_size_mode, verbose=True)

            mimiccxr_metadata = load_mimiccxr_reports_detailed_metadata()
            did2bboxes = load_chest_imagenome_gold_bboxes()

            idx = 0
            for rid, (part_id, subject_id, study_id, dicom_id_view_pairs) in \
                tqdm(enumerate(zip(mimiccxr_metadata['part_ids'],
                    mimiccxr_metadata['subject_ids'],
                    mimiccxr_metadata['study_ids'],
                    mimiccxr_metadata['dicom_id_view_pos_pairs'])), mininterval=2):
                for dicom_id, view in get_dicom_id_and_orientation_list(dicom_id_view_pairs, MIMICCXR_ViewModes.ALL):
                    if dicom_id not in did2bboxes:
                        continue
                    image_paths[idx] = image_path_getter(part_id, subject_id, study_id, dicom_id)
                    bboxes = did2bboxes[dicom_id]
                    bbox_coords = bboxes['coords']
                    bbox_presence = bboxes['presence']
                    bbox_coords, bbox_presence = _clean_bbox_coords_and_presence(bbox_coords, bbox_presence)
                    chest_imagenome_bbox_coords[idx] = bbox_coords
                    chest_imagenome_bbox_presence[idx] = bbox_presence
                    phrase_grounding_masks[idx] = _compute_mask_from_bounding_boxes(mask_height, mask_width,
                                                                                bbox_coords[gold_pres_indices], # use only gold subset
                                                                                bbox_presence[gold_pres_indices])
                    phrase_classification_labels[idx] = bbox_presence[gold_pres_indices] # use bbox_presence as classification labels, use only gold subset
                    idx += 1

            print(f'Total number of images: {idx}')
            image_paths = image_paths[:idx]
            chest_imagenome_bbox_coords = chest_imagenome_bbox_coords[:idx]
            chest_imagenome_bbox_presence = chest_imagenome_bbox_presence[:idx]
            phrase_grounding_masks = phrase_grounding_masks[:idx]

            # Sanity check
            for i in range(idx):
                assert chest_imagenome_bbox_presence[i].shape[0] == chest_imagenome_bbox_coords[i].shape[0] == CHEST_IMAGENOME_NUM_BBOX_CLASSES,\
                    f'chest_imagenome_bbox_presence[{i}].shape[0] = {chest_imagenome_bbox_presence[i].shape[0]}, chest_imagenome_bbox_coords[{i}].shape[0] = {chest_imagenome_bbox_coords[i].shape[0]}'

            # Create dataset and dataloader for testing
            self.test_chest_imagenome_gold_dataset = MIMICCXR_BBoxGroundingDataset(
                image_paths=image_paths, image_transform=test_image_transform,
                phrase_embeddings=bbox_phrase_embeddings, phrase_grounding_masks=phrase_grounding_masks,
                phrase_classification_labels=phrase_classification_labels,
                bbox_coords=chest_imagenome_bbox_coords, bbox_presence=chest_imagenome_bbox_presence, use_yolov8=use_yolov8)
            batch_size = max(min(max_images_per_batch, max_phrases_per_batch // len(bbox_phrases)), 1) * test_batch_size_factor
            self.test_chest_imagenome_gold_dataloader = DataLoader(
                self.test_chest_imagenome_gold_dataset,
                batch_size=batch_size,
                shuffle=False,
                num_workers=num_test_workers,
                collate_fn=lambda batch: bbox_grounding_collate_batch_fn(batch, training_mode=False),
                pin_memory=True,
            )


import os
from os.path import join
import numpy as np
import cv2

import sys
sys.path.append('..')
from config import cfg

def read_annotation():
    data = dict()
    images = []
    bboxes = []
    labelfile = open(cfg.path_wider_bbx_gt, 'r')
    while True:
        # image path
        imagepath = labelfile.readline().strip('\n')
        if not imagepath:
            break
        imagepath = join(cfg.path_wider_imgs, imagepath)
        images.append(imagepath)
        # face numbers
        nums = labelfile.readline().strip('\n')
        # im = cv2.imread(imagepath)
        # h, w, c = im.shape
        one_image_bboxes = []
        for i in range(int(nums)):
            # text = ''
            # text = text + imagepath
            bb_info = labelfile.readline().strip('\n').split(' ')
            # only need x, y, w, h
            face_box = [float(bb_info[i]) for i in range(4)]
            # text = text + ' ' + str(face_box[0] / w) + ' ' + str(face_box[1] / h)
            xmin = face_box[0]
            ymin = face_box[1]
            xmax = xmin + face_box[2]
            ymax = ymin + face_box[3]
            # text = text + ' ' + str(xmax / w) + ' ' + str(ymax / h)
            one_image_bboxes.append([xmin, ymin, xmax, ymax])
            # f.write(text + '\n')
        bboxes.append(one_image_bboxes)

    data['images'] = images#all image pathes
    data['bboxes'] = bboxes#all image bboxes
    # f.close()
    return data

def read_and_write_annotation(base_dir, dir):
    """
    read label file
    :param dir: path
    :return:
    """
    data = dict()
    images = []
    bboxes = []
    labelfile = open(dir, 'r')
    f = open('/home/thinkjoy/data/mtcnn_data/imagelists/train.txt', 'w')
    while True:
        # image path
        imagepath = labelfile.readline().strip('\n')
        if not imagepath:
            break
        imagepath = base_dir + '/WIDER_train/images/' + imagepath
        images.append(imagepath)
        # face numbers
        nums = labelfile.readline().strip('\n')
        im = cv2.imread(imagepath)
        h, w, c = im.shape
        one_image_bboxes = []
        for i in range(int(nums)):
            text = ''
            text = text + imagepath
            bb_info = labelfile.readline().strip('\n').split(' ')
            # only need x, y, w, h
            face_box = [float(bb_info[i]) for i in range(4)]
            text = text + ' ' + str(face_box[0] / w) + ' ' + str(face_box[1] / h)
            xmin = face_box[0]
            ymin = face_box[1]
            xmax = xmin + face_box[2] - 1
            ymax = ymin + face_box[3] - 1
            text = text + ' ' + str(xmax / w) + ' ' + str(ymax / h)
            one_image_bboxes.append([xmin, ymin, xmax, ymax])
            f.write(text + '\n')
        bboxes.append(one_image_bboxes)

    data['images'] = images
    data['bboxes'] = bboxes
    f.close()
    return data

def get_path(base_dir, filename):
    return os.path.join(base_dir, filename)

def IoU(box, bboxes):
    """
    Caculate IoU between detect and ground truth boxes
    :param crop_box:numpy array (4, )
    :param bboxes:numpy array (n, 4):x1, y1, x2, y2
    :return:
    numpy array, shape (n, ) Iou
    """
    box_area = (box[2] - box[0] + 1) * (box[3] - box[1] + 1)
    areas = (bboxes[:, 2] - bboxes[:, 0] + 1) * (bboxes[:, 3] - bboxes[:, 1] + 1)
    xx1 = np.maximum(box[0], bboxes[:, 0])
    yy1 = np.maximum(box[1], bboxes[:, 1])
    xx2 = np.minimum(box[2], bboxes[:, 2])
    yy2 = np.minimum(box[3], bboxes[:, 3])

    # compute the width and height of the bounding box
    w = np.maximum(0, xx2 - xx1 + 1)
    h = np.maximum(0, yy2 - yy1 + 1)

    inter = w * h
    over = inter / (box_area + areas - inter)

    return over

if __name__ == '__main__':
    pass


#!/usr/bin/env python3
from functools import reduce
import csv

actions = ("Random Walk", "Extinguish Fire", "Resupply Water")
states = [("W", 2), ("F", 2)]
sum_states = [1 if i == len(states) - 1 else sum(map(lambda x: x[1], states[i+1:])) for i in range(len(states))]

if __name__ == '__main__':
    import argparse
    parser = argparse.ArgumentParser()
    parser.add_argument("csv_file", help="put the csv file path")
    args = parser.parse_args()
    csv_path = args.csv_file
    out_path = csv_path.replace(".csv", ".tex")

    n_states = reduce(lambda x,y: x*y, map(lambda x: x[1], states))
    n_actions = len(actions)

    table = [[0 for i in range(n_actions)] for j in range(n_states)]
    with open(csv_path) as csvfile:
        reader = csv.reader(csvfile)
        for i, row in enumerate(reader):
            if i < n_states:
                for j, val in enumerate(row[:-1]):
                    table[i][j] = val

    lines = [["" for i in range(len(states) + len(actions))] for j in range(n_states)]
    sep = [r"\hline" for i in range(n_states)]

    for i in range(n_states):
        for j, (state, _) in enumerate(states):
            if i % sum_states[j] == 0:
                if _ == 2:
                    text = "${}{}$".format(r'\neg ' if (i // sum_states[j]) % 2 == 0  else '', state)
                else:
                    text = "${} = {}$".format(state, (i // sum_states[j]) % _)
                lines[i][j] = r"\multirow{" + str(sum_states[j]) + r"}{*}{" + text + r"}"
                if j != len(states) - 1 and sep[i] == r"\hline":
                    sep[i] = r'\cline{' + str(j + 2)  + '-' + str(len(lines[0])) + '}'
                else:
                    lines[i][j] = text

        for j, val in enumerate(table[i]):
            lines[i][len(states) + j] = "{:.3f}".format(float(val))

    header = [' '] * len(states) + list(actions)

    indent = "  "
    tex = ""
    # tex = r"\begin{code}" + "\n"
    tex += r"\begin{center}" + "\n"
    tex += r"\begin{tabular}{|" + "|".join(['c' for i in range(len(lines[0]))]) + "|}\n"
    tex += indent + r"\hline" + "\n"
    tex += ' & '.join(header) + r"\\" + "\n"
    tex += indent + r"\hline" + "\n"
    for i in range(n_states):
        tex += indent + " & ".join(lines[i]) + r"\\" + "\n"
        if i != n_states - 1:
            tex += indent + sep[i] + "\n"
    tex += indent + r"\hline" + "\n"
    tex += r"\end{tabular}" + "\n"
    tex += r"\end{center}" + "\n"
    # tex += r"\end{code}"

    open(out_path, 'w').write(tex)


import sys
import cv2
import argparse
import os

print("OpenCV version"+cv2.__version__)

def variance_of_laplacian(image):
    """
    compute the Laplacian of the image and return the focus measure
    """
    return cv2.Laplacian(image, cv2.CV_64F).var()

parser = argparse.ArgumentParser()
parser._action_groups.pop()
required = parser.add_argument_group('required arguments')
optional = parser.add_argument_group('optional arguments')
required.add_argument("-p", "--path", type=str, default="",
                      help="path to the video file", required=True)
optional.add_argument("-t", "--threshold", type=float, default=100.0,
                      help="default threshold is 100.0. Use 10-30 for motion")
optional.add_argument("-s", "--step", type=int,
                      default=1, help="frame step size")
optional.add_argument("--save", default= "", type= str, help= "path to save the frames in a directory")
args = vars(parser.parse_args())

if not args["path"]:
    sys.exit("Please supply a video file '-p <path>'")

vidcap = cv2.VideoCapture(args["path"])

success, image = vidcap.read()
count = 0
blurryFrame = 0
savedFrame = 0
frameStep = 0
step = args["step"]

print("Working...")

while success:
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    fm = variance_of_laplacian(gray)

    if frameStep == step:
        if fm > args["threshold"]:
            savedFrame += 1
            image_path = os.path.join(args["save"], "frame%d.png" % count)
            cv2.imwrite(image_path, image)
        frameStep = 0

    if fm < args["threshold"]:
        blurryFrame += 1

    success, image = vidcap.read()
    count += 1
    frameStep += 1

sys.exit("Done!")


#Adapted from https://github.com/keras-team/keras-applications/blob/master/keras_applications/densenet.py

import keras
from keras import layers, backend, models

def dense_block(x, blocks, width, name=None):
    for i in range(blocks):
        x = conv_block(x, width, name=name + '_block' + str(i + 1))
    return x

def transition_block(x, reduction, name):
    bn_axis = 3 if backend.image_data_format() == 'channels_last' else 1
    x = layers.BatchNormalization(axis=bn_axis, epsilon=1.001e-5,
                                  name=name + '_bn')(x)
    x = layers.Activation('relu', name=name + '_relu')(x)
    x = layers.Conv2D(int(backend.int_shape(x)[bn_axis] * reduction), 1,
                      use_bias=False,
                      name=name + '_conv')(x)
    x = layers.AveragePooling2D(2, strides=2, name=name + '_pool')(x)
    return x

def conv_block(x, growth_rate, name):
    bn_axis = 3 if backend.image_data_format() == 'channels_last' else 1
    x1 = layers.BatchNormalization(axis=bn_axis,
                                   epsilon=1.001e-5,
                                   name=name + '_0_bn')(x)
    x1 = layers.Activation('relu', name=name + '_0_relu')(x1)
    x1 = layers.Conv2D(4 * growth_rate, 1,
                       use_bias=False,
                       name=name + '_1_conv')(x1)
    x1 = layers.BatchNormalization(axis=bn_axis, epsilon=1.001e-5,
                                   name=name + '_1_bn')(x1)
    x1 = layers.Activation('relu', name=name + '_1_relu')(x1)
    x1 = layers.Conv2D(growth_rate, 3,
                       padding='same',
                       use_bias=False,
                       name=name + '_2_conv')(x1)
    x = layers.Concatenate(axis=bn_axis, name=name + '_concat')([x, x1])
    return x

def DenseNet(blocks, input_shape, num_classes, width):
    img_input = layers.Input(shape=input_shape)

    bn_axis = 3 if backend.image_data_format() == 'channels_last' else 1

    x = layers.ZeroPadding2D(padding=((3, 3), (3, 3)))(img_input)
    x = layers.Conv2D(2 * width, 7, strides=2, use_bias=False, name='conv1/conv')(x)
    x = layers.BatchNormalization(
        axis=bn_axis, epsilon=1.001e-5, name='conv1/bn')(x)
    x = layers.Activation('relu', name='conv1/relu')(x)
    x = layers.ZeroPadding2D(padding=((1, 1), (1, 1)))(x)
    x = layers.MaxPooling2D(3, strides=2, name='pool1')(x)

    x = dense_block(x, blocks[0], width, name='conv2')
    x = transition_block(x, 0.5, name='pool2')
    x = dense_block(x, blocks[1], width, name='conv3')
    x = transition_block(x, 0.5, name='pool3')
    x = dense_block(x, blocks[2], width, name='conv4')
    x = transition_block(x, 0.5, name='pool4')
    x = dense_block(x, blocks[3], width, name='conv5')

    x = layers.BatchNormalization(
        axis=bn_axis, epsilon=1.001e-5, name='bn')(x)
    x = layers.Activation('relu', name='relu')(x)

    x = layers.GlobalAveragePooling2D(name='avg_pool')(x)
    x = layers.Dense(num_classes, activation='softmax', name='fc1000')(x)

    # Create model.
    if blocks == [6, 12, 24, 16]:
        model = models.Model(img_input, x, name='densenet121')
    elif blocks == [6, 12, 32, 32]:
        model = models.Model(img_input, x, name='densenet169')
    elif blocks == [6, 12, 48, 32]:
        model = models.Model(img_input, x, name='densenet201')
    else:
        model = models.Model(img_input, x, name='densenet')

    return model

def DenseNet121(input_shape, num_classes, width):
    return DenseNet([6, 12, 24, 16], input_shape, num_classes, width)


from google.appengine.ext import webapp
from google.appengine.api import urlfetch
import urllib2
import time
import logging, datetime

def remove_www(handler):
    if handler.request.url.startswith('http://www.'):
        handler.redirect(handler.request.url.replace('http://www.', 'http://'))

def makeStatic(template_name, context={}):
    class Static(webapp.RequestHandler):
        def get(self):
            remove_www(self)
            self.response.headers['Content-Type'] = 'text/html'
            self.response.out.write(
                render(template_name, context)
            )
    return Static

import re
# Allow 'abc' and 'abc.def' but not '.abc' or 'abc.'
valid_callback = re.compile('^\w+(\.\w+)*$')

from BeautifulSoup import BeautifulSoup

class twitpicapi(webapp.RequestHandler):
    user = ""
    ids = []
    def get(self):
        self.response.headers['Content-Type'] = 'text/javascript'
        callback = self.request.get('callback', default_value='')
        page = self.request.get('page', default_value='0')
        self.user = self.request.path[1:]

        self.loadTwitPicPage(page)

        json = []
        for j in self.ids:
            json.append("{ id : '%s', url : '%s', twitpic_url : '%s', date : '%s', title : '%s' }" % (j['id'], j['url'], j['twitpic_url'], j['date'], re.escape(j['title'])))

        # json = u"{ works : false, user : '%s', id_size : %s }" % (self.user, len(self.ids))
        json = '[%s]' % (",\n".join(json))
        if callback and valid_callback.match(callback):
            json = '%s(%s)' % (callback, json)
        self.response.out.write(json)

    def loadTwitPicPage(self, page):
        url = ""
        if page > 1:
            url = 'http://twitpic.com/photos/%s?page=%s' % (self.user, page)
        else:
            url = 'http://twitpic.com/photos/%s' % (self.user)

        # self.response.out.write('Grabbing from ' + url + "\n")
        contents = urllib2.urlopen(url)
        soup = BeautifulSoup(contents)
        for photowrapper in soup('div', {"class":"profile-photo-img"}):
            json = {}
            anchor = photowrapper.find('a')
            json['id'] = anchor['href'][1:]
            json['twitpic_url'] = 'http://twitpic.com/show/large/' + json['id']

            image = urlfetch.fetch(url=json['twitpic_url'], follow_redirects=False)
            if image.status_code == 302:
                json['url'] = image.headers['location']
            else:
                json['url'] = json['twitpic_url']

            # required to get the date - sucks that they don't maintain the date on the image URL
            twitpicPage = urllib2.urlopen('http://twitpic.com/' + json['id'])
            twitpicPageSoup = BeautifulSoup(twitpicPage)
            meta = twitpicPageSoup.find('div', { "id" : "photo-info" }).find('div').contents[0].strip() # grab the first nest div
            date = time.strptime(meta,"Posted on %B %d, %Y")
            json['date'] = time.strftime("%Y-%m-%d", date)

            json['title'] = ''
            if (twitpicPageSoup.find('div', { 'id' : 'view-photo-caption' }) is not None):
                json['title'] = twitpicPageSoup.find('div', { 'id' : 'view-photo-caption' }).contents[0].strip()

            self.ids.append(json)

        # if soup.find(text=re.compile("OLDER")):
        #     href = soup.find(text=re.compile("OLDER")).parent['href']
        #     m = re.search('(\d+?)$', href)
        #     if m is not None:
        #         self.loadTwitPicPage(m.group(0))

class Http404Page(webapp.RequestHandler):
    def get(self):
        self.response.headers['Content-Type'] = 'text/html'
        self.error(404)
        self.response.out.write(render('index.html', {
            'path': self.request.path,
        }))

def main():
    logging.getLogger().setLevel(logging.DEBUG)
    from wsgiref.handlers import CGIHandler
    application = webapp.WSGIApplication([
        ('/', makeStatic('index.html')),
        (r'/[a-z0-9]{1,15}$', twitpicapi),
        ('/.*$', Http404Page),
    ], debug=True)
    CGIHandler().run(application)

import os
template_dir = os.path.join(os.path.dirname(__file__), 'templates')
from google.appengine.ext.webapp import template
def render(template_name, context={}):
    path = os.path.join(template_dir, template_name)
    return template.render(path, context)

if __name__ == "__main__":
    main()


from django.conf.urls import patterns, url

from user_bizz import views

urlpatterns = patterns('',
  url(r'^$', views.book_list, name='book_list'),
  url(r'^new$', views.book_create, name='book_new'),
  url(r'^edit/(?P<pk>\d+)$', views.book_update, name='book_edit'),
  url(r'^delete/(?P<pk>\d+)$', views.book_delete, name='book_delete'),
  url(r'^export/csv/$', views.export_users_csv, name='export_users_csv'),
)


# -*- coding: utf-8 -*-
"""
Created on Wed Jan 18 16:21:48 2023

@author: Md.Jahidul Islam
"""

try:
    import tkinter as tk                # python 3
    from tkinter import font as tkfont  # python 3

except ImportError:
    import Tkinter as tk     # python 2
    import tkFont as tkfont  # python 2
from tkinter import filedialog
import tkinter.messagebox
import warnings
warnings.simplefilter(action='ignore', category=FutureWarning)
import fitz
from PIL import Image
import os
import shutil

class SampleApp(tk.Tk):

    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        #Main Frame
        self.title("PDF To TIFF OFFLINE CONVERTER")
        MainFrame= tk.Frame(self,bd=10, width=1100, height=400,relief= tk.RIDGE, bg='cadet blue')
        MainFrame.pack(fill=tk.BOTH,expand=1)
        MainFrame.pack_propagate(0)

        #Panedwindow Botton and Editor
        BE_pan=tk.PanedWindow(MainFrame,orient=tk.HORIZONTAL)

        #Page Frame --Left side of Main Frame
        Page_Frame2= tk.Frame(BE_pan,bd=8, width=800, height=200,relief= tk.RIDGE, bg='AliceBlue')
        Page_Frame2.pack(side="left", fill=tk.BOTH)
        BE_pan.add(Page_Frame2)

        #Main ELEMENT Frame --Right side of Main Frame
        Main_ELEMENT_Frame5= tk.Frame(BE_pan,bd=8, width=50, height=200,relief= tk.RIDGE, bg='AliceBlue')
        Main_ELEMENT_Frame5.pack(side="right")
        Main_ELEMENT_Frame5.pack_propagate(0)

        BE_pan.add(Main_ELEMENT_Frame5)

        BE_pan.pack(fill = tk.BOTH, expand = True)

        # This method is used to show sash
        BE_pan.configure(sashrelief = tk.RAISED)

        #Panedwindow Element and display
        ED_pan=tk.PanedWindow(Page_Frame2,orient=tk.VERTICAL)
        #Page Frame --top side of Main Frame
        Page_Frame1= tk.Frame(ED_pan,bd=8, width=800, height=100,relief= tk.RIDGE, bg='cadet blue')
        Page_Frame1.pack(side="top", fill=tk.BOTH)
        ED_pan.add(Page_Frame1)

        #Main ELEMENT Frame --bottom side of Main Frame
        Frame5= tk.Frame(ED_pan,bd=8, width=800, height=100,relief= tk.RIDGE, bg='cadet blue')
        Frame5.pack(side="bottom")
        Frame5.pack_propagate(0)

        ED_pan.add(Frame5)
        ED_pan.pack(fill = tk.BOTH, expand = True)
        ED_pan.configure(sashrelief = tk.RAISED)

        Fact = """\nHere We Can Get The Update Of The Runing Process."""
        #=============function============
        def Open():
            global path
            path= filedialog.askopenfilenames(title="Select PDF FIles",filetypes=(("PDF Files","*.pdf"),("Excel Files","*.xlsx"),("CSV Files","*.csv"),("All Files","*.*")))
            nb_file="\nNumber of files selected: "+str(len(path))
            T.insert(tk.END,nb_file)
            for i in path:
                filename = i.split('/')[len(i.split('/'))-1]
                filename =filename.replace(".pdf","")
                filename1="\n  "+filename
                T.insert(tk.END,filename1)

        #Location to Save the the report
        def saving():
            global save_only
            save_only= filedialog.askdirectory(title="Select the output folder")
            T.insert(tk.END,f"\nSelected Folder To Save The TIFF File:{save_only}")

        def slider_changed(event):
            pass

        def start():
            for pdf1 in path:
                #Creat Forlder
                dpi = DPI.get()
                zoom = dpi / Zoom.get()
                magnify = fitz.Matrix(zoom, zoom)
                doc = fitz.open(pdf1)
                filename = pdf1.split('/')[len(pdf1.split('/'))-1]
                filename =filename.replace(".pdf","")
                filename1="\n    Start Converting For:"+filename
                T.insert(tk.END,filename1)

                # path
                path_mak = os.path.join(save_only, filename)
                try:
                    os.mkdir(path_mak)
                except OSError as error:
                    tkinter.messagebox.showerror('Error', 'Error: Please Select The location To Save The Files!')

                add=[]
                for index, page in enumerate(doc):
                    pix = page.get_pixmap(matrix=magnify)
                    pix.save(f"{path_mak}/page-{page.number}.tiff")
                    im1 = Image.open(f"{path_mak}/page-{page.number}.tiff")
                    if index==0:
                        pass
                    else:
                        add.append(im1)

                im1 = Image.open(f"{path_mak}/page-0.tiff")
                output_tiff=f"{save_only}/{filename}.tiff"
                im1.save(output_tiff, save_all=True, append_images=add, compression='tiff_lzw', tiffinfo={317: 2})
                T.insert(tk.END,f"\n{filename} Is Converted")
                # removing directory
                shutil.rmtree(path_mak, ignore_errors=False)
            os.startfile(save_only)
            tkinter.messagebox.showinfo("PDF TO TIFF","ALL The Pdfs Are Converted Successfully")

        #===========Button=========
        pdf_button= tk.Button(Main_ELEMENT_Frame5,font =('Bahnschrift Light SemiCondensed', 12, 'bold'),text="SELECT PDFs", bd =5, command= Open).pack(fill=tk.BOTH, expand=1)
        Save_button= tk.Button(Main_ELEMENT_Frame5,font =('Bahnschrift Light SemiCondensed', 12, 'bold'),text="SELECT THE LOCATION TO SAVE", bd =5, command= saving).pack(fill=tk.BOTH, expand=1)
        Convert_button= tk.Button(Main_ELEMENT_Frame5,font =('Bahnschrift Light SemiCondensed', 12, 'bold'),text="Start Converting", cursor="plus",activeforeground='#58D68D',activebackground='#5D6D7E', bd =5, command= start).pack(fill=tk.BOTH, expand=1)
        #===========text=======
        # Create text widget and specify size.
        T = tk.Text(Frame5)
        T.insert(tk.END, Fact)
        T.pack(fill=tk.BOTH, expand=1)
        #================ scorol bar========
        DPI= tk.Scale(Page_Frame1,from_= 300, to=600,orient='horizontal',command=slider_changed)
        DPI.pack(fill=tk.BOTH, expand=1)
        DPIlable=tk.Label(Page_Frame1, text= "Please Select DPI  Value\n Default value: 300", bd =2)
        DPIlable.pack(fill=tk.BOTH, expand=1)
        Zoom= tk.Scale(Page_Frame1,from_= 72, to=200,orient='horizontal',command=slider_changed)
        Zoom.pack(fill=tk.BOTH, expand=1)
        Zoomlable=tk.Label(Page_Frame1, text= "Please Select Zoom Factor Value\nDefault value: 72\nSelect 120-180 for best output", bd =2)
        Zoomlable.pack(fill=tk.BOTH, expand=1)

if __name__ == "__main__":
    app = SampleApp()
    app.mainloop()


import ctypes
import platform

from functools import lru_cache

import pygame

import vars

class Screen:
    """Object containing information about the current display

    Used by draw functions"""

    def __init__(self):
        # Constants
        self.FULLSCREEN = vars.options["fullscreen"]
        self.FRAMERATE = vars.options["framerate"]
        self.DEFAULT_SIZE = (vars.options["resolution_x"], vars.options["resolution_y"])

        # If running Windows, disable high DPI scaling
        if platform.system() == "Windows":
            ctypes.windll.user32.SetProcessDPIAware()

        # Units for drawing the board to the screen
        self.LAST_BOARD_SIZE = None

        self.rescale_window(self.DEFAULT_SIZE, self.FULLSCREEN)

        # Theme to be used for screen drawing
        self.theme = None

        # Pygame
        self.clock = pygame.time.Clock()

        pygame.display.set_caption("Battleships")
        pygame.display.set_icon(pygame.image.load("assets/icon.ico"))

        pygame.font.init()

    def rescale_window(self, size, fullscreen):
        """
        Rescale the window to size
        :param size: (int width, int height)
        :param fullscreen: bool
        """

        if fullscreen is None:
            fullscreen = self.FULLSCREEN

        self.FULLSCREEN = fullscreen

        if self.FULLSCREEN:
            size = pygame.display.list_modes()[0]
            self.screen = pygame.display.set_mode(size, pygame.FULLSCREEN | pygame.HWACCEL)
        else:
            self.screen = pygame.display.set_mode(size, pygame.RESIZABLE)

        self.SIZE = size
        self.WIDTH, self.HEIGHT = self.SIZE
        self.MID = (self.WIDTH / 2, self.HEIGHT / 2)

        # Units for drawing to the screen
        self.UNIT = min(self.SIZE)
        self.BORDER_SIZE = self.UNIT / 20
        self.MARGIN_SIZE = int(self.UNIT / 300)

        # Font settings
        self.FONT_SCALE = self.UNIT / 1000

        # Force text to be rescaled
        self.render_text.cache_clear()

        if self.LAST_BOARD_SIZE:
            self.calc_board_spacing(self.LAST_BOARD_SIZE)

    def toggle_fullscreen(self):
        """
        Toggles fullscreen mode
        """

        if self.FULLSCREEN:
            self.rescale_window(self.DEFAULT_SIZE, False)
        else:
            self.rescale_window(self.DEFAULT_SIZE, True)

    def calc_board_spacing(self, board_size):
        """
        Calculates spacing for boards on screen
        :param board_size: int
        """

        self.LAST_BOARD_SIZE = board_size

        self.CELL_SIZE = int(((vars.screen.UNIT - vars.screen.BORDER_SIZE * 3)
                              / 2 - (board_size + 1) * self.MARGIN_SIZE) / board_size)
        self.CELL_DOT_SIZE = int(self.CELL_SIZE / 4)

        self.BOARD_SIZE = self.CELL_SIZE * board_size + self.MARGIN_SIZE * (board_size + 1)

    def set_theme(self, theme):
        """Sets the theme"""

        self.theme = theme

    @lru_cache(maxsize=32)
    def get_font(self, name, size):
        """Returns a font object given a name and size"""

        return pygame.font.Font(name, size)

    @lru_cache(maxsize=32)
    def render_text(self, size, text, text_color):
        """Returns a text object given a name, size and text to render"""

        # Adjust size of font for screen size
        size = int(self.FONT_SCALE * size)

        # Get font
        font = self.get_font(self.theme.FONT, size)

        # Render text
        text = font.render(text, True, text_color)

        return text

    def draw(self):
        """Draws to the screen"""

        self.clock.tick(self.FRAMERATE)
        pygame.display.flip()

        # print(self.clock.get_fps())


#!/usr/bin/env python

# --------------------------------------------------------
# Tensorflow Faster R-CNN
# Licensed under The MIT License [see LICENSE for details]
# Written by Xinlei Chen, based on code from Ross Girshick
# --------------------------------------------------------

"""
Demo script showing detections in sample images.

See README.md for installation instructions before running.
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import argparse
import os

import cv2
import matplotlib.pyplot as plt
import numpy as np
import tensorflow as tf
from lib.config import config as cfg
from lib.utils.nms_wrapper import nms
from lib.utils.test import im_detect
#from nets.resnet_v1 import resnetv1
from lib.nets.vgg16 import vgg16
from lib.utils.timer import Timer
import lib.config.config as cf

CLASSES = ('__background__', 'defect')

NETS = {'vgg16': ('vgg16_faster_rcnn_iter_30000.ckpt',), 'res101': ('res101_faster_rcnn_iter_110000.ckpt',)}
DATASETS = {'pascal_voc': ('voc_2007_trainval',), 'pascal_voc_0712': ('voc_2007_trainval+voc_2012_trainval',)}

def load_image_set_index():
    """
    Load the indexes listed in this dataset's image set file.
    """
    # Example path to image set file:
     # self._devkit_path/VOC2007/ImageSets/Main/trainval.txt
    image_set_file = os.path.join(cf.FLAGS2["root_dir"],'DateSet','RSDDs_dataset_LJ','RSDDsTest','VOCDevkit2007',"VOC2007",'ImageSets','Main','test.txt')

    assert os.path.exists(image_set_file), \
        'Path does not exist: {}'.format(image_set_file)
    with open(image_set_file) as f:
            # f.read()把整个文件内容读进一个字符串
            # f.readline()读一行
            # f.readlines()把整个文件让你读入一个字符串列表，每一行为一个字符串
         image_index = [x.strip() for x in f.readlines()]
    return image_index

def image_path_from_index(index):
    """
    Construct an image path from the image's "index" identifier.
    """
    image_path = os.path.join(cf.FLAGS2["root_dir"],'DateSet','RSDDs_dataset_LJ','RSDDsTest','VOCdevkit2007','VOC2007','JPEGImages',
                                  index + ".jpg")
    assert os.path.exists(image_path), \
            'Path does not exist: {}'.format(image_path)
    return image_path

def vis_detections(im, class_name, dets,image_name,outputPath, thresh=0.5):
    """Draw detected bounding boxes."""
    inds = np.where(dets[:, -1] >= thresh)[0]
    if len(inds) == 0:
        return

    im = im[:, :, (2, 1, 0)]
    fig, ax = plt.subplots(figsize=(12, 12))  #figure来设置窗口尺寸
    # 在ax子图中绘制im图像
    ax.imshow(im, aspect='equal')
    for i in inds:
        bbox = dets[i, :4]
        score = dets[i, -1]
        # 在子图中添加块
        ax.add_patch(
            plt.Rectangle((bbox[0], bbox[1]),
                          bbox[2] - bbox[0],
                          bbox[3] - bbox[1], fill=False,
                          edgecolor='red', linewidth=3.5)
        )
        #在指定位置添加文本
        ax.text(bbox[0], bbox[1] - 2,
                '{:s} {:.3f}'.format(class_name, score),
                bbox=dict(facecolor='blue', alpha=0.5),
                fontsize=14, color='white')
    # 设置子图标题
    ax.set_title(('{} detections with '
                  'p({} | box) >= {:.1f}').format(class_name, class_name,
                                                  thresh),
                 fontsize=14)
    plt.axis('off')
    plt.tight_layout()
    plt.draw()
    image_name=os.path.join(outputPath,image_name+'.jpg')
    plt.savefig(image_name)

def demo(sess, net, image_name,output_path):
    """Detect object classes in an image using pre-computed object proposals."""

    # Load the demo image
    image_path=image_path_from_index(image_name)
    im = cv2.imread(image_path)

    # Detect all object classes and regress object bounds
    timer = Timer()
    timer.tic()
    # 此处的boxes是经过bbox_pre修正过的Bbox的位置坐标，并且对于预测的每一个类别，都有一个预测的Bbox坐标
    scores, boxes = im_detect(sess, net, im)
    timer.toc()
    print('Detection took {:.3f}s for {:d} object proposals'.format(timer.total_time, boxes.shape[0]))

    # Visualize detections for each class
    CONF_THRESH = 0.1
    NMS_THRESH = 0.1
    #对每个类别进行一次画图,这里只有一个类别defect
    for cls_ind, cls in enumerate(CLASSES[1:]):
        cls_ind += 1  # because we skipped background
        cls_boxes = boxes[:, 4 * cls_ind:4 * (cls_ind + 1)]
        cls_scores = scores[:, cls_ind]
        dets = np.hstack((cls_boxes,
                          cls_scores[:, np.newaxis])).astype(np.float32)
        #利用非极大值抑制，从300个proposal中剔除掉与更大得分的proposal的IOU大于0.1的proposal
        keep = nms(dets, NMS_THRESH)
        dets = dets[keep, :]

        vis_detections(im, cls, dets,image_name,output_path,thresh=CONF_THRESH)

def parse_args():
    """Parse input arguments."""
    parser = argparse.ArgumentParser(description='Tensorflow Faster R-CNN demo')
    parser.add_argument('--net', dest='demo_net', help='Network to use [vgg16 res101]',
                        choices=NETS.keys(), default='vgg16')
    # choices： 参数的取值范围  default：  参数的默认值  help：参数的说明信息
    # dest： 添加对象的属性名，由parse_Args()返回
    parser.add_argument('--dataset', dest='dataset', help='Trained dataset [pascal_voc pascal_voc_0712]',
                        choices=DATASETS.keys(), default='pascal_voc')
    args = parser.parse_args()

    return args

#以双下划线“__”开头和结尾的是python的内置属性
#当作为导入模块使用时，模块__name__属性值为模块的主名，当作为顶层模块直接使用时，__name__属性值为__main__
if __name__ == '__main__':
    #模块独立执行，所以执行下面的代码
    args = parse_args()

    # model path
    demonet = args.demo_net
    dataset = args.dataset

    #加载训练好的模型的路径
    #dataset为键值=pascal_voc，DATASETS[dataset]=('voc_2007_trainval',)，是一个集合，所以[0]是下标
    #DATASETS[dataset][0]='voc_2007_trainval'
    tfmodel = os.path.join(cf.FLAGS2["root_dir"], 'Module', 'LJModule', 'Faster RCNN', demonet, 'RSDDs_1', 'default', NETS[demonet][0])

    if not os.path.isfile(tfmodel + '.meta'):
        print(tfmodel)
        raise IOError(('{:s} not found.\nDid you download the proper networks from '
                       'our server and place them properly?').format(tfmodel + '.meta'))

    # set config
    tfconfig = tf.ConfigProto(allow_soft_placement=True)
    tfconfig.gpu_options.allow_growth = True

    # init session
    sess = tf.Session(config=tfconfig)
    # load network
    if demonet == 'vgg16':
        net = vgg16(batch_size=1)
    # elif demonet == 'res101':
        # net = resnetv1(batch_size=1, num_layers=101)
    else:
        raise NotImplementedError

    n_classes = len(CLASSES)
    # create the structure of the net having a certain shape (which depends on the number of classes)
    '''
    self._predictions["bbox_pred"] *= stds
    self._predictions["bbox_pred"] += means
    '''
    net.create_architecture(sess, "TEST", n_classes,
                            tag='default', anchor_scales=[8, 16, 32])
    saver = tf.train.Saver()
    saver.restore(sess, tfmodel)

    print('Loaded network {:s}'.format(tfmodel))

    output_path='G:\DeepLearning\Project\LJProject\Faster-RCNN\Faster-RCNN-TensorFlow-Python3-master-RSDDs\demo_output\\vgg16\RSDDs_train_test'
    print("save result in  {:s}".format(output_path))
    if not os.path.isdir(output_path):
         os.mkdir(output_path)
    image_index=load_image_set_index()

    for i in range(len(image_index)):
         demo(sess, net, image_index[i],output_path)


import sys
import math
import numpy as np
import time
import sounddevice as sd
import soundfile as sf
import subprocess
from multiprocessing import Process
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

PLAYER_FRAME_DURATION = 0.2
PLAYER_FRAME_SHIFT = 0.1
PLAYER_N_PLOTS = 20
PLAYER_UPDATE_INTERVAL = 0.05

PLAYER_SAMPLERATE = 16000  # samplerate is fixed value
PLAYER_NYQUIST = PLAYER_SAMPLERATE // 2

PLAYER_LIM_FREQ = 5000
PLAYER_LENFREQ = ((int(PLAYER_SAMPLERATE * PLAYER_FRAME_DURATION) >> 1) + 1) // (PLAYER_NYQUIST // PLAYER_LIM_FREQ)

def calc_specgrams(waveform, samplerate):
    specgrams = []

    left = 0
    right = PLAYER_FRAME_DURATION * samplerate

    while right < len(waveform):
        wframe = waveform[int(left):int(right)]

        hanningwindow = np.hanning(len(wframe))
        wframe = hanningwindow * wframe

        specgrams.append(np.log(np.abs(np.fft.rfft(wframe))))

        left += PLAYER_FRAME_SHIFT * samplerate
        right += PLAYER_FRAME_SHIFT * samplerate

    return specgrams

class Player():
    def __init__(self, filename, q):
        super(Player, self).__init__()

        waveform, samplerate = sf.read(sys.argv[1], dtype='float32')

        if samplerate != PLAYER_SAMPLERATE:
            print("ERROR in player: input wav file's sampling rate must be equal to 16,000")
            sys.exit(1)

        self.waveform = waveform

        self.filename = filename
        self.specgrams = calc_specgrams(waveform, samplerate)

        self.readed = 0

        q.put(0)

    def play(self, q):
        self.specgrams = calc_specgrams(self.waveform, PLAYER_SAMPLERATE)

        # playback start
        self.started = time.time()

        def playback(filename):
            # This requires SoX
            subprocess.call(['play', '-q', filename])

        pb = Process(target=playback, args=(self.filename,))
        pb.start()

        while 1:
            time.sleep(PLAYER_UPDATE_INTERVAL)

            elapsed = time.time() - self.started

            if elapsed >= (self.readed + 1) * PLAYER_FRAME_SHIFT:
                self.readed += 1

                if self.readed >= len(self.specgrams):
                    break

                # put latest specgram to queue
                q.put(self.specgrams[self.readed][:PLAYER_LENFREQ])

def player_main(filename, q):
    p = Player(filename, q)
    p.play(q)