convert from IPLImage to QImage in Qt - qt

I would like to display image in qt window , so I used Qlabel->setpixmap
but how can I convert from IPLImage to QImage to display it in the label??
I found the follwing function to convert it but I did not know how to use it in call statement
QImage *IplImageToQImage(const IplImage * iplImage, uchar **data, double mini, double maxi)
{
uchar *qImageBuffer = NULL;
int width = iplImage->width;
int widthStep = iplImage->widthStep;
int height = iplImage->height;
switch (iplImage->depth)
{
case IPL_DEPTH_8U:
if (iplImage->nChannels == 1)
{
// OpenCV image is stored with one byte grey pixel. We convert it
// to an 8 bit depth QImage.
//
qImageBuffer = (uchar *) malloc(width*height*sizeof(uchar));
uchar *QImagePtr = qImageBuffer;
const uchar *iplImagePtr = (const uchar *) iplImage->imageData;
for (int y = 0; y < height; y++)
{
// Copy line by line
memcpy(QImagePtr, iplImagePtr, width);
QImagePtr += width;
iplImagePtr += widthStep;
}
}
else if (iplImage->nChannels == 3)
{
/* OpenCV image is stored with 3 byte color pixels (3 channels).
We convert it to a 32 bit depth QImage.
*/
qImageBuffer = (uchar *) malloc(width*height*4*sizeof(uchar));
uchar *QImagePtr = qImageBuffer;
const uchar *iplImagePtr = (const uchar *) iplImage->imageData;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
// We cannot help but copy manually.
QImagePtr[0] = iplImagePtr[0];
QImagePtr[1] = iplImagePtr[1];
QImagePtr[2] = iplImagePtr[2];
QImagePtr[3] = 0;
QImagePtr += 4;
iplImagePtr += 3;
}
iplImagePtr += widthStep-3*width;
}
}
else
{
qDebug("IplImageToQImage: image format is not supported : depth=8U and %d channels\n", iplImage->nChannels);
}
break;
case IPL_DEPTH_16U:
if (iplImage->nChannels == 1)
{
/* OpenCV image is stored with 2 bytes grey pixel. We convert it
to an 8 bit depth QImage.
*/
qImageBuffer = (uchar *) malloc(width*height*sizeof(uchar));
uchar *QImagePtr = qImageBuffer;
//const uint16_t *iplImagePtr = (const uint16_t *);
const unsigned int *iplImagePtr = (const unsigned int *)iplImage->imageData;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
// We take only the highest part of the 16 bit value. It is
//similar to dividing by 256.
*QImagePtr++ = ((*iplImagePtr++) >> 8);
}
iplImagePtr += widthStep/sizeof(unsigned int)-width;
}
}
else
{
qDebug("IplImageToQImage: image format is not supported : depth=16U and %d channels\n", iplImage->nChannels);
}
break;
case IPL_DEPTH_32F:
if (iplImage->nChannels == 1)
{
/* OpenCV image is stored with float (4 bytes) grey pixel. We
convert it to an 8 bit depth QImage.
*/
qImageBuffer = (uchar *) malloc(width*height*sizeof(uchar));
uchar *QImagePtr = qImageBuffer;
const float *iplImagePtr = (const float *) iplImage->imageData;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
uchar p;
float pf = 255 * ((*iplImagePtr++) - mini) / (maxi - mini);
if (pf < 0) p = 0;
else if (pf > 255) p = 255;
else p = (uchar) pf;
*QImagePtr++ = p;
}
iplImagePtr += widthStep/sizeof(float)-width;
}
}
else
{
qDebug("IplImageToQImage: image format is not supported : depth=32F and %d channels\n", iplImage->nChannels);
}
break;
case IPL_DEPTH_64F:
if (iplImage->nChannels == 1)
{
/* OpenCV image is stored with double (8 bytes) grey pixel. We
convert it to an 8 bit depth QImage.
*/
qImageBuffer = (uchar *) malloc(width*height*sizeof(uchar));
uchar *QImagePtr = qImageBuffer;
const double *iplImagePtr = (const double *) iplImage->imageData;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
uchar p;
double pf = 255 * ((*iplImagePtr++) - mini) / (maxi - mini);
if (pf < 0) p = 0;
else if (pf > 255) p = 255;
else p = (uchar) pf;
*QImagePtr++ = p;
}
}
}
else
{
qDebug("IplImageToQImage: image format is not supported : depth=64F and %d channels\n", iplImage->nChannels);
}
break;
default:
qDebug("IplImageToQImage: image format is not supported : depth=%d and %d channels\n", iplImage->depth, iplImage->nChannels);
}
QImage *qImage;
QVector<QRgb> vcolorTable;
if (iplImage->nChannels == 1)
{
// We should check who is going to destroy this allocation.
QRgb *colorTable = new QRgb[256];
for (int i = 0; i < 256; i++)
{
colorTable[i] = qRgb(i, i, i);
vcolorTable[i] = colorTable[i];
}
qImage = new QImage(qImageBuffer, width, height, QImage::Format_Indexed8);
qImage->setColorTable(vcolorTable);
}
else
{
qImage = new QImage(qImageBuffer, width, height, QImage::Format_RGB32);
}
*data = qImageBuffer;
return qImage;
}
The parameter was:
const IplImage * iplImage, uchar **data, double mini, double maxi
what are data,mini,max? how can I get it from my IPLImage to use it in call statement?
Thanks alot :)

Looks like data is not used by the code, and mini and maxi are used for converting floating point values that certain image formats use to integer values in the range 0-255.
I'd try using NULL for data. mini and maxi really depend on the image data, and I don't know what reasonable ranges are. But if your IplImage is not stored as floating point values then these values shouldn't make any difference.

