Reading QR Code in an image with zxing - c#

I'm using a C# library for reading of QRCodes. A lot of the samples I've found are based off the old version of zxing where the RGBLuminanceSource constructor still takes in bitmap. In the latest version RGBLuminanceSource only takes byte[]. I've tried to convert bitmap to byte[], but the decode result is always null.
Here's the code I used for conversion:
private byte[] GetRGBValues(Bitmap bmp)
{
// Lock the bitmap's bits.
System.Drawing.Rectangle rect = new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height);
System.Drawing.Imaging.BitmapData bmpData = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp.PixelFormat);
// Get the address of the first line.
IntPtr ptr = bmpData.Scan0;
// Declare an array to hold the bytes of the bitmap.
int bytes = bmpData.Stride * bmp.Height;
byte[] rgbValues = new byte[bytes];
// Copy the RGB values into the array.
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);
bmp.UnlockBits(bmpData);
return rgbValues;
}
and for decode:
Bitmap bitmap = Bitmap.FromFile(#"C:\QRimages.jpg") as Bitmap;
LuminanceSource source = new RGBLuminanceSource(GetRGBValues(bitmap), bitmap.Width, bitmap.Height);
var binarizer = new HybridBinarizer(source);
var binBitmap = new BinaryBitmap(binarizer);
QRCodeReader reader = new QRCodeReader();
var result = reader.decode(binBitmap);
Somehow the result is always null.
Also, our requirement is that we have to use image taken by camera. I've tried this:
Bitmap bitmap = Bitmap.FromFile(#"C:\QRimages.jpg") as Bitmap;
BarcodeReader reader = new BarcodeReader { AutoRotate = true, TryHarder = true };
Result result = reader.Decode(bitmap);
It only works for the QR image I download online, but if I print out that image and take a picture of that with my phone, then try to process that image, the result is back to null.
Any suggestions would be appreciated.
Here's the image I'm using:

Related

C#, Byte array to System.Drawing.Image error

I am trying to convert some video playback code from Unity to C# WPF, and I have hit a wall with the conversion.
I have my video frame as a
private byte[] _textureBuffer;
and I am using this code:
MemoryStream ms = new MemoryStream(_textureBuffer, 0, _textureBuffer.Length);
ms.Seek(0, SeekOrigin.Begin);
System.Drawing.Image x = System.Drawing.Image.FromStream(ms);
Which results in a 'Parameter is invalid' crash on the last line.
The data is loaded into the buffer correctly and the buffer is filled:
_textureBuffer.Length = 4147200
The image is 3840 x 2160 resolution.
The original fully functional Unity code is:
private void UpdateTexture(int frameAt)
{
var block = _lz4Blocks[frameAt];
_filestream.Seek((long)block.address, SeekOrigin.Begin);
_filestream.Read(_lz4Buffer, 0, (int)block.size);
Marshal.Copy(_lz4Buffer, 0, _lz4BufferNative, (int)block.size);
Lz4Native.lz4_decompress_safe_native(_lz4BufferNative, _textureBufferNative, (int)block.size, _frameBytes);
Marshal.Copy(_textureBufferNative, _textureBuffer, 0, _frameBytes);
_texture.LoadRawTextureData(_textureBuffer);
_texture.Apply();
}
And my (crashing) WPF version is:
public System.Drawing.Image UpdateTexture(int frameAt)
{
var block = _lz4Blocks[frameAt];
_filestream.Seek((long)block.address, SeekOrigin.Begin);
_filestream.Read(_lz4Buffer, 0, (int)block.size);
Marshal.Copy(_lz4Buffer, 0, _lz4BufferNative, (int)block.size);
Lz4Native.lz4_decompress_safe_native(_lz4BufferNative, _textureBufferNative, (int)block.size, _frameBytes);
Marshal.Copy(_textureBufferNative, _textureBuffer, 0, _frameBytes);
MemoryStream ms = new MemoryStream(_textureBuffer, 0, _textureBuffer.Length);
ms.Seek(0, SeekOrigin.Begin);
System.Drawing.Image x = System.Drawing.Image.FromStream(ms);
return x;
// _texture.LoadRawTextureData(_textureBuffer);
// _texture.Apply();
}
This question says that the image data is not in the correct format, but has no answer for how to fix it.
Where am i going wrong?
EDIT: Using lockbits as suggested, yields me an image:
Bitmap x = new Bitmap(_width, _height, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
BitmapData bmpData = x.LockBits(new System.Drawing.Rectangle(0, 0, x.Width, x.Height), ImageLockMode.WriteOnly, x.PixelFormat);
Marshal.Copy(_textureBuffer, 0, bmpData.Scan0, _textureBuffer.Length);
x.UnlockBits(bmpData);
However it is scrambled.
When i expect:
and using Format8bppIndexed as suggested:

C# Modify a byte array and convert to image

In the code below I want to convert an image to a byte array, modify the value of some pixels, and convert it back to an image.
Everything works fine if I don't modify any pixel value. The two conversions work. But if I try to modify a pixel value between the two conversions I get an exception. Can you tell me what I am doing wrong ?
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.ShowDialog();
FileStream bmpstream = new FileStream(openFileDialog.FileName, FileMode.Open, FileAccess.Read);
Bitmap spotImage = new Bitmap(bmpstream);
ImageConverter imgCon = new ImageConverter();
byte[] rgbValues = (byte[])imgCon.ConvertTo(spotImage, typeof(byte[]));
for (int counter = 2; counter < rgbValues.Length; counter += 3)
{
Buffer.SetByte(rgbValues, counter, 0x00);
//rgbValues[counter] = 0x00; <--I tried also this (not sure of the difference) and I get the same result
}
Image image2 = null;
using (MemoryStream mStream = new MemoryStream(rgbValues, 0, rgbValues.Length))
{
image2 = Image.FromStream(mStream, true); //this line gives the exception
}
pictureBox2.Image = image2;
I also tried to open the file using Bitmap.LockBits and got the same result. Here is the second version of the code (again, it worked as long as I didn't modify the byte array):
Rectangle rect = new Rectangle(0, 0, spotImage.Width, spotImage.Height);
BitmapData bmpData = spotImage.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, spotImage.PixelFormat);
IntPtr pointeur = bmpData.Scan0;
int bytes = Math.Abs(bmpData.Stride) * bmpData.Height;
byte[] rgbValues = new byte[bytes];
System.Runtime.InteropServices.Marshal.Copy(pointeur, rgbValues, 0, bytes);
for (int counter = 2; counter < rgbValues.Length; counter += 3)
{
Buffer.SetByte(rgbValues, counter, 0x00);
//rgbValues[counter] = 0x00;
}
spotImage.UnlockBits(bmpData);
Image image2 = null;
using (MemoryStream mStream = new MemoryStream(rgbValues, 0, rgbValues.Length))
{
image2 = Image.FromStream(mStream, true); //this line gives the exception
}
pictureBox2.Image = image2;
Your both attempts failed, because as in the comments:
First attempt - you mess up bytes in file header
Second attempt - you try to decode raw pixel data as Image
Your second attempt is much closer to correct solution. Lock bits with Write enabled and stay with the image you already open - no need to rebuild new bitmap (if there is actually such need in your specific case then I leave this to you as an exercise):
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.ShowDialog();
FileStream bmpstream = new FileStream(openFileDialog.FileName, FileMode.Open, FileAccess.Read);
Bitmap spotImage = new Bitmap(bmpstream);
Rectangle rect = new Rectangle(0, 0, spotImage.Width, spotImage.Height);
BitmapData bmpData = spotImage.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, spotImage.PixelFormat);
IntPtr pointeur = bmpData.Scan0;
int bytes = Math.Abs(bmpData.Stride) * bmpData.Height;
byte[] rgbValues = new byte[bytes];
System.Runtime.InteropServices.Marshal.Copy(pointeur, rgbValues, 0, bytes);
var pixelSize = Image.GetPixelFormatSize(bmpData.PixelFormat);
for (int counter = 2; counter < rgbValues.Length; counter += 3)
{
rgbValues[counter] = 0x00;
}
// copy buffer back to image
System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, pointeur, bytes);
spotImage.UnlockBits(bmpData);
pictureBox2.Image = spotImage;
This should work. I don't know what effect on the image you wanted to achieve though.

Difference between bitmap and bitmapdata

What is the difference between System.Drawing.bitmap and System.Drawing.Imaging.bitmapdata in C#?
How to convert them to each other?
System.Drawing.Bitmap is an actual bitmap object. You can use it to draw to using a Graphics instance obtained from it, you can display it on the screen, you can save the data to a file, etc.
The System.Drawing.Imaging.BitmapData class is a helper object used when calling the Bitmap.LockBits() method. It contains information about the locked bitmap, which you can use to inspect the pixel data within the bitmap.
You can't really "convert" between the two per se, as they don't represent the same information. You can obtain a BitmapData object from a Bitmap object simply by calling LockBits(). If you have a BitmapData object from some other Bitmap object, you can copy that data to a new Bitmap object by allocating one with the same format as the original, calling LockBits on that one too, and then just copying the bytes from one to the other.
Convert bitmap to bitmap data. Also refer this link
Private void LockUnlockBitsExample(PaintEventArgs e) {
// Create a new bitmap.
Bitmap bmp = new Bitmap("c:\\fakePhoto.jpg");
// Lock the bitmap's bits.
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
System.Drawing.Imaging.BitmapData bmpData = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat);
// Get the address of the first line.
IntPtr ptr = bmpData.Scan0;
// Declare an array to hold the bytes of the bitmap. 
int bytes = Math.Abs(bmpData.Stride) * bmp.Height;
byte[] rgbValues = new byte[bytes];
// Copy the RGB values into the array.
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);
// Set every third value to 255. A 24bpp bitmap will look red.  
for (int counter = 2; counter < rgbValues.Length; counter += 3) rgbValues[counter] = 255;
// Copy the RGB values back to the bitmap
System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);
// Unlock the bits.
bmp.UnlockBits(bmpData);
// Draw the modified image.
e.Graphics.DrawImage(bmp, 0, 150);
}

