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];
}
}
Related
Trying to write an efficient algorithm to scale down YUV 4:2:2 by a factor of 2 - and which doesn't require a conversion to RGB (which is CPU intensive).
I've seen plenty of code on stack overflow for YUV to RGB conversion - but only an example of scaling for YUV 4:2:0 here which I have started based my code on. However, this produces an image which is effectively 3 columns of the same image with corrupt colours, so something is wrong with the algo when applied to 4:2:2.
Can anybody see what is wrong with this code?
public static byte[] HalveYuv(byte[] data, int imageWidth, int imageHeight)
{
byte[] yuv = new byte[imageWidth / 2 * imageHeight / 2 * 3 / 2];
int i = 0;
for (int y = 0; y < imageHeight; y += 2)
{
for (int x = 0; x < imageWidth; x += 2)
{
yuv[i] = data[y * imageWidth + x];
i++;
}
}
for (int y = 0; y < imageHeight / 2; y += 2)
{
for (int x = 0; x < imageWidth; x += 4)
{
yuv[i] = data[(imageWidth * imageHeight) + (y * imageWidth) + x];
i++;
yuv[i] = data[(imageWidth * imageHeight) + (y * imageWidth) + (x + 1)];
i++;
}
}
return yuv;
}
A fast way to generate a low quality thumbnail would be to discard half of the data in each dimension.
We break the image in 4x2 grid of pixels - each pair of pixels in the grid is represented by 4 bytes. In the down-scaled image, we take the color values for the first 2 pixels in the grid by copying the first 4 bytes, whilst discarding the other 12 bytes worth of data.
This scaling can be generalized to any power of 2 (1/2, 1/4, 1/8, ...) - this method is quick because it doesn't use any interpolation. This will give a lower quality image which appears blocky however - for better results consider some sampling approach.
public static byte[] FastResize(
byte[] data,
int imageWidth,
int imageHeight,
int scaleDownExponent)
{
var scaleDownFactor = (uint)Math.Pow(2, scaleDownExponent);
var outputImageWidth = imageWidth / scaleDownFactor;
var outputImageHeight = imageHeight / scaleDownFactor;
// 2 bytes per pixel.
byte[] yuv = new byte[outputImageWidth * outputImageHeight * 2];
var pos = 0;
// Process every other line.
for (uint pixelY = 0; pixelY < imageHeight; pixelY += scaleDownFactor)
{
// Work in blocks of 2 pixels, we discard the second.
for (uint pixelX = 0; pixelX < imageWidth; pixelX += 2*scaleDownFactor)
{
// Position of pixel bytes.
var start = ((pixelY * imageWidth) + pixelX) * 2;
yuv[pos] = data[start];
yuv[pos + 1] = data[start + 1];
yuv[pos + 2] = data[start + 2];
yuv[pos + 3] = data[start + 3];
pos += 4;
}
}
return yuv;
}
I assume that the original data is in the following order (as it seems so from your example code): First there are the luminance (Y) values of the pixels of the image (size = imageWidth*imageHeight bytes). After that there are the chrominance components UV, s.t., the values for a single pixel are given after each other. This means that the total size of the original image is 3*size.
Now for 4:2:2 subsampling means that every other value of the horizontal chrominance component are discarded. This reduces the data to size size + 0.5*size + 0.5*size = 2*size, i.e., luminance is kept completely and both chrominance components are divided to half. Therefore, the result image should be allocated as:
byte[] yuv = new byte[2*imageWidth*imageHeight];
As the first part of the image is copied in full the first loop becomes:
int i = 0;
for (int y = 0; y < imageHeight; y++)
{
for (int x = 0; x < imageWidth; x++)
{
yuv[i] = data[y * imageWidth + x];
i++;
}
}
Because this just copies the beginning of data this can be simplified to
int size = imageHeight*imageWidth;
int i = 0;
for (; i < size; i++)
{
yuv[i] = data[i];
}
Now to copy the rest we need to skip every other horizontal coordinate
for (int y = 0; y < imageHeight; y++)
{
for (int x = 0; x < imageWidth; x += 2) // +2 skip each other horizontal component
{
yuv[i] = data[size + y*2*imageWidth + 2*x];
i++;
yuv[i] = data[size + y*2*imageWidth + 2*x + 1];
i++;
}
}
The factor two in data-array index is needed because there are 2 bytes for each pixel (both chrominance components), so each "row" has 2*imageWidth bytes of data.
I am trying to create a simple image format, which writes for every pixel the argb color to a file, I used this code to get and set all
List<Color> pixels = new List<Color>();
Bitmap img = new Bitmap("*imagePath*");
for (int i = 0; i < img.Width; i++)
{
for (int j = 0; j < img.Height; j++)
{
Color pixel = img.GetPixel(i,j);
pixels.Add(pixel);
}
}
from:
How can I read image pixels' values as RGB into 2d array?
And then I write every pixel on a new line:
foreach(Color p in pixels)
{
streamWriter.WriteLine(p.ToArgb)
}
streamWriter.Close();
and then if I try to read it:
OpenFileDialog op = new OpenFileDialog();
op.ShowDialog();
StreamReader sr = new StreamReader(op.FileName);
int x = 1920;
int y = 1080;
Bitmap img = new Bitmap(x,y);
for (int i = 0; i < img.Width; i++)
{
string rl = sr.ReadLine();
for (int j = 0; j < img.Height; j++)
{
img.SetPixel(i, j, Color.FromArgb(Int32.Parse(rl)));
}
}
pictureBox1.Image = img;
but from this bmp file,
I get this output:
does someone knows how to fix this?
thanks in advance.
When you write the pixels, you are writing each one in a separate line. However, when reading, you are reading a single line per column, and then using that same color value for every row of the column.
instead, call ReadLine inside the innermost loop.
for (int i = 0; i < img.Width; i++)
{
for (int j = 0; j < img.Height; j++)
{
string rl = sr.ReadLine();
img.SetPixel(i, j, Color.FromArgb(Int32.Parse(rl)));
}
}
Needless to add, this image format is incredibly inefficient in terms of space, and in it's current implementation also in read and write performance. You would be wise to use it only as a learning exercise.
I am trying to work towards a
512 x 512 (262144 elements)
I currently have a
List<double[,]> data;
Dimensions are:
4096 x [8 , 8] (262144 elements)
The 2d array I am working towards is square.
List<List<float>> newList = new List<List<float>(); //working towards
I have tried something along the lines of:
for (int i = 0; i < Math.Sqrt(data.Count); i++ ) {
List<float> row = new List<float>();
foreach (double[,] block in data) {
for (int j = 0; j < 8; j++) {
row.Add(block[i,j]); //i clearly out of range
}
}
newList.Add(row);
}
What I was trying to do there was to brute force my way and add up every row (which is 8 in length) and then add the large rows to the newList.
I believe you can do that in the following way
var newList = new List<List<float>>();
for (int i = 0; i < 512; i++)
{
var innerList = new List<float>();
for (int j = 0; j < 512; j++)
{
int x =(i/8)*64 + (j/8);
int y = i % 8;
int z = j % 8;
innerList.Add(data[x][y,z]);
}
newList.Add(innerList);
}
Basically you have 64x64 of your 8x8 blocks. So the (i,j) coordinate of the larger 512x512 structure translate in the following ways. First to determine the 8x8 block you have to figure out the row and column of the 64x64 structure of blocks by dividing the i and j by the size of the block (8) then you multiply the row (i/8) by the number of block in a row (64) and add the column (j/8). For the y and z it's simpler because you know that its just a matter of the remainder of i and j when divided by 8 (i%8) and (j%8).
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'm writing the following code that implements the stft (http://en.wikipedia.org/wiki/Short-time_Fourier_transform) through the Exocortex library (http://www.exocortex.org/dsp/), where "window" is a 512 Hamming window, "left" is the left channel from an audio stream passed into a double array, "frames" is the number of frames I split the audio file into (say around 600) and the "offset" variable performs the overlap.
I've also added the ability of zero padding in the Exocortex FFT class:
if( data.Length < length ) {
for (int k = data.Length; k < length; k++)
{
data[k].Re = 0;
data[k].Im = 0;
}
The problem is that for frames=600 this code runs for about 7000msec! Am I missing something here?
Exocortex.DSP.ComplexF[] x_frame = new Exocortex.DSP.ComplexF[2048];
int offset = 0;
for (int m = 0; m < frames-1; m++)
{
for (int i = 0; i < 512; i++)
{
x_frame[i].Re = (float)(left[i + offset] * window[i]);
x_frame[i].Im = 0;
}
Exocortex.DSP.Fourier.FFT(x_frame, 2048, FourierDirection.Forward);
offset += 256;
}