Ejemplo n.º 1
0
    def fileDialog_saveClassificationConfig(self):
        if not valid_file_selected_in(self.QCBox_SamplingFile):
            iface.messageBar().pushMessage(
                "AcATaMa",
                "Error, please select a sampling file to save configuration",
                level=Qgis.Warning)
            return
        # get file path to suggest to save but not in tmp directory
        file_path = get_file_path_of_layer(
            self.QCBox_SamplingFile.currentLayer())
        path, filename = os.path.split(file_path)
        if self.tmp_dir in path:
            path = os.path.split(
                get_file_path_of_layer(
                    self.QCBox_ThematicRaster.currentLayer()))[0]
        suggested_filename = os.path.splitext(os.path.join(
            path, filename))[0] + "_acatama.yml" if filename else ""

        file_out, _ = QFileDialog.getSaveFileName(
            self, self.tr("Save settings and classification status"),
            suggested_filename,
            self.tr("Yaml (*.yaml *.yml);;All files (*.*)"))
        if file_out != '':
            sampling_layer = self.QCBox_SamplingFile.currentLayer()
            if sampling_layer in Classification.instances:
                Classification.instances[sampling_layer].save_config(file_out)
                iface.messageBar().pushMessage("AcATaMa",
                                               "File saved successfully",
                                               level=Qgis.Success)
            else:
                iface.messageBar().pushMessage(
                    "AcATaMa",
                    "Failed to save, there isn't any configuration to save",
                    level=Qgis.Warning)
Ejemplo n.º 2
0
    def export_to_csv(self):
        # get file path to suggest to save but not in tmp directory
        from AcATaMa.gui.acatama_dockwidget import AcATaMaDockWidget as AcATaMa
        file_path = get_file_path_of_layer(
            AcATaMa.dockwidget.QCBox_SamplingFile_AA.currentLayer())
        path, filename = os.path.split(file_path)
        if AcATaMa.dockwidget.tmp_dir in path:
            path = os.path.split(
                get_file_path_of_layer(
                    AcATaMa.dockwidget.QCBox_ThematicRaster.currentLayer()))[0]
        suggested_filename = os.path.splitext(os.path.join(
            path, filename))[0] + "_results.csv" if filename else ""

        file_out, _ = QFileDialog.getSaveFileName(
            self, self.tr("Export accuracy assessment results to csv"),
            suggested_filename, self.tr("CSV files (*.csv);;All files (*.*)"))
        if file_out != '':
            try:
                accuracy_assessment_results.export_to_csv(
                    self.accuracy_assessment, file_out,
                    self.accuracy_assessment.csv_separator,
                    self.accuracy_assessment.csv_decimal)
                self.MsgBar.pushMessage(
                    "File saved successfully \"{}\"".format(
                        os.path.basename(file_out)),
                    level=Qgis.Success)
            except Exception as err:
                self.MsgBar.pushMessage(
                    "Failed saving the csv file: {}".format(err),
                    level=Qgis.Critical,
                    duration=-1)
Ejemplo n.º 3
0
def get_pixel_count_by_pixel_values_parallel(layer, band, pixel_values=None):
    """Get the total pixel count for each pixel values"""

    if pixel_values is None:
        pixel_values = get_pixel_values(layer, band)

    # split the image in chunks, the 0,0 is left-upper corner
    gdal_file = gdal.Open(get_file_path_of_layer(layer), gdal.GA_ReadOnly)
    chunk_size = 1000
    input_data = []
    for y in chunks(range(gdal_file.RasterYSize), chunk_size):
        yoff = y[0]
        ysize = len(y)
        for x in chunks(range(gdal_file.RasterXSize), chunk_size):
            xoff = x[0]
            xsize = len(x)

            input_data.append((get_file_path_of_layer(layer), band,
                               pixel_values, xoff, yoff, xsize, ysize))

    # compute and merge all parallel process returns in one result
    with multiprocessing.Pool(multiprocessing.cpu_count()) as pool:
        imap_it = pool.imap(pixel_count_in_chunk, input_data)
        pixel_counts = np.sum([proc for proc in imap_it], axis=0).tolist()
        return dict(zip(pixel_values, pixel_counts))
Ejemplo n.º 4
0
    def fileDialog_saveSamplingClassification(self):
        if not valid_file_selected_in(self.QCBox_SamplingFile):
            iface.messageBar().pushMessage("AcATaMa", "Error, please first select a sampling file",
                                           level=Qgis.Warning)
            return
        # get instance
        sampling_layer = self.QCBox_SamplingFile.currentLayer()
        if sampling_layer in Classification.instances:
            classification = Classification.instances[sampling_layer]
            if not classification.is_completed:
                quit_msg = "The classification for this sampling file is not completed, " \
                           "the result will have all sampling partially classified." \
                           "\nDo you want to continue?"
                reply = QMessageBox.question(None, 'The classification is not completed',
                                             quit_msg, QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)
                if reply == QMessageBox.No:
                    return
        else:
            iface.messageBar().pushMessage("AcATaMa",
                                           "Error, the classification for the sampling selected has not been initiated",
                                           level=Qgis.Warning)
            return
        # get file path to suggest to save but not in tmp directory
        file_path = get_file_path_of_layer(self.QCBox_SamplingFile.currentLayer())
        path, filename = os.path.split(file_path)
        if self.tmp_dir in path:
            path = os.path.split(get_file_path_of_layer(self.QCBox_ThematicRaster.currentLayer()))[0]
        suggested_filename = os.path.splitext(os.path.join(path, filename))[0] + "_classified.gpkg" if filename else ""

        file_out, _ = QFileDialog.getSaveFileName(self, self.tr("Save sampling file with the classification"),
                                                  suggested_filename,
                                                  self.tr("GeoPackage files (*.gpkg);;Shape files (*.shp);;All files (*.*)"))
        if file_out != '':
            classification.save_sampling_classification(file_out)
            iface.messageBar().pushMessage("AcATaMa", "File saved successfully", level=Qgis.Success)
Ejemplo n.º 5
0
def do_clipping_with_shape(target_layer, shape_layer, out_path, dst_nodata=None):
    target_file = get_file_path_of_layer(target_layer)
    filename, ext = os.path.splitext(out_path)
    tmp_file = filename + "_tmp" + ext
    # set the nodata
    dst_nodata = "-dstnodata {}".format(dst_nodata) if dst_nodata not in [None, -1] else ""
    # set the file path for the area of interest
    # check if the shape is a memory layer, then save and used it
    if not os.path.isfile(get_file_path_of_layer(shape_layer)):
        tmp_memory_fd, tmp_memory_file = tempfile.mkstemp(prefix='memory_layer_', suffix='.gpkg')
        QgsVectorFileWriter.writeAsVectorFormat(shape_layer, tmp_memory_file, "System", shape_layer.crs(), "GPKG")
        os.close(tmp_memory_fd)
        shape_file = tmp_memory_file
    else:
        shape_file = get_file_path_of_layer(shape_layer)
    # clipping in shape
    return_code = call('gdalwarp -multi -wo NUM_THREADS=ALL_CPUS --config GDALWARP_IGNORE_BAD_CUTLINE YES'
                       ' -cutline "{}" {} "{}" "{}"'.format(shape_file, dst_nodata, target_file, tmp_file), shell=True)
    # create convert coordinates
    crsSrc = QgsCoordinateReferenceSystem(shape_layer.crs())
    crsDest = QgsCoordinateReferenceSystem(target_layer.crs())
    xform = QgsCoordinateTransform(crsSrc, crsDest, QgsProject.instance())
    # trim the boundaries using the maximum extent for all features
    box = []
    for f in shape_layer.getFeatures():
        g = f.geometry()
        g.transform(xform)
        f.setGeometry(g)
        if box:
            box.combineExtentWith(f.geometry().boundingBox())
        else:
            box = f.geometry().boundingBox()
    # intersect with the rater file extent
    box = box.intersect(target_layer.extent())
    # trim
    gdal.Translate(out_path, tmp_file, projWin=[box.xMinimum(), box.yMaximum(), box.xMaximum(), box.yMinimum()])
    # clean tmp file
    if not os.path.isfile(get_file_path_of_layer(shape_layer)) and os.path.isfile(tmp_memory_file):
        os.remove(tmp_memory_file)
    if os.path.isfile(tmp_file):
        os.remove(tmp_file)

    if return_code == 0:  # successfully
        return out_path
    else:
        iface.messageBar().pushMessage("AcATaMa", "Error while clipping the raster file with shape.",
                                       level=Qgis.Warning)
