From: Till Theato Date: Sun, 30 Jan 2011 14:24:57 +0000 (+0000) Subject: First work on rotoscoping GUI X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;ds=sidebyside;h=bbc9a66eae6d7b06727543a2cb53f5a7efc8289b;p=kdenlive First work on rotoscoping GUI (MLT module: github.com/ttill/MLT-roto) svn path=/trunk/kdenlive/; revision=5367 --- diff --git a/data/blacklisted_effects.txt b/data/blacklisted_effects.txt index 9d35973e..a4e28890 100644 --- a/data/blacklisted_effects.txt +++ b/data/blacklisted_effects.txt @@ -77,6 +77,7 @@ grain lines oldfilm tcolor +rotoscoping #effects that have simplekeyframes vignette diff --git a/effects/CMakeLists.txt b/effects/CMakeLists.txt index 0cb0f490..c293b514 100644 --- a/effects/CMakeLists.txt +++ b/effects/CMakeLists.txt @@ -115,5 +115,6 @@ vignette.xml swapchannels.xml audiobalance.xml audiopan.xml +rotoscoping.xml DESTINATION ${DATA_INSTALL_DIR}/kdenlive/effects) diff --git a/effects/rotoscoping.xml b/effects/rotoscoping.xml new file mode 100644 index 00000000..1e24d2d8 --- /dev/null +++ b/effects/rotoscoping.xml @@ -0,0 +1,28 @@ + + + Rotoscoping + Keyframable vector based rotoscoping + Till Theato + + + Alpha,Matte,RGB + Mode + + + + Write on clear,Maximum,Minimum,Add,Subtract + Alpha Operation + + + + Invert + + + + Precision + + + + Rotoscopy Spline + + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 25dd4ed4..a2a7cd1a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,17 +3,21 @@ add_subdirectory(colorcorrection) add_subdirectory(kiss_fft) add_subdirectory(mimetypes) add_subdirectory(onmonitoritems) +add_subdirectory(rotoscoping) add_subdirectory(widgets) macro_optional_find_package(Nepomuk) include(FindQImageBlitz) +find_package(QJSON) + include_directories( ${KDE4_INCLUDE_DIR} ${KDE4_INCLUDE_DIR}/KDE ${QT_INCLUDES} ${LIBMLT_INCLUDE_DIR} ${LIBMLTPLUS_INCLUDE_DIR} + ${QJSON_INCLUDE_DIR} ${QDBUS_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} @@ -22,6 +26,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/colorcorrection ${CMAKE_SOURCE_DIR}/src/kiss_fft ${CMAKE_SOURCE_DIR}/src/onmonitoritems + ${CMAKE_SOURCE_DIR}/src/onmonitoritems/rotoscoping ${CMAKE_SOURCE_DIR}/src/widgets ) @@ -256,6 +261,8 @@ set(kdenlive_SRCS blackmagic/devices.cpp onmonitoritems/onmonitorrectitem.cpp onmonitoritems/onmonitorcornersitem.cpp + onmonitoritems/rotoscoping/splineitem.cpp + onmonitoritems/rotoscoping/bpointitem.cpp cornerswidget.cpp kiss_fft/_kiss_fft_guts.h kiss_fft/kiss_fft.c @@ -266,6 +273,7 @@ set(kdenlive_SRCS beziercurve/cubicbezierspline.cpp dragvalue.cpp monitoreditwidget.cpp + rotoscoping/rotowidget.cpp ) add_definitions(${KDE4_DEFINITIONS}) @@ -321,6 +329,7 @@ target_link_libraries(kdenlive ${KDE4_KROSSUI_LIBS} ${CMAKE_DL_LIBS} ${CMAKE_THREAD_LIBS_INIT} + ${QJSON_LIBRARIES} ) if(Q_WS_X11) diff --git a/src/effectstackedit.cpp b/src/effectstackedit.cpp index 1cb9d1d2..892dd851 100644 --- a/src/effectstackedit.cpp +++ b/src/effectstackedit.cpp @@ -35,6 +35,7 @@ #include "doubleparameterwidget.h" #include "cornerswidget.h" #include "beziercurve/beziersplinewidget.h" +#include "rotoscoping/rotowidget.h" #include #include @@ -407,6 +408,15 @@ void EffectStackEdit::transferParamDesc(const QDomElement d, int pos, int in, in QString depends = pa.attribute("depends"); if (!depends.isEmpty()) meetDependency(paramName, type, EffectsList::parameter(e, depends)); + } else if (type == "roto-spline") { + RotoWidget *roto = new RotoWidget(value, m_monitor, m_in, m_out, this); + roto->slotShowScene(!disable); + connect(roto, SIGNAL(valueChanged()), this, SLOT(collectAllParameters())); + connect(roto, SIGNAL(checkMonitorPosition(int)), this, SIGNAL(checkMonitorPosition(int))); + connect(this, SIGNAL(syncEffectsPos(int)), roto, SLOT(slotSyncPosition(int))); + connect(this, SIGNAL(effectStateChanged(bool)), roto, SLOT(slotShowScene(bool))); + m_vbox->addWidget(roto); + m_valueItems[paramName] = roto; } else if (type == "wipe") { Wipeval *wpval = new Wipeval; wpval->setupUi(toFillin); @@ -672,6 +682,9 @@ void EffectStackEdit::collectAllParameters() QString depends = pa.attributes().namedItem("depends").nodeValue(); if (!depends.isEmpty()) meetDependency(paramName, type, EffectsList::parameter(newparam, depends)); + } else if (type == "roto-spline") { + RotoWidget *widget = static_cast(m_valueItems.value(paramName)); + setValue = widget->getSpline(); } else if (type == "wipe") { Wipeval *wp = (Wipeval*)m_valueItems.value(paramName); wipeInfo info; diff --git a/src/onmonitoritems/CMakeLists.txt b/src/onmonitoritems/CMakeLists.txt index c7f78231..1afa18c3 100644 --- a/src/onmonitoritems/CMakeLists.txt +++ b/src/onmonitoritems/CMakeLists.txt @@ -1 +1 @@ -# Empty cmake file to satisfy CMake \ No newline at end of file +add_subdirectory(rotoscoping) diff --git a/src/onmonitoritems/rotoscoping/CMakeLists.txt b/src/onmonitoritems/rotoscoping/CMakeLists.txt new file mode 100644 index 00000000..e69de29b diff --git a/src/onmonitoritems/rotoscoping/bpointitem.cpp b/src/onmonitoritems/rotoscoping/bpointitem.cpp new file mode 100644 index 00000000..232255e0 --- /dev/null +++ b/src/onmonitoritems/rotoscoping/bpointitem.cpp @@ -0,0 +1,154 @@ +/*************************************************************************** + * Copyright (C) 2011 by Till Theato (root@ttill.de) * + * This file is part of Kdenlive (www.kdenlive.org). * + * * + * Kdenlive is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 2 of the License, or * + * (at your option) any later version. * + * * + * Kdenlive is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with Kdenlive. If not, see . * + ***************************************************************************/ + +#include "bpointitem.h" +#include "splineitem.h" + +#include +#include +#include + + +BPointItem::BPointItem(BPoint point, QGraphicsItem* parent) : + QAbstractGraphicsShapeItem(parent), + m_selection(-1) +{ + setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable); + + QPen framepen(Qt::SolidLine); + framepen.setColor(Qt::yellow); + setPen(framepen); + setBrush(Qt::NoBrush); + setAcceptHoverEvents(true); + + setPos(point.p); + m_point.h1 = mapFromScene(point.h1); + m_point.p = mapFromScene(point.p); + m_point.h2 = mapFromScene(point.h2); + m_point.handlesLinked = false; +} + +BPoint BPointItem::getPoint() +{ + return BPoint(mapToScene(m_point.h1), mapToScene(m_point.p), mapToScene(m_point.h2)); +} + +int BPointItem::type() const +{ + return Type; +} + +QRectF BPointItem::boundingRect() const +{ + QPolygonF p = QPolygonF() << m_point.h1 << m_point.p << m_point.h2; + return p.boundingRect().adjusted(-6, -6, 6, 6); +} + +void BPointItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + + painter->setPen(QPen(Qt::yellow, 1, Qt::SolidLine)); + painter->setBrush(QBrush(isSelected() ? Qt::red : Qt::yellow)); + painter->setRenderHint(QPainter::Antialiasing); + + double handleSize = 6 / painter->matrix().m11(); + double handleSizeHalf = handleSize / 2; + + QPolygonF handle = QPolygonF() << QPointF(0, -handleSizeHalf) << QPointF(handleSizeHalf, 0) << QPointF(0, handleSizeHalf) << QPointF(-handleSizeHalf, 0); + + painter->drawLine(m_point.h1, m_point.p); + painter->drawLine(m_point.p, m_point.h2); + +#if QT_VERSION >= 0x040600 + painter->drawConvexPolygon(handle.translated(m_point.h1.x(), m_point.h1.y())); + painter->drawConvexPolygon(handle.translated(m_point.h2.x(), m_point.h2.y())); +#else + tmp = handle; + tmp.translate(m_point.h1.x(), m_point.h1.y()); + p.drawConvexPolygon(tmp); + tmp.translate(m_point.h2.x(), m_point.h2.y()); + p.drawConvexPolygon(tmp); +#endif + + painter->drawEllipse(QRectF(m_point.p.x() - handleSizeHalf, + m_point.p.y() - handleSizeHalf, handleSize, handleSize)); +} + +int BPointItem::getSelection(QPointF pos) +{ + QPainterPath mouseArea; + mouseArea.addRect(pos.x() - 6, pos.y() - 6, 12, 12); + + if (mouseArea.contains(m_point.p)) + return 1; + else if (mouseArea.contains(m_point.h1)) + return 0; + else if (mouseArea.contains(m_point.h2)) + return 2; + + return -1; +} + +void BPointItem::mousePressEvent(QGraphicsSceneMouseEvent* event) +{ + m_selection = getSelection(event->pos()); + + if (m_selection < 0) { + event->ignore(); + setSelected(false); + } else { + setSelected(true); + } +} + +void BPointItem::mouseMoveEvent(QGraphicsSceneMouseEvent* event) +{ + prepareGeometryChange(); + switch (m_selection) { + case 0: + m_point.setH1(event->pos()); + break; + case 1: + m_point.setP(event->pos()); + break; + case 2: + m_point.setH2(event->pos()); + break; + } + + if (parentItem()) { + SplineItem *parent = qgraphicsitem_cast(parentItem()); + if (parent) + parent->updateSpline(); + } +} + +void BPointItem::mouseReleaseEvent(QGraphicsSceneMouseEvent* event) +{ +QGraphicsItem::mouseReleaseEvent(event); +} + +void BPointItem::hoverMoveEvent(QGraphicsSceneHoverEvent* event) +{ + if (getSelection(event->pos()) < 0) + unsetCursor(); + else + setCursor(QCursor(Qt::PointingHandCursor)); +} diff --git a/src/onmonitoritems/rotoscoping/bpointitem.h b/src/onmonitoritems/rotoscoping/bpointitem.h new file mode 100644 index 00000000..7cb73db7 --- /dev/null +++ b/src/onmonitoritems/rotoscoping/bpointitem.h @@ -0,0 +1,54 @@ +/*************************************************************************** + * Copyright (C) 2011 by Till Theato (root@ttill.de) * + * This file is part of Kdenlive (www.kdenlive.org). * + * * + * Kdenlive is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 2 of the License, or * + * (at your option) any later version. * + * * + * Kdenlive is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with Kdenlive. If not, see . * + ***************************************************************************/ + +#ifndef BPOINTITEM_H +#define BPOINTITEM_H + +#include "bpoint.h" + +#include +#include + +class BPointItem : public QAbstractGraphicsShapeItem +{ +public: + BPointItem(BPoint point, QGraphicsItem* parent = 0); + + BPoint getPoint(); + + enum { Type = UserType + 11 }; + virtual int type() const; + + virtual QRectF boundingRect() const; + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + +protected: + virtual void mousePressEvent(QGraphicsSceneMouseEvent *event); + virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event); + virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); + virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *event); + +private: + BPoint m_point; + int m_selection; + + /** @brief Gets The action mode for the area @param pos +- 4. */ + int getSelection(QPointF pos); +}; + +#endif diff --git a/src/onmonitoritems/rotoscoping/splineitem.cpp b/src/onmonitoritems/rotoscoping/splineitem.cpp new file mode 100644 index 00000000..9260d4fc --- /dev/null +++ b/src/onmonitoritems/rotoscoping/splineitem.cpp @@ -0,0 +1,75 @@ +/*************************************************************************** + * Copyright (C) 2011 by Till Theato (root@ttill.de) * + * This file is part of Kdenlive (www.kdenlive.org). * + * * + * Kdenlive is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 2 of the License, or * + * (at your option) any later version. * + * * + * Kdenlive is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with Kdenlive. If not, see . * + ***************************************************************************/ + +#include "splineitem.h" +#include "bpointitem.h" + +#include + +SplineItem::SplineItem(const QList< BPoint >& points, QGraphicsItem* parent, QGraphicsScene *scene) : + QGraphicsPathItem(parent, scene) +{ + QPen framepen(Qt::SolidLine); + framepen.setColor(Qt::yellow); + setPen(framepen); + setBrush(Qt::NoBrush); + + if (points.isEmpty()) + return; + + QPainterPath path(points.at(0).p); + int j; + for (int i = 0; i < points.count(); ++i) { + new BPointItem(points.at(i), this); + j = (i + 1) % points.count(); + path.cubicTo(points.at(i).h2, points.at(j).h1, points.at(j).p); + } + setPath(path); +} + +int SplineItem::type() const +{ + return Type; +} + +void SplineItem::updateSpline() +{ + QPainterPath path(qgraphicsitem_cast(childItems().at(0))->getPoint().p); + + BPoint p1, p2; + int j; + for (int i = 0; i < childItems().count(); ++i) { + j = (i + 1) % childItems().count(); + p1 = qgraphicsitem_cast(childItems().at(i))->getPoint(); + p2 = qgraphicsitem_cast(childItems().at(j))->getPoint(); + path.cubicTo(p1.h2, p2.h1, p2.p); + } + setPath(path); + + emit changed(); +} + +QList SplineItem::getPoints() +{ + QList points; + foreach (QGraphicsItem *child, childItems()) + points << qgraphicsitem_cast(child)->getPoint(); + return points; +} + +#include "splineitem.moc" diff --git a/src/onmonitoritems/rotoscoping/splineitem.h b/src/onmonitoritems/rotoscoping/splineitem.h new file mode 100644 index 00000000..2fd8f0df --- /dev/null +++ b/src/onmonitoritems/rotoscoping/splineitem.h @@ -0,0 +1,45 @@ +/*************************************************************************** + * Copyright (C) 2011 by Till Theato (root@ttill.de) * + * This file is part of Kdenlive (www.kdenlive.org). * + * * + * Kdenlive is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 2 of the License, or * + * (at your option) any later version. * + * * + * Kdenlive is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with Kdenlive. If not, see . * + ***************************************************************************/ + +#ifndef SPLINEITEM_H +#define SPLINEITEM_H + +#include +#include + +class BPoint; + +class SplineItem : public QObject, public QGraphicsPathItem +{ + Q_OBJECT + +public: + SplineItem(const QList &points, QGraphicsItem* parent = 0, QGraphicsScene *scene = 0); + + enum { Type = UserType + 10 }; + + virtual int type() const; + + void updateSpline(); + QList getPoints(); + +signals: + void changed(); +}; + +#endif diff --git a/src/rotoscoping/CMakeLists.txt b/src/rotoscoping/CMakeLists.txt new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/src/rotoscoping/CMakeLists.txt @@ -0,0 +1 @@ + diff --git a/src/rotoscoping/rotowidget.cpp b/src/rotoscoping/rotowidget.cpp new file mode 100644 index 00000000..2d9e0adc --- /dev/null +++ b/src/rotoscoping/rotowidget.cpp @@ -0,0 +1,126 @@ +/*************************************************************************** + * Copyright (C) 2011 by Till Theato (root@ttill.de) * + * This file is part of Kdenlive (www.kdenlive.org). * + * * + * Kdenlive is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 2 of the License, or * + * (at your option) any later version. * + * * + * Kdenlive is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with Kdenlive. If not, see . * + ***************************************************************************/ + +#include "rotowidget.h" +#include "monitor.h" +#include "renderer.h" +#include "monitorscene.h" +#include "monitoreditwidget.h" +#include "onmonitoritems/rotoscoping/bpointitem.h" +#include "onmonitoritems/rotoscoping/splineitem.h" + +#include +#include + + +RotoWidget::RotoWidget(QString data, Monitor *monitor, int in, int out, QWidget* parent) : + QWidget(parent), + m_monitor(monitor), + m_showScene(true), + m_in(in), + m_out(out), + m_pos(0) +{ + MonitorEditWidget *edit = monitor->getEffectEdit(); + edit->showVisibilityButton(true); + m_scene = edit->getScene(); + + QJson::Parser parser; + bool ok; + m_data = parser.parse(data.toUtf8(), &ok); + if (!ok) { + // :( + } + + int width = m_monitor->render->frameRenderWidth(); + int height = m_monitor->render->renderHeight(); + QList points; + foreach (const QVariant &bpoint, m_data.toList()) { + QList l = bpoint.toList(); + BPoint p; + p.h1 = QPointF(l.at(0).toList().at(0).toDouble() * width, l.at(0).toList().at(1).toDouble() * height); + p.p = QPointF(l.at(1).toList().at(0).toDouble() * width, l.at(2).toList().at(1).toDouble() * height); + p.h2 = QPointF(l.at(2).toList().at(0).toDouble() * width, l.at(2).toList().at(1).toDouble() * height); + points << p; + } + + m_item = new SplineItem(points, NULL, m_scene); + + connect(m_item, SIGNAL(changed()), this, SLOT(slotUpdateData())); + connect(edit, SIGNAL(showEdit(bool)), this, SLOT(slotShowScene(bool))); + connect(m_monitor, SIGNAL(renderPosition(int)), this, SLOT(slotCheckMonitorPosition(int))); +} + +RotoWidget::~RotoWidget() +{ + m_scene->removeItem(m_item); + delete m_item; + + if (m_monitor) { + MonitorEditWidget *edit = m_monitor->getEffectEdit(); + edit->showVisibilityButton(false); + edit->removeCustomControls(); + m_monitor->slotEffectScene(false); + } +} + +void RotoWidget::slotCheckMonitorPosition(int renderPos) +{ + if (m_showScene) + emit checkMonitorPosition(renderPos); +} + +void RotoWidget::slotSyncPosition(int relTimelinePos) +{ + Q_UNUSED(relTimelinePos); +} + +void RotoWidget::slotShowScene(bool show) +{ + m_showScene = show; + if (!m_showScene) + m_monitor->slotEffectScene(false); + else + slotCheckMonitorPosition(m_monitor->render->seekFramePosition()); +} + +void RotoWidget::slotUpdateData() +{ + int width = m_monitor->render->frameRenderWidth(); + int height = m_monitor->render->renderHeight(); + + QList spline = m_item->getPoints(); + QList vlist; + foreach (const BPoint &point, spline) { + QList pl; + for (int i = 0; i < 3; ++i) + pl << QVariant(QList () << QVariant(point[i].x() / width) << QVariant(point[i].y() / height)); + vlist << QVariant(pl); + } + m_data = QVariant(vlist); + + emit valueChanged(); +} + +QString RotoWidget::getSpline() +{ + QJson::Serializer serializer; + return QString(serializer.serialize(m_data)); +} + +#include "rotowidget.moc" diff --git a/src/rotoscoping/rotowidget.h b/src/rotoscoping/rotowidget.h new file mode 100644 index 00000000..3ac9fa0a --- /dev/null +++ b/src/rotoscoping/rotowidget.h @@ -0,0 +1,69 @@ +/*************************************************************************** + * Copyright (C) 2011 by Till Theato (root@ttill.de) * + * This file is part of Kdenlive (www.kdenlive.org). * + * * + * Kdenlive is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 2 of the License, or * + * (at your option) any later version. * + * * + * Kdenlive is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with Kdenlive. If not, see . * + ***************************************************************************/ + +#ifndef ROTOWIDGET_H +#define ROTOWIDGET_H + +#include "bpoint.h" + +#include + +class Monitor; +class MonitorScene; +class SplineItem; + +class RotoWidget : public QWidget +{ + Q_OBJECT + +public: + RotoWidget(QString data, Monitor *monitor, int in, int out, QWidget* parent = 0); + virtual ~RotoWidget(); + + QString getSpline(); + +public slots: + /** @brief Switches from normal monitor to monitor scene according to @param show. */ + void slotShowScene(bool show = true); + /** @brief Updates the on-monitor item. */ + void slotSyncPosition(int relTimelinePos); + +signals: + void valueChanged(); + void checkMonitorPosition(int); + + +private: + Monitor *m_monitor; + MonitorScene *m_scene; + bool m_showScene; + QVariant m_data; + SplineItem *m_item; + int m_in; + int m_out; + int m_pos; + +private slots: + /** @brief Makes sure the monitor effect scene is only visible if the clip this geometry belongs to is visible. + * @param renderPos Postion of the Monitor / Timeline cursor */ + void slotCheckMonitorPosition(int renderPos); + + void slotUpdateData(); +}; + +#endif