def preprocess(self): start = time() channel = self.chan_combo.currentIndex() if channel == 0: img = cv.cvtColor(self.image, cv.COLOR_BGR2GRAY) elif channel == 4: b, g, r = cv.split(self.image.astype(np.float64)) img = cv.sqrt(cv.pow(b, 2) + cv.pow(g, 2) + cv.pow(r, 2)) else: img = self.image[:, :, 3 - channel] kernel = 3 border = kernel // 2 shape = (img.shape[0] - kernel + 1, img.shape[1] - kernel + 1, kernel, kernel) strides = 2 * img.strides patches = np.lib.stride_tricks.as_strided(img, shape=shape, strides=strides) patches = patches.reshape((-1, kernel, kernel)) mask = np.full((kernel, kernel), 255, dtype=np.uint8) mask[border, border] = 0 output = np.array([self.minmax_dev(patch, mask) for patch in patches]).reshape(shape[:-2]) output = cv.copyMakeBorder(output, border, border, border, border, cv.BORDER_CONSTANT) self.low = output == -1 self.high = output == +1 self.process() self.info_message.emit( self.tr('Min/Max Deviation = {}'.format(elapsed_time(start))))
def process(self): start = time() intensity = int(self.intensity_spin.value() / 100 * 127) invert = self.invert_check.isChecked() equalize = self.equalize_check.isChecked() self.intensity_spin.setEnabled(not equalize) blue_mode = self.blue_combo.currentIndex() if invert: dx = (-self.dx).astype(np.float32) dy = (-self.dy).astype(np.float32) else: dx = (+self.dx).astype(np.float32) dy = (+self.dy).astype(np.float32) dx_abs = np.abs(dx) dy_abs = np.abs(dy) red = ((dx / np.max(dx_abs) * 127) + 127).astype(np.uint8) green = ((dy / np.max(dy_abs) * 127) + 127).astype(np.uint8) if blue_mode == 0: blue = np.zeros_like(red) elif blue_mode == 1: blue = np.full_like(red, 255) elif blue_mode == 2: blue = norm_mat(dx_abs + dy_abs) elif blue_mode == 3: blue = norm_mat(np.linalg.norm(cv.merge((red, green)), axis=2)) else: blue = None gradient = cv.merge([blue, green, red]) if equalize: gradient = equalize_img(gradient) elif intensity > 0: gradient = cv.LUT(gradient, create_lut(intensity, intensity)) self.viewer.update_processed(gradient) self.info_message.emit(self.tr('Luminance Gradient = {}'.format(elapsed_time(start))))
def process(self): start = time() grayscale = self.gray_check.isChecked() if grayscale: original = cv.cvtColor(self.image, cv.COLOR_BGR2GRAY) else: original = self.image radius = self.radius_spin.value() kernel = radius * 2 + 1 sigma = self.sigma_spin.value() choice = self.mode_combo.currentText() if choice == self.tr('Median'): self.sigma_spin.setEnabled(False) denoised = cv.medianBlur(original, kernel) elif choice == self.tr('Gaussian'): self.sigma_spin.setEnabled(False) denoised = cv.GaussianBlur(original, (kernel, kernel), 0) elif choice == self.tr('BoxBlur'): self.sigma_spin.setEnabled(False) denoised = cv.blur(original, (kernel, kernel)) elif choice == self.tr('Bilateral'): self.sigma_spin.setEnabled(True) denoised = cv.bilateralFilter(original, kernel, sigma, sigma) elif choice == self.tr('NonLocal'): if grayscale: denoised = cv.fastNlMeansDenoising(original, None, kernel) else: denoised = cv.fastNlMeansDenoisingColored( original, None, kernel, kernel) else: denoised = None if self.denoised_check.isChecked(): self.levels_spin.setEnabled(False) result = denoised else: self.levels_spin.setEnabled(True) noise = cv.absdiff(original, denoised) levels = self.levels_spin.value() if levels == 0: if grayscale: result = cv.equalizeHist(noise) else: result = equalize_img(noise) else: result = cv.LUT(noise, create_lut(0, 255 - levels)) if grayscale: result = cv.cvtColor(result, cv.COLOR_GRAY2BGR) self.viewer.update_processed(result) self.info_message.emit( self.tr('Noise estimation = {}'.format(elapsed_time(start))))
def process(self): start = time() kernel = 2 * self.radius_spin.value() + 1 contrast = int(self.contrast_spin.value() / 100 * 255) lut = create_lut(0, contrast) laplace = [] for channel in cv.split(self.image): deriv = np.fabs(cv.Laplacian(channel, cv.CV_64F, None, kernel)) deriv = cv.normalize(deriv, None, 0, 255, cv.NORM_MINMAX, cv.CV_8UC1) laplace.append(cv.LUT(deriv, lut)) self.viewer.update_processed(cv.merge(laplace)) self.info_message.emit('Echo Edge Filter = {}'.format( elapsed_time(start)))
def process(self): equalize = self.equalize_check.isChecked() self.scale_spin.setEnabled(not equalize) start = time() quality = self.quality_spin.value() scale = self.scale_spin.value() compressed = compress_jpeg(self.image, quality) if not equalize: ela = cv.convertScaleAbs(cv.subtract(compressed, self.image), None, scale) else: ela = equalize_image(cv.absdiff(compressed, self.image)) self.viewer.update_processed(ela) self.info_message.emit( self.tr('Error Level Analysis = {}'.format(elapsed_time(start))))
def process(self): start = time() scale = self.scale_spin.value() contrast = int(self.contrast_spin.value() / 100 * 128) linear = self.linear_check.isChecked() grayscale = self.gray_check.isChecked() if not linear: difference = cv.absdiff(self.original, self.compressed.astype(np.float32) / 255) ela = cv.convertScaleAbs(cv.sqrt(difference) * 255, None, scale / 20) else: ela = cv.convertScaleAbs(cv.subtract(self.compressed, self.image), None, scale) ela = cv.LUT(ela, create_lut(contrast, contrast)) if grayscale: ela = desaturate(ela) self.viewer.update_processed(ela) self.info_message.emit(self.tr('Error Level Analysis = {}'.format(elapsed_time(start))))
def process(self): start = time() rows, cols, _ = self.dft.shape mask = np.zeros((rows, cols), np.float32) half = np.sqrt(rows**2 + cols**2) / 2 radius = int(half * self.split_spin.value() / 100) mask = cv.circle(mask, (cols // 2, rows // 2), radius, 1, cv.FILLED) kernel = 2 * int(half * self.smooth_spin.value() / 100) + 1 mask = cv.GaussianBlur(mask, (kernel, kernel), 0) mask /= np.max(mask) threshold = int(self.thr_spin.value() / 100 * 255) if threshold > 0: mask[self.magnitude < threshold] = 0 zeros = (mask.size - np.count_nonzero(mask)) / mask.size * 100 else: zeros = 0 self.zero_label.setText( self.tr('(zeroed coefficients = {:.2f}%)').format(zeros)) mask2 = np.repeat(mask[:, :, np.newaxis], 2, axis=2) rows0, cols0, _ = self.image.shape low = cv.idft(np.fft.ifftshift(self.dft * mask2), flags=cv.DFT_SCALE) low = norm_mat(cv.magnitude(low[:, :, 0], low[:, :, 1])[:rows0, :cols0], to_bgr=True) self.low_viewer.update_processed(low) high = cv.idft(np.fft.ifftshift(self.dft * (1 - mask2)), flags=cv.DFT_SCALE) high = norm_mat(cv.magnitude(high[:, :, 0], high[:, :, 1]), to_bgr=True) self.high_viewer.update_processed( np.copy(high[:self.image.shape[0], :self.image.shape[1]])) magnitude = (self.magnitude * mask).astype(np.uint8) phase = (self.phase * mask).astype(np.uint8) kernel = 2 * self.filter_spin.value() + 1 if kernel >= 3: magnitude = cv.GaussianBlur(magnitude, (kernel, kernel), 0) phase = cv.GaussianBlur(phase, (kernel, kernel), 0) # phase = cv.medianBlur(phase, kernel) self.mag_viewer.update_original( cv.cvtColor(magnitude, cv.COLOR_GRAY2BGR)) self.phase_viewer.update_original(cv.cvtColor(phase, cv.COLOR_GRAY2BGR)) self.info_message.emit( self.tr('Frequency Split = {}'.format(elapsed_time(start))))
def preprocess(self): start = time() channel = self.chan_combo.currentIndex() if channel == 0: img = cv.cvtColor(self.image, cv.COLOR_BGR2GRAY) elif channel == 4: b, g, r = cv.split(self.image.astype(np.float64)) img = cv.sqrt(cv.pow(b, 2) + cv.pow(g, 2) + cv.pow(r, 2)) else: img = self.image[:, :, 3 - channel] kernel = 3 border = kernel // 2 shape = (img.shape[0] - kernel + 1, img.shape[1] - kernel + 1, kernel, kernel) strides = 2 * img.strides patches = np.lib.stride_tricks.as_strided(img, shape=shape, strides=strides) patches = patches.reshape((-1, kernel, kernel)) mask = np.full((kernel, kernel), 255, dtype=np.uint8) mask[border, border] = 0 progress = QProgressDialog(self.tr('Computing deviation...'), self.tr('Cancel'), 0, shape[0] * shape[1] - 1, self) progress.canceled.connect(self.cancel) progress.setWindowModality(Qt.WindowModal) blocks = [0] * shape[0] * shape[1] for i, patch in enumerate(patches): blocks[i] = self.minmax_dev(patch, mask) progress.setValue(i) if self.stopped: self.stopped = False return output = np.array(blocks).reshape(shape[:-2]) output = cv.copyMakeBorder(output, border, border, border, border, cv.BORDER_CONSTANT) self.low = output == -1 self.high = output == +1 self.min_combo.setEnabled(True) self.max_combo.setEnabled(True) self.filter_spin.setEnabled(True) self.process_button.setEnabled(False) self.process() self.info_message.emit( self.tr('Min/Max Deviation = {}'.format(elapsed_time(start))))
def process(self): start = time() quality = self.quality_spin.value() scale = self.scale_spin.value() / 20 contrast = int(self.contrast_spin.value() / 100 * 128) equalize = self.equalize_check.isChecked() grayscale = self.gray_check.isChecked() self.scale_spin.setEnabled(not equalize) self.contrast_spin.setEnabled(not equalize) compressed = compress_jpeg(self.image, quality).astype(np.float32) / 255 difference = cv.absdiff(self.original, compressed) if equalize: ela = equalize_img((difference * 255).astype(np.uint8)) else: ela = cv.convertScaleAbs(cv.sqrt(difference) * 255, None, scale) ela = cv.LUT(ela, create_lut(contrast, contrast)) if grayscale: ela = desaturate(ela) self.viewer.update_processed(ela) self.info_message.emit(self.tr('Error Level Analysis = {}'.format(elapsed_time(start))))
def redraw(self): start = time() v = self.sampling_spin.value() x = self.colors[v][:, self.xaxis_combo.currentIndex()] y = self.colors[v][:, self.yaxis_combo.currentIndex()] s = self.size_spin.value()**2 c = None if not self.colors_check.isChecked( ) else self.colors[v][:, :3] if self.tab_widget.currentIndex() == 0: self.zaxis_combo.setEnabled(False) self.grid_check.setEnabled(True) self.alpha_spin.setEnabled(True) a = self.alpha_spin.value() xlim = self.axes2.get_xlim() ylim = self.axes2.get_ylim() self.axes2.clear() self.axes2.set_facecolor([0.5] * 3 if c is not None else [1.0] * 3) self.axes2.scatter(x, y, s, c, '.', alpha=a) self.axes2.set_xlabel(self.xaxis_combo.currentText()) self.axes2.set_ylabel(self.yaxis_combo.currentText()) self.axes2.grid(self.grid_check.isChecked(), which='both') self.axes2.set_xlim(xlim) self.axes2.set_ylim(ylim) self.axes2.figure.canvas.draw() else: self.zaxis_combo.setEnabled(True) self.grid_check.setEnabled(False) self.alpha_spin.setEnabled(False) z = self.colors[v][:, self.zaxis_combo.currentIndex()] self.axes3.clear() self.axes3.set_facecolor([0.5] * 3 if c is not None else [1.0] * 3) self.axes3.scatter(x, y, z, s=s, c=c, marker='.', depthshade=True) self.axes3.set_xlabel(self.xaxis_combo.currentText()) self.axes3.set_ylabel(self.yaxis_combo.currentText()) self.axes3.set_zlabel(self.zaxis_combo.currentText()) self.axes3.grid(self.grid_check.isChecked(), which='both') self.axes3.figure.canvas.draw() self.total_label.setText(self.tr('[{} points]'.format(len(x)))) self.info_message.emit('Plot redraw = {}'.format(elapsed_time(start)))
def process(self): minmax = np.zeros_like(self.image) minimum = self.min_combo.currentIndex() maximum = self.max_combo.currentIndex() radius = self.filter_spin.value() if radius > 0: start = time() radius += 2 if minimum < 4: low = self.blk_filter(self.low, radius) if minimum <= 2: minmax[:, :, 2 - minimum] = low else: minmax = np.repeat(low[:, :, np.newaxis], 3, axis=2) if maximum < 4: high = self.blk_filter(self.high, radius) if maximum <= 2: minmax[:, :, 2 - maximum] += high else: minmax += np.repeat(high[:, :, np.newaxis], 3, axis=2) minmax = normalize_mat(minmax) self.info_message.emit( self.tr('Min/Max Filter = {}'.format(elapsed_time(start)))) else: if minimum == 0: minmax[self.low] = [0, 0, 255] elif minimum == 1: minmax[self.low] = [0, 255, 0] elif minimum == 2: minmax[self.low] = [255, 0, 0] elif minimum == 3: minmax[self.low] = [255, 255, 255] if maximum == 0: minmax[self.high] = [0, 0, 255] elif maximum == 1: minmax[self.high] = [0, 255, 0] elif maximum == 2: minmax[self.high] = [255, 0, 0] elif maximum == 3: minmax[self.high] = [255, 255, 255] self.viewer.update_processed(minmax)
def process(self): minmax = np.zeros_like(self.image) minimum = self.min_combo.currentIndex() maximum = self.max_combo.currentIndex() radius = self.filter_spin.value() if radius > 0: start = time() radius += 2 low = self.blk_filter(self.low, radius) high = self.blk_filter(self.high, radius) if minimum <= 2: minmax[:, :, 2 - minimum] = low else: minmax = low if maximum <= 2: minmax[:, :, 2 - maximum] += high else: # FIXME: minmax ha un solo canale quando si sceglie black come colore minmax += high minmax = normalize_mat(minmax) self.info_message.emit( self.tr('Min/Max Filter = {}'.format(elapsed_time(start)))) else: if minimum == 0: minmax[self.low] = [0, 0, 255] elif minimum == 1: minmax[self.low] = [0, 255, 0] elif minimum == 2: minmax[self.low] = [255, 0, 0] elif minimum == 3: minmax[self.low] = [255, 255, 255] if maximum == 0: minmax[self.high] = [0, 0, 255] elif maximum == 1: minmax[self.high] = [0, 255, 0] elif maximum == 2: minmax[self.high] = [255, 0, 0] elif maximum == 3: minmax[self.high] = [255, 255, 255] self.viewer.update_processed(minmax)
def redraw(self): start = time() v = self.sampling_spin.value() x = self.colors[v][:, self.xaxis_combo.currentIndex()] y = self.colors[v][:, self.yaxis_combo.currentIndex()] xlim = self.axes.get_xlim() ylim = self.axes.get_ylim() s = self.size_spin.value()**2 c = None if not self.colors_check.isChecked( ) else self.colors[v][:, :3] a = self.alpha_spin.value() m = self.markers[self.style_combo.currentIndex()] self.axes.clear() self.axes.set_facecolor([0.5] * 3 if c is not None else [1.0] * 3) self.axes.scatter(x, y, s, c, m, alpha=a) self.axes.set_xlabel(self.xaxis_combo.currentText()) self.axes.set_ylabel(self.yaxis_combo.currentText()) self.axes.grid(self.grid_check.isChecked(), which='both') self.axes.set_xlim(xlim) self.axes.set_ylim(ylim) self.axes.figure.canvas.draw() self.total_label.setText(self.tr('[{} points]'.format(len(x)))) self.info_message.emit('Plot redraw = {}'.format(elapsed_time(start)))
def process(self): start = time() self.canceled = False self.status_label.setText(self.tr('Processing, please wait...')) algorithm = self.detector_combo.currentIndex() response = 100 - self.response_spin.value() matching = self.matching_spin.value() / 100 * 255 distance = self.distance_spin.value() / 100 cluster = self.cluster_spin.value() modify_font(self.status_label, bold=False, italic=True) QCoreApplication.processEvents() if self.kpts is None: if algorithm == 0: detector = cv.BRISK_create() elif algorithm == 1: detector = cv.ORB_create() elif algorithm == 2: detector = cv.AKAZE_create() else: return mask = self.mask if self.onoff_button.isChecked() else None self.kpts, self.desc = detector.detectAndCompute(self.gray, mask) self.total = len(self.kpts) responses = np.array([k.response for k in self.kpts]) strongest = (cv.normalize(responses, None, 0, 100, cv.NORM_MINMAX) >= response).flatten() self.kpts = list(compress(self.kpts, strongest)) if len(self.kpts) > 30000: QMessageBox.warning( self, self.tr('Warning'), self. tr('Too many keypoints found ({}), please reduce response value' .format(self.total))) self.kpts = self.desc = None self.total = 0 self.status_label.setText('') return self.desc = self.desc[strongest] if self.matches is None: matcher = cv.BFMatcher_create(cv.NORM_HAMMING, True) self.matches = matcher.radiusMatch(self.desc, self.desc, matching) if self.matches is None: self.status_label.setText( self.tr('No keypoint match found with current settings')) modify_font(self.status_label, italic=False, bold=True) return self.matches = [ item for sublist in self.matches for item in sublist ] self.matches = [ m for m in self.matches if m.queryIdx != m.trainIdx ] if not self.matches: self.clusters = [] elif self.clusters is None: self.clusters = [] min_dist = distance * np.min(self.gray.shape) / 2 kpts_a = np.array([p.pt for p in self.kpts]) ds = np.linalg.norm([ kpts_a[m.queryIdx] - kpts_a[m.trainIdx] for m in self.matches ], axis=1) self.matches = [ m for i, m in enumerate(self.matches) if ds[i] > min_dist ] total = len(self.matches) progress = QProgressDialog(self.tr('Clustering matches...'), self.tr('Cancel'), 0, total, self) progress.canceled.connect(self.cancel) progress.setWindowModality(Qt.WindowModal) for i in range(total): match0 = self.matches[i] d0 = ds[i] query0 = match0.queryIdx train0 = match0.trainIdx group = [match0] for j in range(i + 1, total): match1 = self.matches[j] query1 = match1.queryIdx train1 = match1.trainIdx if query1 == train0 and train1 == query0: continue d1 = ds[j] if np.abs(d0 - d1) > min_dist: continue a0 = np.array(self.kpts[query0].pt) b0 = np.array(self.kpts[train0].pt) a1 = np.array(self.kpts[query1].pt) b1 = np.array(self.kpts[train1].pt) aa = np.linalg.norm(a0 - a1) bb = np.linalg.norm(b0 - b1) ab = np.linalg.norm(a0 - b1) ba = np.linalg.norm(b0 - a1) if not (0 < aa < min_dist and 0 < bb < min_dist or 0 < ab < min_dist and 0 < ba < min_dist): continue for g in group: if g.queryIdx == train1 and g.trainIdx == query1: break else: group.append(match1) if len(group) >= cluster: self.clusters.append(group) progress.setValue(i) if self.canceled: self.update_detector() return progress.close() output = np.copy(self.image) hsv = np.zeros((1, 1, 3)) nolines = self.nolines_check.isChecked() show_kpts = self.kpts_check.isChecked() if show_kpts: for kpt in self.kpts: cv.circle(output, (int(kpt.pt[0]), int(kpt.pt[1])), 2, (250, 227, 72)) angles = [] for c in self.clusters: for m in c: ka = self.kpts[m.queryIdx] pa = tuple(map(int, ka.pt)) sa = int(np.round(ka.size)) kb = self.kpts[m.trainIdx] pb = tuple(map(int, kb.pt)) sb = int(np.round(kb.size)) angle = np.arctan2(pb[1] - pa[1], pb[0] - pa[0]) if angle < 0: angle += np.pi angles.append(angle) hsv[0, 0, 0] = angle / np.pi * 180 hsv[0, 0, 1] = 255 hsv[0, 0, 2] = m.distance / matching * 255 rgb = cv.cvtColor(hsv.astype(np.uint8), cv.COLOR_HSV2BGR) rgb = tuple([int(x) for x in rgb[0, 0]]) cv.circle(output, pa, sa, rgb, 1, cv.LINE_AA) cv.circle(output, pb, sb, rgb, 1, cv.LINE_AA) if not nolines: cv.line(output, pa, pb, rgb, 1, cv.LINE_AA) regions = 0 if angles: angles = np.reshape(np.array(angles, dtype=np.float32), (len(angles), 1)) if np.std(angles) < 0.1: regions = 1 else: criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 10, 1.0) attempts = 10 flags = cv.KMEANS_PP_CENTERS compact = [ cv.kmeans(angles, k, None, criteria, attempts, flags)[0] for k in range(1, 11) ] compact = cv.normalize(np.array(compact), None, 0, 1, cv.NORM_MINMAX) regions = np.argmax(compact < 0.005) + 1 self.viewer.update_processed(output) self.process_button.setEnabled(False) modify_font(self.status_label, italic=False, bold=True) self.status_label.setText( self. tr('Keypoints: {} --> Filtered: {} --> Matches: {} --> Clusters: {} --> Regions: {}' .format(self.total, len(self.kpts), len(self.matches), len(self.clusters), regions))) self.info_message.emit( self.tr('Copy-Move Forgery = {}'.format(elapsed_time(start))))