Beispiel #1
0
    def __save_module_dataset(self):
        """Saves the data to the directory selected when opening the file explorer."""
        self.progress_bar_all_frames.setEnabled(True)
        self.progress_bar_intra_frame.setEnabled(True)
        button_reply = QtWidgets.QMessageBox.question(self, 'Save dataset',
                                                      "Want to save dataset to {}?".format(self.output_directory),
                                                      QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No,
                                                      QtWidgets.QMessageBox.No)
        if button_reply == QtWidgets.QMessageBox.No:
            Logger.warning("Rejected directory <{}> for saving all images".format(self.output_directory))
            self.output_directory = None
            self.__save_module_dataset()
        else:
            Logger.info("Saving all images to <{}>".format(self.output_directory))
            Logger.warning("If dialog freezes, check log file, but DON'T close the window!")
            working_modules_output_dir = os.path.join(self.output_directory, "working")
            broken_modules_output_dir = os.path.join(self.output_directory, "broken")
            misdetected_modules_output_dir = os.path.join(self.output_directory, "misdetected")

            overall_iter = 0

            def save_modules_into_directory(module_dict: dict, directory: str):
                global overall_iter

                os.mkdir(os.path.abspath(directory))
                for module_number, (module_id, registered_modules) in enumerate(module_dict.items()):
                    Logger.debug("Saving all views of module ID {}: view {}/{}".format(module_id, module_number,
                                                                                       len(module_dict.keys()) - 1))
                    self.progress_bar_all_frames.setValue(self.progress_bar_all_frames.value() + 1)
                    self.progress_bar_intra_frame.setValue(0)
                    self.progress_bar_intra_frame.setMaximum(len(registered_modules))
                    for m_index, m in enumerate(registered_modules):
                        name = "id_{0:05d}_frame_{1:05d}.jpg".format(module_id, m["frame_id"])
                        path = os.path.join(directory, name)
                        img = cv2.cvtColor(m["image"], cv2.COLOR_RGB2BGR)
                        cv2.imwrite(path, img)
                        self.progress_bar_intra_frame.setValue(m_index + 1)

            Logger.info("Saving working modules to <{}>".format(working_modules_output_dir))
            save_modules_into_directory(self.working_modules, working_modules_output_dir)
            Logger.info("Saved all working modules to <{}>".format(working_modules_output_dir))
            Logger.info("Saving broken modules to <{}>".format(broken_modules_output_dir))
            save_modules_into_directory(self.broken_modules, broken_modules_output_dir)
            Logger.info("Saved all broken modules to <{}>".format(broken_modules_output_dir))
            Logger.info("Saving misdetected modules to <{}>".format(misdetected_modules_output_dir))
            save_modules_into_directory(self.misdetected_modules, misdetected_modules_output_dir)
            Logger.info("Saved all misdetected modules to <{}>".format(misdetected_modules_output_dir))

        _ = QtWidgets.QMessageBox.information(self, "Saved!", "Saved all modules to {}".format(self.output_directory),
                                              QtWidgets.QMessageBox.Ok)
        self.close()
Beispiel #2
0
    def classify(self, image_list: list) -> np.ndarray:
        """Classifies the image list passed as argument using the model loaded in :attr:`self.model`.

        :param image_list: Python list of numpy arrays representing the images to be classified. All images are classified as a mini-batch.
        :return: A numpy array of shape `[len(image_list), self.num_classes]` containing the class probability for each image passed as argument.

        .. note:: If the images contained in the input parameter are not of the same shape as the one store in :attr:`self.image_shape`, the input images are resized to fit the desired image shape.
        """
        if len(image_list) == 0:
            return np.empty(shape=[0])

        img_tensor = []
        for img in image_list:
            if (img.shape[0:2] != self.image_shape[0:2]).any():
                shape = img.shape
                img = img.astype(np.float32)
                Logger.warning(
                    "Image is of size {}, should be {},  resizing".format(
                        shape, self.image_shape))
                img = cv2.resize(img,
                                 (self.image_shape[1], self.image_shape[0]),
                                 interpolation=cv2.INTER_AREA)
            if img.shape[2] != self.image_shape[2]:
                if self.image_shape[2] == 1:
                    img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
                    img = img
                elif self.image_shape[2] == 3:
                    img = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB)

            img_mean = np.mean(img, axis=(0, 1))
            img_std = np.std(img, axis=(0, 1))
            img = (img - img_mean) / img_std

            img_tensor.append(img)

        img_tensor = np.array(img_tensor)

        if len(img_tensor.shape) == 3:
            img_tensor = img_tensor[..., np.newaxis]

        Logger.debug("Classifying {} module image{}".format(
            img_tensor.shape[0], "" if img_tensor.shape[0] == 1 else "s"))

        class_probabilities = self.sess.run(self.probabilities,
                                            feed_dict={
                                                self.x: img_tensor,
                                                self.keep_probability: 1.0
                                            })
        return class_probabilities
