def getArchivedImages(constants, cameras, startTimeDT, timeRangeSeconds, minusMinutes): """Get random images from HPWREN archive matching given constraints and optionally subtract them Args: constants (dict): "global" contants cameras (list): list of cameras startTimeDT (datetime): starting time of time range timeRangeSeconds (int): number of seconds in time range minusMinutes (int): number of desired minutes between images to subract Returns: Tuple containing camera name, current timestamp, filepath of regular image, and filepath of difference image """ if getArchivedImages.tmpDir == None: getArchivedImages.tmpDir = tempfile.TemporaryDirectory() logging.warning('TempDir %s', getArchivedImages.tmpDir.name) cameraID = cameras[int(len(cameras) * random.random())]['name'] timeDT = startTimeDT + datetime.timedelta(seconds=random.random() * timeRangeSeconds) if minusMinutes: prevTimeDT = timeDT + datetime.timedelta(seconds=-60 * minusMinutes) else: prevTimeDT = timeDT files = img_archive.getHpwrenImages(constants['googleServices'], settings, getArchivedImages.tmpDir.name, constants['camArchives'], cameraID, prevTimeDT, timeDT, minusMinutes or 1) # logging.warning('files %s', str(files)) if not files: return (None, None, None, None) if minusMinutes: if len(files) > 1: if files[0] >= files[ 1]: # files[0] is supposed to be earlier than files[1] logging.warning('unexpected file order %s', str(files)) for file in files: os.remove(file) return (None, None, None, None) imgDiffPath = genDiffImage(files[1], files[0], minusMinutes) os.remove(files[0]) # no longer needed parsedName = img_archive.parseFilename(files[1]) return (cameraID, parsedName['unixTime'], files[1], imgDiffPath) else: logging.warning('unexpected file count %s', str(files)) for file in files: os.remove(file) return (None, None, None, None) elif len(files) > 0: parsedName = img_archive.parseFilename(files[0]) return (cameraID, parsedName['unixTime'], files[0], files[0]) return (None, None, None, None)
def getNextImageFromDir(imgDirectory): """Gets the next image to check for smoke from given directory A variant of getNextImage() above but works with files already present on the locla filesystem. Args: imgDirectory (str): directory containing the files Returns: Tuple containing camera name, current timestamp, and filepath of the image """ if getNextImageFromDir.tmpDir == None: getNextImageFromDir.tmpDir = tempfile.TemporaryDirectory() logging.warning('TempDir %s', getNextImageFromDir.tmpDir.name) if not getNextImageFromDir.files: allFiles = os.listdir(imgDirectory) # filter out files with _Score suffix because they contain annotated scores # generated by drawFireBox() function below. getNextImageFromDir.files = list( filter(lambda x: '_Score.jpg' not in x, allFiles)) getNextImageFromDir.index += 1 if getNextImageFromDir.index < len(getNextImageFromDir.files): fileName = getNextImageFromDir.files[getNextImageFromDir.index] origPath = os.path.join(imgDirectory, fileName) destPath = os.path.join(getNextImageFromDir.tmpDir.name, fileName) shutil.copyfile(origPath, destPath) parsed = img_archive.parseFilename(fileName) if not parsed: # failed to parse, so skip to next image return getNextImageFromDir(imgDirectory) md5 = hashlib.md5(open(destPath, 'rb').read()).hexdigest() return (parsed['cameraID'], parsed['unixTime'], destPath, md5) logging.warning('Finished processing all images in directory. Exiting') exit(0)
def downloadClassImage(service, classLocations, imgClass, fileName, outputDirectory): """Download image file with given name from given image class from Fuego Cropping/Pictures/<imgClass> folder Args: service: Drive service (from getGoogleServices()['drive']) classLocations (dict): Dict of immgClass -> drive folder ID imgClass (str): image class (smoke, nonSmoke, etc..) fileName (str): Name of image file outputDirectory (str): Local directory where to store the file Returns: Local file system path to downloaded file """ localFilePath = os.path.join(outputDirectory, fileName) if os.path.isfile(localFilePath): return localFilePath # already downloaded, nothing to do # parse cameraID from fileName parsed = img_archive.parseFilename(fileName) cameraID = parsed['cameraID'] # find subdir for camera (dirID, dirName) = getDirForClassCamera(service, classLocations, imgClass, cameraID) # find file in camera subdir downloadFile(service, dirID, fileName, localFilePath) return localFilePath
def getCameraDir(service, cameraCache, fileName): parsed = img_archive.parseFilename(fileName) cameraID = parsed['cameraID'] dirID = cameraCache.get(cameraID) if not dirID: (dirID, dirName) = goog_helper.getDirForClassCamera(service, settings.IMG_CLASSES, 'smoke', cameraID) cameraCache[cameraID] = dirID return dirID
def capture_and_record(googleServices, dbManager, outputDir, camera_name): """requests current image from camera and uploads it to cloud Args: googleServices: Drive service (from getGoogleServices()) outputDir (str): folder path to download into camera_name (str): name of camera as recorded by alertwildfire Returns: imgPath: local path to downloaded object """ success = False retriesLeft = 5 pull1 = alertwildfire_API.get_individual_camera_info(camera_name) while (not success) and (retriesLeft > 0): imgPath = alertwildfire_API.request_current_image( outputDir, camera_name) pull2 = alertwildfire_API.get_individual_camera_info(camera_name) if pull1['position'] == pull1['position']: success = True else: pull1 = pull2 retriesLeft -= 1 #validate that it is new data md5 = hashlib.md5(open(imgPath, 'rb').read()).hexdigest() ###warning approximitly doubles image processing time #SQLcommand="select FileID from archive where md5='"+str(md5)+"'" #matches = dbManager.query(SQLcommand) #if len(matches)>0: # logging.warning('skipping %s, image has not changed since last upload.', camera_name) # return ### image_base_name = pathlib.PurePath(imgPath).name image_name_with_metadata = build_name_with_metadata(image_base_name, pull1) cloud_file_path = 'alert_archive/' + camera_name + '/' + image_name_with_metadata goog_helper.uploadBucketObject(googleServices["storage"], settings.archive_storage_bucket, cloud_file_path, imgPath) #add to Database timeStamp = img_archive.parseFilename(image_base_name)['unixTime'] img_archive.addImageToArchiveDb(dbManager, camera_name, timeStamp, 'gs://' + settings.archive_storage_bucket, cloud_file_path, pull1['position']['pan'], pull1['position']['tilt'], pull1['position']['zoom'], md5)
def genDiffImage(imgPath, earlierImgPath, minusMinutes): """Subtract the two given images and store result in new difference image file Args: imgPath (str): filepath of the current image (to subtract from) imgPath (str): filepath of the earlier image (value to subtract) minusMinutes (int): number of minutes separating subtracted images Returns: file path to the difference image """ imgA = Image.open(imgPath) imgB = Image.open(earlierImgPath) imgDiff = img_archive.diffImages(imgA, imgB) parsedName = img_archive.parseFilename(imgPath) parsedName['diffMinutes'] = minusMinutes imgDiffName = img_archive.repackFileName(parsedName) ppath = pathlib.PurePath(imgPath) imgDiffPath = os.path.join(str(ppath.parent), imgDiffName) imgDiff.save(imgDiffPath, format='JPEG') return imgDiffPath
def getTimeFromName(imgName): return img_archive.parseFilename(imgName)
def image_library(input_csv): cropped_image_list = np.loadtxt(input_csv, delimiter = ',', dtype = str) image_name_list = [] for image_name in cropped_image_list: image_name_list += [parseFilename(image_name[0])] return cropped_image_list, image_name_list
def main(): reqArgs = [ ["o", "outputDir", "local directory to save diff image segments"], ["i", "inputDir", "input local directory containing nonSmoke image segments"], ["m", "minusMinutes", "subtract images from given number of minutes ago"], ] optArgs = [ ["s", "startRow", "starting row"], ["e", "endRow", "ending row"], ] args = collect_args.collectArgs(reqArgs, optionalArgs=optArgs, parentParsers=[goog_helper.getParentParser()]) minusMinutes = int(args.minusMinutes) startRow = int(args.startRow) if args.startRow else 0 endRow = int(args.endRow) if args.endRow else 1e9 googleServices = goog_helper.getGoogleServices(settings, args) cookieJar = None camArchives = None cookieJar = img_archive.loginAjax() camArchives = img_archive.getHpwrenCameraArchives(googleServices['sheet'], settings) timeGapDelta = datetime.timedelta(seconds = 60*minusMinutes) skippedBadParse = [] skippedArchive = [] imageFileNames = sorted(os.listdir(args.inputDir)) rowIndex = -1 for fileName in imageFileNames: rowIndex += 1 if rowIndex < startRow: continue if rowIndex > endRow: print('Reached end row', rowIndex, endRow) break if (fileName[:3] == 'v2_') or (fileName[:3] == 'v3_'): continue # skip replicated files logging.warning('Processing row %d, file: %s', rowIndex, fileName) parsedName = img_archive.parseFilename(fileName) if (not parsedName) or parsedName['diffMinutes'] or ('minX' not in parsedName): logging.warning('Skipping file with unexpected parsed data: %s, %s', fileName, str(parsedName)) skippedBadParse.append((rowIndex, fileName, parsedName)) continue # skip files without crop info or with diff matchingCams = list(filter(lambda x: parsedName['cameraID'] == x['id'], camArchives)) if len(matchingCams) != 1: logging.warning('Skipping camera without archive: %d, %s', len(matchingCams), str(matchingCams)) skippedArchive.append((rowIndex, fileName, matchingCams)) continue archiveDirs = matchingCams[0]['dirs'] logging.warning('Found %s directories', archiveDirs) earlierImgPath = None dt = datetime.datetime.fromtimestamp(parsedName['unixTime']) dt -= timeGapDelta for dirName in archiveDirs: logging.warning('Searching for files in dir %s', dirName) imgPaths = img_archive.getFilesAjax(cookieJar, settings.downloadDir, parsedName['cameraID'], dirName, dt, dt, 1) if imgPaths: earlierImgPath = imgPaths[0] break # done if not earlierImgPath: logging.warning('Skipping image without prior image: %s, %s', str(dt), fileName) skippedArchive.append((rowIndex, fileName, dt)) continue logging.warning('Subtracting old image %s', earlierImgPath) earlierImg = Image.open(earlierImgPath) print('CR', (parsedName['minX'], parsedName['minY'], parsedName['maxX'], parsedName['maxY'])) croppedEarlyImg = earlierImg.crop((parsedName['minX'], parsedName['minY'], parsedName['maxX'], parsedName['maxY'])) imgOrig = Image.open(os.path.join(args.inputDir, fileName)) diffImg = img_archive.diffImages(imgOrig, croppedEarlyImg) parsedName['diffMinutes'] = minusMinutes diffImgPath = os.path.join(args.outputDir, img_archive.repackFileName(parsedName)) logging.warning('Saving new image %s', diffImgPath) diffImg.save(diffImgPath, format='JPEG') logging.warning('Skipped bad parse %d, %s', len(skippedBadParse), str(skippedBadParse)) logging.warning('Skipped images without archives %d, %s', len(skippedArchive), str(skippedArchive))
def main(): reqArgs = [ ["o", "outputDir", "local directory to save images segments"], ["i", "inputCsv", "csvfile with contents of Fuego Cropped Images"], ] optArgs = [ ["s", "startRow", "starting row"], ["e", "endRow", "ending row"], ["d", "display", "(optional) specify any value to display image and boxes"], ["x", "minDiffX", "(optional) override default minDiffX of 299"], ["y", "minDiffY", "(optional) override default minDiffY of 299"], ["a", "minArea", "(optional) override default throw away areas < 1/100 of 299x299"], ["t", "throwSize", "(optional) override default throw away size of 1000x1000"], ["g", "growRatio", "(optional) override default grow ratio of 1.2"], ["m", "minusMinutes", "(optional) subtract images from given number of minutes ago"], ] args = collect_args.collectArgs(reqArgs, optionalArgs=optArgs, parentParsers=[goog_helper.getParentParser()]) startRow = int(args.startRow) if args.startRow else 0 endRow = int(args.endRow) if args.endRow else 1e9 minDiffX = int(args.minDiffX) if args.minDiffX else 299 minDiffY = int(args.minDiffY) if args.minDiffY else 299 throwSize = int(args.throwSize) if args.throwSize else 1000 growRatio = float(args.growRatio) if args.growRatio else 1.2 minArea = int(args.minArea) if args.minArea else int(299*2.99) minusMinutes = int(args.minusMinutes) if args.minusMinutes else 0 googleServices = goog_helper.getGoogleServices(settings, args) camArchives = img_archive.getHpwrenCameraArchives(googleServices['sheet'], settings) if minusMinutes: timeGapDelta = datetime.timedelta(seconds = 60*minusMinutes) cameraCache = {} skippedTiny = [] skippedHuge = [] skippedArchive = [] with open(args.inputCsv) as csvFile: csvreader = csv.reader(csvFile) for (rowIndex, csvRow) in enumerate(csvreader): if rowIndex < startRow: continue if rowIndex > endRow: print('Reached end row', rowIndex, endRow) break [cropName, minX, minY, maxX, maxY, fileName] = csvRow[:6] minX = int(minX) minY = int(minY) maxX = int(maxX) maxY = int(maxY) oldCoords = (minX, minY, maxX, maxY) if ((maxX - minX) > throwSize) and ((maxY - minY) > throwSize): logging.warning('Skip large image: dx=%d, dy=%d, name=%s', maxX - minX, maxY - minY, fileName) skippedHuge.append((rowIndex, fileName, maxX - minX, maxY - minY)) continue if ((maxX - minX) * (maxY - minY)) < minArea: logging.warning('Skipping tiny image with area: %d, name=%s', (maxX - minX) * (maxY - minY), fileName) skippedTiny.append((rowIndex, fileName, (maxX - minX) * (maxY - minY))) continue # get base image from google drive that was uploaded by sort_images.py dirID = getCameraDir(googleServices['drive'], cameraCache, fileName)#-##REPLACE DEP. GDRIVE W HPREWN# localFilePath = os.path.join(settings.downloadDir, fileName)#sets a path for that image() not yet downloadedby this iteration print('local', localFilePath) if not os.path.isfile(localFilePath):# if file has not been downloaded by a previous iteration print('download', fileName) #+##REPLACE DEP. GDRIVE W HPREWN#nameParsed = img_archive.parseFilename(fileName)#parses file name into dictionary of parts name,unixtime,etc. #+##REPLACE DEP. GDRIVE W HPREWN#matchingCams = list(filter(lambda x: nameParsed['cameraID'] == x['id'], camArchives))#filter through camArchives for ids matching cameraid #+##REPLACE DEP. GDRIVE W HPREWN#if len(matchingCams) != 1:#if we cannot determine where the image will come from we cannot use the image #+##REPLACE DEP. GDRIVE W HPREWN# logging.warning('Skipping camera without archive: %d, %s', len(matchingCams), str(matchingCams)) #+##REPLACE DEP. GDRIVE W HPREWN# skippedArchive.append((rowIndex, fileName, matchingCams)) #+##REPLACE DEP. GDRIVE W HPREWN# continue #+##REPLACE DEP. GDRIVE W HPREWN#archiveDirs = matchingCams[0]['dirs'] #+##REPLACE DEP. GDRIVE W HPREWN#logging.warning('Found %s directories', archiveDirs) #+##REPLACE DEP. GDRIVE W HPREWN#time = datetime.datetime.fromtimestamp(nameParsed['unixTime']) #+##REPLACE DEP. GDRIVE W HPREWN#for dirName in archiveDirs:#search directories of camera for a time near #+##REPLACE DEP. GDRIVE W HPREWN# logging.warning('Searching for files in dir %s', dirName) #+##REPLACE DEP. GDRIVE W HPREWN# imgPaths = img_archive.downloadFilesHpwren(settings.downloadDir, nameParsed['cameraID'], dirName, time, time, 1, 0) #+##REPLACE DEP. GDRIVE W HPREWN# if imgPaths: #+##REPLACE DEP. GDRIVE W HPREWN# localFilePath = imgPaths[0] #+##REPLACE DEP. GDRIVE W HPREWN# break #+##REPLACE DEP. GDRIVE W HPREWN#if not imgPaths: #+##REPLACE DEP. GDRIVE W HPREWN# logging.warning('Skipping image not found: %s', fileName) #+##REPLACE DEP. GDRIVE W HPREWN# skippedArchive.append((rowIndex, fileName, time))#archive that images were skipped #+##REPLACE DEP. GDRIVE W HPREWN# continue goog_helper.downloadFile(googleServices['drive'], dirID, fileName, localFilePath)#-##REPLACE DEP. GDRIVE W HPREWN# imgOrig = Image.open(localFilePath)#opens image # if in subracted images mode, download an earlier image and subtract if minusMinutes: nameParsed = img_archive.parseFilename(fileName)#parses file name into dictionary of parts name,unixtime,etc. dt = datetime.datetime.fromtimestamp(nameParsed['unixTime']) dt -= timeGapDelta earlierImgPath = None files = img_archive.getHpwrenImages(googleServices, settings, settings.downloadDir, camArchives, nameParsed['cameraID'], dt, dt, 1) if files: earlierImgPath = files[0] else: logging.warning('Skipping image without prior image: %s, %s', str(dt), fileName) skippedArchive.append((rowIndex, fileName, dt)) continue logging.warning('Subtracting old image %s', earlierImgPath) earlierImg = Image.open(earlierImgPath) diffImg = img_archive.diffImages(imgOrig, earlierImg) # realImgOrig = imgOrig # is this useful? imgOrig = diffImg fileNameParts = os.path.splitext(fileName) fileName = str(fileNameParts[0]) + ('_Diff%d' % minusMinutes) + fileNameParts[1] # crop the full sized image to show just the smoke, but shifted and flipped # shifts and flips increase number of segments for training and also prevent overfitting by perturbing data cropCoords = getCropCoords((minX, minY, maxX, maxY), minDiffX, minDiffY, growRatio, (imgOrig.size[0], imgOrig.size[1])) for newCoords in cropCoords: # XXXX - save work if old=new? print('coords old,new', oldCoords, newCoords) imgNameNoExt = str(os.path.splitext(fileName)[0]) cropImgName = imgNameNoExt + '_Crop_' + 'x'.join(list(map(lambda x: str(x), newCoords))) + '.jpg' cropImgPath = os.path.join(args.outputDir, cropImgName) cropped_img = imgOrig.crop(newCoords) cropped_img.save(cropImgPath, format='JPEG') flipped_img = cropped_img.transpose(Image.FLIP_LEFT_RIGHT) flipImgName = imgNameNoExt + '_Crop_' + 'x'.join(list(map(lambda x: str(x), newCoords))) + '_Flip.jpg' flipImgPath = os.path.join(args.outputDir, flipImgName) flipped_img.save(flipImgPath, format='JPEG') print('Processed row: %s, file: %s' % (rowIndex, fileName)) if args.display: displayCoords = [oldCoords] + cropCoords displayImageWithScores(imgOrig, displayCoords) imageDisplay(imgOrig) logging.warning('Skipped tiny images %d, %s', len(skippedTiny), str(skippedTiny)) logging.warning('Skipped huge images %d, %s', len(skippedHuge), str(skippedHuge)) logging.warning('Skipped images without archives %d, %s', len(skippedArchive), str(skippedArchive))