본문 바로가기
연구/소원 - 팀장

PyQt5 , Open CV라이브러리를 활용해서 GUI로 동영상 재생하기

by I am wish 2020. 10. 8.
반응형

* pycharm에서 pyqt5 하고 opencv-python 패키지 설치해야합니다 *

 

PyQt5는 Gui를 만드는 라이브러리, Open CV는 동영상을 재생하는 라이브러리다.

간단히 PyQt5로 GUI 창을 만듦

-> 버튼, 이미지 등 처럼 비디오를 재생할 수 있는 비디오 위젯이 제공됨

-> 비디오 위젯하고 Open CV를 매칭

-> Open CV로는 저장된 영상 가져오기

이러한 일련의 과정을 통해서 구현이 가능하다.

 

이번 게시물에서는 주석으로 설명할 것이다.

#PyQt5 라이브러리
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtGui import QPixmap, QImage
#open cv에서는 영상을 프레임단위로 가져오기 때문에 sleep을 통해서 프레임을 연결시켜주어 영상으로 보이게 만드는 것임
from time import sleep
#비디오 재생을 위해 스레드 생성
import threading
#화면을 윈도우에 띄우기 위해 sys접근
import sys

#open cv 라이브러리
import cv2

#메인문
if __name__ == "__main__":
    import sys

    #화면 만들려면 기본으로 있어야 하는 코드들 건들지않기
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)

    #영상 스레드 시작
    ui.video_thread(MainWindow)

    #창 띄우기
    MainWindow.show()

    sys.exit(app.exec_())

 가장 기본이 되는 메인 문이다. 여기를 시작으로 여러 모듈들이 수행될 것이기 때문에 앞으로 수정될 여지가 있다.

 

class Ui_MainWindow(object):
    #기본적으로 창만드는 작업
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("ForSign")
        MainWindow.resize(500, 300) #창 사이즈
        MainWindow.move(500,500) #창 뜰 때 위치
        #이 아래로는 나도 잘 모름 화면을 구성하고 영상을 재생하는 위젯을 만드는거 같음 유지해두는게 나을듯
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")

        self.video_viewer_label = QtWidgets.QLabel(self.centralwidget)
        self.video_viewer_label.setGeometry(QtCore.QRect(10, 10, 400, 300))

        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 21))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    #단어주소 들가서 영상주소 크롤링해서 리턴
    def crawling(self):
        num = "6848"
        options = webdriver.ChromeOptions()
        options.add_argument('headless')
        driver = webdriver.Chrome('/Users/sowon/Downloads/chromedriver', options=options)
        #5초 지연의 주범. 동적페이지라서 selenium을 꼭 써야지 비디오 주소가 접근되는데 이거때문에 지연이 생김
        driver.get('http://sldict.korean.go.kr/front/sign/signContentsView.do?origin_no={}'.format(num))

        html = driver.page_source
        soup = BeautifulSoup(html, 'lxml')
        # print(soup.find('video'))
        video_url = soup.find(type="video/mp4").get("src")
        return video_url

    def Video_to_frame(self, MainWindow):

        video_url = self.crawling() #crawling 함수로 영상주소 받아서 변수에 저장
        savename = 'save_by_urllib.mp4' #저장될 영상 이름

        urllib.request.urlretrieve(video_url, savename) #영상 주소 접근해서 저장
        print("저장완료")

        cap = cv2.VideoCapture('save_by_urllib.mp4') #저장된 영상 가져오기 프레임별로 계속 가져오는 듯

        ###cap으로 영상의 프레임을 가지고와서 전처리 후 화면에 띄움###
        while True:
            self.ret, self.frame = cap.read() #영상의 정보 저장
            if self.ret:
                self.rgbImage = cv2.cvtColor(self.frame, cv2.COLOR_BGR2RGB) #프레임에 색입히기
                self.convertToQtFormat = QImage(self.rgbImage.data, self.rgbImage.shape[1], self.rgbImage.shape[0],
                                                QImage.Format_RGB888)

                self.pixmap = QPixmap(self.convertToQtFormat)
                self.p = self.pixmap.scaled(400, 300, QtCore.Qt.IgnoreAspectRatio) #프레임 크기 조정

                self.video_viewer_label.setPixmap(self.p)
                self.video_viewer_label.update() #프레임 띄우기

                sleep(0.01)  # 영상 1프레임당 0.01초로 이걸로 영상 재생속도 조절하면됨 0.02로하면 0.5배속인거임

            else:
                break

        cap.release()
        cv2.destroyAllWindows()

    # 창 이름 설정
    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("ForSign", "ForSign"))

    # video_to_frame을 쓰레드로 사용
    #이게 영상 재생 쓰레드 돌리는거 얘를 조작하거나 함수를 생성해서 연속재생 관리해야할듯
    def video_thread(self, MainWindow):
        thread = threading.Thread(target=self.Video_to_frame, args=(self,))
        thread.daemon = True  # 프로그램 종료시 프로세스도 함께 종료 (백그라운드 재생 X)
        thread.start()

class로 창 제작과 기능 수행이 편리하게 해두었다. 사실 오픈소스인데 UI 구성부터 스레드, openCV와 비디오 위젯 매칭까지 되어있어서 많은 도움이 되었다. 내가 만든 함수는 crawling 과 Video_to_frame의 일부로 crawling은 이전전 개시물과 같다.

Video_to_frame 함수는 이전 게시물에서 소개했던 동영상 주소를 활용해서 동영상을 저장하는 것으로 시작한다.

 

위 코드들은 합치고 빠진 라이브러리를 임포트하면 실제로 돌아가는 코드로

크롤링 -> 영상 저장 -> 영상 재생 까지 다 된다. 함정은 selenium때문에 창이 띄워지고 5초 뒤에 영상이 나옴.

그래도 숫자 바꿀때마다 새로운 영상으로 실행 잘 되서 뿌듯

반응형