14

I need to perform lot of operations on an image. So I used OpenCV. OpenCV is very efficient in image processing, however it is not too good to present a suitable GUI. So I decided to use PyQt to draw a custom GUI and OpenCV to process my image.

I created a very simple program you directly picked from the documentation. I simply read a jpg picture and save it in a png format by pressing the key s.

My aim is to replace the key s with a button to press to perform the same action using PyQt. Also, I want the window displayed by PyQt to have the same behavior as OpenCV: mainly speaking, the function imshow() displays a window that fits to the image size.

Here is my OpenCV simple code:

import numpy 
import cv2

class LoadImage:
    def loadImage(self):
        img = cv2.imread('photo.jpg')
        cv2.imshow('Image on a window',img)
        k = cv2.waitKey(0)
        if k == 27:
            cv2.destroyAllWindows()
        elif k == ord('s'):
            cv2.imwrite('photopng.png',img)
            cv2.destroyAllWindows()

if __name__=="__main__":
    LI=LoadImage()
    LI.loadImage()

Output:

enter image description here

Here is a simple PyQt code to draw a simple window:

import sys
from PyQt4 import QtGui

class DrawWindow:
    def drawWindow(self):
        app=QtGui.QApplication(sys.argv)
        w=QtGui.QWidget()
        #w.resize(250,250)
        w.move(300,300)
        w.setWindowTitle("Simple Window")
        w.show()

        sys.exit(app.exec_())

if __name__=="__main__":
    DW=DrawWindow()
    DW.drawWindow()

How can I mix the 2 codes to reach my goal?

ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199

2 Answers2

13

Modified some code basing on your post, I didn't use the Opencv to render the image, instead using QPixmap to render it. then use KeyPressEvent to capture the user input .

# -*- coding: utf-8 -*-


import numpy
import cv2
from PyQt4.QtGui import *
from PyQt4.QtCore import *


class MyDialog(QDialog):
    def __init__(self, parent=None):
        super(MyDialog, self).__init__(parent)

        self.cvImage = cv2.imread(r'cat.jpg')
        height, width, byteValue = self.cvImage.shape
        byteValue = byteValue * width

        cv2.cvtColor(self.cvImage, cv2.COLOR_BGR2RGB, self.cvImage)

        self.mQImage = QImage(self.cvImage, width, height, byteValue, QImage.Format_RGB888)

    def paintEvent(self, QPaintEvent):
        painter = QPainter()
        painter.begin(self)
        painter.drawImage(0, 0, self.mQImage)
        painter.end()

    def keyPressEvent(self, QKeyEvent):
        super(MyDialog, self).keyPressEvent(QKeyEvent)
        if 's' == QKeyEvent.text():
            cv2.imwrite("cat2.png", self.cvImage)
        else:
            app.exit(1)


if __name__=="__main__":
    import sys
    app = QApplication(sys.argv)
    w = MyDialog()
    w.resize(600, 400)
    w.show()
    app.exec_()
Cui Heng
  • 1,265
  • 8
  • 10
  • Thank you for trying. First, I really need to use OpenCV for image processing. Second, I got several errors when compiled your code. +1 however for the effort. –  Feb 03 '15 at 07:59
  • This Code seems correct. The processing is in OpenCV (e.g. look at cv2.cvtColor) and only the displaying is handled using Qt (QPixmap) which is fine. I am doing the same in a lot off scripts. Be carefull though when converting your image from cv to qt (search the web for converters)! – Mailerdaimon Feb 03 '15 at 10:04
1

You can create a QImage directly from the image data read by OpenCV, convert that to a QPixmap using QPixmap.fromImage and then use that to set the pixmap of a QLabel using the setPixmap method.

This page shows how to view a webcam feed by using PySide and OpenVC: https://gist.github.com/bsdnoobz/8464000. I made it work for videos as well, by commenting out these two lines

self.capture.set(cv2.cv.CV_CAP_PROP_FRAME_WIDTH, self.video_size.width())
self.capture.set(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT, self.video_size.height())

and instead using

resized_bgr_frame = cv2.resize(
    bgr_frame,
    (self.video_size.width(), self.video_size.height()),
    interpolation=cv2.INTER_CUBIC if self.video_size.width() > bgr_frame.shape[1] else cv2.INTER_AREA)

on the video frame (where bgr_frame is the frame that was obtained with self.capture.read()).

(Note that there is some different naming and namespace conventions for the OpenCV constants going on here, perhaps due to differing cv2 versions?)

HelloGoodbye
  • 3,624
  • 8
  • 42
  • 57