You can simply create a QImage where the data is owned by something else (eg the IPLImage) using the QImage(data,widht,height,format) and data is the IPLImage data ptr as long as the format isthe samein both QImage and IPLImage (eg RGB888 = 8U_C3)

I have found some bugs in the code.... maybe there are still more bugs in it but for now it looks fine for me. QImage with Format_Index8 needs sometimes (depending on the image resolution....) 2 byte added on the right side (don t know why but it seems like to be like this).
Here is the new adapted code
QImage *IplImageToQImage(const IplImage * iplImage, uchar **data, double mini, double maxi)
{
uchar *qImageBuffer = NULL;
int width = iplImage->width;
int widthStep = iplImage->widthStep;
int height = iplImage->height;
QImage *qImage;
switch (iplImage->depth)
{
case IPL_DEPTH_8U:
if (iplImage->nChannels == 1)
{
// OpenCV image is stored with one byte grey pixel. We convert it
// to an 8 bit depth QImage.
qImage = new QImage(width,height,QImage::Format_Indexed8);
uchar *QImagePtr = qImage->scanLine(0);
qImageBuffer = qImage->scanLine(0);
const uchar *iplImagePtr = (const uchar *) iplImage->imageData;
for (int y = 0; y < height; y++)
{
// Copy line by line
QImagePtr = qImage->scanLine(y);
memcpy(QImagePtr, iplImagePtr, width);
iplImagePtr += widthStep;
}
/*
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
// We take only the highest part of the 16 bit value. It is
//similar to dividing by 256.
//*QImagePtr++ = ((*iplImagePtr++) >> 8);
*QImagePtr = *iplImagePtr;
QImagePtr++;
iplImagePtr++;
}
iplImagePtr += widthStep/sizeof(uchar)-width;
}*/
}
else if (iplImage->nChannels == 3)
{
/* OpenCV image is stored with 3 byte color pixels (3 channels).
We convert it to a 32 bit depth QImage.
*/
qImageBuffer = (uchar *) malloc(width*height*4*sizeof(uchar));
uchar *QImagePtr = qImageBuffer;
const uchar *iplImagePtr = (const uchar *) iplImage->imageData;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
// We cannot help but copy manually.
QImagePtr[0] = iplImagePtr[0];
QImagePtr[1] = iplImagePtr[1];
QImagePtr[2] = iplImagePtr[2];
QImagePtr[3] = 0;
QImagePtr += 4;
iplImagePtr += 3;
}
iplImagePtr += widthStep-3*width;
}
}
else
{
qDebug("IplImageToQImage: image format is not supported : depth=8U and %d channels\n", iplImage->nChannels);
}
break;
case IPL_DEPTH_16U:
if (iplImage->nChannels == 1)
{
/* OpenCV image is stored with 2 bytes grey pixel. We convert it
to an 8 bit depth QImage.
*/
qImage = new QImage(width,height,QImage::Format_Indexed8);
uchar *QImagePtr = qImage->scanLine(0);
qImageBuffer = qImage->scanLine(0);
//const uint16_t *iplImagePtr = (const uint16_t *);
const unsigned short *iplImagePtr = (const unsigned short *)iplImage->imageData;
for (int y = 0; y < height; y++)
{
QImagePtr = qImage->scanLine(y);
for (int x = 0; x < width; x++)
{
// We take only the highest part of the 16 bit value. It is
//similar to dividing by 256.
//*QImagePtr++ = ((*iplImagePtr++) >> 8);
//change here 16 bit could be everything !! set max min to your desire
*QImagePtr = 255*(((*iplImagePtr) - mini) / (maxi - mini));
QImagePtr++;
iplImagePtr++;
}
iplImagePtr += widthStep/sizeof(unsigned short)-width;
}
}
else
{
qDebug("IplImageToQImage: image format is not supported : depth=16U and %d channels\n", iplImage->nChannels);
}
break;
case IPL_DEPTH_32F:
if (iplImage->nChannels == 1)
{
/* OpenCV image is stored with float (4 bytes) grey pixel. We
convert it to an 8 bit depth QImage.
*/
qImage = new QImage(width,height,QImage::Format_Indexed8);
uchar *QImagePtr = qImage->scanLine(0);
qImageBuffer = qImage->scanLine(0);
const float *iplImagePtr = (const float *) iplImage->imageData;
for (int y = 0; y < height; y++)
{
QImagePtr = qImage->scanLine(y);
for (int x = 0; x < width; x++)
{
uchar p;
float pf = 255 * ((*iplImagePtr++) - mini) / (maxi - mini);
if (pf < 0) p = 0;
else if (pf > 255) p = 255;
else p = (uchar) pf;
*QImagePtr++ = p;
}
iplImagePtr += widthStep/sizeof(float)-width;
}
}
else
{
qDebug("IplImageToQImage: image format is not supported : depth=32F and %d channels\n", iplImage->nChannels);
}
break;
case IPL_DEPTH_64F:
if (iplImage->nChannels == 1)
{
/* OpenCV image is stored with double (8 bytes) grey pixel. We
convert it to an 8 bit depth QImage.
*/
qImage = new QImage(width,height,QImage::Format_Indexed8);
uchar *QImagePtr = qImage->scanLine(0);
qImageBuffer = qImage->scanLine(0);
const double *iplImagePtr = (const double *) iplImage->imageData;
for (int y = 0; y < height; y++)
{
QImagePtr = qImage->scanLine(y);
for (int x = 0; x < width; x++)
{
uchar p;
double pf = 255 * ((*iplImagePtr++) - mini) / (maxi - mini);
if (pf < 0) p = 0;
else if (pf > 255) p = 255;
else p = (uchar) pf;
*QImagePtr++ = p;
}
}
}
else
{
qDebug("IplImageToQImage: image format is not supported : depth=64F and %d channels\n", iplImage->nChannels);
}
break;
default:
qDebug("IplImageToQImage: image format is not supported : depth=%d and %d channels\n", iplImage->depth, iplImage->nChannels);
}
QVector<QRgb> vcolorTable;
if (iplImage->nChannels == 1)
{
// We should check who is going to destroy this allocation.
vcolorTable.resize(256);
for (int i = 0; i < 256; i++)
{
vcolorTable[i] = qRgb(i, i, i);
}
//Qt vector is difficult to use... start with std to qvector
//here I allocate QImage using qt constructor (Forma_Indexed8 adds sometimes 2 bytes on the right side !!! o.O not specified nowhere !!!)
//qImage = new QImage(tmpImg->scanLine(0), width, height, QImage::Format_Indexed8);
qImage->setColorTable(vcolorTable);
}
else
{
qImage = new QImage(qImageBuffer, width, height, QImage::Format_RGB32);
}
*data = qImageBuffer;
return qImage;
}
I don t know if 3 channels have also the same bug but I hope not

