Related
I have a Xaramin.Android project and I am trying to create a Custom TileProvider to use offline maps from mbtiles sqlite database and found an example that does what i want to do here https://github.com/antoniocarlon/MapUtils however this example is done in java so i started creating my own based on the above code but in Xamarin.Android in c#.
So i have created a Class MBTilesProvider that inherits from Android.Gms.Maps.Model.TileProvider however the : base(width, height) shows an error that 'TileProvider' does not contain a constructor that takes 2 arguments. I know that error is pretty self explanatory but i can't seem to find any documentation around what the constructor arguments are for TileProvider ? if i remove the :base from my class i get the error message that 'TileProvider' does not contain a constructor that contains 0 arguments.
public class MBTilesProvider : TileProvider
{
private int _width;
private int _height;
public MBTilesProvider(int width, int height) : base(width, height)
{
this._width = width;
this._height = height;
}
public Tile GetTile(int x, int y, int zoom)
{
y = tms2gmaps(y, zoom);
byte[] bitmap = RetreiveImage(x, y, zoom);
Tile tile = new Tile(_width, _height, bitmap);
return tile;
}
private byte[] RetreiveImage(int x, int y, int zoom)
{
byte[] image = null;
if(zoom > 0)
{
image = ReadImageFromDB(x, y, zoom);
if(image == null)
{
image = Crop(RetreiveImage(x / 2, y / 2, zoom - 1), x, y);
}
return image;
} else
{
return image;
}
}
private byte[] ReadImageFromDB(int x, int y, int zoom)
{
DataClient.MBTilesClient mBTilesClient = new DataClient.MBTilesClient();
return mBTilesClient.GetTile(x, y, zoom);
}
private int tms2gmaps(int y, int zoom)
{
int ymax = 1 << zoom;
return ymax - y - 1;
}
private byte[] Crop(byte[] image, int x, int y)
{
byte[] output = image;
if(image == null)
{
return output;
}
Bitmap bitmap = BitmapFactory.DecodeByteArray(image, 0, image.Length);
bitmap = Bitmap.CreateBitmap(
bitmap,
x % 2 == 0 ? 0 : bitmap.Width / 2,
y % 2 == 0 ? bitmap.Height / 2 : 0,
bitmap.Width,
bitmap.Height
);
var stream = new MemoryStream();
bitmap.Compress(Bitmap.CompressFormat.Png, 100, stream);
bitmap.Recycle();
output = stream.ToArray();
return output;
}
}
Any Help would be greatly appreciated.
Eddie
Use the ITileProvider interface instead of the TileProvider abstract class. Then you won't have issues with constructors.
public class MBTilesProvider : Java.Lang.Object, ITileProvider
I don't know why Xamarin creates both or how the abstract class should be used. I had the same issue, but this solved it for me. The Java.Lang.Object is so you don't have to override the Handle and Dispose methods.
In this post: Possible memory leak in Zxing's System.Drawing.Bitmap a question is asked about a memory leak in the ZXing library. I've downloaded and amended the library with the free of the allocated memory. I've even introduced using(){} statements where applicable but I still get a memory leak.
I have a suspicion. Does the Marshal.Copy maybe do more then just copy the data from source to destination. Do I maybe also have to free the destination after the copy?
As you can see in the code below I even tried allocating the buffer only once and only reallocating it when an image larger than the previous one is requested, but that did not solve the problem.
Regards
Paul
My altered code:
using System;
using MonoTouch.UIKit;
using MonoTouch.CoreGraphics;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace System.Drawing
{
public class Bitmap : IDisposable
{
byte[] pixelData = new byte[0];
int width = 0;
int height = 0;
static IntPtr m_BufferPointer = default(IntPtr);
static int m_Size;
/// <summary>
/// Reallocs the buffer when it becomes too small
/// </summary>
private IntPtr ReallocBuffer(int size)
{
if(m_BufferPointer != default(IntPtr))
{
if(m_Size < size)
{
Marshal.FreeHGlobal(m_BufferPointer);
m_BufferPointer = Marshal.AllocHGlobal(size);
}
}
else
{
m_BufferPointer = Marshal.AllocHGlobal(size);
}
m_Size = size;
return m_BufferPointer;
}
public Bitmap (UIImage image)
{
UIImage backingImage = image;
IntPtr rawData;
using (CGImage imageRef = backingImage.CGImage)
{
width = imageRef.Width;
height = imageRef.Height;
using (CGColorSpace colorSpace = CGColorSpace.CreateDeviceRGB ())
{
int size = height * width * 4;
rawData = ReallocBuffer(size); //Marshal.AllocHGlobal (height * width * 4);
using (CGContext context = new CGBitmapContext (rawData, width, height, 8, 4 * width, colorSpace, CGImageAlphaInfo.PremultipliedLast))
{
context.DrawImage (new RectangleF (0.0f, 0.0f, (float)width, (float)height), imageRef);
pixelData = new byte[height * width * 4];
Marshal.Copy (rawData, pixelData, 0, pixelData.Length);
}
}
}
}
private static int CountCalled;
private static int LastCountCalled = 20000000; //30411000;
public Color GetPixel (int x, int y)
{
try
{
CountCalled++;
if (CountCalled - LastCountCalled > 100000)
{
Debug.WriteLine (CountCalled);
LastCountCalled += 1000000;
}
byte bytesPerPixel = 4;
int bytesPerRow = width * bytesPerPixel;
int rowOffset = y * bytesPerRow;
int colOffset = x * bytesPerPixel;
int pixelDataLoc = rowOffset + colOffset;
Color ret = Color.FromArgb (pixelData [pixelDataLoc + 3], pixelData [pixelDataLoc + 0], pixelData [pixelDataLoc + 1], pixelData [pixelDataLoc + 2]);
return ret;
}
catch (Exception ex)
{
Console.WriteLine ("Req: {0}x{1}", x, y);
throw ex;
}
}
#region IDisposable implementation
public void Dispose ()
{
pixelData = null;
GC.Collect(0);
}
#endregion
}
}
You need to free the native buffer, CGBitmapContext won't do it for you:
IntPtr rawData = Marshal.AllocHGlobal (height * width * 4);
try {
using (CGContext context = new CGBitmapContext (rawData, width, height, 8, 4 * width, colorSpace, CGImageAlphaInfo.PremultipliedLast))
{
context.DrawImage (new RectangleF (0.0f, 0.0f, (float)width, (float)height), imageRef);
pixelData = new byte[height * width * 4];
Marshal.Copy (rawData, pixelData, 0, pixelData.Length);
}
} finally {
Marshal.FreeHGlobal (rawData);
}
Updated according to Jonathan.Peppers try-finally suggestion in the comments
I'm loading up an image into a BitmapImage and convert this into an array of PixelColor's. What I would like is to be able to manipulate some of these pixels to make them Lighter/Darker/Transparent but I can't seem to get it to work. It does work to set it to a certain color but the alpha channel is ignored.
It's a WPF app using C#4
Thanks!
And the code...
namespace BitmapTest {
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Image = System.Windows.Controls.Image;
public partial class MainWindow {
public MainWindow() {
InitializeComponent();
LoadImage();
}
[DllImport("gdi32")]
private static extern int DeleteObject(IntPtr o);
public static BitmapSource LoadBitmap(Bitmap source) {
var ip = source.GetHbitmap();
try {
return Imaging.CreateBitmapSourceFromHBitmap(ip,
IntPtr.Zero, Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
} finally {
DeleteObject(ip);
}
}
private void LoadImage() {
var i = new Image();
var src = new BitmapImage();
src.BeginInit();
src.UriSource = new Uri("road.jpg", UriKind.Relative);
src.CacheOption = BitmapCacheOption.OnLoad;
src.EndInit();
var pixels = GetPixels(src);
for (var x = 0; x < Math.Min(50, pixels.GetLength(0)); x++) {
for (var y = 0; y < Math.Min(50, pixels.GetLength(1)); y++) {
pixels[x, y] = new PixelColor {Alpha = 100, Red = pixels[x, y].Red, Green = pixels[x, y].Green, Blue = pixels[x, y].Blue};
}
}
var bitmap = new WriteableBitmap(src.PixelWidth, src.PixelHeight, src.DpiX, src.DpiY, src.Format, src.Palette);
PutPixels(bitmap, pixels, 0, 0);
i.Source = bitmap;
i.Stretch = Stretch.Fill;
RootGrid.Children.Add(i);
}
public PixelColor[,] GetPixels(BitmapSource source) {
if (source.Format != PixelFormats.Bgra32)
source = new FormatConvertedBitmap(source, PixelFormats.Bgra32, null, 0);
var pixels = source.CopyPixels();
return pixels;
}
public void PutPixels(WriteableBitmap bitmap, PixelColor[,] pixels, int x, int y) {
var width = pixels.GetLength(0);
var height = pixels.GetLength(1);
var sourceRect = new Int32Rect(0, 0, width, height);
bitmap.WritePixels(sourceRect, pixels, width*4, x, y);
}
[StructLayout(LayoutKind.Sequential)]
public struct PixelColor {
public byte Blue;
public byte Green;
public byte Red;
public byte Alpha;
}
}
public static class BitmapSourceHelper {
public static MainWindow.PixelColor[,] CopyPixels(this BitmapSource source) {
if (source.Format != PixelFormats.Bgra32)
source = new FormatConvertedBitmap(source, PixelFormats.Bgra32, null, 0);
var pixels = new MainWindow.PixelColor[source.PixelWidth, source.PixelHeight];
var stride = source.PixelWidth * ((source.Format.BitsPerPixel + 7) / 8);
var pinnedPixels = GCHandle.Alloc(pixels, GCHandleType.Pinned);
source.CopyPixels(
new Int32Rect(0, 0, source.PixelWidth, source.PixelHeight),
pinnedPixels.AddrOfPinnedObject(),
pixels.GetLength(0) * pixels.GetLength(1) * 4,
stride);
pinnedPixels.Free();
return pixels;
}
}
}
Here is an example of lightening and darkening an image in a windows forms app. The code here is based the Brightness filter section of an article on The Code Project site: Image Processing for Dummies with C# and GDI+ Part 1.
public Bitmap Lighten(Bitmap bitmap, int amount)
{
if (amount < -255 || amount > 255)
return bitmap;
// GDI+ still lies to us - the return format is BGR, NOT RGB.
BitmapData bmData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
int stride = bmData.Stride;
System.IntPtr Scan0 = bmData.Scan0;
int nVal = 0;
unsafe
{
byte* p = (byte*)(void*)Scan0;
int nOffset = stride - bitmap.Width * 3;
int nWidth = bitmap.Width * 3;
for (int y = 0; y < bitmap.Height; ++y)
{
for (int x = 0; x < nWidth; ++x)
{
nVal = (int)(p[0] + amount);
if (nVal < 0) nVal = 0;
if (nVal > 255) nVal = 255;
p[0] = (byte)nVal;
++p;
}
p += nOffset;
}
}
bitmap.UnlockBits(bmData);
return bitmap;
}
private void btnLighten_Click(object sender, EventArgs e)
{
Bitmap image = pictureBox1.Image as Bitmap;
pictureBox1.Image = Lighten(image, 10);
}
private void btnDarken_Click(object sender, EventArgs e)
{
Bitmap image = pictureBox1.Image as Bitmap;
pictureBox1.Image = Lighten(image, -10);
}
This code would adjusts a given rectangle in the image, according to brightness, contrast, alpha, gamma:
Bitmap clonedImage = originalImage.Clone(rect, originalImage.PixelFormat);
float gamma = 1.0f; // no change in gamma
float adjustedBrightness = brightness - 1.0f;
// create matrix that will brighten and contrast the image
float[][] ptsArray ={
new float[] {contrast, 0, 0, 0, 0}, // scale red
new float[] {0, contrast, 0, 0, 0}, // scale green
new float[] {0, 0, contrast, 0, 0}, // scale blue
new float[] {0, 0, 0, alpha, 0},
new float[] {adjustedBrightness, adjustedBrightness, adjustedBrightness, 0, 1}};
var imageAttributes = new ImageAttributes();
imageAttributes.ClearColorMatrix();
imageAttributes.SetColorMatrix(new ColorMatrix(ptsArray), ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
imageAttributes.SetGamma(gamma, ColorAdjustType.Bitmap);
// Copy back to the original image from the cloned image
Graphics g = Graphics.FromImage(originalImage);
g.DrawImage(clonedImage, new Rectangle(0, 0, clonedImage.Width, clonedImage.Height)
, rect.left, rect.top, rect.Width, rect.Height,
GraphicsUnit.Pixel, imageAttributes);
g.Flush();
This question is related to: How to convert Bitmap to byte[,,] faster?
I have byte[] which has:
[r0, g0, b0, r1, g1, b1 ... ]
(r0 is the r-value of zeroth pixel and so on)
How can I copy this quickly into byte[,,]?
Or maybe I can get byte[,,] ditectly from BitmapData?
Based on Martinho's answer but perhaps a bit faster(don't have time for benchmarking now):
struct BitmapDataAccessor
{
private readonly byte[] data;
private readonly int[] rowStarts;
public readonly int Height;
public readonly int Width;
public BitmapDataAccessor(byte[] data, int width, int height)
{
this.data = data;
this.Height = height;
this.Width = width;
rowStarts = new int[height];
for(int y=0;y<height;y++)
rowStarts[y]=y*width;
}
public byte this[int x, int y, int color] // Maybe use an enum with Red = 0, Green = 1, and Blue = 2 members?
{
get { return data[(rowStarts[y] + x) *3 + color]; }
set { data[(rowStarts[y] + x) *3 + color] = value; }
}
public byte[] Data
{
get { return data; }
}
}
Ok, let's say you've got your data in a one-dimensional byte array. Do you really need to push it over into a three-dimensional array? If all you want is an easier way to access the pixel data, why don't you simply write such a simple interface to that array? Something along these lines:
class BitmapDataAccessor
{
private readonly byte[] data;
private readonly int rows;
private readonly int columns;
public BitmapDataAccessor(byte[] data, int rows, int columns)
{
this.data = data;
this.rows = rows;
this.columns = columns;
}
public byte this[int row, int column, int color] // Maybe use an enum with Red = 0, Green = 1, and Blue = 2 members?
{
get { return data[(row * columns + column) * 3 + color]; }
set { data[(row * columns + column) * 3 + color] = value; }
}
public byte[] Data
{
get { return data; }
}
}
How about using something like this for ease of accessing the discrete bytes:
class ByteIndexer
{
private readonly byte[] _bits;
private readonly int _width;
public ByteIndexer(byte[] bits, int width)
{
_bits = bits;
_width = width;
}
public byte this[int x, int y, int c]
{ get { return _bits[(((_width * y) + x) * 3) + c]; } }
}
You could even make it easier, overload this[] with:
public Color this[int x, int y]
{ get { return Color.FromArgb(this[x,y,0], this[x,y,1], this[x,y,2]); }
You could also consider using the built-in Bitmap in System.Drawing. Here's an example with a 4x3 image.
var image = new byte[] {255,255,255,0,0,0,255,255,255,0,0,0,
255,255,255,0,0,0,255,127,255,0,0,0,
0,0,0,255,255,255,0,0,0,255,255,255};
Bitmap bmp = new Bitmap(4, 3, PixelFormat.Format24bppRgb);
BitmapData bmpData = bmp.LockBits(
new Rectangle(0, 0, bmp.Width, bmp.Height),
ImageLockMode.WriteOnly, bmp.PixelFormat);
Marshal.Copy(image, 0, bmpData.Scan0, image.Length);
bmp.UnlockBits(bmpData);
var testPixel = bmp.GetPixel(2, 1);
testPixel will be a System.Drawing.Color set to {Color [A=255, R=255, G=127, B=255]}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
Hello I am in the process of doing a school project, where we have a robot driving on the ground in between Flamingo plates. We need to create an algorithm that can identify the locations of these plates, so we can create paths around them (We are using A Star for that).
So far have we worked with AForged Library and we have created the following class, the only problem with this is that when it create the rectangles dose it not take in account that the plates are not always parallel with the camera border, and it that case will it just create a rectangle that cover the whole plate.
So we need to some way find the rotation on the object, or another way to identify this.
I have create an image that might help explain this
Image the describe the problem: http://img683.imageshack.us/img683/9835/imagerectangle.png
Any help on how I can do this would be greatly appreciated.
Any other information or ideers are always welcome.
public class PasteMap
{
private Bitmap image;
private Bitmap processedImage;
private Rectangle[] rectangels;
public void initialize(Bitmap image)
{
this.image = image;
}
public void process()
{
processedImage = image;
processedImage = applyFilters(processedImage);
processedImage = filterWhite(processedImage);
rectangels = extractRectangles(processedImage);
//rectangels = filterRectangles(rectangels);
processedImage = drawRectangelsToImage(processedImage, rectangels);
}
public Bitmap getProcessedImage
{
get
{
return processedImage;
}
}
public Rectangle[] getRectangles
{
get
{
return rectangels;
}
}
private Bitmap applyFilters(Bitmap image)
{
image = new ContrastCorrection(2).Apply(image);
image = new GaussianBlur(10, 10).Apply(image);
return image;
}
private Bitmap filterWhite(Bitmap image)
{
Bitmap test = new Bitmap(image.Width, image.Height);
for (int width = 0; width < image.Width; width++)
{
for (int height = 0; height < image.Height; height++)
{
if (image.GetPixel(width, height).R > 200 &&
image.GetPixel(width, height).G > 200 &&
image.GetPixel(width, height).B > 200)
{
test.SetPixel(width, height, Color.White);
}
else
test.SetPixel(width, height, Color.Black);
}
}
return test;
}
private Rectangle[] extractRectangles(Bitmap image)
{
BlobCounter bc = new BlobCounter();
bc.FilterBlobs = true;
bc.MinWidth = 5;
bc.MinHeight = 5;
// process binary image
bc.ProcessImage( image );
Blob[] blobs = bc.GetObjects(image, false);
// process blobs
List<Rectangle> rects = new List<Rectangle>();
foreach (Blob blob in blobs)
{
if (blob.Area > 1000)
{
rects.Add(blob.Rectangle);
}
}
return rects.ToArray();
}
private Rectangle[] filterRectangles(Rectangle[] rects)
{
List<Rectangle> Rectangles = new List<Rectangle>();
foreach (Rectangle rect in rects)
{
if (rect.Width > 75 && rect.Height > 75)
Rectangles.Add(rect);
}
return Rectangles.ToArray();
}
private Bitmap drawRectangelsToImage(Bitmap image, Rectangle[] rects)
{
BitmapData data = image.LockBits(new Rectangle(0, 0, image.Width, image.Height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
foreach (Rectangle rect in rects)
Drawing.FillRectangle(data, rect, Color.Red);
image.UnlockBits(data);
return image;
}
}
You need to analyse the blobs a bit more to find the corners as #kigurai has said. The AForge library allows you to do this, see the section Finding convex hull on this page for more info. The screenshot below (from the page) shows a small sample of what the convex hull is.
(source: aforgenet.com)
You want to take a look at the GetBlobsLeftAndRightEdges function and the GrahamConvexHull class.
If anyone is interested, this is the way I did it.
Blobsprocessing:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using AForge;
using AForge.Imaging;
using AForge.Imaging.Filters;
using AForge.Imaging.Textures;
using AForge.Math.Geometry;
namespace CDIO.Library
{
public class Blobsprocessing
{
Bitmap image;
BlobCounter BlobCounter;
Blob[] blobs;
List<Polygon> hulls;
public Blobsprocessing(Bitmap image)
{
this.image = image;
}
public void Process()
{
BlobCounter = new BlobCounter();
processBlobs();
extractConvexHull();
}
public List<Polygon> getHulls()
{
return hulls;
}
private void processBlobs()
{
BlobCounter.FilterBlobs = true;
BlobCounter.MinWidth = 5;
BlobCounter.MinHeight = 5;
// set ordering options
BlobCounter.ObjectsOrder = ObjectsOrder.Size;
// process binary image
BlobCounter.ProcessImage(image);
blobs = BlobCounter.GetObjectsInformation();
}
private void extractConvexHull()
{
GrahamConvexHull hullFinder = new GrahamConvexHull();
// process each blob
hulls = new List<Polygon>();
foreach (Blob blob in blobs)
{
List<IntPoint> leftPoints, rightPoints, edgePoints;
edgePoints = new List<IntPoint>();
// get blob's edge points
BlobCounter.GetBlobsLeftAndRightEdges(blob,
out leftPoints, out rightPoints);
edgePoints.AddRange(leftPoints);
edgePoints.AddRange(rightPoints);
// blob's convex hull
List<IntPoint> hull = hullFinder.FindHull(edgePoints);
hulls.Add(new Polygon(hull));
}
}
}
}
MapFilters:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using AForge;
using AForge.Imaging;
using AForge.Imaging.Filters;
using AForge.Imaging.Textures;
using AForge.Math.Geometry;
namespace CDIO.Library
{
public class MapFilters
{
private Bitmap image;
private Bitmap processedImage;
private Rectangle[] rectangels;
public void initialize(Bitmap image)
{
this.image = image;
}
public void process()
{
processedImage = image;
processedImage = applyFilters(processedImage);
processedImage = filterWhite(processedImage);
}
public Bitmap getProcessedImage
{
get
{
return processedImage;
}
}
private Bitmap applyFilters(Bitmap image)
{
image = new ContrastCorrection(2).Apply(image);
image = new GaussianBlur(10, 10).Apply(image);
return image;
}
private Bitmap filterWhite(Bitmap image)
{
Bitmap test = new Bitmap(image.Width, image.Height);
for (int width = 0; width < image.Width; width++)
{
for (int height = 0; height < image.Height; height++)
{
if (image.GetPixel(width, height).R > 200 &&
image.GetPixel(width, height).G > 200 &&
image.GetPixel(width, height).B > 200)
{
test.SetPixel(width, height, Color.White);
}
else
test.SetPixel(width, height, Color.Black);
}
}
return test;
}
}
}
Polygon:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.Threading;
using AForge;
using AForge.Imaging;
using AForge.Imaging.Filters;
using AForge.Imaging.Textures;
using AForge.Math.Geometry;
namespace CDIO.Library
{
public class Polygon
{
List<IntPoint> hull;
public Polygon(List<IntPoint> hull)
{
this.hull = hull;
}
public bool inPoly(int x, int y)
{
int i, j = hull.Count - 1;
bool oddNodes = false;
for (i = 0; i < hull.Count; i++)
{
if (hull[i].Y < y && hull[j].Y >= y
|| hull[j].Y < y && hull[i].Y >= y)
{
try
{
if (hull[i].X + (y - hull[i].X) / (hull[j].X - hull[i].X) * (hull[j].X - hull[i].X) < x)
{
oddNodes = !oddNodes;
}
}
catch (DivideByZeroException e)
{
if (0 < x)
{
oddNodes = !oddNodes;
}
}
}
j = i;
}
return oddNodes;
}
public Rectangle getRectangle()
{
int x = -1, y = -1, width = -1, height = -1;
foreach (IntPoint item in hull)
{
if (item.X < x || x == -1)
x = item.X;
if (item.Y < y || y == -1)
y = item.Y;
if (item.X > width || width == -1)
width = item.X;
if (item.Y > height || height == -1)
height = item.Y;
}
return new Rectangle(x, y, width-x, height-y);
}
public Bitmap drawRectangle(Bitmap image)
{
Rectangle rect = getRectangle();
Bitmap clonimage = (Bitmap)image.Clone();
BitmapData data = clonimage.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadWrite, image.PixelFormat);
Drawing.FillRectangle (data, rect, getRandomColor());
clonimage.UnlockBits(data);
return clonimage;
}
public Point[] getMap()
{
List<Point> points = new List<Point>();
Rectangle rect = getRectangle();
for (int x = rect.X; x <= rect.X + rect.Width; x++)
{
for (int y = rect.Y; y <= rect.Y + rect.Height; y++)
{
if (inPoly(x, y))
points.Add(new Point(x, y));
}
}
return points.ToArray();
}
public float calculateArea()
{
List<IntPoint> list = new List<IntPoint>();
list.AddRange(hull);
list.Add(hull[0]);
float area = 0.0f;
for (int i = 0; i < hull.Count; i++)
{
area += list[i].X * list[i + 1].Y - list[i].Y * list[i + 1].X;
}
area = area / 2;
if (area < 0)
area = area * -1;
return area;
}
public Bitmap draw(Bitmap image)
{
Bitmap clonimage = (Bitmap)image.Clone();
BitmapData data = clonimage.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadWrite, image.PixelFormat);
Drawing.Polygon(data, hull, Color.Red);
clonimage.UnlockBits(data);
return clonimage;
}
static Random random = new Random();
int Color1, Color2, Color3;
public Color getRandomColor()
{
Color1 = random.Next(0, 255);
Color2 = random.Next(0, 255);
Color3 = random.Next(0, 255);
Color color = Color.FromArgb(Color1, Color2, Color3);
Console.WriteLine("R: " + Color1 + " G: " + Color2 + " B: " + Color3 + " = " + color.Name);
return color;
}
}
}
The most straight forward solution is probably to find the corners of each detected blob and then geometrically calculate which point-pairs make up the different sides of the squares.
This assumes that the camera is looking straight down such that a square is actually a square in the image (no perspective distorsion).
I am however a bit curious why you need to know the rotation of the rectangles. In all the example images the rectangles are more or less aligned with the image borders, so a bounding box for a rectangle blob would be very close to what you are trying to find. At least it should be good enough for path finding.
You should be using neural networks.
See: http://en.wikipedia.org/wiki/Neural_network