C# Decoding QRCODE in real image using ZXING.NET - c#

I'm trying to reading QR CODES in the images acquired by an usb camera.
In other posts I have read that the best open source library is ZXing.
If the qrcode comes from a digitally generated image the library works fine, but if the qrcode comes from a real case where the image is acquired by a camera the deconding library has some difficulties.
The acquired images are disturbed by some glare, or code deformation, or slow contrast.
Do you know some parameters to setup better the reader?
Or some filter to add to the image before elaboration?
For example:
BarcodeReader reader = new BarcodeReader();
reader.AutoRotate = true;
reader.Options.TryHarder = true;
reader.Options.PureBarcode = false;
reader.Options.PossibleFormats = new List<BarcodeFormat>();
reader.Options.PossibleFormats.Add(BarcodeFormat.QR_CODE);
var result = reader.Decode(image);
Thank you

After several test the best result for 300dpi scanned image comes with :
//use gaussian filter to remove noise
var gFilter = new GaussianBlur(2);
image = gFilter.ProcessImage(image);
var options = new DecodingOptions { PossibleFormats = new List<BarcodeFormat> { BarcodeFormat.QR_CODE }, TryHarder = true };
using (image)
{
//use GlobalHistogramBinarizer for best result
var reader = new BarcodeReader(null, null, ls => new GlobalHistogramBinarizer(ls)) { AutoRotate = false, TryInverted = false, Options = options };
var result = reader.Decode(image);
reader = null;
return result;
}
For gaussian filter I use this code from http://www.cnblogs.com/Dah/archive/2007/03/30/694527.html
Hope this help someone.

Related

C# Excel Drop Down List

