Magnetometer biases issue - arduino

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);
}
};

Related

How do I plot E8 (Exceptional Lie Group order 8) in 2D?

For the last week or so I have been struggling to find a resource that will allow me to make something like the 2D petrie polygon diagrams in this article.
My main trouble is finding out what the rules are for the edge and node connections.
I.e. in this plot, is there a simple way to make the image from scratch (even if it not fully representative of the bigger theory behind it)?
Any help is massively appreciated!
K
Here is how I solved this problem!
e8
// to run
// clink -c Ex8
// ./Ex8
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "dislin.h"
// method to generate all permutations of a set with repeated elements:
the root system
float root_sys[240][8];
int count = 0;
/// checks elements in root system to see if they should be permuted
int shouldSwap(float base[], int start, int curr)
{
for (int i = start; i < curr; i++)
if (base[i] == base[curr])
return 0;
return 1;
}
/// performs permutations of root system
void permutations(float base[], int index, int n)
{
if (index >= n) {
for(int i = 0; i < n; i++){
root_sys[count][i] = base[i];
}
count++;
return;
}
for (int i = index; i < n; i++) {
int check = shouldSwap(base, index, i);
if (check) {
float temp_0 = base[index];
float temp_1 = base[i];
base[index] = temp_1;
base[i] = temp_0;
permutations(base, index + 1, n);
float temp_2 = base[index];
float temp_3 = base[i];
base[index] = temp_3;
base[i] = temp_2;
}
}
}
// function to list all distances from one node to others
float inner_product(float * vect_0, float * vect_1){
float sum = 0;
for(int i = 0; i < 8; i++){
sum = sum + ((vect_0[i] - vect_1[i]) * (vect_0[i] - vect_1[i]));
}return sum;
}
/// inner product funtion
float inner_product_plus(float * vect_0, float * vect_1){
float sum = 0;
for(int i = 0; i < 8; i++){
sum = sum + (vect_0[i] * vect_1[i]);
}return sum;
}
int main(void){
// base vector permutations of E8 root system
float base_sys[8][8] = {
{1,1,0,0,0,0,0,0},
{1,-1,0,0,0,0,0,0},
{-1,-1,0,0,0,0,0,0},
{0.5,0.5,-0.5,-0.5,-0.5,-0.5,-0.5,-0.5},
{0.5,0.5,0.5,0.5,-0.5,-0.5,-0.5,-0.5},
{0.5,0.5,0.5,0.5,0.5,0.5,-0.5,-0.5},
{0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5},
{-0.5,-0.5,-0.5,-0.5,-0.5,-0.5,-0.5,-0.5}
};
//permute the base vectors
for(int i = 0; i < 8; i++){
permutations(base_sys[i],0,8);
}
//calculating distances between all roots, outputting correspondence matrix
int distance_matrix[240][240];
for(int i = 0; i < 240; i++){
int dist_m = 100;
for(int ii = 0; ii < 240; ii++){
float dist = inner_product(root_sys[i], root_sys[ii]);
if(dist == 2){ //connecting distance in E8
distance_matrix[i][ii] = 1;
}else{distance_matrix[i][ii] == 0;};
}
}
//use another program to calculate eigenvectors of root system . . . after some fiddling, these vectors appear
float re[8] = {0.438217070641, 0.205187681291,
0.36459828198, 0.0124511903657,
-0.0124511903657, -0.36459828198,
-0.205187681291, -0.67645247517};
float im[8] = {-0.118465163028, 0.404927414852,
0.581970822973, 0.264896157496,
0.501826483552, 0.345040496917,
0.167997088796, 0.118465163028};
//define co-ordinate system for relevent points
float rings_x[240];
float rings_y[240];
//decide on which points belong to the system
for(int i = 0; i < 240; i++){
float current_point[8];
for(int ii = 0; ii < 8; ii++){
current_point[ii] = root_sys[i][ii];
}
rings_x[i] = inner_product_plus(current_point, re);
rings_y[i] = inner_product_plus(current_point, im);
}
//graph the system using DISLIN library
scrmod("revers");
setpag("da4l");
metafl("cons");
disini();
graf(-1.2, 1.2, -1.2, 1.2, -1.2, 1.2, -1.2, 1);
// a connection appears depending on the previously calculated distance matrix
for(int i = 0; i < 240; i++){
for(int ii = 0; ii < 240; ii++){
int connect = distance_matrix[i][ii];
if(connect == 1){
rline(rings_x[i], rings_y[i], rings_x[ii], rings_y[ii]);
distance_matrix[ii][i] = 0;
}else{continue;}
}
}
// More DISLIN functions
titlin("E8", 1);
name("R-axis", "x");
name("I-axis", "y");
marker(21);
hsymbl(15);
qplsca(rings_x, rings_y, 240);
return 0;
}
Extra points to anyone who can explain how to rotate the 2d plot to create a 3-d animation of this object

