C# to C++ ( simple OCR Code )

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
skystar
In need of some credit
In need of some credit
Posts: 6
Joined: Sat Feb 11, 2006 9:56 pm

C# to C++ ( simple OCR Code )

Post by skystar »

Hi.

I have a code written in c# that can recognize digits written on
an image (bitmap).

please, can you help to convert this code to c++ using the greate wxWidgets libraries.


Thanks.

Code: Select all



	class Number
	{
	
		public static string GetText(Bitmap map)
		{
			
			Number[] defaultNumbers = BuildDefaultImage();

			System.Collections.ArrayList numbers = new System.Collections.ArrayList();

			
			//find numbers
			if (!ProcessImage(map,numbers))
				return "invalid image format";

			map.Dispose();

			string output = "";

			//for each number found...
			for (int i = 0; i < numbers.Count; i++)
			{
				int max = 0;
				int index = 0;
				for (int n = 0; n < 10; n++)
				{
					//get the difference between this number and each reference number (brute force)
					int dif = ((Number)numbers[i]).Compare(defaultNumbers[n]);

					if (max == 0 || dif < max) // get the lowest difference
					{
						max = dif;
						index = n;
					}
				}

				output += index.ToString();
			}

			return output;
		}
		
		static Number[] defaults;
		readonly byte[] data;
		const int SampleX = 8, SampleY = 16;

		static Number[] BuildDefaultImage()
		{
			if (defaults!=null)
				return defaults;

			System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(140,30);

			System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bmp);

			System.Drawing.Font f = new System.Drawing.Font("Arial",15,System.Drawing.FontStyle.Regular);
			System.Drawing.Brush b = new System.Drawing.SolidBrush(System.Drawing.Color.Black);
			g.Clear(System.Drawing.Color.White);
			g.DrawString("0123456789",f,b,1,1);

			b.Dispose();
			f.Dispose();
			g.Dispose();

			bmp.Save("test.bmp");

			System.Collections.ArrayList numbers =new System.Collections.ArrayList();

			//get all the numbers
			if (!ProcessImage(bmp,numbers))
				return null;

			bmp.Dispose();

			defaults = new Number[numbers.Count];
			for	(int n=0; n<defaults.Length; n++)
				defaults[n] = (Number)numbers[n];

			return defaults;
		}

		/*
		 * 
		 * This of course, is the complex bit.
		 * 
		 */
		static bool ProcessImage(System.Drawing.Bitmap image, System.Collections.ArrayList numbers)
		{
			//number of bytes per pixel
			int bytePixelStride = System.Drawing.Image.GetPixelFormatSize(image.PixelFormat) / 8;

			if (bytePixelStride == 0)
				return false;

			//this makes the rest of the code more efficient (sequential access, etc), ignore
			image.RotateFlip(System.Drawing.RotateFlipType.Rotate90FlipNone);

			//copy the bitmap data out
			System.Drawing.Imaging.BitmapData bd = image.LockBits(new System.Drawing.Rectangle(0, 0, image.Width, image.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, image.PixelFormat);
			byte[] imageData = new byte[bd.Stride * image.Height];
			System.Runtime.InteropServices.Marshal.Copy(bd.Scan0, imageData, 0, imageData.Length);
			image.UnlockBits(bd);

			int stride = bd.Stride;

			//values used during next loop
			int start = -1, end = 0, startHeight = image.Width * bytePixelStride;

			//this loop runs through the rows of pixels in the image, looking for rows with non white pixels (ie, rows with numbers :)
			//the first time a row is hit, the row number is stored. When a blank row is then hit, the end value is stored.
			//therefore, this loop generates pairs of start/end values, representing where non-white rows start and end.
			//Ie, where numbers start and end. As a speed boost, the minimum height bottom edge of the number is also stored in startHeight.
			for (int x = 0; x < image.Height; x++)
			{
				int index = x * stride;

				int height = image.Width * bytePixelStride;

				bool emptyRow = true;

				//pixels in the row..
				for (int y = index; y < index + image.Width * bytePixelStride; y += bytePixelStride)
				{
					if (imageData[y] < 128)
					{
						//this is a row with a number on it,

						if (end != start)
						{
							//if end and start are different, the previous row was white.
							start = x;
							end = x;
						}

						//work out start height of number
						if (y - index < height)
							height = y - index;

						emptyRow = false;
						break;
					}
				}

				if (!emptyRow)
				{
					if (height < startHeight)
						startHeight = height; // min start height of number
				}

				if (emptyRow && end == start)
				{
					//make a new number object
					end = x;
					startHeight /= bytePixelStride;
					Number number = new Number(start, end, imageData, startHeight, image.Width, stride, bytePixelStride);

					numbers.Add(number);

					//reset
					startHeight = image.Width * bytePixelStride;
				}
			}

			image.Dispose();

			return true;
		}

		//saved values from values.dat
		public Number(byte[] data, int index)
		{
			this.data = new byte[SampleX * SampleY];

			int start = SampleX * SampleY * index;

			for (int i = 0; i < this.data.Length; i++)
				this.data[i] = data[start + i];
		}

		//build the number
		public Number(int x, int x_end, byte[] imageData, int startHeight, int imageWidth, int stride, int byteCount)
		{
			this.data = null;

			int endHeight = 0;

			//now, the start x positon, width and start y positon are known.
			//All that is needed is to find the height of the number
			for (int row = x; row < x_end; row++)
			{
				int rowEndHeight = 0;
				int rowStart = row * stride + startHeight * byteCount;
				int rowEnd = row * stride + imageWidth * byteCount;

				//loop along the rows
				for (int i = rowStart; i < rowEnd; i += byteCount)
				{
					//if pixel is not white, increase this rows Height
					if (imageData[i] < 128)
						rowEndHeight = i;
				}

				rowEndHeight -= rowStart;
				rowEndHeight /= byteCount;

				if (endHeight < rowEndHeight)
					endHeight = rowEndHeight;
			}

			int width = x_end - x;
			int y = startHeight;
			int height = endHeight;

			//now have the bounds of the number, x,y,width,height
			//proceed to resize it to a 16x8 image

			data = new byte[SampleX * SampleY];

			//this saves calculation inside the loop
			int[] scalersY = new int[SampleY];
			//nearest neighbour sampling indices on the y axis
			for (int i = 0; i < SampleY; i++)
				scalersY[i] = (y + (i * height) / (SampleY - 1)) * byteCount;

			//cheap nearest neighbour resampling
			int index = 0;
			for (int rx = 0; rx < SampleX; rx++)
			{
				//nearest neighbour sample on xaxis
				int image_x = (x + (rx * width) / (SampleX - 1)) * stride;

				for (int ry = 0; ry < SampleY; ry++)
				{
					int image_y = scalersY[ry];

					data[index] = imageData[image_x + image_y];

					index++;
				}
			}
			//data is now set.

		}


		//compares this to another number
		public int Compare(Number l2)
		{
			int compare = 0;

			for (int i = 0; i < data.Length; i++)
			{
				//compare pixel difference
				int dif = (int)data[i] - (int)l2.data[i];

				//take absolute value, and add to total difference
				if (dif < 0)
					compare -= dif;
				else
					compare += dif;
			}

			return compare;
		}
	}

}

 
protocol
Moderator
Moderator
Posts: 680
Joined: Wed Jan 18, 2006 6:13 pm
Location: Dallas, TX
Contact:

