示例#1
0
    def __init__(self, dbMethod, dbIp, dbPort, dbUser, dbPassword, dbName, tempPath, unknownPath, timezone, hash):
        self.dbIp = dbIp
        self.dbPort = dbPort
        self.dbUser = dbUser
        self.dbPassword = dbPassword
        self.dbName = dbName
        self.tempPath = tempPath
        self.unknownPath = unknownPath
        self.timezone = timezone
        self.uniqueHash = hash
        self.dbMethod = dbMethod
        
        #new www service
        self.www_hash = 'www_hash'

        self.dbWrapper = DbWrapper(self.dbMethod, self.dbIp, self.dbPort, self.dbUser, self.dbPassword, self.dbName, self.timezone, self.uniqueHash)

        if not os.path.exists(self.tempPath):
            log.info('Temp directory created')
            os.makedirs(self.tempPath)

        if not os.path.exists(self.unknownPath):
            log.info('Unknow directory created')
            os.makedirs(self.unknownPath)
            
        if not os.path.exists(self.www_hash):
            log.info('www_hash directory created')
            os.makedirs(self.www_hash)
示例#2
0
from db.dbWrapper import DbWrapper
from walkerArgs import parseArgs
import os, glob
from shutil import copyfile

args = parseArgs()
dbWrapper = DbWrapper(str(args.db_method), str(args.dbip), args.dbport,
                      args.dbusername, args.dbpassword, args.dbname,
                      args.timezone)


def main():
    print ''
    print 'If you want to insert a Gymhash to your Database, just take the File from Unknown Folder starting with *gym_crop* '
    print 'and copy the last part of the Filename.'
    print ''
    print 'f.e. 1_gym_crop_55.747355_99.163981_1536177248.96_45b5939252c695a9.jpg - the Hash is 45b5939252c695a9 '
    print ''
    print 'Additionally you need the gym_id or fort_id (rm or monocle)'
    print ''

    hash = raw_input("Enter Hash Value from Filename: ")

    gym = raw_input("Enter Gym / Fort ID: ")

    print ''
    if hash and gym:
        if dbWrapper.insertHash(hash, 'gym', gym, '999'):
            print 'Hash added - the Gym should now be recognized.'

            for file in glob.glob("www_hash/unkgym_*" + str(hash) + ".jpg"):
示例#3
0
def main_thread():
    global nextRaidQueue
    global lastPogoRestart
    global telnMore
    global pogoWindowManager
    global sleep
    global runWarningThreadEvent
    global windowLock
    global screenWrapper
    global lastScreenshotTaken
    global lastScreenHash
    global lastScreenHashCount

    log.info("main: Starting TelnetGeo Client")
    telnGeo = TelnetGeo(str(args.tel_ip), args.tel_port,
                        str(args.tel_password), args.tel_timeout_command,
                        args.tel_timeout_socket)

    log.info("main: Starting dbWrapper")
    dbWrapper = DbWrapper(str(args.db_method), str(args.dbip), args.dbport,
                          args.dbusername, args.dbpassword, args.dbname,
                          args.timezone)
    updateRaidQueue(dbWrapper)
    lastRaidQueueUpdate = time.time()

    if lastPogoRestart is None:
        lastPogoRestart = time.time()

    route = getJsonRoute(args.file, args.gym_distance,
                         args.max_count_gym_sum_up_around_gym, args.route_file)

    log.info("main: Route to be taken: %s, amount of coords: %s" %
             (str(route), str(len(route))))
    log.info("main: Max_distance before teleporting: %s" % args.max_distance)
    log.info("main: Checking if screen is on and pogo is running")

    if not sleep:
        if args.no_initial_restart is False:
            turnScreenOnAndStartPogo()
        else:
            startPogo()

    log.info('Starting speedweatherWarning Thread....')
    w = Thread(target=checkSpeedWeatherWarningThread, name='speedWeatherCheck')
    w.daemon = True
    w.start()

    emptycount = 0
    locationCount = 0
    while True:
        log.info("main: Next round")
        curLat = 0.0
        curLng = 0.0
        i = 0  # index in route
        failcount = 0
        lastRoundEggHatch = False

        # loop over gyms:
        # walk to next gym
        # get to raidscreen
        # take screenshot
        # check time to restart pogo

        # process the entire route, prioritize hatched eggs in every second round (if anything has hatched)
        while i < len(route):
            while sleep:
                time.sleep(1)
            curTime = time.time()
            # update the raid queue every 5mins...
            if (curTime - lastRaidQueueUpdate) >= (5 * 60):
                updateRaidQueue(dbWrapper)
                lastRaidQueueUpdate = curTime

            windowLock.acquire()
            # Restart pogo every now and then...
            if args.restart_pogo > 0:
                # log.debug("main: Current time - lastPogoRestart: %s" % str(curTime - lastPogoRestart))
                # if curTime - lastPogoRestart >= (args.restart_pogo * 60):
                locationCount += 1
                if locationCount > args.restart_pogo:
                    log.error("scanned " + str(args.restart_pogo) +
                              " locations, restarting pogo")
                    restartPogo()
                    locationCount = 0
            windowLock.release()

            # let's check for speed and weather warnings while we're walking/teleporting...
            runWarningThreadEvent.set()
            lastLat = curLat
            lastLng = curLng
            egghatchLocation = False
            log.debug(
                "main: Checking for raidqueue priority. Current time: %s, Current queue: %s"
                % (str(time.time()), str(nextRaidQueue)))
            # determine whether we move to the next gym or to the top of our priority queue
            if not lastRoundEggHatch and len(
                    nextRaidQueue) > 0 and nextRaidQueue[0][0] < time.time():
                # the topmost item in the queue lays in the past...
                log.info(
                    'main: An egg has hatched, get there asap. Location: %s' %
                    str(nextRaidQueue[0]))
                egghatchLocation = True
                nextStop = heapq.heappop(nextRaidQueue)[
                    1]  # gets the location tuple
                curLat = nextStop.latitude
                curLng = nextStop.longitude
                time.sleep(1)
                lastRoundEggHatch = True
            else:
                # continue as usual
                log.info('main: Moving on with gym at %s' % route[i])
                curLat = route[i]['lat']
                curLng = route[i]['lng']
                # remove whitespaces that might be on either side...
                i += 1
                lastRoundEggHatch = False

            # store current position in file
            posfile = open(args.position_file + '.position', "w")
            posfile.write(str(curLat) + ", " + str(curLng))
            posfile.close()

            log.debug("main: next stop: %s, %s" % (str(curLat), str(curLng)))
            log.debug(
                'main: LastLat: %s, LastLng: %s, CurLat: %s, CurLng: %s' %
                (lastLat, lastLng, curLat, curLng))
            # get the distance from our current position (last) to the next gym (cur)
            distance = getDistanceOfTwoPointsInMeters(float(lastLat),
                                                      float(lastLng),
                                                      float(curLat),
                                                      float(curLng))
            log.info('main: Moving %s meters to the next position' % distance)
            delayUsed = 0
            if (args.speed == 0
                    or (args.max_distance and 0 < args.max_distance < distance)
                    or (lastLat == 0.0 and lastLng == 0.0)):
                log.info("main: Teleporting...")
                telnGeo.setLocation(curLat, curLng, 0)
                delayUsed = args.post_teleport_delay
                # Test for cooldown / teleported distance
                if args.cool_down_sleep:
                    if distance > 2500:
                        delayUsed = 30
                    elif distance > 5000:
                        delayUsed = 45
                    elif distance > 10000:
                        delayUsed = 60
                    log.info("Need more sleep after Teleport: %s seconds!" %
                             str(delayUsed))

                if 0 < args.walk_after_teleport_distance < distance:
                    toWalk = getDistanceOfTwoPointsInMeters(
                        float(curLat), float(curLng),
                        float(curLat) + 0.0001,
                        float(curLng) + 0.0001)
                    log.error("Walking a bit: %s" % str(toWalk))
                    time.sleep(0.3)
                    telnGeo.walkFromTo(curLat, curLng, curLat + 0.0001,
                                       curLng + 0.0001, 11)
                    log.debug("Walking back")
                    time.sleep(0.3)
                    telnGeo.walkFromTo(curLat + 0.0001, curLng + 0.0001,
                                       curLat, curLng, 11)
                    log.debug("Done walking")
            else:
                log.info("main: Walking...")
                telnGeo.walkFromTo(lastLat, lastLng, curLat, curLng,
                                   args.speed)
                delayUsed = args.post_walk_delay
            log.info("Sleeping %s" % str(delayUsed))
            time.sleep(delayUsed)

            # ok, we should be at the next gym, check for errors and stuff
            # TODO: improve errorhandling by checking results and trying again and again
            # not using continue to always take a new screenshot...
            log.debug("main: Acquiring lock")

            while sleep or not runWarningThreadEvent.isSet():
                time.sleep(0.1)
            windowLock.acquire()
            log.debug("main: Lock acquired")
            if not takeScreenshot():
                windowLock.release()
                continue

            if args.last_scanned:
                log.info('main: Set new scannedlocation in Database')
                dbWrapper.setScannedLocation(str(curLat), str(curLng),
                                             str(curTime))

            log.info(
                "main: Checking raidcount and copying raidscreen if raids present"
            )
            countOfRaids = pogoWindowManager.readRaidCircles(
                os.path.join(args.temp_path, 'screenshot.png'), 123)
            if countOfRaids == -1:
                # reopen raidtab and take screenshot...
                log.warning(
                    "main: Count present but no raid shown, reopening raidTab")
                reopenRaidTab()
                # tabOutAndInPogo()
                if not takeScreenshot():
                    windowLock.release()
                    continue
                countOfRaids = pogoWindowManager.readRaidCircles(
                    os.path.join(args.temp_path, 'screenshot.png'), 123)
            #    elif countOfRaids == 0:
            #        emptycount += 1
            #        if emptycount > 30:
            #            emptycount = 0
            #            log.error("Had 30 empty scans, restarting pogo")
            #            restartPogo()

            # not an elif since we may have gotten a new screenshot..
            #detectin weather
            if args.weather:
                weather = checkWeather(
                    os.path.join(args.temp_path, 'screenshot.png'))
                if weather[0]:
                    log.debug('Submit Weather')
                    dbWrapper.updateInsertWeather(curLat, curLng, weather[1],
                                                  curTime)
                else:
                    log.error('Weather could not detected')

            if countOfRaids > 0:
                log.debug(
                    "main: New und old Screenshoot are different - starting OCR"
                )
                log.debug("main: countOfRaids: %s" % str(countOfRaids))
                curTime = time.time()
                copyFileName = args.raidscreen_path + '/raidscreen_' + str(
                    curTime) + "_" + str(curLat) + "_" + str(
                        curLng) + "_" + str(countOfRaids) + '.png'
                log.debug('Copying file: ' + copyFileName)
                copyfile(os.path.join(args.temp_path, 'screenshot.png'),
                         copyFileName)
                os.remove(os.path.join(args.temp_path, 'screenshot.png'))

            log.debug("main: Releasing lock")
            windowLock.release()
