fix various bugs
add commandline parser for various options allow cameras to be operated in serial fashion allow disabeling of quirks allow changing of Photonfocus quirk timeings
This commit is contained in:
@ -6,7 +6,8 @@
|
||||
#include <unistd.h>
|
||||
#include <QTimer>
|
||||
|
||||
Cameras::Cameras(uvosled* led): led_(led)
|
||||
Cameras::Cameras(uvosled* led, bool quirks, bool serial):
|
||||
led_(led), quirks_(quirks), serial_(serial)
|
||||
{
|
||||
ledTimer.setSingleShot(true);
|
||||
cameraFailureTimer.setSingleShot(true);
|
||||
@ -82,7 +83,7 @@ bool Cameras::addCamera(const cam::Camera::Description& desc)
|
||||
|
||||
cameras_.back()->cam()->setExposureTime(exposrueTime_);
|
||||
|
||||
if(desc.getVendor().find("Photonfocus") != std::string::npos)
|
||||
if(quirks_ && desc.getVendor().find("Photonfocus") != std::string::npos)
|
||||
{
|
||||
qDebug()<<"Mitiagting broken PhotonFocus single shot mode";
|
||||
std::shared_ptr<Camera> camera = cameras_.back();
|
||||
@ -107,7 +108,13 @@ bool Cameras::addCamera(const cam::Camera::Description& desc)
|
||||
camera->cam()->setAcquisitionMode(cam::Camera::MODE_FREE);
|
||||
camera->cam()->setFrameRate(10);
|
||||
camera->cam()->startAcquisition();
|
||||
QTimer::singleShot(5000, [camera, this](){finishAddCamera(camera);});
|
||||
if(!serial_)
|
||||
QTimer::singleShot(quirkTime, this, [this, camera](){finishAddCamera(camera);});
|
||||
else
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(static_cast<long>(quirkTime*1000)));
|
||||
finishAddCamera(camera);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -147,10 +154,23 @@ void Cameras::lightOff()
|
||||
|
||||
void Cameras::trigger()
|
||||
{
|
||||
lightFor(lighting_, exposrueTime_*1.5);
|
||||
|
||||
for(auto& camera : cameras_)
|
||||
camera->cam()->trigger();
|
||||
if(serial_)
|
||||
{
|
||||
if(captureingCamera == 0)
|
||||
lightFor(lighting_, exposrueTime_*1.5*cameras_.size());
|
||||
cameras_[captureingCamera]->cam()->trigger();
|
||||
++captureingCamera;
|
||||
if(captureingCamera < cameras_.size())
|
||||
QTimer::singleShot(exposrueTime_*1000, this, &Cameras::trigger);
|
||||
else
|
||||
captureingCamera = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
lightFor(lighting_, exposrueTime_*1.5);
|
||||
for(auto& camera : cameras_)
|
||||
camera->cam()->trigger();
|
||||
}
|
||||
}
|
||||
|
||||
bool Cameras::start()
|
||||
@ -242,7 +262,12 @@ void Cameras::imageRecived(Camera::Image img)
|
||||
qDebug()<<"Recived"<<images_.size()<<"of"<<cameras_.size()<<"images";
|
||||
|
||||
if(images_.size() == 1)
|
||||
cameraFailureTimer.start(exposrueTime_*1000+1000);
|
||||
{
|
||||
if(!serial_)
|
||||
cameraFailureTimer.start(exposrueTime_*1000+1000);
|
||||
else
|
||||
cameraFailureTimer.start(exposrueTime_*1000*(cameras_.size()+1)+2000);
|
||||
}
|
||||
|
||||
if(images_.size() == cameras_.size())
|
||||
{
|
||||
|
@ -30,8 +30,11 @@ private:
|
||||
LightingSetup lighting_;
|
||||
std::vector<std::shared_ptr<Camera>> cameras_;
|
||||
std::vector<Camera::Image> images_;
|
||||
size_t captureingCamera = 0;
|
||||
QTimer ledTimer;
|
||||
QTimer cameraFailureTimer;
|
||||
bool quirks_;
|
||||
bool serial_;
|
||||
|
||||
bool lightFor(const LightingSetup& lighting, double time);
|
||||
|
||||
@ -57,7 +60,7 @@ public slots:
|
||||
void reloadCameras();
|
||||
|
||||
public:
|
||||
Cameras(uvosled* led = nullptr);
|
||||
Cameras(uvosled* led = nullptr, bool quirks = true, bool serial = false);
|
||||
~Cameras();
|
||||
bool setCameras(const std::vector<cam::Camera::Description>& descriptions);
|
||||
bool addCamera(const cam::Camera::Description& desc);
|
||||
@ -70,6 +73,8 @@ public:
|
||||
void load(QSettings& settings);
|
||||
void store(QSettings& settings);
|
||||
void disable(bool disable);
|
||||
|
||||
inline static float quirkTime = 3;
|
||||
};
|
||||
|
||||
#endif // CAMERAS_H
|
||||
|
@ -8,12 +8,41 @@
|
||||
#include <algorithm>
|
||||
#include <opencv2/highgui.hpp>
|
||||
|
||||
ImagePipeline::ImagePipeline(Cameras* cameras, QObject *parent): QObject(parent), cameras_(cameras)
|
||||
ImagePipeline::ImagePipeline(Cameras* cameras, bool simpleStichingAlg, QObject *parent):
|
||||
QObject(parent), cameras_(cameras), simpleStichingAlg_(simpleStichingAlg)
|
||||
{
|
||||
connect(cameras_, &Cameras::newImages, this, &ImagePipeline::apply);
|
||||
}
|
||||
|
||||
cv::Mat ImagePipeline::process(const Profile profile, std::vector<Camera::Image> images)
|
||||
void ImagePipeline::applyDarkMap(cv::Mat& image, const cv::Mat& darkmap)
|
||||
{
|
||||
cv::Mat localDarkMap;
|
||||
if(image.size() != darkmap.size())
|
||||
{
|
||||
qWarning()<<"image and darkmap not of the same size"<<image.size().height<<'x'<<image.size().width<<darkmap.size().height<<'x'<<darkmap.size().width;
|
||||
return;
|
||||
}
|
||||
else if(image.channels() != darkmap.channels())
|
||||
{
|
||||
qWarning()<<"image and darkmap do not have the same number of channels";
|
||||
if(image.channels() == 1 && darkmap.channels() == 3)
|
||||
cv::cvtColor(darkmap, localDarkMap, cv::COLOR_BGR2GRAY);
|
||||
else if(image.channels() == 3 && darkmap.channels() == 1)
|
||||
cv::cvtColor(darkmap, localDarkMap, cv::COLOR_GRAY2BGR);
|
||||
else
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
localDarkMap = darkmap;
|
||||
}
|
||||
cv::Mat subtracted;
|
||||
image.copyTo(subtracted);
|
||||
subtracted = image - localDarkMap;
|
||||
image = subtracted;
|
||||
}
|
||||
|
||||
cv::Mat ImagePipeline::process(const Profile profile, std::vector<Camera::Image> images, bool simpleStichingAlg)
|
||||
{
|
||||
qDebug()<<__func__<<"got"<<images.size()<<"images";
|
||||
std::vector<RemapedImage> remapedImages;
|
||||
@ -32,7 +61,7 @@ cv::Mat ImagePipeline::process(const Profile profile, std::vector<Camera::Image>
|
||||
img.origin.y = 0;
|
||||
image.mat.copyTo(img.image);
|
||||
if(profile.cameras[0].darkmap.data)
|
||||
img.image = img.image - profile.cameras[0].darkmap;
|
||||
applyDarkMap(img.image, profile.cameras[0].darkmap);
|
||||
remapedImages.push_back(img);
|
||||
break;
|
||||
}
|
||||
@ -42,7 +71,7 @@ cv::Mat ImagePipeline::process(const Profile profile, std::vector<Camera::Image>
|
||||
{
|
||||
for(Camera::Image& image : images)
|
||||
{
|
||||
qDebug()<<__FUNCTION__<<"image cam id"<<image.cameraId;
|
||||
qDebug()<<__func__<<"image cam id"<<image.cameraId;
|
||||
bool matched = false;
|
||||
for(auto& camera : profile.cameras)
|
||||
{
|
||||
@ -51,13 +80,7 @@ cv::Mat ImagePipeline::process(const Profile profile, std::vector<Camera::Image>
|
||||
if(!camera.remapMap.xMat.data || !camera.remapMap.yMat.data)
|
||||
return cv::Mat();
|
||||
if(camera.darkmap.data)
|
||||
{
|
||||
cv::Mat subtracted;
|
||||
image.mat.copyTo(subtracted);
|
||||
qDebug()<<"Camera"<<camera.id<<"has darkmap"<<image.mat.type()<<camera.darkmap.type();
|
||||
subtracted = image.mat - camera.darkmap;
|
||||
image.mat = subtracted;
|
||||
}
|
||||
applyDarkMap(image.mat, camera.darkmap);
|
||||
RemapedImage remaped = applyRemap(image.mat, camera.remapMap);
|
||||
qDebug()<<"Camera"<<camera.id<<"image remaped to"<<remaped.image.data<<remaped.image.rows<<remaped.image.cols
|
||||
<<"at"<<remaped.origin.x<<'x'<<remaped.origin.y;
|
||||
@ -81,7 +104,11 @@ cv::Mat ImagePipeline::process(const Profile profile, std::vector<Camera::Image>
|
||||
if(remapedImages.size() > 0)
|
||||
{
|
||||
std::sort(remapedImages.begin(), remapedImages.end(), [](const RemapedImage& imgA, const RemapedImage& imgB) -> bool {return imgA.origin.x < imgB.origin.x;});
|
||||
cv::Mat output = stich(remapedImages);
|
||||
cv::Mat output;
|
||||
if(simpleStichingAlg)
|
||||
output = simpleStich(remapedImages);
|
||||
else
|
||||
output = stich(remapedImages, true);
|
||||
|
||||
if(output.depth() != CV_8U)
|
||||
output.convertTo(output, CV_8U);
|
||||
@ -125,7 +152,7 @@ void ImagePipeline::apply(std::vector<Camera::Image> images)
|
||||
connect(futureImageWatchers_.back(), &QFutureWatcher<cv::Mat>::finished, this, &ImagePipeline::imageFinished);
|
||||
|
||||
statusMsg("Processing");
|
||||
QFuture<cv::Mat> futureImage = QtConcurrent::run(&ImagePipeline::process, profile_, images);
|
||||
QFuture<cv::Mat> futureImage = QtConcurrent::run(&ImagePipeline::process, profile_, images, simpleStichingAlg_);
|
||||
futureImageWatchers_.back()->setFuture(futureImage);
|
||||
}
|
||||
}
|
||||
@ -141,7 +168,7 @@ void ImagePipeline::setProfile(const Profile& profile)
|
||||
{
|
||||
qDebug()<<setup.id;
|
||||
//TODO: dehardcode this
|
||||
setup.remapMap.outputCellSize=150;
|
||||
setup.remapMap.outputCellSize=200;
|
||||
}
|
||||
invalid_ = false;
|
||||
if(!profile_.camerasSufficant(cameras_->getCameras()))
|
||||
|
@ -19,8 +19,10 @@ private:
|
||||
Profile profile_;
|
||||
bool invalid_ = true;
|
||||
std::vector<QFutureWatcher<cv::Mat>*> futureImageWatchers_;
|
||||
bool simpleStichingAlg_;
|
||||
|
||||
static cv::Mat process(const Profile profile, std::vector<Camera::Image> images);
|
||||
static cv::Mat process(const Profile profile, std::vector<Camera::Image> images, bool simpleStich);
|
||||
static void applyDarkMap(cv::Mat& image, const cv::Mat &darkmap);
|
||||
|
||||
private slots:
|
||||
|
||||
@ -36,7 +38,7 @@ public slots:
|
||||
void setProfile(const Profile& profile);
|
||||
|
||||
public:
|
||||
ImagePipeline(Cameras* cameras, QObject* parent = nullptr);
|
||||
ImagePipeline(Cameras* cameras, bool simpleStichingAlg = false, QObject* parent = nullptr);
|
||||
};
|
||||
|
||||
#endif // IMAGEPIPELINE_H
|
||||
|
31
src/main.cpp
31
src/main.cpp
@ -10,6 +10,7 @@
|
||||
#include <opencv2/core/mat.hpp>
|
||||
#include <unistd.h>
|
||||
#include <uvosunwrap/log.h>
|
||||
#include <QCommandLineParser>
|
||||
|
||||
#include "cameras.h"
|
||||
#include "./ui/cameradialog.h"
|
||||
@ -66,9 +67,25 @@ int main(int argc, char *argv[])
|
||||
QApplication a(argc, argv);
|
||||
QCoreApplication::setOrganizationName("UVOS");
|
||||
QCoreApplication::setOrganizationDomain("uvos.xyz");
|
||||
QCoreApplication::setApplicationName("LubircantThiknessMapperUi");
|
||||
QCoreApplication::setApplicationName("MAClient");
|
||||
QCoreApplication::setApplicationVersion("0.1");
|
||||
|
||||
//parse comand line
|
||||
QCommandLineParser parser;
|
||||
parser.addHelpOption();
|
||||
parser.addVersionOption();
|
||||
QCommandLineOption noQuirkOption(QStringList() << "q" << "no-quirk", QCoreApplication::translate("main", "Do not enable camera specific quirks"));
|
||||
parser.addOption(noQuirkOption);
|
||||
QCommandLineOption serialOption(QStringList() << "s" << "serial", QCoreApplication::translate("main", "Take images in sequence instead of all at once"));
|
||||
parser.addOption(serialOption);
|
||||
QCommandLineOption simpleStichOption(QStringList() << "x" << "simple-stich", QCoreApplication::translate("main", "use simple sticher"));
|
||||
parser.addOption(simpleStichOption);
|
||||
QCommandLineOption quirkDurationOption(QStringList() << "d" << "quirk-duration", QCoreApplication::translate("main", "PhotonFocus quirk duration time"), QCoreApplication::translate("main", "time"));
|
||||
parser.addOption(quirkDurationOption);
|
||||
QCommandLineOption cameraBootDurationOption(QStringList() << "d" << "quirk-duration", QCoreApplication::translate("main", "Camera boot time"), QCoreApplication::translate("main", "time"));
|
||||
parser.addOption(cameraBootDurationOption);
|
||||
parser.process(a);
|
||||
|
||||
QSplashScreen splash(QPixmap(":/images/splash.png"));
|
||||
splash.show();
|
||||
|
||||
@ -88,12 +105,18 @@ int main(int argc, char *argv[])
|
||||
uvosled_poweron(&led);
|
||||
// Give cameras some time to power on
|
||||
// TODO: figure out how to do this better
|
||||
sleep(10);
|
||||
if(parser.isSet(cameraBootDurationOption))
|
||||
sleep(parser.value(cameraBootDurationOption).toDouble());
|
||||
else
|
||||
sleep(20);
|
||||
}
|
||||
|
||||
Cameras cameras(uvosledRet < 0 ? nullptr : &led);
|
||||
Cameras cameras(uvosledRet < 0 ? nullptr : &led, !parser.isSet(noQuirkOption), parser.isSet(serialOption));
|
||||
cameras.setFree(false);
|
||||
ImagePipeline pipe(&cameras);
|
||||
ImagePipeline pipe(&cameras, parser.isSet(simpleStichOption));
|
||||
|
||||
if(parser.isSet(quirkDurationOption))
|
||||
cameras.quirkTime = parser.value(quirkDurationOption).toDouble();
|
||||
|
||||
MainWindow w;
|
||||
|
||||
|
@ -9,11 +9,12 @@
|
||||
#include <opencv2/imgproc.hpp>
|
||||
#include <QDebug>
|
||||
|
||||
ConfigureCameraDialog::ConfigureCameraDialog(const CameraSetup& setup, std::shared_ptr<Camera> camera, double exposureTime, QWidget *parent):
|
||||
ConfigureCameraDialog::ConfigureCameraDialog(const CameraSetup& setup, std::shared_ptr<Camera> camera, double exposureTime, bool nodistort, QWidget *parent):
|
||||
QDialog(parent),
|
||||
setup_(setup),
|
||||
camera_(camera),
|
||||
profileExposure_(exposureTime),
|
||||
nodistort_(nodistort),
|
||||
ui(new Ui::ConfigureCameraDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
@ -21,6 +22,14 @@ ConfigureCameraDialog::ConfigureCameraDialog(const CameraSetup& setup, std::shar
|
||||
ui->doubleSpinBox->setValue(profileExposure_);
|
||||
setExposure(profileExposure_);
|
||||
|
||||
if(nodistort)
|
||||
{
|
||||
ui->ledRemap->setHidden(true);
|
||||
ui->label_2->setHidden(true);
|
||||
ui->pushButtonRemapClear->setHidden(true);
|
||||
ui->pushButtonRemapCreate->setHidden(true);
|
||||
}
|
||||
|
||||
switch(setup.bayerMode)
|
||||
{
|
||||
case cam::Camera::BAYER_BLUE:
|
||||
@ -215,5 +224,5 @@ bool ConfigureCameraDialog::checkConfig()
|
||||
ui->ledDark->setLit(darkMapOK);
|
||||
ui->ledRemap->setLit(remapMapOk);
|
||||
|
||||
return remapMapOk;
|
||||
return remapMapOk || nodistort_;
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ class ConfigureCameraDialog : public QDialog
|
||||
int mode_ = MODE_IDLE;
|
||||
cv::Mat fgImage;
|
||||
double profileExposure_;
|
||||
bool nodistort_;
|
||||
|
||||
private:
|
||||
bool checkConfig();
|
||||
@ -40,7 +41,7 @@ public slots:
|
||||
void accept() override;
|
||||
|
||||
public:
|
||||
explicit ConfigureCameraDialog(const CameraSetup& setup, const std::shared_ptr<Camera> camera, double exposureTime = 1.0/60, QWidget *parent = nullptr);
|
||||
explicit ConfigureCameraDialog(const CameraSetup& setup, const std::shared_ptr<Camera> camera, double exposureTime = 1.0/60, bool nodistort = false, QWidget *parent = nullptr);
|
||||
~ConfigureCameraDialog();
|
||||
CameraSetup getCameraSetup(){return setup_;}
|
||||
|
||||
|
@ -48,7 +48,7 @@ EditProfileDialog::EditProfileDialog(Cameras* cameras, const Profile profile, QW
|
||||
ui->ledLightmap->setLit(profile_.lightmap.data);
|
||||
|
||||
connect(ui->doubleSpinBoxBrightness, QOverload<double>::of(&QDoubleSpinBox::valueChanged), [this](double in){profile_.lighting.brightness = in/100.0;});
|
||||
connect(ui->doubleSpinBoxExposure, QOverload<double>::of(&QDoubleSpinBox::valueChanged), [this](double in){profile_.exposureTime = in; invalidateCameras();});
|
||||
connect(ui->doubleSpinBoxExposure, QOverload<double>::of(&QDoubleSpinBox::valueChanged), [this](double in){profile_.exposureTime = in;});
|
||||
connect(ui->lineEditName, &QLineEdit::textChanged, [this](QString in){profile_.setName(in);});
|
||||
connect(ui->checkBoxCh1, &QCheckBox::clicked, this, &EditProfileDialog::setMask);
|
||||
connect(ui->checkBoxCh2, &QCheckBox::clicked, this, &EditProfileDialog::setMask);
|
||||
@ -168,7 +168,7 @@ void EditProfileDialog::configureCamera()
|
||||
std::shared_ptr<Camera> camera = cameras_->getCamera(profile_.cameras[i].id);
|
||||
if(camera)
|
||||
{
|
||||
ConfigureCameraDialog diag(profile_.cameras[i], camera, profile_.exposureTime, this);
|
||||
ConfigureCameraDialog diag(profile_.cameras[i], camera, profile_.exposureTime, profile_.nodistort, this);
|
||||
diag.show();
|
||||
int ret = diag.exec();
|
||||
if(ret == QDialog::Accepted)
|
||||
@ -182,8 +182,10 @@ void EditProfileDialog::configureCamera()
|
||||
|
||||
void EditProfileDialog::accept()
|
||||
{
|
||||
if(!setConfigured() || profile_.getName() == "Unamed")
|
||||
if(!setConfigured())
|
||||
QMessageBox::information(this, "Unfinished", "Can not accept with unconfigured cameras");
|
||||
else if(profile_.getName().isEmpty() || profile_.getName() == "Unamed")
|
||||
QMessageBox::information(this, "Unfinished", "A profile name is required");
|
||||
else
|
||||
QDialog::accept();
|
||||
}
|
||||
|
@ -26,7 +26,10 @@
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineEditName">
|
||||
<property name="text">
|
||||
<string>Unamed</string>
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string notr="true">Unamed</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -151,6 +151,7 @@ QString MainWindow::getProfileName()
|
||||
|
||||
void MainWindow::refreshProfiles()
|
||||
{
|
||||
QString tmp = ui->comboBox->currentText();
|
||||
ui->comboBox->clear();
|
||||
QList<QString> profiles = Profile::avaiableProfiles();
|
||||
for(const QString& string : profiles)
|
||||
|
Reference in New Issue
Block a user