Beispiel #3
0
    def step(self, frame_id, frame) -> bool:
        """Perform a single step of the module detection using the frame passed as argument.

        If the detection step is successful, the :attr:`self.last_*` parameters are filled with the newly computed elements.

        :param frame_id: Integer identifying the id of the frame to be processed.
        :param frame: Numpy array containing the RGB image representing the frame to be processed.
        :return: True if the detection was successful, False otherwise.
        """
        self.last_frame_id = frame_id
        self.last_input_frame = frame
        distorted_image = frame
        if self.should_undistort_image:
            undistorted_image = cv2.undistort(
                src=distorted_image,
                cameraMatrix=self.camera.camera_matrix,
                distCoeffs=self.camera.distortion_coeff)
        else:
            undistorted_image = distorted_image
        self.last_input_frame = undistorted_image

        self.preprocess_frame()
        self.detect_edges()
        self.detect_segments()
        if len(self.last_segments) < 3:
            Logger.warning("Found less than three segments!")
            return False

        self.cluster_segments()
        self.detect_intersections()
        self.detect_rectangles()

        # Motion estimate.
        self.last_mean_motion = self.motion_detector.motion_estimate(
            self.last_scaled_frame)

        # Add the detected rectangles to the global map.
        self.module_map.insert(self.last_rectangles, frame_id,
                               self.last_mean_motion)

        if len(self.last_rectangles) == 0:
            Logger.warning("No rectangles detected!")
            return False

        return True
Beispiel #4
0
    def __open_directory_dialog(self):
        """Opens a file explorer to select the destination of the files to store to disk."""
        output_directory = QtWidgets.QFileDialog.getExistingDirectory(caption="Select dataset output directory")
        Logger.debug("Selected <{}> directory to store all images".format(output_directory))
        if output_directory == "":
            return

        self.output_directory = output_directory

        if len(os.listdir(self.output_directory)) > 0:
            Logger.warning("Directory {} is not empty!".format(self.output_directory))
            QtWidgets.QMessageBox.warning(self, "Non empty directory",
                                          "Directory {} not empty! Select an empty directory!".format(
                                              self.output_directory), QtWidgets.QMessageBox.Ok,
                                          QtWidgets.QMessageBox.Ok)
            self.__open_directory_dialog()
        else:
            self.save_directory_label.setText('Saving to directory: "{}"'.format(self.output_directory))
            self.save_button.setEnabled(True)
Beispiel #5
0
    def __load_video(self, video_raw: cv2.VideoCapture):
        if not video_raw.isOpened():
            Logger.error("Unable to read {} feed".format(self.video_path))

        self.frames = []

        num_video_frames = int(video_raw.get(cv2.CAP_PROP_FRAME_COUNT))
        if self.end_frame is None or self.end_frame > num_video_frames:
            Logger.warning("Setting end_frame to {}".format(num_video_frames))
            self.end_frame = num_video_frames

        num_frames = 0

        # Skip the first frames until the self_start frame.
        video_raw.set(cv2.CAP_PROP_POS_FRAMES, self.start_frame)

        Logger.info("Loading {} frames...".format(self.end_frame -
                                                  self.start_frame))
        bar = progressbar.ProgressBar(maxval=self.num_frames,
                                      widgets=[
                                          progressbar.Bar('=', '[', ']'), ' ',
                                          progressbar.Percentage()
                                      ])
        bar.start()
        for i in range(self.end_frame - self.start_frame):
            ret = video_raw.grab()
            if not ret:
                Logger.error(
                    "Could not load frame {}".format(i + self.start_frame))
                raise ValueError(
                    "Could not load frame {}".format(i + self.start_frame))

            self.frames.append(video_raw.retrieve()[1])
            num_frames += 1
            bar.update(num_frames)

        bar.finish()
        video_raw.release()
