Ejemplo n.º 1
0
 def configFilterTypeButtons(self,
                             name=u"default",
                             checked=False,
                             xPos=0,
                             yPos=0,
                             idButton=0):
     button = QRadioButton(self)
     button.setObjectName(name)
     button.setEnabled(True)
     button.setGeometry(QRect(xPos, yPos, 82, 17))
     button.setCursor(QCursor(Qt.PointingHandCursor))
     button.setChecked(checked)
     lam = lambda id=idButton: self.buttonChecked(id)
     self.connect(button, SIGNAL("clicked()"), lam)
     self.filterTypeButtons.addButton(button, idButton)
Ejemplo n.º 2
0
    def add_horizontal_splitter(self, layout):
        splitter = QSplitter()
        splitter.setOrientation(Qt.Orientation.Vertical)
        layout.addWidget(splitter)

        # ADD TOP
        top_widget = QWidget(splitter)
        top = QVBoxLayout(top_widget)

        # NORMAL
        btn = FillPushButton('Push Button')
        top.layout().addWidget(btn)

        #DISABLED
        btn = FillPushButton('Push Button Disabled')
        btn.setEnabled(False)
        top.layout().addWidget(btn)

        # ADD BOTTOM
        bottom_widget = QWidget(splitter)
        right = QGridLayout(bottom_widget)

        # NORMAL
        cbx = QCheckBox('Check Box')
        right.addWidget(cbx)

        #DISABLED
        cbx = QCheckBox('Check Box Disabled')
        cbx.setEnabled(False)
        right.addWidget(cbx)

        rob = QRadioButton('Radio Button')
        right.addWidget(rob)

        rob = QRadioButton('Radio Button Disabled')
        rob.setEnabled(False)
        right.addWidget(rob)
