视频中的一帧
提取后在黑色物体边生成红色矩形框,并在图片左上角输出矩形框中心坐标。
代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using Emgu.Util;
using Emgu.CV.Util;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Text;
using System.Windows.Forms;
namespace ClassLibrary1
{
public class Class1
{
public Class1()
{ }
static public Rectangle Findcoordinate(Mat frame, int bigarea, int smallarea)
{
Mat grayimg = new Mat(), thresholdimg = new Mat(), canny = new Mat();
VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
double gnthresh = 40;
int idx, idy = 0;
String text1 = null, text2 = null, text3 = null;
Rectangle box = new Rectangle();
CvInvoke.CvtColor(frame, grayimg, ColorConversion.Bgr2Gray);
CvInvoke.Blur(grayimg, grayimg, new Size(3, 3), new Point(-1, -1));
CvInvoke.Threshold(grayimg, thresholdimg, gnthresh, 255, ThresholdType.Binary);
//CvInvoke.Dilate(thresholdimg, thresholdimg, null, new Point(-1, -1), 1, BorderType.Constant, CvInvoke.MorphologyDefaultBorderValue);//膨胀扩张
CvInvoke.Erode(thresholdimg, thresholdimg, null, new Point(-1, -1), 1, BorderType.Constant, CvInvoke.MorphologyDefaultBorderValue);//腐蚀,先膨胀后腐蚀是闭运算,消除小黑洞
CvInvoke.Canny(thresholdimg, canny, 100, 50);//最大幅值100,最小幅值50,大于100,则保留;小于50,排除;两者之间且连着大于100的点才保留
//Mat mask1 = new Mat(thresholdimg.Size.Height,thresholdimg.Size.Width,DepthType.Cv8U,1);
//mask1.SetTo(new MCvScalar(255));
//canny.CopyTo(mask1);
int[,] hierachy = CvInvoke.FindContourTree(canny, contours, ChainApproxMethod.ChainApproxSimple);//最后一个参数表示一个矩形只要4个点的参数
if (contours.Size == 0) return box;
for (; idy >= 0 && text1 == null; idy = hierachy[idy, 0])
for (idx = idy; idx >= 0; idx = hierachy[idx, 2])//hierachy[idx, 0]表示后一个轮廓索引编号 [idx,2]表示内部轮廓
{
using (VectorOfPoint c = contours[idx])
using (VectorOfPoint approx = new VectorOfPoint())
{
CvInvoke.ApproxPolyDP(c, approx, CvInvoke.ArcLength(c, true) * 0.001, true);//逼近多边形,ApproxPolyDP(,,精度为周长的0.02倍,要封闭的)
double area = CvInvoke.ContourArea(approx);
/*Point[] pts = approx.ToArray();
for (int j = 0; j < pts.Length; j++)
{
Point p1 = new Point(pts[j].X, pts[j].Y);
Point p2;
if (j == pts.Length - 1)
p2 = new Point(pts[0].X, pts[0].Y);
else
p2 = new Point(pts[j + 1].X, pts[j + 1].Y);
CvInvoke.Line(frame, p1, p2, new MCvScalar(255, 255, 0), 3);
}*/
if (bigarea > area && area > smallarea)
{
box = CvInvoke.BoundingRectangle(c);//返回外部矩形边界
Mat candidate = new Mat();
using (Mat tmp = new Mat(frame, box)) //roi
{
CvInvoke.CvtColor(tmp, candidate, ColorConversion.Bgr2Gray);
}
using (Mat mask = new Mat(candidate.Size.Height, candidate.Width, DepthType.Cv8U, 1)) //set the value of pixels not in the contour region to zero 设置像素值不在轮廓区域为零
{
mask.SetTo(new MCvScalar(255));//白色图像
//CvInvoke.DrawContours(mask, contours, idx, new MCvScalar(0), -1, LineType.EightConnected, null, int.MaxValue, new Point(-box.X, -box.Y));//黑色轮廓
//CvInvoke.Imshow("x", mask);
CvInvoke.Rectangle(frame, box, new MCvScalar(0, 0, 255), 2);
text1 = Convert.ToString((2 * box.X + box.Width) / 2);//横向坐标
text2 = Convert.ToString(box.Y);//纵向坐标
text3 = Convert.ToString(area);
}
break;
}
}
}
if (text1 != null && text2 != null)
{
CvInvoke.PutText(frame, text1, new Point(0, 40), FontFace.HersheyTriplex, 1, new MCvScalar(255, 255, 255), 2);
CvInvoke.PutText(frame, text2, new Point(160, 40), FontFace.HersheyTriplex, 1, new MCvScalar(255, 255, 255), 2);
CvInvoke.PutText(frame, text3, new Point(320, 40), FontFace.HersheyTriplex, 1, new MCvScalar(255, 255, 255), 2);
}
return box;
}
}
}