PDA

View Full Version : Select pixel from image



sergio87
14th April 2011, 12:25
Hi!
Firt of all, sorry for my poor English. I'm new in QT.

I open an image in a QLabel: imageLabel->setPixmap(QPixmap::fromImage(image));

This works well, but then I would like to add a mouse event. When the mouse was cliked in the image returns the pixel (of the image) in coordenates (X,Y). ¿It's possible?

I read that the QLabel class could not get a mouseClicked. Do I have to use another class? ¿Do I have to use the class Graphics View?

I'm using the example code of QT 4.7.2 called "Imageviewer". I'm programming in Windows with Eclipse Helios Release 2 (CDT).

Thank you very very much!!!

high_flyer
14th April 2011, 12:43
Your English is just fine, I have seen much worse here, believe me!

I read that the QLabel class could not get a mouseClicked.
Where did you read that?


Do I have to use another class?
In your code you are setting a QPixmap in your QLabel.
The QPixmap is the object that is representing your Image.
You can either:
1. install an event filter on the QPixmap to extract the mouse position during a mousePressEvent()
2. Subclass QPixmap and override the mousePressEvent().

sergio87
2nd May 2011, 08:49
First of all, thanks for answer!!

I tried to subclass QPixmap and override the mousePressEvent(). But nothing happened. I'll explain:

I subclass the QPixmap like this (in imageviewer.h):


class SubQPixmap : public QPixmap
{
public:
void mousePressEvent(QMouseEvent *event);
};


Then, I put this code in imageviewer.cpp:


void SubQPixmap::mousePressEvent(QMouseEvent *event)
{
cout<<"entra"<<endl;

if (event->button() == Qt::LeftButton) {
cout<<"pulsado en ("<<event->x()<<","<<event->y()<<")"<<endl;
}
}


But nothing is printed to the console.

I read that to subclass any "QT class" and override any signal or slot, the "QT class" has to be a QObject. QPixmap is not a QObject.
http://lists.trolltech.com/qt-interest/2007-02/thread01050-0.html

So, if I do this:

class SubQPixmap : public QPixmap
{
Q_OBJECT
public:
void mousePressEvent(QMouseEvent *event);
};

The compiler says:

'staticMetaObject' is not a member of 'QPixmap'

So, I think that it didn't work for this reason. ¿It's possible?

high_flyer
2nd May 2011, 11:11
Sorry, you are right, I forgot QPixmap is not a QWidget, so you don't have mousePressEvent().
So just to the same to the QLabel.
QLabel is a QWidget so you can catch the mouse press on it.
You can then either use QPixmap or QImage to extract the pixel data.
QImage should be faster for pixel access.

sergio87
2nd May 2011, 12:48
OK, thanks!

I did what you said.

Now I can extract the pixel where the mouse cliked. But is not the pixel of the image, it's the pixel of QLabel. So, If y scale the image, (zoom, for example), I don't extract the real pixel of the image, only of the QLabel. But I solved this saving the scale factor and doing some operations with it and the X,Y.


If somebody has the same problem as me, there is the code:

