Related
I have written the following code in c# where it calculates the Snake index of a 2-dimensional point.
public static uint SnakeCurveIndex(uint bits, uint x, uint y )
{
uint index = 0;
//The dimension of the array
uint dim = (uint)Math.Pow( 2.0 , (double)bits);
if(y % (uint)2 == 0 )
{
index = x + y * dim;
}
else
{
index = (dim - 1 - x) + y * dim;
}
if (index >= dim*dim)
{
//Debug console
throw new Exception("The index is out of bounds");
}
return index;
}
The variable bits it responsible for the order of the curve. The following image represents the order of the curve for 1 to 3.
My question is who to extend this code for n-dimensional points? Do I need a multidimensional-array or some other technique?
Thank you for your time.
I am trying to get the RGB values of each CameraSpacePoint in Kinect v2. While trying to access converted frame data, the code is throwing IndexOutOfRangeException. I found out that following lines are throwing this error:
byte red = pixels[4 * pixelsBaseIndex + 0];
byte green = pixels[4 * pixelsBaseIndex + 1];
byte blue = pixels[4 * pixelsBaseIndex + 2];
byte alpha = pixels[4 * pixelsBaseIndex + 3];
Please see the complete code below:
int depthWidth = kinectSensor.DepthFrameSource.FrameDescription.Width;
int depthHeight = kinectSensor.DepthFrameSource.FrameDescription.Height;
int colorWidth = kinectSensor.ColorFrameSource.FrameDescription.Width;
int colorHeight = kinectSensor.ColorFrameSource.FrameDescription.Height;
ushort[] depthData = new ushort[depthWidth * depthHeight];
CameraSpacePoint[] cameraPoints = new CameraSpacePoint[depthData.Length];
ColorSpacePoint[] colorPoints = new ColorSpacePoint[depthData.Length];
// Assuming RGBA format here
byte[] pixels = new byte[colorWidth * colorHeight * 4];
depthFrame = multiSourceFrame.DepthFrameReference.AcquireFrame();
colorFrame = multiSourceFrame.ColorFrameReference.AcquireFrame();
if ((depthFrame == null) || (colorFrame == null))
{
return;
}
depthFrame.CopyFrameDataToArray(depthData);
coordinateMapper.MapDepthFrameToCameraSpace(depthData, cameraPoints);
coordinateMapper.MapDepthFrameToColorSpace(depthData, colorPoints);
// We are using RGBA format
colorFrame.CopyConvertedFrameDataToArray(pixels, ColorImageFormat.Rgba);
for (var index = 0; index < depthData.Length; index++)
{
var u = colorPoints[index].X;
var v = colorPoints[index].Y;
if (u < 0 || u >= colorWidth || v < 0 || v >= colorHeight) continue;
int pixelsBaseIndex = (int)(v * colorWidth + u);
try
{
byte red = pixels[4 * pixelsBaseIndex + 0];
byte green = pixels[4 * pixelsBaseIndex + 1];
byte blue = pixels[4 * pixelsBaseIndex + 2];
byte alpha = pixels[4 * pixelsBaseIndex + 3];
}
catch (IndexOutOfRangeException ex)
{
int minValue = 4 * pixelsBaseIndex;
int maxValue = 4 * pixelsBaseIndex + 3;
Console.WriteLine((minValue > 0) + ", " + (maxValue < pixels.Length));
}
}
The code looks fine however I am not sure what am I missing here! How to avoid IndexOutOfRangeException exception? Any suggestions, please?
First thing pixelsBaseIndex =< 2070601 (2070601 = 1919 * 1079)
2074817 is an invalid value for the pixelsBaseIndex.
This error could be somewhere here.
if (u < 0 || u >= colorWidth || v < 0 || v >= colorHeight) continue;
int pixelsBaseIndex = (int)(v * colorWidth + u);
Best thing is to console log u, v, colorWidth, colorHeight and validate them.
EDIT
As i suspected, it is caused by the Floating-Point Arithmetic.
Mapping one frame to another frame needs complex matrix calculations, thus u,v get floating point values. Keep in mind that u,v are the pixel coordinates of the color space. They must be non-negative integers.
My recommended solution is
...
int u = (int) Math.Floor(colorPoints[index].X);
int v = (int) Math.Floor(colorPoints[index].Y);
if (u < 0 || u >= colorWidth || v < 0 || v >= colorHeight) continue;
...
FYI
Check out following lines of code to understand why u, v pixel coordinates getting floating point values. The decision, taking the floor or discarding the invalid values, is depending on the developer since in either cases, you are loosing some sort of information. For example, taking the floor means you are taking the color of the nearest pixel.
In my personal option, out putting more precise value (thus floating point value) is important for developers who do more calculations on the outputted values.For example, point cloud registration.
depth_to_color
calculating x offset for rgb image based on depth value
I need some help with optimisation of my CCL algorithm implementation. I use it to detect black areas on the image. On a 2000x2000 it takes 11 seconds, which is pretty much. I need to reduce the running time to the lowest value possible to achieve. Also, I would be glad to know if there is any other algorithm out there which allows you to do the same thing, but faster than this one. So here is my code:
//The method returns a dictionary, where the key is the label
//and the list contains all the pixels with that label
public Dictionary<short, LinkedList<Point>> ProcessCCL()
{
Color backgroundColor = this.image.Palette.Entries[1];
//Matrix to store pixels' labels
short[,] labels = new short[this.image.Width, this.image.Height];
//I particulary don't like how I store the label equality table
//But I don't know how else can I store it
//I use LinkedList to add and remove items faster
Dictionary<short, LinkedList<short>> equalityTable = new Dictionary<short, LinkedList<short>>();
//Current label
short currentKey = 1;
for (int x = 1; x < this.bitmap.Width; x++)
{
for (int y = 1; y < this.bitmap.Height; y++)
{
if (!GetPixelColor(x, y).Equals(backgroundColor))
{
//Minumum label of the neighbours' labels
short label = Math.Min(labels[x - 1, y], labels[x, y - 1]);
//If there are no neighbours
if (label == 0)
{
//Create a new unique label
labels[x, y] = currentKey;
equalityTable.Add(currentKey, new LinkedList<short>());
equalityTable[currentKey].AddFirst(currentKey);
currentKey++;
}
else
{
labels[x, y] = label;
short west = labels[x - 1, y], north = labels[x, y - 1];
//A little trick:
//Because of those "ifs" the lowest label value
//will always be the first in the list
//but I'm afraid that because of them
//the running time also increases
if (!equalityTable[label].Contains(west))
if (west < equalityTable[label].First.Value)
equalityTable[label].AddFirst(west);
if (!equalityTable[label].Contains(north))
if (north < equalityTable[label].First.Value)
equalityTable[label].AddFirst(north);
}
}
}
}
//This dictionary will be returned as the result
//I'm not proud of using dictionary here too, I guess there
//is a better way to store the result
Dictionary<short, LinkedList<Point>> result = new Dictionary<short, LinkedList<Point>>();
//I define the variable outside the loops in order
//to reuse the memory address
short cellValue;
for (int x = 0; x < this.bitmap.Width; x++)
{
for (int y = 0; y < this.bitmap.Height; y++)
{
cellValue = labels[x, y];
//If the pixel is not a background
if (cellValue != 0)
{
//Take the minimum value from the label equality table
short value = equalityTable[cellValue].First.Value;
//I'd like to get rid of these lines
if (!result.ContainsKey(value))
result.Add(value, new LinkedList<Point>());
result[value].AddLast(new Point(x, y));
}
}
}
return result;
}
Thanks in advance!
You could split your picture in multiple sub-pictures and process them in parallel and then merge the results.
1 pass: 4 tasks, each processing a 1000x1000 sub-picture
2 pass: 2 tasks, each processing 2 of the sub-pictures from pass 1
3 pass: 1 task, processing the result of pass 2
For C# I recommend the Task Parallel Library (TPL), which allows to easily define tasks depending and waiting for each other. Following code project articel gives you a basic introduction into the TPL: The Basics of Task Parallelism via C#.
I would process one scan line at a time, keeping track of the beginning and end of each run of black pixels.
Then I would, on each scan line, compare it to the runs on the previous line. If there is a run on the current line that does not overlap a run on the previous line, it represents a new blob. If there is a run on the previous line that overlaps a run on the current line, it gets the same blob label as the previous. etc. etc. You get the idea.
I would try not to use dictionaries and such.
In my experience, randomly halting the program shows that those things may make programming incrementally easier, but they can exact a serious performance cost due to new-ing.
The problem is about GetPixelColor(x, y), it take very long time to access image data.
Set/GetPixel function are terribly slow in C#, so if you need to use them a lot, you should use Bitmap.lockBits instead.
private void ProcessUsingLockbits(Bitmap ProcessedBitmap)
{
BitmapData bitmapData = ProcessedBitmap.LockBits(new Rectangle(0, 0, ProcessedBitmap.Width, ProcessedBitmap.Height), ImageLockMode.ReadWrite, ProcessedBitmap.PixelFormat);
int BytesPerPixel = System.Drawing.Bitmap.GetPixelFormatSize(ProcessedBitmap.PixelFormat) / 8;
int ByteCount = bitmapData.Stride * ProcessedBitmap.Height;
byte[] Pixels = new byte[ByteCount];
IntPtr PtrFirstPixel = bitmapData.Scan0;
Marshal.Copy(PtrFirstPixel, Pixels, 0, Pixels.Length);
int HeightInPixels = bitmapData.Height;
int WidthInBytes = bitmapData.Width * BytesPerPixel;
for (int y = 0; y < HeightInPixels; y++)
{
int CurrentLine = y * bitmapData.Stride;
for (int x = 0; x < WidthInBytes; x = x + BytesPerPixel)
{
int OldBlue = Pixels[CurrentLine + x];
int OldGreen = Pixels[CurrentLine + x + 1];
int OldRed = Pixels[CurrentLine + x + 2];
// Transform blue and clip to 255:
Pixels[CurrentLine + x] = (byte)((OldBlue + BlueMagnitudeToAdd > 255) ? 255 : OldBlue + BlueMagnitudeToAdd);
// Transform green and clip to 255:
Pixels[CurrentLine + x + 1] = (byte)((OldGreen + GreenMagnitudeToAdd > 255) ? 255 : OldGreen + GreenMagnitudeToAdd);
// Transform red and clip to 255:
Pixels[CurrentLine + x + 2] = (byte)((OldRed + RedMagnitudeToAdd > 255) ? 255 : OldRed + RedMagnitudeToAdd);
}
}
// Copy modified bytes back:
Marshal.Copy(Pixels, 0, PtrFirstPixel, Pixels.Length);
ProcessedBitmap.UnlockBits(bitmapData);
}
Here is the basic code to access pixel data.
And I made a function to transform this into a 2D matrix, it's easier to manipulate (but little slower)
private void bitmap_to_matrix()
{
unsafe
{
bitmapData = ProcessedBitmap.LockBits(new Rectangle(0, 0, ProcessedBitmap.Width, ProcessedBitmap.Height), ImageLockMode.ReadWrite, ProcessedBitmap.PixelFormat);
int BytesPerPixel = System.Drawing.Bitmap.GetPixelFormatSize(ProcessedBitmap.PixelFormat) / 8;
int HeightInPixels = ProcessedBitmap.Height;
int WidthInPixels = ProcessedBitmap.Width;
int WidthInBytes = ProcessedBitmap.Width * BytesPerPixel;
byte* PtrFirstPixel = (byte*)bitmapData.Scan0;
Parallel.For(0, HeightInPixels, y =>
{
byte* CurrentLine = PtrFirstPixel + (y * bitmapData.Stride);
for (int x = 0; x < WidthInBytes; x = x + BytesPerPixel)
{
// Conversion in grey level
double rst = CurrentLine[x] * 0.0721 + CurrentLine[x + 1] * 0.7154 + CurrentLine[x + 2] * 0.2125;
// Fill the grey matix
TG[x / 3, y] = (int)rst;
}
});
}
}
And the website where the code comes
"High performance SystemDrawingBitmap"
Thanks to the author for his really good job !
Hope this will help !
Sorry I had no idea how set a topic which could express what help I need.
I have in an array of bytes, values for each pixel from a bitmap. It is a one dimensional array, from left to right. It takes each row and add it to the end of array's index.
I would like to split a bitmap to 225(=15*15) pieces. Each brick has for example dimension 34x34 and the length of array is then 260100(=225*34*34). So as you see now we will need 15 bricks on width and on height.
Few months ago I was using two loops starting from 0 - 14. I wrote own long code to get all that 34x34 bricks. However I didn't used any array which was storing all values.
Now I have a one dimensional array because marshal copy and bitmapdata with bitlocks were the best way to fast copy all pixels' values to array.
But I stand face to face with problem how to get 34 elements then one row lower and another one knowing that on 35 level will be another brick with its own starting value..
PS. edit my post if something is not good.
Few people could say "first make any your test code". I tried that but what I got was just trash and I really don't know how to do that.
This method was used to crop image to smaller images containing bricks. But I don't want store small images of brick. I need values storing in array of bytes.
Under, there is a proof.
private void OCropImage(int ii, int jj, int p, int p2)
{
////We took letter and save value to binnary, then we search in dictionary by value
this.rect = new Rectangle();
this.newBitmap = new Bitmap(this.bitmap);
for (ii = 0; ii < p; ii++)
{
for (jj = 0; jj < p2; jj++)
{
////New bitmap
this.newBitmap = new Bitmap(this.bitmap);
////Set rectangle working area with letters
this.rect = new Rectangle(jj * this.miniszerokosc, ii * this.miniwysokosc, this.miniszerokosc, this.miniwysokosc);
////Cut single rectangle with letter
this.newBitmap = this.newBitmap.Clone(this.rect, this.newBitmap.PixelFormat);
////Add frame to rectangle to delet bad noise
this.OAddFrameToCropImage(this.newBitmap, this.rect.Width, this.rect.Height);
this.frm1.SetIm3 = (System.Drawing.Image)this.newBitmap;
////Create image with letter which constains less background
this.newBitmap = this.newBitmap.Clone(this.GetAreaLetter(this.newBitmap), this.newBitmap.PixelFormat);
////Count pixels in bitmap
this.workingArea = this.GetBinnary(this.newBitmap);
var keysWithMatchingValues = this.alphabetLetters.Where(x => x.Value == this.workingArea).Select(x => x.Key);
foreach (var key in keysWithMatchingValues)
{
this.chesswords += key.ToString();
}
}
this.chesswords += Environment.NewLine;
var ordered = this.alphabetLetters.OrderBy(x => x.Value);
}
}
PS2. sorry for my English, please correct it if it is needed.
If I get you right, then if you have an image like this
p00|p01|p02|...
---+---+-------
p10|p11|p12|...
---+---+-------
p20|p21|p22|...
---+---+---+---
...|...|...|...
Which is stored in an array in left-to-right row scan like this:
p00,p01,...,p0n, p10,p11,...,p1n, p20,p21, ...
If I understand you correctly, what you want to be able to do, is to take a given rectangle (from a certain x and y with a certain width and height) from the image. Here is code to do this, with explanations:
byte[] crop_area (byte[] source_image, int image_width, int image_height,
int start_x, int start_y, int result_width, int result_height)
{
byte[] result = new byte[result_width * result_height];
int endX = x + result_width;
int endY = y + result_height;
int pos = 0;
for (int y = startY; y < endY; y++)
for (int x = startX; x < endX; x++)
{
/* To get to the pixel in the row I (starting from I=1), we need
* to skip I-1 rows. Since our y indexes start from row 0 (not 1),
* then we don't need to subtract 1.
*
* So, the offset of the pixel at (x,y) is:
*
* y * image_width + x
* |-----------------------| |-----------------|
* Skip pixels of y rows Offset inside row
*/
result[pos] = source_image[y * image_width + x];
/* Advance to the next pixel in the result image */
pos++;
}
return result;
}
Then, to take the block in the row I and column J (I,J=0,...,14) do:
crop_area (source_image, image_width, image_height, J*image_width/15, I*image_height/15, image_width/15, image_height/15)
I am trying to flatten 3D array into 1D array for "chunk" system in my game. It's a 3D-block game and basically I want the chunk system to be almost identical to Minecraft's system (however, this isn't Minecraft clone by any measure). In my previous 2D-games I have accessed the flattened array with following algorithm:
Tiles[x + y * WIDTH]
However, this obviously doesn't work with 3D since it's missing the Z-axis. I have no idea how to implement this sort of algorithm in 3D-space. Width, height and depth are all constants (and width is just as large as height).
Is it just x + y*WIDTH + Z*DEPTH ? I am pretty bad with math and I am just beginning 3D-programming so I am pretty lost :|
PS. The reason for this is that I am looping and getting stuff by index from it quite a lot. I know that 1D arrays are faster than multi-dimensional arrays (for reasons I cant remember :P ). Even though this may not be necessary, I want as good performance as possible :)
Here is a solution in Java that gives you both:
from 3D to 1D
from 1D to 3D
Below is a graphical illustration of the path I chose to traverse the 3D matrix, the cells are numbered in their traversal order:
Conversion functions:
public int to1D( int x, int y, int z ) {
return (z * xMax * yMax) + (y * xMax) + x;
}
public int[] to3D( int idx ) {
final int z = idx / (xMax * yMax);
idx -= (z * xMax * yMax);
final int y = idx / xMax;
final int x = idx % xMax;
return new int[]{ x, y, z };
}
The algorithm is mostly the same. If you have a 3D array Original[HEIGHT, WIDTH, DEPTH] then you could turn it into Flat[HEIGHT * WIDTH * DEPTH] by
Flat[x + WIDTH * (y + DEPTH * z)] = Original[x, y, z]
As an aside, you should prefer arrays of arrays over multi-dimensional arrays in .NET. The performance differences are significant
I think the above needs a little correction. Lets say you have a HEIGHT of 10, and a WIDTH of 90, single dimensional array will be 900. By the above logic, if you are at the last element on the array 9 + 89*89, obviously this is greater than 900. The correct algorithm is:
Flat[x + HEIGHT* (y + WIDTH* z)] = Original[x, y, z], assuming Original[HEIGHT,WIDTH,DEPTH]
Ironically if you the HEIGHT>WIDTH you will not experience an overflow, just complete bonkers results ;)
x + y*WIDTH + Z*WIDTH*DEPTH. Visualize it as a rectangular solid: first you traverse along x, then each y is a "line" width steps long, and each z is a "plane" WIDTH*DEPTH steps in area.
You're almost there. You need to multiply Z by WIDTH and DEPTH:
Tiles[x + y*WIDTH + Z*WIDTH*DEPTH] = elements[x][y][z]; // or elements[x,y,z]
TL;DR
The correct answer can be written various ways, but I like it best when it can be written in a way that is very easy to understand and visualize. Here is the exact answer:
(width * height * z) + (width * y) + x
TS;DR
Visualize it:
someNumberToRepresentZ + someNumberToRepresentY + someNumberToRepresentX
someNumberToRepresentZ indicates which matrix we are on (depth). To know which matrix we are on, we have to know how big each matrix is. A matrix is 2d sized as width * height, simple. The question to ask is "how many matrices are before the matrix I'm on?" The answer is z:
someNumberToRepresentZ = width * height * z
someNumberToRepresentY indicates which row we are on (height). To know which row we are on, we have to know how big each row is: Each row is 1d, sized as width. The question to ask is "how many rows are before the row I'm on?". The answer is y:
someNumberToRepresentY = width * y
someNumberToRepresentX indicates which column we are on (width). To know which column we are on we simply use x:
someNumberToRepresentX = x
Our visualization then of
someNumberToRepresentZ + someNumberToRepresentY + someNumberToRepresentX
Becomes
(width * height * z) + (width * y) + x
The forward and reverse transforms of Samuel Kerrien above are almost correct. A more concise (R-based) transformation maps are included below with an example (the "a %% b" is the modulo operator representing the remainder of the division of a by b):
dx=5; dy=6; dz=7 # dimensions
x1=1; y1=2; z1=3 # 3D point example
I = dx*dy*z1+dx*y1+x1; I # corresponding 2D index
# [1] 101
x= I %% dx; x # inverse transform recovering the x index
# [1] 1
y = ((I - x)/dx) %% dy; y # inverse transform recovering the y index
# [1] 2
z= (I-x -dx*y)/(dx*dy); z # inverse transform recovering the z index
# [1] 3
Mind the division (/) and module (%%) operators.
The correct Algorithm is:
Flat[ x * height * depth + y * depth + z ] = elements[x][y][z]
where [WIDTH][HEIGHT][DEPTH]
To better understand description of 3D array in 1D array would be ( I guess Depth in best answer is meant Y size)
IndexArray = x + y * InSizeX + z * InSizeX * InSizeY;
IndexArray = x + InSizeX * (y + z * InSizeY);
m[x][y][z] = data[xYZ + yZ + z]
x-picture:
0-YZ
.
.
x-YZ
y-picture
0-Z
.
.
.
y-Z
summing up, it should be : targetX*YZ + targetY*Z + targetZ
In case, somebody is interested to flatten an nD (2D, 3D, 4D, ...) array to 1D, I wrote the below code. For example, if the size of the array in different dimensions is stored in the sizes array:
# pseudo code
sizes = {size_x, size_y, size_z,...};
This recursive function gives you the series of {1, size_x, size_x*size_y, size_x*size_y*size_z, ...}
// i: number of the term
public int GetCoeff(int i){
if (i==0)
return 1;
return sizes[i-1]*GetCoeff(i-1);
}
So, we have to multiply nD indexes by their corresponding series term and sum them to get {ix + iy*size_x + iz*size_x*size_y, ...}:
// indexNd: {ix, iy, iz, ...}
public int GetIndex1d(int[] indexNd){
int sum =0;
for (var i=0; i<indexNd.Length;i++)
sum += indexNd[i]*GetCoeff(i);
return sum;
}
In this code I assumed, the nD array is contiguous in memory along firstly x, then y, z, ... . So probably you call your array-like arr[z,y,x]. But, if you call them the other way, arr[x,y,z] then z is the fastest index and we like to calculate iz + iy*size_z + ix* size_z*size_y. In this case, the below function gives us the series {1, size_z, size_z*size_y, ...}:
// Dims is dimension of array, like 3 for 3D
public int GetReverseCoeff(int i){
if (i==0)
return 1;
return sizes[Dims-i]*GetReverseCoeff(i-1);
}
The coefficients are stored in the right order:
public void SetCoeffs(){
for (int i=0;i<Dims;i++)
coeffs[Dims-i-1] = GetReverseCoeff(i);
}
The 1D index is calculated the same as before except coeffs array is used:
// indexNd: {ix, iy, iz, ...}
public int GetIndex1d(int[] indexNd){
int sum =0;
for (var i=0; i<indexNd.Length;i++)
sum += indexNd[i]*coeffs[i];
return sum;
}
Samuel Kerrien's answer to python :
def to1D(crds,dims):
x,y,z=crds
xMax,yMax,zMax=dims
return (z * xMax * yMax) + (y * xMax) + x
def to3D(idx,dims):
xMax,yMax,zMax=dims
z = idx // (xMax * yMax)
idx -= (z * xMax * yMax)
y = idx // xMax
x = idx % xMax
return x, y, z