Related

Picking the dominant color in Qt

How can I get the dominant color of a QImage or QIcon in Qt5 ?
Does it need generating a histogram manually ?
And if yes , how ?
You can't get this data via Qt.
But I found for You this web page (http://robocraft.ru/blog/computervision/1063.html).
On this web page some guy wrote code for your question! But all description only on Russian language. I translated it for you.
He is using OpenCV lib.
//
// determination of the prevailing colors in the image
// via k-Means
//
#include <cv.h>
#include <highgui.h>
#include <stdlib.h>
#include <stdio.h>
#include <vector>
#include <algorithm>
// getting an image pixel (by type of image and coordinates)
#define CV_PIXEL(type,img,x,y) (((type*)((img)->imageData+(y)*(img)->widthStep))+(x)*(img)->nChannels)
const CvScalar BLACK = CV_RGB(0, 0, 0); // black
const CvScalar WHITE = CV_RGB(255, 255, 255); // white
const CvScalar RED = CV_RGB(255, 0, 0); // red
const CvScalar ORANGE = CV_RGB(255, 100, 0); // orange
const CvScalar YELLOW = CV_RGB(255, 255, 0); // yellow
const CvScalar GREEN = CV_RGB(0, 255, 0); // green
const CvScalar LIGHTBLUE = CV_RGB(60, 170, 255); // blue
const CvScalar BLUE = CV_RGB(0, 0, 255); // blue 2
const CvScalar VIOLET = CV_RGB(194, 0, 255); // Violet
const CvScalar GINGER = CV_RGB(215, 125, 49); // redhead
const CvScalar PINK = CV_RGB(255, 192, 203); // pink
const CvScalar LIGHTGREEN = CV_RGB(153, 255, 153); // light green
const CvScalar BROWN = CV_RGB(150, 75, 0); // brown
typedef unsigned char uchar;
typedef unsigned int uint;
typedef struct ColorCluster {
CvScalar color;
CvScalar new_color;
int count;
ColorCluster():count(0) {
}
} ColorCluster;
float rgb_euclidean(CvScalar p1, CvScalar p2)
{
float val = sqrtf( (p1.val[0]-p2.val[0])*(p1.val[0]-p2.val[0]) +
(p1.val[1]-p2.val[1])*(p1.val[1]-p2.val[1]) +
(p1.val[2]-p2.val[2])*(p1.val[2]-p2.val[2]) +
(p1.val[3]-p2.val[3])*(p1.val[3]-p2.val[3]));
return val;
}
// sorting flowers by quantity
bool colors_sort(std::pair< int, uint > a, std::pair< int, uint > b)
{
return (a.second > b.second);
}
int main(int argc, char* argv[])
{
// for save image
IplImage* image=0, *src=0, *dst=0, *dst2=0;
//
// loading image
//
char img_name[] = "Image0.jpg";
// name of image in first arg
char* image_filename = argc >= 2 ? argv[1] : img_name;
// get image
image = cvLoadImage(image_filename, 1);
printf("[i] image: %s\n", image_filename);
if(!image){
printf("[!] Error: cant load test image: %s\n", image_filename);
return -1;
}
// show image
cvNamedWindow("image");
cvShowImage("image", image);
// resize image (for processing speed)
src = cvCreateImage(cvSize(image->width/2, image->height/2), IPL_DEPTH_8U, 3);
cvResize(image, src, CV_INTER_LINEAR);
cvNamedWindow("img");
cvShowImage("img", src);
// image for storing cluster indexes
IplImage* cluster_indexes = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);
cvZero(cluster_indexes);
#define CLUSTER_COUNT 10
int cluster_count = CLUSTER_COUNT;
ColorCluster clusters[CLUSTER_COUNT];
int i=0, j=0, k=0, x=0, y=0;
// initial cluster colors
#if 0
clusters[0].new_color = RED;
clusters[1].new_color = ORANGE;
clusters[2].new_color = YELLOW;
// clusters[3].new_color = GREEN;
// clusters[4].new_color = LIGHTBLUE;
// clusters[5].new_color = BLUE;
// clusters[6].new_color = VIOLET;
#elif 0
clusters[0].new_color = BLACK;
clusters[1].new_color = GREEN;
clusters[2].new_color = WHITE;
#else
CvRNG rng = cvRNG(-1);
for(k=0; k<cluster_count; k++)
clusters[k].new_color = CV_RGB(cvRandInt(&rng)%255, cvRandInt(&rng)%255, cvRandInt(&rng)%255);
#endif
// k-means
float min_rgb_euclidean = 0, old_rgb_euclidean=0;
while(1) {
for(k=0; k<cluster_count; k++) {
clusters[k].count = 0;
clusters[k].color = clusters[k].new_color;
clusters[k].new_color = cvScalarAll(0);
}
for (y=0; y<src->height; y++) {
for (x=0; x<src->width; x++) {
// get the RGB components of the pixel
uchar B = CV_PIXEL(uchar, src, x, y)[0]; // B
uchar G = CV_PIXEL(uchar, src, x, y)[1]; // G
uchar R = CV_PIXEL(uchar, src, x, y)[2]; // R
min_rgb_euclidean = 255*255*255;
int cluster_index = -1;
for(k=0; k<cluster_count; k++) {
float euclid = rgb_euclidean(cvScalar(B, G, R, 0), clusters[k].color);
if( euclid < min_rgb_euclidean ) {
min_rgb_euclidean = euclid;
cluster_index = k;
}
}
// set the cluster index
CV_PIXEL(uchar, cluster_indexes, x, y)[0] = cluster_index;
clusters[cluster_index].count++;
clusters[cluster_index].new_color.val[0] += B;
clusters[cluster_index].new_color.val[1] += G;
clusters[cluster_index].new_color.val[2] += R;
}
}
min_rgb_euclidean = 0;
for(k=0; k<cluster_count; k++) {
// new color
clusters[k].new_color.val[0] /= clusters[k].count;
clusters[k].new_color.val[1] /= clusters[k].count;
clusters[k].new_color.val[2] /= clusters[k].count;
float ecli = rgb_euclidean(clusters[k].new_color, clusters[k].color);
if(ecli > min_rgb_euclidean)
min_rgb_euclidean = ecli;
}
//printf("%f\n", min_rgb_euclidean);
if( fabs(min_rgb_euclidean - old_rgb_euclidean)<1 )
break;
old_rgb_euclidean = min_rgb_euclidean;
}
//-----------------------------------------------------
// Now we drive the array into a vector and sort it :)
std::vector< std::pair< int, uint > > colors;
colors.reserve(CLUSTER_COUNT);
int colors_count = 0;
for(i=0; i<CLUSTER_COUNT; i++){
std::pair< int, uint > color;
color.first = i;
color.second = clusters[i].count;
colors.push_back( color );
if(clusters[i].count>0)
colors_count++;
}
// sort
std::sort( colors.begin(), colors.end(), colors_sort );
// show color
dst2 = cvCreateImage( cvGetSize(src), IPL_DEPTH_8U, 3 );
cvZero(dst2);
int h = dst2->height / CLUSTER_COUNT;
int w = dst2->width;
for(i=0; i<CLUSTER_COUNT; i++ ){
cvRectangle(dst2, cvPoint(0, i*h), cvPoint(w, i*h+h), clusters[colors[i].first].color, -1);
printf("[i] Color: %d %d %d (%d)\n", (int)clusters[colors[i].first].color.val[2],
(int)clusters[colors[i].first].color.val[1],
(int)clusters[colors[i].first].color.val[0],
clusters[colors[i].first].count);
}
cvNamedWindow("colors");
cvShowImage("colors", dst2);
//cvResize(dst2, image, CV_INTER_LINEAR);
//cvSaveImage("dominate_colors_table.png", image);
//-----------------------------------------------------
// show the picture in the colors found
dst = cvCloneImage(src);
for (y=0; y<dst->height; y++) {
for (x=0; x<dst->width; x++) {
int cluster_index = CV_PIXEL(uchar, cluster_indexes, x, y)[0];
CV_PIXEL(uchar, dst, x, y)[0] = clusters[cluster_index].color.val[0];
CV_PIXEL(uchar, dst, x, y)[1] = clusters[cluster_index].color.val[1];
CV_PIXEL(uchar, dst, x, y)[2] = clusters[cluster_index].color.val[2];
}
}
cvNamedWindow("dst");
cvShowImage("dst", dst);
//cvResize(dst, image, CV_INTER_LINEAR);
//cvSaveImage("dominate_colors.png", image);
//-----------------------------------------------------
// waiting for the keystroke
cvWaitKey(0);
// free up resources
cvReleaseImage(&image);
cvReleaseImage(&src);
cvReleaseImage(&cluster_indexes);
cvReleaseImage(&dst);
cvReleaseImage(&dst2);
// delete windows
cvDestroyAllWindows();
return 0;
}
Finally with the help of QImage class I'm able to get this done and I implemented a simple algorithm from scratch.
The idea is to get the most frequent intensity in each color channel , and then combining them to get the final RGB color.
It returns a QVector<int> of three channels.
Helper function:
int MainWindow::get_max(QVector<int> vec){
int max = vec[0];
int index = 0;
for(int i = 0 ; i < 255 ; i++){
if(vec[i] > max){
max = vec[i];
index = i;
}
}
return index;
}
And the picker function :
QVector<int> MainWindow::get_mean_rgb_for_img(const QImage img){
QRgb *ct;
int width , height;
width = img.width();
height = img.height();
QVector<int> red(256);
QVector<int> green(256);
QVector<int> blue(256);
for(int i = 0 ; i < height ; i++){
ct = (QRgb *)img.scanLine(i);
for(int j = 0 ; j < width ; j++){
red[qRed(ct[j])]+=1;
}
}
for(int i = 0 ; i < height ; i++){
ct = (QRgb *)img.scanLine(i);
for(int j = 0 ; j < width ; j++){
green[qGreen(ct[j])]+=1;
}
}
for(int i = 0 ; i < height ; i++){
ct = (QRgb *)img.scanLine(i);
for(int j = 0 ; j < width ; j++){
blue[qBlue(ct[j])]+=1;
}
}
int red_val = get_max(red);
int green_val = get_max(green);
int blue_val = get_max(blue);
QVector<int> result(3);
result.insert(0 , red_val);
result.insert(1 , green_val);
result.insert(2 , blue_val);
return result;
}
Although there is just one thread for those calculations (At least on the paper , but in practice Qt spawned a handful of threads without my notice by itself) it's pretty much fast and requires little CPU time even for 4K images !!!

