How To Use ZXing C# Port - c#

NOTE: My original question was about whether the ZXing C# port is reliable, but here, I'm trying to figure out how to use it. Thus, they are not duplicates.
I'm trying to use the ZXing C# module, but I'm having trouble. Does anyone who has used ZXing before know how to do it correctly? Unfortunately, the C# documentation is quite small.
My current code is:
using com.google.zxing;
using com.google.zxing.client.j2se;
using com.google.zxing.common;
//...
Reader reader = new MultiFormatReader();
MonochromeBitmapSource image = new BufferedImageMonochromeBitmapSource(new Bitmap(Image.FromFile("barcode.jpg")),false);
Result result = reader.decode(image);
string text = result.getText();
sbyte[] rawbytes = result.getRawBytes();
BarcodeFormat format = result.getBarcodeFormat();
ResultPoint[] points = result.getResultPoints();
Console.WriteLine("barcode text: {0}", text);
Console.WriteLine("raw bytes: {0}", rawbytes);
Console.WriteLine("format: {0}", format);
Console.ReadLine();
I'm getting an exception on the line that starts with "Result result = ..." The ReaderException states: "Unable to cast object of type 'com.google.zxing.oned.MultiFormatOneDReader' to type 'com.google.zxing.Reader'.
So, what am I doing wrong?
UPDATE: I'm going to try the suggested ideas, but in the meantime, I found this issue in the ZXing group.

