Weird order when painting triangle outlines using GL_LINE_STRIP - ios

I'm developing an app for iOS-Plaftorms using OpenGL.
Currently I'm having a weird issue when painting a plane (terrain) which consists of multiple subplanes, where each subplane consists of 2 triangles forming a rect. I'm painting this terrain as a wireframe by using a call to glDrawElements and provide the parameters GL_Line_Strip and the precalculated indices. The problem is that the triangles get painted in the wrong order or are rather vertically mirrored. They do not get painted in the order how I specified the indices, which is confusing.
This is the simplified code to generate the vertices:
int pos = 0;
for(NSInteger y = - gridSegmentsY / 2; y < gridSegmentsY / 2; y ++) {
for(NSInteger x = - gridSegmentsX / 2; x < gridSegmentsX / 2; x ++) {
vertices[pos++] = x * 5;
vertices[pos++] = y * 5;
vertices[pos++] = 0;
}
}
This is how I generate the indices including degenerated ones (To use as IBO).
pos = 0;
for(int y = 0; y < gridSegmentsY - 1; y ++) {
if (y > 0) {
// Degenerate begin: repeat first vertex
indices[pos++] = (unsigned short)(y * gridSegmentsY);
}
for(int x = 0; x < gridSegmentsX; x++) {
// One part of the strip
indices[pos++] = (unsigned short)((y * gridSegmentsY) + x);
indices[pos++] = (unsigned short)(((y + 1) * gridSegmentsY) + x);
}
if (y < gridSegmentsY - 2) {
// Degenerate end: repeat last vertex
indices[pos++] = (unsigned short)(((y + 1) * gridSegmentsY) + (gridSegmentsX - 1));
}
}
So in this part...
indices[pos++] = (unsigned short)((y * gridSegmentsY) + x);
indices[pos++] = (unsigned short)(((y + 1) * gridSegmentsY) + x);
...I'm setting the first index in the indices array to point to the current (x,y) and the next index to (x,y+1). I'm doin' this for all x's in the current strip, then I'm handling degenerated triangles and repeat this procedure for the next strip (y+1).
This method is taken from http://www.learnopengles.com/android-lesson-eight-an-introduction-to-index-buffer-objects-ibos/
So I expect the resulting mesh to get painted like:
a----b----c
| /| /|
| / | / |
| / | / |
|/ |/ |
d----e----f
| /| /|
| / | / |
| / | / |
|/ |/ |
g----h----i
by painting it as described using:
glDrawElements(GL_LINE_STRIP, indexCount, GL_UNSIGNED_SHORT, 0);
...since I expect GL_Line_Strip to paint first a line from (a->d), then from (d->b), then (b, e)... and so on (as specified in the indices calculation)
But what actually gets painted is:
*----*----*
|\ |\ |
| \ | \ |
| \ | \ |
| \| \|
*----*----*
|\ |\ |
| \ | \ |
| \ | \ |
| \| \|
*----*----*
So the triangles are somehow painted in the wrong order and I need to know why? ;). Does somebody know? Does the problem lie in using GL_Line_Strip or is there a bug in my code?
My eye is at (0.0f, 0.0f, 20.0f) and looks at (0,0,0). The mesh is painted along the x-axis & y-axis from left to right with z = 0, so the mesh should not be flipped or anything.

Did you remember to account for the fact that opengl's 0,0 is bottom-left and not top-left (like Core Graphics)? Coordinate system origin and handedness is important - and can result in exactly the mirroring that you are seeing.

Related

Getting size of point for collision detection

