stories-matiasucker created by GitHub Classroom

Overview

Stories do Instagram

Este projeto tem como objetivo desenvolver uma pequena aplicação que simule os efeitos e funcionalidades ao estilo Instagram.

A aplicação deve permitir ao usuário:

  • Carregar uma imagem ou vídeo
  • Aplicar diferentes filtros (você deve oferecer pelo menos 4 opções diferentes)
  • Adicionar stickers (figurinhas predefinidas)
  • Adicionar outro elemento a sua escolha (gif, texto, temperatura, local, selfie, etc...)
  • Salvar a foto ou vídeo editado
  • Interação por teclado e/ou mouse

Sumário

  1. Requisitos
  2. Funcionamento
  3. Funções utilizadas da biblioteca OpenCV
  4. Técnicas e funções
    4.1 Brilho e contraste
    4.2 Blur
    4.3 Gray
    4.4 Detector de bordas canny
    4.5 Negativo da imagem
    4.6 Pontilhismo
    4.7 K-means
    4.8 Stickers
    4.9 Texto
  5. Exemplo de edição de vídeo
  6. Funcionamento do código
  7. Conclusão
  8. Código final completo em Python

Requisitos

  • Python 3.8
  • OpenCV 4.5.3
  • Numpy
  • Imutils
  • PyQt5
  • PyQt5 tools

Funcionamento do programa

O programa carrega uma interface bem simples para o usuário, onde é possível carregar fotos ou vídeos para edição. Ao carregar uma foto ou um vídeo, o usuário tem a opção de utilizar diversos filtros, dentre eles o ajuste de contraste, brilho, blur, tons de cinza, detector de bordas canny, negativo, pontilhismo, k-means, adicionar stickers e também texto. O objetivo é proporcionar uma experiência agradável para o usuário editar imagens e vídeos, gerando um resultado satisfatório.

Para utilizar é necessário seguir estes passos:

  • Criar o ambiente virtual para execução do código, instalando os pacotes conforme os requisitos acima.
  • Realizar o comando git clone para clonar o repositório, ou copiar somente a pasta stories-instagram para a pasta do seu projeto.
  • Executar o arquivo stories_instagram.py para iniciar a aplicação.

Funções utilizadas da biblioteca OpenCV

  • cvtColor()
  • threshold()
  • bitwise_not()
  • bitwise_and()
  • add()
  • convertScaleAbs()
  • GaussianBlur()
  • Canny()
  • circle()
  • kmeans()
  • imread()
  • putText()
  • imwrite()
  • VideoCapture()
  • VideoWriter_fourcc()
  • VideoWriter()

Tela inicial

Tela com uma imagem de exemplo carregada.

Técnicas e funções

Brilho e contraste

Para ajuste de brilho e contraste, foi utilizada a função convertScaleAbs() para ajustar a imagem conforme os parâmetros passados leo usuário.

        if self.contrast_adjusted == True or self.brightness_adjusted == True:
            contrast = self.contrast_spinbox.value()
            brightness = self.brightness_spinbox.value()
            self.cv_image = cv2.convertScaleAbs(self.cv_image, self.processed_cv_image, contrast, brightness)

Contraste

Brilho positivo

Brilho negativo

Blur

Para causar o efeito de blur na imagem, foi utilizada a função GaussianBlur(), passando o tamanho do kernel como parâmetros da função, quanto maior, maior o efeito do blur na imagem.

        if self.image_smoothing_checked == True:
            blur = self.smoothing_spinbox.value()
            self.cv_image = cv2.GaussianBlur(self.cv_image, (blur, blur), 0)

Blur

Gray Tons de cinza

Para transformar a imagem colorida em tons de cinza, foi utilizada a função cvtColor(), passando o parâmetro COLOR_BGR2GRAY.

        if self.gray_checked == True:
            if len(self.cv_image.shape) == 3:
                self.cv_image = cv2.cvtColor(self.cv_image, cv2.COLOR_BGR2GRAY)
            else:
                pass

Tons de cinza

Detector de bordas canny

Para detectar as bordas de uma imagem, foi utilizada a função Canny(), passando como parâmetro o valor do slider definido pelo usuário.

        if self.edge_detection_checked == True:
            slider = self.edges_slider.value()
            self.cv_image = cv2.Canny(self.cv_image, slider, 3 * slider)

Detecção de bordas com canny

Negativo da imagem

Para transformar a imagem em seu negativo, foi utilizado a função bitwise_not(), que inverte os bits de cada pixel da imagem.

        if self.negative_checked == True:
            self.cv_image = cv2.bitwise_not(self.cv_image)

Negativo da imagem

Pontilhismo

Para criar o efeito de pontilhismo na imagem, foi utilizada a função circle(), que desenha círculos na nova imagem gerada com as cores da imagem original, antes de aplicar esta técnica, é utilizado funções para randomizar a distância dos centros de cada círculo com as bibliotecas do Numpy.

        if self.points_checked == True:
            STEP = 5
            JITTER = 3
            RAIO = 3
            xrange = np.arange(0, self.cv_image.shape[0] - STEP, STEP) + STEP // 2
            yrange = np.arange(0, self.cv_image.shape[1] - STEP, STEP) + STEP // 2
            points = np.zeros(self.cv_image.shape, dtype=np.uint8)
            np.random.shuffle(xrange)
            for i in xrange:
                np.random.shuffle(yrange)
                for j in yrange:
                    x = i + np.random.randint((2 * JITTER) - JITTER + 1)
                    y = j + np.random.randint((2 * JITTER) - JITTER + 1)
                    color = self.cv_image[x, y]
                    cv2.circle(points, (y, x), RAIO, (int(color[0]), int(color[1]), int(color[2])), -1, cv2.LINE_AA)
            self.cv_image = points.copy()

Pontilhismo

K-means

Para clusterizar a imagem conforme o número de cores definido pelo usuário, foi utilizada a função kmeans(), passando como argumento o número de clusters de que se deseja.

        if self.kmeans_checked == True:
            NCLUSTERS = self.kmeans_spinbox.value()
            NROUNDS = 10
            samples = self.cv_image.reshape((-1, 3))
            samples = np.float32(samples)
            ret, labels, centers = cv2.kmeans(samples,
                                              NCLUSTERS,
                                              None,
                                              (cv2.TERM_CRITERIA_MAX_ITER | cv2.TERM_CRITERIA_EPS, 10, 1),
                                              NROUNDS,
                                              cv2.KMEANS_RANDOM_CENTERS)
            centers = np.uint8(centers)
            res = centers[labels.flatten()]
            self.cv_image = res.reshape((self.cv_image.shape))

K-means

Stickers