How to make this OpenGL (Qt3D) code efficient?

I have written a small program that renders a 175x175 heightmap. The rendering is done using Qt3D which is basically a set of wrappers around OpenGL. The program loads fine and runs fine on a powerful desktop. However, when I run it on a lower power GPU, image updates are very choppy when I start moving the camera around. Rendering 3D terrain mesh really shouldn't be that difficult for even a small GPU, so I assume I am doing something very wrong. Are there some obvious ways to optimize this code or am I just expecting too much from a small GPU?
Fragment shader
https://github.com/qt/qt3d/blob/5.12/src/extras/shaders/es2/phong.inc.frag
Vertex shader:
https://github.com/qt/qt3d/blob/5.12/src/extras/shaders/es2/morphphong.vert
int main(int argc, char* argv[])
{
QGuiApplication app(argc, argv);
Qt3DExtras::Qt3DWindow view;
// Scene Root
Qt3DCore::QEntity *sceneRoot = new Qt3DCore::QEntity();
// Scene Camera
Qt3DRender::QCamera *basicCamera = view.camera();
basicCamera->setProjectionType(Qt3DRender::QCameraLens::PerspectiveProjection);
basicCamera->setUpVector(QVector3D(0.0f, 1.0f, 0.0f));
basicCamera->setViewCenter(QVector3D(60.0f, 15.0f, -60.0f));
basicCamera->setPosition(QVector3D(60.0f, 26.0f, 0.0f));
// For camera controls
Qt3DExtras::QFirstPersonCameraController *camController = new Qt3DExtras::QFirstPersonCameraController(sceneRoot);
camController->setCamera(basicCamera);
// Material
Qt3DRender::QMaterial *material= new Qt3DExtras::QPhongMaterial(sceneRoot);
Qt3DCore::QEntity *customMeshEntity = new Qt3DCore::QEntity(sceneRoot);
// Transform
Qt3DCore::QTransform *transform = new Qt3DCore::QTransform;
Qt3DRender::QGeometryRenderer *customMeshRenderer = new Qt3DRender::QGeometryRenderer;
Qt3DRender::QGeometry *customGeometry = new Qt3DRender::QGeometry(customMeshRenderer);
Qt3DRender::QBuffer *vertexDataBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::VertexBuffer, customGeometry);
Qt3DRender::QBuffer *indexDataBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::IndexBuffer, customGeometry);
QImage heightmap("../assets/heightmap.png");
QByteArray vertexBufferData;
vertexBufferData.resize(heightmap.width() * heightmap.height() * (3 + 3 + 3) * sizeof(float));
QVector<QVector3D> vertexPositions;
for (int row = 0; row < heightmap.height(); row++) {
for (int column = 0; column < heightmap.width(); column++) {
vertexPositions.append(QVector3D(row, heightmap.pixelColor(row, column).red()/8.0, -column));
}
}
QVector<QVector3D> vertexNormals;
for (int row = 0; row < heightmap.height(); row++) {
for (int column = 0; column < heightmap.width(); column++) {
int center = (row * heightmap.width()) + column;
int upper = center - heightmap.width();
int lower = center + heightmap.width();
int right = center + 1;
int left = center -1;
int lowerLeft = center - 1 + heightmap.width();
int upperRight = center + 1 - heightmap.width();
int rightEdge = heightmap.width() - 1;
int bottomEdge = heightmap.height() -1;
// Calculate normals for each adjacent face and sum
// Check for edge conditions
QVector3D vertexNormal(0, 0, 0);
if (column != 0 && row != 0 ) {
vertexNormal += QVector3D::normal(vertexPositions[center], vertexPositions[upper], vertexPositions[left]);
}
if (column != rightEdge && row != 0) {
vertexNormal += QVector3D::normal(vertexPositions[center], vertexPositions[upperRight], vertexPositions[upper]);
vertexNormal += QVector3D::normal(vertexPositions[center], vertexPositions[right], vertexPositions[upperRight]);
}
if (column != rightEdge && row != bottomEdge) {
vertexNormal += QVector3D::normal(vertexPositions[center], vertexPositions[lower], vertexPositions[right]);
}
if (column != 0 && row != bottomEdge) {
vertexNormal += QVector3D::normal(vertexPositions[center], vertexPositions[lowerLeft], vertexPositions[lower]);
vertexNormal += QVector3D::normal(vertexPositions[center], vertexPositions[left], vertexPositions[lowerLeft]);
}
vertexNormals.append(vertexNormal.normalized());
}
}
// Colors
QVector3D red(1.0f, 0.0f, 0.0f);
QVector3D yellow(1.0f, 1.0f, 0.0f);
QVector3D green(0.0f, 1.0f, 0.0f);
QVector3D blue(0.0f, 0.0f, 1.0f);
QVector3D white(1.0f, 1.0f, 1.0f);
QVector<QVector3D> vertices;
for (int i = 0; i < vertexPositions.count(); i ++) {
vertices.append(vertexPositions[i]);
vertices.append(vertexNormals[i]);
if (vertexPositions[i].y() > 20.0) {
vertices.append(red);
}
else if (vertexPositions[i].y() > 18.0) {
vertices.append(yellow);
}
else {
vertices.append(green);
}
}
float *rawVertexArray = reinterpret_cast<float *>(vertexBufferData.data());
int idx = 0;
Q_FOREACH (const QVector3D &v, vertices) {
rawVertexArray[idx++] = v.x();
rawVertexArray[idx++] = v.y();
rawVertexArray[idx++] = v.z();
}
// Indices
QByteArray indexBufferData;
int indicesCount = (heightmap.height() - 1) * (heightmap.width() - 1) * 2 * 3;
indexBufferData.resize( indicesCount * sizeof(uint));
uint *rawIndexArray = reinterpret_cast<uint *>(indexBufferData.data());
int index = 0;
for (int row = 0; row < heightmap.height()-1; row++) {
for (int column = 0; column < heightmap.width()-1; column++) {
// 1 <- 3
// | /
// | /
// v /
// 2
int vertexBufferIndex = (row * heightmap.width()) + column;
rawIndexArray[index++] = vertexBufferIndex;
rawIndexArray[index++] = vertexBufferIndex + heightmap.width(); // down one row
rawIndexArray[index++] = vertexBufferIndex + 1; // right one column
// 1
// / ^
// / |
// / |
// 2 -> 3
rawIndexArray[index++] = vertexBufferIndex + 1; // right one column
rawIndexArray[index++] = vertexBufferIndex + heightmap.width(); // down one row
rawIndexArray[index++] = vertexBufferIndex + heightmap.width() + 1; // down one row and right one column
}
}
vertexDataBuffer->setData(vertexBufferData);
indexDataBuffer->setData(indexBufferData);
// Attributes
Qt3DRender::QAttribute *positionAttribute = new Qt3DRender::QAttribute();
positionAttribute->setAttributeType( Qt3DRender::QAttribute::VertexAttribute);
positionAttribute->setBuffer(vertexDataBuffer);
positionAttribute->setDataType( Qt3DRender::QAttribute::Float);
positionAttribute->setDataSize(3);
positionAttribute->setByteOffset(0);
positionAttribute->setByteStride(9 * sizeof(float));
positionAttribute->setCount(vertexPositions.count());
positionAttribute->setName( Qt3DRender::QAttribute::defaultPositionAttributeName());
Qt3DRender::QAttribute *normalAttribute = new Qt3DRender::QAttribute();
normalAttribute->setAttributeType( Qt3DRender::QAttribute::VertexAttribute);
normalAttribute->setBuffer(vertexDataBuffer);
normalAttribute->setDataType( Qt3DRender::QAttribute::Float);
normalAttribute->setDataSize(3);
normalAttribute->setByteOffset(3 * sizeof(float));
normalAttribute->setByteStride(9 * sizeof(float));
normalAttribute->setCount(vertexPositions.count());
normalAttribute->setName( Qt3DRender::QAttribute::defaultNormalAttributeName());
Qt3DRender::QAttribute *colorAttribute = new Qt3DRender::QAttribute();
colorAttribute->setAttributeType( Qt3DRender::QAttribute::VertexAttribute);
colorAttribute->setBuffer(vertexDataBuffer);
colorAttribute->setDataType( Qt3DRender::QAttribute::Float);
colorAttribute->setDataSize(3);
colorAttribute->setByteOffset(6 * sizeof(float));
colorAttribute->setByteStride(9 * sizeof(float));
colorAttribute->setCount(vertexPositions.count());
colorAttribute->setName( Qt3DRender::QAttribute::defaultColorAttributeName());
Qt3DRender::QAttribute *indexAttribute = new Qt3DRender::QAttribute();
indexAttribute->setAttributeType( Qt3DRender::QAttribute::IndexAttribute);
indexAttribute->setBuffer(indexDataBuffer);
indexAttribute->setDataType( Qt3DRender::QAttribute::UnsignedInt);
indexAttribute->setDataSize(1);
indexAttribute->setByteOffset(0);
indexAttribute->setByteStride(0);
indexAttribute->setCount(indicesCount);
customGeometry->addAttribute(positionAttribute);
customGeometry->addAttribute(normalAttribute);
customGeometry->addAttribute(colorAttribute);
customGeometry->addAttribute(indexAttribute);
customMeshRenderer->setInstanceCount(1);
customMeshRenderer->setFirstVertex(0);
customMeshRenderer->setFirstInstance(0);
customMeshRenderer->setPrimitiveType(Qt3DRender::QGeometryRenderer::Triangles);
customMeshRenderer->setGeometry(customGeometry);
customMeshEntity->addComponent(customMeshRenderer);
customMeshEntity->addComponent(transform);
customMeshEntity->addComponent(material);
view.setRootEntity(sceneRoot);
view.show();
return app.exec();
}
The Qt blog has a very good write-up on optimizing Qt3D applications for low-end hardware.
https://blog.qt.io/blog/2019/04/02/optimizing-real-time-3d-entry-level-hardware/

