def setMod(self, height=5760, width=3840): """ Create the lensfunpy modifier """ equip = self.equipmentDict try: cam = equip['cam'] camMaker = equip.get('camMaker', '') camModel = equip.get('camModel', '') cam = self.db.find_cameras(camMaker, camModel, loose_search=False) if isinstance(cam, list): cam = cam[0] lens = str(equip.get('lens', None)) print(f'dict lens = {lens}') lens = self.db.find_lenses(cam, lens=lens, loose_search=True) if isinstance(lens, list): lens = lens[0] if lens is None: self.undist_coords = None return focalDistance = equip.get('focalDistance', 0.255) mod = lensfunpy.Modifier(lens, cam.crop_factor, width, height) # is lensfunpy.LensCalibTCA useful here? mod.initialize(equip['focalLength'], equip['apertureValue'], focalDistance, flags=lensfunpy.ModifyFlags.ALL) self.undist_coords = mod.apply_subpixel_geometry_distortion() except KeyError as e: print(f'error {e}') self.undist_coords = None
def testModifier(): db = lensfun.Database() cam = db.find_cameras(cam_maker, cam_model)[0] lens = db.find_lenses(cam, lens_maker, lens_model)[0] focal_length = 28.0 aperture = 1.4 distance = 10 width = 4256 height = 2832 mod = lensfun.Modifier(lens, cam.crop_factor, width, height) mod.initialize(focal_length, aperture, distance) undistCoords = mod.apply_geometry_distortion() assert undistCoords.shape[0] == height and undistCoords.shape[1] == width # check if coordinates were actually transformed y, x = np.mgrid[0:undistCoords.shape[0], 0:undistCoords.shape[1]] coords = np.dstack((x, y)) assert np.any(undistCoords != coords) undistCoords = mod.apply_subpixel_distortion() assert undistCoords.shape[0] == height and undistCoords.shape[1] == width assert np.any(undistCoords[:, :, 0] != coords) undistCoords = mod.apply_subpixel_geometry_distortion() assert undistCoords.shape[0] == height and undistCoords.shape[1] == width assert np.any(undistCoords[:, :, 0] != coords)
def getLensfunModifierFromExif(tags, width=None, height=None, lensfunDbObj=None, distance=10000, minAcceptedScore=MIN_ACCEPTED_SCORE): """ WARNING: Not setting width and height may produce surprising results for RAW files. If width and height are not set, then Composite:ImageSize is used. This tag contains the full RAW size, but many RAW decoders produce slightly cropped images. Therefore it may be necessary to first decode the RAW image and determine the width and height directly. :param dict tags: must contain 'EXIF:Model', 'EXIF:Make', 'Composite:LensID', 'EXIF:FocalLength', 'Composite:Aperture' and optionally 'Composite:ImageSize' if width,height is None """ cam, lens = findCameraAndLensFromExif(tags, lensfunDbObj, minAcceptedScore=minAcceptedScore) if width is None: width, height = tags['Composite:ImageSize'].split('x') width, height = int(width), int(height) mod = lensfunpy.Modifier(lens, cam.crop_factor, width, height) mod.initialize(tags['EXIF:FocalLength'], tags['Composite:Aperture'], distance=distance) return mod, cam, lens
def correct_photo(photo): '''Apply distortion correction''' #exif = get_exif_data(photo) #exif.get('Make') #exif.get('Model') #https://pypi.python.org/pypi/lensfunpy/0.12.0 cam_maker = "GoPro" cam_model = "HD2" #lens="HD2 & Compatibles" #Set output filename fileName, fileExtension = os.path.splitext(photo) undistortedImagePath = "".join([fileName, "_fixN", fileExtension]) #Query the Lensfun db for camera parameters db = lensfunpy.Database() cam = db.find_cameras(cam_maker, cam_model)[0] lens = db.find_lenses(cam)[0] #TODO: set camera parameters from exif data and lensfun focalLength = lens.min_focal #2.5 aperture = 2.8 distance = 0 im = cv2.imread(photo) height, width = im.shape[0], im.shape[1] mod = lensfunpy.Modifier(lens, cam.crop_factor, width, height) mod.initialize(focalLength, aperture, distance) undistCoords = mod.apply_geometry_distortion() #imUndistorted = cv2.remap(im, undistCoords, None, cv2.INTER_LANCZOS4) imUndistorted = cv2.remap(im, undistCoords, None, cv2.INTER_NEAREST) #cv2.imwrite(undistortedImagePath, imUndistorted,[int(cv2.IMWRITE_JPEG_QUALITY), 95]) #Change the order of colors to RGB for Pil (Pillow) cvRgbImage = cv2.cvtColor(imUndistorted, cv2.COLOR_BGR2RGB) pil_im = Image.fromarray(cvRgbImage) #update the metadata for the new files exif_dict = piexif.load(photo) #exif_dict = piexif.load(pil_im.info["exif"]) exif_dict["0th"][piexif.ImageIFD.Model] = "HD2 U" exif_dict["0th"][piexif.ImageIFD.Make] = "GoPro" exif_dict["Exif"][piexif.ExifIFD.FocalLength] = (250, 100) #it's actually 21.5 but exif barfs on float exif_dict["Exif"][piexif.ExifIFD.FocalLengthIn35mmFilm] = 21 exif_bytes = piexif.dump(exif_dict) #Write the file with metadata, 100% or 95% pil_im.save(undistortedImagePath, "jpeg", quality=100, exif=exif_bytes)
def lens_correction(image_to_lens_correct): height, width = image_to_lens_correct.shape[ 0], image_to_lens_correct.shape[1] db = lensfunpy.Database() cam = db.find_cameras(cam_maker, cam_model)[0] lens = db.find_lenses(cam, lens_maker, lens_model)[0] mod = lensfunpy.Modifier(lens, cam.crop_factor, width, height) mod.initialize(focal_length, apperture, 1) undist_coords = mod.apply_geometry_distortion() grey_image_undistorted = cv2.remap(image_to_lens_correct, undist_coords, None, cv2.INTER_LANCZOS4) return grey_image_undistorted
def getLensfunModifierFromParams(model, params, width, height): """ :param str model: 'ptlens', 'poly3', or 'poly5' :param list params: a list of 1, 2 or 3 parameters, depending on the model :param width: image width in pixels :param height: image height in pixels """ xml = lensfunXML(model, *params) db = lensfunpy.Database(xml=xml, load_common=False) cam = db.cameras[0] lens = db.lenses[0] mod = lensfunpy.Modifier(lens, cam.crop_factor, width, height) mod.initialize(1, 1) return mod
def _lensfun(filename): """Use the EXIF data an image calculate lens distortion corrections using the lensfun database Args: filename(str): The filename to open and extract EXIF data from. Returns: numpy.ndarray: A map suitable for use with cv2.remap() Raises: ValueError: The distortion corrections could not be calculated. """ exif = _exif(filename) if exif is None: raise ValueError('Unable to load EXIF data from {0}'.format(filename)) # open the lensfun db db = lensfunpy.Database() # see if our make/model is in the DB try: cam = db.find_cameras(exif['Make'], exif['Model'])[0] lens = db.find_lenses(cam)[0] except IndexError: raise ValueError('Unable to find a Lensfun entry for {0} {1}'.format( exif['Make'], exif['Model'])) # calculate the distortion corrections try: focal_length = float(exif['FocalLengthIn35mmFilm']) aperture = float(Fraction(*exif['FNumber'])) distance = int(exif['SubjectDistanceRange']) except KeyError as exc: raise ValueError( 'Unable to calculate lens distortion: EXIF data is missing item {0}' .format(exc)) mod = lensfunpy.Modifier(lens, cam.crop_factor, exif['ExifImageWidth'], exif['ExifImageHeight']) mod.initialize(focal_length, aperture, distance) return mod.apply_geometry_distortion()
def unskew(image_path, old): cam_maker = config["camera_maker"] cam_model = config["camera_model"] lens_maker = config["lens_maker"] lens_model = config["lens_model"] # TODO: this would have to be removed... if old: cam_model = 'Nikon D3300' lens_model = "Nikon AF-S DX Zoom-Nikkor 18-55mm f/3.5-5.6G VR" db = lensfunpy.Database() try: cam = db.find_cameras(cam_maker, cam_model)[0] except Exception: raise (Exception("Camera not found!")) try: lens = db.find_lenses(cam, lens_maker, lens_model)[0] except Exception: raise (Exception("Lens not found!")) # focal_length = lens.min_focal # TODO: read from exif focal_length = 30 aperture = 4.2 # TODO: what's the unit here? distance = 10 im = cv2.imread(image_path) height, width = im.shape[0], im.shape[1] mod = lensfunpy.Modifier(lens, cam.crop_factor, width, height) mod.initialize(focal_length, aperture, distance) undist_coords = mod.apply_geometry_distortion() unskewed = cv2.remap(im, undist_coords, None, cv2.INTER_LANCZOS4) return unskewed
def testVignettingCorrection(): cam_maker = 'NIKON CORPORATION' cam_model = 'NIKON D3S' lens_maker = 'Nikon' lens_model = 'Nikkor AF 20mm f/2.8D' focal_length = 20 aperture = 4 distance = 10 width = 4256 height = 2832 db = lensfun.Database() cam = db.find_cameras(cam_maker, cam_model)[0] lens = db.find_lenses(cam, lens_maker, lens_model)[0] mod = lensfun.Modifier(lens, cam.crop_factor, width, height) mod.initialize(focal_length, aperture, distance) img = np.zeros((height, width, 3), np.uint8) img[:] = 127 mod.apply_color_modification(img) assert img.mean() > 127
bottom_crop = 2800 NUMBER_OF_OYSTERS_HIGH = 8 NUMBER_OF_OYSTERS_WIDE = 2 # Note built for a max of 2 wide, if this needs to be changed for more than 2 code in the ROI section deeds to be edited """Actual Code Now""" """PRE-PROCESSING SECTION""" #Reading Image raw_image = cv2.imread('OysterImages/1 (27).JPG') grey_image = cv2.cvtColor(raw_image, cv2.COLOR_BGR2GRAY) height, width = grey_image.shape[0], grey_image.shape[1] #Lens Correction db = lensfunpy.Database() cam = db.find_cameras(cam_maker, cam_model)[0] lens = db.find_lenses(cam, lens_maker, lens_model)[0] mod = lensfunpy.Modifier(lens, cam.crop_factor, width, height) mod.initialize(focal_length, apperture, 1) undist_coords = mod.apply_geometry_distortion() grey_image_undistorted = cv2.remap(grey_image, undist_coords, None, cv2.INTER_LANCZOS4) #Blur grey_image_undistorted = cv2.GaussianBlur(grey_image_undistorted, (5, 5), 1) grey_image_undistorted = cv2.GaussianBlur(grey_image_undistorted, (5, 5), 1) #Rotation Correction if width > height: #if image is landscape (meaning oyster hinges are sideways) rows, cols = grey_image_undistorted.shape rotation_matrix = cv2.getRotationMatrix2D((cols / 2, rows / 2), 270, 1) grey_rotated_undistort_image = cv2.warpAffine(grey_image_undistorted, rotation_matrix,
def get_modifier(path, lfdb): """Construct a modifier from a Lensfun DB, based on EXIF data.""" (cam, lens) = get_cam_lens(path, lfdb) (width, height) = map(int, get_exif(path, 'ImageSize').split('x')) return lensfunpy.Modifier(lens, cam.crop_factor, width, height)