Magnetometer biases issue

I am using lis3mdl magnetometer in my quadcopter project to compensate gyroscope drift. Unfortunatelly Im having problems probably with calibrating.
Ive achive max and min values (what is weird they are 14 bits instead of 16) and calculated biases like that :
biases[i] = (MAX_VALUES[i]+MIN_VALUES[i])/2;
(where i represent each of 3 axis).
Ive substracted biases from raw values x = (double)new_x-biases[0]; (etc), and then wanted to calculate heading like that :
heading = atan2(x,y);
heading += declinationAngle;
where declination angle is calculated.
Outcome are angles (conversion from radians heading*(180/M_PI)), and it does change when Iam rotating quad in yaw axi, BUT when I am rotating it in roll and pitch axi value change either. I want to achive stable yaw value which does not change when Iam rotating object in other axis. Maybe some type of fusing with accelerometer?
I am not sure when Ive made mistake in my calculations...
Whole class:
class Magnetometer {
int x=0,y=0,z=0;
LIS3MDL mag;
int running_min[3] = {32767, 32767, 32767}, running_max[3] = {-32768, -32768, -32768};
double mag_norm = 0.0;
double declinationAngle = 0.0;
double heading=0.0;
const int MAX_VALUES[3] = {3014,3439,10246};
const int MIN_VALUES[3] = {-4746, -4110, 492};
double biases[3] = {0.0};
double scales[3] = {0.0};
double avg_scale = 0.0;
ButterworthDLPF xyz_filter[3];
double DLPF_ON = true;
const float sample_rate = MAG_SAMPLE_RATE;
const float cutoff_freq = 4.0;
public:
Magnetometer() {}
void Init() {
declinationAngle = (6.0 + (8.0 / 60.0)) / (180.0 / M_PI);
for(int i=0; i<3; i++) {
biases[i] = (MAX_VALUES[i]+MIN_VALUES[i])/2;
scales[i] = (MAX_VALUES[i]-MIN_VALUES[i])/2;
}
avg_scale = (scales[0]+scales[1]+scales[2])/3.0;
for(int i=0; i<3; i++) scales[i] = avg_scale / scales[i];
Serial.println("Turning on magnetometer. . .");
if(!mag.init()) {
Serial.println("Failed to detect magnetometer!");
ESP.restart();
}
mag.enableDefault();
//Calibrate();
for(int i=0; i<3; i++) xyz_filter[i].Init(sample_rate, cutoff_freq);
Serial.println("9DOF readdy!");
}
void Calibrate() {
delay(100);
while(true) {
mag.read();
if(running_max[0]<mag.m.x) running_max[0] = mag.m.x;
if(running_max[1]<mag.m.y) running_max[1] = mag.m.y;
if(running_max[2]<mag.m.z) running_max[2] = mag.m.z;
if(running_min[0]>mag.m.x) running_min[0] = mag.m.x;
if(running_min[1]>mag.m.y) running_min[1] = mag.m.y;
if(running_min[2]>mag.m.z) running_min[2] = mag.m.z;
Serial.println((String)running_max[0]+" "+(String)running_max[1]+" "+(String)running_max[2]+ " "+(String)running_min[0] +" "+(String)running_min[1]+" "+(String)running_min[2]);
delay(20);
}
}
void Update(){
mag.read();
xyz_filter[0].Update(mag.m.x);
xyz_filter[1].Update(mag.m.y);
xyz_filter[2].Update(mag.m.z);
//Serial.println(xyz_filter[0].getData());
/*x = ((double)xyz_filter[0].getData()-biases[0])*scales[0];
y = ((double)xyz_filter[1].getData()-biases[1])*scales[1];
z = ((double)xyz_filter[2].getData()-biases[2])*scales[2];*/
x = ((double)mag.m.x-biases[0])*scales[0];
y = ((double)mag.m.y-biases[1])*scales[1];
z = ((double)mag.m.z-biases[2])*scales[2];
CalculateHeading();
}
void CalculateHeading() {
heading = atan2(y,x);
heading += declinationAngle;
//if(heading<0) heading += 2*PI;
//else if(heading>2*PI) heading -= 2*PI;
heading=MOD(heading*(180/M_PI));
}
double GetHeading() {return heading;}
void ShowRawValues(bool names=false) {
if(names) Serial.print("X: "+(String)x+" Y: "+ (String)y+ " Z: " + (String)z);
else Serial.print((String)x+" "+ (String)y+ " " + (String)z);
}
};