Convert Image into Byte[]

I want to start learning about how to tear images apart to find patterns in them but in order to do that I need to first see what makes it up. I want to take a png and convert it into a byte array so I can print it out and see if I can recognize simple patterns in the array values.
So far I have this
public MainWindow()
{
InitializeComponent();
System.Drawing.Image image;
image = System.Drawing.Image.FromFile("one.png");
byte[] imArray = imageToByteArray(image);
String bytes = "";
foreach (Char bite in imArray)
{
bytes += "-"+bite;
}
MessageBox.Show(bytes);
}
public byte[] imageToByteArray(System.Drawing.Image imageIn)
{
MemoryStream ms = new MemoryStream();
imageIn.Save(ms, System.Drawing.Imaging.ImageFormat.Gif);
return ms.ToArray();
}
But it doesn't seem to be working. It gives me a null error when the conversion method is called. I have NO clue why this isn't working because my understanding of the compenents is nill.
If you can suggest an easier way to make this conversion feel free to post it. Im not stuck on this code I just want a working example so I have a starting point.
Thanks!
I'd recommend starting with Bitmap to look at binary data - most other formats store data compressed, so you have no chance to understand what is inside an image by looking at the bytes.
The method you want is Bitmap.LockBits. The article also includes complete sample how to read from file and look t bits, excerpt below:
Bitmap bmp = new Bitmap("c:\\fakePhoto.jpg");
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
BitmapData bmpData =
bmp.LockBits(rect, ImageLockMode.ReadWrite, bmp.PixelFormat);
int bytes = Math.Abs(bmpData.Stride) * bmp.Height;
byte[] rgbValues = new byte[bytes];
// Copy the RGB values into the array.
Marshal.Copy(bmpData.Scan0, rgbValues, 0, bytes);
you could try converting the image to a dataURI then converting it to a blob, heres an example of how you can convert dataURIs to blobs
Blob from DataURL?
function dataURItoBlob(dataURI) {
var byteString = atob(dataURI.split(',')[1]);
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
var bb = new BlobBuilder();
bb.append(ab); return bb.getBlob(mimeString);
}
Or you can just open the file in a binary editor.

