How to mask certain areas of the video image in C#

This description demonstrates what does masking certain areas of the video image means and how you can use it in different ways. If you mix the masking with a motion detection technology, you can create either a focused security monitoring system or an analyzing system (see later in the Tutorial 9). To implement this functionality, you need to have Ozeki Camera SDK installed, and a reference to OzekiSDK.dll should be added to your Visual Studio project.

What is a mask?

For Photoshop and Flash users can be familiar the mask therminology. Masking itself means creating a filter that hides or reveals different areas of the image. In a nutshell it uses a bitmap, which marks that a pixel of the image is invisible (black) or visible (white) (Figure 1). A mask item can be e.g. a filled shape, a type object or an instance of a graphic symbol.

image and mask
Figure 1 - Image and its mask

Why is it good for us?

In case of the image of the camera we can limit or lower the range that the user sees. If we combine masking with motion detection we can create a response or counter system with ease. Here are three examples.

The first one is for security reasons. There is a museum, which exhibits a 1 million dollar diamond. It has a great and expensive security system, but temporarily it is down with the exception of the remote camera, which sees the hall, the crowd and other displayed pieces. If you add motion detection and a mask, which limits the motion detection to the diamond, then you can create a second alarm system (in case of the first line is down).

entrance masking
Figure 2 - Entrance masking

The second example is for analysis. There is an office and you observe the entrance because you want to know how many people get in (Figure 2) a day. With masking you can reduce the observed area and you can focus onto the entrance hereby turning the motion detector to a counter device.

The third example is for privacy reasons. A celling camera of a shop unfortunately observes the fitting room too. With masking you can mask the top of the fitting room without moivng the celling camera to an other position.

Windows forms version

MainForm.cs

using System;
using System.Windows.Forms;
using System.Drawing;
using Ozeki.Camera;
using Ozeki.Media;
using Ozeki.Vision;

namespace ImageMask_WF
{
    public partial class MainForm : Form
    {
        private OzekiCamera _camera;
        private MediaConnector _connector;
        private CameraURLBuilderWF _myCameraUrlBuilder;
        private ImageMask _imageMask;
        private DrawingImageProvider _imageProvider;

        public MainForm()
        {
            InitializeComponent();
        }

        void MainForm_Load(object sender, EventArgs e)
        {
            Init();

            SetVideoViewers();
        }

        void Init()
        {
            _myCameraUrlBuilder = new CameraURLBuilderWF();
            _connector = new MediaConnector();
            _imageProvider = new DrawingImageProvider();

            _imageMask = new ImageMask();

        }

        void SetVideoViewers()
        {
            OriginalViewer.SetImageProvider(_imageProvider);
        }

        void ConnectCam()
        {
            _connector.Connect(_camera.VideoChannel, _imageMask);

            _connector.Connect(_imageMask, _imageProvider);
        }

        void Start()
        {
            OriginalViewer.Start();

            _camera.Start();
            _imageMask.Start();
        }

        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, _imageMask);
                _connector.Disconnect(_imageMask, _imageProvider);
                _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, _imageMask);
            _connector.Disconnect(_imageMask, _imageProvider);

            _camera = null;
        }

        private void btn_browse_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog1 = new OpenFileDialog();
            DialogResult result = openFileDialog1.ShowDialog();
            if (result == DialogResult.OK)
            {
                string filePath = openFileDialog1.FileName;

                tb_imageurl.Text = openFileDialog1.SafeFileName;

                button_Compose.Enabled = true;

                var img = Image.FromFile(openFileDialog1.FileName);

                _imageMask.MaskImage = img;

                _imageMask.Mask = MaskOption.Background;
            }
   
        }

        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            
            if (this.combo_ground.SelectedItem  == "BackGround")
               _imageMask.Mask = MaskOption.Background;
           else _imageMask.Mask = MaskOption.Foreground;
        }

    }
}

		
Code 1 - Masking video example in C#

Please note that none of the cancel and disconnect methods are included in the example because of the demonstrating intent and briefness of the article.

GUI

Figure 1 - The graphical user interface of your application

