PyQT4 - рисование на изображении для выбора региона - PullRequest
4 голосов
/ 13 июля 2011

Я хотел бы написать инструмент для маркировки изображений с использованием PyQT4:

  • загрузить несколько изображений из указанной папки;для каждого изображения:
    • пользователь выбирает объекты (например, автомобиль) из изображений, рисуя область для этого объекта с помощью мыши
    • , когда выбор сделан, отображается маска объектаНаложенный на исходное изображение
    • , когда выбор всех объектов завершен, программа сохраняет каждую маску объекта (фон: 0, передний план: 255) как отдельное изображение png
  • пользователь должен иметь возможность увеличивать / уменьшать изображение

Я уже написал аналогичную программу (без увеличения / уменьшения) на c ++ с wxWidgets.Я новичок в PyQT4 и пытаюсь узнать, как все работает.Самым сложным кажется рисование и правильное получение масок объектов, даже когда пользователь увеличивает / уменьшает.

Какие классы PyQT были бы идеальными для этой проблемы?Как я могу правильно получить маски объектов (возможно, в виде массива) и сохранить их?

Большое спасибо.


Следуя вашей рекомендации, я написал фрагмент кода для отображенияimage и рисуйте на изображении с помощью мыши (все еще в стадии эксперимента и обучения).

Я сохраняю изображение в QGraphicsPixmapItem, добавляю его к сцене.Затем я рисую изображение, переопределяя его метод рисования.Наконец, я переопределяю события мыши, чтобы определить положение мыши и нарисовать там круг.Но когда я двигаю мышь, старый круг удаляется, а новый окрашивается.То есть круг не нарисован на самом изображении.Я думаю, мне следует использовать что-то вроде следующего, чтобы рисование было постоянным на изображении:

painter = QPainter()
painter.begin(pixmap)
# here do the drawing
painter.end() 

Но проблема в том, что функция рисования уже принимает художника в качестве аргумента;воссоздание нового в функции рисования не работает (очевидно) ..

Вот код:

from PyQt4.QtCore import *
from PyQt4.QtGui import *

class ImageDrawPanel(QGraphicsPixmapItem):
    def __init__(self, pixmap=None, parent=None, scene=None):
        super(ImageDrawPanel, self).__init__()
        self.x, self.y = -1, -1        
        self.radius = 10

        self.pen = QPen(Qt.SolidLine)
        self.pen.setColor(Qt.black)
        self.pen.setWidth(2)

        self.brush = QBrush(Qt.yellow)


    def paint(self, painter, option, widget=None):               
        painter.drawPixmap(0, 0, self.pixmap())                
        painter.setPen(self.pen)
        painter.setBrush(self.brush)        
        if self.x >= 0 and self.y >= 0:
            painter.drawEllipse(self.x-self.radius, self.y-self.radius, 2*self.radius, 2*self.radius)
            self.x, self.y = -1, -1

    def mousePressEvent (self, event):
        print 'mouse pressed'
        self.x=event.pos().x()
        self.y=event.pos().y()            
        self.update()

    def mouseMoveEvent (self, event):
        print 'mouse moving'
        self.x=event.pos().x()
        self.y=event.pos().y()            
        self.update()        

class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()

        self.scene = QGraphicsScene()
        self.scene.setSceneRect(0, 0, 800, 600)

        pixmap=self.openImage()        
        self.imagePanel = ImageDrawPanel(scene = self.scene)
        self.imagePanel.setPixmap(pixmap)
        self.scene.addItem(self.imagePanel)

        self.view = QGraphicsView(self.scene)

        layout = QHBoxLayout()        
        layout.addWidget(self.view)

        self.widget = QWidget()
        self.widget.setLayout(layout)

        self.setCentralWidget(self.widget)
        self.setWindowTitle("Image Draw")

    def openImage(self):
        fname = QFileDialog.getOpenFileName(self, "Open image", ".", "Image Files (*.bmp *.jpg *.png *.xpm)")
        if fname.isEmpty(): return None
        return QPixmap(fname)        

import sys
if __name__ == "__main__":    
    app = QApplication(sys.argv)
    mainWindow = MainWindow()
    mainWindow.show()
    sys.exit(app.exec_())

Что мне теперь делать, чтобы навсегда нарисовать на изображении?Я могу сохранить все точки и заново нарисовать их краской, но это не кажется эффективным.Должен ли я рисовать в QGraphicsScene, а не в самом QGraphicsPixmapItem?

Вторая проблема, после рисования на изображении, как я могу получить маску выделенной области?Что-то вроде создания нового изображения с альфа-каналом, а затем извлечения значений пикселей?Или рисовать на пустом изображении параллельно?Затем я также должен отслеживать увеличение / уменьшение масштаба ..

1 Ответ

3 голосов
/ 13 июля 2011

У вас есть несколько различных опций, которые я закажу от более высокого уровня до более низкого уровня:

  1. Использование QGraphicsScene , QGraphicsView и QGraphicsItems .Этот набор, вероятно, формирует основной вариант и лучший вариант для интенсивных графических операций.Установив QGLWidget в качестве области просмотра, вы даже получите аппаратное ускорение во многих системах.
  2. Используйте QScrollArea для поддержки увеличения изображения, которое может бытьпростой QLabel .Изменяя видимый регион, вы получите эффектное увеличение.QLabel можно использовать для рисования изображения, но вам придется вручную отслеживать выбранные регионы и делать любые наложения выделения.
  3. Используйте один QWidget и выполняйте пользовательскую рисование.Позвонив по номеру update () после различных событий, вы сможете внести любые необходимые изменения.Ожидайте делать практически все вручную.

Я бы порекомендовал подход № 1. Вы можете использовать QGraphicsPixmapItem для хранения вашего изображения.Затем вы можете создать графический элемент, который представляет ваш выбор, и использовать его ограничивающий прямоугольник, чтобы найти пересекающихся областей.QGraphicsView может обрабатывать все масштабирование для вас.

...