This code works and get the pixel of any image. (It's based on image_viewer example of QT).
imageviewer.cpp:

#include <QtGui>

#include "imageviewer.h"
#include <iostream> // one of two
using namespace std; // two of two, yay!

void SubQLabel::setFactor(const double &factor){
cout<<"setFactor"<<endl;
scaleFactor = factor;
}

ImageViewer::ImageViewer()
{
imageLabel = new SubQLabel;
imageLabel->setBackgroundRole(QPalette::Base);
imageLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
imageLabel->setScaledContents(true);

scrollArea = new QScrollArea;
scrollArea->setBackgroundRole(QPalette::Dark);
scrollArea->setWidget(imageLabel);
setCentralWidget(scrollArea);

createActions();
createMenus();

setWindowTitle(tr("Image Viewer"));
resize(500, 400);
}

void ImageViewer::open()
{
QString fileName = QFileDialog::getOpenFileName(this,
tr("Open File"), QDir::currentPath());
if (!fileName.isEmpty()) {
QImage image(fileName);
if (image.isNull()) {
QMessageBox::information(this, tr("Image Viewer"),
tr("Cannot load %1.").arg(fileName));
return;
}
imageLabel->setPixmap(QPixmap::fromImage(image));
scaleFactor = 1.0;

printAct->setEnabled(true);
fitToWindowAct->setEnabled(true);
updateActions();

if (!fitToWindowAct->isChecked())
imageLabel->adjustSize();
}
}

void ImageViewer::print()
{
Q_ASSERT(imageLabel->pixmap());
#ifndef QT_NO_PRINTER
QPrintDialog dialog(&printer, this);
if (dialog.exec()) {
QPainter painter(&printer);
QRect rect = painter.viewport();
QSize size = imageLabel->pixmap()->size();
size.scale(rect.size(), Qt::KeepAspectRatio);
painter.setViewport(rect.x(), rect.y(), size.width(), size.height());
painter.setWindow(imageLabel->pixmap()->rect());
painter.drawPixmap(0, 0, *imageLabel->pixmap());
}
#endif
}

void ImageViewer::zoomIn()
{
scaleImage(1.25);
}

void ImageViewer::zoomOut()
{
scaleImage(0.8);
}

void ImageViewer::normalSize()
{
imageLabel->adjustSize();
scaleFactor = 1.0;
}

void ImageViewer::fitToWindow()
{
bool fitToWindow = fitToWindowAct->isChecked();
scrollArea->setWidgetResizable(fitToWindow);
if (!fitToWindow) {
normalSize();
}
updateActions();
}

void SubQLabel::mousePressEvent(QMouseEvent *event)

{
cout<<"Ha pulsado:"<<endl;
int x = event->x();
int y = event->y();

int x_image = x/scaleFactor;
int y_image = y/scaleFactor;

if (event->button() == Qt::LeftButton) {
cout<<"x: "<< x <<endl;
cout<<"y: "<< y <<endl;

cout<<"Pixels de la imagen: ("<< x_image <<","<< y_image <<endl;
//cout<<"pulsado en ("<<event->x()/scaleFactor<<","<<event->y()/scaleFactor<<")"<<endl;

}
cout<<"Factor de escalado" << scaleFactor<<endl;
}

void SubQLabel::setScaleFactor(double factor){
scaleFactor = factor;
}

void ImageViewer::about()
{
QMessageBox::about(this, tr("About Image Viewer"),
tr("<p>The <b>Image Viewer</b> example shows how to combine QLabel "
"and QScrollArea to display an image. QLabel is typically used "
"for displaying a text, but it can also display an image. "
"QScrollArea provides a scrolling view around another widget. "
"If the child widget exceeds the size of the frame, QScrollArea "
"automatically provides scroll bars. </p><p>The example "
"demonstrates how QLabel's ability to scale its contents "
"(QLabel::scaledContents), and QScrollArea's ability to "
"automatically resize its contents "
"(QScrollArea::widgetResizable), can be used to implement "
"zooming and scaling features. </p><p>In addition the example "
"shows how to use QPainter to print an image.</p>"));
}

void ImageViewer::createActions()
{
openAct = new QAction(tr("&Open..."), this);
openAct->setShortcut(tr("Ctrl+O"));
connect(openAct, SIGNAL(triggered()), this, SLOT(open()));

printAct = new QAction(tr("&Print..."), this);
printAct->setShortcut(tr("Ctrl+P"));
printAct->setEnabled(false);
connect(printAct, SIGNAL(triggered()), this, SLOT(print()));

exitAct = new QAction(tr("E&xit"), this);
exitAct->setShortcut(tr("Ctrl+Q"));
connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));

zoomInAct = new QAction(tr("Zoom &In (25%)"), this);
zoomInAct->setShortcut(tr("Ctrl++"));
zoomInAct->setEnabled(false);
connect(zoomInAct, SIGNAL(triggered()), this, SLOT(zoomIn()));

zoomOutAct = new QAction(tr("Zoom &Out (25%)"), this);
zoomOutAct->setShortcut(tr("Ctrl+-"));
zoomOutAct->setEnabled(false);
connect(zoomOutAct, SIGNAL(triggered()), this, SLOT(zoomOut()));

normalSizeAct = new QAction(tr("&Normal Size"), this);
normalSizeAct->setShortcut(tr("Ctrl+S"));
normalSizeAct->setEnabled(false);
connect(normalSizeAct, SIGNAL(triggered()), this, SLOT(normalSize()));