I am trying to create a drop list, haven't had any luck finding similar sample code or documentation to follow so I'm flying solo
When I run this sample code I created
static void Main(string[] args)
{
using (FileStream filename = new FileStream(#"INSERTYOUROWNPATH.xlsx", FileMode.Create))
{
var workbook = new XSSFWorkbook();
XSSFSheet xsheet = (XSSFSheet)workbook.CreateSheet("Validation");
CT_DataValidation valid = new CT_DataValidation();
valid.showDropDown = true;
valid.allowBlank = true;
var constraint = new XSSFDataValidationConstraint(new string[] { "0064", "0061" }); //to be used in list
var range = new CellRangeAddressList(11, 14, 13, 13); //apply to row 12:14 starting at column N finishing at column N
var addingconstraint = new XSSFDataValidation(constraint, range, valid);
addingconstraint.EmptyCellAllowed = true;
addingconstraint.SuppressDropDownArrow = false;
xsheet.AddValidationData(addingconstraint);
workbook.Write(filename);
}
}
I get the following errors when I open the spreadsheet:
"We found a problem with some content in "Validations.xlsx" do you
want use to try to recover as much as we can? If you trust the source
of this workbook, click Yes"
Then I get the following repair message:
"Repaired Part: /xl/worksheets/sheet1.xml part with XML error. Load
error. Line 1 column 684"
Could I please get some insight in to where this is failing?
your issue seems to be very similar to this problem about data validation and data constraint.
XSSFDataValidation dataValidation = null;
XSSFDataValidationConstraint dvConstraint = null;
XSSFDataValidationHelper validationHelper = null;
int DVRowLimit = (Int16.MaxValue);
XSSFCellStyle numberCellStyle = (XSSFCellStyle)workbook.CreateCellStyle();
XSSFDataFormat numberDataFormat = (XSSFDataFormat)workbook.CreateDataFormat();
numberCellStyle.SetDataFormat(numberDataFormat.GetFormat("#,###,###"));
CellRangeAddressList cellRangeFieldsType1 = new CellRangeAddressList(1, DVRowLimit, headerCount, headerCount);
dvConstraint = (XSSFDataValidationConstraint)validationHelper.CreateintConstraint(OperatorType.BETWEEN, "0", Int64.MaxValue.ToString());
dataValidation = (XSSFDataValidation)validationHelper.CreateValidation(dvConstraint, cellRangeFieldsType1);
dataValidation.ShowErrorBox = true;
dataValidation.SuppressDropDownArrow = true;
dataValidation.ErrorStyle = 0;
dataValidation.CreateErrorBox("InvalidValue", "Number Should be a integer.");
dataValidation.ShowErrorBox = true;
dataValidation.CreatePromptBox("Number Data Validation", "Enter Number.");
dataValidation.ShowPromptBox = true;
sheet.AddValidationData(dataValidation);
sheet.SetDefaultColumnStyle(column, numberCellStyle);

Autorotate option for GenericMultipleBarcodeReader in Zxing.Net

How can I set the hint 'AutoRotate' for 'GenericMultipleBarcodeReader' in Zxing.net. I have set Try_Harder = true. But no results for detecting multiple 1d/2d barcodes from a rotated image. If the image is aligned properly it gives the results.
Edit: In 'GenericMultipleBarcodeReader' I am using 'ByQuadrantReader'. This could detect barcodes and QR codes from properly aligned images. For a rotated image it could not find anything.
MultiFormatReader multiReader = new MultiFormatReader();
ZXing.Multi.GenericMultipleBarcodeReader byquadReader = new ZXing.Multi.GenericMultipleBarcodeReader(new ByQuadrantReader(multiReader));
Dictionary<DecodeHintType, object> hints = new Dictionary<DecodeHintType, object>();
hints.Add(DecodeHintType.TRY_HARDER, true);
List<BarcodeFormat> formats = new List<BarcodeFormat>();
formats.Add(BarcodeFormat.All_1D);
formats.Add(BarcodeFormat.QR_CODE);
hints.Add(DecodeHintType.POSSIBLE_FORMATS, formats);
****
byquadresults = byquadReader.decodeMultiple(binaryBitmap, hints);
Could any one please help me.
AutoRotate can only be used with the BarcodeReader class.
var bitmap = (Bitmap)Bitmap.FromFile("<path to your image file>");
var reader = new BarcodeReader
{
AutoRotate = true,
Options = new DecodingOptions
{
TryHarder = true,
PossibleFormats = new List<BarcodeFormat>
{
BarcodeFormat.All_1D,
BarcodeFormat.QR_CODE
}
}
};
var results = reader.DecodeMultiple(bitmap);
If you want to use the ByQuadrantReader you have to replace the line
var reader = new BarcodeReader...
with
var reader = new BarcodeReader(new ByQuadrantReader(new MultiFormatReader()), null, null)...

Xamarin - Video Cropping for iOS

I was wondering if there was a way to crop videos in Xamarin. I can't seem to find any examples. I tried looking at the existing functions and Classes but I couldn't find anything.
Basically make square videos like what Vine and Instagram have. I think this is done by cropping out the rest of the video and not just zooming in.
I find part of the code from one source, I tried to add owner but I could not find. The solution's key part is added by me for cropping which is "VideoCleanAperture" inside AVVideoSettingsCompressed.
videoUrl = ((AVFoundation.AVUrlAsset)avAsset).Url;
NSError assetReaderError;
var assetReader = AVAssetReader.FromAsset(avAsset, out assetReaderError);
var assetTrack = avAsset.Tracks.First();
//Height = (System.nint?)avAsset.NaturalSize.Height,
//Width = (System.nint?)avAsset.NaturalSize.Width,
var inputSettings = new AVVideoSettingsUncompressed()
{
Height = (System.nint?)avAsset.NaturalSize.Height,
Width = (System.nint?)avAsset.NaturalSize.Width,
};
var assetReaderOutput = new AVAssetReaderTrackOutput(assetTrack, settings: inputSettings);
assetReaderOutput.AlwaysCopiesSampleData = false;
string tempFile = Path.Combine(Path.GetTempPath(), "CroppedVideo.mp4");
if (File.Exists(tempFile)) File.Delete(tempFile);
var url = NSUrl.FromFilename(tempFile);
NSError assetWriterError;
var assetWriter = new AVAssetWriter(url, AVFileType.Mpeg4, out assetWriterError);
var outputSettings = new AVVideoSettingsCompressed()
{
Height = 300,
Width = 300,
Codec = AVVideoCodec.H264,
CodecSettings = new AVVideoCodecSettings()
{
AverageBitRate = 1000000,
VideoCleanAperture = new AVVideoCleanApertureSettings(
new NSDictionary(
AVVideo.CleanApertureWidthKey, new NSNumber(300),
AVVideo.CleanApertureHeightKey, new NSNumber(300),
AVVideo.CleanApertureVerticalOffsetKey, new NSNumber(10),
AVVideo.CleanApertureHorizontalOffsetKey, new NSNumber(10)
)
)
},
ScalingMode = AVVideoScalingMode.ResizeAspectFill
};
var assetWriterInput = new AVAssetWriterInput(mediaType: AVMediaType.Video, outputSettings: outputSettings);
assetWriterInput.ExpectsMediaDataInRealTime = false;
assetWriter.AddInput(assetWriterInput);
assetWriter.StartWriting();
assetReader.AddOutput(assetReaderOutput);
assetReader.StartReading();
assetWriter.StartSessionAtSourceTime(CoreMedia.CMTime.Zero);
var mediaInputQueue = new DispatchQueue("mediaInputQueue");
assetWriterInput.RequestMediaData(mediaInputQueue, () =>
{
while (assetWriterInput.ReadyForMoreMediaData)
{
var nextBuffer = assetReaderOutput.CopyNextSampleBuffer();
if (nextBuffer != null)
{
assetWriterInput.AppendSampleBuffer(nextBuffer);
}
else
{
assetWriterInput.MarkAsFinished();
assetWriter.FinishWritingAsync();
assetReader.CancelReading();
assetReader.Dispose();
assetReaderOutput.Dispose();
assetWriter.Dispose();
assetWriterInput.Dispose();
break;
}
}
});
}

How to create a NotifyIcon from a BitmapImage?

I have a resource item (a png file) in my resource dictionary which I'm using in several places. Now I want to use it as application's NotifyIcon. But I don't know how to do this. Have you any idea please?
// my image:
var bitmap = new BitmapImage();
bitmap.UriSource = new Uri("pack://application:,,,/MyProj.Resources;component/Icons/Logo_48x48.png");
// and I try to do this:
var iconHandle = bitmap.GetHicon(); // but this line doesn't work
var ni = new NotifyIcon {
Icon = System.Drawing.Icon.FromHandle(iconHandle),
Visible = true
};
var sri = Application.GetResourceStream(
new Uri("pack://application:,,,/MyProj.Resources;component/Icons/Logo_48x48.png"));
var bitmap = new Bitmap(sri.Stream);
var handle = bitmap.GetHicon();
var ni = new NotifyIcon {
Icon = System.Drawing.Icon.FromHandle(handle),
Visible = true
};

How to transfer an image obtained from a windows phone to a c# picturebox image

I have a windows phone app that takes a picture and sends it to a wcf service which sends it to a database so another app (windows forms app) can check the database and obtain the image.
It's adding data to the database as a byte array but when I check the values, they all say the same numbers, but it seems it works because theirs data there.
When I try to turn that data into an image though, it throws an exception saying the parameter isn't valid. I've searched for how to do this but what i find (even on here) says exactly what I'm doing. So I'm not sure what's wrong.
here's my code for the windows phone:
if (e.TaskResult == TaskResult.OK)
{
var bitImage = new BitmapImage();
bitImage.SetSource(e.ChosenPhoto);
//image is a Image Control in the form
ImageServiceClient client = new ImageServiceClient();
byte[] array;
using(var stream = new MemoryStream())
{
var btmMap = new WriteableBitmap(bitImage.PixelWidth, bitImage.PixelHeight);
// write an image into the stream
btmMap.SaveJpeg(stream, bitImage.PixelWidth, bitImage.PixelHeight, 0, 100);
array = stream.ToArray();
}
client.AddImageAsync(array);
}
the last line calls the add method in my wcf service which looks like:
public void AddImage(byte[] array)
{
var con =
new MySqlConnection(
"server=instance11297.db.xeround.com;User Id=Admin;Password=nomoredrama2010;port=7692;database=capstone");
con.Open();
string h = array.Aggregate(h, (current, b) => current + b);
string text = "INSERT INTO images VALUES (''," + h + ")";
Console.WriteLine(text);
var command = new MySqlCommand(text, con);
var result = command.ExecuteReader();
result.Close();
}
It's good to note that it doesn't matter if I use the passed in array directly or if I turn it into text, they both show up the same in the database.
Then finally, in the app this is sending everything to, I have this:
var con =
new MySqlConnection(
"server=instance11297.db.xeround.com;User Id=Admin;Password=nomoredrama2010;port=7692;database=capstone");
con.Open();
string h = "";
string text = "select Image from images where ImageId=4";
var command = new MySqlCommand(text, con);
var dr = command.ExecuteReader();
var g = new byte[] {};
if(dr.Read())
g = (byte[])dr[0];
dr.Close();
var image = Image.FromStream(new MemoryStream(g));
pictureBox1.Image = image;
but it always breaks on "var image = Image.FromStream(new MemoryStream(g));" saying the parameter is not valid.
I found out it has a big array once it gets the image but the one in the database is only 65 bytes and they all say 57.
Why is it completely disregarding my image's array and replacing it with a 65 byte one of all 57?
What am I doing wrong?
***************EDIT*****************************
I finally found what was wrong after enabling debugger in a wcf app.
http://msdn.microsoft.com/en-us/library/ff649234.aspx (for those who don't know)
I also looked here : http://www.codeproject.com/Articles/9686/Save-An-Image-Into-SQL-Server-2000-Database
to see why it was throwing a "your sql is wrong" type error and changed my sql statement to use the adding method instead of putting the value into the string.
That fixed it finally. The working code looks like this for nayone else comes across this problem:
public void AddImage(byte[] array)
{
var con =
new MySqlConnection("server=instance11297.db.xeround.com;User Id=Admin;Password=nomoredrama2010;port=7692;database=capstone");
con.Open();
string text = "INSERT INTO images (ImageId, Image) VALUES ('',#bytes)";
var command = new MySqlCommand(text, con);
command.Parameters.AddWithValue("#bytes", array);
command.ExecuteNonQuery();
con.Close();
}
I can finally stop beating my head against the wall. :)
you should use something like this.
//---read the data in buffer and write to ms2---
MemoryStream ms2 = new MemoryStream();
ms2.Write(b, 0, b.Lenght);
//---load it in a PictureBox control---
pictureBox2.Image = new Bitmap(ms2);

Categories