示例#4
0
class Scanner:
    def __init__(self, dbMethod, dbIp, dbPort, dbUser, dbPassword, dbName, tempPath, unknownPath, timezone, hash):
        self.dbIp = dbIp
        self.dbPort = dbPort
        self.dbUser = dbUser
        self.dbPassword = dbPassword
        self.dbName = dbName
        self.tempPath = tempPath
        self.unknownPath = unknownPath
        self.timezone = timezone
        self.uniqueHash = hash
        self.dbMethod = dbMethod
        
        #new www service
        self.www_hash = 'www_hash'

        self.dbWrapper = DbWrapper(self.dbMethod, self.dbIp, self.dbPort, self.dbUser, self.dbPassword, self.dbName, self.timezone, self.uniqueHash)

        if not os.path.exists(self.tempPath):
            log.info('Temp directory created')
            os.makedirs(self.tempPath)

        if not os.path.exists(self.unknownPath):
            log.info('Unknow directory created')
            os.makedirs(self.unknownPath)
            
        if not os.path.exists(self.www_hash):
            log.info('www_hash directory created')
            os.makedirs(self.www_hash)

    def detectRaidTime(self, raidpic, hash, raidNo, radius):
        zero = datetime.datetime.now()
        unixnow =  time.mktime(zero.timetuple())
        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'detectRaidTime: Reading Raidtimer')
        height, width, channel = raidpic.shape
        raidtimer = raidpic[int(round(radius*2*0.03)+(2*radius)+(radius*2*0.265)):int(round(radius*2*0.03)+(2*radius)+(radius*2*0.43)), 0:width]
        raidtimer = cv2.resize(raidtimer, (0,0), fx=2, fy=2, interpolation=cv2.INTER_CUBIC)
        emptyRaidTempPath = os.path.join(self.tempPath, str(raidNo) + str(hash) + '_emptyraid.png')
        cv2.imwrite(emptyRaidTempPath, raidtimer)
        rt = Image.open(emptyRaidTempPath)
        gray = rt.convert('L')
        bw = gray.point(lambda x: 0 if x<200 else 255, '1')
        raidtimer = pytesseract.image_to_string(bw, config='--psm 6 --oem 3').replace(' ', '').replace('~','').replace('o','0').replace('O','0').replace('-','').replace('.',':').replace('U','0')
        #cleanup
        os.remove(emptyRaidTempPath)
        raidFound = len(raidtimer) > 0
        if raidFound:
            if ':' in raidtimer:
                log.info('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'detectRaidTime: found raidtimer %s' % raidtimer)
                hatchTime = self.getHatchTime(raidtimer, raidNo)

                if hatchTime:
                    log.info('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'detectRaidTime: Hatchtime %s' % str(hatchTime))
                    if hatchTime > unixnow + (60 * 60 * 2) or hatchTime < unixnow:
                        log.info('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'detectRaidTime: Hatchtime not logical')
                        return (raidFound, False, False, False)
                    #raidstart = getHatchTime(self, raidtimer) - self.timezone * (self.timezone*60*60)
                    raidstart = hatchTime #- (self.timezone * 60 * 60)
                    raidend = hatchTime + (int(args.raid_time) * 60) #- (self.timezone * 60 * 60)
                    #raidend = getHatchTime(self, raidtimer) + int(45*60) - (self.timezone*60*60)
                    log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'detectRaidTime: Start: ' + str(raidstart) + ' End: ' + str(raidend))
                    return (raidFound, True, raidstart, raidend)
                else:
                    return (raidFound, True, False, False)

            else:
                return (raidFound, False, '0', '0')
        else:
            return (raidFound, False, False, False)

    def detectRaidEndtimer(self, raidpic, hash, raidNo, radius):
        zero = datetime.datetime.now()
        unixnow =  time.mktime(zero.timetuple())
        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'detectRaidEndtimer: Reading Raidtimer')
        height, width, channel = raidpic.shape
        raidtimer = raidpic[int(round(radius*2*0.03)+(2*radius)+(radius*2*0.10)):int(round(radius*2*0.03)+(2*radius)+(radius*2*0.23)), 0:width]
        raidtimer = cv2.resize(raidtimer, (0,0), fx=3, fy=3, interpolation=cv2.INTER_CUBIC)
        emptyRaidTempPath = os.path.join(self.tempPath, str(raidNo) + str(hash) + '_endraid.png')
        cv2.imwrite(emptyRaidTempPath, raidtimer)
        rt = Image.open(emptyRaidTempPath)
        gray = rt.convert('L')
        bw = gray.point(lambda x: 0 if x<200 else 255, '1')


        raidtimer = pytesseract.image_to_string(bw, config='--psm 6 --c tessedit_char_whitelist=01234567890:').replace(' ', '').replace('~','').replace('o','0').replace('O','0').replace('"','').replace('-','').replace('.',':').replace('B','8').replace('A','4').replace('—','').replace('_','').replace("'","").replace('U','0')
        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'detectRaidEndtimer: Raid-End-Text: ' + str(raidtimer))
        
        

        os.remove(emptyRaidTempPath)
        raidEndFound = len(raidtimer) > 0

        if raidEndFound:
            if raidtimer.count(':') < 2 :
                if len(raidtimer) == 7:
                    raidtimer = '0:' + str(raidtimer[2:4]) + ':' + str(raidtimer[5:7])
                    log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'detectRaidEndtimer: Try to repair Endtime: %s' % str(raidtimer))
            if ':' in raidtimer:
                now = datetime.datetime.now()
                log.info('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'detectRaidEndtimer: found raidendtimer %s' % raidtimer)
                endTime = self.getEndTime(raidtimer, raidNo)
                if endTime:
                    log.info('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'detectRaidEndtimer: Endtime %s' % str(endTime))
                    if endTime > unixnow + (int(args.raid_time) * 60):
                        log.info('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'detectRaidEndtimer: Endtime not logical')
                        return (raidEndFound, False, False)
                    #raidstart = getHatchTime(self, raidtimer) - self.timezone * (self.timezone*60*60)
                    raidend = endTime  #- (self.timezone * 60 * 60)
                    #raidend = getHatchTime(self, raidtimer) + int(45*60) - (self.timezone*60*60)
                    return (raidEndFound, True, raidend)
                else:
                    return (raidEndFound, False, False)

            else:
                log.info('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'detectRaidEndtimer: no raidendtimer detected')
                return (raidEndFound, False, '0')
        else:
            return (raidEndFound, False, False)

    def detectRaidBoss(self, raidpic, lvl, hash, raidNo):
        foundmon = None
        monID = None
        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'Extracting Raidboss')
        picName = os.path.join(self.tempPath, str(hash) + '_raidboss' + str(raidNo) +'.jpg')
        #self.genCannyMonPic(raidpic, picName)
        cv2.imwrite(picName,raidpic)

        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'detectRaidBoss: Scanning Raidboss')
        monHash = None
        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'detectRaidBoss: Monhash: ' + str(monHash))

        if monHash is None:
            for file in glob.glob("mon_img/_mon_*_" + str(lvl) + ".png"):
                log.debug("Comparing to %s" % str(file))
                find_mon = mt_mon.mon_image_matching(file, picName, raidNo, hash)

                if foundmon is None or find_mon > foundmon[0]:
                    foundmon = find_mon, file
                    
                if foundmon and foundmon[0]>0.01:
                    monSplit = foundmon[1].split('_')
                    monID = monSplit[3]

            #we found the mon that's most likely to be the one that's in the crop
            log.info('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'detectRaidBoss: Found mon in mon_img: ' + str(monID))

        else:
            os.remove(picName)
            return monHash, picName

        if monID:
            #self.imageHash(picName, monID, False, 'mon-' + str(lvl), raidNo)
            os.remove(picName)
            return monID, picName

        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'No Mon found!')

        os.remove(picName)
        return False, picName

    def detectLevel(self, raidpic, hash, raidNo, radius):
        foundlvl = None
        lvl = None
        
        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'Scanning Level')
        height, width, channel = raidpic.shape
        raidlevel = raidpic[int(round(radius*2*0.03)+(2*radius)+(radius*2*0.43)):int(round(radius*2*0.03)+(2*radius)+(radius*2*0.68)), 0:width]
        raidlevel = cv2.resize(raidlevel, (0,0), fx=0.5, fy=0.5) 

        imgray = cv2.cvtColor(raidlevel, cv2.COLOR_BGR2GRAY)
        imgray = cv2.GaussianBlur(imgray, (9, 9), 2)
        ret, thresh = cv2.threshold(imgray, 220, 255,0)
        (_, contours, _) = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
        
        lvl = len(contours)-1
        
        if lvl >=1 and lvl <=5:
            
            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'detectLevel: found level %s' % str(lvl))
            return lvl
            
        log.info('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'detectLevel: could not find level')
        return None
            
    def checkDummy(self,raidpic, x1, x2, y1, y2, hash, raidNo, radius):
        foundgym = None
        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'checkDummy: Check for dummy Gym Image')
        
        template = ("mon_img/dummy_nearby.jpg")

        find_gym = mt.fort_image_matching(raidpic, template, True, 0.9, raidNo, hash, True, radius, x1, x2, y1, y2)
        
        if find_gym >= 0.9:
            return True
        return False

    def detectGym(self, raidpic, hash, raidNo, captureLat, captureLng, radius, monId = None):
        foundgym = None
        gymId = None
        x1=0.30
        x2=0.62
        y1=0.62
        y2=1.23

        foundMonCrops = False

        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'detectGym: Scanning Gym')


        #if gymHash is none, we haven't seen the gym yet, otherwise, gymHash == gymId we are looking for
        if monId:
            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'detectGym: Got Mon-ID for Gym-Detection %s' % monId)
            with open('monsspec.json') as f:
                data = json.load(f)

            if str(monId) in data:
                foundMonCrops = True
                crop = data[str(monId)]["Crop"]
                log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'detectGym: Found other Crops for Mon %s' % monId)
                log.debug(str(crop))
                x1 = crop['X1']
                x2 = crop['X2']
                y1 = crop['Y1']
                y2 = crop['Y2']

        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'detectGym: Cropsizes: x1:%s, x2:%s, y1:%s, y2:%s' % (str(x1), str(x2), str(y1), str(y2)))
            

        gymHashvalue = self.getImageHash(raidpic, True, raidNo, 'gym', x1, x2, y1, y2, radius)
        gymHash = self.imageHashExists(raidpic, True, 'gym', raidNo, x1, x2, y1, y2, radius)
            
        if gymHash is None:
            
            if self.checkDummy(raidpic, x1, x2, y1, y2, hash, raidNo, radius):
                log.info('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'detectGym: Found dummy gym pic')
                self.unknownfound(raidpic, 'unkgym', False, raidNo, hash, False, gymHashvalue, captureLat, captureLng)
                return 'dummy'
                
            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'detectGym: No Gym-Hash: found - searching')
            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'detectGym: Searching closest gyms')
            closestGymIds = self.dbWrapper.getNearGyms(captureLat, captureLng, hash, raidNo, str(args.gym_scan_distance))

            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'detectGym: Detecting Gym')
            for closegym in closestGymIds:

                for file in glob.glob("gym_img/_" + str(closegym[0]) + "_.jpg"):
                    find_gym = mt.fort_image_matching(raidpic, file, True, float(args.gym_detection_value), raidNo, hash, checkX=True, radius=radius, x1=x1, x2=x2, y1=y1, y2=y2)
                    log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'detectGym: Compare Gym-ID - ' + str(closegym[0]) + ' - Match: ' + str(find_gym))
                    if foundgym is None or find_gym > foundgym[0]:
                        foundgym = find_gym, file

                    if foundgym and foundgym[0]>=float(args.gym_detection_value):
                        #okay, we very likely found our gym
                        gymSplit = foundgym[1].split('_')
                        gymId = gymSplit[2]

        else:
            self.imageHash(raidpic, gymHash, True, 'gym', raidNo, x1, x2, y1, y2, radius)
            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'detectGym: Detected Gym-ID: ' + str(gymHash))
            return gymHash

        if gymId:
            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'detectGym: Detected Gym - Gym-ID: '+ str(gymId))
            gymHash = self.imageHash(raidpic, gymId, True, 'gym', raidNo, x1=x1, x2=x2, y1=y1, y2=y2, radius=radius)
            self.unknownfound(raidpic, 'gym', False, raidNo, hash, False, gymHashvalue, '0', '0')
            return gymId
        else:
            #we could not find the gym...
            self.unknownfound(raidpic, 'unkgym', False, raidNo, hash, False, gymHashvalue, captureLat, captureLng)
            return None

    def unknownfound(self, raidpic, type, zoom, raidNo, hash, captureTime, imageHash=0, lat=0, lng=0):
        
        if captureTime:
            text = datetime.datetime.fromtimestamp(float(captureTime))
            text = "Scanned: " + str(text.strftime("%Y-%m-%d %H:%M"))
            self.addTextToCrop(raidpic, text, True)
        
        raidpic = cv2.imread(raidpic)
        if imageHash:
            existFile = os.path.join(self.www_hash, str(type) + "_*_" + str(imageHash) +".jpg")
            if not glob.glob(existFile):
                cv2.imwrite(os.path.join(self.www_hash, str(type) + "_" + str(lat) + "_" + str(lng) + "_" + str(imageHash) +".jpg"), raidpic)
                log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'saveforweb: Write hash file for www: ' + str(type) + "_" + str(lat) + "_" + str(lng) + "_" + str(imageHash) +".jpg") 
            else:
                log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'saveforweb: Hash file for www already exists: ' + str(type) + "_" + str(lat) + "_" + str(lng) + "_" + str(imageHash) +".jpg") 
        else:
            cv2.imwrite(os.path.join(self.unknownPath, str(raidNo) + "_" + str(type) + "_" + str(lat) + "_" + str(lng) + "_" + str(time.time()) +  "_" + str(imageHash) +".jpg"), raidpic)
            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'unknownfound: Write unknown file: ' +  str(type) + "_" + str(lat) + "_" + str(lng) + "_" + str(time.time()) +".jpg")
        return True
        
    def addTextToCrop(self, picture, text, grayscale=False):
        from PIL import Image, ImageFont, ImageDraw
        img = Image.open(picture)
        draw = ImageDraw.Draw(img)
        font = ImageFont.truetype('font/arial.ttf', 10)
        x,y = 0,0
        
        w, h = font.getsize(text)
        draw.rectangle((x, y, x + img.size[0] , y + h + 1), fill='black')
        if grayscale:
            draw.text((x, y),text,(255),font=font)
        else:
            draw.text((x, y), text, (255,255,255), font=font)
        img.save(picture)
        
    def successfound(self, raidpic, type, gymId, raidNo, lvl, captureTime, mon=0):
        if not args.save_success:
            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'successfound: Saving submit raidpics is disable')
            return
        
        
        text = datetime.datetime.fromtimestamp(float(captureTime))
        text = "Scanned: " + str(text.strftime("%Y-%m-%d %H:%M"))
        self.addTextToCrop(raidpic, text)

        if not os.path.exists(args.successsave_path):
            log.info('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'successfound: Save directory created')
            os.makedirs(args.successsave_path)
           
        with open('gym_info.json') as f:
            data = json.load(f)
            
        gymname = 'unknown'
        latitude = '00'
        longitude = '00'
        
        if str(gymId) in data:
            gymname = data[str(gymId)]["name"].replace('/', '-').replace('\\','/')
            latitude = data[str(gymId)]["latitude"]
            longitude = data[str(gymId)]["longitude"]
            
        curTime = time.time()
        saveFileName = str(type) + "_" +  str(curTime) + "__LVL_" + str(lvl) + "__MON_" + str(mon) + "__LAT_"+ str(latitude) + "__LNG_" + str(longitude) + "__" + str(gymname) + "__" + str(gymId) + ".jpg"
        log.info('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'successfound: Filename: ' + str(saveFileName))
        
        copyfile(raidpic, os.path.join(args.successsave_path, str(saveFileName)))
        
        log.info('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'successfound: Raidcrop successfully saved')
    
    def decodeHashJson(self, hashJson, raidNo):
        data = json.loads(hashJson)
        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'Decoding Raid Hash Json')

        raidGym = data['gym']
        raidLvl = data["lvl"]
        raidMon = data["mon"]

        return raidGym, raidLvl, raidMon

    def encodeHashJson(self, gym, lvl, mon, raidNo):
        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'Encoding Raid Hash Json')
        hashJson = json.dumps({'gym': gym, 'lvl': lvl, 'mon': mon, 'lvl': lvl}, separators=(',',':'))
        return hashJson

    def cropImage(self, image, raidNo, radius):
        gray=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
        gray=cv2.GaussianBlur(gray, (7, 7), 2)
        output = image.copy()
        height, width, channel = output.shape
        output = output[0:height*2/3,0:width]
        image_cols, image_rows, _ = image.shape
        circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1, 20, param1=50,param2=30, minRadius=radius, maxRadius=radius)
        if circles is not None:
            circles = np.round(circles[0, :]).astype("int")
            for (x, y, r) in circles:
                        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'cropImage: Detect crop coordinates x: ' + str(x) +' y: ' + str(y) +' with radius: ' + str(r))
                        new_crop = output[y-r:y+r, x-r:x+r]
                        return new_crop
        return False

    def start_detect(self, filenameOfCrop, hash, raidNo, captureTime, captureLat, captureLng, orgFileName, radius):
        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'start_detect: Starting detection of crop')
        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'start_detect: Original Filename: ' + str(orgFileName))
        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'start_detect: Original Lat: ' + str(captureLat))
        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'start_detect: Original Lng: ' + str(captureLng))
        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'start_detect: Capture Time: ' + str(captureTime))
        if not os.path.isfile(filenameOfCrop):
            log.error('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'start_detect: File does not exist: %s'% str(filenameOfCrop))
            return

        monfound = False
        eggfound = False

        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'start_detect: Starting analysis of ID %s' % str(hash))

        img = cv2.imread(filenameOfCrop,3)

        raidhash = self.cropImage(img, raidNo, radius)

        raidhashPic = os.path.join(self.tempPath, str(hash) + "_raidhash" + str(raidNo) +".jpg")
        cv2.imwrite(raidhashPic, raidhash)
        
        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'start_detect: Generating Raidhash')
        genRaidHash = self.getImageHash(raidhashPic, False, raidNo, 'raid')

        #get (raidstart, raidend, raidtimer) as (timestamp, timestamp, human-readable hatch)
        raidtimer = self.detectRaidTime(img, hash, raidNo, radius)
        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'start_detect: Got raidtime %s' % (str(raidtimer)))
        

        #first item in tuple stands for raid present in crop or not
        if (not raidtimer[0]):
            #there is no raid, stop analysis of crop, abandon ship
            os.remove(filenameOfCrop)
            os.remove(raidhashPic)
            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'start_detect: Crop does not show a raid, stopping analysis')
            return False

        #second item is true for egg present, False for mon present
        eggfound = raidtimer[1]
        raidstart = raidtimer[2] #will be 0 if eggfound = False. We report a mon anyway
        raidend = raidtimer[3] #will be 0 if eggfound = False. We report a mon anyway

        if (not raidstart or not raidend):
            #there is no raid, stop analysis of crop, abandon ship
            os.remove(filenameOfCrop)
            os.remove(raidhashPic)
            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'start_detect: Crop does not show a valid time, stopping analysis')
            return False

        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'start_detect: Creating Hash overall')
        raidHash = self.imageHashExists(raidhashPic, False, 'raid', raidNo)
        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'start_detect: detectRaidHash: ' + str(raidHash))
        
        raidlevel = self.detectLevel(img, hash, raidNo, radius) #we need the raid level to make the possible set of mons smaller
        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'start_detect: Determined raidlevel to be %s' % (str(raidlevel)))

        if raidHash:
            raidHash_ = self.decodeHashJson(raidHash, raidNo)
            gym = raidHash_[0]
            lvl = raidHash_[1]
            mon = raidHash_[2]
            
            if lvl == raidlevel and raidlevel is not None:

                if not mon:
                    lvl = self.detectLevel(img, hash, raidNo, radius) #redetect level
                    log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'start_detect: Determined raidlevel to be %s' % (str(lvl)))
 
                    if lvl is None:
                        log.error('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'start_detect: Could not determine raidlevel. Filename of Crop: %s' %  (filenameOfCrop))
                        os.remove(filenameOfCrop)
                        os.remove(raidhashPic)
                        return True
                
                    log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'start_detect: Found Raidhash with an egg - fast submit')
                    log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'start_detect: Found egg level %s starting at %s and ending at %s. GymID: %s' % (lvl, raidstart, raidend, gym))
                    self.dbWrapper.submitRaid(str(gym), None, lvl, raidstart, raidend, 'EGG', raidNo, captureTime)
                else:
                    
                    raidend = self.detectRaidEndtimer(img, hash, raidNo, radius)
                    if raidend[1]:
                        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'start_detect: Found Raidhash with an mon and endtime - fast submit')
                        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'start_detect: Submitting mon. ID: %s, gymId: %s' % (str(mon), str(gym)))
                        self.dbWrapper.submitRaid(str(gym), mon, lvl, None, raidend[2], 'MON', raidNo, captureTime, True)
                    else:
                        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'start_detect: Found Raidhash with an mon - fast submit')
                        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'start_detect: Submitting mon. ID: %s, gymId: %s' % (str(mon), str(gym)))
                        self.dbWrapper.submitRaid(str(gym), mon, lvl, None, None, 'MON', raidNo, captureTime)
                    
                self.imageHash(raidhashPic, raidHash, False, 'raid', raidNo)
                os.remove(filenameOfCrop)
                os.remove(raidhashPic)
                log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'start_detect: Finished')
                return True
            else:
                log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'start_detect: detected Level not Hash Level')
            

        if raidlevel is None:
            log.error('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'start_detect: Could not determine raidlevel. Filename of Crop: %s' %  (filenameOfCrop))
            os.remove(filenameOfCrop)
            os.remove(raidhashPic)
            return True

        if eggfound:
            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'start_detect: Found the crop to contain an egg')
            eggId = eggIdsByLevel[int(raidlevel) - 1]

        if not eggfound:
            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'start_detect: Found the crop to contain a raidboss, lets see what boss it is')
            monFound = self.detectRaidBoss(img, raidlevel, hash, raidNo)
            if not monFound[0]:
                #we could not determine the mon... let's move the crop to unknown and stop analysing
                log.warning('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'start_detect: Could not determine mon in crop, aborting and moving crop to unknown')
                monUnkPic = os.path.join(self.tempPath, str(hash) + "_unkmon" + str(raidNo) +".jpg")
                cv2.imwrite(monUnkPic, img)
                self.unknownfound(monUnkPic, 'mon', False, raidNo, hash, captureTime, False, captureLat, captureLng)
                log.warning('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'start_detect: could not determine mon, aborting analysis')
                os.remove(raidhashPic)
                os.remove(monUnkPic)
                os.remove(filenameOfCrop)
                return True
            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'start_detect: Scanning Gym')
            gymId = self.detectGym(raidhashPic, hash, raidNo, captureLat, captureLng, radius, monFound[0])
            

        else:
            #let's get the gym we're likely scanning the image of
            gymId = self.detectGym(raidhashPic, hash, raidNo, captureLat, captureLng, radius)
            #gymId is either None for Gym not found or contains the gymId as String
            
        if gymId == 'dummy':
            log.warning('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'start_detect: determine dummy pic, aborting analysis')
            return True

        if gymId is None:
            #gym unknown...
            log.warning('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'start_detect: Could not determine gym, aborting analysis')
            os.remove(filenameOfCrop)
            os.remove(raidhashPic)
            log.debug("start_detect[crop %s]: finished" % str(raidNo))
            return True #return true since a raid is present, we just couldn't find the correct gym

        if eggfound:
            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'start_detect: Found egg level %s starting at %s and ending at %s. GymID: %s' % (raidlevel, raidstart, raidend, gymId))
            submitStatus = self.dbWrapper.submitRaid(str(gymId), None, raidlevel, raidstart, raidend, 'EGG', raidNo, captureTime)
            if submitStatus:
                self.successfound(filenameOfCrop, 'EGG', gymId, raidNo, raidlevel, captureTime)
            raidHashJson = self.encodeHashJson(gymId, raidlevel, False, raidNo)
            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'start_detect: Adding Raidhash to Database: ' + str(raidHashJson))
            self.imageHash(raidhashPic, raidHashJson, False, 'raid', raidNo)

        else:
            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'start_detect: Checking for Endtime')
            if not self.dbWrapper.readRaidEndtime(str(gymId), raidNo):
                log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'start_detect: No existing Egg found')
                raidend = self.detectRaidEndtimer(img, hash, raidNo, radius)
                if raidend[1]:
                    log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'start_detect: Submitting mon without egg. ID: %s, gymId: %s' % (str(monFound[0]), str(gymId)))
                    submitStatus = self.dbWrapper.submitRaid(str(gymId), monFound[0], raidlevel, None, raidend[2], 'MON', raidNo, captureTime, True)
                else:
                    log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'start_detect: Submitting mon without raidend. ID: %s, gymId: %s' % (str(monFound[0]), str(gymId)))
                    submitStatus = self.dbWrapper.submitRaid(str(gymId), monFound[0], raidlevel, None, None, 'MON', raidNo, captureTime)
            else:
                log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'start_detect: Submitting mon with previously reported endtime. ID: %s, gymId: %s' % (str(monFound[0]), str(gymId)))
                submitStatus = self.dbWrapper.submitRaid(str(gymId), monFound[0], raidlevel, None, None, 'MON', raidNo, captureTime)
                
            if submitStatus:
                self.successfound(filenameOfCrop, 'MON', gymId, raidNo, raidlevel, captureTime, str(monFound[0]))
            raidHashJson = self.encodeHashJson(gymId, raidlevel, monFound[0], raidNo)
            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'start_detect: Adding Raidhash to Database: ' + str(raidHashJson))
            self.imageHash(raidhashPic, raidHashJson, False, 'raid', raidNo)
            
        self.unknownfound(raidhashPic, 'raid', False, raidNo, hash, False, genRaidHash, '0', '0')

        os.remove(raidhashPic)
        os.remove(filenameOfCrop)

        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' +  'start_detect: Finished')
        return True


    def dhash(self, image, raidNo, hash_size = 8):
                # Grayscale and shrink the image in one step.
                
        h = str(imagehash.dhash(image))
        return h
        
        image = image.convert('L').resize(
            (hash_size + 1, hash_size),
            Image.ANTIALIAS,
        )
        pixels = list(image.getdata())
        # Compare adjacent pixels.
        difference = []
        for row in xrange(hash_size):
            for col in xrange(hash_size):
                pixel_left = image.getpixel((col, row))
                pixel_right = image.getpixel((col + 1, row))
                difference.append(pixel_left > pixel_right)
        # Convert the binary array to a hexadecimal string.
            decimal_value = 0
            hex_string = []
            for index, value in enumerate(difference):
                if value:
                    decimal_value += 2**(index % 8)
                if (index % 8) == 7:
                    hex_string.append(hex(decimal_value)[2:].rjust(2, '0'))
                    decimal_value = 0

        hashValue = ''.join(hex_string)
        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' +  'ImageHash: Generated Image Hash: ' + str(hashValue))
        return hashValue


    def imageHashExists(self, image, zoom, type, raidNo, x1=0.30, x2=0.62, y1=0.62, y2=1.23, radius=0, hashSize=8):
        image2 = cv2.imread(image,3)
        image2 = cv2.cvtColor(image2, cv2.COLOR_BGR2GRAY)
        if zoom:
            x1 = int(round(radius*2*0.03)+(radius*x1))
            x2 = int(round(radius*2*0.03)+(radius*x2))
            y1 = int(round(radius*2*0.03)+(radius*y1))
            y2 = int(round(radius*2*0.03)+(radius*y2))
            crop = image2[int(y1):int(y2),int(x1):int(x2)]
        else:
            crop = image2

        tempHash = os.path.join(self.tempPath, str(time.time()) + "_" + str(raidNo) + "temphash_check.jpg")
        cv2.imwrite(tempHash, crop)
        hashPic = Image.open(tempHash)
        imageHash = self.dhash(hashPic, raidNo)

        os.remove(tempHash)
        
        if type == 'raid':
            distance = 4
        else:
            distance = 4

        existHash = self.dbWrapper.checkForHash(str(imageHash), str(type), raidNo, distance)

        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'imageHashExists: Hash found: %s' % existHash[1])
        return existHash[1]

    def imageHash(self, image, id, zoom, type, raidNo, x1=0.30, x2=0.62, y1=0.62, y2=1.23, radius=0, hashSize=8):
        image2 = cv2.imread(image,3)
        image2 = cv2.cvtColor(image2, cv2.COLOR_BGR2GRAY)
        if zoom:
            x1 = int(round(radius*2*0.03)+(radius*x1))
            x2 = int(round(radius*2*0.03)+(radius*x2))
            y1 = int(round(radius*2*0.03)+(radius*y1))
            y2 = int(round(radius*2*0.03)+(radius*y2))
            crop = image2[int(y1):int(y2),int(x1):int(x2)]
        else:
            crop = image2

        tempHash = os.path.join(self.tempPath, str(time.time()) + "_" + str(raidNo) + "temphash_new.jpg")
        cv2.imwrite(tempHash, crop)
        hashPic = Image.open(tempHash)
        imageHash = self.dhash(hashPic, raidNo)

        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' +  'imageHash: ' + str(imageHash))

        os.remove(tempHash)
        
        if type == 'raid':
            distance = 4
        else:
            distance = 4
        
        existHash = self.dbWrapper.checkForHash(str(imageHash), str(type), raidNo, distance)
        if existHash[0]:
            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'imageHash: Hash already in Database: ' + str(existHash[2]) )
            self.dbWrapper.insertHash(str(existHash[2]), str(type), str(id), raidNo)
            return str(existHash[2])
        else:
            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'imageHash: Adding Hash to Database: '+ str(imageHash))
            self.dbWrapper.insertHash(str(imageHash), str(type), str(id), raidNo)
            return str(imageHash)

    def getImageHash(self, image, zoom, raidNo, type, x1=0.30, x2=0.62, y1=0.62, y2=1.23, radius=0, hashSize=8):
        image2 = cv2.imread(image,3)
        image2 = cv2.cvtColor(image2, cv2.COLOR_BGR2GRAY)
        if zoom:
            x1 = int(round(radius*2*0.03)+(radius*x1))
            x2 = int(round(radius*2*0.03)+(radius*x2))
            y1 = int(round(radius*2*0.03)+(radius*y1))
            y2 = int(round(radius*2*0.03)+(radius*y2))
            crop = image2[int(y1):int(y2),int(x1):int(x2)]
        else:
            crop = image2

        tempHash = os.path.join(self.tempPath, str(time.time()) + "_" + str(raidNo) + "temphash_new.jpg")
        cv2.imwrite(tempHash, crop)
        hashPic = Image.open(tempHash)
        imageHash = self.dhash(hashPic, raidNo)
        
        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' +  'getImageHash: ' + str(imageHash))
        os.remove(tempHash)
        
        if type == 'raid':
            distance = 4
        else:
            distance = 4
        
        existHash = self.dbWrapper.checkForHash(str(imageHash), str(type), raidNo, distance)
        if existHash[0]:
            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'getImageHash: Hash already in Database: ' + str(existHash[2]) )
            return str(existHash[2])
        else:
            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'getImageHash: Hash not in Database: '+ str(imageHash))
            return str(imageHash)

    def checkHourMin(self, hour_min):
        hour_min[0] = unicode(hour_min[0].replace('O','0').replace('o','0').replace('A','4'))
        hour_min[1] = unicode(hour_min[1].replace('O','0').replace('o','0').replace('A','4'))
        if (hour_min[0]).isnumeric()==True and (hour_min[1]).isnumeric()==True:
            return True, hour_min
        else:
            return False, hour_min

    def checkHourMinSec(self, hour_min_sec):
        hour_min_sec[0] = unicode(hour_min_sec[0].replace('O','0').replace('o','0').replace('A','4'))
        hour_min_sec[1] = unicode(hour_min_sec[1].replace('O','0').replace('o','0').replace('A','4'))
        hour_min_sec[2] = unicode(hour_min_sec[2].replace('O','0').replace('o','0').replace('A','4'))
        if (hour_min_sec[0]).isnumeric()==True and (hour_min_sec[1]).isnumeric()==True and (hour_min_sec[2]).isnumeric()==True:
            return True, hour_min_sec
        else:
            return False, hour_min_sec

    # returns UTC timestamp
    def getHatchTime(self,data, raidNo):
        zero = datetime.datetime.now().replace(hour=0,minute=0,second=0,microsecond=0)
        unix_zero =  time.mktime(zero.timetuple())
        hour_min_divider = data.find(':')
        if hour_min_divider is None or hour_min_divider == -1:
            return False

        #TODO: think about only one big fat regex noone wants to read lateron
        am_found = re.search(r'[a|A]\w+', data)
        pm_found = re.search(r'[p|P]\w+', data)
        hour_min = re.search(r'([\d]{1,2}:[\d]{1,2})', data)

        if hour_min is None:
            log.fatal('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ]' + 'getHatchTime: Could not locate a HH:MM')
            return False
        else:
            hour_min = hour_min.group(1).split(':')

        ret, hour_min = self.checkHourMin(hour_min)
        if not ret:
            return False

        if am_found:
            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'getHatchTime: Found AM')
            return int(unix_zero)+int(hour_min[0])*3600+int(hour_min[1])*60
        elif pm_found:
            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'getHatchTime: Found PM')
            if hour_min[0] == '12':
                return int(unix_zero)+int(hour_min[0])*3600+int(hour_min[1])*60
            else:
                return int(unix_zero)+(int(hour_min[0])+12)*3600+int(hour_min[1])*60
        else:
            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'getHatchTime: Found EU Time')
            return int(unix_zero)+int(hour_min[0])*3600+int(hour_min[1])*60

    def getEndTime(self, data, raidNo):
        zero = datetime.datetime.now()
        unix_zero =  time.mktime(zero.timetuple())
        hour_min_divider = data.find(':')
        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'getHatchTime: :Count: ' + str(data.count(':')))
        if data.count(':') < 2 :
            log.error('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +') ] ' + 'getHatchTime: Detect wrong Endtimer of Raid')
            return False
        if hour_min_divider != -1:
            data = data.replace('~','').replace('-','').replace(' ','')
            hour_min = data.split(':')
            ret, hour_min = self.checkHourMinSec(hour_min)
            if ret:
                return int(unix_zero)+int(hour_min[0])*3600+int(hour_min[1])*60+int(hour_min[2])
            else:
                return False
        else:
            return False