Ejemplo n.º 6
0
def get_pixel_count_by_pixel_values(layer, band, pixel_values=None):
    if pixel_values is None:
        pixel_values = get_pixel_values(layer, band)

    raster_numpy = gdalnumeric.LoadFile(get_file_path_of_layer(layer))
    pixel_counts = []
    for pixel_value in pixel_values:
        pixel_counts.append((raster_numpy == int(pixel_value)).sum())

    return dict(zip(pixel_values, pixel_counts))
Ejemplo n.º 7
0
    def file_dialog_save_acatama_state(self):
        if self.suggested_yml_file:
            suggested_filename = self.suggested_yml_file
        elif valid_file_selected_in(self.QCBox_ThematicRaster) or valid_file_selected_in(self.QCBox_SamplingFile):
            # get file path to suggest where to save
            if valid_file_selected_in(self.QCBox_ThematicRaster):
                file_path = get_file_path_of_layer(self.QCBox_ThematicRaster.currentLayer())
            else:
                file_path = get_file_path_of_layer(self.QCBox_SamplingFile.currentLayer())
            path, filename = os.path.split(file_path)
            suggested_filename = os.path.splitext(os.path.join(path, filename))[0] + "_acatama.yml" if filename else "_acatama.yml"
        else:
            suggested_filename = "_acatama.yml"

        file_out, _ = QFileDialog.getSaveFileName(self, self.tr("Save AcATaMa configuration and state"),
                                                  suggested_filename, self.tr("Yaml (*.yaml *.yml);;All files (*.*)"))
        if file_out != '':
            config.save(file_out)
            self.suggested_yml_file = file_out
            iface.messageBar().pushMessage("AcATaMa", "Configuration file saved successfully", level=Qgis.Success)
Ejemplo n.º 8
0
    def save_config(self, file_out):
        import yaml
        from AcATaMa.gui.acatama_dockwidget import AcATaMaDockWidget as AcATaMa

        def setup_yaml():
            """
            Keep dump ordered with orderedDict
            """
            represent_dict_order = lambda self, data: self.represent_mapping('tag:yaml.org,2002:map',
                                                                             list(data.items()))
            yaml.add_representer(OrderedDict, represent_dict_order)

        setup_yaml()

        data = OrderedDict()
        data["thematic_raster"] = \
            {"path": get_current_file_path_in(AcATaMa.dockwidget.QCBox_ThematicRaster, show_message=False),
             "band": int(AcATaMa.dockwidget.QCBox_band_ThematicRaster.currentText())
                if AcATaMa.dockwidget.QCBox_band_ThematicRaster.currentText() else None,
             "nodata": AcATaMa.dockwidget.nodata_ThematicRaster.value()}
        data["sampling_layer"] = get_file_path_of_layer(self.sampling_layer)
        data["dialog_size"] = self.dialog_size
        data["grid_view_widgets"] = {"columns": self.grid_columns, "rows": self.grid_rows}
        data["current_sample_idx"] = self.current_sample_idx
        data["fit_to_sample"] = self.fit_to_sample
        data["is_completed"] = self.is_completed
        data["view_widgets_config"] = self.view_widgets_config
        data["classification_buttons"] = self.buttons_config

        # save samples status
        points_config = {}
        for pnt_idx, point in enumerate(self.points):
            if point.is_classified:
                points_config[pnt_idx] = {"classif_id": point.classif_id, "shape_id": point.shape_id}
        data["points"] = points_config
        # save the samples order
        data["points_order"] = [p.shape_id for p in self.points]

        # save sampling selected in accuracy assessment
        data["accuracy_assessment_sampling_file"] = get_current_file_path_in(AcATaMa.dockwidget.QCBox_SamplingFile_AA,
                                                                             show_message=False)
        # save config of the accuracy assessment dialog if exists
        if self.accuracy_assessment:
            data["accuracy_assessment_dialog"] = {
                "area_unit": QgsUnitTypes.toString(self.accuracy_assessment.area_unit),
                "z_score": self.accuracy_assessment.z_score,
                "csv_separator": self.accuracy_assessment.csv_separator,
                "csv_decimal": self.accuracy_assessment.csv_decimal,
            }

        with open(file_out, 'w') as yaml_file:
            yaml.dump(data, yaml_file)
