def _add_aligned_face(self, filename, alignments, image_size): """ Add a :class:`lib.align.AlignedFace` object to the cache. Parameters ---------- filename: str The file path for the current image alignments: dict The alignments for a single face, extracted from a PNG header image_size: int The pixel size of the image loaded from disk Returns ------- :class:`lib.align.DetectedFace` The Detected Face object that was used to create the Aligned Face """ if self._size is None: self._size = get_centered_size( "legacy" if self._extract_version == 1.0 else "head", self._centering, image_size) detected_face = DetectedFace() detected_face.from_png_meta(alignments) aligned_face = AlignedFace(detected_face.landmarks_xy, centering=self._centering, size=self._size, is_aligned=True) logger.trace("Caching aligned face for: %s", filename) self._cache[os.path.basename(filename)]["aligned_face"] = aligned_face return detected_face
def estimate_blur_fft(cls, image, metadata=None): """ Estimate the amount of blur a fft filtered image has. Parameters ---------- image: :class:`numpy.ndarray` Use Fourier Transform to analyze the frequency characteristics of the masked face using 2D Discrete Fourier Transform (DFT) filter to find the frequency domain. A mean value is assigned to the magnitude spectrum and returns a blur score. Adapted from https://www.pyimagesearch.com/2020/06/15/ opencv-fast-fourier-transform-fft-for-blur-detection-in-images-and-video-streams/ metadata: dict, optional The metadata for the face image or ``None`` if no metadata is available. If metadata is provided the face will be masked by the "components" mask prior to calculating blur. Default:``None`` Returns ------- float The estimated fft blur score for the face """ if metadata is not None: alignments = metadata["alignments"] det_face = DetectedFace() det_face.from_png_meta(alignments) aln_face = AlignedFace(np.array(alignments["landmarks_xy"], dtype="float32"), image=image, centering="legacy", size=256, is_aligned=True) mask = det_face.mask["components"] mask.set_sub_crop(aln_face.pose.offset[mask.stored_centering] * -1, centering="legacy") mask = cv2.resize(mask.mask, (256, 256), interpolation=cv2.INTER_CUBIC)[..., None] image = np.minimum(aln_face.face, mask) if image.ndim == 3: image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) height, width = image.shape c_height, c_width = (int(height / 2.0), int(width / 2.0)) fft = np.fft.fft2(image) fft_shift = np.fft.fftshift(fft) fft_shift[c_height - 75:c_height + 75, c_width - 75:c_width + 75] = 0 ifft_shift = np.fft.ifftshift(fft_shift) shift_back = np.fft.ifft2(ifft_shift) magnitude = np.log(np.abs(shift_back)) score = np.mean(magnitude) return score
def estimate_blur(cls, image, metadata=None): """ Estimate the amount of blur an image has with the variance of the Laplacian. Normalize by pixel number to offset the effect of image size on pixel gradients & variance. Parameters ---------- image: :class:`numpy.ndarray` The face image to calculate blur for metadata: dict, optional The metadata for the face image or ``None`` if no metadata is available. If metadata is provided the face will be masked by the "components" mask prior to calculating blur. Default:``None`` Returns ------- float The estimated blur score for the face """ if metadata is not None: alignments = metadata["alignments"] det_face = DetectedFace() det_face.from_png_meta(alignments) aln_face = AlignedFace(np.array(alignments["landmarks_xy"], dtype="float32"), image=image, centering="legacy", size=256, is_aligned=True) mask = det_face.mask["components"] mask.set_sub_crop(aln_face.pose.offset[mask.stored_centering] * -1, centering="legacy") mask = cv2.resize(mask.mask, (256, 256), interpolation=cv2.INTER_CUBIC)[..., None] image = np.minimum(aln_face.face, mask) if image.ndim == 3: image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) blur_map = cv2.Laplacian(image, cv2.CV_32F) score = np.var(blur_map) / np.sqrt(image.shape[0] * image.shape[1]) return score