(iOS) Accelerometer Graph (convert g-force to +/- 128) granularity - ios

I am using this Accelerometer graph from Apple and trying to convert their G-force code to calculate +/- 128.
The following image shows that the x, y, z values in the labels do not match the output on the graph: (Note that addX:y:z values are what is shown in the labels above the graph)
ViewController
The x, y, z values are received from a bluetooth peripheral, then converted using:
// Updates LABELS
- (void)didReceiveRawAcceleromaterDataWithX:(NSInteger)x Y:(NSInteger)y Z:(NSInteger)z
{
dispatch_async(dispatch_get_main_queue(), ^{
_labelAccel.text = [NSString stringWithFormat:#"x:%li y:%li z:%li", (long)x, (long)y, (long)z];
});
}
// Updates GRAPHS
- (void)didReceiveAcceleromaterDataWithX:(NSInteger)x Y:(NSInteger)y Z:(NSInteger)z
{
dispatch_async(dispatch_get_main_queue(), ^{
float xx = ((float)x) / 8192;
float yy = ((float)y) / 8192;
float zz = ((float)z) / 8192;
[_xGraph addX:xx y:0 z:0];
[_yGraph addX:0 y:yy z:0];
[_zGraph addX:0 y:0 z:zz];
});
}
GraphView
- (BOOL)addX:(UIAccelerationValue)x y:(UIAccelerationValue)y z:(UIAccelerationValue)z
{
// If this segment is not full, then we add a new acceleration value to the history.
if (index > 0)
{
// First decrement, both to get to a zero-based index and to flag one fewer position left
--index;
xhistory[index] = x;
yhistory[index] = y;
zhistory[index] = z;
// And inform Core Animation to redraw the layer.
[layer setNeedsDisplay];
}
// And return if we are now full or not (really just avoids needing to call isFull after adding a value).
return index == 0;
}
- (void)drawLayer:(CALayer*)l inContext:(CGContextRef)context
{
// Fill in the background
CGContextSetFillColorWithColor(context, kUIColorLightGray(1.f).CGColor);
CGContextFillRect(context, layer.bounds);
// Draw the grid lines
DrawGridlines(context, 0.0, 32.0);
// Draw the graph
CGPoint lines[64];
int i;
float _granularity = 16.f; // 16
NSInteger _granualCount = 32; // 32
// X
for (i = 0; i < _granualCount; ++i)
{
lines[i*2].x = i;
lines[i*2+1].x = i + 1;
lines[i*2].y = xhistory[i] * _granularity;
lines[i*2+1].y = xhistory[i+1] * _granularity;
}
CGContextSetStrokeColorWithColor(context, _xColor.CGColor);
CGContextStrokeLineSegments(context, lines, 64);
// Y
for (i = 0; i < _granualCount; ++i)
{
lines[i*2].y = yhistory[i] * _granularity;
lines[i*2+1].y = yhistory[i+1] * _granularity;
}
CGContextSetStrokeColorWithColor(context, _yColor.CGColor);
CGContextStrokeLineSegments(context, lines, 64);
// Z
for (i = 0; i < _granualCount; ++i)
{
lines[i*2].y = zhistory[i] * _granularity;
lines[i*2+1].y = zhistory[i+1] * _granularity;
}
CGContextSetStrokeColorWithColor(context, _zColor.CGColor);
CGContextStrokeLineSegments(context, lines, 64);
}
How can I calculate the above code to show the correct accelerometer values on the graph with precision?

I post this as an aswer not a comment, because I have not enough reputation, but what I'll write might be enough to send you in the right direction, that it even may count as an answer...
Your question still doesn't include what is really important. I assume the calculation of the xx/yy/zz is no problem. Although I have no idea what the 8192 is supposed to mean.
I guess the preblem is in the part where you map your values to pixel coordinates...
the lines[] contains your values in a range of 1/8192th of the values in the label. so your x value of -2 should be at a pixel position of -0.0000something, so slightly(far less than 1 Pixel) above the view... Because you see the line a lot further down there must be some translation in place (not shown in your code)
The second part that is important but not shown is DrawGridlines. Probably in there is a different approach to map the values to pixel-coordinates...
Use the debugger to check what pixel-coordinates you get when draw your +127-line and what you get if you insert the value of +127 in your history-array
And some Ideas for improvements when reading your code:
1.)Put the graph in it's own class that draws one graph(and has only one history. Somehow you seem to have that partially already (otherwise I cannot figure out your _xGraph/_yGraph/_zGraph) But on the other hand you draw all 3 values in one drawLayer??? Currently you seem to have 3*3 history buffers of which 3*2 are filled with zeros...
2.) use one place where you do the calculation of Y that you use both for drawing the grid and drawing the lines...
3.) use CGContextMoveToPoint(); + CGContextAddLineToPoint(); instead of copying into lines[] with these ugly 2*i+1 indecies...

