예제 #1
0
 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))))
예제 #2
0
 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))))
예제 #3
0
파일: noise.py 프로젝트: parampavar/sherloq
    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))))
예제 #4
0
파일: echo.py 프로젝트: fiuderazes/sherloq
 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)))
예제 #5
0
파일: ela.py 프로젝트: Vidocapt/sherloq
 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))))
예제 #6
0
 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))))
예제 #7
0
    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))))
예제 #8
0
파일: minmax.py 프로젝트: Vidocapt/sherloq
 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))))
예제 #9
0
 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))))
예제 #10
0
    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)))
예제 #11
0
파일: minmax.py 프로젝트: Vidocapt/sherloq
 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)
예제 #12
0
 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)
예제 #13
0
파일: plots.py 프로젝트: Vidocapt/sherloq
 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)))
예제 #14
0
    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))))