From bbf7e6df28e944897da4033310434bb7d2aa5467 Mon Sep 17 00:00:00 2001 From: "d.kilic" <d.kilic@fz-juelich.de> Date: Fri, 20 Nov 2020 10:13:30 +0100 Subject: [PATCH] Fixed: - not considering border correctly in color picker - not considering distortion in color picker - drifting part of map-index in GUI and in source code --- include/colorPlot.h | 16 +++--- include/control.h | 8 +-- include/view.h | 4 +- src/colorPlot.cpp | 34 ++++++++++-- src/control.cpp | 96 ++++++++++++++++----------------- src/view.cpp | 5 +- tests/unit_test/tst_control.cpp | 35 +++++++----- 7 files changed, 117 insertions(+), 81 deletions(-) diff --git a/include/colorPlot.h b/include/colorPlot.h index 46c289d0f..a4efa0950 100644 --- a/include/colorPlot.h +++ b/include/colorPlot.h @@ -68,27 +68,27 @@ public: : mColored(true), mMapHeight(DEFAULT_HEIGHT), mInversHue(false) { setRect(0., 0., 0., 0.); - mFromCol = mFromCol.toHsv(); - mToCol = mToCol.toHsv(); + mFromCol = QColor::fromHsv(0,0,0); + mToCol = QColor::fromHsv(359,255,255); } RectMap(QRectF r) : QRectF(r), mInversHue(false) { setRect(0., 0., 0., 0.); - mFromCol = mFromCol.toHsv(); - mToCol = mToCol.toHsv(); + mFromCol = QColor::fromHsv(0,0,0); + mToCol = QColor::fromHsv(359,255,255); } RectMap(double x, double y, double w, double h, bool colored, double mapHeight) : QRectF(x, y, w, h), mColored(colored), mMapHeight(mapHeight), mInversHue(false) { - mFromCol = mFromCol.toHsv(); - mToCol =mToCol.toHsv(); + mFromCol = QColor::fromHsv(0,0,0); + mToCol = QColor::fromHsv(359,255,255); } RectMap(QRectF r, bool colored, double mapHeight) : QRectF(r), mColored(colored), mMapHeight(mapHeight), mInversHue(false) { - mFromCol = mFromCol.toHsv(); - mToCol = mToCol.toHsv(); + mFromCol = QColor::fromHsv(0,0,0); + mToCol = QColor::fromHsv(359,255,255); } inline bool colored() const { diff --git a/include/control.h b/include/control.h index e5c45a860..64c43face 100644 --- a/include/control.h +++ b/include/control.h @@ -190,9 +190,9 @@ public: int getCalibGrid3DResolution(); void setCalibGrid3DResolution(int i); - void expandRange(QColor& fromColor, QColor& toColor, const std::array<int, 3>& clickedColor); + void expandRange(QColor& fromColor, QColor& toColor, const QColor& clickedColor); void saveChange(const QColor& fromColor, const QColor& toColor, RectPlotItem* map); - bool getColors(QPoint& p, GraphicsView* graphicsView, std::array<int, 3>& clickedColor, QColor& toColor, QColor& fromColor, RectPlotItem*& map); + bool getColors(QColor& clickedColor, QColor& toColor, QColor& fromColor, RectPlotItem*& map); void setXml(QDomElement &elem); void getXml(QDomElement &elem); @@ -263,8 +263,8 @@ private slots: void on_mapResetHeight_clicked(); void on_mapResetPos_clicked(); void on_mapDefaultHeight_valueChanged(double d); - void on_expandColor(QPoint p, GraphicsView* graphicsView); - void on_setColor(QPoint, GraphicsView*); + void on_expandColor(); + void on_setColor(); void on_trackShow_stateChanged(int i); diff --git a/include/view.h b/include/view.h index f3b690652..54b4b13c7 100644 --- a/include/view.h +++ b/include/view.h @@ -57,8 +57,8 @@ signals: void mouseRightDoubleClick(QPointF pos, int direction); void mouseMiddleDoubleClick(int direction); void mouseShiftWheel(int delta); - void colorSelected(QPoint p, GraphicsView* graphicsView); - void setColorEvent(QPoint p, GraphicsView* graphicsView); + void colorSelected(); + void setColorEvent(); //void mouseRightClick(QPointF pos); }; diff --git a/src/colorPlot.cpp b/src/colorPlot.cpp index d1dbd3404..d2b41ad49 100644 --- a/src/colorPlot.cpp +++ b/src/colorPlot.cpp @@ -416,8 +416,24 @@ int RectPlotItem::addMap() void RectPlotItem::delMap(int index) { + if(mMaps.size() == 1){ + if(index != 0) + { + debout << "Invalid index for map deletion!" << std::endl; + return; + } + mMaps.replace(0, RectMap()); + return; + } + if (index >= 0 && index < mMaps.size() && mMaps.size() > 0) + { mMaps.removeAt(index); + return; + } + + debout << "Invalid index for map deletion!" << std::endl; + return; } void RectPlotItem::changeMap(int index, double x, double y, double w, double h, bool colored, double mapHeight) @@ -457,17 +473,29 @@ void RectPlotItem::changeActMapToColor(const QColor &toCol) bool RectPlotItem::getActMapInvHue() { - return mMaps[mActIndex].invHue(); + if (mActIndex >= 0 && mActIndex < mMaps.size()) + { + return mMaps[mActIndex].invHue(); + } + return false; // Dependent on other fail checks } QColor RectPlotItem::getActMapToColor() { - return mMaps[mActIndex].toColor(); + if (mActIndex >= 0 && mActIndex < mMaps.size()) + { + return mMaps[mActIndex].toColor(); + } + return QColor::Invalid; } QColor RectPlotItem::getActMapFromColor() { - return mMaps[mActIndex].fromColor(); + if (mActIndex >= 0 && mActIndex < mMaps.size()) + { + return mMaps[mActIndex].fromColor(); + } + return QColor::Invalid; } RectMap RectPlotItem::getMap(int index) const diff --git a/src/control.cpp b/src/control.cpp index dda63c440..4bcdb1e2c 100644 --- a/src/control.cpp +++ b/src/control.cpp @@ -3221,21 +3221,20 @@ void Control::getXml(QDomElement &elem) void Control::on_colorPickerButton_clicked(bool checked) { //true wenn neu gechecked, false wenn wieder abgewählt + GraphicsView *view = mMainWindow->getView(); if(checked) { - connect(mMainWindow->getView(), SIGNAL(colorSelected(QPoint, GraphicsView*)), this, SLOT(on_expandColor(QPoint, GraphicsView*))); - connect(mMainWindow->getView(), SIGNAL(setColorEvent(QPoint, GraphicsView*)), this, SLOT(on_setColor(QPoint, GraphicsView*))); + connect(view, &GraphicsView::colorSelected, this, &Control::on_expandColor); + connect(view, &GraphicsView::setColorEvent, this, &Control::on_setColor); }else{ - disconnect(mMainWindow->getView(), SIGNAL(colorSelected(QPoint, GraphicsView*)), this, SLOT(on_expandColor(QPoint, GraphicsView*))); - disconnect(mMainWindow->getView(), SIGNAL(setColorEvent(QPoint, GraphicsView*)), this, SLOT(on_setColor(QPoint, GraphicsView*))); + disconnect(view, &GraphicsView::colorSelected, this, &Control::on_expandColor); + disconnect(view, &GraphicsView::setColorEvent, this, &Control::on_setColor); } } /** * @brief Gets necessary colors and the RectPlotItem * - * @param[in] p Clicked Point (gets changed!!!) - * @param[in] graphicsView GraphicsView in which the event was detected * @param[out] clickedColor color which was clicked on, with Hue from 0-360 instead of OpenCVs 0-180 * @param[out] toColor toColor as in model with triangle color picker * @param[out] fromColor fromColor as in model with triangle picker @@ -3243,35 +3242,33 @@ void Control::on_colorPickerButton_clicked(bool checked) * * @return Boolean describing, if a color was retrieved */ -bool Control::getColors(QPoint& p, GraphicsView* graphicsView, std::array<int, 3>& clickedColor, QColor& toColor, QColor& fromColor, RectPlotItem*& map) +bool Control::getColors(QColor& clickedColor, QColor& toColor, QColor& fromColor, RectPlotItem*& map) { if(mMainWindow->getImg().empty()) { return false; } - cv::Mat hsvImg; - cv::cvtColor(mMainWindow->getImg(), hsvImg, cv::COLOR_BGR2HSV); - p.setX(p.x() + mMainWindow->getImageBorderSize()); - p.setY(p.y() + mMainWindow->getImageBorderSize()); + QImage *hsvImg = mMainWindow->getImage(); + QPointF imgPoint = mMainWindow->getMousePosOnImage(); - - QPointF pointOnScene = graphicsView->mapToScene(p); - QPointF imgPoint = mMainWindow->getImageItem()->mapToScene(pointOnScene); - if(imgPoint.x() < 0 || imgPoint.x() > hsvImg.cols || imgPoint.y() < 0 || imgPoint.y() > hsvImg.rows) + if(imgPoint.x() < 0 || imgPoint.x() > hsvImg->width() || imgPoint.y() < 0 || imgPoint.y() > hsvImg->height()) { debout << "Clicked outside the image with color picker." << std::endl; return false; } //debout << "Koordinaten: " << imgPoint.x() << ", " << imgPoint.y() << std::endl; - cv::Vec3b color = hsvImg.at<cv::Vec3b>((int)imgPoint.y(), (int)imgPoint.x()); - clickedColor = {color[0] * 2, color[1], color[2]}; + clickedColor = QColor {hsvImg->pixel(imgPoint.toPoint())}; //debout << "Farbe: " << (int)clickedColor[0] << ", " << (int)clickedColor[1] << ", " << (int)clickedColor[2] << std::endl; map = this->getColorPlot()->getMapItem(); toColor = map->getActMapToColor(); fromColor = map->getActMapFromColor(); + if(!toColor.isValid() || !fromColor.isValid()){ + debout << "Map is corrupted" << std::endl; + return false; + } return true; } @@ -3285,13 +3282,13 @@ bool Control::getColors(QPoint& p, GraphicsView* graphicsView, std::array<int, 3 * @param p * @param graphicsView */ -void Control::on_expandColor(QPoint p, GraphicsView* graphicsView) +void Control::on_expandColor() { QColor fromColor, toColor; RectPlotItem* map; - std::array<int, 3> clickedColor; - if(!getColors(p, graphicsView, clickedColor, toColor, fromColor, map)) + QColor clickedColor; + if(!getColors(clickedColor, toColor, fromColor, map)) { return; } @@ -3307,36 +3304,37 @@ void Control::on_expandColor(QPoint p, GraphicsView* graphicsView) * @param p * @param graphicsView */ -void Control::on_setColor(QPoint p , GraphicsView* graphicsView){ +void Control::on_setColor() +{ constexpr int BUFFER = 5; QColor fromColor, toColor; RectPlotItem* map; - std::array<int, 3> clickedColor; - if(!getColors(p, graphicsView, clickedColor, toColor, fromColor, map)) + QColor clickedColor; + if(!getColors(clickedColor, toColor, fromColor, map)) { return; } int minHue, maxHue; - if( (clickedColor[0]+BUFFER)%359 < clickedColor[0]+BUFFER) + if( (clickedColor.hue()+BUFFER)%359 < clickedColor.hue()+BUFFER) { - maxHue = (clickedColor[0]+BUFFER)%BUFFER; + maxHue = (clickedColor.hue()+BUFFER)%BUFFER; map->changeActMapInvHue(true); }else{ - maxHue = clickedColor[0]+BUFFER; + maxHue = clickedColor.hue()+BUFFER; map->changeActMapInvHue(false); } - if( (clickedColor[0] - BUFFER) < 0) + if( (clickedColor.hue() - BUFFER) < 0) { - minHue = 360 + (clickedColor[0] - BUFFER); + minHue = 360 + (clickedColor.hue() - BUFFER); map->changeActMapInvHue(true); }else{ - minHue = clickedColor[0] - BUFFER; + minHue = clickedColor.hue() - BUFFER; //map->changeActMapInvHue(false); } - toColor.setHsv(maxHue, min((clickedColor[1]+BUFFER),255), min(clickedColor[2]+BUFFER, 255)); - fromColor.setHsv(minHue, max(clickedColor[1]-BUFFER,0), max(clickedColor[2]-BUFFER,0)); + toColor.setHsv(maxHue, min((clickedColor.saturation()+BUFFER),255), min(clickedColor.value()+BUFFER, 255)); + fromColor.setHsv(minHue, max(clickedColor.saturation()-BUFFER,0), max(clickedColor.value()-BUFFER,0)); //debout << "Inv Hue nach setCol: " << map->getActMapInvHue() << std::endl; saveChange(fromColor, toColor, map); @@ -3370,11 +3368,13 @@ void Control::saveChange(const QColor& fromColor, const QColor& toColor, RectPlo * @param toColor[in,out] toColor of the map, gets changed! * @param clickedColor[in] */ -void Control::expandRange(QColor& fromColor, QColor& toColor, const std::array<int, 3>& clickedColor) +void Control::expandRange(QColor& fromColor, QColor& toColor, const QColor& clickedColor) { // NOTE BUFFER in Klassenebene verschieben und bei setColor auch nutzen? (verschiedene Größe vllt. gewünscht?) constexpr int BUFFER = 10; + std::array<int, 3> clickedColorArr; + clickedColor.getHsv(&clickedColorArr[0], &clickedColorArr[1], &clickedColorArr[2]); std::array<int, 3> toColorArr; toColor.getHsv(&toColorArr[0], &toColorArr[1], &toColorArr[2]); std::array<int, 3> fromColorArr; @@ -3390,30 +3390,30 @@ void Control::expandRange(QColor& fromColor, QColor& toColor, const std::array<i // What values do need to be altered? if(invHue) { - if(toColorArr[0] > fromColorArr[0]) + if(toColor.hue() > fromColor.hue()) { - if(!(clickedColor[0] >= toColorArr[0] || clickedColor[0] <= fromColorArr[0])) + if(!(clickedColor.hue() >= toColor.hue() || clickedColor.hue() <= fromColor.hue())) { isInRange[0] = false; } }else { - if(!(clickedColor[0] <= toColorArr[0] || clickedColor[0] >= fromColorArr[0])) + if(!(clickedColor.hue() <= toColor.hue() || clickedColor.hue() >= fromColor.hue())) { isInRange[0] = false; } } }else { - if(toColorArr[0] > fromColorArr[0]) + if(toColor.hue() > fromColor.hue()) { - if(!(clickedColor[0] <= toColorArr[0] && clickedColor[0] >= fromColorArr[0])) + if(!(clickedColor.hue() <= toColor.hue() && clickedColor.hue() >= fromColor.hue())) { isInRange[0] = false; } }else { - if(!(clickedColor[0] >= toColorArr[0] && clickedColor[0] <= fromColorArr[0])) + if(!(clickedColor.hue() >= toColor.hue() && clickedColor.hue() <= fromColor.hue())) { isInRange[0] = false; } @@ -3424,12 +3424,12 @@ void Control::expandRange(QColor& fromColor, QColor& toColor, const std::array<i { if(toColorArr[i] > fromColorArr[i]) { - if(!(clickedColor[i] <= toColorArr[i] && clickedColor[i] >= fromColorArr[i])) + if(!(clickedColorArr[i] <= toColorArr[i] && clickedColorArr[i] >= fromColorArr[i])) { isInRange[i] = false; } }else{ - if(!(clickedColor[i] >= toColorArr[i] && clickedColor[i] <= fromColorArr[i])) + if(!(clickedColorArr[i] >= toColorArr[i] && clickedColorArr[i] <= fromColorArr[i])) { isInRange[i] = false; } @@ -3449,26 +3449,26 @@ void Control::expandRange(QColor& fromColor, QColor& toColor, const std::array<i if(isInRange[i]) continue; - distToColor = abs(toColorArr[i] - clickedColor[i]); - distFromColor = abs(fromColorArr[i] - clickedColor[i]); + distToColor = abs(toColorArr[i] - clickedColorArr[i]); + distFromColor = abs(fromColorArr[i] - clickedColorArr[i]); if(distFromColor < distToColor) { - int buffer = fromColorArr[i] - clickedColor[i] < 0 ? BUFFER : -BUFFER; + int buffer = fromColorArr[i] - clickedColorArr[i] < 0 ? BUFFER : -BUFFER; if(i==0) // Hue { - fromColorArr[i] = min(359, max(0, clickedColor[i] + buffer)); + fromColorArr[i] = min(359, max(0, clickedColorArr[i] + buffer)); }else { - fromColorArr[i] = min(255, max(0, clickedColor[i] + buffer)); + fromColorArr[i] = min(255, max(0, clickedColorArr[i] + buffer)); } }else{ - int buffer = toColorArr[i] - clickedColor[i] < 0 ? BUFFER : -BUFFER; + int buffer = toColorArr[i] - clickedColorArr[i] < 0 ? BUFFER : -BUFFER; if(i==0) // Hue { - toColorArr[i] = min(359, max(0, clickedColor[i] + buffer)); + toColorArr[i] = min(359, max(0, clickedColorArr[i] + buffer)); }else { - toColorArr[i] = min(255, max(0, clickedColor[i] + buffer)); + toColorArr[i] = min(255, max(0, clickedColorArr[i] + buffer)); } } } diff --git a/src/view.cpp b/src/view.cpp index b721bd923..47dcc792a 100644 --- a/src/view.cpp +++ b/src/view.cpp @@ -61,6 +61,7 @@ GraphicsView::GraphicsView(ViewWidget *viewWidget) // setDragMode(QGraphicsView::ScrollHandDrag); // } + void GraphicsView::wheelEvent(QWheelEvent * event) { QPoint numDegrees = event->angleDelta() / 8; @@ -199,9 +200,9 @@ void GraphicsView::mousePressEvent(QMouseEvent *event) { if(event->modifiers() & Qt::ShiftModifier){ - emit setColorEvent(event->pos(), this); + emit setColorEvent(); }else{ - emit colorSelected(event->pos(), this); + emit colorSelected(); } QGraphicsView::mousePressEvent(event); } diff --git a/tests/unit_test/tst_control.cpp b/tests/unit_test/tst_control.cpp index c51e21ba7..3c2e30777 100644 --- a/tests/unit_test/tst_control.cpp +++ b/tests/unit_test/tst_control.cpp @@ -44,22 +44,22 @@ void checkSelectedColor(Control* con, bool invHue, int toHue, int fromHue, QColor fromColor = con->getColorPlot()->getMapItem()->getActMapFromColor(); // Hue - REQUIRE(toColor.hue() == toHue); - REQUIRE(fromColor.hue() == fromHue); + REQUIRE(toColor.hue() == Approx(toHue).margin(1)); + REQUIRE(fromColor.hue() == Approx(fromHue).margin(1)); // Saturation - REQUIRE(toColor.saturation() == toSat); - REQUIRE(fromColor.saturation() == fromSat); + REQUIRE(toColor.saturation() == Approx(toSat).margin(1)); + REQUIRE(fromColor.saturation() == Approx(fromSat).margin(1)); // Value - REQUIRE(toColor.value() == toVal); - REQUIRE(fromColor.value() == fromVal); + REQUIRE(toColor.value() == Approx(toVal).margin(1)); + REQUIRE(fromColor.value() == Approx(fromVal).margin(1)); // Sliders - REQUIRE(con->mapX->value() == mapX); - REQUIRE(con->mapW->value() == mapW); - REQUIRE(con->mapY->value() == mapY); - REQUIRE(con->mapH->value() == mapH); + REQUIRE(con->mapX->value() == Approx(mapX).margin(2)); + REQUIRE(con->mapW->value() == Approx(mapW).margin(2)); + REQUIRE(con->mapY->value() == Approx(mapY).margin(2)); + REQUIRE(con->mapH->value() == Approx(mapH).margin(2)); } @@ -88,12 +88,13 @@ SCENARIO("I open PeTrack with a red image", "[ui][config]") AND_GIVEN("I shift+click on one point of the (red) image"){ eventList.clear(); eventList.addMouseClick(Qt::MouseButton::LeftButton, Qt::KeyboardModifier::ShiftModifier, viewCenter); + eventList.addMouseClick(Qt::MouseButton::LeftButton, Qt::KeyboardModifier::ShiftModifier, viewCenter); - QSignalSpy setColorSpy{pet.getView(), SIGNAL(setColorEvent(QPoint, GraphicsView*))}; + QSignalSpy setColorSpy{pet.getView(), &GraphicsView::setColorEvent}; REQUIRE(setColorSpy.isValid()); setColorSpy.wait(20); eventList.simulate(pet.getView()->viewport()); - REQUIRE(setColorSpy.count() == 1); + REQUIRE(setColorSpy.count() == 2); THEN("This pixel and its sourroundings get selected as new color"){ // Red, so we need Inverse Hue @@ -161,6 +162,7 @@ SCENARIO("I open PeTrack with a red image", "[ui][config]") QTestEventList eventList; eventList.addMouseClick(Qt::MouseButton::LeftButton, Qt::KeyboardModifier::ShiftModifier, viewCenter); + eventList.addMouseClick(Qt::MouseButton::LeftButton, Qt::KeyboardModifier::ShiftModifier, viewCenter); eventList.simulate(pet.getView()->viewport()); REQUIRE(!con->getColorPlot()->getMapItem()->getActMapInvHue()); @@ -185,6 +187,7 @@ SCENARIO("I open PeTrack with a red image", "[ui][config]") pet.updateImage(pinkTestImage); QTestEventList eventList; + eventList.addMouseMove(viewCenter); eventList.addMouseClick(Qt::MouseButton::LeftButton, Qt::KeyboardModifier::NoModifier, viewCenter); eventList.simulate(pet.getView()->viewport()); @@ -199,17 +202,21 @@ SCENARIO("I open PeTrack with a red image", "[ui][config]") newTestImage.at<cv::Vec3b>(cv::Point(25,25)) = cv::Vec3b(100,255,255); cv::cvtColor(newTestImage, newTestImage, cv::COLOR_HSV2BGR); pet.updateImage(newTestImage); + QMouseEvent event {QEvent::HoverMove, QPoint(25, 25), Qt::NoButton, Qt::NoButton, Qt::NoModifier}; - QTestEventList eventList; QPointF pointOnScene = pet.getImageItem()->mapToScene(QPoint(25, 25)); QPoint pointOnViewport = pet.getView()->mapFromScene(pointOnScene); + + // Only after a click the hover event setting mMousePosOnImage gets fired. Focus? + eventList.addMouseClick(Qt::MouseButton::LeftButton, Qt::KeyboardModifier::ShiftModifier, + pointOnViewport); eventList.addMouseClick(Qt::MouseButton::LeftButton, Qt::KeyboardModifier::ShiftModifier, pointOnViewport); eventList.simulate(pet.getView()->viewport()); THEN("I get a color selection fitting this single pixel"){ bool invHue = false; - // Upper Bound Hue 200 + 5 -> 105 Lower Bound: 200 - 5 -> 95 + // Upper Bound Hue 200 + 5 -> 205 Lower Bound: 200 - 5 -> 195 int fromHue = 195, toHue = 205; // mapW = tH-fH = 10 int mapW = 10; -- GitLab