示例#5
0
    def copyMons(pogoasset):

        monList = []

        log.info('Processing Pokemon Matching....')
        with open('raidmons.json') as f:
            data = json.load(f)

        monImgPath = os.getcwd() + '/mon_img/'
        filePath = os.path.dirname(monImgPath)

        if not os.path.exists(filePath):
            log.info('mon_img directory created')
            os.makedirs(filePath)

        assetPath = pogoasset

        if not os.path.exists(assetPath):
            log.error('PogoAssets not found')
            exit(0)

        for file in glob.glob(monImgPath + "*mon*.png"):
            os.remove(file)

        for mons in data:
            for mon in mons['DexID']:
                lvl = mons['Level']
                if str(mon).find("_") > -1:
                    mon_split = str(mon).split("_")
                    mon = mon_split[0]
                    frmadd = mon_split[1]
                else:
                    frmadd = "00"

                mon = '{:03d}'.format(int(mon))
                monList.append(mon)

                monFile = monImgPath + '_mon_' + str(mon) + '_' + str(
                    lvl) + '.png'

                if not os.path.isfile(monFile):

                    monFileAsset = assetPath + '/pokemon_icons/pokemon_icon_' + str(
                        mon) + '_' + frmadd + '.png'

                    if not os.path.isfile(monFileAsset):
                        log.error('File ' + str(monFileAsset) + ' not found')
                        exit(0)

                    copyfile(monFileAsset, monFile)

                    image = Image.open(monFile)
                    image.convert("RGBA")
                    canvas = Image.new(
                        'RGBA', image.size,
                        (255, 255, 255, 255))  # Empty canvas colour (r,g,b,a)
                    canvas.paste(
                        image, mask=image
                    )  # Paste the image onto the canvas, using it's alpha channel as mask
                    canvas.save(monFile, format="PNG")

                    monAsset = cv2.imread(monFile, 3)
                    height, width, channels = monAsset.shape
                    monAsset = cv2.inRange(monAsset, np.array([240, 240, 240]),
                                           np.array([255, 255, 255]))
                    cv2.imwrite(monFile, monAsset)
                    crop = cv2.imread(monFile, 3)
                    crop = crop[0:int(height), 0:int((width / 10) * 10)]
                    kernel = np.ones((1, 1), np.uint8)
                    crop = cv2.erode(crop, kernel, iterations=1)
                    cv2.imwrite(monFile, crop)

        _monList = myList = ','.join(map(str, monList))
        dbWrapper = DbWrapper(str(args.db_method), str(args.dbip), args.dbport,
                              args.dbusername, args.dbpassword, args.dbname,
                              args.timezone)
        dbWrapper.deleteHashTable(_monList, 'mon')
