How to achieve corner detection in C#
In the following guide you will find the needed information on how to implement corner detection with your C# camera application using the Ozeki Camera SDK. In order to make this example work, Ozeki Camera SDK has to be installed and a reference to OzekiSDK.dll has to be added to your Visual Studio project.
Important: you should study this article in order to find out how to setup your Windows Forms Application correctly.
Getting started
To get started it is recomended to Download and Install the latest version of Ozeki Camera SDK. After installation you can find the example code discussed in this page with full source code in the following location on your harddisk:
Download Ozeki Camera SDK: | https://www.camera-sdk.com/https://camera-sdk.com/p_6513-download-onvif-ozeki-camera-sdk-for-c-sharp.html |
Windows forms version: | C:\Users\user\Documents\Ozeki\Ozeki SDK\Examples\Camera\04_ComputerVision\04_CornerDetection\CornerDetection |
To compile this example you will need Microsoft Visual Studio installed on your computer.
Corporate use of corner detection
Corner detection can be used to detect corners on an image, which is an important part of image analysis. Corner detection can be extremely useful in the field of construction. To mention another example: corner detection can be also used in land market. If you wish to analyse the images which show different buildings you can benefit from this function.
Corner detection can be used with several applications. It can be a great help in quality motion detection, video tracking, image mosaicing, panorama stitching,image registration, in 3D modelling and object recognition.
Implement corner detection in C#
Some computer vision possibilities which are supplied by the SDK require an extra ToolKit. This ToolKit is the OzekiComputerVision.dll to which a reference has to be added in the project, just like in the case of the OzekiSDK.dll. This dll is responsible for the algorithms and tools which are necessary for the CV (Computer Vision) actions.
Corner detection
For detecting corners we can use the ICornerDetector object of the Ozeki Camera SDK. After an instance has been created with the help of the static ImageProcesserFactory class we can detect on frames and on video as well.
In the case of frames the output image can be created by the Process() method of the instance. In the case of videos we have to use the ImageProcesserHandler mediahandler.
ImageProcesserHandler:
This is a mediahandler from a VideoHandler class (so it is VideoReceiver and VideoSender at the same time) which means that the input can be a VideoSender (for example WebCamera) and the output can also be created for a VideoReceiver. These connections can be achieved with the help of an instance of the MediaConnector class in the SDK.
No actions are executed on the input frames they are simply forwarded by default. However, the object which implement the IImageProcesser interface (for example the ICornerDetector) can be added with the help of the AddProcesser() method. More instance can be added which implement IImageProcesser, they will run one after the other using the image which is before them in the list.
Global Variables
- OzekiCamera _camera;
- MediaConnector _connector;
- CameraURLBuilderWF _myCameraUrlBuilder;
- ImageProcesserHandler _imageProcesserHandler;
- ICornerDetector _cornerDetector;
- FrameCapture _frameCapture;
- VideoViewerWF instances
- DrawingImageProvider instances
Webcamera instance, with the help of this we can get the images
Using this we can connect the mediahandlers
Make access to all avaiable cameras, which you can select from afterwards.
This is a Mediahandler, which runs the IImageProcesser interface (this processes the images) on the incoming video
This is an image processer interface which can detect corners, this implements the IImageProcesser interface
With the help of this mediahandler we can determine the frequency of processing
This is a GUI tool which is responsible for displaying the video for Windows Forms applications
Mediahandler which prepares the image which is sent by the mediahandlers from the VideoSender class for the VideoViewerWF instances.
Methods
- Init()
- SetVideoViewers()
- InvokeGUIThread()
- InitDetectorFields()
- ConnectCam()
- Start()
The initialization of the global variables is the task of the Init() method. The instance of the FrameCapture mediahandler are set here and the ICornerDetector instance is also created here with the help of the ImageProcesserFactory. This also can be added to the ImageProcesserHandlerinstance. The processing of all images is indicated by the DetectionOccured event of the ICornerDetector instance. Here we can subscribe to this event.
The SetVideoViewer() creates and initialize the objects which are responsible for the displaying of the video. It defines the VideoViewerWF instances, configures their properties and assigns the appropiate DrawingImageProvider instances. Furthermore, the SetVideoViewers() adds these instances to the GUI.
This method handles the GUI thread. It performs a specific method on the GUI thread in asynchronous mode.
This method fills the TextBox-es which can be found on the GUI with the actual settings of the ICornerDetector instance using the InvokeGUIThread() helper method.
This method connects the appropiate mediahandler instances with the help of the MediaConnector instance. One of the ImageProvider object recives the original image of the webcamera and the other object receives the processed image.
After the initializations the mediahandlers can start to operate which is the responsibility of the Start()method
Configurations
- BlockSize: the size of the block which does the averaging. With the help of this we can calculate eigen values and eigen vectors and after this, we can detect corners
- Epsilon: after the reaching of a certain accuracy the corner detection can end on a given image/frame
- MaxDetectedObjects: this is the maximum number of matches/results with which the DetectionOccured event returns
- MaxIteration: after the reaching of a certain iteration the corner detection can end on a given image/frame
- MinDistance: the minimum distance between two corners which can be detected
- QualityLevel: this is a multiplier to the eigen maxmin. With the help of this we can determine a minimum quality level
- SearchWindiwSize: the half of the size of the Search Window
- ZeroZoneSize: this size is the half of the dead area in the search zone. In this area the summation is not done. It can be useful if we wish to exclude singularities
PostProcess configurations
After the detection we can configure the behavior of the output image and what changes are required. Examples for this kind of configurations:
- ShowImage: declares whether the original image should be shown or only the detected shapes should be seen with black backround. It is important if there are more image processer algorithm are running after each other
- DrawColor: the color of the selection of the detected object can be provided here
- DrawThickness: the thickness of the selection of the detected onject can be provided here
- DrawSize: the size of the cross which indicates the corners
Detection
After all image/frame processing a DetectionOccurred event is popped up. In the arguments of this event you can find the list of detected corners where the centers/radius and area of the corners can be queried.
C# code example for corner detection
Windows Form |
Windows forms version
MainForm.cs
using System; using System.Windows.Forms; using Ozeki.Camera; using Ozeki.Media; using Ozeki.Vision; namespace CornerDetection_WF { public partial class MainForm : Form { private OzekiCamera _camera; private MediaConnector _connector; private CameraURLBuilderWF _myCameraUrlBuilder; private ImageProcesserHandler _imageProcesserHandler; private ICornerDetector _cornerDetector; private FrameCapture _frameCapture; private DrawingImageProvider _originalImageProvider; private DrawingImageProvider _processedImageProvider; public MainForm() { InitializeComponent(); } void MainForm_Load(object sender, EventArgs e) { Init(); SetVideoViewers(); InitDetectorFields(); } void Init() { _frameCapture = new FrameCapture(); _frameCapture.SetInterval(5); _myCameraUrlBuilder = new CameraURLBuilderWF(); _connector = new MediaConnector(); _originalImageProvider = new DrawingImageProvider(); _processedImageProvider = new DrawingImageProvider(); _cornerDetector = ImageProcesserFactory.CreateCornerDetector(); _imageProcesserHandler = new ImageProcesserHandler(); _imageProcesserHandler.AddProcesser(_cornerDetector); } void SetVideoViewers() { OriginalViewer.SetImageProvider(_originalImageProvider); ProcessedViewer.SetImageProvider(_processedImageProvider); } void InitDetectorFields() { InvokeGuiThread(() => { tb_blocksize.Text = _cornerDetector.BlockSize.ToString(); tb_mindistance.Text = _cornerDetector.MinDistance.ToString(); }); } void ConnectCam() { _connector.Connect(_camera.VideoChannel, _originalImageProvider); _connector.Connect(_camera.VideoChannel, _frameCapture); _connector.Connect(_frameCapture, _imageProcesserHandler); _connector.Connect(_imageProcesserHandler, _processedImageProvider); } void Start() { OriginalViewer.Start(); ProcessedViewer.Start(); _frameCapture.Start(); _camera.Start(); _imageProcesserHandler.Start(); } void btn_HighlightSet_Click(object sender, EventArgs e) { InvokeGuiThread(() => { _cornerDetector.BlockSize = int.Parse(tb_blocksize.Text); _cornerDetector.MinDistance = int.Parse(tb_mindistance.Text); }); } void InvokeGuiThread(Action action) { BeginInvoke(action); } private void button_Compose_Click(object sender, EventArgs e) { var result = _myCameraUrlBuilder.ShowDialog(); if (result != DialogResult.OK) return; tb_cameraUrl.Text = _myCameraUrlBuilder.CameraURL; button_Connect.Enabled = true; } private void button_Connect_Click(object sender, EventArgs e) { if (_camera != null) { _camera.CameraStateChanged -= _camera_CameraStateChanged; _camera.Disconnect(); _connector.Disconnect(_camera.VideoChannel, _processedImageProvider); _connector.Disconnect(_camera.VideoChannel, _originalImageProvider); _camera.Dispose(); _camera = null; } _camera = new OzekiCamera(_myCameraUrlBuilder.CameraURL); _camera.CameraStateChanged += _camera_CameraStateChanged; button_Connect.Enabled = false; ConnectCam(); Start(); } private void _camera_CameraStateChanged(object sender, CameraStateEventArgs e) { InvokeGuiThread(() => { if (e.State == CameraState.Streaming) button_Disconnect.Enabled = true; if (e.State == CameraState.Disconnected) { button_Connect.Enabled = true; button_Disconnect.Enabled = false; } }); InvokeGuiThread(() => { stateLabel.Text = e.State.ToString(); }); } private void button_Disconnect_Click(object sender, EventArgs e) { if (_camera == null) return; _camera.Disconnect(); _connector.Disconnect(_camera.VideoChannel, _originalImageProvider); _connector.Disconnect(_camera.VideoChannel, _processedImageProvider); _camera = null; } } }
GUI
After you have downloaded the Ozeki Camera SDK software you can find the GUI code in the Example folder.
MainForm.Designer.cs
namespace CornerDetection_WF { partial class MainForm { private System.ComponentModel.IContainer components = null; protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } #region Windows Form Designer generated code private void InitializeComponent() { this.label1 = new System.Windows.Forms.Label(); this.label2 = new System.Windows.Forms.Label(); this.tb_blocksize = new System.Windows.Forms.TextBox(); this.tb_mindistance = new System.Windows.Forms.TextBox(); this.label5 = new System.Windows.Forms.Label(); this.label4 = new System.Windows.Forms.Label(); this.groupBox2 = new System.Windows.Forms.GroupBox(); this.btn_HighlightSet = new System.Windows.Forms.Button(); this.OriginalViewer = new Ozeki.Media.VideoViewerWF(); this.ProcessedViewer = new Ozeki.Media.VideoViewerWF(); this.groupBox5 = new System.Windows.Forms.GroupBox(); this.stateLabel = new System.Windows.Forms.Label(); this.label14 = new System.Windows.Forms.Label(); this.button_Connect = new System.Windows.Forms.Button(); this.button_Disconnect = new System.Windows.Forms.Button(); this.tb_cameraUrl = new System.Windows.Forms.TextBox(); this.label13 = new System.Windows.Forms.Label(); this.button_Compose = new System.Windows.Forms.Button(); this.groupBox2.SuspendLayout(); this.groupBox5.SuspendLayout(); this.SuspendLayout(); this.label1.AutoSize = true; this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(238))); this.label1.Location = new System.Drawing.Point(7, 357); this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(87, 13); this.label1.TabIndex = 0; this.label1.Text = "Original image"; this.label2.AutoSize = true; this.label2.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(238))); this.label2.Location = new System.Drawing.Point(348, 357); this.label2.Name = "label2"; this.label2.Size = new System.Drawing.Size(103, 13); this.label2.TabIndex = 1; this.label2.Text = "Processed image"; this.tb_blocksize.Location = new System.Drawing.Point(155, 13); this.tb_blocksize.Name = "tb_blocksize"; this.tb_blocksize.Size = new System.Drawing.Size(87, 20); this.tb_blocksize.TabIndex = 4; this.tb_mindistance.Location = new System.Drawing.Point(155, 41); this.tb_mindistance.Name = "tb_mindistance"; this.tb_mindistance.Size = new System.Drawing.Size(87, 20); this.tb_mindistance.TabIndex = 5; this.label5.AutoSize = true; this.label5.Location = new System.Drawing.Point(6, 44); this.label5.Name = "label5"; this.label5.Size = new System.Drawing.Size(93, 13); this.label5.TabIndex = 12; this.label5.Text = "Minimum Distance"; this.label4.AutoSize = true; this.label4.Location = new System.Drawing.Point(6, 19); this.label4.Name = "label4"; this.label4.Size = new System.Drawing.Size(60, 13); this.label4.TabIndex = 11; this.label4.Text = "Block Size:"; this.groupBox2.Controls.Add(this.label5); this.groupBox2.Controls.Add(this.tb_mindistance); this.groupBox2.Controls.Add(this.btn_HighlightSet); this.groupBox2.Controls.Add(this.label4); this.groupBox2.Controls.Add(this.tb_blocksize); this.groupBox2.Location = new System.Drawing.Point(351, 12); this.groupBox2.Name = "groupBox2"; this.groupBox2.Size = new System.Drawing.Size(322, 89); this.groupBox2.TabIndex = 13; this.groupBox2.TabStop = false; this.groupBox2.Text = "Settings"; this.btn_HighlightSet.Location = new System.Drawing.Point(258, 60); this.btn_HighlightSet.Name = "btn_HighlightSet"; this.btn_HighlightSet.Size = new System.Drawing.Size(58, 23); this.btn_HighlightSet.TabIndex = 19; this.btn_HighlightSet.Text = "Set"; this.btn_HighlightSet.UseVisualStyleBackColor = true; this.btn_HighlightSet.Click += new System.EventHandler(this.btn_HighlightSet_Click); this.OriginalViewer.BackColor = System.Drawing.Color.Black; this.OriginalViewer.FlipMode = Ozeki.Media.FlipMode.None; this.OriginalViewer.FrameStretch = Ozeki.Media.FrameStretch.Uniform; this.OriginalViewer.FullScreenEnabled = true; this.OriginalViewer.Location = new System.Drawing.Point(10, 110); this.OriginalViewer.Name = "OriginalViewer"; this.OriginalViewer.RotateAngle = 0; this.OriginalViewer.Size = new System.Drawing.Size(330, 240); this.OriginalViewer.TabIndex = 17; this.OriginalViewer.Text = "videoViewerWF1"; this.ProcessedViewer.BackColor = System.Drawing.Color.Black; this.ProcessedViewer.FlipMode = Ozeki.Media.FlipMode.None; this.ProcessedViewer.FrameStretch = Ozeki.Media.FrameStretch.Uniform; this.ProcessedViewer.FullScreenEnabled = true; this.ProcessedViewer.Location = new System.Drawing.Point(351, 110); this.ProcessedViewer.Name = "ProcessedViewer"; this.ProcessedViewer.RotateAngle = 0; this.ProcessedViewer.Size = new System.Drawing.Size(320, 240); this.ProcessedViewer.TabIndex = 18; this.ProcessedViewer.Text = "videoViewerWF1"; this.groupBox5.Controls.Add(this.stateLabel); this.groupBox5.Controls.Add(this.label14); this.groupBox5.Controls.Add(this.button_Connect); this.groupBox5.Controls.Add(this.button_Disconnect); this.groupBox5.Controls.Add(this.tb_cameraUrl); this.groupBox5.Controls.Add(this.label13); this.groupBox5.Controls.Add(this.button_Compose); this.groupBox5.Location = new System.Drawing.Point(12, 12); this.groupBox5.Name = "groupBox5"; this.groupBox5.Size = new System.Drawing.Size(328, 89); this.groupBox5.TabIndex = 21; this.groupBox5.TabStop = false; this.groupBox5.Text = "Connect"; this.stateLabel.AutoSize = true; this.stateLabel.Location = new System.Drawing.Point(80, 72); this.stateLabel.Name = "stateLabel"; this.stateLabel.Size = new System.Drawing.Size(0, 13); this.stateLabel.TabIndex = 24; this.label14.AutoSize = true; this.label14.Location = new System.Drawing.Point(39, 72); this.label14.Name = "label14"; this.label14.Size = new System.Drawing.Size(35, 13); this.label14.TabIndex = 23; this.label14.Text = "State:"; this.button_Connect.Enabled = false; this.button_Connect.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238))); this.button_Connect.ForeColor = System.Drawing.Color.Black; this.button_Connect.Location = new System.Drawing.Point(83, 39); this.button_Connect.Name = "button_Connect"; this.button_Connect.Size = new System.Drawing.Size(69, 23); this.button_Connect.TabIndex = 18; this.button_Connect.Text = "Connect"; this.button_Connect.UseVisualStyleBackColor = true; this.button_Connect.Click += new System.EventHandler(this.button_Connect_Click); this.button_Disconnect.Enabled = false; this.button_Disconnect.Location = new System.Drawing.Point(180, 39); this.button_Disconnect.Name = "button_Disconnect"; this.button_Disconnect.Size = new System.Drawing.Size(69, 23); this.button_Disconnect.TabIndex = 22; this.button_Disconnect.Text = "Disconnect"; this.button_Disconnect.UseVisualStyleBackColor = true; this.button_Disconnect.Click += new System.EventHandler(this.button_Disconnect_Click); this.tb_cameraUrl.Location = new System.Drawing.Point(83, 13); this.tb_cameraUrl.Name = "tb_cameraUrl"; this.tb_cameraUrl.ReadOnly = true; this.tb_cameraUrl.Size = new System.Drawing.Size(166, 20); this.tb_cameraUrl.TabIndex = 21; this.label13.AutoSize = true; this.label13.Location = new System.Drawing.Point(6, 16); this.label13.Name = "label13"; this.label13.Size = new System.Drawing.Size(71, 13); this.label13.TabIndex = 20; this.label13.Text = "Camera URL:"; this.button_Compose.Location = new System.Drawing.Point(253, 11); this.button_Compose.Name = "button_Compose"; this.button_Compose.Size = new System.Drawing.Size(69, 23); this.button_Compose.TabIndex = 19; this.button_Compose.Text = "Compose"; this.button_Compose.UseVisualStyleBackColor = true; this.button_Compose.Click += new System.EventHandler(this.button_Compose_Click); this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(686, 386); this.Controls.Add(this.groupBox5); this.Controls.Add(this.ProcessedViewer); this.Controls.Add(this.OriginalViewer); this.Controls.Add(this.groupBox2); this.Controls.Add(this.label2); this.Controls.Add(this.label1); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; this.MaximizeBox = false; this.Name = "MainForm"; this.Text = "Corner Detection"; this.Load += new System.EventHandler(this.MainForm_Load); this.groupBox2.ResumeLayout(false); this.groupBox2.PerformLayout(); this.groupBox5.ResumeLayout(false); this.groupBox5.PerformLayout(); this.ResumeLayout(false); this.PerformLayout(); } #endregion private System.Windows.Forms.Label label1; private System.Windows.Forms.Label label2; private System.Windows.Forms.TextBox tb_blocksize; private System.Windows.Forms.TextBox tb_mindistance; private System.Windows.Forms.Label label5; private System.Windows.Forms.Label label4; private System.Windows.Forms.GroupBox groupBox2; private System.Windows.Forms.Button btn_HighlightSet; private Ozeki.Media.VideoViewerWF OriginalViewer; private Ozeki.Media.VideoViewerWF ProcessedViewer; private System.Windows.Forms.GroupBox groupBox5; private System.Windows.Forms.Button button_Connect; private System.Windows.Forms.Button button_Disconnect; private System.Windows.Forms.TextBox tb_cameraUrl; private System.Windows.Forms.Label label13; private System.Windows.Forms.Button button_Compose; private System.Windows.Forms.Label stateLabel; private System.Windows.Forms.Label label14; } }
Conclusion
With this guide you will be able to implement corner detection successfully with your C# camera application using the Ozeki Camera SDK. On this webpage you can find detailed information , exmaples and codes for achieving your aims on the field of corner detection.
Related pages
- How to download Ozeki Camera SDK
- How to implement line detection in C#
- How to implement edge detection in C#
- How to implement circle detection in C#
FAQ
Below you can find the answers for the most frequently asked questions related to this topic:
-
I have not managed to build the solution. How to solve it?
- Please set the Target framework property of the project to .NET 4.0.
- You should add the OzekiSDK.dll to the references of the solution.
- Please import the missing classes.
-
What are the hardware requirements?
- 1 GHz or faster processor
- 1GB RAM (32-bit) || 2GB RAM (64-bit)
-
Which OS are supported? Does it work with Windows 8?
Yes,the SDK works with Windows 8. The following Operating Systems are supported:.
- Microsoft Windows XP
- Microsoft Windows Vista
- Microsoft Windows 7
- Microsoft Windows 8
- Microsoft Windows 10
- Microsoft Windows Server 2003
- Microsoft Windows Server 2008
More information
- How to implement circle detection in C#
- How to accomplish corner detection in C#
- How to detect, filter and track colors in C#
- How to implement edge detection in C#
- How to implement face detection in C#
- How to accomplish line detection in C#
- How to implement Motion detector in C#
- How to implement ObjectTracking in C#
- How to create Rectangle Detector in C#
- How to implement SURF function in C#
- How to measure the width of an object in C#