Added "Camera from TCP/IP..." action. Find-Object can connect to a server to receive images over TCP/IP. Look at the "imagesTcpServer" example to know how to send a images. The stream format is [quint64 size, std::vector<unsigned char> data]. The data array is decoded to a cv:Mat image using cv::imdecode(data, cv::IMREAD_UNCHANGED). In the server example, the images are encoded like that: cv::imencode(".png", image, data).

git-svn-id: http://find-object.googlecode.com/svn/trunk/find_object@280 620bd6b2-0a58-f614-fd9a-1bd335dccda9
This commit is contained in:
matlabbe
2014-05-21 21:31:42 +00:00
parent 2d3b4ebebe
commit 19b5776ba4
12 changed files with 503 additions and 62 deletions
+141 -41
View File
@@ -8,6 +8,76 @@
#include "Settings.h"
#include <QtCore/QFile>
#include "utilite/UDirectory.h"
#include "QtOpenCV.h"
CameraTcpClient::CameraTcpClient(QObject *parent) :
QTcpSocket(parent),
blockSize_(0)
{
connect(this, SIGNAL(readyRead()), this, SLOT(readData()));
connect(this, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(displayError(QAbstractSocket::SocketError)));
connect(this, SIGNAL(disconnected()), this, SLOT(connectionLost()));
}
cv::Mat CameraTcpClient::getImage()
{
cv::Mat img = image_;
image_ = cv::Mat();
return img;
}
void CameraTcpClient::readData()
{
QDataStream in(this);
in.setVersion(QDataStream::Qt_4_0);
if (blockSize_ == 0)
{
if (this->bytesAvailable() < (int)sizeof(quint64))
{
return;
}
in >> blockSize_;
}
if (this->bytesAvailable() < (int)blockSize_)
{
return;
}
std::vector<unsigned char> buf(blockSize_);
in.readRawData((char*)buf.data(), blockSize_);
image_ = cv::imdecode(buf, cv::IMREAD_UNCHANGED);
blockSize_ = 0;
}
void CameraTcpClient::displayError(QAbstractSocket::SocketError socketError)
{
switch (socketError)
{
case QAbstractSocket::RemoteHostClosedError:
break;
case QAbstractSocket::HostNotFoundError:
printf("[ERROR] CameraTcp: Tcp error: The host was not found. Please "
"check the host name and port settings.\n");
break;
case QAbstractSocket::ConnectionRefusedError:
printf("[ERROR] CameraTcp: The connection was refused by the peer. "
"Make sure your images server is running, "
"and check that the host name and port "
"settings are correct.\n");
break;
default:
printf("The following error occurred: %s.\n", this->errorString().toStdString().c_str());
break;
}
}
void CameraTcpClient::connectionLost()
{
printf("[WARNING] CameraTcp: Connection lost!\n");
}
Camera::Camera(QObject * parent) :
QObject(parent),
@@ -28,6 +98,7 @@ void Camera::stop()
capture_.release();
images_.clear();
currentImageIndex_ = 0;
cameraTcpClient_.close();
}
void Camera::pause()
@@ -87,6 +158,21 @@ void Camera::takeImage()
img = cv::imread(images_[currentImageIndex_++]);
}
}
else
{
img = cameraTcpClient_.getImage();
while(img.empty() && cameraTcpClient_.waitForReadyRead())
{
img = cameraTcpClient_.getImage();
}
if(!cameraTcpClient_.waitForConnected())
{
printf("Connection is lost, try reconnecting to server (%s:%d)...\n",
Settings::getCamera_7IP().toStdString().c_str(),
Settings::getCamera_8port());
cameraTcpClient_.connectToHost(Settings::getCamera_7IP(), Settings::getCamera_8port());
}
}
if(img.empty())
{
@@ -117,62 +203,76 @@ void Camera::takeImage()
bool Camera::start()
{
if(!capture_.isOpened() && images_.empty())
if(!capture_.isOpened() && images_.empty() && !cameraTcpClient_.isOpen())
{
QString path = Settings::getCamera_5mediaPath();
if(UDirectory::exists(path.toStdString()))
if(Settings::getCamera_6useTcpCamera())
{
//Images directory
QString ext = Settings::getGeneral_imageFormats();
ext.remove('*');
ext.remove('.');
UDirectory dir(path.toStdString(), ext.toStdString()); // this will load fileNames matching the extensions (in natural order)
const std::list<std::string> & fileNames = dir.getFileNames();
currentImageIndex_ = 0;
images_.clear();
// Modify to have full path
for(std::list<std::string>::const_iterator iter = fileNames.begin(); iter!=fileNames.end(); ++iter)
cameraTcpClient_.connectToHost(Settings::getCamera_7IP(), Settings::getCamera_8port());
if(!cameraTcpClient_.waitForConnected())
{
images_.append(path.toStdString() + UDirectory::separator() + *iter);
}
printf("Camera: Reading %d images from directory \"%s\"...\n", (int)images_.size(), path.toStdString().c_str());
if(images_.isEmpty())
{
printf("[WARNING] Directory \"%s\" is empty (no images matching the \"%s\" extensions). "
"If you want to disable loading automatically this directory, "
"clear the Camera/mediaPath parameter. By default, webcam will be used instead of the directory.\n",
path.toStdString().c_str(),
ext.toStdString().c_str());
printf("[WARNING] Camera: Cannot connect to server \"%s:%d\"\n",
Settings::getCamera_7IP().toStdString().c_str(),
Settings::getCamera_8port());
cameraTcpClient_.close();
}
}
else if(!path.isEmpty())
else
{
//Video file
capture_.open(path.toStdString().c_str());
if(!capture_.isOpened())
QString path = Settings::getCamera_5mediaPath();
if(UDirectory::exists(path.toStdString()))
{
printf("[WARNING] Cannot open file \"%s\". If you want to disable loading automatically this video file, clear the Camera/mediaPath parameter. By default, webcam will be used instead of the file.\n", path.toStdString().c_str());
//Images directory
QString ext = Settings::getGeneral_imageFormats();
ext.remove('*');
ext.remove('.');
UDirectory dir(path.toStdString(), ext.toStdString()); // this will load fileNames matching the extensions (in natural order)
const std::list<std::string> & fileNames = dir.getFileNames();
currentImageIndex_ = 0;
images_.clear();
// Modify to have full path
for(std::list<std::string>::const_iterator iter = fileNames.begin(); iter!=fileNames.end(); ++iter)
{
images_.append(path.toStdString() + UDirectory::separator() + *iter);
}
printf("Camera: Reading %d images from directory \"%s\"...\n", (int)images_.size(), path.toStdString().c_str());
if(images_.isEmpty())
{
printf("[WARNING] Camera: Directory \"%s\" is empty (no images matching the \"%s\" extensions). "
"If you want to disable loading automatically this directory, "
"clear the Camera/mediaPath parameter. By default, webcam will be used instead of the directory.\n",
path.toStdString().c_str(),
ext.toStdString().c_str());
}
}
else
else if(!path.isEmpty())
{
printf("Camera: Reading from video file \"%s\"...\n", path.toStdString().c_str());
//Video file
capture_.open(path.toStdString().c_str());
if(!capture_.isOpened())
{
printf("[WARNING] Camera: Cannot open file \"%s\". If you want to disable loading automatically this video file, clear the Camera/mediaPath parameter. By default, webcam will be used instead of the file.\n", path.toStdString().c_str());
}
else
{
printf("Camera: Reading from video file \"%s\"...\n", path.toStdString().c_str());
}
}
}
if(!capture_.isOpened() && images_.empty())
{
//set camera device
capture_.open(Settings::getCamera_1deviceId());
if(Settings::getCamera_2imageWidth() && Settings::getCamera_3imageHeight())
if(!capture_.isOpened() && images_.empty())
{
capture_.set(CV_CAP_PROP_FRAME_WIDTH, double(Settings::getCamera_2imageWidth()));
capture_.set(CV_CAP_PROP_FRAME_HEIGHT, double(Settings::getCamera_3imageHeight()));
//set camera device
capture_.open(Settings::getCamera_1deviceId());
if(Settings::getCamera_2imageWidth() && Settings::getCamera_3imageHeight())
{
capture_.set(CV_CAP_PROP_FRAME_WIDTH, double(Settings::getCamera_2imageWidth()));
capture_.set(CV_CAP_PROP_FRAME_HEIGHT, double(Settings::getCamera_3imageHeight()));
}
printf("Camera: Reading from camera device %d...\n", Settings::getCamera_1deviceId());
}
printf("Camera: Reading from camera device %d...\n", Settings::getCamera_1deviceId());
}
}
if(!capture_.isOpened() && images_.empty())
if(!capture_.isOpened() && images_.empty() && !cameraTcpClient_.isOpen())
{
printf("[ERROR] Failed to open a capture object!\n");
printf("[ERROR] Camera: Failed to open a capture object!\n");
return false;
}
+22
View File
@@ -8,6 +8,27 @@
#include <opencv2/highgui/highgui.hpp>
#include <QtCore/QObject>
#include <QtCore/QTimer>
#include <QtGui/QImage>
#include <QtNetwork/QTcpSocket>
class CameraTcpClient : public QTcpSocket
{
Q_OBJECT;
public:
CameraTcpClient(QObject * parent = 0);
cv::Mat getImage();
bool isConnected() const {return connected_;}
private slots:
void readData();
void displayError(QAbstractSocket::SocketError socketError);
void connectionLost();
private:
quint64 blockSize_;
cv::Mat image_;
bool connected_;
};
class Camera : public QObject {
Q_OBJECT
@@ -40,6 +61,7 @@ private:
QTimer cameraTimer_;
QList<std::string> images_;
unsigned int currentImageIndex_;
CameraTcpClient cameraTcpClient_;
};
#endif /* CAMERA_H_ */
+69 -18
View File
@@ -37,6 +37,7 @@
#include <QtGui/QCloseEvent>
#include <QtGui/QCheckBox>
#include <QtGui/QScrollBar>
#include <QtGui/QInputDialog>
#include "utilite/UDirectory.h"
@@ -136,6 +137,7 @@ MainWindow::MainWindow(Camera * camera, const QString & settings, QWidget * pare
connect(ui_->actionLoad_objects, SIGNAL(triggered()), this, SLOT(loadObjects()));
connect(ui_->actionCamera_from_video_file, SIGNAL(triggered()), this, SLOT(setupCameraFromVideoFile()));
connect(ui_->actionCamera_from_directory_of_images, SIGNAL(triggered()), this, SLOT(setupCameraFromImagesDirectory()));
connect(ui_->actionCamera_from_TCP_IP, SIGNAL(triggered()), this, SLOT(setupCameraFromTcpIp()));
connect(ui_->actionAbout, SIGNAL(triggered()), aboutDialog_ , SLOT(exec()));
connect(ui_->actionRestore_all_default_settings, SIGNAL(triggered()), ui_->toolBox, SLOT(resetAllPages()));
connect(ui_->actionRemove_all_objects, SIGNAL(triggered()), this, SLOT(removeAllObjects()));
@@ -149,7 +151,7 @@ MainWindow::MainWindow(Camera * camera, const QString & settings, QWidget * pare
connect(ui_->horizontalSlider_frames, SIGNAL(valueChanged(int)), ui_->label_frame, SLOT(setNum(int)));
ui_->pushButton_play->setVisible(true);
ui_->pushButton_pause->setVisible(false);
ui_->pushButton_stop->setEnabled(true);
ui_->pushButton_stop->setEnabled(false);
ui_->horizontalSlider_frames->setEnabled(false);
ui_->label_frame->setVisible(false);
@@ -162,6 +164,7 @@ MainWindow::MainWindow(Camera * camera, const QString & settings, QWidget * pare
ui_->actionCamera_from_video_file->setChecked(!Settings::getCamera_5mediaPath().isEmpty() && !UDirectory::exists(Settings::getCamera_5mediaPath().toStdString()));
ui_->actionCamera_from_directory_of_images->setChecked(!Settings::getCamera_5mediaPath().isEmpty() && UDirectory::exists(Settings::getCamera_5mediaPath().toStdString()));
ui_->actionCamera_from_TCP_IP->setChecked(Settings::getCamera_6useTcpCamera());
ui_->label_ipAddress->setTextInteractionFlags(Qt::TextSelectableByMouse);
ui_->label_port->setTextInteractionFlags(Qt::TextSelectableByMouse);
@@ -554,6 +557,7 @@ void MainWindow::setupCameraFromVideoFile()
}
ui_->actionCamera_from_video_file->setChecked(!Settings::getCamera_5mediaPath().isEmpty());
ui_->actionCamera_from_directory_of_images->setChecked(false);
ui_->actionCamera_from_TCP_IP->setChecked(false);
}
void MainWindow::setupCameraFromImagesDirectory()
@@ -581,6 +585,42 @@ void MainWindow::setupCameraFromImagesDirectory()
}
ui_->actionCamera_from_directory_of_images->setChecked(!Settings::getCamera_5mediaPath().isEmpty());
ui_->actionCamera_from_video_file->setChecked(false);
ui_->actionCamera_from_TCP_IP->setChecked(false);
}
void MainWindow::setupCameraFromTcpIp()
{
if(!ui_->actionCamera_from_TCP_IP->isChecked())
{
Settings::setCamera_6useTcpCamera(false);
ui_->toolBox->updateParameter(Settings::kCamera_6useTcpCamera());
}
else
{
QString ip = QInputDialog::getText(this, tr("Server IP..."), "IP: ", QLineEdit::Normal, Settings::getCamera_7IP());
if(!ip.isEmpty())
{
int port = QInputDialog::getInteger(this, tr("Server port..."), "Port: ", Settings::getCamera_8port());
if(port > 0)
{
Settings::setCamera_6useTcpCamera(true);
ui_->toolBox->updateParameter(Settings::kCamera_6useTcpCamera());
Settings::setCamera_7IP(ip);
ui_->toolBox->updateParameter(Settings::kCamera_7IP());
Settings::setCamera_8port(port);
ui_->toolBox->updateParameter(Settings::kCamera_8port());
if(camera_->isRunning())
{
this->stopProcessing();
}
this->startProcessing();
}
}
}
ui_->actionCamera_from_directory_of_images->setChecked(false);
ui_->actionCamera_from_video_file->setChecked(false);
ui_->actionCamera_from_TCP_IP->setChecked(Settings::getCamera_6useTcpCamera());
}
void MainWindow::showObject(ObjWidget * obj)
@@ -936,6 +976,7 @@ void MainWindow::startProcessing()
ui_->actionLoad_scene_from_file->setEnabled(false);
ui_->actionCamera_from_directory_of_images->setEnabled(false);
ui_->actionCamera_from_video_file->setEnabled(false);
ui_->actionCamera_from_TCP_IP->setEnabled(false);
ui_->label_timeRefreshRate->setVisible(true);
//update control bar
@@ -963,7 +1004,14 @@ void MainWindow::startProcessing()
}
if(this->isVisible())
{
QMessageBox::critical(this, tr("Camera error"), tr("Camera initialization failed! (with device %1)").arg(Settings::getCamera_1deviceId()));
if(Settings::getCamera_6useTcpCamera())
{
QMessageBox::critical(this, tr("Camera error"), tr("Camera initialization failed! (with server %1:%2)").arg(Settings::getCamera_7IP()).arg(Settings::getCamera_8port()));
}
else
{
QMessageBox::critical(this, tr("Camera error"), tr("Camera initialization failed! (with device %1)").arg(Settings::getCamera_1deviceId()));
}
}
else
{
@@ -985,6 +1033,7 @@ void MainWindow::stopProcessing()
ui_->actionLoad_scene_from_file->setEnabled(true);
ui_->actionCamera_from_directory_of_images->setEnabled(true);
ui_->actionCamera_from_video_file->setEnabled(true);
ui_->actionCamera_from_TCP_IP->setEnabled(true);
ui_->pushButton_play->setVisible(true);
ui_->pushButton_pause->setVisible(false);
ui_->pushButton_stop->setEnabled(false);
@@ -1655,22 +1704,24 @@ void MainWindow::update(const cv::Mat & image)
}
// Emit homographies
if(objectsDetected.size())
if(objectsDetected.size() > 1)
{
if(objectsDetected.size() > 1)
{
printf("(%s) %d objects detected!\n",
QTime::currentTime().toString("HH:mm:ss.zzz").toStdString().c_str(),
(int)objectsDetected.size());
}
else
{
printf("(%s) Object %d detected!\n",
QTime::currentTime().toString("HH:mm:ss.zzz").toStdString().c_str(),
(int)objectsDetected.begin().key());
}
emit objectsFound(objectsDetected);
printf("(%s) %d objects detected!\n",
QTime::currentTime().toString("HH:mm:ss.zzz").toStdString().c_str(),
(int)objectsDetected.size());
}
else if(objectsDetected.size() == 1)
{
printf("(%s) Object %d detected!\n",
QTime::currentTime().toString("HH:mm:ss.zzz").toStdString().c_str(),
(int)objectsDetected.begin().key());
}
else
{
printf("(%s) No objects detected.\n",
QTime::currentTime().toString("HH:mm:ss.zzz").toStdString().c_str());
}
emit objectsFound(objectsDetected);
ui_->label_objectsDetected->setNum(objectsDetected.size());
}
else
@@ -1740,7 +1791,7 @@ void MainWindow::notifyParametersChanged(const QStringList & paramChanged)
bool nearestNeighborParamsChanged = false;
for(QStringList::const_iterator iter = paramChanged.begin(); iter!=paramChanged.end(); ++iter)
{
printf("Parameter changed: %s\n", iter->toStdString().c_str());
printf("Parameter changed: %s -> \"%s\"\n", iter->toStdString().c_str(), Settings::getParameter(*iter).toString().toStdString().c_str());
if(lastObjectsUpdateParameters_.value(*iter) != Settings::getParameter(*iter))
{
if(!detectorDescriptorParamsChanged && iter->contains("Feature2D"))
@@ -1788,5 +1839,5 @@ void MainWindow::notifyParametersChanged(const QStringList & paramChanged)
ui_->actionCamera_from_video_file->setChecked(!Settings::getCamera_5mediaPath().isEmpty() && !UDirectory::exists(Settings::getCamera_5mediaPath().toStdString()));
ui_->actionCamera_from_directory_of_images->setChecked(!Settings::getCamera_5mediaPath().isEmpty() && UDirectory::exists(Settings::getCamera_5mediaPath().toStdString()));
ui_->actionCamera_from_TCP_IP->setChecked(Settings::getCamera_6useTcpCamera());
}
+1
View File
@@ -66,6 +66,7 @@ private slots:
void loadSceneFromFile();
void setupCameraFromVideoFile();
void setupCameraFromImagesDirectory();
void setupCameraFromTcpIp();
void removeObject(ObjWidget * object);
void removeAllObjects();
void updateObjectsSize();
-1
View File
@@ -39,7 +39,6 @@ cv::Mat cvtQImage2CvMat(const QImage & image)
cvImage = cv::Mat(image.height(), image.width(), CV_8UC3);
unsigned char * data = cvImage.data;
const IplImage test = cvImage;
printf("%d vs %d\n", cvImage.cols*int(cvImage.elemSize()), test.widthStep);
for(int y = 0; y < image.height(); ++y, data+=cvImage.cols*cvImage.elemSize())
{
for(int x = 0; x < image.width(); ++x)
+3
View File
@@ -60,6 +60,9 @@ class Settings
PARAMETER(Camera, 3imageHeight, int, 480, "Image height (0 means default height from camera).");
PARAMETER(Camera, 4imageRate, double, 2.0, "Image rate in Hz (0 Hz means as fast as possible)."); // Hz
PARAMETER(Camera, 5mediaPath, QString, "", "Video file or directory of images. If set, the camera is not used. See General->videoFormats and General->imageFormats for available formats.");
PARAMETER(Camera, 6useTcpCamera, bool, false, "Use TCP/IP input camera.");
PARAMETER(Camera, 7IP, QString, "127.0.0.1", "The images server's IP to connect when useTcpCamera is checked.");
PARAMETER(Camera, 8port, int, 5000, "The images server's port to connect when useTcpCamera is checked.");
//List format : [Index:item0;item1;item3;...]
PARAMETER(Feature2D, 1Detector, QString, "7:Dense;Fast;GFTT;MSER;ORB;SIFT;Star;SURF;BRISK" , "Keypoint detector.");
+11 -2
View File
@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>826</width>
<height>689</height>
<height>713</height>
</rect>
</property>
<property name="windowTitle">
@@ -228,6 +228,7 @@
<addaction name="actionLoad_scene_from_file"/>
<addaction name="actionCamera_from_directory_of_images"/>
<addaction name="actionCamera_from_video_file"/>
<addaction name="actionCamera_from_TCP_IP"/>
<addaction name="separator"/>
<addaction name="actionStart_camera"/>
<addaction name="actionPause_camera"/>
@@ -346,7 +347,7 @@
<x>0</x>
<y>0</y>
<width>198</width>
<height>559</height>
<height>583</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_objects">
@@ -764,6 +765,14 @@
<string>Load settings...</string>
</property>
</action>
<action name="actionCamera_from_TCP_IP">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Camera from TCP/IP...</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>