示例#6
0
def main_thread():
    global nextRaidQueue
    global lastPogoRestart
    global telnMore
    global pogoWindowManager
    global sleep
    global runWarningThreadEvent
    global windowLock
    global screenWrapper
    global lastScreenshotTaken

    log.info("main: Starting TelnetGeo Client")
    telnGeo = TelnetGeo(str(args.tel_ip), args.tel_port,
                        str(args.tel_password), args.tel_timeout_command,
                        args.tel_timeout_socket)

    log.info("main: Starting dbWrapper")
    dbWrapper = DbWrapper(str(args.db_method), str(args.dbip), args.dbport,
                          args.dbusername, args.dbpassword, args.dbname,
                          args.timezone)
    updateRaidQueue(dbWrapper)
    lastRaidQueueUpdate = time.time()

    if lastPogoRestart is None:
        lastPogoRestart = time.time()

    route = getJsonRoute(args.file, args.gym_distance,
                         args.max_count_gym_sum_up_around_gym)

    log.info("main: Route to be taken: %s, amount of coords: %s" %
             (str(route), str(len(route))))
    log.info("main: Max_distance before teleporting: %s" % args.max_distance)
    log.info("main: Checking if screen is on and pogo is running")

    if not sleep:
        turnScreenOnAndStartPogo()

    emptycount = 0
    locationCount = 0
    while True:
        log.info("main: Next round")
        curLat = 0.0
        curLng = 0.0
        i = 0  # index in route
        failcount = 0
        lastRoundEggHatch = False

        # loop over gyms:
        # walk to next gym
        # get to raidscreen
        # take screenshot
        # check time to restart pogo

        # process the entire route, prioritize hatched eggs in every second round (if anything has hatched)
        while i < len(route):
            while sleep:
                time.sleep(1)
            curTime = time.time()
            # update the raid queue every 5mins...
            if (curTime - lastRaidQueueUpdate) >= (5 * 60):
                updateRaidQueue(dbWrapper)
                lastRaidQueueUpdate = curTime

            # Restart pogo every now and then...
            if args.restart_pogo > 0:
                #log.debug("main: Current time - lastPogoRestart: %s" % str(curTime - lastPogoRestart))
                # if curTime - lastPogoRestart >= (args.restart_pogo * 60):
                locationCount += 1
                if locationCount > args.restart_pogo:
                    log.error("scanned " + str(args.restart_pogo) +
                              " locations, restarting pogo")
                    restartPogo()
                    locationCount = 0

            # let's check for speed and weather warnings while we're walking/teleporting...
            runWarningThreadEvent.set()
            lastLat = curLat
            lastLng = curLng
            egghatchLocation = False
            log.debug(
                "main: Checking for raidqueue priority. Current time: %s, Current queue: %s"
                % (str(time.time()), str(nextRaidQueue)))
            # determine whether we move to the next gym or to the top of our priority queue
            if not lastRoundEggHatch and len(
                    nextRaidQueue) > 0 and nextRaidQueue[0][0] < time.time():
                # the topmost item in the queue lays in the past...
                log.info(
                    'main: An egg has hatched, get there asap. Location: %s' %
                    str(nextRaidQueue[0]))
                egghatchLocation = True
                nextStop = heapq.heappop(nextRaidQueue)[
                    1]  # gets the location tuple
                curLat = nextStop.latitude
                curLng = nextStop.longitude
                time.sleep(1)
                lastRoundEggHatch = True
            else:
                # continue as usual
                log.info('main: Moving on with gym at %s' % route[i])
                curLat = route[i]['lat']
                curLng = route[i]['lng']
                # remove whitespaces that might be on either side...
                i += 1
                lastRoundEggHatch = False

            log.debug("main: next stop: %s, %s" % (str(curLat), str(curLng)))
            log.debug(
                'main: LastLat: %s, LastLng: %s, CurLat: %s, CurLng: %s' %
                (lastLat, lastLng, curLat, curLng))
            # get the distance from our current position (last) to the next gym (cur)
            distance = getDistanceOfTwoPointsInMeters(float(lastLat),
                                                      float(lastLng),
                                                      float(curLat),
                                                      float(curLng))
            log.info('main: Moving %s meters to the next position' % distance)
            delayUsed = 0
            if (args.speed == 0 or (args.max_distance and args.max_distance > 0
                                    and distance > args.max_distance)
                    or (lastLat == 0.0 and lastLng == 0.0)):
                log.info("main: Teleporting...")
                telnGeo.setLocation(curLat, curLng, 0)
                delayUsed = args.post_teleport_delay
            else:
                log.info("main: Walking...")
                telnGeo.walkFromTo(lastLat, lastLng, curLat, curLng,
                                   args.speed)
                delayUsed = args.post_walk_delay
            time.sleep(delayUsed)

            # ok, we should be at the next gym, check for errors and stuff
            # TODO: improve errorhandling by checking results and trying again and again
            # not using continue to always take a new screenshot...
            log.debug("main: Clearing event, acquiring lock")
            runWarningThreadEvent.clear()
            windowLock.acquire()
            log.debug("main: Lock acquired")
            log.debug("main: Checking if pogo is running...")
            if not telnMore.isPogoTopmost():
                log.warning("main: Starting Pogo")
                startPogo(False)
                windowLock.release()
                continue

            while not getToRaidscreen(12):
                if failcount > 5:
                    log.fatal(
                        "main: failed to find raidscreen way too often. Exiting"
                    )
                    sys.exit(1)
                failcount += 1
                log.error(
                    "main: Failed to find the raidscreen multiple times in a row. Stopping pogo and taking a "
                    "break of 5 minutes")
                stopPogo()
                time.sleep(300)
                startPogo(False)
            failcount = 0

            # well... we are on the raidtab, but we want to reopen it every now and then, so screw it
            reopenedRaidTab = False
            # if not egghatchLocation and math.fmod(i, 30) == 0:
            #    log.warning("main: Closing and opening raidtab every 30 locations scanned... Doing so")
            #    reopenRaidTab()
            #    tabOutAndInPogo()
            #    screenWrapper.getScreenshot('screenshot.png')
            #    reopenedRaidTab = True

            if args.last_scanned:
                log.info('main: Set new scannedlocation in Database')
                dbWrapper.setScannedLocation(str(curLat), str(curLng),
                                             str(curTime))

            log.info(
                "main: Checking raidcount and copying raidscreen if raids present"
            )
            countOfRaids = pogoWindowManager.readRaidCircles(
                'screenshot.png', 123)
            if countOfRaids == -1 and not reopenedRaidTab:
                # reopen raidtab and take screenshot...
                log.warning(
                    "main: Count present but no raid shown, reopening raidTab")
                reopenRaidTab()
                tabOutAndInPogo()
                screenWrapper.getScreenshot('screenshot.png')
                countOfRaids = pogoWindowManager.readRaidCircles(
                    'screenshot.png', 123)
        #    elif countOfRaids == 0:
        #        emptycount += 1
        #        if emptycount > 30:
        #            emptycount = 0
        #            log.error("Had 30 empty scans, restarting pogo")
        #            restartPogo()
            log.debug("main: countOfRaids: %s" % str(countOfRaids))
            if countOfRaids > 0:
                curTime = time.time()
                copyfile(
                    'screenshot.png', args.raidscreen_path + '/raidscreen_' +
                    str(curTime) + "_" + str(curLat) + "_" + str(curLng) +
                    "_" + str(countOfRaids) + '.png')
            log.debug("main: Releasing lock")
            windowLock.release()
