Python, Qt 및 OpenCV로 간단한 WebP 변환 도구를 구축하는 방법

Python, Qt 및 OpenCV로 간단한 WebP 변환 도구를 구축하는 방법

2022-10-04 last update

28 minutes reading webp python qt opencv
"WebP는 손실 압축과 무손실 압축을 모두 사용하는 이미지 형식으로 애니메이션 및 알파 투명도를 지원합니다. Google에서 개발한 이 파일은 JPEG보다 더 작은 파일을 만들거나 동일한 크기에서 더 높은 품질로 만들도록 설계되었습니다. PNG 및 GIF 이미지 형식"- Wikipedia . 속도는 SEO 최적화의 핵심 요소 중 하나입니다. 개발자는 웹 페이지를 SEO 친화적으로 만들기 위해 WebP를 사용하여 JPEG, PNG 및 GIF를 대체하는 경향이 있습니다. 이 기사에서는 Python, Qt 및 OpenCV를 사용하여 간단한 WebP 변환 도구를 빌드하는 방법을 보여줍니다.

설치


  • Python 3.x

  • OpenCV 및 Qt(pyside2 또는 pyside6)

    pip install opencv-python pyside2
    


  • WebP 변환 도구 개발



    1단계: 레이아웃 디자인 및 Python 코드에 UI 로드



    GUI를 디자인하기 위해 열어봅시다Python/Lib/site-packages/PySide2/designer.


  • 레이블: 로드된 이미지를 표시합니다.
  • 수평 슬라이더: WebP 이미지의 품질을 조정합니다.
  • 푸시 버튼: WebP 변환을 트리거합니다.
  • 목록 위젯: 목록에 이미지 파일을 추가합니다.

  • UI 디자인이 완료되면 .ui 에 있는 .py 를 사용하여 pyside2-uic 파일을 Python/Scripts/ 파일로 변환합니다.

    pyside2-uic design.ui -o design.py
    


    다음 단계는 design.py 파일을 로드하고 main.py 파일에 다음 코드를 추가하는 것입니다.

    import sys
    from PySide2.QtGui import QPixmap, QImage, QPainter, QPen, QColor
    from PySide2.QtWidgets import QApplication, QMainWindow, QInputDialog
    from PySide2.QtCore import QFile, QTimer, QEvent
    from PySide2.QtWidgets import *
    from design import Ui_MainWindow
    
    import os
    import cv2
    
    from PySide2.QtCore import QObject, QThread, Signal
    
    class MainWindow(QMainWindow):
    
        def __init__(self):
            super(MainWindow, self).__init__()
            self.ui = Ui_MainWindow()
            self.ui.setupUi(self)
            self.setAcceptDrops(True)
    
    def main():
        app = QApplication(sys.argv)
        window = MainWindow()
        window.show()
        sys.exit(app.exec_())
    
    
    if __name__ == '__main__':
        main()
    


    이제 main.py 파일을 실행하면 GUI가 표시됩니다.

    2단계: 위젯을 나열하고 이미지를 표시할 이미지 파일 로드



    이미지 파일 또는 폴더를 로드하는 방법에는 두 가지가 있습니다.
  • 버튼을 클릭하여 시스템 파일 대화 상자를 엽니다.
  • 이미지 파일 또는 폴더를 응용 프로그램으로 끌어다 놓습니다.

  • 시스템 파일 대화 상자를 열려면 QFileDialog 를 사용하여 getOpenFileName 파일을 선택하고 getExistingDirectory 디렉터리를 선택합니다.

    self.ui.actionOpen_File.triggered.connect(self.openFile)
    self.ui.actionOpen_Folder.triggered.connect(self.openFolder)
    
    def openFile(self):
        filename = QFileDialog.getOpenFileName(self, 'Open File',
                                                self._path, "Barcode images (*)")
    
    def openFolder(self):
        directory = QFileDialog.getExistingDirectory(self, 'Open Folder',
                                                self._path, QFileDialog.ShowDirsOnly)
    
    


    파일 및 폴더에 대해 끌어서 놓기를 활성화하려면 setAcceptDrops(True)에 대해 MainWindow를 설정하고 dragEnterEventdropEvent 메서드를 재정의해야 합니다.

    def __init__(self):
        # ...
        self.setAcceptDrops(True)
    
    def dragEnterEvent(self, event):
        event.acceptProposedAction()
    
    def dropEvent(self, event):
        urls = event.mimeData().urls()
        filename = urls[0].toLocalFile()
        if os.path.isdir(filename):
            self.appendFolder(filename)
        else:
            self.appendFile(filename)
        event.acceptProposedAction()
    


    파일 경로를 얻으면 새 목록 위젯 항목을 만들고 목록 위젯에 추가합니다.

    item = QListWidgetItem()
    item.setText(filename)
    self.ui.listWidget.addItem(item)
    


    Qt 레이블에 이미지를 표시하려면 Mat를 QImage로 변환해야 합니다.

    def showImage(self, filename):
        frame = cv2.imread(filename)
        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        image = QImage(frame, frame.shape[1], frame.shape[0], frame.strides[0], QImage.Format_RGB888)
        pixmap = QPixmap.fromImage(image)
        self._pixmap = self.resizeImage(pixmap)
        self.ui.label.setPixmap(self._pixmap)
        return frame
    


    3단계: 슬라이더 값 가져오기 및 이미지를 WebP로 변환



    최신 OpenCV는 WebP를 지원하므로 cv2.imwrite()를 사용하여 이미지를 WebP로 변환하는 것이 편리합니다.

    quality = int(self.ui.horizontalSlider.value())
    frame = cv2.imread(filename)
    webp_file = filename.split('.')[0] + '.webp'
    cv2.imwrite(webp_file, frame, [cv2.IMWRITE_WEBP_QUALITY, quality])
    


    여러 이미지를 운용할 때의 성능을 고려하여 WebP 변환 코드를 작업자 스레드로 이동합니다. 또한 진행률 표시줄을 표시하면 응용 프로그램의 응답성이 향상됩니다.

    class Worker(QObject):
        finished = Signal()
        progress = Signal(object)
    
        def __init__(self, files, quality):
            super(Worker, self).__init__()
            self.files = files
            self.total = len(files)
            self.isRunning = True
            self.quality = quality
    
        def run(self):
            count = 0
            keys = list(self.files.keys())
            while self.isRunning and len(self.files) > 0:
                filename = keys[count]
                count += 1
                print(filename)
                frame = cv2.imread(filename)
                webp_file = filename.split('.')[0] + '.webp'
                cv2.imwrite(webp_file, frame, [cv2.IMWRITE_WEBP_QUALITY, self.quality])
                self.progress.emit((webp_file, count, self.total))
                self.files.pop(filename)
    
            self.finished.emit()
    
    def reportProgress(self, data):
        filename, completed, total = data
        self.addImage(filename)
        if not self.isProcessing:
            return
    
        progress = completed
        self.progress_dialog.setLabelText(str(completed) +"/"+ str(total))
        self.progress_dialog.setValue(progress)
        if completed == total:
            self.onProgressDialogCanceled()
            self.showMessageBox('WebP Conversion', "Done!")
    
    def onProgressDialogCanceled(self):
        self.isProcessing = False
        self.worker.isRunning = False
        self.progress_dialog.cancel()
    
    def runLongTask(self):
        if (len(self._all_images) == 0):
            return
    
        self.isProcessing = True
        self.progress_dialog = QProgressDialog('Progress', 'Cancel', 0, len(self._all_images), self)
        self.progress_dialog.setLabelText('Progress')
        self.progress_dialog.setCancelButtonText('Cancel')
        self.progress_dialog.setRange(0, len(self._all_images))
        self.progress_dialog.setValue(0)
        self.progress_dialog.setMinimumDuration(0)
        self.progress_dialog.show()
        self.progress_dialog.canceled.connect(self.onProgressDialogCanceled)
    
        self.thread = QThread()
        self.worker = Worker(self._all_images, int(self.ui.label_slider.text()))
        self.worker.moveToThread(self.thread)
        self.thread.started.connect(self.worker.run)
        self.worker.finished.connect(self.thread.quit)
        self.worker.finished.connect(self.worker.deleteLater)
        self.thread.finished.connect(self.thread.deleteLater)
        self.worker.progress.connect(self.reportProgress)
        self.thread.start()
    


    4단계: 응용 프로그램을 실행하여 이미지를 WebP로 변환




    python main.py
    




    소스 코드



    https://github.com/yushulx/webp-image-conversion