Я хотел бы написать инструмент для маркировки изображений, используя PyQT4:
- load a number of images from a specified folder; for each image:
- the user selects objects (e.g., car) from the images, by painting the region for that object with the mouse
- когда выбор сделан, маска объекта отображается наложенной на исходное изображение.
- когда выделение всех объектов завершено, программа сохраняет каждую маску объекта (фон: 0, передний план: 255) как отдельное изображение png
- пользователь должен иметь возможность увеличивать/уменьшать изображение
Я уже писал похожую программу (без увеличения/уменьшения) на c++ с помощью wxWidgets. Я новичок в PyQT4 и пытаюсь понять, как все работает. Наиболее сложной частью кажется рисование и правильное получение масок объектов, даже когда пользователь увеличивает/уменьшает масштаб.
Какие классы PyQT идеально подходят для решения этой проблемы? Как я могу правильно получить маски объектов (возможно, в виде массива numpy) и сохранить их?
Большое спасибо.
Следуя вашей рекомендации, я написал фрагмент кода для отображения изображения и рисования изображения с помощью мыши (все еще на стадии экспериментов и обучения).
Я сохраняю изображение в 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?
Вторая проблема заключается в том, как после рисования изображения получить маску выбранной области? Что-то вроде создания нового изображения с альфа-каналом, а затем извлечения значений пикселей? Или рисовать на пустом изображении параллельно? Затем я также должен отслеживать увеличение/уменьшение масштаба.