def testXmlFormatException(): try: lensfun.Database(xml='garbage') except lensfun.XMLFormatError: pass else: assert False
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 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 get_map_coords(path, distance=10): """Initialize a Lensfun modifier with a subject distance (in meters) and return its geometry map for undoing distortion.""" db = lensfunpy.Database() mod = get_modifier(path, db) focal_length = float(get_exif('FocalLength', path, numeric=True)) aperture = float(get_exif('Aperture', path, numeric=True)) mod.initialize(focal_length, aperture, distance) return mod.apply_geometry_distortion()
def testNewLensType(): # https://github.com/letmaik/lensfunpy/issues/10 # lensfun added new lens types which were not supported yet by lensfunpy. # This test accesses one such lens type and was raising an exception previously. db = lensfun.Database() cam = db.find_cameras('NIKON CORPORATION', 'NIKON D3S')[0] lenses = db.find_lenses(cam, 'Sigma', 'Sigma 8mm f/3.5 EX DG circular fisheye') if lenses: # newer lens, only run test if lens actually exists assert_equal(lenses[0].type, lensfun.LensType.FISHEYE_EQUISOLID) else: print('Skipping testNewLensType as lens not found')
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 testDeallocationBug(): db = lensfun.Database() cam = db.find_cameras(cam_maker, cam_model)[0] lens = db.find_lenses(cam, lens_maker, lens_model)[0] # By garbage collecting the database object, its queried objects # were deallocated as well, which is not what we want. # Now, all queried objects hold a reference to the Database object # they came from. This way, the Database object is only deallocated # when all queried objects were garbage collected. del db gc.collect() assert_equal(cam.maker.lower(), cam_maker.lower()) assert_equal(lens.maker.lower(), lens_maker.lower())
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 testDatabaseXMLLoading(): xml = """ <lensdatabase> <mount> <name>Nikon F AF</name> <compat>Nikon F</compat> <compat>Nikon F AI</compat> <compat>Nikon F AI-S</compat> <compat>M42</compat> <compat>T2</compat> <compat>Generic</compat> </mount> <camera> <maker>Nikon Corporation</maker> <maker lang="en">Nikon</maker> <model>Nikon D3S</model> <model lang="en">D3S</model> <mount>Nikon F AF</mount> <cropfactor>1.0</cropfactor> </camera> <lens> <maker>Nikon</maker> <model>Nikon AI-S Nikkor 28mm f/2.8</model> <model lang="en">Nikkor AI-S 28mm f/2.8</model> <mount>Nikon F AI-S</mount> <cropfactor>1</cropfactor> <calibration> <!-- Taken with Nikon D600 --> <distortion model="ptlens" focal="28" a="0.00929" b="-0.02155" c="0.0021"/> <tca model="poly3" focal="28" br="-0.0002306" vr="1.0006860" bb="0.0002350" vb="0.9995614"/> </calibration> </lens> </lensdatabase> """ db = lensfun.Database(xml=xml, load_common=False, load_bundled=False) assert_equal(len(db.cameras), 1) assert_equal(len(db.lenses), 1) assert_equal(len(db.mounts), 1) cam = db.find_cameras(cam_maker, cam_model)[0] lens = db.find_lenses(cam, lens_maker, lens_model)[0] assert_equal(cam.maker.lower(), cam_maker.lower()) assert_equal(cam.model.lower(), cam_model.lower()) assert_equal(lens.maker.lower(), lens_maker.lower()) assert_equal(lens.model.lower(), lens_model.lower())
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 testDatabaseLoading(): db = lensfun.Database() cams = db.find_cameras(cam_maker, cam_model) print(cams) assert_equal(len(cams), 1) cam = cams[0] assert_equal(cam.maker.lower(), cam_maker.lower()) assert_equal(cam.model.lower(), cam_model.lower()) assert len(str(cam)) > 0 lenses = db.find_lenses(cam, lens_maker, lens_model) assert_equal(len(lenses), 1) lens = lenses[0] assert_equal(lens.maker.lower(), lens_maker.lower()) assert len(str(lens)) > 0 assert_equal(lens.model.lower(), lens_model.lower())
def testDatabaseXMLLoading(): xml = """ <lensdatabase> <mount> <name>Nikon F AF</name> <compat>Nikon F</compat> <compat>Nikon F AI</compat> <compat>Nikon F AI-S</compat> <compat>M42</compat> <compat>T2</compat> <compat>Generic</compat> </mount> <camera> <maker>Nikon Corporation</maker> <maker lang="en">Nikon</maker> <model>Nikon D3S</model> <model lang="en">D3S</model> <mount>Nikon F AF</mount> <cropfactor>1.0</cropfactor> </camera> <lens> <maker>Nikon</maker> <model>Nikkor 28mm f/2.8D AF</model> <mount>Nikon F AF</mount> <cropfactor>1.0</cropfactor> <calibration> <distortion model="ptlens" focal="28" a="0" b="0.025773" c="-0.085777" /> </calibration> </lens> </lensdatabase> """ db = lensfun.Database(xml=xml, load_common=False, load_bundled=False) assert_equal(len(db.cameras), 1) assert_equal(len(db.lenses), 1) assert_equal(len(db.mounts), 1) cam = db.find_cameras(cam_maker, cam_model)[0] lens = db.find_lenses(cam, lens_maker, lens_model)[0] assert_equal(cam.maker.lower(), cam_maker.lower()) assert_equal(cam.model.lower(), cam_model.lower()) assert_equal(lens.maker.lower(), lens_maker.lower()) assert_equal(lens.model.lower(), lens_model.lower())
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 testDatabaseLoading(): db = lensfun.Database() cams = db.find_cameras(cam_maker, cam_model) assert_equal(len(cams), 1) cam = cams[0] assert_equal(cam.maker.lower(), cam_maker.lower()) assert_equal(cam.model.lower(), cam_model.lower()) assert len(str(cam)) > 0 lenses = db.find_lenses(cam, lens_maker, lens_model) assert_equal(len(lenses), 1) lens = lenses[0] assert_equal(lens.maker.lower(), lens_maker.lower()) assert len(str(lens)) > 0 if lensfun.lensfun_version >= (0, 3): # lens names were "streamlined" in lensfun 0.3 assert_equal(lens.model.lower(), u'nikon af nikkor 28mm f/2.8d') else: assert_equal(lens.model.lower(), lens_model.lower())
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
import lensfunpy cam_maker = 'Canon' cam_model = 'Canon EOS Rebel T5' mount = 'T-mount' lens_maker = 'Canon' lens_model = 'EFS 18-55mm Image Stabilizer' db = lensfunpy.Database() cam = db.find_cameras(cam_maker, cam_model)[0] lens = db.find_lenses(cam, lens_maker, lens_model, loose_search=True) print(cam) print(db.find_mount(cam.mount).compat) print(lens)
def list_lenses(): database = lensfunpy.Database() for lense in database.lenses: lense_string = "Maker: %s \t Model: %s" % (lense.maker, lense.model) click.echo(lense_string)
def list_cameras(): database = lensfunpy.Database() for camera in database.cameras: camera_string = "Maker: %s \t Model: %s" % (camera.maker, camera.model) click.echo(camera_string)
def findCameraAndLensFromExif(tags, lensfunDbObj=None, minAcceptedScore=MIN_ACCEPTED_SCORE, raiseIfNotFoundInDB=True): ''' Note that as of lensfun 0.3.0 lens names are synced to exiv2's naming scheme. Before that, exiftool's scheme was used. In general the correct lens will still be found in either case with the default minimum score of 85 which is used here. ''' if not tags.get('Composite:LensID'): raise LensNotFoundInEXIFError('No LensID in EXIF data') if not tags.get('EXIF:Make') or not tags.get('EXIF:Model'): raise CameraNotFoundInEXIFError('No camera make/model in EXIF data') if lensfunDbObj is None: db = lensfunpy.Database() else: db = lensfunDbObj cams = db.find_cameras(tags['EXIF:Make'], tags['EXIF:Model'], loose_search=False) if not cams: if raiseIfNotFoundInDB: raise CameraNotFoundInDBError('Camera "' + tags['EXIF:Make'] + ' - ' + tags['EXIF:Model'] + '" not found in DB!') else: return None, None # FIXME cam score is always 0 # if cams[0].score < minAcceptedScore: # raise CameraNotFoundInDBError('Camera "' + tags['EXIF:Make'] + ' - ' + tags['EXIF:Model'] + '" not found! ' + # 'Closest was "' + cams[0].maker + ' - ' + cams[0].model + '" with score ' + # str(cams[0].score) + ' (<' + str(minAcceptedScore) + ')' ) cam = cams[0] lenses = db.find_lenses(cam, None, tags['Composite:LensID'], loose_search=True) if not lenses or lenses[0].score < minAcceptedScore: if raiseIfNotFoundInDB: if not lenses: raise LensNotFoundInDBError('Lens "' + tags['Composite:LensID'] + '" not found in DB!') if lenses[0].score < minAcceptedScore: raise LensNotFoundInDBError('Lens "' + tags['Composite:LensID'] + '" not found in DB! ' + 'Closest was "' + lenses[0].model + '" with score ' + str(lenses[0].score) + ' (<' + str(minAcceptedScore) + ')') else: return cam, None lens = lenses[0] if lens.model != tags['Composite:LensID']: print('NOTE: Using lensfun lens "' + lens.model + '" with score ' + str(lens.score) + \ ' (EXIF: "' + tags['Composite:LensID'] + '")') return cam, lens
def __init__(self, parent=None, equipmentDict={}, *args): super(eqRead, self).__init__() self.parent = parent self.equipmentDict = equipmentDict self.db = lensfunpy.Database( paths=glob.glob('libs/lensfunpy-db/*.xml'))