Related

Template Matching on various sizes

Right now I am working on an OCR algorithm with Template Matching, using the opencv library. I am comparing pixel by pixel, and till now I have obtained good results. The problem comes when the area I want to match is of different size.
Ex: Template size = 70x100 while ROI = 140x200.
Is there any function that I can use in order adapt the required size and end up with the same amount of rows and columns?
Thanks
Robert Grech
Usually one makes an image scale pyramid and then only scans with the 70x100 windows across all scales i.e. as in opencv HOGDescriptor:
double scale = 1.;
double scale0 = 1.05;
int maxLevels = 64;
int nLevels;
Size templateSize(70,100);
cv::Mat testImage = cv::imread("test1.jpg");
vector<double> levelScale;
for( nLevels = 0; nLevels < maxLevels; nLevels++ )
{
levelScale.push_back(scale);
if( cvRound(testImage.cols/scale) < templateSize.width ||
cvRound(testImage.rows/scale) < templateSize.height ||
scale0 <= 1 )
break;
scale *= scale0;
}
nLevels = std::max(nLevels, 1);
levelScale.resize(nLevels);
int level;
for(level =0; level<nLevels; level++)
{
cv::Mat testAtScale;
Size sz(cvRound(testImage.cols/levelScale[level]),
cvRound(testImage.rows/levelScale[level]));
resize(testImage,testAtScale,sz);
//result = match(template,testAtScale);
//cv::imshow("sclale",testAtScale);
//cv::waitKey();
}
you would then need to post-process your results back to the original scale, this is simple with a box, but if you have a heat map / response map / probability map, then re-sizing it back up maybe somewhat hacky.

What is the correct way to apply filter to a image

