GDI+, using DrawImage to draw a transperancy mask of the source image - gdi+

Is it possible to draw a transperancy mask of an image (that is, paint all visible pixels with a constant color) using Graphics::DrawImage? I am not looking for manually scanning the image pixel-by-pixel and creating a seperate mask image, I wonder if it's possible to draw one directly from the original image.
My guessing is that it should be done with certain manipulations to ImageAttributes, if possible at all.
The color of the mask is arbitrary and should be accurate, and it would be a plus if there can be a threshold value for the transparency.

I have to draw an image with a per pixel alpha mask and found the best way was to just draw the base RGB image then draw the opaque parts of the alpha mask over the top. You need to map each alpha level to an alpha level + colour to get the image to honour every detail in the alpha mask. The code I've got has the alpha mask as a seperate 8bit image but the draw code looks like this:
g.DrawImage(&picture, r.left, r.top, r.Width(), r.Height()); // base image
if ( AlphaBuf != NULL ) // do we have and alpha mask?
{
Gdiplus::Bitmap mask(Width, Height, Width(), PixelFormat8bppIndexed, AlphaBuf);
picture.GetPalette( palette, picture.GetPaletteSize() );
// invert - only shows the transparent
palette->Entries[0] = DLIMAKEARGB(255, 0, 0, 200); // 0 = fully transparent
palette->Entries[255] = DLIMAKEARGB(0, 0, 0, 0); // 255 = fully opaque
mask.SetPalette(palette);
g.DrawImage(&mask, r.left, r.top, r.Width(), r.Height()); // draw the mask
}
My alpha masks are only full transparent or full opaque but I would think that setting the other alpha values in the pallette would let you follow a more graduated mask.
palette->Entries[1] = DLIMAKEARGB(254, 0, 0, 200);
palette->Entries[2] = DLIMAKEARGB(253, 0, 0, 200);
etc..
Hope this helps (or at least makes sense :-p )

Do you mean that you want to transform every existing color in the bitmap into one uniform color, while fully honoring the alpha/transparency information present in the image?
If so, just use the following colormatrix:
imageAttributes.SetColorMatrix( new ColorMatrix( new float[][] {
new float[] {0, 0, 0, 0, 0},
new float[] {0, 0, 0, 0, 0},
new float[] {0, 0, 0, 0, 0},
new float[] {0, 0, 0, 1, 0},
new float[] {r, g, b, 0, 1}} ) );
where r, g, b are between 0 and 1, like so:
float r = DesiredColor.R / 255f;
float g = DesiredColor.G / 255f;
float B = DesiredColor.B / 255f;
I don't understand what you mean by "it would be a plus if there can be a threshold value for the transparency", though... so maybe this isn't the answer you were looking for?

Related

camera origin is visible with projection matrix

In the image above, I show the result of having the camera positioned in the same position as the vertex covered by the mouse. A similar result comes from using an orthographic matrix. My problem is that when rotating the camera, it rotates around the visible origin of the camera. What I want is for the view to rotate like normal FPS Cameras.
What I believe to be useful information:
I am doing the math manually and rendering to the screen using OpenGL.
The cube's vertices are from {0, 0, 0} to {1, 1, 1}
The camera is positioned at {0, 0, 0}
My (4x4) matrices are in column major and I get the same result from uploading the individual matrices to the shader via uniforms and multiplying them in the same order
The movement and rotation is otherwise sensible even when translating the camera, just that the origin of the camera is visible.
This last point makes sense to me mathematically with an orthographic projection, however, since the near clipping plane is supposed to be slightly in front of the camera, I'd expect the point near the mouse to be clipped. I know for a fact that it is not clipped, because if I rotate the camera to look down on the cube (without translating it), the clipping plane cuts off roughly halfway up that vertical edge of the cube.
I think my confusion may be due to a fundamental misunderstanding of how the mathematics works for the perspective projection matrix, but it may be due to my code as well, so let me include that:
static inline constexpr auto ortho(T l, T r, T b, T t, T n, T f) {
return Matrix4x4{{(T)2 / (r - l), 0, 0, 0},
{0, (T)2 / (t - b), 0, 0},
{0, 0, (T)2 / (n - f), 0},
{(l + r) / (l - r), (b + t) / (b - t), (f + n) / (n - f), 1}};
}
static inline constexpr auto perspective(T fov, T aspect, T near, T far) {
const T q = (T)1.0 / std::tan(0.5 * fov),
a = q * aspect,
b = (near + far) / (near - far),
c = near * far * 2 / (near - far);
return Matrix4x4{
{q, 0, 0, 0},
{0, a, 0, 0},
{0, 0, b, -1},
{0, 0, c, 1},
};
}
If anyone needs extra information on what is going on, let me know in the comments and will happily either answer or make an addendum to the question
After reading the link provided in the comments, and comparing my method with the code that I had written, I realized that I made a mistake in transcribing the mathematics into my code. I accidentally put a 1 in the last row of the last column of the perspective matrix, while it should have been a 0.
The corrected code is shown here:
static inline constexpr auto perspective(T fov, T aspect, T near, T far) {
const T q = (T)1.0 / std::tan(0.5 * fov),
a = q * aspect,
b = (near + far) / (near - far),
c = near * far * 2 / (near - far);
return Matrix4x4{
{q, 0, 0, 0},
{0, a, 0, 0},
{0, 0, b, -1},
{0, 0, c, 0},
};
}