Ejemplo n.º 9
0
def export_to_csv(accu_asse, file_out, csv_separator, csv_decimal_separator):
    csv_rows = []
    csv_rows.append(["Classification accuracy assessment results"])
    csv_rows.append([])
    csv_rows.append(["Thematic raster:"])
    csv_rows.append([os.path.basename(accu_asse.ThematicR.file_path)])
    csv_rows.append([])
    csv_rows.append(["Sampling file:"])
    csv_rows.append([
        os.path.basename(
            get_file_path_of_layer(accu_asse.classification.sampling_layer))
    ])
    csv_rows.append([])
    csv_rows.append(["Classification status:"])
    csv_rows.append([
        "{}/{} samples classified".format(
            accu_asse.classification.total_classified,
            accu_asse.classification.num_points)
    ])

    ###########################################################################
    csv_rows.append([])
    csv_rows.append(["1) Error matrix:"])
    csv_rows.append(["", "", "Classified values"])
    labels = [
        "{} ({})".format(
            i, accu_asse.labels[str(i)] if str(i) in accu_asse.labels else "-")
        for i in accu_asse.values
    ]
    csv_rows.append(["", ""] + labels + [
        "Total", "User accuracy", "Total class area ({area_unit})".format(
            area_unit=accu_asse.pixel_area_unit), "Wi"
    ])

    for idx_row, value in enumerate(accu_asse.values):
        r = []
        if idx_row == 0:
            r.append("Thematic raster classes")
        else:
            r.append("")
        r.append(value)
        r += accu_asse.error_matrix[idx_row]
        r.append(sum(accu_asse.error_matrix[idx_row]))
        r.append(
            rf(accu_asse.error_matrix[idx_row][idx_row] /
               sum(accu_asse.error_matrix[idx_row])
               ) if sum(accu_asse.error_matrix[idx_row]) > 0 else "-")
        r.append(
            rf(accu_asse.thematic_pixels_count[value] *
               accu_asse.pixel_area_value))
        r.append(
            rf(accu_asse.thematic_pixels_count[value] / sum(
                [accu_asse.thematic_pixels_count[v]
                 for v in accu_asse.values])))
        csv_rows.append(r)

    csv_rows.append(["", "total"] +
                    [sum(t) for t in zip(*accu_asse.error_matrix)] +
                    [total_samples] + [""] + [sum_total_class_area])
    csv_rows.append(["", "Producer accuracy"] + [
        rf(col[idx_col] / sum(col)) if sum(col) > 0 else "-"
        for idx_col, col in enumerate(zip(*accu_asse.error_matrix))
    ] + [""] + [
        rf(
            sum([
                col[idx_col]
                for idx_col, col in enumerate(zip(*accu_asse.error_matrix))
            ]) / total_samples) if total_samples != 0 else "-"
    ])

    ###########################################################################
    csv_rows.append([])
    csv_rows.append(["2) Error matrix of estimated area proportion:"])
    csv_rows.append(["", "", "Classified values"])
    labels = [
        "{} ({})".format(
            i, accu_asse.labels[str(i)] if str(i) in accu_asse.labels else "-")
        for i in accu_asse.values
    ]
    csv_rows.append(["", ""] + labels + ["Wi"])

    error_matrix_area_prop = copy.deepcopy(accu_asse.error_matrix)
    for idx_row, row in enumerate(accu_asse.error_matrix):
        wi = accu_asse.thematic_pixels_count[accu_asse.values[idx_row]] / \
             total_pixels_classes
        for idx_col, value in enumerate(row):
            error_matrix_area_prop[idx_row][idx_col] = (
                value / sum(row)) * wi if sum(row) > 0 else 0

    for idx_row, value in enumerate(accu_asse.values):
        r = []
        if idx_row == 0:
            r.append("Thematic raster classes")
        else:
            r.append("")
        r.append(value)
        r += [rf(t) if t > 0 else "-" for t in error_matrix_area_prop[idx_row]]
        r.append(
            rf(sum(error_matrix_area_prop[idx_row])
               ) if sum(error_matrix_area_prop[idx_row]) > 0 else "-")
        csv_rows.append(r)

    csv_rows.append(["", "total"] +
                    [rf(sum(t)) for t in zip(*error_matrix_area_prop)])

    ###########################################################################
    csv_rows.append([])
    csv_rows.append(
        ["3) Quadratic error matrix of estimated area proportion:"])
    csv_rows.append(["", "", "Classified values"])
    labels = [
        "{} ({})".format(
            i, accu_asse.labels[str(i)] if str(i) in accu_asse.labels else "-")
        for i in accu_asse.values
    ]
    csv_rows.append(["", ""] + labels)

    quadratic_error_matrix = copy.deepcopy(accu_asse.error_matrix)
    for idx_row, row in enumerate(accu_asse.error_matrix):
        wi = accu_asse.thematic_pixels_count[accu_asse.values[idx_row]] / \
             total_pixels_classes
        for idx_col, value in enumerate(row):
            quadratic_error_matrix[idx_row][idx_col] = \
                (wi ** 2 * ((value / sum(row)) * (1 - (value / sum(row))) / (sum(row) - 1))) if sum(row) > 1 else 0

    for idx_row, value in enumerate(accu_asse.values):
        r = []
        if idx_row == 0:
            r.append("Thematic raster classes")
        else:
            r.append("")
        r.append(value)
        r += [rf(t) if t > 0 else "-" for t in quadratic_error_matrix[idx_row]]
        csv_rows.append(r)

    csv_rows.append(["", "total"] +
                    [rf(sum(t)**0.5) for t in zip(*quadratic_error_matrix)])

    ###########################################################################
    csv_rows.append([])
    csv_rows.append(["4) Accuracy matrices:"])
    csv_rows.append([])
    csv_rows.append(["User's accuracy matrix of estimated area proportion:"])
    csv_rows.append(["", "", "Classified values"])
    labels = [
        "{} ({})".format(
            i, accu_asse.labels[str(i)] if str(i) in accu_asse.labels else "-")
        for i in accu_asse.values
    ]
    csv_rows.append(["", ""] + labels)

    user_accuracy_matrix = copy.deepcopy(error_matrix_area_prop)
    for idx_row, row in enumerate(error_matrix_area_prop):
        for idx_col, value in enumerate(row):
            user_accuracy_matrix[idx_row][idx_col] = value / sum(row) if sum(
                row) > 0 else 0

    for idx_row, value in enumerate(accu_asse.values):
        r = []
        if idx_row == 0:
            r.append("Thematic raster classes")
        else:
            r.append("")
        r.append(value)
        r += [rf(t) if t > 0 else "-" for t in user_accuracy_matrix[idx_row]]
        csv_rows.append(r)

    csv_rows.append([])
    csv_rows.append(
        ["Producer's accuracy matrix of estimated area proportion:"])
    csv_rows.append(["", "", "Classified values"])
    labels = [
        "{} ({})".format(
            i, accu_asse.labels[str(i)] if str(i) in accu_asse.labels else "-")
        for i in accu_asse.values
    ]
    csv_rows.append(["", ""] + labels)

    producer_accuracy_matrix = copy.deepcopy(error_matrix_area_prop)
    for idx_col, col in enumerate(zip(*error_matrix_area_prop)):
        for idx_row, value in enumerate(col):
            producer_accuracy_matrix[idx_row][idx_col] = value / sum(
                col) if sum(col) > 0 else 0

    for idx_row, value in enumerate(accu_asse.values):
        r = []
        if idx_row == 0:
            r.append("Thematic raster classes")
        else:
            r.append("")
        r.append(value)
        r += [
            rf(t) if t > 0 else "-" for t in producer_accuracy_matrix[idx_row]
        ]
        csv_rows.append(r)

    csv_rows.append([])
    csv_rows.append(["Overall Accuracy:"])
    overall_accuracy = sum(
        [row[idx_row] for idx_row, row in enumerate(error_matrix_area_prop)])
    csv_rows.append([rf(overall_accuracy)])

    ###########################################################################
    csv_rows.append([])
    csv_rows.append(["5) Class area adjusted table:"])
    csv_rows.append([
        "", "Area ({area_unit})".format(area_unit=accu_asse.pixel_area_unit),
        "Error", "Lower limit", "Upper limit"
    ])

    total_area = 0

    for idx_row, value in enumerate(accu_asse.values):
        r = []
        r.append("{} ({})".format(
            value, accu_asse.labels[str(value)]
            if str(value) in accu_asse.labels else "-"))

        # area
        area = sum(list(
            zip(*error_matrix_area_prop))[idx_row]) * sum_total_class_area
        r.append(rf(area))
        total_area += area
        # error
        error = (sum(list(zip(*quadratic_error_matrix))[idx_row])**
                 0.5) * sum_total_class_area
        r.append(rf(error))
        # lower limit
        r.append(rf(area - accu_asse.z_score * error))
        # upper limit
        r.append(rf(area + accu_asse.z_score * error))
        csv_rows.append(r)

    csv_rows.append(["total"] + [rf(total_area)])

    # write CSV file
    with open(file_out, 'w') as csvfile:
        csv_w = csv.writer(csvfile, delimiter=str(csv_separator))
        # replace with the user define decimal separator
        if csv_decimal_separator != ".":
            for idx, row in enumerate(csv_rows):
                csv_rows[idx] = [
                    str(item).replace('.', csv_decimal_separator)
                    if isinstance(item, float) else item for item in row
                ]

        csv_w.writerows(csv_rows)