Convert Kinect ColorImageFrame to Bitmap

I´m using Kinect (Microsoft SDK) with XNA. I want to use GRATF for marker-recognition
How to convert the data of a Kinect ColorImageFrame to a System.Drawing.Bitmap or AForge.Imaging.UnmanagedImage that I can process them with GRATF?
void kinectSensor_ColorFrameReady(object sender, ColorImageFrameReadyEventArgs e)
{
Bitmap bitmap = null;
ColorImageFrame frame = e.OpenColorImageFrame();
byte[] buffer = new byte[frame.PixelDataLength];
frame.CopyPixelData(buffer);
// how to convert the data in buffer to a bitmap?
var glyphs = recognizer.FindGlyphs(bitmap);
...
}
You can find the answer in this article.
To summarize it, this method should do the trick:
Bitmap ImageToBitmap(ColorImageFrame img)
{
byte[] pixeldata = new byte[img.PixelDataLength];
img.CopyPixelDataTo(pixeldata);
Bitmap bmap = new Bitmap(img.Width, img.Height, PixelFormat.Format32bppRgb);
BitmapData bmapdata = bmap.LockBits(
new Rectangle(0, 0, img.Width, img.Height),
ImageLockMode.WriteOnly,
bmap.PixelFormat);
IntPtr ptr = bmapdata.Scan0;
Marshal.Copy(pixeldata, 0, ptr, img.PixelDataLength);
bmap.UnlockBits(bmapdata);
return bmap;
}

Categories

Resources