Hello I have heightData in memory and sometimes (when I edit it) I wanna save it to jpg. This is my code:
float multi = 0.2f;
float[,] heightData = quadTree.HeightData;
Color[] heightMapColors = new Color[heightData.Length];
for (int x = 0; x < heightData.GetLength(0); x++)
{
for (int y = 0; y < heightData.GetLength(1); y++)
{
byte colorData = (byte)(heightData[x, y] / multi);
heightMapColors[x + y * heightData.GetLength(0)].R = colorData;
heightMapColors[x + y * heightData.GetLength(0)].G = colorData;
heightMapColors[x + y * heightData.GetLength(0)].B = colorData;
}
}
Texture2D heightMap = new Texture2D(device, heightData.GetLength(0), heightData.GetLength(1), false, SurfaceFormat.Color);
heightMap.SetData<Color>(heightMapColors);
using (System.IO.Stream stream = System.IO.File.OpenWrite(#"D:\test.jpg"))
{
heightMap.SaveAsJpeg(stream, heightData.GetLength(0), heightData.GetLength(1));
}
I am 100% sure that I have data in heightMapColors, but saved jpg is only black. :/ Is it a good way how to do it or something is wrong?
Alpha should not be zero
heightMapColors[x + y * heightData.GetLength(0)].R = colorData;
heightMapColors[x + y * heightData.GetLength(0)].G = colorData;
heightMapColors[x + y * heightData.GetLength(0)].B = colorData;
heightMapColors[x + y * heightData.GetLength(0)].A = 255;
A JPG is probably not a good format to store a heightmap into because it is a lossy format. You should be putting it into a BMP pr PNG. That said, what is the range of your "height"? It looks like your height is a float which means it is probably not in the right range to be displayed or even converted to discrete values.
If your allowed height range is Xf to Yf, convert that to a 0 - 255 range using
byteValue = (byte)(((OldValue - OldMin) * (255 - 0)) / (OldMax - OldMin)) + 0
and then give it a shot.
Related
I have a C# desktop application.
I am using emgu framework for image processing.
What I am trying to do is improve 'washed' out images and make them more vibrant.
Using myImage._EqualHist() works OK for when the picture has a rich array of colours (like during the day) but at night-time the white-balancing will distort after applying that emgu filter and I get a very bright/busy night-time image. If I could just adjust the contrast that would be good - I think.
I have found some code that will adjust the contrast for me. I am now trying to find what value should I use to adjust the contrast by. Obviously, this value will vary during a 24hr cycle.
I have made a 1st stab at what relationship/formula I can use to auto-contrast an image.
Obviously, I am guessing and trying things out. Not very scientific//mathematical and I am searching the net for some logic I can apply.
Should I also consider the gamma of an image?
This is my code so far:
Image<Bgr, Byte> imgColor = new Image<Bgr, byte>(#"d:\20140320022038047.jpg");
Image<Hsv,Byte> hsv = new Image<Hsv,byte>(imgColor.ToBitmap());
double averageHue = hsv[0].GetAverage().Intensity;
double averageSat = hsv[1].GetAverage().Intensity;
double averageLum = hsv[2].GetAverage().Intensity;
//I am guessing here and playing around with the constants
float adjustContrastBy =(float)( averageLum / averageHue);
byte[, ,] data = imgColor.Data;
//this part of the code enumertaes through the Image byte array
for (int y = 0; y < imgColor.Height ; y++)
{
for (int x = 0; x < imgColor.Width; x++)
{
byte B = data[y, x, 0];
byte G = data[y, x, 1];
byte R = data[y, x, 2];
float Red = R / 255.0f;
float Green = G / 255.0f;
float Blue = B / 255.0f;
Red = (((Red - 0.5f) * adjustContrastBy) + 0.5f) * 255.0f;
Green = (((Green - 0.5f) * adjustContrastBy) + 0.5f) * 255.0f;
Blue = (((Blue - 0.5f) * adjustContrastBy) + 0.5f) * 255.0f;
int iR = (int)Red;
iR = iR > 255 ? 255 : iR;
iR = iR < 0 ? 0 : iR;
int iG = (int)Green;
iG = iG > 255 ? 255 : iG;
iG = iG < 0 ? 0 : iG;
int iB = (int)Blue;
iB = iB > 255 ? 255 : iB;
iB = iB < 0 ? 0 : iB;
data[y, x, 0] = (byte)iB;
data[y, x, 1] = (byte)iG;
data[y, x, 2] = (byte)iR;
}
}
pictureBox1.Image = imgColor.ToBitmap();
I also adjust the gamma using this method:
double intensity = grayCurrent.GetAverage().Intensity;
double g = Math.Log(Shared.Optimum / 255) / Math.Log(intensity / 255);
grayCurrent._GammaCorrect(g);
This certainly helps me with the motion detection but want I am now focusing on is improving what the User 'sees' as opposed to what computer detects..
I run this code in c# language ,but there is error that
"value of "257 is not valid for red.red should be greater than or equal to 0 and less than or equal to 255"
How can I correct this error?
Int32[,] Y1= new Int32[width,height];//R,G,B not empty array
Int32[,] R= new Int32[width,height];
Int32[,] G= new Int32[width,height];
Int32[,] B= new Int32[width,height];
Bitmap bmp=new Bitmap[width,height];
for (int y = 0; y < height; y++)
for (int x = 0; x < width; x++)
{
Y1[x, y] = Convert.ToInt32(0.39 * R[x, y] + 0.59 * G[x, y] + 0.12 * B[x, y]);
bmp.SetPixel(x, y, Color.FromArgb(Y1[x,y],Y1[x,y],Y1[x,y]));
}
pictureBox1.Image = bmp;
I know that "Color.FromArgb(Y1[x,y],Y1[x,y],Y1[x,y])" out of range but how can I
correct it ?
You're probably trying to convert to grayscale. There are two things you should do:
Your weights are wrong. The correct weights are 0.299, 0.587 and 0.114.
Apply a cap using Math.Min(). Something like:
Y1[x, y] = Math.Min(255, Convert.ToInt32(0.299 * R[x, y] + 0.587 * G[x, y] + 0.114 * B[x, y]));
The cap is there only to make sure our formula never exceeds the max byte value.
I need to generate a grey scale bitmap from the alpha channel of a System.Drawing.Bitmap.
I tried using GetPixel and SetPixel but this does not work with bitmaps with a PixelFormat of Format16bppGrayScale.
For example, setting all the pixels in my greyscale image to black. SetPixel throws an exception.
var bitmap = new Bitmap(16, 16, PixelFormat.Format16bppGrayScale);
for (int x = 0; x < bitmap.Width; x++)
{
for (int y = 0; y < bitmap.Height; y++)
{
bitmap.SetPixel(x,y, Color.Black);
}
}
You can use BitmapData bitmapDataIn = bitmap.LockBits(... )
Then use use byte* pDataIn = (byte*)bitmapDataIn.Scan0; to get a pointer to raw bitmap data.
This is 32-bit bitmap data, though
pDataIn[y * iStrideSize + x * 4 + 0] //Blue
pDataIn[y * iStrideSize + x * 4 + 1] //Greed
pDataIn[y * iStrideSize + x * 4 + 2] //Red
pDataIn[y * iStrideSize + x * 4 + 3] //Alpha
You can modify or read pixel values with the pointer
This is copy-paste of my code,
unsafe
{
byte* pDataIn = (byte*)bitmapDataIn.Scan0;
int iStrideSize = bitmapDataIn.Stride; //one row size in bytes, iWidth * 4
int y, x;
byte B, G, R, A;
for (y = 0; y < iHeight; y++)
{
for (x = 0; x < iWidth; x++)
{
B = pDataIn[y * iStrideSize + x * 4 + 0];
G = pDataIn[y * iStrideSize + x * 4 + 1];
R = pDataIn[y * iStrideSize + x * 4 + 2];
A = pDataIn[y * iStrideSize + x * 4 + 3];
}
}
bitmap.UnlockBits(bitmapDataIn);
}
I'm trying to add texture coordinates to each of the vertices so that a grass texture is added to each triangle. The code I have stretches the texture across the entire area which works but doesn't scale up very well. How do I correctly add (0,0), (0,1), (1,1), etc to the vertices?
Currently they're added in the SetUpVertices() method, should they be added in the SetUpIndices() method when the code can distinguish whether it's top left, bottom left, bottom right, etc. Any help would be greatly appreciated. The relevant methods are below and the full Game1.cs code is here http://pastebin.com/REd8QDZA
private void SetUpVertices()
{
vertices = new VertexPositionNormalTexture[terrainWidth * terrainHeight];
for (int x = 0; x < terrainWidth; x++)
{
for (int y = 0; y < terrainHeight; y++)
{
vertices[x + y * terrainWidth].Position = new Vector3(x, -y, heightData[x, y]);
vertices[x + y * terrainWidth].TextureCoordinate.X = x / (terrainWidth - 1.0);
vertices[x + y * terrainWidth].TextureCoordinate.Y = y / (terrainHeight - 1.0);
}
}
}
private void SetUpIndices()
{
indices = new short[(terrainWidth - 1) * (terrainHeight - 1) * 6];
int counter = 0;
for (int y = 0; y < terrainHeight - 1; y++)
{
for (int x = 0; x < terrainWidth - 1; x++)
{
int lowerLeft = x + y * terrainWidth;
int lowerRight = (x + 1) + y * terrainWidth;
int topLeft = x + (y + 1) * terrainWidth;
int topRight = (x + 1) + (y + 1) * terrainWidth;
indices[counter++] = (short)topLeft;
indices[counter++] = (short)lowerRight;
indices[counter++] = (short)lowerLeft;
indices[counter++] = (short)topLeft;
indices[counter++] = (short)topRight;
indices[counter++] = (short)lowerRight;
}
}
}
Just specify
vertices[x + y * terrainWidth].TextureCoordinate.X = x;
vertices[x + y * terrainWidth].TextureCoordinate.Y = y;
By default, texture coordinates greater than 1 will be wrapped and the texture is repeated.
Using this:
public static void DrawNormalizedAudio(ref float[] data, PictureBox pb,
Color color)
{
Bitmap bmp;
if (pb.Image == null)
{
bmp = new Bitmap(pb.Width, pb.Height);
}
else
{
bmp = (Bitmap)pb.Image;
}
int BORDER_WIDTH = 5;
int width = bmp.Width - (2 * BORDER_WIDTH);
int height = bmp.Height - (2 * BORDER_WIDTH);
using (Graphics g = Graphics.FromImage(bmp))
{
g.Clear(Color.Black);
Pen pen = new Pen(color);
int size = data.Length;
for (int iPixel = 0; iPixel < width; iPixel++)
{
// determine start and end points within WAV
int start = (int)((float)iPixel * ((float)size / (float)width));
int end = (int)((float)(iPixel + 1) * ((float)size / (float)width));
float min = float.MaxValue;
float max = float.MinValue;
for (int i = start; i < end; i++)
{
float val = data[i];
min = val < min ? val : min;
max = val > max ? val : max;
}
int yMax = BORDER_WIDTH + height - (int)((max + 1) * .5 * height);
int yMin = BORDER_WIDTH + height - (int)((min + 1) * .5 * height);
g.DrawLine(pen, iPixel + BORDER_WIDTH, yMax,
iPixel + BORDER_WIDTH, yMin);
}
}
pb.Image = bmp;
}
I got an error at this line:
g.DrawLine(pen, iPixel + BORDER_WIDTH, yMax,
iPixel + BORDER_WIDTH, yMin);
It says operation overflow(cannot divide by zero) or something like that. Any clue on the problem? Thanks.
UPDATE:
The codes i use to call the function is:
fileName = "c:\\sound\\happy_birthday.wav";
byte[] bytes = File.ReadAllBytes(fileName);
float[] getval = FloatArrayFromByteArray(bytes);
DrawNormalizedAudio(ref getval, pictureBox1, Color.White);
You are dividing by zero. Don't do it, as this operation is invalid. Check the values you pass to DrawLine are not 0.
int yMin = BORDER_WIDTH + height - (int)((min + 1) * .5 * height);
You are using the signed int data type - what happens is that this calculation overflows and results in a negative value, you get -2147483572 which is int.MaxValue+75 (overflow), could it be that min is a large negative value that causes the result to be 75 larger than int.MaxValue ?
The min and max were wrong, should be
float min = float.MinValue;
float max = float.MaxValue;