How to convert Ximea xiAPI camera data into QImage?

I have data from a camera in mono 8bit.
This is converted into an int vector using
std::vector<int> grayVector(size);
// convert / copy pointer data into vector: 8 bit
if (static_cast<XI_IMG_FORMAT>(format) == XI_MONO8)
{
quint8* imageIterator = reinterpret_cast<quint8*> (pMemVoid);
for (size_t count = 0; count < size; ++count)
{
grayVector[count] = static_cast<int>(*imageIterator);
imageIterator++;
}
}
Next, I need to convert this into a QImage. If I set the image format to QImage::Format_Mono the app crashes. With QImage::Format_RGB16 I get strippes, and with QImage::Format_RGB32 everything is black.
I would like to know how to do this the best, efficient and correct way?
// convert gray values into QImage data
QImage image = QImage(static_cast<int>(sizeX), static_cat<int>(sizeY), QImage::Format_RGB16);
for ( int y = 0; y < sizeY; ++y )
{
int yoffset = sizeY*y;
QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y)) ;
for ( int x = 0; x < sizeX ; ++x )
{
int pos = x + yoffset;
int color = grayVector[static_cast<size_t>(pos)];
*line++ = qRgb(color, color, color);
}
}
The conversion to int is unnecessary and you do it in a very inefficient way; all you need is to use the QImage::Format_Grayscale8 available since Qt 5.5 (mid-2015).
Anyway, what you really want is a way to go from XI_IMG to QImage. The default BP_UNSAFE buffering policy should be adequate - the QImage will do a format conversion, so taking the data from XiApi's internal buffer is OK. Thus the following - all of the conversions are implemented in Qt and are quite efficient - much better than most any naive code.
I didn't check whether some Xi formats may need a BGR swap. If so, then the swap can be set to true in the format selection code and the rest will happen automatically.
See also: xiAPI manual.
static QVector<QRgb> grayScaleColorTable() {
static QVector<QRgb> table;
if (table.isEmpty()) {
table.resize(256);
auto *data = table.data();
for (int i = 0; i < table.size(); ++i)
data[i] = qRgb(i, i, i);
}
return table;
}
constexpr QImage::Format grayScaleFormat() {
return (QT_VERSION >= QT_VERSION_CHECK(5,5,0))
? QImage::Format_Grayscale8
: QImage::Format_Indexed8;
}
QImage convertToImage(const XI_IMG *src, QImage::Format f) {
Q_ASSERT(src->fmt == XI_MONO16);
Q_ASSERT((src->padding_x % 2) == 0);
if (src->fmt != XI_MONO16) return {};
const quint16 *s = static_cast<const quint16*>(src->bp);
const int s_pad = src->padding_x/2;
if (f == QImage::Format_BGR30 ||
f == QImage::Format_A2BGR30_Premultiplied ||
f == QImage::Format_RGB30 ||
f == QImage::Format_A2RGB30_Premultiplied)
{
QImage ret{src->width, src->height, f};
Q_ASSERT((ret->bytesPerLine() % 4) == 0);
const int d_pad = ret->bytesPerLine()/4 - ret->width();
quint32 *d = (quint32*)ret.bits();
if (s_pad == d_pad) {
const int N = (src->width + s_pad) * src->height - s_pad;
for (int i = 0; i < N; ++i) {
quint32 const v = (*s++) >> (16-10);
*d++ = 0xC0000000 | v << 20 | v << 10 | v;
}
} else {
for (int j = 0; j < src->height; ++j) {
for (int i = 0; i < src->width; ++i) {
quint32 const v = (*s++) >> (16-10);
*d++ = 0xC0000000u | v << 20 | v << 10 | v;
}
s += s_pad;
d += d_pad;
}
}
return ret;
}
QImage ret{src->width, src->height, grayScaleFormat()};
const int d_pad = ret->bytesPerLine() - ret->width();
auto *d = ret.bits();
if (s_pad == d_pad) {
const int N = (src->width + s_pad) * src->height - s_pad;
for (int i = 0; i < N; ++i) {
*d++ = (*s++) >> 8;
} else {
for (int j = 0; j < src->height; ++j) {
for (int i = 0; i < src->width; ++i)
*d++ = (*s++) >> 8;
s += s_pad;
d += d_pad;
}
}
return ret;
}
QImage fromXiImg(const XI_IMG *src, QImage::Format dstFormat = QImage::Format_ARGB32Premultiplied) {
Q_ASSERT(src->width > 0 && src->height > 0 && src->padding_x >= 0 && src->bp_size > 0);
Q_ASSERT(dstFormat != QImage::Format_Invalid);
bool swap = false;
int srcPixelBytes = 0;
bool externalConvert = false;
QImage::Format srcFormat = QImage::Format_Invalid;
switch (src->fmt) {
case XI_MONO8:
srcPixelBytes = 1;
srcFormat = grayScaleFormat();
break;
case XI_MONO16:
srcPixelBytes = 2;
externalConvert = true;
break;
case XI_RGB24:
srcPixelBytes = 3;
srcFormat = QImage::Format_RGB888;
break;
case XI_RGB32:
srcPixelBytes = 4;
srcFormat = QImage::Format_RGB32;
break;
};
if (srcFormat == QImage::Format_Invalid && !externalConvert) {
qWarning("Unhandled XI_IMG image format");
return {};
}
Q_ASSERT(srcPixelBytes > 0 && srcPixelBytes <= 4);
int bytesPerLine = src->width * srcPixelBytes + src->padding_x;
if ((bytesPerLine * src->height - src->padding_x) > src->bp_size) {
qWarning("Inconsistent XI_IMG data");
return {};
}
QImage ret;
if (!externalConvert)
ret = QImage{static_cast<const uchar*>(src->bp), src->width, src->height,
bytesPerLine, srcFormat};
else
ret = convertToImage(src, dstFormat);
if (ret.format() == QImage::Format_Indexed8)
ret.setColorTable(grayScaleColorTable());
if (ret.format() != dstFormat)
ret = std::move(ret).convertToFormat(dstFormat);
if (swap)
ret = std::move(ret).rgbSwapped();
if (!ret.isDetached()) // ensure that we don't share XI_IMG's data buffer
ret.detach();
return ret;
}

OpenCL: Move data between __global memory

I am trying to move some data between 2 global memory before running a kernel on it.
Here buffer contains data that needs to be written in array, but sadly not contiguously:
void exchange_2_halo_write(
__global float2 *array,
__global float *buffer,
const unsigned int im,
const unsigned int jm,
const unsigned int km
) {
const unsigned int v_dim = 2;
unsigned int i, j, k, v, i_buf = 0;
// Which vector component, ie along v_dim
for (v = 0; v < v_dim; v++) {
// top halo
for (k = 0; k < km; k++) {
for (i = 0; i < im; i++) {
((__global float*)&array[i + k*im*jm])[v] = buffer[i_buf];
i_buf++;
}
}
// bottom halo
for (k = 0; k < km; k++) {
for (i = 0; i < im; i++) {
((__global float*)&array[i + k*im*jm + im*(jm-1)])[v] = buffer[i_buf];
i_buf++;
}
}
// left halo
for (k = 0; k < km; k++) {
for (j = 1; j < jm-1; j++) {
((__global float*)&array[j*im + k*im*jm])[v] = buffer[i_buf];
i_buf++;
}
}
// right halo
for (k = 0; k < km; k++) {
for (j = 1; j < jm-1; j++) {
((__global float*)&array[j*im + k*im*jm + (im-1)])[v] = buffer[i_buf];
i_buf++;
}
}
}
}
This works really fine in C (with a few minor changes), and for the data size I need (im = 150, jm = 150, km = 90, buf_sz = 107280), it runs in about 0.02s.
I had expected the same code to be slower on the GPU, but not that slower, it actually takes about 90 minutes to do the same thing (that's about 250000x slower!).
Simply doing a straight allocation takes about 15 minutes, which clearly shows it is not the way to go.
for (i = 0; i < buf_sz; i++) {
array[i] = buffer[i];
}
In that case, I have seen that I can do something like this:
int xid = get_global_id(0);
array[xid] = buffer[xid];
which seems to work fine/quickly.
However, I do not know how to adapt this to use the conditions I have in the first code.
The top and bottom_halo parts have im contiguous elements to transfer to array, which I think means it could be ok to transfer easily. Sadly the left and right_halos don't.
Also with better code, can I expect to get somewhat close to the CPU time? If it is impossible to do it in, say, under 1s, it's probably going to be a waste.
Thank you.
Before the answer, 1 remark. When you do a for loop inside a kernel, like this:
for (i = 0; i < buf_sz; i++) {
array[i] = buffer[i];
}
And you launch ie: 512 work items, you are doing the copy 512 times!!, not doing it in parallel with 512 threads. So obviously, it is going to be even slower! more than 512x slower!!!
That said, you can split it in this way:
2D Global size: km x max(im,jm)
void exchange_2_halo_write(
__global float2 *array,
__global float *buffer,
const unsigned int im,
const unsigned int jm
) {
const unsigned int v_dim = 2;
const unsigned int k = get_global_id(0);
const unsigned int i = get_global_id(1);
const unsigned int km = get_global_size(0);
// Which vector component, ie along v_dim
for (unsigned int v = 0; v < v_dim; v++) {
if(i < im){
// top halo
((__global float*)&array[i + k*im*jm])[v] = buffer[v*(2*km*im + 2*km*(jm-2))+km*i];
// bottom halo
((__global float*)&array[i + k*im*jm + im*(jm-1)])[v] = buffer[v*(2*km*im + 2*km*(jm-2))+km*im+km*i];
}
if(i < jm-1 && i > 0){
// left halo
((__global float*)&array[i*im + k*im*jm])[v] = buffer[v*(2*km*im + 2*km*(jm-2))+km*im*2+km*(i-1)];
// right halo
((__global float*)&array[i*im + k*im*jm + (im-1))[v] = buffer[v*(2*km*im + 2*km*(jm-2))+km*im*2+km*(jm-2)+km*(i-1)];
}
}
}
Other options are possible, like using local memory, but that is a tedious work....

QT4 How to blur QPixmap image?

QT4 How to blur QPixmap image?
I am looking for something like one of the following:
Blur(pixmap);
painter.Blur();
painter.Blur(rect);
What is the best way to do this?
1st) declare external QT routine:
QT_BEGIN_NAMESPACE
extern Q_WIDGETS_EXPORT void qt_blurImage( QPainter *p, QImage &blurImage, qreal radius, bool quality, bool alphaOnly, int transposed = 0 );
QT_END_NAMESPACE
2nd) Use:
extern QImage srcImg;//source image
QPixmap pxDst( srcImg.size() );//blurred destination
pxDst.fill( Qt::transparent );
{
QPainter painter( &pxDst );
qt_blurImage( &painter, srcImg, 2, true, false );//blur radius: 2px
}
Let's contribute to this topic. As of Qt 5.3, following function will help you a lot with applying QGraphicsEffect to QImage (and not losing the alpha)
QImage applyEffectToImage(QImage src, QGraphicsEffect *effect, int extent = 0)
{
if(src.isNull()) return QImage(); //No need to do anything else!
if(!effect) return src; //No need to do anything else!
QGraphicsScene scene;
QGraphicsPixmapItem item;
item.setPixmap(QPixmap::fromImage(src));
item.setGraphicsEffect(effect);
scene.addItem(&item);
QImage res(src.size()+QSize(extent*2, extent*2), QImage::Format_ARGB32);
res.fill(Qt::transparent);
QPainter ptr(&res);
scene.render(&ptr, QRectF(), QRectF( -extent, -extent, src.width()+extent*2, src.height()+extent*2 ) );
return res;
}
Them, using this function to blur your image is straightforward:
QGraphicsBlurEffect *blur = new QGraphicsBlurEffect;
blur->setBlurRadius(8);
QImage source("://img1.png");
QImage result = applyEffectToImage(source, blur);
result.save("final.png");
Of course, you don't need to save it, this was just an example of usefulness.
You can even drop a shadow:
QGraphicsDropShadowEffect *e = new QGraphicsDropShadowEffect;
e->setColor(QColor(40,40,40,245));
e->setOffset(0,10);
e->setBlurRadius(50);
QImage p("://img3.png");
QImage res = applyEffectToImage(p, e, 40);
And note the extent parameter, it adds extent number of pixels to all sides of the original image, especially useful for shadows and blurs to not be cut-off.
Check out this:
#include <QtGui/QApplication>
#include <QImage>
#include <QPixmap>
#include <QLabel>
QImage blurred(const QImage& image, const QRect& rect, int radius, bool alphaOnly = false)
{
int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 };
int alpha = (radius < 1) ? 16 : (radius > 17) ? 1 : tab[radius-1];
QImage result = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
int r1 = rect.top();
int r2 = rect.bottom();
int c1 = rect.left();
int c2 = rect.right();
int bpl = result.bytesPerLine();
int rgba[4];
unsigned char* p;
int i1 = 0;
int i2 = 3;
if (alphaOnly)
i1 = i2 = (QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3);
for (int col = c1; col <= c2; col++) {
p = result.scanLine(r1) + col * 4;
for (int i = i1; i <= i2; i++)
rgba[i] = p[i] << 4;
p += bpl;
for (int j = r1; j < r2; j++, p += bpl)
for (int i = i1; i <= i2; i++)
p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
}
for (int row = r1; row <= r2; row++) {
p = result.scanLine(row) + c1 * 4;
for (int i = i1; i <= i2; i++)
rgba[i] = p[i] << 4;
p += 4;
for (int j = c1; j < c2; j++, p += 4)
for (int i = i1; i <= i2; i++)
p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
}
for (int col = c1; col <= c2; col++) {
p = result.scanLine(r2) + col * 4;
for (int i = i1; i <= i2; i++)
rgba[i] = p[i] << 4;
p -= bpl;
for (int j = r1; j < r2; j++, p -= bpl)
for (int i = i1; i <= i2; i++)
p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
}
for (int row = r1; row <= r2; row++) {
p = result.scanLine(row) + c2 * 4;
for (int i = i1; i <= i2; i++)
rgba[i] = p[i] << 4;
p -= 4;
for (int j = c1; j < c2; j++, p -= 4)
for (int i = i1; i <= i2; i++)
p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
}
return result;
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QLabel label;
QImage image("image.png");
image = blurred(image,image.rect(),10,false);
label.setPixmap(QPixmap::fromImage(image));
label.show();
return a.exec();
}
Method 1a: grab the raw bits and do it yourself. You'll need to be sufficiently familiar with bitmaps and blurring algorithms to implement the blur yourself. If you want that sort of precision, this is the way to go.
QImage image = pixmap.toImage();
if (image.format() != QImage::Format_RGB32)
image = image.convertToFormat(QImage::Format_RGB32);
uchar* bits = image.bits();
int rowBytes = image.bytesPerLine();
DoMyOwnBlurAlgorithm(bits, image.width(), image.height(), rowBytes);
return QPixmap::fromImage(image);
Method 1b: who needs raw bits? You can use image.pixel(x,y) and image.setPixel(x,y,color) instead. This won't be as fast as 1a, but it should be a bit easier to understand and code.
QImage image = pixmap.toImage();
QImage output(image.width(), image.height(), image.format());
for (int y=0; y<image.height(); ++y)
for (int x=0; x<image.width(); ++x)
output.setPixel(getBlurredColor(image, x, y));
return output;
Method 2: use a QGraphicsBlurEffect, through a widget or scene. The code here uses a label widget:
QPixmap BlurAPixmap(const QPixmap& inPixmap)
{
QLabel* label = new QLabel();
label->setPixmap(inPixmap);
label->setGraphicsEffect(new QGraphicsBlurEffect());
QPixmap output(inPixmap.width(), inPixmap.height());
QPainter painter(&output);
label->render(&painter);
return output;
}
Tweak as needed. For example, I'm presuming the default graphics blur effect is acceptable. I'm using Method 2 in my project.
A Gaussian blur is a simple way to create a blurring effect.
Edit: And lo, I came across Qt's QGraphicsBlurEffect. Introduced in Qt 4.6, it seems to do exactly what you want.
Add python code based on #Петър Петров answer for QT 5.
def applyEffectToImage(src, effect):
scene = QGraphicsScene()
item = QGraphicsPixmapItem()
item.setPixmap(QPixmap.fromImage(src))
item.setGraphicsEffect(effect)
scene.addItem(item)
res = QImage(src.size(), QImage.Format_ARGB32)
res.fill(Qt.transparent)
ptr = QPainter(res)
scene.render(ptr, QRectF(), QRectF(0,0, src.width(), src.height()) )
return res
blur = QGraphicsBlurEffect()
blur.setBlurRadius(8)
source = QImage(r"C:\Users\fran\Desktop\test.png")
result = applyEffectToImage(source, blur)
result.save(r"C:\Users\fran\Desktop\result.png")

Resources