This is a sample to generate a QRCode.
QRCodeWriter writer = new QRCodeWriter();
com.google.zxing.common.ByteMatrix matrix;
int size = 180;
matrix = writer.encode("MECARD:N:Owen,Sean;ADR:76 9th Avenue, 4th Floor, New York, NY 10011;TEL:+12125551212;EMAIL:srowen#example.com;; ", BarcodeFormat.QR_CODE, size, size, null);
Bitmap img = new Bitmap(size, size);
Color Color = Color.FromArgb(0, 0, 0);
for (int y = 0; y < matrix.Height; ++y)
{
for (int x = 0; x < matrix.Width; ++x)
{
Color pixelColor = img.GetPixel(x, y);
//Find the colour of the dot
if (matrix.get_Renamed(x, y) == -1)
{
img.SetPixel(x, y, Color.White );
}
else
{
img.SetPixel(x, y, Color.Black);
}
}
}
img.Save(#"c:\test.bmp",ImageFormat.Bmp);
See the Barcode format at http://code.google.com/p/zxing/wiki/BarcodeContents

I think that must be a deficiency in the port, since in the original Java these classes are cast-compatible. Perhaps just use MultiFormatOneDReader as the reference type in the code rather than Reader, though the line should have been fine as-is. If you otherwise fix the source and want to submit the change let us (the project) know.

I suspect you are just missing a cast/are using the wrong type, try changing
Result result = reader.decode(image);
line in to one of the following
Result result = (Result)reader.decode(image);
or possibly
MultiFormatOneDResult result = reader.decode(image);
I'm afraid I don't have access to a c# compiler right now, so I can't verify this - so I apologise if I'm way off the mark!

Related

Converting c++ to c# code for image color matching script

I'm trying to create a script to match the colours between two images using EmguCV.
I've managed to find code that does exactly what I want to, here, however it's written in C++ which I'm not very familiar with.
I'm sure a lot of these things are basic C++ -> C# issues even if you're not familiar with EmguCV / OpenCV...
So far I'm stumped on the following (see code below).
'mask(p)' - mask is of type Mat, and this produces an error in C#: 'a method name is expected'. I presume that the code is trying to index the mask but not sure how to do this. There are quite a few of these instances in the code.
'chns[i]' - probably similar to the above, chns is again of type Mat, and this produces the error "Cannot apply indexing with [] to an expression of type Mat".
With 'mask(p)' above, and the other various instances, once the issue above is corrected I suspect that there will be another issue in comparing the Mat with an integer to iterate through - perhaps this is looking at the columns or the rows, I'm not sure. (I'm referring to, for example 'if (mask(p) > 0)' )
With 'CvInvoke.Split(src, chns)' creates an error 'Cannot convert from 'System.Collections.Generic.List<Emgu.CV.Mat> to Emgu.CV.IOutputArray'. I assume I need to define chns and chns1 to an IOutputArray - although I'm not sure how to do this - declaring an IOutputArray using new OutputArray requires an IntPtr reference (possibly 'new Mat()'? and a parent - not quite sure what's required here. lease see below.
I've run the original C++ code through a C++ to C# converter to get rid of the obvious issues, and have made as many changes as I can to convert OpenCV calls to EmguCV, and I'm left with the below. Any help in deciphering the remaining parts would be most gratefully received.
Further assumptions that I've applied:
In referencing 'Mat' in the method names, I don't think C# requires you to specify the depth as you do in C++, so I've removed the and references, but instead updated the DepthTypes when the mats are declared, e.g. 'new Mat(1, 256, DepthType.Cv64F, 1);' (in the case of double)
Updated variable types, e.g. 'uchar' -> 'byte'
Other conversions have been annoted, apart from obvious OpenCV -> EmguCV conversions that are clearly correct.
Code I've got to so far:
public static class EmguCVColourMatchingHelper
{
// Compute histogram and CDF for an image with mask
// C++: void do1ChnHist(const Mat_<uchar> &img, const Mat_<uchar> &mask, Mat_<double> &h, Mat_<double> &cdf)
public static void do1ChnHist(Mat img, Mat mask, Mat h, Mat cdf)
{
// C++: for (size_t p = 0; p<img.total(); p++)
for (var p = 0; p < (Int32)img.Total; p++)
{
if (mask(p) > 0) // ERROR (Issue 1): 'Mat mask - Method name expected' - happens with all Mat types followed by ().
{
byte c = img(p); // ERROR (Issue 1)
h(c) += 1.0; // ERROR (Issue 1)
}
}
CvInvoke.Normalize(h, h, 1, 0, NormType.MinMax);
cdf(0) = h(0); // ERROR (Issue 1)
for (int j = 1; j < 256; j++)
{
cdf(j) = cdf(j - 1) + h(j); // ERROR (Issue 1)
}
CvInvoke.Normalize(cdf, cdf, 1, 0, NormType.MinMax);
}
public static void histMatchRGB(Mat src, Mat src_mask, Mat dst, Mat dst_mask)
{
double histmatch_epsilon = 0.000001;
// C++: vector<Mat_<uchar>> chns, chns1;
// List<Mat> chns = new List<Mat>(); - this is the main way to convert vector<Mat> chns, chns1 - however itn's not compatible with CvInvoke.Split below
// I think I need to declare an IOutputArray below, but not exactly sure how to do this.
IOutputArray chns = new OutputArray(new Mat(), something??); // Issue 4.
CvInvoke.Split(src, chns);
CvInvoke.Split(dst, chns1);
for (int i = 0; i < 3; i++)
{
// C++: Mat_<double> src_hist = Mat_<double>::zeros(1, 256); etc...
// NOTE: here I've assumed 1 channel (last '1' reference in new statements below), as I think we're iterating through RGB
Mat src_hist = new Mat(1, 256, DepthType.Cv64F, 1);
Mat dst_hist = new Mat(1, 256, DepthType.Cv64F, 1);
Mat src_cdf = new Mat(1, 256, DepthType.Cv64F, 1);
Mat dst_cdf = new Mat(1, 256, DepthType.Cv64F, 1);
do1ChnHist(chns[i], src_mask, src_hist, src_cdf); // ERROR (Issue 2): Cannot apply indexing with [] to an expression of type 'Mat'
do1ChnHist(chns1[i], dst_mask, dst_hist, dst_cdf); // ERROR(Issue 2)
byte last = 0;
Mat lut = new Mat(1, 256, DepthType.Cv8U, 1);
for (int j = 0; j < src_cdf.Cols; j++)
{
double F1j = src_cdf(j); // ERROR (Issue 1)
for (byte k = last; k < dst_cdf.Cols; k++)
{
double F2k = dst_cdf(k); // ERROR (Issue 1)
if (Math.Abs(F2k - F1j) < histmatch_epsilon || F2k > F1j)
{
lut(j) = k; // ERROR (Issue 1)
last = k;
break;
}
}
}
CvInvoke.LUT(chns[i], lut, chns[i]); //ERROR(Issue 2)
}
Mat res = new Mat();
CvInvoke.Merge(chns, res);
res.CopyTo(src);
}
internal static void Main(string[] args)
{
Mat src = CvInvoke.Imread("e:/test/iO6S1m.png");
Mat dst = CvInvoke.Imread("e:/test/kfku3m.png");
Mat mask = new Mat(src.Size, DepthType.Cv8U, 255);
histMatchRGB(dst, mask, src, mask);
}
}
Thanks for any help!
mask(p)
The compiler interprets this as a method call, but the mask is an object, so this does not work. I would assume you want to extract the element at that position. Since the Mat class does not seem to contain an indexer you might have to use GetData or GetDataPointer to either convert the matrix to a array, or use a unsafe pointer for access.
chns[i]
I would assume the intent is to extract a single channel. For this there seem to be the split method
Overall, you need to have some idea of what the code is doing, and read the documentation to find equivalent ways to do things.

C# String Concatenation OutOfRange error

I'm utilizing Get String functions from a "Label" class to put together lines to print on a bitmap. The program compiles fine, and the previous form passes the LabelQueue properly (it would appear with no issue before I tried to print the bitmap). All the code of this particular initializer/constructor is below. The erroneous lines of code are the final three lines of the function before the "c++".
Let me know if you need me to add any more necessary code.
I'm getting an IndexOutofRange exception, claiming it was outside of the bounds of the array.
private LabelQueue lq;
public Print(LabelQueue queue)
{
InitializeComponent();
lq = queue;
pictureBox1.Image = new Bitmap(2550, 3300);
System.Drawing.Graphics formGraphics = this.CreateGraphics();
System.Drawing.Font textFont = new System.Drawing.Font("Times New Roman", 8);
System.Drawing.SolidBrush textBrush = new System.Drawing.SolidBrush(System.Drawing.Color.Black);
System.Drawing.StringFormat textFormat = new System.Drawing.StringFormat();
int x, y, c = 0;
while (c < 30)
{
// Get coordinates for where to put values.
x = ((c % 3) * 600) + 300;
// Accounts for column gap
if (c % 3 > 0)
x = x + ((c % 3) - 1) * 75;
y = ((c % 10) * 270) + 300;
string firstLine, secondLine, thirdLine;
firstLine = lq.labels[c].GetLastName() + ", " + lq.labels[c].GetFirstName() + " " + lq.labels[c].GetMiddleName();
secondLine = lq.labels[c].GetNewStreet();
thirdLine = lq.labels[c].GetNewCity() + ", " + lq.labels[c].GetNewState() + lq.labels[c].GetNewZIP() + lq.labels[c].GetNewCountry();
formGraphics.DrawString(firstLine, textFont, textBrush, x, y, textFormat); // Line turning up the error
formGraphics.DrawString(firstLine, textFont, textBrush, x, y + 10, textFormat); // Naturally, both these lines would need to be fixed too
formGraphics.DrawString(firstLine, textFont, textBrush, x, y + 20, textFormat);
c++;
}
}
Without a good, minimal, complete code example that reliably demonstrates the problem, it's impossible to know for sure the exact fix you need.
However, based on the information on this question and the comments so far, it appears that you simply aren't limiting your loop correctly. The while statement should look like this:
while (c < lq.Count())
Note that the above uses the Enumerable.Count() extension method. I chose that as the answer, because you didn't include the declaration/implementation of your LabelQueue object, so there's no way to know for sure what the correct syntax would be, but the extension method is likely to work because pretty much any reasonable collection type that supports an indexer will implement some interface that allows the Enumerable.Count() method to work well.
That said, your type probably has a Count property, which you can use instead of the Count() extension method. Either will work equally well.
Finally, for future reference it is fine to answer your own question. It's just that your answer should actually be an answer. I.e. it needs to explain clearly what was wrong, and what you did to fix it. Writing "Issue is fixed" doesn't count as an answer.
For that matter, if you don't like my answer here and you want to write your own, you can still do that. You can even accept your own answer instead of mine if you'd rather. Just make sure it's a real answer.

Converting image into CvMat in OpenCV for training neural network

I'm writing a program which uses OpenCv neural networks module along with C# and OpenCvSharp library. It must recognise the face of user, so in order to train the network, i need a set of samples. The problem is how to convert a sample image into array suitable for training. What i've got is 200x200 BitMap image, and network with 40000 input neurons, 200 hidden neurons and one output:
CvMat layerSizes = Cv.CreateMat(3, 1, MatrixType.S32C1);
layerSizes[0, 0] = 40000;
layerSizes[1, 0] = 200;
layerSizes[2, 0] = 1;
Network = new CvANN_MLP(layerSizes,MLPActivationFunc.SigmoidSym,0.6,1);
So then I'm trying to convert BitMap image into CvMat array:
private void getTrainingMat(int cell_count, CvMat trainMAt, CvMat responses)
{
CvMat res = Cv.CreateMat(cell_count, 10, MatrixType.F32C1);//10 is a number of samples
responses = Cv.CreateMat(10, 1, MatrixType.F32C1);//array of supposed outputs
int counter = 0;
foreach (Bitmap b in trainSet)
{
IplImage img = BitmapConverter.ToIplImage(b);
Mat imgMat = new Mat(img);
for (int i=0;i<imgMat.Height;i++)
{
for (int j = 0; j < imgMat.Width; j++)
{
int val =imgMat.Get<int>(i, j);
res[counter, 0] = imgMat.Get<int>(i, j);
}
responses[i, 0] = 1;
}
trainMAt = res;
}
}
And then, when trying to train it, I've got this exception:
input training data should be a floating-point matrix withthe number of rows equal to the number of training samples and the number of columns equal to the size of 0-th (input) layer
Code for training:
trainMAt = Cv.CreateMat(inp_layer_size, 10, MatrixType.F32C1);
responses = Cv.CreateMat(inp_layer_size, 1, MatrixType.F32C1);
getTrainingMat(inp_layer_size, trainMAt, responses);
Network.Train(trainMAt, responses, new CvMat(),null, Parameters);
I'm new to OpenCV and I think I did something wrong in converting because of lack of understanding CvMat structure. Where is my error and is there any other way of transforming the bitmap?
With the number of rows equal to the number of training samples
That's 10 samples.
and the number of columns equal to the size of 0-th (input) layer
That's inp_layer_size.
trainMAt = Cv.CreateMat(10, inp_layer_size, MatrixType.F32C1);
responses = Cv.CreateMat(10, 1, MatrixType.F32C1); // 10 labels for 10 samples
I primarily do C++, so forgive me if I'm misunderstanding, but your pixel loop will need adapting in addition.
Your inner loop looks broken, as you assign to val, but never use it, and also never increment your counter.
In addition, in your outer loop assigning trainMAt = res; for every image doesn't seem like a very good idea.
I am certain you will get it to operate correctly, just keep in mind the fact that the goal is to flatten each image into a single row, so you end up with 10 rows and inp_layer_size columns.

C# image recognition performance - comparing list of images to dictionary of images

I've managed to do recognize characters from image. For this reason:
I save all recognized blobs(images) in List
Bitmap bpt1 = new Bitmap(#"C:\2\torec1.png", true);
Bitmap bpt2 = new Bitmap(#"C:\2\torec2.png", true);
List<Bitmap> toRecognize = new List<Bitmap>();
toRecognize.Add(bpt1);
toRecognize.Add(bpt2);
I keep a library of known letters in Dictionary.
Bitmap le = new Bitmap(#"C:\2\e.png", true);
Bitmap lg = new Bitmap(#"C:\2\g.png", true);
Bitmap ln = new Bitmap(#"C:\2\n.png", true);
Bitmap li = new Bitmap(#"C:\2\i.png", true);
Bitmap ls = new Bitmap(#"C:\2\s.png", true);
Bitmap lt = new Bitmap(#"C:\2\t.png", true);
var dict = new Dictionary<string, Bitmap>();
dict.Add("e", le);
dict.Add("g", lg);
dict.Add("n", ln);
dict.Add("i", li);
dict.Add("s", ls);
dict.Add("t", lt);
Then I create New List with Images - from library:
var target = dict.ToList();
And do the comparison of images: (target[index].Key, target[index].Value)
for (int i = 0; i < x; i++)
{
for (int j = 0; j < y; j++)
{
if (CompareMemCmp(toRecognize[i], target[j].Value) == true)
{
textBox3.AppendText("Found!" + Environment.NewLine);
textBox2.AppendText(target[j].Key); //Letter is found - save it!
}
else {textBox3.AppendText("Don't match!" + Environment.NewLine); }
}
}
1. [removed]
2. Is the method that I used tolerable from the perspective of performance? I'm planning to do the recornition of 10-20 images at the same time (average letter count for each is 8) and the library for letters will consist of English alphabet (26 upper + 26 lower case), special letter(~10) and Numbers (10).
So I have 80+ letters that have to be recognized and pattern library which consists of ~70+ characters. Will the performance be at a good level?
Constructive criticism gladly accepted. ;)
Question 1:
[removed]
Question 2:
It depends.
First of all, if performance is not enough, what's your bottleneck ?
I suspect it's CompareMemCmp() function... so can you speed-up it ?
If not, given that each iteration of your loop seems independent from the previous ones, you could try to run it in parallel.
To do this have a look at the Task Parallel Library methods of framework 4.0, in particular to Parallel.For.
EDIT :
If we are talking about perfect matching between images, you can try to use dictionary look-up to speed things up.
First, you can build a wrapper class for Bitmap that can be efficiently used as Dictionary<> key, like this:
class BitmapWrapper
{
private readonly int hash;
public Bitmap Image { get; private set; }
public BitmapWrapper(Bitmap img)
{
this.Image = img;
this.hash = this.ComputeHash();
}
private int ComputeHash()
{
// you could turn this code into something unsafe to speed-up GetPixel
// e.g. using lockbits etc...
unchecked // Overflow is fine, just wrap
{
int h = 17;
for (int x = 0; x < this.Image.Size.Width; x++)
for (int y = 0; y < this.Image.Size.Height; y++)
h = h * 23 + this.Image.GetPixel(x, y).GetHashCode();
return h;
}
}
public override int GetHashCode()
{
return this.hash;
}
public override bool Equals(object obj)
{
var objBitmap = obj as Bitmap;
if (obj == null)
return false;
// use CompareMemCmp in case of hash collisions
return Utils.CompareMemCmp(this.Image, objBitmap);
}
}
This class computes the hascode in ComputeHash method that is inspired by this answer (but you can just ex-or every pixel). That surely can be improved by involving unsafe code (something like in the CompareMemCmp method).
Once you have this class, you can build a look-up dictionary like this:
Bitmap le = new Bitmap(#"C:\2\e.png", true);
Bitmap lg = new Bitmap(#"C:\2\g.png", true);
...
var lookup = new Dictionary<string, Bitmap>();
lookup.Add(new BitmapWrapper(le), "e");
lookup.Add(new BitmapWrapper(lg), "g");
...
then the search will be simply:
foreach(var imgToRecognize in toRecognize)
{
string letterFound;
if(lookup.TryGetValue(new BitmapWrapper(imgToRecognize), out letterFound))
{
textBox3.AppendText("Found!" + Environment.NewLine);
textBox2.AppendText(letterFound); //Letter is found - save it!
}
else
textBox3.AppendText("Don't match!" + Environment.NewLine);
}
The performances of this method definitely depends on the hash computation, but certainly they can save a lot of CompareMemCmp() calls.
If C# is the right tool for the job depends on how big your images are. A hash table is a nice approach but you need to compare the whole image before you can check if you have a match. Xoring the images is very fast but you need to xor all images until you find the matching ones which is quite inefficient.
A better approach would be to choose a fingerprint which is designed in a way that you need to read only minimal amount of data. E.g. you can generate a hash code of a vertical line in the middle if your image which would produce a different value for each of your images. If not adapt the approach until you arrive at an algorithm where you do not need to read the image as a whole but only a few bytes until you can assign the image to the right bucket. This does only work if your input data contains only the images in your dictionary. Otherwise it would be only a probabilistic method.

How can I create an array of Cha info that includes attributes like foreground color?

I'm currently writing a roguelike game for learning purposes/fun. I'm writing it in the console, and I'm having issues with laggy updating of the map. I have done tons of online searching and came across a possible solution but it was written in c++ (I believe).
The solution was to use WriteConsoleOutput, however I do not believe this is available in C#. Further searching resulted in a possible C# solution. Pass an array to the Console.Write method. However the issue with this method is that I cannot pass (to my current knowledge) attributes about the character, like foreground color.
I threw something together to test passing an array to Console.Write. The below code will display a grid of numbers. I would like to have the ability to change the foreground color for each value in the grid. So 1 would be blue, and 2 would be red, etc...
static void Main(string[] args)
{
Console.SetWindowSize(80, 35);
Console.BufferWidth = 80;
Console.BufferHeight = 35;
string temp = "";
int[,] aryMap = new int[,] {
{0,0,0,0,0},
{1,1,1,1,1},
{2,2,2,2,2},
{3,3,3,3,3},
{4,4,4,4,4},
{5,5,5,5,5}
};
for (int h = 0; h < 5; h++)
{
temp += "\n";
for (int w = 0; w < 5; w++)
{
temp += aryMap[h, w];
}
}
Console.SetCursorPosition(0, 0);
Console.Write(temp);
string test = Console.ReadLine();
}
SOLUTION
I ended up using Malison which is a library for doing console-style interfaces in C#. Works great, and now I don't have to create my own console.
http://bitbucket.org/munificent/malison/wiki/Home
You can either output ANSI escape sequences, or use the Control.ForegroundColor and Console.BackgroundColor properties to set the property before writing your character.
I would suggest the ANSI escape sequences if you need to make the write in a single call.
This code works nicely: http://www.daniweb.com/code/snippet216395.html
I'm sure you can modify it to fit what you need.

Categories

Resources