Exemple #1
0
 def start(self):
     signals.do_log('Processing...')
     from rvsearch.main import CoreProcess
     in_path = self.csvpath_input.text()  # Path for csv input
     out_path = self.csvpath_output.text()  # Path for csv output
     results = CoreProcess().main([in_path], out_path)
     return results
Exemple #2
0
 def change_path(self):
     """Change working directory to a temporary directory."""
     if vconf.VERBOSE: signals.do_log(f'Running from {self.file_path}')
     Path(Path(self.file_path) / "rvidtmp/").mkdir(parents=True,
                                                   exist_ok=True)
     os.chdir(self.file_path + "/rvidtmp")
     return None
Exemple #3
0
 def get_video(self, url) -> list[str, str]:
     """Gets the video infor from YouTube and then downloads it"""
     url = str(url)
     # TODO: if above 30min
     id, name, channel = self._get_info(url)
     if Path(id).exists():
         if not vconf.QUIET:
             signals.do_log('** Skipping download, file already exists')
     else:
         response = self.download(url)
     return [id, name, channel, url]
Exemple #4
0
 def save_results(self, record_df, output, name):
     # TODO: maybe save in comparing?
     signals.do_log('Saving...')
     home_path = os.path.expanduser('~')
     if output:
         save_path = os.path.join(home_path, 'Documents', f'{output}.csv')
     else:
         save_path = os.path.join(home_path, 'Documents',
                                  f'{name}_results.csv')
     final_csv_name = save_csv(record_df, f'{save_path}')
     if not vconf.QUIET:
         signals.do_log(f'Results saved to {final_csv_name}')
     return None
Exemple #5
0
 def compare_videos_parallel(self, source_frames, source_fps, target_frames,
                             target_fps):
     """Slice the frames to equal parts and multiprocess-compare them"""
     pool = mp.Pool()
     cpus = mp.cpu_count()
     n = int(len(source_frames) / cpus)
     subs = [
         source_frames[i:i + n] for i in range(0, len(source_frames), n)
     ]
     args = [(sub, source_fps, target_frames, target_fps) for sub in subs]
     if vconf.VERBOSE:
         signals.do_log(f'you\'re having {cpus} process simultaneously')
     results = pool.starmap(self.compare_videos, args)
     ret = []
     for res in results:
         if res:
             ret.append(res)
     return ret
Exemple #6
0
    def video_init(self, vid_info):
        """Extract the frames from video and get all the infos from downloader"""
        vid_meta = {
            'path': vid_info[0],
            'name': vid_info[1],
            'channel': vid_info[2],
            'url': vid_info[3]
        }
        vid = cv2.VideoCapture(vid_meta['path'])  # TODO: GPU accelrate
        fps = vid.get(cv2.CAP_PROP_FPS)
        vid_meta['fps'] = fps

        # Save frames into RAM
        if not vconf.QUIET:
            signals.do_log(
                f"Loading video: {vid_meta['path']} -- {vid_meta['name']}")
            start = monotonic()
        frames = self.get_frames(vid, int(fps))
        if vconf.VERBOSE:
            signals.do_log(f'Loading took {monotonic() - start} seconds')
        return frames, vid_meta
Exemple #7
0
def record_similarity(record_df, timestamps, urls, names, channels):
    """When you find a similar video, save its information to a dataframe then give it back."""
    # If you want to dynamically save .csv, init before recording
    if timestamps:
        signals.do_log(f'Found {len(timestamps[0])} similar frames')
        for thread_res in timestamps:
            for stamp in thread_res:
                # TODO: Sum near timestamps together
                m1, s1 = stamp[0][0], stamp[0][1]
                m2, s2 = stamp[1][0], stamp[1][1]
                score = stamp[2]  # Not used, but can be

                info = {'Cmpl_url': f'{urls[0]}',
                        'Cmp_name': names[0],
                        'Cmp_chnl': channels[0],
                        'Source_url': f'{urls[1]}',
                        'Source_name': names[1],
                        'Source_chnl': channels[1],
                        'Cmp_TimeStamp': fix_time(f'{int(m1)}:{int(s1)}'),
                        'Source_TimeStamp': fix_time(f'{int(m2)}:{int(s2)}')}
                if vconf.VERBOSE: signals.do_log(str(info))
                record_df = record_df.append(info, ignore_index=True)
                success = True
    else:
        signals.do_log(f'Found no similar frames')
        success = False
    return record_df, success