Below you can find the code that belongs to the interface of the previously presented application. With the help of this section your Windows Forms Application will be able to work properly.

MainForm.Designer.cs

namespace ImageMask_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.tb_imageurl = new System.Windows.Forms.TextBox();
            this.label4 = new System.Windows.Forms.Label();
            this.groupBox2 = new System.Windows.Forms.GroupBox();
            this.combo_ground = new System.Windows.Forms.ComboBox();
            this.btn_browse = new System.Windows.Forms.Button();
            this.OriginalViewer = 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.tb_imageurl.Location = new System.Drawing.Point(50, 18);
            this.tb_imageurl.Name = "tb_imageurl";
            this.tb_imageurl.Size = new System.Drawing.Size(180, 20);
            this.tb_imageurl.TabIndex = 4;

            this.label4.AutoSize = true;
            this.label4.Location = new System.Drawing.Point(6, 21);
            this.label4.Name = "label4";
            this.label4.Size = new System.Drawing.Size(39, 13);
            this.label4.TabIndex = 11;
            this.label4.Text = "Image:";

            this.groupBox2.Controls.Add(this.combo_ground);
            this.groupBox2.Controls.Add(this.btn_browse);
            this.groupBox2.Controls.Add(this.label4);
            this.groupBox2.Controls.Add(this.tb_imageurl);
            this.groupBox2.Location = new System.Drawing.Point(12, 107);
            this.groupBox2.Name = "groupBox2";
            this.groupBox2.Size = new System.Drawing.Size(328, 89);
            this.groupBox2.TabIndex = 13;
            this.groupBox2.TabStop = false;
            this.groupBox2.Text = "Settings";

            this.combo_ground.FormattingEnabled = true;
            this.combo_ground.Items.AddRange(new object[] {
            "BackGround",
            "ForeGround"});
            this.combo_ground.SelectedItem = "BackGround";
            this.combo_ground.Location = new System.Drawing.Point(6, 53);
            this.combo_ground.Name = "combo_ground";
            this.combo_ground.Size = new System.Drawing.Size(121, 21);
            this.combo_ground.TabIndex = 20;
            this.combo_ground.SelectedIndexChanged += new System.EventHandler(this.comboBox1_SelectedIndexChanged);

            this.btn_browse.Location = new System.Drawing.Point(248, 16);
            this.btn_browse.Name = "btn_browse";
            this.btn_browse.Size = new System.Drawing.Size(68, 23);
            this.btn_browse.TabIndex = 19;
            this.btn_browse.Text = "Borwse";
            this.btn_browse.UseVisualStyleBackColor = true;
            this.btn_browse.Click += new System.EventHandler(this.btn_browse_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(12, 202);
            this.OriginalViewer.Name = "OriginalViewer";
            this.OriginalViewer.RotateAngle = 0;
            this.OriginalViewer.Size = new System.Drawing.Size(328, 240);
            this.OriginalViewer.TabIndex = 17;
            this.OriginalViewer.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.Enabled = false;
            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(350, 450);
            this.Controls.Add(this.groupBox5);
            this.Controls.Add(this.OriginalViewer);
            this.Controls.Add(this.groupBox2);
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
            this.MaximizeBox = false;
            this.Name = "MainForm";
            this.Text = "Image mask";
            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);

        }

        #endregion

        private System.Windows.Forms.TextBox tb_imageurl;
        private System.Windows.Forms.Label label4;
        private System.Windows.Forms.GroupBox groupBox2;
        private System.Windows.Forms.Button btn_browse;
        private Ozeki.Media.VideoViewerWF OriginalViewer;
        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;
        private System.Windows.Forms.ComboBox combo_ground;
    }
}
		
Code 2 - GUI example in C#

Related Pages

FAQ

Below you can find the answers for the most frequently asked questions related to this topic:

  1. Why I need to mask instead of zooming?

    • Because some camera doesn't support zooming.
    • If your camera can zoom, but you want to observe the surrounding enviroment too, not just the e.g. certain shelf, than it is advisable to choose the masking solution.

More information