C#使用OpenCV

  • 一、OpenCV的安装
  • 1、需要安装两个拓展包:OpenCvSharp4和OpenCvSharp4.runtime.win
  • 2、出错
  • 二、C#使用OpenCV的一些代码
  • 1、需要加头文件
  • 2、读取图片
  • 3、定义一个没有初始化的图片作为复制
  • 4、灰度化
  • 5、高斯模糊和size数据格式的定义
  • 6、二值化
  • 7、开闭运算
  • 8、FindContours查找轮廓和contours参数的定义和操作
  • 9、Rect和Size格式的定义
  • 10、 resize函数
  • 在图片上画矩形框
  • 在图片上画直线
  • 不错的链接
  • 一些完成的代码
  • 1、帧差法判断当前帧有没有物体


一、OpenCV的安装

1、需要安装两个拓展包:OpenCvSharp4和OpenCvSharp4.runtime.win

在VS中,通过其工具中自带的扩展包就安装了,不需要像C++中用opencv那样,还要配置属性。

安装步骤:工具——》Nuget包管理器——》管理解决方案的Nuget包。直接搜索opencvsharp。

opencvsharp 热点区域 opencv connect_Image

2、出错

c# OpenCvSharp4 无法加载 DLLOpenCvSharpExtern:找不到指定的模块

opencvsharp 热点区域 opencv connect_Image_02


这句话的意思是,这个包只包含内部算法的核心部分,因此,使用时还需添加OPENCV4.runtime

opencvsharp 热点区域 opencv connect_c#_03


安装这个拓展包就可以使用了。

二、C#使用OpenCV的一些代码

1、需要加头文件

using OpenCvSharp;   //为了使用opencv
using Point = OpenCvSharp.Point;   //为了确定我们使用的point是opencv的而不是draw的

2、读取图片

Mat img1 = new Mat("F:\\all_truck\\truck_3.jpg", ImreadModes.Color);
Cv2.ImShow("win1", img1);
Cv2.WaitKey(0);

3、定义一个没有初始化的图片作为复制

//pBkImage是已经赋值了的图片,将这个图片复制到pBkImage_copy中
Mat pBkImage_copy = new Mat();
pBkImage.CopyTo(pBkImage_copy);

4、灰度化

CvtColor(InputArray src, OutputArray dst, ColorConversionCodes code, int dstCn = 0)
第一个参数 src 是原图像。
第二个参数 dst 是转换后的图像。
第三个参数 code 转换成什么格式的图片。
第四个参数 dstcn 为通道数。

这里第三个参数的编码格式,更快捷的方式是首先输入ColorConversionCodes.,然后按照c#或者python的代码中的BGR2GRAY直接输入就可以了,这里会自动跳出合适的选项。

opencvsharp 热点区域 opencv connect_OpenCV_04

Cv2.CvtColor(pBkImage_copy, pBkImage_gray, ColorConversionCodes.BGR2GRAY);

5、高斯模糊和size数据格式的定义

下面是size数据格式的定义

OpenCvSharp.Size up = new Size(1000, 500);

高斯模糊:难点是size格式的定义,这里使用了:new OpenCvSharp.Size(11,11)

Cv2.GaussianBlur(pBkImage_gray, pBkImage_gauss, new OpenCvSharp.Size(11,11), 4, 4);

6、二值化

难点:ThresholdTypes.Binary

Cv2.Threshold(Image_diff, Image_threshold, 60, 255, ThresholdTypes.Binary);

7、开闭运算

//自定义核,进行开、闭运算
Mat element = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(5, 5));
Cv2.MorphologyEx(Image_threshold, Image_morp, MorphTypes.Open, element);
Cv2.MorphologyEx(Image_morp, Image_morp, MorphTypes.Close, element);

8、FindContours查找轮廓和contours参数的定义和操作

C#中OpenCVSharp实现轮廓检测 这个链接的示例非常好
难点:contours,hierarchy格式的定义。contours.Length和Cv2.ContourArea(contours[i]);函数的使用

Point[][] contours;
HierarchyIndex[] hierarchy;
Cv2.FindContours(Image_morp, out contours, out hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxSimple, new Point(0, 0));
if (contours.Length == 0)
{
    System.Diagnostics.Debug.WriteLine("没有任何前景"); 
    return 0;
}
double image_area = 0.0;
for (int i = 0; i < contours.Length; i++)
{
    image_area += Cv2.ContourArea(contours[i]);
}

9、Rect和Size格式的定义

