I'm trying to merge an array of Bitmaps into a single Bitmap. Given a Bitmap[,] array b like the following (assume these are images that look like characters):
b[0,0] = 1
b[1,0] = 2
b[0,1] = 3
b[1,1] = 4
I want to generate
result = 12
34
For example, given the following four Bitmaps:
b[0,0] =;
b[1,0] =;
b[0,1] =;
b[1,1] =;
I want to generate
result =;
Here's my code so far:
public static Bitmap Moisac(ref Bitmap[,] b)
{
BitmapData[,] bmData = new BitmapData[b.GetUpperBound(0) + 1, b.GetUpperBound(1) + 1];
IntPtr[,] scan0 = new IntPtr[b.GetUpperBound(0) + 1, b.GetUpperBound(1) + 1];
unsafe
{
byte*[,] p = new byte*[b.GetUpperBound(0) + 1,b.GetUpperBound(1) + 1];
for (int i = 0; i <= b.GetUpperBound(0); i++)
for (int j = 0; j <= b.GetUpperBound(1); j++)
if (b[i, j].Width != b[0, 0].Width | b[i, j].Height != b[0, 0].Height)
throw new ArgumentException(
"Width and Height properties of all elements of b must be equal.",
"b");
int oneW = b[0, 0].Width;
int oneH = b[0, 0].Height;
int overallWidth = oneW * (b.GetUpperBound(0) + 1);
int overallHeight = oneH * (b.GetUpperBound(1) + 1);
Bitmap result = new Bitmap(b[0, 0], overallWidth, overallHeight);
for (int i = 0; i <= b.GetUpperBound(0); i++)
for (int j = 0; j <= b.GetUpperBound(1); j++)
{
bmData[i, j] = b[i, j].LockBits(new Rectangle(0, 0, oneW, oneH),
ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
scan0[i, j] = bmData[i, j].Scan0;
p[i, j] = (byte*)(void*)scan0[i, j];
}
BitmapData rbmData = result.LockBits(new Rectangle(0, 0, overallWidth, overallHeight),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
int stride = bmData[0, 0].Stride;
int nOffset = stride - 3*b[0, 0].Width;
int rStride = rbmData.Stride;
IntPtr rScan0 = rbmData.Scan0;
byte* rp = (byte*) (void*) rScan0;
for (int imgY = 0; imgY < b.GetUpperBound(1); ++imgY)
{
for (int imgX = 0; imgX <= b.GetUpperBound(0); ++imgX)
{
byte* currp = p[imgX, imgY];
for (int y = 0; y < oneH; ++y)
{
for (int x = 0; x < 3*oneW; ++x)
{
rp[rStride*(imgY*oneH + y) + 3*imgX*oneW + x] = currp[0];
++currp;
}
currp += nOffset;
}
}
}
for (int i = 0; i <= b.GetUpperBound(0); i++)
for (int j = 0; j <= b.GetUpperBound(1); j++)
b[i, j].UnlockBits(bmData[i,j]);
result.UnlockBits(rbmData);
return result;
}
}
See the images in the album here. All of them won't display here.
I made the most stupid mistake ever. However, if it may help anyone, change
for (int imgY = 0; imgY < b.GetUpperBound(1); ++imgY)
to
for (int imgY = 0; imgY <= b.GetUpperBound(1); ++imgY)
(the < should be <=).
I made a version based on your code that copies lines of pixels rather than pixels. Seems to work (faster) on my box at least. Maybe you like it. Minimal changes just within the for each loops.
Im using it really only for concatenating...before warping images into a donut for a 360 simple degree view of multiple camera images...
public static Bitmap Mosaic(ref Bitmap[,] b)
{
BitmapData[,] bmData = new BitmapData[b.GetUpperBound(0) + 1, b.GetUpperBound(1) + 1];
IntPtr[,] scan0 = new IntPtr[b.GetUpperBound(0) + 1, b.GetUpperBound(1) + 1];
unsafe
{
byte*[,] p = new byte*[b.GetUpperBound(0) + 1, b.GetUpperBound(1) + 1];
for (int i = 0; i <= b.GetUpperBound(0); i++)
for (int j = 0; j <= b.GetUpperBound(1); j++)
if (b[i, j].Width != b[0, 0].Width | b[i, j].Height != b[0, 0].Height)
throw new ArgumentException(
"Width and Height properties of all elements of b must be equal.",
"b");
int oneW = b[0, 0].Width;
int oneH = b[0, 0].Height;
int overallWidth = oneW * (b.GetUpperBound(0) + 1);
int overallHeight = oneH * (b.GetUpperBound(1) + 1);
Bitmap result = new Bitmap(b[0, 0], overallWidth, overallHeight);
for (int i = 0; i <= b.GetUpperBound(0); i++)
for (int j = 0; j <= b.GetUpperBound(1); j++)
{
bmData[i, j] = b[i, j].LockBits(new Rectangle(0, 0, oneW, oneH),
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
scan0[i, j] = bmData[i, j].Scan0;
p[i, j] = (byte*)(void*)scan0[i, j];
}
BitmapData rbmData = result.LockBits(new Rectangle(0, 0, overallWidth, overallHeight),
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
int stride = bmData[0, 0].Stride;
int nOffset = stride - 4 * b[0, 0].Width;
int rStride = rbmData.Stride;
IntPtr rScan0 = rbmData.Scan0;
byte* rp = (byte*)(void*)rScan0;
for (int imgY = 0; imgY <= b.GetUpperBound(1); ++imgY)
{
for (int y = 0; y < oneH; ++y)
{
byte* currp = p[0, imgY];
for (int imgX = 0; imgX <= b.GetUpperBound(0); ++imgX)
{
currp = p[imgX, imgY];
currp += stride*y;
byte[] buffer = new byte[stride];
Marshal.Copy(new IntPtr(currp), buffer, 0, buffer.Length);
Marshal.Copy(buffer, 0, new IntPtr(rp), buffer.Length);
rp += stride;
}
}
}
for (int i = 0; i <= b.GetUpperBound(0); i++)
for (int j = 0; j <= b.GetUpperBound(1); j++)
b[i, j].UnlockBits(bmData[i, j]);
result.UnlockBits(rbmData);
return result;
}
}
Related
I want to display the frequency spectrum of a .wav file.
I don’t know how to do it right. I use C# with naudio nuget to handle the audio data.
When I Insert all spec_data points I only have one-col filled with data. (Picture 1)
what it looks like now (Picture 1)
how it should look like at the end
How can I get all spectrum points of the audio file?
var buffer = new byte[fft_size];
int bytes_read = fileStream.Read(buffer, 0, buffer.Length);
int BYTES_PER_POINT = fileStream.WaveFormat.BitsPerSample / 8; //8Bit = 1Byte
short[] values = new short[buffer.Length / BYTES_PER_POINT];
for (int n = 0; n < BYTES_PER_POINT; n++)
{
for (int i = 0; i < bytes_read; i += BYTES_PER_POINT)
{
values[i / BYTES_PER_POINT] = (short)((buffer[i + 1] << 8) | buffer[i + 0]);
}
}
neanalizir_values.AddRange(values);
short[] data = new short[fft_size];
data = neanalizir_values.GetRange(0, fft_size).ToArray();
spec_data.RemoveAt(0);
List<double> new_data = new List<double>();
Complex[] fft_buffer = new Complex[fft_size];
for (int i = 0; i < fft_size; i++)
{
fft_buffer[i].X = (float)(neanalizir_values[i] * FastFourierTransform.HammingWindow(i, fft_size));
fft_buffer[i].Y = 0;
}
FastFourierTransform.FFT(true, (int)Math.Log(fft_size, 2.0), fft_buffer);
for (int i = 0; i < spec_data[spec_data.Count - 1].Count; i++)
{
double val;
val = (double)fft_buffer[i].X + (double)fft_buffer[i].Y;
val = Math.Abs(val);
new_data.Add(val);
}
new_data.Reverse();
spec_data.Insert(spec_data.Count, new_data);
neanalizir_values.RemoveRange(0, fft_size / pixelsPerBuffer);
Bitmap bitmap = new Bitmap(spec_data.Count, spec_data[0].Count, PixelFormat.Format8bppIndexed);
ColorPalette pal = bitmap.Palette;
for (int i = 0; i < 256; i++)
pal.Entries[i] = Color.FromArgb(255, i, i, i);
bitmap.Palette = pal;
BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat);
byte[] pixels = new byte[bitmapData.Stride * bitmap.Height];
for (int col = 0; col < spec_data.Count; col++)
{
double scaleFactor = 40;
for (int row = 0; row < spec_data[col].Count; row++)
{
int bytePosition = row * bitmapData.Stride + col;
double pixelVal = spec_data[col][row] * scaleFactor;
pixelVal = Math.Max(0, pixelVal);
pixelVal = Math.Min(255, pixelVal);
pixels[bytePosition] = (byte)(pixelVal);
}
}
Marshal.Copy(pixels, 0, bitmapData.Scan0, pixels.Length);
bitmap.UnlockBits(bitmapData);
pictureBox1.Image = bitmap;
Take a look at this source code. A 3x3 Sharpen filter with the following kernel
0 -1 0
-1 5 -1
0 -1 0
gives the following output:
I tried to replicate the outcome using my own code which is pretty much straight forward:
public partial class FilterForm : Form
{
public FilterForm()
{
InitializeComponent();
Bitmap image = (Bitmap)Bitmap.FromFile("lena.jpg");
InputPictureBox.Image = image;
double[,] dImage = ToDouble2d(image);
double[,] dMask = { { 0,-1, 0, },
{ -1, 5, -1, },
{ 0,-1, 0, }, };
double[,]dConv = LinearConvolutionSpatial(dImage, dMask);
Bitmap conv = ToBitmap2d(dConv, PixelFormat.Format32bppArgb);
OutputPictureBox.Image = conv;
}
public double[,] ToDouble2d(Bitmap input)
{
int width = input.Width;
int height = input.Height;
double[,] array2d = new double[width, height];
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
Color cl = input.GetPixel(x, y);
double gray = ((cl.R * 0.3) + (cl.G * 0.59) + (cl.B * 0.11));
array2d[x, y] = gray / 255.0;
}
}
return array2d;
}
public Bitmap ToBitmap2d(double[,] image, PixelFormat pixelFormat)
{
int Width = image.GetLength(0);
int Height = image.GetLength(1);
Bitmap bmp = new Bitmap(Width, Height, pixelFormat);
for (int y = 0; y < Height; y++)
{
for (int x = 0; x < Width; x++)
{
int i = (int)(image[x, y] * 255.0);
if (i > 255) i = 255;
if (i < 0) i = 0;
Color clr = Color.FromArgb(i, i, i);
bmp.SetPixel(x, y, clr);
}
}
return bmp;
}
private double[,] LinearConvolutionSpatial(double[,] paddedImage, double[,] mask)
{
int paddedImageWidth = paddedImage.GetLength(0);
int paddedImageHeight = paddedImage.GetLength(1);
int maskWidth = mask.GetLength(0);
int maskHeight = mask.GetLength(1);
int imageWidth = paddedImageWidth - maskWidth;
int imageHeight = paddedImageHeight - maskHeight;
double[,] convolve = new double[imageWidth, imageHeight];
for (int y = 0; y < imageHeight; y++)
{
for (int x = 0; x < imageWidth; x++)
{
double sum = Sum(paddedImage, mask, x, y);
int xxx = x;
int yyy = y;
convolve[xxx, yyy] = sum;
string str = string.Empty;
}
}
Rescale(convolve);
return convolve;
}
double Sum(double[,] paddedImage1, double[,] mask1, int startX, int startY)
{
double sum = 0;
int maskWidth = mask1.GetLength(0);
int maskHeight = mask1.GetLength(1);
for (int y = startY; y < (startY + maskHeight); y++)
{
for (int x = startX; x < (startX + maskWidth); x++)
{
double img = paddedImage1[x, y];
double msk = mask1[maskWidth - x + startX - 1, maskHeight - y + startY - 1];
sum = sum + (img * msk);
}
}
return sum;
}
void Rescale(double[,] convolve)
{
int imageWidth = convolve.GetLength(0);
int imageHeight = convolve.GetLength(1);
double minAmp = 0.0;
double maxAmp = 0.0;
for (int j = 0; j < imageHeight; j++)
{
for (int i = 0; i < imageWidth; i++)
{
minAmp = Math.Min(minAmp, convolve[i, j]);
maxAmp = Math.Max(maxAmp, convolve[i, j]);
}
}
double scale = 1 / (Math.Abs(minAmp) + maxAmp);
for (int j = 0; j < imageHeight; j++)
{
for (int i = 0; i < imageWidth; i++)
{
double d = (convolve[i, j] + Math.Abs(minAmp)) * scale;
convolve[i, j] = d;
}
}
}
}
But, the problem I am facing is, my output has a different contrast.
What points I should work on?
Some of the above code has a min/max effect and balances the histogram.
Remove the normalizing bit from this line:
array2d[x, y] = gray;// / 255.0;
I've removed the rescale multiplier of 255 in this piece:
public Bitmap ToBitmap2d(double[,] image, PixelFormat pixelFormat)
{
int Width = image.GetLength(0);
int Height = image.GetLength(1);
Bitmap bmp = new Bitmap(Width, Height, pixelFormat);
for (int y = 0; y < Height; y++)
{
for (int x = 0; x < Width; x++)
{
int i = (int)(image[x, y] * 1);
if (i > 255) i = 255;
if (i < 0) i = 0;
Color clr = Color.FromArgb(i, i, i);
bmp.SetPixel(x, y, clr);
}
}
return bmp;
}
And I've also removed the scaling factor from this function:
void Rescale(double[,] convolve)
{
int imageWidth = convolve.GetLength(0);
int imageHeight = convolve.GetLength(1);
double minAmp = 0.0;
double maxAmp = 255.0;
for (int j = 0; j < imageHeight; j++)
{
for (int i = 0; i < imageWidth; i++)
{
minAmp = Math.Min(minAmp, convolve[i, j]);
maxAmp = Math.Max(maxAmp, convolve[i, j]);
}
}
double scale = 1 / (Math.Abs(minAmp) + maxAmp);
for (int j = 0; j < imageHeight; j++)
{
for (int i = 0; i < imageWidth; i++)
{
double d = (convolve[i, j]);// + Math.Abs(minAmp)) * scale;
convolve[i, j] = d;
}
}
}
Appears to work as intended after those changes are made, in this case.
I have found the solution from this link. The main clue was to introduce an offset and a factor.
factor is the sum of all values in the kernel.
offset is an arbitrary value to fix the output further.
The following source code is supplied in the given link:
private void SafeImageConvolution(Bitmap image, ConvMatrix fmat)
{
//Avoid division by 0
if (fmat.Factor == 0)
return;
Bitmap srcImage = (Bitmap)image.Clone();
int x, y, filterx, filtery;
int s = fmat.Size / 2;
int r, g, b;
Color tempPix;
for (y = s; y < srcImage.Height - s; y++)
{
for (x = s; x < srcImage.Width - s; x++)
{
r = g = b = 0;
// Convolution
for (filtery = 0; filtery < fmat.Size; filtery++)
{
for (filterx = 0; filterx < fmat.Size; filterx++)
{
tempPix = srcImage.GetPixel(x + filterx - s, y + filtery - s);
r += fmat.Matrix[filtery, filterx] * tempPix.R;
g += fmat.Matrix[filtery, filterx] * tempPix.G;
b += fmat.Matrix[filtery, filterx] * tempPix.B;
}
}
r = Math.Min(Math.Max((r / fmat.Factor) + fmat.Offset, 0), 255);
g = Math.Min(Math.Max((g / fmat.Factor) + fmat.Offset, 0), 255);
b = Math.Min(Math.Max((b / fmat.Factor) + fmat.Offset, 0), 255);
image.SetPixel(x, y, Color.FromArgb(r, g, b));
}
}
}
I am calculating the average of the RGB channels of images in C# and matlab and getting slightly different result?? (am using 0-255 pixel values...)
The difference is not large but I just can't seem to understand the reason...
Is this common?? Or is it due to bitmap implementation of image?? Or precision issue?? Or does it mean their is something wrong with my code??
Code:
Matlab
I = imread('Photos\hv2512.jpg');
Ir=double(I(:,:,1));
Ig=double(I(:,:,2));
Ib=double(I(:,:,3));
avRed=mean2(Ir)
avGn=mean2(Ig)
avBl=mean2(Ib)
C#
Bitmap bmp= new Bitmap(open.FileName)
double[,] Red = new double[bmp.Width, bmp.Height];
double[,] Green = new double[bmp.Width, bmp.Height];
double[,] Blue = new double[bmp.Width, bmp.Height];
int PixelSize = 3;
BitmapData bmData = null;
if (Safe)
{
Color c;
for (int j = 0; j < bmp.Height; j++)
{
for (int i = 0; i < bmp.Width; i++)
{
c = bmp.GetPixel(i, j);
Red[i, j] = (double) c.R;
Green[i, j] = (double) c.G;
Blue[i, j] = (double) c.B;
}
}
}
double avRed = 0, avGrn = 0, avBlue = 0;
double sumRed = 0, sumGrn = 0, sumBlue = 0;
int cnt = 0;
for (int rws = 0; rws < Red.GetLength(0); rws++)
for (int clms = 0; clms < Red.GetLength(1); clms++)
{
sumRed = sumRed + Red[rws, clms];
sumGrn = sumGrn + Green[rws, clms];
sumBlue = sumBlue + Blue[rws, clms];
cnt++;
}
avRed = sumRed / cnt;
avGrn = sumGrn / cnt;
avBlue = sumBlue / cnt;
This is the image I am using
I've written code to smooth an image,it's using 3x3 averaging filter. But seem it's not working
The picture output almost black
public void Smooth(Bitmap bmpInput){
Bitmap temp;
Color c;
float sum = 0;
for (int i = 0; i < bmpInput.Width; i++)
{
for (int j = 0; j < bmpInput.Height; j++)
{
c = bmpInput.GetPixel(i, j);
byte gray = (byte)(.333 * c.R + .333 * c.G + .333 * c.B);
bmpInput.SetPixel(i, j, Color.FromArgb(gray, gray, gray));
}
}
temp = bmpInput;
for (int i = 0; i <= bmpInput.Width - 3; i++)
for (int j = 0; j <= bmpInput.Height - 3; j++)
{
for (int x = i; x <= i + 2; x++)
for (int y = j; y <= j + 2; y++)
{
c = bmpInput.GetPixel(x,y);
sum = sum + c.R ;
}
int color = (int)Math.Round(sum/9,10);
temp.SetPixel(i + 1, j + 1, Color.FromArgb(color, color, color));
sum = 0;
}
bmpInput = temp;
}
The variable tempstill refers to the exact same bitmap. You have to assign tempto new Bitmap image and work with this. Alternatively, you can store the new pixel values in a temporary array and transfer the contents of this array back to the image afterwards.
I have an MxNx3 matrix and i want to transfer it into matlab using MWArray.
Here is my code, however there is no CTOR for that.
Is there any way to do it?
RGBImage image = _currentImage as RGBImage;
int height = image.Height;
int width = image.Width;
//transform the 1D array of byte into MxNx3 matrix
byte[, ,] rgbByteImage = new byte[3, height, width];
if (image[0].Bpp > 16)
{
for (int i = 0; i < height; i++)
{
for (int j = 0, k = 0; k < width; j = j + 3, k++)
{
rgbByteImage[0, i, k] = image[0].Data[i * width + j];
rgbByteImage[1, i, k] = image[0].Data[i * width + j + 1];
rgbByteImage[2, i, k] = image[0].Data[i * width + j + 2 ];
}
}
}
MWNumericArray tempArr = new MWNumericArray(rgbByteImage);
RGBImage image = _currentImage as RGBImage;
int height = image.Height;
int width = image.Width;
//transform the 1D array of byte into MxNx3 matrix
byte[ , , ] RGBByteImage = new byte[3,height, width];
if (image[0].Bpp > 16)
{
for (int i = 0; i < height; i++)
{
for (int j = 0, k = 0; k < width; j = j + 3, k++)
{
RGBByteImage[0, i, k] = image[0].Data[3 * i * width + j];
RGBByteImage[1, i, k] = image[0].Data[3 * i * width + j + 1];
RGBByteImage[2, i, k] = image[0].Data[3 * i * width + j + 2];
}
}
}
MWNumericArray matrix = null;
matrix = new MWNumericArray(MWArrayComplexity.Real, MWNumericType.Int8, 3,height, width);
matrix = RGBByteImage;
This is what I have found.
There is also a nice tutorial here
http://domoreinlesstime.wordpress.com/2013/01/26/access-matlab-from-c/
Please notice that you have the correct refernce to the MWArray.dll file (x64 or x86). I have wasted a day or so on that.