Ejemplo n.º 10
0
def get_html(accu_asse):
    ###########################################################################
    # #### preprocess common variables

    total_samples = sum([sum(r) for r in accu_asse.error_matrix])
    total_pixels_classes = sum(
        [accu_asse.thematic_pixels_count[v] for v in accu_asse.values])
    sum_total_class_area = total_pixels_classes * accu_asse.pixel_area_value

    if accu_asse.sampling_type in [
            'Simple random sampling post-stratified',
            'Stratified random sampling'
    ]:

        error_matrix_area_prop = copy.deepcopy(accu_asse.error_matrix)
        for idx_row, row in enumerate(accu_asse.error_matrix):
            wi = accu_asse.thematic_pixels_count[accu_asse.values[idx_row]] / \
                 total_pixels_classes
            for idx_col, value in enumerate(row):
                error_matrix_area_prop[idx_row][idx_col] = (
                    value / sum(row)) * wi if sum(row) > 0 else 0

        quadratic_error_matrix = copy.deepcopy(accu_asse.error_matrix)
        for idx_row, row in enumerate(accu_asse.error_matrix):
            wi = accu_asse.thematic_pixels_count[accu_asse.values[idx_row]] / \
                 total_pixels_classes
            for idx_col, value in enumerate(row):
                quadratic_error_matrix[idx_row][idx_col] = \
                    (wi ** 2 * ((value / sum(row)) * (1 - (value / sum(row))) / (sum(row) - 1))) if sum(row) > 1 else 0

    accuracy_table = error_matrix_area_prop if accu_asse.sampling_type == 'Stratified random sampling' else accu_asse.error_matrix

    ###########################################################################
    # #### html init
    html = '''
        <head>
        
        <style type="text/css">
        table {
          table-layout: fixed;
          white-space: normal!important;
          background: #ffffff;
          margin: 4px;
        }
        th {
          word-wrap: break-word;
          padding: 4px 6px;
          background: #efefef;
          valign: middle;
        }
        td {
          word-wrap: break-word;
          padding: 4px 6px;
          background: #efefef;
        }
        .highlight {
          background: #dddddd;
        }
        .th-rows {
          max-width: 120px;
        }
        .empty {
          background: #f9f9f9;
        }
        </style>
        </head>
        <body>
        '''
    html += "<h2>Classification accuracy assessment results</h2>"
    html += "<p><strong>Thematic raster:</strong> {}</p>".format(
        os.path.basename(accu_asse.ThematicR.file_path))
    html += "<p><strong>Sampling file:</strong> {}</p>".format(
        os.path.basename(
            get_file_path_of_layer(accu_asse.classification.sampling_layer)))
    html += "<p><strong>Sampling type:</strong> {}</p>".format(
        accu_asse.sampling_type)
    html += "<p><strong>Classification status:</strong> {}/{} samples classified</p>".format(
        accu_asse.classification.total_classified,
        accu_asse.classification.num_points)

    # warning block if the thematic has a geographic units
    if accu_asse.base_area_unit == QgsUnitTypes.AreaSquareDegrees:
        html += "<p style='color:black;background-color:#ffc53a;white-space:pre;padding:4px'><strong>Warning!</strong><br/>" \
                "The thematic raster has a geographic coordinate system, therefore all area values are not accurate.<br/>" \
                "For fix that use the UTM coordinate system.</p>"

    # warning block for samples outside the thematic raster area or inside the no data values
    if accu_asse.samples_outside_the_thematic:
        html += "<p style='color:black;background-color:#ffc53a;white-space:pre;padding:4px'><strong>Warning!</strong><br/>" \
                "There are {} samples classified that are outside the thematic raster area or inside the no data values:<br/>".format(
            len(accu_asse.samples_outside_the_thematic))
        for idx, sample in enumerate(accu_asse.samples_outside_the_thematic):
            html += "    {}) Sample ID: {}, Coordinate: {},{}<br/>".format(
                idx + 1, sample.shape_id, int(sample.QgsPnt.x()),
                int(sample.QgsPnt.y()))
        html += "These samples will be ignored for accuracy assessment results.</p>"

    ###########################################################################
    # #### 1) Error matrix

    html += "<p style='font-size:2px'><br/></p>"
    html += "<h3>1) Error matrix:</h3>"
    html += '''
        <table>
        <tbody>
        <tr>
        <td class="empty"></td>
        <td class="empty"></td>
         <th colspan="{table_size}">Classified values</th>
            <td class="empty"></td>
            <td class="empty"></td>
            <td class="empty"></td>
            <td class="empty"></td>
        </tr>
        <tr>
        <td class="empty"></td>
        <td class="empty"></td>
        '''.format(table_size=len(accu_asse.values))
    labels = [
        "{} ({})".format(
            i, accu_asse.labels[str(i)] if str(i) in accu_asse.labels else "-")
        for i in accu_asse.values
    ]
    html += "".join(["<th >" + str(i) + "</th>" for i in labels])
    html += '''
        <th>Total</th>
        <th>User accuracy</th>
        <th>Total class area ({area_unit})</th>
        <th>Wi</th>
        </tr>
        '''.format(area_unit=accu_asse.pixel_area_unit)
    for idx_row, value in enumerate(accu_asse.values):
        html += "<tr>"
        if idx_row == 0:
            html += '''
                <th  class="th-rows" rowspan="{table_size}">Thematic raster<br />classes</th>
                '''.format(table_size=len(accu_asse.values))

        html += "<th>{value}</th>".format(value=value)
        html += "".join([
            '''
            <td class="highlight">{table_field}</td>
            '''.format(table_field=t) for t in accu_asse.error_matrix[idx_row]
        ])
        html += '''
            <td>{total_row}</td>
            <td>{u_accuracy}</td>
            <td>{total_class_area}</td>
            <td>{wi}</td>
            </tr>
            '''.format(
            total_row=sum(accu_asse.error_matrix[idx_row]),
            u_accuracy=rf(accuracy_table[idx_row][idx_row] /
                          sum(accuracy_table[idx_row]))
            if sum(accuracy_table[idx_row]) > 0 else "-",
            total_class_area=rf(accu_asse.thematic_pixels_count[value] *
                                accu_asse.pixel_area_value),
            wi=rf(accu_asse.thematic_pixels_count[value] /
                  total_pixels_classes))
    html += '''    
        <tr>
        <td class="empty"></td>
          <th>Total</th>
        '''
    html += "".join([
        '''
                <td>{total_col}</td>
                '''.format(total_col=sum(t))
        for t in zip(*accu_asse.error_matrix)
    ])
    html += '''
        <td>{total_total}</td>
        '''.format(total_total=total_samples)
    html += '''
        <td class="empty"></td>
        '''
    html += '''
        <td>{total_classes_area}</td>
        '''.format(total_classes_area=rf(sum_total_class_area))
    html += '''
        <td class="empty"></td>
        </tr>
        <tr>
        <td class="empty"></td>
          <th>Producer accuracy</th>
        '''
    for idx_col, col in enumerate(zip(*accuracy_table)):
        html += '''
            <td>{p_accuracy}</td>
            '''.format(p_accuracy=rf(col[idx_col] /
                                     sum(col)) if sum(col) > 0 else "-")
    html += '''
        <td class="empty"></td>
        <td class="empty"></td>
        '''
    html += '''
        <td class="empty"></td>
        <td class="empty"></td>
        </tr>
        </tbody>
        </table>
        '''

    ###########################################################################
    # #### 2) Accuracy

    if accu_asse.sampling_type in [
            'Simple random sampling', 'Simple random sampling post-stratified'
    ]:
        # overall
        overall_accuracy = sum([
            row[idx_row] for idx_row, row in enumerate(accu_asse.error_matrix)
        ]) / total_samples
        standard_deviation = (overall_accuracy * (1 - overall_accuracy) /
                              (total_samples - 1))**0.5
    if accu_asse.sampling_type == 'Stratified random sampling':
        # overall
        overall_accuracy = sum([
            row[idx_row] for idx_row, row in enumerate(error_matrix_area_prop)
        ])
        overall_variance = sum([
            ((accu_asse.thematic_pixels_count[value] / total_pixels_classes)**
             2) * (accu_asse.error_matrix[idx_row][idx_row] /
                   sum(accu_asse.error_matrix[idx_row])) *
            (1 - (accu_asse.error_matrix[idx_row][idx_row] /
                  sum(accu_asse.error_matrix[idx_row]))) /
            (sum(accu_asse.error_matrix[idx_row]) - 1)
            for idx_row, value in enumerate(accu_asse.values)
        ])
        standard_deviation = overall_variance**0.5

    html += "<p style='font-size:2px'><br/></p>"
    html += "<h3>2) Accuracy:</h3>"

    html += "<h4>Overall:</h4>"
    # Overall Accuracy
    html += '''
            <table>
            <tbody>
            <tr>
            <td><strong>Overall Accuracy</strong></td>
            <td><strong>Standard deviation</strong></td>
            </tr>
            <tr>
            <td class="highlight">{overall_accuracy}</td>
            <td>{standard_deviation}</td>
            </tr>'''.format(overall_accuracy=rf(overall_accuracy),
                            standard_deviation=rf(standard_deviation))
    html += '''
            </tbody>
            </table>
            '''
    # user's accuracy
    html += "<h4>User:</h4>"
    html += '''
            <table>
            <tbody>
            <tr>
            <td class="empty"></td>
            '''.format(table_size=len(accu_asse.values))
    headers = ["User's accuracy", "Standard deviation"]
    html += "".join(["<th>" + str(h) + "</th>" for h in headers])
    html += "</tr>"
    for idx_row, value in enumerate(accu_asse.values):
        html += "<tr>"
        html += "<th >{} ({})</th>".format(
            value, accu_asse.labels[str(value)]
            if str(value) in accu_asse.labels else "-")
        # accuracy
        accuracy = accuracy_table[idx_row][idx_row] / sum(
            accuracy_table[idx_row])
        html += '''<td class="highlight">{}</th>'''.format(rf(accuracy))
        # standard error
        html += '''<td>{}</th>'''.format(
            rf((accuracy * (1 - accuracy) /
                (sum(accu_asse.error_matrix[idx_row]) - 1))**0.5))
        html += "</tr>"
    html += '''
            </tbody>
            </table>
            '''
    # producer's accuracy
    html += "<h4>Producer:</h4>"
    html += '''
            <table>
            <tbody>
            <tr>
            <td class="empty"></td>
            '''.format(table_size=len(accu_asse.values))
    headers = ["Producer's accuracy", "Standard deviation"]
    html += "".join(["<th>" + str(h) + "</th>" for h in headers])
    html += "</tr>"
    for idx_row, value in enumerate(accu_asse.values):
        html += "<tr>"
        html += "<th >{} ({})</th>".format(
            value, accu_asse.labels[str(value)]
            if str(value) in accu_asse.labels else "-")
        # accuracy
        accuracy = accuracy_table[idx_row][idx_row] / sum(
            list(zip(*accuracy_table))[idx_row])
        html += '''<td class="highlight">{}</th>'''.format(rf(accuracy))
        # standard error
        if accu_asse.sampling_type in [
                'Simple random sampling',
                'Simple random sampling post-stratified'
        ]:
            producer_standard_error = (
                accuracy * (1 - accuracy) /
                (sum(list(zip(*accu_asse.error_matrix))[idx_row]) - 1))**0.5
        if accu_asse.sampling_type == 'Stratified random sampling':
            u_accuracy = accuracy_table[idx_row][idx_row] / sum(
                accuracy_table[idx_row])
            producer_standard_error = \
                (1/(sum([n*row[idx_row]/total_row for total_row, row, n in
                         zip([sum(r) for r in accu_asse.error_matrix], accu_asse.error_matrix,
                             [accu_asse.thematic_pixels_count[v] for v in accu_asse.values])])**2) *
                 sum([n**2*(1-accuracy)**2*u_accuracy*(1-u_accuracy)/(total_row-1) if idx == idx_row else
                      accuracy**2*n**2*row[idx_row]/total_row*(1-row[idx_row]/sum(list(zip(*accu_asse.error_matrix))[idx_row]))/(total_row-1)
                      for idx, total_row, row, n in zip(range(len(accu_asse.error_matrix)),
                                                        [sum(r) for r in accu_asse.error_matrix], accu_asse.error_matrix,
                                                        [accu_asse.thematic_pixels_count[v] for v in accu_asse.values])]))**0.5
        html += '''<td>{}</th>'''.format(rf(producer_standard_error))
        html += "</tr>"
    html += '''
            </tbody>
            </table>
            '''

    # #### 2b) Accuracy matrix of estimated area proportion

    if accu_asse.sampling_type == 'Stratified random sampling':
        html += "<p style='font-size:2px'><br/></p>"
        html += "<h3>2b) Accuracy matrix of estimated area proportion:</h3>"
        ###################################
        html += "<h4>User:</h4>"
        html += '''
            <table>
            <tbody>
            <tr>
            <td class="empty"></td>
            <td class="empty"></td>
             <th colspan="{table_size}">Classified values</th>
            </tr>
            <tr>
            <td class="empty"></td>
            <td class="empty"></td>
            '''.format(table_size=len(accu_asse.values))
        labels = [
            "{} ({})".format(
                i, accu_asse.labels[str(i)]
                if str(i) in accu_asse.labels else "-")
            for i in accu_asse.values
        ]
        html += "".join(["<th >" + str(i) + "</th>" for i in labels])
        html += "</tr>"

        user_accuracy_matrix = copy.deepcopy(error_matrix_area_prop)
        for idx_row, row in enumerate(error_matrix_area_prop):
            for idx_col, value in enumerate(row):
                user_accuracy_matrix[idx_row][idx_col] = value / sum(
                    row) if sum(row) > 0 else 0

        for idx_row, value in enumerate(accu_asse.values):
            html += "<tr>"
            if idx_row == 0:
                html += '''
                    <th  class="th-rows" rowspan="{table_size}">Thematic raster<br />classes</th>
                    '''.format(table_size=len(accu_asse.values))

            html += "<th>{value}</th>".format(value=value)
            html += "".join([
                '''
                <td class="highlight">{table_field}</td>
                '''.format(table_field=(rf(t)) if t > 0 else "-")
                for t in user_accuracy_matrix[idx_row]
            ])
            html += "</tr>"
        html += '''
            </tbody>
            </table>
            '''
        ###################################
        html += "<h4>Producer:</h4>"
        html += '''
            <table>
            <tbody>
            <tr>
            <td class="empty"></td>
            <td class="empty"></td>
             <th colspan="{table_size}">Classified values</th>
            </tr>
            <tr>
            <td class="empty"></td>
            <td class="empty"></td>
            '''.format(table_size=len(accu_asse.values))
        labels = [
            "{} ({})".format(
                i, accu_asse.labels[str(i)]
                if str(i) in accu_asse.labels else "-")
            for i in accu_asse.values
        ]
        html += "".join(["<th >" + str(i) + "</th>" for i in labels])
        html += "</tr>"

        producer_accuracy_matrix = copy.deepcopy(error_matrix_area_prop)
        for idx_col, col in enumerate(zip(*error_matrix_area_prop)):
            for idx_row, value in enumerate(col):
                producer_accuracy_matrix[idx_row][idx_col] = value / sum(
                    col) if sum(col) > 0 else 0

        for idx_row, value in enumerate(accu_asse.values):
            html += "<tr>"
            if idx_row == 0:
                html += '''
                    <th  class="th-rows" rowspan="{table_size}">Thematic raster<br />classes</th>
                    '''.format(table_size=len(accu_asse.values))

            html += "<th>{value}</th>".format(value=value)
            html += "".join([
                '''
                <td class="highlight">{table_field}</td>
                '''.format(table_field=(rf(t)) if t > 0 else "-")
                for t in producer_accuracy_matrix[idx_row]
            ])
            html += "</tr>"

        html += '''
            </tbody>
            </table>
            '''

    ###########################################################################
    # #### 3) Error matrix of estimated area proportion

    if accu_asse.sampling_type in [
            'Simple random sampling post-stratified',
            'Stratified random sampling'
    ]:
        html += "<p style='font-size:2px'><br/></p>"
        html += "<h3>3) Error matrix of estimated area proportion:</h3>"
        html += '''
            <table>
            <tbody>
            <tr>
            <td class="empty"></td>
            <td class="empty"></td>
             <th colspan="{table_size}">Classified values</th>
                <td class="empty"></td>
            </tr>
            <tr>
            <td class="empty"></td>
            <td class="empty"></td>
            '''.format(table_size=len(accu_asse.values))
        labels = [
            "{} ({})".format(
                i, accu_asse.labels[str(i)]
                if str(i) in accu_asse.labels else "-")
            for i in accu_asse.values
        ]
        html += "".join(["<th >" + str(i) + "</th>" for i in labels])
        html += '''
            <th>Wi</th>
            </tr>
            '''
        for idx_row, value in enumerate(accu_asse.values):
            html += "<tr>"
            if idx_row == 0:
                html += '''
                    <th  class="th-rows" rowspan="{table_size}">Thematic raster<br />classes</th>
                    '''.format(table_size=len(accu_asse.values))

            html += "<th>{value}</th>".format(value=value)
            html += "".join([
                '''
                <td class="highlight">{table_field}</td>
                '''.format(table_field=(rf(t)) if t > 0 else "-")
                for t in error_matrix_area_prop[idx_row]
            ])
            html += '''
                <td>{wi}</td>
                </tr>
                '''.format(wi=rf(sum(error_matrix_area_prop[idx_row])) if
                           sum(error_matrix_area_prop[idx_row]) > 0 else "-")
        html += '''    
            <tr>
            <td class="empty"></td>
              <th>total</th>
            '''
        html += "".join([
            '''
                    <td>{total_col}</td>
                    '''.format(total_col=rf(sum(t)))
            for t in zip(*error_matrix_area_prop)
        ])
        html += '''
            <td></td>
            </tr>
            </tbody>
            </table>
            '''

    ###########################################################################
    # #### 4) Quadratic error matrix of estimated area proportion

    if accu_asse.sampling_type in [
            'Simple random sampling post-stratified',
            'Stratified random sampling'
    ]:
        html += "<p style='font-size:2px'><br/></p>"
        html += "<h3>4) Quadratic error matrix of estimated area proportion:</h3>"
        html += '''
            <table>
            <tbody>
            <tr>
            <td class="empty"></td>
            <td class="empty"></td>
             <th colspan="{table_size}">Classified values</th>
            </tr>
            <tr>
            <td class="empty"></td>
            <td class="empty"></td>
            '''.format(table_size=len(accu_asse.values))
        labels = [
            "{} ({})".format(
                i, accu_asse.labels[str(i)]
                if str(i) in accu_asse.labels else "-")
            for i in accu_asse.values
        ]
        html += "".join(["<th >" + str(i) + "</th>" for i in labels])
        html += "</tr>"

        for idx_row, value in enumerate(accu_asse.values):
            html += "<tr>"
            if idx_row == 0:
                html += '''
                    <th  class="th-rows" rowspan="{table_size}">Thematic raster<br />classes</th>
                    '''.format(table_size=len(accu_asse.values))

            html += "<th>{value}</th>".format(value=value)
            html += "".join([
                '''
                <td class="highlight">{table_field}</td>
                '''.format(table_field=(rf(t)) if t > 0 else "-")
                for t in quadratic_error_matrix[idx_row]
            ])
            html += "</tr>"
        html += '''    
            <tr>
            <td class="empty"></td>
              <th>total</th>
            '''
        html += "".join([
            '''
                        <td>{total_col}</td>
                        '''.format(total_col=rf(sum(t)**0.5))
            for t in zip(*quadratic_error_matrix)
        ])
        html += '''
            </tr>
            </tbody>
            </table>
            '''

    ###########################################################################
    # #### 3/5) Class area adjusted

    html += "<p style='font-size:2px'><br/></p>"
    html += "<h3>{}) Class area adjusted:</h3>".format(
        "3" if accu_asse.sampling_type == 'Simple random sampling' else "5")
    html += '''
        <table>
        <tbody>
        <tr>
        <td class="empty"></td>
        '''.format(table_size=len(accu_asse.values))
    headers = [
        "Area adjusted ({area_unit})".format(
            area_unit=accu_asse.pixel_area_unit), "Error", "Lower limit",
        "Upper limit"
    ]
    html += "".join(["<th >" + str(h) + "</th>" for h in headers])
    html += "</tr>"

    total_area = 0

    # the error for post-stratified
    if accu_asse.sampling_type == 'Simple random sampling post-stratified':
        std_dev_table = [[
            (1 - i / total_row)**2 * i / (total_row - 1) for i in row
        ] for total_row, row in zip([sum(r) for r in accu_asse.error_matrix],
                                    accu_asse.error_matrix)]
        wi = [
            accu_asse.thematic_pixels_count[value] / total_pixels_classes
            for value in accu_asse.values
        ]
        variance = [
            ((1 - total_samples / total_pixels_classes) / total_samples) *
            sum([w * s for w, s in zip(wi, std_dev_col)]) +
            (1 / (total_samples**2)) * sum([(1 - w) * s
                                            for w, s in zip(wi, std_dev_col)])
            for std_dev_col in zip(*std_dev_table)
        ]
        _error = [sum_total_class_area * v**0.5 for v in variance]

    for idx_row, value in enumerate(accu_asse.values):
        if accu_asse.sampling_type == 'Simple random sampling':
            p_k = sum(list(
                zip(*accu_asse.error_matrix))[idx_row]) / total_samples
            area = p_k * sum_total_class_area
            v_p_k = ((p_k) * (1 - p_k) / total_samples) * (
                total_pixels_classes - total_samples) / (total_pixels_classes -
                                                         1)
            error = (v_p_k**0.5) * sum_total_class_area
        if accu_asse.sampling_type == 'Simple random sampling post-stratified':
            area = sum(list(
                zip(*error_matrix_area_prop))[idx_row]) * sum_total_class_area
            error = _error[idx_row]
        if accu_asse.sampling_type == 'Stratified random sampling':
            area = sum(list(
                zip(*error_matrix_area_prop))[idx_row]) * sum_total_class_area
            error = (sum(list(zip(*quadratic_error_matrix))[idx_row])**
                     0.5) * sum_total_class_area

        html += "<tr>"
        html += "<th >{} ({})</th>".format(
            value, accu_asse.labels[str(value)]
            if str(value) in accu_asse.labels else "-")
        # area
        html += '''<td>{area}</th>'''.format(area=rf(area))
        total_area += area
        # error
        html += '''<td>{error}</th>'''.format(error=rf(error))
        # lower limit
        lower_limit = area - accu_asse.z_score * error
        lower_limit = 0 if lower_limit < 0 else lower_limit
        html += '''<td>{lower_limit}</th>'''.format(
            lower_limit=rf(lower_limit))
        # upper limit
        html += '''<td>{upper_limit}</th>'''.format(
            upper_limit=rf(area + accu_asse.z_score * error))
        html += "</tr>"

    html += '''    
        <tr>
          <th>total</th>
        '''
    html += '''<td>{total_area}</th>'''.format(total_area=rf(total_area))
    html += '''
        <td class="empty"></td>
        <td class="empty"></td>
        <td class="empty"></td>
        </tr>'''

    html += '''
        </tbody>
        </table>
        '''

    html += '''
        </body>
        '''

    return html
