Firstly, if this is a question that has been asked already, don't get angry and just link me the original please, I couldn't find it. Thank you :)
Ok, so I don't really know how to explain this. When I step into my code which gets all the pixels of a bitmap and puts it into a dictionary in order. When I step into the code it all runs perfectly and completes its fast. However, when I don't put any break points in, x and y at colour = bmpThread.GetPixel(x,y); go out of bounds and go to 4 and I have no idea why. Why is it doing this and how do I stop it?
void PixelAnalyse(int x, int y, int currentPixel)
{
Bitmap bmpThread = bmp;
Color colour;
lock (bmpThread)
{
colour = bmpThread.GetPixel(x, y);
//pTemp = bmpThread.GetPixel(x, y);
}
//this.Invoke(new Action(() => dataGridView1.Rows.Clear()));
//Get the pixel colours
arrayOfColours[currentPixel] = colour;
//this.Invoke(new Action(() => dataGridView1.FirstDisplayedCell = dataGridView1.Rows[dataGridView1.Rows.Count - 1].Cells[0]));W
//this.Invoke(new Action(() => progressBar1.Value++));
CancellationTokenSource cts = new CancellationTokenSource();
cts.Cancel();
}
private void analyse1_Click(object sender, EventArgs e)
{
ThreadPool.SetMaxThreads(imageSize + 1, imageSize + 1);
for (int m = 0; m < imageSize; m++)
{
arrayOfColours.Add(m, Color.Black);
}
int y, x;
int currentPixel = 0;
for (x = 0; x < xSize; x++)
{
for (y = 0; y < ySize; y++)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(o => PixelAnalyse(x, y, currentPixel)));
currentPixel++;
}
}
PrintToDataGraph();
}
Because you're capturing the variables, not the current value of them; basically, you're doing this:
queue an operation that accesses the variable currentPixel, x and y (ot the current value)
change the value of those variables
loop
this means that when each operation actually happens, the values of currentPixel, x and y are not what they were when you scheduled the work.
You can avoid this by declaring new variables at the lowest scope:
var a = x;
var b = y;
var c = currentPixel;
ThreadPool.QueueUserWorkItem(new WaitCallback(o => PixelAnalyse(a, b, c)));
However, it is unlikely that creating that many work items is an optimal approach; usually you should prefer to create a smaller number of "chunky" work items for the thread-pool.
Related
I am making a precipitation map for an experiment with Perlin noise, where I also create biomes.
I am using temperature and precipitation to determine a biome of a certain pixel, I have the program for the precipitation, but the multiple For loops in the program is making Unity3d become unresponsive for a long period of time.
Does anyone know how to make this faster? I have looked around on the internet, but I couldn't find an answer
Here is my code:
public float[,] PrecipMap (float[,] noise,int mapWidth,int mapHeight)
{
float[,] precipMap = new float[mapWidth, mapHeight];//array that it to be used for precipitation
float[,] waterTiles = WaterTiles(mapHeight, mapWidth, noise);//array with all values that are water
for (int y = 0; y < mapHeight; y++)
{
for(int x = 0; x < mapWidth; x++)
{
float[] distance = new float[count];//distance between pixel and water tile
for(int wy = 0; wy < mapHeight; wy++)
{
for(int wx = 0; wx < mapWidth; wx++)
{
if (waterTiles[x, y] == 1) { // if the selected tile in water tiles has water
for(int i = 0; i < count; i++)// distance makes an array of all possible distances.
{
distance[i] = Mathf.Sqrt(((x + -wx) * (x + -wx)) + ((y +-wy) * (y +-wy)));// finds distance between pixel and water tile
}
}
}
Array.Sort(distance); /// sorts distance from least to greatest
precipMap[x, y] = distance[count-1];//enters in distance
}
}
}
return precipMap;
}
If anyone could help, I would be thankful. I am very grateful for any help/criticism.
As was already commented your loops run quite often and by default everything in unity runs on the main thread. So before Unity can render the next frame, you method has to finish.
Additionally you run Array.Sort which is quite expensive and allocate new arrays for each iteration which also keeps your GC busy!
Then I don't see what your distance array is good for. The variable i is Neve used in yoir calculation so you just fill all 1500 entries with the same value, sort it and read out the last one ... They will all be equal anyway so this is completely redundant!
Also you check redundantly
if (waterTiles[x, y] == 1)
which would be enough to check once as soon as you have x and y and is unnecessarily done further below within the nested loops - loops that you could have skipped completely if the condition is false anyway.
You could actually move your entire method to a thread and wait for the result using async await (also see Using async-await in Unity3D). Unfortunately I'm no async-await expert but this should do it
public async void CalculatePrecipMap(float[,] noise, int mapWidth, int mapHeight, Action<float[,]> callback)
{
var result = await PrecipMap(noise, mapWidth, mapHeight);
callback?.Invoke(result);
}
private async Task<float[,]> PrecipMap (float[,] noise,int mapWidth,int mapHeight)
{
//array that it to be used for precipitation
float[,] precipMap = new float[mapWidth, mapHeight];
//array with all values that are water
float[,] waterTiles = WaterTiles(mapHeight, mapWidth, noise);
for (var y = 0; y < mapHeight; y++)
{
for(var x = 0; x < mapWidth; x++)
{
// Skip as soon as possible
// Completely unnecessary to run your loop at all if this is already false
if (waterTiles[x, y] != 1) continue;
// if the selected tile in water tiles has water
for(var wy = 0; wy < mapHeight; wy++)
{
for(var wx = 0; wx < mapWidth; wx++)
{
// i is nowhere used in below calculation!
// I don't see any reason to use an distance array here at all !!!
precipMap[x, y] = Mathf.Sqrt(((x + -wx) * (x + -wx)) + ((y +-wy) * (y +-wy)));
}
}
}
}
return precipMap;
}
You would then use it using a lambda expression like
CalculatePrecipMap(someNoise, someWidth, someHeight, result =>
{
// Do something with the result
}
or using a method like
CalculatePrecipMap(someNoise, someWidth, someHeight, OnResultReady);
private void OnResultReady (float[,] result)
{
// Do something with the result
}
Note: Typed on smartphone but I hope the idea gets clear
So how can I update the position every time I call the StartRandomizingRightSpikePosition
private bool CheckOverlap(GameObject o1, GameObject o2)
{
return spikeRight.Select(t => t.GetComponent<Collider>().bounds.Intersects(t.GetComponent<Collider>().bounds)).FirstOrDefault();
}
public void StartRandomizingRightSpikesPosition()
{
foreach (var t in spikeRight)
{
foreach (var t1 in spikeRight)
{
if (t == t1) continue;
if (!CheckOverlap(t, t1)) continue;
yPosition = Random.Range(-7, 7);
var position = t1.transform.position;
desiredPosition = new Vector3(position.x, yPosition, position.z);
t1.transform.position = desiredPosition;
Debug.Log(t.gameObject + " intersects " + t1.gameObject);
}
}
}
The short answer is yes but I'm not sure you would want too. I'm not sure you're going to find a way to do this efficiently and you might be better off finding a way to generate the objects such that this step is not necessary.
I can't tell from your question how the objects are actually stored so I'm going to provide some sample code that just deals with a simple array of Rectangles. You should be able to adapt it to your specifics.
I tried to make it slightly more efficient by not checking both t1 == t and t == t1.
const int Bounds = 1000;
static bool RemovedOverlappingRects(Rectangle[] rects)
{
for (int pos = 0; pos < rects.Length; ++pos)
{
for (int check = pos +1; check < rects.Length; ++check)
{
var r1 = rects[pos];
var r2 = rects[check];
if (r1.IntersectsWith(r2))
{
r2.Y = Rng.Next(1, Bounds);
rects[check] = r2;
Console.WriteLine($"{pos} overlaps with {check}");
return true;
}
}
}
return false;
}
Once we've randomly generated a new rectangle we have to start over. Which means invoking the above method in a loop.
var rects = GetRandomeRects(20).ToArray();
while (RemovedOverlappingRects(rects))
;
Because of the random movement I'm not certain you can guarantee this will always end. If you can deal with the non-random look of the results changing it to stack the overlaps would I believe always finish. That would be this:
r2.Y = r1.Y + r1.Height + 1;
in place of
r2.Y = Rng.Next(1, Bounds);
But even then you're still dealing with a very unpredictable run time due to the random input.
Maybe someone else can show us a more efficient way...
I am currently writing a C# application to demonstrate the speedup of parallel computing over single threaded applications. My case is Median blur of an image. But putting more threads to work slows down the application significantly (60 seconds single threaded vs 75 seconds multithreaded) . Given my current approach, I don't know how I could improve the process for multithreading. Sorry in advance for the long code in this post.
my current approach:
first, I calculate how many pixels each thread needs to process to even out the work, the DateTime calculation is to know how much time is passed single threaded and how much time is passed multithreaded:
public void blurImage(int cores)
{
_startTotal = DateTime.Now;
int numberOfPixels = _originalImage.Width * _originalImage.Height;
if (cores>=numberOfPixels)
{
for (int i = 0; i < numberOfPixels; i++)
{
startThread(0, numberOfPixels);
}
}
else
{
int pixelsPerThread = numberOfPixels / cores;
int threshold = numberOfPixels - (pixelsPerThread * cores);
startThread(0, pixelsPerThread + threshold);
for (int i = 1; i < cores; i++)
{
int startPixel = i * pixelsPerThread + threshold;
startThread(startPixel, startPixel + pixelsPerThread);
}
}
_SeqTime = DateTime.Now.Subtract(_startTotal);
}
the startThread method starts a thread and saves the result into a special class object so it can all be merged into one image, I pass a copy of the input image in each thread.
private void startThread(int startPixel, int numberOfPixels)
{
BlurOperation operation = new BlurOperation(blurPixels);
_operations.Add(operation);
BlurResult result = new BlurResult();
operation.BeginInvoke((Bitmap)_processedImage.Clone(), startPixel, numberOfPixels, _windowSize, result, operation, new AsyncCallback(finish), result);
}
Every thread blurs their set of pixels and saves the result into a new list of colors, the result is saved into the result object as well as the startpixel and the current operation, so the program knows when all threads are finished:
private void blurPixels(Bitmap bitmap, int startPixel, int endPixel, int window, BlurResult result, BlurOperation operation)
{
List<Color> colors = new List<Color>();
for (int i = startPixel; i < endPixel; i++)
{
int x = i % bitmap.Width;
int y = i / bitmap.Width;
colors.Add(PixelBlurrer.ShadePixel(x, y, bitmap, window));
}
result._pixels = colors;
result._startPixel = startPixel;
result._operation = operation;
}
the PixelBlurrer calculates the median of each color channel and returns it:
public static Color ShadePixel(int x, int y, Bitmap image, int window)
{
List<byte> red = new List<byte>();
List<byte> green = new List<byte>();
List<byte> blue = new List<byte>();
int xBegin = Math.Max(x - window, 0);
int yBegin = Math.Max(y - window, 0);
int xEnd = Math.Min(x + window, image.Width - 1);
int yEnd = Math.Min(y + window, image.Height - 1);
for (int tx = xBegin; tx < xEnd; tx++)
{
for (int ty = yBegin; ty < yEnd; ty++)
{
Color c = image.GetPixel(tx, ty);
red.Add(c.R);
green.Add(c.G);
blue.Add(c.B);
}
}
red.Sort();
green.Sort();
blue.Sort();
Color output = Color.FromArgb(red[red.Count / 2], green[green.Count / 2], blue[blue.Count / 2]);
return output;
}
on the callback, we return to the GUI thread and merge all pixels into the resulting image. Lastly an event is called telling my form the process is done:
private void finish(IAsyncResult iar)
{
Application.Current.Dispatcher.BeginInvoke(new AsyncCallback(update), iar);
}
private void update(IAsyncResult iar)
{
BlurResult result = (BlurResult)iar.AsyncState;
updateImage(result._pixels, result._startPixel, result._operation);
}
private void updateImage(List<Color> colors, int startPixel, BlurOperation operation)
{
DateTime updateTime = DateTime.Now;
_operations.Remove(operation);
int end = startPixel + colors.Count;
for (int i = startPixel; i < end; i++)
{
int x = i % _processedImage.Width;
int y = i / _processedImage.Width;
_processedImage.SetPixel(x, y, colors[i - startPixel]);
}
if (_operations.Count==0)
{
done(this, null);
}
_SeqTime += DateTime.Now.Subtract(updateTime);
}
Any thoughts? I tried using Parallel.For instead of delegates, but that made it worse. Is there a way to speedup Median blur by multithreading or is this a failed case?
after some thinking, I figured out my logic is solid, but I didn't send a deep copy to each thread. After changing this line in StartThread:
operation.BeginInvoke((Bitmap)_processedImage.Clone(), startPixel, numberOfPixels, _windowSize, result, operation, new AsyncCallback(finish), result);
to this:
operation.BeginInvoke(new Bitmap(_processedImage), startPixel, numberOfPixels, _windowSize, result, operation, new AsyncCallback(finish), result);
I can see a speedup multithreaded
Okay, so this is the code I have but I am trying to figure out how to change this foreach loop to an if statement. I've been trying to figure it out by myself but it doesn't seem to be working the way I want it to. So if anyone could help that would be much appreciated. Just as something extra, I am still a noob at C#. :)
// Used to make sure that the script can read the text file
using (StreamReader sr = new StreamReader ("Maze.txt"))
{
lineArray = File.ReadAllLines("Maze.txt");
// Access one line at a time
foreach (string line in lineArray)
{
// Reset X axis for each line of the file
int x = 0;
// Access each character in the file
foreach (char c in line)
{
string currentPosition = c.ToString();
newFilePosition = Convert.ToInt32(currentPosition);
if (newFilePosition == 1)
{
// Create a cube on the X axis
NewCubePosition = new Vector3 (x, y, 0);
Instantiate (g_mazeCubes, NewCubePosition, Quaternion.identity);
}
// Loop until X axis is done
x++;
}
// Loop until Y axis is done
y++;
}
}
If you are refering to transform a foreach to a for that test an condition. Making this transformation in code means you don't need to set x=0 and y=0 before and increment them inside foreach loop.
Using for you will do initialization, the condition, and the afterthought of x and y and iterate through array at once.
As many say you don't neet StreamReader. File.ReadAllLines opens and close the file for you.
lineArray = File.ReadAllLines("Maze.txt");
// Access one line at a time
for (y = 0; y < lineArray.Count(); y++)
{
string line = lineArray[y];
// Access each character in the file
for (int x = 0 ; x < line.Count(); x++)
{
char c = line[x];
string currentPosition = c.ToString();
newFilePosition = Convert.ToInt32(currentPosition);
if (newFilePosition == 1)
{
// Create a cube on the X axis
NewCubePosition = new Vector3 (x, y, 0);
Instantiate (g_mazeCubes, NewCubePosition, Quaternion.identity);
}
}
}
You can reduce the code with a bit of LINQ, but I don't think there's anything you can do to get rid of the inner loop.
var lineArray = File.ReadAllLines("Maze.txt");
for (var y = 0; y < lineArray.Length; y++)
{
foreach (var c in lineArray[y].Select((value, i) => new { Character = value, Index = i })
.Where(x => Convert.ToInt32(x.Character) == 1))
{
Instantiate(g_mazeCubes, new Vector3(c.Index, y, 0), Quaternion.identity);
}
}
(You also don't need the StreamReader)
In my opinion if you try to reduce the the code further than this you'll obfuscate the intent with no benefit.
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 !