def get_image_paths_and_snap_id(img1_id_in, img2_id_in, img_id_out): img1_dict_in = get_document_with_exception(str(img1_id_in), 'picture') img1_filename_in = img1_dict_in['filename'] img2_dict_in = get_document_with_exception(str(img2_id_in), 'picture') img2_filename_in = img2_dict_in['filename'] img_filename_out = build_picture_name(img_id_out) pic1_path_in = build_picture_path(picture_name=img1_filename_in, snap_id=img1_dict_in['snap_id']) pic2_path_in = build_picture_path(picture_name=img2_filename_in, snap_id=img1_dict_in['snap_id']) pic_path_out = build_picture_path(picture_name=img_filename_out, snap_id=img1_dict_in['snap_id']) return {'img1_path': pic1_path_in, 'img2_path': pic2_path_in, 'img_out_path': pic_path_out, 'img_out_filename': img_filename_out, 'snap_id': img1_dict_in['snap_id']}
def build_three_pictures(self, snap_id): pic_ids = [] for i in range(1, 3): pic_id = uuid.uuid4() filename = build_picture_name(pic_id) picture_path = build_picture_path(picture_name=filename, snap_id=snap_id) the_doc = { '_id': str(pic_id), 'snap_id': str(snap_id), 'uri': picture_path, 'filename': filename, 'source': 'whatever', 'type': 'picture' } save_generic(the_doc, 'picture') pic_ids.append(pic_id) # touch the picture file in the temp directory with open(picture_path, 'a'): os.utime(picture_path, None) if not item_exists(snap_id, 'snap'): snap_doc = {'_id': snap_id, 'type': 'snap', 'clean_up_files': True} save_generic(snap_doc, 'snap') return pic_ids
def distort_image_shepards_fixed(img_id_in, img_id_out, group_id, **kwargs): group_document = get_group_document(group_id) group_id = group_document['_id'] img_dict_in = find_picture(str(img_id_in)) img_filename_out = build_picture_name(img_id_out) pic_path_in = img_dict_in['uri'] pic_path_out = build_picture_path(picture_name=img_filename_out, snap_id=img_dict_in['snap_id']) command = "convert {0} -distort Shepards '300,110 350,140 600,310 650,340' {1}".format(pic_path_in, pic_path_out) os.system(command) img_dict_out = { '_id': str(img_id_out), 'type': 'picture', 'source': 'analysis', 'source_image_id': str(img_id_in), 'analysis_type': 'distort', 'group_id': group_id, 'snap_id': img_dict_in['snap_id'], 'filename': img_filename_out, 'uri': pic_path_out, 'created': str(datetime.datetime.now()) } save_picture_document(img_dict_out)
def send_mail(snap_id, group_id): """ Sends an email to users specified in the group, with all the images for a supplied snap """ group_document = get_group_document(group_id) if ( "email_recipients" in group_document and "send_email_contents" in group_document and group_document["email_recipients"] and group_document["send_email_contents"] ): pics_have_been_attached = False subject = "pictures from snap {0}".format(snap_id) recipients = group_document["email_recipients"].split(",") sender_addr = os.environ.get("MAIL_USERNAME") msg = Message(subject, sender=sender_addr, recipients=recipients) msg.body = "this is the image for snap id {0}\n\n".format(snap_id) pictures = search_generic(document_type="picture", args_dict={"snap_id": str(snap_id)}) picture_types = group_document["send_email_contents"].split(",") for pic_id in pictures.keys(): if pictures[pic_id]["source"] in picture_types: pic_name = build_picture_name(pic_id) pic_path = build_picture_path(picture_name=pic_name, snap_id=snap_id) file_contents = get_file_contents(pic_path) msg.attach(pic_name, "image/jpeg", file_contents) pics_have_been_attached = True # with current_app.open_resource(pic_path) as fp: # msg.attach(pic_name, "image/jpeg", fp.read()) # pics_have_been_attached = True if pics_have_been_attached: mail.send(msg)
def send_mail(snap_id, group_id): group_document = get_group_document(group_id) if ('email_recipients' in group_document and 'send_email_contents' in group_document and group_document['email_recipients'] and group_document['send_email_contents']): pics_have_been_attached = False subject = "pictures from snap {0}".format(snap_id) recipients = group_document['email_recipients'].split(',') sender_addr = os.environ.get('MAIL_USERNAME') msg = Message(subject, sender=sender_addr, recipients=recipients) msg.body = "this is the image for snap id {0}\n\n".format(snap_id) pictures = find_pictures({'snap_id': str(snap_id)}) picture_types = group_document['send_email_contents'].split(',') for pic_id in pictures.keys(): if pictures[pic_id]['source'] in picture_types: pic_name = build_picture_name(pic_id) pic_path = build_picture_path(picture_name=pic_name, snap_id=snap_id) with current_app.open_resource(pic_path) as fp: msg.attach(pic_name, "image/jpeg", fp.read()) pics_have_been_attached = True if pics_have_been_attached: mail.send(msg)
def distort_image_shepards(image_id_in=None, image_id_out=None, distortion_set_id=None): ''' Distorts an image using all the distortion pairs in a named distortion set It is necessary to call ImageMagick via command line to make this happen, no bindings in Pillow for this functionality :( Uses the Shepards algorithm for distortion ''' img_dict_in = get_document_with_exception(image_id_in, 'picture') group_id = img_dict_in['group_id'] img_filename_out = build_picture_name(image_id_out) pic_path_in = img_dict_in['uri'] pic_path_out = build_picture_path(picture_name=img_filename_out, snap_id=img_dict_in['snap_id']) command_string = build_command_string(distortion_set_id, pic_path_in, pic_path_out) os.system(command_string) img_dict_out = { '_id': str(image_id_out), 'type': 'picture', 'source': 'analysis', 'source_image_id': str(image_id_in), 'analysis_type': 'distort', 'group_id': group_id, 'snap_id': img_dict_in['snap_id'], 'filename': img_filename_out, 'uri': pic_path_out, 'created': str(datetime.datetime.now()) } save_generic(img_dict_out, 'picture')
def scale_image(img_id_in, img_id_out, group_id, **kwargs): # only works on black and white images for now # that should only be a problem for images that aren't of type 'L'. Add this test if 'scale_type' in kwargs: scale_type = kwargs['colorize_bicubic'] else: scale_type = 'colorize_bicubic' #TODO add a test to show that scale_type makes it in through kwargs group_document = get_group_document(group_id) group_id = group_document['_id'] img_dict_in = find_picture(str(img_id_in)) img_filename_in = img_dict_in['filename'] img_filename_out = build_picture_name(img_id_out) pic_path_in = img_dict_in['uri'] pic_path_out = build_picture_path(picture_name=img_filename_out, snap_id=img_dict_in['snap_id']) image_in = Image.open(pic_path_in) # scale image scale_method = Image.BICUBIC if scale_type and 'bilinear' in scale_type: scale_method == Image.BILINEAR if scale_type and 'antialias' in scale_type: scale_method == Image.ANTIALIAS width = current_app.config['STILL_IMAGE_WIDTH'] height = current_app.config['STILL_IMAGE_HEIGHT'] image_scaled = image_in.resize((width, height), scale_method) #TODO: below is terribly inefficient. After I look at PIL internals I should be able to do better #blur image if scale_type and 'blur' in scale_type: for i in range(1,10): image_scaled = image_scaled.filter(ImageFilter.BLUR) #colorize image if scale_type and 'colorize' in scale_type: (colorize_range_low, colorize_range_high) = ('#000080', '#FFD700') if 'colorize_range_low' in group_document and 'colorize_range_high' in group_document: colorize_range_low = group_document['colorize_range_low'] colorize_range_high = group_document['colorize_range_high'] image_colorized = ImageOps.colorize(image_scaled, colorize_range_low, colorize_range_high) image_colorized.save(pic_path_out) else: image_scaled.save(pic_path_out) img_dict_out = { '_id': str(img_id_out), 'type': 'picture', 'source': 'analysis', 'source_image_id': str(img_id_in), 'analysis_type': scale_type, 'group_id': group_id, 'snap_id': img_dict_in['snap_id'], 'filename': img_filename_out, 'uri': pic_path_out, 'created': str(datetime.datetime.now()) } save_picture_document(img_dict_out)
def merge_images(img1_primary_id_in, img1_alternate_id_in, img2_id_in, img_id_out, group_id): #deal with the fact that different merge methods require different parameters group_document = get_group_document(group_id) group_id = group_document['_id'] img1_id_in = img1_primary_id_in if picture_exists(img1_alternate_id_in): img1_id_in = img1_alternate_id_in if 'merge_type' in group_document: merge_type = group_document['merge_type'] if hasattr(ImageChops, merge_type): merge_method = getattr(ImageChops, merge_type) else: merge_method = getattr(ImageChops, 'screen') img1_dict_in = find_picture(str(img1_id_in)) img1_filename_in = img1_dict_in['filename'] img2_dict_in = find_picture(str(img2_id_in)) img2_filename_in = img2_dict_in['filename'] img_filename_out = build_picture_name(img_id_out) pic1_path_in = build_picture_path(picture_name=img1_filename_in, snap_id=img1_dict_in['snap_id']) pic2_path_in = build_picture_path(picture_name=img2_filename_in, snap_id=img1_dict_in['snap_id']) pic_path_out = build_picture_path(picture_name=img_filename_out, snap_id=img1_dict_in['snap_id']) image1_in = Image.open(pic1_path_in) image2_in = Image.open(pic2_path_in) image_out = merge_method(image1_in.convert('RGBA'), image2_in.convert('RGBA')) image_out.save(pic_path_out) img_dict_out = { '_id': str(img_id_out), 'type': 'picture', 'source': 'merge', 'source_image_id_1': str(img1_id_in), 'source_image_id_2': str(img2_id_in), 'merge_type': merge_type, 'group_id': group_id, 'snap_id': img1_dict_in['snap_id'], 'filename': img_filename_out, 'uri': pic_path_out, 'created': str(datetime.datetime.now()) } save_picture_document(img_dict_out)
def test_scale_image(self): class MockImage(object): pass group_id = uuid.uuid4() snap_id = uuid.uuid4() ans.save_picture_document = Mock() the_picture_path = build_picture_path(picture_name='whatever', snap_id=snap_id, create_directory=False) ans.find_picture = Mock(return_value={'filename': 'whatever', 'group_id': str(group_id), 'snap_id': str(snap_id), 'uri': the_picture_path } ) ans.get_group_document = Mock(return_value={ '_id': str(group_id), 'colorize_range_low': 1.1, 'colorize_range_high': 2.2 } ) the_mock_image = MockImage() Image.open = Mock(return_value=the_mock_image) MockImage.resize = Mock(return_value=the_mock_image) MockImage.save = Mock() ImageOps.colorize = Mock(return_value=the_mock_image) img_id_in = uuid.uuid4() img_id_out = uuid.uuid4() image_width = current_app.config['STILL_IMAGE_WIDTH'] image_height = current_app.config['STILL_IMAGE_HEIGHT'] img_filename_out = ans.build_picture_name(img_id_out) pic_path_out = ans.build_picture_path(picture_name=img_filename_out, snap_id=snap_id) test_img_dict_out = { '_id': str(img_id_out), 'type': 'picture', 'source': 'analysis', 'source_image_id': str(img_id_in), 'analysis_type': 'colorize_bicubic', 'group_id': str(group_id), 'snap_id': str(snap_id), 'filename': img_filename_out, 'uri': ANY, 'created': ANY } ans.scale_image(img_id_in, img_id_out, 'whatever') ans.get_group_document.assert_called_once_with('whatever') ans.find_picture.assert_called_once_with(str(img_id_in)) Image.open.assert_called_once_with(ans.build_picture_path(picture_name='whatever', snap_id=snap_id)) MockImage.resize.assert_called_once_with((image_width, image_height), Image.BICUBIC) ImageOps.colorize.assert_called_once_with(the_mock_image, 1.1, 2.2) MockImage.save.assert_called_once_with(pic_path_out) ans.save_picture_document.assert_called_once_with(test_img_dict_out)
def take_picam_still(snap_id, group_id, normal_exposure_pic_id, long_exposure_pic_id): ''' Top level method in the camera service for taking a still image via the picam (regular raspberry pi) camera. Also saves a picture record to the db Depending on settings and real time conditions, may cause a second, longer exposure to be taken ''' group_document = get_group_document(str(group_id)) retake_picam_pics_when_dark = get_retake_picam_pics_when_dark_setting(group_document) brightness_threshold = get_brightness_threshold(group_document) picture_name = build_picture_name(normal_exposure_pic_id) pic_path = build_picture_path(picture_name=picture_name, snap_id=snap_id) pic_dict = { '_id': str(normal_exposure_pic_id), 'type': 'picture', 'source': 'picam', 'exposure_type': 'standard', 'group_id': str(group_id), 'snap_id': str(snap_id), 'filename': picture_name, 'uri': pic_path, 'created': str(datetime.datetime.now()) } take_standard_exposure_picam_still(pic_path) save_picture(pic_dict) image_is_too_dark = check_if_image_is_too_dark(pic_path, brightness_threshold) if image_is_too_dark and retake_picam_pics_when_dark: picture_name = build_picture_name(long_exposure_pic_id) pic_path = build_picture_path(picture_name=picture_name, snap_id=snap_id) pic_dict2 = copy.deepcopy(pic_dict) pic_dict2['exposure_type'] = 'long' pic_dict2['_id'] = str(long_exposure_pic_id) pic_dict2['filename'] = picture_name pic_dict2['uri'] = pic_path pic_dict2['created'] = str(datetime.datetime.now()) take_long_exposure_picam_still(pic_path) save_picture(pic_dict2)
def edge_detect(img_id_in, alternate_img_id_in, auto_id, wide_id=None, tight_id=None): if picture_exists(alternate_img_id_in): img_id_in = alternate_img_id_in pic_dict_in = find_picture(img_id_in) image_in = cv2.imread(pic_dict_in['uri']) gray = cv2.cvtColor(image_in, cv2.COLOR_BGR2GRAY) blurred = cv2.GaussianBlur(gray, (3, 3), 0) # apply Canny edge detection using a wide threshold, tight # threshold, and automatically determined threshold auto = auto_canny(blurred) auto = auto_canny(image_in) auto_filename = build_picture_name(auto_id) auto_path_out = build_picture_path(picture_name=auto_filename, snap_id=pic_dict_in['snap_id']) cv2.imwrite(auto_path_out, auto) auto_dict_out = make_edge_picture_dict(pic_id=auto_id, pic_filename=auto_filename, pic_path=auto_path_out, snap_id=pic_dict_in['snap_id'], group_id=pic_dict_in['group_id'], source_pic_id=img_id_in, edge_detect_type='auto') save_picture_document(auto_dict_out) if wide_id: wide = cv2.Canny(blurred, 10, 200) wide_filename = build_picture_name(wide_id) wide_path_out = build_picture_path(picture_name=wide_filename, snap_id=pic_dict_in['snap_id']) cv2.imwrite(wide_path_out, wide) wide_dict_out = make_edge_picture_dict(pic_id=wide_id, pic_filename=wide_filename, pic_path=wide_path_out, snap_id=pic_dict_in['snap_id'], group_id=pic_dict_in['group_id'], source_pic_id=img_id_in, edge_detect_type='wide') save_picture_document(wide_dict_out) if tight_id: tight = cv2.Canny(blurred, 225, 250) tight_filename = build_picture_name(tight_id) tight_path_out = build_picture_path(picture_name=tight_filename, snap_id=pic_dict_in['snap_id']) cv2.imwrite(tight_path_out, tight) tight_dict_out = make_edge_picture_dict(pic_id=tight_id, pic_filename=tight_filename, pic_path=tight_path_out, snap_id=pic_dict_in['snap_id'], group_id=pic_dict_in['group_id'], source_pic_id=img_id_in, edge_detect_type='tight') save_picture_document(tight_dict_out)
def edge_detect_auto(img_id_in, pic_dict_in, auto_id): blurred = build_blurred_cv2_image(img_id_in) # apply Canny edge detection using an automatically determined threshold auto = auto_canny(blurred) auto_filename = build_picture_name(auto_id) auto_path_out = build_picture_path(picture_name=auto_filename, snap_id=pic_dict_in['snap_id']) cv2.imwrite(auto_path_out, auto) auto_dict_out = make_edge_picture_dict(pic_id=auto_id, pic_filename=auto_filename, pic_path=auto_path_out, snap_id=pic_dict_in['snap_id'], group_id=pic_dict_in['group_id'], source_pic_id=img_id_in, edge_detect_type='auto') save_generic(auto_dict_out, 'picture')
def edge_detect_with_canny_limits(img_id_in, pic_dict_in, new_id, limit_low, limit_high): blurred = build_blurred_cv2_image(img_id_in) # apply Canny edge detection using a custom threshold # TODO if limit_low or limit_high aren't positive ints, with high > low throw an error new_image = cv2.Canny(blurred, limit_low, limit_high) new_filename = build_picture_name(new_id) new_path_out = build_picture_path(picture_name=new_filename, snap_id=pic_dict_in['snap_id']) cv2.imwrite(new_path_out, new_image) new_dict_out = make_edge_picture_dict(pic_id=new_id, pic_filename=new_filename, pic_path=new_path_out, snap_id=pic_dict_in['snap_id'], group_id=pic_dict_in['group_id'], source_pic_id=img_id_in, edge_detect_type='custom:{0}-{1}'.format(limit_low, limit_high)) save_generic(new_dict_out, 'picture')
def edge_detect_with_canny_limits(img_id_in, pic_dict_in, new_id, limit_low, limit_high): blurred = build_blurred_cv2_image(img_id_in) # apply Canny edge detection using a custom threshold # TODO if limit_low or limit_high aren't positive ints, with high > low throw an error new_image = cv2.Canny(blurred, limit_low, limit_high) new_filename = build_picture_name(new_id) new_path_out = build_picture_path(picture_name=new_filename, snap_id=pic_dict_in['snap_id']) cv2.imwrite(new_path_out, new_image) new_dict_out = make_edge_picture_dict( pic_id=new_id, pic_filename=new_filename, pic_path=new_path_out, snap_id=pic_dict_in['snap_id'], group_id=pic_dict_in['group_id'], source_pic_id=img_id_in, edge_detect_type='custom:{0}-{1}'.format(limit_low, limit_high)) save_generic(new_dict_out, 'picture')
def scale_image(img_id_in, img_id_out, group_id, **kwargs): # only works on black and white images for now # that should only be a problem for images that aren't of type 'L'. Add this test group_document = get_group_document(group_id) if 'scale_type' in kwargs: scale_type = kwargs['scale_type'] else: if 'scale_type' in group_document: scale_type = group_document['scale_type'] else: scale_type = 'colorize_bicubic' group_id = group_document['_id'] img_dict_in = get_document_with_exception(str(img_id_in), 'picture') img_filename_in = img_dict_in['filename'] img_filename_out = build_picture_name(img_id_out) pic_path_in = img_dict_in['uri'] pic_path_out = build_picture_path(picture_name=img_filename_out, snap_id=img_dict_in['snap_id']) image_in = Image.open(pic_path_in) image_scaled = scale_image_subtask(scale_type, image_in) image_scaled = blur_image(scale_type, image_scaled) image_colorized = colorize_image(scale_type, group_document, image_scaled) image_colorized.save(pic_path_out) img_dict_out = { '_id': str(img_id_out), 'type': 'picture', 'source': 'analysis', 'source_image_id': str(img_id_in), 'analysis_type': scale_type, 'group_id': group_id, 'snap_id': img_dict_in['snap_id'], 'filename': img_filename_out, 'uri': pic_path_out, 'created': str(datetime.datetime.now()) } save_generic(img_dict_out, 'picture')
def build_three_pictures(self, snap_id): pic_ids = [] for i in range(1,3): pic_id = uuid.uuid4() filename = build_picture_name(pic_id) picture_path = build_picture_path(picture_name=filename, snap_id=snap_id) the_doc = { '_id': str(pic_id), 'snap_id': str(snap_id), 'uri': picture_path, 'filename': filename, 'source': 'whatever', 'type': 'picture' } save_picture_document(the_doc) pic_ids.append(pic_id) #touch the picture file in the temp directory with open(picture_path, 'a'): os.utime(picture_path, None) return pic_ids
def build_three_pictures(self, snap_id): pic_ids = [] for i in range(1, 3): pic_id = uuid.uuid4() filename = build_picture_name(pic_id) picture_path = build_picture_path(picture_name=filename, snap_id=snap_id) the_doc = { '_id': str(pic_id), 'snap_id': str(snap_id), 'uri': picture_path, 'filename': filename, 'source': 'whatever', 'type': 'picture' } save_picture_document(the_doc) pic_ids.append(pic_id) #touch the picture file in the temp directory with open(picture_path, 'a'): os.utime(picture_path, None) return pic_ids
def take_thermal_still(snap_id, group_id, pic_id): ''' Top level method in the camera service for taking a still image via the Lepton camera. Also saves a picture record to the db ''' picture_name = build_picture_name(pic_id) pic_path = build_picture_path(picture_name=picture_name, snap_id=snap_id) lepton = Lepton() lepton.take_still(pic_path=pic_path) pic_dict = { '_id': str(pic_id), 'type': 'picture', 'source': 'thermal', 'group_id': str(group_id), 'snap_id': str(snap_id), 'filename': picture_name, 'uri': pic_path, 'created': str(datetime.datetime.now()) } save_picture(pic_dict)
def test_build_picture_path_does_not_create_directory_if_requested(self): picture_name = 'whatever' snap_id = uuid.uuid4() assert not os.path.isdir(os.path.join(current_app.config['PICTURE_SAVE_DIRECTORY'], str(snap_id))) picture_path = ps.build_picture_path(picture_name=picture_name, snap_id=snap_id, create_directory=False) assert not os.path.isdir(os.path.join(current_app.config['PICTURE_SAVE_DIRECTORY'], str(snap_id)))