Doppler radar (HB100) Arduino code : Why do we use bit-shifting?

I've been working on my doppler radar speed project for a while. I found this very helpful link and the code below:
// Based on the Adafruit Trinket Sound-Reactive LED Color Organ
// http://learn.adafruit.com/trinket-sound-reactive-led-color-organ/code
#define RADAR A5 // RADAR inut is attached to A7
#define MICRODELAY 100 // 100microseconds ~10000hz
#define MAXINDEX 1024 // 10 bits
#define TOPINDEX 1023 // 10 bits
byte collect[MAXINDEX];
int mean;
int minimum;
int maximum;
int hysteresis; // 1/16 of max-min
bool currentphase; // are value above mean + hysteresis;
int lastnull; // index for last null passing value
int prevnull; // index for previous null passing value
int deltaindex;
int deltadeltaindex;
int index;
bool phasechange = false;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
while (!Serial) {}
index = 0;
mean = 0;
maximum = 255;
minimum = 0;
hysteresis = 0;
currentphase = false;
lastnull = 0;
prevnull = 0;
Serial.print("deltadeltaindex");
Serial.print("\t");
Serial.print("deltaindex");
Serial.print("\t");
Serial.println("delta");
}
void loop() {
int newVal = analogRead(RADAR); // Raw reading from amplified radar
mean -= (collect[index] >> 2);
mean += (newVal >> 2);
collect[index]= newVal;
minimum = newVal < minimum ? newVal : minimum + 1;
maximum = newVal > maximum ? newVal : maximum - 1;
hysteresis = abs(maximum - minimum) >> 5;
if(newVal > (mean + hysteresis))
{
if(false == currentphase)
{
currentphase = true;
phasechange = true;
}
}
else if(newVal < (mean - hysteresis))
{
if(currentphase)
{
currentphase = false;
phasechange = true;
}
}
if(phasechange)
{
prevnull = lastnull;
lastnull = index;
int delta = (prevnull > lastnull) ?
(lastnull - prevnull + MAXINDEX) :
(lastnull - prevnull);
deltadeltaindex = abs(deltaindex - delta);
deltaindex = delta;
Serial.print(deltadeltaindex);
Serial.print("\t");
Serial.print(deltaindex);
Serial.print("\t");
Serial.println(delta);
}
index = index == TOPINDEX ? 0 : index + 1;
phasechange = false;
//delayMicroseconds(10);
}
I tried it out on my Arduino with HB100(model with breakout board), and it works just fine.
However, what I really wanted to do was to understand the mechanism behind the code. I read some articles on hysteresis and bit-shifting, but I simply cannot understand why the programmer here used bit-shifting.
What would mean -= (collect[index] >> 2); and mean += (newVal >> 2); do to the values exactly?
Help will be appreciated.