why convert

Post by protocol »

If its not a must to convert the code to C++ just create a C# dll and access it as a COM component. And use the wx load dll library function.
skystar
In need of some credit
In need of some credit
Posts: 6
Joined: Sat Feb 11, 2006 9:56 pm

Post by skystar »

Are you sure ??

I don't know but i think this is not possible with c# or generally with any other managed code.

did you see or have an example ??

all the example i saw in this forum are for loading dll made by eaither borland c++ or VC++.

another thing, if this is possible, do i need to have the .net runtime to run my applicaiton ??

so many question !! :shock:

it is better to convert to c++ anyway, but i am not good in c++ ( pointers, functions that return arrays .....) :cry:

Thanks.
protocol
Moderator
Moderator
Posts: 680
Joined: Wed Jan 18, 2006 6:13 pm
Location: Dallas, TX
Contact:

Post by protocol »

Ummm... I have used a class from C# to with my C++ code, and yes you would need the framework. So with that said I don't think anyone here (or me) has the time to convert the code to wxWidgets. But you can.

check out http://www.wxwidgets.org/manuals/2.6.2/ ... .html#wxdc

That is the painting class for wxWidgets. If they can make a popular paint prog from it then you can convert your C# code.

If you have trouble, let me know I'm a beast at C# and C++. There like my native languages (CLR).
/* UIKit && wxWidgets 2.8 && Cocoa && .Net */
QuRegExmm
wxPCRE & ObjPCRE - Regex It!
shroukkhan
Earned a small fee
Earned a small fee
Posts: 12
Joined: Thu Dec 11, 2008 10:58 am

C# dll example in wxWidgets

Post by shroukkhan »

hi, so have you been able to create a DLL in c# and use it in wxWidgets? i have been looking for a way to do it for ages!
protocol
Moderator
Moderator
Posts: 680
Joined: Wed Jan 18, 2006 6:13 pm
Location: Dallas, TX
Contact:

Post by protocol »

Have you tried wx.NET?

regards.
/* UIKit && wxWidgets 2.8 && Cocoa && .Net */
QuRegExmm
wxPCRE & ObjPCRE - Regex It!
Post Reply