QChart with QAreaSeries with large data is very slow - performance

I am playing around with QCharts (using area chart example as a template).
I am drawing an area chart with 10000 points in each of the series, and am finding that it is very slow, 30s for the window to appear and resizing the window results in the process hanging, its unusable for this dataset . Any ideas what could be wrong here ? I have seen that disabling anti aliasing might help, however it doesn't.
I have the folllowing code
#include <QtWidgets/QApplication>
#include <QtWidgets/QMainWindow>
#include <QtCharts/QChartView>
#include <QtCharts/QLineSeries>
#include <QtCharts/QAreaSeries>
#include <QRandomGenerator>
#include <QDateTime>
#include <QtCharts/QHXYModelMapper>
#include <QTimer>
#include "boost/range/irange.hpp"
QT_CHARTS_USE_NAMESPACE
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
auto *upper = new QLineSeries;
auto *lower = new QLineSeries;
auto *generator = QRandomGenerator::global();
const auto maxSamples = 10000;
for(auto x : boost::irange(0, maxSamples))
{
lower->append(QPointF(x, 0));
upper->append(QPointF(x, generator->bounded(0, 100)));
}
auto *series = new QAreaSeries(upper, lower);
QChart *chart = new QChart();
chart->addSeries(series);
chart->createDefaultAxes();
chart->legend()->setVisible(false);
chart->axisY(series)->setRange(0, 100);
QChartView *chartView = new QChartView(chart);
//chartView->setRenderHint(QPainter::Antialiasing);
QMainWindow window;
window.setCentralWidget(chartView);
window.resize(800, 600);
window.show();
return a.exec();
}
Any ideas what could be the problem here?

We have bounced into this times ago and found that the implementation of append() in a QXYSeries was suboptimal and was consuming a lot of time with large datasets.
To improve the performance, we now use:
void QXYSeries::replace(QVector<QPointF> points)
with a local vector that we first allocate to the dataset size, and then fill with the actual data.
With large datasets, you may still have performance issues, depending on the type of series, due to the construction of the graphics items used to render the series.

Related

QPrinter + QPainter writes invalid PDF file

I am simply trying to draw a rectangle to a PDF file using QPrinter + QPainter:
#include <QtWidgets>
#include <QPrinter>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
QPrinter printer(QPrinter::HighResolution);
printer.setOutputFileName("/Users/jason/Desktop/example.pdf");
printer.setOutputFormat(QPrinter::PdfFormat);
QPainter painter;
painter.begin(&printer);
int width = painter.viewport().width();
int height = painter.viewport().height();
painter.setPen(Qt::black);
painter.drawRect(0.25*width, 0.25*height, 0.5*width, 0.5*height);
painter.end();
}
Using MacOS 10.15.4 and Qt 5.15.2 this results in a blank/invalid PDF file. The same code without the QPrinter.setOutputFormat and QPrinter.setOutputFileName correctly prints a rectangle on paper.
How can I using QPrinter/QPdfWriter + QPainter to draw to a PDF file?
I am a fool. I thought the PDF was blank, but it turns out if I zoom in really really far, I can see a faint grey line. Apparently the resolution of a PDF is much higher than that of my printer!
Using painter.setPen(QPen(QBrush(Qt::red), 100.0)) shows a clear rectangle as expected.

Get Pixmap out of Xlib