Duplicate structured surface/mesh in gmsh

I'm trying to build a large structure from a simple geometric shape in gmsh and I'd like to use a structured (quadrilateral) grid. I start by creating that shape and then duplicating and translating it as often as needed to build my final structure.
The problem is that even if I define the lines and surfaces of the original shape to be transfinite, this property is lost once I duplicate and translate it. Check this sample code for a square:
Point(1) = {0, 0, 0, 1};
Point(2) = {0, 1, 0, 1};
Point(3) = {1, 1, 0, 1};
Point(4) = {1, 0, 0, 1};
Line(1) = {1, 2};
Line(2) = {2, 3};
Line(3) = {3, 4};
Line(4) = {4, 1};
Line Loop(5) = {1, 2, 3, 4};
Plane Surface(6) = {5};
Transfinite Line {1, 2, 3, 4} = 10 Using Progression 1;
Transfinite Surface {6};
Recombine Surface {6};
Translate {0, 1, 0} {
Duplicata { Surface{6}; }
}
I obtain the original square with a structured grid but the duplicated one does not have this property.
Is there a possibility to retain the structured grid when I copy the surface?
EDIT: It seems that there is indeed no possibility to duplicate a structured volume or surface. The problem is that these properties are directly related to the mesh itself and not the geometry. And the mesh cannot be duplicated.
It is possible.
You can use the GMSH Geometry.CopyMeshingMethod property that is responsible for copying the meshing method for duplicated or translated geometric entities. By default, it is turned off. To turn it on, you can simply add the following line to the beginning of your GEO file.
Geometry.CopyMeshingMethod = 1;
Now, compare:
Tested on GMSH 3.0.5, but should work with any modern version.
This fix (using "Geometry.CopyMeshingMethod = 1;") works unless you use OpenCASCADE to define your geometry.
Try simply to include "SetFactory("OpenCASCADE");" in the beginning of your script and you will see it fails.

How to determine the side of an octahedron and a dodecahedron using an accelerometer?

I have three figures: a cube, an octahedron, a dodecahedron.
Inside, each figure has an accelerometer.
The sides of the figures numbered between 1 and n.
Task: determine the current side of the cube, octahedron, dodecahedron.
For the cube, I derived the formula:
side = round((Ax*1/988)+(Ay*2/988)+(Az*3/988));
Variable "side" will give values in interval -3 and 3 (without 0), which means the current side of cube between 1 and 6.
Now I need to do the same for the octahedron and the dodecahedron. Help, how can I do this? Do I need additional sensors or accelerometer is enough?
Using a formula like that is quite clever but it has some undesirable properties. Firstly, when moving from one side to another, it will move through some intermediate values as a result of the formula that are geometrically meaningless. For example, if you are on side -3 and rotate to side -1, it will necessarily move through -2. Secondly it may not be robust to noisy accelerometer data, for example a vector that is part way between sides -3 and -1, but closer to -1 may give -2, when it should give -1.
An alternative approach is to store an array of face normals for the figure, and then take the dot product of the accelerometer reading with each of them. The closest match (the one with the highest dot product) is the closest side.
e.g:
float cube_sides[6][3] = {
{-1, 0, 0},
{0, -1, 0},
{0, 0, -1},
{1, 0, 0},
{0, 1, 0},
{0, 0, 1},
};
int closest_cube_side(float Ax, float Ay, float Az)
{
float largest_dot = 0;
int closest_side = -1; // will return -1 in case of a zero A vector
for(int side = 0; side < 6; side++)
{
float dot = (cube_sides[side][0] * Ax) +
(cube_sides[side][1] * Ay) +
(cube_sides[side][2] * Az);
if(dot > largest_dot)
{
largest_dot = dot;
closest_side = side;
}
}
return closest_side;
}
You can extend this for an octahedron and dodecahedron just by using the surface normals for each. No additional sensors should be necessary.

Coordinates system in Babylon.js