示例#7
0
    def copyMons(pogoasset):

        monList = []

        log.info('Processing Pokemon Matching....')
        with open('raidmons.json') as f:
            data = json.load(f)

        monImgPath = os.getcwd() + '/mon_img/'
        filePath = os.path.dirname(monImgPath)

        if not os.path.exists(filePath):
            log.info('mon_img directory created')
            os.makedirs(filePath)

        assetPath = pogoasset

        if not os.path.exists(assetPath):
            log.error('PogoAssets not found')
            exit(0)

        for file in glob.glob(monImgPath + "*mon*.png"):
            os.remove(file)

        for mons in data:
            for mon in mons['DexID']:
                lvl = mons['Level']
                if str(mon).find("_") > -1:
                    mon_split = str(mon).split("_")
                    mon = mon_split[0]
                    frmadd = mon_split[1]
                else:
                    frmadd = "00"

                mon = '{:03d}'.format(int(mon))
                monList.append(mon)

                monFile = monImgPath + '_mon_' + str(mon) + '_' + str(
                    lvl) + '.png'

                if not os.path.isfile(monFile):

                    monFileAsset = assetPath + '/pokemon_icons/pokemon_icon_' + str(
                        mon) + '_' + frmadd + '.png'

                    if not os.path.isfile(monFileAsset):
                        log.error('File ' + str(monFileAsset) + ' not found')
                        exit(0)

                    copyfile(monFileAsset, monFile)

                    image = Image.open(monFile)
                    image.convert("RGBA")
                    canvas = Image.new(
                        'RGBA', image.size,
                        (255, 255, 255, 255))  # Empty canvas colour (r,g,b,a)
                    canvas.paste(
                        image, mask=image
                    )  # Paste the image onto the canvas, using it's alpha channel as mask
                    canvas.save(monFile, format="PNG")

                    monAsset = cv2.imread(monFile, 3)
                    height, width, channels = monAsset.shape
                    monAsset = cv2.inRange(monAsset, np.array([240, 240, 240]),
                                           np.array([255, 255, 255]))
                    cv2.imwrite(monFile, monAsset)
                    crop = cv2.imread(monFile, 3)
                    crop = crop[0:int(height), 0:int((width / 10) * 10)]
                    kernel = np.ones((2, 2), np.uint8)
                    crop = cv2.erode(crop, kernel, iterations=1)
                    kernel = np.ones((3, 3), np.uint8)
                    crop = cv2.morphologyEx(crop, cv2.MORPH_CLOSE, kernel)

                    #gray = cv2.cvtColor(crop,cv2.COLOR_BGR2GRAY)
                    #_,thresh = cv2.threshold(gray,1,255,cv2.THRESH_BINARY_INV)
                    #contours = cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
                    #cnt = contours[0]
                    #x,y,w,h = cv2.boundingRect(cnt)
                    #crop = crop[y-1:y+h+1,x-1:x+w+1]
                    cv2.imwrite(monFile, crop)

        _monList = myList = '|'.join(map(str, monList))
        dbWrapper = DbWrapper(str(args.db_method), str(args.dbip), args.dbport,
                              args.dbusername, args.dbpassword, args.dbname,
                              args.timezone)
        dbWrapper.clearHashGyms(_monList)
