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。
2、出错
c# OpenCvSharp4 无法加载 DLLOpenCvSharpExtern:找不到指定的模块
这句话的意思是,这个包只包含内部算法的核心部分,因此,使用时还需添加OPENCV4.runtime
安装这个拓展包就可以使用了。
二、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直接输入就可以了,这里会自动跳出合适的选项。
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;
}