Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion PythonQt/PythonQt
Submodule PythonQt updated 1 files
+2 −1 appveyor.yml
3 changes: 1 addition & 2 deletions appveyor.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
image: Visual Studio 2019

clone_folder: c:\trik-runtime

skip_commits:
Expand Down Expand Up @@ -27,6 +25,7 @@ environment:
QTDIR: C:\Qt\5.14\mingw73_32
PYTHON_PATH: C:\Python38
CONFIGURATION: release
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
- MINGW: C:\Qt\Tools\mingw730_32
QTDIR: C:\Qt\5.12\mingw73_32
PYTHON_PATH: C:\Python37
Expand Down
2 changes: 1 addition & 1 deletion deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ else
echo "Usage: deploy.sh <robot ip>"
exit 1
fi

#asdf
ssh root@"$ip" " sh -c 'chmod -x /etc/trik/trikGui.sh && killall trikGui'"
rsync -avz -e ssh . root@$ip:/home/root/trik
ssh root@"$ip" "sh -c 'chmod +x /etc/trik/trikGui.sh && kill -hup 1'"
2 changes: 1 addition & 1 deletion translations/fr/trikGui_fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
<context>
<name>trikGui::CameraWidget</name>
<message>
<location filename="../../trikGui/cameraWidget.cpp" line="+28"/>
<location filename="../../trikGui/cameraWidget.cpp" line="+30"/>
<source>Camera</source>
<translation type="unfinished"></translation>
</message>
Expand Down
2 changes: 1 addition & 1 deletion translations/ru/trikGui_ru.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
<context>
<name>trikGui::CameraWidget</name>
<message>
<location filename="../../trikGui/cameraWidget.cpp" line="+28"/>
<location filename="../../trikGui/cameraWidget.cpp" line="+30"/>
<source>Camera</source>
<translation>Камера</translation>
</message>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,18 @@

#include <QImage>

#include "declSpec.h"

namespace trikControl {

/// The class that makes utility code reusable.
class Utilities
class TRIKCONTROL_EXPORT Utilities
{
public:
/// Creates image for show method from data according to format. Image is scaled to fill the screen.
static QImage imageFromBytes(const QVector<int32_t> &array, int width, int height, const QString &format);

/// Reworks data from brick.getStillImage() to better getPhoto()
static QVector<int32_t> rescalePhoto(const QVector<uchar> &data);
};
}
59 changes: 55 additions & 4 deletions trikControl/src/utilities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@

#include "QsLog.h"