Para adicionar stickers, foi utilizada as funções threshold(), bitwise_not(), bitwise_and() e add() para criação da máscara e adição do sticker à imagem. Os sliders funcionam, facilitando o posicionamento do sticker em qualquer lugar na imagem, assim como também a função para modificar o tamanho do sticker.

    def overlaySticker(self):
        self.stickers_horizontal_slider.setRange(0, self.cv_image.shape[1])
        self.stickers_vertical_slider.setRange(0, self.cv_image.shape[0])

        self.size = self.stickers_spinbox.value()
        self.axis_x = self.stickers_horizontal_slider.value()
        self.axis_y = self.stickers_vertical_slider.value()

        self.sticker = imutils.resize(self.sticker, width=(self.cv_image.shape[0] // self.size))
        while True:
            if self.sticker.shape[1] <= self.cv_image.shape[1]:
                if self.sticker.shape[0] <= self.cv_image.shape[0]:
                    break
                else:
                    self.sticker = imutils.resize(self.sticker, height=(self.cv_image.shape[0] // 2))
            else:
                self.sticker = imutils.resize(self.sticker, width=(self.cv_image.shape[1] // 2))

        (rows, cols) = self.sticker.shape[:2]
        if (self.axis_y + rows) > self.cv_image.shape[0]:
            self.axis_y = self.cv_image.shape[0] - rows

        if (self.axis_x + cols) > self.cv_image.shape[1]:
            self.axis_x = self.cv_image.shape[1] - cols

        roi = self.cv_image[self.axis_y:(self.axis_y + rows), self.axis_x:(self.axis_x + cols)]
        self.sticker_gray = cv2.cvtColor(self.sticker, cv2.COLOR_BGR2GRAY)
        ret, mask = cv2.threshold(self.sticker_gray, 10, 255, cv2.THRESH_BINARY)
        mask_inv = cv2.bitwise_not(mask)
        self.cv_image_bg = cv2.bitwise_and(roi, roi, mask=mask_inv)
        self.sticker_fg = cv2.bitwise_and(self.sticker, self.sticker, mask=mask)
        dst = cv2.add(self.cv_image_bg, self.sticker_fg)
        self.cv_image[self.axis_y:(self.axis_y + rows), self.axis_x:(self.axis_x + cols)] = dst

\

Elementos stickers

Texto

Para adicionar texto, foi utilizada a função putText(), onde o usuário poderá inserir o texto, e este texto é adicionado an imagem.

        if self.text_checked == True:
            text = self.textQLine.text()
            font = cv2.FONT_HERSHEY_SIMPLEX
            org = (400, 400)
            fontScale = 1
            color = (0, 0, 255)
            thickness = 2
            self.cv_image = cv2.putText(self.cv_image, text, org, font, fontScale, color, thickness, cv2.LINE_AA, False)

Adição de texto

Resultado da imagem processada

Imagem processada com vários elementos

Exemplo de edição de vídeo

Negativo do vídeo

Sticker no vídeo

Sticker no vídeo

Funcionamento do código

Importação das bibliotecas.

import sys, os, cv2, imutils
import numpy as np
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QLabel, QLineEdit,
                             QPushButton, QCheckBox, QSpinBox, QDoubleSpinBox, QSlider, QFrame, QFileDialog,
                             QMessageBox, QHBoxLayout, QVBoxLayout, QAction)
from PyQt5.QtGui import QPixmap, QImage
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtCore import Qt


Estilizando a interface com o usuário

style_sheet = """
QLabel#ImageLabel{
color: darkgrey;
border: 2px solid #000000;
qproperty-alignment: AlignCenter
}"""


Classe principal do programa

class StoriesInstagram(QMainWindow):
    def __init__(self):
        super().__init__()
        self.initializeUI()


Função para inicializar as componentes gráficas.

    def initializeUI(self):
        self.setMinimumSize(900, 600)
        self.setWindowTitle('Stories Instagram')
        self.contrast_adjusted = False
        self.brightness_adjusted = False
        self.image_smoothing_checked = False
        self.gray_checked = False
        self.edge_detection_checked = False
        self.points_checked = False
        self.kmeans_checked = False
        self.negative_checked = False
        self.stickers_checked = False
        self.text_checked = False
        self.setupWindow()
        self.setupMenu()
        self.show()


Função para renderizar as componentes gráficas

    def setupWindow(self):
        self.image_label = QLabel()
        self.image_label.setObjectName("ImageLabel")

        self.desktop = cv2.imread("assets/stories-do-instagram.png")
        self.convertCVToQImage(self.desktop)

        self.contrast_spinbox = QDoubleSpinBox()
        self.contrast_spinbox.setMinimumWidth(100)
        self.contrast_spinbox.setRange(0.0, 4.0)
        self.contrast_spinbox.setValue(1.0)
        self.contrast_spinbox.setSingleStep(.10)
        self.contrast_cb = QCheckBox("Contraste [Range: 0.0:4.0]")
        self.contrast_cb.stateChanged.connect(self.adjustContrast)

        self.brightness_spinbox = QSpinBox()
        self.brightness_spinbox.setMinimumWidth(100)
        self.brightness_spinbox.setRange(-127, 127)
        self.brightness_spinbox.setValue(0)
        self.brightness_spinbox.setSingleStep(1)
        self.brightness_cb = QCheckBox("Brilho [Range: -127:127]")
        self.brightness_cb.stateChanged.connect(self.adjustBrightness)

        self.smoothing_spinbox = QSpinBox()
        self.smoothing_spinbox.setMinimumWidth(100)
        self.smoothing_spinbox.setRange(3, 25)
        self.smoothing_spinbox.setValue(3)
        self.smoothing_spinbox.setSingleStep(2)
        self.filter_2D_cb = QCheckBox("Blur [Range: 3:25]")
        self.filter_2D_cb.stateChanged.connect(self.imageSmoothingFilter)

        self.gray_cb = QCheckBox("Tons de cinza")
        self.gray_cb.stateChanged.connect(self.makeGray)

        self.edges_slider = QSlider()
        self.edges_slider.setGeometry(QtCore.QRect(370, 340, 160, 19))
        self.edges_slider.setMinimumWidth(100)
        self.edges_slider.setRange(10, 300)
        self.edges_slider.setValue(10)
        self.edges_slider.setSingleStep(10)
        self.edges_slider.setOrientation(QtCore.Qt.Horizontal)
        self.canny_cb = QCheckBox("Detector de Bordas [Range: 10:300]")
        self.canny_cb.stateChanged.connect(self.edgeDetection)

        self.negative_cb = QCheckBox("Negativo")
        self.negative_cb.stateChanged.connect(self.makeNegative)

        self.points_cb = QCheckBox("Pontilhismo")
        self.points_cb.stateChanged.connect(self.makePoints)

        self.kmeans_spinbox = QSpinBox()
        self.kmeans_spinbox.setMinimumWidth(100)
        self.kmeans_spinbox.setRange(1, 32)
        self.kmeans_spinbox.setValue(8)
        self.kmeans_spinbox.setSingleStep(1)
        self.kmeans_cb = QCheckBox("K-means [Range: 1:32]")
        self.kmeans_cb.stateChanged.connect(self.kmeansFilter)

        self.stickers_cb = QCheckBox("Adicionar stickers")
        self.stickers_cb.stateChanged.connect(self.addStickers)

        self.radioButton = QtWidgets.QRadioButton()
        self.radioButton.setGeometry(QtCore.QRect(380, 200, 95, 20))
        self.radioButton.setText("Capitão américa")

        self.radioButton2 = QtWidgets.QRadioButton()
        self.radioButton2.setGeometry(QtCore.QRect(380, 200, 95, 20))
        self.radioButton2.setText("Cerveja")

        self.radioButton3 = QtWidgets.QRadioButton()
        self.radioButton3.setGeometry(QtCore.QRect(380, 200, 95, 20))
        self.radioButton3.setText("Ônibus")

        self.radioButton4 = QtWidgets.QRadioButton()
        self.radioButton4.setGeometry(QtCore.QRect(380, 200, 95, 20))
        self.radioButton4.setText("Las Vegas")

        self.radioButton5 = QtWidgets.QRadioButton()
        self.radioButton5.setGeometry(QtCore.QRect(380, 200, 95, 20))
        self.radioButton5.setText("Morte")

        self.radioButton6 = QtWidgets.QRadioButton()
        self.radioButton6.setGeometry(QtCore.QRect(380, 200, 95, 20))
        self.radioButton6.setText("Batman")

        self.stickers_horizontal_slider = QSlider()
        self.stickers_horizontal_slider.setGeometry(QtCore.QRect(370, 340, 160, 19))
        self.stickers_horizontal_slider.setMinimumWidth(100)
        self.stickers_horizontal_slider.setRange(0, 1200)
        self.stickers_horizontal_slider.setValue(0)
        self.stickers_horizontal_slider.setSingleStep(1)
        self.stickers_horizontal_slider.setOrientation(QtCore.Qt.Horizontal)

        self.stickers_vertical_slider = QSlider()
        self.stickers_vertical_slider.setGeometry(QtCore.QRect(370, 340, 19, 160))
        self.stickers_vertical_slider.setMinimumHeight(200)
        self.stickers_vertical_slider.setInvertedAppearance(True)
        self.stickers_vertical_slider.setRange(0, 920)
        self.stickers_vertical_slider.setValue(0)
        self.stickers_vertical_slider.setSingleStep(1)
        self.stickers_vertical_slider.setOrientation(QtCore.Qt.Vertical)

        self.stickersLabel = QLabel("Tamanho do sticker [Range: 1:5]")
        self.stickers_spinbox = QSpinBox()
        self.stickers_spinbox.setMinimumWidth(100)
        self.stickers_spinbox.setRange(1, 5)
        self.stickers_spinbox.setValue(5)
        self.stickers_spinbox.setSingleStep(1)

        self.text_cb = QCheckBox("Adicionar texto")
        self.text_cb.stateChanged.connect(self.addText)
        self.textQLine = QLineEdit("")
        self.textQLine.setMinimumWidth(100)
        self.textQLine.setMinimumHeight(50)

        self.apply_process_button = QPushButton("Aplicar filtros")
        self.apply_process_button.setEnabled(False)
        self.apply_process_button.clicked.connect(self.applyImageProcessing)

        self.reset_button = QPushButton("Voltar imagem original")
        self.reset_button.setEnabled(False)
        self.reset_button.clicked.connect(self.resetImageAndSettings)

        self.line1 = QtWidgets.QFrame()
        self.line1.setGeometry(QtCore.QRect(200, 420, 118, 3))
        self.line1.setFrameShape(QtWidgets.QFrame.HLine)
        self.line1.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.line1.setObjectName("line1")

        self.line2 = QtWidgets.QFrame()
        self.line2.setGeometry(QtCore.QRect(200, 420, 118, 3))
        self.line2.setFrameShape(QtWidgets.QFrame.HLine)
        self.line2.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.line2.setObjectName("line2")

        self.line3 = QtWidgets.QFrame()
        self.line3.setGeometry(QtCore.QRect(200, 420, 118, 3))
        self.line3.setFrameShape(QtWidgets.QFrame.HLine)
        self.line3.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.line3.setObjectName("line3")

        self.line4 = QtWidgets.QFrame()
        self.line4.setGeometry(QtCore.QRect(200, 420, 118, 3))
        self.line4.setFrameShape(QtWidgets.QFrame.HLine)
        self.line4.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.line4.setObjectName("line4")

        self.line5 = QtWidgets.QFrame()
        self.line5.setGeometry(QtCore.QRect(200, 420, 118, 3))
        self.line5.setFrameShape(QtWidgets.QFrame.HLine)
        self.line5.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.line5.setObjectName("line5")

        self.line6 = QtWidgets.QFrame()
        self.line6.setGeometry(QtCore.QRect(200, 420, 118, 3))
        self.line6.setFrameShape(QtWidgets.QFrame.HLine)
        self.line6.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.line6.setObjectName("line6")

        self.line7 = QtWidgets.QFrame()
        self.line7.setGeometry(QtCore.QRect(200, 420, 118, 3))
        self.line7.setFrameShape(QtWidgets.QFrame.HLine)
        self.line7.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.line7.setObjectName("line7")

        self.line8 = QtWidgets.QFrame()
        self.line8.setGeometry(QtCore.QRect(200, 420, 118, 3))
        self.line8.setFrameShape(QtWidgets.QFrame.HLine)
        self.line8.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.line8.setObjectName("line8")

        self.line9 = QtWidgets.QFrame()
        self.line9.setGeometry(QtCore.QRect(200, 420, 118, 3))
        self.line9.setFrameShape(QtWidgets.QFrame.HLine)
        self.line9.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.line9.setObjectName("line9")

        self.line10 = QtWidgets.QFrame()
        self.line10.setGeometry(QtCore.QRect(200, 420, 118, 3))
        self.line10.setFrameShape(QtWidgets.QFrame.HLine)
        self.line10.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.line10.setObjectName("line10")

        side_panel_v_box = QVBoxLayout()
        side_panel_v_box.setAlignment(Qt.AlignTop)

        side_panel_v_box.addWidget(self.contrast_cb)
        side_panel_v_box.addWidget(self.contrast_spinbox)

        side_panel_v_box.addSpacing(15)
        side_panel_v_box.addWidget(self.line1)

        side_panel_v_box.addWidget(self.brightness_cb)
        side_panel_v_box.addWidget(self.brightness_spinbox)

        side_panel_v_box.addSpacing(15)
        side_panel_v_box.addWidget(self.line2)

        side_panel_v_box.addWidget(self.filter_2D_cb)
        side_panel_v_box.addWidget(self.smoothing_spinbox)

        side_panel_v_box.addSpacing(15)
        side_panel_v_box.addWidget(self.line3)

        side_panel_v_box.addWidget(self.gray_cb)

        side_panel_v_box.addSpacing(15)
        side_panel_v_box.addWidget(self.line4)

        side_panel_v_box.addWidget(self.canny_cb)
        side_panel_v_box.addWidget(self.edges_slider)

        side_panel_v_box.addSpacing(15)
        side_panel_v_box.addWidget(self.line5)

        side_panel_v_box.addWidget(self.negative_cb)

        side_panel_v_box.addSpacing(15)
        side_panel_v_box.addWidget(self.line6)

        side_panel_v_box.addWidget(self.points_cb)

        side_panel_v_box.addSpacing(15)
        side_panel_v_box.addWidget(self.line7)

        side_panel_v_box.addWidget(self.kmeans_cb)
        side_panel_v_box.addWidget(self.kmeans_spinbox)

        side_panel_v_box.addSpacing(15)
        side_panel_v_box.addWidget(self.line8)
        side_panel_v_box.addWidget(self.stickers_cb)

        side_panel_v_box.addWidget(self.radioButton)
        side_panel_v_box.addWidget(self.radioButton2)
        side_panel_v_box.addWidget(self.radioButton3)
        side_panel_v_box.addWidget(self.radioButton4)
        side_panel_v_box.addWidget(self.radioButton5)
        side_panel_v_box.addWidget(self.radioButton6)

        side_panel_v_box.addWidget(self.stickers_horizontal_slider)
        side_panel_v_box.addWidget(self.stickers_vertical_slider)
        side_panel_v_box.addWidget(self.stickersLabel)
        side_panel_v_box.addWidget(self.stickers_spinbox)

        side_panel_v_box.addSpacing(15)
        side_panel_v_box.addWidget(self.line9)
        side_panel_v_box.addWidget(self.text_cb)
        side_panel_v_box.addWidget(self.textQLine)

        side_panel_v_box.addSpacing(100)
        side_panel_v_box.addWidget(self.line10)
        side_panel_v_box.addWidget(self.apply_process_button)
        side_panel_v_box.addWidget(self.reset_button)

        side_panel_frame = QFrame()
        side_panel_frame.setMinimumWidth(250)
        side_panel_frame.setFrameStyle(QFrame.WinPanel)
        side_panel_frame.setLayout(side_panel_v_box)

        scrollArea = QtWidgets.QScrollArea()
        scrollArea.setMinimumWidth(300)
        scrollArea.setWidgetResizable(True)
        scrollArea.setWidget(side_panel_frame)

        main_h_box = QHBoxLayout()
        main_h_box.addWidget(self.image_label, 1)
        main_h_box.addWidget(scrollArea)

        container = QWidget()
        container.setLayout(main_h_box)
        self.setCentralWidget(container)


Função para renderizar o menu superior.

    def setupMenu(self):
        open_image_act = QAction('Abrir imagem', self)
        open_image_act.setShortcut('Ctrl+O')
        open_image_act.triggered.connect(self.openImageFile)
        save_image_act = QAction('Salvar imagem', self)
        save_image_act.setShortcut('Ctrl+S')
        save_image_act.triggered.connect(self.saveImageFile)

        open_video_act = QAction('Abrir video', self)
        open_video_act.setShortcut('Ctrl+O')
        open_video_act.triggered.connect(self.openVideoFile)
        save_video_act = QAction('Salvar video', self)
        save_video_act.setShortcut('Ctrl+S')
        save_video_act.triggered.connect(self.saveVideoFile)

        menu_bar = self.menuBar()
        menu_bar.setNativeMenuBar(False)

        file_menu = menu_bar.addMenu('File')
        file_menu.addAction(open_image_act)
        file_menu.addAction(save_image_act)
        file_menu.addAction(open_video_act)
        file_menu.addAction(save_video_act)


Funções para identificar o estado de ativação das alterações para cada função FILTRO.

    def adjustContrast(self, state):
        if state == Qt.Checked and self.image_label.pixmap() != None:
            self.contrast_adjusted = True
        elif state != Qt.Checked and self.image_label.pixmap() != None:
            self.contrast_adjusted = False


    def adjustBrightness(self, state):
        if state == Qt.Checked and self.image_label.pixmap() != None:
            self.brightness_adjusted = True
        elif state != Qt.Checked and self.image_label.pixmap() != None:
            self.brightness_adjusted = False


    def imageSmoothingFilter(self, state):
        if state == Qt.Checked and self.image_label.pixmap() != None:
            self.image_smoothing_checked = True
        elif state != Qt.Checked and self.image_label.pixmap() != None:
            self.image_smoothing_checked = False


    def makeGray(self, state):
        if state == Qt.Checked and self.image_label.pixmap() != None:
            self.gray_checked = True
        elif state != Qt.Checked and self.image_label.pixmap() != None:
            self.gray_checked = False


    def edgeDetection(self, state):
        if state == Qt.Checked and self.image_label.pixmap() != None:
            self.edge_detection_checked = True
        elif state != Qt.Checked and self.image_label.pixmap() != None:
            self.edge_detection_checked = False


    def makeNegative(self, state):
        if state == Qt.Checked and self.image_label.pixmap() != None:
            self.negative_checked = True
        elif state != Qt.Checked and self.image_label.pixmap() != None:
            self.negative_checked = False


    def makePoints(self, state):
        if state == Qt.Checked and self.image_label.pixmap() != None:
            self.points_checked = True
        elif state != Qt.Checked and self.image_label.pixmap() != None:
            self.points_checked = False


    def kmeansFilter(self, state):
        if state == Qt.Checked and self.image_label.pixmap() != None:
            self.kmeans_checked = True
        elif state != Qt.Checked and self.image_label.pixmap() != None:
            self.kmeans_checked = False

    def addStickers(self, state):
        if state == Qt.Checked and self.image_label.pixmap() != None:
            self.stickers_checked = True
        elif state != Qt.Checked and self.image_label.pixmap() != None:
            self.stickers_checked = False

    def addText(self, state):
        if state == Qt.Checked and self.image_label.pixmap() != None:
            self.text_checked = True
        elif state != Qt.Checked and self.image_label.pixmap() != None:
            self.text_checked = False


Função para adicionar um sticker à uma imagem, os sliders funcionam em toda a sua região, é possível adicionar um sticker em qualquer área da imagem, e ainda selecionar o tamanho deste sticker.

    def overlaySticker(self):
        self.stickers_horizontal_slider.setRange(0, self.cv_image.shape[1])
        self.stickers_vertical_slider.setRange(0, self.cv_image.shape[0])

        self.size = self.stickers_spinbox.value()
        self.axis_x = self.stickers_horizontal_slider.value()
        self.axis_y = self.stickers_vertical_slider.value()

        self.sticker = imutils.resize(self.sticker, width=(self.cv_image.shape[0] // self.size))
        while True:
            if self.sticker.shape[1] <= self.cv_image.shape[1]:
                if self.sticker.shape[0] <= self.cv_image.shape[0]:
                    break
                else:
                    self.sticker = imutils.resize(self.sticker, height=(self.cv_image.shape[0] // 2))
            else:
                self.sticker = imutils.resize(self.sticker, width=(self.cv_image.shape[1] // 2))

        (rows, cols) = self.sticker.shape[:2]
        if (self.axis_y + rows) > self.cv_image.shape[0]:
            self.axis_y = self.cv_image.shape[0] - rows

        if (self.axis_x + cols) > self.cv_image.shape[1]:
            self.axis_x = self.cv_image.shape[1] - cols

        roi = self.cv_image[self.axis_y:(self.axis_y + rows), self.axis_x:(self.axis_x + cols)]
        self.sticker_gray = cv2.cvtColor(self.sticker, cv2.COLOR_BGR2GRAY)
        ret, mask = cv2.threshold(self.sticker_gray, 10, 255, cv2.THRESH_BINARY)
        mask_inv = cv2.bitwise_not(mask)
        self.cv_image_bg = cv2.bitwise_and(roi, roi, mask=mask_inv)
        self.sticker_fg = cv2.bitwise_and(self.sticker, self.sticker, mask=mask)
        dst = cv2.add(self.cv_image_bg, self.sticker_fg)
        self.cv_image[self.axis_y:(self.axis_y + rows), self.axis_x:(self.axis_x + cols)] = dst


Função para aplicar os filtros escolhidos na imagem.

    def applyImageProcessing(self):
        if self.contrast_adjusted == True or self.brightness_adjusted == True:
            contrast = self.contrast_spinbox.value()
            brightness = self.brightness_spinbox.value()
            self.cv_image = cv2.convertScaleAbs(self.cv_image, self.processed_cv_image, contrast, brightness)

        if self.image_smoothing_checked == True:
            blur = self.smoothing_spinbox.value()
            self.cv_image = cv2.GaussianBlur(self.cv_image, (blur, blur), 0)

        if self.gray_checked == True:
            if len(self.cv_image.shape) == 3:
                self.cv_image = cv2.cvtColor(self.cv_image, cv2.COLOR_BGR2GRAY)
            else:
                pass

        if self.edge_detection_checked == True:
            slider = self.edges_slider.value()
            self.cv_image = cv2.Canny(self.cv_image, slider, 3 * slider)

        if self.negative_checked == True:
            self.cv_image = cv2.bitwise_not(self.cv_image)

        if self.points_checked == True:
            STEP = 5
            JITTER = 3
            RAIO = 3
            xrange = np.arange(0, self.cv_image.shape[0] - STEP, STEP) + STEP // 2
            yrange = np.arange(0, self.cv_image.shape[1] - STEP, STEP) + STEP // 2
            points = np.zeros(self.cv_image.shape, dtype=np.uint8)
            np.random.shuffle(xrange)
            for i in xrange:
                np.random.shuffle(yrange)
                for j in yrange:
                    x = i + np.random.randint((2 * JITTER) - JITTER + 1)
                    y = j + np.random.randint((2 * JITTER) - JITTER + 1)
                    color = self.cv_image[x, y]
                    cv2.circle(points, (y, x), RAIO, (int(color[0]), int(color[1]), int(color[2])), -1, cv2.LINE_AA)
            self.cv_image = points.copy()

        if self.kmeans_checked == True:
            NCLUSTERS = self.kmeans_spinbox.value()
            NROUNDS = 10
            samples = self.cv_image.reshape((-1, 3))
            samples = np.float32(samples)
            ret, labels, centers = cv2.kmeans(samples,
                                              NCLUSTERS,
                                              None,
                                              (cv2.TERM_CRITERIA_MAX_ITER | cv2.TERM_CRITERIA_EPS, 10, 1),
                                              NROUNDS,
                                              cv2.KMEANS_RANDOM_CENTERS)
            centers = np.uint8(centers)
            res = centers[labels.flatten()]
            self.cv_image = res.reshape((self.cv_image.shape))


        if self.stickers_checked == True:
            if self.radioButton.isChecked():
                self.sticker = cv2.imread("assets/capitao.png")
                self.overlaySticker()

            elif self.radioButton2.isChecked():
                self.sticker = cv2.imread("assets/cerveja.png")
                self.overlaySticker()

            elif self.radioButton3.isChecked():
                self.sticker = cv2.imread("assets/onibus.png")
                self.overlaySticker()

            elif self.radioButton4.isChecked():
                self.sticker = cv2.imread("assets/lasvegas.png")
                self.overlaySticker()

            elif self.radioButton5.isChecked():
                self.sticker = cv2.imread("assets/morte.png")
                self.overlaySticker()

            elif self.radioButton6.isChecked():
                self.sticker = cv2.imread("assets/batman.png")
                self.overlaySticker()

        if self.text_checked == True:
            text = self.textQLine.text()
            font = cv2.FONT_HERSHEY_SIMPLEX
            org = (400, 400)
            fontScale = 1
            color = (0, 0, 255)
            thickness = 2
            self.cv_image = cv2.putText(self.cv_image, text, org, font, fontScale, color, thickness, cv2.LINE_AA, False)

        self.convertCVToQImage(self.cv_image)
        self.image_label.repaint()


Função para cancelar os filtros, limpar os checkbox de seleção e voltar a imagem original.

    def resetImageAndSettings(self):
        answer = QMessageBox.information(self, "Voltar imagem original",
                                         "Você tem certeza de que deseja voltar a imagem original?",
                                         QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        if answer == QMessageBox.No:
            pass
        elif answer == QMessageBox.Yes and self.image_label.pixmap() != None:
            self.cv_image = self.copy_cv_image.copy()
            self.resetWidgetValues()
            self.convertCVToQImage(self.copy_cv_image)
            self.image_label.repaint()


    def resetWidgetValues(self):
        self.contrast_cb.setChecked(False)
        self.contrast_spinbox.setValue(1.0)
        self.brightness_cb.setChecked(False)
        self.brightness_spinbox.setValue(0)
        self.filter_2D_cb.setChecked(False)
        self.smoothing_spinbox.setValue(3)
        self.gray_cb.setChecked(False)
        self.canny_cb.setChecked(False)
        self.edges_slider.setValue(10)
        self.negative_cb.setChecked(False)
        self.points_cb.setChecked(False)
        self.kmeans_cb.setChecked(False)
        self.kmeans_spinbox.setValue(8)
        self.stickers_cb.setChecked(False)
        self.stickers_spinbox.setValue(5)
        self.radioButton.setChecked(False)
        self.radioButton2.setChecked(False)
        self.radioButton3.setChecked(False)
        self.radioButton4.setChecked(False)
        self.radioButton5.setChecked(False)
        self.radioButton6.setChecked(False)
        self.stickers_horizontal_slider.setValue(0)
        self.stickers_vertical_slider.setValue(0)
        self.text_cb.setChecked(False)
        self.textQLine.setText("")


Função para abrir uma imagem.

    def openImageFile(self):
        image_file, _ = QFileDialog.getOpenFileName(self, "Abrir imagem",
                                                    os.getenv('HOME'), "Images (*.png *.jpeg *.jpg *.bmp)")
        if image_file:
            self.resetWidgetValues()
            self.apply_process_button.setEnabled(True)
            self.reset_button.setEnabled(True)
            self.cv_image = cv2.imread(image_file)
            self.copy_cv_image = self.cv_image.copy()
            self.processed_cv_image = np.zeros(self.cv_image.shape, self.cv_image.dtype)
            self.convertCVToQImage(self.cv_image)
        else:
            QMessageBox.information(self, "Erro", "Nenhuma imagem foi carregada.", QMessageBox.Ok)


Função para salvar uma imagem.

    def saveImageFile(self):
        image_file, _ = QFileDialog.getSaveFileName(self, "Salvar imagem",
                                                    os.getenv('HOME'),
                                                    "JPEG (*.jpeg);;JPG (*.jpg);;PNG (*.png);;Bitmap (*.bmp)")
        if image_file and self.image_label.pixmap() != None:
            cv2.imwrite(image_file, self.cv_image)
        else:
            QMessageBox.information(self, "Erro",
                                    "Não é possível salvar a imagem.", QMessageBox.Ok)


Função para abrir um vídeo.

    def openVideoFile(self):
        self.input_video_file, _ = QFileDialog.getOpenFileName(self, "Abrir video",
                                                    os.getenv('HOME'), "Video (*.mp4)")
        if self.input_video_file:
            self.resetWidgetValues()
            self.apply_process_button.setEnabled(True)
            self.reset_button.setEnabled(True)
            capture = cv2.VideoCapture(self.input_video_file)
            exist_frame, frame = capture.read()
            self.height, self.width = frame.shape[:2]
            if exist_frame:
                frame = cv2.cvtColor(frame, cv2.IMREAD_COLOR)
                self.cv_image = cv2.cvtColor(frame, cv2.IMREAD_COLOR)
                self.copy_cv_image = self.cv_image.copy()

                self.processed_cv_image = np.zeros(self.cv_image.shape, self.cv_image.dtype)
                self.convertCVToQImage(self.cv_image)
        else:
            QMessageBox.information(self, "Erro", "Nenhum video foi carregado.", QMessageBox.Ok)


Função para salvar um vídeo.

    def saveVideoFile(self):
        self.output_video_file, _ = QFileDialog.getSaveFileName(self, "Salvar video",
                                                    os.getenv('HOME'),
                                                    "AVI (*.avi)")
        if self.output_video_file and self.image_label.pixmap() != None:
            capture = cv2.VideoCapture(self.input_video_file)
            fourcc = cv2.VideoWriter_fourcc(*'XVID')
            out = cv2.VideoWriter(self.output_video_file, fourcc, 24, (self.width, self.height))
            while True:
                exist_frame, frame = capture.read()
                if not exist_frame:
                    break

                self.cv_image = frame
                self.applyImageProcessing()

                frame = self.cv_image
                out.write(frame)

            capture.release()
            out.release()
        else:
            QMessageBox.information(self, "Erro",
                                    "Não é possível salvar o video.", QMessageBox.Ok)


Função para converter uma imagem carregada pelo OpenCV para uma imagem a ser reconhecida pela função QImage da biblioteca PyQt5.

    def convertCVToQImage(self, image):
        cv_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
        height, width, channels = cv_image.shape
        bytes_per_line = width * channels
        converted_Qt_image = QImage(cv_image, width, height, bytes_per_line, QImage.Format_RGB888)
        self.image_label.setPixmap(QPixmap.fromImage(converted_Qt_image).scaled(
            self.image_label.width(), self.image_label.height(),
            Qt.KeepAspectRatio))


Entrypoint do programa, função principal main para iniciar o programa.

if __name__ == '__main__':
    app = QApplication(sys.argv)
    app.setStyleSheet(style_sheet)
    window = StoriesInstagram()
    sys.exit(app.exec_())

\


Conclusão

O programa desenvolvido apresentou bons resultados tanto na edição de imagem, quanto na edição de vídeo, o usuário é capaz de carregar um arquivo de imagem ou vídeo, escolher o filtro desejado, aplicar mais de um filtro, e depois salvar, também é possível desfazer os filtros e voltar a imagem original para recomeçar com outros filtros.. A interação do usuário através da interface gráfica utilizando o PyQt5, também se torna mais atrativa durante a edição.


Código final completo em Python

self.cv_image.shape[0]: self.axis_y = self.cv_image.shape[0] - rows if (self.axis_x + cols) > self.cv_image.shape[1]: self.axis_x = self.cv_image.shape[1] - cols roi = self.cv_image[self.axis_y:(self.axis_y + rows), self.axis_x:(self.axis_x + cols)] self.sticker_gray = cv2.cvtColor(self.sticker, cv2.COLOR_BGR2GRAY) ret, mask = cv2.threshold(self.sticker_gray, 10, 255, cv2.THRESH_BINARY) mask_inv = cv2.bitwise_not(mask) self.cv_image_bg = cv2.bitwise_and(roi, roi, mask=mask_inv) self.sticker_fg = cv2.bitwise_and(self.sticker, self.sticker, mask=mask) dst = cv2.add(self.cv_image_bg, self.sticker_fg) self.cv_image[self.axis_y:(self.axis_y + rows), self.axis_x:(self.axis_x + cols)] = dst def applyImageProcessing(self): if self.contrast_adjusted == True or self.brightness_adjusted == True: contrast = self.contrast_spinbox.value() brightness = self.brightness_spinbox.value() self.cv_image = cv2.convertScaleAbs(self.cv_image, self.processed_cv_image, contrast, brightness) if self.image_smoothing_checked == True: blur = self.smoothing_spinbox.value() self.cv_image = cv2.GaussianBlur(self.cv_image, (blur, blur), 0) if self.gray_checked == True: if len(self.cv_image.shape) == 3: self.cv_image = cv2.cvtColor(self.cv_image, cv2.COLOR_BGR2GRAY) else: pass if self.edge_detection_checked == True: slider = self.edges_slider.value() self.cv_image = cv2.Canny(self.cv_image, slider, 3 * slider) if self.negative_checked == True: self.cv_image = cv2.bitwise_not(self.cv_image) if self.points_checked == True: STEP = 5 JITTER = 3 RAIO = 3 xrange = np.arange(0, self.cv_image.shape[0] - STEP, STEP) + STEP // 2 yrange = np.arange(0, self.cv_image.shape[1] - STEP, STEP) + STEP // 2 points = np.zeros(self.cv_image.shape, dtype=np.uint8) np.random.shuffle(xrange) for i in xrange: np.random.shuffle(yrange) for j in yrange: x = i + np.random.randint((2 * JITTER) - JITTER + 1) y = j + np.random.randint((2 * JITTER) - JITTER + 1) color = self.cv_image[x, y] cv2.circle(points, (y, x), RAIO, (int(color[0]), int(color[1]), int(color[2])), -1, cv2.LINE_AA) self.cv_image = points.copy() if self.kmeans_checked == True: NCLUSTERS = self.kmeans_spinbox.value() NROUNDS = 10 samples = self.cv_image.reshape((-1, 3)) samples = np.float32(samples) ret, labels, centers = cv2.kmeans(samples, NCLUSTERS, None, (cv2.TERM_CRITERIA_MAX_ITER | cv2.TERM_CRITERIA_EPS, 10, 1), NROUNDS, cv2.KMEANS_RANDOM_CENTERS) centers = np.uint8(centers) res = centers[labels.flatten()] self.cv_image = res.reshape((self.cv_image.shape)) if self.stickers_checked == True: if self.radioButton.isChecked(): self.sticker = cv2.imread("assets/capitao.png") self.overlaySticker() elif self.radioButton2.isChecked(): self.sticker = cv2.imread("assets/cerveja.png") self.overlaySticker() elif self.radioButton3.isChecked(): self.sticker = cv2.imread("assets/onibus.png") self.overlaySticker() elif self.radioButton4.isChecked(): self.sticker = cv2.imread("assets/lasvegas.png") self.overlaySticker() elif self.radioButton5.isChecked(): self.sticker = cv2.imread("assets/morte.png") self.overlaySticker() elif self.radioButton6.isChecked(): self.sticker = cv2.imread("assets/batman.png") self.overlaySticker() if self.text_checked == True: text = self.textQLine.text() font = cv2.FONT_HERSHEY_SIMPLEX org = (400, 400) fontScale = 1 color = (0, 0, 255) thickness = 2 self.cv_image = cv2.putText(self.cv_image, text, org, font, fontScale, color, thickness, cv2.LINE_AA, False) self.convertCVToQImage(self.cv_image) self.image_label.repaint() def resetImageAndSettings(self): answer = QMessageBox.information(self, "Voltar imagem original", "Você tem certeza de que deseja voltar a imagem original?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if answer == QMessageBox.No: pass elif answer == QMessageBox.Yes and self.image_label.pixmap() != None: self.cv_image = self.copy_cv_image.copy() self.resetWidgetValues() self.convertCVToQImage(self.copy_cv_image) self.image_label.repaint() def resetWidgetValues(self): self.contrast_cb.setChecked(False) self.contrast_spinbox.setValue(1.0) self.brightness_cb.setChecked(False) self.brightness_spinbox.setValue(0) self.filter_2D_cb.setChecked(False) self.smoothing_spinbox.setValue(3) self.gray_cb.setChecked(False) self.canny_cb.setChecked(False) self.edges_slider.setValue(10) self.negative_cb.setChecked(False) self.points_cb.setChecked(False) self.kmeans_cb.setChecked(False) self.kmeans_spinbox.setValue(8) self.stickers_cb.setChecked(False) self.stickers_spinbox.setValue(5) self.radioButton.setChecked(False) self.radioButton2.setChecked(False) self.radioButton3.setChecked(False) self.radioButton4.setChecked(False) self.radioButton5.setChecked(False) self.radioButton6.setChecked(False) self.stickers_horizontal_slider.setValue(0) self.stickers_vertical_slider.setValue(0) self.text_cb.setChecked(False) self.textQLine.setText("") def openImageFile(self): image_file, _ = QFileDialog.getOpenFileName(self, "Abrir imagem", os.getenv('HOME'), "Images (*.png *.jpeg *.jpg *.bmp)") if image_file: self.resetWidgetValues() self.apply_process_button.setEnabled(True) self.reset_button.setEnabled(True) self.cv_image = cv2.imread(image_file) self.copy_cv_image = self.cv_image.copy() self.processed_cv_image = np.zeros(self.cv_image.shape, self.cv_image.dtype) self.convertCVToQImage(self.cv_image) else: QMessageBox.information(self, "Erro", "Nenhuma imagem foi carregada.", QMessageBox.Ok) def saveImageFile(self): image_file, _ = QFileDialog.getSaveFileName(self, "Salvar imagem", os.getenv('HOME'), "JPEG (*.jpeg);;JPG (*.jpg);;PNG (*.png);;Bitmap (*.bmp)") if image_file and self.image_label.pixmap() != None: cv2.imwrite(image_file, self.cv_image) else: QMessageBox.information(self, "Erro", "Não é possível salvar a imagem.", QMessageBox.Ok) def openVideoFile(self): self.input_video_file, _ = QFileDialog.getOpenFileName(self, "Abrir video", os.getenv('HOME'), "Video (*.mp4)") if self.input_video_file: self.resetWidgetValues() self.apply_process_button.setEnabled(True) self.reset_button.setEnabled(True) capture = cv2.VideoCapture(self.input_video_file) exist_frame, frame = capture.read() self.height, self.width = frame.shape[:2] if exist_frame: frame = cv2.cvtColor(frame, cv2.IMREAD_COLOR) self.cv_image = cv2.cvtColor(frame, cv2.IMREAD_COLOR) self.copy_cv_image = self.cv_image.copy() self.processed_cv_image = np.zeros(self.cv_image.shape, self.cv_image.dtype) self.convertCVToQImage(self.cv_image) else: QMessageBox.information(self, "Erro", "Nenhum video foi carregado.", QMessageBox.Ok) def saveVideoFile(self): self.output_video_file, _ = QFileDialog.getSaveFileName(self, "Salvar video", os.getenv('HOME'), "AVI (*.avi)") if self.output_video_file and self.image_label.pixmap() != None: capture = cv2.VideoCapture(self.input_video_file) fourcc = cv2.VideoWriter_fourcc(*'XVID') out = cv2.VideoWriter(self.output_video_file, fourcc, 24, (self.width, self.height)) while True: exist_frame, frame = capture.read() if not exist_frame: break self.cv_image = frame self.applyImageProcessing() frame = self.cv_image out.write(frame) capture.release() out.release() else: QMessageBox.information(self, "Erro", "Não é possível salvar o video.", QMessageBox.Ok) def convertCVToQImage(self, image): cv_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) height, width, channels = cv_image.shape bytes_per_line = width * channels converted_Qt_image = QImage(cv_image, width, height, bytes_per_line, QImage.Format_RGB888) self.image_label.setPixmap(QPixmap.fromImage(converted_Qt_image).scaled( self.image_label.width(), self.image_label.height(), Qt.KeepAspectRatio)) if __name__ == '__main__': app = QApplication(sys.argv) app.setStyleSheet(style_sheet) window = StoriesInstagram() sys.exit(app.exec_())">
import sys, os, cv2, imutils
import numpy as np
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QLabel, QLineEdit,
                             QPushButton, QCheckBox, QSpinBox, QDoubleSpinBox, QSlider, QFrame, QFileDialog,
                             QMessageBox, QHBoxLayout, QVBoxLayout, QAction)
from PyQt5.QtGui import QPixmap, QImage
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtCore import Qt

style_sheet = """
QLabel#ImageLabel{
color: darkgrey;
border: 2px solid #000000;
qproperty-alignment: AlignCenter
}"""


class StoriesInstagram(QMainWindow):
    def __init__(self):
        super().__init__()
        self.initializeUI()


    def initializeUI(self):
        self.setMinimumSize(900, 600)
        self.setWindowTitle('Stories Instagram')
        self.contrast_adjusted = False
        self.brightness_adjusted = False
        self.image_smoothing_checked = False
        self.gray_checked = False
        self.edge_detection_checked = False
        self.points_checked = False
        self.kmeans_checked = False
        self.negative_checked = False
        self.stickers_checked = False
        self.text_checked = False
        self.setupWindow()
        self.setupMenu()
        self.show()


    def setupWindow(self):
        self.image_label = QLabel()
        self.image_label.setObjectName("ImageLabel")

        self.desktop = cv2.imread("assets/stories-do-instagram.png")
        self.convertCVToQImage(self.desktop)

        self.contrast_spinbox = QDoubleSpinBox()
        self.contrast_spinbox.setMinimumWidth(100)
        self.contrast_spinbox.setRange(0.0, 4.0)
        self.contrast_spinbox.setValue(1.0)
        self.contrast_spinbox.setSingleStep(.10)
        self.contrast_cb = QCheckBox("Contraste [Range: 0.0:4.0]")
        self.contrast_cb.stateChanged.connect(self.adjustContrast)

        self.brightness_spinbox = QSpinBox()
        self.brightness_spinbox.setMinimumWidth(100)
        self.brightness_spinbox.setRange(-127, 127)
        self.brightness_spinbox.setValue(0)
        self.brightness_spinbox.setSingleStep(1)
        self.brightness_cb = QCheckBox("Brilho [Range: -127:127]")
        self.brightness_cb.stateChanged.connect(self.adjustBrightness)

        self.smoothing_spinbox = QSpinBox()
        self.smoothing_spinbox.setMinimumWidth(100)
        self.smoothing_spinbox.setRange(3, 25)
        self.smoothing_spinbox.setValue(3)
        self.smoothing_spinbox.setSingleStep(2)
        self.filter_2D_cb = QCheckBox("Blur [Range: 3:25]")
        self.filter_2D_cb.stateChanged.connect(self.imageSmoothingFilter)

        self.gray_cb = QCheckBox("Tons de cinza")
        self.gray_cb.stateChanged.connect(self.makeGray)

        self.edges_slider = QSlider()
        self.edges_slider.setGeometry(QtCore.QRect(370, 340, 160, 19))
        self.edges_slider.setMinimumWidth(100)
        self.edges_slider.setRange(10, 300)
        self.edges_slider.setValue(10)
        self.edges_slider.setSingleStep(10)
        self.edges_slider.setOrientation(QtCore.Qt.Horizontal)
        self.canny_cb = QCheckBox("Detector de Bordas [Range: 10:300]")
        self.canny_cb.stateChanged.connect(self.edgeDetection)

        self.negative_cb = QCheckBox("Negativo")
        self.negative_cb.stateChanged.connect(self.makeNegative)

        self.points_cb = QCheckBox("Pontilhismo")
        self.points_cb.stateChanged.connect(self.makePoints)

        self.kmeans_spinbox = QSpinBox()
        self.kmeans_spinbox.setMinimumWidth(100)
        self.kmeans_spinbox.setRange(1, 32)
        self.kmeans_spinbox.setValue(8)
        self.kmeans_spinbox.setSingleStep(1)
        self.kmeans_cb = QCheckBox("K-means [Range: 1:32]")
        self.kmeans_cb.stateChanged.connect(self.kmeansFilter)

        self.stickers_cb = QCheckBox("Adicionar stickers")
        self.stickers_cb.stateChanged.connect(self.addStickers)

        self.radioButton = QtWidgets.QRadioButton()
        self.radioButton.setGeometry(QtCore.QRect(380, 200, 95, 20))
        self.radioButton.setText("Capitão américa")

        self.radioButton2 = QtWidgets.QRadioButton()
        self.radioButton2.setGeometry(QtCore.QRect(380, 200, 95, 20))
        self.radioButton2.setText("Cerveja")

        self.radioButton3 = QtWidgets.QRadioButton()
        self.radioButton3.setGeometry(QtCore.QRect(380, 200, 95, 20))
        self.radioButton3.setText("Ônibus")

        self.radioButton4 = QtWidgets.QRadioButton()
        self.radioButton4.setGeometry(QtCore.QRect(380, 200, 95, 20))
        self.radioButton4.setText("Las Vegas")

        self.radioButton5 = QtWidgets.QRadioButton()
        self.radioButton5.setGeometry(QtCore.QRect(380, 200, 95, 20))
        self.radioButton5.setText("Morte")

        self.radioButton6 = QtWidgets.QRadioButton()
        self.radioButton6.setGeometry(QtCore.QRect(380, 200, 95, 20))
        self.radioButton6.setText("Batman")

        self.stickers_horizontal_slider = QSlider()
        self.stickers_horizontal_slider.setGeometry(QtCore.QRect(370, 340, 160, 19))
        self.stickers_horizontal_slider.setMinimumWidth(100)
        self.stickers_horizontal_slider.setRange(0, 1200)
        self.stickers_horizontal_slider.setValue(0)
        self.stickers_horizontal_slider.setSingleStep(1)
        self.stickers_horizontal_slider.setOrientation(QtCore.Qt.Horizontal)

        self.stickers_vertical_slider = QSlider()
        self.stickers_vertical_slider.setGeometry(QtCore.QRect(370, 340, 19, 160))
        self.stickers_vertical_slider.setMinimumHeight(200)
        self.stickers_vertical_slider.setInvertedAppearance(True)
        self.stickers_vertical_slider.setRange(0, 920)
        self.stickers_vertical_slider.setValue(0)
        self.stickers_vertical_slider.setSingleStep(1)
        self.stickers_vertical_slider.setOrientation(QtCore.Qt.Vertical)

        self.stickersLabel = QLabel("Tamanho do sticker [Range: 1:5]")
        self.stickers_spinbox = QSpinBox()
        self.stickers_spinbox.setMinimumWidth(100)
        self.stickers_spinbox.setRange(1, 5)
        self.stickers_spinbox.setValue(5)
        self.stickers_spinbox.setSingleStep(1)

        self.text_cb = QCheckBox("Adicionar texto")
        self.text_cb.stateChanged.connect(self.addText)
        self.textQLine = QLineEdit("")
        self.textQLine.setMinimumWidth(100)
        self.textQLine.setMinimumHeight(50)

        self.apply_process_button = QPushButton("Aplicar filtros")
        self.apply_process_button.setEnabled(False)
        self.apply_process_button.clicked.connect(self.applyImageProcessing)

        self.reset_button = QPushButton("Voltar imagem original")
        self.reset_button.setEnabled(False)
        self.reset_button.clicked.connect(self.resetImageAndSettings)

        self.line1 = QtWidgets.QFrame()
        self.line1.setGeometry(QtCore.QRect(200, 420, 118, 3))
        self.line1.setFrameShape(QtWidgets.QFrame.HLine)
        self.line1.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.line1.setObjectName("line1")

        self.line2 = QtWidgets.QFrame()
        self.line2.setGeometry(QtCore.QRect(200, 420, 118, 3))
        self.line2.setFrameShape(QtWidgets.QFrame.HLine)
        self.line2.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.line2.setObjectName("line2")

        self.line3 = QtWidgets.QFrame()
        self.line3.setGeometry(QtCore.QRect(200, 420, 118, 3))
        self.line3.setFrameShape(QtWidgets.QFrame.HLine)
        self.line3.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.line3.setObjectName("line3")

        self.line4 = QtWidgets.QFrame()
        self.line4.setGeometry(QtCore.QRect(200, 420, 118, 3))
        self.line4.setFrameShape(QtWidgets.QFrame.HLine)
        self.line4.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.line4.setObjectName("line4")

        self.line5 = QtWidgets.QFrame()
        self.line5.setGeometry(QtCore.QRect(200, 420, 118, 3))
        self.line5.setFrameShape(QtWidgets.QFrame.HLine)
        self.line5.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.line5.setObjectName("line5")

        self.line6 = QtWidgets.QFrame()
        self.line6.setGeometry(QtCore.QRect(200, 420, 118, 3))
        self.line6.setFrameShape(QtWidgets.QFrame.HLine)
        self.line6.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.line6.setObjectName("line6")

        self.line7 = QtWidgets.QFrame()
        self.line7.setGeometry(QtCore.QRect(200, 420, 118, 3))
        self.line7.setFrameShape(QtWidgets.QFrame.HLine)
        self.line7.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.line7.setObjectName("line7")

        self.line8 = QtWidgets.QFrame()
        self.line8.setGeometry(QtCore.QRect(200, 420, 118, 3))
        self.line8.setFrameShape(QtWidgets.QFrame.HLine)
        self.line8.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.line8.setObjectName("line8")

        self.line9 = QtWidgets.QFrame()
        self.line9.setGeometry(QtCore.QRect(200, 420, 118, 3))
        self.line9.setFrameShape(QtWidgets.QFrame.HLine)
        self.line9.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.line9.setObjectName("line9")

        self.line10 = QtWidgets.QFrame()
        self.line10.setGeometry(QtCore.QRect(200, 420, 118, 3))
        self.line10.setFrameShape(QtWidgets.QFrame.HLine)
        self.line10.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.line10.setObjectName("line10")

        side_panel_v_box = QVBoxLayout()
        side_panel_v_box.setAlignment(Qt.AlignTop)

        side_panel_v_box.addWidget(self.contrast_cb)
        side_panel_v_box.addWidget(self.contrast_spinbox)

        side_panel_v_box.addSpacing(15)
        side_panel_v_box.addWidget(self.line1)

        side_panel_v_box.addWidget(self.brightness_cb)
        side_panel_v_box.addWidget(self.brightness_spinbox)

        side_panel_v_box.addSpacing(15)
        side_panel_v_box.addWidget(self.line2)

        side_panel_v_box.addWidget(self.filter_2D_cb)
        side_panel_v_box.addWidget(self.smoothing_spinbox)

        side_panel_v_box.addSpacing(15)
        side_panel_v_box.addWidget(self.line3)

        side_panel_v_box.addWidget(self.gray_cb)

        side_panel_v_box.addSpacing(15)
        side_panel_v_box.addWidget(self.line4)

        side_panel_v_box.addWidget(self.canny_cb)
        side_panel_v_box.addWidget(self.edges_slider)

        side_panel_v_box.addSpacing(15)
        side_panel_v_box.addWidget(self.line5)

        side_panel_v_box.addWidget(self.negative_cb)

        side_panel_v_box.addSpacing(15)
        side_panel_v_box.addWidget(self.line6)

        side_panel_v_box.addWidget(self.points_cb)

        side_panel_v_box.addSpacing(15)
        side_panel_v_box.addWidget(self.line7)

        side_panel_v_box.addWidget(self.kmeans_cb)
        side_panel_v_box.addWidget(self.kmeans_spinbox)

        side_panel_v_box.addSpacing(15)
        side_panel_v_box.addWidget(self.line8)
        side_panel_v_box.addWidget(self.stickers_cb)

        side_panel_v_box.addWidget(self.radioButton)
        side_panel_v_box.addWidget(self.radioButton2)
        side_panel_v_box.addWidget(self.radioButton3)
        side_panel_v_box.addWidget(self.radioButton4)
        side_panel_v_box.addWidget(self.radioButton5)
        side_panel_v_box.addWidget(self.radioButton6)

        side_panel_v_box.addWidget(self.stickers_horizontal_slider)
        side_panel_v_box.addWidget(self.stickers_vertical_slider)
        side_panel_v_box.addWidget(self.stickersLabel)
        side_panel_v_box.addWidget(self.stickers_spinbox)

        side_panel_v_box.addSpacing(15)
        side_panel_v_box.addWidget(self.line9)
        side_panel_v_box.addWidget(self.text_cb)
        side_panel_v_box.addWidget(self.textQLine)

        side_panel_v_box.addSpacing(100)
        side_panel_v_box.addWidget(self.line10)
        side_panel_v_box.addWidget(self.apply_process_button)
        side_panel_v_box.addWidget(self.reset_button)

        side_panel_frame = QFrame()
        side_panel_frame.setMinimumWidth(250)
        side_panel_frame.setFrameStyle(QFrame.WinPanel)
        side_panel_frame.setLayout(side_panel_v_box)

        scrollArea = QtWidgets.QScrollArea()
        scrollArea.setMinimumWidth(300)
        scrollArea.setWidgetResizable(True)
        scrollArea.setWidget(side_panel_frame)

        main_h_box = QHBoxLayout()
        main_h_box.addWidget(self.image_label, 1)
        main_h_box.addWidget(scrollArea)

        container = QWidget()
        container.setLayout(main_h_box)
        self.setCentralWidget(container)


    def setupMenu(self):
        open_image_act = QAction('Abrir imagem', self)
        open_image_act.setShortcut('Ctrl+O')
        open_image_act.triggered.connect(self.openImageFile)
        save_image_act = QAction('Salvar imagem', self)
        save_image_act.setShortcut('Ctrl+S')
        save_image_act.triggered.connect(self.saveImageFile)

        open_video_act = QAction('Abrir video', self)
        open_video_act.setShortcut('Ctrl+O')
        open_video_act.triggered.connect(self.openVideoFile)
        save_video_act = QAction('Salvar video', self)
        save_video_act.setShortcut('Ctrl+S')
        save_video_act.triggered.connect(self.saveVideoFile)

        menu_bar = self.menuBar()
        menu_bar.setNativeMenuBar(False)

        file_menu = menu_bar.addMenu('File')
        file_menu.addAction(open_image_act)
        file_menu.addAction(save_image_act)
        file_menu.addAction(open_video_act)
        file_menu.addAction(save_video_act)


    def adjustContrast(self, state):
        if state == Qt.Checked and self.image_label.pixmap() != None:
            self.contrast_adjusted = True
        elif state != Qt.Checked and self.image_label.pixmap() != None:
            self.contrast_adjusted = False


    def adjustBrightness(self, state):
        if state == Qt.Checked and self.image_label.pixmap() != None:
            self.brightness_adjusted = True
        elif state != Qt.Checked and self.image_label.pixmap() != None:
            self.brightness_adjusted = False


    def imageSmoothingFilter(self, state):
        if state == Qt.Checked and self.image_label.pixmap() != None:
            self.image_smoothing_checked = True
        elif state != Qt.Checked and self.image_label.pixmap() != None:
            self.image_smoothing_checked = False


    def makeGray(self, state):
        if state == Qt.Checked and self.image_label.pixmap() != None:
            self.gray_checked = True
        elif state != Qt.Checked and self.image_label.pixmap() != None:
            self.gray_checked = False


    def edgeDetection(self, state):
        if state == Qt.Checked and self.image_label.pixmap() != None:
            self.edge_detection_checked = True
        elif state != Qt.Checked and self.image_label.pixmap() != None:
            self.edge_detection_checked = False


    def makeNegative(self, state):
        if state == Qt.Checked and self.image_label.pixmap() != None:
            self.negative_checked = True
        elif state != Qt.Checked and self.image_label.pixmap() != None:
            self.negative_checked = False


    def makePoints(self, state):
        if state == Qt.Checked and self.image_label.pixmap() != None:
            self.points_checked = True
        elif state != Qt.Checked and self.image_label.pixmap() != None:
            self.points_checked = False


    def kmeansFilter(self, state):
        if state == Qt.Checked and self.image_label.pixmap() != None:
            self.kmeans_checked = True
        elif state != Qt.Checked and self.image_label.pixmap() != None:
            self.kmeans_checked = False

    def addStickers(self, state):
        if state == Qt.Checked and self.image_label.pixmap() != None:
            self.stickers_checked = True
        elif state != Qt.Checked and self.image_label.pixmap() != None:
            self.stickers_checked = False

    def addText(self, state):
        if state == Qt.Checked and self.image_label.pixmap() != None:
            self.text_checked = True
        elif state != Qt.Checked and self.image_label.pixmap() != None:
            self.text_checked = False

    def overlaySticker(self):
        self.stickers_horizontal_slider.setRange(0, self.cv_image.shape[1])
        self.stickers_vertical_slider.setRange(0, self.cv_image.shape[0])

        self.size = self.stickers_spinbox.value()
        self.axis_x = self.stickers_horizontal_slider.value()
        self.axis_y = self.stickers_vertical_slider.value()

        self.sticker = imutils.resize(self.sticker, width=(self.cv_image.shape[0] // self.size))
        while True:
            if self.sticker.shape[1] <= self.cv_image.shape[1]:
                if self.sticker.shape[0] <= self.cv_image.shape[0]:
                    break
                else:
                    self.sticker = imutils.resize(self.sticker, height=(self.cv_image.shape[0] // 2))
            else:
                self.sticker = imutils.resize(self.sticker, width=(self.cv_image.shape[1] // 2))

        (rows, cols) = self.sticker.shape[:2]
        if (self.axis_y + rows) > self.cv_image.shape[0]:
            self.axis_y = self.cv_image.shape[0] - rows

        if (self.axis_x + cols) > self.cv_image.shape[1]:
            self.axis_x = self.cv_image.shape[1] - cols

        roi = self.cv_image[self.axis_y:(self.axis_y + rows), self.axis_x:(self.axis_x + cols)]
        self.sticker_gray = cv2.cvtColor(self.sticker, cv2.COLOR_BGR2GRAY)
        ret, mask = cv2.threshold(self.sticker_gray, 10, 255, cv2.THRESH_BINARY)
        mask_inv = cv2.bitwise_not(mask)
        self.cv_image_bg = cv2.bitwise_and(roi, roi, mask=mask_inv)
        self.sticker_fg = cv2.bitwise_and(self.sticker, self.sticker, mask=mask)
        dst = cv2.add(self.cv_image_bg, self.sticker_fg)
        self.cv_image[self.axis_y:(self.axis_y + rows), self.axis_x:(self.axis_x + cols)] = dst


    def applyImageProcessing(self):
        if self.contrast_adjusted == True or self.brightness_adjusted == True:
            contrast = self.contrast_spinbox.value()
            brightness = self.brightness_spinbox.value()
            self.cv_image = cv2.convertScaleAbs(self.cv_image, self.processed_cv_image, contrast, brightness)

        if self.image_smoothing_checked == True:
            blur = self.smoothing_spinbox.value()
            self.cv_image = cv2.GaussianBlur(self.cv_image, (blur, blur), 0)

        if self.gray_checked == True:
            if len(self.cv_image.shape) == 3:
                self.cv_image = cv2.cvtColor(self.cv_image, cv2.COLOR_BGR2GRAY)
            else:
                pass

        if self.edge_detection_checked == True:
            slider = self.edges_slider.value()
            self.cv_image = cv2.Canny(self.cv_image, slider, 3 * slider)

        if self.negative_checked == True:
            self.cv_image = cv2.bitwise_not(self.cv_image)

        if self.points_checked == True:
            STEP = 5
            JITTER = 3
            RAIO = 3
            xrange = np.arange(0, self.cv_image.shape[0] - STEP, STEP) + STEP // 2
            yrange = np.arange(0, self.cv_image.shape[1] - STEP, STEP) + STEP // 2
            points = np.zeros(self.cv_image.shape, dtype=np.uint8)
            np.random.shuffle(xrange)
            for i in xrange:
                np.random.shuffle(yrange)
                for j in yrange:
                    x = i + np.random.randint((2 * JITTER) - JITTER + 1)
                    y = j + np.random.randint((2 * JITTER) - JITTER + 1)
                    color = self.cv_image[x, y]
                    cv2.circle(points, (y, x), RAIO, (int(color[0]), int(color[1]), int(color[2])), -1, cv2.LINE_AA)
            self.cv_image = points.copy()

        if self.kmeans_checked == True:
            NCLUSTERS = self.kmeans_spinbox.value()
            NROUNDS = 10
            samples = self.cv_image.reshape((-1, 3))
            samples = np.float32(samples)
            ret, labels, centers = cv2.kmeans(samples,
                                              NCLUSTERS,
                                              None,
                                              (cv2.TERM_CRITERIA_MAX_ITER | cv2.TERM_CRITERIA_EPS, 10, 1),
                                              NROUNDS,
                                              cv2.KMEANS_RANDOM_CENTERS)
            centers = np.uint8(centers)
            res = centers[labels.flatten()]
            self.cv_image = res.reshape((self.cv_image.shape))


        if self.stickers_checked == True:
            if self.radioButton.isChecked():
                self.sticker = cv2.imread("assets/capitao.png")
                self.overlaySticker()

            elif self.radioButton2.isChecked():
                self.sticker = cv2.imread("assets/cerveja.png")
                self.overlaySticker()

            elif self.radioButton3.isChecked():
                self.sticker = cv2.imread("assets/onibus.png")
                self.overlaySticker()

            elif self.radioButton4.isChecked():
                self.sticker = cv2.imread("assets/lasvegas.png")
                self.overlaySticker()

            elif self.radioButton5.isChecked():
                self.sticker = cv2.imread("assets/morte.png")
                self.overlaySticker()

            elif self.radioButton6.isChecked():
                self.sticker = cv2.imread("assets/batman.png")
                self.overlaySticker()

        if self.text_checked == True:
            text = self.textQLine.text()
            font = cv2.FONT_HERSHEY_SIMPLEX
            org = (400, 400)
            fontScale = 1
            color = (0, 0, 255)
            thickness = 2
            self.cv_image = cv2.putText(self.cv_image, text, org, font, fontScale, color, thickness, cv2.LINE_AA, False)

        self.convertCVToQImage(self.cv_image)
        self.image_label.repaint()


    def resetImageAndSettings(self):
        answer = QMessageBox.information(self, "Voltar imagem original",
                                         "Você tem certeza de que deseja voltar a imagem original?",
                                         QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        if answer == QMessageBox.No:
            pass
        elif answer == QMessageBox.Yes and self.image_label.pixmap() != None:
            self.cv_image = self.copy_cv_image.copy()
            self.resetWidgetValues()
            self.convertCVToQImage(self.copy_cv_image)
            self.image_label.repaint()


    def resetWidgetValues(self):
        self.contrast_cb.setChecked(False)
        self.contrast_spinbox.setValue(1.0)
        self.brightness_cb.setChecked(False)
        self.brightness_spinbox.setValue(0)
        self.filter_2D_cb.setChecked(False)
        self.smoothing_spinbox.setValue(3)
        self.gray_cb.setChecked(False)
        self.canny_cb.setChecked(False)
        self.edges_slider.setValue(10)
        self.negative_cb.setChecked(False)
        self.points_cb.setChecked(False)
        self.kmeans_cb.setChecked(False)
        self.kmeans_spinbox.setValue(8)
        self.stickers_cb.setChecked(False)
        self.stickers_spinbox.setValue(5)
        self.radioButton.setChecked(False)
        self.radioButton2.setChecked(False)
        self.radioButton3.setChecked(False)
        self.radioButton4.setChecked(False)
        self.radioButton5.setChecked(False)
        self.radioButton6.setChecked(False)
        self.stickers_horizontal_slider.setValue(0)
        self.stickers_vertical_slider.setValue(0)
        self.text_cb.setChecked(False)
        self.textQLine.setText("")

    def openImageFile(self):
        image_file, _ = QFileDialog.getOpenFileName(self, "Abrir imagem",
                                                    os.getenv('HOME'), "Images (*.png *.jpeg *.jpg *.bmp)")
        if image_file:
            self.resetWidgetValues()
            self.apply_process_button.setEnabled(True)
            self.reset_button.setEnabled(True)
            self.cv_image = cv2.imread(image_file)
            self.copy_cv_image = self.cv_image.copy()
            self.processed_cv_image = np.zeros(self.cv_image.shape, self.cv_image.dtype)
            self.convertCVToQImage(self.cv_image)
        else:
            QMessageBox.information(self, "Erro", "Nenhuma imagem foi carregada.", QMessageBox.Ok)


    def saveImageFile(self):
        image_file, _ = QFileDialog.getSaveFileName(self, "Salvar imagem",
                                                    os.getenv('HOME'),
                                                    "JPEG (*.jpeg);;JPG (*.jpg);;PNG (*.png);;Bitmap (*.bmp)")
        if image_file and self.image_label.pixmap() != None:
            cv2.imwrite(image_file, self.cv_image)
        else:
            QMessageBox.information(self, "Erro",
                                    "Não é possível salvar a imagem.", QMessageBox.Ok)


    def openVideoFile(self):
        self.input_video_file, _ = QFileDialog.getOpenFileName(self, "Abrir video",
                                                    os.getenv('HOME'), "Video (*.mp4)")
        if self.input_video_file:
            self.resetWidgetValues()
            self.apply_process_button.setEnabled(True)
            self.reset_button.setEnabled(True)
            capture = cv2.VideoCapture(self.input_video_file)
            exist_frame, frame = capture.read()
            self.height, self.width = frame.shape[:2]
            if exist_frame:
                frame = cv2.cvtColor(frame, cv2.IMREAD_COLOR)
                self.cv_image = cv2.cvtColor(frame, cv2.IMREAD_COLOR)
                self.copy_cv_image = self.cv_image.copy()

                self.processed_cv_image = np.zeros(self.cv_image.shape, self.cv_image.dtype)
                self.convertCVToQImage(self.cv_image)
        else:
            QMessageBox.information(self, "Erro", "Nenhum video foi carregado.", QMessageBox.Ok)


    def saveVideoFile(self):
        self.output_video_file, _ = QFileDialog.getSaveFileName(self, "Salvar video",
                                                    os.getenv('HOME'),
                                                    "AVI (*.avi)")
        if self.output_video_file and self.image_label.pixmap() != None:
            capture = cv2.VideoCapture(self.input_video_file)
            fourcc = cv2.VideoWriter_fourcc(*'XVID')
            out = cv2.VideoWriter(self.output_video_file, fourcc, 24, (self.width, self.height))
            while True:
                exist_frame, frame = capture.read()
                if not exist_frame:
                    break

                self.cv_image = frame
                self.applyImageProcessing()

                frame = self.cv_image
                out.write(frame)

            capture.release()
            out.release()
        else:
            QMessageBox.information(self, "Erro",
                                    "Não é possível salvar o video.", QMessageBox.Ok)


    def convertCVToQImage(self, image):
        cv_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
        height, width, channels = cv_image.shape
        bytes_per_line = width * channels
        converted_Qt_image = QImage(cv_image, width, height, bytes_per_line, QImage.Format_RGB888)
        self.image_label.setPixmap(QPixmap.fromImage(converted_Qt_image).scaled(
            self.image_label.width(), self.image_label.height(),
            Qt.KeepAspectRatio))


if __name__ == '__main__':
    app = QApplication(sys.argv)
    app.setStyleSheet(style_sheet)
    window = StoriesInstagram()
    sys.exit(app.exec_())
A python based all-in-one tool for Google Drive

gdrive-tools A python based all-in-one tool for Google Drive Uses For Gdrive-Tools ✓ generate SA ✓ Add the SA and Add them to TD automatically ✓ Gener

XcodersHub 32 Feb 09, 2022
股票量化

StockQuant Gary-Hertel 请勿提交issue!可以加入交流群与其他朋友一起自学交流,加微信mzjimmy 一、配置文件的设置 启动框架需要先导入必要的模块,并且载入一次配置文件! 配置文件是一个json格式的文件config.json,在docs文件夹中有模板

218 Dec 25, 2022
A simple tool which automate commands of discord economy bots

A simple tool which automate commands of discord economy bots. Fully configurable using an intuitive configuration made in YAML

SkydenFly 5 Sep 18, 2022
Coin-based opinion monitoring system

介绍 本仓库提供了基于币安 (Binance) 的二级市场舆情系统,可以根据自己的需求修改代码,设定各类告警提示 代码结构 binance.py - 与币安API交互 data_loader.py - 数据相关的读写 monitor.py - 监控的核心方法实现 analyze.py - 基于历史数

luv_dusk 6 Jun 08, 2022
A simple script & container to pull COVID data from covidlive.com.au and post a summary to a slack channel

CovidLive AU Summary Slackbot This bot is a very simple slackbot that pulls data, summarises and posts up to date AU COVID stats to a provided slack c

James 3 Dec 18, 2021
A way to export your saved reddit posts to a Notion table.

reddit-saved-to-notion A way to export your saved reddit posts and comments to a Notion table.Uses notion-sdk-py and praw for interacting with Notion

19 Sep 12, 2022
Reddit bot that uses sentiment analysis

Reddit Bot Project 2: Neural Network Boogaloo Reddit bot that uses sentiment analysis from NLTK.VADER WIP_WIP_WIP_WIP_WIP_WIP Link to test subreddit:

TpK 1 Oct 24, 2021
Pyspark sam - Analyze Big Sequence Alignments with PySpark in AWS EMR

pyspark_sam This repo hosts my code for the article "Analyze Big Sequence Alignm

Sixing Huang 4 Dec 09, 2022
Bagas Mirror&Leech Bot is a multipurpose Telegram Bot written in Python for mirroring files on the Internet to our beloved Google Drive. Based on python-aria-mirror-bot

- [ MAYBE UPDATE & ADD MORE MODULE ] Bagas Mirror&Leech Bot Bagas Mirror&Leech Bot is a multipurpose Telegram Bot written in Python for mirroring file

4 Nov 23, 2021
A simple and stupid Miinto API wrapper

miinto-api-wrapper Miinto API Wrapper is a simple python wrapper for Miinto API. Miinto is a fashion luxury marketplace. For more information see the

Giuseppe Checchia 3 Jan 09, 2022
A telegram bot which can show you the status of telegram bot

BotStatus-Ts-Bot An open source telegram Bot Status bot For demo you can check here The status is updated in every 1 hour About Bot This is a Bot stat

Ts_Bots 8 Nov 17, 2022
Instagram Bot posting earthquakes with magnitude greater than or equal to 3.5.

Instagram Bot posting earthquakes with magnitude greater than or equal to 3.5

Alican Yüksel 4 Aug 22, 2022
A minimalist file manager for those who want to use Linux mobile devices.

Portfolio A minimalist file manager for those who want to use Linux mobile devices. Usage Tap to activate and press to select, to browse, open, copy,

Martin Abente Lahaye 71 Nov 18, 2022
A simple API wrapper for the Tenor API

Gifpy A simple API wrapper for the Tenor API Installation Python 3.9 or higher is recommended python3 -m pip install gifpy Clone repository: $ git cl

Juan Ignacio Battiston 4 Dec 22, 2021
An open-source Discord Bot Project based on programming!

An open-source Discord Bot Project based on programming!

Vladimer Moore 2 Aug 22, 2022
A badge generator service to count visitors of your markdown file.

Github Visitors Badge A badge generator service to count visitors of your markdown file. Hello every one! In this post, I will tell you the story of m

Kɪꜱᴀʀᴀ Pᴇꜱᴀɴᴊɪᴛʜ Pᴇʀᴇʀᴀ 〄 1 Feb 06, 2022
Select random winners for a Twitter giveaway

twitter_picker Select random winners for a Twitter giveaway Once the Twitter giveaway (or airdrop) is closed, assign a number to each participant. The

Michael Rawner 1 Dec 11, 2021
Discord Bot written in Python that plays music in your voice channel

Discord Bot that plays music! I decided to create a simple Discord bot using Python in order to advance my coding skills. Please don't ask me for help

Eric Yeung 39 Jan 01, 2023
Latest Open Source Code for Playing Music in Telegram Video Chat. Made with Pyrogram and Pytgcalls 💖

MusicPlayer_TG Latest Open Source Code for Playing Music in Telegram Video Chat. Made with Pyrogram and Pytgcalls 💖 Requirements 📝 FFmpeg NodeJS nod

Abhijith Sudhakaran 2 Feb 04, 2022
A simple, lightweight Discord bot running with only 512 MB memory on Heroku

Haruka This used to be a music bot, but people keep using it for NSFW content. Can't everyone be less horny? Bot commands See the built-in help comman

Haruka 4 Dec 26, 2022