Forgive me if my terminology is wrong, but I'm just trying to do some simple point collision detection in WebGL. I have a bunch of gl.POINTS floating around a canvas (640x480, set as HTML attributes), I've set gl_PointSize = 10.0 in my vertex shader, and am trying to convert this to the correct coordinate system.
I just want to do some basic collision detection based on the four corners of each rendered point (just to have the points bounce off each other, given I've increased their size to represent a square).
The issue I'm having is that I can't seem to wrap my head around how to calculate their exact size. I have their vertex location and thought I could simply do a normalization between the canvas size, point size, and the WebGL coordinates of [-1, 1].
Basically, is there a 'simple' way to calculate the precise size of a point?
The size of a point is its center +/- half its size
+-[canvas]-----------------------+
| |
| |
| |
| +---+ |
| | + | |
| +---+ |
| |
+--------------------------------+
In the example above the canvas 32x7
The center of the point is at 4x2 in pixels. Its gl_PointSize is 3. Its clip space position would be
cx = px / canvasWidth * 2 - 1
cx = 4 / 32 * 2 - 1 = -0.75
cy = py / canvasHeight * 2 - 1
cy = 2 / 7 * 2 - 1 = -0.43
Its clip space width and height are
clipWidth = gl_PointSize / canvasWidth
clipHeight = gl_PointSize / canvasHeight
Also remember that +Y is up in WebGL
const gl = document.querySelector('canvas').getContext('webgl');
const vs =`
attribute vec4 position;
attribute float pointSize;
attribute vec4 color;
varying vec4 v_color;
void main() {
gl_Position = position;
gl_PointSize = pointSize;
v_color = color;
}
`;
const fs = `
precision mediump float;
varying vec4 v_color;
void main() {
gl_FragColor = v_color;
}
`;
const prg = twgl.createProgram(gl, [vs, fs]);
const posLoc = gl.getAttribLocation(prg, 'position');
const sizeLoc = gl.getAttribLocation(prg, 'pointSize');
const colorLoc = gl.getAttribLocation(prg, 'color');
const numPoints = 12;
const points = [];
for (let i = 0; i < numPoints; ++i) {
points.push({
x: r(-1, 1),
y: r(-1, 1),
color: [0, r(0, 1), r(0, 1), 1],
size: r(15, 55),
});
}
function r(min, max) {
return Math.random() * (max - min) + min;
}
let px = -10;
let py = -10;
function render() {
gl.useProgram(prg);
// convert mouse to clipspace
const cx = px / gl.canvas.width * 2 - 1;
const cy = py / gl.canvas.height * -2 + 1;
for (const point of points) {
const {x, y, color, size} = point;
// size to clip size
const halfClipWidth = size / gl.canvas.width;
const halfClipHeight = size / gl.canvas.height;
const left = x - halfClipWidth;
const right = x + halfClipWidth;
const top = y + halfClipHeight;
const bottom = y - halfClipHeight;
const hit = cx >= left && cx <= right &&
cy >= bottom && cy <= top;
gl.vertexAttrib2f(posLoc, x, y);
gl.vertexAttrib1f(sizeLoc, size);
gl.vertexAttrib4fv(colorLoc, hit ? [1, 0, 0, 1] : color);
gl.drawArrays(gl.POINTS, 0, 1);
}
}
render();
gl.canvas.addEventListener('mousemove', (e) => {
const rect = gl.canvas.getBoundingClientRect();
px = (e.clientX - rect.left) * gl.canvas.width / gl.canvas.clientWidth;
py = (e.clientY - rect.top) * gl.canvas.height / gl.canvas.clientHeight;
render();
});
body { margin: 40px; }
canvas { border: 1px solid black; }
<canvas></canvas>
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
Also remember that positions in WebGL are edges not pixels. If you have a 2x2 canvas the center of the bottom left pixel in clip space is -0.5, -0.5
-1 0 1
| | |
+---+---+-- 1
| | |
| | |
| | |
+---+---+-- 0
| | |
| + | | <--- you can see the center of that pixel is at -0.5, -0.5
| | |
+---+---+-- -1
In pixel space the same canvas would be
0 1 2
| | |
+---+---+-- 2
| | |
| | |
| | |
+---+---+-- 1
| | |
| + | | <--- you can see the center of that pixel is at 0.5, 0.5
| | |
+---+---+-- 0
gl.POINTS takes the center of the point in pixel space, adds +/- gl_PointSize / 2 to make a rectangle. Any pixel who's center is inside that rectangle will be rendered (or rather considered for rendering given all the other tests depth/stencil/discard, etc...)

Google Maps heat map color by average weight

The Google Maps iOS SDK's heat map (more specifically the Google-Maps-iOS-Utils framework) decides the color to render an area in essentially by calculating the density of the points in that area.
However, I would like to instead select the color based on the average weight or intensity of the points in that area.
From what I understand, this behavior is not built in (but who knows––the documentation sort of sucks). The file where the color-picking is decided is I think in /src/Heatmap/GMUHeatmapTileLayer.mThis is a relatively short file, but I am not very well versed in Objective-C, so I am having some difficulty figuring out what does what. I think -tileForX:y:zoom: in GMUHeatmapTileLayer.m is the important function, but I'm not sure and even if it is, I don't quite know how to modify it. Towards the end of this method, the data is 'convolved' first horizontally and then vertically. I think this is where the intensities are actually calculated. Unfortunately, I do not know exactly what it's doing, and I am afraid of changing things because I suck at obj-c. This is what the convolve parts of this method look like:
- (UIImage *)tileForX:(NSUInteger)x y:(NSUInteger)y zoom:(NSUInteger)zoom {
// ...
// Convolve data.
int lowerLimit = (int)data->_radius;
int upperLimit = paddedTileSize - (int)data->_radius - 1;
// Convolve horizontally first.
float *intermediate = calloc(paddedTileSize * paddedTileSize, sizeof(float));
for (int y = 0; y < paddedTileSize; y++) {
for (int x = 0; x < paddedTileSize; x++) {
float value = intensity[y * paddedTileSize + x];
if (value != 0) {
// convolve to x +/- radius bounded by the limit we care about.
int start = MAX(lowerLimit, x - (int)data->_radius);
int end = MIN(upperLimit, x + (int)data->_radius);
for (int x2 = start; x2 <= end; x2++) {
float scaledKernel = value * [data->_kernel[x2 - x + data->_radius] floatValue];
// I THINK THIS IS WHERE I NEED TO MAKE THE CHANGE
intermediate[y * paddedTileSize + x2] += scaledKernel;
// ^
}
}
}
}
free(intensity);
// Convole vertically to get final intensity.
float *finalIntensity = calloc(kGMUTileSize * kGMUTileSize, sizeof(float));
for (int x = lowerLimit; x <= upperLimit; x++) {
for (int y = 0; y < paddedTileSize; y++) {
float value = intermediate[y * paddedTileSize + x];
if (value != 0) {
int start = MAX(lowerLimit, y - (int)data->_radius);
int end = MIN(upperLimit, y + (int)data->_radius);
for (int y2 = start; y2 <= end; y2++) {
float scaledKernel = value * [data->_kernel[y2 - y + data->_radius] floatValue];
// I THINK THIS IS WHERE I NEED TO MAKE THE CHANGE
finalIntensity[(y2 - lowerLimit) * kGMUTileSize + x - lowerLimit] += scaledKernel;
// ^
}
}
}
}
free(intermediate);
// ...
}
This is the method where the intensities are calculated for each iteration, right? If so, how can I change this to achieve my desired effect (average, not summative colors, which I think are proportional to intensity).
So: How can I have averaged instead of summed intensities by modifying the framework?
I think you are on the right track. To calculate average you divide the point sum by the point count. Since you already have the sums calculated, I think an easy solution would be to also save the count for each point. If I understand it correctly, this it what you have to do.
When allocating memory for the sums also allocate memory for the counts
// At this place
float *intermediate = calloc(paddedTileSize * paddedTileSize, sizeof(float));
// Add this line, calloc will initialize them to zero
int *counts = calloc(paddedTileSize * paddedTileSize, sizeof(int));
Then increase the count in each loop.
// Below this line (first loop)
intermediate[y * paddedTileSize + x2] += scaledKernel;
// Add this
counts[y * paddedTileSize + x2]++;
// And below this line (second loop)
finalIntensity[(y2 - lowerLimit) * kGMUTileSize + x - lowerLimit] += scaledKernel;
// Add this
counts[(y2 - lowerLimit) * kGMUTileSize + x - lowerLimit]++;
After the two loops you should have two arrays, one with your sums finalIntensity and one with your counts counts. Now go through the values and calculate the averages.
for (int y = 0; y < paddedTileSize; y++) {
for (int x = 0; x < paddedTileSize; x++) {
int n = y * paddedTileSize + x;
if (counts[n] != 0)
finalIntensity[n] = finalIntensity[n] / counts[n];
}
}
free(counts);
The finalIntensity should now contain your averages.
If you prefer, and the rest of the code makes it possible, you can skip the last loop and instead do the division when using the final intensity values. Just change any subsequent finalIntensity[n] to counts[n] == 0 ? finalIntensity[n] : finalIntensity[n] / counts[n].
I may have just solved the same issue for the java version.
My problem was having a custom gradient with 12 different values.
But my actual weighted data does not necessarily contain all intensity values from 1 to 12.
The problem is, the highest intensity value gets mapped to the highest color.
Also 10 datapoints with intensity 1 that are close by will get the same color as a single point with intensity 12.
So the function where the tile gets created is a good starting point:
Java:
public Tile getTile(int x, int y, int zoom) {
// ...
// Quantize points
int dim = TILE_DIM + mRadius * 2;
double[][] intensity = new double[dim][dim];
int[][] count = new int[dim][dim];
for (WeightedLatLng w : points) {
Point p = w.getPoint();
int bucketX = (int) ((p.x - minX) / bucketWidth);
int bucketY = (int) ((p.y - minY) / bucketWidth);
intensity[bucketX][bucketY] += w.getIntensity();
count[bucketX][bucketY]++;
}
// Quantize wraparound points (taking xOffset into account)
for (WeightedLatLng w : wrappedPoints) {
Point p = w.getPoint();
int bucketX = (int) ((p.x + xOffset - minX) / bucketWidth);
int bucketY = (int) ((p.y - minY) / bucketWidth);
intensity[bucketX][bucketY] += w.getIntensity();
count[bucketX][bucketY]++;
}
for(int bx = 0; bx < dim; bx++)
for (int by = 0; by < dim; by++)
if (count[bx][by] != 0)
intensity[bx][by] /= count[bx][by];
//...
I added a counter and count every addition to the intensities, after that I go through every intensity and calculate the average.
For C:
- (UIImage *)tileForX:(NSUInteger)x y:(NSUInteger)y zoom:(NSUInteger)zoom {
//...
// Quantize points.
int paddedTileSize = kGMUTileSize + 2 * (int)data->_radius;
float *intensity = calloc(paddedTileSize * paddedTileSize, sizeof(float));
int *count = calloc(paddedTileSize * paddedTileSize, sizeof(int));
for (GMUWeightedLatLng *item in points) {
GQTPoint p = [item point];
int x = (int)((p.x - minX) / bucketWidth);
// Flip y axis as world space goes south to north, but tile content goes north to south.
int y = (int)((maxY - p.y) / bucketWidth);
// If the point is just on the edge of the query area, the bucketing could put it outside
// bounds.
if (x >= paddedTileSize) x = paddedTileSize - 1;
if (y >= paddedTileSize) y = paddedTileSize - 1;
intensity[y * paddedTileSize + x] += item.intensity;
count[y * paddedTileSize + x] ++;
}
for (GMUWeightedLatLng *item in wrappedPoints) {
GQTPoint p = [item point];
int x = (int)((p.x + wrappedPointsOffset - minX) / bucketWidth);
// Flip y axis as world space goes south to north, but tile content goes north to south.
int y = (int)((maxY - p.y) / bucketWidth);
// If the point is just on the edge of the query area, the bucketing could put it outside
// bounds.
if (x >= paddedTileSize) x = paddedTileSize - 1;
if (y >= paddedTileSize) y = paddedTileSize - 1;
// For wrapped points, additional shifting risks bucketing slipping just outside due to
// numerical instability.
if (x < 0) x = 0;
intensity[y * paddedTileSize + x] += item.intensity;
count[y * paddedTileSize + x] ++;
}
for(int i=0; i < paddedTileSize * paddedTileSize; i++)
if (count[i] != 0)
intensity[i] /= count[i];
Next is the convolving.
What I did there, is to make sure that the calculated value does not go over the maximum in my data.
Java:
// Convolve it ("smoothen" it out)
double[][] convolved = convolve(intensity, mKernel, mMaxAverage);
// the mMaxAverage gets set here:
public void setWeightedData(Collection<WeightedLatLng> data) {
// ...
// Add points to quad tree
for (WeightedLatLng l : mData) {
mTree.add(l);
mMaxAverage = Math.max(l.getIntensity(), mMaxAverage);
}
// ...
// And finally the convolve method:
static double[][] convolve(double[][] grid, double[] kernel, double max) {
// ...
intermediate[x2][y] += val * kernel[x2 - (x - radius)];
if (intermediate[x2][y] > max) intermediate[x2][y] = max;
// ...
outputGrid[x - radius][y2 - radius] += val * kernel[y2 - (y - radius)];
if (outputGrid[x - radius][y2 - radius] > max ) outputGrid[x - radius][y2 - radius] = max;
For C:
// To get the maximum average you could do that here:
- (void)setWeightedData:(NSArray<GMUWeightedLatLng *> *)weightedData {
_weightedData = [weightedData copy];
for (GMUWeightedLatLng *dataPoint in _weightedData)
_maxAverage = Math.max(dataPoint.intensity, _maxAverage)
// ...
// And then simply in the convolve section
intermediate[y * paddedTileSize + x2] += scaledKernel;
if (intermediate[y * paddedTileSize + x2] > _maxAverage)
intermediate[y * paddedTileSize + x2] = _maxAverage;
// ...
finalIntensity[(y2 - lowerLimit) * kGMUTileSize + x - lowerLimit] += scaledKernel;
if (finalIntensity[(y2 - lowerLimit) * kGMUTileSize + x - lowerLimit] > _maxAverage)
finalIntensity[(y2 - lowerLimit) * kGMUTileSize + x - lowerLimit] = _maxAverage;
And finally the coloring
Java:
// The maximum intensity is simply the size of my gradient colors array (or the starting points)
Bitmap bitmap = colorize(convolved, mColorMap, mGradient.mStartPoints.length);
For C:
// Generate coloring
// ...
float max = [data->_maxIntensities[zoom] floatValue];
max = _gradient.startPoints.count;
I did this in Java and it worked for me, not sure about the C-code though.
You have to play around with the radius and you could even edit the kernel. Because I found that when I have a lot of homogeneous data (i.e. little variation in the intensities, or a lot of data in general) the heat map will degenerate to a one-colored overlay, because the gradient on the edges will get smaller and smaller.
But hope this helps anyway.
// Erik

Un-Distort raw images received from the Leap motion cameras

I've been working with the leap for a long time now. 2.1.+ SDK version allows us to access the cameras and get raw images. I want to use those images with OpenCV for square/circle detection and stuff... the problem is i can't get those images undistorted. i read the docs, but don't quite get what they mean. here's one thing i need to understand properly before going forward
distortion_data_ = image.distortion();
for (int d = 0; d < image.distortionWidth() * image.distortionHeight(); d += 2)
{
float dX = distortion_data_[d];
float dY = distortion_data_[d + 1];
if(!((dX < 0) || (dX > 1)) && !((dY < 0) || (dY > 1)))
{
//what do i do now to undistort the image?
}
}
data = image.data();
mat.put(0, 0, data);
//Imgproc.Canny(mat, mat, 100, 200);
//mat = findSquare(mat);
ok.showImage(mat);
in the docs it says something like this "
The calibration map can be used to correct image distortion due to lens curvature and other imperfections. The map is a 64x64 grid of points. Each point consists of two 32-bit values....(the rest on the dev website)"
can someone explain this in detail please, OR OR, just post the java code to undistort the images give me an output MAT image so i may continue processing that (i'd still prefer a good explanation if possible)
Ok, I have no leap camera to test all this, but this is how I understand the documentation:
The calibration map does not hold offsets but full point positions. An entry says where the pixel has to be placed instead. Those values are mapped between 0 and 1, which means that you have to mutiply them by your real image width and height.
What isnt explained explicitly is, how you pixel positions are mapped to 64 x 64 positions of your calibration map. I assume that it's the same way: 640 pixels width are mapped to 64 pixels width and 240 pixels height are mapped to 64 pixels height.
So in general, to move from one of your 640 x 240 pixel positions (pX, pY) to the undistorted position you will:
compute corresponding pixel position in the calibration map: float cX = pX/640.0f * 64.0f; float cY = pY/240.0f * 64.0f;
(cX, cY) is now the locaion of that pixel in the calibration map. You will have to interpolate between two pixel locaions, but I will now only explain how to go on for a discrete location in the calibration map (cX', cY') = rounded locations of (cX, cY).
read the x and y values out of the calibration map: dX, dY as in the documentation. You have to compute the location in the array by: d = dY*calibrationMapWidth*2 + dX*2;
dX and dY are values between 0 and 1 (if not: dont undistort this point because there is no undistortion available. To find out the pixel location in your real image, multiply by the image size: uX = dX*640; uY = dY*240;
set your pixel to the undistorted value: undistortedImage(pX,pY) = distortedImage(uX,uY);
but you dont have discrete point positions in your calibration map, so you have to interpolate. I'll give you an example:
let be (cX,cY) = (13.7, 10.4)
so you read from your calibration map four values:
calibMap(13,10) = (dX1, dY1)
calibMap(14,10) = (dX2, dY2)
calibMap(13,11) = (dX3, dY3)
calibMap(14,11) = (dX4, dY4)
now your undistorted pixel position for (13.7, 10.4) is (multiply each with 640 or 240 to get uX1, uY1, uX2, etc):
// interpolate in x direction first:
float tmpUX1 = uX1*0.3 + uX2*0.7
float tmpUY1 = uY1*0.3 + uY2*0.7
float tmpUX2 = uX3*0.3 + uX4*0.7
float tmpUY2 = uY3*0.3 + uY4*0.7
// now interpolate in y direction
float combinedX = tmpUX1*0.6 + tmpUX2*0.4
float combinedY = tmpUY1*0.6 + tmpUY2*0.4
and your undistorted point is:
undistortedImage(pX,pY) = distortedImage(floor(combinedX+0.5),floor(combinedY+0.5)); or interpolate pixel values there too.
Hope this helps for a basic understanding. I'll try to add openCV remap code soon! The only point thats unclear for me is, whether the mapping between pX/Y and cX/Y is correct, cause thats not explicitly explained in the documentation.
Here is some code. You can skip the first part, where I am faking a distortion and creating the map, which is your initial state.
With openCV it is simple, just resize the calibration map to your image size and multiply all the values with your resolution. The nice thing is, that openCV performs the interpolation "automatically" while resizing.
int main()
{
cv::Mat input = cv::imread("../Data/Lenna.png");
cv::Mat distortedImage = input.clone();
// now i fake some distortion:
cv::Mat transformation = cv::Mat::eye(3,3,CV_64FC1);
transformation.at<double>(0,0) = 2.0;
cv::warpPerspective(input,distortedImage,transformation,input.size());
cv::imshow("distortedImage", distortedImage);
//cv::imwrite("../Data/LenaFakeDistorted.png", distortedImage);
// now fake a calibration map corresponding to my faked distortion:
const unsigned int cmWidth = 64;
const unsigned int cmHeight = 64;
// compute the calibration map by transforming image locations to values between 0 and 1 for legal positions.
float calibMap[cmWidth*cmHeight*2];
for(unsigned int y = 0; y < cmHeight; ++y)
for(unsigned int x = 0; x < cmWidth; ++x)
{
float xx = (float)x/(float)cmWidth;
xx = xx*2.0f; // this if from my fake distortion... this gives some values bigger than 1
float yy = (float)y/(float)cmHeight;
calibMap[y*cmWidth*2+ 2*x] = xx;
calibMap[y*cmWidth*2+ 2*x+1] = yy;
}
// NOW you have the initial situation of your scenario: calibration map and distorted image...
// compute the image locations of calibration map values:
cv::Mat cMapMatX = cv::Mat(cmHeight, cmWidth, CV_32FC1);
cv::Mat cMapMatY = cv::Mat(cmHeight, cmWidth, CV_32FC1);
for(int j=0; j<cmHeight; ++j)
for(int i=0; i<cmWidth; ++i)
{
cMapMatX.at<float>(j,i) = calibMap[j*cmWidth*2 +2*i];
cMapMatY.at<float>(j,i) = calibMap[j*cmWidth*2 +2*i+1];
}
//cv::imshow("mapX",cMapMatX);
//cv::imshow("mapY",cMapMatY);
// interpolate those values for each of your original images pixel:
// here I use linear interpolation, you could use cubic or other interpolation too.
cv::resize(cMapMatX, cMapMatX, distortedImage.size(), 0,0, CV_INTER_LINEAR);
cv::resize(cMapMatY, cMapMatY, distortedImage.size(), 0,0, CV_INTER_LINEAR);
// now the calibration map has the size of your original image, but its values are still between 0 and 1 (for legal positions)
// so scale to image size:
cMapMatX = distortedImage.cols * cMapMatX;
cMapMatY = distortedImage.rows * cMapMatY;
// now create undistorted image:
cv::Mat undistortedImage = cv::Mat(distortedImage.rows, distortedImage.cols, CV_8UC3);
undistortedImage.setTo(cv::Vec3b(0,0,0)); // initialize black
//cv::imshow("undistorted", undistortedImage);
for(int j=0; j<undistortedImage.rows; ++j)
for(int i=0; i<undistortedImage.cols; ++i)
{
cv::Point undistPosition;
undistPosition.x =(cMapMatX.at<float>(j,i)); // this will round the position, maybe you want interpolation instead
undistPosition.y =(cMapMatY.at<float>(j,i));
if(undistPosition.x >= 0 && undistPosition.x < distortedImage.cols
&& undistPosition.y >= 0 && undistPosition.y < distortedImage.rows)
{
undistortedImage.at<cv::Vec3b>(j,i) = distortedImage.at<cv::Vec3b>(undistPosition);
}
}
cv::imshow("undistorted", undistortedImage);
cv::waitKey(0);
//cv::imwrite("../Data/LenaFakeUndistorted.png", undistortedImage);
}
cv::Mat SelfDescriptorDistances(cv::Mat descr)
{
cv::Mat selfDistances = cv::Mat::zeros(descr.rows,descr.rows, CV_64FC1);
for(int keyptNr = 0; keyptNr < descr.rows; ++keyptNr)
{
for(int keyptNr2 = 0; keyptNr2 < descr.rows; ++keyptNr2)
{
double euclideanDistance = 0;
for(int descrDim = 0; descrDim < descr.cols; ++descrDim)
{
double tmp = descr.at<float>(keyptNr,descrDim) - descr.at<float>(keyptNr2, descrDim);
euclideanDistance += tmp*tmp;
}
euclideanDistance = sqrt(euclideanDistance);
selfDistances.at<double>(keyptNr, keyptNr2) = euclideanDistance;
}
}
return selfDistances;
}
I use this as input and fake a remap/distortion from which I compute my calib mat:
input:
faked distortion:
used the map to undistort the image:
TODO: after those computatons use a opencv map with those values to perform faster remapping.
Here's an example on how to do it without using OpenCV. The following seems to be faster than using the Leap::Image::warp() method (probably due to the additional function call overhead when using warp()):
float destinationWidth = 320;
float destinationHeight = 120;
unsigned char destination[(int)destinationWidth][(int)destinationHeight];
//define needed variables outside the inner loop
float calX, calY, weightX, weightY, dX1, dX2, dX3, dX4, dY1, dY2, dY3, dY4, dX, dY;
int x1, x2, y1, y2, denormalizedX, denormalizedY;
int x, y;
const unsigned char* raw = image.data();
const float* distortion_buffer = image.distortion();
//Local variables for values needed in loop
const int distortionWidth = image.distortionWidth();
const int width = image.width();
const int height = image.height();
for (x = 0; x < destinationWidth; x++) {
for (y = 0; y < destinationHeight; y++) {
//Calculate the position in the calibration map (still with a fractional part)
calX = 63 * x/destinationWidth;
calY = 63 * y/destinationHeight;
//Save the fractional part to use as the weight for interpolation
weightX = calX - truncf(calX);
weightY = calY - truncf(calY);
//Get the x,y coordinates of the closest calibration map points to the target pixel
x1 = calX; //Note truncation to int
y1 = calY;
x2 = x1 + 1;
y2 = y1 + 1;
//Look up the x and y values for the 4 calibration map points around the target
// (x1, y1) .. .. .. (x2, y1)
// .. ..
// .. (x, y) ..
// .. ..
// (x1, y2) .. .. .. (x2, y2)
dX1 = distortion_buffer[x1 * 2 + y1 * distortionWidth];
dX2 = distortion_buffer[x2 * 2 + y1 * distortionWidth];
dX3 = distortion_buffer[x1 * 2 + y2 * distortionWidth];
dX4 = distortion_buffer[x2 * 2 + y2 * distortionWidth];
dY1 = distortion_buffer[x1 * 2 + y1 * distortionWidth + 1];
dY2 = distortion_buffer[x2 * 2 + y1 * distortionWidth + 1];
dY3 = distortion_buffer[x1 * 2 + y2 * distortionWidth + 1];
dY4 = distortion_buffer[x2 * 2 + y2 * distortionWidth + 1];
//Bilinear interpolation of the looked-up values:
// X value
dX = dX1 * (1 - weightX) * (1- weightY) + dX2 * weightX * (1 - weightY) + dX3 * (1 - weightX) * weightY + dX4 * weightX * weightY;
// Y value
dY = dY1 * (1 - weightX) * (1- weightY) + dY2 * weightX * (1 - weightY) + dY3 * (1 - weightX) * weightY + dY4 * weightX * weightY;
// Reject points outside the range [0..1]
if((dX >= 0) && (dX <= 1) && (dY >= 0) && (dY <= 1)) {
//Denormalize from [0..1] to [0..width] or [0..height]
denormalizedX = dX * width;
denormalizedY = dY * height;
//look up the brightness value for the target pixel
destination[x][y] = raw[denormalizedX + denormalizedY * width];
} else {
destination[x][y] = -1;
}
}
}

Working out heightmap normals in DirectX using triangle strips

I'm trying to load in heightmap data but I'm struggling to figure out how to work out the normals. Have looked online but can't seem to find anything useful.
I store the vertices using
m_HeightMapVtxCount = (m_HeightMapLength - 1) * m_HeightMapWidth * 2;
m_pVertices = new XMFLOAT3[m_HeightMapVtxCount];
Then the vertices are loaded in using
for (int l = 0; l < m_HeightMapLength - 1; ++l)
{
if(l % 2 == 0) //for every second row - start at the bottom left corner, continue to the right, one row up and continue to the left
{
for(int w = 0; w < m_HeightMapWidth; ++w)
{
m_pVertices[i++] = XMFLOAT3(m_pHeightMap[w + l * m_HeightMapWidth]); //bottom vertex
m_pVertices[i++] = XMFLOAT3(m_pHeightMap[w + (l + 1) * m_HeightMapWidth]); //top vertex
}
}
else //for the row above, add the vertices from right to left
{
for(int w = m_HeightMapWidth - 1; w >= 0; --w)
{
m_pVertices[i++] = XMFLOAT3(m_pHeightMap[w + l * m_HeightMapWidth]); //bottom vertex
m_pVertices[i++] = XMFLOAT3(m_pHeightMap[w + (l + 1) * m_HeightMapWidth]); //top vertex
}
}
}
I was able to calculate the normals using triangle lists, that was quite simple, but unsure of how to do it using strips

Get and Set Pixel Gray scale image Using Emgu CV

I am trying to get and set pixels of a gray scale image by using emgu Cv with C#.
If I use a large image size this error message occurs: "Index was outside the bounds of the array."
If I use an image 200x200 or less then there is no error but I don't understand why.
Following is my code:
Image<Gray , byte> grayImage;
--------------------------------------------------------------------
for (int v = 0; v < grayImage.Height; v++)
{
for (int u = 0; u < grayImage.Width; u++)
{
byte a = grayImage.Data[u , v , 0]; //Get Pixel Color | fast way
byte b = (byte)(myHist[a] * (K - 1) / M);
grayImage.Data[u , v , 0] = b; //Set Pixel Color | fast way
}
}
--------------------------------------------------------------------
http://i306.photobucket.com/albums/nn262/neji1909/9-6-25565-10-39.png
Please help me and sorry I am not good at English.
you are not indexing by (x,y) but by (row, col) - inverted. When you used 200x200 image it was the same whether you used width or height.
you could do that by using pointers (much faster) because if you are using indexing EmguCV internally uses calls to opencv for an every pixel.
so:
byte* ptr = (byte*)image.MIplImage.imageData;
int stride = image.MIplImage.widthStep;
int width = image.Width;
int height = image.Height;
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
ptr[i] = (byte)(myHist[a] * (K - 1) / M);
}
ptr += stride;
}
That's because the x and y are inverted in the Data array. You should change your code this way (invert u and v):
for (int v = 0; v < grayImage.Height; v++)
{
for (int u = 0; u < grayImage.Width; u++)
{
byte a = grayImage.Data[v , u , 0]; //Get Pixel Color | fast way
byte b = (byte)(myHist[a] * (K - 1) / M);
grayImage.Data[v , u , 0] = b; //Set Pixel Color | fast way
}
}
See also Iterate over pixels of an image with emgu cv

Resources