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()
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
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
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)
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()
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()
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 + '¶meter=' + 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¶meter=' + 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!")