Ejemplo n.º 11
0
def get_html(accu_asse):
    html = '''
        <head>
        <style type="text/css">
        table {
          table-layout: fixed;
          white-space: normal!important;
          background: #ffffff;
        }
        th {
          word-wrap: break-word;
          padding: 2px;
          background: #efefef;
          valign: middle;
        }
        td {
          word-wrap: break-word;
          padding: 2px;
          background: #efefef;
        }
        .field-values {
          background: #dddddd;
        }
        .th-rows {
          max-width: 120px;
        }
        .empty {
          background: #f9f9f9;
        }
        </style>
        </head>
        <body>
        '''
    html += "<h2>Classification accuracy assessment results</h2>"
    html += "<p><strong>Thematic raster:</strong> {}</p>".format(
        os.path.basename(accu_asse.ThematicR.file_path))
    html += "<p><strong>Sampling file:</strong> {}</p>".format(
        os.path.basename(
            get_file_path_of_layer(accu_asse.classification.sampling_layer)))
    html += "<p><strong>Classification status:</strong> {}/{} samples classified</p>".format(
        accu_asse.classification.total_classified,
        accu_asse.classification.num_points)

    # warning block if the thematic has a geographic units
    if accu_asse.base_area_unit == QgsUnitTypes.AreaSquareDegrees:
        html += "<p style='color:black;background-color:#ffc53a;white-space:pre;padding:4px'><strong>Warning!</strong><br/>" \
                "The thematic raster has a geographic coordinate system, therefore all area values are not accurate.<br/>" \
                "For fix that use the UTM coordinate system.</p>"

    # warning block for samples outside the thematic raster area or inside the no data values
    if accu_asse.samples_outside_the_thematic:
        html += "<p style='color:black;background-color:#ffc53a;white-space:pre;padding:4px'><strong>Warning!</strong><br/>" \
                "There are {} samples classified that are outside the thematic raster area or inside the no data values:<br/>".format(
            len(accu_asse.samples_outside_the_thematic))
        for idx, sample in enumerate(accu_asse.samples_outside_the_thematic):
            html += "    {}) Sample ID: {}, Coordinate: {},{}<br/>".format(
                idx + 1, sample.shape_id, int(sample.QgsPnt.x()),
                int(sample.QgsPnt.y()))
        html += "These samples will be ignored for accuracy assessment results.</p>"

    ###########################################################################
    html += "<p style='font-size:2px'><br/></p>"
    html += "<h3>1) Error matrix (confusion matrix):</h3>"
    html += '''
        <table>
        <tbody>
        <tr>
        <td class="empty"></td>
        <td class="empty"></td>
         <th colspan="{table_size}">Classified values</th>
            <td class="empty"></td>
            <td class="empty"></td>
            <td class="empty"></td>
            <td class="empty"></td>
        </tr>
        <tr>
        <td class="empty"></td>
        <td class="empty"></td>
        '''.format(table_size=len(accu_asse.values))
    labels = [
        "{} ({})".format(
            i, accu_asse.labels[str(i)] if str(i) in accu_asse.labels else "-")
        for i in accu_asse.values
    ]
    html += "".join(["<th >" + str(i) + "</th>" for i in labels])
    html += '''
        <th>Total</th>
        <th>User accuracy</th>
        <th>Total class area ({area_unit})</th>
        <th>Wi</th>
        </tr>
        '''.format(area_unit=accu_asse.pixel_area_unit)
    for idx_row, value in enumerate(accu_asse.values):
        html += "<tr>"
        if idx_row == 0:
            html += '''
                <th  class="th-rows" rowspan="{table_size}">Thematic raster<br />classes</th>
                '''.format(table_size=len(accu_asse.values))

        html += "<th>{value}</th>".format(value=value)
        html += "".join([
            '''
            <td class="field-values">{table_field}</td>
            '''.format(table_field=t) for t in accu_asse.error_matrix[idx_row]
        ])
        html += '''
            <td>{total_row}</td>
            <td>{u_accuracy}</td>
            <td>{total_class_area}</td>
            <td>{wi}</td>
            </tr>
            '''.format(
            total_row=sum(accu_asse.error_matrix[idx_row]),
            u_accuracy=rf(accu_asse.error_matrix[idx_row][idx_row] /
                          sum(accu_asse.error_matrix[idx_row]))
            if sum(accu_asse.error_matrix[idx_row]) > 0 else "-",
            total_class_area=rf(accu_asse.thematic_pixels_count[value] *
                                accu_asse.pixel_area_value),
            wi=rf(accu_asse.thematic_pixels_count[value] / sum(
                [accu_asse.thematic_pixels_count[v]
                 for v in accu_asse.values])))
    html += '''    
        <tr>
        <td class="empty"></td>
          <th>total</th>
        '''
    html += "".join([
        '''
                <td>{total_col}</td>
                '''.format(total_col=sum(t))
        for t in zip(*accu_asse.error_matrix)
    ])
    html += '''
        <td>{total_total}</td>
        '''.format(total_total=sum([sum(r) for r in accu_asse.error_matrix]))
    html += '''
        <td></td>
        '''
    html += '''
        <td>{total_classes_area}</td>
        '''.format(total_classes_area=rf(
        sum([accu_asse.thematic_pixels_count[v]
             for v in accu_asse.values]) * accu_asse.pixel_area_value))
    html += '''
        <td></td>
        </tr>
        <tr>
        <td class="empty"></td>
          <th>Producer accuracy</th>
        '''
    for idx_col, col in enumerate(zip(*accu_asse.error_matrix)):
        html += '''
            <td>{p_accuracy}</td>
            '''.format(p_accuracy=rf(col[idx_col] /
                                     sum(col)) if sum(col) > 0 else "-")
    html += '''
        <td></td>
        <td>{u_p_accuracy}</td>
        '''.format(u_p_accuracy=rf(
        sum([
            col[idx_col]
            for idx_col, col in enumerate(zip(*accu_asse.error_matrix))
        ]) / sum([sum(r) for r in accu_asse.error_matrix])
    ) if sum([sum(r) for r in accu_asse.error_matrix]) != 0 else "-")
    html += '''
        <td></td>
        <td></td>
        </tr>
        </tbody>
        </table>
        '''

    ###########################################################################
    html += "<p style='font-size:2px'><br/></p>"
    html += "<h3>2) Error matrix of estimated area proportion:</h3>"
    html += '''
        <table>
        <tbody>
        <tr>
        <td class="empty"></td>
        <td class="empty"></td>
         <th colspan="{table_size}">Classified values</th>
            <td class="empty"></td>
        </tr>
        <tr>
        <td class="empty"></td>
        <td class="empty"></td>
        '''.format(table_size=len(accu_asse.values))
    labels = [
        "{} ({})".format(
            i, accu_asse.labels[str(i)] if str(i) in accu_asse.labels else "-")
        for i in accu_asse.values
    ]
    html += "".join(["<th >" + str(i) + "</th>" for i in labels])
    html += '''
        <th>Wi</th>
        </tr>
        '''
    error_matrix_area_prop = copy.deepcopy(accu_asse.error_matrix)
    for idx_row, row in enumerate(accu_asse.error_matrix):
        wi = accu_asse.thematic_pixels_count[accu_asse.values[idx_row]] / \
             sum([accu_asse.thematic_pixels_count[v] for v in accu_asse.values])
        for idx_col, value in enumerate(row):
            error_matrix_area_prop[idx_row][idx_col] = (
                value / sum(row)) * wi if sum(row) > 0 else 0

    for idx_row, value in enumerate(accu_asse.values):
        html += "<tr>"
        if idx_row == 0:
            html += '''
                <th  class="th-rows" rowspan="{table_size}">Thematic raster<br />classes</th>
                '''.format(table_size=len(accu_asse.values))

        html += "<th>{value}</th>".format(value=value)
        html += "".join([
            '''
            <td class="field-values">{table_field}</td>
            '''.format(table_field=(rf(t)) if t > 0 else "-")
            for t in error_matrix_area_prop[idx_row]
        ])
        html += '''
            <td>{wi}</td>
            </tr>
            '''.format(wi=rf(sum(error_matrix_area_prop[idx_row]))
                       if sum(error_matrix_area_prop[idx_row]) > 0 else "-")
    html += '''    
        <tr>
        <td class="empty"></td>
          <th>total</th>
        '''
    html += "".join([
        '''
                <td>{total_col}</td>
                '''.format(total_col=rf(sum(t)))
        for t in zip(*error_matrix_area_prop)
    ])
    html += '''
        <td></td>
        </tr>
        </tbody>
        </table>
        '''

    ###########################################################################
    html += "<p style='font-size:2px'><br/></p>"
    html += "<h3>3) Quadratic error matrix of estimated area proportion:</h3>"
    html += '''
        <table>
        <tbody>
        <tr>
        <td class="empty"></td>
        <td class="empty"></td>
         <th colspan="{table_size}">Classified values</th>
        </tr>
        <tr>
        <td class="empty"></td>
        <td class="empty"></td>
        '''.format(table_size=len(accu_asse.values))
    labels = [
        "{} ({})".format(
            i, accu_asse.labels[str(i)] if str(i) in accu_asse.labels else "-")
        for i in accu_asse.values
    ]
    html += "".join(["<th >" + str(i) + "</th>" for i in labels])
    html += "</tr>"

    quadratic_error_matrix = copy.deepcopy(accu_asse.error_matrix)
    for idx_row, row in enumerate(accu_asse.error_matrix):
        wi = accu_asse.thematic_pixels_count[accu_asse.values[idx_row]] / \
             sum([accu_asse.thematic_pixels_count[v] for v in accu_asse.values])
        for idx_col, value in enumerate(row):
            quadratic_error_matrix[idx_row][idx_col] = \
                (wi**2*((value/sum(row))*(1-(value/sum(row)))/(sum(row)-1))) if sum(row) > 1 else 0

    for idx_row, value in enumerate(accu_asse.values):
        html += "<tr>"
        if idx_row == 0:
            html += '''
                <th  class="th-rows" rowspan="{table_size}">Thematic raster<br />classes</th>
                '''.format(table_size=len(accu_asse.values))

        html += "<th>{value}</th>".format(value=value)
        html += "".join([
            '''
            <td class="field-values">{table_field}</td>
            '''.format(table_field=(rf(t)) if t > 0 else "-")
            for t in quadratic_error_matrix[idx_row]
        ])
        html += "</tr>"
    html += '''    
        <tr>
        <td class="empty"></td>
          <th>total</th>
        '''
    html += "".join([
        '''
                    <td>{total_col}</td>
                    '''.format(total_col=rf(sum(t)**0.5))
        for t in zip(*quadratic_error_matrix)
    ])
    html += '''
        </tr>
        </tbody>
        </table>
        '''

    ###########################################################################
    html += "<p style='font-size:2px'><br/></p>"
    html += "<h3>4) Accuracy matrices:</h3>"
    ###################################
    html += "<h4>User's accuracy matrix of estimated area proportion:</h4>"
    html += '''
        <table>
        <tbody>
        <tr>
        <td class="empty"></td>
        <td class="empty"></td>
         <th colspan="{table_size}">Classified values</th>
        </tr>
        <tr>
        <td class="empty"></td>
        <td class="empty"></td>
        '''.format(table_size=len(accu_asse.values))
    labels = [
        "{} ({})".format(
            i, accu_asse.labels[str(i)] if str(i) in accu_asse.labels else "-")
        for i in accu_asse.values
    ]
    html += "".join(["<th >" + str(i) + "</th>" for i in labels])
    html += "</tr>"

    user_accuracy_matrix = copy.deepcopy(accu_asse.error_matrix)
    for idx_row, row in enumerate(accu_asse.error_matrix):
        for idx_col, value in enumerate(row):
            user_accuracy_matrix[idx_row][idx_col] = \
                value/sum(row) if sum(row) > 0 else 0

    for idx_row, value in enumerate(accu_asse.values):
        html += "<tr>"
        if idx_row == 0:
            html += '''
                <th  class="th-rows" rowspan="{table_size}">Thematic raster<br />classes</th>
                '''.format(table_size=len(accu_asse.values))

        html += "<th>{value}</th>".format(value=value)
        html += "".join([
            '''
            <td class="field-values">{table_field}</td>
            '''.format(table_field=(rf(t)) if t > 0 else "-")
            for t in user_accuracy_matrix[idx_row]
        ])
        html += "</tr>"
    html += '''
        </tbody>
        </table>
        '''
    ###################################
    html += "<h4>Producer's accuracy matrix of estimated area proportion:</h4>"
    html += '''
        <table>
        <tbody>
        <tr>
        <td class="empty"></td>
        <td class="empty"></td>
         <th colspan="{table_size}">Classified values</th>
        </tr>
        <tr>
        <td class="empty"></td>
        <td class="empty"></td>
        '''.format(table_size=len(accu_asse.values))
    labels = [
        "{} ({})".format(
            i, accu_asse.labels[str(i)] if str(i) in accu_asse.labels else "-")
        for i in accu_asse.values
    ]
    html += "".join(["<th >" + str(i) + "</th>" for i in labels])
    html += "</tr>"

    producer_accuracy_matrix = copy.deepcopy(error_matrix_area_prop)
    for idx_col, col in enumerate(zip(*error_matrix_area_prop)):
        for idx_row, value in enumerate(col):
            producer_accuracy_matrix[idx_row][idx_col] = value / sum(
                col) if sum(col) > 0 else 0

    for idx_row, value in enumerate(accu_asse.values):
        html += "<tr>"
        if idx_row == 0:
            html += '''
                <th  class="th-rows" rowspan="{table_size}">Thematic raster<br />classes</th>
                '''.format(table_size=len(accu_asse.values))

        html += "<th>{value}</th>".format(value=value)
        html += "".join([
            '''
            <td class="field-values">{table_field}</td>
            '''.format(table_field=(rf(t)) if t > 0 else "-")
            for t in producer_accuracy_matrix[idx_row]
        ])
        html += "</tr>"

    html += '''
        </tbody>
        </table>
        '''
    ###################################
    html += "<h4>Overall Accuracy: </h4>"
    overall_accuracy = sum(
        [row[idx_row] for idx_row, row in enumerate(error_matrix_area_prop)])
    html += '''
            <table>
            <tbody>
            <tr>
            <td>{}</td>
            </tr>'''.format(rf(overall_accuracy))
    html += '''
            </tbody>
            </table>
            '''

    ###################################
    html += "<p style='font-size:2px'><br/></p>"
    html += "<h3>5) Class area adjusted table:</h3>"
    html += '''
        <table>
        <tbody>
        <tr>
        <td class="empty"></td>
        '''.format(table_size=len(accu_asse.values))
    headers = [
        "Area ({area_unit})".format(area_unit=accu_asse.pixel_area_unit),
        "Error", "Lower limit", "Upper limit"
    ]
    html += "".join(["<th >" + str(h) + "</th>" for h in headers])
    html += "</tr>"

    total_area = 0

    for idx_row, value in enumerate(accu_asse.values):
        html += "<tr>"

        html += "<th >{} ({})</th>".format(
            value, accu_asse.labels[str(value)]
            if str(value) in accu_asse.labels else "-")
        # area
        area = sum(list(zip(*error_matrix_area_prop))[idx_row]) * \
               sum([accu_asse.thematic_pixels_count[v] for v in accu_asse.values]) * accu_asse.pixel_area_value
        html += '''<td>{area}</th>'''.format(area=rf(area))
        total_area += area
        # error
        error = (sum(list(zip(*quadratic_error_matrix))[idx_row])**0.5) * \
                sum([accu_asse.thematic_pixels_count[v] for v in accu_asse.values]) * accu_asse.pixel_area_value
        html += '''<td>{error}</th>'''.format(error=rf(error))
        # lower limit
        html += '''<td>{lower_limit}</th>'''.format(
            lower_limit=rf(area - accu_asse.z_score * error))
        # upper limit
        html += '''<td>{upper_limit}</th>'''.format(
            upper_limit=rf(area + accu_asse.z_score * error))
        html += "</tr>"

    html += '''    
        <tr>
          <th>total</th>
        '''
    html += '''<td>{total_area}</th>'''.format(total_area=rf(total_area))
    html += '''
        <td class="empty"></td>
        <td class="empty"></td>
        <td class="empty"></td>
        </tr>'''

    html += '''
        </tbody>
        </table>
        '''

    html += '''
        </body>
        '''

    return html