I've been trying to find a way of grabbing video directly from an X window and got pointed to Xlib and the compositing extension.
So far, I've been able to listen to change events and grab a Pixmap with this code:
#include <X11/Intrinsic.h>
#include <X11/extensions/Xcomposite.h>
#include <X11/extensions/Xdamage.h>
#include <iostream>
#include <fstream>
using namespace std;
int main(int argc, char ** argv) {
int br, base;
Window win = 0x3400003;
Display *dsp = XOpenDisplay(0);
XCompositeQueryExtension(dsp, &base, &br);
XDamageQueryExtension(dsp,&base, &br);
cout << base << endl;
Damage damage = XDamageCreate(dsp, win, XDamageReportRawRectangles);
XCompositeRedirectWindow(dsp, win, CompositeRedirectAutomatic);
XEvent ev;
while(true) {
XNextEvent(dsp, &ev);
if(ev.type == base + XDamageNotify) {
Pixmap pm = XCompositeNameWindowPixmap(dsp, win);
XWindowAttributes attr;
XGetWindowAttributes(dsp, win, &attr);
XWriteBitmapFile(dsp, "test.bmp", pm, attr.width, attr.height, -1, -1);
return 0;
}
}
XCompositeUnredirectWindow(dsp, win, CompositeRedirectAutomatic);
XDamageDestroy(dsp, damage);
return 0;
}
The problem here is that the resulting bmp (created by XWriteBitmapFile) is black&white horribleness. Disregarding the fact that I don't want to write the data to file anyway, I am apparently doing something wrong in reading it.
I would love to convert the Pixmap to either a framebuffer in opengl or a binary blob in ram.
Thanks in advance for any help you can give me on this.
Best regards.
"Bitmaps" in X world refer to two-colored images. I guess XWriteBitmapFile does internally GetImage request and transforms server pixmap to a bitmap. Note that file format is it's own 'X11 bitmap', not windows bitmap.
Use XGetImage function If you actually need image's binary blob.

Xcode, Instruments, Allocations, Command Line App, not registering free()

I have a very simple Command Line Tool in Xcode:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int main(int argc, const char * argv[])
{
void *p = calloc(32, 1);
assert(p);
free(p);
return 0;
}
When I run Instruments->Allocations it shows one living block. The free seems to be ignored.
In the olden days, I remember that you could actually still use the last free'ed block. So I tried this:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int main(int argc, const char * argv[])
{
void *p = calloc(32, 1);
assert(p);
free(p);
void *q = calloc(32, 1);
assert(q);
free(q);
return 0;
}
Now, Instruments->Allocations shows no living blocks. This seems correct.
Can anyone explain or reproduce the problem I am seeing in the first program?
I'm using Xcode 4.1.1
Thanks.
Let me rephrase the comments above.
Apple LLVM in Xcode 5 resolved the alloc / free behavior so that no blocks allocated now, thus the free() method runs as expected.

How can one share depth images between two processes?

I have 4 different depth cameras available to me: Kinect, Xtion, PMD nano, Softkinetic DepthSense.
I have the libraries that know how to read all of them: OpenNI, PMD drivers, Softkinetic drivers.
I would ideally like to make a simple grabber for each kind of camera and then just use it as a plugin into any other program i.e. get fast, non redundant access (i.e. not too many memory copies) to the data stream.
One of the problems is that in many cases I dont have the right library in 32 or 64 bit so I cant compile all grabbers in the same project.
What is the best way to achieve this?
I am a researcher so this idea isnt necessarily useful for production code but given this scenario my best solution has been to create a server process for each type of camera. Each server process knows how to load its own type of camera stream and then throws it into a shared memory space that other processes can read from.
It is obviously possible to use different kind of locking mechanisms but I have left the below code without any locks.
The server process will include the following:
#define BOOST_ALL_NO_LIB
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
using namespace std;
using namespace boost::interprocess;
struct sharedImage
{
enum { width = 320 };
enum { height = 240 };
enum { dataLength = width*height*sizeof(unsigned short) };
sharedImage(){}
interprocess_mutex mutex;
unsigned short data[dataLength];
};
shared_memory_object shm;
sharedImage * sIm;
mapped_region region;
int setupSharedMemory(){
// Clear the object if it exists
shared_memory_object::remove("ImageMem");
shm = shared_memory_object(create_only /*only create*/,"ImageMem" /*name*/,read_write/*read-write mode*/);
printf("Size:%i\n",sizeof(sharedImage));
//Set size
shm.truncate(sizeof(sharedImage));
//Map the whole shared memory in this process
region = mapped_region(shm, read_write);
//Get the address of the mapped region
void * addr = region.get_address();
//Construct the shared structure in the preallocated memory of shm
sIm = new (addr) sharedImage;
return 0;
}
int shutdownSharedMemory(){
shared_memory_object::remove("ImageMem");
return 0;
}
To start it up call setupSharedMemory() and to shut down call shutdownSharedMemory().
All the values are hard coded in this simple example but its easy to imagine making it more flexible.
Now lets assume that you are using SoftKinetic's DepthSense. So then you could write the following callback for the Depth node.
void onNewDepthSample(DepthNode node, DepthNode::NewSampleReceivedData data) {
//scoped_lock<interprocess_mutex> lock(sIm->mutex);
memcpy(sIm->data, data.depthMap, sIm->dataLength);
}
What this does is simply copies the latest depth map into the shared memory space.
You could also add a timestamp and a lock and anything else you need but this basic code works well enough for me so I will leave it as it is.
Now in some other process you can access the data in a very similar fashion.
The code below is what I use to get the live SoftKinetic DepthSense depth stream into Matlab for real time processing. This method has a huge advantage over trying to write my own mex wrapper specifically for SoftKinetic because I can use the same code for all the other cameras if I write servers for them.
#include <math.h>
#include <windows.h>
#include "mex.h"
#define BOOST_ALL_NO_LIB
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace boost::interprocess;
struct sharedImage
{
enum { width = 320 };
enum { height = 240 };
enum { dataLength = width*height*sizeof(short) };
sharedImage(): dirty(true){}
interprocess_mutex mutex;
uint8_t data[dataLength];
bool dirty;
};
void getFrame(unsigned short *D)
{
//Open the shared memory object.
shared_memory_object shm(open_only ,"ImageMem", read_write);
//Map the whole shared memory in this process
mapped_region region(shm ,read_write);
//Get the address of the mapped region
void * addr = region.get_address();
//Construct the shared structure in memory
sharedImage * sIm = static_cast<sharedImage*>(addr);
//scoped_lock<interprocess_mutex> lock(sIm->mutex);
memcpy((char*)D, (char*)sIm->data, sIm->dataLength);
}
void mexFunction(int nlhs, mxArray *plhs[ ], int nrhs, const mxArray *prhs[ ])
{
// Build outputs
mwSize dims[2] = {320, 240};
plhs[0] = mxCreateNumericArray(2, dims, mxUINT16_CLASS, mxREAL);
unsigned short *D = (unsigned short*)mxGetData(plhs[0]);
try
{
getFrame(D);
}
catch (interprocess_exception &ex)
{
mexPrintf("getFrame:%s\n", ex.what());
}
}
which on my computer I compile in Matlab with: mex getSKFrame.cpp -IC:\Development\boost_1_48_0
And then finally to use it in Matlab: D = getSKFrame()'; imagesc(D)

