I'm trying to write a program that detects a circle when you hold it in front of the webcam. I know how the circle detection works for an image, but I can't figure out how to get it to work with a webcam stream, using the following code:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
ImageViewer viewer = new ImageViewer(); //create an image viewer
Capture capture = new Capture(); //create a camera capture
Application.Idle += new EventHandler(delegate(object sender, EventArgs e)
{ //run this until application closed (close button click on image viewer)
Image<Bgr, Byte> image = capture.QueryFrame();
//MemStorage storage = new MemStorage();
//Contour<Point> contours = image.FindContours();
//Contour<Point> currentContour = contours.ApproxPoly(contours.Perimeter * 0.05, storage);
viewer.Image = image; //draw the image obtained from camera
});
viewer.ShowDialog(); //show the image viewer
}
As you can see I've tried using FindContours in the innermost loop but the program just freezes when I try running it, so I commented that particular part out. Can anyone tell me how to implement circle detection using a webcam?
You can use HoughCircle Method for circle detection
Image gray = img.Convert().PyrDown().PyrUp();
Gray cannyThreshold = new Gray(180);
Gray cannyThresholdLinking = new Gray(120);
Gray circleAccumulatorThreshold = new Gray(120);
CircleF[] circles = gray.HoughCircles(
cannyThreshold,
circleAccumulatorThreshold,
5.0, //Resolution of the accumulator used to detect centers of the circles
10.0, //min distance
5, //min radius
0 //max radius
)[0]; //Get the circles from the first channel
See Method HoughCircle
Related
Using C# and Winforms, I want to display a PDF, select a rectangular region, and then extract that area of text from a number of PDFs. For displaying the PDF, I have a number of options...
Use an "Adobe PDF Reader" control to display the PDF - However, I cant use mouseover events and according to https://forums.adobe.com/thread/1640606 its just not possible to select a region.
Use a "WebBrowser" control to display the PDF, but it appears I have the same issue with mouseover events and cannot select a region.
Convert the PDF to an image (using ghostscript in my case) and displaying it in a picturebox. I'm finding the most success here, as I can now generate and record the coordinates of a rectangular region. When I take these coordinates and apply them to the PDF using Itext, I don't think my rectangular region translates correctly.
My question is, How do I render the GhostScripted image in a picture box maintaining the same ratios so that my coordinates will line up with the PDF?
Thank you in advance for the down votes!!
Here is the current state of my code... Everything works with the exception that my units are off in space somewhere. The action DOES return text, but it's never the text I selected. Im sure its a combination of the coordinate system / units and I will continue to try to understand this.
---- update
With a PDF at 0 deg rotation (portrait), I think the following holds true, or is at least working for me right now... User Units having not been changed, the coordinates taken from selecting in the picturebox need adjusting. The Y coordinates need to be subtracted from the overall height while the X coordinate remains the same.
iTextSharp.text.Rectangle rect = new iTextSharp.text.Rectangle(first.X, 3024-first.Y, last.X, 3024-last.Y);
This is picking text up exactly as expected on 0 deg rotated PDFs. On 90 deg rotated PDFs, the X and Y coordinates just need to be swapped.I am updating the code snippet below to show my working example.
using System;
using System.Drawing;
using System.Windows.Forms;
using Ghostscript.NET.Rasterizer;
using iTextSharp.text.pdf;
using iTextSharp.text.pdf.parser;
namespace formPdf
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
string fileName; // The filename of the pdf
float width; // The width of the PDF in pixels
float hight; // the Height of the PDF in pixels
float rotation; // the Rotation of the PDF 0 or 90
float llx = 0; // The Lower Left X value for applying to the PDF
float lly = 0; // the Lower Left Y value for applying to the PDF
float urx = 0; // the Upper Right X value for applying to the PDF
float ury = 0; // the Upper Right Y value for applying to the PDF
// OnCLick event to open the file browser and select a file... The Width, Height and rotation values are set and the program
// is directed to render the First page of the pdf by calling the setPicture function
private void button1_Click(object sender, EventArgs e)
{
OpenFileDialog openFileDialog1 = new OpenFileDialog();
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
try
{
fileName = openFileDialog1.FileName;
PdfReader reader = new PdfReader(fileName);
iTextSharp.text.Rectangle dim = reader.GetPageSizeWithRotation(1);
width = dim.Width;
hight = dim.Height;
rotation = dim.Rotation;
setPicture(openFileDialog1.FileName);
} catch
{
// do nothing for now
}
}
}
// Using Ghostscript, the image is rendered to a picturebox. DPIs are set assuming the PDF default value is used
private void setPicture(string fileName)
{
GhostscriptRasterizer rasterizer = new GhostscriptRasterizer();
rasterizer.Open(fileName);
Image img = rasterizer.GetPage(72, 72, 1);
pictureBox1.SizeMode = PictureBoxSizeMode.AutoSize;
pictureBox1.Image = img;
}
// Declare point variables for the user defined rectangle indicating the locatoin of the PDF to be searched...
Point first = new Point();
Point last = new Point();
// The first point is collected on the MouseDown event
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
first = e.Location;
}
// The second point is collected on the mouse down event. Points to be applied to the PDF are adjusted based on the rotation of the PDF.
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
last = e.Location;
if (rotation == 0)
{
llx = first.X;
lly = hight - first.Y;
urx = last.X;
ury = hight - last.Y;
} else if(rotation == 90) {
llx = first.Y;
lly = first.X;
urx = last.Y;
ury = last.X;
}
gettext();
}
// the original PDF is opened with Itext and the text is extracted from t he defined location...
private void gettext()
{
PdfReader reader = new PdfReader(fileName);
iTextSharp.text.Rectangle rect = new iTextSharp.text.Rectangle(llx, lly, urx, ury);
RenderFilter[] renderfilter = new RenderFilter[1];
renderfilter[0] = new RegionTextRenderFilter(rect);
ITextExtractionStrategy textExtractionStrategy = new FilteredTextRenderListener(new LocationTextExtractionStrategy(), renderfilter);
string text = PdfTextExtractor.GetTextFromPage(reader, 1, textExtractionStrategy);
iTextSharp.text.Rectangle mediabox = reader.GetPageSizeWithRotation(1);
MessageBox.Show("", text+" "+mediabox+" "+first+" "+last);
}
// Image Controls....
}
}
I'm trying to extract a portion of a pdf (the coordinates of the section will always remain constant) using PDF Sharp. Then I will resize the portion to 4" x 6" for printing onto a sticky back label. How would I extract the portion of the PDF? This is in a console application, C#.
There is no easy way to extract parts from a PDF file.
A possible workaround: create a new page in label size, then draw the existing page onto the new page so that the required rectangle is visible on the new page.
If needed, draw white rectangles to hide information that is not part of the section you need, but that is visible on the new page.
So here was how I managed to do this, not a perfect solution (you do loose some quality). This uses Spire.PDF, not PDF Sharp as I originally planned. I got fairly lucky in that the output size was nearly 4" X 6". So I just used shrink to fit on print options.
static void Main(string[] args)
{
ConvertPDFToBmp("FilePathOfPDF");
CropAtRect("FilePathOfConvertedImage");
ConvertToPDF("FilePathOfCroppedImage");
}
public static void ConvertPDFToBmp(string filePath)
{
PdfDocument document = new PdfDocument();
document.LoadFromFile(filePath);
Image emf = document.SaveAsImage(0, Spire.Pdf.Graphics.PdfImageType.Bitmap, 400, 400);
emf.Save("FilePath", ImageFormat.Jpeg);
}
public static void CropAtRect(string filePath)
{
Bitmap b = (Bitmap)Bitmap.FromFile(filePath);
Rectangle r = new Rectangle(new /*Where the rectangle starts*/Point(/*Width*/, /*Height*/), (new /*How big is the rectangle*/Size(/*Width*/, /*Height*/)));
Bitmap nb = new Bitmap(r.Width, r.Height);
nb.SetResolution(400, 400); //Scale to keep quality
Graphics g = Graphics.FromImage(nb);
g.DrawImage(b, -r.X, -r.Y);
nb.Save("FilePath", ImageFormat.Jpeg);
}
public static void ConvertToPDF(string filePath)
{
Bitmap b = (Bitmap)Bitmap.FromFile(filePath);
PdfDocument doc = new PdfDocument();
PdfImage pdfImage = PdfImage.FromImage(b);
PdfUnitConvertor uinit = new PdfUnitConvertor();
PdfPageBase page = doc.Pages.Add(new /*Size of PDF Page*/SizeF(585, 365), new PdfMargins(0f));
page.Canvas.DrawImage(pdfImage, new /*Where the image starts*/PointF(0, 0));
doc.SaveToFile("FilePath");
}
I am creating windows 8 store application with MonoGame framework. I want to get each bitmap from camera in order to process some image recognition on that bitmap. The thing is I only get the whole video stream from camera (randomAccessStream) but not each frame from the video.
async private void Start_Click(object sender, RoutedEventArgs e)
{
//1. Initialize:
mediaCaptureMgr = new MediaCapture();
randomAccessStream = new InMemoryRandomAccessStream();
await mediaCaptureMgr.InitializeAsync();
//2. create profile
MediaEncodingProfile encordingProfile = MediaEncodingProfile.CreateWmv(VideoEncodingQuality.Auto);
//3. start recording
await mediaCaptureMgr.StartRecordToStreamAsync(encordingProfile, randomAccessStream);
}
How can I receive new up-coming frame/bitmap from camera?
Take a look here
It is a sample app from Microsoft. Among other things it shows:
How to capture an image using the new LowLagPhotoCapture and LowLagPhotoControl classes.
How to capture a sequence of photos using the new LowLagPhotoSequenceCapture and LowLagPhotoSequenceControl classes.
...
If you are going to process the images, you could just take pictures on an interval. I don't think you need to process every single frame of a video stream..
I've put together a custom top-down camera logic script based on Unity3D's ThirdPersonCamera.js script. Everything appears to be working properly, the camera follows the target player on the XZ plane and even moves along the Y-axis as appropriate when the player jumps.
Only the camera isn't looking at the player. So I tried using Transform.LookAt() on the cameraTransform to have the camera looking directly down on the player. This does cause the camera to correctly look directly down on the player, but then movement via WASD no longer works. The player just sits there. Using Spacebar for jumping does still work though.
This doesn't make sense to me, how should the orientation of the camera's transform be affecting the movement of the player object?
The code for my script is below:
// The transform of the camera that we're manipulating
var cameraTransform : Transform;
// The postion that the camera is currently focused on
var focusPosition = Vector3.zero;
// The idle height we are aiming to be above the target when the target isn't moving
var idleHeight = 7.0;
// How long should it take the camera to focus on the target on the XZ plane
var xzSmoothLag = 0.3;
// How long should it take the camera to focus on the target vertically
var heightSmoothLag = 0.3;
private var _target : Transform;
private var _controller : ThirdPersonController;
private var _centerOffset = Vector3.zero;
private var _headOffset = Vector3.zero;
private var _footOffset = Vector3.zero;
private var _xzVelocity = 0.0;
private var _yVelocity = 0.0;
private var _cameraHeightVelocity = 0.0;
// ===== UTILITY FUNCTIONS =====
// Apply the camera logic to the camera with respect for the target
function process()
{
// Early out if we don't have a target
if ( !_controller )
return;
var targetCenter = _target.position + _centerOffset;
var targetHead = _target.position + _headOffset;
var targetFoot = _target.position + _footOffset;
// Determine the XZ offset of the focus position from the target foot
var xzOffset = Vector2(focusPosition.x, focusPosition.z) - Vector2(targetFoot.x, targetFoot.z);
// Determine the distance of the XZ offset
var xzDistance = xzOffset.magnitude;
// Determine the Y distance of the focus position from the target foot
var yDistance = focusPosition.y - targetFoot.y;
// Damp the XZ distance
xzDistance = Mathf.SmoothDamp(xzDistance, 0.0, _xzVelocity, xzSmoothLag);
// Damp the XZ offset
xzOffset *= xzDistance;
// Damp the Y distance
yDistance = Mathf.SmoothDamp(yDistance, 0.0, _yVelocity, heightSmoothLag);
// Reposition the focus position by the dampened distances
focusPosition.x = targetFoot.x + xzOffset.x;
focusPosition.y = targetFoot.y + yDistance;
focusPosition.z = targetFoot.z + xzOffset.y;
var minCameraHeight = targetHead.y;
var targetCameraHeight = minCameraHeight + idleHeight;
// Determine the current camera height with respect to the minimum camera height
var currentCameraHeight = Mathf.Max(cameraTransform.position.y, minCameraHeight);
// Damp the camera height
currentCameraHeight = Mathf.SmoothDamp( currentCameraHeight, targetCameraHeight, _cameraHeightVelocity, heightSmoothLag );
// Position the camera over the focus position
cameraTransform.position = focusPosition;
cameraTransform.position.y = currentCameraHeight;
// PROBLEM CODE - BEGIN
// Have the camera look at the focus position
cameraTransform.LookAt(focusPosition, Vector3.forward);
// PROBLEM CODE - END
Debug.Log("Camera Focus Position: " + focusPosition);
Debug.Log("Camera Transform Position: " + cameraTransform.position);
}
// ===== END UTILITY FUNCTIONS =====
// ===== UNITY FUNCTIONS =====
// Initialize the script
function Awake( )
{
// If the camera transform is unassigned and we have a main camera,
// set the camera transform to the main camera's transform
if ( !cameraTransform && Camera.main )
cameraTransform = Camera.main.transform;
// If we don't have a camera transform, report an error
if ( !cameraTransform )
{
Debug.Log( "Please assign a camera to the TopDownThirdPersonCamera script." );
enabled = false;
}
// Set the target to the game object transform
_target = transform;
// If we have a target set the controller to the target's third person controller
if ( _target )
{
_controller = _target.GetComponent( ThirdPersonController );
}
// If we have a controller, calculate the center offset and head offset
if ( _controller )
{
var characterController : CharacterController = _target.collider;
_centerOffset = characterController.bounds.center - _target.position;
_headOffset = _centerOffset;
_headOffset.y = characterController.bounds.max.y - _target.position.y;
_footOffset = _centerOffset;
_footOffset.y = characterController.bounds.min.y - _target.position.y;
}
// If we don't have a controller, report an error
else
Debug.Log( "Please assign a target to the camera that has a ThirdPersonController script attached." );
// Apply the camera logic to the camera
process();
}
function LateUpdate( )
{
// Apply the camera logic to the camera
process();
}
// ===== END UNITY FUNCTIONS =====
I've marked the problem code section with PROBLEM CODE comments. If the problem code is removed, it allows WASD movement to work again, but then the camera is no longer looking at the target.
Any insight into this issue is very much appreciated.
I figured it out, the issue was with the ThirdPersonController.js script that I was using. In the function UpdateSmoothedMovementDirection(), the ThirdPersonController uses the cameraTransform to determine the forward direction along the XZ plane based on where the camera is looking at. In doing so, it zeros out the Y axis and normalizes what's left.
The cameraTransform.LookAt() call I perform in my custom TopDownCamera.js script has the camera looking directly down the Y-axis. So when the ThirdPersonController gets a hold of it and zeros out the Y-axis, I end up with zero forward direction, which causes the XZ movement to go nowhere.
Copying ThirdPersonController.js and altering the code so that:
var forward = cameraTransform.TransformDirection(Vector3.forward);
forward.y = 0;
forward = forward.normalized;
becomes:
forward = Vector3.forward;
fixed the issue.
I've been trying to display an image which has a transparent border as the background to a control.
Unfortunately, the transparent area creates a hole in the parent form as follows:
In the above image, the form has a red background which I'd hoped to see behind my control in the transparent areas.
The code I used is as follows:
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
if (this.Image != null)
{
Graphics g = Graphics.FromImage(this.Image);
ImageAttributes attr = new ImageAttributes();
//set the transparency based on the top left pixel
attr.SetColorKey((this.Image as Bitmap).GetPixel(0, 0), (this.Image as Bitmap).GetPixel(0, 0));
//draw the image using the image attributes.
Rectangle dstRect = new Rectangle(0, 0, this.Image.Width, this.Image.Height);
e.Graphics.DrawImage(this.Image, dstRect, 0, 0, this.Image.Width, this.Image.Height,
GraphicsUnit.Pixel, attr);
}
else
{
base.OnPaint(e);
}
}
protected override void OnPaintBackground(System.Windows.Forms.PaintEventArgs e)
{
//base.OnPaintBackground(e);
}
This class is inherited from a PictureBox because I needed a control which implements OnMouseMove and OnMouseUp Events.
I've been researching most of the day without success testing out different ideas but unfortunately most only work on the full framework and not .Net CF.
Any ideas would be much appreciated.
Ah the joys of CF transparency. I could go on and on about it (and have in my blog and the Project Resistance code I did ages ago).
The gist is this. The child control has to paint it's areas, but first it has to call back up to it's parent (the Form in your case) and tell it to redraw it's background image everywhere except in the child's clipping region and then draw itself on top of that. If that sounds a bit confusing it's because it is.
For example, if you look at Project Resistance, a View (which is just a Control) draws a resistor and bands. It lies in a Form that has an image background, and that background needs to "show through" the transparent areas of the resistor:
So in the drawing code of the resistor it does this:
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
try
{
RECT rect = new RECT(this.Bounds);
// draw the blank
Infrastructure.GraphicTools.DrawTransparentBitmap(e.Graphics, m_blankImage, Bounds,
new Rectangle(0, 0, m_blankImage.Width, m_blankImage.Height));
if (m_bandsImage != null)
{
// draw the bands
Infrastructure.GraphicTools.DrawTransparentBitmap(e.Graphics, m_bandsImage, Bounds,
new Rectangle(0, 0, m_bandsImage.Width, m_bandsImage.Height));
}
}
finally
{
}
if (!Controller.TouchMode)
{
// TODO: draw in the selection arrow
// Controller.SelectedBand
}
}
Which is simple enough. The key is that it calls to it's base OnPaint, which does this:
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
// this assumes we're in a workspace, on MainForm (the whole Parent.Parent thing)
IBackgroundPaintProvider bgPaintProvider = Parent.Parent as IBackgroundPaintProvider;
if (bgPaintProvider != null)
{
Rectangle rcPaint = e.ClipRectangle;
// use the parent, since it's the workspace position in the Form we want,
// not our position in the workspace
rcPaint.Offset(Parent.Left, Parent.Top);
bgPaintProvider.PaintBackground(e.Graphics, e.ClipRectangle, rcPaint);
}
}
You can see it's calling PaintBackground of the containing Form (it's Parent.Parent in this case becuse the Control is actually in a container called a Workspace - you wouldn't need to walk up twice in your case). That draws in the background image in the area you're currently seeing as the "hole"
public void PaintBackground(Graphics g, Rectangle targetRect, Rectangle sourceRect)
{
g.DrawImage(m_bmBuffer, targetRect, sourceRect, GraphicsUnit.Pixel);
}