first time working with C# here. I am reading a few images files, do some calculations, and output and array of double. I need to be able to save this double array (or these, since I will have multiples arrays) to a greyscale image. I have been looking around on the internet, I couldn't find much. i have done it on Python and Mathlab, but C# doesn't seems to be as friendly to me. here is what I have done so far (for the double image creation).
static Image MakeImage(double[,] data)
{
Image img = new Bitmap(data.GetUpperBound(1), data.GetUpperBound(0));
//Bitmap bitmap = new Bitmap(data.GetUpperBound(1), data.GetUpperBound(0));
for (int i = 0; i < data.GetUpperBound(1); i++)
{
for (int k = 0; k < data.GetUpperBound(0); k++)
{
//bitmap.SetPixel(k, i, Color.FromArgb((int)data[i, k],(int) data[i, k],(int) data[i, k]));
}
}
return img;
}
}
}
This code actually doesnt do much. It create my blank image template. color doesnt take double as input. I have no Idea how to create an image from data... I am stuck =)
thank you in advance.
If you can accept using an unsafe block this is pretty fast:
private Image CreateImage(double[,] data)
{
double min = data.Min();
double max = data.Max();
double range = max - min;
byte v;
Bitmap bm = new Bitmap(data.GetLength(0), data.GetLength(1));
BitmapData bd = bm.LockBits(new Rectangle(0, 0, bm.Width, bm.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
// This is much faster than calling Bitmap.SetPixel() for each pixel.
unsafe
{
byte* ptr = (byte*)bd.Scan0;
for (int j = 0; j < bd.Height; j++)
{
for (int i = 0; i < bd.Width; i++)
{
v = (byte)(255 * (data[i, bd.Height - 1 - j] - min) / range);
ptr[0] = v;
ptr[1] = v;
ptr[2] = v;
ptr[3] = (byte)255;
ptr += 4;
}
ptr += (bd.Stride - (bd.Width * 4));
}
}
bm.UnlockBits(bd);
return bm;
}
Related
I have a 2D array containing Temperature data from a numerically solved heat transfer problem in C#. To visualize the temperature distribution I used the "Bitmap"; Where the lowest Temperature is showed by the color Blue while the hottest is represented by Red!
The problem is that it takes too much time to generate the bitmap for a 300x300 image size! While i'm trying to work with larger ones which makes it impossible!
Is there any more efficient way to make it work?
Any help would be greatly appreciated
Here's a little bit of my code and a a generated bitmap:enter image description here
//RGB Struct
struct RGB
{
public Int32 num;
public int red;
public int green;
public int blue;
public RGB(Int32 num)
{
int[] color = new int[3];
int i = 2;
while (num > 0)
{
color[i] = num % 256;
num = num - color[i];
num = num / 256;
i--;
}
this.red = color[0];
this.green = color[1];
this.blue = color[2];
this.num = (256 * 256) * color[0] + 256 * color[1] + color[2];
}
}
//Create Color Array
Int32 red = 16711680;
Int32 blue = 255;
Int32[,] decimalColor = new Int32[Nx, Ny];
for (int i = 0; i < Nx; i++)
{
for (int j = 0; j < Ny; j++)
{
double alpha = (T_new[i, j] - T_min) / (T_max - T_min);
double C = alpha * (red - blue);
decimalColor[i, j] = Convert.ToInt32(C) + blue;
}
}
//Bitmap Result
Bitmap bmp = new Bitmap(Nx, Ny);
for (int i = 0; i < Nx; i++)
{
for (int j = 0; j < Ny; j++)
{
RGB rgb = new RGB(decimalColor[i, j]);
bmp.SetPixel(i,j,Color.FromArgb(rgb.red,rgb.green,rgb.blue));
}
}
pictureBox1.Image = bmp;
I have a Problem to Convert an RGB Image to a 2D double array that each element is between 0 to 1 in C#. I used a function to read each pixel of an Image then average and scale them to convert it into a 2d array. but this code is too slow. for a 36 Mega Pixel image it takes about 30 seconds in comparison with MATLAB that it takes just 0.5 second. since it is vital for my project to increase the speed of processing I don't know to do it
public static double[,] Image2Matrix(Bitmap Image)
{
int nR = Image.Size.Height;
int nC = Image.Size.Width;
double S=0 ;
Color C;
double[,] M = new double[nR, nC];
for (int i = 0; i < nR; i++)
{
for (int j = 0; j < nC; j++)
{
C= Image.GetPixel(j, i);
M[i, j] = (Convert.ToDouble(C.R) + Convert.ToDouble(C.B)+Convert.ToDouble(C.G)) / (3*255);
}
}
return M;
}
With a bit of LockBits and unsafe code it's possible to speed things up about 100 times.
Solution mostly cribbed from here.
public static double[,] Image2Matrix(Bitmap image)
{
if (image == null)
throw new ArgumentNullException("image");
var data = image.LockBits(
new Rectangle(0, 0, image.Width, image.Height),
ImageLockMode.ReadOnly, image.PixelFormat);
double[,] matrix = new double[image.Height, image.Width];
try
{
unsafe
{
byte* ptr = (byte*)data.Scan0;
for (int i = 0; i < data.Height; i++)
{
for (int j = 0; j < data.Width; j++)
{
matrix[i, j] = (ptr[0] + ptr[1] + ptr[2]) / (3d * 255);
ptr += 3;
}
ptr += data.Stride - data.Width * 3;
}
return matrix;
}
}
finally
{
image.UnlockBits(data);
}
}
A quick benchmark:
spender's method took : 59ms
sadegh's method took : 5162ms
arrays are identical : True
spender's method took : 66ms
sadegh's method took : 5133ms
arrays are identical : True
spender's method took : 68ms
sadegh's method took : 5168ms
arrays are identical : True
By parallelizing the summing, this goes even faster on my machine. YMMV.
public static double[,] Image2Matrix2(Bitmap image)
{
if (image == null)
throw new ArgumentNullException("image");
var data = image.LockBits(
new Rectangle(0, 0, image.Width, image.Height),
ImageLockMode.ReadOnly, image.PixelFormat);
double[,] matrix = new double[image.Height, image.Width];
try
{
unsafe
{
byte* scan0 = (byte*)data.Scan0;
Parallel.For(0, data.Height, i => {
for (int j = 0; j < data.Width; j++)
{
byte* ptr = scan0 + (i * data.Stride + j * 3);
matrix[i, j] = (ptr[0] + ptr[1] + ptr[2]) / (3d * 255);
}
});
return matrix;
}
}
finally
{
image.UnlockBits(data);
}
}
spender's method took : 22ms
sadegh's method took : 5284ms
I wrote an algorithm on Matlab. Hence I wanna use it on .Net. I perfectly converted .m file to .dll for using it on .Net with Matlab Library Compiler. First, I tried converting Matlab function to .dll without any parameter and it worked well on .Net. However, when I wanna use that function with parameter, I'm getting some error below. The parameter is basically image. I call the function on Matlab like this I = imread('xxx.jpg'); Detect(I);So my c# code like this
static void Main(string[] args)
{
DetectDots detectDots = null;
Bitmap bitmap = new Bitmap("xxx.jpg");
//Get image dimensions
int width = bitmap.Width;
int height = bitmap.Height;
//Declare the double array of grayscale values to be read from "bitmap"
double[,] bnew = new double[width, height];
//Loop to read the data from the Bitmap image into the double array
int i, j;
for (i = 0; i < width; i++)
{
for (j = 0; j < height; j++)
{
Color pixelColor = bitmap.GetPixel(i, j);
double b = pixelColor.GetBrightness(); //the Brightness component
bnew.SetValue(b, i, j);
}
}
MWNumericArray arr = bnew;
try
{
detectDots = new DetectDots();
detectDots.Detect(arr);
Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
I used the same image that I called xxx.jpg which is 5312 x 2988.
But I'm getting this error below.
... MWMCR::EvaluateFunction error ...
Index exceeds matrix dimensions.
Error in => DetectDots.m at line 12.
... Matlab M-code Stack Trace ...
at
file C:\Users\TAHAME~1\AppData\Local\Temp\tahameral\mcrCache9.0\MTM_220\MTM\DetectDots.m, name DetectDots, line 12.
The important thing is, it says "Index exceeds matrix dimensions", is it true way converting Bitmap to MWArray? What is the problem?
I realised that rows in C# correspond to columns in MWarray. So I change small things on the code.
Instead of double[,] bnew = new double[width, height]; I use it double[,] bnew = new double[height, width];
and instead of bnew.SetValue(b, i, j); I use it bnew.SetValue(b, j, i);
Someone may use the whole code about Bitmap to MWArray below
Bitmap bitmap = new Bitmap("001-2.bmp");
//Get image dimensions
int width = bitmap.Width;
int height = bitmap.Height;
//Declare the double array of grayscale values to be read from "bitmap"
double[,] bnew = new double[height, width];
//Loop to read the data from the Bitmap image into the double array
int i, j;
for (i = 0; i < width; i++)
{
for (j = 0; j < height; j++)
{
Color pixelColor = bitmap.GetPixel(i, j);
double b = pixelColor.GetBrightness(); //the Brightness component
//Note that rows in C# correspond to columns in MWarray
bnew.SetValue(b, j, i);
}
}
MWNumericArray arr = bnew;
On MSDN I found this for the definition of the image stride. In short it is the width in bytes of one line in the buffer.
Now I have an RGB image in a similar buffer and I have been given the stride and the image width in pixels, and I want to know how much padding bytes there have been added.
Is this simply stride - 3 * imagewidth since I have 3 bytes (RGB) per pixel?
unsafe private void setPrevFrame(IntPtr pBuffer)
{
prevFrame = new byte[m_videoWidth, m_videoHeight, 3];
Byte* b = (byte*) pBuffer;
for (int i = 0; i < m_videoWidth; i++)
{
for (int j = 0; j < m_videoHeight; j++)
{
for (int k = 0; k < 3; k++)
{
prevFrame[i,j,k] = *b;
b++;
}
}
b += (m_stride - 3 * m_videoHeight);
}
}
It's the last line of code I'm not sure about
Stride will be padded to a 4 byte boundary:
So if your image width is W and it is 3 bytes per pixel:
int strideWidth = ((W * 3) - 1) / 4 * 4 + 4;
//or simply
int strideWidth = Math.Abs(bData.Stride);
//and so
int padding = strideWidth - W * 3;
If you are using the .Stride property of the BitmapData object, you must Abs that value because it may be negative.
Following your edit of the question:
There is no need for you to know the padding in order to iterate all the bytes of the image:
unsafe private void setPrevFrame(IntPtr pBuffer)
{
for (int j = 0; j < m_videoHeight; j++)
{
b = scan0 + j * stride; //the first byte of the first pixel of the row
for (int i = 0; i < m_videoWidth; i++)
{
...
}
}
}
Your previous method will also fail on bottom-up images, as described in the MSDN link you posted.
I am writing a class for printing bitmaps to a portable bluetooth printer in Android via Mono For Android. My class is used to obtain the pixel data from the stream so that is can be sent to the printer in the correct format. Right now the class is simple, it just reads the height, width, and bits per pixel.
Using the offset it reads and returns the pixel data to the printer. Right now I am just working with 1 bit per pixel black and white images. The bitmaps I am working with are in Windows format.
Here is the original image:
Here is the result of printing, the first image is without any transformation. And the second one is the result of modifying the BitArray with the following code:
BitArray bits = new BitArray(returnBytes);
BitArray flippedBits = new BitArray(bits);
for (int i = 0, j = bits.Length - 1; i < bits.Length; i++, j--)
{
flippedBits[i] = bits[j];
}
My Question is:
How do I flip the image vertically when I am working with a byte array. I am having trouble finding the algorithm for doing this, all examples seem to suggest using established graphics libraries which I cannot use.
Edit:
My Bitmap is saved in a 1 dimensional array, with the first rows bytes, then the second, third, etc.
You need to do something like this:
BitArray bits = new BitArray(returnBytes);
BitArray flippedBits = new BitArray(bits);
for (int i = 0; i < bits.Length; i += width) {
for (int j = 0, k = width - 1; j < width; ++j, --k) {
flippedBits[i + j] = bits[i + k];
}
}
If you need to mirror picture upside-down, use this code:
BitArray bits = new BitArray(returnBytes);
BitArray flippedBits = new BitArray(bits);
for (int i = 0, j = bits.Length - width; i < bits.Length; i += width, j -= width) {
for (int k = 0; k < width; ++k) {
flippedBits[i + k] = bits[j + k];
}
}
For the format with width*height bits in row order, you just need to view the bit array as a two-dimensional array.
for(int row = 0; row < height; ++row) {
for(int column = 0; column < width; ++column) {
flippedBits[row*width + column] = bits[row*width + (width-1 - column)];
}
}
It would be a bit more complicated if there were more than one bit per pixel.
You need to use two loops, the first to iterate over all the rows and the second to iterate the pixels inside each row.
for (int y = 0; y < height; y++)
{
int row_start = (width/8) * y;
int flipped_row = (width/8) * (height-1 - y);
for (int x = 0; x < width/8; x++)
{
flippedBits[flipped_row+x] = bits[row_start+x];
}
}