Resizing a cell's height and Witdth and loading an image in QTableWidget

I want to make a 8*8 table with square cells ( a chess board ). Now I have the code to make the table but don't know how to resize the cells to be square shaped.
I also want to put pictures of pieces into the cells. How should I do these?
here is the code i have:
#include <QtGui/QApplication>
#include "mainwindow.h"
#include <QHBoxLayout>
#include <QTableWidget>
class Table : public QWidget
{
public:
Table(QWidget *parent = 0);
};
Table::Table(QWidget *parent)
: QWidget(parent)
{
QHBoxLayout *hbox = new QHBoxLayout(this);
QTableWidget *table = new QTableWidget(8 , 8 , this);
hbox->addWidget(table);
setLayout(hbox);
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Table t;
t.show();
return a.exec();
}
EDIT:
If anyone can help me with loading an image as the background of cell too, it would be very appreciated!
I use this code and compiler does not generate an error but program fails to run. I think the problem is with the table->item(0,0). Should I initialize it first?
QString fileName = "1.bmp";
QPixmap pic (fileName);
QIcon icon (pic);
table->item(0,0)->setIcon(icon);
To make the cells square shaped do something like this:
// set the default size, here i've set it to 20px by 20x
table->horizontalHeader()->setDefaultSectionSize(20);
table->verticalHeader()->setDefaultSectionSize(20);
// set the resize mode to fixed, so the user cannot change the height/width
table->horizontalHeader()->setResizeMode(QHeaderView::Fixed);
table->verticalHeader()->setResizeMode(QHeaderView::Fixed);
Edit: To set the images, set the icon attribute on your QTableWidgetItems
after searching and searching and searching.... I finally got the answer. I should first make a QBrush object and set it as a background of a QtableWidgetItem and then use table->setItem !!!
QString fileName = "/1.bmp";
QPixmap pic (fileName);
QBrush brush(pic);
QTableWidgetItem* item = new QTableWidgetItem();
item->setBackground(brush);
table->setItem(0,0,item);

Resources