Ejemplo n.º 12
0
def get_pixel_count_by_pixel_values(layer, band, pixel_values=None, nodata=-1):
    app = QCoreApplication.instance()

    nodata = nodata if nodata != -1 else None
    if pixel_values is None:
        pixel_values = get_pixel_values(layer, band)

    # put nodata at the beginning, with the idea to include it for stopping
    # the counting when reaching the total pixels, delete it at the end
    if nodata is not None:
        if nodata in pixel_values: pixel_values.remove(nodata)
        pixel_values.insert(0, nodata)

    try:
        import xarray as xr
        import dask.array as da
        dataset = xr.open_rasterio(get_file_path_of_layer(layer),
                                   chunks={
                                       'band': 1,
                                       'x': 2000,
                                       'y': 2000
                                   })
        parallel = True
    except:
        dataset = gdal_array.LoadFile(get_file_path_of_layer(layer))
        parallel = False

    if len(dataset.shape) == 3:
        if parallel:
            dataset = dataset.sel(band=band)
        else:
            dataset = dataset[band - 1]

    max_pixels = dataset.shape[-1] * dataset.shape[-2]

    progress = QProgressDialog(
        'AcATaMa is counting the number of pixels for each thematic value.\n'
        'Depending on the size of the image, it would take a few minutes.',
        None, 0, 100, iface.mainWindow())
    progress.setWindowTitle("AcATaMa - Counting pixels by values... " +
                            ("[parallel]" if parallel else "[not parallel!]"))
    progress.setWindowModality(Qt.WindowModal)
    progress.setValue(0)
    progress.show()
    app.processEvents()

    global total_count
    total_count = 0

    def count_value(pixel_value):
        global total_count
        if total_count >= max_pixels:
            return 0
        if parallel:
            count = da.count_nonzero(dataset == pixel_value).compute()
        else:
            count = np.count_nonzero(dataset == pixel_value)
        total_count += count
        progress.setValue(int(total_count * 100 / max_pixels))
        return count

    pixel_counts = [count_value(pixel_value) for pixel_value in pixel_values]

    if nodata is not None:
        pixel_values.pop(0)
        pixel_counts.pop(0)

    progress.accept()
    return dict(zip(pixel_values, pixel_counts))