openCV+C#混合編程的簡單實現

摘要: 以opencv驅動攝像頭, 並處理圖像, 將結果傳遞給C#, 不涉及圖像數據Mat的傳遞. 工程主體爲C#, 封裝opencv爲dll, 進行調用. 開發環境用VS2019



系統簡化: 爲了能夠更具體地描述openCV C++與C#混合編程, 對系統進行簡化. 目標是用簡單的C#窗體程序, 讀取攝像頭, 並顯示原始圖像, 算法處理後, 顯示結果圖像. 不涉及圖像數據傳遞, 也就無法在窗體中重繪圖像, 顯示窗口仍用opencv的HighGUI模塊.


openCV 程序設計

全局變量

由於不傳遞圖像Mat, openCV程序應在作用域內處理圖像, 就需要用到全局變量. 主要定義有:

  • VideoCapture
  • frame

攝像頭初始化

void initCamera(int cameraIndex, double frameWidth, double frameHeight, double fps)
{
    camera.open(cameraIndex);
    if(!camera.isOpened())
    {
        cerr << "Couldn't open camera." << endl;
    }
    camera.set(cv::CAP_PROP_FRAME_WIDTH, frameWidth);      // 寬度
    camera.set(cv::CAP_PROP_FRAME_HEIGHT, frameHeight);    // 高度
    camera.set(cv::CAP_PROP_FPS, fps);                     // 幀率
}

攝像頭高級設置(注意備份, 謹慎更改)

void setCameraParams(double brightness, double contrast, double saturation, double hue, double gain, double exposure)
{
    //打印攝像頭參數
    cout << "\n參數修改前:" << endl;
    printf("brightness = %.2f\n", camera.get(cv::CAP_PROP_BRIGHTNESS));
    printf("contrast = %.2f\n", camera.get(cv::CAP_PROP_CONTRAST));
    printf("saturation = %.2f\n", camera.get(cv::CAP_PROP_SATURATION));
    printf("hue = %.2f\n", camera.get(cv::CAP_PROP_HUE));
    printf("gain = %.2f\n", camera.get(cv::CAP_PROP_GAIN));
    printf("exposure = %.2f\n", camera.get(cv::CAP_PROP_EXPOSURE));
    // 修改攝像頭參數
    camera.set(cv::CAP_PROP_BRIGHTNESS, brightness);        // 亮度
    camera.set(cv::CAP_PROP_CONTRAST, contrast);            // 對比度
    camera.set(cv::CAP_PROP_SATURATION, saturation);        // 飽和度
    camera.set(cv::CAP_PROP_HUE, hue);                      // 色調
    camera.set(cv::CAP_PROP_GAIN, gain);                    // 增益
    camera.set(cv::CAP_PROP_EXPOSURE, exposure);            // 曝光度
    //打印攝像頭參數
    cout << "\n參數修改後:" << endl;
    printf("brightness = %.2f\n", camera.get(cv::CAP_PROP_BRIGHTNESS));
    printf("contrast = %.2f\n", camera.get(cv::CAP_PROP_CONTRAST));
    printf("saturation = %.2f\n", camera.get(cv::CAP_PROP_SATURATION));
    printf("hue = %.2f\n", camera.get(cv::CAP_PROP_HUE));
    printf("gain = %.2f\n", camera.get(cv::CAP_PROP_GAIN));
    printf("exposure = %.2f\n", camera.get(cv::CAP_PROP_EXPOSURE));
}

讀取幀並顯示

void readFrame()
{
    camera >> frame;
    cv::imshow("camera", frame);
    cv::waitKey(1);
}

圖像處理

void processingImage()
{
    cv::cvtColor(frame, frame, cv::COLOR_BGR2GRAY);
    cv::Canny(frame, frame, 100, 200);
    cv::imshow("processor", frame);
    cv::waitKey(1);
}

關閉顯示

void closeCamera(string winName)
{
    if(winName == "camera")
        cv::destroyWindow("camera");
    else if(winName == "processor")
        cv::destroyWindow("processor");
    else
        ;// do nothing
}

頭文件聲明

由於是導出爲dll, 需要特別的語法支持

extern "C" __declspec(dllexport) void initCamera(int cameraIndex, double frameWidth, double frameHeight, double fps);
extern "C" __declspec(dllexport) void readFrame();
extern "C" __declspec(dllexport) void processingImage();
extern "C" __declspec(dllexport) void closeCamera(string winName);

生成dll

  • 更改項目屬性, 設置配置類型爲 dll, 如圖. 然後右鍵生成Ctrl+Shift+B, 即可在輸出目錄看到dll文件
  • 由於該dll依賴於opencv庫, 所以還應包含opencv的dll. 如果是獨立模塊, 則需包括所有調用的; 如果是集合成了world文件, 就只需包含"opencv_world411.dll"即可. 參見博客: 封裝opencv的函數成dll,獨立調用

在這裏插入圖片描述

C#窗體程序

建立窗體項目

注意不要選錯類型, 具體步驟可參考微軟官方教程: Create a Windows Forms app in Visual Studio with C#
在這裏插入圖片描述

導入dll

如同導出聲明一樣, 需要特定的導入格式

// 初始化攝像頭
[DllImport("ImageTracker.dll", EntryPoint = "initCamera", CallingConvention = CallingConvention.Cdecl)]
public static extern void initCamera(int cameraIndex, double frameWidth, double frameHeight, double fps);

有博客提到, 用reference的方法添加dll, 未嘗試. Visual Studio 在 C# 項目添加動態鏈接庫 dll

調用dll

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace Camera
{
    public partial class FormCamera : Form
    {
        // 初始化攝像頭
        [DllImport("ImageProcessing.dll", EntryPoint = "initCamera", CallingConvention = CallingConvention.Cdecl)]
        public static extern void initCamera(int cameraIndex, double frameWidth, double frameHeight, double fps);            
            
        // 讀取圖像並顯示
        [DllImport("ImageProcessing.dll", EntryPoint = "readFrame", CallingConvention = CallingConvention.Cdecl)]
        public static extern void readFrame();
        
        // 處理圖像並顯示
        [DllImport("ImageProcessing.dll", EntryPoint = "processingImage", CallingConvention = CallingConvention.Cdecl)]
        public  static extern void processingImage();

        // 關閉窗口
        [DllImport("ImageProcessing.dll", EntryPoint = "closeCamera", CallingConvention = CallingConvention.Cdecl)]
        public static extern void closeCamera(string winName);


        public FormCamera()
        {
            InitializeComponent();
            ImageProcessing();
        }


        private void ImageProcessing()
        {
            initCamera(0, -1, -1, -1);
            for(int i = 0; i <= 10000; i++)
            {
                readFrame();
                processingImage();
            }
            closeCamera("camera");
            closeCamera("processor");
        }
    }
}

其中遇到的問題

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章