[SOLVED] Cursor and image coordinates(problem with scaling)



  • I have an MDI Application. Each child window is QWidget based class. This class(ImageWidget class) contains scroll area and QLabel in this area. In Qlabel we have image (like in Qt examples Image viewer) and I have zoomIn and zoomOut, normalSize functions there. So I add a function to process the image, and need actually know coordinates of image selected pixel by cursor coordinates:
    @void ImageWidget::mousePressEvent( QMouseEvent * event )
    {
    int x = event->pos().x();
    int y = event->pos().y();

    // Calculate scale and image sizes
    int h = m_imageLabel->height();
    int w = m_imageLabel->width();

    if(x>w || y>h)
    return;

    x = x/m_scaleFactor;
    y = y/m_scaleFactor;

    QRgb pixel = m_image.pixel(x,y);

    QColor color = QColor::fromRgb(pixel);

    }@
    So if my image is zoomed out I can get right coordinates by dividing current coordinates(each of it x and y) to scale factor. But if image is zoomed in and it's new size more then size of widgets this method don't work and I get wrong coordinates. what can I do now ?



  • Hi Anticross,

    Make x and y doubles

    make m_scaleFactor a double with 1.0 = 100 %

    make m_scaleFactor > 1.0 zoomed in and < 1.0 scaled out and use:

    @
    x *= m_scaleFactor;
    y *= m_scaleFactor;
    @



  • I modified it and now it looks like this:
    @void ImageWidget::mousePressEvent( QMouseEvent * event )
    {
    double x = event->pos().x();
    double y = event->pos().y();

    // Calculate scale and image sizes
    double h = m_imageLabel->height();
    double w = m_imageLabel->width();

    if(x>w || y>h)
    return;

    if(h>size().height() || w>size().width())
    {
    m_scaleFactor = 1.0;
    }

    x *= m_scaleFactor;
    y *= m_scaleFactor;

    QRgb pixel = m_image.pixel(x,y);

    QColor color = QColor::fromRgb(pixel);

    }@ but I still have wrong coords(sometimes with some offset from right coords).



  • The whole source of ImageViever class is
    *.cpp:
    @#include "ImageWidget.h"

    //-----------------------------------------------------------------------------
    ImageWidget::ImageWidget( QWidget * parent, const QString & filename ) : QWidget(parent)
    {
    m_imageLabel = new QLabel();
    m_imageLabel->setBackgroundRole(QPalette::Base);
    m_imageLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
    m_imageLabel->setScaledContents(true);

    m_scrollArea = new QScrollArea(this);
    m_scrollArea->setBackgroundRole(QPalette::Dark);
    m_scrollArea->setWidget(m_imageLabel);

    QVBoxLayout * layout = new QVBoxLayout();
    layout->addWidget(m_scrollArea);
    setLayout(layout);

    setWindowTitle(filename);
    resize(500, 400);

    // open file

    m_image = QImage(filename);
    if (m_image.isNull()) {
    QMessageBox::information(this, tr("Warning"),
    tr("Cannot load %1.").arg(filename));
    return;
    }

    m_imageLabel->setPixmap(QPixmap::fromImage(m_image));

    m_scaleFactor = 1.0;
    normalSize();

    m_pixelatorFlag = false;

    //connect(parent->ui.actionPixelator, SIGNAL(triggered()), this, SLOT(pixelatorOn()));
    }
    //-----------------------------------------------------------------------------
    void ImageWidget::zoomIn()
    {

    scaleImage(1.25);
    }
    //-----------------------------------------------------------------------------
    void ImageWidget::zoomOut()
    {
    scaleImage(0.8);
    }
    //-----------------------------------------------------------------------------
    void ImageWidget::normalSize()
    {
    m_imageLabel->adjustSize();
    m_scaleFactor = 1.0;
    }
    //-----------------------------------------------------------------------------
    void ImageWidget::fitToWindow( bool fitToWindow )
    {
    m_scrollArea->setWidgetResizable(fitToWindow);
    if (!fitToWindow) {
    normalSize();
    }
    }
    //-----------------------------------------------------------------------------
    void ImageWidget::scaleImage( double factor )
    {
    Q_ASSERT(m_imageLabel->pixmap());
    m_scaleFactor *= factor;
    m_imageLabel->resize(m_scaleFactor * m_imageLabel->pixmap()->size());

    adjustScrollBar(m_scrollArea->horizontalScrollBar(), factor);
    adjustScrollBar(m_scrollArea->verticalScrollBar(), factor);
    }
    //-----------------------------------------------------------------------------
    void ImageWidget::adjustScrollBar( QScrollBar *scrollBar, double factor )
    {
    scrollBar->setValue(int(factor * scrollBar->value()

    • ((factor - 1) * scrollBar->pageStep()/2)));
      }
      //-----------------------------------------------------------------------------
      void ImageWidget::mousePressEvent( QMouseEvent * event )
      {
      double x = event->pos().x();
      double y = event->pos().y();

    // Calculate scale and image sizes
    double h = m_imageLabel->height();
    double w = m_imageLabel->width();

    if(x>w || y>h)
    return;

    if(h>size().height() || w>size().width())
    {
    m_scaleFactor = 1.0;
    }

    x *= m_scaleFactor;
    y *= m_scaleFactor;

    QRgb pixel = m_image.pixel(x,y);

    QColor color = QColor::fromRgb(pixel);

    emit colorSelected(color.name(),x,y);

    proccessImage(color,false);
    }
    //-----------------------------------------------------------------------------
    void ImageWidget::proccessImage(QColor color, bool inverse)
    {
    // Search algorithm

    QImage image = m_image;
    int difference = 20;

    for(int y = 0; y < image.height(); y++)
    {
    for(int x = 0; x < image.width(); x++)
    {
    QRgb currentPixel = image.pixel(x,y);

    if( qAbs(qRed(currentPixel) - color.red()) > difference &&
    qAbs(qGreen(currentPixel) - color.green()) > difference &&
    qAbs(qBlue(currentPixel) - color.blue()) > difference)
    {
    if(!inverse)
    image.setPixel(x,y,qRgb(255,255,255));
    }
    else
    {
    if(inverse)
    image.setPixel(x,y,qRgb(255,255,255));
    }
    }
    }
    m_imageLabel->setPixmap(QPixmap::fromImage(image));
    }
    //-----------------------------------------------------------------------------
    void ImageWidget::pixelatorOn()
    {
    // QAction * act = (QAction *)QObject::sender();
    //
    // if(act == NULL)
    // return;
    //
    // if(act->isChecked())
    // m_pixelatorFlag = true;
    // else
    // m_pixelatorFlag = false;
    }
    //-----------------------------------------------------------------------------
    @
    *.h:
    @#ifndef IMAGEWIDGET_H
    #define IMAGEWIDGET_H

    #include <QWidget>
    #include <QScrollBar>
    #include <QScrollArea>
    #include <QLabel>
    #include <QMessageBox>
    #include <QVBoxLayout>
    #include <QMouseEvent>
    #include <QColor>

    class ImageWidget : public QWidget
    {
    Q_OBJECT

    QLabel *m_imageLabel;
    QScrollArea *m_scrollArea;
    double m_scaleFactor;
    QImage m_image;
    bool m_pixelatorFlag;

    public:
    ImageWidget(QWidget * parent, const QString & filename);
    void zoomIn();
    void zoomOut();
    void normalSize();
    void fitToWindow(bool fitToWindow);

    private:
    void scaleImage(double factor);
    void adjustScrollBar(QScrollBar *scrollBar, double factor);
    void proccessImage(QColor color, bool inverse);

    protected:
    void mousePressEvent(QMouseEvent * event);

    public slots:
    void pixelatorOn();

    signals:
    void colorSelected(const QString & color, int x, int y);

    };

    #endif//IMAGEWIDGET_H
    @

    Maybe I miss something when editing qt example and thats why I get wrong coords ?



  • You handle the mouse event with coordinates of teh ImageWidget class, but the picture is displayed in a subwidget. Map the coordinates to the label and it should work.



  • I replace 84-85 rows of my cpp file by this:

    @QPoint pos = m_imageLabel->mapFromParent(event->pos());
    double x = pos.x();
    double y = pos.y();@

    And it's worked, thx Gerolf.



  • Same trouble after some modificatin. When zoomOut and then make a click. Coordinates moved up left from real position, and after zoomOut its moved down right. Changed code looks like this:
    *.h
    @#ifndef IMAGEWIDGET_H
    #define IMAGEWIDGET_H

    #include <QWidget>
    #include <QScrollBar>
    #include <QScrollArea>
    #include <QLabel>
    #include <QMessageBox>
    #include <QVBoxLayout>
    #include <QMouseEvent>
    #include <QColor>
    #include <QGraphicsItem>

    enum curAction {ePixel, eErase, eNoact};

    class ImageWidget : public QWidget
    {
    Q_OBJECT

    QLabel *m_imageLabel;
    QScrollArea *m_scrollArea;
    double m_scaleFactor;
    QImage m_image;
    bool m_pixelatorFlag;
    int m_difference;
    QColor m_currentColor;
    curAction m_action;

    public:
    ImageWidget(QWidget * parent, const QString & filename);
    void zoomIn();
    void zoomOut();
    void normalSize();
    void fitToWindow(bool fitToWindow);
    void setCurrentAction(curAction action);

    private:
    void scaleImage(double factor);
    void adjustScrollBar(QScrollBar *scrollBar, double factor);
    void proccessImage(QColor color, bool inverse);
    void eraseImage(const QPointF & startPoint,const QPointF & endPoint);
    void revertChanges();

    protected:
    void mousePressEvent(QMouseEvent * event);
    void keyPressEvent (QKeyEvent * event);

    public slots:
    void onChangeDifference(int difference);

    signals:
    void colorSelected(const QString & color, int x, int y);

    };

    #endif//IMAGEWIDGET_H
    @



  • *.cpp
    @#include "ImageWidget.h"

    //-----------------------------------------------------------------------------
    ImageWidget::ImageWidget( QWidget * parent, const QString & filename ) : QWidget(parent)
    {
    m_imageLabel = new QLabel();
    m_imageLabel->setBackgroundRole(QPalette::Base);
    m_imageLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
    m_imageLabel->setScaledContents(true);

    m_scrollArea = new QScrollArea(this);
    m_scrollArea->setBackgroundRole(QPalette::Dark);
    m_scrollArea->setWidget(m_imageLabel);

    QVBoxLayout * layout = new QVBoxLayout();
    layout->addWidget(m_scrollArea);
    setLayout(layout);

    setWindowTitle(filename);
    resize(500, 400);

    // open file

    m_image = QImage(filename);
    if (m_image.isNull()) {
    QMessageBox::information(this, tr("Warning"),
    tr("Cannot load %1.").arg(filename));
    return;
    }

    m_imageLabel->setPixmap(QPixmap::fromImage(m_image));

    m_scaleFactor = 1.0;
    normalSize();

    m_pixelatorFlag = false;

    //connect(parent->ui.actionPixelator, SIGNAL(triggered()), this, SLOT(pixelatorOn()));

    m_difference = 20;
    m_currentColor = Qt::black;
    }
    //-----------------------------------------------------------------------------
    void ImageWidget::zoomIn()
    {

    scaleImage(1.25);
    }
    //-----------------------------------------------------------------------------
    void ImageWidget::zoomOut()
    {
    scaleImage(0.8);
    }
    //-----------------------------------------------------------------------------
    void ImageWidget::normalSize()
    {
    m_imageLabel->adjustSize();
    m_scaleFactor = 1.0;
    }
    //-----------------------------------------------------------------------------
    void ImageWidget::fitToWindow( bool fitToWindow )
    {
    m_scrollArea->setWidgetResizable(fitToWindow);
    if (!fitToWindow) {
    normalSize();
    }
    }
    //-----------------------------------------------------------------------------
    void ImageWidget::scaleImage( double factor )
    {
    Q_ASSERT(m_imageLabel->pixmap());
    m_scaleFactor *= factor;
    m_imageLabel->resize(m_scaleFactor * m_imageLabel->pixmap()->size());

    adjustScrollBar(m_scrollArea->horizontalScrollBar(), factor);
    adjustScrollBar(m_scrollArea->verticalScrollBar(), factor);
    }
    //-----------------------------------------------------------------------------
    void ImageWidget::adjustScrollBar( QScrollBar *scrollBar, double factor )
    {
    scrollBar->setValue(int(factor * scrollBar->value()

    • ((factor - 1) * scrollBar->pageStep()/2)));
      }
      //-----------------------------------------------------------------------------
      void ImageWidget::mousePressEvent( QMouseEvent * event )
      {
      QPointF pos = m_imageLabel->mapFromParent(event->pos());

    double x = pos.x();
    double y = pos.y();

    // Calculate scale and image sizes
    double h = m_imageLabel->height();
    double w = m_imageLabel->width();

    if(x>w || y>h)
    return;

    if(h>size().height() || w>size().width())
    {
    m_scaleFactor = 1.0;
    }

    x *= m_scaleFactor;
    y *= m_scaleFactor;

    pos = QPointF(x,y);

    QRgb pixel = m_image.pixel(x,y);

    m_currentColor = QColor::fromRgb(pixel);

    emit colorSelected(m_currentColor.name(),x,y);

    switch (m_action)
    {
    case ePixel:
    proccessImage(m_currentColor,false);
    break;
    case eErase:
    eraseImage(pos, QPointF(pos.x()+50,pos.y()+50));
    break;
    case eNoact:
    break;
    }
    }
    //-----------------------------------------------------------------------------
    void ImageWidget::keyPressEvent( QKeyEvent * event )
    {
    switch(event->key())
    {
    case Qt::Key_Z:
    {
    if(event->modifiers() == Qt::ControlModifier)
    revertChanges();
    }
    break;
    default:
    QWidget::keyPressEvent(event);
    }
    }
    //-----------------------------------------------------------------------------
    void ImageWidget::proccessImage(QColor color, bool inverse)
    {
    // Search algorithm

    QImage image = m_image;

    for(int y = 0; y < image.height(); y++)
    {
    for(int x = 0; x < image.width(); x++)
    {
    QRgb currentPixel = image.pixel(x,y);

    if( qAbs(qRed(currentPixel) - color.red()) > m_difference &&
    qAbs(qGreen(currentPixel) - color.green()) > m_difference &&
    qAbs(qBlue(currentPixel) - color.blue()) > m_difference)
    {
    if(!inverse)
    image.setPixel(x,y,qRgb(255,255,255));
    }
    else
    {
    if(inverse)
    image.setPixel(x,y,qRgb(255,255,255));
    }
    }
    }
    m_imageLabel->setPixmap(QPixmap::fromImage(image));

    // QMessageBox::information(this, tr("Done"),
    // tr("Processing image done.n"
    // "The document has been modified."),
    // QMessageBox::Ok);
    }
    //-----------------------------------------------------------------------------
    void ImageWidget::eraseImage( const QPointF & startPoint,const QPointF & endPoint )
    {
    QImage image = m_image;

    for(int y = 0; y < image.height(); y++)
    for(int x = 0; x < image.width(); x++)
    if(y > startPoint.y() && y < endPoint.y())
    if(x > startPoint.x() && x<endPoint.x())
    image.setPixel(x,y,qRgb(255,255,255));

    m_imageLabel->setPixmap(QPixmap::fromImage(image));

    m_image = image;
    }
    //-----------------------------------------------------------------------------
    void ImageWidget::revertChanges()
    {
    QImage image = m_imageLabel->pixmap()->toImage();

    m_imageLabel->setPixmap(QPixmap::fromImage(m_image));

    m_image = image;
    }
    //-----------------------------------------------------------------------------
    void ImageWidget::onChangeDifference(int difference)
    {
    m_difference = difference;
    //proccessImage(m_currentColor,false);
    }
    //-----------------------------------------------------------------------------
    void ImageWidget::setCurrentAction( curAction action )
    {
    m_action = action;
    }
    //-----------------------------------------------------------------------------
    @



  • I done this:
    make m_scalefactor double;
    When zoom in 0,8;
    when zoom out 1,25;

    if(h>size().height() || w>size().width())
    {
    m_scaleFactor = 1.0;
    }

    But I still have wrong coords in mouse press event x and y if I already make zomming, without zumming it's work correct. Please check somebody my code and make some corrections or recommendations.



  • Hello, i'am Novice in Qt program. I'am interested for you program (extention of imageViewer).
    Can you post it if you have the solution. Thank you.



  • I post header and source file of my Image widget class before. So you can see it, mahdhaoui. You just need to make an empty qt solution and use my class :)


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.