Ejemplo n.º 3
0
class ComparisonWidget(ToolWidget):
    def __init__(self, filename, image, parent=None):
        super(ComparisonWidget, self).__init__(parent)

        load_button = QPushButton(self.tr('Load reference image...'))
        self.comp_label = QLabel(self.tr('Comparison:'))
        self.normal_radio = QRadioButton(self.tr('Normal'))
        self.normal_radio.setToolTip(self.tr('Show reference (raw pixels)'))
        self.normal_radio.setChecked(True)
        self.difference_radio = QRadioButton(self.tr('Difference'))
        self.difference_radio.setToolTip(
            self.tr('Show evidence/reference difference'))
        self.ssim_radio = QRadioButton(self.tr('SSIM Map'))
        self.ssim_radio.setToolTip(self.tr('Structure similarity quality map'))
        self.butter_radio = QRadioButton(self.tr('Butteraugli'))
        self.butter_radio.setToolTip(
            self.tr('Butteraugli spatial changes heatmap'))
        self.gray_check = QCheckBox(self.tr('Grayscale'))
        self.gray_check.setToolTip(self.tr('Show desaturated output'))
        self.equalize_check = QCheckBox(self.tr('Equalized'))
        self.equalize_check.setToolTip(self.tr('Apply histogram equalization'))
        self.last_radio = self.normal_radio
        self.metric_button = QPushButton(self.tr('Compute metrics'))
        self.metric_button.setToolTip(
            self.tr('Image quality assessment metrics'))

        self.evidence = image
        self.reference = self.difference = self.ssim_map = self.butter_map = None
        basename = os.path.basename(filename)
        self.evidence_viewer = ImageViewer(
            self.evidence, None, self.tr('Evidence: {}'.format(basename)))
        self.reference_viewer = ImageViewer(np.full_like(self.evidence, 127),
                                            None, self.tr('Reference'))

        self.table_widget = QTableWidget(21, 3)
        self.table_widget.setHorizontalHeaderLabels(
            [self.tr('Metric'),
             self.tr('Value'),
             self.tr('Better')])
        self.table_widget.setItem(0, 0, QTableWidgetItem(self.tr('RMSE')))
        self.table_widget.setItem(
            0, 2, QTableWidgetItem(QIcon('gui/icons/low.svg'), '(0)'))
        self.table_widget.item(0, 0).setToolTip(
            self.
            tr('Root Mean Square Error (RMSE) is commonly used to compare \n'
               'the difference between the reference and evidence images \n'
               'by directly computing the variation in pixel values. \n'
               'The combined image is close to the reference image when \n'
               'RMSE value is zero. RMSE is a good indicator of the spectral \n'
               'quality of the reference image.'))
        self.table_widget.setItem(1, 0, QTableWidgetItem(self.tr('SAM')))
        self.table_widget.setItem(
            1, 2, QTableWidgetItem(QIcon('gui/icons/low.svg'), '(0)'))
        self.table_widget.item(1, 0).setToolTip(
            self.
            tr('It computes the spectral angle between the pixel, vector of the \n'
               'evidence image and reference image. It is worked out in either \n'
               'degrees or radians. It is performed on a pixel-by-pixel base. \n'
               'A SAM equal to zero denotes the absence of spectral distortion.'
               ))
        self.table_widget.setItem(2, 0, QTableWidgetItem(self.tr('ERGAS')))
        self.table_widget.setItem(
            2, 2, QTableWidgetItem(QIcon('gui/icons/low.svg'), '(0)'))
        self.table_widget.item(2, 0).setToolTip(
            self.
            tr('It is used to compute the quality of reference image in terms \n'
               'of normalized average error of each band of the reference image. \n'
               'Increase in the value of ERGAS indicates distortion in the \n'
               'reference image, lower value of ERGAS indicates that it is \n'
               'similar to the reference image.'))
        self.table_widget.setItem(3, 0, QTableWidgetItem(self.tr('MB')))
        self.table_widget.setItem(
            3, 2, QTableWidgetItem(QIcon('gui/icons/low.svg'), '(0)'))
        self.table_widget.item(3, 0).setToolTip(
            self.
            tr('Mean Bias is the difference between the mean of the evidence \n'
               'image and reference image. The ideal value is zero and indicates \n'
               'that the evidence and reference images are similar. Mean value \n'
               'refers to the grey level of pixels in an image.'))
        self.table_widget.setItem(4, 0, QTableWidgetItem(self.tr('PFE')))
        self.table_widget.setItem(
            4, 2, QTableWidgetItem(QIcon('gui/icons/low.svg'), '(0)'))
        self.table_widget.item(4, 0).setToolTip(
            self.
            tr('It computes the norm of the difference between the corresponding \n'
               'pixels of the reference and fused image to the norm of the reference \n'
               'image. When the calculated value is zero, it indicates that both the \n'
               'reference and fused images are similar and value will be increased \n'
               'when the merged image is not similar to the reference image.'))
        self.table_widget.setItem(5, 0, QTableWidgetItem(self.tr('PSNR')))
        self.table_widget.setItem(
            5, 2,
            QTableWidgetItem(QIcon('gui/icons/high.svg'),
                             '(+' + u'\u221e' + ')'))
        self.table_widget.item(5, 0).setToolTip(
            self.
            tr('It is widely used metric it is computed by the number of gray levels \n'
               'in the image divided by the corresponding pixels in the evidence and \n'
               'the reference images. When the value is high, both images are similar.'
               ))
        self.table_widget.setItem(6, 0, QTableWidgetItem(self.tr('PSNR-B')))
        self.table_widget.setItem(
            6, 2,
            QTableWidgetItem(QIcon('gui/icons/high.svg'),
                             '(+' + u'\u221e' + ')'))
        self.table_widget.item(6, 0).setToolTip(
            self.tr('PSNR with Blocking Effect Factor.'))
        self.table_widget.setItem(7, 0, QTableWidgetItem(self.tr('SSIM')))
        self.table_widget.setItem(
            7, 2, QTableWidgetItem(QIcon('gui/icons/high.svg'), '(1)'))
        self.table_widget.item(7, 0).setToolTip(
            self.
            tr('SSIM is used to compare the local patterns of pixel intensities between \n'
               ' the reference and fused images. The range varies between -1 to 1. \n'
               'The value 1 indicates the reference and fused images are similar.'
               ))
        self.table_widget.setItem(8, 0, QTableWidgetItem(self.tr('MS-SSIM')))
        self.table_widget.setItem(
            8, 2, QTableWidgetItem(QIcon('gui/icons/high.svg'), '(1)'))
        self.table_widget.item(8, 0).setToolTip(
            self.tr('Multiscale version of SSIM.'))
        self.table_widget.setItem(9, 0, QTableWidgetItem(self.tr('RASE')))
        self.table_widget.setItem(
            9, 2, QTableWidgetItem(QIcon('gui/icons/low.svg'), '(0)'))
        self.table_widget.item(9, 0).setToolTip(
            self.tr('Relative average spectral error'))
        self.table_widget.setItem(10, 0, QTableWidgetItem(self.tr('SCC')))
        self.table_widget.setItem(
            10, 2, QTableWidgetItem(QIcon('gui/icons/high.svg'), '(1)'))
        self.table_widget.item(10, 0).setToolTip(
            self.tr('Spatial Correlation Coefficient'))
        self.table_widget.setItem(11, 0, QTableWidgetItem(self.tr('UQI')))
        self.table_widget.setItem(
            11, 2, QTableWidgetItem(QIcon('gui/icons/high.svg'), '(1)'))
        self.table_widget.item(11, 0).setToolTip(
            self.tr('Universal Image Quality Index'))
        self.table_widget.setItem(12, 0, QTableWidgetItem(self.tr('VIF-P')))
        self.table_widget.setItem(
            12, 2, QTableWidgetItem(QIcon('gui/icons/high.svg'), '(1)'))
        self.table_widget.item(12, 0).setToolTip(
            self.tr('Pixel-based Visual Information Fidelity'))
        self.table_widget.setItem(13, 0,
                                  QTableWidgetItem(self.tr('SSIMulacra')))
        self.table_widget.setItem(
            13, 2, QTableWidgetItem(QIcon('gui/icons/low.svg'), '(0)'))
        self.table_widget.item(13, 0).setToolTip(
            self.tr('Structural SIMilarity Unveiling Local '
                    'And Compression Related Artifacts'))
        self.table_widget.setItem(14, 0,
                                  QTableWidgetItem(self.tr('Butteraugli')))
        self.table_widget.setItem(
            14, 2, QTableWidgetItem(QIcon('gui/icons/low.svg'), '(0)'))
        self.table_widget.item(14, 0).setToolTip(
            self.tr('Estimate psychovisual error'))
        self.table_widget.setItem(15, 0,
                                  QTableWidgetItem(self.tr('Correlation')))
        self.table_widget.setItem(
            15, 2, QTableWidgetItem(QIcon('gui/icons/high.svg'), '(1)'))
        self.table_widget.item(15,
                               0).setToolTip(self.tr('Histogram correlation'))
        self.table_widget.setItem(16, 0,
                                  QTableWidgetItem(self.tr('Chi-Square')))
        self.table_widget.setItem(
            16, 2, QTableWidgetItem(QIcon('gui/icons/low.svg'), '(0)'))
        self.table_widget.item(16,
                               0).setToolTip(self.tr('Histogram Chi-Square'))
        self.table_widget.setItem(17, 0,
                                  QTableWidgetItem(self.tr('Chi-Square 2')))
        self.table_widget.setItem(
            17, 2, QTableWidgetItem(QIcon('gui/icons/low.svg'), '(0)'))
        self.table_widget.item(17,
                               0).setToolTip(self.tr('Alternative Chi-Square'))
        self.table_widget.setItem(18, 0,
                                  QTableWidgetItem(self.tr('Intersection')))
        self.table_widget.setItem(
            18, 2,
            QTableWidgetItem(QIcon('gui/icons/high.svg'),
                             '(+' + u'\u221e' + ')'))
        self.table_widget.item(18,
                               0).setToolTip(self.tr('Histogram intersection'))
        self.table_widget.setItem(19, 0,
                                  QTableWidgetItem(self.tr('Hellinger')))
        self.table_widget.setItem(
            19, 2, QTableWidgetItem(QIcon('gui/icons/low.svg'), '(0)'))
        self.table_widget.item(19, 0).setToolTip(
            self.tr('Histogram Hellinger distance'))
        self.table_widget.setItem(20, 0,
                                  QTableWidgetItem(self.tr('Divergence')))
        self.table_widget.setItem(
            20, 2, QTableWidgetItem(QIcon('gui/icons/low.svg'), '(0)'))
        self.table_widget.item(20, 0).setToolTip(
            self.tr('Kullback-Leibler divergence'))

        for i in range(self.table_widget.rowCount()):
            modify_font(self.table_widget.item(i, 0), bold=True)
        self.table_widget.setSelectionMode(QAbstractItemView.SingleSelection)
        self.table_widget.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.table_widget.resizeColumnsToContents()
        self.table_widget.setMaximumWidth(250)
        self.table_widget.setAlternatingRowColors(True)
        self.stopped = False

        self.comp_label.setEnabled(False)
        self.normal_radio.setEnabled(False)
        self.difference_radio.setEnabled(False)
        self.ssim_radio.setEnabled(False)
        self.butter_radio.setEnabled(False)
        self.gray_check.setEnabled(False)
        self.equalize_check.setEnabled(False)
        self.metric_button.setEnabled(False)
        self.table_widget.setEnabled(False)

        load_button.clicked.connect(self.load)
        self.normal_radio.clicked.connect(self.change)
        self.difference_radio.clicked.connect(self.change)
        self.butter_radio.clicked.connect(self.change)
        self.gray_check.stateChanged.connect(self.change)
        self.equalize_check.stateChanged.connect(self.change)
        self.ssim_radio.clicked.connect(self.change)
        self.evidence_viewer.viewChanged.connect(
            self.reference_viewer.changeView)
        self.reference_viewer.viewChanged.connect(
            self.evidence_viewer.changeView)
        self.metric_button.clicked.connect(self.metrics)

        top_layout = QHBoxLayout()
        top_layout.addWidget(load_button)
        top_layout.addStretch()
        top_layout.addWidget(self.comp_label)
        top_layout.addWidget(self.normal_radio)
        top_layout.addWidget(self.difference_radio)
        top_layout.addWidget(self.ssim_radio)
        top_layout.addWidget(self.butter_radio)
        top_layout.addWidget(self.gray_check)
        top_layout.addWidget(self.equalize_check)

        metric_layout = QVBoxLayout()
        index_label = QLabel(self.tr('Image Quality Assessment'))
        index_label.setAlignment(Qt.AlignCenter)
        modify_font(index_label, bold=True)
        metric_layout.addWidget(index_label)
        metric_layout.addWidget(self.table_widget)
        metric_layout.addWidget(self.metric_button)

        center_layout = QHBoxLayout()
        center_layout.addWidget(self.evidence_viewer)
        center_layout.addWidget(self.reference_viewer)
        center_layout.addLayout(metric_layout)

        main_layout = QVBoxLayout()
        main_layout.addLayout(top_layout)
        main_layout.addLayout(center_layout)
        self.setLayout(main_layout)

    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('Reference: {}'.format(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 change(self):
        if self.normal_radio.isChecked():
            result = self.reference
            self.gray_check.setEnabled(False)
            self.equalize_check.setEnabled(False)
            self.last_radio = self.normal_radio
        elif self.difference_radio.isChecked():
            result = self.difference
            self.gray_check.setEnabled(True)
            self.equalize_check.setEnabled(True)
            self.last_radio = self.difference_radio
        elif self.ssim_radio.isChecked():
            result = self.ssim_map
            self.gray_check.setEnabled(False)
            self.equalize_check.setEnabled(True)
            self.last_radio = self.ssim_radio
        elif self.butter_radio.isChecked():
            result = self.butter_map
            self.gray_check.setEnabled(True)
            self.equalize_check.setEnabled(False)
            self.last_radio = self.butter_radio
        else:
            self.last_radio.setChecked(True)
            return
        if self.equalize_check.isChecked():
            result = equalize_img(result)
        if self.gray_check.isChecked():
            result = desaturate(result)
        self.reference_viewer.update_original(result)

    def metrics(self):
        progress = QProgressDialog(self.tr('Computing metrics...'),
                                   self.tr('Cancel'), 1,
                                   self.table_widget.rowCount(), self)
        progress.canceled.connect(self.cancel)
        progress.setWindowModality(Qt.WindowModal)
        img1 = cv.cvtColor(self.evidence, cv.COLOR_BGR2GRAY)
        img2 = cv.cvtColor(self.reference, cv.COLOR_BGR2GRAY)
        x = img1.astype(np.float64)
        y = img2.astype(np.float64)

        rmse = self.rmse(x, y)
        progress.setValue(1)
        if self.stopped:
            return
        sam = sewar.sam(img1, img2)
        progress.setValue(2)
        if self.stopped:
            return
        ergas = sewar.ergas(img1, img2)
        progress.setValue(3)
        if self.stopped:
            return
        mb = self.mb(x, y)
        progress.setValue(4)
        if self.stopped:
            return
        pfe = self.pfe(x, y)
        progress.setValue(5)
        if self.stopped:
            return
        psnr = self.psnr(x, y)
        progress.setValue(6)
        if self.stopped:
            return
        try:
            psnrb = sewar.psnrb(img1, img2)
        except NameError:
            # FIXME: C'\`e un bug in psnrb (https://github.com/andrewekhalel/sewar/issues/17)
            psnrb = 0
        progress.setValue(7)
        if self.stopped:
            return
        ssim, self.ssim_map = self.ssim(x, y)
        progress.setValue(8)
        if self.stopped:
            return
        mssim = sewar.msssim(img1, img2).real
        progress.setValue(9)
        if self.stopped:
            return
        rase = sewar.rase(img1, img2)
        progress.setValue(10)
        if self.stopped:
            return
        scc = sewar.scc(img1, img2)
        progress.setValue(11)
        if self.stopped:
            return
        uqi = sewar.uqi(img1, img2)
        progress.setValue(12)
        if self.stopped:
            return
        vifp = sewar.vifp(img1, img2)
        progress.setValue(13)
        if self.stopped:
            return
        ssimul = self.ssimul(img1, img2)
        progress.setValue(14)
        if self.stopped:
            return
        butter, self.butter_map = self.butter(img1, img2)
        progress.setValue(15)
        if self.stopped:
            return

        sizes = [256, 256, 256]
        ranges = [0, 256] * 3
        channels = [0, 1, 2]
        hist1 = cv.calcHist([self.evidence], channels, None, sizes, ranges)
        hist2 = cv.calcHist([self.reference], channels, None, sizes, ranges)
        correlation = cv.compareHist(hist1, hist2, cv.HISTCMP_CORREL)
        progress.setValue(16)
        if self.stopped:
            return
        chi_square = cv.compareHist(hist1, hist2, cv.HISTCMP_CHISQR)
        progress.setValue(17)
        if self.stopped:
            return
        chi_square2 = cv.compareHist(hist1, hist2, cv.HISTCMP_CHISQR_ALT)
        progress.setValue(18)
        if self.stopped:
            return
        intersection = cv.compareHist(hist1, hist2, cv.HISTCMP_INTERSECT)
        progress.setValue(19)
        if self.stopped:
            return
        hellinger = cv.compareHist(hist1, hist2, cv.HISTCMP_HELLINGER)
        progress.setValue(20)
        if self.stopped:
            return
        divergence = cv.compareHist(hist1, hist2, cv.HISTCMP_KL_DIV)
        progress.setValue(21)

        self.table_widget.setItem(0, 1,
                                  QTableWidgetItem('{:.2f}'.format(rmse)))
        self.table_widget.setItem(1, 1, QTableWidgetItem('{:.4f}'.format(sam)))
        self.table_widget.setItem(2, 1,
                                  QTableWidgetItem('{:.2f}'.format(ergas)))
        self.table_widget.setItem(3, 1, QTableWidgetItem('{:.4f}'.format(mb)))
        self.table_widget.setItem(4, 1, QTableWidgetItem('{:.2f}'.format(pfe)))
        if psnr > 0:
            self.table_widget.setItem(
                5, 1, QTableWidgetItem('{:.2f} dB'.format(psnr)))
        else:
            self.table_widget.setItem(
                5, 1, QTableWidgetItem('+' + u'\u221e' + ' dB'))
        self.table_widget.setItem(6, 1,
                                  QTableWidgetItem('{:.2f}'.format(psnrb)))
        self.table_widget.setItem(7, 1,
                                  QTableWidgetItem('{:.4f}'.format(ssim)))
        self.table_widget.setItem(8, 1,
                                  QTableWidgetItem('{:.4f}'.format(mssim)))
        self.table_widget.setItem(9, 1,
                                  QTableWidgetItem('{:.2f}'.format(rase)))
        self.table_widget.setItem(10, 1,
                                  QTableWidgetItem('{:.4f}'.format(scc)))
        self.table_widget.setItem(11, 1,
                                  QTableWidgetItem('{:.4f}'.format(uqi)))
        self.table_widget.setItem(12, 1,
                                  QTableWidgetItem('{:.4f}'.format(vifp)))
        self.table_widget.setItem(13, 1,
                                  QTableWidgetItem('{:.4f}'.format(ssimul)))
        self.table_widget.setItem(14, 1,
                                  QTableWidgetItem('{:.2f}'.format(butter)))
        self.table_widget.setItem(
            15, 1, QTableWidgetItem('{:.2f}'.format(correlation)))
        self.table_widget.setItem(
            16, 1, QTableWidgetItem('{:.2f}'.format(chi_square)))
        self.table_widget.setItem(
            17, 1, QTableWidgetItem('{:.2f}'.format(chi_square2)))
        self.table_widget.setItem(
            18, 1, QTableWidgetItem('{:.2f}'.format(intersection)))
        self.table_widget.setItem(19, 1,
                                  QTableWidgetItem('{:.2f}'.format(hellinger)))
        self.table_widget.setItem(
            20, 1, QTableWidgetItem('{:.2f}'.format(divergence)))
        self.table_widget.resizeColumnsToContents()
        self.table_widget.setEnabled(True)
        self.metric_button.setEnabled(False)
        self.ssim_radio.setEnabled(True)
        self.butter_radio.setEnabled(True)

    def cancel(self):
        self.stopped = True

    @staticmethod
    def rmse(x, y):
        return np.sqrt(np.mean(np.square(x - y)))

    @staticmethod
    def mb(x, y):
        mx = np.mean(x)
        my = np.mean(y)
        return (mx - my) / mx

    @staticmethod
    def pfe(x, y):
        return np.linalg.norm(x - y) / np.linalg.norm(x) * 100

    @staticmethod
    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)

    @staticmethod
    def corr(x, y):
        return np.corrcoef(x, y)[0, 1]

    @staticmethod
    def psnr(x, y):
        k = np.mean(np.square(x - y))
        if k == 0:
            return -1
        return 20 * math.log10((255**2) / k)

    @staticmethod
    def butter(x, y):
        try:
            exe = butter_exe()
            if exe is None:
                raise FileNotFoundError
            temp_dir = QTemporaryDir()
            if temp_dir.isValid():
                filename1 = os.path.join(temp_dir.path(), 'img1.png')
                cv.imwrite(filename1, x)
                filename2 = os.path.join(temp_dir.path(), 'img2.png')
                cv.imwrite(filename2, y)
                filename3 = os.path.join(temp_dir.path(), 'map.ppm')
                p = run([exe, filename1, filename2, filename3], stdout=PIPE)
                value = float(p.stdout)
                heatmap = cv.imread(filename3, cv.IMREAD_COLOR)
                return value, heatmap
        except FileNotFoundError:
            return -1, cv.cvtColor(np.full_like(x, 127), cv.COLOR_GRAY2BGR)

    @staticmethod
    def ssimul(x, y):
        try:
            exe = ssimul_exe()
            if exe is None:
                raise FileNotFoundError
            temp_dir = QTemporaryDir()
            if temp_dir.isValid():
                filename1 = os.path.join(temp_dir.path(), 'img1.png')
                cv.imwrite(filename1, x)
                filename2 = os.path.join(temp_dir.path(), 'img2.png')
                cv.imwrite(filename2, y)
                p = run([exe, filename1, filename2], stdout=PIPE)
                value = float(p.stdout)
                return value
        except FileNotFoundError:
            return -1
Ejemplo n.º 4
0
class ComparisonWidget(ToolWidget):
    def __init__(self, image, parent=None):
        super(ComparisonWidget, self).__init__(parent)

        load_button = QPushButton(self.tr('Load reference...'))
        self.file_label = QLabel()
        modify_font(self.file_label, bold=True)
        self.comp_label = QLabel(self.tr('Comparison:'))
        self.normal_radio = QRadioButton(self.tr('Normal'))
        self.normal_radio.setChecked(True)
        self.diff_radio = QRadioButton(self.tr('Difference'))
        self.gray_check = QCheckBox(self.tr('Grayscale'))
        self.equal_check = QCheckBox(self.tr('Equalized'))
        self.map_radio = QRadioButton(self.tr('SSIM Map'))
        self.last_radio = self.normal_radio

        self.comp_label.setEnabled(False)
        self.normal_radio.setEnabled(False)
        self.diff_radio.setEnabled(False)
        self.gray_check.setEnabled(False)
        self.equal_check.setEnabled(False)
        self.map_radio.setEnabled(False)

        self.evidence = image
        self.reference = np.full_like(image, 127)
        self.difference = np.full_like(image, 127)
        self.equalized = np.full_like(image, 127)
        self.indexmap = np.full_like(image, 127)
        self.evidence_viewer = ImageViewer(self.evidence, None,
                                           self.tr('Evidence'))
        self.reference_viewer = ImageViewer(self.reference, None,
                                            self.tr('Reference'))

        self.table_widget = QTableWidget(5, 2)
        self.table_widget.setHorizontalHeaderLabels(
            [self.tr('Index'), self.tr('Value')])
        self.table_widget.setItem(0, 0, QTableWidgetItem(self.tr('MSE')))
        self.table_widget.setItem(1, 0, QTableWidgetItem(self.tr('COVAR')))
        self.table_widget.setItem(2, 0, QTableWidgetItem(self.tr('PSNR')))
        self.table_widget.setItem(3, 0, QTableWidgetItem(self.tr('SSIM')))
        self.table_widget.setItem(4, 0, QTableWidgetItem(self.tr('CORR')))
        for i in range(self.table_widget.rowCount()):
            modify_font(self.table_widget.item(i, 0), bold=True)
        self.table_widget.setEnabled(False)

        load_button.clicked.connect(self.load)
        self.normal_radio.toggled.connect(self.change)
        self.diff_radio.toggled.connect(self.change)
        self.gray_check.stateChanged.connect(self.change)
        self.equal_check.stateChanged.connect(self.change)
        self.map_radio.toggled.connect(self.change)
        self.evidence_viewer.view_changed.connect(
            self.reference_viewer.change_view)
        self.reference_viewer.view_changed.connect(
            self.evidence_viewer.change_view)

        top_layout = QHBoxLayout()
        top_layout.addWidget(load_button)
        top_layout.addWidget(self.file_label)
        top_layout.addStretch()
        top_layout.addWidget(self.comp_label)
        top_layout.addWidget(self.normal_radio)
        top_layout.addWidget(self.map_radio)
        top_layout.addWidget(self.diff_radio)
        top_layout.addWidget(self.gray_check)
        top_layout.addWidget(self.equal_check)

        index_layout = QVBoxLayout()
        index_label = QLabel(self.tr('Image Quality Assessment'))
        modify_font(index_label, bold=True)
        index_layout.addWidget(index_label)
        index_layout.addWidget(self.table_widget)

        center_layout = QHBoxLayout()
        center_layout.addWidget(self.evidence_viewer)
        center_layout.addWidget(self.reference_viewer)
        center_layout.addLayout(index_layout)

        main_layout = QVBoxLayout()
        main_layout.addLayout(top_layout)
        main_layout.addLayout(center_layout)
        self.setLayout(main_layout)

    def load(self):
        filename, basename, image = load_image(self)
        if filename is None:
            return
        if image.shape != self.evidence.shape:
            QMessageBox.critical(
                self, self.tr('Error'),
                self.tr('Evidence and reference must have the same size!'))
            return
        self.file_label.setText(basename)
        self.reference = image
        self.difference = normalize_mat(
            cv.absdiff(self.evidence, self.reference))
        self.equalized = cv.merge(
            [cv.equalizeHist(c) for c in cv.split(self.difference)])

        x = cv.cvtColor(self.evidence, cv.COLOR_BGR2GRAY).astype(np.float32)
        y = cv.cvtColor(self.reference, cv.COLOR_BGR2GRAY).astype(np.float32)
        mse = self.mse(x, y)
        covar = self.covar(x, y)
        psnr = self.psnr(mse)
        ssim, self.indexmap = self.ssim(x, y)
        corr = self.corr(x, y)
        self.table_widget.setItem(0, 1, QTableWidgetItem('{:.4f}'.format(mse)))
        self.table_widget.setItem(1, 1,
                                  QTableWidgetItem('{:.4f}'.format(covar)))
        if psnr > 0:
            self.table_widget.setItem(
                2, 1, QTableWidgetItem('{:.2f} dB'.format(psnr)))
        else:
            self.table_widget.setItem(
                2, 1, QTableWidgetItem('+' + u'\u221e' + ' dB'))
        self.table_widget.setItem(3, 1,
                                  QTableWidgetItem('{:.4f}'.format(ssim)))
        self.table_widget.setItem(4, 1,
                                  QTableWidgetItem('{:.4f}'.format(corr)))
        self.table_widget.setEnabled(True)

        self.comp_label.setEnabled(True)
        self.normal_radio.setEnabled(True)
        self.diff_radio.setEnabled(True)
        self.gray_check.setEnabled(True)
        self.equal_check.setEnabled(True)
        self.map_radio.setEnabled(True)
        self.change()

    def change(self):
        self.gray_check.setEnabled(False)
        self.equal_check.setEnabled(False)
        if self.normal_radio.isChecked():
            self.reference_viewer.update_original(self.reference)
            self.last_radio = self.normal_radio
        elif self.diff_radio.isChecked():
            self.gray_check.setEnabled(True)
            self.equal_check.setEnabled(True)
            if self.equal_check.isChecked():
                result = self.equalized
            else:
                result = self.difference
            if self.gray_check.isChecked():
                result = desaturate(result)
            self.reference_viewer.update_original(result)
            self.last_radio = self.diff_radio
        elif self.map_radio.isChecked():
            self.reference_viewer.update_original(self.indexmap)
            self.last_radio = self.map_radio
        else:
            self.last_radio.setChecked(True)

    @staticmethod
    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
        indexmap = cv.divide(t3, t1)
        ssim = cv.mean(indexmap)[0]
        return ssim, 255 - normalize_mat(indexmap, to_bgr=True)

    @staticmethod
    def corr(x, y):
        return np.corrcoef(x, y)[0, 1]

    @staticmethod
    def covar(x, y):
        return np.std(cv.absdiff(x, y))

    @staticmethod
    def mse(x, y):
        return cv.mean(cv.pow(x - y, 2))[0]

    @staticmethod
    def psnr(mse):
        k = math.sqrt(mse)
        if k == 0:
            return -1
        return 20 * math.log10((255**2) / k)
Ejemplo n.º 5
0
class mainWindow(QObject):

    signalRun = Signal(SpiderThread)
    signalRunApi = Signal(apiTester)
    def __init__(self):
        QObject.__init__(self)  # must init parent QObject,if you want to use signal
        self.widget = QWidget()
        self.ipLabel = QLabel(self.widget)
        self.thread = QThread()
        self.worker = Worker()
        self.worker.moveToThread(self.thread)
        self.man = SpiderThread()
        self.api = apiTester()
        # 1 2:loop 3: time
        self.testStatus = [False,1,0,"ip","mac"]

        # advance config
        self.findCoreStop = True
        self.cleanCacheSet = False
        self.useApiTest = False
        self.showTestProgress = True
        self.saveTestLog = False
        self.saveLogPath = ""
        self.chromePath =  ""
        self.showChrome = False
        self.coreDumpPath = ""

        # ui form
        self.passwordLabel = QLabel(self.widget)

        self.ipLineEdit = QLineEdit(self.widget)
        self.passwordLineEdit = QLineEdit(self.widget)

        self.startBtn = QPushButton(self.widget)
        self.stopBtn = QPushButton(self.widget)

        self.messageBox = QTextEdit(self.widget)
        self.messageBox.setReadOnly(True)

        self.userLabel = QLabel(self.widget)
        self.userLineEdit = QLineEdit(self.widget)

        self.intervalLabel = QLabel(self.widget)
        self.intervalSpinBox = QSpinBox(self.widget)

        self.loopLabel = QLabel(self.widget)
        self.loopSpinBox = QSpinBox(self.widget)

        self.intervalSpinBox.setRange(0,9999)
        self.loopSpinBox.setRange(1,9999)

        self.radioReboot = QRadioButton(self.widget)
        self.radioProvision = QRadioButton(self.widget)
        self.radioFactory = QRadioButton(self.widget)

        # self.apiCheckBox = QCheckBox(self.widget)

        self.menu = QMenu()
        self.gxpAction = QAction("Classic UI")
        self.grp2602Action = QAction("Ant Design UI")
        self.gxpAction.setCheckable(True)
        self.grp2602Action.setCheckable(True)
        self.menu.addAction(self.gxpAction)
        self.menu.addAction(self.grp2602Action)
        self.webLabel = QLabel(self.widget)
        self.webBtn = QPushButton(self.widget)
        self.webBtn.setMenu(self.menu)
        self.clearBtn = QPushButton(self.widget)
        self.messageList = deque()
        self.timer = QTimer()


        self.advanceBtn = QPushButton(self.widget)
        self.infoLabel = QLabel(self.widget)

        # provision widget
        self.provWidget = QWidget(self.widget)
        self.ver1Label = QLabel(self.provWidget)
        self.ver2Label = QLabel(self.provWidget)
        self.ver3Label = QLabel(self.provWidget)
        self.ver1LineEdit = QLineEdit(self.provWidget)
        self.ver2LineEdit = QLineEdit(self.provWidget)
        self.ver3LineEdit = QLineEdit(self.provWidget)

        self.dir1Label = QLabel(self.provWidget)
        self.dir2Label = QLabel(self.provWidget)
        self.dir3Label = QLabel(self.provWidget)
        self.dir1LineEdit = QLineEdit(self.provWidget)
        self.dir2LineEdit = QLineEdit(self.provWidget)
        self.dir3LineEdit = QLineEdit(self.provWidget)

        self.radioHttp = QRadioButton(self.provWidget)
        self.radioHttps = QRadioButton(self.provWidget)
        self.radioTftp = QRadioButton(self.provWidget)
        self.radioFtp = QRadioButton(self.provWidget)
        self.radioFtps = QRadioButton(self.provWidget)
        self.radioWindow = QRadioButton(self.provWidget)

        # advance widget
        self.advanceWidget = QWidget()
        self.checkCoreBox = QCheckBox(self.advanceWidget)
        self.cleanCache = QCheckBox(self.advanceWidget)
        self.checkSaveLogBox = QCheckBox(self.advanceWidget)
        self.selectDirBtn = QPushButton(self.advanceWidget)
        self.saveDirLabel = QLabel(self.advanceWidget)
        self.saveDirLabel.setStyleSheet("background:white")
        self.checkProgressBox = QCheckBox(self.advanceWidget)
        self.advanceOkBtn = QPushButton(self.advanceWidget)
        self.selectChromeBtn = QPushButton(self.advanceWidget)
        self.chromePathLabel = QLabel(self.advanceWidget)
        self.chromePathLabel.setStyleSheet("background:white")
        self.checkShowChromeBox = QCheckBox(self.advanceWidget)
        self.chromeLabel = QLabel(self.advanceWidget)
        self.pcapLabel = QLabel(self.advanceWidget)
        self.apiCheckBox = QCheckBox(self.advanceWidget)
        self.corePathLabel = QLabel(self.advanceWidget)
        self.corePathLabel.setStyleSheet("background:white")
        self.corePathBtn = QPushButton(self.advanceWidget)

        self.interfaceMenu = QComboBox(self.advanceWidget)
        self.interfaceMenu.addItem('Default')

        self.aiOptionBox= QCheckBox(self.advanceWidget)

        a = IFACES
        print(a)
        for i in a.keys():
            print(a[i].description)
            self.interfaceMenu.addItem(a[i].description)

        # connect singal and slot
        self.startBtn.clicked.connect(self.clickedStarBtn)
        self.radioProvision.clicked.connect(self.clickedProvision)
        self.radioReboot.clicked.connect(self.clickedOthers)
        self.radioFactory.clicked.connect(self.clickedOthers)
        self.stopBtn.clicked.connect(self.clickedStopBtn)
        self.grp2602Action.triggered.connect(self.clickedGrp2602)
        self.gxpAction.triggered.connect(self.clickedGxpType)
        self.timer.timeout.connect(self.updateMessage)
        self.apiCheckBox.stateChanged.connect(self.apiTestBoxCheck)
        self.clearBtn.clicked.connect(self.clickedClearBtn)

        self.advanceBtn.clicked.connect(self.clickedAdvanceBtn)
        self.advanceOkBtn.clicked.connect(self.clickedAdvanceOkBtn)
        self.checkSaveLogBox.stateChanged.connect(self.saveLogBoxCheck)
        self.selectChromeBtn.clicked.connect(self.clickedSelectChromeBtn)
        self.selectDirBtn.clicked.connect(self.clickedSelectDirBtn)
        self.corePathBtn.clicked.connect(self.clickedCorePathBtn)

        self.worker.signalJobEnd.connect(self.slotTestStoped)
        self.worker.apiTestFinished.connect(self.slotTestStoped)
        self.signalRun.connect(self.worker.dowork)
        self.signalRunApi.connect(self.worker.doworkApi)

        # self.man.signalUpdateMessage.connect(self.pushMessage)

    def setupUI(self):
        # set text content /value
        self.widget.setWindowTitle("自动重启升降级测试工具")
        self.ipLabel.setText("初始IP:")
        self.passwordLabel.setText("密码:")
        self.startBtn.setText("开始测试")
        self.stopBtn.setText("停止测试")
        self.userLabel.setText("用户名:")
        self.intervalLabel.setText("间隔时间:")
        self.loopLabel.setText("测试次数:")
        self.intervalSpinBox.setValue(130)
        self.radioFactory.setText("恢复出厂")
        self.radioProvision.setText("升降级")
        self.radioReboot.setText("重启")
        self.ver1Label.setText("版本 1:")
        self.ver2Label.setText("版本 2:")
        self.ver3Label.setText("版本 3:")
        self.dir1Label.setText("路径 1:")
        self.dir2Label.setText("路径 2:")
        self.dir3Label.setText("路径 3:")
        self.radioHttp.setText("Http")
        self.radioHttps.setText("Https")
        self.radioTftp.setText("Tftp")
        self.radioFtp.setText("Ftp")
        self.radioFtps.setText("Ftps")
        self.apiCheckBox.setText("使用API测试,配置CoreDump下载路径")
        self.webLabel.setText("网页类型:")
        self.webBtn.setText("请选择UI类型")
        self.clearBtn.setText("清空输入")

        self.advanceWidget.setWindowTitle("高级设置")
        self.advanceBtn.setText("高级设置")
        self.checkCoreBox.setText("发现Core Dump时停止测试")
        self.cleanCache.setText("清除页面cache")
        self.checkSaveLogBox.setText("保存测试日志")
        self.selectDirBtn.setText("浏览")
        self.checkProgressBox.setText("显示底部状态条")
        self.advanceOkBtn.setText("OK")
        self.checkShowChromeBox.setText("测试时显示Chrome浏览器")
        self.selectChromeBtn.setText("浏览")
        self.chromeLabel.setText("Chrome浏览器路径")
        self.infoLabel.setText("未开始测试")
        self.pcapLabel.setText("Net Interface")
        self.corePathBtn.setText("浏览")
        self.radioWindow.setText("网页拖拽文件")
        # self.aiOptionBox.setText("AI")

        #init value
        self.saveDirLabel.hide()
        self.selectDirBtn.hide()

        self.gxpAction.setChecked(True)
        self.radioReboot.click()
        self.radioHttp.click()
        self.stopBtn.setEnabled(False)
        self.passwordLineEdit.setEchoMode(QLineEdit.PasswordEchoOnEdit)

        # set position-------------------------------
        xPos = 20
        yPos = 30
        colum2 = xPos +200

        # line 1
        self.ipLabel.move(xPos,yPos)
        self.intervalLabel.move(colum2,yPos)
        self.intervalSpinBox.move(colum2+60,yPos-2)
        self.ipLineEdit.move(xPos+50,yPos-2)

        # line 2
        line2 = yPos +40
        self.passwordLabel.move(xPos,line2)
        self.passwordLineEdit.move(xPos+50,line2-2)
        self.loopLabel.move(colum2,line2)
        self.loopSpinBox.move(colum2+60,line2-2)

        # line3
        line3 = yPos +80
        self.userLabel.move(xPos,line3)
        self.userLineEdit.move(xPos+50,line3-2)

        self.radioReboot.move(colum2,line3)
        self.radioFactory.move(colum2+60,line3)
        self.radioProvision.move(colum2,line3+30)

        self.webLabel.move(xPos,line3+40)
        self.webBtn.move(xPos+60,line3+35)

        # provWidget
        self.provWidget.resize(400,130)
        self.provWidget.move(xPos,line3+70)
        spaceY = 30
        x = 0
        y = 0
        cl = 200
        self.ver1Label.move(x,y)
        self.ver1LineEdit.move(x+50,y)
        self.ver2Label.move(x,y+spaceY)
        self.ver2LineEdit.move(x+50,y+spaceY)
        self.ver3Label.move(x,y+spaceY*2)
        self.ver3LineEdit.move(x+50,y+spaceY*2)

        self.dir1Label.move(cl,y)
        self.dir1LineEdit.move(cl+50,y)
        self.dir2Label.move(cl,y+spaceY)
        self.dir2LineEdit.move(cl+50,y+spaceY)
        self.dir3Label.move(cl,y+spaceY*2)
        self.dir3LineEdit.move(cl+50,y+spaceY*2)

        self.radioHttp.move(x,y+spaceY*3)
        self.radioHttps.move(x+50,y+spaceY*3)
        self.radioTftp.move(x+110,y+spaceY*3)
        self.radioFtp.move(x+160,y+spaceY*3)
        self.radioFtps.move(x+210,y+spaceY*3)
        self.radioWindow.move(x+265,y+spaceY*3)

        # advance widget
        self.advanceWidget.resize(300,400)
        x = 20
        y = 20
        space = 30

        self.checkCoreBox.move(x,y)
        self.cleanCache.move(x,y+space)
        self.checkProgressBox.move(x,y+space*2)
        self.checkShowChromeBox.move(x,y+space*3)
        self.apiCheckBox.move(x,y+space*4)
        self.corePathBtn.move(x-2,y+space*5-8)
        self.corePathLabel.move(x+35,y+space*5-8)

        y += 40
        self.chromeLabel.move(x,y+space*4+10)
        self.selectChromeBtn.move(x-2,y+space*5)
        self.chromePathLabel.move(x+35,y+space*5+2)

        self.checkSaveLogBox.move(x,y+space*6+10)
        self.selectDirBtn.move(x-2,y+space*7)
        self.saveDirLabel.move(x+35,y+space*7+2)
        self.advanceOkBtn.move(x+170,y+space*10+10)
        self.interfaceMenu.move(x-5,y+space*8+10)
        self.pcapLabel.move(x,y+space*8-2)
        # self.aiOptionBox.move(x, y+space*9+8)
        # set size
        self.messageBox.resize(373,155)
        # self.widget.resize(410,400)
        self.loopSpinBox.resize(60,25)
        self.intervalSpinBox.resize(60,25)
        self.webBtn.resize(100,25)

        self.saveDirLabel.resize(185,22)
        self.selectDirBtn.resize(32,24)
        self.selectChromeBtn.resize(32,24)
        self.chromePathLabel.resize(185,22)
        self.infoLabel.resize(400, 25)
        self.corePathBtn.resize(32,24)
        self.corePathLabel.resize(185,22)
        #
        self.provWidget.hide()
        self.changePosition(True)
        self.widget.show()
        self.loadCache()
    # ----------------end of setupUI ---------------------


    def changePosition(self,hide):
        xPos = 20
        if hide:
            buttonLine = 200
            self.widget.resize(420,415)
        else:
            buttonLine = 310
            self.widget.resize(420,524)

        self.startBtn.move(xPos,buttonLine)
        self.stopBtn.move(xPos+90,buttonLine)
        self.clearBtn.move(xPos+180,buttonLine)
        self.advanceBtn.move(xPos+270,buttonLine)
        self.messageBox.move(xPos,buttonLine+30)
        boxH = self.messageBox.height()
        self.infoLabel.move(xPos,buttonLine+boxH+35)

    def setItemEnable(self,enable):
        self.provWidget.setEnabled(enable)
        self.ipLineEdit.setEnabled(enable)
        self.passwordLineEdit.setEnabled(enable)
        self.userLineEdit.setEnabled(enable)
        self.intervalSpinBox.setEnabled(enable)
        self.loopSpinBox.setEnabled(enable)
        self.radioFactory.setEnabled(enable)
        self.radioReboot.setEnabled(enable)
        self.radioProvision.setEnabled(enable)
        self.advanceBtn.setEnabled(enable)
        self.startBtn.setEnabled(enable)
        self.clearBtn.setEnabled(enable)
        if self.useApiTest:
            self.webBtn.setEnabled(False)
        else:
            self.webBtn.setEnabled(enable)
        self.stopBtn.setEnabled(not enable)

    def outputError(self,str):
        appstr = "<span style=\"color:red\">"
        appstr += str + "</span>"
        self.messageBox.append(appstr)

    def outputWarning(self,str):
        appstr = "<span style=\"color:orange\">"
        appstr += str + "</span>"
        self.messageBox.append(appstr)

    def loadCache(self):
        file = QFile("cache")
        if not file.open(QIODevice.ReadOnly | QIODevice.Text):
            return

        inStream = QTextStream(file)

        # ip
        self.ipLineEdit.setText(inStream.readLine())
        # passwordLabel
        self.passwordLineEdit.setText(inStream.readLine())
        # user
        self.userLineEdit.setText(inStream.readLine())
        # ver1
        self.ver1LineEdit.setText(inStream.readLine())
        self.dir1LineEdit.setText(inStream.readLine())
        # ver2
        self.ver2LineEdit.setText(inStream.readLine())
        self.dir2LineEdit.setText(inStream.readLine())
        # ver3
        self.ver3LineEdit.setText(inStream.readLine())
        self.dir3LineEdit.setText(inStream.readLine())

        self.intervalSpinBox.setValue(int(inStream.readLine()))
        self.loopSpinBox.setValue(int(inStream.readLine()))

        # web type button
        webType = inStream.readLine()
        if webType == "gxpAction":
            self.grp2602Action.setChecked(False)
            self.gxpAction.setChecked(True)
            self.webBtn.setText(self.gxpAction.text())
        else:
            self.grp2602Action.setChecked(True)
            self.gxpAction.setChecked(False)
            self.webBtn.setText(self.grp2602Action.text())

        testType = inStream.readLine()
        if testType == "reboot":
            self.radioReboot.setChecked(True)
        elif testType == "provision":
            self.radioProvision.setChecked(True)
            self.changePosition(False)
            self.provWidget.show()
        else:
            self.radioFactory.setChecked(True)

        serverType = inStream.readLine()
        if serverType == "Http":
            self.radioHttp.setChecked(True)
        elif serverType == "Https":
            self.radioHttps.setChecked(True)
        elif serverType == "Tftp":
            self.radioTftp.setChecked(True)
        elif serverType == "Ftp":
            self.radioFtp.setChecked(True)
        elif serverType == "Ftps":            
            self.radioFtps.setChecked(True)
        else:
            self.radioWindow.setChecked(True)

        if inStream.readLine() == "True":
            self.findCoreStop = True
        else:
            self.findCoreStop = False

        if inStream.readLine() == "True":
            self.cleanCacheSet = True
        else:
            self.cleanCacheSet = False

        if inStream.readLine() == "True":
            self.useApiTest = True
            self.webBtn.setEnabled(False)
        else:
            self.useApiTest = False
            self.corePathBtn.hide()
            self.corePathLabel.hide()

        if inStream.readLine() == "True":
            self.showTestProgress = True
        else:
            self.showTestProgress = False
            self.infoLabel.hide()

        if inStream.readLine() == "True":
            self.showChrome = True
        else:
            self.showChrome = False

        self.chromePath = inStream.readLine()

        if inStream.readLine() == "True":
            self.saveTestLog = True
        else:
            self.saveTestLog = False

        self.saveLogPath = inStream.readLine()

        self.coreDumpPath = inStream.readLine()

        file.close()

    def saveCache(self):
        file = QFile("cache")
        if not file.open(QIODevice.WriteOnly):
            return

        content = self.ipLineEdit.text() + "\n"
        content += self.passwordLineEdit.text() + "\n"
        content += self.userLineEdit.text() + "\n"
        content += self.ver1LineEdit.text() + "\n"
        content += self.dir1LineEdit.text() + "\n"
        content += self.ver2LineEdit.text() + "\n"
        content += self.dir2LineEdit.text() + "\n"
        content += self.ver3LineEdit.text() + "\n"
        content += self.dir3LineEdit.text() + "\n"

        content += str(self.intervalSpinBox.value()) + "\n"
        content += str(self.loopSpinBox.value()) + "\n"

        if self.gxpAction.isChecked():
            content += "gxpAction\n"
        else:
            content += "grp2602Action\n"

        if self.radioReboot.isChecked():
            content += "reboot\n"
        elif self.radioProvision.isChecked():
            content += "provision\n"
        else:
            content += "factory\n"

        if self.radioHttp.isChecked():
            content += "Http\n"
        elif self.radioHttps.isChecked():
            content += "Https\n"
        elif self.radioTftp.isChecked():
            content += "Tftp\n"
        elif self.radioFtp.isChecked():
            content += "Ftp\n"
        elif self.radioFtps.isChecked():
            content += "Ftps\n"
        else :
            content += "Window\n"

        content += str(self.findCoreStop) + "\n"
        content += str(self.cleanCacheSet) + "\n"
        content += str(self.useApiTest) + "\n"
        content += str(self.showTestProgress) + "\n"
        content += str(self.showChrome) + "\n"
        content += self.chromePath +"\n"
        content += str(self.saveTestLog) +"\n"
        content += self.saveLogPath +"\n"
        content += self.coreDumpPath +"\n"

        byteArr = bytes(content,"utf-8")
        file.write(QByteArray(byteArr))
        file.close()


    def checkBeforeRun(self):
        containError = False
        #---------check Ip address--------------
        if self.ipLineEdit.text() == "":
            containError = True
            self.outputError("IP地址不能为空!")
        else:
            pattern = re.compile("^((1[0-9][0-9]\.)|(2[0-4][0-9]\.)|(25[0-5]\.)|([1-9][0-9]\.)|([0-9]\.)){3}((1[0-9][0-9])|(2[0-4][0-9])|(25[0-5])|([1-9][0-9])|([0-9]))$")
            if not pattern.search(self.ipLineEdit.text()):
                containError = True
                self.outputError("IP地址格式错误,检查是否含有多余空格!(仅支持IPV4)")

        #------------------------
        if self.passwordLineEdit.text() == "":
            containError = True
            self.outputError("密码不能为空!")
        if self.userLineEdit.text() == "":
            containError = True
            self.outputError("用户名不能为空!")
        if self.intervalSpinBox.value() <= 40:
            self.outputWarning("间隔时间过短,可能对测试造成影响")
        if not self.radioProvision.isChecked() and not self.radioReboot.isChecked() and \
           not self.radioFactory.isChecked():
            containError = True
            self.outputError("必须选择测试方式(重启,升降级,恢复出厂)")

        # check provision ----------
        if self.radioProvision.isChecked():
            if self.ver1LineEdit.text() == "" or self.ver2LineEdit.text() == "" or \
               self.dir1LineEdit.text() == "" or self.dir2LineEdit.text() == "":
                containError = True
                self.outputError("升降级测试至少填上前两个版本及其路径")

            bin_name = ""
            if os.path.exists(os.path.abspath("config.ini") ):
                f = open(os.path.abspath("config.ini") , "r")
                line = f.readline()
                while line:
                    option = line.split("=")
                    if option[0] == "firmbinname":
                        if option[1].strip('"') != "":
                            filenamebin = option[1].strip()
                            bin_name = filenamebin.strip('"')
                        pass
                    line = f.readline()
                f.close()

            filename = os.path.join(self.dir1LineEdit.text(), bin_name)
            if not os.path.exists(filename) and self.radioWindow.isChecked():
                containError = True
                self.outputError("firmware1 文件不存在!" + filename)
            filename = os.path.join(self.dir2LineEdit.text(), bin_name)
            if not os.path.exists(filename) and self.radioWindow.isChecked():
                containError = True
                self.outputError("firmware2 文件不存在!" + filename)
           

            filename = os.path.join(self.dir3LineEdit.text(), bin_name)
            if self.ver3LineEdit.text() != "" and self.dir3LineEdit.text() == "":
                containError = True
                self.outputError("填写了版本3,但对应路径为空!")
            if self.dir3LineEdit.text() != "" and self.ver3LineEdit.text() == "":
                containError = True
                self.outputError("填写了路径3,但对应版本为空!")
            elif self.dir3LineEdit.text() != "" and self.radioWindow.isChecked() and not os.path.exists(filename):
                containError = True
                self.outputError("firmware3 文件不存在!" + filename)

            if not self.radioFtp.isChecked() and not self.radioFtps.isChecked() and \
               not self.radioHttp.isChecked() and not self.radioHttps.isChecked() and \
               not self.radioTftp.isChecked() and not self.radioWindow.isChecked():
                containError = True
                self.outputError("升降级测试必须选择服务器类型(Tftp,Ftp,Ftps,Http,Https)")
        return containError



    def startTest(self):
        ip = self.ipLineEdit.text()
        passwd = self.passwordLineEdit.text()
        username = self.userLineEdit.text()
        ptime = self.intervalSpinBox.value()
        loop = self.loopSpinBox.value()
        modelType = self.webBtn.text()
        if self.gxpAction.isChecked():
            device_type = "GXP21XX"
        elif self.grp2602Action.isChecked():
            device_type = "GRP260X"

        if self.radioReboot.isChecked():
            task_type = "reboot"
        elif self.radioProvision.isChecked():
            task_type = "provision"
            text_ver1 = self.ver1LineEdit.text()
            text_ver2 = self.ver2LineEdit.text()
            text_ver3 = self.ver3LineEdit.text()
            text_dir1 = self.dir1LineEdit.text()
            text_dir2 = self.dir2LineEdit.text()
            text_dir3 = self.dir3LineEdit.text()
            prov_dict = {"ver1": text_ver1.strip(), "dir1": text_dir1.strip(), "ver2": text_ver2.strip(),
                        "dir2": text_dir2.strip(), "ver3": text_ver3.strip(), "dir3": text_dir3.strip()}

            if self.radioHttp.isChecked():
                self.man.update_prov_setting("HTTP", prov_dict)
            elif self.radioHttps.isChecked():
                self.man.update_prov_setting("HTTPS", prov_dict)
            elif self.radioTftp.isChecked():
                self.man.update_prov_setting("TFTP", prov_dict)
            elif self.radioFtp.isChecked():
                self.man.update_prov_setting("FTP", prov_dict)
            elif self.radioFtps.isChecked():
                self.man.update_prov_setting("FTPS", prov_dict)
            elif self.radioWindow.isChecked():
                self.man.update_prov_setting("browser", prov_dict)

        else:
            task_type = "reset"

        coredump_stop = True
        headless_flag = False
        clean_cache = False
        if self.checkCoreBox.isChecked() == False:
            self.messageBox.append("Find core dump will not stop")
            coredump_stop = False
        if self.cleanCache.isChecked() == True:
            clean_cache = True
            
        if self.checkShowChromeBox.isChecked() == True or self.radioWindow.isChecked() == True:
            headless_flag = False
        else:
            headless_flag = True

        # ai_mode = False
        # if self.aiOptionBox.isChecked() == True:
        #     ai_mode = True

        browser_path = ""
        if self.chromePathLabel.text() != "":
            browser_path = self.chromePathLabel.text()

        self.testStatus = [True,1,0,"ip",""]
        print(self.interfaceMenu.currentText())
        self.man.setStatus(self.testStatus)
        self.man.setMessageList(self.messageList)
        self.man.update_setting(ip.strip(), username.strip(), passwd.strip(), device_type, \
                                task_type, loop, ptime, coredump_stop, headless_flag, browser_path, \
                                clean_cache, self.interfaceMenu.currentText(), False)
    
    def startApiTest(self):
        ip = self.ipLineEdit.text()
        passwd = self.passwordLineEdit.text()
        username = self.userLineEdit.text()
        ptime = self.intervalSpinBox.value()
        loop = self.loopSpinBox.value()
        
        testType = "Reboot"
        if self.radioProvision.isChecked():
            testType = "Provision"
        self.api.setValue(ip,username,passwd,ptime,loop,testType)

        v1 = self.ver1LineEdit.text()
        v2 = self.ver2LineEdit.text()
        v3 = self.ver3LineEdit.text()
        d1 = self.dir1LineEdit.text()
        d2 = self.dir2LineEdit.text()
        d3 = self.dir3LineEdit.text()
        self.api.setVersion(v1,v2,v3,d1,d2,d3)

        self.api.setTestStatus(self.testStatus,self.messageList,self.coreDumpPath)

        if self.radioHttp.isChecked():
            self.api.setServerType("http")
        elif self.radioHttps.isChecked():
            self.api.setServerType("https")
        elif self.radioTftp.isChecked():
            self.api.setServerType("tftp")
        elif self.radioFtp.isChecked():
            self.api.setServerType("ftp")
        else: #self.radioFtps.isChecked()
            self.api.setServerType("ftps")
        
        self.api.setFoundCoreStop(self.findCoreStop)


    # slot ---------------------------------
    def apiTestBoxCheck(self,state):
        if state == 2:
            self.corePathBtn.show()
            self.corePathLabel.show()
        else:
            self.corePathBtn.hide()
            self.corePathLabel.hide()

    def clickedCorePathBtn(self):
        dir = QFileDialog.getExistingDirectory(self.advanceWidget,"选择Core Dump存放路径","/home")
        if dir != "":
            self.corePathLabel.setText(dir)
            self.coreDumpPath = dir

    def clickedSelectDirBtn(self):
        dir = QFileDialog.getExistingDirectory(self.advanceWidget,"选择日志存放路径","/home")
        if dir != "":
            self.saveDirLabel.setText(dir)
            self.saveLogPath = dir

    def clickedSelectChromeBtn(self):
        fileName = QFileDialog.getOpenFileName(self.advanceWidget,"选择谷歌浏览器","/home","Chrome (*.exe)")
        if fileName != "":
            self.chromePathLabel.setText(fileName[0])
            self.chromePath = fileName[0]

    def saveLogBoxCheck(self,state):
        if state == 2: # checked
            self.selectDirBtn.show()
            self.saveDirLabel.show()
        else:
            self.selectDirBtn.hide()
            self.saveDirLabel.hide()

    def clickedAdvanceOkBtn(self):
        self.findCoreStop = self.checkCoreBox.isChecked()
        self.cleanCacheSet = self.cleanCache.isChecked()
        self.useApiTest = self.apiCheckBox.isChecked()
        self.showTestProgress = self.checkProgressBox.isChecked()
        self.saveTestLog = self.checkSaveLogBox.isChecked()
        self.saveLogPath = self.saveDirLabel.text()
        self.showChrome = self.checkShowChromeBox.isChecked()
        self.chromePath = self.chromePathLabel.text()
        self.coreDumpPath = self.corePathLabel.text()

        if self.useApiTest:
            self.webBtn.setEnabled(False)
            self.corePathBtn.show()
            self.corePathLabel.show()
        else:
            self.webBtn.setEnabled(True)
            self.corePathBtn.hide()
            self.corePathLabel.hide()

        if self.showTestProgress:
            self.infoLabel.show()
        else:
            self.infoLabel.hide()
                
        self.saveCache()
        self.advanceWidget.hide()


    def clickedAdvanceBtn(self):
        self.advanceWidget.hide()
        self.checkCoreBox.setChecked(self.findCoreStop)
        self.cleanCache.setChecked(self.cleanCacheSet)
        self.apiCheckBox.setChecked(self.useApiTest)
        self.checkProgressBox.setChecked(self.showTestProgress)
        self.checkSaveLogBox.setChecked(self.saveTestLog)
        self.saveDirLabel.setText(self.saveLogPath)
        self.checkShowChromeBox.setChecked(self.showChrome)
        self.chromePathLabel.setText(self.chromePath)
        self.corePathLabel.setText(self.coreDumpPath)
        self.advanceWidget.show()

    def slotTestStoped(self):
        self.testStatus[0] = False
        self.setItemEnable(True)
        self.timer.stop()
        self.updateMessage()
        self.thread.quit()

        # save Test log
        if self.saveTestLog:
            fileName = time.strftime("%Y_%m_%d.%H_%M_%S.",time.localtime())
            if self.radioReboot.isChecked():
                fileName += "reboot"
            elif self.radioProvision:
                fileName += "provision"
            else:
                fileName += "factoryReset"
            fileName += ".htm"
            if self.saveLogPath == "":
                self.outputWarning("日志地址没有设置,无法保存")
            else:
                fileName = self.saveLogPath + "\\" + fileName
                print(fileName)

                file = QFile(fileName)
                if not file.open(QIODevice.WriteOnly):
                    self.outputError("打开文件错误,保存日志失败")
                    return

                byteArr = bytes(self.messageBox.toHtml(),"utf-8")
                file.write(QByteArray(byteArr))
                file.close()

    def clickedClearBtn(self):
        self.ipLineEdit.setText("")
        self.passwordLineEdit.setText("")
        self.userLineEdit.setText("")
        self.ver1LineEdit.setText("")
        self.dir1LineEdit.setText("")
        self.ver2LineEdit.setText("")
        self.dir2LineEdit.setText("")
        self.ver3LineEdit.setText("")
        self.dir3LineEdit.setText("")

    def clickedStarBtn(self):
        if self.checkBeforeRun():
            return
        self.messageBox.clear()
        self.saveCache()
        self.messageBox.append("Init Setting...")
        self.setItemEnable(False)
        self.timer.start(500)
        self.thread.start()

        # deside use what to test
        if self.useApiTest:
            if self.radioFactory.isChecked():
                self.outputWarning("Api not support Factory Reset, will test as Gxp type web driver")	
                self.clickedGxpType()
                self.startTest()
                self.signalRun.emit(self.man)
            else:
                self.startApiTest()
                self.signalRunApi.emit(self.api)
        else:
            self.startTest()
            self.signalRun.emit(self.man)

    def clickedStopBtn(self):
        self.stopBtn.setEnabled(False)
        self.testStatus[0] = False
        self.man.quit()
        self.outputWarning("正在停止...")

    def clickedProvision(self):
        self.provWidget.show()
        self.changePosition(False)

    def clickedOthers(self):
        self.provWidget.hide()
        self.changePosition(True)

    def clickedGxpType(self):
        self.gxpAction.setChecked(True)
        self.grp2602Action.setChecked(False)
        self.webBtn.setText(self.gxpAction.text())

    def clickedGrp2602(self):
        self.gxpAction.setChecked(False)
        self.grp2602Action.setChecked(True)
        self.webBtn.setText(self.grp2602Action.text())

    def updateMessage(self):
        while len(self.messageList) >0:
            info = self.messageList.popleft()
            self.messageBox.append(info)
        if self.testStatus[0] == False:
            self.infoLabel.setText("未开始测试")
        else:
            info = "第" + str(self.testStatus[1]) + "次测试   "
            if self.testStatus[2] > 0:
                info += "等待:{} 秒".format( self.testStatus[2] )
            else:
                info += "运行中"
            
            info += "  " + self.testStatus[3]
            info += "  " + self.testStatus[4]
            self.infoLabel.setText(info)