I was wondering what the correct way would be to apply filter to a image. The image processing textbook that I am reading only talks about the mathematical and theoretical aspect of filters but doesn't talk much the programming part of it !
I came up with this pseudo code could some one tell me if it is correct cause I applied the sobel edge filter to a image and I am not satisfied with the output. I think it detected many unnecessary points as edges and missed out on several points along the edge.
int filter[][] = {{0d,-1d,0d},{-1d,8d,-1d},{0d,-1d,0d}};// I dont exactly remember the //sobel filter
int total = 0;
for(int i = 2;i<image.getWidth()-2;i++)
for(int j = 2;j<image.getHeight()-2;j++)
{
total = 0;
for(int k = 0;k<3;k++)
for(int l = 0;l<3;l++)
{
total += intensity(image.getRGB(i,j)) * filter[i+k][j+l];
}
if(total >= threshold){
image.setRGB(i,j,WHITE);
}
}
int intensity(int color)
{
return (((color >> 16) & 0xFF) + ((color >> 8) & 0xFF) + color)/3;
}
Two issues:
(1) The sober operator includes x-direction and y-direction, they are
int filter[][] = {{1d,0d,-1d},{2d,0d,-2d},{1d,0d,-1d}}; and
int filter[][] = {{1d,2d,1d},{0d,0d,0d},{-1d,-2d,-1d}};
(2) The convolution part:
total += intensity(image.getRGB(i+k,j+l)) * filter[k][l];
Your code doesn't look quiet right to me. In order to apply the filter to the image you must apply the discrete time convolution algorithm http://en.wikipedia.org/wiki/Convolution.
When you do convolution you want to slide the 3x3 filter over the image, moving it one pixel at a time. At each step you multiply the value of the filter 'pixel' by the corresponding value of the image pixel which is under that particular filter 'pixel' (the 9 pixels under the filter are all affected). The values that result should be added up onto a new resulting image as you go.
Thresholding is optional...
The following is your code modified with some notes:
int filter[][] = {{0d,-1d,0d},{-1d,8d,-1d},{0d,-1d,0d}};
//create a new array for the result image on the heap
int newImage[][][3] = ...
//initialize every element in the newImage to 0
for(int i = 0;i<image.getWidth()-1;i++)
for(int j = 0;j<image.getHeight()-1;j++)
for (int k = 0; k<3; k++)
{
newImage[i][j][k] = 0;
}
//Convolve the filter and the image
for(int i = 1;i<image.getWidth()-2;i++)
for(int j = 1;j<image.getHeight()-2;j++)
{
for(int k = -1;k<2;k++)
for(int l = -1;l<2;l++)
{
newImage[i+k][j+l][1] += getRed(image.getRGB(i+k ,j+l)) * filter[k+1][l+1];
newImage[i+k][j+l][2] += getGreen(image.getRGB(i+k ,j+l)) * filter[k+1][l+1];
newImage[i+k][j+l][3] += getBlue(image.getRGB(i+k ,j+l)) * filter[k+1][l+1];
}
}
int getRed(int color)
{
...
}
int getBlue(int color)
{
...
}
int getGreen(int color)
{
...
}
Please note that the code above does not handle the edges of the image exactly right. If you wanted to make it absolutely perfect you'd start by sliding the filter mostly off screen (so the first position would apply the lower right corner of the filter to the image 0,0 pixel of the image. Doing this is really a pain though, so usually its easier just to ignore the 2 pixel border around the edges.
Once you've got that working you can experiment by sliding the Sobel filter in the horizontal and then the vertical directions. You will notice that the filter acts most strongly on lines which are perpendicular to the direction of travel (to the filter). So for the best results apply the filter in the horizontal and then the vertical direction (using the same newImage). That way you will detect vertical as well as horizontal lines equally well. :)
You have some serious undefined behavior going on here. The array filter is 3x3 but the subscripts you're using i+k and j+l are up to the size of the image. It looks like you've misplaced this addition:
total += intensity(image.getRGB(i+k,j+l)) * filter[k][l];
Use GPUImage, it's quite good for you.

GB2ShapeCache Shape Scale? (Physics Editor) [Box2D]

