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(f"Luminance Gradient = {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.magnitude0 < 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]])) self.magnitude = (self.magnitude0 * mask).astype(np.uint8) self.phase = (self.phase0 * mask).astype(np.uint8) self.postprocess() self.info_message.emit(self.tr(f"Frequency Split = {elapsed_time(start)}"))
def ssim(x, y): c1 = 6.5025 c2 = 58.5225 k = (11, 11) s = 1.5 x2 = x**2 y2 = y**2 xy = x * y mu_x = cv.GaussianBlur(x, k, s) mu_y = cv.GaussianBlur(y, k, s) mu_x2 = mu_x**2 mu_y2 = mu_y**2 mu_xy = mu_x * mu_y s_x2 = cv.GaussianBlur(x2, k, s) - mu_x2 s_y2 = cv.GaussianBlur(y2, k, s) - mu_y2 s_xy = cv.GaussianBlur(xy, k, s) - mu_xy t1 = 2 * mu_xy + c1 t2 = 2 * s_xy + c2 t3 = t1 * t2 t1 = mu_x2 + mu_y2 + c1 t2 = s_x2 + s_y2 + c2 t1 *= t2 ssim_map = cv.divide(t3, t1) ssim = cv.mean(ssim_map)[0] return ssim, 255 - norm_mat(ssim_map, to_bgr=True)
def load(self): filename, basename, reference = load_image(self) if filename is None: return if reference.shape != self.evidence.shape: QMessageBox.critical( self, self.tr("Error"), self.tr("Evidence and reference must have the same size!")) return self.reference = reference self.reference_viewer.set_title(self.tr(f"Reference: {basename}")) self.difference = norm_mat(cv.absdiff(self.evidence, self.reference)) self.comp_label.setEnabled(True) self.normal_radio.setEnabled(True) self.difference_radio.setEnabled(True) self.ssim_radio.setEnabled(False) self.butter_radio.setEnabled(False) self.gray_check.setEnabled(True) self.equalize_check.setEnabled(True) self.metric_button.setEnabled(True) for i in range(self.table_widget.rowCount()): self.table_widget.setItem(i, 1, QTableWidgetItem()) self.normal_radio.setChecked(True) self.table_widget.setEnabled(False) self.change()
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 += 3 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 = norm_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 estimate_noise(self): if self.noise is None: start = time() self.noise_button.setText( self.tr('Estimating noise, please wait...')) modify_font(self.noise_button, bold=False, italic=True) QCoreApplication.processEvents() qf = estimate_qf(self.image) self.noise = genNoiseprint(self.image0, qf, model_name='net') vmin, vmax, _, _ = cv.minMaxLoc(self.noise[34:-34, 34:-34]) self.noise_viewer.update_processed( norm_mat(self.noise.clip(vmin, vmax), to_bgr=True)) elapsed = time() - start self.noise_button.setText( self.tr('Noise estimated ({:.1f} s)'.format(elapsed))) modify_font(self.noise_button, bold=False, italic=False) self.map_button.setEnabled(True) self.noise_button.setCheckable(True) self.noise_button.setChecked(True)
def preprocess(self): 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)).astype( np.uint8) else: img = self.image[:, :, 3 - channel] self.planes = [ norm_mat(cv.bitwise_and(np.full_like(img, 2**b), img), to_bgr=True) for b in range(8) ] # rows, cols = img.shape # bits = 8 # data = [np.binary_repr(img[i][j], width=bits) for i in range(rows) for j in range(cols)] # self.planes = [ # (np.array([int(i[b]) for i in data], dtype=np.uint8) * 2 ** (bits - b - 1)).reshape( # (rows, cols)) for b in range(bits)] self.process()
def __init__(self, image, parent=None): super(PcaWidget, self).__init__(parent) self.component_combo = QComboBox() self.component_combo.addItems([self.tr(f"#{i + 1}") for i in range(3)]) self.distance_radio = QRadioButton(self.tr("Distance")) self.distance_radio.setToolTip(self.tr("Distance from the closest point on selected component")) self.project_radio = QRadioButton(self.tr("Projection")) self.project_radio.setToolTip(self.tr("Projection onto the selected principal component")) self.crossprod_radio = QRadioButton(self.tr("Cross product")) self.crossprod_radio.setToolTip(self.tr("Cross product between input and selected component")) self.distance_radio.setChecked(True) self.last_radio = self.distance_radio self.invert_check = QCheckBox(self.tr("Invert")) self.invert_check.setToolTip(self.tr("Output bitwise complement")) self.equalize_check = QCheckBox(self.tr("Equalize")) self.equalize_check.setToolTip(self.tr("Apply histogram equalization")) rows, cols, chans = image.shape x = np.reshape(image, (rows * cols, chans)).astype(np.float32) mu, ev, ew = cv.PCACompute2(x, np.array([])) p = np.reshape(cv.PCAProject(x, mu, ev), (rows, cols, chans)) x0 = image.astype(np.float32) - mu self.output = [] for i, v in enumerate(ev): cross = np.cross(x0, v) distance = np.linalg.norm(cross, axis=2) / np.linalg.norm(v) project = p[:, :, i] self.output.extend([norm_mat(distance, to_bgr=True), norm_mat(project, to_bgr=True), norm_img(cross)]) table_data = [ [mu[0, 2], mu[0, 1], mu[0, 0]], [ev[0, 2], ev[0, 1], ev[0, 0]], [ev[1, 2], ev[1, 1], ev[1, 0]], [ev[2, 2], ev[2, 1], ev[2, 0]], [ew[2, 0], ew[1, 0], ew[0, 0]], ] table_widget = QTableWidget(5, 4) table_widget.setHorizontalHeaderLabels([self.tr("Element"), self.tr("Red"), self.tr("Green"), self.tr("Blue")]) table_widget.setItem(0, 0, QTableWidgetItem(self.tr("Mean vector"))) table_widget.setItem(1, 0, QTableWidgetItem(self.tr("Eigenvector 1"))) table_widget.setItem(2, 0, QTableWidgetItem(self.tr("Eigenvector 2"))) table_widget.setItem(3, 0, QTableWidgetItem(self.tr("Eigenvector 3"))) table_widget.setItem(4, 0, QTableWidgetItem(self.tr("Eigenvalues"))) for i in range(len(table_data)): modify_font(table_widget.item(i, 0), bold=True) for j in range(len(table_data[i])): table_widget.setItem(i, j + 1, QTableWidgetItem(str(table_data[i][j]))) # item = QTableWidgetItem() # item.setBackgroundColor(QColor(mu[0, 2], mu[0, 1], mu[0, 0])) # table_widget.setItem(0, 4, item) # table_widget.resizeRowsToContents() # table_widget.resizeColumnsToContents() table_widget.setEditTriggers(QAbstractItemView.NoEditTriggers) table_widget.setSelectionMode(QAbstractItemView.SingleSelection) table_widget.setMaximumHeight(190) self.viewer = ImageViewer(image, image, None) self.process() self.component_combo.currentIndexChanged.connect(self.process) self.distance_radio.clicked.connect(self.process) self.project_radio.clicked.connect(self.process) self.crossprod_radio.clicked.connect(self.process) self.invert_check.stateChanged.connect(self.process) self.equalize_check.stateChanged.connect(self.process) top_layout = QHBoxLayout() top_layout.addWidget(QLabel(self.tr("Component:"))) top_layout.addWidget(self.component_combo) top_layout.addWidget(QLabel(self.tr("Mode:"))) top_layout.addWidget(self.distance_radio) top_layout.addWidget(self.project_radio) top_layout.addWidget(self.crossprod_radio) top_layout.addWidget(self.invert_check) top_layout.addWidget(self.equalize_check) top_layout.addStretch() bottom_layout = QHBoxLayout() bottom_layout.addWidget(table_widget) main_layout = QVBoxLayout() main_layout.addLayout(top_layout) main_layout.addWidget(self.viewer) main_layout.addLayout(bottom_layout) self.setLayout(main_layout)
def __init__(self, image, parent=None): super(StereoWidget, self).__init__(parent) gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY) small = cv.resize(gray, None, None, 1, 0.5) start = 10 end = small.shape[1] // 3 diff = np.fromiter([ cv.mean(cv.absdiff(small[:, i:], small[:, :-i]))[0] for i in range(start, end) ], np.float32) _, maximum, _, argmax = cv.minMaxLoc(np.ediff1d(diff)) if maximum < 2: error_label = QLabel(self.tr("Unable to detect stereogram!")) modify_font(error_label, bold=True) error_label.setStyleSheet("color: #FF0000") error_label.setAlignment(Qt.AlignCenter) main_layout = QVBoxLayout() main_layout.addWidget(error_label) self.setLayout(main_layout) return offset = argmax[1] + start a = image[:, offset:] b = image[:, :-offset] self.pattern = norm_img(cv.absdiff(a, b)) temp = cv.cvtColor(self.pattern, cv.COLOR_BGR2GRAY) thr, _ = cv.threshold(temp, 0, 255, cv.THRESH_TRIANGLE) self.silhouette = cv.medianBlur( gray_to_bgr(cv.threshold(temp, thr, 255, cv.THRESH_BINARY)[1]), 3) a = cv.cvtColor(a, cv.COLOR_BGR2GRAY) b = cv.cvtColor(b, cv.COLOR_BGR2GRAY) flow = cv.calcOpticalFlowFarneback(a, b, None, 0.5, 5, 15, 5, 5, 1.2, cv.OPTFLOW_FARNEBACK_GAUSSIAN)[:, :, 0] self.depth = gray_to_bgr(norm_mat(flow)) flow = np.repeat(cv.normalize(flow, None, 0, 1, cv.NORM_MINMAX)[:, :, np.newaxis], 3, axis=2) self.shaded = cv.normalize( self.pattern.astype(np.float32) * flow, None, 0, 255, cv.NORM_MINMAX).astype(np.uint8) self.viewer = ImageViewer(self.pattern, None, export=True) self.pattern_radio = QRadioButton(self.tr("Pattern")) self.pattern_radio.setChecked(True) self.pattern_radio.setToolTip( self.tr("Difference between raw and aligned image")) self.silhouette_radio = QRadioButton(self.tr("Silhouette")) self.silhouette_radio.setToolTip( self.tr("Apply threshold to discovered pattern")) self.depth_radio = QRadioButton(self.tr("Depth")) self.depth_radio.setToolTip( self.tr("Estimate 3D depth using optical flow")) self.shaded_radio = QRadioButton(self.tr("Shaded")) self.shaded_radio.setToolTip( self.tr("Combine pattern and depth information")) self.silhouette_radio.clicked.connect(self.process) self.pattern_radio.clicked.connect(self.process) self.depth_radio.clicked.connect(self.process) self.shaded_radio.clicked.connect(self.process) top_layout = QHBoxLayout() top_layout.addWidget(QLabel(self.tr("Mode:"))) top_layout.addWidget(self.pattern_radio) top_layout.addWidget(self.silhouette_radio) top_layout.addWidget(self.depth_radio) top_layout.addWidget(self.shaded_radio) top_layout.addStretch() main_layout = QVBoxLayout() main_layout.addLayout(top_layout) main_layout.addWidget(self.viewer) self.setLayout(main_layout)