OpenCvSharp.Size up = new Size(1000, 500);
Rect rect =new Rect(x, y, width, height);
Rect rect =new OpenCvSharp.Rect(x, y, width, height);

10、 resize函数

//这个代码可以成功运行
Cv2.Resize(pFrImage_mid, pFrImage_resize, new OpenCvSharp.Size(image_size[0], image_size[1]));       


//这个代码没法成功运行,因为后面的InterpolationFlags.Linear显示无法转换为double,到最后都没有解决
Cv2.Resize(pFrImage_mid, pFrImage_resize, new OpenCvSharp.Size(image_size[0], image_size[1]), InterpolationFlags.Linear);

在图片上画矩形框

Mat img1 = new Mat("F:\\all_truck\\truck_3.jpg", ImreadModes.Color);
Cv2.ImShow("win1", img1);
OpenCvSharp.Point truck_a = new Point(100, 100);
OpenCvSharp.Point truck_b = new Point(300, 300);
Cv2.Rectangle(img1, truck_a, truck_b, Scalar.Red);
Cv2.WaitKey(0);

在图片上画直线

Mat img1 = new Mat("F:\\all_truck\\truck_3.jpg", ImreadModes.Color);
Cv2.ImShow("win1", img1);
OpenCvSharp.Point truck_a = new Point(100, 100);
OpenCvSharp.Point truck_b = new Point(300, 300);
Cv2.Line(img1,up,down,Scalar.Red);
Cv2.ImShow("win_line", img1);
Cv2.WaitKey(0);

不错的链接

OpencvSharp的踩坑之路

一些完成的代码

1、帧差法判断当前帧有没有物体

一共定义了三个函数
public void redefineWH(int weight, int hight, int maxSize, int[] size)
public int target_judgment(Mat pBkImage, Mat pFrImage)
public int object_judgment(string pBkImage_file, string pFrImage_file)