I'm a little confused about the coordinates system in Babylon.js. That is, when I use the following sequence of statements :
var camera = new BABYLON.ArcRotateCamera("Camera", 0, 0, 50, new BABYLON.Vector3(0, 0, 0), scene);
var sphere1 = BABYLON.Mesh.CreateSphere("sphere1", 16, 1.0, scene);
the sphere is painted in the center of the screen. OK. When I use the following sequence :
var camera = new BABYLON.ArcRotateCamera("Camera", 50, 0, 0, new BABYLON.Vector3(0, 0, 0), scene);
var sphere1 = BABYLON.Mesh.CreateSphere("sphere1", 16, 1.0, scene);
no sphere is painted.
I know that usually the coordinates (in CG) are as follows: Oy - vertical, Ox - horizontal, Oz - pointing to the screen. So, in the second sequence, the camera is in the point x = 50, in the plane xOz (that is ground) and is looking to origin, where the sphere is.
I guess somewhere on the road I was lost. Can you help to understand where I am wrong ?
Thank you,
Eb_cj
Hello ArcRotateCamera uses two angles (alpha and beta) to define the position of the camera on a sphere centered around a point.
Feel free to read this for more info:
https://github.com/BabylonJS/Babylon.js/wiki/05-Cameras

Oblique perspective - projection matrizes in processing

I want to extend processing in order to be able to render 3D stuff with oblique projections (cabinet or cavalier). After looking around source of the camera(), perspective() and ortho() methods I was able to set up an orthographic perspective and then adjust the PGraphics3D#camera matrix to an appropriate value with partial success.
void setup() {
camera(30, 30, 30, 0, 0, 0, 1, 1, 0);
ortho(-100, 100, -100, 100, -500, 500);
p3d.camera.set(1, 0, -0.433f, 0, 0, 1, 0.25f, 0, 0, 0, 0, 0, 0, 0, 0, 1);
}
void draw() {
box(20);
}
This results in the right perspective, but without surface filling. When removing either the camera and ortho method calls or both, the screen is empty, although I'd expect camera(...) to operate on the same matrix that is overwritten later on.
Moreover I'm a little bit confused about the matrizes in PGraphics3D: camera, modelView and projection. While OpenGL keeps two matrix stacks - modelView and projection, here is a third one - camera. Can anybody shed some light on the difference and relation between these matrizes?
This would be helpful in order to know when to use/set which one.
Great question!
I ran the following code as you had it, and it looked like an isometric view of a white cube.
1: size(300,300,P3D);
2: camera(30, 30, 30, 0, 0, 0, 1, 1, 0);
3: ortho(-100, 100, -100, 100, -500, 500);
4: PGraphics3D p3d = (PGraphics3D)g;
5: p3d.camera.set(1, 0, -0.433f, 0, 0, 1, 0.25f, 0, 0, 0, 0, 0, 0, 0, 0, 1);
6: box(20);
Here's what's happening:
Line 2: sets both the camera and modelview matrices
Line 3: sets the projection matrix
Line 4: sets the camera matrix only, but this actually did nothing here. (read on)
Transformations are only performed using the modelview and projection matrices. The camera matrix is merely a convenient separation of what the modelview is usually initialized to.
If you used the draw() function, the modelview matrix is actually initialized to the camera matrix before each time it is called. Since you didn't use the draw() function, your camera matrix was never updated with your oblique transform in your camera matrix.
How to create an Oblique Projection
As a disclaimer, you must truly understand how matrices are used to transform coordinates. Order is very important. This is a good resource for learning it:
http://glprogramming.com/red/chapter03.html
The quickest explanation I can give is that the modelview matrix turns object coordinates into relative eye coordinates, then the projection matrix takes those eye coordinates and turns them in to screen coordinates. So you want to apply the oblique projection before the transformation into screen coordinates.
Here's a runnable example for creating a cabinet projection that displays some cubes:
void setup()
{
strokeWeight(2);
smooth();
noLoop();
size(600,600,P3D);
oblique(radians(60),0.5);
}
void draw()
{
background(100);
// size of the box
float w = 100;
// draw box in the middle
translate(width/2,height/2);
fill(random(255),random(255),random(255),100);
box(w);
// draw box behind
translate(0,0,-w*4);
fill(random(255),random(255),random(255),100);
box(w);
// draw box in front
translate(0,0,w*8);
fill(random(255),random(255),random(255),100);
box(w);
}
void oblique(float angle, float zscale)
{
PGraphics3D p3d = (PGraphics3D)g;
// set orthographic projection
ortho(-width/2,width/2,-height/2,height/2,-5000,5000);
// get camera's z translation
// ... so we can transform from the original z=0
float z = p3d.camera.m23;
// apply z translation
p3d.projection.translate(0,0,z);
// apply oblique projection
p3d.projection.apply(
1,0,-zscale*cos(angle),0,
0,1,zscale*sin(angle),0,
0,0,1,0,
0,0,0,1);
// remove z translation
p3d.projection.translate(0,0,-z);
}

Resources