Beispiel #6
0
    def detect(self):
        """Detects the segments in the input image using the parameters passed as argument using a probilistic Hough transform.
        """
        Logger.debug("Detecting segments")
        self.segments = cv2.HoughLinesP(
            image=self.input_image,
            rho=self.params.d_rho,
            theta=self.params.d_theta,
            threshold=self.params.min_num_votes,
            minLineLength=self.params.min_line_length,
            maxLineGap=self.params.max_line_gap)

        # If no segments have been found, return an empty array.
        if self.segments is None:
            Logger.warning("No segments were detected")
            self.segments = np.empty(shape=(0, 4))
            return

        # Otherwise need to reshape the segment array, and to extend the segments on each side to allow better
        # intersection detection.
        self.segments = np.squeeze(self.segments)
        if len(self.segments.shape) <= 1:
            self.segments = np.array([self.segments])
        self.__extend_segments()
Beispiel #7
0
def download_oasi_data(custom_params: dict = None) -> None:
    """Downloads all the data specified in the passed argument to the data folder.

    :Example:

        .. code-block:: python

            domains = ['meteo', 'air']
            years = range(2000, 2018)
            download_params = {
                "domains": domains,
                "years": years
            }
            download_oasi_data(download_params)

    :param custom_params: Dictionary of custom params to be used to download the data.
    """
    if custom_params is None:
        custom_params = {}

    params = {
        "domains": ["air", "meteo"],
        "years": range(2000, 2018),
        "data_directory": pm.Settings.data_dir,
        "overwrite": False,
        "ignore_locations":
        ["Stabio_16"]  # Ignore this location, as it is downloaded
        # thorough the Oasi-Client interface which offers multiple temperature sensors.
    }
    params.update(custom_params)

    # Log the parameters being used.
    logger_msg = "Downloading oasi data with following params:"
    align = max([len(name) for name in params]) + 4
    for name, value in params.items():
        logger_msg += "\n{:>{align}}: {}".format(name, value, align=align)
    Logger.info(msg=logger_msg)

    domains = params["domains"]
    years = params["years"]
    data_directory = params["data_directory"]
    overwrite = params["overwrite"]

    if len(domains) == 0:
        raise RuntimeError("Domains passed to `download_oasi_data` is empty!")

    if not os.path.exists(data_directory):
        os.makedirs(data_directory, exist_ok=True)

    for dom in domains:
        Logger.info("Downloading domain {}".format(dom))
        dom_path = os.path.join(data_directory, dom)
        os.makedirs(dom_path, exist_ok=True)
        domain = requests.get(
            'http://www.oasi.ti.ch/web/rest/parameters?domain=' + dom)
        domain_features = json.loads(domain.text)

        for feature in domain_features:
            feature_path = os.path.join(dom_path, feature['code'])
            Logger.info("Downloading feature {}/{}".format(
                dom, feature["code"]))
            os.makedirs(feature_path, exist_ok=True)

            # Get locations associated to the features.
            locations = requests.get(
                'http://www.oasi.ti.ch/web/rest/locations?domain=' + dom +
                '&parameter=' + feature['code'])

            locations = json.loads(locations.text)

            for loc in locations:
                if loc['name'] + "_" + loc['code'] in params[
                        "ignore_locations"]:
                    Logger.warning(
                        "Ignoring {} location".format(loc['name'] + "_" +
                                                      loc['code']))
                    continue
                loc_path = os.path.join(feature_path,
                                        loc['name'] + "_" + loc['code'])
                os.makedirs(loc_path, exist_ok=True)
                for year in years:
                    csv_file_name = os.path.join(loc_path, str(year) + '.csv')

                    # If the file already exists, then continue to next data without
                    # overwriting.
                    if not overwrite and os.path.exists(csv_file_name):
                        Logger.debug(
                            "File {} already existing. Skipping to next "
                            "file".format(csv_file_name))
                        continue

                    Logger.debug("Requesting {}.{}.{}.{}".format(
                        dom, feature["code"], loc['name'], year))

                    locations = requests.get(
                        'http://www.oasi.ti.ch/web/rest/measure/csv?domain=' +
                        dom + '&resolution=h&parameter=' + feature['code'] +
                        '&from=' + str(year) + '-01-01&to=' + str(year) +
                        '-12-31&location=' + loc['code'])

                    first_line = locations.text.split('\n', 1)[0]
                    if first_line == '# GENERALE':
                        write_csv_file(csv_file_name, locations)
                    else:
                        Logger.debug("Request was not successful!")