示例#8
0
class Scanner:
    def __init__(self, dbMethod, dbIp, dbPort, dbUser, dbPassword, dbName,
                 tempPath, unknownPath, timezone, hash):
        self.dbIp = dbIp
        self.dbPort = dbPort
        self.dbUser = dbUser
        self.dbPassword = dbPassword
        self.dbName = dbName
        self.tempPath = tempPath
        self.unknownPath = unknownPath
        self.timezone = timezone
        self.uniqueHash = hash
        self.dbMethod = dbMethod

        self.dbWrapper = DbWrapper(self.dbMethod, self.dbIp, self.dbPort,
                                   self.dbUser, self.dbPassword, self.dbName,
                                   self.timezone, self.uniqueHash)

        if not os.path.exists(self.tempPath):
            log.info('Temp directory created')
            os.makedirs(self.tempPath)

        if not os.path.exists(self.unknownPath):
            log.info('Unknow directory created')
            os.makedirs(self.unknownPath)

    def detectRaidTime(self, raidpic, hash, raidNo):
        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                  ') ] ' + 'detectRaidTime: Reading Raidtimer')
        raidtimer = raidpic[200:230, 30:150]
        raidtimer = cv2.resize(raidtimer, (0, 0),
                               fx=2,
                               fy=2,
                               interpolation=cv2.INTER_CUBIC)
        emptyRaidTempPath = os.path.join(
            self.tempPath,
            str(raidNo) + str(hash) + '_emptyraid.png')
        cv2.imwrite(emptyRaidTempPath, raidtimer)
        rt = Image.open(emptyRaidTempPath)
        gray = rt.convert('L')
        bw = gray.point(lambda x: 0 if x < 200 else 255, '1')
        raidtimer = pytesseract.image_to_string(
            bw, config='--psm 6 --oem 3').replace(' ', '').replace(
                '~',
                '').replace('o',
                            '0').replace('O',
                                         '0').replace('-',
                                                      '').replace('.', ':')
        #log.debug(re.match(r'\d\d:\d\d[am|pm]*', raidtimer))
        #cleanup
        os.remove(emptyRaidTempPath)
        raidFound = len(raidtimer) > 0

        if raidFound:
            if ':' in raidtimer:
                log.info('[Crop: ' + str(raidNo) + ' (' +
                         str(self.uniqueHash) + ') ] ' +
                         'detectRaidTime: found raidtimer %s' % raidtimer)
                hatchTime = self.getHatchTime(raidtimer, hash)

                if hatchTime:
                    log.info('[Crop: ' + str(raidNo) + ' (' +
                             str(self.uniqueHash) + ') ] ' +
                             'detectRaidTime: Hatchtime %s' % str(hatchTime))
                    #raidstart = getHatchTime(self, raidtimer) - self.timezone * (self.timezone*60*60)
                    raidstart = hatchTime  #- (self.timezone * 60 * 60)
                    raidend = hatchTime + 45 * 60  #- (self.timezone * 60 * 60)
                    #raidend = getHatchTime(self, raidtimer) + int(45*60) - (self.timezone*60*60)
                    log.debug('[Crop: ' + str(raidNo) + ' (' +
                              str(self.uniqueHash) + ') ] ' +
                              'detectRaidTime: Start: ' + str(raidstart) +
                              ' End: ' + str(raidend))
                    return (raidFound, True, raidstart, raidend)
                else:
                    return (raidFound, True, False, False)

            else:
                return (raidFound, False, '0', '0')
        else:
            return (raidFound, False, False, False)

    def detectRaidEndtimer(self, raidpic, hash, raidNo):
        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                  ') ] ' + 'detectRaidEndtimer: Reading Raidtimer')
        raidtimer = raidpic[178:200, 45:130]
        raidtimer = cv2.resize(raidtimer, (0, 0),
                               fx=2,
                               fy=2,
                               interpolation=cv2.INTER_CUBIC)
        emptyRaidTempPath = os.path.join(
            self.tempPath,
            str(raidNo) + str(hash) + '_endraid.png')
        cv2.imwrite(emptyRaidTempPath, raidtimer)
        rt = Image.open(emptyRaidTempPath)
        gray = rt.convert('L')
        bw = gray.point(lambda x: 0 if x < 200 else 255, '1')

        raidtimer = pytesseract.image_to_string(
            bw, config='--psm 6 --oem 3').replace(' ', '').replace(
                '~', '').replace('o', '0').replace('O', '0').replace(
                    '-', '').replace('.', ':').replace('B', '8').replace(
                        'A', '4').replace('—', '')
        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                  ') ] ' + 'detectRaidEndtimer: Raid-End-Text: ' +
                  str(raidtimer))

        os.remove(emptyRaidTempPath)
        raidEndFound = len(raidtimer) > 0

        if raidEndFound:
            if ':' in raidtimer:
                now = datetime.datetime.now()
                log.info('[Crop: ' + str(raidNo) + ' (' +
                         str(self.uniqueHash) + ') ] ' +
                         'detectRaidEndtimer: found raidendtimer %s' %
                         raidtimer)
                endTime = self.getEndTime(raidtimer, hash)
                if endTime:
                    log.info('[Crop: ' + str(raidNo) + ' (' +
                             str(self.uniqueHash) + ') ] ' +
                             'detectRaidEndtimer: Endtime %s' % str(endTime))
                    #raidstart = getHatchTime(self, raidtimer) - self.timezone * (self.timezone*60*60)
                    raidend = endTime  #- (self.timezone * 60 * 60)
                    #raidend = getHatchTime(self, raidtimer) + int(45*60) - (self.timezone*60*60)
                    return (raidEndFound, True, raidend)
                else:
                    return (raidEndFound, False, False)

            else:
                log.info('[Crop: ' + str(raidNo) + ' (' +
                         str(self.uniqueHash) + ') ] ' +
                         'detectRaidEndtimer: no raidendtimer detected')
                return (raidEndFound, False, '0')
        else:
            return (raidEndFound, False, False)

    def detectRaidBoss(self, raidpic, lvl, hash, raidNo):
        foundmon = None
        monID = None
        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                  ') ] ' + 'Extracting Raidboss')
        lower = np.array([80, 60, 30], dtype="uint8")
        upper = np.array([110, 90, 70], dtype="uint8")
        kernel = np.ones((3, 3), np.uint8)
        kernel2 = np.ones((6, 6), np.uint8)
        raidMonZoom = cv2.resize(raidpic, (0, 0), fx=2, fy=2)
        mask = cv2.inRange(raidMonZoom, lower, upper)
        output = cv2.bitwise_and(raidMonZoom, raidMonZoom, mask=mask)
        monAsset = cv2.inRange(output, np.array([0, 0, 0]),
                               np.array([15, 15, 15]))
        monAsset = cv2.morphologyEx(monAsset, cv2.MORPH_CLOSE, kernel)
        monAsset = cv2.morphologyEx(monAsset, cv2.MORPH_OPEN, kernel2)

        picName = os.path.join(self.tempPath,
                               str(hash) + '_raidboss' + str(raidNo) + '.jpg')
        cv2.imwrite(picName, monAsset)

        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                  ') ] ' + 'detectRaidBoss: Scanning Raidboss')
        monHash = self.imageHashExists(
            os.path.join(self.tempPath,
                         str(hash) + '_raidboss' + str(raidNo) + '.jpg'),
            False, 'mon-' + str(lvl), raidNo)
        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                  ') ] ' + 'detectRaidBoss: Monhash: ' + str(monHash))

        if monHash is None:
            for file in glob.glob("mon_img/_mon_*_" + str(lvl) + ".png"):

                find_mon = mt.fort_image_matching(file, picName, False, 0.60,
                                                  raidNo, hash)

                if foundmon is None or find_mon > foundmon[0]:
                    foundmon = find_mon, file

                if foundmon and foundmon[0] > 0.60:
                    monSplit = foundmon[1].split('_')
                    monID = monSplit[3]

            #we found the mon that's most likely to be the one that's in the crop
            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                      ') ] ' + 'detectRaidBoss: Found mon in mon_img: ' +
                      str(monID))

        else:
            os.remove(picName)
            return monHash, monAsset

        if monID:
            self.imageHash(picName, monID, False, 'mon-' + str(lvl), raidNo)
            os.remove(picName)
            return monID, monAsset

        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                  ') ] ' + 'No Mon found!')

        os.remove(picName)
        return False, monAsset

    def detectLevel(self, raidpic, hash, raidNo):
        foundlvl = None
        lvl = None
        lvlTypes = [
            'mon_img/_raidlevel_5_.jpg', 'mon_img/_raidlevel_4_.jpg',
            'mon_img/_raidlevel_3_.jpg', 'mon_img/_raidlevel_2_.jpg',
            'mon_img/_raidlevel_1_.jpg'
        ]

        raidlevel = raidpic[230:260, 0:170]
        #raidlevel = cv2.resize(raidlevel, (0,0), fx=2, fy=2)

        cv2.imwrite(
            os.path.join(self.tempPath,
                         str(hash) + '_raidlevel' + str(raidNo) + '.jpg'),
            raidlevel)

        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                  ') ] ' + 'Scanning Level')
        for file in lvlTypes:
            find_lvl = mt.fort_image_matching(
                file,
                os.path.join(self.tempPath,
                             str(hash) + '_raidlevel' + str(raidNo) + '.jpg'),
                False, 0.7, raidNo, hash)

            if foundlvl is None or find_lvl > foundlvl[0]:
                foundlvl = find_lvl, file

            if not foundlvl is None:
                lvlSplit = foundlvl[1].split('_')
                lvl = lvlSplit[3]

        os.remove(
            os.path.join(self.tempPath,
                         str(hash) + '_raidlevel' + str(raidNo) + '.jpg'))

        if lvl:
            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                      ') ] ' + 'detectLevel: found level %s' % str(lvl))
            return lvl
        else:
            log.info('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                     ') ] ' + 'detectLevel: could not find level')
            return None

    def checkDummy(self, raidpic, x1, x2, y1, y2, hash, raidNo):

        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                  ') ] ' + 'checkDummy: Check for dummy Gym Image')

        img = cv2.imread(raidpic, 3)
        template = cv2.imread("mon_img/dummy_nearby.jpg", 3)
        crop = img[int(y1):int(y2), int(x1):int(x2)]

        result = cv2.matchTemplate(crop, template, cv2.TM_CCOEFF_NORMED)
        (_, maxVal, minLoc, maxLoc) = cv2.minMaxLoc(result)

        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                  ') ] ' + 'checkDummy: Match: ' + str(maxVal))

        if maxVal >= 0.90:
            return True
        return False

    def detectGym(self,
                  raidpic,
                  hash,
                  raidNo,
                  captureLat,
                  captureLng,
                  monId=None):
        foundgym = None
        gymId = None
        x1 = 25
        x2 = 50
        y1 = 50
        y2 = 80
        foundMonCrops = False

        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                  ') ] ' + 'detectGym: Scanning Gym')

        #if gymHash is none, we haven't seen the gym yet, otherwise, gymHash == gymId we are looking for
        if monId:
            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                      ') ] ' +
                      'detectGym: Got Mon-ID for Gym-Detection %s' % monId)
            with open('monsspec.json') as f:
                data = json.load(f)

            if str(monId) in data:
                foundMonCrops = True
                crop = data[str(monId)]["Crop"]
                log.debug('[Crop: ' + str(raidNo) + ' (' +
                          str(self.uniqueHash) + ') ] ' +
                          'detectGym: Found other Crops for Mon %s' % monId)
                log.debug(str(crop))
                x1 = crop['X1']
                x2 = crop['X2']
                y1 = crop['Y1']
                y2 = crop['Y2']

        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                  ') ] ' + 'detectGym: Cropsizes: x1:%s, x2:%s, y1:%s, y2:%s' %
                  (str(x1), str(x2), str(y1), str(y2)))

        if self.checkDummy(raidpic, x1, x2, y1, y2, hash, raidNo):
            log.info('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                     ') ] ' + 'detectGym: Found dummy gym pic')
            return None

        gymHash = self.imageHashExists(raidpic, True, 'gym', raidNo, x1, x2,
                                       y1, y2)

        if gymHash is None:

            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                      ') ] ' + 'detectGym: No Gym-Hash: found - searching')
            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                      ') ] ' + 'detectGym: Searching closest gyms')
            closestGymIds = self.dbWrapper.getNearGyms(captureLat, captureLng,
                                                       hash, raidNo)

            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                      ') ] ' + 'detectGym: Detecting Gym')
            for closegym in closestGymIds:

                for file in glob.glob("gym_img/_" + str(closegym[0]) +
                                      "_.jpg"):
                    find_gym = mt.fort_image_matching(
                        raidpic, file, True, float(args.gym_detection_value),
                        raidNo, hash, x1, x2, y1, y2)
                    log.debug('[Crop: ' + str(raidNo) + ' (' +
                              str(self.uniqueHash) + ') ] ' +
                              'detectGym: Compare Gym-ID - ' +
                              str(closegym[0]) + ' - Match: ' + str(find_gym))
                    if foundgym is None or find_gym > foundgym[0]:
                        foundgym = find_gym, file

                    if foundgym and foundgym[0] >= float(
                            args.gym_detection_value):
                        #okay, we very likely found our gym
                        gymSplit = foundgym[1].split('_')
                        gymId = gymSplit[2]

        else:
            self.imageHash(raidpic, gymId, True, 'gym', raidNo, x1, x2, y1, y2)
            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                      ') ] ' + 'detectGym: Detected Gym-ID: ' + str(gymHash))
            return gymHash

        if gymId:
            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                      ') ] ' + 'detectGym: Found Gym - Gym-ID: ' + str(gymId))
            if foundMonCrops:
                log.debug('[Crop: ' + str(raidNo) + ' (' +
                          str(self.uniqueHash) + ') ] ' +
                          'detectGym: Dont hash Gym with spec. Mon Crops')
            else:
                self.imageHash(raidpic, gymId, True, 'gym', raidNo, x1, x2, y1,
                               y2)

            return gymId
        else:
            #we could not find the gym...
            return None

    def unknownfound(self,
                     raidpic,
                     type,
                     zoom,
                     raidNo,
                     hash,
                     captureTime,
                     imageHash=0,
                     lat=0,
                     lng=0):

        if captureTime:
            text = datetime.datetime.fromtimestamp(float(captureTime))
            text = "Scanned: " + str(text.strftime("%Y-%m-%d %H:%M"))
            self.addTextToCrop(raidpic, text)

        raidpic = cv2.imread(raidpic)
        cv2.imwrite(
            os.path.join(
                self.unknownPath,
                str(type) + "_" + str(lat) + "_" + str(lng) + "_" +
                str(time.time()) + "_" + str(imageHash) + ".jpg"), raidpic)
        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                  ') ] ' + 'unknownfound: Write unknown file: ' + str(type) +
                  "_" + str(lat) + "_" + str(lng) + "_" + str(time.time()) +
                  ".jpg")
        return True

    def addTextToCrop(self, picture, text):
        from PIL import Image, ImageFont, ImageDraw
        img = Image.open(picture)
        draw = ImageDraw.Draw(img)
        font = ImageFont.truetype('font/arial.ttf', 10)
        x, y = 0, 0

        w, h = font.getsize(text)
        draw.rectangle((x, y, x + img.size[0], y + h + 1), fill='black')
        draw.text((x, y), text, (255, 255, 255), font=font)
        img.save(picture)

    def successfound(self,
                     raidpic,
                     type,
                     gymId,
                     raidNo,
                     lvl,
                     captureTime,
                     mon=0):
        if not args.save_success:
            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                      ') ] ' +
                      'successfound: Saving submit raidpics is disable')
            return

        text = datetime.datetime.fromtimestamp(float(captureTime))
        text = "Scanned: " + str(text.strftime("%Y-%m-%d %H:%M"))
        self.addTextToCrop(raidpic, text)

        if not os.path.exists(args.successsave_path):
            log.info('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                     ') ] ' + 'successfound: Save directory created')
            os.makedirs(args.successsave_path)

        with open('gym_info.json') as f:
            data = json.load(f)

        gymname = 'unknown'
        latitude = '00'
        longitude = '00'

        if str(gymId) in data:
            gymname = data[str(gymId)]["name"].replace('/',
                                                       '-').replace('\\', '/')
            latitude = data[str(gymId)]["latitude"]
            longitude = data[str(gymId)]["longitude"]

        curTime = time.time()
        saveFileName = str(type) + "_" + str(curTime) + "__LVL_" + str(
            lvl) + "__MON_" + str(mon) + "__LAT_" + str(
                latitude) + "__LNG_" + str(longitude) + "__" + str(
                    gymname) + "__" + str(gymId) + ".jpg"
        log.info('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                 ') ] ' + 'successfound: Filename: ' + str(saveFileName))

        copyfile(raidpic, os.path.join(args.successsave_path,
                                       str(saveFileName)))

        log.info('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                 ') ] ' + 'successfound: Raidcrop successfully saved')

    def decodeHashJson(self, hashJson, raidNo):
        data = json.loads(hashJson)
        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                  ') ] ' + 'Decoding Raid Hash Json')

        raidGym = data['gym']
        raidLvl = data["lvl"]
        raidMon = data["mon"]

        return raidGym, raidLvl, raidMon

    def encodeHashJson(self, gym, lvl, mon, raidNo):
        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                  ') ] ' + 'Encoding Raid Hash Json')
        hashJson = json.dumps({
            'gym': gym,
            'lvl': lvl,
            'mon': mon,
            'lvl': lvl
        },
                              separators=(',', ':'))
        return hashJson

    def cropImage(self, image, raidNo):
        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
        output = image.copy()
        image_cols, image_rows, _ = image.shape
        circles = cv2.HoughCircles(gray,
                                   cv2.HOUGH_GRADIENT,
                                   2,
                                   image_cols,
                                   param1=100,
                                   param2=15,
                                   minRadius=71,
                                   maxRadius=71)
        if circles is not None:
            circles = np.round(circles[0, :]).astype("int")
            for (x, y, r) in circles:
                log.debug('[Crop: ' + str(raidNo) + ' (' +
                          str(self.uniqueHash) + ') ] ' +
                          'cropImage: Detect crop coordinates x: ' + str(x) +
                          ' y: ' + str(y) + ' with radius: ' + str(r))
                new_crop = output[y - r - 1:y + r + 1, x - r - 1:x + r + 1]
                return new_crop
        return False

    def resize(image, width=None, height=None, inter=cv2.INTER_AREA):
        dim = None
        (h, w) = image.shape[:2]
        if width is None and height is None:
            return image
        if width is None:
            r = height / float(h)
            dim = (int(w * r), height)
        else:
            r = width / float(w)
            dim = (width, int(h * r))
        resized = cv2.resize(image, dim, interpolation=inter)
        return resized

    def start_detect(self, filenameOfCrop, hash, raidNo, captureTime,
                     captureLat, captureLng, orgFileName):
        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                  ') ] ' + 'start_detect: Starting detection of crop')
        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                  ') ] ' + 'start_detect: Original Filename: ' +
                  str(orgFileName))
        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                  ') ] ' + 'start_detect: Original Lat: ' + str(captureLat))
        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                  ') ] ' + 'start_detect: Original Lng: ' + str(captureLng))
        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                  ') ] ' + 'start_detect: Capture Time: ' + str(captureTime))
        if not os.path.isfile(filenameOfCrop):
            log.error('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                      ') ] ' + 'start_detect: File does not exist: %s' %
                      str(filenameOfCrop))
            return

        monfound = False
        eggfound = False

        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                  ') ] ' +
                  'start_detect: Starting analysis of ID %s' % str(hash))

        img_temp = Image.open(filenameOfCrop)
        hpercent = (270 / float(img_temp.size[1]))
        wsize = int((float(img_temp.size[0]) * float(hpercent)))
        img_temp = img_temp.resize((wsize, 270), Image.ANTIALIAS)
        img_temp.save(filenameOfCrop)

        img = cv2.imread(filenameOfCrop)

        raidhash = img[0:175, 0:170]
        raidhash = self.cropImage(raidhash, raidNo)

        raidhashPic = os.path.join(
            self.tempPath,
            str(hash) + "_raidhash" + str(raidNo) + ".jpg")
        cv2.imwrite(raidhashPic, raidhash)

        #get (raidstart, raidend, raidtimer) as (timestamp, timestamp, human-readable hatch)
        raidtimer = self.detectRaidTime(img, hash, raidNo)
        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                  ') ] ' + 'start_detect: Got raidtime %s' % (str(raidtimer)))
        #first item in tuple stands for raid present in crop or not
        if (not raidtimer[0]):
            #there is no raid, stop analysis of crop, abandon ship
            os.remove(filenameOfCrop)
            os.remove(raidhashPic)
            log.debug(
                '[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                ') ] ' +
                'start_detect: Crop does not show a raid, stopping analysis')
            return False

        #second item is true for egg present, False for mon present
        eggfound = raidtimer[1]
        raidstart = raidtimer[
            2]  #will be 0 if eggfound = False. We report a mon anyway
        raidend = raidtimer[
            3]  #will be 0 if eggfound = False. We report a mon anyway

        if (not raidstart or not raidend):
            #there is no raid, stop analysis of crop, abandon ship
            os.remove(filenameOfCrop)
            os.remove(raidhashPic)
            log.debug(
                '[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                ') ] ' +
                'start_detect: Crop does not show a valid time, stopping analysis'
            )
            return False

        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                  ') ] ' + 'start_detect: Creating Hash overall')
        #raidHash = self.imageHashExists(raidhashPic, False, 'raid', raidNo)
        raidHash = False
        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                  ') ] ' + 'start_detect: detectRaidHash: ' + str(raidHash))

        if raidHash:
            raidHash = self.decodeHashJson(raidHash, raidNo)
            gym = raidHash[0]
            lvl = raidHash[1]
            mon = raidHash[2]

            #if lvl != raidlevel:
            #    log.debug('Scanned Raidlevel is different to hash - taking scanned level')
            #    lvl = raidlevel

            if not mon:
                log.debug(
                    '[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                    ') ] ' +
                    'start_detect: Found Raidhash with an egg - fast submit')
                log.debug(
                    '[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                    ') ] ' +
                    'start_detect: Found egg level %s starting at %s and ending at %s. GymID: %s'
                    % (lvl, raidstart, raidend, gym))
                self.dbWrapper.submitRaid(str(gym), None, lvl, raidstart,
                                          raidend, 'EGG', raidNo, captureTime)
            else:
                log.debug(
                    '[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                    ') ] ' +
                    'start_detect: Found Raidhash with an mon - fast submit')
                log.debug('[Crop: ' + str(raidNo) + ' (' +
                          str(self.uniqueHash) + ') ] ' +
                          'start_detect: Submitting mon. ID: %s, gymId: %s' %
                          (str(mon), str(gym)))
                self.dbWrapper.submitRaid(str(gym), mon, lvl, None, None,
                                          'MON', raidNo, captureTime)
            os.remove(filenameOfCrop)
            os.remove(raidhashPic)
            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                      ') ] ' + 'start_detect: Finished')
            return True

        raidlevel = self.detectLevel(
            img, hash, raidNo
        )  #we need the raid level to make the possible set of mons smaller
        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                  ') ] ' + 'start_detect: Determined raidlevel to be %s' %
                  (str(raidlevel)))

        if raidlevel is None:
            log.error(
                '[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                ') ] ' +
                'start_detect: Could not determine raidlevel. Filename of Crop: %s'
                % (filenameOfCrop))
            os.remove(filenameOfCrop)
            os.remove(raidhashPic)
            return True

        if eggfound:
            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                      ') ] ' +
                      'start_detect: Found the crop to contain an egg')
            eggId = eggIdsByLevel[int(raidlevel) - 1]

        if not eggfound:
            log.debug(
                '[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                ') ] ' +
                'start_detect: Found the crop to contain a raidboss, lets see what boss it is'
            )
            monFound = self.detectRaidBoss(img, raidlevel, hash, raidNo)
            if not monFound[0]:
                #we could not determine the mon... let's move the crop to unknown and stop analysing
                log.warning(
                    '[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                    ') ] ' +
                    'start_detect: Could not determine mon in crop, aborting and moving crop to unknown'
                )
                self.unknownfound(filenameOfCrop, 'mon', False, raidNo, hash,
                                  captureTime, False, captureLat, captureLng)
                log.warning(
                    '[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                    ') ] ' +
                    'start_detect: could not determine mon, aborting analysis')
                os.remove(raidhashPic)
                os.remove(filenameOfCrop)
                return True
            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                      ') ] ' + 'start_detect: Scanning Gym')
            gymId = self.detectGym(raidhashPic, hash, raidNo, captureLat,
                                   captureLng, monFound[0])

        else:
            #let's get the gym we're likely scanning the image of
            gymId = self.detectGym(raidhashPic, hash, raidNo, captureLat,
                                   captureLng)
            #gymId is either None for Gym not found or contains the gymId as String

        if gymId is None:
            #gym unknown...
            log.warning(
                '[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                ') ] ' +
                'start_detect: Could not determine gym, aborting analysis')
            gymhash = self.getImageHash(raidhashPic,
                                        True,
                                        raidNo,
                                        x1=25,
                                        x2=50,
                                        y1=50,
                                        y2=80)
            self.unknownfound(filenameOfCrop, 'gym', False, raidNo, hash,
                              captureTime, False, captureLat, captureLng)
            self.unknownfound(raidhashPic, 'gym_crop', False, raidNo, hash,
                              False, gymhash, captureLat, captureLng)
            os.remove(filenameOfCrop)
            os.remove(raidhashPic)
            log.debug("start_detect[crop %s]: finished" % str(raidNo))
            return True  #return true since a raid is present, we just couldn't find the correct gym

        if eggfound:
            log.debug(
                '[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                ') ] ' +
                'start_detect: Found egg level %s starting at %s and ending at %s. GymID: %s'
                % (raidlevel, raidstart, raidend, gymId))
            submitStatus = self.dbWrapper.submitRaid(str(gymId), None,
                                                     raidlevel, raidstart,
                                                     raidend, 'EGG', raidNo,
                                                     captureTime)
            if submitStatus:
                self.successfound(filenameOfCrop, 'EGG', gymId, raidNo,
                                  raidlevel, captureTime)
            raidHashJson = self.encodeHashJson(gymId, raidlevel, False, raidNo)
            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                      ') ] ' + 'start_detect: Adding Raidhash to Database')
            #self.imageHash(raidhashPic, raidHashJson, False, 'raid', raidNo)

        else:
            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                      ') ] ' + 'start_detect: Checking for Endtime')
            if not self.dbWrapper.readRaidEndtime(str(gymId), raidNo):
                log.debug('[Crop: ' + str(raidNo) + ' (' +
                          str(self.uniqueHash) + ') ] ' +
                          'start_detect: No existing Egg found')
                raidend = self.detectRaidEndtimer(img, hash, raidNo)
                if raidend[1]:
                    log.debug(
                        '[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                        ') ] ' +
                        'start_detect: Submitting mon without egg. ID: %s, gymId: %s'
                        % (str(monFound[0]), str(gymId)))
                    submitStatus = self.dbWrapper.submitRaid(
                        str(gymId), monFound[0], raidlevel, None, raidend[2],
                        'MON', raidNo, captureTime, True)
                else:
                    log.debug(
                        '[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                        ') ] ' +
                        'start_detect: Submitting mon without raidend. ID: %s, gymId: %s'
                        % (str(monFound[0]), str(gymId)))
                    submitStatus = self.dbWrapper.submitRaid(
                        str(gymId), monFound[0], raidlevel, None, None, 'MON',
                        raidNo, captureTime)
            else:
                log.debug(
                    '[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                    ') ] ' +
                    'start_detect: Submitting mon with previously reported endtime. ID: %s, gymId: %s'
                    % (str(monFound[0]), str(gymId)))
                submitStatus = self.dbWrapper.submitRaid(
                    str(gymId), monFound[0], raidlevel, None, None, 'MON',
                    raidNo, captureTime)

            if submitStatus:
                self.successfound(filenameOfCrop, 'MON', gymId, raidNo,
                                  raidlevel, captureTime, str(monFound[0]))

            raidHashJson = self.encodeHashJson(gymId, raidlevel, monFound[0],
                                               raidNo)
            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                      ') ] ' + 'start_detect: Adding Raidhash to Database')
            #self.imageHash(raidhashPic, raidHashJson, False, 'raid', raidNo)

        os.remove(raidhashPic)
        os.remove(filenameOfCrop)

        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                  ') ] ' + 'start_detect: Finished')
        return True

    def dhash(self, image, raidNo, hash_size=8):
        # Grayscale and shrink the image in one step.
        image = image.convert('L').resize(
            (hash_size + 1, hash_size),
            Image.ANTIALIAS,
        )
        pixels = list(image.getdata())
        # Compare adjacent pixels.
        difference = []
        for row in xrange(hash_size):
            for col in xrange(hash_size):
                pixel_left = image.getpixel((col, row))
                pixel_right = image.getpixel((col + 1, row))
                difference.append(pixel_left > pixel_right)
        # Convert the binary array to a hexadecimal string.
            decimal_value = 0
            hex_string = []
            for index, value in enumerate(difference):
                if value:
                    decimal_value += 2**(index % 8)
                if (index % 8) == 7:
                    hex_string.append(hex(decimal_value)[2:].rjust(2, '0'))
                    decimal_value = 0

        hashValue = ''.join(hex_string)
        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                  ') ] ' + 'ImageHash: Generated Image Hash: ' +
                  str(hashValue))
        return hashValue

    def imageHashExists(self,
                        image,
                        zoom,
                        type,
                        raidNo,
                        x1=25,
                        x2=50,
                        y1=50,
                        y2=80,
                        hashSize=8):
        image2 = cv2.imread(image, 3)
        image2 = cv2.cvtColor(image2, cv2.COLOR_BGR2GRAY)
        if zoom:
            crop = image2[int(y1):int(y2), int(x1):int(x2)]
        else:
            crop = image2

        tempHash = os.path.join(
            self.tempPath,
            str(time.time()) + "_" + str(raidNo) + "temphash_check.jpg")
        cv2.imwrite(tempHash, crop)
        hashPic = Image.open(tempHash)
        imageHash = self.dhash(hashPic, raidNo)

        os.remove(tempHash)

        existHash = self.dbWrapper.checkForHash(str(imageHash), str(type),
                                                raidNo)

        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                  ') ] ' + 'imageHashExists: Hash found: %s' % existHash[1])
        return existHash[1]

    def imageHash(self,
                  image,
                  id,
                  zoom,
                  type,
                  raidNo,
                  x1=25,
                  x2=50,
                  y1=50,
                  y2=80,
                  hashSize=8):
        image2 = cv2.imread(image, 3)
        image2 = cv2.cvtColor(image2, cv2.COLOR_BGR2GRAY)
        if zoom:
            crop = image2[int(y1):int(y2), int(x1):int(x2)]
        else:
            crop = image2

        tempHash = os.path.join(
            self.tempPath,
            str(time.time()) + "_" + str(raidNo) + "temphash_new.jpg")
        cv2.imwrite(tempHash, crop)
        hashPic = Image.open(tempHash)
        imageHash = self.dhash(hashPic, raidNo)

        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                  ') ] ' + 'imageHash: ' + str(imageHash))

        os.remove(tempHash)

        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                  ') ] ' + 'imageHash: Adding Hash to Database')

        self.dbWrapper.insertHash(str(imageHash), str(type), str(id), raidNo)

    def getImageHash(self,
                     image,
                     zoom,
                     raidNo,
                     x1=25,
                     x2=50,
                     y1=50,
                     y2=80,
                     hashSize=8):
        image2 = cv2.imread(image, 3)
        image2 = cv2.cvtColor(image2, cv2.COLOR_BGR2GRAY)
        if zoom:
            crop = image2[int(y1):int(y2), int(x1):int(x2)]
        else:
            crop = image2

        tempHash = os.path.join(
            self.tempPath,
            str(time.time()) + "_" + str(raidNo) + "temphash_new.jpg")
        cv2.imwrite(tempHash, crop)
        hashPic = Image.open(tempHash)
        imageHash = self.dhash(hashPic, raidNo)

        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                  ') ] ' + 'imageHash: ' + str(imageHash))

        os.remove(tempHash)

        return imageHash

    def checkHourMin(self, hour_min):
        hour_min[0] = unicode(hour_min[0].replace('O', '0').replace(
            'o', '0').replace('A', '4'))
        hour_min[1] = unicode(hour_min[1].replace('O', '0').replace(
            'o', '0').replace('A', '4'))
        if (hour_min[0]).isnumeric() == True and (
                hour_min[1]).isnumeric() == True:
            return True, hour_min
        else:
            return False, hour_min

    def checkHourMinSec(self, hour_min_sec):
        hour_min_sec[0] = unicode(hour_min_sec[0].replace('O', '0').replace(
            'o', '0').replace('A', '4'))
        hour_min_sec[1] = unicode(hour_min_sec[1].replace('O', '0').replace(
            'o', '0').replace('A', '4'))
        hour_min_sec[2] = unicode(hour_min_sec[2].replace('O', '0').replace(
            'o', '0').replace('A', '4'))
        if (hour_min_sec[0]).isnumeric() == True and (
                hour_min_sec[1]).isnumeric() == True and (
                    hour_min_sec[2]).isnumeric() == True:
            return True, hour_min_sec
        else:
            return False, hour_min_sec

    # returns UTC timestamp
    def getHatchTime(self, data, raidNo):
        zero = datetime.datetime.now().replace(hour=0,
                                               minute=0,
                                               second=0,
                                               microsecond=0)
        unix_zero = time.mktime(zero.timetuple())
        hour_min_divider = data.find(':')
        if hour_min_divider is None or hour_min_divider == -1:
            return False

        #TODO: think about only one big fat regex noone wants to read lateron
        am_found = re.search(r'[a|A]\w+', data)
        pm_found = re.search(r'[p|P]\w+', data)
        hour_min = re.search(r'([\d]{1,2}:[\d]{1,2})', data)

        if hour_min is None:
            log.fatal('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                      ') ]' + 'getHatchTime: Could not locate a HH:MM')
            return False
        else:
            hour_min = hour_min.group(1).split(':')

        ret, hour_min = self.checkHourMin(hour_min)
        if not ret:
            return False

        if am_found:
            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                      ') ] ' + 'getHatchTime: Found AM')
            return int(unix_zero) + int(hour_min[0]) * 3600 + int(
                hour_min[1]) * 60
        elif pm_found:
            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                      ') ] ' + 'getHatchTime: Found PM')
            if hour_min[0] == '12':
                return int(unix_zero) + int(hour_min[0]) * 3600 + int(
                    hour_min[1]) * 60
            else:
                return int(unix_zero) + (int(hour_min[0]) + 12) * 3600 + int(
                    hour_min[1]) * 60
        else:
            log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                      ') ] ' + 'getHatchTime: Found EU Time')
            return int(unix_zero) + int(hour_min[0]) * 3600 + int(
                hour_min[1]) * 60

    def getEndTime(self, data, raidNo):
        zero = datetime.datetime.now()
        unix_zero = time.mktime(zero.timetuple())
        hour_min_divider = data.find(':')
        log.debug('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                  ') ] ' + 'getHatchTime: :Count: ' + str(data.count(':')))
        if data.count(':') < 2:
            log.error('[Crop: ' + str(raidNo) + ' (' + str(self.uniqueHash) +
                      ') ] ' + 'getHatchTime: Detect wrong Endtimer of Raid')
            return False
        if hour_min_divider != -1:
            data = data.replace('~', '').replace('-', '').replace(' ', '')
            hour_min = data.split(':')
            ret, hour_min = self.checkHourMinSec(hour_min)
            if ret:
                return int(unix_zero) + int(hour_min[0]) * 3600 + int(
                    hour_min[1]) * 60 + int(hour_min[2])
            else:
                return False
        else:
            return False