Exemple #8
0
 def _progress(d):
     """da progress"""
     if d['status'] == 'finished':
         signals.do_log('Done downloading.')
Exemple #9
0
 def error(self, msg):
     signals.do_log(msg)
Exemple #10
0
 def warning(self, msg):
     if vconf.VERBOSE:
         signals.do_log(msg)
Exemple #11
0
 def debug(self, msg):
     signals.do_log(msg)
Exemple #12
0
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(682, 665)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.csvpath_input = QtWidgets.QLineEdit(self.centralwidget)
        self.csvpath_input.setGeometry(QtCore.QRect(130, 40, 441, 21))
        self.csvpath_input.setText("")
        self.csvpath_input.setObjectName("csvpath_input")
        self.csvpath = QtWidgets.QLabel(self.centralwidget)
        self.csvpath.setGeometry(QtCore.QRect(70, 40, 71, 20))
        self.csvpath.setObjectName("csvpath")
        self.path_open = QtWidgets.QToolButton(self.centralwidget)
        self.path_open.setGeometry(QtCore.QRect(570, 40, 41, 22))
        self.path_open.setObjectName("path_open")
        self.log = QtWidgets.QTextBrowser(self.centralwidget)
        self.log.setGeometry(QtCore.QRect(20, 160, 641, 141))
        self.log.setObjectName("log")
        signals.connect(self.on_text_changed)
        self.start_button = QtWidgets.QPushButton(self.centralwidget)
        self.start_button.setGeometry(QtCore.QRect(250, 130, 80, 23))
        self.start_button.setObjectName("start_button")
        self.stop_button = QtWidgets.QPushButton(self.centralwidget)
        self.stop_button.setGeometry(QtCore.QRect(350, 130, 80, 23))
        self.stop_button.setObjectName("stop_button")
        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setGeometry(QtCore.QRect(20, 310, 57, 15))
        font = QtGui.QFont()
        font.setPointSize(11)
        self.label.setFont(font)
        self.label.setObjectName("label")
        self.csvpath_2 = QtWidgets.QLabel(self.centralwidget)
        self.csvpath_2.setGeometry(QtCore.QRect(80, 70, 51, 20))
        self.csvpath_2.setObjectName("csvpath_2")
        self.csvpath_output = QtWidgets.QLineEdit(self.centralwidget)
        self.csvpath_output.setGeometry(QtCore.QRect(130, 70, 441, 21))
        self.csvpath_output.setText("")
        self.csvpath_output.setObjectName("csvpath_output")
        self.output = QtWidgets.QTableView(self.centralwidget)
        self.output.setGeometry(QtCore.QRect(20, 331, 641, 291))
        self.output.setObjectName("output")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 682, 20))
        self.menubar.setObjectName("menubar")
        self.menu = QtWidgets.QMenu(self.menubar)
        self.menu.setObjectName("menu")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setEnabled(True)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)
        self.actionExit = QtWidgets.QAction(MainWindow)
        self.actionExit.setObjectName("actionExit")
        self.actionOpen = QtWidgets.QAction(MainWindow)
        self.actionOpen.setObjectName("actionOpen")
        self.actionAbout = QtWidgets.QAction(MainWindow)
        self.actionAbout.setObjectName("actionAbout")
        self.menu.addAction(self.actionOpen)
        self.menu.addAction(self.actionAbout)
        self.menu.addSeparator()
        self.menu.addAction(self.actionExit)
        self.menubar.addAction(self.menu.menuAction())

        # ==============================================================================
        # Importnant parts
        self.retranslateUi(MainWindow)
        self.path_open.clicked.connect(self.file_opener)  # Open button
        self.actionOpen.triggered.connect(self.file_opener)  # Open in menu
        self.actionExit.triggered.connect(self.exit_program)  # Exit in menu
        self.start_button.clicked.connect(self.thread_start)  # Start button
        self.stop_button.clicked.connect(self.thread_stop)  # Stop button
        QtCore.QMetaObject.connectSlotsByName(MainWindow)
        self.start_button.setEnabled(False)