调用的话使用的是最后一个object_judgment函数,传送进入的是背景帧和当前帧的路径(必须是绝对路径,c#的相对路径读取不到)。

返回值有三个:
-1:没有读取到图片(背景帧和当前帧都有可能,如果想具体判断那个帧我可以再修改)
0:当前帧中没有物体
1:当前帧中有物体

private void button6_Click(object sender, EventArgs e)
{
    string source_wrl = "C:/Users/liu/source/repos/car_segment_1/car_segment";

    string fileUrl_Bk = source_wrl + "/photo/background_absdiff/Wide_angle_78_1/0.jpg";
    string fileUrl_Fr = source_wrl + "/photo/background_absdiff/Wide_angle_78_1/15.jpg";
    Mat pFrImage = new Mat(fileUrl_Fr, ImreadModes.Color);
    Mat pBkImage = new Mat(fileUrl_Bk, ImreadModes.Color);

    textBox1.Text = "213";
    int s = 9;
    s = object_judgment(fileUrl_Bk,fileUrl_Fr);
    textBox1.Text = s.ToString();

}

public void redefineWH(int weight, int hight, int maxSize, int[] size)
{
    int maxValue = Math.Max(weight, hight);
    float rate = (float)maxSize / (float)maxValue;
    int w = (int)Math.Round(weight * rate);
    int h = (int)Math.Round(hight * rate);
    size[0] = w;
    size[1] = h;
}
//如果返回0说明没有物体,如果返回1说明有物体
public int target_judgment(Mat pBkImage, Mat pFrImage)
{
    //这里需要加上一个图片是否存在的判断


    /*cout << "进入循环函数" << endl;*/
    Mat pBkImage_copy = new Mat();
    Mat pFrImage_copy = new Mat();
    Mat pBkImage_gray = new Mat();
    Mat pFrImage_gray = new Mat();
    Mat pBkImage_gauss = new Mat();
    Mat pFrImage_gauss = new Mat();
    Mat Image_diff = new Mat();
    Mat Image_threshold = new Mat();
    Mat Image_morp = new Mat();
    pBkImage.CopyTo(pBkImage_copy);
    pFrImage.CopyTo(pFrImage_copy);

    //灰度化
    Cv2.CvtColor(pBkImage_copy, pBkImage_gray, ColorConversionCodes.BGR2GRAY);
    Cv2.CvtColor(pFrImage_copy, pFrImage_gray, ColorConversionCodes.BGR2GRAY);
    /*cout << "灰度化" << endl;*/

    //高斯模糊
    Cv2.GaussianBlur(pBkImage_gray, pBkImage_gauss, new OpenCvSharp.Size(11,11), 4, 4);
    Cv2.GaussianBlur(pFrImage_gray, pFrImage_gauss, new OpenCvSharp.Size(11, 11), 4, 4);
    //blur(src_gray, src_gray, Size(3, 3));
    /*cout << "高斯模糊" << endl;*/

    //帧差
    Cv2.Absdiff(pBkImage_gauss, pFrImage_gauss, Image_diff);
    /*cout << "帧差" << endl;*/
    Cv2.ImShow("Image_diff", Image_diff);

    //二值化CV_THRESH_BINARY
    Cv2.Threshold(Image_diff, Image_threshold, 60, 255, ThresholdTypes.Binary);
    Cv2.ImShow("Image_threshold", Image_threshold);
    /*cout << "二值化" << endl;*/


    //自定义核,进行开、闭运算
    Mat element = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(5, 5));
    Cv2.MorphologyEx(Image_threshold, Image_morp, MorphTypes.Open, element);
    Cv2.MorphologyEx(Image_morp, Image_morp, MorphTypes.Close, element);
    /*cout << "进行开" << endl;*/

    //查找前景的区域
    //vector<vector<Point>> contours;
    //vector<Vec4i> hierarchy;
    Point[][] contours;
    HierarchyIndex[] hierarchy;
    //Cv2.FindContours(Image_morp, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(0, 0));
    Cv2.FindContours(Image_morp, out contours, out hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxSimple, new Point(0, 0));

    //cout << "查找前景的区域" << endl;

    //vector<vector<Point> > contours_poly(contours.size());
    //vector<Rect> boundRect(contours.size());
    //vector<Point2f>center(contours.size());
    //vector<float>radius(contours.size());

    //cout << "查找前景的区域-定义存储器" << endl;
    //vector<int> xs, xy;
    //cout << "contours.size(): " << contours.size() << endl;

    if (contours.Length == 0)
    {
        System.Diagnostics.Debug.WriteLine("没有任何前景"); 
        return 0;
    }
    double image_area = 0.0;
    for (int i = 0; i < contours.Length; i++)
    {
        //approxPolyDP(Mat(contours[i]), contours_poly[i], 3, true);

        //cout << "进入函数" << endl;

        //boundRect[i] = boundingRect(Mat(contours[i]));
        image_area += Cv2.ContourArea(contours[i]);
        //image_area += contourArea(contours[i]);
        //cout << "是空的" << endl;
        //cout << boundRect[i].x << "     ii " << endl;
        //cout << boundRect[i].y << "     ii " << endl;
        //cout << boundRect[i].width << "     ii " << endl;
        //cout << boundRect[i].height << "     ii " << endl;
        //cout << boundRect[i] << "     ii " << endl;
        //xs.push_back(boundRect[i].x);
        //xs.push_back(boundRect[i].x + boundRect[i].width);
        //xy.push_back(boundRect[i].y);
        //xy.push_back(boundRect[i].y + boundRect[i].height);

        //minEnclosingCircle(contours[i], center[i], radius[i]);
    }
    //int x_max, x_min, y_max, y_min;
    //x_max = *max_element(xs.begin(), xs.end());
    //x_min = *min_element(xs.begin(), xs.end());
    //y_max = *max_element(xy.begin(), xy.end());
    //y_min = *min_element(xy.begin(), xy.end());

    //cout << "x_max: v " << x_max << endl;
    //cout << "x_min: v " << x_min << endl;
    //cout << "y_max: v " << y_max << endl;
    //cout << "y_min: v " << y_min << endl;
    //cout << "src.col: v " << pBkImage.cols << endl;
    //cout << " src.rows: v " << pBkImage.rows << endl;
    //cout << " 总面积为:  " << image_area << endl;
    System.Diagnostics.Debug.WriteLine("面积为: " + image_area.ToString());
    //如果前景物体的面积大于1200,则返回1,否则判断为没有物体,返回0
    if (image_area > (double)(1200))
    {
        return 1;
    }
    else
    {
        return 0;
    }

    //画出矩阵和圆形
    //Mat drawing = Mat::zeros(Image_threshold.size(), CV_8UC3);
    //for (int i = 0; i < contours.size(); i++)
    //{
    //	Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
    //	drawContours(drawing, contours_poly, i, color, 1, 8, vector<Vec4i>(), 0, Point());
    //	rectangle(drawing, boundRect[i].tl(), boundRect[i].br(), color, 2, 8, 0);
    //	circle(drawing, center[i], (int)radius[i], color, 2, 8, 0);
    //}

    /// 显示在一个窗口
    //namedWindow("Contours", CV_WINDOW_AUTOSIZE);
    //imshow("Contours", drawing);

    //waitKey(0);
    return 1;

}
public int object_judgment(string pBkImage_file, string pFrImage_file)
{
    //Mat pBkImage_mid, pFrImage_mid, pBkImage_resize, pFrImage_resize;      //定义了前景和背景帧
     //定义了前景和背景帧
    Mat pBkImage = new Mat();
    Mat pFrImage = new Mat();
    Mat pBkImage_mid = new Mat();
    Mat pFrImage_mid = new Mat();
    Mat pBkImage_resize = new Mat();
    Mat pFrImage_resize = new Mat();

    //pBkImage = imread("./photo/background_absdiff/Wide_angle_78_1/0.jpg");
    //pFrImage = imread("./photo/background_absdiff/Wide_angle_78_1/14.jpg");
    pBkImage = Cv2.ImRead(pBkImage_file, ImreadModes.Color);
    pFrImage = Cv2.ImRead(pFrImage_file, ImreadModes.Color);

    Mat a = Cv2.ImRead(pBkImage_file, ImreadModes.Color);
    Cv2.ImShow("a", a);
    Cv2.ImShow("pFrImage", pFrImage);
    if (pBkImage.Empty())
    {
        System.Diagnostics.Debug.WriteLine("没有背景图片"); 
        return -1;
    }
    if (pFrImage.Empty())
    {
        System.Diagnostics.Debug.WriteLine("没有前景图片");
        return -1;
    }

    pBkImage.CopyTo(pBkImage_mid);
    pFrImage.CopyTo(pFrImage_mid);

    int x, y, width, height;

    x = 0;
    y = (int)(pBkImage.Rows / 3);
    width = (int)(pBkImage.Cols);
    height = (int)(pBkImage.Rows / 6);

    //cout << "x:  " << x << endl;
    //cout << " y:  " << y << endl;
    //cout << "width:  " << width << endl;
    //cout << " height:  " << height << endl;

    Rect rect =new OpenCvSharp.Rect(x, y, width, height);
    pBkImage_mid = (new Mat(pBkImage, rect)).Clone();
    pFrImage_mid = (new Mat(pFrImage, rect)).Clone();


    //namedWindow("pBkImage_mid", CV_WINDOW_AUTOSIZE);
    //imshow("pBkImage_mid", pBkImage_mid);
    //namedWindow("pFrImage_mid", CV_WINDOW_AUTOSIZE);
    //imshow("pFrImage_mid", pFrImage_mid);

    int scale = 640;
    int []image_size = new int [2];
    redefineWH(pBkImage_mid.Cols, pBkImage_mid.Rows, (int)scale, image_size);
    //Cv2.Resize(pBkImage_mid, pBkImage_resize, new OpenCvSharp.Size(image_size[0], image_size[1]), InterpolationFlags.Linear);           //按照计算的x和y进行resize
    //Cv2.Resize(pFrImage_mid, pFrImage_resize, new OpenCvSharp.Size(image_size[0], image_size[1]), InterpolationFlags.Linear);           //按照计算的x和y进行resize
    Cv2.Resize(pBkImage_mid, pBkImage_resize, new OpenCvSharp.Size(image_size[0], image_size[1]));           //按照计算的x和y进行resize
    Cv2.Resize(pFrImage_mid, pFrImage_resize, new OpenCvSharp.Size(image_size[0], image_size[1]));           //按照计算的x和y进行resize


    //cout << "pBkImage_resize.col: v " << pBkImage_resize.cols << endl;
    //cout << " pBkImage_resize.rows: v " << pBkImage_resize.rows << endl;
    //cout << "pFrImage_resize.col: v " << pFrImage_resize.cols << endl;
    //cout << " pFrImage_resize.rows: v " << pFrImage_resize.rows << endl;

    //namedWindow("pBkImage_resize", CV_WINDOW_AUTOSIZE);
    //imshow("pBkImage_resize", pBkImage_resize);
    //namedWindow("pFrImage_resize", CV_WINDOW_AUTOSIZE);
    //imshow("pFrImage_resize", pFrImage_resize);

    int flag = 0;
    flag = target_judgment(pBkImage_resize, pFrImage_resize);
    //cout << "flag 的值为: " << flag << endl;
    //waitKey(0);
    System.Diagnostics.Debug.WriteLine(flag.ToString());
    return flag;
}