There is a class associated with the program Physics Editor called GB2ShapeCache that loads shapes that I make in the program. I noticed that it is not currently possible to change the scale of the shapes on the fly so I would like to be able to scale the fixtures for the shapes that I made in Physics Editor. Now the scale of my CCSprite in my app can be random so currently in the addShapesWithFile method, I do this for polygons:
vertices[vindex].x = (offset.x * sprite.scaleX) / ptmRatio_;
vertices[vindex].y = (offset.y * sprite.scaleY) / ptmRatio_;
and this for circles:
circleShape->m_radius = ([[circleData objectForKey:#"radius"] floatValue] / ptmRatio_) *sprite.scale;
I also changed the method so that I can pass in my sprite so I can get the scale to:
-(void) addShapesWithFile:(NSString*)plist forSprite:(CCSprite*)sprite
so that I can pass in my sprite so I can get the scale.
HOWEVER, I find this to be inefficient because I should not have to reload ALL my shapes in my plist since they are already added.
So is there any way to do what I am doing now but in the addFixturesToBody method? This way I do not re-create the already added plist shapes and I only scale the fixtures when it is ready to be added to my body.
If anyone needs to see more code or needs more info, feel free to ask. I know this issue must be simple!!!
Thanks!
I would recommend implementing it in the addFixturesToBody method.
(see https://github.com/AndreasLoew/GBox2D/blob/master/GBox2D/GB2ShapeCache.mm)
Try this method below, this should scale the shapes accordingly to the sprite's they are for. Just pass in your CCSprite and this method will handle the rest.
- (void)addFixturesToBody:(b2Body*)body forShapeName:(NSString*)shape forSprite:(CCSprite*)sprite {
BodyDef *so = [shapeObjects_ objectForKey:shape];
assert(so);
FixtureDef *fix = so->fixtures;
if ((sprite.scaleX == 1.0f) && (sprite.scaleY == 1.0f)) {
// simple case - so do not waste any energy on this
while(fix) {
body->CreateFixture(&fix->fixture);
fix = fix->next;
}
} else {
b2Vec2 vertices[b2_maxPolygonVertices];
while(fix) {
// make local copy of the fixture def
b2FixtureDef fix2 = fix->fixture;
// get the shape
const b2Shape *s = fix2.shape;
// clone & scale polygon
const b2PolygonShape *p = dynamic_cast<const b2PolygonShape*>(s);
if(p)
{
b2PolygonShape p2;
for(int i=0; i<p->m_vertexCount; i++)
{
vertices[i].x = p->m_vertices[i].x * sprite.scaleX;
vertices[i].y = p->m_vertices[i].y * sprite.scaleY;
}
p2.Set(vertices, p->m_vertexCount);
fix2.shape = &p2;
}
// clone & scale circle
const b2CircleShape *c = dynamic_cast<const b2CircleShape *>(s);
if(c) {
b2CircleShape c2;
c2.m_radius = c->m_radius * sprite.scale;
c2.m_p.x = c->m_p.x * sprite.scaleX;
c2.m_p.y = c->m_p.y * sprite.scaleY;
fix2.shape = &c2;
}
// add to body
body->CreateFixture(&fix2);
fix = fix->next;
}
}
}

Problem assigning values to Mat array in OpenCV 2.3 - seems simple

Using the new API for OpenCV 2.3, I am having trouble assigning values to a Mat array (or say image) inside a loop. Here is the code snippet which I am using;
int paddedHeight = 256 + 2*padSize;
int paddedWidth = 256 + 2*padSize;
int n = 266; // padded height or width
cv::Mat fx = cv::Mat(paddedHeight,paddedWidth,CV_64FC1);
cv::Mat fy = cv::Mat(paddedHeight,paddedWidth,CV_64FC1);
float value = -n/2.0f;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
fx.at<cv::Vec2d>(i,j) = value++;
value = -n/2.0f;
}
meshElement = -n/2.0f;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
fy.at<cv::Vec2d>(i,j) = value;
value++;
}
Now in the first loop as soon as j = 133, I get an exception which seems to be related to depth of the image, I cant figure out what I am doing wrong here.
Please Advise! Thanks!
You are accessing the data as 2-component double vector (using .at<cv::Vec2d>()), but you created the matrices to contain only 1 component doubles (using CV_64FC1). Either create the matrices to contain two components per element (with CV_64FC2) or, what seems more appropriate to your code, access the values as simple doubles, using .at<double>(). This explodes exactly at j=133 because that is half the size of your image and when treated as containing 2-component vectors when it only contains 1, it is only half as wide.
Or maybe you can merge these two matrices into one, containing two components per element, but this depends on the way you are going to use these matrices in the future. In this case you can also merge the two loops together and really set a 2-component vector:
cv::Mat f = cv::Mat(paddedHeight,paddedWidth,CV_64FC2);
float yValue = -n/2.0f;
for(int i=0;i<n;i++)
{
float xValue = -n/2.0f;
for(int j=0;j<n;j++)
{
f.at<cv::Vec2d>(i,j)[0] = xValue++;
f.at<cv::Vec2d>(i,j)[1] = yValue;
}
++yValue;
}
This might produce a better memory accessing scheme if you always need both values, the one from fx and the one from fy, for the same element.

randomness from spritemap in spritebatch

Im sure this is easily fixed, and I do have searched both high and low, traversed the net both east, west, north and south but to no prevail...
My problem is this. Im in the middle of trying to make a bejeweled clone, just to get me started in xna. However im stuck on the random plotting of gems/icons/pictures.
This is what i have.
First a generated list of positions, a random and a rectangle:
List<Vector2> platser = new List<Vector2>();
Random slump = new Random();
Rectangle bildsourcen;
protected override void Initialize()
{
for (int j = 0; j < 5; j++)
{
for (int i = 0; i < 5; i++)
{
platser.Add(new Vector2((i*100),(j*100)));
}
}
base.Initialize();
}
Pretty straight-forward.
I also have loaded a texture, with 5 icons/gems/pictures -> 5*100px = width of 500px.
allImage = Content.Load<Texture2D>("icons/all");
Then comes the "error".
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
int x = slump.Next(2);
bildsourcen = new Rectangle((x * 100), 0, 100, 100);
for (int i = 0; i < platser.Count; i++)
{
spriteBatch.Draw(allImage, new Rectangle((int)platser[i].X, (int)platser[i].Y, 100, 100), bildsourcen, Color.White);
}
So, there is my code. And this is what happens:
I want it to randomly pick a part of my image and plot it at the given coords taken from the vector2-list. However, it puts the same image at all coords and keeps randomly replacing them, not with random images but with the same. So the whole board keeps flickering the same icons. Ie, instead of generating 15231 and keeping it frozen, it one second puts 11111 and the next second it puts 33333.
Does anybody understand what im trying to describe ? I'm almost at the point of pulling my own hair out. The cat's hair has already been pulled...
Thx in advance
The Draw function is called once each frame. This line:
int x = slump.Next(2);
Is generating a random number (either a 0 or a 1 in this case) each frame, hence the flicker.
The line after that selects a sprite from your sprite atlas based on that number (specifically it specifies the rectangle containing that sprite). And in the loop that follows you're drawing multiple copies of that sprite (always the same image).
You should be doing all of your game logic in your Update function. That function will give you a time and you will probably want to implement a method of waiting for a certain amount of time to pass before you generate a random block (so keep accumulating the time that passes between each Update, until it reaches some threshold). The exact mechanics of when you want to generate your random block is up to you.
Of course, that is not to mention that there are other flaws in the structure of your code. Bejewelled is played on a fixed-sized board with different coloured blocks (each block you could represent with a number from 1 to X). The location of the blocks should be be implicit in your data structure (so you don't need to generate your platser list).
So your Game class should have something like:
const int BoardWidth = 10;
const int BoardHeight = 10;
int[,] board = new int[BoardWidth, BoardHeight];
Then in your Initialize function you should fill board and perhaps use 0 as an empty space and 1 to X to represent your colours, like so:
for(int x = 0; x < BoardWidth; x++) for(int y = 0; y < BoardHeight; y++)
{
board[x,y] = slump.Next(1, 6); // gives 5 different sprites
}
Then in Update wait for user input or a time-out before modifying the board (depending on your gameplay).
Then in your Draw function do something like this:
for(int x = 0; x < BoardWidth; x++) for(int y = 0; y < BoardHeight; y++)
{
if(board[x,y] == 0) continue; // don't render an empty space
Vector2 position = new Vector2(100*x, 100*y);
Rectangle bildsourcen = new Rectangle(100*(board[x,y]-1), 0, 100, 100);
sb.Draw(allImage, position, bildsourcen, Color.White);
}

Resources