QImage Utilities::imageFromBytes(const QVector<int32_t> &array, int width, int height, const QString &format){
using namespace trikControl;

QImage Utilities::imageFromBytes(const QVector<int32_t> &array, int width, int height, const QString &format){
// QImage requires 32-bit aligned scan lines
// Helper function to convert data
uchar *formattedData = nullptr;
auto copyAligned = [&](int perLine){
if (perLine * height > array.size()) {
if (width * height > array.size()) {
QLOG_WARN() << "imageFromBytes: not enough data";
return;
}
Expand All @@ -36,8 +38,10 @@ QImage Utilities::imageFromBytes(const QVector<int32_t> &array, int width, int h
auto fmt = QImage::Format_Invalid;

if (!format.compare("rgb32", Qt::CaseInsensitive)) {
fmt = QImage::Format_RGB32;
copyAligned(4 * width);
if (width * height <= array.size()) {
auto code = static_cast<const uchar *>(static_cast<const void *>(array.data()));
formattedData = std::copy(code, code + width * height , formattedData);
}
} else if (!format.compare("rgb888", Qt::CaseInsensitive)) {
fmt = QImage::Format_RGB888;
copyAligned(3 * width);
Expand All @@ -55,3 +59,50 @@ QImage Utilities::imageFromBytes(const QVector<int32_t> &array, int width, int h
return QImage(formattedData, width, height, fmt, cleanUp, formattedData);
}
}

static inline int32_t getMedian(uint8_t &a, uint8_t &b, uint8_t &c, uint8_t &d)
{
if (a > b)
std::swap(a, b);
if (c > d)
std::swap(c, d);
if (a > c)
std::swap(a, c);
if (b > d)
std::swap(b, d);
return (static_cast<int32_t>(b) + c) >> 1;
}

QVector<int32_t> Utilities::rescalePhoto(const QVector<uchar> &data)
{
QVector<int32_t> result;
result.reserve(data.size() / 3); //Repack RGB88 from 3 x uint8_t into int32_t
constexpr auto IMAGE_WIDTH = 320;
constexpr auto IMAGE_HEIGHT = 240;
if (data.size() >= IMAGE_WIDTH * IMAGE_HEIGHT * 3) {
for(int row = 0; row < IMAGE_HEIGHT; row += 2) {
for(int col = 0; col < IMAGE_WIDTH; col += 2) {
auto row1 = &data[(row * IMAGE_WIDTH + col) * 3];
auto row2 = row1 + IMAGE_WIDTH*3;
auto r1 = row1[0];
auto g1 = row1[1];
auto b1 = row1[2];
auto r2 = row1[3];
auto g2 = row1[4];
auto b2 = row1[5];
auto r3 = row2[0];
auto g3 = row2[1];
auto b3 = row2[2];
auto r4 = row2[3];
auto g4 = row2[4];
auto b4 = row2[5];

result.push_back((getMedian(r1, r2, r3, r4) << 16)
| (getMedian(g1, g2, g3, g4) << 8)
| getMedian(b1, b2, b3, b4));
}
}
}

return result;
}
4 changes: 2 additions & 2 deletions trikControl/trikControl.pro
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ PUBLIC_HEADERS += \
$$PWD/include/trikControl/vectorSensorInterface.h \
$$PWD/include/trikControl/gyroSensorInterface.h \
$$PWD/include/trikControl/markerInterface.h \
$$PWD/include/trikControl/i2cDeviceInterface.h
$$PWD/include/trikControl/i2cDeviceInterface.h \
$$PWD/include/trikControl/utilities.h
# $$PWD/include/trikControl/headingSensorInterface.h \

HEADERS += \
Expand Down Expand Up @@ -106,7 +107,6 @@ HEADERS += \
$$PWD/src/imitationCameraImplementation.h \
$$PWD/src/i2cDevice.h \
$$PWD/src/i2cCommunicator.h \
$$PWD/src/utilities.h
# $$PWD/src/headingSensor.h \

SOURCES += \
Expand Down
12 changes: 7 additions & 5 deletions trikGui/cameraWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
#include <QtGui/QKeyEvent>

#include "trikControl/brickInterface.h"
#include "trikControl/utilities.h"

#include "trikKernel/paths.h"
#include "QsLog.h"

Expand Down Expand Up @@ -63,12 +65,11 @@ void CameraWidget::doPhoto()
return;
}

auto const & photo = mBrick.getStillImage();

if (!photo.isEmpty()) {
QImage image(photo.data(), 320, 240, QImage::Format_RGB888);
mPixmap.setPixmap(QPixmap::fromImage(image));
auto const photo = trikControl::Utilities::rescalePhoto(mBrick.getStillImage());
// imageFromBytes allocates memory and delete it when it is necessery
auto image = trikControl::Utilities::imageFromBytes(photo, 160, 120, "rgb32");

if (!image.isNull()) {
QDir dir(trikKernel::Paths::imagesPath());

if (!dir.exists() && !dir.mkpath(trikKernel::Paths::imagesPath())) {
Expand All @@ -79,6 +80,7 @@ void CameraWidget::doPhoto()
QLOG_ERROR() << "Failed to save captured image" << name;
}
}
mPixmap.setPixmap(QPixmap::fromImage(std::move(image)));
} else {
mPixmap.setText(tr("Camera is not available"));
}
Expand Down
6 changes: 4 additions & 2 deletions trikScriptRunner/src/pythonEngineWorker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -264,8 +264,10 @@ void PythonEngineWorker::setWorkingDirectory(const QDir &workingDir)
void PythonEngineWorker::run(const QString &script, const QFileInfo &scriptFile)
{
QMutexLocker locker(&mScriptStateMutex);
mState = starting;
QMetaObject::invokeMethod(this, [this, script, scriptFile](){this->doRun(script, scriptFile);});
if (mState == ready) {
mState = starting;
QMetaObject::invokeMethod(this, [this, script, scriptFile](){this->doRun(script, scriptFile);});
}
}

void PythonEngineWorker::doRun(const QString &script, const QFileInfo &scriptFile)
Expand Down
2 changes: 1 addition & 1 deletion trikScriptRunner/src/scriptEngineWorker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ QScriptEngine * ScriptEngineWorker::createScriptEngine(bool supportThreads)

Scriptable<QTimer>::registerMetatype(engine);
qScriptRegisterMetaType(engine, &timeValToScriptValue, &timeValFromScriptValue);
qScriptRegisterSequenceMetaType<QVector<int>>(engine);
qScriptRegisterSequenceMetaType<QVector<int32_t>>(engine);
qScriptRegisterSequenceMetaType<QStringList>(engine);
qScriptRegisterSequenceMetaType<QVector<uint8_t>>(engine);

Expand Down
51 changes: 4 additions & 47 deletions trikScriptRunner/src/scriptExecutionControl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
#include <QRandomGenerator>
#include <QsLog.h>

#include "utilities.h"

using namespace trikScriptRunner;

ScriptExecutionControl::ScriptExecutionControl(trikControl::BrickInterface &brick): mBrick(brick) {
Expand All @@ -39,7 +41,7 @@ void ScriptExecutionControl::reset()
mInEventDrivenMode = false;
emit stopWaiting();
for (auto &&timer : mTimers) {
QMetaObject::invokeMethod(timer, "stop", Qt::QueuedConnection);
QMetaObject::invokeMethod(timer, &QTimer::stop, Qt::QueuedConnection);
timer->deleteLater();
}

Expand Down Expand Up @@ -144,52 +146,7 @@ void ScriptExecutionControl::removeFile(const QString &file)
out.remove();
}

static inline int32_t getMedian(uint8_t &a, uint8_t &b, uint8_t &c, uint8_t &d)
{
if (a > b)
std::swap(a, b);
if (c > d)
std::swap(c, d);
if (a > c)
std::swap(a, c);
if (b > d)
std::swap(b, d);
return (static_cast<int32_t>(b) + c) >> 1;
}

QVector<int32_t> ScriptExecutionControl::getPhoto()
{
QLOG_INFO() << "Calling getStillImage()";
auto data = mBrick.getStillImage();
QVector<int32_t> result;
result.reserve(data.size() / 3); //Repack RGB88 from 3 x uint8_t into int32_t
constexpr auto IMAGE_WIDTH = 320;
constexpr auto IMAGE_HEIGHT = 240;
if (data.size() >= IMAGE_WIDTH * IMAGE_HEIGHT * 3) {
for(int row = 0; row < IMAGE_HEIGHT; row += 2) {
for(int col = 0; col < IMAGE_WIDTH; col+=2) {
auto row1 = &data[(row*IMAGE_WIDTH+col)*3];
auto row2 = row1 + IMAGE_WIDTH*3;
auto r1 = row1[0];
auto g1 = row1[1];
auto b1 = row1[2];
auto r2 = row1[3];
auto g2 = row1[4];
auto b2 = row1[5];
auto r3 = row2[0];
auto g3 = row2[1];
auto b3 = row2[2];
auto r4 = row2[3];
auto g4 = row2[4];
auto b4 = row2[5];

result.push_back((getMedian(r1, r2, r3, r4) << 16)
| (getMedian(g1, g2, g3, g4) << 8)
| getMedian(b1, b2, b3, b4));
}
}
}

QLOG_INFO() << "Constructed result of getStillImage()";
return result;
return trikControl::Utilities::rescalePhoto(mBrick.getStillImage());
}