fitToWindowAct = new QAction(tr("&Fit to Window"), this);
fitToWindowAct->setEnabled(false);
fitToWindowAct->setCheckable(true);
fitToWindowAct->setShortcut(tr("Ctrl+F"));
connect(fitToWindowAct, SIGNAL(triggered()), this, SLOT(fitToWindow()));

aboutAct = new QAction(tr("&About"), this);
connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));

aboutQtAct = new QAction(tr("About &Qt"), this);
connect(aboutQtAct, SIGNAL(triggered()), qApp, SLOT(aboutQt()));

connect(
this,
SIGNAL(scaleFactorChanged(const double&)),
imageLabel,
SLOT(setFactor(const double&)));
}

void ImageViewer::createMenus()
{
fileMenu = new QMenu(tr("&File"), this);
fileMenu->addAction(openAct);
fileMenu->addAction(printAct);
fileMenu->addSeparator();
fileMenu->addAction(exitAct);

viewMenu = new QMenu(tr("&View"), this);
viewMenu->addAction(zoomInAct);
viewMenu->addAction(zoomOutAct);
viewMenu->addAction(normalSizeAct);
viewMenu->addSeparator();
viewMenu->addAction(fitToWindowAct);

helpMenu = new QMenu(tr("&Help"), this);
helpMenu->addAction(aboutAct);
helpMenu->addAction(aboutQtAct);

menuBar()->addMenu(fileMenu);
menuBar()->addMenu(viewMenu);
menuBar()->addMenu(helpMenu);
}

void ImageViewer::updateActions()
{
zoomInAct->setEnabled(!fitToWindowAct->isChecked());
zoomOutAct->setEnabled(!fitToWindowAct->isChecked());
normalSizeAct->setEnabled(!fitToWindowAct->isChecked());
}

void ImageViewer::scaleImage(double factor)
{
Q_ASSERT(imageLabel->pixmap());
scaleFactor *= factor;
imageLabel->resize(scaleFactor * imageLabel->pixmap()->size());

adjustScrollBar(scrollArea->horizontalScrollBar(), factor);
adjustScrollBar(scrollArea->verticalScrollBar(), factor);

zoomInAct->setEnabled(scaleFactor < 3.0);
zoomOutAct->setEnabled(scaleFactor > 0.333);

emit scaleFactorChanged( scaleFactor );
}

void ImageViewer::adjustScrollBar(QScrollBar *scrollBar, double factor)
{
scrollBar->setValue(int(factor * scrollBar->value()
+ ((factor - 1) * scrollBar->pageStep()/2)));
}

ImageViewer.h:

#ifndef IMAGEVIEWER_H_
#define IMAGEVIEWER_H_

#include <QMainWindow>
#include <QPrinter>
#include <QPixmap>
#include <QLabel>
#include <iostream>

class QAction;
class QLabel;
class QMenu;
class QScrollArea;
class QScrollBar;
class SubQLabel;



class ImageViewer : public QMainWindow
{
Q_OBJECT

public:
ImageViewer();

private slots:
void open();
void print();
void zoomIn();
void zoomOut();
void normalSize();
void fitToWindow();
void about();

//protected:
// void mousePressEvent(QMouseEvent *event);
signals:
void scaleFactorChanged(const double& );


private:
void createActions();
void createMenus();
void updateActions();
void scaleImage(double factor);
void adjustScrollBar(QScrollBar *scrollBar, double factor);
double getSacleImage();

SubQLabel *imageLabel;
QScrollArea *scrollArea;
double scaleFactor;

#ifndef QT_NO_PRINTER
QPrinter printer;
#endif

QAction *openAct;
QAction *printAct;
QAction *exitAct;
QAction *zoomInAct;
QAction *zoomOutAct;
QAction *normalSizeAct;
QAction *fitToWindowAct;
QAction *aboutAct;
QAction *aboutQtAct;

QMenu *fileMenu;
QMenu *viewMenu;
QMenu *helpMenu;
};

#endif /* IMAGEVIEWER_H_ */


class SubQLabel : public QLabel
{
Q_OBJECT

public:
void mousePressEvent(QMouseEvent *event);
void setScaleFactor(double factor);

public slots:
void setFactor(const double &factor);

private:
double scaleFactor;
//public:
//SubQPixmap();

};


With signals and slots I get and set the scaleFactor.

Thanks!!