MandelBrot set Using openCL

Trying to use the same code (sort of) as what I have used when running using TBB (threading building blocks).
I don't have a great deal of experience with OpenCL, but I think most of the main code is correct. I believe the errors are in the .cl file, where it does the math.
Here is my mandelbrot code in TBB:
Mandelbrot TBB
Here is my code in OpenCL
Mandelbrot OpenCL
Any help would be greatly appreciated.
I changed the code in the kernel, and it ran fine. My new kernel code is the following:
// voronoi kernels
//
// local memory version
//
kernel void voronoiL(write_only image2d_t outputImage)
{
// get id of element in array
int x = get_global_id(0);
int y = get_global_id(1);
int w = get_global_size(0);
int h = get_global_size(1);
float4 result = (float4)(0.0f,0.0f,0.0f,1.0f);
float MinRe = -2.0f;
float MaxRe = 1.0f;
float MinIm = -1.5f;
float MaxIm = MinIm+(MaxRe-MinRe)*h/w;
float Re_factor = (MaxRe-MinRe)/(w-1);
float Im_factor = (MaxIm-MinIm)/(h-1);
float MaxIterations = 50;
//C imaginary
float c_im = MaxIm - y*Im_factor;
//C real
float c_re = MinRe + x*Re_factor;
//Z real
float Z_re = c_re, Z_im = c_im;
bool isInside = true;
bool col2 = false;
bool col3 = false;
int iteration =0;
for(int n=0; n<MaxIterations; n++)
{
// Z - real and imaginary
float Z_re2 = Z_re*Z_re, Z_im2 = Z_im*Z_im;
//if Z real squared plus Z imaginary squared is greater than c squared
if(Z_re2 + Z_im2 > 4)
{
if(n >= 0 && n <= (MaxIterations/2-1))
{
col2 = true;
isInside = false;
break;
}
else if(n >= MaxIterations/2 && n <= MaxIterations-1)
{
col3 = true;
isInside = false;
break;
}
}
Z_im = 2*Z_re*Z_im + c_im;
Z_re = Z_re2 - Z_im2 + c_re;
iteration++;
}
if(col2)
{
result = (float4)(iteration*0.05f,0.0f, 0.0f, 1.0f);
}
else if(col3)
{
result = (float4)(255, iteration*0.05f, iteration*0.05f, 1.0f);
}
else if(isInside)
{
result = (float4)(0.0f, 0.0f, 0.0f, 1.0f);
}
write_imagef(outputImage, (int2)(x, y), result);
}
You can also find it here:
https://docs.google.com/file/d/0B6DBARvnB__iUjNSTWJubFhUSDA/edit
See this link. It's developed by #eric-bainville. The CPU code both native and with OpenCL is not optimal (it does not use SSE/AVX) but I think the GPU code may be good. For the CPU you can speed up the code quite a bit by using AVX and operating on eight pixels at once.
http://www.bealto.com/mp-mandelbrot.html

convert from IPLImage to QImage in 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

Resources