Exemple #13
0
 def thread_stop(self):
     signals.working = False
     signals.do_log('Terminating...')
     return None
Exemple #14
0
    def main(self, csv_path, output_path=""):
        """Main function: read csv, download videos, compare them, save results."""
        signals.do_log('Started')
        record_df = init_record_file()
        self.change_path()
        if not csv_path[0]:
            signals.do_log('You have not provided any input')
            self.clean()
            os.chdir(self.currnt_path)
            exit()

        for csv in csv_path:
            csv = Path(self.currnt_path) / csv
            com_url, source_list = read_csv(csv)

            # Downloading
            try:
                cmp_file = self.downloader.get_video(com_url[0])
            except youtube_dl.utils.DownloadError:
                signals.do_log('Compilation video is not available.')
                return {}

            for source_url in source_list:
                while signals.working:
                    # Downloading
                    try:
                        src_file = self.downloader.get_video(source_url)
                    except:
                        signals.do_log(
                            'This video is not available. skipping...')
                        break

                    # Getting things ready
                    if not vconf.QUIET:
                        signals.do_log(
                            'Getting ready to start comparison process')
                    frames_cmp, meta_cmp = self.video_init(cmp_file)
                    frames_src, meta_src = self.video_init(src_file)
                    if not vconf.QUIET:
                        signals.do_log(f'Comparing source: {meta_src["name"]}')

                    # Do the comparison
                    if not signals.working:
                        signals.do_log('Terminated')
                        return None

                    if not vconf.QUIET:
                        signals.do_log(
                            '**Comparing started**\nIt may take a few minutes...'
                        )
                    time_stamps = self.compare_videos_parallel(
                        frames_cmp, meta_cmp['fps'], frames_src,
                        meta_src['fps'])
                    if not vconf.QUIET:
                        signals.do_log(
                            f"Comparing {meta_cmp['path']} and {meta_src['path']} finished"
                        )

                    record_df, success = record_similarity(
                        record_df, time_stamps,
                        [meta_cmp['url'], meta_src['url']],
                        [meta_cmp['name'], meta_src['name']],
                        [meta_cmp['channel'], meta_src['channel']])
                    if success:
                        record_df = cluster_timestamps(record_df)
                        self.save_results(record_df, output_path,
                                          meta_cmp["name"])
                    break
        if not vconf.QUIET: signals.do_log(f'====All done====')
        return record_df
Exemple #15
0
    def compare_videos(self, source_frames, source_fps, target_frames,
                       target_fps):
        """Get two video object, start comparing them frame by frame. Linear Search algorithm."""
        from rvsearch.signals import Signals as signals

        current_frame_s = 0
        current_frame_t = 0
        timestamps = []
        if vconf.VERBOSE:
            start = monotonic()
            with _mutex:
                signals.do_log('Comparing started')
        for s_frame in source_frames:
            current_frame_s += source_fps  # Go up 1 second
            current_frame_t = 0  # One target done, now reset
            for t_frame in target_frames:
                current_frame_t += target_fps  # Go up 1 second
                score = self.compare_hash_frames(s_frame, t_frame, hash_len=12)
                if not signals.working:
                    signals.do_log('Terminated')
                    return timestamps
                if self.check_score(score, threshold=0.75):
                    # Record its timestamp
                    m1, s1 = divmod((current_frame_s / source_fps), 60)
                    m2, s2 = divmod((current_frame_t / target_fps), 60)
                    timestamps.append([[m1, s1], [m2, s2], score])
                    if not vconf.QUIET:
                        signals.do_log(
                            f'Compilation video: similarity found at {int(m1)}:{int(s1)}'
                        )
                    if vconf.VERBOSE:
                        signals.do_log(f'ter is: {signals.working}')
                        with _mutex:
                            signals.do_log(timestamps[-1])
                            signals.do_log("--- %s seconds ---" %
                                           (monotonic() - start))
                    break  # First similarity in video, break

        if vconf.VERBOSE:
            signals.do_log("Elapsed time: --- %s seconds ---" %
                           (monotonic() - start))
        return timestamps